@quilted/rollup 0.1.19 → 0.2.1

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.
Files changed (129) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/build/esm/app.mjs +450 -222
  3. package/build/esm/constants.mjs +5 -5
  4. package/build/esm/features/assets.mjs +93 -81
  5. package/build/esm/features/async.mjs +186 -0
  6. package/build/esm/features/css.mjs +26 -39
  7. package/build/esm/features/env.mjs +47 -44
  8. package/build/esm/features/esnext.mjs +57 -0
  9. package/build/esm/features/graphql/transform.mjs +60 -56
  10. package/build/esm/features/graphql.mjs +65 -47
  11. package/build/esm/features/request-router.mjs +6 -4
  12. package/build/esm/features/source-code.mjs +54 -28
  13. package/build/esm/features/system-js.mjs +29 -20
  14. package/build/esm/features/typescript.mjs +13 -10
  15. package/build/esm/features/workers.mjs +173 -0
  16. package/build/esm/index.mjs +3 -2
  17. package/build/esm/module.mjs +69 -62
  18. package/build/esm/package.mjs +275 -84
  19. package/build/esm/server.mjs +118 -0
  20. package/build/esm/shared/browserslist.mjs +141 -16
  21. package/build/esm/shared/magic-module.mjs +9 -7
  22. package/build/esm/shared/package-json.mjs +7 -1
  23. package/build/esm/shared/path.mjs +7 -0
  24. package/build/esm/shared/rollup.mjs +89 -25
  25. package/build/esm/shared/strings.mjs +7 -6
  26. package/build/tsconfig.tsbuildinfo +1 -1
  27. package/build/typescript/app.d.ts +132 -29
  28. package/build/typescript/app.d.ts.map +1 -1
  29. package/build/typescript/features/assets.d.ts +1 -2
  30. package/build/typescript/features/assets.d.ts.map +1 -1
  31. package/build/typescript/features/async.d.ts +10 -0
  32. package/build/typescript/features/async.d.ts.map +1 -0
  33. package/build/typescript/features/css.d.ts +2 -1
  34. package/build/typescript/features/css.d.ts.map +1 -1
  35. package/build/typescript/features/env.d.ts +1 -0
  36. package/build/typescript/features/env.d.ts.map +1 -1
  37. package/build/typescript/features/esnext.d.ts +9 -0
  38. package/build/typescript/features/esnext.d.ts.map +1 -0
  39. package/build/typescript/features/graphql.d.ts +2 -2
  40. package/build/typescript/features/graphql.d.ts.map +1 -1
  41. package/build/typescript/features/source-code.d.ts +9 -3
  42. package/build/typescript/features/source-code.d.ts.map +1 -1
  43. package/build/typescript/features/system-js.d.ts +4 -1
  44. package/build/typescript/features/system-js.d.ts.map +1 -1
  45. package/build/typescript/features/workers.d.ts +52 -0
  46. package/build/typescript/features/workers.d.ts.map +1 -0
  47. package/build/typescript/index.d.ts +3 -2
  48. package/build/typescript/index.d.ts.map +1 -1
  49. package/build/typescript/module.d.ts +24 -6
  50. package/build/typescript/module.d.ts.map +1 -1
  51. package/build/typescript/package.d.ts +196 -4
  52. package/build/typescript/package.d.ts.map +1 -1
  53. package/build/typescript/server.d.ts +98 -0
  54. package/build/typescript/server.d.ts.map +1 -0
  55. package/build/typescript/shared/browserslist.d.ts +20 -3
  56. package/build/typescript/shared/browserslist.d.ts.map +1 -1
  57. package/build/typescript/shared/path.d.ts +2 -0
  58. package/build/typescript/shared/path.d.ts.map +1 -0
  59. package/build/typescript/shared/rollup.d.ts +27 -1
  60. package/build/typescript/shared/rollup.d.ts.map +1 -1
  61. package/configuration/rollup.config.js +40 -0
  62. package/package.json +62 -9
  63. package/source/app.ts +475 -99
  64. package/source/features/assets.ts +5 -7
  65. package/source/features/async.ts +249 -0
  66. package/source/features/css.ts +4 -2
  67. package/source/features/env.ts +6 -0
  68. package/source/features/esnext.ts +70 -0
  69. package/source/features/graphql.ts +4 -2
  70. package/source/features/source-code.ts +27 -9
  71. package/source/features/system-js.ts +25 -2
  72. package/source/features/workers.ts +292 -0
  73. package/source/index.ts +4 -0
  74. package/source/module.ts +45 -19
  75. package/source/package.ts +394 -36
  76. package/source/server.ts +245 -0
  77. package/source/shared/browserslist.ts +208 -18
  78. package/source/shared/path.ts +5 -0
  79. package/source/shared/rollup.ts +102 -4
  80. package/tsconfig.json +6 -2
  81. package/build/cjs/app.cjs +0 -441
  82. package/build/cjs/constants.cjs +0 -13
  83. package/build/cjs/features/assets.cjs +0 -240
  84. package/build/cjs/features/css.cjs +0 -71
  85. package/build/cjs/features/env.cjs +0 -135
  86. package/build/cjs/features/graphql/transform.cjs +0 -186
  87. package/build/cjs/features/graphql.cjs +0 -86
  88. package/build/cjs/features/request-router.cjs +0 -31
  89. package/build/cjs/features/source-code.cjs +0 -54
  90. package/build/cjs/features/system-js.cjs +0 -36
  91. package/build/cjs/features/typescript.cjs +0 -56
  92. package/build/cjs/index.cjs +0 -13
  93. package/build/cjs/module.cjs +0 -121
  94. package/build/cjs/package.cjs +0 -170
  95. package/build/cjs/shared/browserslist.cjs +0 -25
  96. package/build/cjs/shared/magic-module.cjs +0 -32
  97. package/build/cjs/shared/package-json.cjs +0 -31
  98. package/build/cjs/shared/rollup.cjs +0 -72
  99. package/build/cjs/shared/strings.cjs +0 -16
  100. package/build/esnext/app.esnext +0 -414
  101. package/build/esnext/constants.esnext +0 -7
  102. package/build/esnext/features/assets.esnext +0 -215
  103. package/build/esnext/features/css.esnext +0 -69
  104. package/build/esnext/features/env.esnext +0 -112
  105. package/build/esnext/features/graphql/transform.esnext +0 -181
  106. package/build/esnext/features/graphql.esnext +0 -84
  107. package/build/esnext/features/request-router.esnext +0 -29
  108. package/build/esnext/features/source-code.esnext +0 -51
  109. package/build/esnext/features/system-js.esnext +0 -33
  110. package/build/esnext/features/typescript.esnext +0 -34
  111. package/build/esnext/index.esnext +0 -3
  112. package/build/esnext/module.esnext +0 -100
  113. package/build/esnext/package.esnext +0 -148
  114. package/build/esnext/shared/browserslist.esnext +0 -23
  115. package/build/esnext/shared/magic-module.esnext +0 -30
  116. package/build/esnext/shared/package-json.esnext +0 -10
  117. package/build/esnext/shared/rollup.esnext +0 -49
  118. package/build/esnext/shared/strings.esnext +0 -14
  119. package/build/typescript/env.d.ts +0 -55
  120. package/build/typescript/env.d.ts.map +0 -1
  121. package/build/typescript/graphql/transform.d.ts +0 -17
  122. package/build/typescript/graphql/transform.d.ts.map +0 -1
  123. package/build/typescript/graphql.d.ts +0 -6
  124. package/build/typescript/graphql.d.ts.map +0 -1
  125. package/build/typescript/request-router.d.ts +0 -15
  126. package/build/typescript/request-router.d.ts.map +0 -1
  127. package/build/typescript/shared/source-code.d.ts +0 -5
  128. package/build/typescript/shared/source-code.d.ts.map +0 -1
  129. package/quilt.project.ts +0 -5
