@zntc/core 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,54 +1,61 @@
1
1
  # @zntc/core
2
2
 
3
- ZNTC (Zig Native Transpiler & Compiler) 의 코어 — Zig 로 작성된 JS/TS/Flow 트랜스파일러 + 번들러의 Node.js NAPI 바인딩 + JS API + CLI.
3
+ English · **[한국어](./README_KO.md)**
4
4
 
5
- SWC / oxc 동급 성능을 목표로, in-process 호출 (NAPI) + Vite/Rollup 어댑터 / 단독 CLI 모두 제공.
5
+ > The core of ZNTC (Zig Native Transpiler & Compiler) — a NAPI binding + JS API + `zntc` CLI for a JS / TS / Flow transpiler and bundler written in Zig.
6
6
 
7
- ## 설치
7
+ [![npm](https://img.shields.io/npm/v/@zntc/core.svg)](https://www.npmjs.com/package/@zntc/core)
8
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/ohah/zntc/blob/main/LICENSE)
9
+
10
+ `@zntc/core` ships the native `.node` NAPI binding plus the `zntc` CLI for Node.js and Bun. It targets SWC / oxc-class performance and provides in-process (NAPI) calls, Vite / Rollup adapters, and a standalone CLI — covering transpile, bundle, and lightningcss-based CSS handling.
11
+
12
+ ## Installation
8
13
 
9
14
  ```bash
10
15
  bun add -D @zntc/core
11
- # 또는
16
+ # or
12
17
  npm i -D @zntc/core
13
18
  ```
14
19
 
15
- 플랫폼별 prebuilt binary 함께 install (linux/darwin/windows × x64/arm64).
20
+ Platform-specific prebuilt binaries are installed automatically (linux / darwin / windows × x64 / arm64).
16
21
 
17
- ### Optional (필요 )
22
+ ### Optional (as needed)
18
23
 
19
24
  ```bash
20
25
  bun add -D browserslist core-js core-js-compat lightningcss
21
26
  ```
22
27
 
23
- - `browserslist` / `core-js-compat` — `runtimePolyfills` 옵션 사용 시
24
- - `lightningcss` — CSS minify / nesting 사용 시
28
+ - `browserslist` / `core-js-compat` — required for the `runtimePolyfills` option
29
+ - `lightningcss` — required for CSS minify / nesting
30
+
31
+ ## Usage
25
32
 
26
- ## CLI
33
+ ### CLI
27
34
 
28
35
  ```bash
29
- # transpile single file
36
+ # Transpile a single file
30
37
  bunx zntc src/index.ts --outfile out.js
31
38
 
32
- # bundle (multi-entry)
39
+ # Bundle (multi-entry)
33
40
  bunx zntc --bundle src/index.ts --outfile dist/bundle.js --format=esm --target=node
34
41
  ```
35
42
 
36
- 전체 옵션: `bunx zntc --help`
43
+ See `bunx zntc --help` for the full list of options.
37
44
 
38
- App-mode (`bunx zntc dev / build / preview`) `@zntc/web` 또는 `@zntc/react-native` 함께 install 되어야 동작 패키지 README 참조.
45
+ App mode (`bunx zntc dev / build / preview`) requires `@zntc/web` or `@zntc/react-native` to also be installedsee each package's README.
39
46
 
40
- ## JS API
47
+ ### JS / NAPI API
41
48
 
42
49
  ```ts
43
50
  import { init, transpile, build } from '@zntc/core';
44
51
 
45
52
  await init();
46
53
 
47
- // 단일 파일 transpile
54
+ // Transpile a single file
48
55
  const r = transpile('const x: number = 1;', { filename: 'input.ts' });
49
56
  console.log(r.code); // "const x = 1;"
50
57
 
51
- // bundle (multi-file)
58
+ // Bundle (multi-file)
52
59
  const out = await build({
53
60
  entryPoints: ['src/index.ts'],
54
61
  outdir: 'dist',
@@ -57,16 +64,19 @@ const out = await build({
57
64
  });
58
65
  ```
59
66
 
60
- 자세한 옵션: [docs/CONFIG.md](https://github.com/ohah/zts/blob/main/docs/CONFIG.md) · [docs/USAGE.md](https://github.com/ohah/zts/blob/main/docs/USAGE.md)
67
+ ## Related packages
61
68
 
62
- ## 관련 패키지
63
-
64
- - [@zntc/web](https://npmjs.com/package/@zntc/web) — dev server + HMR overlay + postcss/sass
69
+ - [@zntc/web](https://npmjs.com/package/@zntc/web) — dev server + HMR overlay + postcss / sass
65
70
  - [@zntc/react-native](https://npmjs.com/package/@zntc/react-native) — RN preset + Metro HMR adapter
66
- - [@zntc/wasm](https://npmjs.com/package/@zntc/wasm) — browser-side WASM 빌드 (NAPI 대신)
67
- - [@zntc/init](https://npmjs.com/package/@zntc/init) — 기존 RN 프로젝트에 ZNTC 도입
68
- - [@zntc/vite-plugin](https://npmjs.com/package/@zntc/vite-plugin) — Vite esbuild transform ZNTC 로 교체
71
+ - [@zntc/wasm](https://npmjs.com/package/@zntc/wasm) — browser-side WASM build (instead of NAPI)
72
+ - [@zntc/init](https://npmjs.com/package/@zntc/init) — add ZNTC to an existing RN project
73
+ - [@zntc/vite-plugin](https://npmjs.com/package/@zntc/vite-plugin) — replace Vite's esbuild transform with ZNTC
74
+
75
+ ## Documentation
76
+
77
+ - Repository: <https://github.com/ohah/zntc>
78
+ - Docs: <https://ohah.github.io/zntc>
69
79
 
70
- ## 라이센스
80
+ ## License
71
81
 
72
- MIT.
82
+ MIT
package/bin/cli-flags.mjs CHANGED
@@ -131,8 +131,14 @@ export const FLAG_REGISTRY = [
131
131
  forms: ['equal'],
132
132
  },
133
133
  { kind: 'string', flag: '--rn-platform', target: 'rnPlatform', forms: ['equal', 'pair'] },
134
+ // RN 버전 타겟 — platform=react-native 함의 + RN 문서 기준 버전별 정밀 다운레벨.
135
+ // 예: --rn-version=0.80 / --rn-version ">=0.74" / "<=0.84" / "==0.76"
136
+ { kind: 'string', flag: '--rn-version', target: 'rnVersion', forms: ['equal', 'pair'] },
134
137
  // #2540 PR #7 — RN preset 의 projectRoot. 기본 cwd, 사용자 monorepo root 지정 시 사용.
135
138
  { kind: 'string', flag: '--rn-project-root', target: 'rnProjectRoot', forms: ['equal', 'pair'] },
139
+ // #4438 디스크 캐시 opt-in: --disk-cache(활성, 기본 node_modules/.cache/zntc) / --cache-dir <path>.
140
+ { kind: 'bool', flag: '--disk-cache', target: 'diskCache' },
141
+ { kind: 'string', flag: '--cache-dir', target: 'cacheDir', forms: ['equal', 'pair'] },
136
142
  // ─── RN CLI 호환 flag 매트릭스 (#2605 audit P0) ───
137
143
  // `react-native bundle` / Metro CLI 의 standard flag 들 — `zntc bundle --platform=react-native`
138
144
  // 가 dropin 으로 동작하기 위한 호환 layer. zntc 내부 옵션 (outfile 등) 과 별개로 받아 매핑.
@@ -188,6 +194,8 @@ export const FLAG_REGISTRY = [
188
194
  { kind: 'int', flag: '--line-limit', target: 'lineLimit', forms: ['equal'] },
189
195
  // Rollup output.experimentalMinChunkSize 류 — 작은 common 청크 자동 병합 (bytes).
190
196
  { kind: 'int', flag: '--min-chunk-size', target: 'minChunkSize', forms: ['equal'] },
197
+ // #4466 — 이 byte 수 이하 asset 을 data URL 로 인라인 (0 = 끔). 기본 4096.
198
+ { kind: 'int', flag: '--asset-inline-limit', target: 'assetInlineLimit', forms: ['equal'] },
191
199
  // RN CLI 호환 — `--max-workers N` (Metro). zntc `--jobs` 와 의미 동일이므로 alias.
192
200
  { kind: 'int', flag: '--max-workers', target: 'jobs', forms: ['equal'] },
193
201
 
@@ -121,6 +121,11 @@ function assignRnBuildOptionOverrides(out, config, opts = {}) {
121
121
  } else if (opts.inlineDynamicImports === false || cfg.inlineDynamicImports === false) {
122
122
  out.inlineDynamicImports = false;
123
123
  }
124
+ // --rn-version: RN preset 경로(runRnBundle/runRnDev)에서도 버전별 정밀 매트릭스를 적용하도록
125
+ // override 로 forward. 없으면 preset 의 blunt fromHermesPreset 이 그대로 쓰인다.
126
+ if (typeof opts.rnVersion === 'string' || typeof cfg.rnVersion === 'string') {
127
+ out.rnVersion = opts.rnVersion ?? cfg.rnVersion;
128
+ }
124
129
  }
125
130
 
126
131
  /**
package/bin/zntc.mjs CHANGED
@@ -258,7 +258,11 @@ function parseArgs(argv) {
258
258
  bundle: false,
259
259
  watch: false,
260
260
  watchJson: false,
261
- watchDelay: 16,
261
+ // SCALAR_KEYS 머지 키 — config.watchDelay 가 적용되려면 default 가 `undefined`
262
+ // 여야 한다(머지 조건 `opts[key] === undefined`). 16ms 디바운스 default 는
263
+ // 소비처(setTimeout)에서 `?? 16` 으로 보정(#4223 — 이전 `16` default 라 config
264
+ // watchDelay 가 silent 무시되던 schema-drift 가드 발동).
265
+ watchDelay: undefined,
262
266
  serve: false,
263
267
  serveDir: '.',
264
268
  port: undefined,
@@ -299,6 +303,8 @@ function parseArgs(argv) {
299
303
  entryNames: undefined,
300
304
  chunkNames: undefined,
301
305
  assetNames: undefined,
306
+ // #4466 — undefined 여야 native default(4096)를 덮지 않는다. 명시 0 = 인라인 끔.
307
+ assetInlineLimit: undefined,
302
308
  cssNames: undefined,
303
309
  jsx: undefined,
304
310
  jsxDev: false,
@@ -344,6 +350,9 @@ function parseArgs(argv) {
344
350
  resolveExtensions: [],
345
351
  mainFields: [],
346
352
  rnPlatform: undefined,
353
+ rnVersion: undefined,
354
+ diskCache: false, // #4438 디스크 캐시 활성 (--disk-cache)
355
+ cacheDir: undefined, // #4438 디스크 캐시 경로 (--cache-dir)
347
356
  jsxInJs: false,
348
357
  outExtensionJs: undefined,
349
358
  sourceRoot: undefined,
@@ -1320,6 +1329,8 @@ function mergeConfigIntoOpts(opts, config) {
1320
1329
  'format',
1321
1330
  'platform',
1322
1331
  'target',
1332
+ 'rnVersion',
1333
+ 'cacheDir', // #4438 디스크 캐시 경로 (NAPI 가 disk_cache_dir 로 해석)
1323
1334
  'banner',
1324
1335
  'footer',
1325
1336
  'globalName',
@@ -1327,6 +1338,7 @@ function mergeConfigIntoOpts(opts, config) {
1327
1338
  'entryNames',
1328
1339
  'chunkNames',
1329
1340
  'assetNames',
1341
+ 'assetInlineLimit', // #4466 asset data URL 인라인 임계값 (숫자 scalar)
1330
1342
  'cssNames',
1331
1343
  'jsx',
1332
1344
  'jsxFactory',
@@ -1359,6 +1371,8 @@ function mergeConfigIntoOpts(opts, config) {
1359
1371
  'runtimePolyfills',
1360
1372
  'coreJs',
1361
1373
  'tokenizeFormat',
1374
+ // #4223 — config.watchDelay 가 머지되도록(opts default=undefined, 소비처 `?? 16`).
1375
+ 'watchDelay',
1362
1376
  ];
1363
1377
  for (const key of SCALAR_KEYS) {
1364
1378
  if (opts[key] === undefined && config[key] !== undefined) {
@@ -1398,6 +1412,7 @@ function mergeConfigIntoOpts(opts, config) {
1398
1412
  // 머지 안 되던 실 BuildOption bool.
1399
1413
  'analyze',
1400
1414
  'devMode',
1415
+ 'diskCache', // #4438 디스크 캐시 활성 (NAPI 가 disk_cache_dir 로 해석)
1401
1416
  ];
1402
1417
  for (const key of BOOL_KEYS) {
1403
1418
  if ((opts[key] === false || opts[key] === undefined) && config[key] === true) {
@@ -1421,7 +1436,10 @@ function mergeConfigIntoOpts(opts, config) {
1421
1436
  // tristate bool: false 가 명시적 의미를 가져서 default 를 undefined 로 두는 키.
1422
1437
  // CLI 가 미지정(undefined)일 때만 config 값(true/false)을 채택한다 (CLI flag 우선).
1423
1438
  // inlineDynamicImports=false 의 single-file 보정은 applySingleFileDynamicImportDefault.
1424
- for (const key of ['inlineDynamicImports']) {
1439
+ // reactRefresh(#4223): `zntc dev` 는 default on(parseArgs 가 opts.reactRefresh=true)
1440
+ // 그 경우 머지 skip(opts defined). build/transpile 은 opts undefined 라 config(true/
1441
+ // false) 채택 — 이전 머지 리스트 누락으로 silent 무시되던 schema-drift 해소.
1442
+ for (const key of ['inlineDynamicImports', 'reactRefresh']) {
1425
1443
  if (opts[key] === undefined && config[key] !== undefined) {
1426
1444
  opts[key] = config[key];
1427
1445
  }
@@ -1533,6 +1551,11 @@ async function buildBundleOptions(opts, config, { filterCallerPreWarmCss = false
1533
1551
  format: opts.format,
1534
1552
  platform: opts.platform,
1535
1553
  target: opts.target,
1554
+ // --rn-version: platform=react-native 함의 + RN 문서 기준 버전별 다운레벨 (NAPI 가 해석).
1555
+ rnVersion: opts.rnVersion,
1556
+ // #4438 디스크 캐시 opt-in: --disk-cache(활성) / --cache-dir <path>. NAPI 가 disk_cache_dir 로 해석.
1557
+ diskCache: opts.diskCache,
1558
+ cacheDir: opts.cacheDir,
1536
1559
  browserslist: opts.browserslist,
1537
1560
  external: opts.external,
1538
1561
  packagesExternal: opts.packagesExternal,
@@ -1610,6 +1633,7 @@ async function buildBundleOptions(opts, config, { filterCallerPreWarmCss = false
1610
1633
  entryNames: opts.entryNames,
1611
1634
  chunkNames: opts.chunkNames,
1612
1635
  assetNames: opts.assetNames,
1636
+ assetInlineLimit: opts.assetInlineLimit,
1613
1637
  cssNames: opts.cssNames,
1614
1638
  jsx: opts.jsx,
1615
1639
  jsxDev: opts.jsxDev,
@@ -1772,7 +1796,7 @@ async function runWatch(opts, config) {
1772
1796
  }
1773
1797
 
1774
1798
  clearTimeout(debounceTimer);
1775
- debounceTimer = setTimeout(rebuild, opts.watchDelay);
1799
+ debounceTimer = setTimeout(rebuild, opts.watchDelay ?? 16);
1776
1800
  });
1777
1801
  attachWatcherErrorHandler(watcher, dir, opts.logLevel);
1778
1802
  }
@@ -2734,7 +2758,7 @@ async function runServe(opts, config, { appDev = null } = {}) {
2734
2758
  }
2735
2759
  dirty.add(absPath);
2736
2760
  clearTimeout(debounceTimer);
2737
- debounceTimer = setTimeout(drain, opts.watchDelay);
2761
+ debounceTimer = setTimeout(drain, opts.watchDelay ?? 16);
2738
2762
  });
2739
2763
  attachWatcherErrorHandler(watcher, dir, opts.logLevel);
2740
2764
  }
@@ -447,6 +447,23 @@ interface BuildOptionsCommon {
447
447
  entryPoints: string[];
448
448
  format?: 'esm' | 'cjs' | 'iife' | 'umd' | 'amd';
449
449
  external?: string[];
450
+ /**
451
+ * React Native version target — e.g. `'0.80'`, `'>=0.74'`, `'<=0.84'`, `'==0.76'`.
452
+ * Implies `platform: 'react-native'` and applies a per-version downlevel matrix
453
+ * derived from the RN javascript-environment docs (syntax the docs list as supported
454
+ * stays native; everything else is downleveled) instead of the blunt Hermes preset.
455
+ * `>=`/bare/`==` target that version; `<=`/`<` use the most conservative matrix.
456
+ * Conflicts with `platform: 'node' | 'neutral'`.
457
+ */
458
+ rnVersion?: string;
459
+ /**
460
+ * #4438 Disk cache: persist parse/semantic across builds for faster cold rebuilds.
461
+ * `true` enables it at the default dir `node_modules/.cache/zntc`; pass `cacheDir`
462
+ * for a custom path. Opt-in (off by default). Mirrors CLI `--disk-cache`.
463
+ */
464
+ diskCache?: boolean;
465
+ /** #4438 Disk cache directory (implies `diskCache`). Mirrors CLI `--cache-dir`. */
466
+ cacheDir?: string;
450
467
  minify?: boolean;
451
468
  minifyWhitespace?: boolean;
452
469
  minifyIdentifiers?: boolean;
@@ -550,6 +567,15 @@ interface BuildOptionsCommon {
550
567
  entryNames?: string;
551
568
  chunkNames?: string;
552
569
  assetNames?: string;
570
+ /** 이 byte 수 **이하**의 asset 은 별도 파일로 emit 하지 않고 data URL 로 인라인한다
571
+ * (#4466). Vite 의 `assetsInlineLimit` 상당.
572
+ *
573
+ * - 기본값: `4096` (4KB)
574
+ * - `0`: 인라인 끔 — 크기와 무관하게 항상 파일로 emit
575
+ *
576
+ * 인라인된 asset 은 `assetNames` 패턴을 타지 않고, CSS `url()` / import 값이
577
+ * `data:` URI 로 치환된다. */
578
+ assetInlineLimit?: number;
553
579
  /** CSS chunk path pattern. Default: `[dir]/[name]` (PR B-4b sub-2; esbuild parity).
554
580
  * Supports `[name]`, `[hash]` (content), and `[dir]` (entry-relative). */
555
581
  cssNames?: string;
@@ -1362,6 +1388,20 @@ export interface AppDevPrepareResult {
1362
1388
  /** Number of files emitted while preparing the dev app, when available. */
1363
1389
  outputCount?: number;
1364
1390
  }
1391
+ /**
1392
+ * 단일 출력 파일의 디스크 경로를 결정한다(순수 함수 — 단위 테스트용 분리).
1393
+ *
1394
+ * outfile 모드에선 메인 번들(`bundle.js`)을 outfile 로, 그 짝 sourcemap(`bundle.js.map`)을
1395
+ * `outfile.map` 으로 보낸다. **메인 map 에만 특정**(`=== 'bundle.js.map'`) — 과거 `endsWith('.map')`
1396
+ * 광범위 매칭은 메인이 아닌 map(다중 청크 등)도 같은 `outfile.map` 으로 보내 덮어썼다. 그 외
1397
+ * 파일은 outdir 가 있으면 그 아래로, 없으면 cwd 기준으로 해석.
1398
+ *
1399
+ * @internal
1400
+ */
1401
+ export declare function resolveOutputPath(filePath: string, opts: {
1402
+ outfileResolved: string | null;
1403
+ outdir?: string;
1404
+ }): string;
1365
1405
  /**
1366
1406
  * Runs bundling asynchronously. Does not block the event loop.
1367
1407
  * Promise/async hooks of JS plugins are supported in this function.
@@ -447,6 +447,23 @@ interface BuildOptionsCommon {
447
447
  entryPoints: string[];
448
448
  format?: 'esm' | 'cjs' | 'iife' | 'umd' | 'amd';
449
449
  external?: string[];
450
+ /**
451
+ * React Native version target — e.g. `'0.80'`, `'>=0.74'`, `'<=0.84'`, `'==0.76'`.
452
+ * Implies `platform: 'react-native'` and applies a per-version downlevel matrix
453
+ * derived from the RN javascript-environment docs (syntax the docs list as supported
454
+ * stays native; everything else is downleveled) instead of the blunt Hermes preset.
455
+ * `>=`/bare/`==` target that version; `<=`/`<` use the most conservative matrix.
456
+ * Conflicts with `platform: 'node' | 'neutral'`.
457
+ */
458
+ rnVersion?: string;
459
+ /**
460
+ * #4438 Disk cache: persist parse/semantic across builds for faster cold rebuilds.
461
+ * `true` enables it at the default dir `node_modules/.cache/zntc`; pass `cacheDir`
462
+ * for a custom path. Opt-in (off by default). Mirrors CLI `--disk-cache`.
463
+ */
464
+ diskCache?: boolean;
465
+ /** #4438 Disk cache directory (implies `diskCache`). Mirrors CLI `--cache-dir`. */
466
+ cacheDir?: string;
450
467
  minify?: boolean;
451
468
  minifyWhitespace?: boolean;
452
469
  minifyIdentifiers?: boolean;
@@ -550,6 +567,15 @@ interface BuildOptionsCommon {
550
567
  entryNames?: string;
551
568
  chunkNames?: string;
552
569
  assetNames?: string;
570
+ /** 이 byte 수 **이하**의 asset 은 별도 파일로 emit 하지 않고 data URL 로 인라인한다
571
+ * (#4466). Vite 의 `assetsInlineLimit` 상당.
572
+ *
573
+ * - 기본값: `4096` (4KB)
574
+ * - `0`: 인라인 끔 — 크기와 무관하게 항상 파일로 emit
575
+ *
576
+ * 인라인된 asset 은 `assetNames` 패턴을 타지 않고, CSS `url()` / import 값이
577
+ * `data:` URI 로 치환된다. */
578
+ assetInlineLimit?: number;
553
579
  /** CSS chunk path pattern. Default: `[dir]/[name]` (PR B-4b sub-2; esbuild parity).
554
580
  * Supports `[name]`, `[hash]` (content), and `[dir]` (entry-relative). */
555
581
  cssNames?: string;
@@ -1362,6 +1388,20 @@ export interface AppDevPrepareResult {
1362
1388
  /** Number of files emitted while preparing the dev app, when available. */
1363
1389
  outputCount?: number;
1364
1390
  }
1391
+ /**
1392
+ * 단일 출력 파일의 디스크 경로를 결정한다(순수 함수 — 단위 테스트용 분리).
1393
+ *
1394
+ * outfile 모드에선 메인 번들(`bundle.js`)을 outfile 로, 그 짝 sourcemap(`bundle.js.map`)을
1395
+ * `outfile.map` 으로 보낸다. **메인 map 에만 특정**(`=== 'bundle.js.map'`) — 과거 `endsWith('.map')`
1396
+ * 광범위 매칭은 메인이 아닌 map(다중 청크 등)도 같은 `outfile.map` 으로 보내 덮어썼다. 그 외
1397
+ * 파일은 outdir 가 있으면 그 아래로, 없으면 cwd 기준으로 해석.
1398
+ *
1399
+ * @internal
1400
+ */
1401
+ export declare function resolveOutputPath(filePath: string, opts: {
1402
+ outfileResolved: string | null;
1403
+ outdir?: string;
1404
+ }): string;
1365
1405
  /**
1366
1406
  * Runs bundling asynchronously. Does not block the event loop.
1367
1407
  * Promise/async hooks of JS plugins are supported in this function.
@@ -132,7 +132,7 @@ export declare function readFileIfExists(absPath: string): string | null;
132
132
  * 동기 stat (`existsSync`) 사용 — CLI 시작 시 한 번만 호출되므로 비용 무시 가능.
133
133
  * parent 디렉토리 traversal 은 모노레포 워크스페이스 (#2111 / Phase 3-4) 에서 처리.
134
134
  *
135
- * Note: Zig CLI (`src/main.zig:293` `applyZntcConfigJson`) 은 현재 `.json` 만
135
+ * Note: Zig CLI (`src/cli/options.zig` `applyZntcConfigJson`) 은 현재 `.json` 만
136
136
  * 직접 처리한다. 다른 확장자는 JS CLI (`zntc.mjs`) 만 자동 탐색하므로 두 경로의
137
137
  * 동작이 의도적으로 갈린다. 통합은 #2105 (Phase 2-3 bundler 옵션 매핑) 에서.
138
138
  */
@@ -7,11 +7,11 @@
7
7
  * `zntc.config.*` 에 적을 일 없으므로 typo 검출 대상 아님)
8
8
  * - `packages/core/bin/zntc-cli-schema-sync.test.ts`: CLI flag 미노출 정당화
9
9
  *
10
- * Zig DTO sync (`src/transpile_options_dto_test.zig:ts_buildoptions_only_allowlist`) 는 별
10
+ * Zig DTO sync (`src/config_options_dto_test.zig:ts_buildoptions_only_allowlist`) 는 별
11
11
  * 언어라 별도 유지 — 새 internal 키 추가 시 양쪽 모두 갱신 필요. (TypeScript Compiler API
12
12
  * 도입 + codegen 으로 single source 화는 ROI 낮아 보류, future work.)
13
13
  *
14
14
  * 새 internal 키 추가 시 여기 1곳에만 등록 → 두 TS 테스트 모두 자동 통과. 각 테스트의 추가
15
15
  * allowlist (테스트만의 특수 케이스) 는 그대로 유지.
16
16
  */
17
- export declare const NAPI_INTERNAL_ONLY_KEYS: readonly ["allowOverwrite", "assetRegistry", "blockList", "collectModuleCodes", "configurableExports", "devMode", "emitDiskSourcemap", "entryErrorGuard", "experimentalCodeCache", "fallback", "globalIdentifiers", "onReady", "onRebuild", "polyfills", "reactRefresh", "rootDir", "runBeforeMain", "scopeHoist", "silentConsoleErrorPatterns", "skipInitialOutput", "strictExecutionOrder", "watchExclude", "watchFolders", "watchInclude", "workletPluginVersion", "workletTransform", "write"];
17
+ export declare const NAPI_INTERNAL_ONLY_KEYS: readonly ["allowOverwrite", "assetRegistry", "blockList", "collectModuleCodes", "configurableExports", "devMode", "emitDiskSourcemap", "entryErrorGuard", "fallback", "globalIdentifiers", "onReady", "onRebuild", "polyfills", "reactRefresh", "rootDir", "runBeforeMain", "scopeHoist", "silentConsoleErrorPatterns", "skipInitialOutput", "strictExecutionOrder", "watchExclude", "watchFolders", "watchInclude", "workletPluginVersion", "workletTransform", "write"];
package/dist/index.cjs CHANGED
@@ -15,7 +15,7 @@ function formatSupportedPlatforms() {
15
15
  }
16
16
  //#endregion
17
17
  //#region compat-engines.ts
18
- const FEATURES = ["arrow", "class", "template_literal", "destructuring", "for_of", "spread", "object_extensions", "default_params", "block_scoping", "generator", "new_target", "exponentiation", "async_await", "object_spread", "optional_catch_binding", "nullish_coalescing", "optional_chaining", "logical_assignment", "class_static_block", "class_private_method", "class_private_field", "top_level_await", "hashbang", "using", "regex_sticky", "regex_dotall", "regex_named_groups", "unicode_brace_escape"],SUPPORT = { arrow: { chrome: [45, 0], firefox: [22, 0], safari: [10, 0], edge: [12, 0], node: [4, 0], deno: [1, 0], ios: [10, 0] }, class: { chrome: [49, 0], firefox: [45, 0], safari: [10, 1], edge: [13, 0], node: [6, 0], deno: [1, 0], ios: [10, 3] }, template_literal: { chrome: [41, 0], firefox: [34, 0], safari: [9, 0], edge: [12, 0], node: [4, 0], deno: [1, 0], ios: [9, 0] }, destructuring: { chrome: [49, 0], firefox: [41, 0], safari: [8, 0], edge: [14, 0], node: [6, 0], deno: [1, 0], ios: [8, 0] }, for_of: { chrome: [38, 0], firefox: [13, 0], safari: [7, 0], edge: [12, 0], node: [0, 12], deno: [1, 0], ios: [7, 0], hermes: [0, 7] }, spread: { chrome: [46, 0], firefox: [27, 0], safari: [10, 0], edge: [13, 0], node: [5, 0], deno: [1, 0], ios: [10, 0], hermes: [0, 7] }, object_extensions: { chrome: [43, 0], firefox: [34, 0], safari: [9, 0], edge: [12, 0], node: [4, 0], deno: [1, 0], ios: [9, 0], hermes: [0, 7] }, default_params: { chrome: [49, 0], firefox: [15, 0], safari: [10, 0], edge: [14, 0], node: [6, 0], deno: [1, 0], ios: [10, 0] }, block_scoping: { chrome: [49, 0], firefox: [51, 0], safari: [11, 0], edge: [14, 0], node: [6, 0], deno: [1, 0], ios: [11, 0] }, generator: { chrome: [50, 0], firefox: [53, 0], safari: [10, 0], edge: [13, 0], node: [6, 0], deno: [1, 0], ios: [10, 0] }, new_target: { chrome: [46, 0], firefox: [41, 0], safari: [10, 0], edge: [14, 0], node: [5, 0], deno: [1, 0], ios: [10, 0] }, exponentiation: { chrome: [52, 0], firefox: [52, 0], safari: [10, 1], edge: [14, 0], node: [7, 0], deno: [1, 0], ios: [10, 3], hermes: [0, 7] }, async_await: { chrome: [55, 0], firefox: [52, 0], safari: [11, 0], edge: [15, 0], node: [7, 6], deno: [1, 0], ios: [11, 0] }, object_spread: { chrome: [60, 0], firefox: [55, 0], safari: [11, 1], edge: [79, 0], node: [8, 3], deno: [1, 0], ios: [11, 3], hermes: [0, 7] }, optional_catch_binding: { chrome: [66, 0], firefox: [58, 0], safari: [11, 1], edge: [79, 0], node: [10, 0], deno: [1, 0], ios: [11, 3], hermes: [0, 12] }, nullish_coalescing: { chrome: [80, 0], firefox: [72, 0], safari: [13, 1], edge: [80, 0], node: [14, 0], deno: [1, 0], ios: [13, 4], hermes: [0, 7] }, optional_chaining: { chrome: [91, 0], firefox: [74, 0], safari: [13, 1], edge: [91, 0], node: [16, 9], deno: [1, 9], ios: [13, 4], hermes: [0, 12] }, logical_assignment: { chrome: [85, 0], firefox: [79, 0], safari: [14, 0], edge: [85, 0], node: [15, 0], deno: [1, 2], ios: [14, 0], hermes: [0, 7] }, class_static_block: { chrome: [94, 0], firefox: [93, 0], safari: [16, 4], edge: [94, 0], node: [16, 11], deno: [1, 14], ios: [16, 4] }, class_private_method: { chrome: [84, 0], firefox: [90, 0], safari: [15, 0], edge: [84, 0], node: [14, 6], deno: [1, 0], ios: [15, 0] }, class_private_field: { chrome: [74, 0], firefox: [90, 0], safari: [14, 1], edge: [79, 0], node: [12, 0], deno: [1, 0], ios: [14, 5] }, hashbang: { chrome: [74, 0], firefox: [67, 0], safari: [13, 1], edge: [79, 0], node: [12, 0], deno: [1, 0], ios: [13, 4], hermes: [0, 7] }, using: {} };
18
+ const FEATURES = ["arrow", "class", "template_literal", "destructuring", "for_of", "spread", "object_extensions", "default_params", "block_scoping", "generator", "new_target", "exponentiation", "async_await", "object_spread", "optional_catch_binding", "nullish_coalescing", "optional_chaining", "logical_assignment", "class_static_block", "class_private_method", "class_private_field", "top_level_await", "hashbang", "using", "regex_sticky", "regex_dotall", "regex_named_groups", "unicode_brace_escape", "regex_duplicate_named_groups", "regex_modifiers", "regex_lookbehind"],SUPPORT = { arrow: { chrome: [45, 0], firefox: [22, 0], safari: [10, 0], edge: [12, 0], node: [4, 0], deno: [1, 0], ios: [10, 0] }, class: { chrome: [49, 0], firefox: [45, 0], safari: [10, 1], edge: [13, 0], node: [6, 0], deno: [1, 0], ios: [10, 3] }, template_literal: { chrome: [41, 0], firefox: [34, 0], safari: [9, 0], edge: [12, 0], node: [4, 0], deno: [1, 0], ios: [9, 0] }, destructuring: { chrome: [49, 0], firefox: [41, 0], safari: [8, 0], edge: [14, 0], node: [6, 0], deno: [1, 0], ios: [8, 0] }, for_of: { chrome: [38, 0], firefox: [13, 0], safari: [7, 0], edge: [12, 0], node: [0, 12], deno: [1, 0], ios: [7, 0], hermes: [0, 7] }, spread: { chrome: [46, 0], firefox: [27, 0], safari: [10, 0], edge: [13, 0], node: [5, 0], deno: [1, 0], ios: [10, 0], hermes: [0, 7] }, object_extensions: { chrome: [43, 0], firefox: [34, 0], safari: [9, 0], edge: [12, 0], node: [4, 0], deno: [1, 0], ios: [9, 0], hermes: [0, 7] }, default_params: { chrome: [49, 0], firefox: [15, 0], safari: [10, 0], edge: [14, 0], node: [6, 0], deno: [1, 0], ios: [10, 0] }, block_scoping: { chrome: [49, 0], firefox: [51, 0], safari: [11, 0], edge: [14, 0], node: [6, 0], deno: [1, 0], ios: [11, 0] }, generator: { chrome: [50, 0], firefox: [53, 0], safari: [10, 0], edge: [13, 0], node: [6, 0], deno: [1, 0], ios: [10, 0] }, new_target: { chrome: [46, 0], firefox: [41, 0], safari: [10, 0], edge: [14, 0], node: [5, 0], deno: [1, 0], ios: [10, 0] }, exponentiation: { chrome: [52, 0], firefox: [52, 0], safari: [10, 1], edge: [14, 0], node: [7, 0], deno: [1, 0], ios: [10, 3], hermes: [0, 7] }, async_await: { chrome: [55, 0], firefox: [52, 0], safari: [11, 0], edge: [15, 0], node: [7, 6], deno: [1, 0], ios: [11, 0] }, object_spread: { chrome: [60, 0], firefox: [55, 0], safari: [11, 1], edge: [79, 0], node: [8, 3], deno: [1, 0], ios: [11, 3], hermes: [0, 7] }, optional_catch_binding: { chrome: [66, 0], firefox: [58, 0], safari: [11, 1], edge: [79, 0], node: [10, 0], deno: [1, 0], ios: [11, 3], hermes: [0, 12] }, nullish_coalescing: { chrome: [80, 0], firefox: [72, 0], safari: [13, 1], edge: [80, 0], node: [14, 0], deno: [1, 0], ios: [13, 4], hermes: [0, 7] }, optional_chaining: { chrome: [91, 0], firefox: [74, 0], safari: [13, 1], edge: [91, 0], node: [16, 9], deno: [1, 9], ios: [13, 4], hermes: [0, 12] }, logical_assignment: { chrome: [85, 0], firefox: [79, 0], safari: [14, 0], edge: [85, 0], node: [15, 0], deno: [1, 2], ios: [14, 0], hermes: [0, 7] }, class_static_block: { chrome: [94, 0], firefox: [93, 0], safari: [16, 4], edge: [94, 0], node: [16, 11], deno: [1, 14], ios: [16, 4] }, class_private_method: { chrome: [84, 0], firefox: [90, 0], safari: [15, 0], edge: [84, 0], node: [14, 6], deno: [1, 0], ios: [15, 0] }, class_private_field: { chrome: [74, 0], firefox: [90, 0], safari: [14, 1], edge: [79, 0], node: [12, 0], deno: [1, 0], ios: [14, 5] }, hashbang: { chrome: [74, 0], firefox: [67, 0], safari: [13, 1], edge: [79, 0], node: [12, 0], deno: [1, 0], ios: [13, 4], hermes: [0, 7] }, using: {}, regex_duplicate_named_groups: { chrome: [125, 0], edge: [125, 0], firefox: [129, 0], safari: [17, 4], ios: [17, 4], node: [23, 0], deno: [1, 44] }, regex_modifiers: { chrome: [125, 0], edge: [125, 0], firefox: [132, 0], safari: [26, 0], ios: [26, 0], node: [23, 0], deno: [1, 44] }, regex_lookbehind: { chrome: [62, 0], edge: [79, 0], firefox: [78, 0], safari: [16, 4], ios: [16, 4], node: [8, 10], deno: [1, 0] } };
19
19
  function verGte(a,b) {
20
20
  if (a[0] !== b[0])return a[0] > b[0];
21
21
  return a[1] >= b[1];
@@ -42,7 +42,7 @@ function computeUnsupportedFromEngines(engines) {
42
42
  }
43
43
  //#endregion
44
44
  //#region index.ts
45
- const ES_TARGET_BITS = { es5: 0x0fffffff, es2015: 0x06fff800, es2016: 0x06fff000, es2017: 0x06ffe000, es2018: 0x00ffc000, es2019: 0x00ff8000, es2020: 0x00fe0000, es2021: 0x00fc0000, es2022: 0x00c00000, es2023: 0x00800000, es2024: 0x00800000, es2025: 0x0, esnext: 0x0 };
45
+ const ES_TARGET_BITS = { es5: 0x7fffffff, es2015: 0x76fff800, es2016: 0x76fff000, es2017: 0x76ffe000, es2018: 0x30ffc000, es2019: 0x30ff8000, es2020: 0x30fe0000, es2021: 0x30fc0000, es2022: 0x30c00000, es2023: 0x30800000, es2024: 0x30800000, es2025: 0x0, esnext: 0x0 };
46
46
  function isPlainObject(value) {
47
47
  return value !== null && typeof value == "object" && !Array.isArray(value);
48
48
  }
@@ -343,7 +343,7 @@ async function resolveConfigValue(raw,env,absPath) {
343
343
  async function loadModuleDefault(absPath,kind,options) {
344
344
  const allowArray = options?.allowArray === true,ext = extname(absPath).toLowerCase();
345
345
  if (ext === ".json") {
346
- const raw = readFileOrThrowNotFound(absPath);
346
+ const raw = readFileOrThrowNotFound(absPath, kind);
347
347
  try {
348
348
  return JSON.parse(raw);
349
349
  } catch (err) {
@@ -368,7 +368,7 @@ async function loadModuleDefault(absPath,kind,options) {
368
368
  }
369
369
  async function loadTsModule(absPath,kind,allowArray) {
370
370
  init();
371
- const source = readFileOrThrowNotFound(absPath),parseFilename = absPath.endsWith(".cts") ? absPath.slice(0, -4) + ".ts" : absPath,result = transpile(source, { filename: parseFilename, format: "esm" });
371
+ const source = readFileOrThrowNotFound(absPath, kind),parseFilename = absPath.endsWith(".cts") ? absPath.slice(0, -4) + ".ts" : absPath,result = transpile(source, { filename: parseFilename, format: "esm" });
372
372
  if (result.errors) {
373
373
  throw new Error(`@zntc/core: ${kind} compile failed in ${absPath}\n${result.errors}`);
374
374
  }
@@ -406,12 +406,12 @@ async function importAndResolveDefault(absPath,options) {
406
406
  }
407
407
  return value;
408
408
  }
409
- function readFileOrThrowNotFound(absPath) {
409
+ function readFileOrThrowNotFound(absPath,kind) {
410
410
  try {
411
411
  return readFileSync$1(absPath, "utf8");
412
412
  } catch (err) {
413
413
  if (err.code === "ENOENT") {
414
- throw new Error(`@zntc/core: config file not found: ${absPath}`);
414
+ throw new Error(`@zntc/core: ${kind} file not found: ${absPath}`);
415
415
  }
416
416
  throw err;
417
417
  }
@@ -460,6 +460,7 @@ function mergeUserConfigs(base,mode) {
460
460
  }
461
461
  //#endregion
462
462
  //#region load-env.ts
463
+ var join$1 = require("node:path").join;
463
464
  var pathResolve$1 = require("node:path").resolve;
464
465
  function parseDotenvLine(line) {
465
466
  const trimmed = line.trim();
@@ -490,7 +491,7 @@ function parseDotenvFile(filePath) {
490
491
  function loadEnv(mode,envDir,prefixes=["VITE_", "ZNTC_"]) {
491
492
  const prefixList = Array.isArray(prefixes) ? prefixes : [prefixes],dir = pathResolve$1(envDir),files = [`.env`, `.env.local`, `.env.${mode}`, `.env.${mode}.local`],merged = {};
492
493
  for (const file of files) {
493
- Object.assign(merged, parseDotenvFile(`${dir}/${file}`));
494
+ Object.assign(merged, parseDotenvFile(join$1(dir, file)));
494
495
  }
495
496
  const filtered = {};
496
497
  for (const [key, value] of Object.entries(merged)) {
@@ -554,14 +555,14 @@ function warnUnknownKeys(config,known,options={}) {
554
555
  }
555
556
  return result;
556
557
  }
557
- const KNOWN_CONFIG_KEYS = ["entryPoints", "output", "outdir", "outfile", "outbase", "format", "platform", "target", "browserslist", "runtimePolyfills", "coreJs", "jsx", "jsxDev", "jsxFactory", "jsxFragment", "jsxImportSource", "jsxInJs", "jsxSideEffects", "minify", "minifyWhitespace", "minifyIdentifiers", "minifySyntax", "sourcemap", "sourcemapMode", "sourcemapDebugIds", "sourcesContent", "sourceRoot", "external", "alias", "define", "server", "loader", "conditions", "nodePaths", "moduleSpecifierMap", "resolveExtensions", "mainFields", "packagesExternal", "preserveSymlinks", "resolveSymlinkSiblings", "disableHierarchicalLookup", "splitting", "outputExports", "preserveModules", "preserveModulesRoot", "inlineDynamicImports", "manualChunks", "minChunkSize", "metafile", "treeShaking", "shimMissingExports", "keepNames", "drop", "dropConsole", "dropDebugger", "dropLabels", "banner", "footer", "intro", "outro", "inject", "pure", "legalComments", "entryNames", "chunkNames", "assetNames", "cssNames", "experimentalDecorators", "emitDecoratorMetadata", "useDefineForClassFields", "verbatimModuleSyntax", "tsconfigPath", "tsconfigRaw", "globalName", "globals", "publicPath", "charsetUtf8", "asciiOnly", "quotes", "compiler", "mf", "flow", "plugins", "logLevel", "logLimit", "lineLimit", "profile", "profileFormat", "profileLevel", "tokenizeFormat", "stopAfter", "ignoreAnnotations", "watchDelay", "jobs", "codegenTransform", "extends", "root", "projectRoot", "entry", "dev", "outDir", "bundler", "resolver", "transformer", "serializer", "symbolicator", "watchFolders"];
558
+ const KNOWN_CONFIG_KEYS = ["entryPoints", "output", "outdir", "outfile", "outbase", "format", "platform", "target", "rnVersion", "diskCache", "cacheDir", "browserslist", "runtimePolyfills", "coreJs", "jsx", "jsxDev", "jsxFactory", "jsxFragment", "jsxImportSource", "jsxInJs", "jsxSideEffects", "minify", "minifyWhitespace", "minifyIdentifiers", "minifySyntax", "sourcemap", "sourcemapMode", "sourcemapDebugIds", "sourcesContent", "sourceRoot", "external", "alias", "aliasExact", "define", "server", "loader", "conditions", "nodePaths", "moduleSpecifierMap", "resolveExtensions", "mainFields", "packagesExternal", "preserveSymlinks", "resolveSymlinkSiblings", "disableHierarchicalLookup", "splitting", "outputExports", "preserveModules", "preserveModulesRoot", "inlineDynamicImports", "manualChunks", "minChunkSize", "metafile", "treeShaking", "shimMissingExports", "keepNames", "drop", "dropConsole", "dropDebugger", "dropLabels", "banner", "footer", "intro", "outro", "inject", "pure", "legalComments", "entryNames", "chunkNames", "assetNames", "assetInlineLimit", "cssNames", "experimentalDecorators", "emitDecoratorMetadata", "useDefineForClassFields", "verbatimModuleSyntax", "tsconfigPath", "tsconfigRaw", "globalName", "globals", "publicPath", "charsetUtf8", "asciiOnly", "quotes", "compiler", "mf", "flow", "plugins", "logLevel", "logLimit", "lineLimit", "profile", "profileFormat", "profileLevel", "tokenizeFormat", "stopAfter", "ignoreAnnotations", "watchDelay", "jobs", "codegenTransform", "lazyCompilation", "lazyForceParse", "preserveSafePlugins", "extends", "root", "projectRoot", "entry", "dev", "outDir", "bundler", "resolver", "transformer", "serializer", "symbolicator", "watchFolders"];
558
559
  //#endregion
559
560
  //#region workspace.ts
560
561
  var existsSync$1 = require("node:fs").existsSync;
561
562
  var readdirSync = require("node:fs").readdirSync;
562
563
  var readFileSync$2 = require("node:fs").readFileSync;
563
564
  var basename = require("node:path").basename;
564
- var join$1 = require("node:path").join;
565
+ var join$2 = require("node:path").join;
565
566
  var pathResolve$2 = require("node:path").resolve;
566
567
  var CONFIG_EXT_PRIORITY_LOCAL = [".ts", ".mts", ".cts", ".mjs", ".js", ".cjs", ".json"];
567
568
  function defineWorkspace(input) {
@@ -570,7 +571,7 @@ function defineWorkspace(input) {
570
571
  var WORKSPACE_EXT_PRIORITY = CONFIG_EXT_PRIORITY_LOCAL;
571
572
  function findWorkspacePath(cwd) {
572
573
  for (const ext of WORKSPACE_EXT_PRIORITY) {
573
- const p = join$1(cwd, `zntc.workspace${ext}`);
574
+ const p = join$2(cwd, `zntc.workspace${ext}`);
574
575
  if (existsSync$1(p))return p;
575
576
  }
576
577
  return null;
@@ -601,8 +602,9 @@ async function loadWorkspace(filePath,env) {
601
602
  }
602
603
  function identifyWorkspaceEntries(entries,rootDir) {
603
604
  const seen = new Set(),out = [],push = (w) => {
604
- if (seen.has(w.cwd))return;
605
- seen.add(w.cwd);
605
+ const key = w.source === "inline" ? `inline:${w.name}` : w.cwd;
606
+ if (seen.has(key))return;
607
+ seen.add(key);
606
608
  out.push(w);
607
609
  };
608
610
  for (const entry of entries) {
@@ -652,7 +654,7 @@ function enumerateDirs(baseDir,namePattern) {
652
654
  if (!d.isDirectory())continue;
653
655
  if (d.name.startsWith("."))continue;
654
656
  if (d.name === "node_modules")continue;
655
- if (matcher(d.name))out.push(join$1(baseDir, d.name));
657
+ if (matcher(d.name))out.push(join$2(baseDir, d.name));
656
658
  }
657
659
  out.sort();
658
660
  return out;
@@ -663,7 +665,7 @@ function makeStarMatcher(pattern) {
663
665
  return (s) => re.test(s);
664
666
  }
665
667
  function detectPackageName(absDir) {
666
- const pkgPath = join$1(absDir, "package.json");
668
+ const pkgPath = join$2(absDir, "package.json");
667
669
  if (existsSync$1(pkgPath)) {
668
670
  try {
669
671
  const pkg = JSON.parse(readFileSync$2(pkgPath, "utf8"));
@@ -688,7 +690,7 @@ var createRequire$1 = require("module").createRequire;
688
690
  var existsSync$2 = require("fs").existsSync;
689
691
  var mkdirSync = require("fs").mkdirSync;
690
692
  var writeFileSync$1 = require("fs").writeFileSync;
691
- var join$2 = require("path").join;
693
+ var join$3 = require("path").join;
692
694
  var dirname$2 = require("path").dirname;
693
695
  var resolve$1 = require("path").resolve;
694
696
  var fileURLToPath = require("url").fileURLToPath;
@@ -723,9 +725,9 @@ function getPlatformPackage() {
723
725
  return match ? subPackageName(match) : null;
724
726
  }
725
727
  function findAddon() {
726
- const __dirname = dirname$2(fileURLToPath(require("url").pathToFileURL(__filename).href)),platformPkg = getPlatformPackage(),zigOut = join$2(__dirname, "../../zig-out/lib/zntc.node");
728
+ const __dirname = dirname$2(fileURLToPath(require("url").pathToFileURL(__filename).href)),platformPkg = getPlatformPackage(),zigOut = join$3(__dirname, "../../zig-out/lib/zntc.node");
727
729
  if (existsSync$2(zigOut))return zigOut;
728
- const zigOut2 = join$2(__dirname, "../../../zig-out/lib/zntc.node");
730
+ const zigOut2 = join$3(__dirname, "../../../zig-out/lib/zntc.node");
729
731
  if (existsSync$2(zigOut2))return zigOut2;
730
732
  if (platformPkg) {
731
733
  try {
@@ -734,9 +736,9 @@ function findAddon() {
734
736
  } catch {
735
737
  }
736
738
  }
737
- const local = join$2(__dirname, "zntc.node");
739
+ const local = join$3(__dirname, "zntc.node");
738
740
  if (existsSync$2(local))return local;
739
- const parent = join$2(__dirname, "../zntc.node");
741
+ const parent = join$3(__dirname, "../zntc.node");
740
742
  if (existsSync$2(parent))return parent;
741
743
  const expected = platformPkg ? ` (expected sub-package: ${platformPkg})` : "";
742
744
  throw new Error(`@zntc/core: native binary not found for ${process.platform}-${process.arch}${expected}. ` + `Supported: ${formatSupportedPlatforms()}. ` + "For development run `zig build napi`. " + "If your platform should be supported, please open an issue.");
@@ -795,13 +797,13 @@ var TsconfigCache = class {
795
797
  }
796
798
  };
797
799
  function transpile(source,options={}) {
798
- if (!source)throw new Error("@zntc/core: empty source");
800
+ if (typeof source != "string")throw new Error("@zntc/core: source must be a string");
799
801
  validateTsConfigRaw(options.tsconfigRaw);
800
802
  const optionsJson = buildOptionsJson(options, resolveUnsupported(options));
801
803
  return ensureNative().transpile(source, options.filename ?? "input.js", optionsJson, options.cache ? TsconfigCache._unwrap(options.cache) : undefined);
802
804
  }
803
805
  function tokenize(source,options={}) {
804
- if (!source)throw new Error("@zntc/core: empty source");
806
+ if (typeof source != "string")throw new Error("@zntc/core: source must be a string");
805
807
  return ensureNative().tokenize(source, options.filename ?? "input.js");
806
808
  }
807
809
  function configureProfile(profile,level) {
@@ -903,13 +905,13 @@ function collectPluginRegistry(plugins) {
903
905
  const registry = { hooks: { resolveId: [], load: [], transform: [], renderChunk: [], resolveContext: [] }, generateBundleCallbacks: [], buildStartCallbacks: [], buildEndCallbacks: [], closeBundleCallbacks: [], astFunctionHooks: [], lifecycleFailures: [], pluginWarnings: [], contexts: new Map() };
904
906
  for (const plugin of plugins) {
905
907
  const build = { onResolve(opts,cb) {
906
- registry.hooks.resolveId.push({ pluginName: plugin.name, filter: opts.filter, callback: cb });
908
+ registry.hooks.resolveId.push({ pluginName: plugin.name, filter: stripStatefulFilterFlags(opts.filter), callback: cb });
907
909
  }, onLoad(opts,cb) {
908
- registry.hooks.load.push({ pluginName: plugin.name, filter: opts.filter, callback: cb });
910
+ registry.hooks.load.push({ pluginName: plugin.name, filter: stripStatefulFilterFlags(opts.filter), callback: cb });
909
911
  }, onTransform(opts,cb) {
910
- registry.hooks.transform.push({ pluginName: plugin.name, filter: opts.filter, callback: cb });
912
+ registry.hooks.transform.push({ pluginName: plugin.name, filter: stripStatefulFilterFlags(opts.filter), callback: cb });
911
913
  }, onRenderChunk(opts,cb) {
912
- registry.hooks.renderChunk.push({ pluginName: plugin.name, filter: opts.filter, callback: cb });
914
+ registry.hooks.renderChunk.push({ pluginName: plugin.name, filter: stripStatefulFilterFlags(opts.filter), callback: cb });
913
915
  }, onGenerateBundle(cb) {
914
916
  registry.generateBundleCallbacks.push({ pluginName: plugin.name, callback: cb });
915
917
  }, onBuildStart(cb) {
@@ -919,9 +921,9 @@ function collectPluginRegistry(plugins) {
919
921
  }, onCloseBundle(cb) {
920
922
  registry.closeBundleCallbacks.push({ pluginName: plugin.name, callback: cb });
921
923
  }, onAstFunction(opts,cb) {
922
- registry.astFunctionHooks.push({ pluginName: plugin.name, filter: opts.filter, callback: cb });
924
+ registry.astFunctionHooks.push({ pluginName: plugin.name, filter: stripStatefulFilterFlags(opts.filter), callback: cb });
923
925
  }, onResolveContext(opts,cb) {
924
- registry.hooks.resolveContext.push({ pluginName: plugin.name, filter: opts.filter, callback: cb });
926
+ registry.hooks.resolveContext.push({ pluginName: plugin.name, filter: stripStatefulFilterFlags(opts.filter), callback: cb });
925
927
  } };
926
928
  plugin.setup(build);
927
929
  }
@@ -962,6 +964,10 @@ function getPluginContext(reg,pluginName,getModuleInfo,resolve,emitFile,getFileN
962
964
  slot.__getFileName = getFileName;
963
965
  return ctx;
964
966
  }
967
+ function stripStatefulFilterFlags(re) {
968
+ if (!re.global && !re.sticky)return re;
969
+ return new RegExp(re.source, re.flags.replace(/[gy]/g, ""));
970
+ }
965
971
  function* dispatchHook(reg,hookName,arg1,arg2,getModuleInfo,resolve,emitFile,getFileName) {
966
972
  if (hookName === "astFunction") {
967
973
  if (reg.astFunctionHooks.length === 0)return null;
@@ -1177,7 +1183,17 @@ function withDefaultAppBuildDefines(options) {
1177
1183
  return define;
1178
1184
  }
1179
1185
  function prepareNapiOptions(options) {
1180
- const napiOptions = { ...options },define = withDefaultBuildDefines(options);
1186
+ const napiOptions = { ...options };
1187
+ if (typeof options.rnVersion == "string") {
1188
+ const m = /^[ \t]*(?:>=|<=|==|>|<)?[ \t]*(\d+)\.(\d+)(?:\.\d+)*[ \t]*$/.exec(options.rnVersion);
1189
+ if (!m || Number(m[1]) > 65535 || Number(m[2]) > 65535) {
1190
+ throw new Error(`Invalid rnVersion '${options.rnVersion}' (expected e.g. '0.74', '>=0.74', '<=0.84', '==0.76')`);
1191
+ }
1192
+ if (options.platform === "node" || options.platform === "neutral") {
1193
+ throw new Error(`rnVersion conflicts with platform: '${options.platform}' (rnVersion implies react-native)`);
1194
+ }
1195
+ }
1196
+ const define = withDefaultBuildDefines(options);
1181
1197
  if (define)napiOptions.define = define;
1182
1198
  delete napiOptions.write;
1183
1199
  delete napiOptions.outdir;
@@ -1283,6 +1299,13 @@ function postProcessCssOutputs(result,options) {
1283
1299
  }
1284
1300
  }
1285
1301
  }
1302
+ function resolveOutputPath(filePath,opts) {
1303
+ const { outfileResolved:outfileResolved, outdir:outdir } = opts;
1304
+ if (outfileResolved && filePath === "bundle.js")return outfileResolved;
1305
+ if (outfileResolved && filePath === "bundle.js.map")return `${outfileResolved}.map`;
1306
+ if (outdir)return join$3(resolve$1(outdir), filePath);
1307
+ return resolve$1(filePath);
1308
+ }
1286
1309
  function writeOutputFiles(result,options) {
1287
1310
  const shouldWrite = options.write ?? (options.outdir != null || options.outfile != null);
1288
1311
  if (!shouldWrite)return;
@@ -1296,17 +1319,7 @@ function writeOutputFiles(result,options) {
1296
1319
  }
1297
1320
  const createdDirs = new Set(),outfileResolved = options.outfile ? resolve$1(options.outfile) : null;
1298
1321
  for (const file of result.outputFiles) {
1299
- let outPath;
1300
- if (outfileResolved && file.path === "bundle.js") {
1301
- outPath = outfileResolved;
1302
- } else if (outfileResolved && file.path.endsWith(".map")) {
1303
- outPath = outfileResolved + ".map";
1304
- } else if (options.outdir) {
1305
- outPath = join$2(resolve$1(options.outdir), file.path);
1306
- } else {
1307
- outPath = resolve$1(file.path);
1308
- }
1309
- const dir = dirname$2(outPath);
1322
+ const outPath = resolveOutputPath(file.path, { outfileResolved, outdir: options.outdir }),dir = dirname$2(outPath);
1310
1323
  if (!createdDirs.has(dir)) {
1311
1324
  mkdirSync(dir, { recursive: true });
1312
1325
  createdDirs.add(dir);
@@ -1782,6 +1795,7 @@ exports.tlsSelfCheck = tlsSelfCheck;
1782
1795
  exports.startDevServer = startDevServer;
1783
1796
  exports.stopDevServer = stopDevServer;
1784
1797
  exports.getDevServerPort = getDevServerPort;
1798
+ exports.resolveOutputPath = resolveOutputPath;
1785
1799
  exports.build = build;
1786
1800
  exports.buildSync = buildSync;
1787
1801
  exports.BuildInstance = BuildInstance;
package/dist/index.js CHANGED
@@ -818,7 +818,7 @@ var require_node = __commonJS((exports, module) => {
818
818
  // index.ts
819
819
  import { createRequire as createRequire3 } from "module";
820
820
  import { existsSync as existsSync3, mkdirSync, writeFileSync as writeFileSync2 } from "fs";
821
- import { join as join3, dirname as dirname3, resolve as resolve2 } from "path";
821
+ import { join as join4, dirname as dirname3, resolve as resolve2 } from "path";
822
822
  import { fileURLToPath } from "url";
823
823
 
824
824
  // src/platforms.ts
@@ -935,7 +935,10 @@ var FEATURES = [
935
935
  "regex_sticky",
936
936
  "regex_dotall",
937
937
  "regex_named_groups",
938
- "unicode_brace_escape"
938
+ "unicode_brace_escape",
939
+ "regex_duplicate_named_groups",
940
+ "regex_modifiers",
941
+ "regex_lookbehind"
939
942
  ];
940
943
  var SUPPORT = {
941
944
  arrow: {
@@ -1146,7 +1149,34 @@ var SUPPORT = {
1146
1149
  ios: [13, 4],
1147
1150
  hermes: [0, 7]
1148
1151
  },
1149
- using: {}
1152
+ using: {},
1153
+ regex_duplicate_named_groups: {
1154
+ chrome: [125, 0],
1155
+ edge: [125, 0],
1156
+ firefox: [129, 0],
1157
+ safari: [17, 4],
1158
+ ios: [17, 4],
1159
+ node: [23, 0],
1160
+ deno: [1, 44]
1161
+ },
1162
+ regex_modifiers: {
1163
+ chrome: [125, 0],
1164
+ edge: [125, 0],
1165
+ firefox: [132, 0],
1166
+ safari: [26, 0],
1167
+ ios: [26, 0],
1168
+ node: [23, 0],
1169
+ deno: [1, 44]
1170
+ },
1171
+ regex_lookbehind: {
1172
+ chrome: [62, 0],
1173
+ edge: [79, 0],
1174
+ firefox: [78, 0],
1175
+ safari: [16, 4],
1176
+ ios: [16, 4],
1177
+ node: [8, 10],
1178
+ deno: [1, 0]
1179
+ }
1150
1180
  };
1151
1181
  function verGte(a, b) {
1152
1182
  if (a[0] !== b[0])
@@ -1177,17 +1207,17 @@ function computeUnsupportedFromEngines(engines) {
1177
1207
  }
1178
1208
  // ../shared/index.ts
1179
1209
  var ES_TARGET_BITS = {
1180
- es5: 268435455,
1181
- es2015: 117438464,
1182
- es2016: 117436416,
1183
- es2017: 117432320,
1184
- es2018: 16760832,
1185
- es2019: 16744448,
1186
- es2020: 16646144,
1187
- es2021: 16515072,
1188
- es2022: 12582912,
1189
- es2023: 8388608,
1190
- es2024: 8388608,
1210
+ es5: 2147483647,
1211
+ es2015: 1996486656,
1212
+ es2016: 1996484608,
1213
+ es2017: 1996480512,
1214
+ es2018: 822067200,
1215
+ es2019: 822050816,
1216
+ es2020: 821952512,
1217
+ es2021: 821821440,
1218
+ es2022: 817889280,
1219
+ es2023: 813694976,
1220
+ es2024: 813694976,
1191
1221
  es2025: 0,
1192
1222
  esnext: 0
1193
1223
  };
@@ -1928,7 +1958,7 @@ async function loadModuleDefault(absPath, kind, options) {
1928
1958
  const allowArray = options?.allowArray === true;
1929
1959
  const ext = extname(absPath).toLowerCase();
1930
1960
  if (ext === ".json") {
1931
- const raw = readFileOrThrowNotFound(absPath);
1961
+ const raw = readFileOrThrowNotFound(absPath, kind);
1932
1962
  try {
1933
1963
  return JSON.parse(raw);
1934
1964
  } catch (err) {
@@ -1953,7 +1983,7 @@ async function loadModuleDefault(absPath, kind, options) {
1953
1983
  }
1954
1984
  async function loadTsModule(absPath, kind, allowArray) {
1955
1985
  init();
1956
- const source = readFileOrThrowNotFound(absPath);
1986
+ const source = readFileOrThrowNotFound(absPath, kind);
1957
1987
  const parseFilename = absPath.endsWith(".cts") ? absPath.slice(0, -4) + ".ts" : absPath;
1958
1988
  const result = transpile(source, {
1959
1989
  filename: parseFilename,
@@ -2000,12 +2030,12 @@ async function importAndResolveDefault(absPath, options) {
2000
2030
  }
2001
2031
  return value;
2002
2032
  }
2003
- function readFileOrThrowNotFound(absPath) {
2033
+ function readFileOrThrowNotFound(absPath, kind) {
2004
2034
  try {
2005
2035
  return readFileSync2(absPath, "utf8");
2006
2036
  } catch (err) {
2007
2037
  if (err.code === "ENOENT") {
2008
- throw new Error(`@zntc/core: config file not found: ${absPath}`);
2038
+ throw new Error(`@zntc/core: ${kind} file not found: ${absPath}`);
2009
2039
  }
2010
2040
  throw err;
2011
2041
  }
@@ -2061,7 +2091,7 @@ function mergeUserConfigs(base, mode) {
2061
2091
  return merged;
2062
2092
  }
2063
2093
  // src/load-env.ts
2064
- import { resolve as pathResolve2 } from "node:path";
2094
+ import { join as join2, resolve as pathResolve2 } from "node:path";
2065
2095
  function parseDotenvLine(line) {
2066
2096
  const trimmed = line.trim();
2067
2097
  if (!trimmed || trimmed.startsWith("#"))
@@ -2099,7 +2129,7 @@ function loadEnv(mode, envDir, prefixes = ["VITE_", "ZNTC_"]) {
2099
2129
  const files = [`.env`, `.env.local`, `.env.${mode}`, `.env.${mode}.local`];
2100
2130
  const merged = {};
2101
2131
  for (const file of files) {
2102
- Object.assign(merged, parseDotenvFile(`${dir}/${file}`));
2132
+ Object.assign(merged, parseDotenvFile(join2(dir, file)));
2103
2133
  }
2104
2134
  const filtered = {};
2105
2135
  for (const [key, value] of Object.entries(merged)) {
@@ -2190,6 +2220,9 @@ var KNOWN_CONFIG_KEYS = [
2190
2220
  "format",
2191
2221
  "platform",
2192
2222
  "target",
2223
+ "rnVersion",
2224
+ "diskCache",
2225
+ "cacheDir",
2193
2226
  "browserslist",
2194
2227
  "runtimePolyfills",
2195
2228
  "coreJs",
@@ -2211,6 +2244,7 @@ var KNOWN_CONFIG_KEYS = [
2211
2244
  "sourceRoot",
2212
2245
  "external",
2213
2246
  "alias",
2247
+ "aliasExact",
2214
2248
  "define",
2215
2249
  "server",
2216
2250
  "loader",
@@ -2248,6 +2282,7 @@ var KNOWN_CONFIG_KEYS = [
2248
2282
  "entryNames",
2249
2283
  "chunkNames",
2250
2284
  "assetNames",
2285
+ "assetInlineLimit",
2251
2286
  "cssNames",
2252
2287
  "experimentalDecorators",
2253
2288
  "emitDecoratorMetadata",
@@ -2277,6 +2312,9 @@ var KNOWN_CONFIG_KEYS = [
2277
2312
  "watchDelay",
2278
2313
  "jobs",
2279
2314
  "codegenTransform",
2315
+ "lazyCompilation",
2316
+ "lazyForceParse",
2317
+ "preserveSafePlugins",
2280
2318
  "extends",
2281
2319
  "root",
2282
2320
  "projectRoot",
@@ -2292,7 +2330,7 @@ var KNOWN_CONFIG_KEYS = [
2292
2330
  ];
2293
2331
  // src/workspace.ts
2294
2332
  import { existsSync as existsSync2, readdirSync, readFileSync as readFileSync3 } from "node:fs";
2295
- import { basename, join as join2, resolve as pathResolve3 } from "node:path";
2333
+ import { basename, join as join3, resolve as pathResolve3 } from "node:path";
2296
2334
  var CONFIG_EXT_PRIORITY_LOCAL = [".ts", ".mts", ".cts", ".mjs", ".js", ".cjs", ".json"];
2297
2335
  function defineWorkspace(input) {
2298
2336
  return input;
@@ -2300,7 +2338,7 @@ function defineWorkspace(input) {
2300
2338
  var WORKSPACE_EXT_PRIORITY = CONFIG_EXT_PRIORITY_LOCAL;
2301
2339
  function findWorkspacePath(cwd) {
2302
2340
  for (const ext of WORKSPACE_EXT_PRIORITY) {
2303
- const p = join2(cwd, `zntc.workspace${ext}`);
2341
+ const p = join3(cwd, `zntc.workspace${ext}`);
2304
2342
  if (existsSync2(p))
2305
2343
  return p;
2306
2344
  }
@@ -2336,9 +2374,10 @@ function identifyWorkspaceEntries(entries, rootDir) {
2336
2374
  const seen = new Set;
2337
2375
  const out = [];
2338
2376
  const push = (w) => {
2339
- if (seen.has(w.cwd))
2377
+ const key = w.source === "inline" ? `inline:${w.name}` : w.cwd;
2378
+ if (seen.has(key))
2340
2379
  return;
2341
- seen.add(w.cwd);
2380
+ seen.add(key);
2342
2381
  out.push(w);
2343
2382
  };
2344
2383
  for (const entry of entries) {
@@ -2401,7 +2440,7 @@ function enumerateDirs(baseDir, namePattern) {
2401
2440
  if (d.name === "node_modules")
2402
2441
  continue;
2403
2442
  if (matcher(d.name))
2404
- out.push(join2(baseDir, d.name));
2443
+ out.push(join3(baseDir, d.name));
2405
2444
  }
2406
2445
  out.sort();
2407
2446
  return out;
@@ -2414,7 +2453,7 @@ function makeStarMatcher(pattern) {
2414
2453
  return (s) => re.test(s);
2415
2454
  }
2416
2455
  function detectPackageName(absDir) {
2417
- const pkgPath = join2(absDir, "package.json");
2456
+ const pkgPath = join3(absDir, "package.json");
2418
2457
  if (existsSync2(pkgPath)) {
2419
2458
  try {
2420
2459
  const pkg = JSON.parse(readFileSync3(pkgPath, "utf8"));
@@ -2477,10 +2516,10 @@ function getPlatformPackage() {
2477
2516
  function findAddon() {
2478
2517
  const __dirname2 = dirname3(fileURLToPath(import.meta.url));
2479
2518
  const platformPkg = getPlatformPackage();
2480
- const zigOut = join3(__dirname2, "../../zig-out/lib/zntc.node");
2519
+ const zigOut = join4(__dirname2, "../../zig-out/lib/zntc.node");
2481
2520
  if (existsSync3(zigOut))
2482
2521
  return zigOut;
2483
- const zigOut2 = join3(__dirname2, "../../../zig-out/lib/zntc.node");
2522
+ const zigOut2 = join4(__dirname2, "../../../zig-out/lib/zntc.node");
2484
2523
  if (existsSync3(zigOut2))
2485
2524
  return zigOut2;
2486
2525
  if (platformPkg) {
@@ -2489,10 +2528,10 @@ function findAddon() {
2489
2528
  return nodeRequire.resolve(platformPkg);
2490
2529
  } catch {}
2491
2530
  }
2492
- const local = join3(__dirname2, "zntc.node");
2531
+ const local = join4(__dirname2, "zntc.node");
2493
2532
  if (existsSync3(local))
2494
2533
  return local;
2495
- const parent = join3(__dirname2, "../zntc.node");
2534
+ const parent = join4(__dirname2, "../zntc.node");
2496
2535
  if (existsSync3(parent))
2497
2536
  return parent;
2498
2537
  const expected = platformPkg ? ` (expected sub-package: ${platformPkg})` : "";
@@ -2557,15 +2596,15 @@ class TsconfigCache {
2557
2596
  }
2558
2597
  }
2559
2598
  function transpile(source, options = {}) {
2560
- if (!source)
2561
- throw new Error("@zntc/core: empty source");
2599
+ if (typeof source !== "string")
2600
+ throw new Error("@zntc/core: source must be a string");
2562
2601
  validateTsConfigRaw(options.tsconfigRaw);
2563
2602
  const optionsJson = buildOptionsJson(options, resolveUnsupported(options));
2564
2603
  return ensureNative().transpile(source, options.filename ?? "input.js", optionsJson, options.cache ? TsconfigCache._unwrap(options.cache) : undefined);
2565
2604
  }
2566
2605
  function tokenize(source, options = {}) {
2567
- if (!source)
2568
- throw new Error("@zntc/core: empty source");
2606
+ if (typeof source !== "string")
2607
+ throw new Error("@zntc/core: source must be a string");
2569
2608
  return ensureNative().tokenize(source, options.filename ?? "input.js");
2570
2609
  }
2571
2610
  function configureProfile(profile, level) {
@@ -2718,24 +2757,28 @@ function collectPluginRegistry(plugins) {
2718
2757
  onResolve(opts, cb) {
2719
2758
  registry.hooks.resolveId.push({
2720
2759
  pluginName: plugin.name,
2721
- filter: opts.filter,
2760
+ filter: stripStatefulFilterFlags(opts.filter),
2722
2761
  callback: cb
2723
2762
  });
2724
2763
  },
2725
2764
  onLoad(opts, cb) {
2726
- registry.hooks.load.push({ pluginName: plugin.name, filter: opts.filter, callback: cb });
2765
+ registry.hooks.load.push({
2766
+ pluginName: plugin.name,
2767
+ filter: stripStatefulFilterFlags(opts.filter),
2768
+ callback: cb
2769
+ });
2727
2770
  },
2728
2771
  onTransform(opts, cb) {
2729
2772
  registry.hooks.transform.push({
2730
2773
  pluginName: plugin.name,
2731
- filter: opts.filter,
2774
+ filter: stripStatefulFilterFlags(opts.filter),
2732
2775
  callback: cb
2733
2776
  });
2734
2777
  },
2735
2778
  onRenderChunk(opts, cb) {
2736
2779
  registry.hooks.renderChunk.push({
2737
2780
  pluginName: plugin.name,
2738
- filter: opts.filter,
2781
+ filter: stripStatefulFilterFlags(opts.filter),
2739
2782
  callback: cb
2740
2783
  });
2741
2784
  },
@@ -2754,14 +2797,14 @@ function collectPluginRegistry(plugins) {
2754
2797
  onAstFunction(opts, cb) {
2755
2798
  registry.astFunctionHooks.push({
2756
2799
  pluginName: plugin.name,
2757
- filter: opts.filter,
2800
+ filter: stripStatefulFilterFlags(opts.filter),
2758
2801
  callback: cb
2759
2802
  });
2760
2803
  },
2761
2804
  onResolveContext(opts, cb) {
2762
2805
  registry.hooks.resolveContext.push({
2763
2806
  pluginName: plugin.name,
2764
- filter: opts.filter,
2807
+ filter: stripStatefulFilterFlags(opts.filter),
2765
2808
  callback: cb
2766
2809
  });
2767
2810
  }
@@ -2816,6 +2859,11 @@ function getPluginContext(reg, pluginName, getModuleInfo, resolve3, emitFile, ge
2816
2859
  slot.__getFileName = getFileName;
2817
2860
  return ctx;
2818
2861
  }
2862
+ function stripStatefulFilterFlags(re) {
2863
+ if (!re.global && !re.sticky)
2864
+ return re;
2865
+ return new RegExp(re.source, re.flags.replace(/[gy]/g, ""));
2866
+ }
2819
2867
  function* dispatchHook(reg, hookName, arg1, arg2, getModuleInfo, resolve3, emitFile, getFileName) {
2820
2868
  if (hookName === "astFunction") {
2821
2869
  if (reg.astFunctionHooks.length === 0)
@@ -3095,6 +3143,15 @@ function withDefaultAppBuildDefines(options) {
3095
3143
  }
3096
3144
  function prepareNapiOptions(options) {
3097
3145
  const napiOptions = { ...options };
3146
+ if (typeof options.rnVersion === "string") {
3147
+ const m = /^[ \t]*(?:>=|<=|==|>|<)?[ \t]*(\d+)\.(\d+)(?:\.\d+)*[ \t]*$/.exec(options.rnVersion);
3148
+ if (!m || Number(m[1]) > 65535 || Number(m[2]) > 65535) {
3149
+ throw new Error(`Invalid rnVersion '${options.rnVersion}' (expected e.g. '0.74', '>=0.74', '<=0.84', '==0.76')`);
3150
+ }
3151
+ if (options.platform === "node" || options.platform === "neutral") {
3152
+ throw new Error(`rnVersion conflicts with platform: '${options.platform}' (rnVersion implies react-native)`);
3153
+ }
3154
+ }
3098
3155
  const define = withDefaultBuildDefines(options);
3099
3156
  if (define)
3100
3157
  napiOptions.define = define;
@@ -3236,6 +3293,16 @@ function postProcessCssOutputs(result, options) {
3236
3293
  } catch {}
3237
3294
  }
3238
3295
  }
3296
+ function resolveOutputPath(filePath, opts) {
3297
+ const { outfileResolved, outdir } = opts;
3298
+ if (outfileResolved && filePath === "bundle.js")
3299
+ return outfileResolved;
3300
+ if (outfileResolved && filePath === "bundle.js.map")
3301
+ return `${outfileResolved}.map`;
3302
+ if (outdir)
3303
+ return join4(resolve2(outdir), filePath);
3304
+ return resolve2(filePath);
3305
+ }
3239
3306
  function writeOutputFiles(result, options) {
3240
3307
  const shouldWrite = options.write ?? (options.outdir != null || options.outfile != null);
3241
3308
  if (!shouldWrite)
@@ -3251,16 +3318,7 @@ function writeOutputFiles(result, options) {
3251
3318
  const createdDirs = new Set;
3252
3319
  const outfileResolved = options.outfile ? resolve2(options.outfile) : null;
3253
3320
  for (const file of result.outputFiles) {
3254
- let outPath;
3255
- if (outfileResolved && file.path === "bundle.js") {
3256
- outPath = outfileResolved;
3257
- } else if (outfileResolved && file.path.endsWith(".map")) {
3258
- outPath = outfileResolved + ".map";
3259
- } else if (options.outdir) {
3260
- outPath = join3(resolve2(options.outdir), file.path);
3261
- } else {
3262
- outPath = resolve2(file.path);
3263
- }
3321
+ const outPath = resolveOutputPath(file.path, { outfileResolved, outdir: options.outdir });
3264
3322
  const dir = dirname3(outPath);
3265
3323
  if (!createdDirs.has(dir)) {
3266
3324
  mkdirSync(dir, { recursive: true });
@@ -3822,6 +3880,7 @@ export {
3822
3880
  suggestKey,
3823
3881
  stopDevServer,
3824
3882
  startDevServer,
3883
+ resolveOutputPath,
3825
3884
  profileReport,
3826
3885
  prepareAppDevSync,
3827
3886
  mergeUserConfigs,
@@ -11,7 +11,7 @@
11
11
  */
12
12
  export type Engine = 'chrome' | 'firefox' | 'safari' | 'edge' | 'node' | 'deno' | 'ios' | 'opera' | 'hermes';
13
13
  /** compat.zig의 Feature enum과 동일 순서. bit 위치 = 배열 인덱스. */
14
- export declare const FEATURES: readonly ["arrow", "class", "template_literal", "destructuring", "for_of", "spread", "object_extensions", "default_params", "block_scoping", "generator", "new_target", "exponentiation", "async_await", "object_spread", "optional_catch_binding", "nullish_coalescing", "optional_chaining", "logical_assignment", "class_static_block", "class_private_method", "class_private_field", "top_level_await", "hashbang", "using", "regex_sticky", "regex_dotall", "regex_named_groups", "unicode_brace_escape"];
14
+ export declare const FEATURES: readonly ["arrow", "class", "template_literal", "destructuring", "for_of", "spread", "object_extensions", "default_params", "block_scoping", "generator", "new_target", "exponentiation", "async_await", "object_spread", "optional_catch_binding", "nullish_coalescing", "optional_chaining", "logical_assignment", "class_static_block", "class_private_method", "class_private_field", "top_level_await", "hashbang", "using", "regex_sticky", "regex_dotall", "regex_named_groups", "unicode_brace_escape", "regex_duplicate_named_groups", "regex_modifiers", "regex_lookbehind"];
15
15
  export type Feature = (typeof FEATURES)[number];
16
16
  /**
17
17
  * feature × engine → 최소 지원 버전 [major, minor].
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zntc/core",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "ZNTC native transpiler & compiler binding",
5
5
  "keywords": [
6
6
  "bundler",
@@ -76,15 +76,15 @@
76
76
  "@zntc/test-helpers": "0.0.0"
77
77
  },
78
78
  "optionalDependencies": {
79
- "@zntc/core-darwin-arm64": "0.1.2",
80
- "@zntc/core-darwin-x64": "0.1.2",
81
- "@zntc/core-linux-arm64-gnu": "0.1.2",
82
- "@zntc/core-linux-arm64-musl": "0.1.2",
83
- "@zntc/core-linux-x64-gnu": "0.1.2",
84
- "@zntc/core-linux-x64-musl": "0.1.2",
85
- "@zntc/core-win32-arm64-msvc": "0.1.2",
86
- "@zntc/core-win32-ia32-msvc": "0.1.2",
87
- "@zntc/core-win32-x64-msvc": "0.1.2",
79
+ "@zntc/core-darwin-arm64": "0.1.3",
80
+ "@zntc/core-darwin-x64": "0.1.3",
81
+ "@zntc/core-linux-arm64-gnu": "0.1.3",
82
+ "@zntc/core-linux-arm64-musl": "0.1.3",
83
+ "@zntc/core-linux-x64-gnu": "0.1.3",
84
+ "@zntc/core-linux-x64-musl": "0.1.3",
85
+ "@zntc/core-win32-arm64-msvc": "0.1.3",
86
+ "@zntc/core-win32-ia32-msvc": "0.1.3",
87
+ "@zntc/core-win32-x64-msvc": "0.1.3",
88
88
  "browserslist": "^4.24.0",
89
89
  "core-js": "^3.49.0",
90
90
  "core-js-compat": "^3.49.0",