├── .changeset ├── README.md ├── config.json └── flat-oranges-repeat.md ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .github └── workflows │ ├── release.yml │ └── test.yml ├── .gitignore ├── .prettierrc ├── LICENSE ├── README.md ├── examples ├── jest-project │ ├── LICENSE │ ├── jest.config.js │ ├── macros.config.ts │ ├── macros.d.ts │ ├── package.json │ ├── src │ │ └── index.ts │ └── tests │ │ ├── __snapshots__ │ │ └── index.test.ts.snap │ │ └── index.test.ts ├── macro-plugin-project │ ├── package.json │ ├── rollup.config.mjs │ └── src │ │ └── index.ts ├── node-project │ ├── LICENSE │ ├── macros.config.js │ ├── package.json │ └── src │ │ └── index.ts ├── rollup-project │ ├── LICENSE │ ├── macros.config.js │ ├── macros.d.ts │ ├── package.json │ ├── rollup.config.js │ ├── src │ │ ├── index.ts │ │ └── second.ts │ └── tsconfig.json ├── vite-project │ ├── .gitignore │ ├── LICENSE │ ├── index.html │ ├── macros.config.ts │ ├── macros.d.ts │ ├── package.json │ ├── public │ │ └── vite.svg │ ├── src │ │ ├── counter.ts │ │ ├── main.ts │ │ ├── style.css │ │ ├── typescript.svg │ │ └── vite-env.d.ts │ ├── tsconfig.json │ └── vite.config.ts └── webpack-project │ ├── LICENSE │ ├── macros.config.js │ ├── macros.d.ts │ ├── package.json │ ├── src │ └── index.ts │ └── webpack.config.js ├── jest.config.js ├── nx.json ├── package.json ├── packages ├── cli │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── package.json │ ├── rollup.config.mjs │ └── src │ │ ├── index.ts │ │ └── types.ts ├── core │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── package.json │ ├── src │ │ ├── api.ts │ │ ├── ast.ts │ │ ├── defaults.ts │ │ ├── external.ts │ │ ├── index.ts │ │ ├── labeled.ts │ │ ├── lib.ts │ │ ├── macro.ts │ │ ├── parse.ts │ │ ├── print.ts │ │ ├── track.ts │ │ ├── transform.ts │ │ ├── types.ts │ │ ├── utils.ts │ │ └── walk.ts │ └── tests │ │ ├── __snapshots__ │ │ ├── expr.test.ts.snap │ │ ├── global.test.ts.snap │ │ ├── labeled.test.ts.snap │ │ ├── lib.test.ts.snap │ │ ├── literal.test.ts.snap │ │ └── macro.test.ts.snap │ │ ├── expr.test.ts │ │ ├── global.test.ts │ │ ├── labeled.test.ts │ │ ├── lib.test.ts │ │ ├── literal.test.ts │ │ ├── macro.test.ts │ │ ├── print.test.ts │ │ ├── track.test.ts │ │ └── utils.test.ts ├── factory │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── package.json │ ├── rollup.config.mjs │ ├── src │ │ ├── index.ts │ │ ├── macros.ts │ │ └── runtime.ts │ └── tests │ │ ├── __snapshots__ │ │ ├── macros.test.ts.snap │ │ └── runtime.test.ts.snap │ │ ├── macros.test.ts │ │ └── runtime.test.ts ├── jest │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── package.json │ ├── rollup.config.mjs │ └── src │ │ └── index.ts ├── qwik │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── package.json │ ├── src │ │ ├── computed.ts │ │ ├── css.ts │ │ ├── events.ts │ │ ├── index.ts │ │ ├── qwik.ts │ │ ├── resource.ts │ │ ├── signal.ts │ │ ├── store.ts │ │ └── task.ts │ └── tests │ │ ├── __snapshots__ │ │ ├── computed.test.ts.snap │ │ ├── css.test.ts.snap │ │ ├── events.test.ts.snap │ │ ├── qwik.test.ts.snap │ │ ├── resource.test.ts.snap │ │ ├── signal.test.ts.snap │ │ ├── store.test.ts.snap │ │ └── task.test.ts.snap │ │ ├── computed.test.ts │ │ ├── css.test.ts │ │ ├── events.test.ts │ │ ├── qwik.test.ts │ │ ├── resource.test.ts │ │ ├── signal.test.ts │ │ ├── store.test.ts │ │ └── task.test.ts ├── register │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── package.json │ ├── rollup.config.mjs │ └── src │ │ ├── index.ts │ │ └── transformer.ts ├── rollup │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── package.json │ └── src │ │ └── index.ts ├── shared │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── package.json │ ├── src │ │ ├── build.ts │ │ ├── index.ts │ │ ├── match.ts │ │ ├── resolve.ts │ │ └── types.ts │ └── tests │ │ └── match.test.ts ├── solid │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── package.json │ ├── src │ │ ├── effect.ts │ │ ├── index.ts │ │ ├── lifecycle.ts │ │ ├── signal.ts │ │ └── store.ts │ └── tests │ │ ├── __snapshots__ │ │ ├── effect.test.ts.snap │ │ ├── lifecycle.test.ts.snap │ │ ├── signal.test.ts.snap │ │ └── store.test.ts.snap │ │ ├── effect.test.ts │ │ ├── lifecycle.test.ts │ │ ├── signal.test.ts │ │ └── store.test.ts ├── vite │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── package.json │ └── src │ │ └── index.ts ├── vue │ ├── LICENSE │ ├── README.md │ └── package.json └── webpack │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── package.json │ └── src │ ├── index.ts │ └── types.ts ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── rollup.config.mjs ├── scripts └── release.js └── tsconfig.json /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@2.3.0/schema.json", 3 | "changelog": ["@changesets/changelog-github", { "repo": "macro-plugin/macros" }], 4 | "commit": false, 5 | "fixed": [["@macro-plugin/core", "@macro-plugin/register"]], 6 | "linked": [], 7 | "access": "public", 8 | "baseBranch": "main", 9 | "updateInternalDependencies": "patch", 10 | "ignore": ["*-project", "@macro-plugin/cli"] 11 | } 12 | -------------------------------------------------------------------------------- /.changeset/flat-oranges-repeat.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@macro-plugin/rollup": patch 3 | --- 4 | 5 | fix: ignore ast result in rollup plugin 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | indent_style = space 13 | indent_size = 4 14 | insert_final_newline = false 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | macros.d.ts 3 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | /** @type { import("eslint-config-standard") } */ 2 | module.exports = { 3 | env: { 4 | browser: true, 5 | es2021: true, 6 | node: true, 7 | jest: true, 8 | }, 9 | extends: ["standard"], 10 | parser: "@typescript-eslint/parser", 11 | parserOptions: { 12 | ecmaVersion: "latest", 13 | sourceType: "module", 14 | }, 15 | plugins: ["@typescript-eslint"], 16 | rules: { 17 | "arrow-spacing": 2, 18 | camelcase: 1, 19 | "comma-dangle": 0, 20 | "comma-spacing": 2, 21 | eqeqeq: [2, "allow-null"], 22 | indent: [2, 2, { SwitchCase: 1 }], 23 | "no-console": 1, 24 | "no-labels": 0, 25 | "no-undef": 0, 26 | "no-var": 0, 27 | "no-redeclare": 0, 28 | "no-extra-parens": 0, 29 | "no-constant-condition": 1, 30 | "no-use-before-define": 0, 31 | "no-trailing-spaces": 2, 32 | "@typescript-eslint/no-unused-vars": 1, 33 | "@typescript-eslint/no-redeclare": 1, 34 | "@typescript-eslint/no-dupe-class-members": 2, 35 | "@typescript-eslint/no-use-before-define": 1, 36 | "object-curly-spacing": [2, "always"], 37 | quotes: [2, "double", { avoidEscape: true }], 38 | semi: [2, "never"], 39 | }, 40 | } 41 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | release: 10 | permissions: 11 | contents: write # to create release (changesets/action) 12 | pull-requests: write # to create pull request (changesets/action) 13 | name: Release 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Checkout Repo 17 | uses: actions/checkout@v3 18 | with: 19 | # This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits 20 | fetch-depth: 0 21 | 22 | - uses: pnpm/action-setup@v2 23 | with: 24 | version: 7 25 | 26 | - name: Setup Node.js 27 | uses: actions/setup-node@v3 28 | with: 29 | node-version: 16.x 30 | cache: pnpm 31 | 32 | - name: Install Dependencies 33 | run: pnpm install --no-frozen-lockfile 34 | 35 | - name: Run tests 36 | run: pnpm test 37 | 38 | - name: Build project 39 | run: pnpm build:force 40 | 41 | - name: Create Release and Publish to npm 42 | id: changesets 43 | uses: changesets/action@v1 44 | with: 45 | publish: pnpm release 46 | commit: "ci: version packages" 47 | title: "ci: version packages" 48 | createGithubReleases: true 49 | env: 50 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 51 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 52 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | strategy: 14 | matrix: 15 | node-version: [16.x] 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | 20 | - uses: pnpm/action-setup@v2 21 | with: 22 | version: 7 23 | 24 | - name: Setup Node.js 25 | uses: actions/setup-node@v3 26 | with: 27 | node-version: 16.x 28 | cache: pnpm 29 | 30 | - name: Install Dependencies 31 | run: pnpm install --no-frozen-lockfile 32 | 33 | - name: Run tests 34 | run: pnpm test 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ 3 | coverage/ 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 80, 3 | "trailingComma": "es5", 4 | "arrowParens": "avoid", 5 | "bracketSameLine": true, 6 | "semi": false 7 | } 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Raven Satir 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 | -------------------------------------------------------------------------------- /examples/jest-project/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Raven Satir 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 | -------------------------------------------------------------------------------- /examples/jest-project/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import("@jest/types").Config.InitialOptions} */ 2 | module.exports = { 3 | transform: { "^.+\\.(t|j)s$": "@macro-plugin/jest" }, 4 | collectCoverageFrom: ["./tests/**/*.test.ts"], 5 | } 6 | -------------------------------------------------------------------------------- /examples/jest-project/macros.config.ts: -------------------------------------------------------------------------------- 1 | import { $Ast, $Eval, defineConfig } from "@macro-plugin/core" 2 | 3 | export default defineConfig({ 4 | macros: [$Eval, $Ast], 5 | emitDts: true, 6 | jsc: { 7 | parser: { 8 | syntax: "typescript" 9 | }, 10 | target: "esnext", 11 | }, 12 | }) 13 | -------------------------------------------------------------------------------- /examples/jest-project/macros.d.ts: -------------------------------------------------------------------------------- 1 | declare global { 2 | const $Eval: ((expr: string) => T) & ((expr: T) => T) & ( any>(expr: F, ...args: Parameters) => ReturnType); 3 | const $Ast: (expr: T) => import("@swc/core").Expression; 4 | } 5 | export {} 6 | -------------------------------------------------------------------------------- /examples/jest-project/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jest-project", 3 | "private": true, 4 | "version": "0.0.0", 5 | "scripts": { 6 | "test": "jest", 7 | "test:watch": "jest --watch", 8 | "test:update": "jest --updateSnapshot", 9 | "test:clear": "jest --clearCache", 10 | "coverage": "jest --coverage" 11 | }, 12 | "devDependencies": { 13 | "jest": "^29.5.0", 14 | "@macro-plugin/core": "workspace:*", 15 | "@macro-plugin/jest": "workspace:*" 16 | }, 17 | "author": "Raven Satir", 18 | "license": "MIT" 19 | } 20 | -------------------------------------------------------------------------------- /examples/jest-project/src/index.ts: -------------------------------------------------------------------------------- 1 | export function add (a: number, b: number): number { 2 | return a + b 3 | } 4 | 5 | export function binaryAst () { 6 | return $Ast("2 * 3") 7 | } 8 | -------------------------------------------------------------------------------- /examples/jest-project/tests/__snapshots__/index.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`ast macro 1`] = ` 4 | { 5 | "left": { 6 | "raw": "2", 7 | "span": { 8 | "ctxt": 0, 9 | "end": 0, 10 | "start": 0, 11 | }, 12 | "type": "NumericLiteral", 13 | "value": 2, 14 | }, 15 | "operator": "*", 16 | "right": { 17 | "raw": "3", 18 | "span": { 19 | "ctxt": 0, 20 | "end": 0, 21 | "start": 0, 22 | }, 23 | "type": "NumericLiteral", 24 | "value": 3, 25 | }, 26 | "span": { 27 | "ctxt": 0, 28 | "end": 0, 29 | "start": 0, 30 | }, 31 | "type": "BinaryExpression", 32 | } 33 | `; 34 | 35 | exports[`ast macro 2`] = ` 36 | { 37 | "elements": [], 38 | "span": { 39 | "ctxt": 0, 40 | "end": 0, 41 | "start": 0, 42 | }, 43 | "type": "ArrayExpression", 44 | } 45 | `; 46 | 47 | exports[`ast macro 3`] = ` 48 | { 49 | "arguments": [], 50 | "callee": { 51 | "object": { 52 | "expression": { 53 | "raw": "3", 54 | "span": { 55 | "ctxt": 0, 56 | "end": 0, 57 | "start": 0, 58 | }, 59 | "type": "NumericLiteral", 60 | "value": 3, 61 | }, 62 | "span": { 63 | "ctxt": 0, 64 | "end": 0, 65 | "start": 0, 66 | }, 67 | "type": "ParenthesisExpression", 68 | }, 69 | "property": { 70 | "optional": false, 71 | "span": { 72 | "ctxt": 0, 73 | "end": 0, 74 | "start": 0, 75 | }, 76 | "type": "Identifier", 77 | "value": "toFixed", 78 | }, 79 | "span": { 80 | "ctxt": 0, 81 | "end": 0, 82 | "start": 0, 83 | }, 84 | "type": "MemberExpression", 85 | }, 86 | "span": { 87 | "ctxt": 0, 88 | "end": 0, 89 | "start": 0, 90 | }, 91 | "type": "CallExpression", 92 | "typeArguments": null, 93 | } 94 | `; 95 | -------------------------------------------------------------------------------- /examples/jest-project/tests/index.test.ts: -------------------------------------------------------------------------------- 1 | import { add, binaryAst } from "../src" 2 | 3 | test("add", () => { 4 | expect(add(1, 4)).toBe(5) 5 | }) 6 | 7 | test("eval macro", () => { 8 | expect($Eval(3 * 12 - 2)).toBe(34) 9 | expect($Eval("1 + 2")).toBe(3) 10 | }) 11 | 12 | test("ast macro", () => { 13 | expect(binaryAst()).toMatchSnapshot() 14 | expect($Ast([])).toMatchSnapshot() 15 | expect($Ast((3).toFixed())).toMatchSnapshot() 16 | }) 17 | -------------------------------------------------------------------------------- /examples/macro-plugin-project/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "macro-plugin-project", 3 | "private": true, 4 | "main": "dist/index.js", 5 | "module": "dist/index.mjs", 6 | "version": "0.0.0", 7 | "scripts": { 8 | "build": "rollup -c", 9 | "watch": "rollup -cw" 10 | }, 11 | "exports": { 12 | "package.json": "./package.json", 13 | "require": "./dist/index.js", 14 | "import": "./dist/index.mjs" 15 | }, 16 | "devDependencies": { 17 | "rollup": "^3.20.0", 18 | "@macro-plugin/core": "workspace:*", 19 | "@macro-plugin/rollup": "workspace:*" 20 | }, 21 | "author": "Raven Satir", 22 | "license": "MIT" 23 | } 24 | -------------------------------------------------------------------------------- /examples/macro-plugin-project/rollup.config.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "rollup" 2 | import macroPlugin from "@macro-plugin/rollup" 3 | 4 | export default defineConfig({ 5 | input: "src/index.ts", 6 | output: [ 7 | { 8 | file: "dist/index.js", 9 | format: "cjs" 10 | }, 11 | { 12 | file: "dist/index.mjs", 13 | format: "es" 14 | } 15 | ], 16 | plugins: [ 17 | macroPlugin({ 18 | tsconfig: false 19 | }) 20 | ] 21 | }) 22 | -------------------------------------------------------------------------------- /examples/macro-plugin-project/src/index.ts: -------------------------------------------------------------------------------- 1 | import { createExprMacro } from "@macro-plugin/core" 2 | 3 | export const $Add = createExprMacro("$Add", ($a: number, $b: number) => $a + $b) 4 | 5 | export const $Multi = createExprMacro("$Multi", ($a: number, $b: number) => $a * $b) 6 | -------------------------------------------------------------------------------- /examples/node-project/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Raven Satir 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 | -------------------------------------------------------------------------------- /examples/node-project/macros.config.js: -------------------------------------------------------------------------------- 1 | const { $Ast, $Eval, $Quote, createLitMacro, macro } = require("@macro-plugin/core") 2 | 3 | /** @type { import("@macro-plugin/core").Config } */ 4 | module.exports = { 5 | macros: [ 6 | macro, 7 | $Eval, 8 | $Ast, 9 | $Quote, 10 | createLitMacro({ 11 | __DEV__: false 12 | }) 13 | ], 14 | jsc: { 15 | parser: { 16 | syntax: "typescript" 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/node-project/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-project", 3 | "private": true, 4 | "version": "0.0.0", 5 | "scripts": { 6 | "eval": "macros run ./src/index.ts", 7 | "build": "macros build ./src/*.ts -o ./dist", 8 | "dev": "macros dev ./src/*.ts -o ./dist", 9 | "emit": "macros emit", 10 | "shell": "macros shell", 11 | "shell:swc": "macros shell --transform --swc", 12 | "shell:ast": "macros shell --ast", 13 | "shell:transform": "macros shell --transform" 14 | }, 15 | "devDependencies": { 16 | "@macro-plugin/core": "workspace:*", 17 | "@macro-plugin/register": "workspace:*" 18 | }, 19 | "author": "Raven Satir", 20 | "license": "MIT" 21 | } 22 | -------------------------------------------------------------------------------- /examples/node-project/src/index.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | 3 | console.log($Ast(1 + 2)) 4 | -------------------------------------------------------------------------------- /examples/rollup-project/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Raven Satir 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 | -------------------------------------------------------------------------------- /examples/rollup-project/macros.config.js: -------------------------------------------------------------------------------- 1 | import { createLitMacro, defineConfig } from "@macro-plugin/core" 2 | 3 | export default defineConfig({ 4 | emitDts: true, 5 | tsconfig: false, 6 | macros: [ 7 | createLitMacro({ 8 | __DEV__: false 9 | }) 10 | ], 11 | depends: [ 12 | "@macro-plugin/core", 13 | "macro-plugin-project" 14 | ], 15 | externals: [ 16 | "@macro-plugin/factory", 17 | ] 18 | }) 19 | -------------------------------------------------------------------------------- /examples/rollup-project/macros.d.ts: -------------------------------------------------------------------------------- 1 | declare global { 2 | const __DEV__: boolean; 3 | const $Ast: (expr: T) => import("@swc/core").Expression; 4 | const $Column: () => number; 5 | const $Concat: (...args: (string | null | undefined | boolean | number | bigint)[]) => string; 6 | const $Env: (key: string) => R; 7 | const $Eval: ((expr: string) => T) & ((expr: T) => T) & ( any>(expr: F, ...args: Parameters) => ReturnType); 8 | const $Expr: (strings: TemplateStringsArray, ...expressions: unknown[]) => import("@swc/core").Expression; 9 | const $ID: () => string; 10 | const $Include: (path: string, target?: "es6" | "commonjs" | "umd" | "nodenext") => void; 11 | const $IncludeJSON: (>(path: string) => T) & ((path: string, key: string) => R); 12 | const $IncludeStr: (path: string) => string; 13 | const $Line: () => number; 14 | const $Quote: (strings: TemplateStringsArray, ...expressions: unknown[]) => (import("@swc/core").Expression)[]; 15 | const $Span: () => [number, number]; 16 | const $Stringify: ((expr: any) => string) & (() => string); 17 | const $Todo: () => never; 18 | const $UnImplemented: () => never; 19 | const $UnReachable: () => never; 20 | const $WriteFile: (file: string, data: string) => void; 21 | var $Macro: typeof import("@macro-plugin/core").$Macro; 22 | var $LitMacro: typeof import("@macro-plugin/core").$LitMacro; 23 | var $ExprMacro: typeof import("@macro-plugin/core").$ExprMacro; 24 | var $TypeMacro: typeof import("@macro-plugin/core").$TypeMacro; 25 | var $TmplMacro: typeof import("@macro-plugin/core").$TmplMacro; 26 | var $LabeledMacro: typeof import("@macro-plugin/core").$LabeledMacro; 27 | const $Add: (...args: T[]) => T; 28 | const $Multi: (...args: T[]) => T; 29 | } 30 | export {} 31 | -------------------------------------------------------------------------------- /examples/rollup-project/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rollup-project", 3 | "type": "module", 4 | "private": true, 5 | "version": "0.0.0", 6 | "scripts": { 7 | "build": "rollup -c", 8 | "watch": "rollup -cw" 9 | }, 10 | "devDependencies": { 11 | "rollup": "^3.20.0", 12 | "@macro-plugin/core": "workspace:*", 13 | "@macro-plugin/rollup": "workspace:*", 14 | "@macro-plugin/factory": "workspace:*", 15 | "macro-plugin-project": "workspace:*" 16 | }, 17 | "author": "Raven Satir", 18 | "license": "MIT" 19 | } 20 | -------------------------------------------------------------------------------- /examples/rollup-project/rollup.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "rollup" 2 | import macroPlugin from "@macro-plugin/rollup" 3 | 4 | export default defineConfig({ 5 | input: "src/index.ts", 6 | output: { 7 | file: "dist/index.js", 8 | format: "es" 9 | }, 10 | plugins: [ 11 | macroPlugin() 12 | ] 13 | }) 14 | -------------------------------------------------------------------------------- /examples/rollup-project/src/index.ts: -------------------------------------------------------------------------------- 1 | import { $Identifier } from "@macro-plugin/factory" 2 | import { bye } from "./second" 3 | 4 | macro: { 5 | var __ABC__ = "abc" 6 | 7 | var add = $ExprMacro(function ([a0, a1]) { 8 | const a = this.printExpr(a0) 9 | const b = this.printExpr(a1) 10 | 11 | if (+a < 0) return a1 12 | return this.parseExpr(`(() => {return ${a} + ${b}})()`) 13 | }) 14 | } 15 | 16 | export function hello () { 17 | const a = $Eval(1 + 2) 18 | const result = [] 19 | const c = $Add(1, 3) 20 | result.push(c) 21 | 22 | result.push($Quote`1 + ${a}`) 23 | 24 | result.push(bye()) 25 | 26 | if (__DEV__) { 27 | result.push(a) 28 | } 29 | 30 | result.push($Identifier("hello")) 31 | 32 | result.push(__ABC__) 33 | 34 | result.push(add(1, 2)) 35 | 36 | // $Eval(() => { 37 | // import("fs").then(fs => fs.writeFileSync("abc.txt", "123")) 38 | // }) 39 | const someAst = $Ast(a * 2) 40 | 41 | result.push(a, someAst) 42 | 43 | return result 44 | } 45 | -------------------------------------------------------------------------------- /examples/rollup-project/src/second.ts: -------------------------------------------------------------------------------- 1 | export function bye () { 2 | return $Eval("bye".toUpperCase()) 3 | } 4 | -------------------------------------------------------------------------------- /examples/rollup-project/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["."], 4 | "exclude": ["./dist"] 5 | } 6 | -------------------------------------------------------------------------------- /examples/vite-project/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /examples/vite-project/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Raven Satir 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 | -------------------------------------------------------------------------------- /examples/vite-project/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + TS 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/vite-project/macros.config.ts: -------------------------------------------------------------------------------- 1 | import { $Ast, $Eval, $Quote, createLitMacro, defineConfig, macro } from "@macro-plugin/core" 2 | 3 | export default defineConfig({ 4 | emitDts: true, 5 | macros: [ 6 | macro, 7 | $Eval, 8 | $Ast, 9 | $Quote, 10 | createLitMacro({ 11 | __DEV__: false 12 | }) 13 | ] 14 | }) 15 | -------------------------------------------------------------------------------- /examples/vite-project/macros.d.ts: -------------------------------------------------------------------------------- 1 | declare global { 2 | var $Macro: typeof import("@macro-plugin/core").$Macro; 3 | var $LitMacro: typeof import("@macro-plugin/core").$LitMacro; 4 | var $ExprMacro: typeof import("@macro-plugin/core").$ExprMacro; 5 | var $TypeMacro: typeof import("@macro-plugin/core").$TypeMacro; 6 | var $TmplMacro: typeof import("@macro-plugin/core").$TmplMacro; 7 | var $LabeledMacro: typeof import("@macro-plugin/core").$LabeledMacro; 8 | const $Eval: ((expr: string) => T) & ((expr: T) => T) & ( any>(expr: F, ...args: Parameters) => ReturnType); 9 | const $Ast: (expr: T) => import("@swc/core").Expression; 10 | const $Quote: (strings: TemplateStringsArray, ...expressions: unknown[]) => (import("@swc/core").Expression)[]; 11 | const __DEV__: boolean; 12 | } 13 | export {} 14 | -------------------------------------------------------------------------------- /examples/vite-project/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vite-project", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "preview": "vite preview" 10 | }, 11 | "devDependencies": { 12 | "typescript": "^4.9.3", 13 | "vite": "^4.2.0", 14 | "@macro-plugin/core": "workspace:*", 15 | "@macro-plugin/vite": "workspace:*" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/vite-project/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/vite-project/src/counter.ts: -------------------------------------------------------------------------------- 1 | export function setupCounter (element: HTMLButtonElement) { 2 | let counter = 0 3 | const setCounter = (count: number) => { 4 | counter = count 5 | element.innerHTML = `count is ${counter}` 6 | } 7 | element.addEventListener("click", () => setCounter(counter + 1)) 8 | setCounter(0) 9 | } 10 | -------------------------------------------------------------------------------- /examples/vite-project/src/main.ts: -------------------------------------------------------------------------------- 1 | import "./style.css" 2 | 3 | import { setupCounter } from "./counter" 4 | import typescriptLogo from "./typescript.svg" 5 | import viteLogo from "../public/vite.svg" 6 | 7 | const a = 4 8 | document.querySelector("#app")!.innerHTML = ` 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |

Vite + TypeScript

17 |
18 | 19 |
20 |

21 | Click on the Vite and TypeScript logos to learn more 22 |

