Last active
April 26, 2021 02:20
-
-
Save kellywoo/42ce99615d68cb66f7e4bef1d120dadf to your computer and use it in GitHub Desktop.
stringify
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function* pipe(arr, operators) { | |
if (!Array.isArray(arr)) { | |
throw 'It is not Array.'; | |
} | |
if (!Array.isArray(operators)) { | |
throw 'operators should be type of Array<[type: string; fn: (v:any) => any]>'; | |
} | |
const cpArr = [...arr]; | |
let muatated = []; | |
let i = 0; | |
for (const v of cpArr) { | |
i++; | |
let value = v; | |
let shouldShiftOut = false; | |
for (const op of operators) { | |
try { | |
switch (op[0]) { | |
case 'filter' : | |
if (!op[1](value)) { | |
shouldShiftOut = true; | |
} | |
break; | |
case 'map' : | |
value = op[1](value); | |
break; | |
default: | |
throw 'not supporting method'; | |
} | |
if (shouldShiftOut) break; | |
} catch (e) { | |
throw e; | |
} | |
} | |
if (!shouldShiftOut) { | |
muatated.push(value); | |
} | |
if (i === cpArr.length) { | |
return muatated; | |
} else { | |
yield null; | |
} | |
} | |
} | |
const m = pipe([1,2,3,4,5,6,7], [['filter', (v)=>v%2 ===0], ['map', (v)=> v*2 ]]); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const {stringify} = (() => { | |
// simple | |
const strRegexp = [[/\\/g, '\\\\'], [/\n/g, '\\n'], [/\t/g, '\\t'], [/\v/g, '\\v'], [/[\b]/g, '\\b'], [/[\r]/g, '\\r'], [/"/g, '\\"']] | |
class ResultRecords { | |
constructor() { | |
this.data = []; | |
} | |
} | |
// complex | |
const complexType = { | |
array: 'array', | |
object: 'object', | |
itemRecord: 'itemRecord', | |
} | |
const complexHandlers = { | |
[complexType.array]: { | |
createGen: function* (obj) { | |
for (const v of obj) yield {value: v}; | |
}, | |
createRecords: () => { | |
return new class extends ResultRecords { | |
join() { | |
return `[${this.data.join(',')}]`; | |
} | |
push(str) { | |
this.data.push(str) | |
} | |
} | |
}, | |
}, | |
[complexType.object]: { | |
createGen: function* (obj) { | |
for (const k in obj) if (obj.hasOwnProperty(k)) yield {key: k, value: obj[k]}; | |
}, | |
createRecords: () => { | |
return new class extends ResultRecords { | |
join() { | |
return `{${this.data.map((m) => { | |
return `${typeHandler.string(m[0].toString())}:${m[1]}`; | |
}).join(',')}}` | |
} | |
push(str, key) { | |
this.data.push([key, str]) | |
} | |
} | |
}, | |
} | |
} | |
const typeHandler = { | |
default: () => 'null', | |
boolean: v => v.toString(), | |
number: v => { | |
if (isNaN(v) || !isFinite(v)) { | |
return typeHandler.default(); | |
} | |
return v === 0 ? '0' : v.toString(); | |
}, | |
string: (str, i = 0) => { | |
if (i === strRegexp.length) return `"${str}"`; | |
return str ? typeHandler.string(str.replace(strRegexp[i][0], strRegexp[i][1]), ++i) : typeHandler.string(str, strRegexp.length); | |
}, | |
[complexType.itemRecord]: (record) => { | |
return record.join(); | |
} | |
} | |
const processGenerator = (gen, records, stack = null) => { | |
const {value, done} = gen.next(); | |
if (done) { | |
return typeRouter(records, stack); | |
} else { | |
const target = value.value; | |
const currentStack = {gen, records, key: value.key, previous: stack}; | |
return typeRouter(target, currentStack); | |
} | |
} | |
const getType = (v) => { | |
const t = typeof v | |
if (t === 'object') { | |
switch (true) { | |
case !v: | |
return 'null'; | |
case v instanceof ResultRecords: | |
return complexType.itemRecord; | |
case Array.isArray(v): | |
return complexType.array; | |
default: | |
return complexType.object; | |
} | |
} else { | |
return t; | |
} | |
} | |
const typeRouter = (v, stack) => { | |
const t = getType(v); | |
if ([complexType.array, complexType.object].includes(t)) { | |
const gen = complexHandlers[t].createGen(v); | |
const records = complexHandlers[t].createRecords(); | |
return processGenerator(gen, records, stack); | |
} | |
const str = (typeHandler[t] || typeHandler.default)(v); | |
if (stack) { | |
const {gen, records, key, previous} = stack; | |
records.push(str, key); | |
return processGenerator(gen, records, previous); | |
} else { | |
return str | |
} | |
} | |
const stringify = (v) => { | |
return typeRouter(v); | |
} | |
return {stringify}; | |
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const {stringify} = (() => { | |
// simple | |
const strRegexp = [[/\\/g, '\\\\'], [/\n/g, '\\n'], [/\t/g, '\\t'], [/\v/g, '\\v'], [/[\b]/g, '\\b'], [/[\r]/g, '\\r'], [/"/g, '\\"']] | |
class ResultRecords { | |
constructor() { | |
this.data = []; | |
} | |
} | |
// complex | |
const complexType = { | |
array: 'array', | |
object: 'object', | |
itemRecord: 'itemRecord', | |
} | |
const complexHandlers = { | |
[complexType.array]: { | |
createGen: function* (obj) { | |
for (const v of obj) yield {value: v}; | |
}, | |
createRecords: () => { | |
return new class extends ResultRecords { | |
join() { | |
return `[${this.data.join(',')}]`; | |
} | |
push(str) { | |
this.data.push(str) | |
} | |
} | |
}, | |
}, | |
[complexType.object]: { | |
createGen: function* (obj) { | |
for (const k in obj) if (obj.hasOwnProperty(k)) yield {key: k, value: obj[k]}; | |
}, | |
createRecords: () => { | |
return new class extends ResultRecords { | |
join() { | |
return `{${this.data.map((m) => { | |
return `${typeHandler.string(m[0].toString())}:${m[1]}`; | |
}).join(',')}}` | |
} | |
push(str, key) { | |
this.data.push([key, str]) | |
} | |
} | |
}, | |
} | |
} | |
const typeHandler = { | |
default: () => 'null', | |
boolean: v => v.toString(), | |
number: v => { | |
if (isNaN(v) || !isFinite(v)) { | |
return typeHandler.default(); | |
} | |
return v === 0 ? '0' : v.toString(); | |
}, | |
string: (str, i = 0) => { | |
if (i === strRegexp.length) return `"${str}"`; | |
return str ? typeHandler.string(str.replace(strRegexp[i][0], strRegexp[i][1]), ++i) : typeHandler.string(str, strRegexp.length); | |
}, | |
[complexType.itemRecord]: (record) => { | |
return record.join(); | |
} | |
} | |
const processGenerator = (gen, records, stack) => { | |
const {value, done} = gen.next(); | |
if (done) { | |
return typeRouter(records, stack); | |
} else { | |
const target = value.value; | |
const currentStack = {gen, records, key: value.key, previous: stack}; | |
return typeRouter(target, currentStack); | |
} | |
} | |
const getType = (v) => { | |
const t = typeof v | |
if (t === 'object') { | |
switch (true) { | |
case !v: | |
return 'null'; | |
case v instanceof ResultRecords: | |
return complexType.itemRecord; | |
case Array.isArray(v): | |
return complexType.array; | |
default: | |
return complexType.object; | |
} | |
} else { | |
return t; | |
} | |
} | |
const typeRouter = (v, stack) => { | |
const t = getType(v); | |
if ([complexType.array, complexType.object].includes(t)) { | |
const gen = complexHandlers[t].createGen(v); | |
const records = complexHandlers[t].createRecords(); | |
return processGenerator(gen, records, stack); | |
} | |
const str = (typeHandler[t] || typeHandler.default)(v); | |
if (stack) { | |
const {gen, records, key, previous} = stack; | |
records.push(str, key); | |
return processGenerator(gen, records, previous); | |
} else { | |
return str | |
} | |
} | |
const stringify = (v) => { | |
return typeRouter(v, null); | |
} | |
return {stringify}; | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
네. 의도와 달라요 ^^ 개별로 된 두개의 제네레이터를 작성하고 합성해주세요. 특히 yield* 를 사용해주세요.