package/source/package.ts CHANGED
@@ -1,12 +1,26 @@
1
1
  import * as path from 'path';
2
- import {Plugin, type RollupOptions} from 'rollup';
2
+ import * as fs from 'fs/promises';
3
+ import {exec as execCommand} from 'child_process';
4
+ import {promisify} from 'util';
5
+
6
+ import {Plugin, type RollupOptions, type OutputOptions} from 'rollup';
3
7
  import {glob} from 'glob';
4
- import {fileURLToPath} from 'url';
5
8
 
6
- import {getNodePlugins, removeBuildFiles} from './shared/rollup.ts';
9
+ import {multiline} from './shared/strings.ts';
10
+ import {resolveRoot} from './shared/path.ts';
11
+ import {
12
+ getNodePlugins,
13
+ removeBuildFiles,
14
+ type RollupNodePluginOptions,
15
+ } from './shared/rollup.ts';
7
16
  import {loadPackageJSON, type PackageJSON} from './shared/package-json.ts';
17
+ import {
18
+ getBrowserGroupTargetDetails,
19
+ rollupGenerateOptionsForBrowsers,
20
+ } from './shared/browserslist.ts';
8
21
 
9
- export interface PackageOptions {
22
+ export interface PackageBaseOptions
23
+ extends Pick<RollupNodePluginOptions, 'bundle'> {
10
24
  /**
11
25
  * The root directory containing the source code for your application.
12
26
  */
@@ -18,36 +32,233 @@ export interface PackageOptions {
18
32
  * @default true
19
33
  */
20
34
  graphql?: boolean;
35
+
36
+ /**
37
+ * A map of package entry to source file name. The keys in this
38
+ * object should be in the same format as the keys for the `exports`
39
+ * property in the package.json file. For example, the following object
40
+ * species a "root" entry point
41
+ *
42
+ * ```ts
43
+ * quiltPackage({
44
+ * entries: {
45
+ * '.': './source/index.ts',
46
+ * './testing': './source/testing.ts',
47
+ * },
48
+ * });
49
+ * ```
50
+ *
51
+ * When you do not explicitly provide this option, Quilt will provide a
52
+ * default option that reads the `exports` property of your package.json,
53
+ * and attempts to infer the source files for the entry points listed
54
+ * there.
55
+ */
56
+ entries?: Record<string, string>;
57
+
58
+ /**
59
+ * Controls how React will be handled by your package. Setting this value
60
+ * to `preact` will cause Quilt to use `preact` as the JSX import source.
61
+ * Otherwise, `react` will be used as the import source.
62
+ *
63
+ * @default true
64
+ */
65
+ react?: boolean | 'react' | 'preact';
66
+
67
+ /**
68
+ * Customizes the Rollup options used to build your package. This function
69
+ * is called with the default options determined by Quilt, so you can override
70
+ * them however you like. Alternatively, you can provide a static object of
71
+ * Rollup options, which will be merged with the defaults provided by Quilt.
72
+ */
73
+ customize?:
74
+ | RollupOptions
75
+ | ((options: RollupOptions) => RollupOptions | Promise<RollupOptions>);
21
76
  }
22
77
 
23
- export async function quiltPackageESModules({
78
+ export interface PackageESModuleOptions extends PackageBaseOptions {
79
+ /**
80
+ * A map of executables to output for this package. The keys in this
81
+ * object should be the filenames of the executable you want to create,
82
+ * and the values should be the source file that will be run. For example,
83
+ * the following object species a `quilt` executable, which will run the
84
+ * `./source/cli.ts` file:
85
+ *
86
+ * ```ts
87
+ * quiltPackage({
88
+ * executable: {
89
+ * quilt: './source/cli.ts',
90
+ * },
91
+ * });
92
+ * ```
93
+ *
94
+ * By default, no executables are built for a package. For more on building
95
+ * executables, see [Quilt’s package build documentation](https://github.com/lemonmade/quilt/blob/main/documentation/projects/packages/build.md#executable-files)
96
+ */
97
+ executable?: Record<string, string>;
98
+
99
+ /**
100
+ * Whether to build a CommonJS version of this library. This build
101
+ * will be placed in `./build/cjs`; you’ll need to add a `require`
102
+ * export condition to your `package.json` that points at these files
103
+ * for each entry.
104
+ *
105
+ * Instead of a boolean, you can also pass an object with an `exports`
106
+ * field. Passing this value turns on the CommonJS build, and allows you
107
+ * to customize the way in which ES exports from your source files
108
+ * are turned into CommonJS.
109
+ *
110
+ * @default false
111
+ * @see https://github.com/lemonmade/quilt/blob/main/documentation/projects/packages/builds.md#commonjs-build
112
+ */
113
+ commonjs?: boolean | {exports?: 'named' | 'default'};
114
+ }
115
+
116
+ export interface PackageOptions extends PackageESModuleOptions {
117
+ /**
118
+ * Whether to build an “ESNext” version of your package. This version
119
+ * will do minimal transpilation, keeping the resulting builds extremely
120
+ * close to your source code. Quilt apps and services that depend on your
121
+ * package will then re-compile the ESNext outputs to match the language
122
+ * features in the runtime environment they are targeting.
123
+ *
124
+ * @default true
125
+ * @see https://github.com/lemonmade/quilt/blob/main/documentation/projects/packages/builds.md#esnext-build
126
+ */
127
+ esnext?: boolean;
128
+ }
129
+
130
+ export async function quiltPackage({
24
131
  root: rootPath = process.cwd(),
132
+ commonjs = false,
133
+ esnext: explicitESNext,
134
+ entries,
135
+ executable,
136
+ bundle,
137
+ react,
25
138
  graphql = true,
139
+ customize,
26
140
  }: PackageOptions = {}) {
27
- const root =
28
- typeof rootPath === 'string' ? rootPath : fileURLToPath(rootPath);
29
- const outputDirectory = path.join(root, 'build/esm');
141
+ const root = resolveRoot(rootPath);
142
+ const packageJSON = await loadPackageJSON(root);
143
+ const resolvedEntries =
144
+ entries ?? (await sourceEntriesForPackage(root, packageJSON));
30
145
 
31
- const [{sourceCode}, nodePlugins, packageJSON] = await Promise.all([
32
- import('./features/source-code.ts'),
33
- getNodePlugins(),
34
- loadPackageJSON(root),
146
+ const includeESNext =
147
+ explicitESNext ?? Object.keys(resolvedEntries).length > 0;
148
+
149
+ const [esm, esnext] = await Promise.all([
150
+ quiltPackageESModules({
151
+ root,
152
+ react,
153
+ graphql,
154
+ entries: resolvedEntries,
155
+ executable,
156
+ bundle,
157
+ commonjs,
158
+ customize,
159
+ }),
160
+ includeESNext
161
+ ? quiltPackageESNext({
162
+ root,
163
+ react,
164
+ graphql,
165
+ entries: resolvedEntries,
166
+ bundle,
167
+ customize,
168
+ })
169
+ : Promise.resolve(undefined),
35
170
  ]);
36
171
 
37
- const source = await sourceForPackage(root, packageJSON);
172
+ return esnext ? [esm, esnext] : [esm];
173
+ }
174
+
175
+ export async function quiltPackageESModules({
176
+ root: rootPath = process.cwd(),
177
+ commonjs = false,
178
+ entries,
179
+ executable = {},
180
+ react,
181
+ bundle,
182
+ graphql = true,
183
+ customize,
184
+ }: PackageESModuleOptions = {}) {
185
+ const root = resolveRoot(rootPath);
186
+ const outputDirectory = path.resolve(root, 'build/esm');
187
+ const hasExecutables = Object.keys(executable).length > 0;
188
+
189
+ const [{sourceCode}, {esnext}, nodePlugins, packageJSON, browserGroup] =
190
+ await Promise.all([
191
+ import('./features/source-code.ts'),
192
+ import('./features/esnext.ts'),
193
+ getNodePlugins({bundle}),
194
+ loadPackageJSON(root),
195
+ getBrowserGroupTargetDetails({name: 'default'}, {root}),
196
+ ]);
197
+
198
+ const resolvedEntries =
199
+ entries ?? (await sourceEntriesForPackage(root, packageJSON));
200
+ const hasEntries = Object.keys(resolvedEntries).length > 0;
201
+
202
+ const source = sourceForEntries({...resolvedEntries, ...executable}, {root});
38
203
 
39
204
  const plugins: Plugin[] = [
40
205
  ...nodePlugins,
41
- sourceCode({mode: 'production'}),
42
- removeBuildFiles(['build/esm'], {root}),
206
+ sourceCode({mode: 'production', react}),
207
+ esnext({mode: 'production', babel: false}),
208
+ removeBuildFiles(
209
+ [
210
+ 'build/esm',
211
+ ...(commonjs ? ['build/cjs'] : []),
212
+ ...(hasExecutables ? ['bin'] : []),
213
+ ],
214
+ {root},
215
+ ),
43
216
  ];
44
217
 
218
+ if (hasExecutables) {
219
+ plugins.push(packageExecutables(executable, {root}));
220
+ }
221
+
45
222
  if (graphql) {
46
223
  const {graphql} = await import('./features/graphql.ts');
47
224
  plugins.push(graphql({manifest: false}));
48
225
  }
49
226
 
50
- return {
227
+ const generatedCode = await rollupGenerateOptionsForBrowsers(
228
+ browserGroup.browsers,
229
+ );
230
+
231
+ const output: OutputOptions[] = [
232
+ {
233
+ format: 'esm',
234
+ dir: outputDirectory,
235
+ entryFileNames: `[name].mjs`,
236
+ assetFileNames: `[name].[ext]`,
237
+ generatedCode,
238
+ // We only want to preserve the original directory structure if there
239
+ // are actual package entries.
240
+ ...(hasEntries
241
+ ? {
242
+ preserveModules: true,
243
+ preserveModulesRoot: source.root,
244
+ }
245
+ : {}),
246
+ },
247
+ ];
248
+
249
+ if (commonjs) {
250
+ output.push({
251
+ format: 'commonjs',
252
+ dir: path.resolve(outputDirectory, '../cjs'),
253
+ entryFileNames: `[name].cjs`,
254
+ assetFileNames: `[name].[ext]`,
255
+ preserveModules: true,
256
+ preserveModulesRoot: source.root,
257
+ generatedCode,
258
+ });
259
+ }
260
+
261
+ const options = {
51
262
  input: source.files,
52
263
  plugins,
53
264
  onwarn(warning, defaultWarn) {
@@ -62,36 +273,78 @@ export async function quiltPackageESModules({
62
273
 
63
274
  defaultWarn(warning);
64
275
  },
65
- output: {
66
- preserveModules: true,
67
- preserveModulesRoot: source.root,
68
- format: 'esm',
69
- dir: outputDirectory,
70
- entryFileNames: `[name].mjs`,
71
- assetFileNames: `[name].[ext]`,
72
- },
276
+ output,
73
277
  } satisfies RollupOptions;
278
+
279
+ if (customize) {
280
+ if (typeof customize === 'function') {
281
+ return await customize(options);
282
+ } else {
283
+ const customizedPlugins = await customize.plugins;
284
+
285
+ return {
286
+ ...options,
287
+ ...customize,
288
+ plugins: [
289
+ ...options.plugins,
290
+ ...(Array.isArray(customizedPlugins)
291
+ ? customizedPlugins
292
+ : [customizedPlugins]),
293
+ ],
294
+ };
295
+ }
296
+ } else {
297
+ return options;
298
+ }
74
299
  }
75
300
 
301
+ /**
302
+ * Creates a special `esnext` build that is a minimally-processed version
303
+ * of your original source code, preserving native ESModules. This build is
304
+ * ideal for consumers, as it can be processed to transpile only what is
305
+ * needed for the consumer’s target. This will be output in an `esnext`
306
+ * subdirectory of your default build directory. To have consumers prefer
307
+ * this build, make sure that your package.json lists the `quilt:esnext`
308
+ * export condition first for all your export declarations:
309
+ *
310
+ * ```json
311
+ * {
312
+ * "exports": {
313
+ * ".": {
314
+ * "quilt:esnext": "./build/esnext/index.esnext",
315
+ * "import": "./build/esm/index.mjs"
316
+ * }
317
+ * }
318
+ * }
319
+ * ```
320
+ */
76
321
  export async function quiltPackageESNext({
77
322
  root: rootPath = process.cwd(),
323
+ react,
78
324
  graphql = true,
79
- }: PackageOptions = {}) {
80
- const root =
81
- typeof rootPath === 'string' ? rootPath : fileURLToPath(rootPath);
325
+ entries,
326
+ bundle,
327
+ customize,
328
+ }: PackageBaseOptions = {}) {
329
+ const root = resolveRoot(rootPath);
82
330
  const outputDirectory = path.join(root, 'build/esnext');
83
331
 
84
- const [{sourceCode}, nodePlugins, packageJSON] = await Promise.all([
332
+ const [{sourceCode}, {esnext}, nodePlugins, packageJSON] = await Promise.all([
85
333
  import('./features/source-code.ts'),
86
- getNodePlugins(),
334
+ import('./features/esnext.ts'),
335
+ getNodePlugins({bundle}),
87
336
  loadPackageJSON(root),
88
337
  ]);
89
338
 
90
- const source = await sourceForPackage(root, packageJSON);
339
+ const resolvedEntries =
340
+ entries ?? (await sourceEntriesForPackage(root, packageJSON));
341
+
342
+ const source = sourceForEntries(resolvedEntries, {root});
91
343
 
92
344
  const plugins: Plugin[] = [
93
345
  ...nodePlugins,
94
- sourceCode({mode: 'production', babel: false}),
346
+ sourceCode({mode: 'production', babel: false, react}),
347
+ esnext({mode: 'production', babel: false}),
95
348
  removeBuildFiles(['build/esnext'], {root}),
96
349
  ];
97
350
 
@@ -100,7 +353,7 @@ export async function quiltPackageESNext({
100
353
  plugins.push(graphql({manifest: false}));
101
354
  }
102
355
 
103
- return {
356
+ const options = {
104
357
  input: source.files,
105
358
  plugins,
106
359
  onwarn(warning, defaultWarn) {
@@ -122,15 +375,120 @@ export async function quiltPackageESNext({
122
375
  dir: outputDirectory,
123
376
  entryFileNames: `[name].esnext`,
124
377
  assetFileNames: `[name].[ext]`,
378
+ generatedCode: 'es2015',
125
379
  },
126
380
  } satisfies RollupOptions;
381
+
382
+ if (customize) {
383
+ if (typeof customize === 'function') {
384
+ return await customize(options);
385
+ } else {
386
+ const customizedPlugins = await customize.plugins;
387
+
388
+ return {
389
+ ...options,
390
+ ...customize,
391
+ plugins: [
392
+ ...options.plugins,
393
+ ...(Array.isArray(customizedPlugins)
394
+ ? customizedPlugins
395
+ : [customizedPlugins]),
396
+ ],
397
+ };
398
+ }
399
+ } else {
400
+ return options;
401
+ }
127
402
  }
128
403
 
129
- async function sourceForPackage(root: string, packageJSON: PackageJSON) {
130
- const [entries] = await Promise.all([
131
- sourceEntriesForPackage(root, packageJSON),
132
- ]);
404
+ const exec = promisify(execCommand);
405
+
406
+ export function packageExecutables(
407
+ executables: Record<string, string>,
408
+ {root, nodeOptions = []}: {root: string; nodeOptions?: readonly string[]},
409
+ ) {
410
+ return {
411
+ name: '@quilted/package-executables',
412
+ async generateBundle() {
413
+ await Promise.all(
414
+ Object.entries(executables).map(async ([name, source]) => {
415
+ await writeExecutable(name, source);
416
+ }),
417
+ );
418
+ },
419
+ } satisfies Plugin;
420
+
421
+ async function writeExecutable(name: string, source: string) {
422
+ const sourceExtension = path.extname(source);
423
+ let buildFileForSource = source.replace('source', 'build/esm');
424
+ buildFileForSource = path.join(
425
+ path.dirname(buildFileForSource),
426
+ `${path.basename(buildFileForSource, sourceExtension)}.mjs`,
427
+ );
428
+
429
+ const executableFile = path.resolve(
430
+ root,
431
+ 'bin',
432
+ // Node needs a .mjs extension to parse the file as ESM
433
+ name.endsWith('.mjs') ? name : `${name}.mjs`,
434
+ );
435
+
436
+ const relativeFromExecutable = normalizedRelative(
437
+ path.dirname(executableFile),
438
+ path.resolve(root, buildFileForSource),
439
+ );
440
+
441
+ // Cross-platform node options override borrowed from
442
+ // https://github.com/cloudflare/miniflare/blob/master/packages/miniflare/bootstrap.js#L29-L47
443
+ const executableContent =
444
+ nodeOptions.length > 0
445
+ ? multiline`
446
+ #!/usr/bin/env node
447
+
448
+ import {spawn} from 'child_process';
449
+ import {fileURLToPath} from 'url';
450
+ import {dirname, resolve} from 'path';
451
+
452
+ const executableFile = resolve(
453
+ dirname(fileURLToPath(import.meta.url)),
454
+ ${JSON.stringify(relativeFromExecutable)},
455
+ );
456
+
457
+ spawn(
458
+ process.execPath,
459
+ [
460
+ ${nodeOptions
461
+ .map((option) => ` ${JSON.stringify(option)},`)
462
+ .join('\n')}
463
+ ...process.execArgv,
464
+ executableFile,
465
+ ...process.argv.slice(2),
466
+ ],
467
+ {stdio: 'inherit'},
468
+ ).on('exit', (code) => {
469
+ process.exit(code == null ? 1 : code);
470
+ });
471
+ `
472
+ : multiline`
473
+ #!/usr/bin/env node
474
+ import ${JSON.stringify(relativeFromExecutable)};
475
+ `;
476
+
477
+ await fs.mkdir(path.dirname(executableFile), {recursive: true});
478
+ await fs.writeFile(executableFile, executableContent, 'utf8');
479
+ await exec(`chmod +x ${executableFile}`);
480
+ }
481
+ }
482
+
483
+ function normalizedRelative(from: string, to: string) {
484
+ const rel = path.relative(from, to);
485
+ return rel.startsWith('.') ? rel : `./${rel}`;
486
+ }
133
487
 
488
+ function sourceForEntries(
489
+ entries: Record<string, string>,
490
+ {root}: {root: string},
491
+ ) {
134
492
  let sourceRoot = root;
135
493
 
136
494
  const sourceEntryFiles = Object.values(entries);