23 | 24 | ${JSON.stringify($Ast(a * 2))} 25 |
26 | ` 27 | 28 | setupCounter(document.querySelector("#counter")!) 29 | -------------------------------------------------------------------------------- /examples/vite-project/src/style.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | 6 | color-scheme: light dark; 7 | color: rgba(255, 255, 255, 0.87); 8 | background-color: #242424; 9 | 10 | font-synthesis: none; 11 | text-rendering: optimizeLegibility; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | -webkit-text-size-adjust: 100%; 15 | } 16 | 17 | a { 18 | font-weight: 500; 19 | color: #646cff; 20 | text-decoration: inherit; 21 | } 22 | a:hover { 23 | color: #535bf2; 24 | } 25 | 26 | body { 27 | margin: 0; 28 | display: flex; 29 | place-items: center; 30 | min-width: 320px; 31 | min-height: 100vh; 32 | } 33 | 34 | h1 { 35 | font-size: 3.2em; 36 | line-height: 1.1; 37 | } 38 | 39 | #app { 40 | max-width: 1280px; 41 | margin: 0 auto; 42 | padding: 2rem; 43 | text-align: center; 44 | } 45 | 46 | .logo { 47 | height: 6em; 48 | padding: 1.5em; 49 | will-change: filter; 50 | transition: filter 300ms; 51 | } 52 | .logo:hover { 53 | filter: drop-shadow(0 0 2em #646cffaa); 54 | } 55 | .logo.vanilla:hover { 56 | filter: drop-shadow(0 0 2em #3178c6aa); 57 | } 58 | 59 | .card { 60 | padding: 2em; 61 | } 62 | 63 | .read-the-docs { 64 | color: #888; 65 | } 66 | 67 | button { 68 | border-radius: 8px; 69 | border: 1px solid transparent; 70 | padding: 0.6em 1.2em; 71 | font-size: 1em; 72 | font-weight: 500; 73 | font-family: inherit; 74 | background-color: #1a1a1a; 75 | cursor: pointer; 76 | transition: border-color 0.25s; 77 | } 78 | button:hover { 79 | border-color: #646cff; 80 | } 81 | button:focus, 82 | button:focus-visible { 83 | outline: 4px auto -webkit-focus-ring-color; 84 | } 85 | 86 | @media (prefers-color-scheme: light) { 87 | :root { 88 | color: #213547; 89 | background-color: #ffffff; 90 | } 91 | a:hover { 92 | color: #747bff; 93 | } 94 | button { 95 | background-color: #f9f9f9; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /examples/vite-project/src/typescript.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/vite-project/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /examples/vite-project/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "module": "ESNext", 6 | "lib": ["ESNext", "DOM"], 7 | "moduleResolution": "Node", 8 | "strict": true, 9 | "resolveJsonModule": true, 10 | "isolatedModules": true, 11 | "esModuleInterop": true, 12 | "noEmit": true, 13 | "noUnusedLocals": true, 14 | "noUnusedParameters": true, 15 | "noImplicitReturns": true, 16 | "skipLibCheck": true 17 | }, 18 | "include": ["src"] 19 | } 20 | -------------------------------------------------------------------------------- /examples/vite-project/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite" 2 | import macroPlugin from "@macro-plugin/vite" 3 | 4 | export default defineConfig({ 5 | plugins: [ 6 | macroPlugin() 7 | ] 8 | }) 9 | -------------------------------------------------------------------------------- /examples/webpack-project/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Raven Satir 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 | -------------------------------------------------------------------------------- /examples/webpack-project/macros.config.js: -------------------------------------------------------------------------------- 1 | import { $Ast, $Eval, $Quote, createLitMacro, defineConfig, macro } from "@macro-plugin/core" 2 | 3 | export default defineConfig({ 4 | macros: [ 5 | macro, 6 | $Eval, 7 | $Ast, 8 | $Quote, 9 | createLitMacro({ 10 | __DEV__: false 11 | }) 12 | ], 13 | jsc: { 14 | parser: { 15 | syntax: "typescript" 16 | } 17 | } 18 | }) 19 | -------------------------------------------------------------------------------- /examples/webpack-project/macros.d.ts: -------------------------------------------------------------------------------- 1 | declare global { 2 | var $Macro: typeof import("@macro-plugin/core").$Macro; 3 | var $LitMacro: typeof import("@macro-plugin/core").$LitMacro; 4 | var $ExprMacro: typeof import("@macro-plugin/core").$ExprMacro; 5 | var $TypeMacro: typeof import("@macro-plugin/core").$TypeMacro; 6 | var $TmplMacro: typeof import("@macro-plugin/core").$TmplMacro; 7 | var $LabeledMacro: typeof import("@macro-plugin/core").$LabeledMacro; 8 | const $Eval: ((expr: string) => T) & ((expr: T) => T) & ( any>(expr: F, ...args: Parameters) => ReturnType); 9 | const $Ast: (expr: T) => import("@swc/core").Expression; 10 | const $Quote: (strings: TemplateStringsArray, ...expressions: unknown[]) => (import("@swc/core").Expression)[]; 11 | const __DEV__: boolean; 12 | } 13 | export {} 14 | -------------------------------------------------------------------------------- /examples/webpack-project/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webpack-project", 3 | "type": "module", 4 | "private": true, 5 | "version": "0.0.0", 6 | "scripts": { 7 | "build": "webpack" 8 | }, 9 | "devDependencies": { 10 | "@macro-plugin/core": "workspace:*", 11 | "@macro-plugin/webpack": "workspace:*", 12 | "webpack": "^5.80.0", 13 | "webpack-cli": "^5.0.1" 14 | }, 15 | "author": "Raven Satir", 16 | "license": "MIT" 17 | } 18 | -------------------------------------------------------------------------------- /examples/webpack-project/src/index.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | export function main () { 3 | const a = $Eval(1 + 2) 4 | 5 | const someAst = $Ast(a * 2) 6 | console.log(a) 7 | console.log(someAst) 8 | } 9 | 10 | main() 11 | -------------------------------------------------------------------------------- /examples/webpack-project/webpack.config.js: -------------------------------------------------------------------------------- 1 | import { resolve } from "path" 2 | 3 | /** @type { import("webpack").Configuration } */ 4 | export default { 5 | mode: "production", 6 | entry: resolve("./src/index.ts"), 7 | output: { 8 | path: resolve("./dist"), 9 | filename: "index.js" 10 | }, 11 | module: { 12 | rules: [ 13 | { 14 | test: /\.(t|j)sx?$/, 15 | exclude: /node_modules/, 16 | use: [ 17 | { 18 | loader: "@macro-plugin/webpack", 19 | /** @type { import("@macro-plugin/core").Config } */ 20 | options: { 21 | emitDts: true 22 | } 23 | } 24 | ] 25 | } 26 | ] 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs") 2 | 3 | /** @type {import("@jest/types").Config.InitialOptions} */ 4 | module.exports = { 5 | transform: { "^.+\\.(t|j)s$": ["@swc/jest"] }, 6 | moduleNameMapper: Object.fromEntries(fs.readdirSync("./packages").map(i => [[`^@macro-plugin/${i}`], [`/packages/${i}/src`]])), 7 | collectCoverageFrom: ["packages/**/tests/**/*.test.ts"], 8 | testPathIgnorePatterns: ["examples"] 9 | } 10 | -------------------------------------------------------------------------------- /nx.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasksRunnerOptions": { 3 | "default": { 4 | "runner": "nx/tasks-runners/default", 5 | "options": { 6 | "cacheableOperations": ["build", "test"] 7 | } 8 | } 9 | }, 10 | "defaultBase": "main" 11 | } 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "description": "Macro system for JavaScript and TypeScript.", 4 | "scripts": { 5 | "lint": "eslint . --ext .ts", 6 | "lint:fix": "eslint . --ext .ts --fix", 7 | "test": "jest", 8 | "test:watch": "jest --watch", 9 | "test:update": "jest --updateSnapshot", 10 | "build": "nx run-many --target=build --exclude *-project", 11 | "build:force": "nx run-many --target=build --skip-nx-cache --exclude *-project", 12 | "build:affected": "nx affected --target=build --exclude *-project", 13 | "changeset": "changeset", 14 | "bump": "changeset version", 15 | "release": "node ./scripts/release.js", 16 | "graph": "nx graph", 17 | "coverage": "jest --coverage" 18 | }, 19 | "author": "Raven Satir", 20 | "license": "MIT", 21 | "devDependencies": { 22 | "@actions/exec": "^1.1.1", 23 | "@changesets/changelog-github": "^0.4.8", 24 | "@changesets/cli": "^2.26.1", 25 | "@jest/types": "^29.5.0", 26 | "@rollup/plugin-commonjs": "^24.1.0", 27 | "@rollup/plugin-json": "^6.0.0", 28 | "@rollup/plugin-node-resolve": "^15.0.2", 29 | "@rollup/plugin-terser": "^0.4.1", 30 | "@swc/jest": "^0.2.26", 31 | "@types/jest": "^29.5.1", 32 | "@typescript-eslint/eslint-plugin": "^5.59.1", 33 | "@typescript-eslint/parser": "^5.59.1", 34 | "eslint": "^8.39.0", 35 | "eslint-config-standard": "^17.0.0", 36 | "eslint-plugin-import": "^2.27.5", 37 | "eslint-plugin-n": "^15.7.0", 38 | "eslint-plugin-promise": "^6.1.1", 39 | "jest": "^29.5.0", 40 | "nx": "15.8.7", 41 | "rollup": "^3.21.0", 42 | "rollup-plugin-dts": "^5.3.0", 43 | "rollup-plugin-typescript2": "^0.34.1", 44 | "tslib": "^2.5.0", 45 | "typescript": "5.0.3" 46 | }, 47 | "dependencies": { 48 | "@swc/core": "^1.3.55" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /packages/cli/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @macro-plugin/cli 2 | 3 | ## null 4 | 5 | ### Patch Changes 6 | 7 | - Updated dependencies [98425cf] 8 | - @macro-plugin/core@1.0.1 9 | -------------------------------------------------------------------------------- /packages/cli/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Raven Satir 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 | -------------------------------------------------------------------------------- /packages/cli/README.md: -------------------------------------------------------------------------------- 1 | # @macro-plugin/cli 2 | 3 | Macro Plugin Command Line Interface. It can be used to execute TypeScript, develop AST macros, generate macro declaration files, generate transformed files. It also includes a great REPL. 4 | 5 | > **Note:** This package not been released as a separate npm package, but been bundled in `@macro-plugin/core` for easier intergration. 6 | 7 | ## Install 8 | 9 | ```sh 10 | # npm 11 | npm i -g @macro-plugin/core 12 | 13 | # yarn 14 | yarn add -g @macro-plugin/core 15 | 16 | # pnpm 17 | pnpm i -g @macro-plugin/core 18 | ``` 19 | 20 | ## Config 21 | 22 | By default, it will use your `macros.config.js` or `macros.config.ts` as configuration. 23 | 24 | ```js 25 | import { defineConfig } from "@macro-plugin/core" 26 | 27 | export default defineConfig({ 28 | // emit declarations 29 | emitDts: true, 30 | macros: [ 31 | // your macros... 32 | ], 33 | jsc: { 34 | parser: { 35 | syntax: "typescript" // support typescript ... 36 | } 37 | } 38 | }) 39 | ``` 40 | 41 | ## Commands 42 | 43 | ### Show help messages 44 | 45 | ```sh 46 | macros --help 47 | ``` 48 | 49 | ### Transform with macro-plugin then run with node 50 | 51 | ```sh 52 | macros run ./src/index.ts 53 | ``` 54 | 55 | ### Only transform with macro-plugin 56 | 57 | ```sh 58 | macros build ./src/index.ts 59 | ``` 60 | 61 | By default, it writes to `./src/index.output.js`. You can also add an `output` option to specify path. 62 | 63 | ```sh 64 | macros build ./src/index.ts -o ./dist/index.js 65 | ``` 66 | 67 | ### Start watch progress 68 | 69 | ```sh 70 | macros dev ./src/index.ts 71 | ``` 72 | 73 | ### Emit declarations for macros 74 | 75 | ```sh 76 | macros emit 77 | ``` 78 | 79 | ### Start an interactive shell 80 | 81 | ```sh 82 | macros shell 83 | ``` 84 | 85 | ### Start an ast development shell 86 | 87 | ```sh 88 | macros shell --ast 89 | ``` 90 | 91 | ### Start an transform interactive shell 92 | 93 | ```sh 94 | macros shell --transform 95 | ``` 96 | 97 | Enable swc transform with `--swc` option. 98 | 99 | ```sh 100 | macros shell --transform --swc 101 | ``` 102 | -------------------------------------------------------------------------------- /packages/cli/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@macro-plugin/cli", 3 | "private": true, 4 | "version": "0.0.0", 5 | "description": "@macro-plugin/cli", 6 | "main": "dist/index.js", 7 | "module": "dist/index.mjs", 8 | "types": "./dist/index.d.ts", 9 | "files": [ 10 | "dist", 11 | "CHANGELOG.md" 12 | ], 13 | "keywords": [ 14 | "cli", 15 | "macro", 16 | "macros" 17 | ], 18 | "scripts": { 19 | "build": "rollup -c" 20 | }, 21 | "homepage": "https://github.com/macro-plugin/macros/tree/main/packages/cli", 22 | "repository": { 23 | "type": "git", 24 | "url": "https://github.com/macro-plugin/macros.git" 25 | }, 26 | "dependencies": { 27 | "@macro-plugin/core": "1.2.0", 28 | "@macro-plugin/shared": "1.2.1" 29 | }, 30 | "exports": { 31 | "./package.json": "./package.json", 32 | ".": { 33 | "import": "./dist/index.mjs", 34 | "require": "./dist/index.js", 35 | "types": "./dist/index.d.ts" 36 | } 37 | }, 38 | "author": "Raven Satir", 39 | "license": "MIT", 40 | "devDependencies": { 41 | "commander": "^10.0.1", 42 | "node-watch": "^0.7.3" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /packages/cli/rollup.config.mjs: -------------------------------------------------------------------------------- 1 | import commonjs from "@rollup/plugin-commonjs" 2 | import { defineConfig } from "rollup" 3 | import json from "@rollup/plugin-json" 4 | import { nodeResolve } from "@rollup/plugin-node-resolve" 5 | import { rmSync } from "fs" 6 | import terser from "@rollup/plugin-terser" 7 | import typescript from "rollup-plugin-typescript2" 8 | 9 | /** @type { import("rollup").Plugin[] } */ 10 | const plugins = [ 11 | { 12 | name: "del", 13 | buildStart () { 14 | rmSync("./dist", { recursive: true, force: true }) 15 | }, 16 | transform (code, id) { 17 | if (id.endsWith(".cts") || id.endsWith(".mts")) return "" 18 | }, 19 | }, 20 | json(), 21 | commonjs(), 22 | nodeResolve({ 23 | preferBuiltins: true 24 | }), 25 | typescript({ 26 | tsconfigOverride: { 27 | include: ["packages/**/src"] 28 | } 29 | }), 30 | terser({ 31 | module: true, 32 | compress: { 33 | ecma: 2015, 34 | pure_getters: true, 35 | } 36 | }) 37 | ] 38 | 39 | const external = [ 40 | "@swc/core", 41 | "@macro-plugin/core" 42 | ] 43 | 44 | // compile to core dist folder 45 | export default defineConfig([ 46 | { 47 | input: "./src/index.ts", 48 | output: { 49 | file: "../core/dist/cli.js", 50 | format: "cjs", 51 | }, 52 | plugins, 53 | external, 54 | onwarn (warning, warn) { 55 | if (warning.code === "EVAL" || warning.code === "SOURCEMAP_ERROR") return 56 | warn(warning) 57 | } 58 | }, 59 | { 60 | input: "../register/src/index.ts", 61 | output: { 62 | file: "../core/dist/register.js", 63 | format: "cjs", 64 | }, 65 | plugins: [ 66 | ...plugins, 67 | { 68 | name: "del", 69 | writeBundle () { 70 | rmSync("../core/dist/packages", { recursive: true, force: true }) 71 | } 72 | } 73 | ], 74 | external, 75 | }, 76 | ]) 77 | -------------------------------------------------------------------------------- /packages/cli/src/types.ts: -------------------------------------------------------------------------------- 1 | export type BaseOptions = { minify?: boolean }; 2 | 3 | export interface ShellOptions extends BaseOptions { 4 | ast?: boolean; 5 | swc?: boolean; 6 | transform?: boolean; 7 | } 8 | 9 | export interface MainOptions extends BaseOptions { 10 | eval?: string; 11 | run?: boolean; 12 | interactive?: boolean; 13 | output?: string; 14 | print?: boolean; 15 | } 16 | -------------------------------------------------------------------------------- /packages/core/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Raven Satir 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 | -------------------------------------------------------------------------------- /packages/core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@macro-plugin/core", 3 | "version": "1.2.0", 4 | "description": "Macro system for JavaScript and TypeScript.", 5 | "main": "dist/index.js", 6 | "module": "dist/index.mjs", 7 | "types": "./dist/index.d.ts", 8 | "bin": { 9 | "macros": "dist/cli.js" 10 | }, 11 | "files": [ 12 | "dist", 13 | "CHANGELOG.md" 14 | ], 15 | "keywords": [ 16 | "macro", 17 | "macros", 18 | "cli", 19 | "macro-plugin", 20 | "macro-system" 21 | ], 22 | "scripts": { 23 | "build": "rollup -c ../../rollup.config.mjs" 24 | }, 25 | "dependencies": { 26 | "@swc/core": "^1.3.55" 27 | }, 28 | "homepage": "https://github.com/macro-plugin/macros/tree/main/packages/core", 29 | "repository": { 30 | "type": "git", 31 | "url": "https://github.com/macro-plugin/macros.git" 32 | }, 33 | "sideEffects": false, 34 | "exports": { 35 | "./package.json": "./package.json", 36 | ".": { 37 | "import": "./dist/index.mjs", 38 | "require": "./dist/index.js", 39 | "types": "./dist/index.d.ts" 40 | }, 41 | "./cli": { 42 | "require": "./dist/cli.js" 43 | }, 44 | "./register": { 45 | "require": "./dist/register.js" 46 | } 47 | }, 48 | "author": "Raven Satir", 49 | "license": "MIT" 50 | } 51 | -------------------------------------------------------------------------------- /packages/core/src/defaults.ts: -------------------------------------------------------------------------------- 1 | import { TsFunctionType, TsType } from "@swc/core" 2 | 3 | export const dummySpan = { 4 | start: 0, 5 | end: 0, 6 | ctxt: 0, 7 | } 8 | 9 | export const defaultGlobalExpr = { 10 | type: "TsFunctionType", 11 | span: dummySpan, 12 | params: [ 13 | { 14 | type: "RestElement", 15 | span: dummySpan, 16 | rest: dummySpan, 17 | argument: { 18 | type: "Identifier", 19 | span: dummySpan, 20 | value: "args", 21 | optional: false, 22 | }, 23 | typeAnnotation: { 24 | type: "TsTypeAnnotation", 25 | span: dummySpan, 26 | typeAnnotation: { 27 | type: "TsArrayType", 28 | span: dummySpan, 29 | elemType: { 30 | type: "TsTypeReference", 31 | span: dummySpan, 32 | typeName: { 33 | type: "Identifier", 34 | span: dummySpan, 35 | value: "T", 36 | optional: false 37 | }, 38 | } 39 | } 40 | } 41 | } 42 | ], 43 | typeParams: { 44 | type: "TsTypeParameterDeclaration", 45 | span: dummySpan, 46 | parameters: [ 47 | { 48 | type: "TsTypeParameter", 49 | span: dummySpan, 50 | name: { 51 | type: "Identifier", 52 | span: dummySpan, 53 | value: "T", 54 | optional: false 55 | }, 56 | in: false, 57 | out: false, 58 | } 59 | ] 60 | }, 61 | typeAnnotation: { 62 | type: "TsTypeAnnotation", 63 | span: dummySpan, 64 | typeAnnotation: { 65 | type: "TsTypeReference", 66 | span: dummySpan, 67 | typeName: { 68 | type: "Identifier", 69 | span: dummySpan, 70 | value: "T", 71 | optional: false 72 | }, 73 | } 74 | } 75 | } as TsFunctionType 76 | 77 | export const defaultGlobalType = { 78 | type: "TsFunctionType", 79 | span: dummySpan, 80 | params: [], 81 | typeParams: { 82 | type: "TsTypeParameterDeclaration", 83 | span: dummySpan, 84 | parameters: [ 85 | { 86 | type: "TsTypeParameter", 87 | span: dummySpan, 88 | name: { 89 | type: "Identifier", 90 | span: dummySpan, 91 | value: "T", 92 | optional: false 93 | }, 94 | in: false, 95 | out: false, 96 | } 97 | ] 98 | }, 99 | typeAnnotation: { 100 | type: "TsTypeAnnotation", 101 | span: dummySpan, 102 | typeAnnotation: { 103 | type: "TsTypeReference", 104 | span: dummySpan, 105 | typeName: { 106 | type: "Identifier", 107 | span: dummySpan, 108 | value: "T", 109 | optional: false 110 | }, 111 | } 112 | } 113 | } as TsFunctionType 114 | 115 | export const defaultGlobalTmpl = { 116 | type: "TsKeywordType", 117 | span: dummySpan, 118 | kind: "string" 119 | } as TsType 120 | -------------------------------------------------------------------------------- /packages/core/src/external.ts: -------------------------------------------------------------------------------- 1 | import { GlobalMacroPlugin, MacroPlugin } from "./types" 2 | 3 | import { createMacro } from "./api" 4 | 5 | // handle external macro plugins 6 | export default createMacro({ 7 | enter (ast) { 8 | if (ast.type === "ImportDeclaration" && !ast.typeOnly && !ast.asserts) { 9 | if (typeof this.config.externals === "object") { 10 | const macroDict = (this.config.externals as Record>)[ast.source.value] 11 | let plugin: MacroPlugin 12 | if (macroDict) { 13 | for (const specifier of ast.specifiers) { 14 | if (specifier.type === "ImportSpecifier") { 15 | plugin = macroDict[specifier.local.value] 16 | if (plugin) this.addPlugin(plugin) 17 | } else if (specifier.type === "ImportDefaultSpecifier") { 18 | // TODO: this may have problem when changing import name 19 | plugin = macroDict.default 20 | if (plugin) this.addPlugin(plugin) 21 | } else if (specifier.type === "ImportNamespaceSpecifier") { 22 | const keys = Object.keys(macroDict) 23 | this.addPlugin(Object.values(macroDict)) 24 | this.addPlugin({ 25 | MemberExpression (ast) { 26 | if (ast.object.type === "Identifier" && ast.object.value === specifier.local.value && ast.property.type === "Identifier" && keys.includes(ast.property.value)) { 27 | return ast.property 28 | } 29 | } 30 | }) 31 | } 32 | } 33 | } 34 | } 35 | } 36 | } 37 | }) as Required 38 | -------------------------------------------------------------------------------- /packages/core/src/index.ts: -------------------------------------------------------------------------------- 1 | export { createSwcPlugin, transform, transformAst, transformAsync } from "./transform" 2 | export { walk, Walker } from "./walk" 3 | export { macro, $Macro, $LitMacro, $ExprMacro, $TmplMacro, $TypeMacro, $LabeledMacro } from "./macro" 4 | export * from "./labeled" 5 | export * from "./print" 6 | export * from "./parse" 7 | export * from "./api" 8 | export * from "./lib" 9 | export * from "./ast" 10 | export * from "./types" 11 | export * from "./utils" 12 | -------------------------------------------------------------------------------- /packages/core/src/parse.ts: -------------------------------------------------------------------------------- 1 | import type { Expression, ModuleItem, ParseOptions, TsType, TsTypeAliasDeclaration } from "@swc/core" 2 | 3 | import { dummySpan } from "./defaults" 4 | import { parseSync } from "@swc/core" 5 | 6 | export { parse as parseAsync, parseSync as parse } from "@swc/core" 7 | 8 | function extractExpr (stmt: ModuleItem | undefined): Expression { 9 | if (stmt && stmt.type === "ExpressionStatement" && stmt.expression.type === "ParenthesisExpression") return stmt.expression.expression 10 | return { 11 | type: "Invalid", 12 | span: dummySpan 13 | } 14 | } 15 | 16 | export function parseExpr (expr: string, options?: ParseOptions): Expression { 17 | return extractExpr(parseSync("(" + expr + ")", options).body[0]) 18 | } 19 | 20 | export function parseType (ty: string, options?: ParseOptions): TsType { 21 | return (parseSync(`type A = ${ty}`, { ...options, syntax: "typescript" }).body[0] as TsTypeAliasDeclaration).typeAnnotation 22 | } 23 | -------------------------------------------------------------------------------- /packages/core/src/print.ts: -------------------------------------------------------------------------------- 1 | import { Expression, ModuleItem, Options, Program, TsType, print as _printAsync, printSync } from "@swc/core" 2 | 3 | import { BaseNode } from "./types" 4 | import { dummySpan } from "./defaults" 5 | 6 | /** 7 | * Turns an AST into code, maintaining sourcemaps, user preferences, and valid output. 8 | * @param ast - the abstract syntax tree from which to generate output code. 9 | * @param options - used for specifying options for code generation. 10 | * @returns - an object containing the output code and source map. 11 | */ 12 | export function print ( 13 | ast: BaseNode | BaseNode[], 14 | options?: Options 15 | ) { 16 | const { code, map } = printSync({ 17 | type: "Script", 18 | span: dummySpan, 19 | body: Array.isArray(ast) ? ast as unknown as ModuleItem[] : [ast as unknown as ModuleItem], 20 | } as Program, options) 21 | 22 | return { code: code.trim(), map } 23 | } 24 | 25 | export async function printAsync ( 26 | ast: BaseNode | BaseNode[], 27 | options?: Options 28 | ) { 29 | const { code, map } = await _printAsync({ 30 | type: "Script", 31 | span: dummySpan, 32 | body: Array.isArray(ast) ? ast as unknown as ModuleItem[] : [ast as unknown as ModuleItem], 33 | } as Program, options) 34 | 35 | return { code: code.trim(), map } 36 | } 37 | 38 | export function printExpr (expr: BaseNode, options?: Options) { 39 | const { code, map } = print({ 40 | type: "ExpressionStatement", 41 | span: dummySpan, 42 | expression: expr as Expression 43 | }, options) 44 | 45 | return { code: code.replace(/\s*;\s*$/, ""), map } 46 | } 47 | 48 | export async function printExprAsync (expr: BaseNode, options?: Options) { 49 | const { code, map } = await printAsync({ 50 | type: "ExpressionStatement", 51 | span: dummySpan, 52 | expression: expr as Expression 53 | }, options) 54 | 55 | return { code: code.replace(/\s*;\s*$/, ""), map } 56 | } 57 | 58 | export function printType (ty: TsType, options?: Options) { 59 | const { code, map } = print({ 60 | type: "TsTypeAliasDeclaration", 61 | span: dummySpan, 62 | declare: false, 63 | id: { 64 | type: "Identifier", 65 | span: dummySpan, 66 | value: "__PrintType__", 67 | optional: false 68 | }, 69 | typeAnnotation: ty, 70 | }, options) 71 | 72 | return { code: code.replace(/\s*type\s+__PrintType__\s*=\s*/, "").replace(/\s*;\s*$/, ""), map } 73 | } 74 | 75 | export async function printTypeAsync (ty: TsType, options?: Options) { 76 | const { code, map } = await printAsync({ 77 | type: "TsTypeAliasDeclaration", 78 | span: dummySpan, 79 | declare: false, 80 | id: { 81 | type: "Identifier", 82 | span: dummySpan, 83 | value: "__PrintType__", 84 | optional: false 85 | }, 86 | typeAnnotation: ty, 87 | }, options) 88 | 89 | return { code: code.replace(/\s*type\s+__PrintType__\s*=\s*/, "").replace(/\s*;\s*$/, ""), map } 90 | } 91 | -------------------------------------------------------------------------------- /packages/core/src/transform.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Plugin, 3 | Program, 4 | print, 5 | printSync, 6 | } from "@swc/core" 7 | import { createWalkPlugin, getSpanOffset } from "./utils" 8 | import { parse, parseAsync } from "./parse" 9 | 10 | import type { Config } from "./types" 11 | import { Walker } from "./walk" 12 | 13 | export function createSwcPlugin (config: Config, src?: string, spanOffset = 0): Plugin { 14 | return (program: Program) => { 15 | const walker = new Walker(createWalkPlugin(config.macros || []), src, config, true) 16 | 17 | program = walker.walk(program, spanOffset) as Program 18 | if (config.emitDts) { 19 | const dts = walker.emit() 20 | config.onEmitDts?.(dts); 21 | (program as Program & { dts?: string }).dts = dts 22 | } 23 | 24 | return program 25 | } 26 | } 27 | 28 | export function transformAst (ast: Program, config: Config, src?: string, spanOffset = 0): Program & { dts?: string } { 29 | return createSwcPlugin(config, src, spanOffset)(ast) 30 | } 31 | 32 | /** 33 | * Transform code with your labeled macro plugins. 34 | * @param code - input source code. 35 | * @param config - an object containing your macro config. 36 | * @returns - an object containing the output code and source map. 37 | */ 38 | export function transform (code: string, config: Config) { 39 | const spanOffset = getSpanOffset() 40 | const ast = transformAst(parse(code, config.jsc?.parser), config, code, spanOffset) 41 | const dts = ast.dts 42 | if (dts) delete ast.dts 43 | return { ...printSync(ast), ast: ast as Program, dts } 44 | } 45 | 46 | /** 47 | * Transform code with your labeled macro plugins. 48 | * @param code - input source code. 49 | * @param config - an object containing your macro config. 50 | * @returns - an object containing the output code and source map. 51 | */ 52 | export async function transformAsync (code: string, config: Config) { 53 | const spanOffset = getSpanOffset() 54 | const parsed = await parseAsync(code, config.jsc?.parser) 55 | const ast = transformAst(parsed, config, code, spanOffset) 56 | const result = await print(ast) 57 | const dts = ast.dts 58 | if (dts) delete ast.dts 59 | return { ...result, ast: ast as Program, dts } 60 | } 61 | -------------------------------------------------------------------------------- /packages/core/tests/__snapshots__/expr.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`create a template macro 1`] = ` 4 | "let person = "Bob"; 5 | let age = 12; 6 | const des = "That Bob is 12"; 7 | " 8 | `; 9 | 10 | exports[`create a template macro 2`] = ` 11 | "declare global { 12 | const real: (strings: TemplateStringsArray, ...expressions: unknown[]) => string; 13 | } 14 | export {} 15 | " 16 | `; 17 | 18 | exports[`create a type macro with createExprMacro 1`] = ` 19 | "const emit = defineEmits([ 20 | "change", 21 | "update" 22 | ]); 23 | " 24 | `; 25 | 26 | exports[`create a type macro with createExprMacro 2`] = ` 27 | "declare global { 28 | const defineEmits: (...args: T[]) => T; 29 | } 30 | export {} 31 | " 32 | `; 33 | 34 | exports[`create a type macro with createTypeMacro 1`] = ` 35 | "const emit = defineEmits([ 36 | "change", 37 | "update" 38 | ]); 39 | " 40 | `; 41 | 42 | exports[`create a type macro with createTypeMacro 2`] = ` 43 | "declare global { 44 | const defineEmits: () => T; 45 | } 46 | export {} 47 | " 48 | `; 49 | 50 | exports[`create complex expr macro 1`] = ` 51 | "declare global { 52 | const $add: (a: number, b: number) => number; 53 | } 54 | export {} 55 | " 56 | `; 57 | -------------------------------------------------------------------------------- /packages/core/tests/__snapshots__/global.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`inject imports and exports 1`] = ` 4 | "import test from "test"; 5 | import { ref } from "vue"; 6 | import "style.css"; 7 | function myComponent() { 8 | const count = ref(0); 9 | } 10 | export { ref } from "vue"; 11 | export * as all; 12 | " 13 | `; 14 | 15 | exports[`transform function block 1`] = ` 16 | "const add = ()=>{ 17 | return a + b; 18 | }; 19 | " 20 | `; 21 | 22 | exports[`transform function block 2`] = ` 23 | "function add(a, b) { 24 | return a + b; 25 | } 26 | " 27 | `; 28 | -------------------------------------------------------------------------------- /packages/core/tests/__snapshots__/labeled.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`chaining decorators 1`] = ` 4 | "function star(func) { 5 | return (...args)=>{ 6 | console.log("*".repeat(15)); 7 | func.apply(undefined, args); 8 | console.log("*".repeat(15)); 9 | }; 10 | } 11 | function percent(func) { 12 | return (...args)=>{ 13 | console.log("%".repeat(15)); 14 | func.apply(undefined, args); 15 | console.log("%".repeat(15)); 16 | }; 17 | } 18 | function printer(msg) { 19 | return star(percent(function printer(msg) { 20 | console.log(msg); 21 | }))(msg); 22 | } 23 | printer("Hello"); 24 | " 25 | `; 26 | 27 | exports[`decorating functions with parameters 1`] = ` 28 | "function smart_divide(func) { 29 | return function(a, b) { 30 | console.log("I am going to divide", a, "and", b); 31 | if (b === 0) { 32 | throw new Error("Whoops! cannot divide"); 33 | } 34 | return func(a, b); 35 | }; 36 | } 37 | function divide(a, b) { 38 | return smart_divide(function divide(a, b) { 39 | return a / b; 40 | })(a, b); 41 | } 42 | divide(2, 5); 43 | divide(2, 0); 44 | " 45 | `; 46 | 47 | exports[`decorator in arrow function 1`] = ` 48 | "function make_pretty(func) { 49 | function inner() { 50 | console.log("I got decorated"); 51 | func(); 52 | } 53 | return inner; 54 | } 55 | const ordinary = ()=>{ 56 | return make_pretty(function ordinary() { 57 | console.log("I am ordinary"); 58 | })(); 59 | }; 60 | ordinary(); 61 | " 62 | `; 63 | 64 | exports[`decorator in class method 1`] = ` 65 | "function make_pretty(func) { 66 | function inner() { 67 | console.log("I got decorated"); 68 | func(); 69 | } 70 | return inner; 71 | } 72 | class Test { 73 | ordinary() { 74 | return make_pretty(function ordinary() { 75 | console.log("I am ordinary"); 76 | })(); 77 | } 78 | } 79 | new Test().ordinary(); 80 | " 81 | `; 82 | 83 | exports[`decorator macro with empty array 1`] = ` 84 | "function ordinary() { 85 | console.log("I am ordinary"); 86 | } 87 | ordinary(); 88 | " 89 | `; 90 | 91 | exports[`decorator macro with multiple decorator in array 1`] = ` 92 | "function ordinary(a, b, c) { 93 | return d(e(f(function ordinary(a, b, c) { 94 | console.log("I am ordinary"); 95 | })))(a, b, c); 96 | } 97 | ordinary(1, 2, 3); 98 | " 99 | `; 100 | 101 | exports[`decorator macro with simple decorator 1`] = ` 102 | "function make_pretty(func) { 103 | function inner() { 104 | console.log("I got decorated"); 105 | func(); 106 | } 107 | return inner; 108 | } 109 | function ordinary() { 110 | return make_pretty(function ordinary() { 111 | console.log("I am ordinary"); 112 | })(); 113 | } 114 | ordinary(); 115 | " 116 | `; 117 | 118 | exports[`decorator macro with single decorator in array 1`] = ` 119 | "function make_pretty(func) { 120 | function inner() { 121 | console.log("I got decorated"); 122 | func(); 123 | } 124 | return inner; 125 | } 126 | function ordinary() { 127 | return make_pretty(function ordinary() { 128 | console.log("I am ordinary"); 129 | })(); 130 | } 131 | ordinary(); 132 | " 133 | `; 134 | 135 | exports[`decorator with function expression 1`] = ` 136 | "function ordinary() { 137 | return ((func)=>{ 138 | return ()=>{ 139 | console.log("I got decorated"); 140 | func(); 141 | }; 142 | })(function ordinary() { 143 | console.log("I am ordinary"); 144 | })(); 145 | } 146 | " 147 | `; 148 | 149 | exports[`transform codeblock to call 1`] = ` 150 | "(()=>{ 151 | let a = 3; 152 | a += 2; 153 | console.log(a); 154 | })(); 155 | " 156 | `; 157 | 158 | exports[`transform complex 1`] = ` 159 | "let a = 3; 160 | a += 2; 161 | console.log(a); 162 | " 163 | `; 164 | 165 | exports[`transform debug 1`] = ` 166 | "console.log("Hello World"); 167 | " 168 | `; 169 | 170 | exports[`transform in jsx 1`] = ` 171 | "\`

