{"action":"created","issue":{"url":"https://api.github.com/repos/Microsoft/TypeScript/issues/4892","repository_url":"https://api.github.com/repos/Microsoft/TypeScript","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,"node_id":"MDU6SXNzdWUxMDc0MjI4Mjc=","number":4892,"title":"Feature Request: Macros","user":{"login":"Gaelan","id":4495750,"node_id":"MDQ6VXNlcjQ0OTU3NTA=","avatar_url":"https://avatars1.githubusercontent.com/u/4495750?v=4","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":[{"id":114201833,"node_id":"MDU6TGFiZWwxMTQyMDE4MzM=","url":"https://api.github.com/repos/Microsoft/TypeScript/labels/Needs%20Proposal","name":"Needs Proposal","color":"556b75","default":false},{"id":113971155,"node_id":"MDU6TGFiZWwxMTM5NzExNTU=","url":"https://api.github.com/repos/Microsoft/TypeScript/labels/Suggestion","name":"Suggestion","color":"006b75","default":false}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":48,"created_at":"2015-09-20T22:55:02Z","updated_at":"2018-08-22T12:16:55Z","closed_at":null,"author_association":"NONE","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)\n## Interface-Based Validation\n\n``` typescript\n// validation.macros.ts\nfunction interfaceToValidatorCreator(interface: ts.InterfaceDeclaration): ts.Statement {\n    // Would return something like \"const [interface.name]Validator = new Validator({...});\",\n    // using types from the interface\n}\nmacro CreateValidator(interface: ts.InterfaceDeclaration) {\n    return [interface, interfaceToValidator(interface)];\n}\n// mainFile.ts\n/// <macros path='./valididation.macros.ts' />\n@#CreateValidator // Syntax 1: Decorator-Style\ninterface Person {\n    name: string;\n    age: number;\n}\n\nPersonValidator.validate(foo)\n```\n## Type Providers\n\n``` typescript\n// swagger.macros.ts\nmacro GetSwaggerClient(url: ts.StringLiteral): AssertionExpression {\n    // return something like \"new SwaggerClient([url]) as SwaggerClientBase & {...}\" where\n    // ... is an object creating the methods generated from the URL.\n}\n// mainFile.ts\n/// <macros path='./swagger.macros.ts' />\nvar fooClient = #GetSwaggerClient(\"http://foo.com/swagger.json\"); // Syntax 2: Function call syntax\nfooClient.getPeople((people) => {\n    people.every((person) => console.log(person.firstName + \",\" + person.lastName);\n});\n```\n## Conditional Compilation\n\n``` typescript\n// conditional-compilation.macros.ts\nmacro IfFlagSet(flagName: ts.StringLiteral, code: ts.Statement[]): ts.Statement[] {\n    return process.env[flagName.string] ? code : []\n}\n// mainFile.ts\n/// <macros path='./compilation.macros.ts' />\n#IfFlagSet(\"DEVELOPMENT\") { // Syntax 3: Language Construct-Like (multiple arguments can be passed in parentheses)\n    expensiveUnnecessarySanityCheck()\n}\n```\n## Notes\n- Macros would run right after parsing. Not sure how we would deal with macros that need type information.\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`.\n- It might be worth nothing in the docs that the AST format may change at any time, or something along those likes\n- The `macro` keyword would probably compile to a function, followed by a `ts.registerMacro(function, argumentTypes, returnType` call.\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.\n  - Alternatively, we could consider giving the `kind` property special treatment in `macros.ts` files.\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.\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.\n- This issue is likely to be updated quite a bit. For a log of changes, see [the gist](https://gist.github.com/Gaelan/cdacb0cb7c19b0fd0860)\n"},"comment":{"url":"https://api.github.com/repos/Microsoft/TypeScript/issues/comments/415011902","html_url":"https://github.com/Microsoft/TypeScript/issues/4892#issuecomment-415011902","issue_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/4892","id":415011902,"node_id":"MDEyOklzc3VlQ29tbWVudDQxNTAxMTkwMg==","user":{"login":"Frizi","id":919491,"node_id":"MDQ6VXNlcjkxOTQ5MQ==","avatar_url":"https://avatars2.githubusercontent.com/u/919491?v=4","gravatar_id":"","url":"https://api.github.com/users/Frizi","html_url":"https://github.com/Frizi","followers_url":"https://api.github.com/users/Frizi/followers","following_url":"https://api.github.com/users/Frizi/following{/other_user}","gists_url":"https://api.github.com/users/Frizi/gists{/gist_id}","starred_url":"https://api.github.com/users/Frizi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Frizi/subscriptions","organizations_url":"https://api.github.com/users/Frizi/orgs","repos_url":"https://api.github.com/users/Frizi/repos","events_url":"https://api.github.com/users/Frizi/events{/privacy}","received_events_url":"https://api.github.com/users/Frizi/received_events","type":"User","site_admin":false},"created_at":"2018-08-22T12:16:55Z","updated_at":"2018-08-22T12:16:55Z","author_association":"NONE","body":"Macros would be a very useful feature not only as a future language features playground, but also as a way to add logging or debugging to existing codebases. Some informations about the code are lost during the compilation or are inaccessible at runtime (think types or variable names). Macros would allow pulling such things out of the code without manual work of putting that metadata into string literals. Also any kind of DSLs would be possible (think JSX) without explicit compiler support, which could help reduce the core size.\r\n\r\nAs far as type-checking goes, I like the Rust way of handling that. Macros are operating not on AST level, but on the token trees. Those token trees are type-checked themselves to some extend (you can't mix an identifier with a statement for example). Once the token tree is expanded by macro, it can be fully parsed to AST (which might generate an error) and by type-checked (again with potential error). All errors generated strictly inside macros are reported at the macro invocation. Any errors that come from tokens passed to the macro as an argument are reported at those tokens. That means if you have an type error on an expression passed to the macro, it will be highlighted properly."}}
{"actor":{"display_login":"Frizi"}}