{"action":"created","issue":{"url":"https://api.github.com/repos/Microsoft/TypeScript/issues/4892","labels_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/4892/labels{/name}","comments_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/4892/comments","events_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/4892/events","html_url":"https://github.com/Microsoft/TypeScript/issues/4892","id":107422827,"number":4892,"title":"Feature Request: Macros","user":{"login":"Gaelan","id":4495750,"avatar_url":"https://avatars.githubusercontent.com/u/4495750?v=3","gravatar_id":"","url":"https://api.github.com/users/Gaelan","html_url":"https://github.com/Gaelan","followers_url":"https://api.github.com/users/Gaelan/followers","following_url":"https://api.github.com/users/Gaelan/following{/other_user}","gists_url":"https://api.github.com/users/Gaelan/gists{/gist_id}","starred_url":"https://api.github.com/users/Gaelan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Gaelan/subscriptions","organizations_url":"https://api.github.com/users/Gaelan/orgs","repos_url":"https://api.github.com/users/Gaelan/repos","events_url":"https://api.github.com/users/Gaelan/events{/privacy}","received_events_url":"https://api.github.com/users/Gaelan/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/Microsoft/TypeScript/labels/Needs%20Proposal","name":"Needs Proposal","color":"556b75"},{"url":"https://api.github.com/repos/Microsoft/TypeScript/labels/Suggestion","name":"Suggestion","color":"006b75"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":4,"created_at":"2015-09-20T22:55:02Z","updated_at":"2015-12-06T04:45:25Z","closed_at":null,"body":"This one might be waaaaaay out of scope, but I think it is worth proposing. The idea here is to add support for macros, functions that run at compile time, taking one or more AST nodes and returning an AST node or array of AST nodes. Examples/use cases: (Syntax off the top of my head, open to better ideas)\r\n\r\nInterface-Based Validation\r\n-----------------------------------\r\n```typescript\r\n// validation.macros.ts\r\nfunction interfaceToValidatorCreator(interface: ts.InterfaceDeclaration): ts.Statement {\r\n    // Would return something like \"const [interface.name]Validator = new Validator({...});\",\r\n    // using types from the interface\r\n}\r\nmacro CreateValidator(interface: ts.InterfaceDeclaration) {\r\n    return [interface, interfaceToValidator(interface)];\r\n}\r\n// mainFile.ts\r\n/// <macros path='./valididation.macros.ts' />\r\n@#CreateValidator // Syntax 1: Decorator-Style\r\ninterface Person {\r\n    name: string;\r\n    age: number;\r\n}\r\n\r\nPersonValidator.validate(foo)\r\n```\r\n\r\nType Providers\r\n--------------------\r\n```typescript\r\n// swagger.macros.ts\r\nmacro GetSwaggerClient(url: ts.StringLiteral): AssertionExpression {\r\n    // return something like \"new SwaggerClient([url]) as SwaggerClientBase & {...}\" where\r\n    // ... is an object creating the methods generated from the URL.\r\n}\r\n// mainFile.ts\r\n/// <macros path='./swagger.macros.ts' />\r\nvar fooClient = #GetSwaggerClient(\"http://foo.com/swagger.json\"); // Syntax 2: Function call syntax\r\nfooClient.getPeople((people) => {\r\n    people.every((person) => console.log(person.firstName + \",\" + person.lastName);\r\n});\r\n```\r\n\r\nConditional Compilation\r\n--------------------------------\r\n```typescript\r\n// conditional-compilation.macros.ts\r\nmacro IfFlagSet(flagName: ts.StringLiteral, code: ts.Statement[]): ts.Statement[] {\r\n    return process.env[flagName.string] ? code : []\r\n}\r\n// mainFile.ts\r\n/// <macros path='./compilation.macros.ts' />\r\n#IfFlagSet(\"DEVELOPMENT\") { // Syntax 3: Language Construct-Like (multiple arguments can be passed in parentheses)\r\n    expensiveUnnecessarySanityCheck()\r\n}\r\n```\r\n\r\nNotes\r\n--------\r\n\r\n- Macros would run right after parsing. Not sure how we would deal with macros that need type information.\r\n- This would make running `tsc` on unknown code as dangerous as running unknown code. It might be good to require a `--unsafeAllowMacros` argument, not settable from a `tsconfig.json`.\r\n- It might be worth nothing in the docs that the AST format may change at any time, or something along those likes\r\n- The `macro` keyword would probably compile to a function, followed by a `ts.registerMacro(function, argumentTypes, returnType` call.\r\n- Macros must be typed as returning a AST interface. This means that functions creating ASTs will probably need to have an explicit return type (or a calling function could have an explicit return type.\r\n  - Alternatively, we could consider giving the `kind` property special treatment in `macros.ts` files.\r\n- Just because a proposed syntax looks like a normal typescript construct doesn't mean it behaves like one. `#Foo(interface Bar{})` is valid syntax, as long as there is a macro named `Foo` that takes an interface.\r\n  - Exception: The Decorator syntax might need to be a bit more choosy (no decorating `1 + 1`, but decorating Interfaces, interface items, functions, etc. should be fine.\r\n- This issue is likely to be updated quite a bit. For a log of changes, see [the gist][]\r\n\r\n[the gist]: https://gist.github.com/Gaelan/cdacb0cb7c19b0fd0860"},"comment":{"url":"https://api.github.com/repos/Microsoft/TypeScript/issues/comments/162270708","html_url":"https://github.com/Microsoft/TypeScript/issues/4892#issuecomment-162270708","issue_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/4892","id":162270708,"user":{"login":"garkin","id":422774,"avatar_url":"https://avatars.githubusercontent.com/u/422774?v=3","gravatar_id":"","url":"https://api.github.com/users/garkin","html_url":"https://github.com/garkin","followers_url":"https://api.github.com/users/garkin/followers","following_url":"https://api.github.com/users/garkin/following{/other_user}","gists_url":"https://api.github.com/users/garkin/gists{/gist_id}","starred_url":"https://api.github.com/users/garkin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/garkin/subscriptions","organizations_url":"https://api.github.com/users/garkin/orgs","repos_url":"https://api.github.com/users/garkin/repos","events_url":"https://api.github.com/users/garkin/events{/privacy}","received_events_url":"https://api.github.com/users/garkin/received_events","type":"User","site_admin":false},"created_at":"2015-12-06T04:45:25Z","updated_at":"2015-12-06T04:45:25Z","body":"+1"}}