UNPKG

@triviality/core

Version:
293 lines 15.5 kB
"use strict"; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; var __spread = (this && this.__spread) || function () { for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i])); return ar; }; var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; result["default"] = mod; return result; }; Object.defineProperty(exports, "__esModule", { value: true }); var filehound_1 = require("filehound"); var fs = __importStar(require("fs")); var os_1 = require("os"); var ramda_1 = require("ramda"); var yup = __importStar(require("yup")); exports.generateRecurringString = ramda_1.curry(function (total, empty, createString, separator) { return ramda_1.range(empty ? 0 : 1, total + 1).map(createString).join(separator); }); exports.parseNumber = ramda_1.curryN(2, parseInt)(ramda_1.__, 10); /** * Return all generators of a single document. * * Generators need to be inside multi-doc block comment. */ exports.findAnnotationsString = function (annotation) { return ramda_1.match(new RegExp("^.*@" + annotation + "\\([\\s\\S.*]*?\\).*[.\\s\\S]*?\\*\\/$", 'gm')); }; /** * Return all generators of a single document. * * Generators need to be inside multi-doc block comment. */ exports.findFunctionGeneratorAnnotationsString = exports.findAnnotationsString('typeGenerator'); var matchEmptyOrStatement = function () { return /(.*; *$|^ *$)/; }; var GeneratorTemplateSchema = yup.object({ length: yup.number().positive().default(10), templates: yup.array(yup.string().required()).required(), removeNextLines: yup.mixed().default(matchEmptyOrStatement), empty: yup.boolean().default(false), }).noUnknown(); /** * Remove any doc block characters from a string * * // * * /** * * * * / */ exports.stripDocBlock = ramda_1.replace(/^ *(\/?\*+|\/\/)/gm, ''); /** * Remove all ,< from empty generic functions. * * This: * <> * <,C extends string> * <D extends number,, C extends string> * <D extends number,, C extends string>(,dd: string) * <D extends number,, C extends string>(dd: string,,d: string) * * Would be this: * <C extends string> * <D extends number, C extends string> * <D extends number, C extends string>(dd: string) * <D extends number, C extends string>(dd: string,d: string) */ var stripEmptyGeneric = ramda_1.replace(/<>|(<|\(), *|( *, *),|, *(\))/gm, '$1$2$3'); /** * Parse generator function. * * @typeGenerator({ length: 10, templates: ["services<{K% extends keyof T}>({t%: K%}): [{T[K%]}];"], removeNextLines: /; *$/ }) */ exports.parseFunctionGeneratorAnnotation = ramda_1.pipe(ramda_1.match(/@typeGenerator\(([\s\S.]*)\)/), ramda_1.pipe(ramda_1.nth(1), function (target) { var striped = exports.stripDocBlock(target); try { // tslint:disable-next-line:no-eval return eval("(" + striped + ");"); } catch (e) { throw new Error(e + " => (" + striped + ");"); } }), GeneratorTemplateSchema.cast.bind(GeneratorTemplateSchema)); /** * Find all tags "{t%: K%}" of a function template. */ exports.findGeneratorTagsStrings = ramda_1.match(/{{.+?}}/gm); /** * Parse a single tag and return variables. */ exports.parseGeneratorTag = ramda_1.pipe(ramda_1.match(/{{(.*?) *(-(.*))?}}/), ramda_1.applySpec({ tag: ramda_1.nth(0), template: ramda_1.nth(1), separator: ramda_1.pipe(ramda_1.nth(3), ramda_1.cond([ [ramda_1.is(String), ramda_1.identity], [ramda_1.T, ramda_1.always(', ')], ])), })); exports.findGeneratorTags = ramda_1.pipe(exports.findGeneratorTagsStrings, ramda_1.map(exports.parseGeneratorTag)); /** * Fill tag template. * - Replaces % for i given. * - Strip template tokens. */ var populateGeneratorTagTemplate = ramda_1.curry(function (template, i) { return ramda_1.replace(/%/g, i.toString(10), template); }); exports.generateFunction = ramda_1.curry(function (template, i) { var g = exports.generateRecurringString(i, false); var result = exports.findGeneratorTags(template).reduce(function (acc, _a) { var tag = _a.tag, separator = _a.separator, t = _a.template; var f = g(populateGeneratorTagTemplate(t), separator); return acc.replace(tag, f); }, template); return i === 0 ? stripEmptyGeneric(result) : result; }); function generateFunctions(length, emptyArgs, templates) { return exports.generateRecurringString(length, emptyArgs, function (i) { return templates.reduce(function (acc, template) { if (!acc) { return exports.generateFunction(template, i); } return acc + os_1.EOL + exports.generateFunction(template, i); }, null) || ''; }, os_1.EOL); } exports.generateFunctions = generateFunctions; function removeStartLine(text, removeNextLines) { return ramda_1.match(/^.*$/gm, text) .reduce(function (_a, line) { var document = _a.document, done = _a.done; if (done || !removeNextLines.test(line)) { return { document: document === '' ? line : document + os_1.EOL + line, done: true, }; } return { document: document, done: done, }; }, { document: '', done: false }).document; } function generateFunctionsInDocument(document) { return exports.findFunctionGeneratorAnnotationsString(document) .reduce(function (acc, generator) { var _a = exports.parseFunctionGeneratorAnnotation(generator), templates = _a.templates, length = _a.length, removeNextLines = _a.removeNextLines, empty = _a.empty; var index = acc.indexOf(generator); var end = index + generator.length; var cleaned = acc.slice(0, end) + os_1.EOL + removeStartLine(acc.slice(end), removeNextLines); return cleaned.replace(generator, generator + os_1.EOL + generateFunctions(length, empty, templates)); }, document); } exports.generateFunctionsInDocument = generateFunctionsInDocument; /** * Replaces multiple generators of set of files. */ function generateFunctionsOfTemplatesInDirectory() { var _a; var directories = []; for (var _i = 0; _i < arguments.length; _i++) { directories[_i] = arguments[_i]; } (_a = filehound_1.create()).paths.apply(_a, __spread(directories)).ext(['ts', 'tsx']) .discard(/__test__/) .findSync() .forEach(function (file) { var content = fs.readFileSync(file).toString(); var updates = generateFunctionsInDocument(content); if (content !== updates) { fs.writeFileSync(file, updates); } }); } exports.generateFunctionsOfTemplatesInDirectory = generateFunctionsOfTemplatesInDirectory; it('generateRecurringString should generate string based on length and template', function () { var g = exports.generateRecurringString(3, false); expect(g(function (i) { return "[" + i + "]"; }, ', ')).toEqual('[1], [2], [3]'); var gE = exports.generateRecurringString(3, true); expect(gE(function (i) { return "[" + i + "]"; }, ', ')).toEqual('[0], [1], [2], [3]'); }); it('parseNumber', function () { expect(exports.parseNumber('10')).toEqual(10); expect(exports.parseNumber('-10')).toEqual(-10); }); it('findFunctionGeneratorAnnotationsString', function () { expect(exports.findFunctionGeneratorAnnotationsString("\n /**\n * @typeGenerator({ length: 10, templates: [\"services<{K% extends keyof T}>({t%: K%}): [{T[K%]}];\"] })\n */\n export function servives(tags: any): any[];\n\n /**\n * @typeGenerator({ length: 10, templates: [\"export function toInt({a%i: number}): void;\"], removeNextLines: /;/})\n */\n export toInt(...args: number[]): void;\n ")).toMatchSnapshot(); }); it('findFunctionGeneratorAnnotationsString multiline', function () { expect(exports.findFunctionGeneratorAnnotationsString("\n /**\n * @typeGenerator({ length: 10, templates:\n * [\"services<{K% extends keyof T}>({t%: K%}): [{T[K%]}];\"]\n * } )\n */\n ")).toMatchSnapshot(); }); it('parseFunctionGeneratorAnnotation', function () { expect(exports.parseFunctionGeneratorAnnotation('@typeGenerator({ empty: true, length: 10, templates: [\'export function toInt({a%i: number}): void;\'], removeNextLines: /;/ })')).toEqual({ empty: true, length: 10, removeNextLines: /;/, templates: ['export function toInt({a%i: number}): void;'], }); }); it('parseFunctionGeneratorAnnotation with defaults', function () { expect(exports.parseFunctionGeneratorAnnotation('@typeGenerator({ length: 5, templates: [\'export function toInt({a%i: number}): void;\'] })')).toEqual({ empty: false, length: 5, removeNextLines: /(.*; *$|^ *$)/, templates: ['export function toInt({a%i: number}): void;'], }); }); it('findGeneratorTagsStrings', function () { expect(exports.findGeneratorTagsStrings('export function toInt({{a%i: number}}): { data: {{a%i}} };')).toEqual([ '{{a%i: number}}', '{{a%i}}', ]); }); it('parseGeneratorTag', function () { expect(exports.parseGeneratorTag('{{a%}}')).toEqual({ template: 'a%', separator: ', ', tag: '{{a%}}', }); expect(exports.parseGeneratorTag('{{b%- | }}')).toEqual({ template: 'b%', separator: ' | ', tag: '{{b%- | }}', }); }); it('findGeneratorTags', function () { expect(exports.findGeneratorTags('foobar({{a%: number}}): { data: [{{typeof a%}}] };')).toEqual([ { template: 'a%: number', separator: ', ', tag: '{{a%: number}}', }, { template: 'typeof a%', separator: ', ', tag: '{{typeof a%}}', }, ]); }); it('populateGeneratorTagTemplate', function () { expect(populateGeneratorTagTemplate('a%: number', 2)).toEqual('a2: number'); expect(populateGeneratorTagTemplate('c: typeof a%, a%: number', 5)).toEqual('c: typeof a5, a5: number'); }); it('generateFunction', function () { expect(exports.generateFunction('foobar({{a%: number}}): { data: [{{typeof a%}}] };', 2)).toEqual('foobar(a1: number, a2: number): { data: [typeof a1, typeof a2] };'); }); it('generateFunctions', function () { expect(generateFunctions(2, false, ['foo({{a%: string}}): void;', 'bar({{b%:number}}): void;'])) .toEqual("foo(a1: string): void;\nbar(b1:number): void;\nfoo(a1: string, a2: string): void;\nbar(b1:number, b2:number): void;"); }); it('generateFunctions with empty function', function () { expect(generateFunctions(2, true, ['foo({{a%: string}}): void;', 'bar({{b%:number}}): void;'])) .toEqual("foo(): void;\nbar(): void;\nfoo(a1: string): void;\nbar(b1:number): void;\nfoo(a1: string, a2: string): void;\nbar(b1:number, b2:number): void;"); }); it('generateFunctions should remove empty generic types <>', function () { expect(generateFunctions(1, true, ['foo<{{A% extends string}}>({{a%: A1}}): void;'])) .toEqual("foo(): void;\nfoo<A1 extends string>(a1: A1): void;"); expect(generateFunctions(1, true, ['foo<{{A% extends string}}, D extends number>({{a%: A1}}, d: D): void;'])) .toEqual("foo<D extends number>(d: D): void;\nfoo<A1 extends string, D extends number>(a1: A1, d: D): void;"); expect(generateFunctions(1, true, ['foo<C extends Object,{{ A% extends string}}, D extends number>({{a%: A1}}, d: D, c: C): void;'])) .toEqual("foo<C extends Object, D extends number>(d: D, c: C): void;\nfoo<C extends Object, A1 extends string, D extends number>(a1: A1, d: D, c: C): void;"); }); it('generateFunctionsInDocument', function () { expect(generateFunctionsInDocument("\n/**\n * @typeGenerator({ length: 4, templates: [\"compose<{{t% extends keyof T}}}, F extends ({{d%: SFT<T[t%]>}}) => S, S>(f: F, {{k%: t%}}}): () => S;\"] })\n */\n")) .toEqual("\n/**\n * @typeGenerator({ length: 4, templates: [\"compose<{{t% extends keyof T}}}, F extends ({{d%: SFT<T[t%]>}}) => S, S>(f: F, {{k%: t%}}}): () => S;\"] })\n */\ncompose<t1 extends keyof T}, F extends (d1: SFT<T[t1]>) => S, S>(f: F, k1: t1}): () => S;\ncompose<t1 extends keyof T, t2 extends keyof T}, F extends (d1: SFT<T[t1]>, d2: SFT<T[t2]>) => S, S>(f: F, k1: t1, k2: t2}): () => S;\ncompose<t1 extends keyof T, t2 extends keyof T, t3 extends keyof T}, F extends (d1: SFT<T[t1]>, d2: SFT<T[t2]>, d3: SFT<T[t3]>) => S, S>(f: F, k1: t1, k2: t2, k3: t3}): () => S;\ncompose<t1 extends keyof T, t2 extends keyof T, t3 extends keyof T, t4 extends keyof T}, F extends (d1: SFT<T[t1]>, d2: SFT<T[t2]>, d3: SFT<T[t3]>, d4: SFT<T[t4]>) => S, S>(f: F, k1: t1, k2: t2, k3: t3, k4: t4}): () => S;\n"); }); it('generateFunctionsInDocument multiline', function () { expect(generateFunctionsInDocument("\n/**\n * @typeGenerator({ length: 2, templates: [\n * \"Foo{{%}}\",\n * \"Bar{{%}}\",\n * ]})\n */\n")) .toEqual("\n/**\n * @typeGenerator({ length: 2, templates: [\n * \"Foo{{%}}\",\n * \"Bar{{%}}\",\n * ]})\n */\nFoo1\nBar1\nFoo1, 2\nBar1, 2\n"); }); it('removeStartLine', function () { expect(removeStartLine("d;\nddsad;\n\nsad;;\n\nDo not remove!\n\nDon't ignore this;\n", matchEmptyOrStatement())).toEqual("Do not remove!\n\nDon't ignore this;\n"); }); it('generateFunctionsInDocument should remove old lines', function () { expect(generateFunctionsInDocument("\n/**\n * @typeGenerator({ length: 4, templates: [\"compose<{{t% extends keyof T}}}, F extends ({{d%: SFT<T[t%]>}}) => S, S>(f: F, {{k%: t%}}}): () => S;\"] })\n */\n compose<t1 extends keyof T, t2 extends keyof T}, F extends (d1: SFT<T[t1]>, d2: SFT<T[t2]>) => S, S>(f: F, k1: t1, k2: t2}): () => S;\nRemove this;\ncompose<t1 extends keyof T, t2 extends keyof T, t3 extends keyof T, t4 extends keyof T}, F extends (d1: SFT<T[t1]>, d2: SFT<T[t2]>, d3: SFT<T[t3]>, d4: SFT<T[t4]>) => S, S>(f: F, k1: t1, k2: t2, k3: t3, k4: t4}): () => S;\n\npreserve this\n\n")) .toEqual("\n/**\n * @typeGenerator({ length: 4, templates: [\"compose<{{t% extends keyof T}}}, F extends ({{d%: SFT<T[t%]>}}) => S, S>(f: F, {{k%: t%}}}): () => S;\"] })\n */\ncompose<t1 extends keyof T}, F extends (d1: SFT<T[t1]>) => S, S>(f: F, k1: t1}): () => S;\ncompose<t1 extends keyof T, t2 extends keyof T}, F extends (d1: SFT<T[t1]>, d2: SFT<T[t2]>) => S, S>(f: F, k1: t1, k2: t2}): () => S;\ncompose<t1 extends keyof T, t2 extends keyof T, t3 extends keyof T}, F extends (d1: SFT<T[t1]>, d2: SFT<T[t2]>, d3: SFT<T[t3]>) => S, S>(f: F, k1: t1, k2: t2, k3: t3}): () => S;\ncompose<t1 extends keyof T, t2 extends keyof T, t3 extends keyof T, t4 extends keyof T}, F extends (d1: SFT<T[t1]>, d2: SFT<T[t2]>, d3: SFT<T[t3]>, d4: SFT<T[t4]>) => S, S>(f: F, k1: t1, k2: t2, k3: t3, k4: t4}): () => S;\npreserve this\n\n"); }); it('!!', function () { generateFunctionsOfTemplatesInDirectory(__dirname + "/../../"); }); //# sourceMappingURL=ServicesContext.generator.test.js.map