├── .cargo └── config ├── .github └── workflows │ └── release.yml ├── .gitignore ├── .gitmodules ├── .npmignore ├── .travis.yml ├── README.md ├── __tests__ ├── env │ └── env_test.js ├── error_test.js ├── import_test.js ├── module_test.js ├── parse │ └── api_test.js ├── script_test.js └── transform │ ├── api_test.js │ ├── optimizer_test.js │ ├── plugin_test.js │ └── sourcemap_test.js ├── benches ├── multicore.js ├── plugin.js ├── transform.js └── typescript.js └── scripts ├── ci ├── build-github.sh ├── linux-musl │ ├── Dockerfile │ ├── build.sh │ └── start-docker.sh ├── linux │ ├── Dockerfile │ ├── build.sh │ └── start-docker.sh └── settings.txt ├── tag.sh └── update.sh /.cargo/config: -------------------------------------------------------------------------------- 1 | 2 | [build] 3 | rustflags = [ 4 | "--cfg", "procmacro2_semver_exempt", 5 | "-Z", "thinlto=no", 6 | ] 7 | 8 | 9 | # # Enable lto for linux 10 | 11 | # [target.x86_64-unknown-linux-gnu] 12 | # rustflags = [ 13 | # "--cfg", "procmacro2_semver_exempt", 14 | # "-Z", "thinlto=no", 15 | # "-Clto" 16 | # ] 17 | 18 | # [target.x86_64-pc-windows-gnu] 19 | # rustflags = [ 20 | # "--cfg", "procmacro2_semver_exempt", 21 | # "-Z", "thinlto=no", 22 | # "-Clto" 23 | # ] 24 | 25 | # [target.x86_64-pc-windows-msvc] 26 | # rustflags = [ 27 | # "--cfg", "procmacro2_semver_exempt", 28 | # "-Z", "thinlto=no", 29 | # "-Clto" 30 | # ] 31 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - "*.*.*" 7 | 8 | jobs: 9 | build: 10 | strategy: 11 | fail-fast: false 12 | matrix: 13 | platform: [macos-latest, windows-latest] 14 | runs-on: ${{ matrix.platform }} 15 | env: 16 | SKIP_SWC_BINARY_DOWNLOAD_FOR_CI: 1 17 | CI: 1 18 | CARGO_INCREMENTAL: 0 19 | DISABLE_OPENCOLLECTIVE: 1 20 | steps: 21 | - uses: actions/checkout@v2 22 | with: 23 | submodules: true 24 | 25 | - uses: actions/setup-node@v1 26 | with: 27 | node-version: 8 28 | - name: Install npm dependencies 29 | run: | 30 | (cd swc && npm install) 31 | 32 | - name: Build for nodejs 8 33 | run: | 34 | bash ./scripts/ci/build-github.sh 8.15.0 57 35 | 36 | - uses: actions/setup-node@v1 37 | with: 38 | node-version: 10 39 | - name: Build for nodejs 10 40 | run: | 41 | bash ./scripts/ci/build-github.sh 10.15.0 64 42 | 43 | # - uses: actions/setup-node@v1 44 | # with: 45 | # node-version: 11 46 | # - name: Build for nodejs 11 47 | # run: | 48 | # bash ./scripts/ci/build-github.sh 11.6.0 67 49 | 50 | - uses: actions/setup-node@v1 51 | with: 52 | node-version: 12 53 | - name: Build for nodejs 12 54 | run: | 55 | bash ./scripts/ci/build-github.sh 12.11.0 72 56 | 57 | - uses: actions/setup-node@v1 58 | with: 59 | node-version: 13 60 | - name: Build for nodejs 13 61 | run: | 62 | bash ./scripts/ci/build-github.sh 13.3.0 79 63 | 64 | - uses: actions/setup-node@v1 65 | with: 66 | node-version: 14 67 | - name: Build for nodejs 14 68 | run: | 69 | bash ./scripts/ci/build-github.sh 14.2.0 83 70 | 71 | - name: Publish prebuilt binaries 72 | uses: softprops/action-gh-release@v1 73 | with: 74 | files: "swc/*.node" 75 | env: 76 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 77 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | native/index.node 3 | native/artifacts.json 4 | **/*~ 5 | **/node_modules 6 | **/.DS_Store 7 | 8 | pkg/ 9 | 10 | yarn.lock 11 | package-lock.json 12 | *.log 13 | .idea/ 14 | 15 | # Built files 16 | /*.js 17 | /*.d.ts -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "swc"] 2 | path = swc 3 | url = https://github.com/swc-project/swc.git 4 | shallow = true -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | native/target 2 | native/index.node 3 | native/artifacts.json 4 | **/*~ 5 | **/node_modules 6 | **/.DS_Store 7 | 8 | yarn.lock 9 | package-lock.json 10 | *.log 11 | .idea/ 12 | wasm/ -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: shell 2 | sudo: false 3 | osx_image: xcode11.3 4 | services: 5 | - docker 6 | 7 | branches: 8 | except: 9 | - master 10 | 11 | install: 12 | - if [[ "$TRAVIS_OS_NAME" != "windows" ]]; then rm -rf ~/.nvm ; fi 13 | - if [[ "$TRAVIS_OS_NAME" != "windows" ]]; then git clone https://github.com/creationix/nvm.git ~/.nvm ; fi 14 | - if [[ "$TRAVIS_OS_NAME" != "windows" ]]; then source ~/.nvm/nvm.sh ; fi 15 | - nvm version 16 | - nvm install 12.11.0 17 | - nvm install 11.6.0 18 | - nvm install 10.15.0 19 | - nvm install 8.15.0 20 | - which node 21 | - node --version 22 | - which npm 23 | # - npm --version 24 | 25 | # Install nightly rust 26 | - if [[ "$TRAVIS_OS_NAME" != "windows" ]]; then (curl https://sh.rustup.rs -sSf > /tmp/rustup.sh); fi 27 | - if [[ "$TRAVIS_OS_NAME" != "windows" ]]; then sh /tmp/rustup.sh --default-toolchain none -y; fi 28 | - if [[ "$TRAVIS_OS_NAME" != "windows" ]]; then export PATH="$HOME/.cargo/bin:$PATH"; fi 29 | - if [[ "$TRAVIS_OS_NAME" != "windows" ]]; then rustup toolchain install nightly; fi 30 | - ls -al ~/.rustup/toolchains 31 | 32 | # Need to cache the whole `.cargo` directory to keep .crates.toml for 33 | # cargo-update to work 34 | cache: 35 | npm: true 36 | directories: 37 | - /home/travis/.cargo 38 | # But don't cache the cargo registry 39 | # before_cache: 40 | # - rm -rf /home/travis/.cargo/registry 41 | 42 | deploy: 43 | provider: releases 44 | api_key: $GH_TOKEN 45 | file: 46 | # - $SWC_NAME-48.node 47 | - swc/$SWC_NAME-57.node 48 | - swc/$SWC_NAME-64.node 49 | - swc/$SWC_NAME-67.node 50 | - swc/$SWC_NAME-72.node 51 | - swc/$SWC_NAME-79.node 52 | - swc/$SWC_NAME-83.node 53 | skip_cleanup: true 54 | on: 55 | tags: true 56 | 57 | matrix: 58 | include: 59 | 60 | - os: linux 61 | env: 62 | - SWC_NAME=linux-x64 63 | - NODE_ABI=83 64 | install: 65 | - ./scripts/ci/linux/start-docker.sh 14.2.0 83 14.x 66 | script: 67 | - travis_wait 30 docker exec target-83 sh ./scripts/ci/linux/build.sh 83 68 | 69 | - os: linux 70 | env: 71 | - SWC_NAME=linux-x64 72 | - NODE_ABI=79 73 | install: 74 | - ./scripts/ci/linux/start-docker.sh 13.3.0 79 13.x 75 | script: 76 | - travis_wait 30 docker exec target-79 sh ./scripts/ci/linux/build.sh 79 77 | 78 | - os: linux 79 | env: 80 | - SWC_NAME=linux-x64 81 | - NODE_ABI=72 82 | install: 83 | - ./scripts/ci/linux/start-docker.sh 12.12 72 12.x 84 | script: 85 | - travis_wait 30 docker exec target-72 sh ./scripts/ci/linux/build.sh 72 86 | 87 | - os: linux 88 | env: 89 | - SWC_NAME=linux-x64 90 | - NODE_ABI=64 91 | install: 92 | - ./scripts/ci/linux/start-docker.sh 10 64 10.x 93 | script: 94 | - travis_wait 30 docker exec target-64 sh ./scripts/ci/linux/build.sh 64 95 | 96 | - os: linux 97 | env: 98 | - SWC_NAME=linux-x64 99 | - NODE_ABI=57 100 | install: 101 | - ./scripts/ci/linux/start-docker.sh 8 57 8.x 102 | script: 103 | - travis_wait 30 docker exec target-57 sh ./scripts/ci/linux/build.sh 57 104 | 105 | # - os: linux 106 | # env: 107 | # - SWC_NAME=linux_musl-x64 108 | # - NODE_ABI=83 109 | # install: 110 | # - ./scripts/ci/linux-musl/start-docker.sh 14.2.0 83 14 111 | # script: 112 | # - travis_wait 30 docker exec target-83 sh ./scripts/ci/linux-musl/build.sh 83 113 | 114 | # - os: linux 115 | # env: 116 | # - SWC_NAME=linux_musl-x64 117 | # - NODE_ABI=79 118 | # install: 119 | # - ./scripts/ci/linux-musl/start-docker.sh 13.3.0 79 13 120 | # script: 121 | # - travis_wait 30 docker exec target-79 sh ./scripts/ci/linux-muslbuild.sh 79 122 | 123 | # - os: linux 124 | # env: 125 | # - SWC_NAME=linux_musl-x64 126 | # - NODE_ABI=72 127 | # install: 128 | # - ./scripts/ci/linux-musl/start-docker.sh 12.12 72 12 129 | # script: 130 | # - travis_wait 30 docker exec target-72 sh ./scripts/ci/linux-muslbuild.sh 72 131 | 132 | # - os: linux 133 | # env: 134 | # - SWC_NAME=linux_musl-x64 135 | # - NODE_ABI=64 136 | # install: 137 | # - ./scripts/ci/linux-musl/start-docker.sh 10 64 10 138 | # script: 139 | # - travis_wait 30 docker exec target-64 sh ./scripts/ci/linux-muslbuild.sh 64 140 | 141 | # - os: linux 142 | # env: 143 | # - SWC_NAME=linux_musl-x64 144 | # - NODE_ABI=57 145 | # install: 146 | # - ./scripts/ci/linux-musl/start-docker.sh 8 57 8 147 | # script: 148 | # - travis_wait 30 docker exec target-57 sh ./scripts/ci/linux-muslbuild.sh 57 149 | 150 | env: 151 | - CARGO_INCREMENTAL=0 152 | 153 | notifications: 154 | slack: 155 | secure: Zof7PCQoe1TiksHUAU3hg3vwFBpxCvtJoGl0OlERHaKMtcMGF0SpcrYOtYHfjXXJx8RPW8nh/4A9sMp/ljoKP9K17IycwAoeGCqoE8fbqXtTf6IgIK+oKmMbFGLRcZLM0AtHv9xVP80WInNwQx+Si9TuuBL/yqBoOLYEc9o9I0euC7GM5DLD8/FXZeR28M+AraBCdFDUpTmEibWIc90pCHWPM7jWFVbCHrO/UqlwbficoNNRJiXYtVPw0dLGHI5feDP7lZMXRDggfwXaKa3IYPn0aEIrm8cM4RPd8LabuUmplZPu/+bBZnYAkB+JGPpC999eSnDTkI8GxPSJVVG3D5sbDGNB3XK/KKWT/Tn1GdJp0TJunYG5VGY7FiXs31J1xLqxVaBWEiEusC/TjUF2mK2oWSo9m5XVNGzN4XiMMzug5fmS0gbV283qnYY0nH5lDxeoBixeSqBkKPpMz4wbdV7kXkaTM5kPLQUw61+jw6AeKDDb6KcMt4xe4+/xwJg+Gbiey1ZcCwltcE79vqkoxwClJFvXA45UD96iylWiYx1pGQgBNs68v5mQgWF7M+M3UkeMHXsyJ+zKn6yxchumyvaQ9euW0AhY/GRkPZblfm6Lznk6qK2V/lOR6wsO5T+4TpIDAsIYgK+fFJioNbWujueXCfNvbVr2FntcwOH5Zmk= 156 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # node-swc 2 | 3 | [![Build Status](https://travis-ci.com/swc-project/node-swc.svg?branch=master)](https://travis-ci.com/swc-project/node-swc) 4 | ![Release](https://github.com/swc-project/node-swc/workflows/Release/badge.svg?event=push) 5 | nodejs binding for [the swc project][]. 6 | 7 | [the swc project]: https://github.com/swc-project/swc 8 | -------------------------------------------------------------------------------- /__tests__/env/env_test.js: -------------------------------------------------------------------------------- 1 | const swc = require("../.."); 2 | const path = require("path"); 3 | 4 | it("should handle browserlistrc", () => { 5 | const filename = path.resolve( 6 | __dirname + "/../../tests/env/default/input.js" 7 | ); 8 | expect(swc.transformFileSync(filename).code.trim()).toContain( 9 | `const a of foo` 10 | ); 11 | }); 12 | 13 | it("should handle targets in env", () => { 14 | const filename = path.resolve( 15 | __dirname + "/../../tests/env/targets/input.js" 16 | ); 17 | expect(swc.transformFileSync(filename).code.trim()).toContain( 18 | `const a of foo` 19 | ); 20 | }); 21 | -------------------------------------------------------------------------------- /__tests__/error_test.js: -------------------------------------------------------------------------------- 1 | const swc = require("../"); 2 | 3 | it("should work", () => { 4 | expect(() => { 5 | swc.transformFileSync(__dirname + "/../tests/error/simple.js"); 6 | }).toThrow("jsc"); 7 | }); 8 | -------------------------------------------------------------------------------- /__tests__/import_test.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | it('should work', () => { 4 | require('../') 5 | }) -------------------------------------------------------------------------------- /__tests__/module_test.js: -------------------------------------------------------------------------------- 1 | const swc = require("../"); 2 | 3 | it("should emit _interopRequireDefault", () => { 4 | const out = swc.transformSync('import foo from "foo"', { 5 | module: { 6 | type: "commonjs" 7 | } 8 | }); 9 | expect(out.map).toBeFalsy(); 10 | 11 | expect(out.code).toContain(`function _interopRequireDefault`); 12 | expect(out.code).toContain( 13 | `var _foo = _interopRequireDefault(require('foo'))` 14 | ); 15 | }); 16 | 17 | it("should emit _interopRequireWildcard", () => { 18 | const out = swc.transformSync('import * as foo from "foo"', { 19 | module: { 20 | type: "commonjs" 21 | } 22 | }); 23 | expect(out.map).toBeFalsy(); 24 | 25 | expect(out.code).toContain(`function _interopRequireWildcard`); 26 | expect(out.code).toContain( 27 | `var foo = _interopRequireWildcard(require('foo'))` 28 | ); 29 | }); 30 | 31 | it("should work with amd and expternal helpers", () => { 32 | const out = swc.transformSync( 33 | `class Foo {} 34 | class Bar extends Foo {}`, 35 | { 36 | jsc: { 37 | externalHelpers: true 38 | }, 39 | module: { 40 | type: "amd", 41 | moduleId: "a" 42 | } 43 | } 44 | ); 45 | 46 | expect(out.map).toBeFalsy(); 47 | 48 | expect(out.code).toContain( 49 | `define('a', ['@swc/helpers'], function(swcHelpers) {` 50 | ); 51 | expect(out.code).toContain(`swcHelpers.classCallCheck(this, Foo);`); 52 | expect(out.code).toContain(`swcHelpers.inherits(Bar, Foo);`); 53 | }); 54 | -------------------------------------------------------------------------------- /__tests__/parse/api_test.js: -------------------------------------------------------------------------------- 1 | const swc = require("../../"); 2 | 3 | it("should work asynchronously", async () => { 4 | const m = await swc.parse(`class Foo {}`); 5 | 6 | expect(m.type).toBe(`Module`); 7 | expect(m.body).toHaveLength(1); 8 | expect(m.body[0].type).toBe(`ClassDeclaration`); 9 | }); 10 | 11 | it("can work synchronously", () => { 12 | const m = swc.parseSync(`class Foo {}`); 13 | 14 | expect(m.type).toBe(`Module`); 15 | expect(m.body).toHaveLength(1); 16 | expect(m.body[0].type).toBe(`ClassDeclaration`); 17 | }); 18 | 19 | it("can be emit code back asynchronously", async () => { 20 | const m = await swc.parse(`class Foo {}`); 21 | const out = await swc.print(m); 22 | 23 | expect(out.code.trim().replace("\n", "")).toBe(`class Foo{}`); 24 | }); 25 | 26 | it("can be emit code back synchronously", async () => { 27 | const m = await swc.parseSync(`class Foo {}`); 28 | const out = swc.printSync(m); 29 | 30 | expect(out.code.trim().replace("\n", "")).toBe(`class Foo{}`); 31 | }); 32 | -------------------------------------------------------------------------------- /__tests__/script_test.js: -------------------------------------------------------------------------------- 1 | const swc = require("../"); 2 | 3 | it("should handle script", () => { 4 | const script = swc.transformSync(`foo;`, { isModule: false }); 5 | expect(script.code.trim()).toBe(`foo;`); 6 | }); 7 | 8 | it("should parse as script if required", () => { 9 | const script = swc.parseSync(`foo;`, { isModule: false }); 10 | expect(script.type).toBe("Script"); 11 | 12 | const out = swc.printSync(script); 13 | expect(out.code.trim()).toBe(`foo;`); 14 | }); 15 | 16 | it("should parse as module if required", () => { 17 | const m = swc.parseSync(`foo;`); 18 | expect(m.type).toBe("Module"); 19 | 20 | const out = swc.printSync(m); 21 | expect(out.code.trim()).toBe(`foo;`); 22 | }); 23 | -------------------------------------------------------------------------------- /__tests__/transform/api_test.js: -------------------------------------------------------------------------------- 1 | const swc = require("../../"); 2 | 3 | it("should handle minify", () => { 4 | const src = '/* Comment */import foo, {bar} from "foo"'; 5 | 6 | expect( 7 | swc 8 | .transformSync(src, { 9 | minify: true 10 | }) 11 | .code.trim() 12 | ).toBe("import foo,{bar}from'foo';"); 13 | }); 14 | 15 | it("should handle sourceMaps = false", () => { 16 | const src = '/* Comment */import foo, {bar} from "foo"'; 17 | const out = swc.transformSync(src, { 18 | sourceMaps: false 19 | }); 20 | 21 | expect(out.map).toBeFalsy(); 22 | }); 23 | 24 | it("should handle exportNamespaceFrom", () => { 25 | const src = "export * as Foo from 'bar';"; 26 | const out = swc.transformSync(src, { 27 | jsc: { 28 | parser: { 29 | syntax: "ecmascript", 30 | exportNamespaceFrom: true 31 | } 32 | } 33 | }); 34 | 35 | expect(out.code).toContain("import * as _Foo from 'bar';"); 36 | expect(out.code).toContain("export { _Foo as Foo }"); 37 | }); 38 | 39 | it("should handle jsc.target = es3", () => { 40 | const out = swc.transformSync(`foo.default`, { 41 | jsc: { 42 | target: "es3" 43 | } 44 | }); 45 | expect(out.code.trim()).toBe(`foo['default'];`); 46 | }); 47 | 48 | it("should handle jsc.target = es5", () => { 49 | const out = swc.transformSync(`foo.default`, { 50 | jsc: { 51 | target: "es5" 52 | } 53 | }); 54 | expect(out.code.trim()).toBe(`foo.default;`); 55 | }); 56 | 57 | it("(sync) should handle module input", () => { 58 | const m = swc.parseSync("class Foo {}"); 59 | const out = swc.transformSync(m); 60 | 61 | expect(out.code.replace(/\n/g, "")).toBe("class Foo{}"); 62 | }); 63 | 64 | it("(async) should handle module input", async () => { 65 | const m = await swc.parse("class Foo {}"); 66 | const out = await swc.transform(m); 67 | 68 | expect(out.code.replace(/\n/g, "")).toBe("class Foo{}"); 69 | }); 70 | 71 | it("(sync) should handle plugin", () => { 72 | const out = swc.transformSync("class Foo {}", { 73 | plugin: m => ({ ...m, body: [] }) 74 | }); 75 | 76 | expect(out.code).toBe(""); 77 | }); 78 | 79 | it("(async) should handle plugin", async () => { 80 | const out = await swc.transform("class Foo {}", { 81 | plugin: m => ({ ...m, body: [] }) 82 | }); 83 | 84 | expect(out.code).toBe(""); 85 | }); 86 | 87 | it("(async) should handel dynmic import", async () => { 88 | const out = await swc.transform("import('foo');", { 89 | jsc: { 90 | target: "es3", 91 | parser: { 92 | syntax: "ecmascript", 93 | dynamicImport: true 94 | } 95 | } 96 | }); 97 | 98 | expect(out.code.replace(/;/g, "").trim()).toBe(`import('foo')`); 99 | }); 100 | 101 | it("should handle nullish coalescing", async () => { 102 | const out = await swc.transform("a ?? 'foo';", { 103 | jsc: { 104 | parser: { 105 | syntax: "ecmascript", 106 | nullishCoalescing: true 107 | } 108 | } 109 | }); 110 | 111 | expect(out.code).toBe(`a !== null && a !== void 0 ? a : 'foo'; 112 | `); 113 | }); 114 | 115 | it("should handle for of statement in an async function", async () => { 116 | const out = swc.transformSync( 117 | `async function foo() { 118 | for (let a of b) { 119 | } 120 | }` 121 | ); 122 | 123 | expect(out.code).toBe(`a !== null && a !== void 0 ? a : 'foo'; 124 | `); 125 | }); 126 | -------------------------------------------------------------------------------- /__tests__/transform/optimizer_test.js: -------------------------------------------------------------------------------- 1 | const swc = require('../../'); 2 | 3 | it('should perform dce', () => { 4 | const out = swc.transformSync(`if (__DEBUG__) { 5 | console.log('Foo') 6 | }`, { 7 | jsc: { 8 | transform: { 9 | optimizer: { 10 | globals: { 11 | vars: { 12 | __DEBUG__: 'true' 13 | }, 14 | } 15 | } 16 | } 17 | } 18 | } 19 | ); 20 | expect(out.map).toBeFalsy(); 21 | 22 | expect(out.code.trim()).toBe(`console.log('Foo');`); 23 | }); -------------------------------------------------------------------------------- /__tests__/transform/plugin_test.js: -------------------------------------------------------------------------------- 1 | const swc = require("../../"); 2 | const Visitor = require("../../Visitor").default; 3 | 4 | { 5 | const src = ` 6 | 'use strict'; 7 | 8 | class Foo { 9 | foo() {} 10 | } 11 | 12 | class Bar extends Foo { 13 | foo() { 14 | super.foo(); 15 | } 16 | async bar() {} 17 | } 18 | 19 | class Baz extends Bar { 20 | foo() { 21 | super.foo(); 22 | this.baz() 23 | } 24 | baz() { 25 | 26 | } 27 | async other() { 28 | this.baz() 29 | await super.bar() 30 | } 31 | } 32 | 33 | function red( color ) 34 | { 35 | let foo = 3.14; 36 | return color >> 16; 37 | } 38 | 39 | function green( color ) 40 | { 41 | return ( color >> 8 ) & 0xFF; 42 | } 43 | 44 | /** 45 | * Extract blue color out of a color integer: 46 | * 47 | * 0x00DEAD -> 0xAD 48 | * 49 | * @param {Number} color 50 | * @return {Number} 51 | */ 52 | function blue( color ) 53 | { 54 | return color & 0xFF; 55 | } 56 | 57 | function intToHex( int ) 58 | { 59 | const mask = '#000000'; 60 | 61 | const hex = int.toString( 16 ); 62 | 63 | return mask.substring( 0, 7 - hex.length ) + hex; 64 | } 65 | 66 | function hexToInt( hex ) 67 | { 68 | return parseInt( hex.substring( 1 ), 16 ); 69 | } 70 | 71 | 72 | // Verify that visitor can handle class declaration. 73 | class Prent {} 74 | class Child extends Parent {} 75 | 76 | 77 | // Verify that visitor can handle new expression. 78 | new Child(foo); 79 | new Child(...foo); 80 | 81 | 82 | // Verify that visitor can handle call expressions. 83 | call(...foo); 84 | call(foo); 85 | 86 | let arr = [elem, , ...foo]; 87 | 88 | module.exports = { 89 | red, 90 | green, 91 | blue, 92 | intToHex, 93 | hexToInt, 94 | }; 95 | `; 96 | 97 | it("works", () => { 98 | swc.transformSync(src, { 99 | plugin: m => m 100 | }); 101 | }); 102 | 103 | it("works with visitor", () => { 104 | swc.transformSync(src, { 105 | plugin: m => { 106 | let v = new Visitor(); 107 | return v.visitProgram(m); 108 | } 109 | }); 110 | }); 111 | } 112 | -------------------------------------------------------------------------------- /__tests__/transform/sourcemap_test.js: -------------------------------------------------------------------------------- 1 | const swc = require('../../'), 2 | validate = require('sourcemap-validator'), 3 | sourceMap = require('source-map'); 4 | 5 | it('should handle sourcemap correctly', async () => { 6 | const raw = ` 7 | class Foo extends Array { 8 | } 9 | console.log('foo') 10 | `; 11 | const out = await swc.transform(raw, { 12 | filename: 'input.js', 13 | sourceMaps: true 14 | }); 15 | 16 | 17 | expect(out.map).toBeTruthy(); 18 | validate(out.code, out.map, { 'input.js': raw }); 19 | 20 | // await sourceMap.SourceMapConsumer.with(JSON.parse(out.map), null, async (consumer) => { 21 | // consumer.eachMapping((mapping) => { 22 | // console.log(mapping); 23 | // }); 24 | // }); 25 | 26 | 27 | // // Dump output and sourcemap to file 28 | // // https://sokra.github.io/source-map-visualization/#custom 29 | 30 | // const fs = require('fs'); 31 | // fs.writeFileSync('./test.js', out.code); 32 | // fs.writeFileSync('./test.map', out.map); 33 | 34 | }) 35 | 36 | it('should handle input sourcemap correctly', async () => { 37 | const raw = `class Foo extends Array {}`; 38 | const out1 = await swc.transform(raw, { 39 | filename: 'input1.js', 40 | jsc: { 41 | externalHelpers: true, 42 | target: 'es2016', 43 | }, 44 | module: { 45 | type: 'commonjs' 46 | }, 47 | sourceMaps: true 48 | }); 49 | 50 | expect(out1.map).toBeTruthy(); 51 | validate(out1.code, out1.map, { 'input.js': raw }); 52 | console.log(out1.code); 53 | 54 | const out2 = await swc.transform(out1.code, { 55 | filename: 'input2.js', 56 | jsc: { 57 | externalHelpers: true, 58 | target: 'es3', 59 | }, 60 | module: { 61 | type: 'commonjs' 62 | }, 63 | sourceMaps: out1.map, 64 | }); 65 | 66 | console.log(out2.code); 67 | expect(out2.map).toBeTruthy(); 68 | validate(out2.code, out2.map, { 'input2.js': out1.code }); 69 | validate(out2.code, out2.map, { 'input.js': raw }); 70 | 71 | await sourceMap.SourceMapConsumer.with(JSON.parse(out1.map), null, async (consumer1) => { 72 | await sourceMap.SourceMapConsumer.with(JSON.parse(out2.map), null, async (consumer2) => { 73 | consumer1.eachMapping((mapping) => { 74 | // console.log(mapping); 75 | }); 76 | 77 | consumer2.eachMapping((mapping) => { 78 | // console.log(mapping); 79 | }); 80 | }); 81 | }); 82 | 83 | }) -------------------------------------------------------------------------------- /benches/multicore.js: -------------------------------------------------------------------------------- 1 | const os = require("os"); 2 | const cpuCount = os.cpus().length; 3 | 4 | const SOURCE = ` 5 | 'use strict'; 6 | 7 | class Foo { 8 | foo() {} 9 | } 10 | 11 | class Bar extends Foo { 12 | foo() { 13 | super.foo(); 14 | } 15 | async bar() {} 16 | } 17 | 18 | class Baz extends Bar { 19 | foo() { 20 | super.foo(); 21 | this.baz() 22 | } 23 | baz() { 24 | 25 | } 26 | async other() { 27 | this.baz() 28 | await super.bar() 29 | } 30 | } 31 | 32 | /** 33 | * Extract red color out of a color integer: 34 | * 35 | * 0x00DEAD -> 0x00 36 | * 37 | * @param {Number} color 38 | * @return {Number} 39 | */ 40 | function red( color ) 41 | { 42 | let foo = 3.14; 43 | return color >> 16; 44 | } 45 | 46 | /** 47 | * Extract green out of a color integer: 48 | * 49 | * 0x00DEAD -> 0xDE 50 | * 51 | * @param {Number} color 52 | * @return {Number} 53 | */ 54 | function green( color ) 55 | { 56 | return ( color >> 8 ) & 0xFF; 57 | } 58 | 59 | /** 60 | * Extract blue color out of a color integer: 61 | * 62 | * 0x00DEAD -> 0xAD 63 | * 64 | * @param {Number} color 65 | * @return {Number} 66 | */ 67 | function blue( color ) 68 | { 69 | return color & 0xFF; 70 | } 71 | 72 | /** 73 | * Converts an integer containing a color such as 0x00DEAD to a hex 74 | * string, such as '#00DEAD'; 75 | * 76 | * @param {Number} int 77 | * @return {String} 78 | */ 79 | function intToHex( int ) 80 | { 81 | const mask = '#000000'; 82 | 83 | const hex = int.toString( 16 ); 84 | 85 | return mask.substring( 0, 7 - hex.length ) + hex; 86 | } 87 | 88 | /** 89 | * Converts a hex string containing a color such as '#00DEAD' to 90 | * an integer, such as 0x00DEAD; 91 | * 92 | * @param {Number} num 93 | * @return {String} 94 | */ 95 | function hexToInt( hex ) 96 | { 97 | return parseInt( hex.substring( 1 ), 16 ); 98 | } 99 | 100 | // fixer 101 | ({}) ? 1 : 2; 102 | (foo ? 103 | // foo 104 | 1 : 105 | // bar 106 | ( // baz 107 | 2 108 | ) 109 | ) ? 3 : 4; 110 | _iteratorNormalCompletion = (_step = _iterator.next()).done 111 | 112 | module.exports = { 113 | red, 114 | green, 115 | blue, 116 | intToHex, 117 | hexToInt, 118 | }; 119 | `; 120 | 121 | const PARSERS = [ 122 | [ 123 | "swc (es3)", 124 | "../swc/", 125 | module => 126 | module.transform(SOURCE, { 127 | jsc: { target: "es3" } 128 | }) 129 | ], 130 | [ 131 | "swc (es2015)", 132 | "../swc/", 133 | module => 134 | module.transform(SOURCE, { 135 | jsc: { target: "es2015" } 136 | }) 137 | ], 138 | [ 139 | "swc (es2016)", 140 | "../swc/", 141 | module => 142 | module.transform(SOURCE, { 143 | jsc: { target: "es2016" } 144 | }) 145 | ], 146 | [ 147 | "swc (es2017)", 148 | "../swc/", 149 | module => 150 | module.transform(SOURCE, { 151 | jsc: { target: "es2017" } 152 | }) 153 | ], 154 | [ 155 | "swc (es2018)", 156 | "../swc/", 157 | module => 158 | module.transform(SOURCE, { 159 | jsc: { target: "es2018" } 160 | }) 161 | ], 162 | [ 163 | "swc-optimize (es3)", 164 | "../swc/", 165 | module => 166 | module.transform(SOURCE, { 167 | jsc: { 168 | transform: { 169 | optimizer: {} 170 | } 171 | } 172 | }) 173 | ], 174 | [ 175 | "babel (es5)", 176 | "@babel/core", 177 | module => 178 | module.transform(SOURCE, { 179 | presets: ["@babel/preset-env", "@babel/preset-react"], 180 | // This does less work than swc's InlineGlobals pass, but it's ok. 181 | // swc is faster than babel anyway. 182 | plugins: [ 183 | "transform-node-env-inline", 184 | "@babel/plugin-proposal-class-properties", 185 | "@babel/proposal-object-rest-spread", 186 | [ 187 | "@babel/plugin-proposal-decorators", 188 | { decoratorsBeforeExport: true } 189 | ] 190 | ] 191 | }) 192 | ] 193 | ]; 194 | 195 | const arr = []; 196 | for (let i = 0; i < cpuCount / 2; i++) { 197 | arr.push(0); 198 | } 199 | console.info(`CPU Core: ${cpuCount}; Parallelism: ${arr.length}`); 200 | console.info( 201 | `Note that output of this benchmark should be multiplied by ${arr.length} as this test uses Promise.all` 202 | ); 203 | 204 | suite("multicore", () => { 205 | PARSERS.map(args => { 206 | const [name, requirePath, fn] = args; 207 | const func = fn.bind(null, require(requirePath)); 208 | bench(name, async done => { 209 | await Promise.all(arr.map(v => func())); 210 | done(); 211 | }); 212 | }); 213 | }); 214 | -------------------------------------------------------------------------------- /benches/plugin.js: -------------------------------------------------------------------------------- 1 | const SOURCE = ` 2 | 'use strict'; 3 | 4 | class Foo { 5 | foo() {} 6 | } 7 | 8 | class Bar extends Foo { 9 | foo() { 10 | super.foo(); 11 | } 12 | async bar() {} 13 | } 14 | 15 | class Baz extends Bar { 16 | foo() { 17 | super.foo(); 18 | this.baz() 19 | } 20 | baz() { 21 | 22 | } 23 | async other() { 24 | this.baz() 25 | await super.bar() 26 | } 27 | } 28 | 29 | /** 30 | * Extract red color out of a color integer: 31 | * 32 | * 0x00DEAD -> 0x00 33 | * 34 | * @param {Number} color 35 | * @return {Number} 36 | */ 37 | function red( color ) 38 | { 39 | let foo = 3.14; 40 | return color >> 16; 41 | } 42 | 43 | /** 44 | * Extract green out of a color integer: 45 | * 46 | * 0x00DEAD -> 0xDE 47 | * 48 | * @param {Number} color 49 | * @return {Number} 50 | */ 51 | function green( color ) 52 | { 53 | return ( color >> 8 ) & 0xFF; 54 | } 55 | 56 | /** 57 | * Extract blue color out of a color integer: 58 | * 59 | * 0x00DEAD -> 0xAD 60 | * 61 | * @param {Number} color 62 | * @return {Number} 63 | */ 64 | function blue( color ) 65 | { 66 | return color & 0xFF; 67 | } 68 | 69 | /** 70 | * Converts an integer containing a color such as 0x00DEAD to a hex 71 | * string, such as '#00DEAD'; 72 | * 73 | * @param {Number} int 74 | * @return {String} 75 | */ 76 | function intToHex( int ) 77 | { 78 | const mask = '#000000'; 79 | 80 | const hex = int.toString( 16 ); 81 | 82 | return mask.substring( 0, 7 - hex.length ) + hex; 83 | } 84 | 85 | /** 86 | * Converts a hex string containing a color such as '#00DEAD' to 87 | * an integer, such as 0x00DEAD; 88 | * 89 | * @param {Number} num 90 | * @return {String} 91 | */ 92 | function hexToInt( hex ) 93 | { 94 | return parseInt( hex.substring( 1 ), 16 ); 95 | } 96 | 97 | module.exports = { 98 | red, 99 | green, 100 | blue, 101 | intToHex, 102 | hexToInt, 103 | }; 104 | `; 105 | 106 | const swc = require("../swc/"); 107 | const Visitor = require("../swc/Visitor").default; 108 | 109 | const TESTS = [ 110 | ["parse", () => swc.parseSync(SOURCE)], 111 | ["parse + print", () => swc.printSync(swc.parseSync(SOURCE))], 112 | ["parse + transform", () => swc.transformSync(swc.parseSync(SOURCE))], 113 | [ 114 | "plugin", 115 | () => 116 | swc.transformSync(SOURCE, { 117 | plugin: m => new Visitor().visitModule(m) 118 | }) 119 | ] 120 | ]; 121 | 122 | suite("plugin", () => { 123 | TESTS.map(args => { 124 | const [name, fn] = args; 125 | bench(name, fn); 126 | }); 127 | }); 128 | -------------------------------------------------------------------------------- /benches/transform.js: -------------------------------------------------------------------------------- 1 | const SOURCE = ` 2 | 'use strict'; 3 | 4 | class Foo { 5 | foo() {} 6 | } 7 | 8 | class Bar extends Foo { 9 | foo() { 10 | super.foo(); 11 | } 12 | async bar() {} 13 | } 14 | 15 | class Baz extends Bar { 16 | foo() { 17 | super.foo(); 18 | this.baz() 19 | } 20 | baz() { 21 | 22 | } 23 | async other() { 24 | this.baz() 25 | await super.bar() 26 | } 27 | } 28 | 29 | /** 30 | * Extract red color out of a color integer: 31 | * 32 | * 0x00DEAD -> 0x00 33 | * 34 | * @param {Number} color 35 | * @return {Number} 36 | */ 37 | function red( color ) 38 | { 39 | let foo = 3.14; 40 | return color >> 16; 41 | } 42 | 43 | /** 44 | * Extract green out of a color integer: 45 | * 46 | * 0x00DEAD -> 0xDE 47 | * 48 | * @param {Number} color 49 | * @return {Number} 50 | */ 51 | function green( color ) 52 | { 53 | return ( color >> 8 ) & 0xFF; 54 | } 55 | 56 | /** 57 | * Extract blue color out of a color integer: 58 | * 59 | * 0x00DEAD -> 0xAD 60 | * 61 | * @param {Number} color 62 | * @return {Number} 63 | */ 64 | function blue( color ) 65 | { 66 | return color & 0xFF; 67 | } 68 | 69 | /** 70 | * Converts an integer containing a color such as 0x00DEAD to a hex 71 | * string, such as '#00DEAD'; 72 | * 73 | * @param {Number} int 74 | * @return {String} 75 | */ 76 | function intToHex( int ) 77 | { 78 | const mask = '#000000'; 79 | 80 | const hex = int.toString( 16 ); 81 | 82 | return mask.substring( 0, 7 - hex.length ) + hex; 83 | } 84 | 85 | /** 86 | * Converts a hex string containing a color such as '#00DEAD' to 87 | * an integer, such as 0x00DEAD; 88 | * 89 | * @param {Number} num 90 | * @return {String} 91 | */ 92 | function hexToInt( hex ) 93 | { 94 | return parseInt( hex.substring( 1 ), 16 ); 95 | } 96 | 97 | // fixer 98 | ({}) ? 1 : 2; 99 | (foo ? 100 | // foo 101 | 1 : 102 | // bar 103 | ( // baz 104 | 2 105 | ) 106 | ) ? 3 : 4; 107 | _iteratorNormalCompletion = (_step = _iterator.next()).done 108 | 109 | module.exports = { 110 | red, 111 | green, 112 | blue, 113 | intToHex, 114 | hexToInt, 115 | }; 116 | `; 117 | 118 | const PARSERS = [ 119 | [ 120 | "swc (es3)", 121 | "../swc/", 122 | module => 123 | module.transformSync(SOURCE, { 124 | jsc: { target: "es3" } 125 | }) 126 | ], 127 | [ 128 | "swc (es2015)", 129 | "../swc/", 130 | module => 131 | module.transformSync(SOURCE, { 132 | jsc: { target: "es2015" } 133 | }) 134 | ], 135 | [ 136 | "swc (es2016)", 137 | "../swc/", 138 | module => 139 | module.transformSync(SOURCE, { 140 | jsc: { target: "es2016" } 141 | }) 142 | ], 143 | [ 144 | "swc (es2017)", 145 | "../swc/", 146 | module => 147 | module.transformSync(SOURCE, { 148 | jsc: { target: "es2017" } 149 | }) 150 | ], 151 | [ 152 | "swc (es2018)", 153 | "../swc/", 154 | module => 155 | module.transformSync(SOURCE, { 156 | jsc: { target: "es2018" } 157 | }) 158 | ], 159 | [ 160 | "swc-optimize (es3)", 161 | "../swc/", 162 | module => 163 | module.transformSync(SOURCE, { 164 | jsc: { 165 | transform: { 166 | optimizer: {} 167 | } 168 | } 169 | }) 170 | ], 171 | [ 172 | "babel (es5)", 173 | "@babel/core", 174 | module => 175 | module.transformSync(SOURCE, { 176 | presets: ["@babel/preset-env", "@babel/preset-react"], 177 | // This does less work than swc's InlineGlobals pass, but it's ok. 178 | // swc is faster than babel anyway. 179 | plugins: [ 180 | "transform-node-env-inline", 181 | "@babel/plugin-proposal-class-properties", 182 | "@babel/proposal-object-rest-spread", 183 | [ 184 | "@babel/plugin-proposal-decorators", 185 | { decoratorsBeforeExport: true } 186 | ] 187 | ] 188 | }) 189 | ] 190 | ]; 191 | 192 | suite("transform", () => { 193 | PARSERS.map(args => { 194 | const [name, requirePath, fn] = args; 195 | try { 196 | const func = fn.bind(null, require(requirePath)); 197 | bench(name, func); 198 | } catch (e) { 199 | console.log(`Cannot load ${requirePath}: ${e.message}`); 200 | } 201 | }); 202 | }); 203 | -------------------------------------------------------------------------------- /benches/typescript.js: -------------------------------------------------------------------------------- 1 | const SOURCE = ` 2 | 'use strict'; 3 | 4 | class Foo { 5 | foo(): void {} 6 | } 7 | 8 | class Bar extends Foo { 9 | foo(): void { 10 | super.foo(); 11 | } 12 | async bar() {} 13 | } 14 | 15 | class Baz extends Bar { 16 | foo(): void { 17 | super.foo(); 18 | this.baz() 19 | } 20 | baz(): void { 21 | 22 | } 23 | async other() : Promise { 24 | this.baz() 25 | await super.bar() 26 | } 27 | } 28 | 29 | /** 30 | * Extract red color out of a color integer: 31 | * 32 | * 0x00DEAD -> 0x00 33 | * 34 | * @param {Number} color 35 | * @return {Number} 36 | */ 37 | function red( color: number ) 38 | { 39 | let foo: number = 3.14; 40 | return color >> 16; 41 | } 42 | 43 | /** 44 | * Extract green out of a color integer: 45 | * 46 | * 0x00DEAD -> 0xDE 47 | * 48 | * @param {Number} color 49 | * @return {Number} 50 | */ 51 | function green( color: number ) 52 | { 53 | return ( color >> 8 ) & 0xFF; 54 | } 55 | 56 | /** 57 | * Extract blue color out of a color integer: 58 | * 59 | * 0x00DEAD -> 0xAD 60 | * 61 | * @param {Number} color 62 | * @return {Number} 63 | */ 64 | function blue( color: number ) 65 | { 66 | return color & 0xFF; 67 | } 68 | 69 | /** 70 | * Converts an integer containing a color such as 0x00DEAD to a hex 71 | * string, such as '#00DEAD'; 72 | * 73 | * @param {Number} int 74 | * @return {String} 75 | */ 76 | function intToHex( int: number ) 77 | { 78 | const mask = '#000000'; 79 | 80 | const hex = int.toString( 16 ); 81 | 82 | return mask.substring( 0, 7 - hex.length ) + hex; 83 | } 84 | 85 | /** 86 | * Converts a hex string containing a color such as '#00DEAD' to 87 | * an integer, such as 0x00DEAD; 88 | * 89 | * @param {Number} num 90 | * @return {String} 91 | */ 92 | function hexToInt( hex: string ) 93 | { 94 | return parseInt( hex.substring( 1 ), 16 ); 95 | } 96 | 97 | module.exports = { 98 | red, 99 | green, 100 | blue, 101 | intToHex, 102 | hexToInt, 103 | }; 104 | `; 105 | 106 | 107 | 108 | const PARSERS = [ 109 | ['swc (es3)', "../swc/", (module) => module.transformSync(SOURCE, { 110 | jsc: { 111 | target: 'es3', 112 | parser: { 113 | syntax: "typescript", 114 | }, 115 | } 116 | })], 117 | ['swc (es5)', "../swc/", (module) => module.transformSync(SOURCE, { 118 | jsc: { 119 | target: 'es5', 120 | parser: { 121 | syntax: "typescript", 122 | }, 123 | } 124 | })], 125 | ['swc (es2015)', "../swc/", (module) => module.transformSync(SOURCE, { 126 | jsc: { 127 | target: 'es2015', 128 | parser: { 129 | syntax: "typescript", 130 | }, 131 | } 132 | })], 133 | ['swc (es2016)', "../swc/", (module) => module.transformSync(SOURCE, { 134 | jsc: { 135 | target: 'es2016', 136 | parser: { 137 | syntax: "typescript", 138 | }, 139 | } 140 | })], 141 | ['swc (es2017)', "../swc/", (module) => module.transformSync(SOURCE, { 142 | jsc: { 143 | target: 'es2017', 144 | parser: { 145 | syntax: "typescript", 146 | }, 147 | } 148 | })], 149 | ['swc (es2018)', "../swc/", (module) => module.transformSync(SOURCE, { 150 | jsc: { 151 | target: 'es2018', 152 | parser: { 153 | syntax: "typescript", 154 | }, 155 | } 156 | })], 157 | ['swc-optimize (es3)', "../swc/", (module) => module.transformSync(SOURCE, { 158 | jsc: { 159 | parser: { 160 | syntax: "typescript", 161 | }, 162 | transform: { 163 | optimizer: {} 164 | } 165 | } 166 | })], 167 | ['babel (es5)', '@babel/core', (module) => module.transformSync(SOURCE, { 168 | presets: ["@babel/preset-typescript", "@babel/preset-env"], 169 | // This does less work than swc's InlineGlobals pass, but it's ok. 170 | // swc is faster than babel anyway. 171 | plugins: [ 172 | "transform-node-env-inline", 173 | "@babel/proposal-class-properties", 174 | "@babel/proposal-object-rest-spread", 175 | ["@babel/plugin-proposal-decorators", { decoratorsBeforeExport: true }], 176 | ], 177 | filename: 'foo.ts', 178 | })], 179 | ]; 180 | 181 | suite('typescript', () => { 182 | PARSERS.map((args) => { 183 | const [name, requirePath, fn] = args; 184 | try { 185 | const func = fn.bind(null, require(requirePath)); 186 | bench(name, func); 187 | } catch (e) { 188 | console.log(`Cannot load ${requirePath}: ${e.message}`); 189 | } 190 | }); 191 | }); 192 | -------------------------------------------------------------------------------- /scripts/ci/build-github.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #################### 4 | # Usage 5 | # 6 | # build.sh $node_version $abi_version 7 | # 8 | # e.g. build.sh 11 67 9 | #################### 10 | set -e 11 | 12 | cd ./swc 13 | 14 | # Bypasses https://github.com/neon-bindings/neon/issues/384 15 | echo 'Removing old files' 16 | 17 | unameOut="$(uname -s)" 18 | case "${unameOut}" in 19 | Linux*) SWC_NAME=linux-x64;; 20 | Darwin*) SWC_NAME=darwin-x64;; 21 | CYGWIN*) SWC_NAME=win32-x64;; 22 | MSYS*) SWC_NAME=win32-x64;; 23 | MINGW*) SWC_NAME=win32-x64;; 24 | *) SWC_NAME="UNKNOWN:${unameOut}" 25 | esac 26 | echo $SWC_NAME 27 | 28 | rm -rf ./native/index.node \ 29 | ./target/release/libffi.d* \ 30 | ./target/release/ffi.d* \ 31 | ./target/release/build/ffi* \ 32 | ./target/release/.fingerprint/neon* \ 33 | ./target/release/deps/ffi* \ 34 | ./target/release/deps/libffi* \ 35 | ./target/release/deps/neon* \ 36 | ./target/release/deps/libneon* 37 | echo 'Removed old files' 38 | 39 | # if [[ "$TRAVIS_OS_NAME" == "windows" ]]; then ls -al '/c/nodejs' ; fi 40 | # if [[ "$TRAVIS_OS_NAME" == "windows" ]]; then ls -alL '/c/nodejs' ; fi 41 | which node && node --version 42 | which npm 43 | 44 | 45 | # (cd native && cargo build --release --verbose) 46 | echo 'Installing deps...' 47 | npm install --ignore-scripts 48 | npx tsc -d 49 | 50 | # Build it 51 | echo 'Building...' 52 | npx neon build --release 53 | 54 | ls -al ./target/release 55 | 56 | # Verify abi 57 | echo 'Verifying binding with jest...' 58 | npx jest node-swc/__tests__/import_test.js 59 | 60 | 61 | mv native/index.node $SWC_NAME-$2.node 62 | ls -al . 63 | -------------------------------------------------------------------------------- /scripts/ci/linux-musl/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG NODE_VERSION 2 | 3 | FROM node:${NODE_VERSION}-alpine3.10 4 | 5 | ENV CARGO_INCREMENTAL=0 6 | 7 | # Install rust 8 | RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain nightly --profile minimal -y 9 | RUN ln -s "${HOME}"/.cargo/bin/* /usr/bin 10 | 11 | 12 | CMD ["sh"] 13 | -------------------------------------------------------------------------------- /scripts/ci/linux-musl/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #################### 4 | # Usage 5 | # 6 | # build.sh $node_version $abi_version 7 | # 8 | # e.g. build.sh 11 67 9 | #################### 10 | set -e 11 | 12 | cd swc 13 | 14 | echo 'Installing deps...' 15 | npm install --ignore-scripts 16 | npx tsc -d 17 | # Build it 18 | echo 'Building...' 19 | npx neon build --release 20 | 21 | # Verify abi 22 | echo 'Verifying binding with jest...' 23 | npx jest node-swc/__tests__/import_test.js 24 | 25 | strip -s native/index.node 26 | 27 | mv native/index.node linux_musl-x64-$1.node 28 | ls -al . 29 | -------------------------------------------------------------------------------- /scripts/ci/linux-musl/start-docker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Starts our build image inside docker, if we're doing a docker build. 4 | 5 | set -eux 6 | 7 | docker build -t node-rust-$2 -f "scripts/ci/linux-musl/Dockerfile" . --build-arg NODE_VERSION="$3" 8 | 9 | # sleep so our detached container with no long running process sits around to accept commands for a bit 10 | docker run --detach --name target-$2 -v "$(pwd)":/src -w /src node-rust-$2 sleep 999999999 -------------------------------------------------------------------------------- /scripts/ci/linux/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM centos:7 2 | 3 | RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain nightly --profile minimal -y 4 | RUN ln -s "${HOME}"/.cargo/bin/* /usr/local/bin 5 | 6 | ENV CARGO_INCREMENTAL=0 7 | 8 | 9 | RUN yum -y update; yum clean all 10 | RUN yum -y install gcc make gcc-c++ epel-release; yum groupinstall "Development Tools"; yum clean all 11 | 12 | ARG NODE_VERSION 13 | RUN curl -sL https://rpm.nodesource.com/setup_${NODE_VERSION} | bash - 14 | RUN yum -y install nodejs; yum clean all 15 | 16 | CMD ["sh"] 17 | -------------------------------------------------------------------------------- /scripts/ci/linux/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #################### 4 | # Usage 5 | # 6 | # build.sh $node_version $abi_version 7 | # 8 | # e.g. build.sh 11 67 9 | #################### 10 | set -e 11 | 12 | cd swc 13 | 14 | echo 'Installing deps...' 15 | npm install --ignore-scripts 16 | npx tsc -d 17 | # Build it 18 | echo 'Building...' 19 | npx neon build --release 20 | 21 | # Verify abi 22 | echo 'Verifying binding with jest...' 23 | npx jest node-swc/__tests__/import_test.js 24 | 25 | strip -s native/index.node 26 | 27 | mv native/index.node linux-x64-$1.node 28 | ls -al . 29 | -------------------------------------------------------------------------------- /scripts/ci/linux/start-docker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Starts our build image inside docker, if we're doing a docker build. 4 | 5 | set -eux 6 | 7 | docker build -t node-rust-$2 -f "scripts/ci/linux/Dockerfile" . --build-arg NODE_VERSION="$3" 8 | 9 | # sleep so our detached container with no long running process sits around to accept commands for a bit 10 | docker run --detach --name target-$2 -v "$(pwd)":/src -w /src node-rust-$2 sleep 999999999 -------------------------------------------------------------------------------- /scripts/ci/settings.txt: -------------------------------------------------------------------------------- 1 | root: C:\\nvm-root 2 | path: C:\\Program Files\\nodejs 3 | arch: 64 4 | proxy: none -------------------------------------------------------------------------------- /scripts/tag.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eu 4 | 5 | # Current version we are publising 6 | SEMVER=$(cat swc/package.json | jq -r '.version') 7 | # Last version published 8 | LAST_VER=$(npm view @swc/core version) 9 | 10 | echo "@swc/core: ${LAST_VER} => ${SEMVER}" 11 | VER="v$SEMVER" 12 | 13 | # Prevent me from tagging without comitting first. 14 | git add -A || true 15 | git commit || true 16 | 17 | git push 18 | 19 | git tag -d $VER || true 20 | git push origin :$VER || true 21 | 22 | git tag $VER 23 | git push --tags -------------------------------------------------------------------------------- /scripts/update.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | git submodule update --init --remote --------------------------------------------------------------------------------