├── .codeclimate.yml ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── src ├── ast.ts ├── index.ts ├── template.ts ├── traverse.ts └── tsquery-types.ts ├── test ├── concat.spec.ts ├── index.ts ├── literals.spec.ts ├── spread.spec.ts └── subsititution.spec.ts ├── tsconfig.json ├── tslint.json └── wallaby.js /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | plugins: 3 | duplication: 4 | enabled: true 5 | exclude_patterns: 6 | - "**/*.spec.ts" 7 | config: 8 | languages: 9 | - typescript 10 | tslint: 11 | enabled: true 12 | config: tslint.json 13 | fixme: 14 | enabled: true 15 | nodesecurity: 16 | enabled: true 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | npm-debug.log* 2 | node_modules 3 | reports 4 | examples 5 | dist 6 | coverage 7 | yarn-error.log 8 | .DS_Store 9 | .gitattributes 10 | .idea 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "node" 4 | addons: 5 | code_climate: 6 | repo_token: 846ddc4625428fe1230af075e5ccc6e81573429349cd67118e0e25b6a0708545 7 | script: npm run build 8 | after_success: 9 | - npm install -g codeclimate-test-reporter 10 | - codeclimate-test-reporter < ./reports/coverage/lcov.info 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Craig Spence 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TSTemplate 2 | 3 | [![npm version](https://img.shields.io/npm/v/@phenomnomnominal/tstemplate.svg)](https://img.shields.io/npm/v/@phenomnomnominal/tstemplate.svg) 4 | [![Code Climate](https://codeclimate.com/github/phenomnomnominal/tstemplate/badges/gpa.svg)](https://codeclimate.com/github/phenomnomnominal/tstemplate) 5 | [![Test Coverage](https://codeclimate.com/github/phenomnomnominal/tstemplate/coverage.svg)](https://codeclimate.com/github/phenomnomnominal/tstemplate/coverage) 6 | 7 | TSTemplate is a port of the [ESTemplate API](https://github.com/estools/estemplate) for TypeScript! TSTemplate allows you to do template substitution with AST nodes, rather than with text, which I guess is good? Who knows! 8 | 9 | # Installation: 10 | 11 | ``` 12 | npm install @phenomnomnominal/tstemplate --save-dev 13 | ``` 14 | 15 | # Examples: 16 | 17 | You can substitute "homemade" AST nodes like this: 18 | 19 | ```typescript 20 | import { tstemplate } from '@phenomnomnominal/tstemplate'; 21 | import { createPrinter, Identifier, NumericLiteral, SourceFile } from 'typescript' 22 | 23 | const result: SourceFile = tstemplate('var <%= varName %> = <%= value %> + 1;', { 24 | varName: { kind: SyntaxKind.Identifier, escapedText: 'myVar' } as Identifier, 25 | value: { kind: SyntaxKind.NumericLiteral, text: '123' } as NumericLiteral 26 | }); 27 | 28 | const printer = createPrinter(); 29 | console.log(printer.printFile(result)); // var myVar = 123; 30 | ``` 31 | 32 | Or you can use "real" TS AST nodes from TypeScript): 33 | 34 | ```typescript 35 | import { tstemplate } from '@phenomnomnominal/tstemplate'; 36 | import { createIdentifier, createPrinter, Identifier, SourceFile } from 'typescript' 37 | 38 | const result: SourceFile = tstemplate('function f(%= params %, callback) { }', { 39 | params: [createIdentifier('a'), createIdentifier('b')] 40 | }); 41 | 42 | const printer = createPrinter(); 43 | console.log(printer.printFile(result)); // function f(a, b, callback) { } 44 | ``` 45 | 46 | You can even use something like [`TSQuery`](https://github.com/phenomnomnominal/tsquery) to move nodes from one file to another: 47 | 48 | ```typescript 49 | import { tsquery } from '@phenomnomnominal/tsquery'; 50 | import { tstemplate } from '@phenomnomnominal/tstemplate'; 51 | import { readFileSync } from 'fs'; 52 | import { createPrinter } from 'typescript'; 53 | 54 | const ts = readFileSync('./some-typescript.ts'), 'utf-8'); // "console.log('Hello World');" 55 | const body = tsquery(ts, 'ExpressionStatement'); 56 | const result = tstemplate('wrap(() => {%= body %});', { body }); 57 | 58 | const printer = createPrinter(); 59 | console.log(printer.printFile(result)); // wrap(() => { console.log('Hello World'); }); 60 | ``` 61 | 62 | You can also pre-compile the template and then re-use it with different data: 63 | 64 | ```typescript 65 | import { tsquery } from '@phenomnomnominal/tsquery'; 66 | import { tstemplate } from '@phenomnomnominal/tstemplate'; 67 | import { createIdentifier, createPrinter } from 'typescript'; 68 | 69 | const template = tstemplate.compile(` 70 | var <%= varName %> = <%= value %> + 1; 71 | var exampleBoolean = <%= isTrue %>; 72 | `); 73 | 74 | const result1 = template({ 75 | varName: createIdentifier('myVar'), 76 | value: tsquery('123', 'NumericLiteral'), 77 | isTrue: tsquery('true', 'TrueKeyword') 78 | }); 79 | const result2 = template({ 80 | varName: createIdentifier('otherVar'), 81 | value: tsquery('234', 'NumericLiteral'), 82 | isTrue: tsquery('false', 'FalseKeyword') 83 | }); 84 | 85 | const printer = createPrinter(); 86 | console.log(printer.printFile(result1)); // var myVar = 123 + 1; 87 | console.log(printer.printFile(result2)); // var otherVar = 234 + 1; 88 | ``` 89 | **Note:** For more literals, keywords expressions etc. check those typescript typings: https://github.com/microsoft/TypeScript/blob/master/src/compiler/types.ts 90 | 91 | # Templating syntax: 92 | * Node substitution: `var x = <%= expr %> + 1;` 93 | * Array elements: `var a = [%= elements %];` 94 | * Function parameters: `function f(%= params %) {}` 95 | * Call arguments: `var x = f(%= args %);` 96 | * Block statements: `define(function () {%= body %});` 97 | * Literals: `var x = "%= 'alpha' + 'beta' %";` 98 | 99 | You can also combine list substitutions with inline elements: 100 | * `var a = [0, %= numbers %, Infinity];` 101 | * `function f(%= params %, callback) {}` 102 | * `define(function () { console.time('Module'); %= body %; console.timeEnd('Module'); });` 103 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@phenomnomnominal/tstemplate", 3 | "version": "0.1.0", 4 | "description": "Generate TypeScript code with the estemplate API!", 5 | "main": "dist/src/index.js", 6 | "typings": "dist/src/index.d.ts", 7 | "author": "Craig Spence ", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/phenomnomnominal/tstemplate" 11 | }, 12 | "license": "MIT", 13 | "scripts": { 14 | "compile": "tsc", 15 | "lint": "npm run lint:src && npm run lint:test", 16 | "lint:src": "tslint --project ./tsconfig.json -c ./tslint.json 'src/**/*.ts'", 17 | "lint:test": "tslint --project ./tsconfig.json -c ./tslint.json 'test/**/*.ts'", 18 | "lint:fix": "npm run lint:src:fix && npm run lint:test", 19 | "lint:src:fix": "tslint -c tslint.json 'src/**/*.ts' --fix", 20 | "lint:test:fix": "tslint -c tslint.json 'test/**/*.ts' --fix", 21 | "test": "jest", 22 | "test:debug": "node --inspect-brk ./node_modules/jest/bin/jest.js --runInBand", 23 | "build": "npm run compile && npm run lint && npm run test", 24 | "prepublishOnly": "rm -rf dist && npm run build" 25 | }, 26 | "devDependencies": { 27 | "@phenomnomnominal/tsquery": "^2.0.0-beta.2", 28 | "@types/chai": "^4.1.2", 29 | "@types/jest": "^23.0.0", 30 | "@types/node": "^9.4.7", 31 | "chai": "^4.1.2", 32 | "estemplate": "^0.5.1", 33 | "jest": "^22.4.2", 34 | "ts-jest": "^22.4.6", 35 | "ts-node": "^5.0.1", 36 | "tslint": "^5.6.0", 37 | "typescript": "^2" 38 | }, 39 | "files": [ 40 | "dist/src" 41 | ], 42 | "jest": { 43 | "globals": { 44 | "__TS_CONFIG__": "tsconfig.json" 45 | }, 46 | "moduleFileExtensions": [ 47 | "ts", 48 | "js" 49 | ], 50 | "collectCoverage": true, 51 | "collectCoverageFrom": [ 52 | "/src/**" 53 | ], 54 | "coverageDirectory": "/reports/coverage", 55 | "transform": { 56 | "\\.(ts)$": "/node_modules/ts-jest/preprocessor.js" 57 | }, 58 | "testRegex": "/test/.*\\.spec\\.ts$" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/ast.ts: -------------------------------------------------------------------------------- 1 | // Dependencies: 2 | import { createSourceFile, ScriptTarget, SourceFile } from 'typescript'; 3 | 4 | export function ast (text: string, fileName?: string): SourceFile { 5 | return createSourceFile(fileName || '', text, ScriptTarget.Latest, true); 6 | } 7 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | // Dependencies: 2 | import { compile, template } from './template'; 3 | import { TSTemplateApi } from './tsquery-types'; 4 | 5 | const api = template; 6 | api.compile = compile; 7 | 8 | export const tstemplate = api; 9 | -------------------------------------------------------------------------------- /src/template.ts: -------------------------------------------------------------------------------- 1 | // Dependencies: 2 | import { createLiteral, Identifier, Node, SourceFile } from 'typescript'; 3 | import { ast } from './ast'; 4 | import { replace, traverse } from './traverse'; 5 | import { TSTemplateData } from './tsquery-types'; 6 | 7 | // Constants: 8 | const BRACKETS: { [key: string]: string } = { 9 | '<': '>', 10 | '[': ']', 11 | '(': ')', 12 | '{': '}', 13 | '\'': '\'', 14 | '"': '"' 15 | }; 16 | const INTERNAL_DATA_REGEXP = /^__TSTEMPLATE_DATA_\d+;?$/; 17 | const INTERNAL_SPREAD_REGEXP = /^__TSTEMPLATE_SPREAD_\d+;?$/; 18 | const INTERNAL_IDENTIFIER_REGEXP = /^(__TSTEMPLATE_(DATA|SPREAD)_\d+);?$/; 19 | const TEMPLATE_REGEXP = /([^\s,;]?)\s*?%(=?)\s*([\s\S]+?)\s*%\s*?([^\s,;]?)/g; 20 | 21 | export function template (tmpl: string, data: TSTemplateData): SourceFile { 22 | return compile(tmpl)(data); 23 | } 24 | 25 | export function compile (tmpl: string): (data: TSTemplateData) => SourceFile { 26 | const identifiers: { [key: string]: string } = {}; 27 | let index = 0; 28 | 29 | tmpl = tmpl.replace(TEMPLATE_REGEXP, (match: string, open: string, isEval: string, codePart: string, close: string) => { 30 | if (open) { 31 | const expectedClose = BRACKETS[open]; 32 | if (!expectedClose || close && expectedClose !== close) { 33 | return match; 34 | } 35 | } 36 | if (isEval) { 37 | const isSpread = open !== '<' && open !== '\'' && open !== '"'; 38 | const id = index++; 39 | const identifier = isSpread ? `__TSTEMPLATE_SPREAD_${id}` : `__TSTEMPLATE_DATA_${id}`; 40 | identifiers[identifier] = codePart; 41 | return isSpread ? (open + identifier + close) : identifier; 42 | } 43 | 44 | if (open !== '<') { 45 | return match; 46 | } 47 | 48 | return ''; 49 | }); 50 | 51 | const parsed = ast(tmpl); 52 | 53 | return function (data: TSTemplateData): SourceFile { 54 | return replace(parsed, { 55 | visit: (node: Node) => { 56 | if (isInternalData(node)) { 57 | const [, identifier] = node.getText().match(INTERNAL_IDENTIFIER_REGEXP) as Array; 58 | const match = data[identifiers[identifier]]; 59 | 60 | if (typeof match === 'string') { 61 | return createLiteral(match); 62 | } 63 | 64 | const matches: Array = Array.isArray(match) ? match : [match]; 65 | matches.forEach((m: Node) => { 66 | traverse(m, { 67 | enter: resetPos 68 | }); 69 | }); 70 | return matches as any; 71 | } 72 | } 73 | }); 74 | }; 75 | } 76 | 77 | function resetPos (node: Node): void { 78 | node.pos = -1; 79 | node.end = -1; 80 | } 81 | 82 | function isInternalData (node: Node): node is Identifier { 83 | const text = node.getText(); 84 | return INTERNAL_DATA_REGEXP.test(text) || INTERNAL_SPREAD_REGEXP.test(text); 85 | } 86 | -------------------------------------------------------------------------------- /src/traverse.ts: -------------------------------------------------------------------------------- 1 | // Dependencies: 2 | import { Node, SourceFile, transform, TransformationContext, Transformer, TransformerFactory, visitEachChild } from 'typescript'; 3 | import { TSTemplateReplaceOptions, TSTemplateTraverseOptions } from './tsquery-types'; 4 | 5 | export function traverse (node: Node, options: TSTemplateTraverseOptions): void { 6 | if (options.enter) { 7 | options.enter(node, node.parent || null); 8 | } 9 | if (node.forEachChild) { 10 | node.forEachChild(child => traverse(child, options)); 11 | } 12 | if (options.leave) { 13 | options.leave(node, node.parent || null); 14 | } 15 | } 16 | 17 | export function replace (sourceFile: SourceFile, options: TSTemplateReplaceOptions): SourceFile { 18 | const result = transform(sourceFile, [createReplacer(options)]); 19 | const [transformed] = result.transformed; 20 | return transformed as SourceFile; 21 | } 22 | 23 | function createReplacer (options: TSTemplateReplaceOptions): TransformerFactory { 24 | return function (context: TransformationContext): Transformer { 25 | return function visitor (node: Node): Node { 26 | return options.visit(node, context) || visitEachChild(node, visitor, context); 27 | }; 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /src/tsquery-types.ts: -------------------------------------------------------------------------------- 1 | // Dependencies: 2 | import { Node, SourceFile, TransformationContext } from 'typescript'; 3 | 4 | export type TSTemplateApi = { 5 | (tmpl: string, data: TSTemplateData): SourceFile; 6 | compile: (tmpl: string) => (data: TSTemplateData) => SourceFile; 7 | }; 8 | 9 | export type TSTemplateData = { [key: string]: string | Node | Array }; 10 | 11 | export type TSTemplateReplaceOptions = { 12 | visit: (node: Node, context?: TransformationContext) => Node | null | undefined; 13 | }; 14 | 15 | export type TSTemplateTraverseOptions = { 16 | enter?: (node: Node, parent: Node | null) => void; 17 | leave?: (node: Node, parent: Node | null) => void; 18 | }; 19 | -------------------------------------------------------------------------------- /test/concat.spec.ts: -------------------------------------------------------------------------------- 1 | // Test Utilities: 2 | import { expect, print } from './index'; 3 | 4 | // Dependencies: 5 | import { NumericLiteral, SyntaxKind } from 'typescript'; 6 | 7 | // Under test: 8 | import { tsquery } from '@phenomnomnominal/tsquery'; 9 | import { tstemplate } from '../src/index'; 10 | 11 | describe('tstemplate:', () => { 12 | describe('tstemplate - concat:', () => { 13 | it('should append array nodes', () => { 14 | const result = tstemplate('var myArray = [123, %= items %];', { 15 | items: [{ 16 | kind: SyntaxKind.NumericLiteral, text: '456' 17 | } as NumericLiteral, { 18 | kind: SyntaxKind.NumericLiteral, text: '789' 19 | } as NumericLiteral] 20 | }); 21 | 22 | expect(print(result)).to.equal('var myArray = [123, 456, 789];'); 23 | }); 24 | 25 | it('should insert function parameter nodes', () => { 26 | const params = tsquery('a; b;', 'Identifier'); 27 | const result = tstemplate('function f(%= params %, callback) { }', { params }); 28 | 29 | expect(print(result)).to.equal('function f(a, b, callback) { }'); 30 | }); 31 | 32 | it('should insert statements', () => { 33 | const body = tsquery('init(); doSmth(); finalize();', 'ExpressionStatement'); 34 | const result = tstemplate('function f() { console.time("module"); %= body %; console.timeEnd("module"); }', { body }); 35 | 36 | expect(print(result)).to.equal('function f() { console.time("module"); init(); doSmth(); finalize(); console.timeEnd("module"); }'); 37 | }); 38 | 39 | it('should wrap statements', () => { 40 | const result = tstemplate('function f() { %= init %; doSmth(); %= finalize %; }', { 41 | init: tsquery('console.time("module"); init();', 'ExpressionStatement'), 42 | finalize: tsquery('finalize(); console.timeEnd("module");', 'ExpressionStatement') 43 | }); 44 | 45 | expect(print(result)).to.equal('function f() { console.time("module"); init(); doSmth(); finalize(); console.timeEnd("module"); }'); 46 | }); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /test/index.ts: -------------------------------------------------------------------------------- 1 | // Dependencies: 2 | import { createPrinter, SourceFile } from 'typescript'; 3 | 4 | // Test Utilities: 5 | export { expect } from 'chai'; 6 | 7 | const printer = createPrinter(); 8 | export function print (ast: SourceFile): string { 9 | return printer.printFile(ast).trim(); 10 | } 11 | -------------------------------------------------------------------------------- /test/literals.spec.ts: -------------------------------------------------------------------------------- 1 | // Test Utilities: 2 | import { expect, print } from './index'; 3 | 4 | // Under test: 5 | import { tstemplate } from '../src/index'; 6 | 7 | describe('tstemplate:', () => { 8 | describe('tstemplate - substitution:', () => { 9 | it('should replace any AST nodes', () => { 10 | const result = tstemplate('var a = "%= x %"; var b = \'%= y %\';', { 11 | x: 'alpha', 12 | y: 'beta' 13 | }); 14 | 15 | expect(print(result)).to.equal('var a = "alpha";\nvar b = "beta";'); 16 | }); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /test/spread.spec.ts: -------------------------------------------------------------------------------- 1 | // Test Utilities: 2 | import { expect, print } from './index'; 3 | 4 | // Dependencies: 5 | import { Identifier, NumericLiteral, SyntaxKind } from 'typescript'; 6 | 7 | // Under test: 8 | import { tsquery } from '@phenomnomnominal/tsquery'; 9 | import { tstemplate } from '../src/index'; 10 | 11 | describe('tstemplate:', () => { 12 | describe('tstemplate - spread:', () => { 13 | it('should replace array nodes', () => { 14 | const result = tstemplate('var myArray = [%= items %];', { 15 | items: [{ 16 | kind: SyntaxKind.NumericLiteral, text: '123' 17 | } as NumericLiteral, { 18 | kind: SyntaxKind.NumericLiteral, text: '456' 19 | } as NumericLiteral] 20 | }); 21 | 22 | expect(print(result)).to.equal('var myArray = [123, 456];'); 23 | }); 24 | 25 | it('should replace call argument nodes', () => { 26 | const result = tstemplate('var x = f(%= items %);', { 27 | items: [{ 28 | kind: SyntaxKind.NumericLiteral, text: '123' 29 | } as NumericLiteral, { 30 | kind: SyntaxKind.NumericLiteral, text: '456' 31 | } as NumericLiteral] 32 | }); 33 | 34 | expect(print(result)).to.equal('var x = f(123, 456);'); 35 | }); 36 | 37 | it('should replace function parameter nodes', () => { 38 | const [a] = tsquery('a', 'Identifier'); 39 | const [b] = tsquery('b', 'Identifier'); 40 | const result = tstemplate('function f(%= params %) { }', { params: [a, b] }); 41 | 42 | expect(print(result)).to.equal('function f(a, b) { }'); 43 | }); 44 | 45 | it('should replace block statements', () => { 46 | const body = tsquery('module.exports = require("./module").property;', 'ExpressionStatement'); 47 | const result = tstemplate('define(function () {%= body %});', { body }); 48 | 49 | expect(print(result)).to.equal('define(function () { module.exports = require("./module").property; });'); 50 | }); 51 | 52 | it('should replace root level statements', () => { 53 | const body = tsquery('module.exports = require("./module").property;', 'ExpressionStatement'); 54 | const result = tstemplate('var x = 42; %= body %;', { body }); 55 | 56 | expect(print(result)).to.equal('var x = 42;\nmodule.exports = require("./module").property;'); 57 | }); 58 | }); 59 | }); 60 | -------------------------------------------------------------------------------- /test/subsititution.spec.ts: -------------------------------------------------------------------------------- 1 | // Test Utilities: 2 | import { expect, print } from './index'; 3 | 4 | // Dependencies: 5 | import { Identifier, NumericLiteral, SyntaxKind } from 'typescript'; 6 | 7 | // Under test: 8 | import { tstemplate } from '../src/index'; 9 | 10 | describe('tstemplate:', () => { 11 | describe('tstemplate - substitution:', () => { 12 | it('should replace any AST nodes', () => { 13 | const result = tstemplate('var <%= varName %> = <%= value %> + 1;', { 14 | varName: { kind: SyntaxKind.Identifier, escapedText: 'myVar' } as Identifier, 15 | value: { kind: SyntaxKind.NumericLiteral, text: '123' } as NumericLiteral 16 | }); 17 | 18 | expect(print(result)).to.equal('var myVar = 123 + 1;'); 19 | }); 20 | 21 | it('should allow you to pre-compile a template', () => { 22 | const template = tstemplate.compile('var <%= varName %> = <%= value %> + 1;'); 23 | 24 | const result1 = template({ 25 | varName: { kind: SyntaxKind.Identifier, escapedText: 'myVar' } as Identifier, 26 | value: { kind: SyntaxKind.NumericLiteral, text: '123' } as NumericLiteral 27 | }); 28 | const result2 = template({ 29 | varName: { kind: SyntaxKind.Identifier, escapedText: 'otherVar' } as Identifier, 30 | value: { kind: SyntaxKind.NumericLiteral, text: '234' } as NumericLiteral 31 | }); 32 | 33 | expect(print(result1)).to.equal('var myVar = 123 + 1;'); 34 | expect(print(result2)).to.equal('var otherVar = 234 + 1;'); 35 | }); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "declaration": true, 4 | "forceConsistentCasingInFileNames": true, 5 | "lib": [ 6 | "es2017", 7 | ], 8 | "moduleResolution": "node", 9 | "noEmitOnError": true, 10 | "noUnusedLocals": true, 11 | "noUnusedParameters": true, 12 | "pretty": true, 13 | "sourceMap": true, 14 | "strict": true, 15 | "target": "ES5", 16 | "outDir": "./dist", 17 | "typeRoots": [ 18 | "./node_modules/@types/" 19 | ] 20 | }, 21 | "exclude": [ 22 | "./node_modules/*", 23 | "./dist/*" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "array-type": [true, "generic"], 4 | "arrow-return-shorthand": true, 5 | "await-promise": true, 6 | "binary-expression-operand-order": true, 7 | "class-name": true, 8 | "comment-format": [true, "check-space"], 9 | "curly": true, 10 | "cyclomatic-complexity": true, 11 | "deprecation": { "severity": "warn" }, 12 | "eofline": true, 13 | "for-in": true, 14 | "import-spacing": true, 15 | "indent": [true, "spaces", 4], 16 | "interface-name": [true, "never-prefix"], 17 | "linebreak-style": [true, "LF"], 18 | "member-access": true, 19 | "member-ordering": [true, { "order": ["static-field", "instance-field", "static-method", "instance-method"] }], 20 | "new-parens": true, 21 | "no-any": false, 22 | "no-arg": true, 23 | "no-bitwise": true, 24 | "no-conditional-assignment": true, 25 | "no-consecutive-blank-lines": true, 26 | "no-construct": true, 27 | "no-console": [true, "log", "error", "warn", "debug", "info", "time", "timeEnd", "trace"], 28 | "no-debugger": true, 29 | "no-default-export": true, 30 | "no-duplicate-super": true, 31 | "no-duplicate-switch-case": true, 32 | "no-duplicate-variable": true, 33 | "no-empty": true, 34 | "no-eval": true, 35 | "no-for-in-array": true, 36 | "no-inferrable-types": [true, "ignore-params"], 37 | "no-invalid-template-strings": true, 38 | "no-irregular-whitespace": true, 39 | "no-misused-new": true, 40 | "no-namespace": true, 41 | "no-non-null-assertion": true, 42 | "no-reference": true, 43 | "no-return-await": true, 44 | "no-shadowed-variable": true, 45 | "no-string-literal": true, 46 | "no-string-throw": true, 47 | "no-switch-case-fall-through": true, 48 | "no-trailing-whitespace": true, 49 | "no-unsafe-finally": true, 50 | "no-unused-expression": true, 51 | "no-use-before-declare": true, 52 | "no-var-keyword": true, 53 | "number-literal-format": true, 54 | "one-variable-per-declaration": true, 55 | "one-line": [true, "check-open-brace", "check-catch", "check-else", "check-whitespace"], 56 | "ordered-imports": true, 57 | "prefer-const": true, 58 | "prefer-object-spread": true, 59 | "prefer-template": true, 60 | "promise-function-async": true, 61 | "quotemark": [true, "single"], 62 | "radix": true, 63 | "restrict-plus-operands": true, 64 | "semicolon": [true, "always", "ignore-bound-class-methods"], 65 | "trailing-comma": [true, { "multiline": "never", "singleline": "never" }], 66 | "triple-equals": [true, "allow-null-check"], 67 | "typedef": [true, "call-signature", "index-signature", "parameter", "property-signature", "variable-declarator", "member-variable-declarator"], 68 | "typedef-whitespace": [true, { "call-signature": "nospace", "index-signature": "nospace", "parameter": "nospace", "property-declaration": "nospace", "variable-declaration": "nospace" }], 69 | "variable-name": [true, "allow-leading-underscore"], 70 | "whitespace": [true, "check-branch", "check-decl", "check-operator", "check-module", "check-separator", "check-rest-spread", "check-type", "check-type-operator", "check-preblock"] 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /wallaby.js: -------------------------------------------------------------------------------- 1 | module.exports = function (wallaby) { 2 | return { 3 | files: [ 4 | 'src/**/*.ts', 5 | { pattern: 'test/index.ts', instrument: false } 6 | ], 7 | tests: ['test/**/*.spec.ts'], 8 | env: { 9 | type: 'node' 10 | } 11 | }; 12 | }; 13 | --------------------------------------------------------------------------------