Skip to content

Commit 527bfc8

Browse files
committed
feat(npm/oxc-transform): setup npm/oxc-transform and publish
1 parent 02cc14e commit 527bfc8

File tree

4 files changed

+374
-0
lines changed

4 files changed

+374
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
name: Release NAPI transform
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
paths:
8+
- npm/oxc-transform/package.json # Please only commit this file, so we don't need to wait for test CI to pass.
9+
10+
concurrency:
11+
group: ${{ github.workflow }}-${{ github.ref }}
12+
cancel-in-progress: true
13+
14+
defaults:
15+
run:
16+
shell: bash
17+
18+
jobs:
19+
check:
20+
name: Check version
21+
runs-on: ubuntu-latest
22+
outputs:
23+
version: ${{ env.version }}
24+
version_changed: ${{ steps.version.outputs.changed }}
25+
steps:
26+
- uses: taiki-e/checkout-action@v1
27+
28+
- name: Check version changes
29+
uses: EndBug/version-check@v2
30+
id: version
31+
with:
32+
static-checking: localIsNew
33+
file-url: https://unpkg.com/oxc-transform@latest/package.json
34+
file-name: npm/oxc-transform/package.json
35+
36+
- name: Set version name
37+
if: steps.version.outputs.changed == 'true'
38+
run: |
39+
echo "Version change found! New version: ${{ steps.version.outputs.version }} (${{ steps.version.outputs.version_type }})"
40+
echo "version=${{ steps.version.outputs.version }}" >> $GITHUB_ENV
41+
42+
build:
43+
needs: check
44+
if: needs.check.outputs.version_changed == 'true'
45+
env:
46+
version: ${{ needs.check.outputs.version }}
47+
outputs:
48+
version: ${{ env.version }}
49+
strategy:
50+
fail-fast: false
51+
matrix:
52+
include:
53+
- os: windows-latest
54+
target: x86_64-pc-windows-msvc
55+
code-target: win32-x64-msvc
56+
57+
- os: windows-latest
58+
target: aarch64-pc-windows-msvc
59+
code-target: win32-arm64-msvc
60+
61+
- os: ubuntu-latest
62+
target: x86_64-unknown-linux-gnu
63+
code-target: linux-x64-gnu
64+
65+
- os: ubuntu-latest
66+
target: aarch64-unknown-linux-gnu
67+
code-target: linux-arm64-gnu
68+
69+
- os: ubuntu-latest
70+
target: x86_64-unknown-linux-musl
71+
code-target: linux-x64-musl
72+
73+
- os: ubuntu-latest
74+
target: aarch64-unknown-linux-musl
75+
code-target: linux-arm64-musl
76+
77+
- os: macos-13
78+
target: x86_64-apple-darwin
79+
code-target: darwin-x64
80+
81+
- os: macos-14 # M1
82+
target: aarch64-apple-darwin
83+
code-target: darwin-arm64
84+
85+
name: Package ${{ matrix.target }}
86+
runs-on: ${{ matrix.os }}
87+
steps:
88+
- uses: taiki-e/checkout-action@v1
89+
90+
### install musl dependencies ###
91+
92+
- uses: goto-bus-stop/setup-zig@v2
93+
if: ${{ contains(matrix.target, 'musl') }}
94+
with:
95+
version: 0.11.0
96+
97+
- name: Install cargo-zigbuild
98+
if: ${{ contains(matrix.target, 'musl') }}
99+
uses: taiki-e/install-action@v2
100+
with:
101+
tool: cargo-zigbuild
102+
103+
### install non-musl dependencies ###
104+
105+
- name: Install cross
106+
if: ${{ !contains(matrix.target, 'musl') }}
107+
uses: taiki-e/install-action@cross
108+
109+
### Build
110+
111+
- name: Add Rust Target
112+
run: rustup target add ${{ matrix.target }}
113+
114+
- name: Build with cross
115+
if: ${{ !contains(matrix.target, 'musl') }}
116+
run: cross build --release -p oxc_transform_napi --target=${{ matrix.target }}
117+
118+
- name: Build with zig
119+
if: ${{ contains(matrix.target, 'musl') }}
120+
env:
121+
RUSTFLAGS: "-C target-feature=-crt-static"
122+
run: cargo zigbuild --release -p oxc_transform_napi --target=${{ matrix.target }}
123+
124+
### Build Done
125+
126+
- name: Move file on ${{ matrix.os }}
127+
run: |
128+
shopt -s extglob
129+
ls target/${{ matrix.target }}/release/*.@(so|dll|dylib)
130+
mv target/${{ matrix.target }}/release/*.@(so|dll|dylib) napi/transform/transform.${{ matrix.code-target }}.node
131+
ls napi/transform
132+
133+
- name: Test
134+
working-directory: napi/transform
135+
if: ${{ contains(matrix.target, 'x86') && !contains(matrix.target, 'musl') }} # Need docker for aarch64
136+
run: |
137+
ls
138+
node test.mjs
139+
140+
# The binary is zipped to fix permission loss https://github.com/actions/upload-artifact#permission-loss
141+
- name: Archive Binary
142+
if: runner.os == 'Windows'
143+
run: 7z a ${{ matrix.code-target }}.zip napi/transform/transform.${{ matrix.code-target }}.node
144+
145+
# The binary is zipped to fix permission loss https://github.com/actions/upload-artifact#permission-loss
146+
- name: Archive Binary
147+
if: runner.os != 'Windows'
148+
run: tar czf ${{ matrix.code-target }}.tar.gz napi/transform/transform.${{ matrix.code-target }}.node
149+
150+
- name: Upload artifact
151+
uses: actions/upload-artifact@v4
152+
with:
153+
if-no-files-found: error
154+
name: binaries-${{ matrix.code-target }}
155+
path: |
156+
*.zip
157+
*.tar.gz
158+
159+
publish:
160+
name: Publish NAPI
161+
runs-on: ubuntu-latest
162+
permissions:
163+
id-token: write # for `npm publish --provenance`
164+
needs:
165+
- build
166+
steps:
167+
- uses: taiki-e/checkout-action@v1
168+
169+
- name: Install Node.js
170+
uses: actions/setup-node@v4
171+
with:
172+
node-version-file: .node-version
173+
registry-url: 'https://registry.npmjs.org'
174+
175+
- name: Download Artifacts
176+
uses: actions/download-artifact@v4
177+
with:
178+
merge-multiple: true
179+
180+
- name: Unzip
181+
uses: montudor/action-zip@v1
182+
with:
183+
args: unzip -qq *.zip -d .
184+
185+
- name: Untar
186+
run: ls *.gz | xargs -i tar xvf {}
187+
188+
- name: Generate npm packages
189+
run: |
190+
ls
191+
ls napi/transform
192+
node npm/oxc-transform/scripts/generate-packages.mjs
193+
cat npm/oxc-transform/package.json
194+
for package in npm/oxc-transform*
195+
do
196+
ls $package
197+
cat $package/package.json
198+
echo '----'
199+
done
200+
201+
- name: Publish npm packages as latest
202+
env:
203+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
204+
# NOTE: The trailing slash on $package/ changes it to publishing the directory
205+
run: |
206+
# publish subpackages first
207+
for package in npm/oxc-transform-*
208+
do
209+
npm publish $package/ --tag latest --provenance --access public
210+
done
211+
# publish root package last
212+
npm publish npm/oxc-transform/ --provenance --access public --tag latest

npm/oxc-transform/README.md

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# The JavaScript Oxidation Compiler
2+
3+
See index.d.ts for `parseSync` and `parseAsync` API.
4+
5+
## ESM
6+
7+
```javascript
8+
import oxc from './index.js';
9+
import assert from 'assert';
10+
11+
test(oxc.isolatedDeclaration("test.ts", "class A {}"), "declare class A {}\n");
12+
13+
function test(ret, expected) {
14+
assert.equal(ret.sourceText, expected);
15+
assert(ret.errors.length == 0);
16+
}
17+
```

npm/oxc-transform/package.json

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"name": "oxc-transform",
3+
"version": "0.0.1",
4+
"description": "Oxc transform Node API",
5+
"keywords": [
6+
"transform"
7+
],
8+
"author": "Boshen and oxc contributors",
9+
"license": "MIT",
10+
"homepage": "https://oxc.rs",
11+
"bugs": "https://github.com/oxc-project/oxc/issues",
12+
"repository": {
13+
"type": "git",
14+
"url": "https://github.com/oxc-project/oxc.git",
15+
"directory": "npm/oxc-transform"
16+
},
17+
"funding": {
18+
"url": "https://github.com/sponsors/Boshen"
19+
},
20+
"main": "index.js",
21+
"files": [
22+
"index.d.ts",
23+
"index.js"
24+
]
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// Code copied from [Rome](https://github.com/rome/tools/blob/main/npm/rome/scripts/generate-packages.mjs)
2+
3+
import { resolve } from "node:path";
4+
import { fileURLToPath } from "node:url";
5+
import * as fs from "node:fs";
6+
7+
const OXC_ROOT = resolve(fileURLToPath(import.meta.url), "../..");
8+
const PACKAGES_ROOT = resolve(OXC_ROOT, "..");
9+
const BINARY_ROOT = resolve(OXC_ROOT, "../../napi/transform");
10+
const MANIFEST_PATH = resolve(OXC_ROOT, "package.json");
11+
12+
console.log('OXC_ROOT', OXC_ROOT);
13+
console.log('PACKAGES_ROOT', PACKAGES_ROOT);
14+
console.log('BINARY_ROOT', BINARY_ROOT);
15+
console.log('MANIFEST_PATH', MANIFEST_PATH);
16+
17+
const LIBC_MAPPING = {
18+
"gnu": "glibc",
19+
"musl": "musl",
20+
}
21+
22+
const rootManifest = JSON.parse(
23+
fs.readFileSync(MANIFEST_PATH).toString("utf-8")
24+
);
25+
26+
function package_name(target) {
27+
return `@oxc-transform/binding-${target}`
28+
}
29+
function generateNativePackage(target) {
30+
const binaryName = `transform.${target}.node`;
31+
32+
const packageRoot = resolve(PACKAGES_ROOT, `oxc-transform-${target}`);
33+
const binarySource = resolve(BINARY_ROOT, binaryName);
34+
const binaryTarget = resolve(packageRoot, binaryName);
35+
36+
// Remove the directory just in case it already exists (it's autogenerated
37+
// so there shouldn't be anything important there anyway)
38+
fs.rmSync(packageRoot, { recursive: true, force: true });
39+
40+
// Create the package directory
41+
console.log(`Create directory ${packageRoot}`);
42+
fs.mkdirSync(packageRoot);
43+
44+
// Generate the package.json manifest
45+
const { version, author, license, homepage, bugs, repository } = rootManifest;
46+
47+
const triple = target.split("-");
48+
const platform = triple[0];
49+
const arch = triple[1];
50+
const libc = triple[2] && { libc: [LIBC_MAPPING[triple[2]]] }
51+
const manifest = {
52+
name: package_name(target),
53+
version,
54+
main: binaryName,
55+
license,
56+
author,
57+
bugs,
58+
homepage,
59+
repository,
60+
files: [binaryName],
61+
cpu: [arch],
62+
os: [platform],
63+
...libc
64+
};
65+
66+
const manifestPath = resolve(packageRoot, "package.json");
67+
console.log(`Create manifest ${manifestPath}`);
68+
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
69+
70+
console.log(`Copy binary ${binaryTarget}`);
71+
fs.copyFileSync(binarySource, binaryTarget);
72+
}
73+
74+
function writeManifest() {
75+
const packageRoot = resolve(PACKAGES_ROOT, 'oxc-transform');
76+
const manifestPath = resolve(packageRoot, "package.json");
77+
78+
console.log('packageRoot', packageRoot);
79+
80+
const manifestData = JSON.parse(
81+
fs.readFileSync(manifestPath).toString("utf-8")
82+
);
83+
84+
const nativePackages = TARGETS.map((target) => [
85+
package_name(target),
86+
rootManifest.version,
87+
]);
88+
89+
manifestData["version"] = rootManifest.version;
90+
manifestData["optionalDependencies"] = Object.fromEntries(nativePackages);
91+
92+
console.log('manifestPath', manifestPath);
93+
console.log('manifestData', manifestData);
94+
95+
const content = JSON.stringify(manifestData, null, 2);
96+
fs.writeFileSync(manifestPath, content);
97+
98+
let files = ["index.js", "index.d.ts"];
99+
for (const file of files) {
100+
fs.copyFileSync(resolve(BINARY_ROOT, file), resolve(packageRoot, file));
101+
}
102+
}
103+
104+
// NOTE: Must update npm/oxc-transform/package.json
105+
const TARGETS = [
106+
"win32-x64-msvc",
107+
"win32-arm64-msvc",
108+
"linux-x64-gnu",
109+
"linux-arm64-gnu",
110+
"linux-x64-musl",
111+
"linux-arm64-musl",
112+
"darwin-x64",
113+
"darwin-arm64",
114+
];
115+
116+
for (const target of TARGETS) {
117+
generateNativePackage(target);
118+
}
119+
120+
writeManifest();

0 commit comments

Comments
 (0)