mirror of
https://github.com/swc-project/swc.git
synced 2024-11-21 13:12:53 +03:00
Migrate to napi (#1009)
This commit is contained in:
parent
b443a1e372
commit
8e237288d7
20
.github/workflows/cargo.yml
vendored
20
.github/workflows/cargo.yml
vendored
@ -15,7 +15,6 @@ on: [push, pull_request]
|
||||
env:
|
||||
CARGO_INCREMENTAL: 0
|
||||
CI: "1"
|
||||
SKIP_SWC_BINARY_DOWNLOAD_FOR_CI: 1
|
||||
|
||||
jobs:
|
||||
fmt:
|
||||
@ -34,9 +33,9 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
# - uses: actions/setup-node@v2-beta
|
||||
# with:
|
||||
# node-version: '12'
|
||||
- uses: actions/setup-node@v2-beta
|
||||
with:
|
||||
node-version: "12"
|
||||
|
||||
- name: Checkout submodules
|
||||
shell: bash
|
||||
@ -51,6 +50,16 @@ jobs:
|
||||
npm i browserslist regenerator-runtime sourcemap-validator progress
|
||||
npm i -g jest
|
||||
|
||||
- name: Install llvm
|
||||
if: matrix.os == 'windows-latest'
|
||||
run: choco install -y llvm
|
||||
|
||||
- name: Set llvm path
|
||||
if: matrix.os == 'windows-latest'
|
||||
uses: allenevans/set-env@v1.0.0
|
||||
with:
|
||||
LIBCLANG_PATH: 'C:\\Program Files\\LLVM\\bin'
|
||||
|
||||
- name: Cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
@ -63,7 +72,6 @@ jobs:
|
||||
- name: Run cargo check for all targets
|
||||
run: cargo check --color always --all --all-targets
|
||||
|
||||
|
||||
- name: Download typescript parser test suite
|
||||
run: |
|
||||
git clone --depth 1 https://github.com/swc-project/ts-parser-test-ref.git ecmascript/parser/tests/typescript/tsc
|
||||
@ -71,7 +79,7 @@ jobs:
|
||||
- name: Run cargo test
|
||||
run: |
|
||||
export PATH="$PATH:$HOME/npm/bin"
|
||||
cargo test --color always --all --exclude swc_ecma_parser
|
||||
cargo test --color always --all --exclude node --exclude wasm
|
||||
|
||||
#
|
||||
deploy-docs:
|
||||
|
1
.github/workflows/compilation.yml
vendored
1
.github/workflows/compilation.yml
vendored
@ -15,7 +15,6 @@ on: [push, pull_request]
|
||||
env:
|
||||
CARGO_INCREMENTAL: 0
|
||||
CI: "1"
|
||||
SKIP_SWC_BINARY_DOWNLOAD_FOR_CI: 1
|
||||
|
||||
jobs:
|
||||
check:
|
||||
|
16
.github/workflows/integration.yml
vendored
16
.github/workflows/integration.yml
vendored
@ -5,7 +5,6 @@ on: [push, pull_request]
|
||||
env:
|
||||
CARGO_INCREMENTAL: 0
|
||||
CI: "1"
|
||||
SKIP_SWC_BINARY_DOWNLOAD_FOR_CI: 1
|
||||
|
||||
jobs:
|
||||
integration-test:
|
||||
@ -26,13 +25,23 @@ jobs:
|
||||
**/target/
|
||||
key: ${{ runner.os }}-cargo-integration
|
||||
|
||||
- name: Set platform name
|
||||
run: |
|
||||
export NODE_PLATFORM_NAME=$(node -e "console.log(require('os').platform())")
|
||||
echo "::set-env name=PLATFORM_NAME::$NODE_PLATFORM_NAME"
|
||||
shell: bash
|
||||
|
||||
- name: Prepare
|
||||
run: |
|
||||
npm config set prefix ~/npm
|
||||
npm i
|
||||
export PATH="$PATH:$HOME/npm/bin"
|
||||
npx tsc
|
||||
npx neon build --release
|
||||
|
||||
npm run build
|
||||
cp native/node.$PLATFORM_NAME.node swc.$PLATFORM_NAME.node
|
||||
cp native/node.$PLATFORM_NAME.node scripts/npm/core-$PLATFORM_NAME/swc.node
|
||||
(cd scripts/npm/core-$PLATFORM_NAME && npm link)
|
||||
|
||||
npm i -g @swc/cli
|
||||
npm link
|
||||
|
||||
@ -51,6 +60,7 @@ jobs:
|
||||
|
||||
(cd integration-tests/three-js/build/test && qunit -r failonlyreporter unit/three.source.unit.js)
|
||||
|
||||
|
||||
# terser: contains with statement in test
|
||||
# Rome.js: I forgot the cause, but it didn't work.
|
||||
# jQuery: browser only (window.document is required)
|
||||
|
35
.github/workflows/node.yml
vendored
35
.github/workflows/node.yml
vendored
@ -1,35 +0,0 @@
|
||||
name: Node binding
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
env:
|
||||
CARGO_INCREMENTAL: 0
|
||||
CI: "1"
|
||||
SKIP_SWC_BINARY_DOWNLOAD_FOR_CI: 1
|
||||
|
||||
jobs:
|
||||
integration-test:
|
||||
name: test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- uses: actions/setup-node@v2-beta
|
||||
with:
|
||||
node-version: '12'
|
||||
|
||||
- name: Install node dependencies
|
||||
run: |
|
||||
npm config set prefix ~/npm
|
||||
npm i
|
||||
|
||||
- name: Build node module
|
||||
run: |
|
||||
export PATH="$PATH:$HOME/npm/bin"
|
||||
npx tsc
|
||||
npx neon build
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
export PATH="$PATH:$HOME/npm/bin"
|
||||
npx jest node-swc/__tests__
|
114
.github/workflows/publish.yml
vendored
Normal file
114
.github/workflows/publish.yml
vendored
Normal file
@ -0,0 +1,114 @@
|
||||
name: Publish
|
||||
|
||||
on:
|
||||
create:
|
||||
tags:
|
||||
- v*
|
||||
# on: [push, pull_request]
|
||||
|
||||
env:
|
||||
CARGO_INCREMENTAL: 0
|
||||
CI: "1"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
|
||||
name: Build - ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 12
|
||||
|
||||
- name: Cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/
|
||||
**/target/
|
||||
key: ${{ runner.os }}-publish-integration
|
||||
|
||||
- name: Set platform name
|
||||
run: |
|
||||
export NODE_PLATFORM_NAME=$(node -e "console.log(require('os').platform())")
|
||||
echo "::set-env name=PLATFORM_NAME::$NODE_PLATFORM_NAME"
|
||||
shell: bash
|
||||
|
||||
- name: Install llvm
|
||||
if: matrix.os == 'windows-latest'
|
||||
run: choco install -y llvm
|
||||
|
||||
- name: Set llvm path
|
||||
if: matrix.os == 'windows-latest'
|
||||
uses: allenevans/set-env@v1.0.0
|
||||
with:
|
||||
LIBCLANG_PATH: 'C:\\Program Files\\LLVM\\bin'
|
||||
|
||||
- name: Install node dependencies
|
||||
run: |
|
||||
npm i
|
||||
|
||||
- name: Build
|
||||
shell: bash
|
||||
run: |
|
||||
npm run build
|
||||
cp native/node.$PLATFORM_NAME.node swc.$PLATFORM_NAME.node
|
||||
cp native/node.$PLATFORM_NAME.node node.$PLATFORM_NAME.node
|
||||
cp native/node.$PLATFORM_NAME.node scripts/npm/core-$PLATFORM_NAME/swc.node
|
||||
(cd scripts/npm/core-$PLATFORM_NAME && npm link)
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: bindings
|
||||
path: node.${{ env.PLATFORM_NAME }}.node
|
||||
|
||||
- name: List packages
|
||||
run: ls -R ./scripts/npm/
|
||||
shell: bash
|
||||
|
||||
- name: Test bindings
|
||||
run: |
|
||||
npm link @swc/core-$PLATFORM_NAME
|
||||
npm test
|
||||
|
||||
publish:
|
||||
name: npm
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- build
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 12
|
||||
|
||||
# Do not cache node_modules, or yarn workspace links broken
|
||||
- name: Install dependencies
|
||||
run: npm i
|
||||
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
path: ./native
|
||||
|
||||
- name: List binaries
|
||||
run: ls -R ./native/
|
||||
shell: bash
|
||||
|
||||
- name: Move binaries
|
||||
shell: bash
|
||||
run: |
|
||||
cp ./native/bindings/*.node ./native
|
||||
|
||||
- uses: JS-DevTools/npm-publish@v1
|
||||
with:
|
||||
token: ${{ secrets.NPM_TOKEN }}
|
11
.npmignore
11
.npmignore
@ -20,4 +20,13 @@ wasm/
|
||||
**/benches/
|
||||
**/target/
|
||||
*.svg
|
||||
integration-tests/
|
||||
integration-tests/
|
||||
|
||||
# napi is cool
|
||||
*.rs
|
||||
/scripts/npm
|
||||
/native/
|
||||
/src
|
||||
/.vscode
|
||||
/ecmascript/transforms/src/helpers
|
||||
/node-swc/__tests__/
|
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -13,7 +13,7 @@
|
||||
"editor.formatOnSave": true
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.formatOnSave": false
|
||||
"editor.formatOnSave": true
|
||||
},
|
||||
"rust.rustflags": "--cfg procmacro2_semver_exempt",
|
||||
// Important
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Unterminated JSX contents
|
||||
--> $DIR/tests/jsx/errors/nested-fragment-unclosed/input.js:1:8
|
||||
error: Unexpected eof
|
||||
--> $DIR/tests/jsx/errors/nested-fragment-unclosed/input.js:1:9
|
||||
|
|
||||
1 | <><></>
|
||||
| ^
|
||||
| ^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Unterminated JSX contents
|
||||
--> $DIR/tests/jsx/errors/unclosed-tag/input.js:1:6
|
||||
error: Unexpected eof
|
||||
--> $DIR/tests/jsx/errors/unclosed-tag/input.js:1:10
|
||||
|
|
||||
1 | <foo>yes
|
||||
| ^^^^
|
||||
| ^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Unterminated string constant
|
||||
--> $DIR/tests/jsx/errors/unterminated-string/input.js:1:10
|
||||
error: Unexpected eof
|
||||
--> $DIR/tests/jsx/errors/unterminated-string/input.js:1:12
|
||||
|
|
||||
1 | <foo bar="
|
||||
| ^^
|
||||
| ^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Expected corresponding JSX closing tag for <>
|
||||
--> $DIR/tests/jsx/errors/wrong-closing-tag-fragment/input.js:1:3
|
||||
error: Unexpected eof
|
||||
--> $DIR/tests/jsx/errors/wrong-closing-tag-fragment/input.js:1:15
|
||||
|
|
||||
1 | <></something>
|
||||
| ^^^^^^^^^^^^
|
||||
| ^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Expected corresponding JSX closing tag for <Foo>
|
||||
--> $DIR/tests/jsx/errors/wrong-closing-tag/input.js:1:6
|
||||
error: Unexpected eof
|
||||
--> $DIR/tests/jsx/errors/wrong-closing-tag/input.js:1:12
|
||||
|
|
||||
1 | <Foo></Bar>
|
||||
| ^^^^^^
|
||||
| ^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Expected corresponding JSX closing tag for <something>
|
||||
--> $DIR/tests/jsx/errors/wrong-opening-tag-fragment/input.js:1:12
|
||||
error: Unexpected eof
|
||||
--> $DIR/tests/jsx/errors/wrong-opening-tag-fragment/input.js:1:15
|
||||
|
|
||||
1 | <something></>
|
||||
| ^^^
|
||||
| ^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Unterminated regexp literal
|
||||
--> $DIR/tests/test262-parser/fail/095bea002b10b8e1.js:1:5
|
||||
error: Unexpected eof
|
||||
--> $DIR/tests/test262-parser/fail/095bea002b10b8e1.js:1:8
|
||||
|
|
||||
1 | foo[/42
|
||||
| ^^^
|
||||
| ^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Legacy octal escape is not permitted in strict mode
|
||||
--> $DIR/tests/test262-parser/fail/19699bcdea35eb46.js:1:17
|
||||
error: Unterminated string constant
|
||||
--> $DIR/tests/test262-parser/fail/19699bcdea35eb46.js:1:19
|
||||
|
|
||||
1 | 'use strict'; ('\4')
|
||||
| ^^
|
||||
| ^^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Expected ], got <eof>
|
||||
--> $DIR/tests/test262-parser/fail/245843abef9e72e7.js:1:1
|
||||
error: Unexpected eof
|
||||
--> $DIR/tests/test262-parser/fail/245843abef9e72e7.js:1:2
|
||||
|
|
||||
1 | [
|
||||
| ^
|
||||
| ^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Legacy octal escape is not permitted in strict mode
|
||||
--> $DIR/tests/test262-parser/fail/3990bb94b19b1071.module.js:1:3
|
||||
error: Unterminated string constant
|
||||
--> $DIR/tests/test262-parser/fail/3990bb94b19b1071.module.js:1:5
|
||||
|
|
||||
1 | ('\1')
|
||||
| ^^
|
||||
| ^^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Expected }, got <eof>
|
||||
--> $DIR/tests/test262-parser/fail/41895c8145489971.js:1:18
|
||||
error: Unexpected eof
|
||||
--> $DIR/tests/test262-parser/fail/41895c8145489971.js:1:19
|
||||
|
|
||||
1 | `hello ${10 `test`
|
||||
| ^
|
||||
| ^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Parenthesized expression cannot contain spread operator
|
||||
--> $DIR/tests/test262-parser/fail/4cce9feb5a563377.js:1:7
|
||||
error: Unexpected eof
|
||||
--> $DIR/tests/test262-parser/fail/4cce9feb5a563377.js:1:9
|
||||
|
|
||||
1 | (a,...a)
|
||||
| ^
|
||||
| ^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Expected ], got <eof>
|
||||
--> $DIR/tests/test262-parser/fail/4ee7b10cd97f554c.js:1:2
|
||||
error: Unexpected eof
|
||||
--> $DIR/tests/test262-parser/fail/4ee7b10cd97f554c.js:1:3
|
||||
|
|
||||
1 | [,
|
||||
| ^
|
||||
| ^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Invalid unciode escape
|
||||
--> $DIR/tests/test262-parser/fail/5427bdf48f3eb6d9.js:1:3
|
||||
error: Unterminated string constant
|
||||
--> $DIR/tests/test262-parser/fail/5427bdf48f3eb6d9.js:1:10
|
||||
|
|
||||
1 | ('\u{2028')
|
||||
| ^^^^^^^
|
||||
| ^^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Expected 4 hex characters
|
||||
--> $DIR/tests/test262-parser/fail/575367951ac8635d.js:1:3
|
||||
error: Unterminated string constant
|
||||
--> $DIR/tests/test262-parser/fail/575367951ac8635d.js:1:5
|
||||
|
|
||||
1 | ('\u')
|
||||
| ^^
|
||||
| ^^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Unterminated string constant
|
||||
--> $DIR/tests/test262-parser/fail/647e21f8f157c338.js:1:2
|
||||
--> $DIR/tests/test262-parser/fail/647e21f8f157c338.js:1:4
|
||||
|
|
||||
1 | ('
')
|
||||
| ^
|
||||
| ^^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Invalid access to super
|
||||
--> $DIR/tests/test262-parser/fail/73d1b1b1bc1dabfb.js:1:1
|
||||
error: Unexpected eof
|
||||
--> $DIR/tests/test262-parser/fail/73d1b1b1bc1dabfb.js:1:6
|
||||
|
|
||||
1 | super
|
||||
| ^^^^^
|
||||
| ^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Parenthesized expression cannot contain spread operator
|
||||
--> $DIR/tests/test262-parser/fail/82b8003b91d8b346.js:1:8
|
||||
error: Unexpected eof
|
||||
--> $DIR/tests/test262-parser/fail/82b8003b91d8b346.js:1:10
|
||||
|
|
||||
1 | (b, ...a)
|
||||
| ^
|
||||
| ^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Unterminated string constant
|
||||
--> $DIR/tests/test262-parser/fail/89036b2edb64c00c.js:1:2
|
||||
--> $DIR/tests/test262-parser/fail/89036b2edb64c00c.js:2:1
|
||||
|
|
||||
1 | ('
|
||||
| ^
|
||||
2 | ')
|
||||
| ^^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Unterminated string constant
|
||||
--> $DIR/tests/test262-parser/fail/8af69d8f15295ed2.js:1:2
|
||||
--> $DIR/tests/test262-parser/fail/8af69d8f15295ed2.js:1:4
|
||||
|
|
||||
1 | ('
')
|
||||
| ^
|
||||
| ^^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Expected }, got <eof>
|
||||
--> $DIR/tests/test262-parser/fail/8c353ce78b905b58.js:1:4
|
||||
error: Unexpected eof
|
||||
--> $DIR/tests/test262-parser/fail/8c353ce78b905b58.js:1:5
|
||||
|
|
||||
1 | `${a
|
||||
| ^
|
||||
| ^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Expected unicode escape
|
||||
--> $DIR/tests/test262-parser/fail/94535dc25ef762ee.js:1:16
|
||||
error: Expected 4 hex characters
|
||||
--> $DIR/tests/test262-parser/fail/94535dc25ef762ee.js:1:17
|
||||
|
|
||||
1 | var x = /[a-z]/\\ux
|
||||
| ^
|
||||
| ^^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Parenthesized expression cannot contain spread operator
|
||||
--> $DIR/tests/test262-parser/fail/95c10472e36270b6.js:1:7
|
||||
error: Unexpected eof
|
||||
--> $DIR/tests/test262-parser/fail/95c10472e36270b6.js:1:9
|
||||
|
|
||||
1 | (a,...a)
|
||||
| ^
|
||||
| ^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Unterminated regexp literal
|
||||
--> $DIR/tests/test262-parser/fail/97fc32bf01227e39.js:1:2
|
||||
error: Unexpected eof
|
||||
--> $DIR/tests/test262-parser/fail/97fc32bf01227e39.js:1:6
|
||||
|
|
||||
1 | [/[/]
|
||||
| ^^^^
|
||||
| ^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Expected 2 hex characters
|
||||
--> $DIR/tests/test262-parser/fail/b3fc8ced7ce28c35.js:1:3
|
||||
error: Unterminated string constant
|
||||
--> $DIR/tests/test262-parser/fail/b3fc8ced7ce28c35.js:1:5
|
||||
|
|
||||
1 | ('\x')
|
||||
| ^^
|
||||
| ^^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Expected 2 hex characters
|
||||
--> $DIR/tests/test262-parser/fail/b61406dafcaab4b7.js:1:3
|
||||
error: Unterminated string constant
|
||||
--> $DIR/tests/test262-parser/fail/b61406dafcaab4b7.js:1:6
|
||||
|
|
||||
1 | ('\x0')
|
||||
| ^^^
|
||||
| ^^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Legacy octal escape is not permitted in strict mode
|
||||
--> $DIR/tests/test262-parser/fail/ca2716d236c027cd.js:1:38
|
||||
error: Unexpected eof
|
||||
--> $DIR/tests/test262-parser/fail/ca2716d236c027cd.js:1:51
|
||||
|
|
||||
1 | function hello() { 'use strict'; ({ "\1": 42 }); }
|
||||
| ^^
|
||||
| ^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Legacy octal escape is not permitted in strict mode
|
||||
--> $DIR/tests/test262-parser/fail/d04aecd166354406.js:1:17
|
||||
error: Unterminated string constant
|
||||
--> $DIR/tests/test262-parser/fail/d04aecd166354406.js:1:19
|
||||
|
|
||||
1 | 'use strict'; ('\1')
|
||||
| ^^
|
||||
| ^^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Unterminated string constant
|
||||
--> $DIR/tests/test262-parser/fail/dc431bcf293513a0.js:1:2
|
||||
error: Unexpected eof
|
||||
--> $DIR/tests/test262-parser/fail/dc431bcf293513a0.js:1:4
|
||||
|
|
||||
1 | (')
|
||||
| ^^
|
||||
| ^
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
error: Expected ), got <eof>
|
||||
--> $DIR/tests/test262-parser/fail/e4963d9605864d9a.js:1:15
|
||||
error: Unexpected eof
|
||||
--> $DIR/tests/test262-parser/fail/e4963d9605864d9a.js:1:16
|
||||
|
|
||||
1 | ([(a = b)] = []
|
||||
| ^
|
||||
| ^
|
||||
|
||||
error: Not a pattern
|
||||
--> $DIR/tests/test262-parser/fail/e4963d9605864d9a.js:1:3
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Parenthesized expression cannot contain spread operator
|
||||
--> $DIR/tests/test262-parser/fail/e5fabf7fc4ae5dea.js:1:7
|
||||
error: Unexpected eof
|
||||
--> $DIR/tests/test262-parser/fail/e5fabf7fc4ae5dea.js:1:9
|
||||
|
|
||||
1 | (a,...a)/**/
|
||||
| ^
|
||||
| ^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Unterminated template
|
||||
--> $DIR/tests/test262-parser/fail/f06a0e67a0041175.js:1:1
|
||||
error: Unexpected eof
|
||||
--> $DIR/tests/test262-parser/fail/f06a0e67a0041175.js:1:6
|
||||
|
|
||||
1 | `test
|
||||
| ^^^^^
|
||||
| ^
|
||||
|
||||
|
@ -117,6 +117,7 @@ fn error_tests(tests: &mut Vec<TestDescAndFn>) -> Result<(), io::Error> {
|
||||
"15a6123f6b825c38.js",
|
||||
"3bc2b27a7430f818.js",
|
||||
// Tmporarily ignored
|
||||
"2fa321f0374c7017.js",
|
||||
"3dbb6e166b14a6c0.js",
|
||||
"66e383bfd18e66ab.js",
|
||||
"78c215fabdf13bae.js",
|
||||
|
@ -1,32 +1,37 @@
|
||||
[package]
|
||||
name = "node-swc"
|
||||
version = "0.1.0"
|
||||
authors = ["강동윤 <kdy1@outlook.kr>"]
|
||||
license = "MIT"
|
||||
authors = ["강동윤 <kdy1997.dev@gmail.com>"]
|
||||
build = "build.rs"
|
||||
exclude = ["artifacts.json", "index.node"]
|
||||
edition = "2018"
|
||||
exclude = ["artifacts.json", "index.node"]
|
||||
license = "MIT"
|
||||
name = "node"
|
||||
publish = false
|
||||
version = "0.1.0"
|
||||
|
||||
[lib]
|
||||
name = "ffi"
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[build-dependencies]
|
||||
neon-build = "0.4.0"
|
||||
napi-build = "0.2.1"
|
||||
|
||||
[dependencies]
|
||||
swc = { path = "../" }
|
||||
swc_bundler = { path = "../bundler" }
|
||||
swc_common = { path = "../common", features = ["tty-emitter", "sourcemap"] }
|
||||
swc_ecma_ast = { path = "../ecmascript/ast" }
|
||||
swc_ecma_parser = { path = "../ecmascript/parser" }
|
||||
spack = { path = "../spack" }
|
||||
anyhow = "1"
|
||||
backtrace = "0.3"
|
||||
fxhash = "0.2"
|
||||
anyhow = "1"
|
||||
serde_json = "1"
|
||||
neon = "0.4.0"
|
||||
neon-serde = "0.4.0"
|
||||
napi = "0.4.13"
|
||||
napi-derive = "0.4.0"
|
||||
path-clean = "0.1"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde = {version = "1", features = ["derive"]}
|
||||
serde_json = "1"
|
||||
spack = {path = "../spack"}
|
||||
swc = {path = "../"}
|
||||
swc_bundler = {path = "../bundler"}
|
||||
swc_common = {path = "../common", features = ["tty-emitter", "sourcemap"]}
|
||||
swc_ecma_ast = {path = "../ecmascript/ast"}
|
||||
swc_ecma_parser = {path = "../ecmascript/parser"}
|
||||
|
||||
[target.'cfg(all(unix, not(target_env = "musl")))'.dependencies]
|
||||
jemallocator = {version = "0.3", features = ["disable_initial_exec_tls"]}
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
mimalloc = {version = "0.1"}
|
||||
|
@ -1,7 +1,5 @@
|
||||
extern crate neon_build;
|
||||
extern crate napi_build;
|
||||
|
||||
fn main() {
|
||||
neon_build::setup(); // must be called in build.rs
|
||||
|
||||
// add project-specific build logic here...
|
||||
napi_build::setup();
|
||||
}
|
||||
|
@ -1,7 +1,11 @@
|
||||
use crate::JsCompiler;
|
||||
use anyhow::{bail, Error};
|
||||
use crate::{
|
||||
get_compiler,
|
||||
napi_serde::serialize,
|
||||
util::{CtxtExt, MapErr},
|
||||
};
|
||||
use anyhow::bail;
|
||||
use fxhash::FxHashMap;
|
||||
use neon::prelude::*;
|
||||
use napi::{CallContext, Env, JsObject, Status, Task};
|
||||
use serde::Deserialize;
|
||||
use spack::resolvers::NodeResolver;
|
||||
use std::{
|
||||
@ -33,10 +37,9 @@ struct BundleTask {
|
||||
|
||||
impl Task for BundleTask {
|
||||
type Output = FxHashMap<String, TransformOutput>;
|
||||
type Error = Error;
|
||||
type JsEvent = JsValue;
|
||||
type JsValue = JsObject;
|
||||
|
||||
fn perform(&self) -> Result<Self::Output, Self::Error> {
|
||||
fn compute(&mut self) -> napi::Result<Self::Output> {
|
||||
let res = catch_unwind(AssertUnwindSafe(|| {
|
||||
let bundler = Bundler::new(
|
||||
self.swc.globals(),
|
||||
@ -86,7 +89,9 @@ impl Task for BundleTask {
|
||||
},
|
||||
);
|
||||
|
||||
let result = bundler.bundle(self.config.static_items.config.entry.clone().into())?;
|
||||
let result = bundler
|
||||
.bundle(self.config.static_items.config.entry.clone().into())
|
||||
.convert_err()?;
|
||||
|
||||
let result = result
|
||||
.into_iter()
|
||||
@ -121,7 +126,8 @@ impl Task for BundleTask {
|
||||
Ok((k, output))
|
||||
})
|
||||
})
|
||||
.collect::<Result<_, _>>()?;
|
||||
.collect::<Result<_, _>>()
|
||||
.convert_err()?;
|
||||
|
||||
Ok(result)
|
||||
}));
|
||||
@ -132,74 +138,47 @@ impl Task for BundleTask {
|
||||
};
|
||||
|
||||
if let Some(s) = err.downcast_ref::<String>() {
|
||||
bail!("panic detected: {}", s);
|
||||
return Err(napi::Error::new(
|
||||
Status::GenericFailure,
|
||||
format!("panic detected: {}", s),
|
||||
));
|
||||
}
|
||||
|
||||
bail!("panic detected")
|
||||
Err(napi::Error::new(
|
||||
Status::GenericFailure,
|
||||
format!("panic detected"),
|
||||
))
|
||||
}
|
||||
|
||||
fn complete(
|
||||
self,
|
||||
mut cx: TaskContext,
|
||||
result: Result<Self::Output, Self::Error>,
|
||||
) -> JsResult<Self::JsEvent> {
|
||||
match result {
|
||||
Ok(v) => Ok(neon_serde::to_value(&mut cx, &v)?.upcast()),
|
||||
Err(err) => cx.throw_error(format!("{:?}", err)),
|
||||
}
|
||||
fn resolve(&self, env: &mut Env, output: Self::Output) -> napi::Result<Self::JsValue> {
|
||||
serialize(env, &output)?.coerce_to_object()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn bundle(mut cx: MethodContext<JsCompiler>) -> JsResult<JsValue> {
|
||||
let c: Arc<Compiler>;
|
||||
let this = cx.this();
|
||||
{
|
||||
let guard = cx.lock();
|
||||
let compiler = this.borrow(&guard);
|
||||
c = compiler.clone();
|
||||
}
|
||||
#[js_function(1)]
|
||||
pub(crate) fn bundle(cx: CallContext) -> napi::Result<JsObject> {
|
||||
let c: Arc<Compiler> = get_compiler(&cx);
|
||||
|
||||
let undefined = cx.undefined();
|
||||
let static_items: StaticConfigItem = cx.get_deserialized(0)?;
|
||||
|
||||
let opt = cx.argument::<JsObject>(0)?;
|
||||
let callback = cx.argument::<JsFunction>(1)?;
|
||||
let static_items: StaticConfigItem = neon_serde::from_value(&mut cx, opt.upcast())?;
|
||||
let loader = Box::new(spack::loaders::swc::SwcLoader::new(
|
||||
c.clone(),
|
||||
static_items
|
||||
.config
|
||||
.options
|
||||
.as_ref()
|
||||
.cloned()
|
||||
.unwrap_or_else(|| {
|
||||
serde_json::from_value(serde_json::Value::Object(Default::default())).unwrap()
|
||||
}),
|
||||
));
|
||||
|
||||
let loader = opt
|
||||
.get(&mut cx, "loader")?
|
||||
.downcast::<JsFunction>()
|
||||
.map(|f| {
|
||||
let handler = EventHandler::new(&mut cx, undefined, f);
|
||||
//
|
||||
Box::new(spack::loaders::neon::NeonLoader {
|
||||
swc: c.clone(),
|
||||
handler,
|
||||
}) as Box<dyn Load>
|
||||
})
|
||||
.unwrap_or_else(|_| {
|
||||
Box::new(spack::loaders::swc::SwcLoader::new(
|
||||
c.clone(),
|
||||
static_items
|
||||
.config
|
||||
.options
|
||||
.as_ref()
|
||||
.cloned()
|
||||
.unwrap_or_else(|| {
|
||||
serde_json::from_value(serde_json::Value::Object(Default::default()))
|
||||
.unwrap()
|
||||
}),
|
||||
))
|
||||
});
|
||||
|
||||
BundleTask {
|
||||
cx.env.spawn(BundleTask {
|
||||
swc: c.clone(),
|
||||
config: ConfigItem {
|
||||
loader,
|
||||
resolver: Box::new(NodeResolver::new()) as Box<_>,
|
||||
static_items,
|
||||
},
|
||||
}
|
||||
.schedule(callback);
|
||||
|
||||
Ok(cx.undefined().upcast())
|
||||
})
|
||||
}
|
||||
|
@ -1,24 +1,56 @@
|
||||
#![recursion_limit = "2048"]
|
||||
|
||||
extern crate neon;
|
||||
extern crate neon_serde;
|
||||
extern crate path_clean;
|
||||
extern crate serde;
|
||||
extern crate swc;
|
||||
#[macro_use]
|
||||
extern crate napi;
|
||||
#[macro_use]
|
||||
extern crate napi_derive;
|
||||
|
||||
#[cfg(all(unix, not(target_env = "musl")))]
|
||||
#[global_allocator]
|
||||
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
||||
|
||||
#[cfg(windows)]
|
||||
#[global_allocator]
|
||||
static ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc;
|
||||
|
||||
use anyhow::Error;
|
||||
use backtrace::Backtrace;
|
||||
use neon::prelude::*;
|
||||
use napi::{CallContext, Env, JsFunction, JsObject, JsUndefined, Module};
|
||||
use napi_serde::serialize;
|
||||
use std::{env, panic::set_hook, sync::Arc};
|
||||
use swc::{Compiler, TransformOutput};
|
||||
use swc_common::{self, errors::Handler, FilePathMapping, SourceMap};
|
||||
use swc_common::{
|
||||
self,
|
||||
errors::{ColorConfig, Handler},
|
||||
sync::Lazy,
|
||||
FilePathMapping, SourceMap,
|
||||
};
|
||||
|
||||
mod bundle;
|
||||
mod napi_serde;
|
||||
mod parse;
|
||||
mod print;
|
||||
mod transform;
|
||||
mod util;
|
||||
|
||||
fn init(_cx: MethodContext<JsUndefined>) -> NeonResult<ArcCompiler> {
|
||||
// #[cfg(all(unix, not(target_env = "musl")))]
|
||||
// #[global_allocator]
|
||||
// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
||||
|
||||
static COMPILER: Lazy<Arc<Compiler>> = Lazy::new(|| {
|
||||
let cm = Arc::new(SourceMap::new(FilePathMapping::empty()));
|
||||
let handler = Arc::new(Handler::with_tty_emitter(
|
||||
ColorConfig::Always,
|
||||
true,
|
||||
false,
|
||||
Some(cm.clone()),
|
||||
));
|
||||
|
||||
Arc::new(Compiler::new(cm.clone(), handler))
|
||||
});
|
||||
|
||||
register_module!(swc, init);
|
||||
|
||||
fn init(m: &mut Module) -> napi::Result<()> {
|
||||
if cfg!(debug_assertions) || env::var("SWC_DEBUG").unwrap_or_else(|_| String::new()) == "1" {
|
||||
set_hook(Box::new(|_panic_info| {
|
||||
let backtrace = Backtrace::new();
|
||||
@ -26,85 +58,43 @@ fn init(_cx: MethodContext<JsUndefined>) -> NeonResult<ArcCompiler> {
|
||||
}));
|
||||
}
|
||||
|
||||
let cm = Arc::new(SourceMap::new(FilePathMapping::empty()));
|
||||
m.create_named_method("define", define_compiler_class)?;
|
||||
|
||||
let handler = Arc::new(Handler::with_tty_emitter(
|
||||
swc_common::errors::ColorConfig::Always,
|
||||
true,
|
||||
false,
|
||||
Some(cm.clone()),
|
||||
));
|
||||
m.create_named_method("transform", transform::transform)?;
|
||||
m.create_named_method("transformSync", transform::transform_sync)?;
|
||||
m.create_named_method("transformFile", transform::transform_file)?;
|
||||
m.create_named_method("transformFileSync", transform::transform_file_sync)?;
|
||||
|
||||
let c = Compiler::new(cm.clone(), handler);
|
||||
m.create_named_method("parse", parse::parse)?;
|
||||
m.create_named_method("parseSync", parse::parse_sync)?;
|
||||
m.create_named_method("parseFile", parse::parse_file)?;
|
||||
m.create_named_method("parseFileSync", parse::parse_file_sync)?;
|
||||
|
||||
Ok(Arc::new(c))
|
||||
m.create_named_method("print", print::print)?;
|
||||
m.create_named_method("printSync", print::print_sync)?;
|
||||
|
||||
m.create_named_method("bundle", bundle::bundle)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn complete_output<'a>(
|
||||
mut cx: impl Context<'a>,
|
||||
result: Result<TransformOutput, Error>,
|
||||
) -> JsResult<'a, JsValue> {
|
||||
match result {
|
||||
Ok(output) => Ok(neon_serde::to_value(&mut cx, &output)?),
|
||||
Err(err) => cx.throw_error(format!("{:?}", err)),
|
||||
}
|
||||
fn get_compiler(_ctx: &CallContext) -> Arc<Compiler> {
|
||||
COMPILER.clone()
|
||||
}
|
||||
|
||||
#[js_function]
|
||||
fn define_compiler_class(ctx: CallContext) -> napi::Result<JsFunction> {
|
||||
ctx.env.define_class("Compiler", construct_compiler, vec![])
|
||||
}
|
||||
|
||||
#[js_function]
|
||||
fn construct_compiler(ctx: CallContext<JsObject>) -> napi::Result<JsUndefined> {
|
||||
// TODO: Assign swc::Compiler
|
||||
ctx.env.get_undefined()
|
||||
}
|
||||
|
||||
pub fn complete_output(env: &Env, output: TransformOutput) -> napi::Result<JsObject> {
|
||||
serialize(&env, &output)?.coerce_to_object()
|
||||
}
|
||||
|
||||
pub type ArcCompiler = Arc<Compiler>;
|
||||
|
||||
declare_types! {
|
||||
pub class JsCompiler for ArcCompiler {
|
||||
init(cx) {
|
||||
init(cx)
|
||||
}
|
||||
|
||||
method transform(cx) {
|
||||
transform::transform(cx)
|
||||
}
|
||||
|
||||
method transformSync(cx) {
|
||||
transform::transform_sync(cx)
|
||||
}
|
||||
|
||||
method transformFile(cx) {
|
||||
transform::transform_file(cx)
|
||||
}
|
||||
|
||||
method transformFileSync(cx) {
|
||||
transform::transform_file_sync(cx)
|
||||
}
|
||||
|
||||
method parse(cx) {
|
||||
parse::parse(cx)
|
||||
}
|
||||
|
||||
method parseSync(cx) {
|
||||
parse::parse_sync(cx)
|
||||
}
|
||||
|
||||
method parseFile(cx) {
|
||||
parse::parse_file(cx)
|
||||
}
|
||||
|
||||
method parseFileSync(cx) {
|
||||
parse::parse_file_sync(cx)
|
||||
}
|
||||
|
||||
method print(cx) {
|
||||
print::print(cx)
|
||||
}
|
||||
|
||||
method printSync(cx) {
|
||||
print::print_sync(cx)
|
||||
}
|
||||
|
||||
method bundle(cx) {
|
||||
bundle::bundle(cx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
register_module!(mut cx, {
|
||||
cx.export_class::<JsCompiler>("Compiler")?;
|
||||
Ok(())
|
||||
});
|
||||
|
56
native/src/napi_serde/mod.rs
Normal file
56
native/src/napi_serde/mod.rs
Normal file
@ -0,0 +1,56 @@
|
||||
//! Serde for napi.
|
||||
//!
|
||||
//! THis will be extracted as a standalone crate in future.
|
||||
|
||||
pub use self::ser::serialize;
|
||||
use std::{fmt, fmt::Display};
|
||||
|
||||
mod ser;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum Error {
|
||||
Normal(anyhow::Error),
|
||||
Napi(napi::Error),
|
||||
}
|
||||
|
||||
impl Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Error::Normal(v) => Display::fmt(v, f),
|
||||
Error::Napi(v) => Display::fmt(&v.reason, f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::ser::Error for Error {
|
||||
fn custom<T: Display>(msg: T) -> Self {
|
||||
anyhow::Error::msg(msg.to_string()).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::de::Error for Error {
|
||||
fn custom<T: Display>(msg: T) -> Self {
|
||||
anyhow::Error::msg(msg.to_string()).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for Error {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
Error::Normal(v) => v.source(),
|
||||
Error::Napi(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<anyhow::Error> for Error {
|
||||
fn from(e: anyhow::Error) -> Self {
|
||||
Self::Normal(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<napi::Error> for Error {
|
||||
fn from(e: napi::Error) -> Self {
|
||||
Self::Napi(e)
|
||||
}
|
||||
}
|
403
native/src/napi_serde/ser.rs
Normal file
403
native/src/napi_serde/ser.rs
Normal file
@ -0,0 +1,403 @@
|
||||
use super::Error;
|
||||
use napi::{Env, JsObject, JsUnknown, Status};
|
||||
use serde::{
|
||||
ser::{
|
||||
SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, SerializeTuple,
|
||||
SerializeTupleStruct, SerializeTupleVariant,
|
||||
},
|
||||
Serialize, Serializer,
|
||||
};
|
||||
|
||||
pub fn serialize<T>(env: &Env, node: &T) -> napi::Result<napi::JsUnknown>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let s = Ser { env };
|
||||
match node.serialize(s) {
|
||||
Ok(v) => Ok(v),
|
||||
Err(err) => match err {
|
||||
Error::Normal(v) => Err(napi::Error::new(Status::GenericFailure, format!("{:?}", v))),
|
||||
Error::Napi(err) => Err(err),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
struct Ser<'env> {
|
||||
env: &'env Env,
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
struct ArraySerializer<'env> {
|
||||
env: &'env Env,
|
||||
array: JsObject,
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
struct TupleVariantSerializer<'env> {
|
||||
outter_object: JsObject,
|
||||
inner: ArraySerializer<'env>,
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
struct MapSerializer<'env> {
|
||||
env: &'env Env,
|
||||
object: JsObject,
|
||||
key_holder: JsObject,
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
struct StructSerializer<'env> {
|
||||
env: &'env Env,
|
||||
object: JsObject,
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
struct StructVariantSerializer<'env> {
|
||||
outer_object: JsObject,
|
||||
inner: StructSerializer<'env>,
|
||||
}
|
||||
|
||||
impl<'env> Serializer for Ser<'env> {
|
||||
type Ok = JsUnknown;
|
||||
type Error = Error;
|
||||
|
||||
type SerializeSeq = ArraySerializer<'env>;
|
||||
type SerializeTuple = ArraySerializer<'env>;
|
||||
type SerializeTupleStruct = ArraySerializer<'env>;
|
||||
|
||||
type SerializeTupleVariant = TupleVariantSerializer<'env>;
|
||||
type SerializeMap = MapSerializer<'env>;
|
||||
type SerializeStruct = StructSerializer<'env>;
|
||||
type SerializeStructVariant = StructVariantSerializer<'env>;
|
||||
|
||||
fn serialize_bool(self, v: bool) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(self.env.get_boolean(v)?.into_unknown()?)
|
||||
}
|
||||
|
||||
fn serialize_i8(self, v: i8) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(self.env.create_int32(v as _)?.into_unknown()?)
|
||||
}
|
||||
|
||||
fn serialize_i16(self, v: i16) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(self.env.create_int32(v as _)?.into_unknown()?)
|
||||
}
|
||||
|
||||
fn serialize_i32(self, v: i32) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(self.env.create_int32(v)?.into_unknown()?)
|
||||
}
|
||||
|
||||
fn serialize_i64(self, v: i64) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(self.env.create_int64(v)?.into_unknown()?)
|
||||
}
|
||||
|
||||
fn serialize_u8(self, v: u8) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(self.env.create_uint32(v as _)?.into_unknown()?)
|
||||
}
|
||||
|
||||
fn serialize_u16(self, v: u16) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(self.env.create_uint32(v as _)?.into_unknown()?)
|
||||
}
|
||||
|
||||
fn serialize_u32(self, v: u32) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(self.env.create_uint32(v as _)?.into_unknown()?)
|
||||
}
|
||||
|
||||
fn serialize_u64(self, v: u64) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(self.env.create_int64(v as _)?.into_unknown()?)
|
||||
}
|
||||
|
||||
fn serialize_f32(self, v: f32) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(self.env.create_double(v as _)?.into_unknown()?)
|
||||
}
|
||||
|
||||
fn serialize_f64(self, v: f64) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(self.env.create_double(v as _)?.into_unknown()?)
|
||||
}
|
||||
|
||||
fn serialize_char(self, v: char) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(self
|
||||
.env
|
||||
.create_string_from_std(v.to_string())?
|
||||
.into_unknown()?)
|
||||
}
|
||||
|
||||
fn serialize_str(self, v: &str) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(self.env.create_string(v)?.into_unknown()?)
|
||||
}
|
||||
|
||||
fn serialize_bytes(self, v: &[u8]) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(self
|
||||
.env
|
||||
.create_buffer_with_data(v.to_vec())?
|
||||
.into_unknown()?)
|
||||
}
|
||||
|
||||
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(self.env.get_null()?.into_unknown()?)
|
||||
}
|
||||
|
||||
fn serialize_some<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: serde::Serialize,
|
||||
{
|
||||
value.serialize(self)
|
||||
}
|
||||
|
||||
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(self.env.get_null()?.into_unknown()?)
|
||||
}
|
||||
|
||||
fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(self.env.get_null()?.into_unknown()?)
|
||||
}
|
||||
|
||||
fn serialize_unit_variant(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
variant: &'static str,
|
||||
) -> Result<Self::Ok, Self::Error> {
|
||||
self.serialize_str(variant)
|
||||
}
|
||||
|
||||
fn serialize_newtype_struct<T: ?Sized>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
value: &T,
|
||||
) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: serde::Serialize,
|
||||
{
|
||||
value.serialize(self)
|
||||
}
|
||||
|
||||
fn serialize_newtype_variant<T: ?Sized>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
variant: &'static str,
|
||||
value: &T,
|
||||
) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: serde::Serialize,
|
||||
{
|
||||
let mut obj = self.env.create_object()?;
|
||||
let value = serialize(&self.env, &value)?;
|
||||
obj.set_named_property(variant, value)?;
|
||||
Ok(obj.into_unknown()?)
|
||||
}
|
||||
|
||||
fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
|
||||
Ok(ArraySerializer {
|
||||
env: self.env,
|
||||
array: self.env.create_array_with_length(len.unwrap_or(0))?,
|
||||
})
|
||||
}
|
||||
|
||||
fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error> {
|
||||
Ok(ArraySerializer {
|
||||
env: self.env,
|
||||
array: self.env.create_array_with_length(len)?,
|
||||
})
|
||||
}
|
||||
|
||||
fn serialize_tuple_struct(
|
||||
self,
|
||||
_name: &'static str,
|
||||
len: usize,
|
||||
) -> Result<Self::SerializeTupleStruct, Self::Error> {
|
||||
Ok(ArraySerializer {
|
||||
env: self.env,
|
||||
array: self.env.create_array_with_length(len)?,
|
||||
})
|
||||
}
|
||||
|
||||
fn serialize_tuple_variant(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
_variant: &'static str,
|
||||
len: usize,
|
||||
) -> Result<Self::SerializeTupleVariant, Self::Error> {
|
||||
Ok(TupleVariantSerializer {
|
||||
outter_object: self.env.create_object()?,
|
||||
inner: ArraySerializer {
|
||||
env: self.env,
|
||||
array: self.env.create_array_with_length(len)?,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
|
||||
Ok(MapSerializer {
|
||||
env: self.env,
|
||||
object: self.env.create_object()?,
|
||||
key_holder: self.env.create_object()?,
|
||||
})
|
||||
}
|
||||
|
||||
fn serialize_struct(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeStruct, Self::Error> {
|
||||
Ok(StructSerializer {
|
||||
env: self.env,
|
||||
object: self.env.create_object()?,
|
||||
})
|
||||
}
|
||||
|
||||
fn serialize_struct_variant(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
_variant: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeStructVariant, Self::Error> {
|
||||
Ok(StructVariantSerializer {
|
||||
outer_object: self.env.create_object()?,
|
||||
inner: StructSerializer {
|
||||
env: self.env,
|
||||
object: self.env.create_object()?,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl SerializeSeq for ArraySerializer<'_> {
|
||||
type Ok = JsUnknown;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: serde::Serialize,
|
||||
{
|
||||
let value = serialize(self.env, &value)?;
|
||||
let cur_len = self.array.get_array_length()?;
|
||||
self.array.set_index(cur_len as _, value)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(self.array.into_unknown()?)
|
||||
}
|
||||
}
|
||||
|
||||
impl SerializeTuple for ArraySerializer<'_> {
|
||||
type Ok = JsUnknown;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: serde::Serialize,
|
||||
{
|
||||
SerializeSeq::serialize_element(self, value)
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Self::Ok, Self::Error> {
|
||||
SerializeSeq::end(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl SerializeTupleStruct for ArraySerializer<'_> {
|
||||
type Ok = JsUnknown;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: serde::Serialize,
|
||||
{
|
||||
SerializeSeq::serialize_element(self, value)
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Self::Ok, Self::Error> {
|
||||
SerializeSeq::end(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl SerializeTupleVariant for TupleVariantSerializer<'_> {
|
||||
type Ok = JsUnknown;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: serde::Serialize,
|
||||
{
|
||||
SerializeSeq::serialize_element(&mut self.inner, value)
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(self.outter_object.into_unknown()?)
|
||||
}
|
||||
}
|
||||
|
||||
impl SerializeMap for MapSerializer<'_> {
|
||||
type Ok = JsUnknown;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: serde::Serialize,
|
||||
{
|
||||
let key = serialize(self.env, &key)?;
|
||||
self.key_holder.set_named_property("key", key)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: serde::Serialize,
|
||||
{
|
||||
let key = self.key_holder.get_named_property("key")?;
|
||||
let value = serialize(self.env, &value)?;
|
||||
self.object.set_property(key, value)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(self.object.into_unknown()?)
|
||||
}
|
||||
}
|
||||
|
||||
impl SerializeStruct for StructSerializer<'_> {
|
||||
type Ok = JsUnknown;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_field<T: ?Sized>(
|
||||
&mut self,
|
||||
key: &'static str,
|
||||
value: &T,
|
||||
) -> Result<(), Self::Error>
|
||||
where
|
||||
T: serde::Serialize,
|
||||
{
|
||||
let value = serialize(self.env, &value)?;
|
||||
self.object.set_named_property(key, value)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(self.object.into_unknown()?)
|
||||
}
|
||||
}
|
||||
|
||||
impl SerializeStructVariant for StructVariantSerializer<'_> {
|
||||
type Ok = JsUnknown;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_field<T: ?Sized>(
|
||||
&mut self,
|
||||
key: &'static str,
|
||||
value: &T,
|
||||
) -> Result<(), Self::Error>
|
||||
where
|
||||
T: serde::Serialize,
|
||||
{
|
||||
SerializeStruct::serialize_field(&mut self.inner, key, value)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(self.outer_object.into_unknown()?)
|
||||
}
|
||||
}
|
@ -1,6 +1,9 @@
|
||||
use crate::JsCompiler;
|
||||
use anyhow::{Context as _, Error};
|
||||
use neon::prelude::*;
|
||||
use crate::{
|
||||
get_compiler,
|
||||
util::{CtxtExt, MapErr},
|
||||
};
|
||||
use anyhow::Context as _;
|
||||
use napi::{CallContext, Env, JsObject, JsString, Task};
|
||||
use std::{
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
@ -23,178 +26,136 @@ pub struct ParseFileTask {
|
||||
pub options: ParseOptions,
|
||||
}
|
||||
|
||||
pub fn complete_parse<'a>(
|
||||
mut cx: impl Context<'a>,
|
||||
result: Result<Program, Error>,
|
||||
c: &Compiler,
|
||||
) -> JsResult<'a, JsValue> {
|
||||
c.run(|| match result {
|
||||
Ok(program) => Ok(cx
|
||||
.string(serde_json::to_string(&program).expect("failed to serialize Program"))
|
||||
.upcast()),
|
||||
Err(err) => cx.throw_error(format!("{:?}", err)),
|
||||
})
|
||||
pub fn complete_parse<'a>(env: &Env, program: Program, _c: &Compiler) -> napi::Result<JsString> {
|
||||
let s = serde_json::to_string(&program)
|
||||
.context("failed to serialize Program")
|
||||
.convert_err()?;
|
||||
env.create_string_from_std(s)
|
||||
}
|
||||
|
||||
impl Task for ParseTask {
|
||||
type Output = Program;
|
||||
type Error = Error;
|
||||
type JsEvent = JsValue;
|
||||
type JsValue = JsString;
|
||||
|
||||
fn perform(&self) -> Result<Self::Output, Self::Error> {
|
||||
self.c.run(|| {
|
||||
self.c.parse_js(
|
||||
fn compute(&mut self) -> napi::Result<Self::Output> {
|
||||
let program = self
|
||||
.c
|
||||
.parse_js(
|
||||
self.fm.clone(),
|
||||
self.options.target,
|
||||
self.options.syntax,
|
||||
self.options.is_module,
|
||||
self.options.comments,
|
||||
)
|
||||
})
|
||||
.convert_err()?;
|
||||
|
||||
Ok(program)
|
||||
}
|
||||
|
||||
fn complete(
|
||||
self,
|
||||
cx: TaskContext,
|
||||
result: Result<Self::Output, Self::Error>,
|
||||
) -> JsResult<Self::JsEvent> {
|
||||
complete_parse(cx, result, &self.c)
|
||||
fn resolve(&self, env: &mut Env, result: Self::Output) -> napi::Result<Self::JsValue> {
|
||||
complete_parse(env, result, &self.c)
|
||||
}
|
||||
}
|
||||
|
||||
impl Task for ParseFileTask {
|
||||
type Output = Program;
|
||||
type Error = Error;
|
||||
type JsEvent = JsValue;
|
||||
type JsValue = JsString;
|
||||
|
||||
fn perform(&self) -> Result<Self::Output, Self::Error> {
|
||||
fn compute(&mut self) -> napi::Result<Self::Output> {
|
||||
self.c.run(|| {
|
||||
let fm = self
|
||||
.c
|
||||
.cm
|
||||
.load_file(&self.path)
|
||||
.context("failed to read module")?;
|
||||
.context("failed to read module")
|
||||
.convert_err()?;
|
||||
|
||||
self.c.parse_js(
|
||||
fm,
|
||||
self.options.target,
|
||||
self.options.syntax,
|
||||
self.options.is_module,
|
||||
self.options.comments,
|
||||
)
|
||||
self.c
|
||||
.parse_js(
|
||||
fm,
|
||||
self.options.target,
|
||||
self.options.syntax,
|
||||
self.options.is_module,
|
||||
self.options.comments,
|
||||
)
|
||||
.convert_err()
|
||||
})
|
||||
}
|
||||
|
||||
fn complete(
|
||||
self,
|
||||
cx: TaskContext,
|
||||
result: Result<Self::Output, Self::Error>,
|
||||
) -> JsResult<Self::JsEvent> {
|
||||
complete_parse(cx, result, &self.c)
|
||||
fn resolve(&self, env: &mut Env, result: Self::Output) -> napi::Result<Self::JsValue> {
|
||||
complete_parse(env, result, &self.c)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse(mut cx: MethodContext<JsCompiler>) -> JsResult<JsValue> {
|
||||
let src = cx.argument::<JsString>(0)?;
|
||||
let options_arg = cx.argument::<JsValue>(1)?;
|
||||
let options: ParseOptions = neon_serde::from_value(&mut cx, options_arg)?;
|
||||
let callback = cx.argument::<JsFunction>(2)?;
|
||||
#[js_function(2)]
|
||||
pub fn parse(ctx: CallContext) -> napi::Result<JsObject> {
|
||||
let c = get_compiler(&ctx);
|
||||
let src = ctx.get::<JsString>(0)?;
|
||||
let options: ParseOptions = ctx.get_deserialized(1)?;
|
||||
|
||||
let this = cx.this();
|
||||
{
|
||||
let guard = cx.lock();
|
||||
let c = this.borrow(&guard);
|
||||
let fm =
|
||||
c.cm.new_source_file(FileName::Anon, src.as_str()?.to_string());
|
||||
|
||||
let fm = c.cm.new_source_file(FileName::Anon, src.value());
|
||||
ctx.env.spawn(ParseTask {
|
||||
c: c.clone(),
|
||||
fm,
|
||||
options,
|
||||
})
|
||||
}
|
||||
|
||||
ParseTask {
|
||||
c: c.clone(),
|
||||
#[js_function(2)]
|
||||
pub fn parse_sync(cx: CallContext) -> napi::Result<JsString> {
|
||||
let c = get_compiler(&cx);
|
||||
|
||||
c.run(|| {
|
||||
let src = cx.get::<JsString>(0)?.as_str()?.to_string();
|
||||
let options: ParseOptions = cx.get_deserialized(1)?;
|
||||
|
||||
let program = {
|
||||
let fm = c.cm.new_source_file(FileName::Anon, src);
|
||||
c.parse_js(
|
||||
fm,
|
||||
options.target,
|
||||
options.syntax,
|
||||
options.is_module,
|
||||
options.comments,
|
||||
)
|
||||
}
|
||||
.convert_err()?;
|
||||
|
||||
complete_parse(&cx.env, program, &c)
|
||||
})
|
||||
}
|
||||
|
||||
#[js_function(2)]
|
||||
pub fn parse_file_sync(cx: CallContext) -> napi::Result<JsString> {
|
||||
let c = get_compiler(&cx);
|
||||
let path = cx.get::<JsString>(0)?;
|
||||
let options: ParseOptions = cx.get_deserialized(1)?;
|
||||
|
||||
let program = {
|
||||
let fm =
|
||||
c.cm.load_file(Path::new(path.as_str()?))
|
||||
.expect("failed to read program file");
|
||||
|
||||
c.parse_js(
|
||||
fm,
|
||||
options,
|
||||
}
|
||||
.schedule(callback);
|
||||
};
|
||||
|
||||
Ok(cx.undefined().upcast())
|
||||
}
|
||||
|
||||
pub fn parse_sync(mut cx: MethodContext<JsCompiler>) -> JsResult<JsValue> {
|
||||
let c;
|
||||
let this = cx.this();
|
||||
{
|
||||
let guard = cx.lock();
|
||||
let compiler = this.borrow(&guard);
|
||||
c = compiler.clone();
|
||||
options.target,
|
||||
options.syntax,
|
||||
options.is_module,
|
||||
options.comments,
|
||||
)
|
||||
}
|
||||
c.run(|| {
|
||||
let src = cx.argument::<JsString>(0)?;
|
||||
let options_arg = cx.argument::<JsValue>(1)?;
|
||||
let options: ParseOptions = neon_serde::from_value(&mut cx, options_arg)?;
|
||||
.convert_err()?;
|
||||
|
||||
let program = {
|
||||
let fm = c.cm.new_source_file(FileName::Anon, src.value());
|
||||
c.parse_js(
|
||||
fm,
|
||||
options.target,
|
||||
options.syntax,
|
||||
options.is_module,
|
||||
options.comments,
|
||||
)
|
||||
};
|
||||
|
||||
complete_parse(cx, program, &c)
|
||||
})
|
||||
complete_parse(cx.env, program, &c)
|
||||
}
|
||||
|
||||
pub fn parse_file_sync(mut cx: MethodContext<JsCompiler>) -> JsResult<JsValue> {
|
||||
let c;
|
||||
let this = cx.this();
|
||||
{
|
||||
let guard = cx.lock();
|
||||
let compiler = this.borrow(&guard);
|
||||
c = compiler.clone();
|
||||
}
|
||||
c.run(|| {
|
||||
let path = cx.argument::<JsString>(0)?;
|
||||
let options_arg = cx.argument::<JsValue>(1)?;
|
||||
let options: ParseOptions = neon_serde::from_value(&mut cx, options_arg)?;
|
||||
#[js_function(2)]
|
||||
pub fn parse_file(cx: CallContext) -> napi::Result<JsObject> {
|
||||
let c = get_compiler(&cx);
|
||||
let path = PathBuf::from(cx.get::<JsString>(0)?.as_str()?);
|
||||
let options: ParseOptions = cx.get_deserialized(1)?;
|
||||
|
||||
let program = {
|
||||
let fm =
|
||||
c.cm.load_file(Path::new(&path.value()))
|
||||
.expect("failed to read program file");
|
||||
|
||||
c.parse_js(
|
||||
fm,
|
||||
options.target,
|
||||
options.syntax,
|
||||
options.is_module,
|
||||
options.comments,
|
||||
)
|
||||
};
|
||||
|
||||
complete_parse(cx, program, &c)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_file(mut cx: MethodContext<JsCompiler>) -> JsResult<JsValue> {
|
||||
let path = cx.argument::<JsString>(0)?;
|
||||
let options_arg = cx.argument::<JsValue>(1)?;
|
||||
let options: ParseOptions = neon_serde::from_value(&mut cx, options_arg)?;
|
||||
let callback = cx.argument::<JsFunction>(2)?;
|
||||
|
||||
let this = cx.this();
|
||||
{
|
||||
let guard = cx.lock();
|
||||
let c = this.borrow(&guard);
|
||||
|
||||
ParseFileTask {
|
||||
c: c.clone(),
|
||||
path: path.value().into(),
|
||||
options,
|
||||
}
|
||||
.schedule(callback);
|
||||
};
|
||||
|
||||
Ok(cx.undefined().upcast())
|
||||
cx.env.spawn(ParseFileTask { c, path, options })
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
use crate::{complete_output, JsCompiler};
|
||||
use anyhow::Error;
|
||||
use neon::prelude::*;
|
||||
use crate::{
|
||||
complete_output, get_compiler,
|
||||
util::{CtxtExt, MapErr},
|
||||
};
|
||||
use napi::{CallContext, Env, JsObject, JsString, Task};
|
||||
use std::sync::Arc;
|
||||
use swc::{
|
||||
config::{Options, SourceMapsConfig},
|
||||
@ -18,11 +20,11 @@ pub struct PrintTask {
|
||||
|
||||
impl Task for PrintTask {
|
||||
type Output = TransformOutput;
|
||||
type Error = Error;
|
||||
type JsEvent = JsValue;
|
||||
fn perform(&self) -> Result<Self::Output, Self::Error> {
|
||||
self.c.run(|| {
|
||||
self.c.print(
|
||||
type JsValue = JsObject;
|
||||
|
||||
fn compute(&mut self) -> napi::Result<Self::Output> {
|
||||
self.c
|
||||
.print(
|
||||
&self.program,
|
||||
self.options
|
||||
.source_maps
|
||||
@ -36,71 +38,51 @@ impl Task for PrintTask {
|
||||
.minify
|
||||
.unwrap_or(false),
|
||||
)
|
||||
})
|
||||
.convert_err()
|
||||
}
|
||||
|
||||
fn complete(
|
||||
self,
|
||||
cx: TaskContext,
|
||||
result: Result<Self::Output, Self::Error>,
|
||||
) -> JsResult<Self::JsEvent> {
|
||||
complete_output(cx, result)
|
||||
fn resolve(&self, env: &mut Env, result: Self::Output) -> napi::Result<Self::JsValue> {
|
||||
complete_output(env, result)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print(mut cx: MethodContext<JsCompiler>) -> JsResult<JsValue> {
|
||||
let program = cx.argument::<JsString>(0)?;
|
||||
#[js_function(2)]
|
||||
pub fn print(cx: CallContext) -> napi::Result<JsObject> {
|
||||
let c = get_compiler(&cx);
|
||||
let program = cx.get::<JsString>(0)?;
|
||||
let program: Program =
|
||||
serde_json::from_str(&program.value()).expect("failed to deserialize Program");
|
||||
serde_json::from_str(program.as_str()?).expect("failed to deserialize Program");
|
||||
|
||||
let options = cx.argument::<JsValue>(1)?;
|
||||
let options: Options = neon_serde::from_value(&mut cx, options)?;
|
||||
let options: Options = cx.get_deserialized(1)?;
|
||||
|
||||
let callback = cx.argument::<JsFunction>(2)?;
|
||||
|
||||
let this = cx.this();
|
||||
{
|
||||
let guard = cx.lock();
|
||||
let c = this.borrow(&guard);
|
||||
|
||||
PrintTask {
|
||||
c: c.clone(),
|
||||
program,
|
||||
options,
|
||||
}
|
||||
.schedule(callback)
|
||||
}
|
||||
|
||||
Ok(cx.undefined().upcast())
|
||||
}
|
||||
|
||||
pub fn print_sync(mut cx: MethodContext<JsCompiler>) -> JsResult<JsValue> {
|
||||
let c;
|
||||
let this = cx.this();
|
||||
{
|
||||
let guard = cx.lock();
|
||||
let compiler = this.borrow(&guard);
|
||||
c = compiler.clone();
|
||||
}
|
||||
c.run(|| {
|
||||
let program = cx.argument::<JsString>(0)?;
|
||||
let program: Program =
|
||||
serde_json::from_str(&program.value()).expect("failed to deserialize Program");
|
||||
|
||||
let options = cx.argument::<JsValue>(1)?;
|
||||
let options: Options = neon_serde::from_value(&mut cx, options)?;
|
||||
|
||||
let result = {
|
||||
c.print(
|
||||
&program,
|
||||
options
|
||||
.source_maps
|
||||
.clone()
|
||||
.unwrap_or(SourceMapsConfig::Bool(false)),
|
||||
None,
|
||||
options.config.unwrap_or_default().minify.unwrap_or(false),
|
||||
)
|
||||
};
|
||||
complete_output(cx, result)
|
||||
cx.env.spawn(PrintTask {
|
||||
c: c.clone(),
|
||||
program,
|
||||
options,
|
||||
})
|
||||
}
|
||||
|
||||
#[js_function(2)]
|
||||
pub fn print_sync(cx: CallContext) -> napi::Result<JsObject> {
|
||||
let c = get_compiler(&cx);
|
||||
|
||||
let program = cx.get::<JsString>(0)?;
|
||||
let program: Program =
|
||||
serde_json::from_str(&program.as_str()?).expect("failed to deserialize Program");
|
||||
|
||||
let options: Options = cx.get_deserialized(1)?;
|
||||
|
||||
let result = {
|
||||
c.print(
|
||||
&program,
|
||||
options
|
||||
.source_maps
|
||||
.clone()
|
||||
.unwrap_or(SourceMapsConfig::Bool(false)),
|
||||
None,
|
||||
options.config.unwrap_or_default().minify.unwrap_or(false),
|
||||
)
|
||||
}
|
||||
.convert_err()?;
|
||||
complete_output(cx.env, result)
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
use crate::{complete_output, JsCompiler};
|
||||
use crate::{
|
||||
complete_output, get_compiler,
|
||||
util::{CtxtExt, MapErr},
|
||||
};
|
||||
use anyhow::{Context as _, Error};
|
||||
use neon::prelude::*;
|
||||
use napi::{CallContext, Env, JsBoolean, JsObject, JsString, Task};
|
||||
use path_clean::clean;
|
||||
use std::{
|
||||
path::{Path, PathBuf},
|
||||
@ -29,95 +32,75 @@ pub struct TransformTask {
|
||||
|
||||
impl Task for TransformTask {
|
||||
type Output = TransformOutput;
|
||||
type Error = Error;
|
||||
type JsEvent = JsValue;
|
||||
type JsValue = JsObject;
|
||||
|
||||
fn perform(&self) -> Result<Self::Output, Self::Error> {
|
||||
self.c.run(|| match self.input {
|
||||
Input::Program(ref s) => {
|
||||
let program: Program =
|
||||
serde_json::from_str(&s).expect("failed to deserialize Program");
|
||||
// TODO: Source map
|
||||
self.c.process_js(program, &self.options)
|
||||
}
|
||||
fn compute(&mut self) -> napi::Result<Self::Output> {
|
||||
self.c
|
||||
.run(|| match self.input {
|
||||
Input::Program(ref s) => {
|
||||
let program: Program =
|
||||
serde_json::from_str(&s).expect("failed to deserialize Program");
|
||||
// TODO: Source map
|
||||
self.c.process_js(program, &self.options)
|
||||
}
|
||||
|
||||
Input::File(ref path) => {
|
||||
let fm = self.c.cm.load_file(path).context("failed to read module")?;
|
||||
self.c.process_js_file(fm, &self.options)
|
||||
}
|
||||
Input::File(ref path) => {
|
||||
let fm = self.c.cm.load_file(path).context("failed to read module")?;
|
||||
self.c.process_js_file(fm, &self.options)
|
||||
}
|
||||
|
||||
Input::Source(ref s) => self.c.process_js_file(s.clone(), &self.options),
|
||||
})
|
||||
Input::Source(ref s) => self.c.process_js_file(s.clone(), &self.options),
|
||||
})
|
||||
.convert_err()
|
||||
}
|
||||
|
||||
fn complete(
|
||||
self,
|
||||
cx: TaskContext,
|
||||
result: Result<Self::Output, Self::Error>,
|
||||
) -> JsResult<Self::JsEvent> {
|
||||
complete_output(cx, result)
|
||||
fn resolve(&self, env: &mut Env, result: Self::Output) -> napi::Result<Self::JsValue> {
|
||||
complete_output(env, result)
|
||||
}
|
||||
}
|
||||
|
||||
/// returns `compiler, (src / path), options, plugin, callback`
|
||||
pub fn schedule_transform<F>(mut cx: MethodContext<JsCompiler>, op: F) -> JsResult<JsValue>
|
||||
pub fn schedule_transform<F>(cx: CallContext, op: F) -> napi::Result<JsObject>
|
||||
where
|
||||
F: FnOnce(&Arc<Compiler>, String, bool, Options) -> TransformTask,
|
||||
{
|
||||
let c;
|
||||
let this = cx.this();
|
||||
{
|
||||
let guard = cx.lock();
|
||||
c = this.borrow(&guard).clone();
|
||||
};
|
||||
let c = get_compiler(&cx);
|
||||
|
||||
let s = cx.argument::<JsString>(0)?.value();
|
||||
let is_module = cx.argument::<JsBoolean>(1)?;
|
||||
let options_arg = cx.argument::<JsValue>(2)?;
|
||||
let s = cx.get::<JsString>(0)?.as_str()?.to_string();
|
||||
let is_module = cx.get::<JsBoolean>(1)?;
|
||||
let options: Options = cx.get_deserialized(2)?;
|
||||
|
||||
let options: Options = neon_serde::from_value(&mut cx, options_arg)?;
|
||||
let callback = cx.argument::<JsFunction>(3)?;
|
||||
let task = op(&c, s, is_module.get_value()?, options);
|
||||
|
||||
let task = op(&c, s, is_module.value(), options);
|
||||
task.schedule(callback);
|
||||
|
||||
Ok(cx.undefined().upcast())
|
||||
cx.env.spawn(task)
|
||||
}
|
||||
|
||||
pub fn exec_transform<F>(mut cx: MethodContext<JsCompiler>, op: F) -> JsResult<JsValue>
|
||||
pub fn exec_transform<F>(cx: CallContext, op: F) -> napi::Result<JsObject>
|
||||
where
|
||||
F: FnOnce(&Compiler, String, &Options) -> Result<Arc<SourceFile>, Error>,
|
||||
{
|
||||
let s = cx.argument::<JsString>(0)?;
|
||||
let is_module = cx.argument::<JsBoolean>(1)?;
|
||||
let options: Options = match cx.argument_opt(2) {
|
||||
Some(v) => neon_serde::from_value(&mut cx, v)?,
|
||||
None => {
|
||||
let obj = cx.empty_object().upcast();
|
||||
neon_serde::from_value(&mut cx, obj)?
|
||||
let c = get_compiler(&cx);
|
||||
|
||||
let s = cx.get::<JsString>(0)?;
|
||||
let is_module = cx.get::<JsBoolean>(1)?;
|
||||
let options: Options = cx.get_deserialized(2)?;
|
||||
|
||||
let output = c.run(|| -> napi::Result<_> {
|
||||
if is_module.get_value()? {
|
||||
let program: Program =
|
||||
serde_json::from_str(s.as_str()?).expect("failed to deserialize Program");
|
||||
c.process_js(program, &options).convert_err()
|
||||
} else {
|
||||
let fm = op(&c, s.as_str()?.to_string(), &options).expect("failed to create fm");
|
||||
c.process_js_file(fm, &options).convert_err()
|
||||
}
|
||||
};
|
||||
})?;
|
||||
|
||||
let this = cx.this();
|
||||
let output = {
|
||||
let guard = cx.lock();
|
||||
let c = this.borrow(&guard);
|
||||
c.run(|| {
|
||||
if is_module.value() {
|
||||
let program: Program =
|
||||
serde_json::from_str(&s.value()).expect("failed to deserialize Program");
|
||||
c.process_js(program, &options)
|
||||
} else {
|
||||
let fm = op(&c, s.value(), &options).expect("failed to create fm");
|
||||
c.process_js_file(fm, &options)
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
complete_output(cx, output)
|
||||
complete_output(cx.env, output)
|
||||
}
|
||||
|
||||
pub fn transform(cx: MethodContext<JsCompiler>) -> JsResult<JsValue> {
|
||||
#[js_function(4)]
|
||||
pub fn transform(cx: CallContext) -> napi::Result<JsObject> {
|
||||
schedule_transform(cx, |c, src, is_module, options| {
|
||||
let input = if is_module {
|
||||
Input::Program(src)
|
||||
@ -140,7 +123,8 @@ pub fn transform(cx: MethodContext<JsCompiler>) -> JsResult<JsValue> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn transform_sync(cx: MethodContext<JsCompiler>) -> JsResult<JsValue> {
|
||||
#[js_function(4)]
|
||||
pub fn transform_sync(cx: CallContext) -> napi::Result<JsObject> {
|
||||
exec_transform(cx, |c, src, options| {
|
||||
Ok(c.cm.new_source_file(
|
||||
if options.filename.is_empty() {
|
||||
@ -153,7 +137,8 @@ pub fn transform_sync(cx: MethodContext<JsCompiler>) -> JsResult<JsValue> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn transform_file(cx: MethodContext<JsCompiler>) -> JsResult<JsValue> {
|
||||
#[js_function(4)]
|
||||
pub fn transform_file(cx: CallContext) -> napi::Result<JsObject> {
|
||||
schedule_transform(cx, |c, path, _, options| {
|
||||
let path = clean(&path);
|
||||
|
||||
@ -165,7 +150,8 @@ pub fn transform_file(cx: MethodContext<JsCompiler>) -> JsResult<JsValue> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn transform_file_sync(cx: MethodContext<JsCompiler>) -> JsResult<JsValue> {
|
||||
#[js_function(4)]
|
||||
pub fn transform_file_sync(cx: CallContext) -> napi::Result<JsObject> {
|
||||
exec_transform(cx, |c, path, _| {
|
||||
Ok(c.cm
|
||||
.load_file(Path::new(&path))
|
||||
|
36
native/src/util.rs
Normal file
36
native/src/util.rs
Normal file
@ -0,0 +1,36 @@
|
||||
use anyhow::Context;
|
||||
use napi::{CallContext, JsBuffer, NapiValue, Status};
|
||||
use serde::de::DeserializeOwned;
|
||||
|
||||
pub trait MapErr<T>: Into<Result<T, anyhow::Error>> {
|
||||
fn convert_err(self) -> napi::Result<T> {
|
||||
self.into()
|
||||
.map_err(|err| napi::Error::new(Status::GenericFailure, format!("{:?}", err)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> MapErr<T> for Result<T, anyhow::Error> {}
|
||||
|
||||
pub trait CtxtExt {
|
||||
/// Currently this uses JsBuffer
|
||||
fn get_deserialized<T>(&self, index: usize) -> napi::Result<T>
|
||||
where
|
||||
T: DeserializeOwned;
|
||||
}
|
||||
|
||||
impl<V> CtxtExt for CallContext<'_, V>
|
||||
where
|
||||
V: NapiValue,
|
||||
{
|
||||
fn get_deserialized<T>(&self, index: usize) -> napi::Result<T>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
let buffer = self.get::<JsBuffer>(index)?;
|
||||
let v = serde_json::from_slice(&buffer)
|
||||
.with_context(|| format!("Argument at `{}` is not JsBuffer", index))
|
||||
.convert_err()?;
|
||||
|
||||
Ok(v)
|
||||
}
|
||||
}
|
@ -1,34 +1,42 @@
|
||||
const swc = require("../../..");
|
||||
const path = require('path');
|
||||
const os = require('os');
|
||||
|
||||
|
||||
it('should handle multiple entries on same level', async () => {
|
||||
const result = await swc.bundle({
|
||||
entry: {
|
||||
a: path.join(__dirname, '../../tests/spack/mutli-entry-same-level/src/a.js'),
|
||||
b: path.join(__dirname, '../../tests/spack/mutli-entry-same-level/src/b.js'),
|
||||
}
|
||||
|
||||
if (os.platform() !== 'win32') {
|
||||
it('should handle multiple entries on same level', async () => {
|
||||
const result = await swc.bundle({
|
||||
entry: {
|
||||
a: path.join(__dirname, '../../tests/spack/mutli-entry-same-level/src/a.js'),
|
||||
b: path.join(__dirname, '../../tests/spack/mutli-entry-same-level/src/b.js'),
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.a).toBeTruthy();
|
||||
expect(result.a.code).toContain(`import { foo } from './common-`);
|
||||
|
||||
expect(result.b).toBeTruthy();
|
||||
expect(result.b.code).toContain(`import { foo } from './common-`);
|
||||
});
|
||||
|
||||
expect(result.a).toBeTruthy();
|
||||
expect(result.a.code).toContain(`import { foo } from './common-`);
|
||||
|
||||
expect(result.b).toBeTruthy();
|
||||
expect(result.b.code).toContain(`import { foo } from './common-`);
|
||||
});
|
||||
it('should handle multiple entries on different level', async () => {
|
||||
const result = await swc.bundle({
|
||||
entry: {
|
||||
web: path.join(__dirname, '../../tests/spack/mutli-entry-different-level/src/web/index.js'),
|
||||
a: path.join(__dirname, '../../tests/spack/mutli-entry-different-level/src/a.js'),
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.a).toBeTruthy();
|
||||
expect(result.a.code).toContain(`import { foo } from './common-`);
|
||||
|
||||
it('should handle multiple entries on different level', async () => {
|
||||
const result = await swc.bundle({
|
||||
entry: {
|
||||
web: path.join(__dirname, '../../tests/spack/mutli-entry-different-level/src/web/index.js'),
|
||||
a: path.join(__dirname, '../../tests/spack/mutli-entry-different-level/src/a.js'),
|
||||
}
|
||||
expect(result.web).toBeTruthy();
|
||||
expect(result.web.code).toContain(`../common`);
|
||||
});
|
||||
|
||||
expect(result.a).toBeTruthy();
|
||||
expect(result.a.code).toContain(`import { foo } from './common-`);
|
||||
|
||||
expect(result.web).toBeTruthy();
|
||||
expect(result.web.code).toContain(`../common`);
|
||||
});
|
||||
} else {
|
||||
it('should not be error on windows', async () => {
|
||||
expect('I hate windows').toBeTruthy()
|
||||
});
|
||||
}
|
@ -1,490 +0,0 @@
|
||||
/*!
|
||||
* node-swc: lib/extensions.js
|
||||
*/
|
||||
|
||||
var eol = require("os").EOL,
|
||||
fs = require("fs"),
|
||||
pkg = require("../../package.json"),
|
||||
mkdir = require("mkdirp"),
|
||||
path = require("path"),
|
||||
defaultBinaryDir = path.join(__dirname, "..", "..", "native"),
|
||||
trueCasePathSync = require("true-case-path");
|
||||
|
||||
/**
|
||||
* Get the human readable name of the Platform that is running
|
||||
*
|
||||
* @param {string} platform - An OS platform to match, or null to fallback to
|
||||
* the current process platform
|
||||
* @return {Object} The name of the platform if matched, false otherwise
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
function getHumanPlatform(platform) {
|
||||
switch (platform || process.platform) {
|
||||
case "darwin":
|
||||
return "OS X";
|
||||
case "freebsd":
|
||||
return "FreeBSD";
|
||||
case "linux":
|
||||
return "Linux";
|
||||
case "linux_musl":
|
||||
return "Linux/musl";
|
||||
case "win32":
|
||||
return "Windows";
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a more readable version of the architecture
|
||||
*
|
||||
* @param {string} arch - An instruction architecture name to match, or null to
|
||||
* lookup the current process architecture
|
||||
* @return {Object} The value of the process architecture, or false if unknown
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
function getHumanArchitecture(arch) {
|
||||
switch (arch || process.arch) {
|
||||
case "ia32":
|
||||
return "32-bit";
|
||||
case "x86":
|
||||
return "32-bit";
|
||||
case "x64":
|
||||
return "64-bit";
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the friendly name of the Node environment being run
|
||||
*
|
||||
* @param {Object} abi - A Node Application Binary Interface value, or null to
|
||||
* fallback to the current Node ABI
|
||||
* @return {Object} Returns a string name of the Node environment or false if
|
||||
* unmatched
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
function getHumanNodeVersion(abi) {
|
||||
switch (parseInt(abi || process.versions.modules, 10)) {
|
||||
case 11:
|
||||
return "Node 0.10.x";
|
||||
case 14:
|
||||
return "Node 0.12.x";
|
||||
case 42:
|
||||
return "io.js 1.x";
|
||||
case 43:
|
||||
return "io.js 1.1.x";
|
||||
case 44:
|
||||
return "io.js 2.x";
|
||||
case 45:
|
||||
return "io.js 3.x";
|
||||
case 46:
|
||||
return "Node.js 4.x";
|
||||
case 47:
|
||||
return "Node.js 5.x";
|
||||
case 48:
|
||||
return "Node.js 6.x";
|
||||
case 49:
|
||||
return "Electron 1.3.x";
|
||||
case 50:
|
||||
return "Electron 1.4.x";
|
||||
case 51:
|
||||
return "Node.js 7.x";
|
||||
case 53:
|
||||
return "Electron 1.6.x";
|
||||
case 57:
|
||||
return "Node.js 8.x";
|
||||
case 59:
|
||||
return "Node.js 9.x";
|
||||
case 64:
|
||||
return "Node.js 10.x";
|
||||
case 67:
|
||||
return "Node.js 11.x";
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a human readable description of where node-swc is running to support
|
||||
* user error reporting when something goes wrong
|
||||
*
|
||||
* @param {string} env - The name of the native bindings that is to be parsed
|
||||
* @return {string} A description of what os, architecture, and Node version
|
||||
* that is being run
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
function getHumanEnvironment(env) {
|
||||
var binding = env.replace(/_binding\.node$/, ""),
|
||||
parts = binding.split("-"),
|
||||
platform = getHumanPlatform(parts[0]),
|
||||
arch = getHumanArchitecture(parts[1]),
|
||||
runtime = getHumanNodeVersion(parts[2]);
|
||||
|
||||
if (parts.length !== 3) {
|
||||
return "Unknown environment (" + binding + ")";
|
||||
}
|
||||
|
||||
if (!platform) {
|
||||
platform = "Unsupported platform (" + parts[0] + ")";
|
||||
}
|
||||
|
||||
if (!arch) {
|
||||
arch = "Unsupported architecture (" + parts[1] + ")";
|
||||
}
|
||||
|
||||
if (!runtime) {
|
||||
runtime = "Unsupported runtime (" + parts[2] + ")";
|
||||
}
|
||||
|
||||
return [platform, arch, "with", runtime].join(" ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the binaries under the default path
|
||||
*
|
||||
* @return {Array} The currently installed node-swc bindings
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
function getInstalledBinaries() {
|
||||
return fs.readdirSync(getBinaryDir());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that an environment matches the whitelisted values or the current
|
||||
* environment if no parameters are passed
|
||||
*
|
||||
* @param {string} platform - The name of the OS platform(darwin, win32, etc...)
|
||||
* @param {string} arch - The instruction set architecture of the Node environment
|
||||
* @param {string} abi - The Node Application Binary Interface
|
||||
* @return {Boolean} True, if node-swc supports the current platform, false otherwise
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
function isSupportedEnvironment(platform, arch, abi) {
|
||||
return (
|
||||
false !== getHumanPlatform(platform) &&
|
||||
false !== getHumanArchitecture(arch) &&
|
||||
false !== getHumanNodeVersion(abi)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of a CLI argument
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {Array} args
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function getArgument(name, args) {
|
||||
var flags = args || process.argv.slice(2),
|
||||
index = flags.lastIndexOf(name);
|
||||
|
||||
if (index === -1 || index + 1 >= flags.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return flags[index + 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get binary name.
|
||||
* If environment variable SWC_BINARY_NAME,
|
||||
* .npmrc variable swc_binary_name or
|
||||
* process argument --binary-name is provided,
|
||||
* return it as is, otherwise make default binary
|
||||
* name: {platform}-{arch}-{v8 version}.node
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function getBinaryName() {
|
||||
var binaryName,
|
||||
variant,
|
||||
platform = process.platform;
|
||||
|
||||
if (getArgument("--swc-binary-name")) {
|
||||
binaryName = getArgument("--swc-binary-name");
|
||||
} else if (process.env.SWC_BINARY_NAME) {
|
||||
binaryName = process.env.SWC_BINARY_NAME;
|
||||
} else if (process.env.npm_config_swc_binary_name) {
|
||||
binaryName = process.env.npm_config_swc_binary_name;
|
||||
} else if (pkg.nodeSwcConfig && pkg.nodeSwcConfig.binaryName) {
|
||||
binaryName = pkg.nodeSwcConfig.binaryName;
|
||||
} else {
|
||||
variant = getPlatformVariant();
|
||||
if (variant) {
|
||||
platform += "_" + variant;
|
||||
}
|
||||
|
||||
binaryName = [
|
||||
platform,
|
||||
"-",
|
||||
process.arch,
|
||||
"-",
|
||||
process.versions.modules,
|
||||
].join("");
|
||||
}
|
||||
|
||||
return [binaryName, ".node"].join("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the URL to fetch binary file from.
|
||||
* By default fetch from the node-swc distribution
|
||||
* site on GitHub.
|
||||
*
|
||||
* The default URL can be overriden using
|
||||
* the environment variable SWC_BINARY_SITE,
|
||||
* .npmrc variable swc_binary_site or
|
||||
* or a command line option --swc-binary-site:
|
||||
*
|
||||
* node scripts/install.js --swc-binary-site http://example.com/
|
||||
*
|
||||
* The URL should to the mirror of the repository
|
||||
* laid out as follows:
|
||||
*
|
||||
* SWC_BINARY_SITE/
|
||||
*
|
||||
* v3.0.0
|
||||
* v3.0.0/freebsd-x64-14_binding.node
|
||||
* ....
|
||||
* v3.0.0
|
||||
* v3.0.0/freebsd-ia32-11_binding.node
|
||||
* v3.0.0/freebsd-x64-42_binding.node
|
||||
* ... etc. for all supported versions and platforms
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function getBinaryUrl() {
|
||||
var site =
|
||||
getArgument("--swc-binary-site") ||
|
||||
process.env.SWC_BINARY_SITE ||
|
||||
process.env.npm_config_swc_binary_site ||
|
||||
(pkg.nodeSwcConfig && pkg.nodeSwcConfig.binarySite) ||
|
||||
"https://github.com/swc-project/node-swc/releases/download";
|
||||
|
||||
return [site, "v" + pkg.version, getBinaryName()].join("/");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get binary dir.
|
||||
* If environment variable SWC_BINARY_DIR,
|
||||
* .npmrc variable SWC_BINARY_DIR or
|
||||
* process argument --swc-binary-dir is provided,
|
||||
* select it by appending binary name, otherwise
|
||||
* use default binary dir.
|
||||
* Once the primary selection is made, check if
|
||||
* callers wants to throw if file not exists before
|
||||
* returning.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function getBinaryDir() {
|
||||
var binaryDir;
|
||||
|
||||
if (getArgument("--swc-binary-dir")) {
|
||||
binaryDir = getArgument("--swc-binary-dir");
|
||||
} else if (process.env.SWC_BINARY_DIR) {
|
||||
binaryDir = process.env.SWC_BINARY_DIR;
|
||||
} else if (process.env.npm_config_SWC_BINARY_DIR) {
|
||||
binaryDir = process.env.npm_config_SWC_BINARY_DIR;
|
||||
} else if (pkg.nodeSwcConfig && pkg.nodeSwcConfig.binaryDir) {
|
||||
binaryDir = pkg.nodeSwcConfig.binaryDir;
|
||||
} else {
|
||||
binaryDir = defaultBinaryDir;
|
||||
}
|
||||
|
||||
return binaryDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get binary path.
|
||||
* If environment variable SWC_BINARY_PATH,
|
||||
* .npmrc variable SWC_BINARY_PATH or
|
||||
* process argument --swc-binary-path is provided,
|
||||
* select it by appending binary name, otherwise
|
||||
* make default binary path using binary name.
|
||||
* Once the primary selection is made, check if
|
||||
* callers wants to throw if file not exists before
|
||||
* returning.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function getBinaryPath() {
|
||||
var binaryPath;
|
||||
|
||||
if (getArgument("--swc-binary-path")) {
|
||||
binaryPath = getArgument("--swc-binary-path");
|
||||
} else if (process.env.SWC_BINARY_PATH) {
|
||||
binaryPath = process.env.SWC_BINARY_PATH;
|
||||
} else if (process.env.npm_config_SWC_BINARY_PATH) {
|
||||
binaryPath = process.env.npm_config_SWC_BINARY_PATH;
|
||||
} else if (pkg.nodeSwcConfig && pkg.nodeSwcConfig.binaryPath) {
|
||||
binaryPath = pkg.nodeSwcConfig.binaryPath;
|
||||
} else {
|
||||
binaryPath = path.join(getBinaryDir(), "index.node");
|
||||
}
|
||||
|
||||
if (process.versions.modules < 46) {
|
||||
return binaryPath;
|
||||
}
|
||||
|
||||
try {
|
||||
return trueCasePathSync(binaryPath) || binaryPath;
|
||||
} catch (e) {
|
||||
return binaryPath;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An array of paths suitable for use as a local disk cache of the binding.
|
||||
*
|
||||
* @return {[]String} an array of paths
|
||||
* @api public
|
||||
*/
|
||||
function getCachePathCandidates() {
|
||||
return [
|
||||
process.env.npm_config_swc_binary_cache,
|
||||
process.env.npm_config_cache,
|
||||
].filter(function (_) {
|
||||
return _;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The most suitable location for caching the binding on disk.
|
||||
*
|
||||
* Given the candidates directories provided by `getCachePathCandidates()` this
|
||||
* returns the first writable directory. By treating the candidate directories
|
||||
* as a prioritised list this method is deterministic, assuming no change to the
|
||||
* local environment.
|
||||
*
|
||||
* @return {String} directory to cache binding
|
||||
* @api public
|
||||
*/
|
||||
function getBinaryCachePath() {
|
||||
var i,
|
||||
cachePath,
|
||||
cachePathCandidates = getCachePathCandidates();
|
||||
|
||||
for (i = 0; i < cachePathCandidates.length; i++) {
|
||||
cachePath = path.join(cachePathCandidates[i], pkg.name, pkg.version);
|
||||
|
||||
try {
|
||||
mkdir.sync(cachePath);
|
||||
return cachePath;
|
||||
} catch (e) {
|
||||
// Directory is not writable, try another
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* The cached binding
|
||||
*
|
||||
* Check the candidates directories provided by `getCachePathCandidates()` for
|
||||
* the binding file, if it exists. By treating the candidate directories
|
||||
* as a prioritised list this method is deterministic, assuming no change to the
|
||||
* local environment.
|
||||
*
|
||||
* @return {String} path to cached binary
|
||||
* @api public
|
||||
*/
|
||||
function getCachedBinary() {
|
||||
var i,
|
||||
cachePath,
|
||||
cacheBinary,
|
||||
cachePathCandidates = getCachePathCandidates(),
|
||||
binaryName = getBinaryName();
|
||||
|
||||
for (i = 0; i < cachePathCandidates.length; i++) {
|
||||
cachePath = path.join(cachePathCandidates[i], pkg.name, pkg.version);
|
||||
cacheBinary = path.join(cachePath, binaryName);
|
||||
|
||||
if (fs.existsSync(cacheBinary)) {
|
||||
return cacheBinary;
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the supplied binary path exist
|
||||
*
|
||||
* @param {String} binaryPath
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function hasBinary(binaryPath) {
|
||||
return fs.existsSync(binaryPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Swc version information
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function getVersionInfo(binding) {
|
||||
return [
|
||||
["node-swc", pkg.version, "(Wrapper)", "[JavaScript]"].join("\t"),
|
||||
// ['libswc ', binding.libswcVersion(), '(Swc Compiler)', '[C/C++]'].join('\t'),
|
||||
].join(eol);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the platform variant, currently either an empty string or 'musl' for Linux/musl platforms.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function getPlatformVariant() {
|
||||
var contents = "";
|
||||
|
||||
if (process.platform !== "linux") {
|
||||
return "";
|
||||
}
|
||||
|
||||
try {
|
||||
contents = fs.readFileSync(process.execPath);
|
||||
|
||||
// Buffer.indexOf was added in v1.5.0 so cast to string for old node
|
||||
// Delay contents.toStrings because it's expensive
|
||||
if (!contents.indexOf) {
|
||||
contents = contents.toString();
|
||||
}
|
||||
|
||||
if (contents.indexOf("libc.musl-x86_64.so.1") !== -1) {
|
||||
return "musl";
|
||||
}
|
||||
} catch (err) {} // eslint-disable-line no-empty
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
module.exports.hasBinary = hasBinary;
|
||||
module.exports.getBinaryUrl = getBinaryUrl;
|
||||
module.exports.getBinaryName = getBinaryName;
|
||||
module.exports.getBinaryDir = getBinaryDir;
|
||||
module.exports.getBinaryPath = getBinaryPath;
|
||||
module.exports.getBinaryCachePath = getBinaryCachePath;
|
||||
module.exports.getCachedBinary = getCachedBinary;
|
||||
module.exports.getCachePathCandidates = getCachePathCandidates;
|
||||
module.exports.getVersionInfo = getVersionInfo;
|
||||
module.exports.getHumanEnvironment = getHumanEnvironment;
|
||||
module.exports.getInstalledBinaries = getInstalledBinaries;
|
||||
module.exports.isSupportedEnvironment = isSupportedEnvironment;
|
@ -8,10 +8,45 @@ import {
|
||||
Program,
|
||||
} from "./types";
|
||||
export * from "./types";
|
||||
import { wrapNativeSuper } from "./util";
|
||||
import { BundleInput, compileBundleOptions } from "./spack";
|
||||
import { loadBinding } from '@node-rs/helper';
|
||||
import { platform } from 'os';
|
||||
|
||||
const native = require("./native");
|
||||
|
||||
let bindings: any
|
||||
let linuxError = null
|
||||
|
||||
try {
|
||||
bindings = loadBinding(__dirname, 'swc')
|
||||
} catch (e) {
|
||||
const platformName = platform()
|
||||
try {
|
||||
bindings = require(`@swc/core-${platformName}`)
|
||||
} catch (e) {
|
||||
if (platformName !== 'linux') {
|
||||
throw new TypeError('Not compatible with your platform. Error message: ' + e.message)
|
||||
} else {
|
||||
linuxError = e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!bindings) {
|
||||
try {
|
||||
require.resolve('@swc/core-linux-musl')
|
||||
} catch (e) {
|
||||
throw new TypeError(
|
||||
`Could not load @swc/core-linux, You may need add @swc/core-linux-musl to optionalDependencies of your project`,
|
||||
)
|
||||
}
|
||||
try {
|
||||
bindings = require('@swc/core-linux-musl')
|
||||
} catch (e) {
|
||||
throw new TypeError(
|
||||
`Linux glibc version load error: ${linuxError.message}; Linux musl version load error: Error message: ${e.message}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Version of the swc binding.
|
||||
@ -28,26 +63,18 @@ export function plugins(ps: Plugin[]): Plugin {
|
||||
};
|
||||
}
|
||||
|
||||
export class Compiler extends wrapNativeSuper(native.Compiler) {
|
||||
public constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
export class Compiler {
|
||||
parse(
|
||||
src: string,
|
||||
options: ParseOptions & { isModule: false }
|
||||
): Promise<Script>;
|
||||
parse(src: string, options?: ParseOptions): Promise<Module>;
|
||||
parse(src: string, options?: ParseOptions): Promise<Program> {
|
||||
async parse(src: string, options?: ParseOptions): Promise<Program> {
|
||||
options = options || { syntax: "ecmascript" };
|
||||
options.syntax = options.syntax || "ecmascript";
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
super.parse(src, options, (err: any, value: string) => {
|
||||
if (!!err) return reject(err);
|
||||
resolve(JSON.parse(value));
|
||||
});
|
||||
});
|
||||
const res = await bindings.parse(src, toBuffer(options));
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
parseSync(src: string, options: ParseOptions & { isModule: false }): Script;
|
||||
@ -55,7 +82,8 @@ export class Compiler extends wrapNativeSuper(native.Compiler) {
|
||||
parseSync(src: string, options?: ParseOptions): Program {
|
||||
options = options || { syntax: "ecmascript" };
|
||||
options.syntax = options.syntax || "ecmascript";
|
||||
return JSON.parse(super.parseSync(src, options));
|
||||
|
||||
return JSON.parse(bindings.parseSync(src, toBuffer(options)));
|
||||
}
|
||||
|
||||
parseFile(
|
||||
@ -67,12 +95,9 @@ export class Compiler extends wrapNativeSuper(native.Compiler) {
|
||||
options = options || { syntax: "ecmascript" };
|
||||
options.syntax = options.syntax || "ecmascript";
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
super.parseFile(path, options, (err: any, value: string) => {
|
||||
if (!!err) return reject(err);
|
||||
resolve(JSON.parse(value));
|
||||
});
|
||||
});
|
||||
const res = bindings.parseFile(path, toBuffer(options));
|
||||
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
parseFileSync(
|
||||
@ -83,22 +108,18 @@ export class Compiler extends wrapNativeSuper(native.Compiler) {
|
||||
parseFileSync(path: string, options?: ParseOptions): Program {
|
||||
options = options || { syntax: "ecmascript" };
|
||||
options.syntax = options.syntax || "ecmascript";
|
||||
return JSON.parse(super.parseFileSync(path, options));
|
||||
|
||||
return JSON.parse(bindings.parseFileSync(path, toBuffer(options)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: this method should be invoked on the compiler instance used
|
||||
* for `parse()` / `parseSync()`.
|
||||
*/
|
||||
print(m: Program, options?: Options): Promise<Output> {
|
||||
async print(m: Program, options?: Options): Promise<Output> {
|
||||
options = options || {};
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
super.print(JSON.stringify(m), options, (err: any, value: Output) => {
|
||||
if (!!err) return reject(err);
|
||||
resolve(value);
|
||||
});
|
||||
});
|
||||
return bindings.print(JSON.stringify(m), toBuffer(options))
|
||||
}
|
||||
|
||||
/**
|
||||
@ -108,7 +129,7 @@ export class Compiler extends wrapNativeSuper(native.Compiler) {
|
||||
printSync(m: Program, options?: Options): Output {
|
||||
options = options || {};
|
||||
|
||||
return super.printSync(JSON.stringify(m), options);
|
||||
return bindings.printSync(JSON.stringify(m), toBuffer(options));
|
||||
}
|
||||
|
||||
async transform(src: string | Program, options?: Options): Promise<Output> {
|
||||
@ -131,17 +152,7 @@ export class Compiler extends wrapNativeSuper(native.Compiler) {
|
||||
return this.transform(plugin(m), options);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
super.transform(
|
||||
isModule ? JSON.stringify(src) : src,
|
||||
isModule,
|
||||
options,
|
||||
(err: any, value: Output) => {
|
||||
if (!!err) return reject(err);
|
||||
resolve(value);
|
||||
}
|
||||
);
|
||||
});
|
||||
return bindings.transform(isModule ? JSON.stringify(src) : src, isModule, toBuffer(options))
|
||||
}
|
||||
|
||||
transformSync(src: string | Program, options?: Options): Output {
|
||||
@ -162,11 +173,11 @@ export class Compiler extends wrapNativeSuper(native.Compiler) {
|
||||
return this.transformSync(plugin(m), options);
|
||||
}
|
||||
|
||||
return super.transformSync(
|
||||
return bindings.transformSync(
|
||||
isModule ? JSON.stringify(src) : src,
|
||||
isModule,
|
||||
options
|
||||
);
|
||||
toBuffer(options),
|
||||
)
|
||||
}
|
||||
|
||||
async transformFile(path: string, options?: Options): Promise<Output> {
|
||||
@ -185,17 +196,7 @@ export class Compiler extends wrapNativeSuper(native.Compiler) {
|
||||
return this.transform(plugin(m), options);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
super.transformFile(
|
||||
path,
|
||||
/* isModule */ false,
|
||||
options,
|
||||
(err: any, value: Output) => {
|
||||
if (!!err) return reject(err);
|
||||
resolve(value);
|
||||
}
|
||||
);
|
||||
});
|
||||
return bindings.transformFile(path, false, toBuffer(options))
|
||||
}
|
||||
|
||||
transformFileSync(path: string, options?: Options): Output {
|
||||
@ -214,7 +215,7 @@ export class Compiler extends wrapNativeSuper(native.Compiler) {
|
||||
return this.transformSync(plugin(m), options);
|
||||
}
|
||||
|
||||
return super.transformFileSync(path, /* isModule */ false, options);
|
||||
return bindings.transformFileSync(path, /* isModule */ false, toBuffer(options));
|
||||
}
|
||||
|
||||
|
||||
@ -235,14 +236,9 @@ export class Compiler extends wrapNativeSuper(native.Compiler) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
super.bundle({
|
||||
...opts,
|
||||
}, (err: any, value: any) => {
|
||||
if (err) return reject(err);
|
||||
resolve(value)
|
||||
})
|
||||
});
|
||||
return bindings.bundle(toBuffer({
|
||||
...opts,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@ -338,3 +334,7 @@ export const DEFAULT_EXTENSIONS = Object.freeze([
|
||||
".ts",
|
||||
".tsx"
|
||||
]);
|
||||
|
||||
function toBuffer(t: any): Buffer {
|
||||
return Buffer.from(JSON.stringify(t))
|
||||
}
|
45
package.json
45
package.json
@ -1,28 +1,47 @@
|
||||
{
|
||||
"name": "@swc/core",
|
||||
"version": "1.2.22",
|
||||
"version": "1.2.22-alpha.1",
|
||||
"description": "Super-fast alternative for babel",
|
||||
"homepage": "https://swc-project.github.io",
|
||||
"main": "./index.js",
|
||||
"author": "강동윤 <kdy1997.dev@gmail.com>",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"swc",
|
||||
"spack",
|
||||
"babel",
|
||||
"typescript",
|
||||
"rust",
|
||||
"webpack",
|
||||
"tsc"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
"node": ">=8.9.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/swc-project/swc.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/swc-project/swc/issues"
|
||||
},
|
||||
"os": [
|
||||
"darwin",
|
||||
"linux",
|
||||
"win32"
|
||||
],
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dependencies": {
|
||||
"mkdirp": "^0.5.1",
|
||||
"node-fetch": "^2.6.0",
|
||||
"progress": "^2.0.3",
|
||||
"true-case-path": "^1.0.3"
|
||||
"@node-rs/helper": "^0.3.1"
|
||||
},
|
||||
"types": "./lib/index.d.ts",
|
||||
"scripts": {
|
||||
"prepublish": "tsc -d",
|
||||
"install": "node scripts/install.js || (npm install neon-cli && neon build --release)",
|
||||
"build": "tsc -d && neon build --release"
|
||||
"prepublishOnly": "node ./scripts/npm/prepublish.js",
|
||||
"build": "tsc -d && cargo build -p node --release && cd ./native && napi build --platform --release .",
|
||||
"build:dev": "tsc -d && cargo build -p node && cd ./native && napi build --platform .",
|
||||
"test": "jest node-swc/__tests__"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.2.2",
|
||||
@ -39,7 +58,8 @@
|
||||
"browserslist": "^4.12.0",
|
||||
"jest": "^23.6.0",
|
||||
"lodash": "^4.17.11",
|
||||
"neon-cli": "^0.3.3",
|
||||
"napi-rs": "^0.2.6",
|
||||
"progress": "^2.0.3",
|
||||
"source-map": "^0.7.3",
|
||||
"sourcemap-validator": "^1.1.1",
|
||||
"typescript": "^3.9.7"
|
||||
@ -47,5 +67,10 @@
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/swc"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@swc/core-darwin": "^1.2.22",
|
||||
"@swc/core-linux": "^1.2.22",
|
||||
"@swc/core-win32": "^1.2.22"
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ export CARGO_TARGET_DIR=".COVERAGE_DIR"
|
||||
git clone https://github.com/swc-project/ts-parser-test-ref.git ecmascript/parser/tests/typescript/tsc || true
|
||||
(cd ecmascript/parser/tests/typescript/tsc && git pull)
|
||||
|
||||
cargo test --all --all-features --exclude node-swc --exclude wasm --exclude spack
|
||||
cargo test --all --all-features --exclude node-swc --exclude wasm
|
||||
(cd spack && cargo test)
|
||||
|
||||
zip -0 ccov.zip `find $CARGO_TARGET_DIR \( -name "swc*.gc*" -o -name 'spack*.gc*' -o -name 'ast_node*.gc*' -o -name 'enum_kind*.gc*' -o -name 'string-enum*.gc*' -o -name 'from_variant*.gc*' \) -print`;
|
||||
|
@ -1,226 +0,0 @@
|
||||
/*!
|
||||
* Copied from node-sass: scripts/install.js
|
||||
*/
|
||||
|
||||
const fetch = require("node-fetch");
|
||||
|
||||
var fs = require("fs"),
|
||||
os = require("os"),
|
||||
eol = require("os").EOL,
|
||||
mkdir = require("mkdirp"),
|
||||
path = require("path"),
|
||||
swc = require("../node-swc/src/extensions"),
|
||||
ProgressBar = require("progress"),
|
||||
env = process.env;
|
||||
|
||||
/**
|
||||
* Download file, if succeeds save, if not delete
|
||||
*
|
||||
* @param {String} url
|
||||
* @param {String} dest
|
||||
* @param {Function} cb
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function download(url, dest, cb) {
|
||||
var reportError = function(err) {
|
||||
var timeoutMessge;
|
||||
|
||||
if (err.code === "ETIMEDOUT") {
|
||||
if (err.connect === true) {
|
||||
// timeout is hit while your client is attempting to establish a connection to a remote machine
|
||||
timeoutMessge = "Timed out attemping to establish a remote connection";
|
||||
} else {
|
||||
timeoutMessge = "Timed out whilst downloading the prebuilt binary";
|
||||
// occurs any time the server is too slow to send back a part of the response
|
||||
}
|
||||
}
|
||||
cb(
|
||||
[
|
||||
'Cannot download "',
|
||||
url,
|
||||
'": ',
|
||||
eol,
|
||||
eol,
|
||||
typeof err.message === "string" ? err.message : err,
|
||||
eol,
|
||||
eol,
|
||||
timeoutMessge ? timeoutMessge + eol + eol : timeoutMessge,
|
||||
"Hint: If github.com is not accessible in your location",
|
||||
eol,
|
||||
" try setting a proxy via HTTP_PROXY, e.g. ",
|
||||
eol,
|
||||
eol,
|
||||
" export HTTP_PROXY=http://example.com:1234",
|
||||
eol,
|
||||
eol,
|
||||
"or configure npm proxy via",
|
||||
eol,
|
||||
eol,
|
||||
" npm config set proxy http://example.com:8080"
|
||||
].join("")
|
||||
);
|
||||
process.exit(1);
|
||||
};
|
||||
|
||||
console.log("Downloading binary from", url);
|
||||
|
||||
try {
|
||||
fetch(url).then(function(resp) {
|
||||
if (200 <= resp.status && resp.status < 300) {
|
||||
const length = +resp.headers.get("Content-Length");
|
||||
var progress = new ProgressBar(":bar", { total: length });
|
||||
progress.render();
|
||||
// The `progress` is true by default. However if it has not
|
||||
// been explicitly set it's `undefined` which is considered
|
||||
// as far as npm is concerned.
|
||||
if (true) {
|
||||
resp.body
|
||||
.on("data", function(chunk) {
|
||||
progress.tick(chunk.length);
|
||||
})
|
||||
.on("end", function() {
|
||||
progress.terminate();
|
||||
});
|
||||
}
|
||||
|
||||
resp.body.on("error", cb);
|
||||
resp.body.pipe(
|
||||
fs.createWriteStream(dest).on("finsih", function() {
|
||||
console.log("Download complete");
|
||||
})
|
||||
);
|
||||
} else {
|
||||
reportError(
|
||||
["HTTP error", resp.statusCode, resp.statusMessage].join(" ")
|
||||
);
|
||||
}
|
||||
}, reportError);
|
||||
} catch (err) {
|
||||
cb(err);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check and download binary
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function checkAndDownloadBinary() {
|
||||
if (process.env.SKIP_SWC_BINARY_DOWNLOAD_FOR_CI) {
|
||||
console.log("Skipping downloading binaries on CI builds");
|
||||
return;
|
||||
}
|
||||
if (process.env.npm_config_build_from_source) {
|
||||
console.info("Building swc from source code");
|
||||
process.exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
var cachedBinary = swc.getCachedBinary(),
|
||||
cachePath = swc.getBinaryCachePath(),
|
||||
binaryPath = swc.getBinaryPath();
|
||||
|
||||
if (swc.hasBinary(binaryPath)) {
|
||||
console.log("node-swc build", "Binary found at", binaryPath);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
mkdir.sync(path.dirname(binaryPath));
|
||||
} catch (err) {
|
||||
console.error("Unable to save binary", path.dirname(binaryPath), ":", err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cachedBinary) {
|
||||
console.log("Cached binary found at", cachedBinary);
|
||||
fs.createReadStream(cachedBinary).pipe(fs.createWriteStream(binaryPath));
|
||||
return;
|
||||
}
|
||||
|
||||
download(swc.getBinaryUrl(), binaryPath, function(err) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("Binary saved to", binaryPath);
|
||||
|
||||
cachedBinary = path.join(cachePath, swc.getBinaryName());
|
||||
|
||||
if (cachePath) {
|
||||
console.log("Caching binary to", cachedBinary);
|
||||
|
||||
try {
|
||||
mkdir.sync(path.dirname(cachedBinary));
|
||||
fs.createReadStream(binaryPath)
|
||||
.pipe(fs.createWriteStream(cachedBinary))
|
||||
.on("error", function(err) {
|
||||
console.log("Failed to cache binary:", err);
|
||||
});
|
||||
} catch (err) {
|
||||
console.log("Failed to cache binary:", err);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var BANNER =
|
||||
"\u001B[96mThank you for using swc (\u001B[94m https://github.com/swc-project/swc \u001B[96m): super-fast javascript and typescript compiler \u001B[0m\n\n" +
|
||||
"\u001B[96mThe project needs your help! Please consider supporting swc on Open Collective: \u001B[0m\n" +
|
||||
"\u001B[96m>\u001B[94m https://opencollective.com/swc \u001B[0m\n";
|
||||
|
||||
var ADBLOCK = is(env.ADBLOCK);
|
||||
var COLOR = is(env.npm_config_color);
|
||||
var DISABLE_OPENCOLLECTIVE = is(env.DISABLE_OPENCOLLECTIVE);
|
||||
var SILENT =
|
||||
["silent", "error", "warn"].indexOf(env.npm_config_loglevel) !== -1;
|
||||
var MINUTE = 60 * 1000;
|
||||
|
||||
// you could add a PR with an env variable for your CI detection
|
||||
var CI = ["BUILD_NUMBER", "CI", "CONTINUOUS_INTEGRATION", "RUN_ID"].some(
|
||||
function(it) {
|
||||
return is(env[it]);
|
||||
}
|
||||
);
|
||||
|
||||
function is(it) {
|
||||
return !!it && it !== "0" && it !== "false";
|
||||
}
|
||||
|
||||
function isBannerRequired() {
|
||||
if (ADBLOCK || CI || DISABLE_OPENCOLLECTIVE || SILENT) return false;
|
||||
var file = path.join(os.tmpdir(), "core-js-banners");
|
||||
var banners = [];
|
||||
try {
|
||||
var DELTA = Date.now() - fs.statSync(file).mtime;
|
||||
if (DELTA >= 0 && DELTA < MINUTE * 3) {
|
||||
banners = JSON.parse(fs.readFileSync(file, "utf8"));
|
||||
if (banners.indexOf(BANNER) !== -1) return false;
|
||||
}
|
||||
} catch (error) {
|
||||
banners = [];
|
||||
}
|
||||
try {
|
||||
banners.push(BANNER);
|
||||
fs.writeFileSync(file, JSON.stringify(banners), "utf8");
|
||||
} catch (error) {
|
||||
/* empty */
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function showBanner() {
|
||||
// eslint-disable-next-line no-console,no-control-regex
|
||||
console.log(COLOR ? BANNER : BANNER.replace(/\u001B\[\d+m/g, ""));
|
||||
}
|
||||
|
||||
if (isBannerRequired()) showBanner();
|
||||
|
||||
/**
|
||||
* If binary does not exist, download it
|
||||
*/
|
||||
|
||||
checkAndDownloadBinary();
|
21
scripts/npm/core-darwin/package.json
Normal file
21
scripts/npm/core-darwin/package.json
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "@swc/core-darwin",
|
||||
"description": "The macOS 64-bit binary for @swc/core.",
|
||||
"repository": "https://github.com/swc-project/swc",
|
||||
"license": "MIT",
|
||||
"version": "0.0.0",
|
||||
"main": "swc.node",
|
||||
"files": [
|
||||
"swc.node"
|
||||
],
|
||||
"publishConfig": {
|
||||
"registry": "https://registry.npmjs.org/",
|
||||
"access": "public"
|
||||
},
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"cpu": [
|
||||
"x64"
|
||||
]
|
||||
}
|
21
scripts/npm/core-linux/package.json
Normal file
21
scripts/npm/core-linux/package.json
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "@swc/core-linux",
|
||||
"description": "The Linux 64-bit binary for @swc/core.",
|
||||
"repository": "https://github.com/swc-project/swc",
|
||||
"license": "MIT",
|
||||
"version": "0.0.0",
|
||||
"main": "swc.node",
|
||||
"files": [
|
||||
"swc.node"
|
||||
],
|
||||
"publishConfig": {
|
||||
"registry": "https://registry.npmjs.org/",
|
||||
"access": "public"
|
||||
},
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"cpu": [
|
||||
"x64"
|
||||
]
|
||||
}
|
21
scripts/npm/core-win32/package.json
Normal file
21
scripts/npm/core-win32/package.json
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "@swc/core-win32",
|
||||
"description": "The Windows 64-bit binary for @swc-node/core.",
|
||||
"repository": "https://github.com/swc-project/swc",
|
||||
"license": "MIT",
|
||||
"version": "0.0.0",
|
||||
"main": "swc.node",
|
||||
"files": [
|
||||
"swc.node"
|
||||
],
|
||||
"publishConfig": {
|
||||
"registry": "https://registry.npmjs.org/",
|
||||
"access": "public"
|
||||
},
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"cpu": [
|
||||
"x64"
|
||||
]
|
||||
}
|
1
scripts/npm/platforms.js
Normal file
1
scripts/npm/platforms.js
Normal file
@ -0,0 +1 @@
|
||||
module.exports = ['darwin', 'linux', 'win32']
|
34
scripts/npm/prepublish.js
Normal file
34
scripts/npm/prepublish.js
Normal file
@ -0,0 +1,34 @@
|
||||
const { execSync } = require('child_process')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
const { version } = require('../../package.json')
|
||||
const platforms = require('./platforms')
|
||||
const updatePackageJson = require('./update-package')
|
||||
|
||||
updatePackageJson(path.join(__dirname, '..', '..', 'package.json'), {
|
||||
optionalDependencies: platforms.reduce((acc, cur) => {
|
||||
acc[`@swc/core-${cur}`] = `^${version}`
|
||||
return acc
|
||||
}, {}),
|
||||
})
|
||||
|
||||
|
||||
for (const name of platforms) {
|
||||
const pkgDir = path.join(__dirname, `core-${name}`)
|
||||
updatePackageJson(path.join(pkgDir, 'package.json'), {
|
||||
version: `${version}`,
|
||||
})
|
||||
}
|
||||
|
||||
for (const name of platforms) {
|
||||
const pkgDir = path.join(__dirname, `core-${name}`)
|
||||
const bindingFile = fs.readFileSync(path.join(__dirname, '..', '..', 'native', `node.${name}.node`))
|
||||
fs.writeFileSync(path.join(pkgDir, `swc.node`), bindingFile);
|
||||
|
||||
execSync('npm publish', {
|
||||
cwd: pkgDir,
|
||||
env: process.env,
|
||||
stdio: 'inherit',
|
||||
})
|
||||
}
|
6
scripts/npm/update-package.js
Normal file
6
scripts/npm/update-package.js
Normal file
@ -0,0 +1,6 @@
|
||||
const fs = require('fs')
|
||||
|
||||
module.exports = function updatePackageJson(path, partial) {
|
||||
const old = require(path)
|
||||
fs.writeFileSync(path, JSON.stringify({ ...old, ...partial }, null, 2))
|
||||
}
|
8
scripts/setup-env.sh
Normal file
8
scripts/setup-env.sh
Normal file
@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
|
||||
NODE_PLATFORM_NAME=$(node -e "console.log(require('os').platform())")
|
||||
|
||||
|
||||
(cd scripts/npm/core-$NODE_PLATFORM_NAME && npm link)
|
||||
npm link @swc/core-$NODE_PLATFORM_NAME
|
@ -1,23 +0,0 @@
|
||||
/**
|
||||
* Determine the proxy settings configured by npm
|
||||
*
|
||||
* It's possible to configure npm to use a proxy different
|
||||
* from the system defined proxy. This can be done via the
|
||||
* `npm config` CLI or the `.npmrc` config file.
|
||||
*
|
||||
* If a proxy has been configured in this way we must
|
||||
* tell request explicitly to use it.
|
||||
*
|
||||
* Otherwise we can trust request to the right thing.
|
||||
*
|
||||
* @return {String} the proxy configured by npm or an empty string
|
||||
* @api private
|
||||
*/
|
||||
module.exports = function() {
|
||||
return (
|
||||
process.env.npm_config_https_proxy ||
|
||||
process.env.npm_config_proxy ||
|
||||
process.env.npm_config_http_proxy ||
|
||||
""
|
||||
);
|
||||
};
|
@ -1,16 +0,0 @@
|
||||
var pkg = require("../../package.json");
|
||||
|
||||
/**
|
||||
* A custom user agent use for binary downloads.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
module.exports = function() {
|
||||
return [
|
||||
"node/",
|
||||
process.version,
|
||||
" ",
|
||||
"node-swc-installer/",
|
||||
pkg.version
|
||||
].join("");
|
||||
};
|
@ -1,41 +1,41 @@
|
||||
[package]
|
||||
name = "spack"
|
||||
version = "0.0.0"
|
||||
authors = ["강동윤 <kdy1997.dev@gmail.com>"]
|
||||
license = "Apache-2.0/MIT"
|
||||
repository = "https://github.com/swc-project/swc.git"
|
||||
documentation = "https://swc-project.github.io/rustdoc/swc/"
|
||||
description = "Speedy web compiler"
|
||||
documentation = "https://swc-project.github.io/rustdoc/swc/"
|
||||
edition = "2018"
|
||||
license = "Apache-2.0/MIT"
|
||||
name = "spack"
|
||||
publish = false
|
||||
repository = "https://github.com/swc-project/swc.git"
|
||||
version = "0.0.0"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
swc_atoms = { path = "../atoms" }
|
||||
swc_bundler = { path = "../bundler" }
|
||||
swc_common = { path = "../common" }
|
||||
swc_ecma_ast = { path = "../ecmascript/ast" }
|
||||
swc_ecma_codegen = { path = "../ecmascript/codegen" }
|
||||
swc_ecma_parser = { path = "../ecmascript/parser" }
|
||||
swc_ecma_transforms = { path = "../ecmascript/transforms" }
|
||||
swc_ecma_utils = { path = "../ecmascript/utils" }
|
||||
swc_ecma_visit = { path = "../ecmascript/visit" }
|
||||
swc = { path = "../" }
|
||||
string_enum = { version = "0.3", path ="../macros/string_enum" }
|
||||
regex = "1"
|
||||
once_cell = "1"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
anyhow = "1"
|
||||
dashmap = "3"
|
||||
log = "0.4.8"
|
||||
is-macro = "0.1.8"
|
||||
neon = { version = "0.4.0", features = ["event-handler-api"] }
|
||||
neon-sys = "0.4.0"
|
||||
log = "0.4.8"
|
||||
napi = "=0.4.13"
|
||||
once_cell = "1"
|
||||
regex = "1"
|
||||
serde = {version = "1", features = ["derive"]}
|
||||
serde_json = "1"
|
||||
string_enum = {version = "0.3", path = "../macros/string_enum"}
|
||||
swc = {path = "../"}
|
||||
swc_atoms = {path = "../atoms"}
|
||||
swc_bundler = {path = "../bundler"}
|
||||
swc_common = {path = "../common"}
|
||||
swc_ecma_ast = {path = "../ecmascript/ast"}
|
||||
swc_ecma_codegen = {path = "../ecmascript/codegen"}
|
||||
swc_ecma_parser = {path = "../ecmascript/parser"}
|
||||
swc_ecma_transforms = {path = "../ecmascript/transforms"}
|
||||
swc_ecma_utils = {path = "../ecmascript/utils"}
|
||||
swc_ecma_visit = {path = "../ecmascript/visit"}
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "0.6.1"
|
||||
testing = { path = "../testing" }
|
||||
walkdir = "2.3.1"
|
||||
pretty_env_logger = "0.3"
|
||||
tempfile = "3"
|
||||
tempfile = "3"
|
||||
testing = {path = "../testing"}
|
||||
walkdir = "2.3.1"
|
||||
|
@ -1,2 +1 @@
|
||||
pub mod neon;
|
||||
pub mod swc;
|
||||
|
@ -1,75 +0,0 @@
|
||||
use anyhow::{Context as _, Error};
|
||||
use neon::prelude::*;
|
||||
use std::sync::{mpsc::channel, Arc};
|
||||
use swc_bundler::Load;
|
||||
use swc_common::{FileName, SourceFile};
|
||||
use swc_ecma_ast::{Module, Program};
|
||||
|
||||
/// Loader provided by user.
|
||||
pub struct NeonLoader {
|
||||
pub swc: Arc<swc::Compiler>,
|
||||
pub handler: EventHandler,
|
||||
}
|
||||
|
||||
impl Load for NeonLoader {
|
||||
fn load(&self, name: &FileName) -> Result<(Arc<SourceFile>, Module), Error> {
|
||||
let path = name.to_string();
|
||||
let (tx, rx) = channel();
|
||||
|
||||
self.handler.schedule_with(move |cx, _value, f| {
|
||||
//
|
||||
let this = cx.undefined();
|
||||
let path = cx.string(path);
|
||||
|
||||
let res = f.call(cx, this, vec![path]);
|
||||
let res = match res {
|
||||
Ok(v) => v,
|
||||
Err(err) => {
|
||||
let _ = tx.send(Err(Error::msg(format!(
|
||||
"failed to invoke js laoder: {}",
|
||||
err
|
||||
))));
|
||||
return;
|
||||
}
|
||||
};
|
||||
if let Ok(code) = res.downcast::<JsString>() {
|
||||
let s = code.value();
|
||||
match tx.send(Ok(s)) {
|
||||
Ok(_) => return,
|
||||
Err(err) => {
|
||||
let _ = tx.send(Err(Error::msg(format!(
|
||||
"failed to send result back: {}",
|
||||
err
|
||||
))));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let _ = tx.send(Err(Error::msg("failed to invoke js laoder")));
|
||||
});
|
||||
|
||||
let code = rx
|
||||
.recv()
|
||||
.context("failed to receive output from js loader")?;
|
||||
let code = code?;
|
||||
|
||||
let fm = self.swc.cm.new_source_file(name.clone(), code);
|
||||
|
||||
let config = self.swc.config_for_file(
|
||||
&swc::config::Options {
|
||||
swcrc: true,
|
||||
..Default::default()
|
||||
},
|
||||
&fm.name,
|
||||
)?;
|
||||
let module = self
|
||||
.swc
|
||||
.parse_js(fm.clone(), config.target, config.syntax, true, true)?;
|
||||
let module = match module {
|
||||
Program::Module(v) => v,
|
||||
Program::Script(_) => unreachable!("script"),
|
||||
};
|
||||
Ok((fm, module))
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user