tsnv 0.0.0-dev.20260119180902 → 0.0.0-dev.20260201114010

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
@@ -2,7 +2,9 @@
2
2
 
3
3
  # tsnv
4
4
 
5
- Modern bundler for React Native libraries - fast, platform-aware, zero-config<br>
5
+ <img alt="preview" src="./preview.png">
6
+
7
+ Modern build toolkit for React Native libraries<br>
6
8
  (powered by [Rolldown](https://rolldown.rs))
7
9
 
8
10
  </div>
@@ -122,8 +124,7 @@ dist/
122
124
  ├── greeting.ios.js
123
125
  └── types/
124
126
  ├── index.d.ts
125
- ├── greeting.android.d.ts
126
- └── greeting.ios.d.ts
127
+ └── greeting.d.ts
127
128
  ```
128
129
 
129
130
  ### CommonJS only (`format: 'cjs'`)
@@ -135,8 +136,7 @@ dist/
135
136
  ├── greeting.ios.js
136
137
  └── types/
137
138
  ├── index.d.ts
138
- ├── greeting.android.d.ts
139
- └── greeting.ios.d.ts
139
+ └── greeting.d.ts
140
140
  ```
141
141
 
142
142
  ### Dual format (`format: ['esm', 'cjs']`)
@@ -153,8 +153,7 @@ dist/
153
153
  │ └── greeting.ios.js
154
154
  └── types/
155
155
  ├── index.d.ts
156
- ├── greeting.android.d.ts
157
- └── greeting.ios.d.ts
156
+ └── greeting.d.ts
158
157
  ```
159
158
 
160
159
  ## License
package/dist/config.d.cts CHANGED
@@ -1,3 +1,4 @@
1
+ import { TsConfigJson } from "get-tsconfig";
1
2
  import { OutputOptions } from "rolldown";
2
3
 
3
4
  //#region src/types.d.ts
@@ -6,88 +7,103 @@ type Format = 'esm' | 'cjs';
6
7
  //#region src/config/types.d.ts
7
8
  interface Config {
8
9
  /**
9
- * Defaults to `'src'`
10
- */
10
+ * Defaults to `'src'`
11
+ */
11
12
  source?: string;
12
13
  /**
13
- * The directory where output files will be written.
14
- *
15
- * Defaults to `'dist'`
16
- */
14
+ * The directory where output files will be written.
15
+ *
16
+ * Defaults to `'dist'`
17
+ */
17
18
  outDir?: string;
18
19
  /**
19
- * Files to exclude from the build.
20
- *
21
- * Defaults to `/__(?:tests?|fixtures?|mocks?)__/`
22
- */
20
+ * Files to exclude from the build.
21
+ *
22
+ * Defaults to `/__(?:tests?|fixtures?|mocks?)__/`
23
+ */
23
24
  exclude?: RegExp;
24
25
  /**
25
- * Expected format of generated code.
26
- *
27
- * Defaults to `'esm'`
28
- */
26
+ * Expected format of generated code.
27
+ *
28
+ * Defaults to `'esm'`
29
+ */
29
30
  format?: Format | Format[];
30
31
  /**
31
- * Specifiers to resolve platform specific modules.
32
- *
33
- * Defaults to `['android', 'ios', 'native']`
34
- */
32
+ * Specifiers to resolve platform specific modules.
33
+ *
34
+ * Defaults to `['android', 'ios', 'native']`
35
+ */
35
36
  specifiers?: string[];
36
37
  /**
37
- * Source files extensions.
38
- *
39
- * Defaults to `['ts', 'tsx', 'js', 'jsx', 'json']`
40
- */
38
+ * Source files extensions.
39
+ *
40
+ * Defaults to `['ts', 'tsx', 'js', 'jsx', 'json']`
41
+ */
41
42
  sourceExtensions?: string[];
42
43
  /**
43
- * Asset files extensions.
44
- *
45
- * Default to following extensions: [Metro's default asset extensions](https://github.com/facebook/metro/blob/v0.83.3/packages/metro-config/src/defaults/defaults.js)
46
- */
44
+ * Asset files extensions.
45
+ *
46
+ * Default to following extensions: [Metro's default asset extensions](https://github.com/facebook/metro/blob/v0.83.3/packages/metro-config/src/defaults/defaults.js)
47
+ */
47
48
  assetExtensions?: string[];
48
49
  /**
49
- * Enables generation of TypeScript declaration files (.d.ts).
50
- *
51
- * Defaults to `true`
52
- */
50
+ * Enables generation of TypeScript declaration files (.d.ts).
51
+ *
52
+ * Defaults to `true`
53
+ */
53
54
  dts?: boolean;
54
55
  /**
55
- * Generate source map files.
56
- */
56
+ * Generate source map files.
57
+ */
57
58
  sourcemap?: OutputOptions['sourcemap'];
58
59
  /**
59
- * Code to prepend to the beginning of each output chunk.
60
- */
60
+ * Code to prepend to the beginning of each output chunk.
61
+ */
61
62
  banner?: OutputOptions['banner'];
62
63
  /**
63
- * Code to append to the end of each output chunk.
64
- */
64
+ * Code to append to the end of each output chunk.
65
+ */
65
66
  footer?: OutputOptions['footer'];
66
67
  /**
67
- * Code to prepend inside the wrapper function (after banner, before actual code).
68
- */
68
+ * Code to prepend inside the wrapper function (after banner, before actual code).
69
+ */
69
70
  intro?: OutputOptions['intro'];
70
71
  /**
71
- * Code to append inside the wrapper function (after actual code, before footer).
72
- */
72
+ * Code to append inside the wrapper function (after actual code, before footer).
73
+ */
73
74
  outro?: OutputOptions['outro'];
74
75
  /**
75
- * Clean output directory before build.
76
- *
77
- * Defaults to `true`
78
- */
76
+ * Clean output directory before build.
77
+ *
78
+ * Defaults to `true`
79
+ */
79
80
  clean?: boolean;
80
81
  /**
81
- * Experimental configuration.
82
- */
82
+ * The path to the tsconfig.json file.
83
+ *
84
+ * If set to `false`, the plugin will ignore any `tsconfig.json` file.
85
+ * You can still specify `compilerOptions` directly in the options.
86
+ *
87
+ * Defaults to `'tsconfig.json'`
88
+ */
89
+ tsconfig?: string;
90
+ /**
91
+ * Pass a raw `tsconfig.json` object directly to the plugin.
92
+ *
93
+ * @see https://www.typescriptlang.org/tsconfig
94
+ */
95
+ tsconfigRaw?: Omit<TsConfigJson, 'compilerOptions'>;
96
+ /**
97
+ * Experimental configuration.
98
+ */
83
99
  experimental?: ExperimentalConfig;
84
100
  }
85
101
  interface ExperimentalConfig {
86
102
  /**
87
- * Whether to use the tsgo compiler.
88
- *
89
- * To use this option, make sure `@typescript/native-preview` is installed as a dependency.
90
- */
103
+ * Whether to use the tsgo compiler.
104
+ *
105
+ * To use this option, make sure `@typescript/native-preview` is installed as a dependency.
106
+ */
91
107
  tsgo?: boolean;
92
108
  }
93
109
  //#endregion
package/dist/config.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { TsConfigJson } from "get-tsconfig";
1
2
  import { OutputOptions } from "rolldown";
2
3
 
3
4
  //#region src/types.d.ts
@@ -6,88 +7,103 @@ type Format = 'esm' | 'cjs';
6
7
  //#region src/config/types.d.ts
7
8
  interface Config {
8
9
  /**
9
- * Defaults to `'src'`
10
- */
10
+ * Defaults to `'src'`
11
+ */
11
12
  source?: string;
12
13
  /**
13
- * The directory where output files will be written.
14
- *
15
- * Defaults to `'dist'`
16
- */
14
+ * The directory where output files will be written.
15
+ *
16
+ * Defaults to `'dist'`
17
+ */
17
18
  outDir?: string;
18
19
  /**
19
- * Files to exclude from the build.
20
- *
21
- * Defaults to `/__(?:tests?|fixtures?|mocks?)__/`
22
- */
20
+ * Files to exclude from the build.
21
+ *
22
+ * Defaults to `/__(?:tests?|fixtures?|mocks?)__/`
23
+ */
23
24
  exclude?: RegExp;
24
25
  /**
25
- * Expected format of generated code.
26
- *
27
- * Defaults to `'esm'`
28
- */
26
+ * Expected format of generated code.
27
+ *
28
+ * Defaults to `'esm'`
29
+ */
29
30
  format?: Format | Format[];
30
31
  /**
31
- * Specifiers to resolve platform specific modules.
32
- *
33
- * Defaults to `['android', 'ios', 'native']`
34
- */
32
+ * Specifiers to resolve platform specific modules.
33
+ *
34
+ * Defaults to `['android', 'ios', 'native']`
35
+ */
35
36
  specifiers?: string[];
36
37
  /**
37
- * Source files extensions.
38
- *
39
- * Defaults to `['ts', 'tsx', 'js', 'jsx', 'json']`
40
- */
38
+ * Source files extensions.
39
+ *
40
+ * Defaults to `['ts', 'tsx', 'js', 'jsx', 'json']`
41
+ */
41
42
  sourceExtensions?: string[];
42
43
  /**
43
- * Asset files extensions.
44
- *
45
- * Default to following extensions: [Metro's default asset extensions](https://github.com/facebook/metro/blob/v0.83.3/packages/metro-config/src/defaults/defaults.js)
46
- */
44
+ * Asset files extensions.
45
+ *
46
+ * Default to following extensions: [Metro's default asset extensions](https://github.com/facebook/metro/blob/v0.83.3/packages/metro-config/src/defaults/defaults.js)
47
+ */
47
48
  assetExtensions?: string[];
48
49
  /**
49
- * Enables generation of TypeScript declaration files (.d.ts).
50
- *
51
- * Defaults to `true`
52
- */
50
+ * Enables generation of TypeScript declaration files (.d.ts).
51
+ *
52
+ * Defaults to `true`
53
+ */
53
54
  dts?: boolean;
54
55
  /**
55
- * Generate source map files.
56
- */
56
+ * Generate source map files.
57
+ */
57
58
  sourcemap?: OutputOptions['sourcemap'];
58
59
  /**
59
- * Code to prepend to the beginning of each output chunk.
60
- */
60
+ * Code to prepend to the beginning of each output chunk.
61
+ */
61
62
  banner?: OutputOptions['banner'];
62
63
  /**
63
- * Code to append to the end of each output chunk.
64
- */
64
+ * Code to append to the end of each output chunk.
65
+ */
65
66
  footer?: OutputOptions['footer'];
66
67
  /**
67
- * Code to prepend inside the wrapper function (after banner, before actual code).
68
- */
68
+ * Code to prepend inside the wrapper function (after banner, before actual code).
69
+ */
69
70
  intro?: OutputOptions['intro'];
70
71
  /**
71
- * Code to append inside the wrapper function (after actual code, before footer).
72
- */
72
+ * Code to append inside the wrapper function (after actual code, before footer).
73
+ */
73
74
  outro?: OutputOptions['outro'];
74
75
  /**
75
- * Clean output directory before build.
76
- *
77
- * Defaults to `true`
78
- */
76
+ * Clean output directory before build.
77
+ *
78
+ * Defaults to `true`
79
+ */
79
80
  clean?: boolean;
80
81
  /**
81
- * Experimental configuration.
82
- */
82
+ * The path to the tsconfig.json file.
83
+ *
84
+ * If set to `false`, the plugin will ignore any `tsconfig.json` file.
85
+ * You can still specify `compilerOptions` directly in the options.
86
+ *
87
+ * Defaults to `'tsconfig.json'`
88
+ */
89
+ tsconfig?: string;
90
+ /**
91
+ * Pass a raw `tsconfig.json` object directly to the plugin.
92
+ *
93
+ * @see https://www.typescriptlang.org/tsconfig
94
+ */
95
+ tsconfigRaw?: Omit<TsConfigJson, 'compilerOptions'>;
96
+ /**
97
+ * Experimental configuration.
98
+ */
83
99
  experimental?: ExperimentalConfig;
84
100
  }
85
101
  interface ExperimentalConfig {
86
102
  /**
87
- * Whether to use the tsgo compiler.
88
- *
89
- * To use this option, make sure `@typescript/native-preview` is installed as a dependency.
90
- */
103
+ * Whether to use the tsgo compiler.
104
+ *
105
+ * To use this option, make sure `@typescript/native-preview` is installed as a dependency.
106
+ */
91
107
  tsgo?: boolean;
92
108
  }
93
109
  //#endregion
package/dist/index.js CHANGED
@@ -1,10 +1,15 @@
1
+ import path from "path";
1
2
  import { loadConfig } from "c12";
3
+ import pc from "picocolors";
4
+ import { VERSION, build } from "rolldown";
2
5
  import { createDebug } from "obug";
3
6
  import fs, { globSync } from "node:fs";
4
7
  import * as pkg from "empathic/package";
5
- import { build } from "rolldown";
6
- import path from "node:path";
8
+ import { assert } from "es-toolkit";
9
+ import path$1 from "node:path";
7
10
  import { dts } from "rolldown-plugin-dts";
11
+ import { promisify } from "node:util";
12
+ import { brotliCompress, gzip } from "node:zlib";
8
13
 
9
14
  //#region src/common.ts
10
15
  const debug$3 = createDebug("tsnv:common");
@@ -62,19 +67,11 @@ const DEFAULT_CONFIG = {
62
67
  clean: true
63
68
  };
64
69
 
65
- //#endregion
66
- //#region ../../../.yarn/berry/cache/es-toolkit-npm-1.43.0-b8f13c51d9-10c0.zip/node_modules/es-toolkit/dist/util/invariant.mjs
67
- function invariant(condition, message) {
68
- if (condition) return;
69
- if (typeof message === "string") throw new Error(message);
70
- throw message;
71
- }
72
-
73
70
  //#endregion
74
71
  //#region src/context.ts
75
72
  async function resolveContext(cwd) {
76
73
  const packageJsonPath = pkg.up({ cwd });
77
- invariant(packageJsonPath, "could not find package.json");
74
+ assert(packageJsonPath, "could not find package.json");
78
75
  const rawPackageJson = await fs.promises.readFile(packageJsonPath, "utf-8");
79
76
  const packageJson = JSON.parse(rawPackageJson);
80
77
  return {
@@ -92,9 +89,9 @@ function resolvePackageType(packageJson) {
92
89
 
93
90
  //#endregion
94
91
  //#region src/utils/path.ts
95
- async function hasPlatformSpecificModule(id, importer, config$1) {
96
- const specifiers = config$1.specifiers;
97
- const resolveDir = path.dirname(importer);
92
+ async function hasPlatformSpecificModule(id, importer, config) {
93
+ const specifiers = config.specifiers;
94
+ const resolveDir = path$1.dirname(importer);
98
95
  let fileList = hasPlatformSpecificModule.cache.get(resolveDir);
99
96
  if (fileList == null) {
100
97
  fileList = (await fs.promises.readdir(resolveDir, {
@@ -106,7 +103,7 @@ async function hasPlatformSpecificModule(id, importer, config$1) {
106
103
  return specifiers.some((specifier) => fileList.includes(`${basenameWithoutExtension(id)}.${specifier}`));
107
104
  }
108
105
  function basenameWithoutExtension(id) {
109
- return path.basename(id, path.extname(id));
106
+ return path$1.basename(id, path$1.extname(id));
110
107
  }
111
108
  hasPlatformSpecificModule.cache = /* @__PURE__ */ new Map();
112
109
  /**
@@ -125,15 +122,15 @@ function isDts(filename) {
125
122
  }
126
123
  function removePlatformSpecificExtension(filename, extensions, specifiers) {
127
124
  const extPattern = extensions.map((extension) => extension.replace(".", "")).join("|");
128
- const regex = /* @__PURE__ */ new RegExp(`\\.(${specifiers.join("|")})\\.(${extPattern})$`);
125
+ const regex = new RegExp(`\\.(${specifiers.join("|")})\\.(${extPattern})$`);
129
126
  return filename.replace(regex, ".$2");
130
127
  }
131
- function getUniquePlatformSpecificFiles(files$1, extensions, specifiers) {
128
+ function getUniquePlatformSpecificFiles(files, extensions, specifiers) {
132
129
  const extPattern = extensions.map((e) => e.replace(".", "")).join("|");
133
- const regex = /* @__PURE__ */ new RegExp(`\\.(${specifiers.join("|")})\\.(${extPattern})$`);
130
+ const regex = new RegExp(`\\.(${specifiers.join("|")})\\.(${extPattern})$`);
134
131
  const seen = /* @__PURE__ */ new Set();
135
132
  const result = [];
136
- for (const file of files$1) {
133
+ for (const file of files) {
137
134
  const baseName = file.replace(regex, ".$2");
138
135
  if (seen.has(baseName)) continue;
139
136
  seen.add(baseName);
@@ -145,12 +142,14 @@ function getUniquePlatformSpecificFiles(files$1, extensions, specifiers) {
145
142
  //#endregion
146
143
  //#region src/rolldown/plugins/dts.ts
147
144
  const debug$2 = createDebug("tsnv:dts");
148
- function dts$1(config$1) {
149
- if (!config$1.dts) return null;
145
+ function dts$1(config) {
146
+ if (!config.dts) return null;
150
147
  const dtsExtension = ["d"];
151
148
  return [dts({
152
149
  emitDtsOnly: true,
153
- tsgo: config$1.experimental?.tsgo
150
+ tsconfig: config.tsconfig,
151
+ tsconfigRaw: config.tsconfigRaw,
152
+ tsgo: config.experimental?.tsgo
154
153
  }), {
155
154
  name: "tsnv:dts-renamer",
156
155
  outputOptions(options) {
@@ -158,7 +157,7 @@ function dts$1(config$1) {
158
157
  ...options,
159
158
  entryFileNames(chunkInfo) {
160
159
  if (chunkInfo.name.endsWith(".d")) {
161
- const newChunkName = `${removePlatformSpecificExtension(chunkInfo.name, dtsExtension, config$1.specifiers)}.ts`;
160
+ const newChunkName = `${removePlatformSpecificExtension(chunkInfo.name, dtsExtension, config.specifiers)}.ts`;
162
161
  debug$2(`renaming ${chunkInfo.name} to ${newChunkName}`);
163
162
  return newChunkName;
164
163
  } else return chunkInfo.name;
@@ -172,8 +171,8 @@ function dts$1(config$1) {
172
171
  //#region src/rolldown/plugins/external.ts
173
172
  const PLUGIN_NAME = "tsnv:external";
174
173
  const debug$1 = createDebug(PLUGIN_NAME);
175
- function external(context$1) {
176
- const productionDependencies = Array.from(new Set([...Object.keys(context$1.packageJson.dependencies ?? {}), ...Object.keys(context$1.packageJson.peerDependencies ?? {})]));
174
+ function external(context) {
175
+ const productionDependencies = Array.from(new Set([...Object.keys(context.packageJson.dependencies ?? {}), ...Object.keys(context.packageJson.peerDependencies ?? {})]));
177
176
  debug$1("production dependencies", productionDependencies);
178
177
  return {
179
178
  name: PLUGIN_NAME,
@@ -183,16 +182,16 @@ function external(context$1) {
183
182
  id,
184
183
  external: true
185
184
  };
186
- const extname = path.extname(id);
185
+ const extname = path$1.extname(id).slice(1);
187
186
  if (extname) {
188
- if (context$1.config.assetExtensions.includes(extname)) return {
187
+ if (context.config.assetExtensions.includes(extname)) return {
189
188
  id,
190
189
  external: true
191
190
  };
192
- if (!context$1.config.sourceExtensions.includes(extname)) throw new Error(`Unsupported file extension: ${extname}`);
191
+ if (!context.config.sourceExtensions.includes(extname)) throw new Error(`Unsupported file extension: ${extname}`);
193
192
  }
194
193
  const resolved = await this.resolve(id, importer, extraOptions);
195
- if (resolved == null && await hasPlatformSpecificModule(id, importer, context$1.config)) return {
194
+ if (resolved == null && await hasPlatformSpecificModule(id, importer, context.config)) return {
196
195
  id,
197
196
  external: true,
198
197
  moduleSideEffects: true
@@ -205,16 +204,77 @@ function isPackageImportSource(packageName, id) {
205
204
  return id === packageName || id.startsWith(`${packageName}/`);
206
205
  }
207
206
 
207
+ //#endregion
208
+ //#region src/utils/fs.ts
209
+ const gzipAsync = promisify(gzip);
210
+ const brotliCompressAsync = promisify(brotliCompress);
211
+ function collectFiles(config) {
212
+ const files = globSync(`**/*.{${config.sourceExtensions.join(",")}}`, {
213
+ cwd: config.source,
214
+ exclude: (filename) => config.exclude.test(filename) || isDts(filename)
215
+ });
216
+ if (files.length === 0) throw new Error(`No files found in ${path$1.resolve(config.source)}`);
217
+ return files.map((file) => path$1.join(config.source, file));
218
+ }
219
+ async function calcSize(chunk) {
220
+ const content = chunk.type === "chunk" ? chunk.code : chunk.source;
221
+ const raw = Buffer.byteLength(content, "utf8");
222
+ const gzip = (await gzipAsync(content)).length;
223
+ return {
224
+ filename: chunk.fileName,
225
+ dts: chunk.fileName.endsWith(".d.ts"),
226
+ raw,
227
+ rawText: formatBytes(raw),
228
+ gzip,
229
+ gzipText: formatBytes(gzip)
230
+ };
231
+ }
232
+ function formatBytes(bytes) {
233
+ return `${(bytes / 1e3).toFixed(2)} kB`;
234
+ }
235
+
236
+ //#endregion
237
+ //#region src/rolldown/plugins/report.ts
238
+ const noop = (text) => text;
239
+ function report(options) {
240
+ const { cwd, format } = options;
241
+ const formatLabel = (() => {
242
+ switch (format) {
243
+ case "esm": return pc.blue(`[ESM]`);
244
+ case "cjs": return pc.yellow(`[CJS]`);
245
+ case "dts": return pc.green(`[DTS]`);
246
+ }
247
+ })();
248
+ return {
249
+ name: "tsnv:report",
250
+ async writeBundle(outputOptions, bundle) {
251
+ const outDir = path$1.relative(cwd, outputOptions.dir ? path$1.resolve(outputOptions.dir) : path$1.dirname(outputOptions.file));
252
+ const sizes = [];
253
+ for (const chunk of Object.values(bundle)) {
254
+ const size = await calcSize(chunk);
255
+ sizes.push(size);
256
+ }
257
+ let totalRaw = 0;
258
+ for (const size of sizes) totalRaw += size.raw;
259
+ for (const size of sizes) {
260
+ const filenameColor = size.dts ? pc.green : noop;
261
+ const filename = path$1.normalize(size.filename);
262
+ console.log(formatLabel, pc.dim(outDir + path$1.sep) + filenameColor(filename), pc.dim(size.rawText), pc.dim(`(gzip ${size.gzipText})`));
263
+ }
264
+ console.log(formatLabel, `${sizes.length} files, total: ${formatBytes(totalRaw)}`);
265
+ }
266
+ };
267
+ }
268
+
208
269
  //#endregion
209
270
  //#region src/rolldown/build-options.ts
210
- function resolveBuildOptions(context$1, options) {
271
+ function resolveBuildOptions(context, options) {
211
272
  const pluginContext = {
212
- ...context$1,
273
+ ...context,
213
274
  config: options.config
214
275
  };
215
276
  const baseOptions = {
216
277
  input: options.files,
217
- plugins: [external(pluginContext)],
218
278
  output: {
219
279
  banner: options.config.banner,
220
280
  footer: options.config.footer,
@@ -234,9 +294,13 @@ function resolveBuildOptions(context$1, options) {
234
294
  const resolvedBuildOptions = uniqueFormats.map((format) => {
235
295
  return {
236
296
  ...baseOptions,
297
+ plugins: [external(pluginContext), report({
298
+ cwd: options.cwd,
299
+ format
300
+ })],
237
301
  output: {
238
302
  ...baseOptions.output,
239
- dir: isSingleFormat ? options.config.outDir : path.join(options.config.outDir, format),
303
+ dir: isSingleFormat ? options.config.outDir : path$1.join(options.config.outDir, format),
240
304
  cleanDir: options.config.clean,
241
305
  format,
242
306
  entryFileNames: filename,
@@ -247,11 +311,18 @@ function resolveBuildOptions(context$1, options) {
247
311
  if (options.config.dts) resolvedBuildOptions.push({
248
312
  ...baseOptions,
249
313
  input: getUniquePlatformSpecificFiles(options.files, options.config.sourceExtensions, options.config.specifiers),
250
- plugins: [...Array.isArray(baseOptions.plugins) ? baseOptions.plugins : [baseOptions.plugins], dts$1(options.config)],
314
+ plugins: [
315
+ external(pluginContext),
316
+ report({
317
+ cwd: options.cwd,
318
+ format: "dts"
319
+ }),
320
+ dts$1(options.config)
321
+ ],
251
322
  output: {
252
323
  ...baseOptions.output,
253
324
  cleanDir: options.config.clean,
254
- dir: path.join(options.config.outDir, "types"),
325
+ dir: path$1.join(options.config.outDir, "types"),
255
326
  format: "esm",
256
327
  entryFileNames: filename,
257
328
  chunkFileNames: filename
@@ -263,38 +334,47 @@ function resolveBuildOptions(context$1, options) {
263
334
  //#endregion
264
335
  //#region src/rolldown/index.ts
265
336
  const debug = createDebug("tsnv:build");
266
- async function build$1(context$1, options) {
267
- const buildOptions = resolveBuildOptions(context$1, options);
337
+ async function build$1(context, options) {
338
+ const buildOptions = resolveBuildOptions(context, options);
268
339
  debug("Resolved build options", buildOptions);
269
340
  for (const buildOption of buildOptions) await build(buildOption);
270
341
  }
271
342
 
272
343
  //#endregion
273
- //#region src/utils/fs.ts
274
- function collectFiles(config$1) {
275
- const files$1 = globSync(`**/*.{${config$1.sourceExtensions.join(",")}}`, {
276
- cwd: config$1.source,
277
- exclude: (filename) => config$1.exclude.test(filename) || isDts(filename)
344
+ //#region src/index.ts
345
+ const version = `v0.0.0-dev.20260201114010`;
346
+ async function main() {
347
+ console.log(`tsnv ${pc.dim(version)} powered by rolldown ${pc.dim(VERSION)}`);
348
+ debug$3("Loading config...");
349
+ const cwd = process.cwd();
350
+ const { config, configFile } = await loadConfig({
351
+ cwd,
352
+ configFile: "tsnv.config",
353
+ defaultConfig: DEFAULT_CONFIG
354
+ });
355
+ debug$3("Config loaded", config);
356
+ console.log(`Config File: ${pc.underline(configFile)}`);
357
+ console.log(`Source Path: ${pc.blue(path.resolve(config.source))}`);
358
+ const context = await resolveContext(process.cwd());
359
+ debug$3("Resolved context", context);
360
+ const files = await collectFiles(config);
361
+ console.log(`Collected files: ${pc.dim(files.length)}`);
362
+ console.log("Build start");
363
+ const startedAt = performance.now();
364
+ await build$1(context, {
365
+ cwd,
366
+ files,
367
+ config
278
368
  });
279
- if (files$1.length === 0) throw new Error(`No files found in ${path.resolve(config$1.source)}`);
280
- return files$1.map((file) => path.join(config$1.source, file));
369
+ const endedAt = performance.now();
370
+ const duration = `${Math.floor(endedAt - startedAt)}ms`;
371
+ console.log(`Build completed in ${pc.green(duration)}`);
281
372
  }
282
-
283
- //#endregion
284
- //#region src/index.ts
285
- debug$3("Loading config...");
286
- const { config } = await loadConfig({
287
- configFile: "tsnv.config",
288
- defaultConfig: DEFAULT_CONFIG
289
- });
290
- debug$3("Config loaded", config);
291
- const context = await resolveContext(process.cwd());
292
- debug$3("Resolved context", context);
293
- const files = await collectFiles(config);
294
- debug$3("Collected files", files);
295
- await build$1(context, {
296
- files,
297
- config
373
+ await main().catch((reason) => {
374
+ console.error(pc.red(`Build failed`));
375
+ console.error();
376
+ console.error(reason);
377
+ process.exit(1);
298
378
  });
299
379
 
300
380
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tsnv",
3
- "version": "0.0.0-dev.20260119180902",
3
+ "version": "0.0.0-dev.20260201114010",
4
4
  "description": "Modern build toolkit for React Native libraries",
5
5
  "license": "MIT",
6
6
  "author": "Geunhyeok Lee <dev.ghlee@gmail.com>",
@@ -10,6 +10,9 @@
10
10
  "directory": "."
11
11
  },
12
12
  "bin": "bin.js",
13
+ "workspaces": [
14
+ "example"
15
+ ],
13
16
  "files": [
14
17
  "bin.js",
15
18
  "dist"
@@ -40,6 +43,7 @@
40
43
  "fmt": "oxfmt",
41
44
  "test": "vitest --run",
42
45
  "test:e2e": "vitest --run --config vitest.e2e.config.ts",
46
+ "test:all": "yarn test && yarn test:e2e",
43
47
  "build": "tsdown",
44
48
  "scripts:version": ".scripts/version.sh",
45
49
  "scripts:publish": ".scripts/publish.sh"
@@ -47,19 +51,20 @@
47
51
  "dependencies": {
48
52
  "c12": "^3.3.3",
49
53
  "empathic": "^2.0.0",
54
+ "es-toolkit": "^1.44.0",
55
+ "get-tsconfig": "^4.13.1",
50
56
  "obug": "^2.1.1",
51
- "rolldown": "1.0.0-beta.60",
52
- "rolldown-plugin-dts": "0.21.2",
53
- "tsdown": "0.20.0-beta.3"
57
+ "picocolors": "^1.1.1",
58
+ "rolldown": "1.0.0-rc.2",
59
+ "rolldown-plugin-dts": "0.21.8"
54
60
  },
55
61
  "devDependencies": {
56
62
  "@changesets/cli": "^2.29.8",
57
63
  "@types/node": "^24.10.1",
58
- "es-toolkit": "^1.43.0",
59
- "oxfmt": "^0.24.0",
60
- "oxlint": "^1.39.0",
61
- "oxlint-tsgolint": "^0.11.1",
62
- "picocolors": "^1.1.1",
64
+ "oxfmt": "^0.27.0",
65
+ "oxlint": "^1.42.0",
66
+ "oxlint-tsgolint": "^0.11.4",
67
+ "tsdown": "^0.20.1",
63
68
  "tsx": "^4.21.0",
64
69
  "typescript": "^5.9.3",
65
70
  "vitest": "^4.0.17",