hello World

;\`; 172 | " 173 | `; 174 | 175 | exports[`transform in typescript 1`] = ` 176 | "let a: string = "Hello"; 177 | " 178 | `; 179 | -------------------------------------------------------------------------------- /packages/core/tests/__snapshots__/literal.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`create literal macro 1`] = ` 4 | "if (true) { 5 | console.log("development"); 6 | } 7 | " 8 | `; 9 | 10 | exports[`should allow ast for more complex value 1`] = ` 11 | "const expr = call("hello", "world"); 12 | " 13 | `; 14 | 15 | exports[`should pass overwrited variable 1`] = ` 16 | "const before = true; 17 | function testDev(__DEV__) { 18 | if (__DEV__) { 19 | console.log("development"); 20 | } 21 | } 22 | const after = true; 23 | " 24 | `; 25 | 26 | exports[`should support all jsonable values 1`] = ` 27 | "const a = 123; 28 | const b = "Hello World"; 29 | const c = false; 30 | const d = null; 31 | const e = undefined; 32 | const f = ()=>true; 33 | const e = [ 34 | 1, 35 | 2, 36 | 3 37 | ]; 38 | const g = { 39 | "a": 1, 40 | "b": 2 41 | }; 42 | const h = /.*/g; 43 | " 44 | `; 45 | 46 | exports[`should support all jsonable values 2`] = ` 47 | "declare global { 48 | const __num__: number; 49 | const __str__: string; 50 | const __bool__: boolean; 51 | const __null__: null; 52 | const __undefined__: undefined; 53 | const __function__: () => true; 54 | const __array__: number[]; 55 | const __object__: Record; 56 | const __regex__: RegExp; 57 | } 58 | export {} 59 | " 60 | `; 61 | 62 | exports[`should support pass an object 1`] = ` 63 | "const a = 123; 64 | const b = "Hello World"; 65 | const c = false; 66 | const d = null; 67 | const e = undefined; 68 | const f = ()=>true; 69 | const e = [ 70 | 1, 71 | 2, 72 | 3 73 | ]; 74 | const g = { 75 | "a": 1, 76 | "b": 2 77 | }; 78 | const h = /.*/g; 79 | const i = call("hello", "world"); 80 | " 81 | `; 82 | 83 | exports[`should support pass an object 2`] = ` 84 | "declare global { 85 | const __num__: number; 86 | const __str__: string; 87 | const __bool__: boolean; 88 | const __null__: null; 89 | const __undefined__: undefined; 90 | const __function__: () => true; 91 | const __array__: number[]; 92 | const __object__: Record; 93 | const __regex__: RegExp; 94 | const __expr__: string; 95 | } 96 | export {} 97 | " 98 | `; 99 | 100 | exports[`use as swc plugin 1`] = ` 101 | "if (true) { 102 | console.log("development"); 103 | } 104 | " 105 | `; 106 | 107 | exports[`use with swc transform ast 1`] = ` 108 | "var a = "Hello"; 109 | if (true) { 110 | console.log("development"); 111 | } 112 | " 113 | `; 114 | -------------------------------------------------------------------------------- /packages/core/tests/__snapshots__/macro.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`create complex macro with macros 1`] = ` 4 | "; 5 | let a = 4; 6 | let b = 1 + 2; 7 | let c = 8; 8 | let d = "That Bob is 12"; 9 | if (__debug__) { 10 | console.log("debug"); 11 | } 12 | let f = "world"; 13 | " 14 | `; 15 | 16 | exports[`create expr macro in macro block 1`] = ` 17 | "; 18 | let c = 1 + 2; 19 | " 20 | `; 21 | 22 | exports[`create lit macro in macro block 1`] = ` 23 | "declare global { 24 | var $Macro: typeof import("@macro-plugin/core").$Macro; 25 | var $LitMacro: typeof import("@macro-plugin/core").$LitMacro; 26 | var $ExprMacro: typeof import("@macro-plugin/core").$ExprMacro; 27 | var $TypeMacro: typeof import("@macro-plugin/core").$TypeMacro; 28 | var $TmplMacro: typeof import("@macro-plugin/core").$TmplMacro; 29 | var $LabeledMacro: typeof import("@macro-plugin/core").$LabeledMacro; 30 | } 31 | export {} 32 | " 33 | `; 34 | 35 | exports[`create lit macro in macro block 2`] = ` 36 | "; 37 | if (true) { 38 | console.log("debug"); 39 | } 40 | " 41 | `; 42 | 43 | exports[`create lit macro with array pattern and object pattern 1`] = ` 44 | "; 45 | const f1 = [ 46 | 1, 47 | 2, 48 | { 49 | __third__: 3 50 | } 51 | ][0]; 52 | const f2 = [ 53 | 1, 54 | 2, 55 | { 56 | __third__: 3 57 | } 58 | ][1]; 59 | const f3 = ([ 60 | 1, 61 | 2, 62 | { 63 | __third__: 3 64 | } 65 | ][2])["__third__"]; 66 | const k = ({ 67 | __prop__: 1, 68 | __key__: 2 69 | })["__key__"]; 70 | const p = ({ 71 | __prop__: 1, 72 | __key__: 2 73 | })["__prop__"]; 74 | " 75 | `; 76 | -------------------------------------------------------------------------------- /packages/core/tests/global.test.ts: -------------------------------------------------------------------------------- 1 | import { createMacro, dummySpan, transform } from "../src" 2 | 3 | import type { VariableDeclaration } from "@swc/core" 4 | 5 | const arrow = createMacro({ 6 | FunctionDeclaration (ast) { 7 | const children = [] 8 | let isArrow = false 9 | 10 | if (!ast.body) return 11 | 12 | for (const s of ast.body.stmts || []) { 13 | if (s.type === "LabeledStatement" && s.body.type === "ExpressionStatement") { 14 | const expr = s.body.expression 15 | if (s.label.value === "arrow") { 16 | if (expr.type === "BooleanLiteral" && expr.value) { 17 | isArrow = true 18 | } 19 | continue 20 | } 21 | } 22 | children.push(s) 23 | } 24 | 25 | ast.body.stmts = children 26 | 27 | if (isArrow) { 28 | return { 29 | type: "VariableDeclaration", 30 | kind: "const", 31 | declare: false, 32 | span: dummySpan, 33 | declarations: [ 34 | { 35 | type: "VariableDeclarator", 36 | id: ast.identifier, 37 | init: { 38 | type: "ArrowFunctionExpression", 39 | generator: false, 40 | async: false, 41 | params: [], 42 | body: ast.body, 43 | span: dummySpan 44 | }, 45 | definite: false, 46 | span: dummySpan 47 | } 48 | ] 49 | } as VariableDeclaration 50 | } 51 | } 52 | }) 53 | 54 | const inject = createMacro(function () { 55 | this.import("test", "test", true) 56 | this.import("ref", "vue") 57 | this.import("style.css") 58 | this.export("ref", "vue") 59 | this.export("all", undefined, true) 60 | }) 61 | 62 | test("transform function block", () => { 63 | const code = ` 64 | function add(a, b) { 65 | arrow: true 66 | return a + b 67 | } 68 | ` 69 | 70 | const code2 = ` 71 | function add(a, b) { 72 | arrow: false 73 | return a + b 74 | } 75 | ` 76 | expect(transform(code, { macros: [arrow] }).code).toMatchSnapshot() 77 | expect(transform(code2, { macros: [arrow] }).code).toMatchSnapshot() 78 | }) 79 | 80 | test("inject imports and exports", () => { 81 | const code = ` 82 | function myComponent() { 83 | const count = ref(0); 84 | } 85 | ` 86 | 87 | expect(transform(code, { 88 | macros: [inject], 89 | jsc: { 90 | parser: { 91 | syntax: "typescript", 92 | }, 93 | }, 94 | }).code).toMatchSnapshot() 95 | }) 96 | -------------------------------------------------------------------------------- /packages/core/tests/lib.test.ts: -------------------------------------------------------------------------------- 1 | import { $Ast, $Column, $Concat, $Env, $Eval, $Expr, $ID, $Include, $IncludeJSON, $Line, $Quote, $Span, $Stringify, transform } from "../src" 2 | 3 | test("$Eval macro", () => { 4 | expect(transform("$Eval(1 + 2 / 10)", { macros: [$Eval] }).code).toEqual("1.2;\n") 5 | expect(transform("$Eval('1 + 3')", { macros: [$Eval] }).code).toEqual("4;\n") 6 | // eslint-disable-next-line no-template-curly-in-string 7 | expect(transform("let a = 3; let b = 4; $Eval(`${a} + ${b}`)", { macros: [$Eval] }).code).toEqual("let a = 3;\nlet b = 4;\n7;\n") 8 | expect(transform("$Eval((a, b) => { return a + b }, 1, 2)", { macros: [$Eval] }).code).toEqual("3;\n") 9 | }) 10 | 11 | test("$Ast macro", () => { 12 | expect(transform(` 13 | const i = $Ast(abc) 14 | const d = $Ast('abc') 15 | const a = $Ast("'hello'") 16 | const b = $Ast(1 + 2) 17 | const c = $Ast('a * 3') 18 | `, { macros: [$Ast] }).code).toMatchSnapshot() 19 | }) 20 | 21 | test("$Quote macro", () => { 22 | const r = transform(` 23 | const someNumber = $Ast(5) 24 | const someIdent = $Ast('hello') 25 | const someExpr = $Expr\`3 + \${someNumber}\` 26 | const tokens = $Quote\` 27 | let \${someIdent} = \${someExpr} 28 | \` 29 | `, { macros: [$Ast, $Expr, $Quote], emitDts: true, jsc: { parser: { syntax: "typescript", tsx: true } } }) 30 | expect(r.dts).toMatchSnapshot() 31 | expect(r.code).toMatchSnapshot() 32 | }) 33 | 34 | test("$Stringify macro", () => { 35 | expect(transform(` 36 | const a = $Stringify(abc) 37 | const b = $Stringify('abc') 38 | const c = $Stringify(1 + 2) 39 | const d = $Stringify(hello(1, 2)) 40 | const e = $Stringify() 41 | `, { macros: [$Stringify], jsc: { parser: { syntax: "typescript" } } }).code).toMatchSnapshot() 42 | }) 43 | 44 | test("$Env macro", () => { 45 | expect(transform(` 46 | const e = $Env("NODE_ENV") 47 | const s = $Env("NODE_ENV") 48 | const b = $Env("DEV") 49 | const n = $Env("DEV") 50 | `, { macros: [$Env], jsc: { parser: { syntax: "typescript" } } }).code).toMatchSnapshot() 51 | }) 52 | 53 | test("$Span macro", () => { 54 | const code = "$Span()" 55 | expect(code.slice(0, 7)).toBe("$Span()") 56 | expect(/^\s*\[\s*0,\s*7/.test(transform(code, { macros: [$Span] }).code)).toBe(true) 57 | 58 | const multiline = ` 59 | const a = $Span() 60 | ` 61 | expect(multiline.slice(15, 22)).toBe("$Span()") 62 | expect(/\s*\[\s*15,\s*22/.test(transform(multiline, { macros: [$Span] }).code)).toBe(true) 63 | }) 64 | 65 | test("$Line macro", () => { 66 | expect(transform(`const ln = $Line() 67 | const ln2 = $Line() 68 | const ln3 = $Line() 69 | `, { macros: [$Line] }).code).toEqual("const ln = 1;\nconst ln2 = 2;\nconst ln3 = 3;\n") 70 | }) 71 | 72 | test("$Column macro", () => { 73 | expect(transform(`$Column() 74 | $Column() 75 | const col = $Column() 76 | $Column()`, { macros: [$Column] }).code).toEqual("1;\n3;\nconst col = 15;\n3;\n") 77 | }) 78 | 79 | test("$ID macro", () => { 80 | expect(transform("const id = $ID()\nconst id2 = $ID()", { macros: [$ID] }).code).toEqual("const id = \"lb6ods\";\nconst id2 = \"vzqptz\";\n") 81 | }) 82 | 83 | test("$Include macro", () => { 84 | expect(transform("$Include('packages/factory/src/index.ts')", { macros: [$Include] }).code).toMatchSnapshot() 85 | }) 86 | 87 | test("$IncludeJSON macro", () => { 88 | expect(transform("$IncludeJSON('packages/core/package.json')", { macros: [$IncludeJSON] }).code.includes("@macro-plugin/core")).toBe(true) 89 | expect(transform("$IncludeJSON('packages/core/package.json', 'name')", { macros: [$IncludeJSON] }).code).toBe("\"@macro-plugin/core\";\n") 90 | expect(transform("$IncludeJSON('package.json', 'private')", { macros: [$IncludeJSON] }).code).toBe("true;\n") 91 | }) 92 | 93 | test("$Concat macro", () => { 94 | expect(transform("$Concat('hello', 'world', 1, 2, true, undefined, null, 3.14)", { macros: [$Concat] }).code).toEqual("\"helloworld12trueundefinednull3.14\";\n") 95 | expect(() => transform("$Concat('hello', abc)", { macros: [$Concat] }).code).toThrow() 96 | }) 97 | -------------------------------------------------------------------------------- /packages/core/tests/literal.test.ts: -------------------------------------------------------------------------------- 1 | import { createLitMacro, createSwcPlugin, parseExpr, transform } from "../src" 2 | import { parseSync, transformSync as swcTransform } from "@swc/core" 3 | 4 | test("create literal macro", () => { 5 | const code = ` 6 | if (__DEV__) { 7 | console.log('development') 8 | } 9 | ` 10 | 11 | expect(transform(code, { macros: [createLitMacro("__DEV__", true)] }).code).toMatchSnapshot() 12 | }) 13 | 14 | test("use as swc plugin", () => { 15 | const plugin = createSwcPlugin({ macros: [createLitMacro("__DEV__", true)] }) 16 | 17 | const code = ` 18 | if (__DEV__) { 19 | console.log('development') 20 | } 21 | ` 22 | 23 | expect(swcTransform(code, { plugin, jsc: { parser: { syntax: "typescript" } } }).code).toMatchSnapshot() 24 | }) 25 | 26 | test("use with swc transform ast", () => { 27 | const plugin = createSwcPlugin({ macros: [createLitMacro("__DEV__", true)] }) 28 | 29 | const code = ` 30 | let a: string = "Hello" 31 | 32 | if (__DEV__) { 33 | console.log('development') 34 | } 35 | ` 36 | 37 | const program = plugin(parseSync(code, { syntax: "typescript" })) 38 | 39 | expect(swcTransform(program, { jsc: { parser: { syntax: "typescript" } } }).code).toMatchSnapshot() 40 | }) 41 | 42 | test("should pass overwrited variable", () => { 43 | const code = ` 44 | const before = __DEV__ 45 | 46 | function testDev(__DEV__) { 47 | if (__DEV__) { 48 | console.log('development') 49 | } 50 | } 51 | 52 | const after = __DEV__ 53 | ` 54 | expect(transform(code, { macros: [createLitMacro("__DEV__", true)] }).code).toMatchSnapshot() 55 | }) 56 | 57 | test("should support all jsonable values", () => { 58 | const code = ` 59 | const a = __num__ 60 | const b = __str__ 61 | const c = __bool__ 62 | const d = __null__ 63 | const e = __undefined__ 64 | const f = __function__ 65 | const e = __array__ 66 | const g = __object__ 67 | const h = __regex__ 68 | ` 69 | const r = transform(code, { 70 | macros: [ 71 | createLitMacro("__num__", 123), 72 | createLitMacro("__str__", "Hello World"), 73 | createLitMacro("__bool__", false), 74 | createLitMacro("__null__", null), 75 | createLitMacro("__undefined__", undefined), 76 | createLitMacro("__function__", () => true, "() => true"), 77 | createLitMacro("__array__", [1, 2, 3], "number[]"), 78 | createLitMacro("__object__", { a: 1, b: 2 }, "Record"), 79 | createLitMacro("__regex__", /.*/g), 80 | ], 81 | emitDts: true 82 | }) 83 | 84 | expect(r.code).toMatchSnapshot() 85 | expect(r.dts).toMatchSnapshot() 86 | }) 87 | 88 | test("should allow ast for more complex value", () => { 89 | const code = ` 90 | const expr = __expr__ 91 | ` 92 | expect(transform(code, { 93 | macros: [ 94 | createLitMacro("__expr__", parseExpr('call("hello", "world")')) 95 | ] 96 | }).code).toMatchSnapshot() 97 | }) 98 | 99 | test("should support pass an object", () => { 100 | const code = ` 101 | const a = __num__ 102 | const b = __str__ 103 | const c = __bool__ 104 | const d = __null__ 105 | const e = __undefined__ 106 | const f = __function__ 107 | const e = __array__ 108 | const g = __object__ 109 | const h = __regex__ 110 | const i = __expr__ 111 | ` 112 | const r = transform(code, { 113 | macros: [ 114 | createLitMacro({ 115 | __num__: 123, 116 | __str__: "Hello World", 117 | __bool__: false, 118 | __null__: null, 119 | __undefined__: undefined, 120 | __function__: () => true, 121 | __array__: [1, 2, 3], 122 | __object__: { a: 1, b: 2 }, 123 | __regex__: /.*/g, 124 | __expr__: parseExpr('call("hello", "world")') 125 | }, { 126 | __function__: "() => true", 127 | __array__: "number[]", 128 | __object__: "Record", 129 | __expr__: "string" 130 | }) 131 | ], 132 | emitDts: true 133 | }) 134 | expect(r.code).toMatchSnapshot() 135 | expect(r.dts).toMatchSnapshot() 136 | }) 137 | -------------------------------------------------------------------------------- /packages/core/tests/macro.test.ts: -------------------------------------------------------------------------------- 1 | import { macro, transform } from "../src" 2 | 3 | test("create lit macro in macro block", () => { 4 | const code = ` 5 | macro: { 6 | var __DEBUG__ = true 7 | } 8 | 9 | if (__DEBUG__) { 10 | console.log("debug") 11 | } 12 | ` 13 | 14 | const r = transform(code, { macros: [macro], emitDts: true }) 15 | expect(r.dts).toMatchSnapshot() 16 | expect(r.code).toMatchSnapshot() 17 | }) 18 | 19 | test("create lit macro with array pattern and object pattern", () => { 20 | const code = ` 21 | macro: { 22 | var [__first__, __second__, { __third__ }] = [1, 2, { __third__: 3 }] 23 | var { __key__, __prop__ } = { __prop__: 1, __key__: 2 } 24 | } 25 | 26 | const f1 = __first__ 27 | const f2 = __second__ 28 | const f3 = __third__ 29 | const k = __key__ 30 | const p = __prop__ 31 | ` 32 | 33 | expect(transform(code, { macros: [macro] }).code).toMatchSnapshot() 34 | }) 35 | 36 | test("create expr macro in macro block", () => { 37 | const code = ` 38 | macro: { 39 | var $add = (a: number, b: number) => a + b 40 | } 41 | 42 | let c = $add(1, 2) 43 | ` 44 | 45 | expect(transform(code, { macros: [macro], jsc: { parser: { syntax: "typescript" } } }).code).toMatchSnapshot() 46 | }) 47 | 48 | test("create complex macro with macros", () => { 49 | const code = ` 50 | macro: { 51 | var __num__ = $LitMacro(4) 52 | 53 | var add = $ExprMacro<(a: number, b: number) => number>(function(args) { 54 | const a = this.printExpr(args[0]) 55 | const b = this.printExpr(args[1]) 56 | 57 | if (+a < 0) return args[1] 58 | return this.parseExpr(\`\${a} + \${b}\`) 59 | }) 60 | 61 | var typeAdd = $TypeMacro<(() => number)>(function (typeParams) { 62 | return this.parseExpr((typeParams[0].literal.value + typeParams[1].literal.value).toString()) 63 | }) 64 | 65 | var real = $TmplMacro(function (strings, personExpr, ageExpr) { 66 | return { 67 | type: "StringLiteral", 68 | span: { 69 | start: 0, 70 | end: 0, 71 | ctxt: 0, 72 | }, 73 | value: strings[0] + "Bob" + strings[1] + "12" + strings[2] 74 | } 75 | }) 76 | 77 | $LabeledMacro("debug", function (stmt) { 78 | return { 79 | "type": "IfStatement", 80 | "span": { 81 | "start": 0, 82 | "end": 28, 83 | "ctxt": 0 84 | }, 85 | "test": { 86 | "type": "Identifier", 87 | "span": { 88 | "start": 4, 89 | "end": 13, 90 | "ctxt": 1 91 | }, 92 | "value": "__debug__", 93 | "optional": false 94 | }, 95 | "consequent": { 96 | "type": "BlockStatement", 97 | "span": { 98 | "start": 15, 99 | "end": 28, 100 | "ctxt": 0 101 | }, 102 | "stmts": [stmt] 103 | } 104 | } 105 | }) 106 | 107 | $Macro({ 108 | StringLiteral(ast) { 109 | if (ast.value === 'hello') ast.value = 'world' 110 | } 111 | }) 112 | } 113 | 114 | let a = __num__ 115 | let b = add(1, 2) 116 | let c = typeAdd<3, 5>() 117 | let d = real\`That \${person} is \${age}\` 118 | debug: console.log('debug') 119 | let f = 'hello' 120 | ` 121 | 122 | expect(transform(code, { macros: [macro], jsc: { parser: { syntax: "typescript" } } }).code).toMatchSnapshot() 123 | }) 124 | -------------------------------------------------------------------------------- /packages/core/tests/print.test.ts: -------------------------------------------------------------------------------- 1 | import { parseType, printType } from "../src" 2 | 3 | test("print type", () => { 4 | expect(printType(parseType("[]")).code).toEqual("[]") 5 | expect(printType(parseType("string|number")).code).toEqual("string | number") 6 | }) 7 | -------------------------------------------------------------------------------- /packages/core/tests/track.test.ts: -------------------------------------------------------------------------------- 1 | import { ScopeVar, createMacro, transform } from "../src" 2 | 3 | let a: ScopeVar | undefined, b: ScopeVar | undefined, c: ScopeVar | undefined 4 | 5 | const trackValue = createMacro({ 6 | FunctionDeclaration () { 7 | a = this.track("a") 8 | b = this.track("b") 9 | c = this.track("c") 10 | } 11 | }) 12 | 13 | test("track variables", () => { 14 | const code = ` 15 | import { count } from './test' 16 | 17 | const a = 1 18 | const b = 2 19 | 20 | function log(a) { 21 | console.log(a) 22 | } 23 | ` 24 | 25 | transform(code, { 26 | macros: [trackValue] 27 | }) 28 | 29 | // `a` been overwrited 30 | expect(a?.value).toBeUndefined() 31 | // `b` is shadowed 32 | expect(b?.value).toBeDefined() 33 | // `c` is undefined 34 | expect(c).toBeUndefined() 35 | }) 36 | -------------------------------------------------------------------------------- /packages/core/tests/utils.test.ts: -------------------------------------------------------------------------------- 1 | import { $Ast, $Column, $Eval, $Quote, isMacroPlugin, isMacroProxy } from "../src" 2 | 3 | test("isMacroPlugin", () => { 4 | expect(isMacroPlugin($Ast)).toBeTruthy() 5 | expect(isMacroPlugin($Column)).toBeTruthy() 6 | expect(isMacroPlugin($Eval)).toBeTruthy() 7 | expect(isMacroPlugin($Quote)).toBeTruthy() 8 | }) 9 | 10 | test("isMacroProxy", () => { 11 | expect(isMacroProxy($Ast)).toBeFalsy() 12 | expect(isMacroProxy($Column)).toBeFalsy() 13 | expect(isMacroProxy($Eval)).toBeFalsy() 14 | expect(isMacroProxy($Quote)).toBeTruthy() 15 | 16 | expect($Ast.proxy(() => {})).toBeTruthy() 17 | }) 18 | -------------------------------------------------------------------------------- /packages/factory/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Raven Satir 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 | -------------------------------------------------------------------------------- /packages/factory/README.md: -------------------------------------------------------------------------------- 1 | # @macro-plugin/factory 2 | 3 | Macro factories for simplify the process of creating swc AST. 4 | 5 | ## Installation 6 | 7 | ```sh 8 | # if you use npm 9 | npm i -D @macro-plugin/factory 10 | # if you use pnpm 11 | pnpm i -D @macro-plugin/factory 12 | # if you use yarn 13 | yarn add -D @macro-plugin/factory 14 | ``` 15 | 16 | ## Usage 17 | 18 | Given an exmaple. 19 | 20 | ```js 21 | import { createIdentifier } from "@macro-plugin/factory" 22 | 23 | createIdentifier("hello") 24 | 25 | // { 26 | // type: "Identifier", 27 | // value: "hello", 28 | // optional: false, 29 | // span: { 30 | // start: 0, 31 | // end: 0, 32 | // ctxt: 0 33 | // } 34 | // } 35 | 36 | ``` 37 | 38 | Or with macros 39 | 40 | ```js 41 | import { $Identifier } from "@macro-plugin/factory" 42 | 43 | $Identifier("hello") 44 | ``` 45 | 46 | ## Runtime vs Macros 47 | 48 | The results generated by macros and runtime are the same in theory, but macros performance may be better. 49 | 50 | For example, with runtime, if you use `createIdentifier` api, then the `function createIdentifier` will be bundled to your macro plugin. 51 | 52 | If you use `$Identifier`, macro-plugin will replace your call with raw object `{ type: "Identifier", ... }`. So it will perform better. 53 | 54 | ## Built-in factory 55 | 56 | ### Runtime 57 | 58 | See [runtime](./src/runtime.ts) 59 | 60 | ### Macros 61 | 62 | See [macros](./src/macros.ts) 63 | -------------------------------------------------------------------------------- /packages/factory/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@macro-plugin/factory", 3 | "version": "1.2.1", 4 | "description": "Macro factories for creating AST.", 5 | "main": "dist/index.js", 6 | "module": "dist/index.mjs", 7 | "types": "dist/index.d.ts", 8 | "files": [ 9 | "dist", 10 | "CHANGELOG.md" 11 | ], 12 | "keywords": [ 13 | "factory", 14 | "macro", 15 | "macros", 16 | "macro-plugin" 17 | ], 18 | "scripts": { 19 | "build": "rollup -c ./rollup.config.mjs" 20 | }, 21 | "dependencies": { 22 | "@macro-plugin/core": "1.2.0" 23 | }, 24 | "homepage": "https://github.com/macro-plugin/macros/tree/main/packages/factory", 25 | "repository": { 26 | "type": "git", 27 | "url": "https://github.com/macro-plugin/macros.git" 28 | }, 29 | "exports": { 30 | "./package.json": "./package.json", 31 | ".": { 32 | "import": "./dist/index.mjs", 33 | "require": "./dist/index.js", 34 | "types": "./dist/index.d.ts" 35 | }, 36 | "./runtime": { 37 | "import": "./dist/runtime.mjs", 38 | "require": "./dist/runtime.js", 39 | "types": "./dist/runtime.d.ts" 40 | }, 41 | "./macros": { 42 | "import": "./dist/macros.mjs", 43 | "require": "./dist/macros.js", 44 | "types": "./dist/macros.d.ts" 45 | } 46 | }, 47 | "author": "Raven Satir", 48 | "license": "MIT" 49 | } 50 | -------------------------------------------------------------------------------- /packages/factory/rollup.config.mjs: -------------------------------------------------------------------------------- 1 | import { copyFileSync, rmSync } from "fs" 2 | 3 | import { defineConfig } from "rollup" 4 | import dts from "rollup-plugin-dts" 5 | import typescript from "rollup-plugin-typescript2" 6 | 7 | const external = [ 8 | "@macro-plugin/core", 9 | "@swc/core", 10 | "fs", 11 | "path", 12 | "./runtime", 13 | "./macros" 14 | ] 15 | 16 | const ts = typescript({ 17 | tsconfigOverride: { 18 | include: ["packages/**/src"] 19 | } 20 | }) 21 | 22 | /** 23 | * @returns {import("rollup").OutputOptions[]} 24 | */ 25 | function createOutput (index = "index") { 26 | return [ 27 | { 28 | file: `dist/${index}.js`, 29 | format: "cjs", 30 | }, 31 | { 32 | file: `dist/${index}.mjs`, 33 | format: "es", 34 | } 35 | ] 36 | } 37 | 38 | export default defineConfig([ 39 | { 40 | input: "./src/runtime.ts", 41 | output: createOutput("runtime"), 42 | plugins: [ 43 | { 44 | name: "rmDist", 45 | buildStart () { 46 | rmSync("./dist", { recursive: true, force: true }) 47 | } 48 | }, 49 | ts, 50 | ], 51 | external 52 | }, 53 | { 54 | input: "./src/macros.ts", 55 | output: createOutput("macros"), 56 | plugins: [ 57 | ts, 58 | ], 59 | external 60 | }, 61 | { 62 | input: "./src/index.ts", 63 | output: createOutput(), 64 | plugins: [ 65 | ts, 66 | ], 67 | external 68 | }, 69 | { 70 | input: "./dist/packages/factory/src/index.d.ts", 71 | output: [{ 72 | file: "dist/index.d.ts", 73 | format: "es" 74 | }], 75 | plugins: [ 76 | dts({ respectExternal: true }), 77 | { 78 | name: "buildTypes", 79 | buildStart () { 80 | ["runtime", "macros"].map(i => copyFileSync(`./dist/packages/factory/src/${i}.d.ts`, `./dist/${i}.d.ts`)) 81 | }, 82 | buildEnd () { 83 | rmSync("./dist/packages", { recursive: true, force: true }) 84 | } 85 | } 86 | ], 87 | external 88 | } 89 | ]) 90 | -------------------------------------------------------------------------------- /packages/factory/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./runtime" 2 | export * from "./macros" 3 | -------------------------------------------------------------------------------- /packages/factory/tests/__snapshots__/runtime.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`$Argument macro call 1`] = ` 4 | { 5 | "expression": { 6 | "optional": false, 7 | "span": { 8 | "ctxt": 0, 9 | "end": 0, 10 | "start": 0, 11 | }, 12 | "type": "Identifier", 13 | "value": "ref", 14 | }, 15 | "spread": undefined, 16 | } 17 | `; 18 | 19 | exports[`$CallExpression macro call 1`] = ` 20 | { 21 | "arguments": [], 22 | "callee": { 23 | "optional": false, 24 | "span": { 25 | "ctxt": 0, 26 | "end": 0, 27 | "start": 0, 28 | }, 29 | "type": "Identifier", 30 | "value": "ref", 31 | }, 32 | "span": { 33 | "ctxt": 0, 34 | "end": 0, 35 | "start": 0, 36 | }, 37 | "type": "CallExpression", 38 | "typeArguments": undefined, 39 | } 40 | `; 41 | 42 | exports[`$CallExpression macro call 2`] = ` 43 | { 44 | "arguments": [ 45 | { 46 | "expression": { 47 | "raw": undefined, 48 | "span": { 49 | "ctxt": 0, 50 | "end": 0, 51 | "start": 0, 52 | }, 53 | "type": "StringLiteral", 54 | "value": "hello", 55 | }, 56 | "spread": undefined, 57 | }, 58 | ], 59 | "callee": { 60 | "optional": false, 61 | "span": { 62 | "ctxt": 0, 63 | "end": 0, 64 | "start": 0, 65 | }, 66 | "type": "Identifier", 67 | "value": "ref", 68 | }, 69 | "span": { 70 | "ctxt": 0, 71 | "end": 0, 72 | "start": 0, 73 | }, 74 | "type": "CallExpression", 75 | "typeArguments": undefined, 76 | } 77 | `; 78 | -------------------------------------------------------------------------------- /packages/factory/tests/macros.test.ts: -------------------------------------------------------------------------------- 1 | import { $Argument, $CallExpression, $Identifier, $Import, $Span, $StringLiteral } from "../src" 2 | import { createSwcPlugin, transform } from "@macro-plugin/core" 3 | import { parseSync, transformSync as swcTransform } from "@swc/core" 4 | 5 | const spanRegex = /(?<="(start|end)":)\s*\d+/g 6 | 7 | test("$Identifier macro transform", () => { 8 | const code = ` 9 | function id() { 10 | const a = $Identifier("value") 11 | const b = $Identifier("value", false) 12 | const c = $Identifier("value", true) 13 | const d = "value" 14 | const e = $Identifier(d, true) 15 | } 16 | ` 17 | 18 | expect(transform(code, { macros: [$Identifier] }).code).toMatchSnapshot() 19 | }) 20 | 21 | test("$StringLiteral macro transform", () => { 22 | const code = ` 23 | const a = $StringLiteral("hello") 24 | const v = "world" 25 | const b = $StringLiteral(v) 26 | ` 27 | 28 | expect(transform(code, { macros: [$StringLiteral] }).code).toMatchSnapshot() 29 | }) 30 | 31 | test("$Argument macro transform", () => { 32 | const code = ` 33 | const a = $Argument($Identifier("ref")) 34 | const b = $Argument($Identifier("list"), $Span()) 35 | ` 36 | 37 | expect(transform(code, { macros: [$Identifier, $Argument, $Span] }).code).toMatchSnapshot() 38 | }) 39 | 40 | test("$CallExpression macro transform", () => { 41 | const code = ` 42 | const a = $CallExpression($Identifier("ref")) 43 | const b = $CallExpression($Identifier("ref"), [ 44 | $Argument($StringLiteral("hello")), 45 | ]) 46 | ` 47 | 48 | expect(transform(code, { macros: [$Identifier, $CallExpression, $Argument, $StringLiteral] }).code).toMatchSnapshot() 49 | }) 50 | 51 | test("ctxt shouldn't rename variable name", () => { 52 | const code = ` 53 | createMacro({ 54 | MemberExpression(ast) { 55 | if (ast.object.type === "Identifier") { 56 | ast.object = $CallExpression($Identifier("$$ptagWrap"), [ 57 | $Argument(ast.object), 58 | ]) 59 | } 60 | } 61 | }) 62 | ` 63 | const plugin = createSwcPlugin({ macros: [$Identifier, $CallExpression, $Argument] }) 64 | const program = plugin(parseSync(code, { syntax: "typescript", tsx: true })) 65 | 66 | expect(swcTransform(program, { jsc: { parser: { syntax: "typescript", tsx: true } } }).code.replace(spanRegex, "0")).toMatchSnapshot() 67 | }) 68 | 69 | test("ctxt shouldn't rename variable name in multiple block", () => { 70 | const code = ` 71 | createMacro({ 72 | MemberExpression(ast) { 73 | if (ast.object.type === "Identifier") { 74 | ast.object = $CallExpression($Identifier("$$ptagWrap"), [ 75 | $Argument(ast.object), 76 | ]) 77 | } 78 | }, 79 | CallExpression(ast) { 80 | if (ast.callee.type === "Identifier") { 81 | ast.object = $CallExpression($Identifier("$$ptagWrap"), [ 82 | $Argument(ast.callee), 83 | ]) 84 | } 85 | } 86 | }) 87 | ` 88 | const plugin = createSwcPlugin({ macros: [$Identifier, $CallExpression, $Argument] }) 89 | const program = plugin(parseSync(code, { syntax: "typescript", tsx: true })) 90 | 91 | expect(swcTransform(program, { jsc: { parser: { syntax: "typescript", tsx: true } } }).code.replace(spanRegex, "0")).toMatchSnapshot() 92 | }) 93 | 94 | test("optional should works", () => { 95 | const code = ` 96 | const a = $Span(3, 1, 2) 97 | const b = $Span(undefined, 1) 98 | const d = $Span(null, 2, 5) 99 | const e = $Span() 100 | ` 101 | 102 | expect(transform(code, { macros: [$Span] }).code).toMatchSnapshot() 103 | }) 104 | 105 | test("overwite span should works", () => { 106 | const code = ` 107 | $Import() 108 | $Import(undefined) 109 | $Import(null) 110 | $Import($Span(0, 1, 2)) 111 | const s = $Span(3, 4, 0) 112 | $Import(s) 113 | ` 114 | expect(transform(code, { macros: [$Import, $Span] }).code).toMatchSnapshot() 115 | }) 116 | -------------------------------------------------------------------------------- /packages/factory/tests/runtime.test.ts: -------------------------------------------------------------------------------- 1 | import { $Argument, $CallExpression, $Identifier, $StringLiteral } from "../src" 2 | 3 | test("$Identifier macro call", () => { 4 | const id = $Identifier("value") 5 | 6 | expect(id.optional).toBe(false) 7 | expect(id.type).toBe("Identifier") 8 | }) 9 | 10 | test("$StringLiteral macro call", () => { 11 | const str = $StringLiteral("hello") 12 | expect(str.value).toBe("hello") 13 | expect(str.raw).toBeUndefined() 14 | }) 15 | 16 | test("$Argument macro call", () => { 17 | const a = $Argument($Identifier("ref")) 18 | 19 | expect(a).toMatchSnapshot() 20 | }) 21 | 22 | test("$CallExpression macro call", () => { 23 | const a = $CallExpression($Identifier("ref")) 24 | const b = $CallExpression($Identifier("ref"), [ 25 | $Argument($StringLiteral("hello")), 26 | ]) 27 | 28 | expect(a).toMatchSnapshot() 29 | expect(b).toMatchSnapshot() 30 | }) 31 | -------------------------------------------------------------------------------- /packages/jest/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @macro-plugin/jest 2 | 3 | ## 1.1.2 4 | 5 | ### Patch Changes 6 | 7 | - Updated dependencies [[`8c94045`](https://github.com/macro-plugin/macros/commit/8c9404545d207b708ed433328bd383488a3ed0d4), [`b45063f`](https://github.com/macro-plugin/macros/commit/b45063ff784e513380f43bf8425c4f72eaa5c0b4)]: 8 | - @macro-plugin/core@1.2.0 9 | - @macro-plugin/shared@1.2.1 10 | 11 | ## 1.1.1 12 | 13 | ### Patch Changes 14 | 15 | - Updated dependencies [[`c398ad6`](https://github.com/macro-plugin/macros/commit/c398ad61bd1aa9b79c1a98f7e811323f996f5658), [`e3ce376`](https://github.com/macro-plugin/macros/commit/e3ce37696e0a21bdddb56804f7dbcfa904f5fd35), [`b1d3bff`](https://github.com/macro-plugin/macros/commit/b1d3bffcac4ef25930bd7ee4409664f6fb00fb06)]: 16 | - @macro-plugin/shared@1.2.0 17 | - @macro-plugin/core@1.1.4 18 | 19 | ## 1.1.0 20 | 21 | ### Minor Changes 22 | 23 | - [#27](https://github.com/macro-plugin/macros/pull/27) [`8b1c4ad`](https://github.com/macro-plugin/macros/commit/8b1c4adc1a5512d74eaf268d7f8c1ab46f772930) Thanks [@voorjaar](https://github.com/voorjaar)! - refactor: use plugin with swc parse api 24 | 25 | ### Patch Changes 26 | 27 | - Updated dependencies []: 28 | - @macro-plugin/core@1.1.3 29 | - @macro-plugin/shared@1.1.1 30 | 31 | ## 1.0.6 32 | 33 | ### Patch Changes 34 | 35 | - [#23](https://github.com/macro-plugin/macros/pull/23) [`e9b008c`](https://github.com/macro-plugin/macros/commit/e9b008c5089fcdf453cd16e7037fea9432a1f187) Thanks [@voorjaar](https://github.com/voorjaar)! - refactor: move shared to dependencies 36 | 37 | - Updated dependencies [[`4bd75d8`](https://github.com/macro-plugin/macros/commit/4bd75d8f5f59bc3c7befcc7178a9ba87ac9fad8a), [`2dd180d`](https://github.com/macro-plugin/macros/commit/2dd180d67643a63dd3abe706fe393f8da431a5f5), [`0813759`](https://github.com/macro-plugin/macros/commit/081375946893092cdd9280aa5c20333a722e5683), [`294f675`](https://github.com/macro-plugin/macros/commit/294f67574c5ff168bdeb0a499ea4ab2fd57579cf)]: 38 | - @macro-plugin/shared@1.1.0 39 | - @macro-plugin/core@1.1.2 40 | 41 | ## 1.0.5 42 | 43 | ### Patch Changes 44 | 45 | - Updated dependencies [[`b4be79b`](https://github.com/macro-plugin/macros/commit/b4be79be09e8790b95c6a2e9b07dde4ba3822f39), [`df8dcc0`](https://github.com/macro-plugin/macros/commit/df8dcc0ab7f3e09f1157c5c2a7cda4a7f5367991)]: 46 | - @macro-plugin/core@1.1.1 47 | 48 | ## 1.0.4 49 | 50 | ### Patch Changes 51 | 52 | - Updated dependencies [[`4155bb4`](https://github.com/macro-plugin/macros/commit/4155bb4de7968a83e62203411bceae6b0602637f), [`6b25910`](https://github.com/macro-plugin/macros/commit/6b25910567e910b7c71c79646f8569a2f3927be6), [`8dd4939`](https://github.com/macro-plugin/macros/commit/8dd493997931d8d91a82ffb1785927d425c17c61), [`14efcb2`](https://github.com/macro-plugin/macros/commit/14efcb2c6461ab3f5d78e0599ec74b422085ce1d), [`7787022`](https://github.com/macro-plugin/macros/commit/7787022f657b7a79cb18a1e8ba947ae2eaeb682e), [`a17b055`](https://github.com/macro-plugin/macros/commit/a17b055d356c285b394add56192c80077ebde2c2)]: 53 | - @macro-plugin/core@1.1.0 54 | 55 | ## 1.0.3 56 | 57 | ### Patch Changes 58 | 59 | - Updated dependencies [[`07961a0`](https://github.com/macro-plugin/macros/commit/07961a03b6e82080a2b8c8ab2626c187c34f912e), [`f1e40ea`](https://github.com/macro-plugin/macros/commit/f1e40ead32636d4f2d43c442e70cc208e2d43b28), [`556ca2d`](https://github.com/macro-plugin/macros/commit/556ca2d9addaf36ac84da8c8ea7b5bc465e174b7)]: 60 | - @macro-plugin/core@1.0.3 61 | 62 | ## 1.0.2 63 | 64 | ### Patch Changes 65 | 66 | - [#9](https://github.com/macro-plugin/macros/pull/9) [`2c64787`](https://github.com/macro-plugin/macros/commit/2c647875182c5fc6ca41c9e72587a08307ba90ec) Thanks [@voorjaar](https://github.com/voorjaar)! - chore: upgrade to swc 1.3.53 67 | 68 | - Updated dependencies [[`2c64787`](https://github.com/macro-plugin/macros/commit/2c647875182c5fc6ca41c9e72587a08307ba90ec)]: 69 | - @macro-plugin/core@1.0.2 70 | 71 | ## 1.0.1 72 | 73 | ### Patch Changes 74 | 75 | - 98425cf: build: no longer publish iife 76 | - Updated dependencies [98425cf] 77 | - @macro-plugin/core@1.0.1 78 | -------------------------------------------------------------------------------- /packages/jest/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Raven Satir 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 | -------------------------------------------------------------------------------- /packages/jest/README.md: -------------------------------------------------------------------------------- 1 | # @macro-plugin/jest 2 | 3 | [Macro Plugin](https://github.com/macro-plugin) integration for jest. It supports transform macros and typescript and also jsx. 4 | 5 | ## Installation 6 | 7 | ```sh 8 | # if you use npm 9 | npm i -D @macro-plugin/jest 10 | # if you use pnpm 11 | pnpm i -D @macro-plugin/jest 12 | # if you use yarn 13 | yarn add -D @macro-plugin/jest 14 | ``` 15 | 16 | ## Usage 17 | 18 | `jest.config.js`: 19 | 20 | ```js 21 | module.exports = { 22 | transform: { 23 | '^.+\\.(t|j)sx?$': '@macro-plugin/jest', 24 | }, 25 | } 26 | ``` 27 | 28 | It will load the configuration from `macros.config.js` or `macros.config.ts` by default. You can also customize it: 29 | 30 | ```js 31 | const fs = require('fs') 32 | const config = require('./macros.config.js') 33 | 34 | module.exports = { 35 | transform: { 36 | '^.+\\.(t|j)sx?$': ['@macro-plugin/jest', { ...config, /* custom configuration in Jest */ }], 37 | }, 38 | } 39 | ``` 40 | 41 | `macros.config.ts`: 42 | 43 | ```js 44 | import { defineConfig } from "@macro-plugin/core" 45 | 46 | export default defineConfig({ 47 | macros: [], 48 | emitDts: true, 49 | jsc: { 50 | parser: { 51 | syntax: "typescript" 52 | }, 53 | target: "esnext", 54 | }, 55 | }) 56 | ``` 57 | 58 | Or with commonjs 59 | 60 | `macros.config.js` 61 | 62 | ```js 63 | /** @type {import("@macro-plugin/core").Config} */ 64 | module.exports = { 65 | macros: [], 66 | emitDts: true, 67 | jsc: { 68 | parser: { 69 | syntax: "typescript" 70 | }, 71 | target: "esnext", 72 | }, 73 | } 74 | ``` 75 | 76 | ## License 77 | 78 | MIT 79 | 80 | [MacroPlugin]: https://github.com/macro-plugin 81 | -------------------------------------------------------------------------------- /packages/jest/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@macro-plugin/jest", 3 | "version": "1.1.2", 4 | "description": "Macro Plugins integration for jest", 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "files": [ 8 | "dist", 9 | "CHANGELOG.md" 10 | ], 11 | "scripts": { 12 | "build": "rollup -c" 13 | }, 14 | "keywords": [ 15 | "jest", 16 | "macro", 17 | "macros", 18 | "macro-plugin" 19 | ], 20 | "homepage": "https://github.com/macro-plugin/macros/tree/main/packages/jest", 21 | "repository": { 22 | "type": "git", 23 | "url": "https://github.com/macro-plugin/macros.git" 24 | }, 25 | "dependencies": { 26 | "@macro-plugin/core": "1.2.0", 27 | "@macro-plugin/shared": "1.2.1" 28 | }, 29 | "devDependencies": { 30 | "@jest/create-cache-key-function": "^27.4.2", 31 | "@jest/transform": "^27.5.1", 32 | "jest": "^27.4.4", 33 | "pirates": "^4.0.5" 34 | }, 35 | "exports": { 36 | "./package.json": "./package.json", 37 | ".": { 38 | "require": "./dist/index.js", 39 | "types": "./dist/index.d.ts" 40 | } 41 | }, 42 | "author": "Raven Satir", 43 | "license": "MIT" 44 | } 45 | -------------------------------------------------------------------------------- /packages/jest/rollup.config.mjs: -------------------------------------------------------------------------------- 1 | import commonjs from "@rollup/plugin-commonjs" 2 | import { defineConfig } from "rollup" 3 | import json from "@rollup/plugin-json" 4 | import { nodeResolve } from "@rollup/plugin-node-resolve" 5 | import { rmSync } from "fs" 6 | import typescript from "rollup-plugin-typescript2" 7 | 8 | export default defineConfig([ 9 | { 10 | input: "./src/index.ts", 11 | output: { 12 | file: "dist/index.js", 13 | format: "cjs", 14 | }, 15 | plugins: [ 16 | { 17 | name: "del", 18 | transform (code, id) { 19 | if (id.endsWith(".cts") || id.endsWith(".mts")) return "" 20 | }, 21 | buildStart () { 22 | rmSync("./dist", { recursive: true, force: true }) 23 | }, 24 | closeBundle () { 25 | rmSync("./dist/packages", { recursive: true, force: true }) 26 | } 27 | }, 28 | json(), 29 | commonjs(), 30 | nodeResolve(), 31 | typescript({ 32 | tsconfigOverride: { 33 | include: ["packages/**/src"] 34 | } 35 | }), 36 | ], 37 | external: [ 38 | "@swc/core", 39 | "@macro-plugin/core", 40 | "@macro-plugin/shared" 41 | ] 42 | } 43 | ]) 44 | -------------------------------------------------------------------------------- /packages/qwik/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @macro-plugin/qwik 2 | 3 | ## 1.1.0 4 | 5 | ### Minor Changes 6 | 7 | - [#33](https://github.com/macro-plugin/macros/pull/33) [`b45063f`](https://github.com/macro-plugin/macros/commit/b45063ff784e513380f43bf8425c4f72eaa5c0b4) Thanks [@voorjaar](https://github.com/voorjaar)! - refactor: rename span to dummySpan 8 | 9 | ### Patch Changes 10 | 11 | - Updated dependencies [[`8c94045`](https://github.com/macro-plugin/macros/commit/8c9404545d207b708ed433328bd383488a3ed0d4), [`b45063f`](https://github.com/macro-plugin/macros/commit/b45063ff784e513380f43bf8425c4f72eaa5c0b4)]: 12 | - @macro-plugin/core@1.2.0 13 | 14 | ## 1.0.8 15 | 16 | ### Patch Changes 17 | 18 | - Updated dependencies [[`e3ce376`](https://github.com/macro-plugin/macros/commit/e3ce37696e0a21bdddb56804f7dbcfa904f5fd35)]: 19 | - @macro-plugin/core@1.1.4 20 | 21 | ## 1.0.7 22 | 23 | ### Patch Changes 24 | 25 | - Updated dependencies []: 26 | - @macro-plugin/core@1.1.3 27 | 28 | ## 1.0.6 29 | 30 | ### Patch Changes 31 | 32 | - Updated dependencies [[`294f675`](https://github.com/macro-plugin/macros/commit/294f67574c5ff168bdeb0a499ea4ab2fd57579cf)]: 33 | - @macro-plugin/core@1.1.2 34 | 35 | ## 1.0.5 36 | 37 | ### Patch Changes 38 | 39 | - Updated dependencies [[`b4be79b`](https://github.com/macro-plugin/macros/commit/b4be79be09e8790b95c6a2e9b07dde4ba3822f39), [`df8dcc0`](https://github.com/macro-plugin/macros/commit/df8dcc0ab7f3e09f1157c5c2a7cda4a7f5367991)]: 40 | - @macro-plugin/core@1.1.1 41 | 42 | ## 1.0.4 43 | 44 | ### Patch Changes 45 | 46 | - Updated dependencies [[`4155bb4`](https://github.com/macro-plugin/macros/commit/4155bb4de7968a83e62203411bceae6b0602637f), [`6b25910`](https://github.com/macro-plugin/macros/commit/6b25910567e910b7c71c79646f8569a2f3927be6), [`8dd4939`](https://github.com/macro-plugin/macros/commit/8dd493997931d8d91a82ffb1785927d425c17c61), [`14efcb2`](https://github.com/macro-plugin/macros/commit/14efcb2c6461ab3f5d78e0599ec74b422085ce1d), [`7787022`](https://github.com/macro-plugin/macros/commit/7787022f657b7a79cb18a1e8ba947ae2eaeb682e), [`a17b055`](https://github.com/macro-plugin/macros/commit/a17b055d356c285b394add56192c80077ebde2c2)]: 47 | - @macro-plugin/core@1.1.0 48 | 49 | ## 1.0.3 50 | 51 | ### Patch Changes 52 | 53 | - Updated dependencies [[`07961a0`](https://github.com/macro-plugin/macros/commit/07961a03b6e82080a2b8c8ab2626c187c34f912e), [`f1e40ea`](https://github.com/macro-plugin/macros/commit/f1e40ead32636d4f2d43c442e70cc208e2d43b28), [`556ca2d`](https://github.com/macro-plugin/macros/commit/556ca2d9addaf36ac84da8c8ea7b5bc465e174b7)]: 54 | - @macro-plugin/core@1.0.3 55 | 56 | ## 1.0.2 57 | 58 | ### Patch Changes 59 | 60 | - [#9](https://github.com/macro-plugin/macros/pull/9) [`2c64787`](https://github.com/macro-plugin/macros/commit/2c647875182c5fc6ca41c9e72587a08307ba90ec) Thanks [@voorjaar](https://github.com/voorjaar)! - chore: upgrade to swc 1.3.53 61 | 62 | - Updated dependencies [[`2c64787`](https://github.com/macro-plugin/macros/commit/2c647875182c5fc6ca41c9e72587a08307ba90ec)]: 63 | - @macro-plugin/core@1.0.2 64 | 65 | ## 1.0.1 66 | 67 | ### Patch Changes 68 | 69 | - 98425cf: build: no longer publish iife 70 | - Updated dependencies [98425cf] 71 | - @macro-plugin/core@1.0.1 72 | -------------------------------------------------------------------------------- /packages/qwik/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Raven Satir 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 | -------------------------------------------------------------------------------- /packages/qwik/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@macro-plugin/qwik", 3 | "version": "1.1.0", 4 | "description": "A simpler way of creating components for qwik by using macros", 5 | "main": "dist/index.js", 6 | "module": "dist/index.mjs", 7 | "types": "dist/index.d.ts", 8 | "files": [ 9 | "dist", 10 | "CHANGELOG.md" 11 | ], 12 | "keywords": [ 13 | "qwik", 14 | "qwikjs", 15 | "macro", 16 | "macros", 17 | "macro-plugin" 18 | ], 19 | "scripts": { 20 | "build": "rollup -c ../../rollup.config.mjs" 21 | }, 22 | "homepage": "https://github.com/macro-plugin/macros/tree/main/packages/qwik", 23 | "repository": { 24 | "type": "git", 25 | "url": "https://github.com/macro-plugin/macros.git" 26 | }, 27 | "dependencies": { 28 | "@macro-plugin/core": "1.2.0" 29 | }, 30 | "exports": { 31 | "./package.json": "./package.json", 32 | ".": { 33 | "import": "./dist/index.mjs", 34 | "require": "./dist/index.js", 35 | "types": "./dist/index.d.ts" 36 | } 37 | }, 38 | "author": "Raven Satir", 39 | "license": "MIT" 40 | } 41 | -------------------------------------------------------------------------------- /packages/qwik/src/css.ts: -------------------------------------------------------------------------------- 1 | import { CallExpression, ExpressionStatement } from "@swc/core" 2 | import { createLabeledMacro, dummySpan } from "@macro-plugin/core" 3 | 4 | export const css = createLabeledMacro("css", function (stmt) { 5 | if (stmt.type === "ExpressionStatement") { 6 | const specifier = this.get("QwikScoped", false) ? "useStyleScoped$" : "useStyle$" 7 | 8 | this.import(specifier, "@builder.io/qwik") 9 | 10 | stmt.expression = { 11 | type: "CallExpression", 12 | span: dummySpan, 13 | callee: { 14 | type: "Identifier", 15 | span: dummySpan, 16 | value: specifier, 17 | optional: false 18 | }, 19 | arguments: [ 20 | { 21 | expression: stmt.expression 22 | } 23 | ], 24 | } as CallExpression 25 | 26 | return stmt 27 | } else { 28 | throw new Error("this macro only accept an Expression") 29 | } 30 | }) 31 | 32 | export const link = createLabeledMacro("link", function (stmt) { 33 | if (stmt.type !== "ExpressionStatement") return 34 | let name: string 35 | let linkCount = this.get("QwikLinkCount", 0) 36 | const scoped = this.get("QwikScoped", false) 37 | const specifier = scoped ? "useStyleScoped$" : "useStyles$" 38 | const links: string[] = [] 39 | if (stmt.expression.type === "StringLiteral") { 40 | name = "__link" + linkCount 41 | links.push(name) 42 | this.import(name, stmt.expression.value, true) 43 | linkCount += 1 44 | } else if (stmt.expression.type === "ArrayExpression") { 45 | for (const i of stmt.expression.elements) { 46 | if (i?.expression.type === "StringLiteral") { 47 | name = "__link" + linkCount 48 | links.push(name) 49 | this.import(name, i.expression.value, true) 50 | linkCount += 1 51 | } else { 52 | throw new Error("Expect a StringLiteral") 53 | } 54 | } 55 | } else { 56 | throw new Error("Only support StringLiteral or ArrayExpression") 57 | } 58 | this.set("QwikLinkCount", linkCount) 59 | this.import(specifier, "@builder.io/qwik") 60 | return links.map(i => ({ 61 | type: "ExpressionStatement", 62 | span: dummySpan, 63 | expression: { 64 | type: "CallExpression", 65 | span: dummySpan, 66 | callee: { 67 | type: "Identifier", 68 | span: dummySpan, 69 | value: specifier, 70 | optional: false 71 | }, 72 | arguments: [ 73 | { 74 | expression: { 75 | type: "Identifier", 76 | span: dummySpan, 77 | value: i, 78 | optional: false 79 | } 80 | } 81 | ], 82 | } 83 | } as ExpressionStatement)) 84 | }) 85 | 86 | export const scoped = createLabeledMacro("scoped", { 87 | enter (stmt) { 88 | if (stmt.type === "BlockStatement") { 89 | this.set("QwikScoped", true) 90 | } else { 91 | throw new Error("Only accept BlockStatement in scoped macro.") 92 | } 93 | }, 94 | leave (stmt) { 95 | if (stmt.type === "BlockStatement") { 96 | this.replace(stmt.stmts) 97 | this.set("QwikScoped", false) 98 | } 99 | } 100 | }) 101 | -------------------------------------------------------------------------------- /packages/qwik/src/index.ts: -------------------------------------------------------------------------------- 1 | export { qwik } from "./qwik" 2 | export { task, vtask } from "./task" 3 | export { resource } from "./resource" 4 | export { store } from "./store" 5 | export { signal } from "./signal" 6 | export { events } from "./events" 7 | export { computed } from "./computed" 8 | export { link, css, scoped } from "./css" 9 | -------------------------------------------------------------------------------- /packages/qwik/src/qwik.ts: -------------------------------------------------------------------------------- 1 | import { ArrowFunctionExpression, CallExpression, FunctionDeclaration, FunctionExpression, LabeledStatement, VariableDeclaration } from "@swc/core" 2 | import { WalkContext, createMacro, dummySpan } from "@macro-plugin/core" 3 | 4 | function handleFunc (this: WalkContext, ast: FunctionDeclaration | FunctionExpression | ArrowFunctionExpression) { 5 | let label 6 | if (!ast.body || ast.body.type !== "BlockStatement") return 7 | for (let i = 0; i < ast.body.stmts.length; i++) { 8 | if (ast.body.stmts[i].type === "LabeledStatement") { 9 | label = ast.body.stmts[i] as LabeledStatement 10 | if (label.label.value === "qwik") { 11 | if (label.body.type === "ExpressionStatement" && label.body.expression.type === "BooleanLiteral") { 12 | ast.body.stmts = ast.body.stmts.filter((_, index) => index !== i) 13 | const isDecl = "identifier" in ast && ast.identifier != null 14 | 15 | if (label.body.expression.value) { 16 | this.import("component$", "@builder.io/qwik") 17 | 18 | const init = { 19 | type: "CallExpression", 20 | span: dummySpan, 21 | callee: { 22 | type: "Identifier", 23 | span: dummySpan, 24 | value: "component$", 25 | optional: false 26 | }, 27 | arguments: [ 28 | { 29 | expression: isDecl 30 | ? { 31 | type: "ArrowFunctionExpression", 32 | span: dummySpan, 33 | params: ast.params.map(i => i.pat), 34 | body: ast.body, 35 | async: false, 36 | generator: false, 37 | } 38 | : ast 39 | } 40 | ], 41 | } as CallExpression 42 | 43 | if (!isDecl) return init 44 | 45 | return { 46 | type: "VariableDeclaration", 47 | span: dummySpan, 48 | kind: "const", 49 | declare: false, 50 | declarations: [ 51 | { 52 | type: "VariableDeclarator", 53 | span: dummySpan, 54 | id: ast.identifier, 55 | init, 56 | definite: false 57 | } 58 | ] 59 | } as VariableDeclaration 60 | } 61 | } else { 62 | throw new Error("Expect an boolean in qwik macro.") 63 | } 64 | } 65 | } 66 | } 67 | } 68 | 69 | export const qwik = createMacro({ 70 | FunctionDeclaration (ast) { 71 | return handleFunc.apply(this, [ast]) 72 | }, 73 | FunctionExpression (ast) { 74 | return handleFunc.apply(this, [ast]) 75 | }, 76 | ArrowFunctionExpression (ast) { 77 | return handleFunc.apply(this, [ast]) 78 | } 79 | }) 80 | -------------------------------------------------------------------------------- /packages/qwik/src/resource.ts: -------------------------------------------------------------------------------- 1 | import { Identifier, Statement, VariableDeclaration } from "@swc/core" 2 | import { createLabeledMacro, dummySpan } from "@macro-plugin/core" 3 | 4 | const varToReturn = (body: Statement[]) => { 5 | let ident: Identifier | undefined 6 | body = body.map(i => { 7 | if (i.type === "VariableDeclaration" && i.kind === "var") { 8 | if (i.declarations[0].id.type === "Identifier") { 9 | ident = i.declarations[0].id 10 | } else { 11 | throw new Error("Expect an Identifier") 12 | } 13 | return { 14 | type: "ReturnStatement", 15 | argument: i.declarations[0].init, 16 | span: dummySpan 17 | } 18 | } 19 | return i 20 | }) 21 | 22 | return [ident, body] as [Identifier, Statement[]] 23 | } 24 | 25 | export const resource = createLabeledMacro("resource", function (stmt) { 26 | this.import("useResource$", "@builder.io/qwik") 27 | if (stmt.type === "BlockStatement") { 28 | const [id, stmts] = varToReturn(stmt.stmts) 29 | 30 | return { 31 | type: "VariableDeclaration", 32 | declarations: [ 33 | { 34 | type: "VariableDeclarator", 35 | definite: false, 36 | span: dummySpan, 37 | id, 38 | init: { 39 | type: "CallExpression", 40 | callee: { 41 | type: "Identifier", 42 | optional: false, 43 | value: "useResource$", 44 | span: dummySpan 45 | }, 46 | span: dummySpan, 47 | arguments: [ 48 | { 49 | expression: { 50 | type: "ArrowFunctionExpression", 51 | generator: false, 52 | async: false, 53 | params: [], 54 | span: dummySpan, 55 | body: { 56 | type: "BlockStatement", 57 | stmts, 58 | span: dummySpan, 59 | } 60 | } 61 | } 62 | ] 63 | } 64 | } 65 | ], 66 | span: dummySpan, 67 | declare: false, 68 | kind: "const" 69 | } as VariableDeclaration 70 | } else if (stmt.type === "ExpressionStatement" && stmt.expression.type === "ArrowFunctionExpression") { 71 | let id, stmts 72 | 73 | if (stmt.expression.body.type === "BlockStatement") { 74 | [id, stmts] = varToReturn(stmt.expression.body.stmts) 75 | stmt.expression.body.stmts = stmts 76 | } else { 77 | throw new Error("expect an arrow block inside resource.") 78 | } 79 | 80 | return { 81 | type: "VariableDeclaration", 82 | declarations: [ 83 | { 84 | type: "VariableDeclarator", 85 | definite: false, 86 | span: dummySpan, 87 | id, 88 | init: { 89 | type: "CallExpression", 90 | callee: { 91 | type: "Identifier", 92 | value: "useResource$", 93 | span: dummySpan, 94 | optional: false 95 | }, 96 | arguments: [ 97 | { 98 | expression: stmt.expression 99 | } 100 | ], 101 | span: dummySpan, 102 | } 103 | } 104 | ], 105 | kind: "const", 106 | span: dummySpan, 107 | declare: false, 108 | } as VariableDeclaration 109 | } else { 110 | throw new Error("this macro only accept a ArrowFunction or BlockStatement") 111 | } 112 | }) 113 | -------------------------------------------------------------------------------- /packages/qwik/src/signal.ts: -------------------------------------------------------------------------------- 1 | import { MemberExpression, Node, VariableDeclaration } from "@swc/core" 2 | import { createMacro, dummySpan, markedNode } from "@macro-plugin/core" 3 | 4 | export const signal = createMacro({ 5 | LabeledStatement (ast) { 6 | if (ast.body.type !== "BlockStatement" || ast.label.value !== "signal") return 7 | 8 | const signals: Record = {} 9 | 10 | let name 11 | for (const i of ast.body.stmts) { 12 | if (i.type === "VariableDeclaration" && i.kind === "var") { 13 | for (const d of i.declarations) { 14 | if (d.id.type === "Identifier") { 15 | name = d.id.value 16 | signals[name] = { value: d.init } 17 | } else { 18 | throw new Error("Expect Identifier in signal") 19 | } 20 | } 21 | } else { 22 | throw new Error("Expect a `var` kind VariableDeclaration node in signal block") 23 | } 24 | } 25 | 26 | if (Object.keys(signals).length > 0) { 27 | this.import("useSignal", "@builder.io/qwik") 28 | return Object.entries(signals).map(([k, v]) => ({ 29 | type: "VariableDeclaration", 30 | kind: "const", 31 | declare: false, 32 | declarations: [ 33 | { 34 | type: "VariableDeclarator", 35 | id: markedNode("qwikSignal", { 36 | type: "Identifier", 37 | value: k, 38 | optional: false, 39 | span: dummySpan 40 | }), 41 | init: { 42 | type: "CallExpression", 43 | callee: { 44 | type: "Identifier", 45 | value: "useSignal", 46 | optional: false, 47 | span: dummySpan 48 | }, 49 | arguments: [ 50 | { 51 | expression: v.value 52 | } 53 | ], 54 | span: dummySpan 55 | }, 56 | definite: false, 57 | span: dummySpan 58 | } 59 | ], 60 | span: dummySpan 61 | } as VariableDeclaration)) 62 | } 63 | }, 64 | Identifier (ast, parent) { 65 | if (parent?.type !== "VariableDeclarator" && this.track(ast.value)?.marker === "qwikSignal") { 66 | this.replace({ 67 | type: "MemberExpression", 68 | object: ast, 69 | property: { 70 | type: "Identifier", 71 | value: "value", 72 | optional: false, 73 | span: dummySpan 74 | }, 75 | span: dummySpan 76 | } as MemberExpression) 77 | this.skip() 78 | } 79 | } 80 | }) 81 | -------------------------------------------------------------------------------- /packages/qwik/src/store.ts: -------------------------------------------------------------------------------- 1 | import { Node, VariableDeclaration } from "@swc/core" 2 | import { createLabeledMacro, dummySpan, markedNode } from "@macro-plugin/core" 3 | 4 | export const store = createLabeledMacro("store", function (stmt) { 5 | if (stmt.type !== "BlockStatement") return 6 | 7 | const signals: Record = {} 8 | 9 | let name 10 | for (const i of stmt.stmts) { 11 | if (i.type === "VariableDeclaration" && i.kind === "var") { 12 | for (const d of i.declarations) { 13 | if (d.id.type === "Identifier") { 14 | name = d.id.value 15 | signals[name] = { value: d.init } 16 | } else { 17 | throw new Error("Expect Identifier in store") 18 | } 19 | } 20 | } else { 21 | throw new Error("Expect a `var` kind VariableDeclaration node in store block") 22 | } 23 | } 24 | 25 | if (Object.keys(signals).length > 0) { 26 | this.import("useStore", "@builder.io/qwik") 27 | return Object.entries(signals).map(([k, v]) => ({ 28 | type: "VariableDeclaration", 29 | kind: "const", 30 | declare: false, 31 | declarations: [ 32 | { 33 | type: "VariableDeclarator", 34 | id: markedNode("qwikStore", { 35 | type: "Identifier", 36 | value: k, 37 | optional: false, 38 | span: dummySpan 39 | }), 40 | init: { 41 | type: "CallExpression", 42 | callee: { 43 | type: "Identifier", 44 | value: "useStore", 45 | optional: false, 46 | span: dummySpan 47 | }, 48 | arguments: [ 49 | { 50 | expression: v.value 51 | } 52 | ], 53 | span: dummySpan 54 | }, 55 | definite: false, 56 | span: dummySpan 57 | } 58 | ], 59 | span: dummySpan 60 | } as VariableDeclaration)) 61 | } 62 | }) 63 | -------------------------------------------------------------------------------- /packages/qwik/src/task.ts: -------------------------------------------------------------------------------- 1 | import { createLabeledBlock } from "@macro-plugin/core" 2 | 3 | export const task = createLabeledBlock("task", "useTask$", "@builder.io/qwik") 4 | export const vtask = createLabeledBlock("vtask", "useVisibleTask$", "@builder.io/qwik", true) 5 | -------------------------------------------------------------------------------- /packages/qwik/tests/__snapshots__/computed.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`qwik computed 1`] = ` 4 | "import { useSignal } from "@builder.io/qwik"; 5 | import { useTask$ } from "@builder.io/qwik"; 6 | const a = useSignal(3); 7 | const b = useSignal(4); 8 | const count = useSignal(1); 9 | const doubleCount = useSignal(2 * count.value + count.value - a.value); 10 | useTask$(({ track })=>{ 11 | const __count = track(()=>count.value); 12 | const __a = track(()=>a.value); 13 | doubleCount.value = 2 * __count + __count - __a; 14 | }); 15 | " 16 | `; 17 | -------------------------------------------------------------------------------- /packages/qwik/tests/__snapshots__/css.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`qwik css link 1`] = ` 4 | "import { component$ } from "@builder.io/qwik"; 5 | import __link0 from "./code-block.css?inline"; 6 | import { useStyles$ } from "@builder.io/qwik"; 7 | export const CmpStyles = component$(()=>{ 8 | useStyles$(__link0); 9 | return Some text; 10 | }); 11 | " 12 | `; 13 | 14 | exports[`qwik css links 1`] = ` 15 | "import { component$ } from "@builder.io/qwik"; 16 | import __link0 from "./code-block.css?inline"; 17 | import __link1 from "./font-style.css?inline"; 18 | import { useStyles$ } from "@builder.io/qwik"; 19 | export const CmpStyles = component$(()=>{ 20 | useStyles$(__link0); 21 | useStyles$(__link1); 22 | return Some text; 23 | }); 24 | " 25 | `; 26 | 27 | exports[`qwik css string 1`] = ` 28 | "import { component$ } from "@builder.io/qwik"; 29 | import { useStyle$ } from "@builder.io/qwik"; 30 | export const CmpStyles = component$(()=>{ 31 | useStyle$(\` 32 | .my-text { 33 | color: red; 34 | } 35 | \`); 36 | return Some text; 37 | }); 38 | " 39 | `; 40 | 41 | exports[`qwik scoped css 1`] = ` 42 | "import { component$ } from "@builder.io/qwik"; 43 | import __link0 from "./code-block.css?inline"; 44 | import { useStyleScoped$ } from "@builder.io/qwik"; 45 | export const CmpStyles = component$(()=>{ 46 | useStyleScoped$(__link0); 47 | useStyleScoped$(\` 48 | .my-text { 49 | color: red; 50 | } 51 | \`); 52 | return Some text; 53 | }); 54 | " 55 | `; 56 | -------------------------------------------------------------------------------- /packages/qwik/tests/__snapshots__/events.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`useOn events 1`] = ` 4 | "import { component$ } from "@builder.io/qwik"; 5 | import { $ } from "@builder.io/qwik"; 6 | import { useOn } from "@builder.io/qwik"; 7 | import { useSignal } from "@builder.io/qwik"; 8 | export const ClickableComponent = component$(()=>{ 9 | useOn("click", $(()=>{ 10 | alert("Alert from Clickable Component."); 11 | })); 12 | return
click from other component 1
; 13 | }); 14 | export const HoverComponent = component$(()=>{ 15 | const isHover = useSignal(false); 16 | useOn("mouseover", $(()=>{ 17 | isHover.value = true; 18 | })); 19 | return
{isHover.value ? "Now Hovering" : "Not Hovering"}
; 20 | }); 21 | " 22 | `; 23 | 24 | exports[`useOnDocument event 1`] = ` 25 | "import { component$ } from "@builder.io/qwik"; 26 | import { useSignal } from "@builder.io/qwik"; 27 | import { $ } from "@builder.io/qwik"; 28 | import { useOnDocument } from "@builder.io/qwik"; 29 | const KeyBoard = component$(()=>{ 30 | const keyPressed = useSignal(""); 31 | useOnDocument("keydown", $((event)=>{ 32 | keyPressed.value = keyPressed.value + event.key; 33 | })); 34 | return
{keyPressed.value}
; 35 | }); 36 | " 37 | `; 38 | 39 | exports[`useOnDocument event 2`] = ` 40 | "import { component$ } from "@builder.io/qwik"; 41 | import { useSignal } from "@builder.io/qwik"; 42 | import { $ } from "@builder.io/qwik"; 43 | import { useOnDocument } from "@builder.io/qwik"; 44 | const KeyBoard = component$(()=>{ 45 | const keyPressed = useSignal(""); 46 | useOnDocument("keydown", $((event)=>{ 47 | keyPressed.value = keyPressed.value + event.key; 48 | })); 49 | return
{keyPressed.value}
; 50 | }); 51 | " 52 | `; 53 | 54 | exports[`useOnWindow event 1`] = ` 55 | "import { component$ } from "@builder.io/qwik"; 56 | import { $ } from "@builder.io/qwik"; 57 | import { useOnWindow } from "@builder.io/qwik"; 58 | ; 59 | export const Online = component$(()=>{ 60 | useOnWindow("online", $(()=>{ 61 | alert("Your Device is now Online"); 62 | })); 63 | useOnWindow("offline", $(()=>{ 64 | alert("Your Device is now Offline"); 65 | })); 66 | return
; 67 | }); 68 | " 69 | `; 70 | 71 | exports[`useOnWindow event 2`] = ` 72 | "import { component$ } from "@builder.io/qwik"; 73 | import { $ } from "@builder.io/qwik"; 74 | import { useOnWindow } from "@builder.io/qwik"; 75 | ; 76 | export const Online = component$(()=>{ 77 | useOnWindow("online", $(()=>{ 78 | alert("Your Device is now Online"); 79 | })); 80 | useOnWindow("offline", $(()=>{ 81 | alert("Your Device is now Offline"); 82 | })); 83 | return
; 84 | }); 85 | " 86 | `; 87 | -------------------------------------------------------------------------------- /packages/qwik/tests/__snapshots__/qwik.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`complex qwik app 1`] = ` 4 | "import { component$ } from "@builder.io/qwik"; 5 | import { useSignal } from "@builder.io/qwik"; 6 | import { useTask$ } from "@builder.io/qwik"; 7 | export const Cmp = component$(()=>{ 8 | const count = useSignal(1); 9 | const doubleCount = useSignal(2 * count.value); 10 | useTask$(({ track })=>{ 11 | const __count = track(()=>count.value); 12 | doubleCount.value = 2 * __count; 13 | }); 14 | return (
15 | 16 | {count.value} / {doubleCount.value} 17 | 18 |
); 19 | }); 20 | " 21 | `; 22 | 23 | exports[`qwik labeled macro 1`] = ` 24 | "import { component$ } from "@builder.io/qwik"; 25 | const Cmp = component$(()=>{}); 26 | " 27 | `; 28 | 29 | exports[`qwik labeled macro in function expression 1`] = ` 30 | "import { component$ } from "@builder.io/qwik"; 31 | const ABC = component$(function() {}); 32 | export const Cmp = component$(()=>{}); 33 | " 34 | `; 35 | 36 | exports[`qwik labeled macro with value false 1`] = ` 37 | "function Cmp() {} 38 | " 39 | `; 40 | -------------------------------------------------------------------------------- /packages/qwik/tests/__snapshots__/resource.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`qwik resource 1`] = ` 4 | "import { useSignal } from "@builder.io/qwik"; 5 | import { useResource$ } from "@builder.io/qwik"; 6 | const bar = useSignal("foo"); 7 | const someResource = useResource$(async (ctx)=>{ 8 | ctx.track(()=>bar.value); 9 | ctx.track(()=>props.url); 10 | ctx.cleanup(()=>console.log("cleanup")); 11 | return await expensiveCompute(bar.value, props.url); 12 | }); 13 | " 14 | `; 15 | -------------------------------------------------------------------------------- /packages/qwik/tests/__snapshots__/signal.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`qwik signal 1`] = ` 4 | "import { useSignal } from "@builder.io/qwik"; 5 | const count = useSignal(0); 6 | count.value += 1; 7 | " 8 | `; 9 | 10 | exports[`qwik signal in function name 1`] = ` 11 | "import { useSignal } from "@builder.io/qwik"; 12 | const count = useSignal(0); 13 | function abc(count) { 14 | count = 3; 15 | } 16 | count.value += 2; 17 | " 18 | `; 19 | -------------------------------------------------------------------------------- /packages/qwik/tests/__snapshots__/store.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`qwik store 1`] = ` 4 | "import { component$ } from "@builder.io/qwik"; 5 | import { useStore } from "@builder.io/qwik"; 6 | export default component$(()=>{ 7 | const state = useStore({ 8 | count: 0 9 | }); 10 | return (<> 11 | 12 | 13 | 14 | Count: {state.count} 15 | 16 | ); 17 | }); 18 | " 19 | `; 20 | -------------------------------------------------------------------------------- /packages/qwik/tests/__snapshots__/task.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`qwik task 1`] = ` 4 | "import { useSignal } from "@builder.io/qwik"; 5 | import { useTask$ } from "@builder.io/qwik"; 6 | const count = useSignal(1); 7 | const doubleCount = useSignal(0); 8 | useTask$(()=>{ 9 | console.log("component mounted"); 10 | }); 11 | useTask$(({ track })=>{ 12 | const newCount = track(()=>count.value); 13 | doubleCount.value = 2 * newCount; 14 | }); 15 | " 16 | `; 17 | 18 | exports[`qwik vtask 1`] = ` 19 | "import { useVisibleTask$ } from "@builder.io/qwik"; 20 | useVisibleTask$(()=>{ 21 | cosole.log("runs in the browser"); 22 | }); 23 | useVisibleTask$(()=>console.log("runs in the browser"), { 24 | strategy: "document-ready" 25 | }); 26 | " 27 | `; 28 | -------------------------------------------------------------------------------- /packages/qwik/tests/computed.test.ts: -------------------------------------------------------------------------------- 1 | import { computed, signal } from "../src" 2 | 3 | import { transform } from "@macro-plugin/core" 4 | 5 | test("qwik computed", () => { 6 | const code = ` 7 | signal: { 8 | var a = 3 9 | var b = 4 10 | var count = 1 11 | } 12 | computed: { 13 | var doubleCount = 2 * count + count - a 14 | } 15 | ` 16 | 17 | expect(transform(code, { macros: [signal, computed] }).code).toMatchSnapshot() 18 | }) 19 | -------------------------------------------------------------------------------- /packages/qwik/tests/css.test.ts: -------------------------------------------------------------------------------- 1 | import { css, link, qwik, scoped } from "../src" 2 | 3 | import { transform } from "@macro-plugin/core" 4 | 5 | test("qwik css link", () => { 6 | const code = ` 7 | export const CmpStyles = () => { 8 | qwik: true 9 | link: './code-block.css?inline' 10 | 11 | return Some text 12 | } 13 | ` 14 | expect(transform(code, { macros: [qwik, link], jsc: { parser: { syntax: "typescript", tsx: true } } }).code).toMatchSnapshot() 15 | }) 16 | 17 | test("qwik css links", () => { 18 | const code = ` 19 | export const CmpStyles = () => { 20 | qwik: true 21 | link: [ 22 | './code-block.css?inline', 23 | './font-style.css?inline', 24 | ] 25 | 26 | return Some text 27 | } 28 | ` 29 | expect(transform(code, { macros: [qwik, link], jsc: { parser: { syntax: "typescript", tsx: true } } }).code).toMatchSnapshot() 30 | }) 31 | 32 | test("qwik css string", () => { 33 | const code = ` 34 | export const CmpStyles = () => { 35 | qwik: true 36 | css: \` 37 | .my-text { 38 | color: red; 39 | } 40 | \` 41 | 42 | return Some text 43 | } 44 | ` 45 | expect(transform(code, { macros: [qwik, css], jsc: { parser: { syntax: "typescript", tsx: true } } }).code).toMatchSnapshot() 46 | }) 47 | 48 | test("qwik scoped css", () => { 49 | const code = ` 50 | export const CmpStyles = () => { 51 | qwik: true 52 | scoped: { 53 | link: './code-block.css?inline' 54 | 55 | css: \` 56 | .my-text { 57 | color: red; 58 | } 59 | \` 60 | } 61 | 62 | return Some text 63 | } 64 | ` 65 | expect(transform(code, { macros: [qwik, scoped, css, link], jsc: { parser: { syntax: "typescript", tsx: true } } }).code).toMatchSnapshot() 66 | }) 67 | -------------------------------------------------------------------------------- /packages/qwik/tests/events.test.ts: -------------------------------------------------------------------------------- 1 | import { events, qwik, signal } from "../src" 2 | 3 | import { transform } from "@macro-plugin/core" 4 | 5 | test("useOn events", () => { 6 | const code = ` 7 | export function ClickableComponent() { 8 | qwik: true 9 | onclick: { 10 | alert('Alert from Clickable Component.'); 11 | } 12 | 13 | return
click from other component 1
; 14 | } 15 | 16 | export function HoverComponent() { 17 | qwik: true 18 | signal: { 19 | var isHover = false 20 | } 21 | onmouseover: () => { 22 | isHover = true 23 | } 24 | return
{isHover ? 'Now Hovering' : 'Not Hovering'}
; 25 | } 26 | ` 27 | expect(transform(code, { macros: [qwik, signal, events], jsc: { parser: { syntax: "typescript", tsx: true } } }).code).toMatchSnapshot() 28 | }) 29 | 30 | test("useOnDocument event", () => { 31 | const code = ` 32 | function KeyBoard() { 33 | qwik: true 34 | signal: { 35 | var keyPressed = '' 36 | } 37 | onkeydown: (event) => { 38 | document: true 39 | keyPressed = keyPressed + event.key; 40 | } 41 | 42 | return
{keyPressed}
; 43 | } 44 | ` 45 | 46 | expect(transform(code, { macros: [qwik, signal, events], jsc: { parser: { syntax: "typescript", tsx: true } } }).code).toMatchSnapshot() 47 | }) 48 | 49 | test("useOnDocument event", () => { 50 | const code = ` 51 | function KeyBoard() { 52 | qwik: true 53 | signal: { 54 | var keyPressed = '' 55 | } 56 | document: { 57 | onkeydown: (event) => { 58 | keyPressed = keyPressed + event.key; 59 | } 60 | } 61 | 62 | return
{keyPressed}
; 63 | } 64 | ` 65 | 66 | expect(transform(code, { macros: [qwik, signal, events], jsc: { parser: { syntax: "typescript", tsx: true } } }).code).toMatchSnapshot() 67 | }) 68 | 69 | test("useOnWindow event", () => { 70 | const code = ` 71 | export function Online() { 72 | qwik: true 73 | ononline: { 74 | window: true 75 | alert('Your Device is now Online'); 76 | } 77 | onoffline: { 78 | window: true 79 | alert('Your Device is now Offline'); 80 | } 81 | 82 | return
; 83 | }; 84 | ` 85 | expect(transform(code, { macros: [qwik, signal, events], jsc: { parser: { syntax: "typescript", tsx: true } } }).code).toMatchSnapshot() 86 | }) 87 | 88 | test("useOnWindow event", () => { 89 | const code = ` 90 | export function Online() { 91 | qwik: true 92 | window: { 93 | ononline: { 94 | alert('Your Device is now Online'); 95 | } 96 | onoffline: { 97 | alert('Your Device is now Offline'); 98 | } 99 | } 100 | return
; 101 | }; 102 | ` 103 | expect(transform(code, { macros: [qwik, signal, events], jsc: { parser: { syntax: "typescript", tsx: true } } }).code).toMatchSnapshot() 104 | }) 105 | -------------------------------------------------------------------------------- /packages/qwik/tests/qwik.test.ts: -------------------------------------------------------------------------------- 1 | import { computed, qwik, signal } from "../src" 2 | 3 | import { transform } from "@macro-plugin/core" 4 | 5 | test("qwik labeled macro", () => { 6 | const code = ` 7 | function Cmp() { 8 | qwik: true 9 | } 10 | ` 11 | expect(transform(code, { macros: [qwik] }).code).toMatchSnapshot() 12 | }) 13 | 14 | test("qwik labeled macro with value false", () => { 15 | const code = ` 16 | function Cmp() { 17 | qwik: false 18 | } 19 | ` 20 | expect(transform(code, { macros: [qwik] }).code).toMatchSnapshot() 21 | }) 22 | 23 | test("qwik labeled macro with wrong value", () => { 24 | const code = ` 25 | function Cmp() { 26 | qwik: {} 27 | } 28 | ` 29 | expect(() => transform(code, { macros: [qwik] }).code).toThrow() 30 | }) 31 | 32 | test("qwik labeled macro in function expression", () => { 33 | const code = ` 34 | const ABC = function() { 35 | qwik: true 36 | } 37 | 38 | export const Cmp = () => { 39 | qwik: true 40 | } 41 | ` 42 | expect(transform(code, { macros: [qwik] }).code).toMatchSnapshot() 43 | }) 44 | 45 | test("complex qwik app", () => { 46 | const code = ` 47 | export function Cmp() { 48 | qwik: true 49 | signal: { 50 | var count = 1 51 | } 52 | computed: { 53 | var doubleCount = 2 * count 54 | } 55 | return ( 56 |
57 | {count} / {doubleCount} 58 |
59 | ) 60 | } 61 | ` 62 | expect(transform(code, { macros: [qwik, signal, computed], jsc: { parser: { syntax: "typescript", tsx: true } } }).code).toMatchSnapshot() 63 | }) 64 | -------------------------------------------------------------------------------- /packages/qwik/tests/resource.test.ts: -------------------------------------------------------------------------------- 1 | import { resource, signal } from "../src" 2 | 3 | import { transform } from "@macro-plugin/core" 4 | 5 | test("qwik resource", () => { 6 | const code = ` 7 | signal: { 8 | var bar = 'foo' 9 | } 10 | 11 | resource: async (ctx) => { 12 | ctx.track(() => bar); 13 | ctx.track(() => props.url); 14 | ctx.cleanup(() => console.log('cleanup')); 15 | 16 | var someResource = await expensiveCompute(bar, props.url); 17 | } 18 | ` 19 | expect(transform(code, { macros: [signal, resource] }).code).toMatchSnapshot() 20 | }) 21 | -------------------------------------------------------------------------------- /packages/qwik/tests/signal.test.ts: -------------------------------------------------------------------------------- 1 | import { signal } from "@macro-plugin/qwik" 2 | import { transform } from "@macro-plugin/core" 3 | 4 | test("qwik signal", () => { 5 | const code = ` 6 | signal: { 7 | var count = 0 8 | } 9 | 10 | count += 1 11 | ` 12 | expect(transform(code, { macros: [signal] }).code).toMatchSnapshot() 13 | }) 14 | 15 | test("qwik signal in function name", () => { 16 | const code = ` 17 | signal: { 18 | var count = 0 19 | } 20 | function abc(count) { 21 | count = 3 22 | } 23 | count += 2 24 | ` 25 | 26 | expect(transform(code, { macros: [signal] }).code).toMatchSnapshot() 27 | }) 28 | -------------------------------------------------------------------------------- /packages/qwik/tests/store.test.ts: -------------------------------------------------------------------------------- 1 | import { qwik, store } from "../src" 2 | 3 | import { transform } from "@macro-plugin/core" 4 | 5 | test("qwik store", () => { 6 | const code = ` 7 | export default () => { 8 | qwik: true 9 | store: { 10 | var state = { 11 | count: 0 12 | } 13 | } 14 | 15 | return ( 16 | <> 17 | 18 | Count: {state.count} 19 | 20 | ); 21 | }; 22 | ` 23 | expect(transform(code, { macros: [qwik, store], jsc: { parser: { syntax: "typescript", tsx: true } } }).code).toMatchSnapshot() 24 | }) 25 | -------------------------------------------------------------------------------- /packages/qwik/tests/task.test.ts: -------------------------------------------------------------------------------- 1 | import { signal, task, vtask } from "../src" 2 | 3 | import { transform } from "@macro-plugin/core" 4 | 5 | test("qwik task", () => { 6 | const code = ` 7 | signal: { 8 | var count = 1 9 | var doubleCount = 0 10 | } 11 | 12 | task: { 13 | console.log('component mounted'); 14 | } 15 | 16 | task: ({track}) => { 17 | const newCount = track(() => count); 18 | doubleCount = 2 * newCount; 19 | }` 20 | 21 | expect(transform(code, { macros: [signal, task] }).code).toMatchSnapshot() 22 | }) 23 | 24 | test("qwik vtask", () => { 25 | const code = ` 26 | vtask: { 27 | cosole.log('runs in the browser') 28 | } 29 | 30 | vtask: [ 31 | () => console.log('runs in the browser'), 32 | { 33 | strategy: 'document-ready', 34 | } 35 | ] 36 | ` 37 | expect(transform(code, { macros: [signal, vtask] }).code).toMatchSnapshot() 38 | }) 39 | -------------------------------------------------------------------------------- /packages/register/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @macro-plugin/register 2 | 3 | ## 1.2.0 4 | 5 | ### Patch Changes 6 | 7 | - Updated dependencies [[`8c94045`](https://github.com/macro-plugin/macros/commit/8c9404545d207b708ed433328bd383488a3ed0d4), [`b45063f`](https://github.com/macro-plugin/macros/commit/b45063ff784e513380f43bf8425c4f72eaa5c0b4)]: 8 | - @macro-plugin/core@1.2.0 9 | - @macro-plugin/shared@1.2.1 10 | 11 | ## 1.1.4 12 | 13 | ### Patch Changes 14 | 15 | - Updated dependencies [[`c398ad6`](https://github.com/macro-plugin/macros/commit/c398ad61bd1aa9b79c1a98f7e811323f996f5658), [`e3ce376`](https://github.com/macro-plugin/macros/commit/e3ce37696e0a21bdddb56804f7dbcfa904f5fd35), [`b1d3bff`](https://github.com/macro-plugin/macros/commit/b1d3bffcac4ef25930bd7ee4409664f6fb00fb06)]: 16 | - @macro-plugin/shared@1.2.0 17 | - @macro-plugin/core@1.1.4 18 | 19 | ## 1.1.3 20 | 21 | ### Patch Changes 22 | 23 | - [#27](https://github.com/macro-plugin/macros/pull/27) [`95e0d68`](https://github.com/macro-plugin/macros/commit/95e0d686e5056356e5c33a9f1201b667dbc1771e) Thanks [@voorjaar](https://github.com/voorjaar)! - refactor: use plugin with swc parse api 24 | 25 | - Updated dependencies []: 26 | - @macro-plugin/core@1.1.3 27 | - @macro-plugin/shared@1.1.1 28 | 29 | ## 1.1.2 30 | 31 | ### Patch Changes 32 | 33 | - [#23](https://github.com/macro-plugin/macros/pull/23) [`e9b008c`](https://github.com/macro-plugin/macros/commit/e9b008c5089fcdf453cd16e7037fea9432a1f187) Thanks [@voorjaar](https://github.com/voorjaar)! - refactor: move shared to dependencies 34 | 35 | - Updated dependencies [[`4bd75d8`](https://github.com/macro-plugin/macros/commit/4bd75d8f5f59bc3c7befcc7178a9ba87ac9fad8a), [`2dd180d`](https://github.com/macro-plugin/macros/commit/2dd180d67643a63dd3abe706fe393f8da431a5f5), [`0813759`](https://github.com/macro-plugin/macros/commit/081375946893092cdd9280aa5c20333a722e5683), [`294f675`](https://github.com/macro-plugin/macros/commit/294f67574c5ff168bdeb0a499ea4ab2fd57579cf)]: 36 | - @macro-plugin/shared@1.1.0 37 | - @macro-plugin/core@1.1.2 38 | 39 | ## 1.1.1 40 | 41 | ### Patch Changes 42 | 43 | - Updated dependencies [[`b4be79b`](https://github.com/macro-plugin/macros/commit/b4be79be09e8790b95c6a2e9b07dde4ba3822f39), [`df8dcc0`](https://github.com/macro-plugin/macros/commit/df8dcc0ab7f3e09f1157c5c2a7cda4a7f5367991)]: 44 | - @macro-plugin/core@1.1.1 45 | 46 | ## 1.1.0 47 | 48 | ### Patch Changes 49 | 50 | - Updated dependencies [[`4155bb4`](https://github.com/macro-plugin/macros/commit/4155bb4de7968a83e62203411bceae6b0602637f), [`6b25910`](https://github.com/macro-plugin/macros/commit/6b25910567e910b7c71c79646f8569a2f3927be6), [`8dd4939`](https://github.com/macro-plugin/macros/commit/8dd493997931d8d91a82ffb1785927d425c17c61), [`14efcb2`](https://github.com/macro-plugin/macros/commit/14efcb2c6461ab3f5d78e0599ec74b422085ce1d), [`7787022`](https://github.com/macro-plugin/macros/commit/7787022f657b7a79cb18a1e8ba947ae2eaeb682e), [`a17b055`](https://github.com/macro-plugin/macros/commit/a17b055d356c285b394add56192c80077ebde2c2)]: 51 | - @macro-plugin/core@1.1.0 52 | 53 | ## 1.0.3 54 | 55 | ### Patch Changes 56 | 57 | - Updated dependencies [[`07961a0`](https://github.com/macro-plugin/macros/commit/07961a03b6e82080a2b8c8ab2626c187c34f912e), [`f1e40ea`](https://github.com/macro-plugin/macros/commit/f1e40ead32636d4f2d43c442e70cc208e2d43b28), [`556ca2d`](https://github.com/macro-plugin/macros/commit/556ca2d9addaf36ac84da8c8ea7b5bc465e174b7)]: 58 | - @macro-plugin/core@1.0.3 59 | 60 | ## 1.0.2 61 | 62 | ### Patch Changes 63 | 64 | - [#9](https://github.com/macro-plugin/macros/pull/9) [`2c64787`](https://github.com/macro-plugin/macros/commit/2c647875182c5fc6ca41c9e72587a08307ba90ec) Thanks [@voorjaar](https://github.com/voorjaar)! - chore: upgrade to swc 1.3.53 65 | 66 | - Updated dependencies [[`2c64787`](https://github.com/macro-plugin/macros/commit/2c647875182c5fc6ca41c9e72587a08307ba90ec)]: 67 | - @macro-plugin/core@1.0.2 68 | 69 | ## 1.0.1 70 | 71 | ### Patch Changes 72 | 73 | - 98425cf: build: no longer publish iife 74 | - Updated dependencies [98425cf] 75 | - @macro-plugin/core@1.0.1 76 | -------------------------------------------------------------------------------- /packages/register/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Raven Satir 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 | -------------------------------------------------------------------------------- /packages/register/README.md: -------------------------------------------------------------------------------- 1 | # @macro-plugin/register 2 | 3 | Node register for macro plugins. 4 | 5 | ## Installation 6 | 7 | ```sh 8 | # if you use npm 9 | npm i -D @macro-plugin/register 10 | # if you use pnpm 11 | pnpm i -D @macro-plugin/register 12 | # if you use yarn 13 | yarn add -D @macro-plugin/register 14 | ``` 15 | 16 | ## Usage 17 | 18 | ```sh 19 | node -r "@macro-plugin/register" ./src/index.js 20 | ``` 21 | 22 | also support typescript 23 | 24 | ```sh 25 | node -r "@macro-plugin/register" ./src/index.ts 26 | ``` 27 | 28 | equals to 29 | 30 | ```sh 31 | macros run ./src/index.ts 32 | ``` -------------------------------------------------------------------------------- /packages/register/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@macro-plugin/register", 3 | "version": "1.2.0", 4 | "description": "Node register for macro plugins.", 5 | "main": "dist/index.js", 6 | "module": "dist/index.mjs", 7 | "types": "dist/index.d.ts", 8 | "files": [ 9 | "dist", 10 | "CHANGELOG.md" 11 | ], 12 | "scripts": { 13 | "build": "rollup -c" 14 | }, 15 | "keywords": [ 16 | "register", 17 | "node-register", 18 | "macro", 19 | "macros", 20 | "macro-plugin" 21 | ], 22 | "homepage": "https://github.com/macro-plugin/macros/tree/main/packages/register", 23 | "repository": { 24 | "type": "git", 25 | "url": "https://github.com/macro-plugin/macros.git" 26 | }, 27 | "dependencies": { 28 | "@macro-plugin/core": "1.2.0", 29 | "@macro-plugin/shared": "1.2.1" 30 | }, 31 | "exports": { 32 | "./package.json": "./package.json", 33 | ".": { 34 | "require": "./dist/index.js", 35 | "import": "./dist/index.mjs", 36 | "types": "./dist/index.d.ts" 37 | } 38 | }, 39 | "author": "Raven Satir", 40 | "license": "MIT" 41 | } 42 | -------------------------------------------------------------------------------- /packages/register/rollup.config.mjs: -------------------------------------------------------------------------------- 1 | import commonjs from "@rollup/plugin-commonjs" 2 | import { defineConfig } from "rollup" 3 | import json from "@rollup/plugin-json" 4 | import { nodeResolve } from "@rollup/plugin-node-resolve" 5 | import { rmSync } from "fs" 6 | import terser from "@rollup/plugin-terser" 7 | import typescript from "rollup-plugin-typescript2" 8 | 9 | /** @type { import("rollup").Plugin[] } */ 10 | const plugins = [ 11 | { 12 | name: "del", 13 | transform (code, id) { 14 | if (id.endsWith(".cts") || id.endsWith(".mts")) return "" 15 | }, 16 | buildStart () { 17 | rmSync("./dist", { recursive: true, force: true }) 18 | }, 19 | closeBundle () { 20 | rmSync("./dist/packages", { recursive: true, force: true }) 21 | } 22 | }, 23 | json(), 24 | commonjs(), 25 | nodeResolve(), 26 | typescript({ 27 | tsconfigOverride: { 28 | include: ["packages/**/src"] 29 | } 30 | }), 31 | terser({ 32 | module: true, 33 | compress: { 34 | ecma: 2015, 35 | pure_getters: true, 36 | } 37 | }) 38 | ] 39 | 40 | const external = [ 41 | "@swc/core", 42 | "@macro-plugin/core" 43 | ] 44 | 45 | // compile to core dist folder 46 | export default defineConfig([ 47 | { 48 | input: "./src/index.ts", 49 | output: { 50 | file: "./dist/register.js", 51 | format: "cjs", 52 | }, 53 | plugins, 54 | external, 55 | }, 56 | ]) 57 | -------------------------------------------------------------------------------- /packages/register/src/index.ts: -------------------------------------------------------------------------------- 1 | import { transformJS, transformTS } from "./transformer" 2 | 3 | import { addHook } from "@macro-plugin/shared" 4 | 5 | addHook( 6 | transformJS, 7 | { extensions: [".js"] } 8 | ) 9 | 10 | addHook( 11 | transformTS, 12 | { extensions: [".jsx", ".tsx", ".ts"] } 13 | ) 14 | -------------------------------------------------------------------------------- /packages/register/src/transformer.ts: -------------------------------------------------------------------------------- 1 | import { MacroOptions, createSwcPlugin, getSpanOffset, transform } from "@macro-plugin/core" 2 | import { ParserConfig, parseSync as swcParse, transformSync as swcTransform } from "@swc/core" 3 | 4 | import type { Options } from "@swc/core" 5 | import { buildTransformOptionsSync } from "@macro-plugin/shared" 6 | 7 | var CURRENT_CONFIG: [Options, MacroOptions, string | undefined] 8 | 9 | function getConfig () { 10 | if (!CURRENT_CONFIG) CURRENT_CONFIG = buildTransformOptionsSync({}) 11 | return CURRENT_CONFIG 12 | } 13 | 14 | export function transformJS (src: string) { 15 | const macroOptions = getConfig()[1] 16 | return transform(src, macroOptions).code 17 | } 18 | 19 | export function transformTS (src: string, filename: string) { 20 | const [swcOptions, macroOptions] = getConfig() 21 | const macroPlugin = createSwcPlugin(macroOptions, src, getSpanOffset()) 22 | 23 | const isJsx = /\.(js|ts)x$/.test(filename) 24 | const parser: ParserConfig = /\.tsx?$/.test(filename) 25 | ? { 26 | syntax: "typescript", 27 | tsx: isJsx, 28 | } 29 | : { 30 | syntax: "ecmascript", 31 | jsx: isJsx 32 | } 33 | 34 | swcOptions.filename = filename 35 | if (swcOptions.jsc) { 36 | swcOptions.jsc.parser = parser 37 | } else { 38 | swcOptions.jsc = { 39 | parser 40 | } 41 | } 42 | 43 | const program = swcParse(src, parser) 44 | return swcTransform(macroPlugin(program), swcOptions).code 45 | } 46 | -------------------------------------------------------------------------------- /packages/rollup/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Raven Satir 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 | -------------------------------------------------------------------------------- /packages/rollup/README.md: -------------------------------------------------------------------------------- 1 | # @macro-plugin/rollup 2 | 3 | [Macro Plugin](https://github.com/macro-plugin) integration for rollup. It supports transform macros and typescript and also jsx. 4 | 5 | ## Installation 6 | 7 | ```sh 8 | # if you use npm 9 | npm i -D @macro-plugin/rollup 10 | # if you use pnpm 11 | pnpm i -D @macro-plugin/rollup 12 | # if you use yarn 13 | yarn add -D @macro-plugin/rollup 14 | ``` 15 | 16 | ## Usage 17 | 18 | `rollup.config.js`: 19 | 20 | ```js 21 | import { defineConfig } from "rollup" 22 | import macroPlugin from "@macro-plugin/rollup" 23 | 24 | export default defineConfig({ 25 | input: "src/index.js", 26 | output: { 27 | file: "dist/index.js", 28 | format: "es" 29 | }, 30 | plugins: [ 31 | macroPlugin() 32 | ] 33 | }) 34 | ``` 35 | 36 | It will load the configuration from `macros.config.js` or `macros.config.ts` by default. You can also customize it: 37 | 38 | ```js 39 | import { defineConfig } from "rollup" 40 | import macroPlugin from "@macro-plugin/rollup" 41 | 42 | export default defineConfig({ 43 | input: "src/index.ts", 44 | output: { 45 | file: "dist/index.js", 46 | format: "es" 47 | }, 48 | plugins: [ 49 | macroPlugin({ emitDts: true }) 50 | ] 51 | }) 52 | ``` 53 | 54 | `macros.config.ts`: 55 | 56 | ```js 57 | import { defineConfig } from "@macro-plugin/core" 58 | 59 | export default defineConfig({ 60 | macros: [], 61 | emitDts: true, 62 | jsc: { 63 | parser: { 64 | syntax: "typescript" 65 | }, 66 | target: "esnext", 67 | }, 68 | }) 69 | ``` 70 | 71 | Or with commonjs 72 | 73 | `macros.config.js` 74 | 75 | ```js 76 | /** @type {import("@macro-plugin/core").Config} */ 77 | module.exports = { 78 | macros: [], 79 | emitDts: true, 80 | jsc: { 81 | parser: { 82 | syntax: "typescript" 83 | }, 84 | target: "esnext", 85 | }, 86 | } 87 | ``` 88 | 89 | ## License 90 | 91 | MIT 92 | 93 | [MacroPlugin]: https://github.com/macro-plugin 94 | -------------------------------------------------------------------------------- /packages/rollup/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@macro-plugin/rollup", 3 | "version": "1.2.2", 4 | "description": "Macro plugins integration for rollup", 5 | "main": "dist/index.js", 6 | "module": "dist/index.mjs", 7 | "types": "dist/index.d.ts", 8 | "files": [ 9 | "dist", 10 | "CHANGELOG.md" 11 | ], 12 | "scripts": { 13 | "build": "rollup -c ../../rollup.config.mjs" 14 | }, 15 | "keywords": [ 16 | "rollup", 17 | "macro", 18 | "macros", 19 | "macro-plugin" 20 | ], 21 | "homepage": "https://github.com/macro-plugin/macros/tree/main/packages/rollup", 22 | "repository": { 23 | "type": "git", 24 | "url": "https://github.com/macro-plugin/macros.git" 25 | }, 26 | "dependencies": { 27 | "@macro-plugin/core": "1.2.0", 28 | "@macro-plugin/shared": "1.2.1" 29 | }, 30 | "devDependencies": { 31 | "rollup": "^3.20.0" 32 | }, 33 | "exports": { 34 | "./package.json": "./package.json", 35 | ".": { 36 | "require": "./dist/index.js", 37 | "import": "./dist/index.mjs", 38 | "types": "./dist/index.d.ts" 39 | } 40 | }, 41 | "author": "Raven Satir", 42 | "license": "MIT" 43 | } 44 | -------------------------------------------------------------------------------- /packages/rollup/src/index.ts: -------------------------------------------------------------------------------- 1 | import { Config, createSwcPlugin, getSpanOffset, transformAsync } from "@macro-plugin/core" 2 | import { SCRIPT_EXTENSIONS, buildTransformOptions, createFilter, createResolver, createTsLib, createTsResolver, getHasModuleSideEffects, getIdMatcher, matchScriptType, patchTsOptions, resolveTsOptions } from "@macro-plugin/shared" 3 | import { dirname, resolve } from "path" 4 | import { minify as swcMinify, parse as swcParse, transform as swcTransform } from "@swc/core" 5 | 6 | import type { Plugin } from "rollup" 7 | import { TreeshakingOptions } from "rollup" 8 | 9 | const isMacroExternal = (id: string) => /(@macro-plugin)|@swc/.test(id) 10 | 11 | async function rollupMacroPlugin (config?: Config): Promise { 12 | const [basicSwcOptions, macroOptions] = await buildTransformOptions(config) 13 | const filter = createFilter(macroOptions.include, macroOptions.exclude) 14 | const extensions = macroOptions.extensions || SCRIPT_EXTENSIONS 15 | 16 | const plugin: Plugin = { 17 | name: "rollupMacroPlugin", 18 | async transform (code, id) { 19 | if (!filter(id)) return null 20 | 21 | const target = matchScriptType(id, extensions) 22 | if (!target) return null 23 | 24 | if (macroOptions.swcTransform == null || macroOptions.swcTransform === true) { 25 | const { isTypeScript, isJsx, isTsx } = target 26 | 27 | // use swc transform typescript and jsx 28 | if (isTypeScript || isJsx) { 29 | const macroPlugin = createSwcPlugin(macroOptions, code, getSpanOffset()) 30 | const swcOptions = patchTsOptions({ 31 | ...basicSwcOptions, 32 | filename: id, 33 | minify: false 34 | }, macroOptions.tsconfig === false ? undefined : resolveTsOptions(dirname(id), macroOptions.tsconfig), isTypeScript, isTsx, isJsx) 35 | const program = await swcParse(code, swcOptions.jsc?.parser || { syntax: "typescript" }) 36 | return await swcTransform(macroPlugin(program), swcOptions) 37 | } 38 | } 39 | 40 | // native macro transform without swc 41 | const result = await transformAsync(code, macroOptions) 42 | return { code: result.code, map: result.map } 43 | }, 44 | options (options) { 45 | // ignore warning on @macro-plugin 46 | const oldWarn = options.onwarn 47 | options.onwarn = (warning, warn) => { 48 | if (warning.exporter && isMacroExternal(warning.exporter) && ["UNRESOLVED_IMPORT", "UNUSED_EXTERNAL_IMPORT"].includes(warning.code || "")) return 49 | oldWarn ? oldWarn(warning, warn) : warn(warning) 50 | } 51 | 52 | // add @macro-plugin to external 53 | const matchExternal = getIdMatcher(options.external) 54 | options.external = (source, importer, isResolved) => isMacroExternal(source) || matchExternal(source, importer, isResolved) 55 | 56 | // add no-side-effects support for @macro-plugin 57 | const oldTreeshake = options.treeshake 58 | const getSideEffects = getHasModuleSideEffects(typeof oldTreeshake === "object" ? oldTreeshake.moduleSideEffects : undefined) 59 | options.treeshake = { 60 | ...(typeof oldTreeshake === "object" ? oldTreeshake : {}), 61 | moduleSideEffects: (id, external) => isMacroExternal(id) ? false : getSideEffects(id, external), 62 | preset: typeof oldTreeshake === "string" ? oldTreeshake : (oldTreeshake as TreeshakingOptions | undefined)?.preset 63 | } 64 | }, 65 | renderChunk (code) { 66 | if (basicSwcOptions.minify || basicSwcOptions.jsc?.minify?.mangle || basicSwcOptions.jsc?.minify?.compress) { 67 | return swcMinify(code, basicSwcOptions.jsc?.minify) 68 | } 69 | 70 | return null 71 | } 72 | } 73 | 74 | if (macroOptions.resolveTs) { 75 | const tslib = createTsLib() 76 | const tsOptions = macroOptions.tsconfig === false ? {} : resolveTsOptions(resolve("."), macroOptions.tsconfig) 77 | plugin.resolveId = createTsResolver(tslib, tsOptions, filter) 78 | plugin.load = (id) => { 79 | if (id === tslib.virtual) return tslib.source 80 | } 81 | } else { 82 | plugin.resolveId = createResolver(extensions) 83 | } 84 | 85 | return plugin 86 | } 87 | 88 | export default rollupMacroPlugin 89 | -------------------------------------------------------------------------------- /packages/shared/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Raven Satir 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 | -------------------------------------------------------------------------------- /packages/shared/README.md: -------------------------------------------------------------------------------- 1 | # @macro-plugin/shared 2 | 3 | Shared utils for internel and plugin usage. 4 | 5 | ## Installation 6 | 7 | ```sh 8 | # if you use npm 9 | npm i -D @macro-plugin/shared 10 | # if you use pnpm 11 | pnpm i -D @macro-plugin/shared 12 | # if you use yarn 13 | yarn add -D @macro-plugin/shared 14 | ``` 15 | 16 | ## API 17 | 18 | ### `addHook` 19 | 20 | add a require hook 21 | 22 | ### `picomatch` 23 | 24 | picomatch file matcher 25 | 26 | ### `autoRequire` 27 | 28 | require or import a package 29 | 30 | ### `loadConfigFile` 31 | 32 | async loading `macros.config.js` or `macros.config.ts`. 33 | 34 | ### `loadConfigFileSync` 35 | 36 | sync loading `macros.config.js` or `macros.config.ts`. 37 | 38 | ### `writeDts` 39 | 40 | write dts to path, check if content is same first. 41 | 42 | ### `extractSwcOptions` 43 | 44 | extract swc options from all your defined options. 45 | 46 | ### `buildTransformOptions` 47 | 48 | load config file, then return `[swcOptions, macroOptions, configPath]` 49 | 50 | ### `extractInput` 51 | 52 | split `(file | pattern)[]` to `{ files, patterns }` 53 | 54 | ### `extractFiles` 55 | 56 | extract files from `(file | pattern)[]` -------------------------------------------------------------------------------- /packages/shared/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@macro-plugin/shared", 3 | "version": "1.2.1", 4 | "description": "macro-plugin shared utils for plugins", 5 | "main": "dist/index.js", 6 | "module": "dist/index.mjs", 7 | "types": "dist/index.d.ts", 8 | "files": [ 9 | "dist", 10 | "CHANGELOG.md" 11 | ], 12 | "scripts": { 13 | "build": "rollup -c ../../rollup.config.mjs" 14 | }, 15 | "dependencies": { 16 | "@macro-plugin/core": "1.2.0" 17 | }, 18 | "devDependencies": { 19 | "@types/picomatch": "^2.3.0", 20 | "get-tsconfig": "^4.5.0", 21 | "picomatch": "^2.3.1", 22 | "pirates": "^4.0.5" 23 | }, 24 | "homepage": "https://github.com/macro-plugin/macros/tree/main/packages/shared", 25 | "repository": { 26 | "type": "git", 27 | "url": "https://github.com/macro-plugin/macros.git" 28 | }, 29 | "exports": { 30 | "./package.json": "./package.json", 31 | ".": { 32 | "import": "./dist/index.mjs", 33 | "require": "./dist/index.js", 34 | "types": "./dist/index.d.ts" 35 | } 36 | }, 37 | "author": "Raven Satir", 38 | "license": "MIT" 39 | } 40 | -------------------------------------------------------------------------------- /packages/shared/src/build.ts: -------------------------------------------------------------------------------- 1 | import type { Config, MacroOptions } from "@macro-plugin/core" 2 | import { autoRequire, resolveMacroOptions, resolveSwcOptions } from "./resolve" 3 | import { existsSync, readFileSync, rm, writeFile } from "fs" 4 | 5 | import type { Options } from "@swc/core" 6 | import { addHook } from "pirates" 7 | import path from "path" 8 | import process from "process" 9 | import { transformSync } from "@swc/core" 10 | 11 | const h = Object.prototype.hasOwnProperty 12 | export const hasProp = (target: T, prop: PropertyKey) => h.call(target, prop) 13 | 14 | export { addHook } 15 | 16 | export function isModule (): boolean { 17 | try { 18 | require("fs") 19 | return false 20 | } catch {} 21 | return true 22 | } 23 | 24 | export function transformConfig (code: string, isModule: boolean = false) { 25 | return transformSync(code, { module: { type: isModule ? "es6" : "commonjs" }, jsc: { parser: { syntax: "typescript" }, target: "esnext" }, swcrc: false, configFile: false }).code 26 | } 27 | 28 | export function hookRequire (id: string): T { 29 | const revert = addHook( 30 | (code) => transformConfig(code, isModule()), 31 | { extensions: [".js", ".ts"] } 32 | ) 33 | 34 | const r = require(id) 35 | revert() 36 | 37 | return r 38 | } 39 | 40 | // TODO: maybe change module import to createRequire 41 | export async function loadConfigFile (): Promise<[string | undefined, Config]> { 42 | const cwd = process.cwd() 43 | 44 | const jsConfigFile = path.join(cwd, "macros.config.js") 45 | if (existsSync(jsConfigFile)) { 46 | // {type: "module" | "commonjs"} & "macros.config.js" 47 | const config = await autoRequire(jsConfigFile, true) 48 | return [jsConfigFile, config] 49 | } 50 | 51 | const tsConfigFile = path.join(cwd, "macros.config.ts") 52 | if (existsSync(tsConfigFile)) { 53 | // {type: "module"} & "macros.config.ts" 54 | if (isModule()) { 55 | const jsConfigFile = path.join(cwd, ".macros.config.js") 56 | const code = readFileSync(tsConfigFile).toString() 57 | const transformed = transformConfig(code, true) 58 | await writeFile(jsConfigFile, transformed, (err) => { 59 | if (err != null) throw new Error(err.message) 60 | }) 61 | const config = (await import(jsConfigFile) || {}).default 62 | rm(jsConfigFile, (err) => { 63 | if (err != null) throw new Error(err.message) 64 | }) 65 | return [tsConfigFile, config] 66 | } 67 | // {type: "commonjs"} & "macros.config.ts" 68 | const config = hookRequire<{ default: Config }>(tsConfigFile) 69 | return [tsConfigFile, config?.default || {}] 70 | } 71 | 72 | return [undefined, {}] 73 | } 74 | 75 | /** 76 | * sync version of load config, not handing { type: "module" } 77 | */ 78 | export function loadConfigFileSync (): [string | undefined, Config] { 79 | const cwd = process.cwd() 80 | 81 | const jsConfigFile = path.join(cwd, "macros.config.js") 82 | if (existsSync(jsConfigFile)) { 83 | const config = require(jsConfigFile) as Config 84 | return [jsConfigFile, config] 85 | } 86 | 87 | const tsConfigFile = path.join(cwd, "macros.config.ts") 88 | if (existsSync(tsConfigFile)) { 89 | const config = hookRequire<{ default: Config }>(tsConfigFile) 90 | return [tsConfigFile, config?.default || {}] 91 | } 92 | return [undefined, {}] 93 | } 94 | 95 | export async function buildTransformOptions (inputOptions: (Config & { experimental?: unknown }) | undefined): Promise<[Options, MacroOptions, string | undefined]> { 96 | const [configPath, config] = await loadConfigFile() 97 | const combinedOptions = { ...(inputOptions || {}), ...config } 98 | 99 | return [resolveSwcOptions(combinedOptions), resolveMacroOptions(combinedOptions), configPath] 100 | } 101 | 102 | export function buildTransformOptionsSync (inputOptions: (Config & { experimental?: unknown }) | undefined): [Options, MacroOptions, string | undefined] { 103 | const [configPath, config] = loadConfigFileSync() 104 | const combinedOptions = { ...(inputOptions || {}), ...config } 105 | 106 | return [resolveSwcOptions(combinedOptions), resolveMacroOptions(combinedOptions), configPath] 107 | } 108 | -------------------------------------------------------------------------------- /packages/shared/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./resolve" 2 | export * from "./build" 3 | export * from "./match" 4 | export * from "./types" 5 | -------------------------------------------------------------------------------- /packages/shared/src/types.ts: -------------------------------------------------------------------------------- 1 | import { CompilerOptions } from "typescript" 2 | 3 | export interface MatchOptions { 4 | cwd: string; 5 | ignore?: string[]; 6 | } 7 | 8 | export type HasModuleSideEffects = (id: string, external: boolean) => boolean; 9 | 10 | export type Filter = (id: string) => boolean 11 | 12 | export interface TsLib { 13 | lib: string; 14 | virtual: string; 15 | source: string; 16 | version: string; 17 | } 18 | 19 | export interface FormattingHost { 20 | getCompilationSettings: () => CompilerOptions; 21 | getCurrentDirectory: () => string; 22 | getNewLine(): string; 23 | getCanonicalFileName: (fileName: string) => string; 24 | } 25 | -------------------------------------------------------------------------------- /packages/shared/tests/match.test.ts: -------------------------------------------------------------------------------- 1 | import { createFilter } from "../src/match" 2 | 3 | test("createFilter", () => { 4 | const files = [ 5 | "/Users/admin/macros/examples/rollup-project/src/index.ts", 6 | "/Users/admin/macros/examples/rollup-project/src/second.ts", 7 | "/Users/admin/macros/examples/node_modules/abc.js" 8 | ] 9 | 10 | const filter = createFilter() 11 | 12 | expect(filter(files[0])).toBe(true) 13 | expect(filter(files[1])).toBe(true) 14 | expect(filter(files[2])).toBe(false) 15 | }) 16 | 17 | test("createFilter with glob pattern", () => { 18 | const files = [ 19 | "/Users/admin/macros/examples/rollup-project/src/index.ts", 20 | "/Users/admin/macros/examples/rollup-project/src/second.ts", 21 | "/Users/admin/macros/examples/node_modules/abc.js" 22 | ] 23 | 24 | const filter = createFilter(["**/*.ts"], ["**/second.ts"]) 25 | expect(filter(files[0])).toBe(true) 26 | expect(filter(files[1])).toBe(false) 27 | expect(filter(files[2])).toBe(false) 28 | 29 | const filter2 = createFilter(["**/node_modules/**", "**/second.ts"], []) 30 | expect(filter2(files[0])).toBe(false) 31 | expect(filter2(files[1])).toBe(true) 32 | expect(filter2(files[2])).toBe(true) 33 | }) 34 | 35 | test("createFilter with RegExp pattern", () => { 36 | const files = [ 37 | "/Users/admin/macros/examples/rollup-project/src/index.ts", 38 | "/Users/admin/macros/examples/rollup-project/src/second.ts", 39 | "/Users/admin/macros/examples/node_modules/abc.js" 40 | ] 41 | 42 | const filter = createFilter([/rollup-project/], [/second\.ts/]) 43 | expect(filter(files[0])).toBe(true) 44 | expect(filter(files[1])).toBe(false) 45 | expect(filter(files[2])).toBe(false) 46 | 47 | const filter2 = createFilter([/node_modules/], []) 48 | expect(filter2(files[0])).toBe(false) 49 | expect(filter2(files[1])).toBe(false) 50 | expect(filter2(files[2])).toBe(true) 51 | }) 52 | -------------------------------------------------------------------------------- /packages/solid/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @macro-plugin/solid 2 | 3 | ## 1.1.0 4 | 5 | ### Minor Changes 6 | 7 | - [#33](https://github.com/macro-plugin/macros/pull/33) [`b45063f`](https://github.com/macro-plugin/macros/commit/b45063ff784e513380f43bf8425c4f72eaa5c0b4) Thanks [@voorjaar](https://github.com/voorjaar)! - refactor: rename span to dummySpan 8 | 9 | ### Patch Changes 10 | 11 | - Updated dependencies [[`8c94045`](https://github.com/macro-plugin/macros/commit/8c9404545d207b708ed433328bd383488a3ed0d4), [`b45063f`](https://github.com/macro-plugin/macros/commit/b45063ff784e513380f43bf8425c4f72eaa5c0b4)]: 12 | - @macro-plugin/core@1.2.0 13 | 14 | ## 1.0.8 15 | 16 | ### Patch Changes 17 | 18 | - Updated dependencies [[`e3ce376`](https://github.com/macro-plugin/macros/commit/e3ce37696e0a21bdddb56804f7dbcfa904f5fd35)]: 19 | - @macro-plugin/core@1.1.4 20 | 21 | ## 1.0.7 22 | 23 | ### Patch Changes 24 | 25 | - Updated dependencies []: 26 | - @macro-plugin/core@1.1.3 27 | 28 | ## 1.0.6 29 | 30 | ### Patch Changes 31 | 32 | - Updated dependencies [[`294f675`](https://github.com/macro-plugin/macros/commit/294f67574c5ff168bdeb0a499ea4ab2fd57579cf)]: 33 | - @macro-plugin/core@1.1.2 34 | 35 | ## 1.0.5 36 | 37 | ### Patch Changes 38 | 39 | - Updated dependencies [[`b4be79b`](https://github.com/macro-plugin/macros/commit/b4be79be09e8790b95c6a2e9b07dde4ba3822f39), [`df8dcc0`](https://github.com/macro-plugin/macros/commit/df8dcc0ab7f3e09f1157c5c2a7cda4a7f5367991)]: 40 | - @macro-plugin/core@1.1.1 41 | 42 | ## 1.0.4 43 | 44 | ### Patch Changes 45 | 46 | - Updated dependencies [[`4155bb4`](https://github.com/macro-plugin/macros/commit/4155bb4de7968a83e62203411bceae6b0602637f), [`6b25910`](https://github.com/macro-plugin/macros/commit/6b25910567e910b7c71c79646f8569a2f3927be6), [`8dd4939`](https://github.com/macro-plugin/macros/commit/8dd493997931d8d91a82ffb1785927d425c17c61), [`14efcb2`](https://github.com/macro-plugin/macros/commit/14efcb2c6461ab3f5d78e0599ec74b422085ce1d), [`7787022`](https://github.com/macro-plugin/macros/commit/7787022f657b7a79cb18a1e8ba947ae2eaeb682e), [`a17b055`](https://github.com/macro-plugin/macros/commit/a17b055d356c285b394add56192c80077ebde2c2)]: 47 | - @macro-plugin/core@1.1.0 48 | 49 | ## 1.0.3 50 | 51 | ### Patch Changes 52 | 53 | - Updated dependencies [[`07961a0`](https://github.com/macro-plugin/macros/commit/07961a03b6e82080a2b8c8ab2626c187c34f912e), [`f1e40ea`](https://github.com/macro-plugin/macros/commit/f1e40ead32636d4f2d43c442e70cc208e2d43b28), [`556ca2d`](https://github.com/macro-plugin/macros/commit/556ca2d9addaf36ac84da8c8ea7b5bc465e174b7)]: 54 | - @macro-plugin/core@1.0.3 55 | 56 | ## 1.0.2 57 | 58 | ### Patch Changes 59 | 60 | - [#9](https://github.com/macro-plugin/macros/pull/9) [`2c64787`](https://github.com/macro-plugin/macros/commit/2c647875182c5fc6ca41c9e72587a08307ba90ec) Thanks [@voorjaar](https://github.com/voorjaar)! - chore: upgrade to swc 1.3.53 61 | 62 | - Updated dependencies [[`2c64787`](https://github.com/macro-plugin/macros/commit/2c647875182c5fc6ca41c9e72587a08307ba90ec)]: 63 | - @macro-plugin/core@1.0.2 64 | 65 | ## 1.0.1 66 | 67 | ### Patch Changes 68 | 69 | - 98425cf: build: no longer publish iife 70 | - Updated dependencies [98425cf] 71 | - @macro-plugin/core@1.0.1 72 | -------------------------------------------------------------------------------- /packages/solid/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Raven Satir 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 | -------------------------------------------------------------------------------- /packages/solid/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/macro-plugin/macros/338803f77181046ab273d7d4da40850fc66dcf4d/packages/solid/README.md -------------------------------------------------------------------------------- /packages/solid/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@macro-plugin/solid", 3 | "version": "1.1.0", 4 | "description": "A simpler way of creating components for solid by using macros", 5 | "main": "dist/index.js", 6 | "module": "dist/index.mjs", 7 | "types": "dist/index.d.ts", 8 | "files": [ 9 | "dist", 10 | "CHANGELOG.md" 11 | ], 12 | "keywords": [ 13 | "solid", 14 | "solidjs", 15 | "macro", 16 | "macros" 17 | ], 18 | "scripts": { 19 | "build": "rollup -c ../../rollup.config.mjs" 20 | }, 21 | "exports": { 22 | "./package.json": "./package.json", 23 | ".": { 24 | "import": "./dist/index.mjs", 25 | "require": "./dist/index.js", 26 | "types": "./dist/index.d.ts" 27 | } 28 | }, 29 | "homepage": "https://github.com/macro-plugin/macros/tree/main/packages/solid", 30 | "repository": { 31 | "type": "git", 32 | "url": "https://github.com/macro-plugin/macros.git" 33 | }, 34 | "dependencies": { 35 | "@macro-plugin/core": "1.2.0" 36 | }, 37 | "author": "Raven Satir", 38 | "license": "MIT" 39 | } 40 | -------------------------------------------------------------------------------- /packages/solid/src/effect.ts: -------------------------------------------------------------------------------- 1 | import { createLabeledBlock } from "@macro-plugin/core" 2 | 3 | export const effect = createLabeledBlock("effect", "createEffect", "solid-js", true) 4 | -------------------------------------------------------------------------------- /packages/solid/src/index.ts: -------------------------------------------------------------------------------- 1 | export { default as signal } from "./signal" 2 | export { default as store } from "./store" 3 | export { effect } from "./effect" 4 | export { onMount, onCleanup, onError } from "./lifecycle" 5 | -------------------------------------------------------------------------------- /packages/solid/src/lifecycle.ts: -------------------------------------------------------------------------------- 1 | import { createLabeledBlock } from "@macro-plugin/core" 2 | 3 | export const onMount = createLabeledBlock("onMount", "onMount", "solid-js") 4 | export const onError = createLabeledBlock("onError", "onError", "solid-js") 5 | export const onCleanup = createLabeledBlock("onCleanup", "onCleanup", "solid-js") 6 | -------------------------------------------------------------------------------- /packages/solid/tests/__snapshots__/effect.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`solid effect macro 1`] = ` 4 | "import { createEffect } from "solid-js"; 5 | createEffect(()=>{ 6 | console.log("count =", count()); 7 | }); 8 | createEffect((prev)=>{ 9 | return prev; 10 | }); 11 | createEffect((prev)=>prev, 0); 12 | " 13 | `; 14 | -------------------------------------------------------------------------------- /packages/solid/tests/__snapshots__/lifecycle.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`solid onCleanup macro 1`] = ` 4 | "import { onCleanup } from "solid-js"; 5 | onCleanup(()=>{ 6 | console.log("on clean"); 7 | }); 8 | " 9 | `; 10 | 11 | exports[`solid onError macro 1`] = ` 12 | "import { onError } from "solid-js"; 13 | onError(()=>{ 14 | console.log("woops!"); 15 | }); 16 | onError((err)=>{ 17 | console.log(err); 18 | }); 19 | " 20 | `; 21 | 22 | exports[`solid onMount macro 1`] = ` 23 | "import { onMount } from "solid-js"; 24 | onMount(()=>{ 25 | console.log("mounted"); 26 | }); 27 | " 28 | `; 29 | -------------------------------------------------------------------------------- /packages/solid/tests/__snapshots__/signal.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`overwrite signal inside function 1`] = ` 4 | "import { createSignal } from "solid-js"; 5 | var [count, setCount] = createSignal(0); 6 | var [b, setB] = createSignal(2); 7 | setCount(3); 8 | function add(count = 0) { 9 | count += 1; 10 | } 11 | setCount(4); 12 | const plus = (b)=>{ 13 | b = 5; 14 | setCount(count() + 3); 15 | var count = 4; 16 | count += 5; 17 | }; 18 | try { 19 | console.log(123); 20 | } catch (b) { 21 | b += 2; 22 | } 23 | setB(b() + 2); 24 | setCount(count() + 2); 25 | var b = 4; 26 | b += 3; 27 | function component() { 28 | var [c, setC] = createSignal(3); 29 | setC(c() + 2); 30 | } 31 | " 32 | `; 33 | 34 | exports[`solid signal macro 1`] = ` 35 | "import { createSignal } from "solid-js"; 36 | var [count, setCount] = createSignal(0); 37 | setCount(count() + 2); 38 | setCount(5); 39 | setCount(count() * 10); 40 | setCount(count() ** 2); 41 | setCount(count()++); 42 | setCount(count()--); 43 | setCount(++count()); 44 | setCount(--count()); 45 | " 46 | `; 47 | -------------------------------------------------------------------------------- /packages/solid/tests/__snapshots__/store.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`solid store macro 1`] = ` 4 | "import { createStore } from "solid-js/store"; 5 | var [todos, setTodos] = createStore([ 6 | { 7 | id: 1, 8 | title: "Thing I have to do", 9 | done: false 10 | }, 11 | { 12 | id: 2, 13 | title: "Learn a New Framework", 14 | done: false 15 | } 16 | ]); 17 | console.log(todos); 18 | setTodos([ 19 | { 20 | id: 2, 21 | title: "Thing I have to do", 22 | done: false 23 | }, 24 | { 25 | id: 3, 26 | title: "Learn a New Framework", 27 | done: false 28 | } 29 | ]); 30 | " 31 | `; 32 | -------------------------------------------------------------------------------- /packages/solid/tests/effect.test.ts: -------------------------------------------------------------------------------- 1 | import { effect } from "@macro-plugin/solid" 2 | import { transform } from "@macro-plugin/core" 3 | 4 | test("solid effect macro", () => { 5 | const code = ` 6 | effect: { 7 | console.log("count =", count()) 8 | } 9 | 10 | effect: (prev) => { 11 | return prev; 12 | } 13 | 14 | effect: [ 15 | (prev) => prev, 16 | 0 17 | ] 18 | ` 19 | 20 | expect(transform(code, { macros: [effect] }).code).toMatchSnapshot() 21 | }) 22 | -------------------------------------------------------------------------------- /packages/solid/tests/lifecycle.test.ts: -------------------------------------------------------------------------------- 1 | import { onCleanup, onError, onMount } from "@macro-plugin/solid" 2 | 3 | import { transform } from "@macro-plugin/core" 4 | 5 | test("solid onMount macro", () => { 6 | const code = ` 7 | onMount: { 8 | console.log('mounted') 9 | } 10 | ` 11 | 12 | expect(transform(code, { macros: [onMount] }).code).toMatchSnapshot() 13 | }) 14 | 15 | test("solid onCleanup macro", () => { 16 | const code = ` 17 | onCleanup: { 18 | console.log('on clean') 19 | } 20 | ` 21 | 22 | expect(transform(code, { macros: [onCleanup] }).code).toMatchSnapshot() 23 | }) 24 | 25 | test("solid onError macro", () => { 26 | const code = ` 27 | onError: { 28 | console.log('woops!') 29 | } 30 | 31 | onError: (err) => { 32 | console.log(err) 33 | } 34 | ` 35 | 36 | expect(transform(code, { macros: [onError] }).code).toMatchSnapshot() 37 | }) 38 | -------------------------------------------------------------------------------- /packages/solid/tests/signal.test.ts: -------------------------------------------------------------------------------- 1 | import { signal } from "@macro-plugin/solid" 2 | import { transform } from "@macro-plugin/core" 3 | 4 | test("solid signal macro", () => { 5 | const code = ` 6 | signal: { 7 | var count = 0 8 | } 9 | 10 | count += 2 11 | count = 5 12 | count *= 10 13 | count **= 2 14 | count++ 15 | count-- 16 | ++count 17 | --count 18 | ` 19 | 20 | expect(transform(code, { macros: [signal] }).code).toMatchSnapshot() 21 | }) 22 | 23 | test("overwrite signal inside function", () => { 24 | const code = ` 25 | signal: { 26 | var count = 0 27 | var b = 2 28 | } 29 | 30 | count = 3 31 | 32 | function add(count = 0) { 33 | count += 1 34 | } 35 | 36 | count = 4 37 | 38 | const plus = (b) => { 39 | b = 5 40 | count += 3 41 | 42 | var count = 4 43 | count += 5 44 | } 45 | 46 | try { 47 | console.log(123) 48 | } catch (b) { 49 | b += 2 50 | } 51 | 52 | b += 2 53 | count += 2 54 | 55 | var b = 4 56 | b += 3 57 | 58 | function component() { 59 | signal: { 60 | var c = 3 61 | } 62 | 63 | c += 2 64 | } 65 | ` 66 | 67 | expect(transform(code, { macros: [signal] }).code).toMatchSnapshot() 68 | }) 69 | -------------------------------------------------------------------------------- /packages/solid/tests/store.test.ts: -------------------------------------------------------------------------------- 1 | import { store } from "@macro-plugin/solid" 2 | import { transform } from "@macro-plugin/core" 3 | 4 | test("solid store macro", () => { 5 | const code = ` 6 | store: { 7 | var todos = [ 8 | { id: 1, title: "Thing I have to do", done: false }, 9 | { id: 2, title: "Learn a New Framework", done: false }, 10 | ] 11 | } 12 | 13 | console.log(todos) 14 | 15 | todos = [ 16 | { id: 2, title: "Thing I have to do", done: false }, 17 | { id: 3, title: "Learn a New Framework", done: false }, 18 | ] 19 | ` 20 | 21 | // todos[0] = { id: 1, title: "Thing I have to do", done: false } 22 | // todos[1].id = 3; 23 | 24 | expect(transform(code, { macros: [store] }).code).toMatchSnapshot() 25 | }) 26 | -------------------------------------------------------------------------------- /packages/vite/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Raven Satir 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 | -------------------------------------------------------------------------------- /packages/vite/README.md: -------------------------------------------------------------------------------- 1 | # @macro-plugin/vite 2 | 3 | [Macro Plugin](https://github.com/macro-plugin) integration for vite. It supports transform macros and typescript and also jsx. 4 | 5 | ## Installation 6 | 7 | ```sh 8 | # if you use npm 9 | npm i -D @macro-plugin/vite 10 | # if you use pnpm 11 | pnpm i -D @macro-plugin/vite 12 | # if you use yarn 13 | yarn add -D @macro-plugin/vite 14 | ``` 15 | 16 | ## Usage 17 | 18 | `vite.config.js`: 19 | 20 | ```js 21 | import { defineConfig } from "vite" 22 | import macroPlugin from "@macro-plugin/vite" 23 | 24 | export default defineConfig({ 25 | input: "src/index.js", 26 | output: { 27 | file: "dist/index.js", 28 | format: "es" 29 | }, 30 | plugins: [ 31 | macroPlugin() 32 | ] 33 | }) 34 | ``` 35 | 36 | It will load the configuration from `macros.config.js` or `macros.config.ts` by default. You can also customize it: 37 | 38 | ```js 39 | import { defineConfig } from "vite" 40 | import macroPlugin from "@macro-plugin/vite" 41 | 42 | export default defineConfig({ 43 | input: "src/index.ts", 44 | output: { 45 | file: "dist/index.js", 46 | format: "es" 47 | }, 48 | plugins: [ 49 | macroPlugin({ emitDts: true }) 50 | ] 51 | }) 52 | ``` 53 | 54 | `macros.config.ts`: 55 | 56 | ```js 57 | import { defineConfig } from "@macro-plugin/core" 58 | 59 | export default defineConfig({ 60 | macros: [], 61 | emitDts: true, 62 | jsc: { 63 | parser: { 64 | syntax: "typescript" 65 | }, 66 | target: "esnext", 67 | }, 68 | }) 69 | ``` 70 | 71 | Or with commonjs 72 | 73 | `macros.config.js` 74 | 75 | ```js 76 | /** @type {import("@macro-plugin/core").Config} */ 77 | module.exports = { 78 | macros: [], 79 | emitDts: true, 80 | jsc: { 81 | parser: { 82 | syntax: "typescript" 83 | }, 84 | target: "esnext", 85 | }, 86 | } 87 | ``` 88 | 89 | ## License 90 | 91 | MIT 92 | 93 | [MacroPlugin]: https://github.com/macro-plugin 94 | -------------------------------------------------------------------------------- /packages/vite/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@macro-plugin/vite", 3 | "version": "1.2.2", 4 | "description": "Macro plugins integration for vite", 5 | "main": "dist/index.js", 6 | "module": "dist/index.mjs", 7 | "types": "dist/index.d.ts", 8 | "files": [ 9 | "dist", 10 | "CHANGELOG.md" 11 | ], 12 | "scripts": { 13 | "build": "rollup -c ../../rollup.config.mjs" 14 | }, 15 | "keywords": [ 16 | "vite", 17 | "vitejs", 18 | "vite-plugin", 19 | "macro", 20 | "macro-plugin" 21 | ], 22 | "homepage": "https://github.com/macro-plugin/macros/tree/main/packages/vite", 23 | "repository": { 24 | "type": "git", 25 | "url": "https://github.com/macro-plugin/macros.git" 26 | }, 27 | "dependencies": { 28 | "@macro-plugin/core": "1.2.0", 29 | "@macro-plugin/shared": "1.2.1" 30 | }, 31 | "devDependencies": { 32 | "vite": "^4.2.0" 33 | }, 34 | "exports": { 35 | "./package.json": "./package.json", 36 | ".": { 37 | "require": "./dist/index.js", 38 | "import": "./dist/index.mjs", 39 | "types": "./dist/index.d.ts" 40 | } 41 | }, 42 | "author": "Raven Satir", 43 | "license": "MIT" 44 | } 45 | -------------------------------------------------------------------------------- /packages/vite/src/index.ts: -------------------------------------------------------------------------------- 1 | import { Config, createSwcPlugin, getSpanOffset, transformAsync } from "@macro-plugin/core" 2 | import { SCRIPT_EXTENSIONS, buildTransformOptions, createFilter, createResolver, createTsLib, createTsResolver, getHasModuleSideEffects, getIdMatcher, matchScriptType, patchTsOptions, resolveTsOptions } from "@macro-plugin/shared" 3 | import { dirname, resolve } from "path" 4 | import { minify as swcMinify, parse as swcParse, transform as swcTransform } from "@swc/core" 5 | 6 | import type { Plugin } from "vite" 7 | import type { TreeshakingOptions } from "rollup" 8 | 9 | const isMacroExternal = (id: string) => /(@macro-plugin)|@swc/.test(id) 10 | 11 | async function viteMacroPlugin (config?: Config): Promise { 12 | const [basicSwcOptions, macroOptions] = await buildTransformOptions(config) 13 | const filter = createFilter(macroOptions.include, macroOptions.exclude) 14 | const extensions = macroOptions.extensions || SCRIPT_EXTENSIONS 15 | 16 | const plugin: Plugin = { 17 | name: "viteMacroPlugin", 18 | resolveId: createResolver(extensions), 19 | async transform (code, id) { 20 | if (!filter(id)) return null 21 | 22 | const target = matchScriptType(id, extensions) 23 | if (!target) return null 24 | 25 | if (macroOptions.swcTransform == null || macroOptions.swcTransform === true) { 26 | const { isTypeScript, isJsx, isTsx } = target 27 | 28 | // use swc transform typescript and jsx 29 | if (isTypeScript || isJsx) { 30 | const macroPlugin = createSwcPlugin(macroOptions, code, getSpanOffset()) 31 | const swcOptions = patchTsOptions({ 32 | ...basicSwcOptions, 33 | filename: id, 34 | minify: false 35 | }, macroOptions.tsconfig === false ? undefined : resolveTsOptions(dirname(id), macroOptions.tsconfig), isTypeScript, isTsx, isJsx) 36 | const program = await swcParse(code, swcOptions.jsc?.parser || { syntax: "typescript" }) 37 | return await swcTransform(macroPlugin(program), swcOptions) 38 | } 39 | } 40 | 41 | // native macro transform without swc 42 | return await transformAsync(code, macroOptions) 43 | }, 44 | options (options) { 45 | // ignore warning on @macro-plugin 46 | const oldWarn = options.onwarn 47 | options.onwarn = (warning, warn) => { 48 | if (warning.exporter && isMacroExternal(warning.exporter) && ["UNRESOLVED_IMPORT", "UNUSED_EXTERNAL_IMPORT"].includes(warning.code || "")) return 49 | oldWarn ? oldWarn(warning, warn) : warn(warning) 50 | } 51 | 52 | // add @macro-plugin to external 53 | const matchExternal = getIdMatcher(options.external) 54 | options.external = (source, importer, isResolved) => isMacroExternal(source) || matchExternal(source, importer, isResolved) 55 | 56 | // add no-side-effects support for @macro-plugin 57 | const oldTreeshake = options.treeshake 58 | const getSideEffects = getHasModuleSideEffects(typeof oldTreeshake === "object" ? oldTreeshake.moduleSideEffects : undefined) 59 | options.treeshake = { 60 | ...(typeof oldTreeshake === "object" ? oldTreeshake : {}), 61 | moduleSideEffects: (id, external) => isMacroExternal(id) ? false : getSideEffects(id, external), 62 | preset: typeof oldTreeshake === "string" ? oldTreeshake : (oldTreeshake as TreeshakingOptions | undefined)?.preset 63 | } 64 | }, 65 | renderChunk (code) { 66 | if (basicSwcOptions.minify || basicSwcOptions.jsc?.minify?.mangle || basicSwcOptions.jsc?.minify?.compress) { 67 | return swcMinify(code, basicSwcOptions.jsc?.minify) 68 | } 69 | 70 | return null 71 | } 72 | } 73 | 74 | if (macroOptions.resolveTs) { 75 | const tslib = createTsLib() 76 | const tsOptions = macroOptions.tsconfig === false ? {} : resolveTsOptions(resolve("."), macroOptions.tsconfig) 77 | plugin.resolveId = createTsResolver(tslib, tsOptions, filter) 78 | plugin.load = (id) => { 79 | if (id === tslib.virtual) return tslib.source 80 | } 81 | } else { 82 | plugin.resolveId = createResolver(extensions) 83 | } 84 | 85 | return plugin 86 | } 87 | 88 | export default viteMacroPlugin 89 | -------------------------------------------------------------------------------- /packages/vue/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Raven Satir 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 | -------------------------------------------------------------------------------- /packages/vue/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/macro-plugin/macros/338803f77181046ab273d7d4da40850fc66dcf4d/packages/vue/README.md -------------------------------------------------------------------------------- /packages/vue/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@macro-plugin/vue", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "A simpler way of creating components for vue by using macros", 6 | "main": "dist/vue.js", 7 | "module": "dist/vue.mjs", 8 | "types": "./dist/vue.d.ts", 9 | "files": [ 10 | "dist", 11 | "CHANGELOG.md" 12 | ], 13 | "keywords": [ 14 | "vue", 15 | "vuejs", 16 | "macro", 17 | "macros", 18 | "macro-plugin" 19 | ], 20 | "homepage": "https://github.com/macro-plugin/macros/tree/main/packages/vue", 21 | "repository": { 22 | "type": "git", 23 | "url": "https://github.com/macro-plugin/macros.git" 24 | }, 25 | "exports": { 26 | "./package.json": "./package.json", 27 | ".": { 28 | "import": "./dist/vue.mjs", 29 | "require": "./dist/vue.js", 30 | "types": "./dist/vue.d.ts" 31 | } 32 | }, 33 | "author": "Raven Satir", 34 | "license": "MIT" 35 | } 36 | -------------------------------------------------------------------------------- /packages/webpack/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @macro-plugin/webpack 2 | 3 | ## 1.2.1 4 | 5 | ### Patch Changes 6 | 7 | - Updated dependencies [[`8c94045`](https://github.com/macro-plugin/macros/commit/8c9404545d207b708ed433328bd383488a3ed0d4), [`b45063f`](https://github.com/macro-plugin/macros/commit/b45063ff784e513380f43bf8425c4f72eaa5c0b4)]: 8 | - @macro-plugin/core@1.2.0 9 | - @macro-plugin/shared@1.2.1 10 | 11 | ## 1.2.0 12 | 13 | ### Minor Changes 14 | 15 | - [#29](https://github.com/macro-plugin/macros/pull/29) [`34175b3`](https://github.com/macro-plugin/macros/commit/34175b39dad726b139f32c8ded15cce10b68db85) Thanks [@voorjaar](https://github.com/voorjaar)! - feat: support filename filter with include and exclude options 16 | feat: support resolve tsconfig 17 | 18 | ### Patch Changes 19 | 20 | - Updated dependencies [[`c398ad6`](https://github.com/macro-plugin/macros/commit/c398ad61bd1aa9b79c1a98f7e811323f996f5658), [`e3ce376`](https://github.com/macro-plugin/macros/commit/e3ce37696e0a21bdddb56804f7dbcfa904f5fd35), [`b1d3bff`](https://github.com/macro-plugin/macros/commit/b1d3bffcac4ef25930bd7ee4409664f6fb00fb06)]: 21 | - @macro-plugin/shared@1.2.0 22 | - @macro-plugin/core@1.1.4 23 | 24 | ## 1.1.0 25 | 26 | ### Minor Changes 27 | 28 | - [#27](https://github.com/macro-plugin/macros/pull/27) [`6bd5f72`](https://github.com/macro-plugin/macros/commit/6bd5f72fcb89ae988e218a447cbc3d56298174f7) Thanks [@voorjaar](https://github.com/voorjaar)! - refactor: use plugin with swc parse api 29 | 30 | ### Patch Changes 31 | 32 | - Updated dependencies []: 33 | - @macro-plugin/core@1.1.3 34 | 35 | ## 1.0.6 36 | 37 | ### Patch Changes 38 | 39 | - Updated dependencies [[`294f675`](https://github.com/macro-plugin/macros/commit/294f67574c5ff168bdeb0a499ea4ab2fd57579cf)]: 40 | - @macro-plugin/core@1.1.2 41 | 42 | ## 1.0.5 43 | 44 | ### Patch Changes 45 | 46 | - Updated dependencies [[`b4be79b`](https://github.com/macro-plugin/macros/commit/b4be79be09e8790b95c6a2e9b07dde4ba3822f39), [`df8dcc0`](https://github.com/macro-plugin/macros/commit/df8dcc0ab7f3e09f1157c5c2a7cda4a7f5367991)]: 47 | - @macro-plugin/core@1.1.1 48 | 49 | ## 1.0.4 50 | 51 | ### Patch Changes 52 | 53 | - Updated dependencies [[`4155bb4`](https://github.com/macro-plugin/macros/commit/4155bb4de7968a83e62203411bceae6b0602637f), [`6b25910`](https://github.com/macro-plugin/macros/commit/6b25910567e910b7c71c79646f8569a2f3927be6), [`8dd4939`](https://github.com/macro-plugin/macros/commit/8dd493997931d8d91a82ffb1785927d425c17c61), [`14efcb2`](https://github.com/macro-plugin/macros/commit/14efcb2c6461ab3f5d78e0599ec74b422085ce1d), [`7787022`](https://github.com/macro-plugin/macros/commit/7787022f657b7a79cb18a1e8ba947ae2eaeb682e), [`a17b055`](https://github.com/macro-plugin/macros/commit/a17b055d356c285b394add56192c80077ebde2c2)]: 54 | - @macro-plugin/core@1.1.0 55 | 56 | ## 1.0.3 57 | 58 | ### Patch Changes 59 | 60 | - Updated dependencies [[`07961a0`](https://github.com/macro-plugin/macros/commit/07961a03b6e82080a2b8c8ab2626c187c34f912e), [`f1e40ea`](https://github.com/macro-plugin/macros/commit/f1e40ead32636d4f2d43c442e70cc208e2d43b28), [`556ca2d`](https://github.com/macro-plugin/macros/commit/556ca2d9addaf36ac84da8c8ea7b5bc465e174b7)]: 61 | - @macro-plugin/core@1.0.3 62 | 63 | ## 1.0.2 64 | 65 | ### Patch Changes 66 | 67 | - [#9](https://github.com/macro-plugin/macros/pull/9) [`2c64787`](https://github.com/macro-plugin/macros/commit/2c647875182c5fc6ca41c9e72587a08307ba90ec) Thanks [@voorjaar](https://github.com/voorjaar)! - chore: upgrade to swc 1.3.53 68 | 69 | - Updated dependencies [[`2c64787`](https://github.com/macro-plugin/macros/commit/2c647875182c5fc6ca41c9e72587a08307ba90ec)]: 70 | - @macro-plugin/core@1.0.2 71 | 72 | ## 1.0.1 73 | 74 | ### Patch Changes 75 | 76 | - 98425cf: build: no longer publish iife 77 | - Updated dependencies [98425cf] 78 | - @macro-plugin/core@1.0.1 79 | -------------------------------------------------------------------------------- /packages/webpack/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Raven Satir 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 | -------------------------------------------------------------------------------- /packages/webpack/README.md: -------------------------------------------------------------------------------- 1 | # @macro-plugin/webpack 2 | 3 | [Macro Plugin](https://github.com/macro-plugin) integration for vite. It supports transform macros and typescript and also jsx. 4 | 5 | ## Installation 6 | 7 | ```sh 8 | # if you use npm 9 | npm i -D @macro-plugin/webpack 10 | # if you use pnpm 11 | pnpm i -D @macro-plugin/webpack 12 | # if you use yarn 13 | yarn add -D @macro-plugin/webpack 14 | ``` 15 | 16 | ## Usage 17 | 18 | `webpack.config.js`: 19 | 20 | ```js 21 | import { resolve } from "path" 22 | 23 | /** @type { import("webpack").Configuration } */ 24 | export default { 25 | mode: "production", 26 | entry: resolve("./src/index.ts"), 27 | output: { 28 | path: resolve("./dist"), 29 | filename: "index.js" 30 | }, 31 | module: { 32 | rules: [ 33 | { 34 | test: /\.(t|j)sx?$/, 35 | exclude: /node_modules/, 36 | use: [ 37 | { 38 | loader: "@macro-plugin/webpack" 39 | } 40 | ] 41 | } 42 | ] 43 | } 44 | } 45 | ``` 46 | 47 | It will load the configuration from `macros.config.js` or `macros.config.ts` by default. You can also customize it: 48 | 49 | ```js 50 | import { resolve } from "path" 51 | 52 | /** @type { import("webpack").Configuration } */ 53 | export default { 54 | mode: "production", 55 | entry: resolve("./src/index.ts"), 56 | output: { 57 | path: resolve("./dist"), 58 | filename: "index.js" 59 | }, 60 | module: { 61 | rules: [ 62 | { 63 | test: /\.(t|j)sx?$/, 64 | exclude: /node_modules/, 65 | use: [ 66 | { 67 | loader: "@macro-plugin/webpack", 68 | /** @type { import("@macro-plugin/core").Config } */ 69 | options: { 70 | emitDts: true 71 | } 72 | } 73 | ] 74 | } 75 | ] 76 | } 77 | } 78 | ``` 79 | 80 | `macros.config.ts`: 81 | 82 | ```js 83 | import { defineConfig } from "@macro-plugin/core" 84 | 85 | export default defineConfig({ 86 | macros: [], 87 | emitDts: true, 88 | jsc: { 89 | parser: { 90 | syntax: "typescript" 91 | }, 92 | target: "esnext", 93 | }, 94 | }) 95 | ``` 96 | 97 | Or with commonjs 98 | 99 | `macros.config.js` 100 | 101 | ```js 102 | /** @type {import("@macro-plugin/core").Config} */ 103 | module.exports = { 104 | macros: [], 105 | emitDts: true, 106 | jsc: { 107 | parser: { 108 | syntax: "typescript" 109 | }, 110 | target: "esnext", 111 | }, 112 | } 113 | ``` 114 | 115 | ## License 116 | 117 | MIT 118 | 119 | [MacroPlugin]: https://github.com/macro-plugin 120 | -------------------------------------------------------------------------------- /packages/webpack/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@macro-plugin/webpack", 3 | "version": "1.2.1", 4 | "description": "Macro plugins integration for webpack", 5 | "main": "dist/index.js", 6 | "module": "dist/index.mjs", 7 | "types": "dist/index.d.ts", 8 | "files": [ 9 | "dist", 10 | "CHANGELOG.md" 11 | ], 12 | "scripts": { 13 | "build": "rollup -c ../../rollup.config.mjs" 14 | }, 15 | "keywords": [ 16 | "webpack", 17 | "macro", 18 | "macro-plugin" 19 | ], 20 | "homepage": "https://github.com/macro-plugin/macros/tree/main/packages/webpack", 21 | "repository": { 22 | "type": "git", 23 | "url": "https://github.com/macro-plugin/macros.git" 24 | }, 25 | "dependencies": { 26 | "@macro-plugin/core": "1.2.0", 27 | "@macro-plugin/shared": "1.2.1" 28 | }, 29 | "devDependencies": { 30 | "webpack": "^5.80.0" 31 | }, 32 | "exports": { 33 | "./package.json": "./package.json", 34 | ".": { 35 | "require": "./dist/index.js", 36 | "import": "./dist/index.mjs", 37 | "types": "./dist/index.d.ts" 38 | } 39 | }, 40 | "author": "Raven Satir", 41 | "license": "MIT" 42 | } 43 | -------------------------------------------------------------------------------- /packages/webpack/src/types.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from "@macro-plugin/core" 2 | 3 | export type LoaderOptions = Config & { 4 | sourceMap?: string | boolean 5 | customize?: boolean 6 | cacheDirectory?: boolean 7 | cacheIdentifier?: boolean 8 | cacheCompression?: boolean 9 | metadataSubscribers?: boolean 10 | } 11 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - 'packages/*' 3 | - "examples/*" 4 | -------------------------------------------------------------------------------- /rollup.config.mjs: -------------------------------------------------------------------------------- 1 | import { readFileSync, rmSync, writeFileSync } from "fs" 2 | 3 | import commonjs from "@rollup/plugin-commonjs" 4 | import { defineConfig } from "rollup" 5 | import dts from "rollup-plugin-dts" 6 | import json from "@rollup/plugin-json" 7 | import nodeResolve from "@rollup/plugin-node-resolve" 8 | import path from "path" 9 | import typescript from "rollup-plugin-typescript2" 10 | 11 | const name = path.basename(path.resolve(".")) 12 | const pkg = JSON.parse(readFileSync("./package.json").toString()) 13 | const external = [ 14 | ...Object.keys(pkg.dependencies || {}), 15 | "fs", 16 | "path", 17 | "vite", 18 | "rollup", 19 | "webpack", 20 | "typescript", 21 | "@swc/core", 22 | "@macro-plugin/core" 23 | ] 24 | 25 | /** 26 | * @returns {import("rollup").OutputOptions[]} 27 | */ 28 | function createOutput () { 29 | return [ 30 | { 31 | file: "dist/index.js", 32 | format: "cjs", 33 | }, 34 | { 35 | file: "dist/index.mjs", 36 | format: "es", 37 | } 38 | ] 39 | } 40 | 41 | export default defineConfig([ 42 | { 43 | input: "./src/index.ts", 44 | output: createOutput(), 45 | plugins: [ 46 | { 47 | name: "del", 48 | transform (code, id) { 49 | if (id.endsWith(".cts") || id.endsWith(".mts")) return "" 50 | }, 51 | buildStart () { 52 | rmSync("./dist", { recursive: true, force: true }) 53 | } 54 | }, 55 | json(), 56 | nodeResolve(), 57 | commonjs(), 58 | typescript({ 59 | tsconfigOverride: { 60 | include: ["packages/**/src"] 61 | } 62 | }) 63 | ], 64 | onwarn (warning, warn) { 65 | if (warning.code === "CIRCULAR_DEPENDENCY") return 66 | warn(warning) 67 | }, 68 | external 69 | }, 70 | { 71 | input: `./dist/packages/${name}/src/index.d.ts`, 72 | output: [{ 73 | file: "dist/index.d.ts", 74 | format: "es" 75 | }], 76 | plugins: [ 77 | dts({ respectExternal: true }), 78 | { 79 | name: "del", 80 | buildEnd () { 81 | rmSync("./dist/packages", { recursive: true, force: true }) 82 | }, 83 | closeBundle () { 84 | if (name === "shared") { 85 | writeFileSync("./dist/index.d.ts", readFileSync("./dist/index.d.ts").toString().replace("const scan: typeof scan;", "").replace("const constants: typeof constants;", "")) 86 | } 87 | } 88 | } 89 | ], 90 | external 91 | } 92 | ]) 93 | -------------------------------------------------------------------------------- /scripts/release.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | const path = require("path") 3 | const { readdirSync, existsSync } = require("fs") 4 | const { exec, getExecOutput } = require("@actions/exec") 5 | 6 | const { version } = require("../packages/core/package.json") 7 | const tag = `v${version}` 8 | const releaseLine = `v${version.split(".")[0]}` 9 | 10 | process.chdir(path.join(__dirname, "..")); 11 | 12 | (async () => { 13 | const { exitCode, stderr } = await getExecOutput( 14 | "git", 15 | ["ls-remote", "--exit-code", "origin", "--tags", `refs/tags/${tag}`], 16 | { 17 | ignoreReturnCode: true, 18 | } 19 | ) 20 | if (exitCode === 0) { 21 | console.log( 22 | `Action is not being published because version ${tag} is already published` 23 | ) 24 | return 25 | } 26 | if (exitCode !== 2) { 27 | throw new Error(`git ls-remote exited with ${exitCode}:\n${stderr}`) 28 | } 29 | 30 | // publish to npm 31 | await exec("changeset", ["publish"]) 32 | 33 | // push to github 34 | await exec("git", ["checkout", "--detach"]) 35 | 36 | for (const pkg of readdirSync("packages")) { 37 | if (existsSync(path.resolve(`packages/${pkg}/dist`))) { 38 | await exec("git", ["add", "--force", `packages/${pkg}/dist`]) 39 | } 40 | } 41 | 42 | await exec("git", ["commit", "-m", tag]) 43 | 44 | await exec("changeset", ["tag"]) 45 | 46 | await exec("git", [ 47 | "push", 48 | "--force", 49 | "--follow-tags", 50 | "origin", 51 | `HEAD:refs/heads/${releaseLine}`, 52 | ]) 53 | })() 54 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["ESNext", "DOM"], 4 | "outDir": "dist", 5 | "target": "ES2017", 6 | "module": "ESNext", 7 | "rootDir": ".", 8 | "moduleResolution": "node", 9 | "baseUrl": ".", 10 | "declaration": true, 11 | "stripInternal": true, 12 | "esModuleInterop": true, 13 | "noEmitOnError": true, 14 | "allowUnusedLabels": true, 15 | "forceConsistentCasingInFileNames": true, 16 | "strict": true, 17 | "checkJs": true, 18 | "allowJs": true, 19 | "resolveJsonModule": true, 20 | "skipLibCheck": true, 21 | "paths": { 22 | "@macro-plugin/*": ["packages/*/src"] 23 | } 24 | }, 25 | "exclude": [ 26 | "**/dist/**" 27 | ] 28 | } 29 | --------------------------------------------------------------------------------