mirror of https://github.com/alibaba/ice.git
chore: migrate swc (#4966)
* chore: migrate swc * chore: update script * chore: update lock file * chore: update lock file
This commit is contained in:
parent
ee78096f80
commit
828bdec72e
|
|
@ -1,112 +0,0 @@
|
|||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'swc/*'
|
||||
|
||||
name: Build @builder/swc native binaries
|
||||
|
||||
jobs:
|
||||
test-native:
|
||||
name: Unit Test Native Code
|
||||
runs-on: ubuntu-18.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: nightly-2021-11-05
|
||||
profile: minimal
|
||||
- run: cd packages/swc && cargo test
|
||||
|
||||
build-native:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-18.04, macos-latest, windows-latest]
|
||||
description: [default]
|
||||
include:
|
||||
- os: ubuntu-18.04
|
||||
target: x86_64-unknown-linux-gnu
|
||||
name: linux-x64-gnu
|
||||
- os: windows-latest
|
||||
target: x86_64-pc-windows-msvc
|
||||
name: win32-x64-msvc
|
||||
- os: macos-latest
|
||||
target: x86_64-apple-darwin
|
||||
name: darwin-x64
|
||||
- os: macos-latest
|
||||
target: aarch64-apple-darwin
|
||||
name: darwin-arm64
|
||||
description: m1
|
||||
|
||||
name: builder-swc - ${{ matrix.os }} - ${{ matrix.target }} - node@12
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 12
|
||||
check-latest: true
|
||||
- run: npm run setup
|
||||
- name: Install
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly-2021-11-05
|
||||
target: ${{ matrix.target }}
|
||||
- name: Cache cargo registry
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.cargo/registry
|
||||
key: stable-${{ matrix.os }}-node@14-cargo-registry-trimmed-${{ hashFiles('**/Cargo.lock') }}
|
||||
- name: Cache cargo index
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.cargo/git
|
||||
key: stable-${{ matrix.os }}-node@14-cargo-index-trimmed-${{ hashFiles('**/Cargo.lock') }}
|
||||
- name: Cache native binary
|
||||
id: binary-cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: packages/swc/native/**
|
||||
key: builder-swc-nightly-2021-08-12-${{ matrix.target }}-${{ hashFiles('.github/workflows/build_native.yml', 'packages/swc/**') }}
|
||||
- name: Cross build aarch64 setup
|
||||
if: ${{ matrix.target == 'aarch64-apple-darwin' }}
|
||||
run: |
|
||||
sudo rm -rf /Library/Developer/CommandLineTools/SDKs/*;
|
||||
export CC=$(xcrun -f clang);
|
||||
export CXX=$(xcrun -f clang++);
|
||||
SYSROOT=$(xcrun --sdk macosx --show-sdk-path);
|
||||
export CFLAGS="-isysroot $SYSROOT -isystem $SYSROOT";
|
||||
rustup target install aarch64-apple-darwin;
|
||||
- name: 'Build'
|
||||
if: steps.binary-cache.outputs.cache-hit != true
|
||||
run: yarn build:swc --target ${{ matrix.target }}
|
||||
env:
|
||||
MACOSX_DEPLOYMENT_TARGET: '10.13'
|
||||
working-directory: ./
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v2.2.4
|
||||
with:
|
||||
name: builder-swc-binaries
|
||||
path: packages/swc/native/builder-swc.${{ matrix.name }}.node
|
||||
- name: Clear the cargo caches
|
||||
run: |
|
||||
cargo install cargo-cache --no-default-features --features ci-autoclean
|
||||
cargo-cache
|
||||
commit:
|
||||
needs: build-native
|
||||
runs-on: ubuntu-18.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/download-artifact@v2.0.10
|
||||
with:
|
||||
name: builder-swc-binaries
|
||||
path: packages/swc/native
|
||||
- uses: EndBug/add-and-commit@v7
|
||||
with:
|
||||
add: 'packages/swc/native --force'
|
||||
message: 'Build @builder/swc binaries'
|
||||
|
|
@ -23,7 +23,6 @@ jobs:
|
|||
- run: npm run dependency:check
|
||||
- run: npm run lint
|
||||
- run: npm run test
|
||||
- run: npm run copy:swc
|
||||
- run: npm run version:check
|
||||
- run: npm run coverage
|
||||
env:
|
||||
|
|
|
|||
|
|
@ -33,8 +33,6 @@ coverage
|
|||
|
||||
# Packages
|
||||
packages/*/lib/
|
||||
packages/swc/target/
|
||||
packages/swc/npm/**/*.node
|
||||
|
||||
# temp folder .ice
|
||||
examples/*/.ice
|
||||
|
|
|
|||
20
package.json
20
package.json
|
|
@ -14,21 +14,18 @@
|
|||
"watch": "ts-node ./scripts/watch.ts",
|
||||
"build": "ts-node ./scripts/build.ts",
|
||||
"generate:dts": "ts-node ./scripts/generate-dts.ts",
|
||||
"build:swc": "rm -rf packages/swc/native/** && napi build --platform --release --cargo-cwd packages/swc packages/swc/native",
|
||||
"version": "ts-node ./scripts/tag-version.ts && napi version -p packages/swc/npm -c packages/swc/package.json",
|
||||
"version": "ts-node ./scripts/tag-version.ts",
|
||||
"version:check": "ts-node ./scripts/version-check.ts",
|
||||
"publish": "npm run copy:swc && npm run generate:dts && ts-node ./scripts/publish-package.ts",
|
||||
"publish:beta": "npm run copy:swc && npm run generate:dts && PUBLISH_TYPE=beta ts-node ./scripts/publishPackageWithDistTag.ts",
|
||||
"publish:next": "npm run copy:swc && npm run generate:dts && PUBLISH_TYPE=next VERSION_PREFIX=rc ts-node ./scripts/publishPackageWithDistTag.ts",
|
||||
"publish": "npm run generate:dts && ts-node ./scripts/publish-package.ts",
|
||||
"publish:beta": "npm run generate:dts && PUBLISH_TYPE=beta ts-node ./scripts/publishPackageWithDistTag.ts",
|
||||
"publish:next": "npm run generate:dts && PUBLISH_TYPE=next VERSION_PREFIX=rc ts-node ./scripts/publishPackageWithDistTag.ts",
|
||||
"publish:stable": "npm run generate:dts && PUBLISH_TAG=release-1 ts-node ./scripts/publish-package.ts",
|
||||
"publish:stable-beta": "npm run generate:dts && PUBLISH_TAG=release-1 ts-node ./scripts/publish-beta-package.ts",
|
||||
"sync": "ts-node ./scripts/sync.ts",
|
||||
"rollback": "ts-node ./scripts/rollback.ts",
|
||||
"owner": "ts-node ./scripts/owner.ts",
|
||||
"dependency:check": "ts-node ./scripts/dependency-check.ts",
|
||||
"copy:swc": "ts-node ./scripts/copySwcBinaries.ts",
|
||||
"clean": "rimraf packages/*/lib",
|
||||
"clean:swc": "rimraf packages/swc/native/**",
|
||||
"lint": "eslint --cache --ext .js,.jsx,.ts,.tsx ./",
|
||||
"lint:fix": "npm run lint -- --fix",
|
||||
"test": "jest --forceExit --ci",
|
||||
|
|
@ -85,14 +82,5 @@
|
|||
"@typescript-eslint/parser": "^4.0.0",
|
||||
"postcss": "^8.3.5",
|
||||
"eslint-plugin-react": "7.24.0"
|
||||
},
|
||||
"napi": {
|
||||
"name": "builder-swc",
|
||||
"triples": {
|
||||
"additional": [
|
||||
"aarch64-apple-darwin"
|
||||
],
|
||||
"defaults": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
target
|
||||
Cargo.lock
|
||||
.cargo
|
||||
.github
|
||||
npm
|
||||
.eslintrc
|
||||
.prettierignore
|
||||
rustfmt.toml
|
||||
yarn.lock
|
||||
*.node
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
# Changelog
|
||||
|
||||
## 0.1.3
|
||||
|
||||
- feat: remove multiple ends code
|
||||
- chore: add rust cases
|
||||
- fix: transform react config is invalid
|
||||
|
||||
## 0.1.2
|
||||
|
||||
- feat: add minify binding for @builder/swc
|
||||
- chore: update swc version
|
||||
- fix: error with build mode
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,44 +0,0 @@
|
|||
[package]
|
||||
edition = "2018"
|
||||
name = "builder-swc"
|
||||
version = "0.1.0"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
backtrace = "0.3"
|
||||
chrono = "0.4"
|
||||
easy-error = "1.0.0"
|
||||
napi = { version = "1", features = ["serde-json"] }
|
||||
napi-derive = "1"
|
||||
path-clean = "0.1"
|
||||
regex = "1.5"
|
||||
serde = "1"
|
||||
serde_json = "1"
|
||||
swc = "0.81.1"
|
||||
swc_atoms = "0.2.7"
|
||||
swc_common = { version = "0.14.2", features = ["concurrent", "sourcemap"] }
|
||||
swc_css = "0.20.0"
|
||||
swc_ecmascript = { version = "0.84.1", features = ["codegen", "minifier", "optimization", "parser", "react", "transforms", "typescript", "utils", "visit"] }
|
||||
swc_ecma_preset_env = "0.63.1"
|
||||
swc_node_base = "0.5.1"
|
||||
swc_stylis = "0.17.0"
|
||||
fxhash = "0.2.1"
|
||||
retain_mut = "0.1.3"
|
||||
pathdiff = "0.2.0"
|
||||
rustc-hash = "1.1.0"
|
||||
tracing = { version = "0.1.28", features = ["release_max_level_off"] }
|
||||
lazy_static = "1.4.0"
|
||||
|
||||
[dev-dependencies]
|
||||
swc_ecma_transforms_testing = "0.43.1"
|
||||
testing = "0.15.1"
|
||||
walkdir = "2.3.2"
|
||||
|
||||
[build-dependencies]
|
||||
napi-build = "1"
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
extern crate napi_build;
|
||||
|
||||
fn main() {
|
||||
napi_build::setup();
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
incremental = false
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,92 +0,0 @@
|
|||
/* eslint-disable global-require */
|
||||
/* eslint-disable no-restricted-syntax */
|
||||
/* eslint-disable import/no-dynamic-require */
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import { platform, arch } from 'os';
|
||||
import { platformArchTriples } from '@napi-rs/triples';
|
||||
import { Options, JsMinifyOptions, Output, Binding } from './types';
|
||||
|
||||
const ArchName = arch();
|
||||
const PlatformName = platform();
|
||||
|
||||
/**
|
||||
* __dirname means load native addon from current dir
|
||||
* 'swc' is the name of native addon
|
||||
* the second arguments was decided by `napi.name` field in `package.json`
|
||||
* the third arguments was decided by `name` field in `package.json`
|
||||
* `loadBinding` helper will load `swc.[PLATFORM].node` from `__dirname` first
|
||||
* If failed to load addon, it will fallback to load from `swc-[PLATFORM]`
|
||||
*/
|
||||
const bindings: Binding = loadBinding();
|
||||
|
||||
function loadBinding() {
|
||||
const triples = platformArchTriples[PlatformName][ArchName];
|
||||
for (const triple of triples) {
|
||||
const localFilePath = path.join(
|
||||
__dirname,
|
||||
'../native',
|
||||
`builder-swc.${triple.platformArchABI}.node`
|
||||
);
|
||||
if (fs.existsSync(localFilePath)) {
|
||||
console.log('Load local native module.');
|
||||
return require(localFilePath);
|
||||
}
|
||||
|
||||
try {
|
||||
return require(`@builder/swc-${triple.platformArchABI}`);
|
||||
// eslint-disable-next-line no-empty
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
throw new Error('Cannot find target @builder/swc native module!');
|
||||
}
|
||||
|
||||
async function transform(src: string, options: Options): Promise<Output> {
|
||||
options = options || {};
|
||||
|
||||
if (options?.jsc?.parser) {
|
||||
options.jsc.parser.syntax = options.jsc.parser.syntax ?? 'ecmascript';
|
||||
}
|
||||
|
||||
return bindings.transform(
|
||||
src,
|
||||
false,
|
||||
toBuffer(options)
|
||||
);
|
||||
}
|
||||
|
||||
function transformSync(src: string, options: Options): Output {
|
||||
options = options || {};
|
||||
|
||||
if (options?.jsc?.parser) {
|
||||
options.jsc.parser.syntax = options.jsc.parser.syntax ?? 'ecmascript';
|
||||
}
|
||||
|
||||
return bindings.transformSync(
|
||||
src,
|
||||
false,
|
||||
toBuffer(options)
|
||||
);
|
||||
}
|
||||
|
||||
function toBuffer(t) {
|
||||
return Buffer.from(JSON.stringify(t));
|
||||
}
|
||||
|
||||
async function minify(src: string, opts: JsMinifyOptions): Promise<Output> {
|
||||
return bindings.minify(toBuffer(src), toBuffer(opts ?? {}));
|
||||
}
|
||||
|
||||
function minifySync(src: string, opts: JsMinifyOptions): Output {
|
||||
return bindings.minifySync(toBuffer(src), toBuffer(opts ?? {}));
|
||||
}
|
||||
|
||||
export * from './types';
|
||||
|
||||
export {
|
||||
transform,
|
||||
transformSync,
|
||||
minify,
|
||||
minifySync,
|
||||
};
|
||||
|
|
@ -1,758 +0,0 @@
|
|||
/* eslint-disable @typescript-eslint/no-empty-interface */
|
||||
/* eslint-disable camelcase */
|
||||
export interface Binding {
|
||||
transformSync: (src: string, isModule: boolean, options: Buffer) => Output;
|
||||
transform: (src: string, isModule: boolean, options: Buffer) => Promise<Output>;
|
||||
minifySync: (src: Buffer, options: Buffer) => Output;
|
||||
minify: (src: Buffer, options: Buffer) => Promise<Output>;
|
||||
}
|
||||
|
||||
export type TerserEcmaVersion = 5 | 2015 | 2016 | string | number;
|
||||
|
||||
export interface JsMinifyOptions {
|
||||
compress?: TerserCompressOptions | boolean,
|
||||
|
||||
mangle?: TerserMangleOptions | boolean,
|
||||
|
||||
ecma?: TerserEcmaVersion,
|
||||
|
||||
keep_classnames?: boolean,
|
||||
|
||||
keep_fnames?: boolean,
|
||||
|
||||
module?: boolean,
|
||||
|
||||
safari10?: boolean
|
||||
|
||||
toplevel?: boolean
|
||||
|
||||
sourceMap?: boolean
|
||||
|
||||
outputPath?: string
|
||||
|
||||
inlineSourcesContent?: boolean
|
||||
}
|
||||
|
||||
export interface TerserCompressOptions {
|
||||
arguments?: boolean,
|
||||
arrows?: boolean,
|
||||
|
||||
booleans?: boolean,
|
||||
|
||||
booleans_as_integers?: boolean,
|
||||
|
||||
collapse_vars?: boolean,
|
||||
|
||||
comparisons?: boolean,
|
||||
|
||||
computed_props?: boolean,
|
||||
|
||||
conditionals?: boolean,
|
||||
|
||||
dead_code?: boolean,
|
||||
|
||||
defaults?: boolean,
|
||||
|
||||
directives?: boolean,
|
||||
|
||||
drop_console?: boolean,
|
||||
|
||||
drop_debugger?: boolean,
|
||||
|
||||
ecma?: TerserEcmaVersion,
|
||||
|
||||
evaluate?: boolean,
|
||||
|
||||
expression?: boolean,
|
||||
|
||||
global_defs?: any,
|
||||
|
||||
hoist_funs?: boolean,
|
||||
|
||||
hoist_props?: boolean,
|
||||
|
||||
hoist_vars?: boolean,
|
||||
|
||||
ie8?: boolean,
|
||||
|
||||
if_return?: boolean,
|
||||
|
||||
inline?: 0 | 1 | 2 | 3
|
||||
|
||||
join_vars?: boolean,
|
||||
|
||||
keep_classnames?: boolean,
|
||||
|
||||
keep_fargs?: boolean,
|
||||
|
||||
keep_fnames?: boolean,
|
||||
|
||||
keep_infinity?: boolean,
|
||||
|
||||
loops?: boolean,
|
||||
// module : false,
|
||||
|
||||
negate_iife?: boolean,
|
||||
|
||||
passes?: number,
|
||||
|
||||
properties?: boolean,
|
||||
|
||||
pure_getters?: any,
|
||||
|
||||
pure_funcs?: string[],
|
||||
|
||||
reduce_funcs?: boolean,
|
||||
|
||||
reduce_vars?: boolean,
|
||||
|
||||
sequences?: any,
|
||||
|
||||
side_effects?: boolean,
|
||||
|
||||
switches?: boolean,
|
||||
|
||||
top_retain?: any,
|
||||
|
||||
toplevel?: any,
|
||||
|
||||
typeofs?: boolean,
|
||||
|
||||
unsafe_passes?: boolean,
|
||||
|
||||
unsafe_arrows?: boolean,
|
||||
|
||||
unsafe_comps?: boolean,
|
||||
|
||||
unsafe_function?: boolean,
|
||||
|
||||
unsafe_math?: boolean,
|
||||
|
||||
unsafe_symbols?: boolean,
|
||||
|
||||
unsafe_methods?: boolean,
|
||||
|
||||
unsafe_proto?: boolean,
|
||||
|
||||
unsafe_regexp?: boolean,
|
||||
|
||||
unsafe_undefined?: boolean,
|
||||
|
||||
unused?: boolean,
|
||||
|
||||
module?: boolean,
|
||||
}
|
||||
|
||||
export interface TerserMangleOptions {
|
||||
props?: TerserManglePropertiesOptions,
|
||||
|
||||
top_level?: boolean,
|
||||
|
||||
keep_class_names?: boolean,
|
||||
|
||||
keep_fn_names?: boolean,
|
||||
|
||||
keep_private_props?: boolean,
|
||||
|
||||
ie8?: boolean,
|
||||
|
||||
safari10?: boolean,
|
||||
}
|
||||
|
||||
export interface TerserManglePropertiesOptions {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Programmatic options.
|
||||
*/
|
||||
export interface Options extends Config {
|
||||
/**
|
||||
* If true, a file is parsed as a script instead of module.
|
||||
*/
|
||||
script?: boolean;
|
||||
|
||||
/**
|
||||
* The working directory that all paths in the programmatic
|
||||
* options will be resolved relative to.
|
||||
*
|
||||
* Defaults to `process.cwd()`.
|
||||
*/
|
||||
cwd?: string;
|
||||
caller?: CallerOptions;
|
||||
/** The filename associated with the code currently being compiled,
|
||||
* if there is one. The filename is optional, but not all of Swc's
|
||||
* functionality is available when the filename is unknown, because a
|
||||
* subset of options rely on the filename for their functionality.
|
||||
*
|
||||
* The three primary cases users could run into are:
|
||||
*
|
||||
* - The filename is exposed to plugins. Some plugins may require the
|
||||
* presence of the filename.
|
||||
* - Options like "test", "exclude", and "ignore" require the filename
|
||||
* for string/RegExp matching.
|
||||
* - .swcrc files are loaded relative to the file being compiled.
|
||||
* If this option is omitted, Swc will behave as if swcrc: false has been set.
|
||||
*/
|
||||
filename?: string;
|
||||
|
||||
/**
|
||||
* The initial path that will be processed based on the "rootMode" to
|
||||
* determine the conceptual root folder for the current Swc project.
|
||||
* This is used in two primary cases:
|
||||
*
|
||||
* - The base directory when checking for the default "configFile" value
|
||||
* - The default value for "swcrcRoots".
|
||||
*
|
||||
* Defaults to `opts.cwd`
|
||||
*/
|
||||
root?: string;
|
||||
|
||||
/**
|
||||
* This option, combined with the "root" value, defines how Swc chooses
|
||||
* its project root. The different modes define different ways that Swc
|
||||
* can process the "root" value to get the final project root.
|
||||
*
|
||||
* "root" - Passes the "root" value through as unchanged.
|
||||
* "upward" - Walks upward from the "root" directory, looking for a directory
|
||||
* containinga swc.config.js file, and throws an error if a swc.config.js
|
||||
* is not found.
|
||||
* "upward-optional" - Walk upward from the "root" directory, looking for
|
||||
* a directory containing a swc.config.js file, and falls back to "root"
|
||||
* if a swc.config.js is not found.
|
||||
*
|
||||
*
|
||||
* "root" is the default mode because it avoids the risk that Swc
|
||||
* will accidentally load a swc.config.js that is entirely outside
|
||||
* of the current project folder. If you use "upward-optional",
|
||||
* be aware that it will walk up the directory structure all the
|
||||
* way to the filesystem root, and it is always possible that someone
|
||||
* will have a forgotten swc.config.js in their home directory,
|
||||
* which could cause unexpected errors in your builds.
|
||||
*
|
||||
*
|
||||
* Users with monorepo project structures that run builds/tests on a
|
||||
* per-package basis may well want to use "upward" since monorepos
|
||||
* often have a swc.config.js in the project root. Running Swc
|
||||
* in a monorepo subdirectory without "upward", will cause Swc
|
||||
* to skip loading any swc.config.js files in the project root,
|
||||
* which can lead to unexpected errors and compilation failure.
|
||||
*/
|
||||
rootMode?: 'root' | 'upward' | 'upward-optional';
|
||||
|
||||
/**
|
||||
* The current active environment used during configuration loading.
|
||||
* This value is used as the key when resolving "env" configs,
|
||||
* and is also available inside configuration functions, plugins,
|
||||
* and presets, via the api.env() function.
|
||||
*
|
||||
* Defaults to `process.env.SWC_ENV || process.env.NODE_ENV || "development"`
|
||||
*/
|
||||
envName?: string;
|
||||
|
||||
/**
|
||||
* Defaults to searching for a default `.swcrc` file, but can
|
||||
* be passed the path of any JS or JSON5 config file.
|
||||
*
|
||||
*
|
||||
* NOTE: This option does not affect loading of .swcrc files,
|
||||
* so while it may be tempting to do configFile: "./foo/.swcrc",
|
||||
* it is not recommended. If the given .swcrc is loaded via the
|
||||
* standard file-relative logic, you'll end up loading the same
|
||||
* config file twice, merging it with itself. If you are linking
|
||||
* a specific config file, it is recommended to stick with a
|
||||
* naming scheme that is independent of the "swcrc" name.
|
||||
*
|
||||
* Defaults to `path.resolve(opts.root, ".swcrc")`
|
||||
*/
|
||||
configFile?: string | boolean;
|
||||
|
||||
/**
|
||||
* true will enable searching for configuration files relative to the "filename" provided to Swc.
|
||||
*
|
||||
* A swcrc value passed in the programmatic options will override one set within a configuration file.
|
||||
*
|
||||
* Note: .swcrc files are only loaded if the current "filename" is inside of
|
||||
* a package that matches one of the "swcrcRoots" packages.
|
||||
*
|
||||
*
|
||||
* Defaults to true as long as the filename option has been specificed
|
||||
*/
|
||||
swcrc?: boolean;
|
||||
|
||||
/**
|
||||
* By default, Babel will only search for .babelrc files within the "root" package
|
||||
* because otherwise Babel cannot know if a given .babelrc is meant to be loaded,
|
||||
* or if it's "plugins" and "presets" have even been installed, since the file
|
||||
* being compiled could be inside node_modules, or have been symlinked into the project.
|
||||
*
|
||||
*
|
||||
* This option allows users to provide a list of other packages that should be
|
||||
* considered "root" packages when considering whether to load .babelrc files.
|
||||
*
|
||||
*
|
||||
* For example, a monorepo setup that wishes to allow individual packages
|
||||
* to have their own configs might want to do
|
||||
*
|
||||
*
|
||||
*
|
||||
* Defaults to `opts.root`
|
||||
*/
|
||||
swcrcRoots?: boolean | MatchPattern | MatchPattern[];
|
||||
|
||||
/**
|
||||
* `true` will attempt to load an input sourcemap from the file itself, if it
|
||||
* contains a //# sourceMappingURL=... comment. If no map is found, or the
|
||||
* map fails to load and parse, it will be silently discarded.
|
||||
*
|
||||
* If an object is provided, it will be treated as the source map object itself.
|
||||
*
|
||||
* Defaults to `true`.
|
||||
*/
|
||||
inputSourceMap?: boolean | string;
|
||||
|
||||
/**
|
||||
* The name to use for the file inside the source map object.
|
||||
*
|
||||
* Defaults to `path.basename(opts.filenameRelative)` when available, or `"unknown"`.
|
||||
*/
|
||||
sourceFileName?: string;
|
||||
|
||||
/**
|
||||
* The sourceRoot fields to set in the generated source map, if one is desired.
|
||||
*/
|
||||
sourceRoot?: string;
|
||||
|
||||
plugin?: Plugin;
|
||||
|
||||
isModule?: boolean;
|
||||
|
||||
/**
|
||||
* Destination path. Note that this value is used only to fix source path
|
||||
* of source map files and swc does not write output to this path.
|
||||
*/
|
||||
outputPath?: string;
|
||||
keepPlatform ?: string;
|
||||
}
|
||||
|
||||
export interface CallerOptions {
|
||||
name: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export type Swcrc = Config | Config[];
|
||||
|
||||
/**
|
||||
* .swcrc
|
||||
*/
|
||||
export interface Config {
|
||||
/**
|
||||
* Note: The type is string beacuse it follow rust's regex syntax.
|
||||
*/
|
||||
test?: string | string[];
|
||||
/**
|
||||
* Note: The type is string beacuse it follow rust's regex syntax.
|
||||
*/
|
||||
exclude?: string | string[];
|
||||
env?: EnvConfig;
|
||||
jsc?: JscConfig;
|
||||
module?: ModuleConfig;
|
||||
minify?: boolean;
|
||||
|
||||
/**
|
||||
* - true to generate a sourcemap for the code and include it in the result object.
|
||||
* - "inline" to generate a sourcemap and append it as a data URL to the end of the code, but not include it in the result object.
|
||||
*
|
||||
* `swc-cli` overloads some of these to also affect how maps are written to disk:
|
||||
*
|
||||
* - true will write the map to a .map file on disk
|
||||
* - "inline" will write the file directly, so it will have a data: containing the map
|
||||
* - Note: These options are bit weird, so it may make the most sense to just use true
|
||||
* and handle the rest in your own code, depending on your use case.
|
||||
*/
|
||||
sourceMaps?: boolean | 'inline';
|
||||
|
||||
inlineSourcesContent?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration ported from babel-preset-env
|
||||
*/
|
||||
export interface EnvConfig {
|
||||
mode?: 'usage' | 'entry';
|
||||
debug?: boolean;
|
||||
dynamicImport?: boolean;
|
||||
|
||||
loose?: boolean;
|
||||
|
||||
/// Skipped es features.
|
||||
///
|
||||
/// e.g.)
|
||||
/// - `core-js/modules/foo`
|
||||
skip?: string[];
|
||||
|
||||
include?: string[];
|
||||
|
||||
exclude?: string[];
|
||||
|
||||
/**
|
||||
* The version of the used core js.
|
||||
*
|
||||
*/
|
||||
coreJs?: string;
|
||||
|
||||
targets?: any;
|
||||
|
||||
path?: string;
|
||||
|
||||
shippedProposals?: boolean;
|
||||
|
||||
/**
|
||||
* Enable all trnasforms
|
||||
*/
|
||||
forceAllTransforms?: boolean;
|
||||
}
|
||||
|
||||
export interface JscConfig {
|
||||
loose?: boolean;
|
||||
|
||||
/**
|
||||
* Defaults to EsParserConfig
|
||||
*/
|
||||
parser?: ParserConfig;
|
||||
transform?: TransformConfig;
|
||||
/**
|
||||
* Use `@swc/helpers` instead of inline helpers.
|
||||
*/
|
||||
externalHelpers?: boolean;
|
||||
|
||||
/**
|
||||
* Defaults to `es3` (which enableds **all** pass).
|
||||
*/
|
||||
target?: JscTarget;
|
||||
|
||||
/**
|
||||
* Keep class names.
|
||||
*/
|
||||
keepClassNames?: boolean
|
||||
|
||||
experimetal?: {
|
||||
optimizeHygiene?: boolean
|
||||
},
|
||||
|
||||
paths?: {
|
||||
[from: string]: [string]
|
||||
},
|
||||
minify?: JsMinifyOptions
|
||||
}
|
||||
|
||||
export type JscTarget =
|
||||
| 'es3'
|
||||
| 'es5'
|
||||
| 'es2015'
|
||||
| 'es2016'
|
||||
| 'es2017'
|
||||
| 'es2018'
|
||||
| 'es2019'
|
||||
| 'es2020'
|
||||
| 'es2021';
|
||||
|
||||
export type ParserConfig = TsParserConfig | EsParserConfig;
|
||||
export interface TsParserConfig {
|
||||
syntax: 'typescript';
|
||||
/**
|
||||
* Defaults to `false`.
|
||||
*/
|
||||
tsx?: boolean;
|
||||
/**
|
||||
* Defaults to `false`.
|
||||
*/
|
||||
decorators?: boolean;
|
||||
/**
|
||||
* Defaults to `false`
|
||||
*/
|
||||
dynamicImport?: boolean;
|
||||
}
|
||||
|
||||
export interface EsParserConfig {
|
||||
syntax: 'ecmascript';
|
||||
/**
|
||||
* Defaults to false.
|
||||
*/
|
||||
jsx?: boolean;
|
||||
/**
|
||||
* @deprecated Always true because it's in ecmascript spec.
|
||||
*/
|
||||
numericSeparator?: boolean;
|
||||
/**
|
||||
* @deprecated Always true because it's in ecmascript spec.
|
||||
*/
|
||||
classPrivateProperty?: boolean;
|
||||
/**
|
||||
* @deprecated Always true because it's in ecmascript spec.
|
||||
*/
|
||||
privateMethod?: boolean;
|
||||
/**
|
||||
* @deprecated Always true because it's in ecmascript spec.
|
||||
*/
|
||||
classProperty?: boolean;
|
||||
/**
|
||||
* Defaults to `false`
|
||||
*/
|
||||
functionBind?: boolean;
|
||||
/**
|
||||
* Defaults to `false`
|
||||
*/
|
||||
decorators?: boolean;
|
||||
/**
|
||||
* Defaults to `false`
|
||||
*/
|
||||
decoratorsBeforeExport?: boolean;
|
||||
/**
|
||||
* Defaults to `false`
|
||||
*/
|
||||
exportDefaultFrom?: boolean;
|
||||
/**
|
||||
* @deprecated Always true because it's in ecmascript spec.
|
||||
*/
|
||||
exportNamespaceFrom?: boolean;
|
||||
/**
|
||||
* @deprecated Always true because it's in ecmascript spec.
|
||||
*/
|
||||
dynamicImport?: boolean;
|
||||
/**
|
||||
* @deprecated Always true because it's in ecmascript spec.
|
||||
*/
|
||||
nullishCoalescing?: boolean;
|
||||
/**
|
||||
* @deprecated Always true because it's in ecmascript spec.
|
||||
*/
|
||||
optionalChaining?: boolean;
|
||||
/**
|
||||
* @deprecated Always true because it's in ecmascript spec.
|
||||
*/
|
||||
importMeta?: boolean;
|
||||
/**
|
||||
* @deprecated Always true because it's in ecmascript spec.
|
||||
*/
|
||||
topLevelAwait?: boolean;
|
||||
/**
|
||||
* Defaults to `false`
|
||||
*/
|
||||
importAssertions?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for trasnform.
|
||||
*/
|
||||
export interface TransformConfig {
|
||||
/**
|
||||
* Effective only if `syntax` supports ƒ.
|
||||
*/
|
||||
react?: ReactConfig;
|
||||
|
||||
constModules?: ConstModulesConfig;
|
||||
|
||||
/**
|
||||
* Defaults to null, which skips optimizer pass.
|
||||
*/
|
||||
optimizer?: OptimizerConfig;
|
||||
|
||||
/**
|
||||
* https://swc.rs/docs/configuring-swc.html#jsctransformlegacydecorator
|
||||
*/
|
||||
legacyDecorator?: boolean;
|
||||
|
||||
/**
|
||||
* https://swc.rs/docs/configuring-swc.html#jsctransformdecoratormetadata
|
||||
*/
|
||||
decoratorMetadata?: boolean;
|
||||
}
|
||||
|
||||
export interface ReactConfig {
|
||||
/**
|
||||
* Replace the function used when compiling JSX expressions.
|
||||
*
|
||||
* Defaults to `React.createElement`.
|
||||
*/
|
||||
pragma?: string;
|
||||
/**
|
||||
* Replace the component used when compiling JSX fragments.
|
||||
*
|
||||
* Defaults to `React.Fragment`
|
||||
*/
|
||||
pragmaFrag?: string;
|
||||
/**
|
||||
* Toggles whether or not to throw an error if a XML namespaced tag name is used. For example:
|
||||
* `<f:image />`
|
||||
*
|
||||
* Though the JSX spec allows this, it is disabled by default since React's
|
||||
* JSX does not currently have support for it.
|
||||
*
|
||||
*/
|
||||
throwIfNamespace?: boolean;
|
||||
/**
|
||||
* Toggles plugins that aid in development, such as @swc/plugin-transform-react-jsx-self
|
||||
* and @swc/plugin-transform-react-jsx-source.
|
||||
*
|
||||
* Defaults to `false`,
|
||||
*
|
||||
*/
|
||||
development?: boolean;
|
||||
/**
|
||||
* Use `Object.assign()` instead of `_extends`. Defaults to false.
|
||||
*/
|
||||
useBuiltins?: boolean;
|
||||
|
||||
/**
|
||||
* Enable fast refresh feature for React app
|
||||
*/
|
||||
refresh?: boolean;
|
||||
|
||||
/**
|
||||
* jsx runtime
|
||||
*/
|
||||
runtime?: 'automatic' | 'classic'
|
||||
|
||||
/**
|
||||
* Declares the module specifier to be used for importing the `jsx` and `jsxs` factory functions when using `runtime` 'automatic'
|
||||
*/
|
||||
importSource?: string
|
||||
}
|
||||
/**
|
||||
* - `import { DEBUG } from '@ember/env-flags';`
|
||||
* - `import { FEATURE_A, FEATURE_B } from '@ember/features';`
|
||||
*
|
||||
* See: https://github.com/swc-project/swc/issues/18#issuecomment-466272558
|
||||
*/
|
||||
export interface ConstModulesConfig {
|
||||
globals?: {
|
||||
[module: string]: {
|
||||
[name: string]: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/// https://swc.rs/docs/configuring-swc.html#jsctransformoptimizerjsonify
|
||||
export interface OptimizerConfig {
|
||||
/// https://swc.rs/docs/configuring-swc#jsctransformoptimizer
|
||||
globals?: GlobalPassOption;
|
||||
jsonify?: { minCost: number };
|
||||
simplify?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for inline-global pass.
|
||||
*/
|
||||
export interface GlobalPassOption {
|
||||
/**
|
||||
* Global variables.
|
||||
*
|
||||
* e.g. `{ __DEBUG__: true }`
|
||||
*/
|
||||
vars?: { [key: string]: string };
|
||||
|
||||
/**
|
||||
* Name of environment variables to inline.
|
||||
*
|
||||
* Defaults to `["NODE_ENV", "SWC_ENV"]`
|
||||
*/
|
||||
envs?: string[];
|
||||
}
|
||||
|
||||
export type ModuleConfig = CommonJsConfig | UmdConfig | AmdConfig;
|
||||
|
||||
export interface BaseModuleConfig {
|
||||
/**
|
||||
* By default, when using exports with babel a non-enumerable `__esModule`
|
||||
* property is exported. In some cases this property is used to determine
|
||||
* if the import is the default export or if it contains the default export.
|
||||
*
|
||||
* In order to prevent the __esModule property from being exported, you
|
||||
* can set the strict option to true.
|
||||
*
|
||||
* Defaults to `false`.
|
||||
*/
|
||||
strict?: boolean;
|
||||
|
||||
/**
|
||||
* Emits 'use strict' directive.
|
||||
*
|
||||
* Defaults to `true`.
|
||||
*/
|
||||
strictMode?: boolean;
|
||||
|
||||
/**
|
||||
* Changes Babel's compiled import statements to be lazily evaluated when their imported bindings are used for the first time.
|
||||
*
|
||||
* This can improve initial load time of your module because evaluating dependencies up
|
||||
* front is sometimes entirely un-necessary. This is especially the case when implementing
|
||||
* a library module.
|
||||
*
|
||||
*
|
||||
* The value of `lazy` has a few possible effects:
|
||||
*
|
||||
* - `false` - No lazy initialization of any imported module.
|
||||
* - `true` - Do not lazy-initialize local `./foo` imports, but lazy-init `foo` dependencies.
|
||||
*
|
||||
* Local paths are much more likely to have circular dependencies, which may break if loaded lazily,
|
||||
* so they are not lazy by default, whereas dependencies between independent modules are rarely cyclical.
|
||||
*
|
||||
* - `Array<string>` - Lazy-initialize all imports with source matching one of the given strings.
|
||||
*
|
||||
* -----
|
||||
*
|
||||
* The two cases where imports can never be lazy are:
|
||||
*
|
||||
* - `import "foo";`
|
||||
*
|
||||
* Side-effect imports are automatically non-lazy since their very existence means
|
||||
* that there is no binding to later kick off initialization.
|
||||
*
|
||||
* - `export * from "foo"`
|
||||
*
|
||||
* Re-exporting all names requires up-front execution because otherwise there is no
|
||||
* way to know what names need to be exported.
|
||||
*
|
||||
* Defaults to `false`.
|
||||
*/
|
||||
lazy?: boolean | string[];
|
||||
/**
|
||||
* By default, when using exports with swc a non-enumerable __esModule property is exported.
|
||||
* This property is then used to determine if the import is the default export or if
|
||||
* it contains the default export.
|
||||
*
|
||||
* In cases where the auto-unwrapping of default is not needed, you can set the noInterop option
|
||||
* to true to avoid the usage of the interopRequireDefault helper (shown in inline form above).
|
||||
*
|
||||
* Defaults to `false`.
|
||||
*/
|
||||
noInterop?: boolean;
|
||||
}
|
||||
|
||||
export interface CommonJsConfig extends BaseModuleConfig {
|
||||
type: 'commonjs';
|
||||
}
|
||||
|
||||
export interface UmdConfig extends BaseModuleConfig {
|
||||
type: 'umd';
|
||||
globals?: { [key: string]: string };
|
||||
}
|
||||
|
||||
export interface AmdConfig extends BaseModuleConfig {
|
||||
type: 'amd';
|
||||
moduleId?: string;
|
||||
}
|
||||
|
||||
export interface Output {
|
||||
/**
|
||||
* Transformed code
|
||||
*/
|
||||
code: string;
|
||||
/**
|
||||
* Sourcemap (**not** base64 encoded)
|
||||
*/
|
||||
map?: string;
|
||||
}
|
||||
|
||||
export interface MatchPattern { }
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
# `swc-darwin-arm64`
|
||||
|
||||
This is the **aarch64-apple-darwin** binary for `swc`
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
{
|
||||
"name": "@builder/swc-darwin-arm64",
|
||||
"version": "0.1.3",
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"main": "builder-swc.darwin-arm64.node",
|
||||
"files": [
|
||||
"builder-swc.darwin-arm64.node"
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
# `swc-darwin-x64`
|
||||
|
||||
This is the **x86_64-apple-darwin** binary for `swc`
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
{
|
||||
"name": "@builder/swc-darwin-x64",
|
||||
"version": "0.1.3",
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"main": "builder-swc.darwin-x64.node",
|
||||
"files": [
|
||||
"builder-swc.darwin-x64.node"
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
# `swc-linux-x64-gnu`
|
||||
|
||||
This is the **x86_64-unknown-linux-gnu** binary for `swc`
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
{
|
||||
"name": "@builder/swc-linux-x64-gnu",
|
||||
"version": "0.1.3",
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"main": "builder-swc.linux-x64-gnu.node",
|
||||
"files": [
|
||||
"builder-swc.linux-x64-gnu.node"
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
# `swc-win32-x64-msvc`
|
||||
|
||||
This is the **x86_64-pc-windows-msvc** binary for `swc`
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
{
|
||||
"name": "@builder/swc-win32-x64-msvc",
|
||||
"version": "0.1.3",
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"main": "builder-swc.win32-x64-msvc.node",
|
||||
"files": [
|
||||
"builder-swc.win32-x64-msvc.node"
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
{
|
||||
"name": "@builder/swc",
|
||||
"version": "0.1.3",
|
||||
"main": "lib/index.js",
|
||||
"napi": {
|
||||
"name": "builder-swc",
|
||||
"triples": {
|
||||
"additional": [
|
||||
"aarch64-apple-darwin"
|
||||
],
|
||||
"defaults": true
|
||||
}
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@napi-rs/triples": "^1.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@builder/swc-darwin-x64": "^0.1.0",
|
||||
"@builder/swc-linux-x64-gnu": "^0.1.0",
|
||||
"@builder/swc-darwin-arm64": "^0.1.0",
|
||||
"@builder/swc-win32-x64-msvc": "^0.1.0"
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
nightly-2021-11-05
|
||||
|
|
@ -1,140 +0,0 @@
|
|||
use crate::lazy_static;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use swc_common::DUMMY_SP;
|
||||
use swc_ecmascript::ast::{
|
||||
BindingIdent, Bool, Decl, Expr, Ident, ImportNamedSpecifier, ImportSpecifier, Lit, ModuleDecl,
|
||||
ModuleItem, Pat, Stmt, VarDecl, VarDeclKind, VarDeclarator,
|
||||
};
|
||||
|
||||
use swc_ecmascript::visit::Fold;
|
||||
|
||||
#[derive(Debug, Deserialize, Default, Clone)]
|
||||
pub struct KeepPlatformPatcher {
|
||||
pub platform: String,
|
||||
}
|
||||
|
||||
/// Configuration related to source map generated by swc.
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
#[serde(untagged)]
|
||||
pub enum KeepPlatformConfig {
|
||||
Bool(bool),
|
||||
KeepPlatform(String),
|
||||
}
|
||||
|
||||
impl Default for KeepPlatformConfig {
|
||||
fn default() -> Self {
|
||||
KeepPlatformConfig::Bool(false)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn keep_platform(options: KeepPlatformConfig) -> impl Fold {
|
||||
let platform: String = match options {
|
||||
KeepPlatformConfig::KeepPlatform(platform) => platform,
|
||||
_ => "".to_string(),
|
||||
};
|
||||
KeepPlatformPatcher { platform: platform }
|
||||
}
|
||||
|
||||
// platform maps
|
||||
lazy_static! {
|
||||
static ref PLATFORM_MAP: HashMap<String, Vec<String>> = HashMap::from([
|
||||
("web".to_string(), vec!["isWeb".to_string()]),
|
||||
("node".to_string(), vec!["isNode".to_string()]),
|
||||
("weex".to_string(), vec!["isWeex".to_string()]),
|
||||
(
|
||||
"kraken".to_string(),
|
||||
vec!["isKraken".to_string(), "isWeb".to_string()]
|
||||
),
|
||||
(
|
||||
"wechat-miniprogram".to_string(),
|
||||
vec![
|
||||
"isWeChatMiniProgram".to_string(),
|
||||
"isWeChatMiniprogram".to_string()
|
||||
]
|
||||
),
|
||||
("miniapp".to_string(), vec!["isMiniApp".to_string()]),
|
||||
(
|
||||
"bytedance-microapp".to_string(),
|
||||
vec!["isByteDanceMicroApp".to_string()]
|
||||
),
|
||||
(
|
||||
"kuaishou-miniprogram".to_string(),
|
||||
vec!["isKuaiShouMiniProgram".to_string()]
|
||||
),
|
||||
(
|
||||
"baidu-smartprogram".to_string(),
|
||||
vec!["isBaiduSmartProgram".to_string()]
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
impl Fold for KeepPlatformPatcher {
|
||||
fn fold_module_items(&mut self, items: Vec<ModuleItem>) -> Vec<ModuleItem> {
|
||||
// Get platform flag, such as ["isWeb"]
|
||||
let platform_flags: Vec<String> = match PLATFORM_MAP.get(&self.platform.to_string()) {
|
||||
Some(flags) => flags.to_vec(),
|
||||
None => vec![],
|
||||
};
|
||||
// Collect top-level expression
|
||||
let mut new_module_items: Vec<ModuleItem> = vec![];
|
||||
// Save isWeb/isWeex into env_variables
|
||||
let mut env_variables: Vec<&Ident> = vec![];
|
||||
for module_item in items.iter() {
|
||||
match module_item {
|
||||
ModuleItem::ModuleDecl(ModuleDecl::Import(import_decl)) => {
|
||||
if &import_decl.src.value == "universal-env" {
|
||||
for specifier in import_decl.specifiers.iter() {
|
||||
match specifier {
|
||||
ImportSpecifier::Named(named) => {
|
||||
let ImportNamedSpecifier {
|
||||
local,
|
||||
span: _,
|
||||
imported: _,
|
||||
is_type_only: _,
|
||||
} = named;
|
||||
env_variables.push(local);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
new_module_items.push(ModuleItem::ModuleDecl(ModuleDecl::Import(
|
||||
import_decl.clone(),
|
||||
)))
|
||||
}
|
||||
}
|
||||
_ => new_module_items.push(module_item.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
// If it exist env variables, we need insert declare expression
|
||||
if env_variables.len() > 0 {
|
||||
for env_variable in env_variables {
|
||||
let decs: Vec<VarDeclarator> = vec![VarDeclarator {
|
||||
span: DUMMY_SP,
|
||||
definite: false,
|
||||
name: Pat::Ident(BindingIdent {
|
||||
id: env_variable.clone(),
|
||||
type_ann: Default::default(),
|
||||
}),
|
||||
// Init value, such as var isWeb = true
|
||||
init: Option::Some(Box::new(Expr::Lit(Lit::Bool(Bool {
|
||||
value: platform_flags.contains(&env_variable.sym.to_string()),
|
||||
span: Default::default(),
|
||||
})))),
|
||||
}];
|
||||
new_module_items.insert(
|
||||
0,
|
||||
ModuleItem::Stmt(Stmt::Decl(Decl::Var(VarDecl {
|
||||
span: DUMMY_SP,
|
||||
kind: VarDeclKind::Var,
|
||||
declare: false,
|
||||
decls: decs,
|
||||
}))),
|
||||
);
|
||||
}
|
||||
}
|
||||
return new_module_items;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
#![recursion_limit = "2048"]
|
||||
//#![deny(clippy::all)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate napi_derive;
|
||||
extern crate lazy_static;
|
||||
/// Explicit extern crate to use allocator.
|
||||
extern crate swc_node_base;
|
||||
|
||||
use backtrace::Backtrace;
|
||||
use lazy_static::lazy_static;
|
||||
use napi::{CallContext, Env, JsObject, JsUndefined};
|
||||
use serde::Deserialize;
|
||||
use std::{env, panic::set_hook, sync::Arc};
|
||||
use swc::{Compiler, TransformOutput};
|
||||
use swc_common::{self, chain, pass::Optional, sync::Lazy, FileName, FilePathMapping, SourceMap};
|
||||
use swc_ecmascript::transforms::pass::noop;
|
||||
use swc_ecmascript::visit::Fold;
|
||||
|
||||
use crate::keep_platform::{keep_platform, KeepPlatformConfig};
|
||||
|
||||
pub mod keep_platform;
|
||||
pub mod minify;
|
||||
pub mod transform;
|
||||
mod util;
|
||||
|
||||
#[derive(Debug, Deserialize, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TransformOptions {
|
||||
#[serde(flatten)]
|
||||
pub swc: swc::config::Options,
|
||||
#[serde(default)]
|
||||
pub keep_platform: KeepPlatformConfig,
|
||||
}
|
||||
|
||||
pub fn custom_before_pass(name: &FileName, options: &TransformOptions) -> impl Fold {
|
||||
let mut keep_platform_config = KeepPlatformConfig::Bool(false);
|
||||
let enable_keep_platform: bool = match options.keep_platform.clone() {
|
||||
KeepPlatformConfig::KeepPlatform(platform) => {
|
||||
keep_platform_config = KeepPlatformConfig::KeepPlatform(platform);
|
||||
true
|
||||
}
|
||||
KeepPlatformConfig::Bool(val) => val,
|
||||
};
|
||||
|
||||
// custom before pass
|
||||
chain!(
|
||||
Optional::new(keep_platform(keep_platform_config), enable_keep_platform),
|
||||
noop()
|
||||
)
|
||||
}
|
||||
|
||||
static COMPILER: Lazy<Arc<Compiler>> = Lazy::new(|| {
|
||||
let cm = Arc::new(SourceMap::new(FilePathMapping::empty()));
|
||||
|
||||
Arc::new(Compiler::new(cm.clone()))
|
||||
});
|
||||
|
||||
#[module_exports]
|
||||
fn init(mut exports: JsObject) -> napi::Result<()> {
|
||||
if cfg!(debug_assertions) || env::var("SWC_DEBUG").unwrap_or_default() == "1" {
|
||||
set_hook(Box::new(|panic_info| {
|
||||
let backtrace = Backtrace::new();
|
||||
println!("Panic: {:?}\nBacktrace: {:?}", panic_info, backtrace);
|
||||
}));
|
||||
}
|
||||
|
||||
exports.create_named_method("transform", transform::transform)?;
|
||||
exports.create_named_method("transformSync", transform::transform_sync)?;
|
||||
exports.create_named_method("minify", minify::minify)?;
|
||||
exports.create_named_method("minifySync", minify::minify_sync)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_compiler(_ctx: &CallContext) -> Arc<Compiler> {
|
||||
COMPILER.clone()
|
||||
}
|
||||
|
||||
#[js_function]
|
||||
fn construct_compiler(ctx: CallContext) -> napi::Result<JsUndefined> {
|
||||
// TODO: Assign swc::Compiler
|
||||
ctx.env.get_undefined()
|
||||
}
|
||||
|
||||
pub fn complete_output(env: &Env, output: TransformOutput) -> napi::Result<JsObject> {
|
||||
env.to_js_value(&output)?.coerce_to_object()
|
||||
}
|
||||
|
||||
pub type ArcCompiler = Arc<Compiler>;
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
use crate::{
|
||||
complete_output, get_compiler,
|
||||
util::{CtxtExt, MapErr},
|
||||
};
|
||||
use fxhash::FxHashMap;
|
||||
use napi::{CallContext, JsObject, Task};
|
||||
use serde::Deserialize;
|
||||
use std::sync::Arc;
|
||||
use swc::{try_with_handler, TransformOutput};
|
||||
use swc_common::{sync::Lrc, FileName, SourceFile, SourceMap};
|
||||
|
||||
struct MinifyTask {
|
||||
c: Arc<swc::Compiler>,
|
||||
code: MinifyTarget,
|
||||
opts: swc::config::JsMinifyOptions,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum MinifyTarget {
|
||||
/// Code to minify.
|
||||
Single(String),
|
||||
/// `{ filename: code }`
|
||||
Map(FxHashMap<String, String>),
|
||||
}
|
||||
|
||||
impl MinifyTarget {
|
||||
fn to_file(&self, cm: Lrc<SourceMap>) -> Lrc<SourceFile> {
|
||||
match self {
|
||||
MinifyTarget::Single(code) => cm.new_source_file(FileName::Anon, code.clone()),
|
||||
MinifyTarget::Map(codes) => {
|
||||
assert_eq!(
|
||||
codes.len(),
|
||||
1,
|
||||
"swc.minify does not support concatenating multiple files yet"
|
||||
);
|
||||
|
||||
let (filename, code) = codes.iter().next().unwrap();
|
||||
|
||||
cm.new_source_file(FileName::Real(filename.clone().into()), code.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Task for MinifyTask {
|
||||
type Output = TransformOutput;
|
||||
|
||||
type JsValue = JsObject;
|
||||
|
||||
fn compute(&mut self) -> napi::Result<Self::Output> {
|
||||
try_with_handler(self.c.cm.clone(), true, |handler| {
|
||||
let fm = self.code.to_file(self.c.cm.clone());
|
||||
|
||||
self.c.minify(fm, &handler, &self.opts)
|
||||
})
|
||||
.convert_err()
|
||||
}
|
||||
|
||||
fn resolve(self, env: napi::Env, output: Self::Output) -> napi::Result<Self::JsValue> {
|
||||
complete_output(&env, output)
|
||||
}
|
||||
}
|
||||
|
||||
#[js_function(2)]
|
||||
pub fn minify(cx: CallContext) -> napi::Result<JsObject> {
|
||||
let code = cx.get_deserialized(0)?;
|
||||
let opts = cx.get_deserialized(1)?;
|
||||
|
||||
let c = get_compiler(&cx);
|
||||
|
||||
let task = MinifyTask { c, code, opts };
|
||||
|
||||
cx.env.spawn(task).map(|t| t.promise_object())
|
||||
}
|
||||
|
||||
#[js_function(2)]
|
||||
pub fn minify_sync(cx: CallContext) -> napi::Result<JsObject> {
|
||||
let code: MinifyTarget = cx.get_deserialized(0)?;
|
||||
let opts = cx.get_deserialized(1)?;
|
||||
|
||||
let c = get_compiler(&cx);
|
||||
|
||||
let fm = code.to_file(c.cm.clone());
|
||||
|
||||
let output = try_with_handler(c.cm.clone(), true, |handler| c.minify(fm, &handler, &opts))
|
||||
.convert_err()?;
|
||||
|
||||
complete_output(&cx.env, output)
|
||||
}
|
||||
|
|
@ -1,172 +0,0 @@
|
|||
use crate::{
|
||||
complete_output, custom_before_pass, get_compiler,
|
||||
util::{deserialize_json, CtxtExt, MapErr},
|
||||
TransformOptions,
|
||||
};
|
||||
use anyhow::{anyhow, Context as _, Error};
|
||||
use napi::{CallContext, Env, JsBoolean, JsObject, JsString, Status, Task};
|
||||
use std::{
|
||||
panic::{catch_unwind, AssertUnwindSafe},
|
||||
sync::Arc,
|
||||
};
|
||||
use swc::{try_with_handler, Compiler, TransformOutput};
|
||||
use swc_common::{FileName, SourceFile};
|
||||
use swc_ecmascript::ast::Program;
|
||||
use swc_ecmascript::transforms::pass::noop;
|
||||
|
||||
/// Input to transform
|
||||
#[derive(Debug)]
|
||||
pub enum Input {
|
||||
/// Raw source code.
|
||||
Source { src: String },
|
||||
}
|
||||
|
||||
pub struct TransformTask {
|
||||
pub c: Arc<Compiler>,
|
||||
pub input: Input,
|
||||
pub options: String,
|
||||
}
|
||||
|
||||
impl Task for TransformTask {
|
||||
type Output = TransformOutput;
|
||||
type JsValue = JsObject;
|
||||
|
||||
fn compute(&mut self) -> napi::Result<Self::Output> {
|
||||
let res = catch_unwind(AssertUnwindSafe(|| {
|
||||
try_with_handler(self.c.cm.clone(), true, |handler| {
|
||||
self.c.run(|| match &self.input {
|
||||
Input::Source { src } => {
|
||||
let options: TransformOptions = deserialize_json(&self.options)?;
|
||||
|
||||
let filename = if options.swc.filename.is_empty() {
|
||||
FileName::Anon
|
||||
} else {
|
||||
FileName::Real(options.swc.filename.clone().into())
|
||||
};
|
||||
|
||||
let fm = self.c.cm.new_source_file(filename, src.to_string());
|
||||
|
||||
let before_pass = custom_before_pass(&fm.name, &options);
|
||||
self.c.process_js_with_custom_pass(
|
||||
fm.clone(),
|
||||
&handler,
|
||||
&options.swc,
|
||||
before_pass,
|
||||
noop(),
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
}))
|
||||
.map_err(|err| {
|
||||
if let Some(s) = err.downcast_ref::<String>() {
|
||||
anyhow!("failed to process {}", s)
|
||||
} else {
|
||||
anyhow!("failed to process")
|
||||
}
|
||||
});
|
||||
|
||||
match res {
|
||||
Ok(res) => res.convert_err(),
|
||||
Err(err) => Err(napi::Error::new(
|
||||
Status::GenericFailure,
|
||||
format!("{:?}", err),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve(self, env: Env, result: Self::Output) -> napi::Result<Self::JsValue> {
|
||||
complete_output(&env, result)
|
||||
}
|
||||
}
|
||||
|
||||
/// returns `compiler, (src / path), options, plugin, callback`
|
||||
pub fn schedule_transform<F>(cx: CallContext, op: F) -> napi::Result<JsObject>
|
||||
where
|
||||
F: FnOnce(&Arc<Compiler>, String, bool, String) -> TransformTask,
|
||||
{
|
||||
let c = get_compiler(&cx);
|
||||
|
||||
let src = cx.get::<JsString>(0)?.into_utf8()?.as_str()?.to_owned();
|
||||
let is_module = cx.get::<JsBoolean>(1)?;
|
||||
let options = cx.get_buffer_as_string(2)?;
|
||||
|
||||
let task = op(&c, src, is_module.get_value()?, options);
|
||||
|
||||
cx.env.spawn(task).map(|t| t.promise_object())
|
||||
}
|
||||
|
||||
pub fn exec_transform<F>(cx: CallContext, op: F) -> napi::Result<JsObject>
|
||||
where
|
||||
F: FnOnce(&Compiler, String, &TransformOptions) -> Result<Arc<SourceFile>, Error>,
|
||||
{
|
||||
let c = get_compiler(&cx);
|
||||
|
||||
let s = cx.get::<JsString>(0)?.into_utf8()?;
|
||||
let is_module = cx.get::<JsBoolean>(1)?;
|
||||
let mut options: TransformOptions = cx.get_deserialized(2)?;
|
||||
options.swc.swcrc = false;
|
||||
|
||||
let output = try_with_handler(c.cm.clone(), true, |handler| {
|
||||
c.run(|| {
|
||||
if is_module.get_value()? {
|
||||
let program: Program =
|
||||
serde_json::from_str(s.as_str()?).context("failed to deserialize Program")?;
|
||||
c.process_js(&handler, program, &options.swc)
|
||||
} else {
|
||||
let fm =
|
||||
op(&c, s.as_str()?.to_string(), &options).context("failed to load file")?;
|
||||
let before_pass = custom_before_pass(&fm.name, &options);
|
||||
c.process_js_with_custom_pass(fm, &handler, &options.swc, before_pass, noop())
|
||||
}
|
||||
})
|
||||
})
|
||||
.convert_err()?;
|
||||
|
||||
complete_output(cx.env, output)
|
||||
}
|
||||
|
||||
#[js_function(4)]
|
||||
pub fn transform(cx: CallContext) -> napi::Result<JsObject> {
|
||||
schedule_transform(cx, |c, src, _, options| {
|
||||
let input = Input::Source { src };
|
||||
|
||||
TransformTask {
|
||||
c: c.clone(),
|
||||
input,
|
||||
options,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[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.swc.filename.is_empty() {
|
||||
FileName::Anon
|
||||
} else {
|
||||
FileName::Real(options.swc.filename.clone().into())
|
||||
},
|
||||
src,
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deser() {
|
||||
const JSON_STR: &str = r#"{"jsc":{"parser":{"syntax":"ecmascript","dynamicImport":true,"jsx":true},"transform":{"react":{"runtime":"automatic","pragma":"React.createElement","pragmaFrag":"React.Fragment","throwIfNamespace":true,"development":false,"useBuiltins":true}},"target":"es5"},"filename":"/Users/filename","sourceMaps":false,"sourceFileName":"/Users/sourceFilename" }"#;
|
||||
|
||||
let tr: TransformOptions = serde_json::from_str(&JSON_STR).unwrap();
|
||||
|
||||
println!("{:#?}", tr);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deserialize_transform_regenerator() {
|
||||
const JSON_STR: &str = r#"{"jsc":{"parser":{"syntax":"ecmascript","dynamicImport":true,"jsx":true},"transform":{ "regenerator": { "importPath": "foo" }, "react":{"runtime":"automatic","pragma":"React.createElement","pragmaFrag":"React.Fragment","throwIfNamespace":true,"development":false,"useBuiltins":true}},"target":"es5"},"filename":"/Users/sourceFilename","sourceMaps":false,"sourceFileName":"/Users/filename" }"#;
|
||||
|
||||
let tr: TransformOptions = serde_json::from_str(&JSON_STR).unwrap();
|
||||
|
||||
println!("{:#?}", tr);
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
use anyhow::{Context, Error};
|
||||
use napi::{CallContext, JsBuffer, Status};
|
||||
use serde::de::DeserializeOwned;
|
||||
use std::any::type_name;
|
||||
|
||||
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 {
|
||||
fn get_buffer_as_string(&self, index: usize) -> napi::Result<String>;
|
||||
/// Currently this uses JsBuffer
|
||||
fn get_deserialized<T>(&self, index: usize) -> napi::Result<T>
|
||||
where
|
||||
T: DeserializeOwned;
|
||||
}
|
||||
|
||||
impl CtxtExt for CallContext<'_> {
|
||||
fn get_buffer_as_string(&self, index: usize) -> napi::Result<String> {
|
||||
let buffer = self.get::<JsBuffer>(index)?.into_value()?;
|
||||
|
||||
Ok(String::from_utf8_lossy(buffer.as_ref()).to_string())
|
||||
}
|
||||
|
||||
fn get_deserialized<T>(&self, index: usize) -> napi::Result<T>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
let buffer = self.get::<JsBuffer>(index)?.into_value()?;
|
||||
let v = serde_json::from_slice(&buffer)
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"Failed to deserialize argument at `{}` as {}\nJSON: {}",
|
||||
index,
|
||||
type_name::<T>(),
|
||||
String::from_utf8_lossy(&buffer)
|
||||
)
|
||||
})
|
||||
.convert_err()?;
|
||||
|
||||
Ok(v)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn deserialize_json<T>(s: &str) -> Result<T, Error>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
serde_json::from_str(&s)
|
||||
.with_context(|| format!("failed to deserialize as {}\nJSON: {}", type_name::<T>(), s))
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
use builder_swc::keep_platform::{keep_platform, KeepPlatformConfig};
|
||||
use std::path::PathBuf;
|
||||
use swc_ecma_transforms_testing::{test, test_fixture};
|
||||
use swc_ecmascript::parser::{EsConfig, Syntax};
|
||||
use testing::fixture;
|
||||
|
||||
fn unminify_syntax() -> Syntax {
|
||||
Syntax::Es(EsConfig {
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
#[fixture("tests/fixture/keep_platform/web/input.js")]
|
||||
fn transform_web_flag_fixture(input: PathBuf) {
|
||||
let output = input.parent().unwrap().join("output.js");
|
||||
let config = KeepPlatformConfig::KeepPlatform(String::from("web"));
|
||||
test_fixture(
|
||||
unminify_syntax(),
|
||||
&|_tr| keep_platform(config.clone()),
|
||||
&input,
|
||||
&output,
|
||||
);
|
||||
}
|
||||
|
||||
#[fixture("tests/fixture/keep_platform/kraken/input.js")]
|
||||
fn transform_kraken_flag_fixture(input: PathBuf) {
|
||||
let output = input.parent().unwrap().join("output.js");
|
||||
let config = KeepPlatformConfig::KeepPlatform(String::from("kraken"));
|
||||
test_fixture(
|
||||
unminify_syntax(),
|
||||
&|_tr| keep_platform(config.clone()),
|
||||
&input,
|
||||
&output,
|
||||
);
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
import { isWeb, isWeex, isKraken } from 'universal-env';
|
||||
|
||||
if (isWeb) {
|
||||
console.log('This is web');
|
||||
} else if (isWeex) {
|
||||
console.log('This is weex');
|
||||
} else {
|
||||
console.log('others1');
|
||||
}
|
||||
|
||||
if (isKraken) {
|
||||
console.log('This is kraken');
|
||||
} else {
|
||||
console.log('others2');
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
var isKraken = true;
|
||||
var isWeex = false;
|
||||
var isWeb = true;
|
||||
|
||||
if (isWeb) {
|
||||
console.log('This is web');
|
||||
} else if (isWeex) {
|
||||
console.log('This is weex');
|
||||
} else {
|
||||
console.log('others1');
|
||||
}
|
||||
|
||||
if (isKraken) {
|
||||
console.log('This is kraken');
|
||||
} else {
|
||||
console.log('others2');
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
import { isWeb, isWeex } from 'universal-env';
|
||||
|
||||
if (isWeb) {
|
||||
console.log('This is web');
|
||||
} else if (isWeex) {
|
||||
console.log('This is weex');
|
||||
} else {
|
||||
console.log('others');
|
||||
}
|
||||
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
var isWeex = false;
|
||||
var isWeb = true;
|
||||
if (isWeb) {
|
||||
console.log("This is web");
|
||||
} else if (isWeex) {
|
||||
console.log("This is weex");
|
||||
} else {
|
||||
console.log("others");
|
||||
}
|
||||
|
|
@ -1,115 +0,0 @@
|
|||
use builder_swc::keep_platform::KeepPlatformConfig;
|
||||
use builder_swc::{custom_before_pass, TransformOptions};
|
||||
use serde::de::DeserializeOwned;
|
||||
use std::path::{Path, PathBuf};
|
||||
use swc::config::{OptimizerConfig, TransformConfig};
|
||||
use swc::Compiler;
|
||||
use swc_ecmascript::{
|
||||
parser::{Syntax, TsConfig},
|
||||
transforms::pass::noop,
|
||||
};
|
||||
use testing::{fixture, NormalizedOutput, Tester};
|
||||
|
||||
#[fixture("tests/minify/base_syntax/input.js")]
|
||||
fn base_minify(input: PathBuf) {
|
||||
test(&input, true, "".to_string());
|
||||
}
|
||||
|
||||
#[fixture("tests/minify/remove_platform_code/web/input.js")]
|
||||
fn save_web_code(input: PathBuf) {
|
||||
test(&input, true, "web".to_string());
|
||||
}
|
||||
|
||||
#[fixture("tests/minify/remove_platform_code/kraken/input.js")]
|
||||
fn save_kraken_code(input: PathBuf) {
|
||||
test(&input, true, "kraken".to_string());
|
||||
}
|
||||
|
||||
#[fixture("tests/unminify/**/input.js")]
|
||||
fn unminify(input: PathBuf) {
|
||||
test(&input, false, "".to_string());
|
||||
}
|
||||
|
||||
fn test(input: &Path, minify: bool, platform: String) {
|
||||
let output = input.parent().unwrap().join("output.js");
|
||||
|
||||
let keep_platform: KeepPlatformConfig;
|
||||
|
||||
if platform == "" {
|
||||
keep_platform = KeepPlatformConfig::Bool(false);
|
||||
} else {
|
||||
keep_platform = KeepPlatformConfig::KeepPlatform(platform);
|
||||
}
|
||||
|
||||
Tester::new()
|
||||
.print_errors(|cm, handler| {
|
||||
let c = Compiler::new(cm.clone());
|
||||
|
||||
let fm = cm.load_file(input).expect("failed to load file");
|
||||
|
||||
let options = TransformOptions {
|
||||
swc: swc::config::Options {
|
||||
swcrc: true,
|
||||
is_module: true,
|
||||
output_path: Some(output.to_path_buf()),
|
||||
|
||||
config: swc::config::Config {
|
||||
jsc: swc::config::JscConfig {
|
||||
minify: if minify {
|
||||
Some(assert_json(
|
||||
"{ \"compress\": { \"dead_code\": true }, \"mangle\": true }",
|
||||
))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
syntax: Some(Syntax::Typescript(TsConfig {
|
||||
tsx: true,
|
||||
dynamic_import: true,
|
||||
..Default::default()
|
||||
})),
|
||||
transform: Some(TransformConfig {
|
||||
optimizer: Some(OptimizerConfig {
|
||||
simplify: minify,
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
minify: minify,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
keep_platform: keep_platform,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
match c.process_js_with_custom_pass(
|
||||
fm.clone(),
|
||||
&handler,
|
||||
&options.swc,
|
||||
custom_before_pass(&fm.name, &options),
|
||||
noop(),
|
||||
) {
|
||||
Ok(v) => {
|
||||
NormalizedOutput::from(v.code)
|
||||
.compare_to_file(output)
|
||||
.unwrap();
|
||||
}
|
||||
Err(err) => panic!("Error: {:?}", err),
|
||||
};
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.map(|_| ())
|
||||
.expect("failed");
|
||||
}
|
||||
|
||||
/// Using this, we don't have to break code by adding field.s
|
||||
fn assert_json<T>(json_str: &str) -> T
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
serde_json::from_str(json_str).expect("failed to deserialize")
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
|
||||
|
||||
import fs from 'fs'
|
||||
import other from 'other'
|
||||
|
||||
const [a, b, ...rest] = fs.promises
|
||||
const [foo, bar] = other
|
||||
|
||||
export async function getStaticProps() {
|
||||
a
|
||||
b
|
||||
rest
|
||||
bar
|
||||
}
|
||||
|
||||
class Foo {}
|
||||
|
||||
|
||||
export default function Home() {
|
||||
return <div />
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
import c from"regenerator-runtime";import d from"fs";import e from"other";function _arrayWithHoles(c){if(Array.isArray(c))return c}function asyncGeneratorStep(l,d,e,m,n,h,i){try{var j=l[h](i),c=j.value}catch(l){e(l);return}j.done?d(c):Promise.resolve(c).then(m,n)}function _asyncToGenerator(h){return function(){var i=this,j=arguments;return new Promise(function(d,e){var l=h.apply(i,j);function m(c){asyncGeneratorStep(l,d,e,m,n,"next",c)}function n(l){asyncGeneratorStep(l,d,e,m,n,"throw",l)}m(void 0)})}}function _iterableToArray(c){if(Symbol.iterator in Object(c)||"[object Arguments]"===Object.prototype.toString.call(c))return Array.from(c)}function _iterableToArrayLimit(c,d){var f=[],g=!0,h=!1,i=void 0;try{for(var j,k=c[Symbol.iterator]();!(g=(j=k.next()).done)&&(f.push(j.value),!d||f.length!==d);g=!0);}catch(l){h=!0,i=l}finally{try{g||null==k.return||k.return()}finally{if(h)throw i}}return f}function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}function _slicedToArray(c,d){return _arrayWithHoles(c)||_iterableToArrayLimit(c,d)||_nonIterableRest()}function _toArray(c){return _arrayWithHoles(c)||_iterableToArray(c)||_nonIterableRest()}var _promises=_toArray(d.promises),a=_promises[0],b=_promises[1],rest=_promises.slice(2),_other=_slicedToArray(e,2),foo=_other[0],bar=_other[1];function _getStaticProps(){return(_getStaticProps=_asyncToGenerator(c.mark(function d(){return c.wrap(function(c){for(;;)switch(c.prev=c.next){case 0:case"end":return c.stop()}},d)}))).apply(this,arguments)}export function getStaticProps(){return _getStaticProps.apply(this,arguments)}export default function c(){return React.createElement("div",null)}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
import { isWeb, isWeex, isKraken } from 'universal-env';
|
||||
|
||||
if (isWeb) {
|
||||
console.log('This is web');
|
||||
} else if (isWeex) {
|
||||
console.log('This is weex');
|
||||
} else {
|
||||
console.log('others1');
|
||||
}
|
||||
|
||||
if (isKraken) {
|
||||
console.log('This is kraken');
|
||||
} else {
|
||||
console.log('others2');
|
||||
}
|
||||
|
||||
|
|
@ -1 +0,0 @@
|
|||
console.log("This is web"),console.log("This is kraken")
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
import { isWeb, isWeex } from 'universal-env';
|
||||
|
||||
if (isWeb) {
|
||||
console.log('This is web');
|
||||
} else if (isWeex) {
|
||||
console.log('This is weex');
|
||||
} else {
|
||||
console.log('others');
|
||||
}
|
||||
|
||||
|
|
@ -1 +0,0 @@
|
|||
console.log("This is web")
|
||||
|
|
@ -1,113 +0,0 @@
|
|||
import { transformSync } from '../../node';
|
||||
|
||||
describe('swc transform code', () => {
|
||||
it('should transform es6 code to es5', () => {
|
||||
const originalCode = `const a = {
|
||||
x: 1,
|
||||
y: 2,
|
||||
};
|
||||
const b = {
|
||||
z: 3,
|
||||
...a,
|
||||
};
|
||||
`;
|
||||
|
||||
const { code } = transformSync(originalCode, {
|
||||
sourceMaps: false,
|
||||
jsc: {
|
||||
parser: {
|
||||
syntax: 'ecmascript',
|
||||
},
|
||||
target: 'es5'
|
||||
}
|
||||
});
|
||||
|
||||
expect(code).toEqual(`function _defineProperty(obj, key, value) {
|
||||
if (key in obj) {
|
||||
Object.defineProperty(obj, key, {
|
||||
value: value,
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true
|
||||
});
|
||||
} else {
|
||||
obj[key] = value;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
function _objectSpread(target) {
|
||||
for(var i = 1; i < arguments.length; i++){
|
||||
var source = arguments[i] != null ? arguments[i] : {
|
||||
};
|
||||
var ownKeys = Object.keys(source);
|
||||
if (typeof Object.getOwnPropertySymbols === \"function\") {
|
||||
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
|
||||
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
|
||||
}));
|
||||
}
|
||||
ownKeys.forEach(function(key) {
|
||||
_defineProperty(target, key, source[key]);
|
||||
});
|
||||
}
|
||||
return target;
|
||||
}
|
||||
var a = {
|
||||
x: 1,
|
||||
y: 2
|
||||
};
|
||||
var b = _objectSpread({
|
||||
z: 3
|
||||
}, a);
|
||||
`);
|
||||
});
|
||||
|
||||
it('should transform TypeScript to es2021', () => {
|
||||
const originalCode = `interface IType {
|
||||
name: string;
|
||||
}
|
||||
|
||||
const a: IType = {
|
||||
name: 'Hello',
|
||||
};`;
|
||||
|
||||
const { code } = transformSync(originalCode, {
|
||||
jsc: {
|
||||
parser: {
|
||||
syntax: 'typescript',
|
||||
tsx: true,
|
||||
},
|
||||
target: 'es2021'
|
||||
},
|
||||
sourceMaps: false,
|
||||
});
|
||||
|
||||
expect(code).toEqual(`const a = {
|
||||
name: 'Hello'
|
||||
};
|
||||
`);
|
||||
});
|
||||
|
||||
it('should transform JSX to createElement', () => {
|
||||
const originalCode = `import React from 'react';
|
||||
export default function Home() {
|
||||
return <div>home page</div>;
|
||||
}`;
|
||||
|
||||
const { code } = transformSync(originalCode, {
|
||||
sourceMaps: false,
|
||||
jsc: {
|
||||
parser: {
|
||||
syntax: 'ecmascript',
|
||||
jsx: true,
|
||||
},
|
||||
target: 'es5'
|
||||
},
|
||||
});
|
||||
|
||||
expect(code).toEqual(`import React from 'react';
|
||||
export default function Home() {
|
||||
return(/*#__PURE__*/ React.createElement("div", null, "home page"));
|
||||
};
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
import { transformSync } from '../../node';
|
||||
|
||||
describe('swc remove multiple ends code', () => {
|
||||
it('should keep original code with not config removeMultipleEndsCode', () => {
|
||||
const originalCode = `import { isWeb } from 'universal-env';
|
||||
if (isWeb) {
|
||||
console.log('This is web');
|
||||
} else {
|
||||
console.log('This is others');
|
||||
}
|
||||
`;
|
||||
|
||||
const { code } = transformSync(originalCode, {
|
||||
sourceMaps: false,
|
||||
jsc: {
|
||||
parser: {
|
||||
syntax: 'ecmascript',
|
||||
},
|
||||
target: 'es5'
|
||||
}
|
||||
});
|
||||
|
||||
expect(code).toEqual(`import { isWeb } from 'universal-env';
|
||||
if (isWeb) {
|
||||
console.log('This is web');
|
||||
} else {
|
||||
console.log('This is others');
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should assign isWeb as true', () => {
|
||||
const originalCode = `import { isWeb } from 'universal-env';
|
||||
if (isWeb) {
|
||||
console.log('This is web');
|
||||
} else {
|
||||
console.log('This is others');
|
||||
}
|
||||
`;
|
||||
|
||||
const { code } = transformSync(originalCode, {
|
||||
sourceMaps: false,
|
||||
jsc: {
|
||||
parser: {
|
||||
syntax: 'ecmascript',
|
||||
},
|
||||
target: 'es5'
|
||||
},
|
||||
keepPlatform: 'web'
|
||||
});
|
||||
|
||||
expect(code).toEqual(`var isWeb = true;
|
||||
if (isWeb) {
|
||||
console.log('This is web');
|
||||
} else {
|
||||
console.log('This is others');
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should save web code', () => {
|
||||
const originalCode = `import { isWeb, isWeex } from 'universal-env';
|
||||
if (isWeb) {
|
||||
console.log('This is web');
|
||||
} else if (isWeex) {
|
||||
console.log('This is weex');
|
||||
} else {
|
||||
console.log('others');
|
||||
}
|
||||
`;
|
||||
|
||||
const { code } = transformSync(originalCode, {
|
||||
sourceMaps: false,
|
||||
jsc: {
|
||||
minify: {
|
||||
compress: true,
|
||||
mangle: true
|
||||
},
|
||||
parser: {
|
||||
syntax: 'ecmascript',
|
||||
},
|
||||
target: 'es5',
|
||||
transform: {
|
||||
optimizer: {
|
||||
simplify: true
|
||||
}
|
||||
}
|
||||
},
|
||||
keepPlatform: 'web',
|
||||
minify: true
|
||||
});
|
||||
|
||||
expect(code).toEqual('console.log("This is web")');
|
||||
});
|
||||
});
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
|
||||
|
||||
import fs from 'fs'
|
||||
import other from 'other'
|
||||
|
||||
const [a, b, ...rest] = fs.promises
|
||||
const [foo, bar] = other
|
||||
|
||||
export async function getStaticProps() {
|
||||
a
|
||||
b
|
||||
rest
|
||||
bar
|
||||
}
|
||||
|
||||
class Foo {}
|
||||
|
||||
|
||||
export default function Home() {
|
||||
return <div />
|
||||
}
|
||||
|
|
@ -1,103 +0,0 @@
|
|||
import regeneratorRuntime from "regenerator-runtime";
|
||||
import fs from 'fs';
|
||||
import other from 'other';
|
||||
function _arrayWithHoles(arr) {
|
||||
if (Array.isArray(arr)) return arr;
|
||||
}
|
||||
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
|
||||
try {
|
||||
var info = gen[key](arg);
|
||||
var value = info.value;
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
if (info.done) {
|
||||
resolve(value);
|
||||
} else {
|
||||
Promise.resolve(value).then(_next, _throw);
|
||||
}
|
||||
}
|
||||
function _asyncToGenerator(fn) {
|
||||
return function() {
|
||||
var self = this, args = arguments;
|
||||
return new Promise(function(resolve, reject) {
|
||||
var gen = fn.apply(self, args);
|
||||
function _next(value) {
|
||||
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
|
||||
}
|
||||
function _throw(err) {
|
||||
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
|
||||
}
|
||||
_next(undefined);
|
||||
});
|
||||
};
|
||||
}
|
||||
function _classCallCheck(instance, Constructor) {
|
||||
if (!(instance instanceof Constructor)) {
|
||||
throw new TypeError("Cannot call a class as a function");
|
||||
}
|
||||
}
|
||||
function _iterableToArray(iter) {
|
||||
if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter);
|
||||
}
|
||||
function _iterableToArrayLimit(arr, i) {
|
||||
var _arr = [];
|
||||
var _n = true;
|
||||
var _d = false;
|
||||
var _e = undefined;
|
||||
try {
|
||||
for(var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true){
|
||||
_arr.push(_s.value);
|
||||
if (i && _arr.length === i) break;
|
||||
}
|
||||
} catch (err) {
|
||||
_d = true;
|
||||
_e = err;
|
||||
} finally{
|
||||
try {
|
||||
if (!_n && _i["return"] != null) _i["return"]();
|
||||
} finally{
|
||||
if (_d) throw _e;
|
||||
}
|
||||
}
|
||||
return _arr;
|
||||
}
|
||||
function _nonIterableRest() {
|
||||
throw new TypeError("Invalid attempt to destructure non-iterable instance");
|
||||
}
|
||||
function _slicedToArray(arr, i) {
|
||||
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest();
|
||||
}
|
||||
function _toArray(arr) {
|
||||
return _arrayWithHoles(arr) || _iterableToArray(arr) || _nonIterableRest();
|
||||
}
|
||||
var _promises = _toArray(fs.promises), a = _promises[0], b = _promises[1], rest = _promises.slice(2);
|
||||
var _other = _slicedToArray(other, 2), foo = _other[0], bar = _other[1];
|
||||
function _getStaticProps() {
|
||||
_getStaticProps = _asyncToGenerator(regeneratorRuntime.mark(function _callee() {
|
||||
return regeneratorRuntime.wrap(function _callee$(_ctx) {
|
||||
while(1)switch(_ctx.prev = _ctx.next){
|
||||
case 0:
|
||||
a;
|
||||
b;
|
||||
rest;
|
||||
bar;
|
||||
case 4:
|
||||
case "end":
|
||||
return _ctx.stop();
|
||||
}
|
||||
}, _callee);
|
||||
}));
|
||||
return _getStaticProps.apply(this, arguments);
|
||||
}
|
||||
export function getStaticProps() {
|
||||
return _getStaticProps.apply(this, arguments);
|
||||
}
|
||||
var Foo = function Foo() {
|
||||
"use strict";
|
||||
_classCallCheck(this, Foo);
|
||||
};
|
||||
export default function Home() {
|
||||
return(/*#__PURE__*/ React.createElement("div", null));
|
||||
};
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
"extends": "../../tsconfig.settings.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./node",
|
||||
"rootDir": "./node",
|
||||
"outDir": "lib",
|
||||
"moduleResolution": "node"
|
||||
},
|
||||
"include": ["node/index.ts"],
|
||||
"exclude": [
|
||||
"src/**/*"
|
||||
]
|
||||
}
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
/* eslint-disable no-await-in-loop */
|
||||
import { copyFileSync, readdirSync, existsSync } from 'fs-extra';
|
||||
import { join } from 'path';
|
||||
import { cwd } from 'process';
|
||||
|
||||
const NATIVE_PACKAGES_DIR = join(process.cwd(), 'packages/swc/npm');
|
||||
|
||||
function copy() {
|
||||
const platforms = (readdirSync(NATIVE_PACKAGES_DIR)).filter(
|
||||
(name) => name !== '.gitignore'
|
||||
);
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const platform of platforms) {
|
||||
const binaryName = `builder-swc.${platform}.node`;
|
||||
const binaryPath = join(cwd(), 'packages/swc/native', binaryName);
|
||||
if (existsSync(binaryPath)) {
|
||||
console.log(`Copying ${binaryPath}`);
|
||||
copyFileSync(
|
||||
binaryPath,
|
||||
join(NATIVE_PACKAGES_DIR, platform, binaryName)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
copy();
|
||||
|
|
@ -4,7 +4,6 @@ import { getNpmInfo } from 'ice-npm-utils';
|
|||
import * as semver from 'semver';
|
||||
|
||||
const TARGET_DIRECTORY = join(__dirname, '../packages');
|
||||
const NATIVE_NPM_DIRECTORY = join(TARGET_DIRECTORY, 'swc/npm');
|
||||
|
||||
export interface IPackageInfo {
|
||||
name: string;
|
||||
|
|
@ -49,11 +48,7 @@ export async function getPackageInfos(distTag = ''): Promise<IPackageInfo[]> {
|
|||
} else {
|
||||
const packageFolders: string[] = readdirSync(TARGET_DIRECTORY)
|
||||
.filter((filename) => filename[0] !== '.')
|
||||
.map((packageFolder) => join(TARGET_DIRECTORY, packageFolder))
|
||||
.concat(
|
||||
readdirSync(NATIVE_NPM_DIRECTORY)
|
||||
.map((packageFolder) => join(NATIVE_NPM_DIRECTORY, packageFolder))
|
||||
);
|
||||
.map((packageFolder) => join(TARGET_DIRECTORY, packageFolder));
|
||||
console.log('[PUBLISH] Start check with following packages:');
|
||||
await Promise.all(packageFolders.map(async (packageFolder) => {
|
||||
const packageInfoPath = join(packageFolder, 'package.json');
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
"references": [
|
||||
{ "path": "packages/webpack-plugin-query-loader"},
|
||||
{ "path": "packages/runtime" },
|
||||
{ "path": "packages/swc" },
|
||||
{ "path": "packages/build-app-templates" },
|
||||
{ "path": "packages/build-app-helpers" },
|
||||
{ "path": "packages/plugin-fusion" },
|
||||
|
|
|
|||
Loading…
Reference in New Issue