@sse-ui/builder 1.0.0 → 1.0.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.
@@ -1,609 +1,401 @@
1
- import * as fs from "node:fs/promises";
2
- import * as path from "node:path";
3
- import { globby } from "globby";
4
- import { minimatch } from "minimatch";
5
- import * as semver from "semver";
6
- import { PackageJson } from "../core/packageJson";
7
-
8
- export type BundleType = "esm" | "cjs";
9
- export type PackageType = "module" | "commonjs";
10
-
11
- interface GetOutExtensionOptions {
12
- isType?: boolean;
13
- isFlat?: boolean;
14
- packageType?: PackageType;
15
- }
16
-
17
- export function getOutExtension(
18
- bundle: BundleType,
19
- options: GetOutExtensionOptions = {},
20
- ) {
21
- const { isType = false, isFlat = false, packageType = "commonjs" } = options;
22
- const normalizedPackageType: PackageType =
23
- packageType === "module" ? "module" : "commonjs";
24
-
25
- if (!isFlat) {
26
- return isType ? ".d.ts" : ".js";
27
- }
28
-
29
- if (isType) {
30
- if (normalizedPackageType === "module") {
31
- return bundle === "esm" ? ".d.ts" : ".d.cts";
32
- }
33
- return bundle === "cjs" ? ".d.ts" : ".d.mts";
34
- }
35
-
36
- if (normalizedPackageType === "module") {
37
- return bundle === "esm" ? ".js" : ".cjs";
38
- }
39
-
40
- return bundle === "cjs" ? ".js" : ".mjs";
41
- }
42
-
43
- interface CreateExportsFor {
44
- importPath: NonNullable<PackageJson.Exports>;
45
- key: string;
46
- cwd: string;
47
- dir: string;
48
- type: string;
49
- newExports: PackageJson.ExportConditions;
50
- typeOutExtension: string;
51
- outExtension: string;
52
- addTypes: boolean;
53
- }
54
-
55
- async function createExportsFor({
56
- importPath,
57
- key,
58
- cwd,
59
- dir,
60
- type,
61
- newExports,
62
- typeOutExtension,
63
- outExtension,
64
- addTypes,
65
- }: CreateExportsFor): Promise<void> {
66
- if (Array.isArray(importPath)) {
67
- throw new Error(
68
- `Array form of package.json exports is not supported yet. Found in export "${key}".`,
69
- );
70
- }
71
-
72
- let srcPath =
73
- typeof importPath === "string" ? importPath : importPath["sse-src"];
74
- const rest = typeof importPath === "string" ? {} : { ...importPath };
75
- delete rest["sse-src"];
76
-
77
- if (typeof srcPath !== "string") {
78
- throw new Error(
79
- `Unsupported export for "${key}". Only a string or an object with "sse-src" field is supported for now.`,
80
- );
81
- }
82
-
83
- const exportFileExists = srcPath.includes("*")
84
- ? true
85
- : await fs.stat(path.join(cwd, srcPath)).then(
86
- (stats) => stats.isFile() || stats.isDirectory(),
87
- () => false,
88
- );
89
-
90
- if (!exportFileExists) {
91
- throw new Error(
92
- `The import path "${srcPath}" for export "${key}" does not exist in the package. Either remove the export or add the file/folder to the package.`,
93
- );
94
- }
95
-
96
- srcPath = srcPath.replace(/\.\/src\//, `./${dir === "." ? "" : `${dir}/`}`);
97
- const ext = path.extname(srcPath);
98
-
99
- if (ext === ".css") {
100
- newExports[key] = srcPath;
101
- return;
102
- }
103
-
104
- if (typeof newExports[key] === "string" || Array.isArray(newExports[key])) {
105
- throw new Error(
106
- `The export "${key}" is already defined as a string or Array.`,
107
- );
108
- }
109
-
110
- newExports[key] ??= {};
111
- const exportPath = srcPath.replace(ext, outExtension);
112
- newExports[key][type === "cjs" ? "require" : "import"] = addTypes
113
- ? {
114
- ...rest,
115
- types: srcPath.replace(ext, typeOutExtension),
116
- default: exportPath,
117
- }
118
- : Object.keys(rest).length
119
- ? {
120
- ...rest,
121
- default: exportPath,
122
- }
123
- : exportPath;
124
- }
125
-
126
- interface GlobEntry {
127
- value: PackageJson.Exports;
128
- srcPattern: string;
129
- srcPrefix: string;
130
- srcSuffix: string;
131
- keyPrefix: string;
132
- keySuffix: string;
133
- }
134
-
135
- /**
136
- * Expands glob patterns (containing `*`) in package.json export keys/values
137
- * into concrete entries by resolving them against actual files on disk.
138
- */
139
- async function expandExportGlobs(
140
- originalExports: PackageJson.ExportConditions,
141
- cwd: string,
142
- ) {
143
- const expandedExports: PackageJson.ExportConditions = {};
144
- const globEntries: GlobEntry[] = [];
145
- const negationPatterns: string[] = [];
146
-
147
- for (const [key, value] of Object.entries(originalExports)) {
148
- if (value === null) {
149
- if (key.includes("*")) {
150
- negationPatterns.push(key);
151
- } else {
152
- delete expandedExports[key];
153
- }
154
- continue;
155
- }
156
-
157
- if (!key.includes("*")) {
158
- expandedExports[key] = value;
159
- continue;
160
- }
161
-
162
- // Extract the source pattern from the value
163
- let srcPattern: string | undefined;
164
- if (typeof value === "string") {
165
- srcPattern = value;
166
- } else if (value && typeof value === "object" && !Array.isArray(value)) {
167
- srcPattern = value["sse-src"] as string | undefined;
168
- }
169
-
170
- if (typeof srcPattern !== "string" || !srcPattern.includes("*")) {
171
- expandedExports[key] = value;
172
- continue;
173
- }
174
-
175
- // Split patterns around the * wildcard
176
- const srcStarIndex = srcPattern.indexOf("*");
177
- const srcPrefix = srcPattern.substring(0, srcStarIndex);
178
- const srcSuffix = srcPattern.substring(srcStarIndex + 1);
179
-
180
- const keyStarIndex = key.indexOf("*");
181
- const keyPrefix = key.substring(0, keyStarIndex);
182
- const keySuffix = key.substring(keyStarIndex + 1);
183
-
184
- globEntries.push({
185
- value,
186
- srcPattern,
187
- srcPrefix,
188
- srcSuffix,
189
- keyPrefix,
190
- keySuffix,
191
- });
192
- }
193
-
194
- // Resolve all globby calls in parallel
195
- const globResults = await Promise.all(
196
- globEntries.map(({ srcPattern }) => globby(srcPattern, { cwd })),
197
- );
198
-
199
- for (let i = 0; i < globEntries.length; i += 1) {
200
- const { value, srcPrefix, srcSuffix, keyPrefix, keySuffix } =
201
- globEntries[i];
202
- const matches = globResults[i];
203
-
204
- const stems = [];
205
- for (const match of matches) {
206
- if (match.startsWith(srcPrefix) && match.endsWith(srcSuffix)) {
207
- const stem =
208
- srcSuffix.length > 0
209
- ? match.substring(srcPrefix.length, match.length - srcSuffix.length)
210
- : match.substring(srcPrefix.length);
211
- if (stem.length > 0) {
212
- stems.push(stem);
213
- }
214
- }
215
- }
216
-
217
- stems.sort();
218
-
219
- for (const stem of stems) {
220
- const expandedKey = `${keyPrefix}${stem}${keySuffix}`;
221
- const expandedSrcPath = `${srcPrefix}${stem}${srcSuffix}`;
222
-
223
- if (typeof value === "string") {
224
- expandedExports[expandedKey] = expandedSrcPath;
225
- } else {
226
- expandedExports[expandedKey] = {
227
- ...value,
228
- "sse-src": expandedSrcPath,
229
- };
230
- }
231
- }
232
- }
233
-
234
- // Apply negation patterns: remove any expanded keys that match a null-valued glob.
235
- // If no keys matched, preserve the pattern itself with null to block that path at runtime.
236
- for (const pattern of negationPatterns) {
237
- let matched = false;
238
- for (const expandedKey of Object.keys(expandedExports)) {
239
- if (minimatch(expandedKey, pattern)) {
240
- delete expandedExports[expandedKey];
241
- matched = true;
242
- }
243
- }
244
- if (!matched) {
245
- expandedExports[pattern] = null;
246
- }
247
- }
248
-
249
- return expandedExports;
250
- }
251
-
252
- interface CreatePackageExports {
253
- exports: PackageJson["exports"];
254
- bundles: { type: BundleType; dir: string }[];
255
- outputDir: string;
256
- cwd: string;
257
- addTypes: boolean;
258
- isFlat: boolean;
259
- packageType: PackageType;
260
- }
261
-
262
- export async function createPackageExports({
263
- exports: packageExports,
264
- bundles,
265
- outputDir,
266
- cwd,
267
- addTypes = false,
268
- isFlat = false,
269
- packageType = "commonjs",
270
- }: CreatePackageExports) {
271
- const resolvedPackageType = packageType === "module" ? "module" : "commonjs";
272
- const rawExports: PackageJson.ExportConditions =
273
- typeof packageExports === "string" || Array.isArray(packageExports)
274
- ? { ".": packageExports }
275
- : packageExports || {};
276
-
277
- const originalExports = isFlat
278
- ? await expandExportGlobs(rawExports, cwd)
279
- : rawExports;
280
-
281
- const newExports: PackageJson.ExportConditions = {
282
- "./package.json": "./package.json",
283
- };
284
-
285
- const result: {
286
- main?: string;
287
- types?: string;
288
- exports: PackageJson.ExportConditions;
289
- } = {
290
- exports: newExports,
291
- };
292
-
293
- await Promise.all(
294
- bundles.map(async ({ type, dir }) => {
295
- const outExtension = getOutExtension(type, {
296
- isFlat,
297
- packageType: resolvedPackageType,
298
- });
299
- const typeOutExtension = getOutExtension(type, {
300
- isFlat,
301
- isType: true,
302
- packageType: resolvedPackageType,
303
- });
304
- const indexFileExists = await fs
305
- .stat(path.join(outputDir, dir, `index${outExtension}`))
306
- .then(
307
- (stats) => stats.isFile(),
308
- () => false,
309
- );
310
- const typeFileExists =
311
- addTypes &&
312
- (await fs
313
- .stat(path.join(outputDir, dir, `index${typeOutExtension}`))
314
- .then(
315
- (stats) => stats.isFile(),
316
- () => false,
317
- ));
318
- const dirPrefix = dir === "." ? "" : `${dir}/`;
319
- const exportDir = `./${dirPrefix}index${outExtension}`;
320
- const typeExportDir = `./${dirPrefix}index${typeOutExtension}`;
321
-
322
- if (indexFileExists) {
323
- // skip `packageJson.module` to support parcel and some older bundlers
324
- if (type === "cjs") {
325
- result.main = exportDir;
326
- }
327
-
328
- if (
329
- typeof newExports["."] === "string" ||
330
- Array.isArray(newExports["."])
331
- ) {
332
- throw new Error(
333
- `The export "." is already defined as a string or Array.`,
334
- );
335
- }
336
-
337
- newExports["."] ??= {};
338
- newExports["."][type === "cjs" ? "require" : "import"] = typeFileExists
339
- ? {
340
- types: typeExportDir,
341
- default: exportDir,
342
- }
343
- : exportDir;
344
- }
345
- if (typeFileExists && type === "cjs") {
346
- result.types = typeExportDir;
347
- }
348
- const exportKeys = Object.keys(originalExports);
349
- // need to maintain the order of exports
350
- for (const key of exportKeys) {
351
- const importPath = originalExports[key];
352
- if (!importPath) {
353
- newExports[key] = null;
354
- continue;
355
- }
356
- // eslint-disable-next-line no-await-in-loop
357
- await createExportsFor({
358
- importPath,
359
- key,
360
- cwd,
361
- dir,
362
- type,
363
- newExports,
364
- typeOutExtension,
365
- outExtension,
366
- addTypes,
367
- });
368
- }
369
- }),
370
- );
371
-
372
- bundles.forEach(({ dir }) => {
373
- if (dir !== ".") {
374
- newExports[`./${dir}`] = null;
375
- }
376
- });
377
-
378
- Object.keys(newExports).forEach((key) => {
379
- const exportVal = newExports[key];
380
- if (Array.isArray(exportVal)) {
381
- throw new Error(
382
- `Array form of package.json exports is not supported yet. Found in export "${key}".`,
383
- );
384
- }
385
- if (
386
- exportVal &&
387
- typeof exportVal === "object" &&
388
- (exportVal.import || exportVal.require)
389
- ) {
390
- // Use ESM (import) for default if available, otherwise use require
391
- const defaultExport = exportVal.import || exportVal.require;
392
-
393
- if (addTypes) {
394
- exportVal.default = defaultExport;
395
- } else {
396
- exportVal.default =
397
- defaultExport &&
398
- typeof defaultExport === "object" &&
399
- "default" in defaultExport
400
- ? defaultExport.default
401
- : defaultExport;
402
- }
403
- }
404
- });
405
-
406
- return result;
407
- }
408
-
409
- interface CreatePackageBin {
410
- bin: PackageJson["bin"];
411
- bundles: { type: BundleType; dir: string }[];
412
- cwd: string;
413
- isFlat: boolean;
414
- packageType: PackageType;
415
- }
416
-
417
- export async function createPackageBin({
418
- bin,
419
- bundles,
420
- cwd,
421
- isFlat = false,
422
- packageType,
423
- }: CreatePackageBin): Promise<string | Record<string, string> | undefined> {
424
- if (!bin) {
425
- return undefined;
426
- }
427
-
428
- const bundleToUse = bundles.find((b) => b.type === "esm") || bundles[0];
429
- const binOutExtension = getOutExtension(bundleToUse.type, {
430
- isFlat,
431
- packageType,
432
- });
433
-
434
- const binsToProcess = typeof bin === "string" ? { __bin__: bin } : bin;
435
- const newBin: Record<string, string> = {};
436
-
437
- for (const [binKey, binPath] of Object.entries(binsToProcess)) {
438
- // make sure the actual file exists
439
- const binFileExists =
440
- binPath &&
441
- // eslint-disable-next-line no-await-in-loop
442
- (await fs.stat(path.join(cwd, binPath)).then(
443
- (stats) => stats.isFile(),
444
- () => false,
445
- ));
446
- if (!binFileExists) {
447
- throw new Error(
448
- `The bin file "${binPath}" for key "${binKey}" does not exist in the package. Please fix the "bin" field in package.json and point it to the source file.`,
449
- );
450
- }
451
- if (typeof binPath !== "string") {
452
- throw new Error(`The bin path for "${binKey}" should be a string.`);
453
- }
454
- const ext = path.extname(binPath);
455
- newBin[binKey] = binPath
456
- .replace(
457
- /(\.\/)?src\//,
458
- bundleToUse.dir === "." ? "./" : `./${bundleToUse.dir}/`,
459
- )
460
- .replace(new RegExp(`\\${ext}$`), binOutExtension);
461
- }
462
-
463
- if (Object.keys(newBin).length === 1 && newBin.__bin__) {
464
- return newBin.__bin__;
465
- }
466
-
467
- return newBin;
468
- }
469
-
470
- /**
471
- * Validates the package.json before building.
472
- */
473
- export function validatePkgJson(
474
- packageJson: Record<string, any>,
475
- options: { skipMainCheck?: boolean; enableReactCompiler?: boolean } = {},
476
- ): void {
477
- const { skipMainCheck = false, enableReactCompiler = false } = options;
478
- const errors: string[] = [];
479
- const buildDirBase = packageJson.publishConfig?.directory;
480
- if (!buildDirBase) {
481
- errors.push(
482
- `No build directory specified in "${packageJson.name}" package.json. Specify it in the "publishConfig.directory" field.`,
483
- );
484
- }
485
-
486
- if (packageJson.private === false) {
487
- errors.push(
488
- `Remove the field "private": false from "${packageJson.name}" package.json. This is redundant.`,
489
- );
490
- }
491
-
492
- if (!skipMainCheck) {
493
- if (packageJson.main) {
494
- errors.push(
495
- `Remove the field "main" from "${packageJson.name}" package.json. Add it as "exports["."]" instead.`,
496
- );
497
- }
498
-
499
- if (packageJson.module) {
500
- errors.push(
501
- `Remove the field "module" from "${packageJson.name}" package.json. Add it as "exports["."]" instead.`,
502
- );
503
- }
504
-
505
- if (packageJson.types || packageJson.typings) {
506
- errors.push(
507
- `Remove the field "types/typings" from "${packageJson.name}" package.json. Add it as "exports["."]" instead.`,
508
- );
509
- }
510
- }
511
-
512
- const reactVersion = packageJson.peerDependencies?.react;
513
- if (enableReactCompiler) {
514
- if (!reactVersion) {
515
- errors.push(
516
- 'When building with React compiler, "react" must be specified as a peerDependency in package.json.',
517
- );
518
- }
519
- const minSupportedReactVersion = semver.minVersion(reactVersion);
520
- if (!minSupportedReactVersion) {
521
- errors.push(
522
- `Unable to determine the minimum supported React version from the peerDependency range: "${reactVersion}".`,
523
- );
524
- } else if (
525
- semver.lt(minSupportedReactVersion, "19.0.0") &&
526
- !packageJson.peerDependencies?.["react-compiler-runtime"] &&
527
- !packageJson.dependencies?.["react-compiler-runtime"]
528
- ) {
529
- errors.push(
530
- 'When building with React compiler for React versions below 19, "react-compiler-runtime" must be specified as a dependency or peerDependency in package.json.',
531
- );
532
- }
533
- }
534
-
535
- if (errors.length > 0) {
536
- const error = new Error(errors.join("\n"));
537
- throw error;
538
- }
539
- }
540
-
541
- /**
542
- * Marks the start and end of a function execution for performance measurement.
543
- * Uses the Performance API to create marks and measure the duration.
544
- */
545
- export async function markFn<F extends () => Promise<any>>(
546
- label: string,
547
- fn: () => ReturnType<F>,
548
- ): Promise<ReturnType<F>> {
549
- const startMark = `${label}-start`;
550
- const endMark = `${label}-end`;
551
- performance.mark(startMark);
552
- const result = await fn();
553
- performance.mark(endMark);
554
- performance.measure(label, startMark, endMark);
555
- return result;
556
- }
557
-
558
- export function measureFn(label: string) {
559
- const startMark = `${label}-start`;
560
- const endMark = `${label}-end`;
561
- return performance.measure(label, startMark, endMark);
562
- }
563
-
564
- export const BASE_IGNORES = [
565
- "**/*.test.js",
566
- "**/*.test.ts",
567
- "**/*.test.tsx",
568
- "**/*.spec.js",
569
- "**/*.spec.ts",
570
- "**/*.spec.tsx",
571
- "**/*.d.ts",
572
- "**/*.test/*.*",
573
- "**/test-cases/*.*",
574
- ];
575
-
576
- /**
577
- * A utility to map a function over an array of items in a worker pool.
578
- *
579
- * This function will create a pool of workers and distribute the items to be processed among them.
580
- * Each worker will process items sequentially, but multiple workers will run in parallel.
581
- */
582
- export async function mapConcurrently<T, R>(
583
- items: T[],
584
- mapper: (item: T) => Promise<R>,
585
- concurrency: number,
586
- ): Promise<(R | Error)[]> {
587
- if (!items.length) {
588
- return Promise.resolve([]);
589
- }
590
-
591
- const itemIterator = items.entries();
592
- const count = Math.min(concurrency, items.length);
593
- const workers = [];
594
-
595
- const results: (R | Error)[] = new Array(items.length);
596
- for (let i = 0; i < count; i += 1) {
597
- const worker = Promise.resolve().then(async () => {
598
- for (const [index, item] of itemIterator) {
599
- // eslint-disable-next-line no-await-in-loop
600
- const res = await mapper(item);
601
- results[index] = res;
602
- }
603
- });
604
- workers.push(worker);
605
- }
606
-
607
- await Promise.all(workers);
608
- return results;
609
- }
1
+ // src/utils/build.ts
2
+ import * as fs from "fs/promises";
3
+ import * as path from "path";
4
+ import { globby } from "globby";
5
+ import { minimatch } from "minimatch";
6
+ import * as semver from "semver";
7
+ function getOutExtension(bundle, options = {}) {
8
+ const { isType = false, isFlat = false, packageType = "commonjs" } = options;
9
+ const normalizedPackageType = packageType === "module" ? "module" : "commonjs";
10
+ if (!isFlat) {
11
+ return isType ? ".d.ts" : ".js";
12
+ }
13
+ if (isType) {
14
+ if (normalizedPackageType === "module") {
15
+ return bundle === "esm" ? ".d.ts" : ".d.cts";
16
+ }
17
+ return bundle === "cjs" ? ".d.ts" : ".d.mts";
18
+ }
19
+ if (normalizedPackageType === "module") {
20
+ return bundle === "esm" ? ".js" : ".cjs";
21
+ }
22
+ return bundle === "cjs" ? ".js" : ".mjs";
23
+ }
24
+ async function createExportsFor({
25
+ importPath,
26
+ key,
27
+ cwd,
28
+ dir,
29
+ type,
30
+ newExports,
31
+ typeOutExtension,
32
+ outExtension,
33
+ addTypes
34
+ }) {
35
+ if (Array.isArray(importPath)) {
36
+ throw new Error(
37
+ `Array form of package.json exports is not supported yet. Found in export "${key}".`
38
+ );
39
+ }
40
+ let srcPath = typeof importPath === "string" ? importPath : importPath["sse-src"];
41
+ const rest = typeof importPath === "string" ? {} : { ...importPath };
42
+ delete rest["sse-src"];
43
+ if (typeof srcPath !== "string") {
44
+ throw new Error(
45
+ `Unsupported export for "${key}". Only a string or an object with "sse-src" field is supported for now.`
46
+ );
47
+ }
48
+ const exportFileExists = srcPath.includes("*") ? true : await fs.stat(path.join(cwd, srcPath)).then(
49
+ (stats) => stats.isFile() || stats.isDirectory(),
50
+ () => false
51
+ );
52
+ if (!exportFileExists) {
53
+ throw new Error(
54
+ `The import path "${srcPath}" for export "${key}" does not exist in the package. Either remove the export or add the file/folder to the package.`
55
+ );
56
+ }
57
+ srcPath = srcPath.replace(/\.\/src\//, `./${dir === "." ? "" : `${dir}/`}`);
58
+ const ext = path.extname(srcPath);
59
+ if (ext === ".css") {
60
+ newExports[key] = srcPath;
61
+ return;
62
+ }
63
+ if (typeof newExports[key] === "string" || Array.isArray(newExports[key])) {
64
+ throw new Error(
65
+ `The export "${key}" is already defined as a string or Array.`
66
+ );
67
+ }
68
+ newExports[key] ??= {};
69
+ const exportPath = srcPath.replace(ext, outExtension);
70
+ newExports[key][type === "cjs" ? "require" : "import"] = addTypes ? {
71
+ ...rest,
72
+ types: srcPath.replace(ext, typeOutExtension),
73
+ default: exportPath
74
+ } : Object.keys(rest).length ? {
75
+ ...rest,
76
+ default: exportPath
77
+ } : exportPath;
78
+ }
79
+ async function expandExportGlobs(originalExports, cwd) {
80
+ const expandedExports = {};
81
+ const globEntries = [];
82
+ const negationPatterns = [];
83
+ for (const [key, value] of Object.entries(originalExports)) {
84
+ if (value === null) {
85
+ if (key.includes("*")) {
86
+ negationPatterns.push(key);
87
+ } else {
88
+ delete expandedExports[key];
89
+ }
90
+ continue;
91
+ }
92
+ if (!key.includes("*")) {
93
+ expandedExports[key] = value;
94
+ continue;
95
+ }
96
+ let srcPattern;
97
+ if (typeof value === "string") {
98
+ srcPattern = value;
99
+ } else if (value && typeof value === "object" && !Array.isArray(value)) {
100
+ srcPattern = value["sse-src"];
101
+ }
102
+ if (typeof srcPattern !== "string" || !srcPattern.includes("*")) {
103
+ expandedExports[key] = value;
104
+ continue;
105
+ }
106
+ const srcStarIndex = srcPattern.indexOf("*");
107
+ const srcPrefix = srcPattern.substring(0, srcStarIndex);
108
+ const srcSuffix = srcPattern.substring(srcStarIndex + 1);
109
+ const keyStarIndex = key.indexOf("*");
110
+ const keyPrefix = key.substring(0, keyStarIndex);
111
+ const keySuffix = key.substring(keyStarIndex + 1);
112
+ globEntries.push({
113
+ value,
114
+ srcPattern,
115
+ srcPrefix,
116
+ srcSuffix,
117
+ keyPrefix,
118
+ keySuffix
119
+ });
120
+ }
121
+ const globResults = await Promise.all(
122
+ globEntries.map(({ srcPattern }) => globby(srcPattern, { cwd }))
123
+ );
124
+ for (let i = 0; i < globEntries.length; i += 1) {
125
+ const { value, srcPrefix, srcSuffix, keyPrefix, keySuffix } = globEntries[i];
126
+ const matches = globResults[i];
127
+ const stems = [];
128
+ for (const match of matches) {
129
+ if (match.startsWith(srcPrefix) && match.endsWith(srcSuffix)) {
130
+ const stem = srcSuffix.length > 0 ? match.substring(srcPrefix.length, match.length - srcSuffix.length) : match.substring(srcPrefix.length);
131
+ if (stem.length > 0) {
132
+ stems.push(stem);
133
+ }
134
+ }
135
+ }
136
+ stems.sort();
137
+ for (const stem of stems) {
138
+ const expandedKey = `${keyPrefix}${stem}${keySuffix}`;
139
+ const expandedSrcPath = `${srcPrefix}${stem}${srcSuffix}`;
140
+ if (typeof value === "string") {
141
+ expandedExports[expandedKey] = expandedSrcPath;
142
+ } else {
143
+ expandedExports[expandedKey] = {
144
+ ...value,
145
+ "sse-src": expandedSrcPath
146
+ };
147
+ }
148
+ }
149
+ }
150
+ for (const pattern of negationPatterns) {
151
+ let matched = false;
152
+ for (const expandedKey of Object.keys(expandedExports)) {
153
+ if (minimatch(expandedKey, pattern)) {
154
+ delete expandedExports[expandedKey];
155
+ matched = true;
156
+ }
157
+ }
158
+ if (!matched) {
159
+ expandedExports[pattern] = null;
160
+ }
161
+ }
162
+ return expandedExports;
163
+ }
164
+ async function createPackageExports({
165
+ exports: packageExports,
166
+ bundles,
167
+ outputDir,
168
+ cwd,
169
+ addTypes = false,
170
+ isFlat = false,
171
+ packageType = "commonjs"
172
+ }) {
173
+ const resolvedPackageType = packageType === "module" ? "module" : "commonjs";
174
+ const rawExports = typeof packageExports === "string" || Array.isArray(packageExports) ? { ".": packageExports } : packageExports || {};
175
+ const originalExports = isFlat ? await expandExportGlobs(rawExports, cwd) : rawExports;
176
+ const newExports = {
177
+ "./package.json": "./package.json"
178
+ };
179
+ const result = {
180
+ exports: newExports
181
+ };
182
+ await Promise.all(
183
+ bundles.map(async ({ type, dir }) => {
184
+ const outExtension = getOutExtension(type, {
185
+ isFlat,
186
+ packageType: resolvedPackageType
187
+ });
188
+ const typeOutExtension = getOutExtension(type, {
189
+ isFlat,
190
+ isType: true,
191
+ packageType: resolvedPackageType
192
+ });
193
+ const indexFileExists = await fs.stat(path.join(outputDir, dir, `index${outExtension}`)).then(
194
+ (stats) => stats.isFile(),
195
+ () => false
196
+ );
197
+ const typeFileExists = addTypes && await fs.stat(path.join(outputDir, dir, `index${typeOutExtension}`)).then(
198
+ (stats) => stats.isFile(),
199
+ () => false
200
+ );
201
+ const dirPrefix = dir === "." ? "" : `${dir}/`;
202
+ const exportDir = `./${dirPrefix}index${outExtension}`;
203
+ const typeExportDir = `./${dirPrefix}index${typeOutExtension}`;
204
+ if (indexFileExists) {
205
+ if (type === "cjs") {
206
+ result.main = exportDir;
207
+ }
208
+ if (typeof newExports["."] === "string" || Array.isArray(newExports["."])) {
209
+ throw new Error(
210
+ `The export "." is already defined as a string or Array.`
211
+ );
212
+ }
213
+ newExports["."] ??= {};
214
+ newExports["."][type === "cjs" ? "require" : "import"] = typeFileExists ? {
215
+ types: typeExportDir,
216
+ default: exportDir
217
+ } : exportDir;
218
+ }
219
+ if (typeFileExists && type === "cjs") {
220
+ result.types = typeExportDir;
221
+ }
222
+ const exportKeys = Object.keys(originalExports);
223
+ for (const key of exportKeys) {
224
+ const importPath = originalExports[key];
225
+ if (!importPath) {
226
+ newExports[key] = null;
227
+ continue;
228
+ }
229
+ await createExportsFor({
230
+ importPath,
231
+ key,
232
+ cwd,
233
+ dir,
234
+ type,
235
+ newExports,
236
+ typeOutExtension,
237
+ outExtension,
238
+ addTypes
239
+ });
240
+ }
241
+ })
242
+ );
243
+ bundles.forEach(({ dir }) => {
244
+ if (dir !== ".") {
245
+ newExports[`./${dir}`] = null;
246
+ }
247
+ });
248
+ Object.keys(newExports).forEach((key) => {
249
+ const exportVal = newExports[key];
250
+ if (Array.isArray(exportVal)) {
251
+ throw new Error(
252
+ `Array form of package.json exports is not supported yet. Found in export "${key}".`
253
+ );
254
+ }
255
+ if (exportVal && typeof exportVal === "object" && (exportVal.import || exportVal.require)) {
256
+ const defaultExport = exportVal.import || exportVal.require;
257
+ if (addTypes) {
258
+ exportVal.default = defaultExport;
259
+ } else {
260
+ exportVal.default = defaultExport && typeof defaultExport === "object" && "default" in defaultExport ? defaultExport.default : defaultExport;
261
+ }
262
+ }
263
+ });
264
+ return result;
265
+ }
266
+ async function createPackageBin({
267
+ bin,
268
+ bundles,
269
+ cwd,
270
+ isFlat = false,
271
+ packageType
272
+ }) {
273
+ if (!bin) {
274
+ return void 0;
275
+ }
276
+ const bundleToUse = bundles.find((b) => b.type === "esm") || bundles[0];
277
+ const binOutExtension = getOutExtension(bundleToUse.type, {
278
+ isFlat,
279
+ packageType
280
+ });
281
+ const binsToProcess = typeof bin === "string" ? { __bin__: bin } : bin;
282
+ const newBin = {};
283
+ for (const [binKey, binPath] of Object.entries(binsToProcess)) {
284
+ const binFileExists = binPath && // eslint-disable-next-line no-await-in-loop
285
+ await fs.stat(path.join(cwd, binPath)).then(
286
+ (stats) => stats.isFile(),
287
+ () => false
288
+ );
289
+ if (!binFileExists) {
290
+ throw new Error(
291
+ `The bin file "${binPath}" for key "${binKey}" does not exist in the package. Please fix the "bin" field in package.json and point it to the source file.`
292
+ );
293
+ }
294
+ if (typeof binPath !== "string") {
295
+ throw new Error(`The bin path for "${binKey}" should be a string.`);
296
+ }
297
+ const ext = path.extname(binPath);
298
+ newBin[binKey] = binPath.replace(
299
+ /(\.\/)?src\//,
300
+ bundleToUse.dir === "." ? "./" : `./${bundleToUse.dir}/`
301
+ ).replace(new RegExp(`\\${ext}$`), binOutExtension);
302
+ }
303
+ if (Object.keys(newBin).length === 1 && newBin.__bin__) {
304
+ return newBin.__bin__;
305
+ }
306
+ return newBin;
307
+ }
308
+ function validatePkgJson(packageJson, options = {}) {
309
+ const { skipMainCheck = false, enableReactCompiler = false } = options;
310
+ const errors = [];
311
+ const buildDirBase = packageJson.publishConfig?.directory;
312
+ if (!buildDirBase) {
313
+ errors.push(
314
+ `No build directory specified in "${packageJson.name}" package.json. Specify it in the "publishConfig.directory" field.`
315
+ );
316
+ }
317
+ if (packageJson.private === false) {
318
+ errors.push(
319
+ `Remove the field "private": false from "${packageJson.name}" package.json. This is redundant.`
320
+ );
321
+ }
322
+ if (!skipMainCheck) {
323
+ if (packageJson.main) {
324
+ errors.push(
325
+ `Remove the field "main" from "${packageJson.name}" package.json. Add it as "exports["."]" instead.`
326
+ );
327
+ }
328
+ if (packageJson.module) {
329
+ errors.push(
330
+ `Remove the field "module" from "${packageJson.name}" package.json. Add it as "exports["."]" instead.`
331
+ );
332
+ }
333
+ if (packageJson.types || packageJson.typings) {
334
+ errors.push(
335
+ `Remove the field "types/typings" from "${packageJson.name}" package.json. Add it as "exports["."]" instead.`
336
+ );
337
+ }
338
+ }
339
+ const reactVersion = packageJson.peerDependencies?.react;
340
+ if (enableReactCompiler) {
341
+ if (!reactVersion) {
342
+ errors.push(
343
+ 'When building with React compiler, "react" must be specified as a peerDependency in package.json.'
344
+ );
345
+ }
346
+ const minSupportedReactVersion = semver.minVersion(reactVersion);
347
+ if (!minSupportedReactVersion) {
348
+ errors.push(
349
+ `Unable to determine the minimum supported React version from the peerDependency range: "${reactVersion}".`
350
+ );
351
+ } else if (semver.lt(minSupportedReactVersion, "19.0.0") && !packageJson.peerDependencies?.["react-compiler-runtime"] && !packageJson.dependencies?.["react-compiler-runtime"]) {
352
+ errors.push(
353
+ 'When building with React compiler for React versions below 19, "react-compiler-runtime" must be specified as a dependency or peerDependency in package.json.'
354
+ );
355
+ }
356
+ }
357
+ if (errors.length > 0) {
358
+ const error = new Error(errors.join("\n"));
359
+ throw error;
360
+ }
361
+ }
362
+ var BASE_IGNORES = [
363
+ "**/*.test.js",
364
+ "**/*.test.ts",
365
+ "**/*.test.tsx",
366
+ "**/*.spec.js",
367
+ "**/*.spec.ts",
368
+ "**/*.spec.tsx",
369
+ "**/*.d.ts",
370
+ "**/*.test/*.*",
371
+ "**/test-cases/*.*"
372
+ ];
373
+ async function mapConcurrently(items, mapper, concurrency) {
374
+ if (!items.length) {
375
+ return Promise.resolve([]);
376
+ }
377
+ const itemIterator = items.entries();
378
+ const count = Math.min(concurrency, items.length);
379
+ const workers = [];
380
+ const results = new Array(items.length);
381
+ for (let i = 0; i < count; i += 1) {
382
+ const worker = Promise.resolve().then(async () => {
383
+ for (const [index, item] of itemIterator) {
384
+ const res = await mapper(item);
385
+ results[index] = res;
386
+ }
387
+ });
388
+ workers.push(worker);
389
+ }
390
+ await Promise.all(workers);
391
+ return results;
392
+ }
393
+
394
+ export {
395
+ getOutExtension,
396
+ createPackageExports,
397
+ createPackageBin,
398
+ validatePkgJson,
399
+ BASE_IGNORES,
400
+ mapConcurrently
401
+ };