├── .editorconfig ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── examples └── ttypescript │ ├── .gitignore │ ├── index.js │ ├── index.ts │ ├── package.json │ └── tsconfig.json ├── package.json ├── src ├── __fixtures │ └── input.ts ├── __snapshots__ │ └── index.test.ts.snap ├── index.test.ts └── index.ts └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | insert_final_newline = true 5 | end_of_line = lf 6 | charset = utf-8 7 | indent_size = 2 8 | trim_trailing_whitespace = true 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ 3 | package-lock.json 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | env: 2 | global: 3 | secure: FS/TOcFeLcvij98Bw1lv40LhwLLACxyFjL9FMX3ZvMQeG5pjJp/mNlt6ZGvhucah2+VF0PpG0PRYpRAAND5gGPi+kK87TayBUnDWK2WjmAnpYrxWWBaCtXAEDk+ZG/7fa5Pl8k8WDpa0XAfWVi/5x5VM0EjWZFBlA/eDofGwS8ea0StC7Re+fZGAueeY+CHTZ7c4rN0T/fuHediSOfjglsOFmGGS/CBkG47COi67gU0llhlrea/6G5KoWDsuUx6rsm0iAyR9tP3JV63FFXMlRhl/ELZns/n7A6qqMTE4Ig0Pr9KMgsatBGdIGaKoRCXbAJycxvmWyFCQ6f40rvmhXV0+9FGC/uGv5WX//hDxdLF3T87+anGEUr99NOIJGg74VdnhVeKCSQZEroUccjO9D7hiRdDoRfavXMd1T9z7Zj2QktnmZTU/4j7RdYl2GQCYaZgfK5dQYS2Xv7KzJXs5/tRQxivOv6oEM7gASg4yiln9OSuRx7NV8TzA/LWB/Uku5yUjF4jqGtt01DCch57wxdCeEghEaCloPDZBttqORg0WHcywIcSa5U5vtKUxTZ5QpLPXVzhYYmp4USpeid4QQMXrbGSpA67FH843SYFjXGcJLqgNfDB2H2z97SLPc5YVIguzu7ya3tDOUwG/LDnd116UbszgCuGH8eQg36zhNEA= 4 | language: node_js 5 | node_js: 6 | - stable 7 | script: 8 | - npm test -- --coverage 9 | - npm install codecov -g 10 | - codecov 11 | deploy: 12 | provider: npm 13 | email: danielpza@protonmail.com 14 | api_key: 15 | secure: vP1eYbg096YZBzDLj7vZYJlyo8Fqw2xwTrMATRdpcFUyCm1PJ8M2I+ehzuDtWoHektiW/FhWJC0WfkpjU7r4M+WquPz6av7qNh0a/huOrH/huPt1EIUnhzI+1A4S3bzmZtJpsnA28m8+KZQAVKwrS18/sJTOBNvXu5uqUDCSWGe8cu6Bma1ecLKul/hJ2oGO4uzTFWDlSHAOWaj39Mi6zbim/BBxUY3C7/JEWnWIHoURqyubDsHO3yKBHxCHkFs0va7114f7NyFJaeJKQ6U/yMiGB+/u20rSEJenWdIi5R+mhy79uh2RiTDqMLyQK932NuQ/7NvROHFX77KF1QMVgEEcXdNZdUqvs7UGCvKmu6M3oFpWkLUXvjpwd4AMKsmjW+Z/Xbw+OOiBNR40hSMwgdOnYObcvYG6jhZy1vNKbxHJDcxB9Snh+myC0zm1knHyqMBauVQTN4c8fUjOJOP4Su6tstBTVoXYs+dTVkRKr0G7Itv9Fw7e86tY71oHkX6w572G42jGJZ9IOqrJiD1+8dHPx+++KhnnXACZTxq7C3Yq8ewJOCqY+pQDoPx9dtBLqdG5tVWB0VG4A+PH7HZcF7rM0RA1rTC43tYRasPC4MfaSBY2cKuRYdcVckAK8XDdpzrcgk7e3DLtPfcYLCkPAmtq2mUmnhPxjYWOCIJ89M0= 16 | on: 17 | tags: true 18 | repo: LeDDGroup/typescript-transform-macros 19 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | ### [1.1.1](https://github.com/LeDDGroup/typescript-transform-macros/compare/v1.1.0...v1.1.1) (2019-05-20) 6 | 7 | 8 | ### Bug Fixes 9 | 10 | * not working when macros didn't return value ([992a306](https://github.com/LeDDGroup/typescript-transform-macros/commit/992a306)) 11 | 12 | 13 | 14 | # [1.1.0](https://github.com/LeDDGroup/typescript-transform-macros/compare/v1.0.0...v1.1.0) (2019-03-18) 15 | 16 | 17 | ### Bug Fixes 18 | 19 | * not replacing macros inside macros ([4afb6d2](https://github.com/LeDDGroup/typescript-transform-macros/commit/4afb6d2)) 20 | 21 | 22 | ### Features 23 | 24 | * hygienic macros ([2268d05](https://github.com/LeDDGroup/typescript-transform-macros/commit/2268d05)) 25 | * support macros property access like calls ([d7b42d6](https://github.com/LeDDGroup/typescript-transform-macros/commit/d7b42d6)) 26 | 27 | 28 | 29 | # 1.0.0 (2019-03-16) 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 LeddGroup 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # typescript-transform-macros 4 | 5 | Typescript Transform Macros 6 | 7 | 8 | 9 | [![Build Status](https://img.shields.io/travis/LeDDGroup/typescript-transform-macros/master.svg)](https://travis-ci.org/LeDDGroup/typescript-transform-macros) 10 | [![Maintainability](https://api.codeclimate.com/v1/badges/81de2b2c8735684e4020/maintainability)](https://codeclimate.com/github/LeDDGroup/typescript-transform-macros/maintainability) 11 | [![codecov](https://codecov.io/gh/LeDDGroup/typescript-transform-macros/branch/master/graph/badge.svg)](https://codecov.io/gh/LeDDGroup/typescript-transform-macros) 12 | 13 | 14 | 15 | [![npm version](https://img.shields.io/npm/v/typescript-transform-macros.svg)](https://www.npmjs.com/package/typescript-transform-macros) [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier) [![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-yellow.svg)](https://conventionalcommits.org) [![Built with Spacemacs](https://raw.githubusercontent.com/syl20bnr/spacemacs/master/assets/spacemacs-badge.svg?sanitize=true)](http://spacemacs.org) 16 | 17 | 18 | 19 | Examples from . 20 | 21 | 22 | 23 | ## Installation 24 | 25 | ```sh 26 | npm install --save-dev typescript-transform-macros 27 | ``` 28 | 29 | 30 | 31 | ## Usage with [ttypescript](https://github.com/cevek/ttypescript/) 32 | 33 | Add it to _plugins_ in your _tsconfig.json_ 34 | 35 | ```json 36 | { 37 | "compilerOptions": { 38 | "plugins": [{ "transform": "typescript-transform-macros" }] 39 | } 40 | } 41 | ``` 42 | 43 | Also declare globally the _MACRO_ function: 44 | 45 | ```ts 46 | declare function MACRO(t: T): T; 47 | ``` 48 | 49 | ## Example 50 | 51 | _Input:_ 52 | 53 | 54 | 55 | ```ts 56 | declare function MACRO(t: T): T; 57 | 58 | const MAP = MACRO( 59 | ( 60 | inputConst: T[], 61 | visitor: (value: T, index?: number, input?: T[]) => L 62 | ) => { 63 | const input = inputConst; 64 | const length = input.length; 65 | const result = new Array(length) as L[]; 66 | for (let i = 0; i < length; i++) { 67 | result[i] = visitor(input[i], i, input); 68 | } 69 | return result; 70 | } 71 | ); 72 | 73 | declare interface Array { 74 | MAP: Array["map"]; 75 | } 76 | 77 | console.log([1, 2, 3].MAP(n => 3 * n + 1)); 78 | ``` 79 | 80 | 81 | 82 | _Output:_ 83 | 84 | 85 | 86 | ```js 87 | "use strict"; 88 | const input_1 = [1, 2, 3]; 89 | const length_1 = input_1.length; 90 | const result_1 = new Array(length_1); 91 | for (let i_1 = 0; i_1 < length_1; i_1++) { 92 | result_1[i_1] = 3 * input_1[i_1] + 1; 93 | } 94 | console.log(result_1); 95 | //> [ 4, 7, 10 ] 96 | ``` 97 | 98 | 99 | -------------------------------------------------------------------------------- /examples/ttypescript/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /examples/ttypescript/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | const input_1 = [1, 2, 3]; 3 | const length_1 = input_1.length; 4 | const result_1 = new Array(length_1); 5 | for (let i_1 = 0; i_1 < length_1; i_1++) { 6 | result_1[i_1] = 7 | 3 * 8 | input_1[i_1] + 1; 9 | } 10 | console.log(result_1); 11 | -------------------------------------------------------------------------------- /examples/ttypescript/index.ts: -------------------------------------------------------------------------------- 1 | declare function MACRO(t: T): T; 2 | 3 | const MAP = MACRO( 4 | ( 5 | inputConst: T[], 6 | visitor: (value: T, index?: number, input?: T[]) => L 7 | ) => { 8 | const input = inputConst; 9 | const length = input.length; 10 | const result = new Array(length) as L[]; 11 | for (let i = 0; i < length; i++) { 12 | result[i] = visitor(input[i], i, input); 13 | } 14 | return result; 15 | } 16 | ); 17 | 18 | declare interface Array { 19 | MAP: Array["map"]; 20 | } 21 | 22 | console.log([1, 2, 3].MAP(n => 3 * n + 1)); 23 | -------------------------------------------------------------------------------- /examples/ttypescript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example-ttyepescript", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "ttsc", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "devDependencies": { 14 | "ttypescript": "^1.5.6", 15 | "typescript": "^3.3.3333", 16 | "typescript-transform-macros": "file:../.." 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/ttypescript/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "commonjs", 5 | "strict": true, 6 | "plugins": [{ "transform": "typescript-transform-macros" }], 7 | "esModuleInterop": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typescript-transform-macros", 3 | "version": "1.1.1", 4 | "description": "Typescript Transform Macros", 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "files": [ 8 | "dist" 9 | ], 10 | "scripts": { 11 | "prebuild": "rm -rf dist", 12 | "build": "tsc", 13 | "prepare": "npm run build", 14 | "test": "jest" 15 | }, 16 | "keywords": [], 17 | "author": "", 18 | "license": "MIT", 19 | "devDependencies": { 20 | "@types/jest": "^24.0.11", 21 | "jest": "^24.5.0", 22 | "ts-jest": "^24.0.0", 23 | "typescript": "^3.3.3333" 24 | }, 25 | "jest": { 26 | "preset": "ts-jest", 27 | "testEnvironment": "node" 28 | }, 29 | "directories": { 30 | "test": "tests" 31 | }, 32 | "dependencies": {}, 33 | "repository": { 34 | "type": "git", 35 | "url": "git+https://github.com/LeDDGroup/typescript-transform-macros.git" 36 | }, 37 | "bugs": { 38 | "url": "https://github.com/LeDDGroup/typescript-transform-macros/issues" 39 | }, 40 | "preferDev": true, 41 | "homepage": "https://github.com/LeDDGroup/typescript-transform-macros#readme" 42 | } 43 | -------------------------------------------------------------------------------- /src/__fixtures/input.ts: -------------------------------------------------------------------------------- 1 | declare function MACRO(t: T): T; 2 | 3 | const FOR_EACH = MACRO( 4 | ( 5 | inputConst: T[], 6 | visitor: (value: T, index?: number, input?: T[]) => void 7 | ) => { 8 | const input = inputConst; 9 | const length = input.length; 10 | for (let i = 0; i < length; i++) { 11 | visitor(input[i], i, input); 12 | } 13 | } 14 | ); 15 | 16 | const FILTER = MACRO( 17 | ( 18 | inputConst: T[], 19 | visitor: (value: T, index?: number, input?: T[]) => boolean 20 | ) => { 21 | const input = inputConst; 22 | const length = input.length; 23 | const result = []; 24 | for (let i = 0; i < length; i++) { 25 | if (visitor(input[i], i, input)) result.push(input[i]); 26 | } 27 | return result; 28 | } 29 | ); 30 | 31 | const MAP = MACRO( 32 | ( 33 | inputConst: T[], 34 | visitor: (value: T, index?: number, input?: T[]) => L 35 | ) => { 36 | const input = inputConst; 37 | const length = input.length; 38 | const result = new Array(length) as L[]; 39 | for (let i = 0; i < length; i++) { 40 | result[i] = visitor(input[i], i, input); 41 | } 42 | return result; 43 | } 44 | ); 45 | 46 | declare interface Array { 47 | FOR_EACH: Array["forEach"]; 48 | MAP: Array["map"]; 49 | FILTER: Array["filter"]; 50 | } 51 | 52 | [1, 2, 3, 4] 53 | .FILTER(n => n % 2 === 0) 54 | .MAP(n => n + 1) 55 | .MAP(n => n.toString()) 56 | .FOR_EACH(n => console.log(n)); 57 | -------------------------------------------------------------------------------- /src/__snapshots__/index.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`transformer should compile 1`] = ` 4 | "declare function MACRO(t: T): T; 5 | declare interface Array { 6 | FOR_EACH: Array[\\"forEach\\"]; 7 | MAP: Array[\\"map\\"]; 8 | FILTER: Array[\\"filter\\"]; 9 | } 10 | const input_1 = [1, 2, 3, 4]; 11 | const length_1 = input_1.length; 12 | const result_1 = []; 13 | for (let i_1 = 0; i_1 < length_1; i_1++) { 14 | if (input_1[i_1] 15 | % 2 === 0) 16 | result_1.push(input_1[i_1]); 17 | } 18 | const input_2 = result_1; 19 | const length_2 = input_2.length; 20 | const result_2 = (new Array(length_2) as L[]); 21 | for (let i_2 = 0; i_2 < length_2; i_2++) { 22 | result_2[i_2] = 23 | input_2[i_2] 24 | + 1; 25 | } 26 | const input_3 = result_2; 27 | const length_3 = input_3.length; 28 | const result_3 = (new Array(length_3) as L[]); 29 | for (let i_3 = 0; i_3 < length_3; i_3++) { 30 | result_3[i_3] = 31 | input_3[i_3].toString(); 32 | } 33 | const input_4 = result_3; 34 | const length_4 = input_4.length; 35 | for (let i_4 = 0; i_4 < length_4; i_4++) { 36 | console.log(input_4[i_4]); 37 | } 38 | ; 39 | " 40 | `; 41 | -------------------------------------------------------------------------------- /src/index.test.ts: -------------------------------------------------------------------------------- 1 | import * as ts from "typescript"; 2 | import { resolve } from "path"; 3 | import transformer from "./"; 4 | import { readFileSync } from "fs"; 5 | 6 | describe("transformer", () => { 7 | it("should compile", () => { 8 | const inputFile = resolve(__dirname, "__fixtures/input.ts"); 9 | const result = transform(readFileSync(inputFile).toString()); 10 | expect(result).toMatchSnapshot(); 11 | }); 12 | }); 13 | 14 | function transform(sourceText: string) { 15 | const source = ts.createSourceFile( 16 | "temp.ts", 17 | sourceText, 18 | ts.ScriptTarget.ESNext 19 | ); 20 | const result = ts.transform(source, [transformer()], {}); 21 | const printer = ts.createPrinter(); 22 | return printer.printNode( 23 | ts.EmitHint.Unspecified, 24 | result.transformed[0], 25 | ts.createSourceFile("result.ts", "", ts.ScriptTarget.ESNext) 26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import * as ts from "typescript"; 2 | 3 | class Transformer { 4 | rootMacros = new Map(); 5 | constructor(public context: ts.TransformationContext) {} 6 | transform(node: ts.Node): ts.Node { 7 | return ts.visitNode( 8 | ts.visitNode(node, this.extractMacros), 9 | this.resolveMacros 10 | ); 11 | } 12 | extractMacros = (node: ts.Node): ts.Node | undefined => { 13 | if (ts.isVariableStatement(node)) { 14 | const firstDeclaration = node.declarationList.declarations[0]; // TODO maybe check for more 15 | if ( 16 | firstDeclaration.initializer && 17 | ts.isCallExpression(firstDeclaration.initializer) && 18 | ts.isIdentifier(firstDeclaration.initializer.expression) && 19 | firstDeclaration.initializer.expression.text === "MACRO" 20 | ) { 21 | const name = firstDeclaration.name; 22 | if (!ts.isIdentifier(name)) { 23 | throw new Error( 24 | "Expected name to be Identifier for macro declaration" 25 | ); 26 | } 27 | const value = firstDeclaration.initializer.arguments[0]; 28 | this.rootMacros.set(name.text, value); 29 | return undefined; 30 | } 31 | } 32 | return ts.visitEachChild(node, this.extractMacros, this.context); 33 | }; 34 | resolveMacros = (node: ts.Node): ts.Node | undefined => { 35 | if (ts.isBlock(node) || ts.isSourceFile(node)) { 36 | const newBlock = this.replaceMacros(node.statements, this.rootMacros); 37 | if (ts.isBlock(node)) { 38 | return ts.visitEachChild( 39 | ts.updateBlock(node, newBlock), 40 | this.resolveMacros, 41 | this.context 42 | ); 43 | } else { 44 | return ts.visitEachChild( 45 | ts.updateSourceFileNode(node, newBlock), 46 | this.resolveMacros, 47 | this.context 48 | ); 49 | } 50 | } 51 | return ts.visitEachChild(node, this.resolveMacros, this.context); 52 | }; 53 | cleanMacro = (node: T): [ts.Expression | undefined, T] => { 54 | const visit = (node: ts.Node): ts.Node | undefined => { 55 | if (ts.isReturnStatement(node)) { 56 | if (!node.expression) throw new Error("Expected macro to return value"); 57 | result = ts.visitNode(node.expression, visit); 58 | return undefined; 59 | } 60 | if (ts.isPropertyAccessExpression(node)) { 61 | return ts.createPropertyAccess( 62 | ts.visitNode(node.expression, visit), 63 | node.name 64 | ); 65 | } 66 | if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name)) { 67 | variableMap.set(node.name.text, ts.createUniqueName(node.name.text)); 68 | } 69 | if (ts.isIdentifier(node) && variableMap.has(node.text)) { 70 | return variableMap.get(node.text)!; 71 | } 72 | return ts.visitEachChild(node, visit, this.context); 73 | }; 74 | const variableMap = new Map(); 75 | let result: ts.Expression | undefined = undefined; 76 | const resultNode = ts.visitNode(node, visit); 77 | return [result, resultNode]; 78 | }; 79 | replaceMacros = ( 80 | statements: ts.NodeArray, 81 | macros: Map 82 | ): ts.Statement[] => { 83 | const visit = (node: ts.Node): ts.Node => { 84 | if ( 85 | [ 86 | ts.SyntaxKind.InterfaceDeclaration, 87 | ts.SyntaxKind.PropertySignature 88 | ].includes(node.kind) 89 | ) { 90 | return node; 91 | } 92 | if (ts.isBlock(node)) { 93 | return ts.createBlock(this.replaceMacros(node.statements, macros)); 94 | } 95 | if (ts.isIdentifier(node) && macros.has(node.text)) { 96 | return macros.get(node.text)!; 97 | } 98 | if ( 99 | ts.isCallExpression(node) && 100 | ts.isPropertyAccessExpression(node.expression) && 101 | macros.has(node.expression.name.text) 102 | ) { 103 | return ts.visitNode( 104 | ts.updateCall(node, node.expression.name, node.typeArguments, [ 105 | node.expression.expression, 106 | ...node.arguments 107 | ]), 108 | visit 109 | ); 110 | } 111 | if ( 112 | ts.isCallExpression(node) && 113 | ts.isIdentifier(node.expression) && 114 | macros.has(node.expression.text) 115 | ) { 116 | const value = macros.get(node.expression.text)!; 117 | if (!ts.isArrowFunction(value) && !ts.isFunctionExpression(value)) { 118 | throw new Error("Expected function expression for macro value"); 119 | } 120 | const newMacros = new Map([ 121 | ...macros.entries(), 122 | ...getNameValueMap(node.arguments, value.parameters).entries() 123 | ]); 124 | const [resultName, resultBlock] = this.cleanMacro( 125 | ts.visitNode( 126 | ts.createBlock(this.replaceMacros(getStatements(value), newMacros)), 127 | visit 128 | ) 129 | ); 130 | result = result.concat(resultBlock.statements); 131 | if (!resultName) return ts.createEmptyStatement(); 132 | return resultName; 133 | } 134 | return ts.visitEachChild(node, visit, this.context); 135 | }; 136 | let result: ts.Statement[] = []; 137 | for (const statement of statements) { 138 | const newStatement = ts.visitNode(statement, visit); 139 | result.push(newStatement); 140 | } 141 | return result; 142 | }; 143 | } 144 | 145 | const transformer = ( 146 | _program?: ts.Program 147 | ): ts.TransformerFactory => context => { 148 | return node => { 149 | return new Transformer(context).transform(node); 150 | }; 151 | }; 152 | 153 | function getStatements( 154 | node: ts.FunctionExpression | ts.ArrowFunction 155 | ): ts.NodeArray { 156 | if (ts.isBlock(node.body)) { 157 | return node.body.statements; 158 | } 159 | return ts.createNodeArray([ts.createReturn(node.body)]); 160 | } 161 | 162 | function getNameValueMap( 163 | values: ts.NodeArray, 164 | args: ts.NodeArray 165 | ) { 166 | const map = new Map(); 167 | for (let i = 0; i < values.length && i < args.length; i++) { 168 | const argName = args[i].name; 169 | if (!ts.isIdentifier(argName)) { 170 | throw new Error("Expected identifier in macro function definition"); 171 | } 172 | const argValue = values[i]; 173 | map.set(argName.text, argValue); 174 | } 175 | return map; 176 | } 177 | 178 | export default transformer; 179 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "commonjs", 5 | "declaration": true, 6 | "outDir": "./dist", 7 | "rootDir": "./src", 8 | "removeComments": true, 9 | "strict": true 10 | }, 11 | "exclude": ["**/*.test.ts", "**/__fixtures/**/*", "examples/**/*"] 12 | } 13 | --------------------------------------------------------------------------------