bunchee 4.4.8 → 5.0.0-beta.2

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/dist/bin/cli.js CHANGED
@@ -26,13 +26,19 @@ const availableExtensions = new Set([
26
26
  'cts',
27
27
  'mts'
28
28
  ]);
29
- const suffixedExportConventions = new Set([
29
+ const runtimeExportConventions = new Set([
30
30
  'react-server',
31
31
  'react-native',
32
- 'edge-light',
32
+ 'edge-light'
33
+ ]);
34
+ const optimizeConventions = new Set([
33
35
  'development',
34
36
  'production'
35
37
  ]);
38
+ const specialExportConventions = new Set([
39
+ ...runtimeExportConventions,
40
+ ...optimizeConventions
41
+ ]);
36
42
  const SRC = 'src';
37
43
  const DIST = 'dist';
38
44
  const dtsExtensionsMap = {
@@ -52,6 +58,7 @@ const DEFAULT_TS_CONFIG = {
52
58
  moduleResolution: 'bundler'
53
59
  }
54
60
  };
61
+ const BINARY_TAG = '$binary';
55
62
 
56
63
  function getDefaultExportFromCjs (x) {
57
64
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
@@ -158,256 +165,147 @@ function fileExists(filePath) {
158
165
  }
159
166
  const hasAvailableExtension = (filename)=>availableExtensions.has(path__default.default.extname(filename).slice(1));
160
167
  const hasCjsExtension = (filename)=>path__default.default.extname(filename) === '.cjs';
168
+ const getMainFieldExportType = (pkg)=>{
169
+ const isEsmPkg = isESModulePackage(pkg.type);
170
+ const mainExportType = isEsmPkg && pkg.main ? hasCjsExtension(pkg.main) ? 'require' : 'import' : 'require';
171
+ return mainExportType;
172
+ };
161
173
  // TODO: add unit test
162
174
  const baseNameWithoutExtension = (filename)=>path__default.default.basename(filename, path__default.default.extname(filename));
163
175
  const isTestFile = (filename)=>/\.(test|spec)$/.test(baseNameWithoutExtension(filename));
164
-
165
- function getPackageTypings(pkg) {
166
- return pkg.types || pkg.typings;
167
- }
168
- // Reached the end of the export path
169
- function isExportLike(field) {
170
- if (typeof field === 'string') return true;
171
- return Object.entries(field).every(// Every value is string and key is not start with '.'
172
- ([key, value])=>typeof value === 'string' && !key.startsWith('.'));
173
- }
174
- function constructFullExportCondition(exportCondition, packageType) {
175
- let fullExportCond;
176
- if (typeof exportCondition === 'string') {
177
- const exportType = getExportTypeFromFile(exportCondition, packageType);
178
- fullExportCond = {
179
- [exportType]: exportCondition
180
- };
181
- } else {
182
- const exportTypes = Object.keys(exportCondition);
183
- fullExportCond = {};
184
- exportTypes.forEach((exportType)=>{
185
- const condition = exportCondition[exportType];
186
- // Filter out nullable value
187
- if (condition) {
188
- fullExportCond[exportType] = condition;
189
- }
190
- });
191
- }
192
- return fullExportCond;
193
- }
194
176
  function joinRelativePath(...segments) {
195
- let result = path.join(...segments);
177
+ let result = path__default.default.join(...segments);
196
178
  // If the first segment starts with '.', ensure the result does too.
197
179
  if (segments[0] === '.' && !result.startsWith('.')) {
198
180
  result = './' + result;
199
181
  }
200
182
  return result;
201
183
  }
202
- const getFirstExportPath = (fullExportCondition)=>{
203
- // Handle all export cond { <require|import|default>: ... }
204
- if (typeof fullExportCondition === 'object') {
205
- for (const key of Object.keys(fullExportCondition)){
206
- if (key.startsWith('.') || key === 'types') {
207
- continue;
208
- }
209
- return fullExportCondition[key];
210
- }
211
- }
212
- return fullExportCondition;
213
- };
214
- const joinExportAndCondition = (exportPath, condition)=>{
215
- return (exportPath === '.' ? '' : exportPath) + '.' + condition;
216
- };
217
- function findExport(exportPath, exportCondition, paths, packageType, currentPath) {
218
- // Skip `types` field, it cannot be the entry point
219
- if (exportPath === 'types') return;
220
- if (isExportLike(exportCondition)) {
221
- const fullExportCondition = constructFullExportCondition(exportCondition, packageType);
222
- if (exportPath.startsWith('.')) {
223
- paths[exportPath] = {
224
- ...paths[exportPath],
225
- ...fullExportCondition
226
- };
184
+ function isESModulePackage(packageType) {
185
+ return packageType === 'module';
186
+ }
187
+
188
+ function collectExportPath(exportValue, exportKey, currentPath, exportTypes, exportToDist) {
189
+ // End of searching, export value is file path.
190
+ // <export key>: <export value> (string)
191
+ if (typeof exportValue === 'string') {
192
+ const composedTypes = new Set(exportTypes);
193
+ composedTypes.add(exportKey.startsWith('.') ? 'default' : exportKey);
194
+ const exportInfo = exportToDist.get(currentPath);
195
+ const exportCondition = Array.from(composedTypes).join('.');
196
+ if (!exportInfo) {
197
+ const outputConditionPair = [
198
+ exportValue,
199
+ exportCondition
200
+ ];
201
+ exportToDist.set(currentPath, [
202
+ outputConditionPair
203
+ ]);
227
204
  } else {
228
- const exportJsBundlePath = getFirstExportPath(fullExportCondition);
229
- if (suffixedExportConventions.has(exportPath)) {
230
- const specialPath = joinExportAndCondition(currentPath, exportPath);
231
- paths[specialPath] = {
232
- ...paths[specialPath],
233
- ...exportCondition
234
- };
235
- } else {
236
- // exportPath is exportType, import, require, ...
237
- // merge to currentPath
238
- paths[currentPath] = {
239
- ...paths[currentPath],
240
- [exportPath]: exportJsBundlePath
241
- };
242
- }
205
+ exportInfo.push([
206
+ exportValue,
207
+ exportCondition
208
+ ]);
243
209
  }
244
210
  return;
245
211
  }
246
- Object.keys(exportCondition).forEach((subpath)=>{
247
- if (subpath.startsWith('.')) {
248
- // subpath is actual export path, ./a, ./b, ...
249
- const nestedExportPath = joinRelativePath(currentPath, subpath);
250
- const nestedExportCondition = exportCondition[subpath];
251
- findExport(nestedExportPath, nestedExportCondition, paths, packageType, nestedExportPath);
252
- } else {
253
- // subpath is exportType, import, require, ...
254
- const exportType = subpath;
255
- if (typeof exportCondition[subpath] === 'object') {
256
- const defaultPath = exportCondition[subpath].default;
257
- if (defaultPath) {
258
- const nestedExportCondition = {
259
- [exportType]: defaultPath
260
- };
261
- findExport(exportPath, nestedExportCondition, paths, packageType, currentPath);
262
- }
263
- // Find special export type, such as import: { development: './dev.js', production: './prod.js' }
264
- const conditionSpecialTypes = Object.keys(exportCondition[exportType]).filter((key)=>suffixedExportConventions.has(key));
265
- if (conditionSpecialTypes.length > 0) {
266
- for (const conditionSpecialType of conditionSpecialTypes){
267
- const nestedExportConditionPath = {
268
- [exportType]: exportCondition[exportType][conditionSpecialType]
269
- };
270
- findExport(conditionSpecialType, nestedExportConditionPath, paths, packageType, currentPath);
271
- }
272
- }
273
- }
274
- const defaultPath = typeof exportCondition[subpath] === 'object' ? exportCondition[subpath].default : exportCondition[subpath];
275
- const nestedExportCondition = {
276
- [exportType]: defaultPath
277
- };
278
- findExport(exportPath, nestedExportCondition, paths, packageType, currentPath);
279
- }
280
- });
281
- }
282
- /**
283
- *
284
- * Convert package.exports field to paths mapping
285
- * Example
286
- *
287
- * Input:
288
- * {
289
- * "./sub": {
290
- * "import": {
291
- * "types": "./sub.js",
292
- * "default": "./sub.cjs",
293
- * }
294
- * }
295
- * }
296
- *
297
- * Output:
298
- * {
299
- * "./sub": {
300
- * "import": "./sub.js",
301
- * "require": "./sub.cjs",
302
- * "types": "./sub.d.ts",
303
- * }
304
- * }
305
- *
306
- */ function parseExport(exportsCondition, packageType) {
307
- const paths = {};
308
- const initialPath = '.';
309
- if (typeof exportsCondition === 'string') {
310
- paths[initialPath] = constructFullExportCondition(exportsCondition, packageType);
311
- } else if (typeof exportsCondition === 'object') {
312
- if (isExportLike(exportsCondition)) {
313
- paths[initialPath] = constructFullExportCondition(exportsCondition, packageType);
212
+ const exportKeys = Object.keys(exportValue);
213
+ for (const exportKey of exportKeys){
214
+ // Clone the set to avoid modifying the parent set
215
+ const childExports = new Set(exportTypes);
216
+ // Normalize child export value to a map
217
+ const childExportValue = exportValue[exportKey];
218
+ // Visit export path: ./subpath, ./subpath2, ...
219
+ if (exportKey.startsWith('.')) {
220
+ const childPath = joinRelativePath(currentPath, exportKey);
221
+ collectExportPath(childExportValue, exportKey, childPath, childExports, exportToDist);
314
222
  } else {
315
- Object.keys(exportsCondition).forEach((key)=>{
316
- const exportCondition = exportsCondition[key];
317
- findExport(key, exportCondition, paths, packageType, initialPath);
318
- });
223
+ // Visit export type: import, require, ...
224
+ childExports.add(exportKey);
225
+ collectExportPath(childExportValue, exportKey, currentPath, childExports, exportToDist);
319
226
  }
320
227
  }
321
- return paths;
322
228
  }
323
229
  /**
324
- * Get package exports paths
325
- *
326
- * Example:
327
- *
328
- * ```json
329
- * {
330
- * "exports": {
331
- * ".": {
332
- * "require": "./dist/index.cjs",
333
- * "module": "./dist/index.esm.js",
334
- * "default": "./dist/index.esm.js"
335
- * },
336
- * "./foo": {
337
- * "require": "./dist/foo.cjs",
338
- * "module": "./dist/foo.esm.js",
339
- * "default": "./dist/foo.esm.js"
340
- * }
341
- * }
342
- *
343
- * ```
230
+ * parseExports - parse package.exports field and other fields like main,module to a map
344
231
  *
345
- * will be parsed to:
346
- *
347
- * ```js
348
- * {
349
- * '.': {
350
- * main: './dist/index.cjs',
351
- * module: './dist/index.esm.js',
352
- * export: './dist/index.esm.js'
353
- * },
354
- * './foo': {
355
- * main: './dist/foo.cjs',
356
- * module: './dist/foo.esm.js',
357
- * export: './dist/foo.esm.js'
358
- * }
359
- *
360
- *
361
- * pkg.main and pkg.module will be added to ['.'] if exists
362
- */ function getExportPaths(pkg, resolvedWildcardExports) {
363
- var _pathsMap_;
364
- let pathsMap = {};
365
- const packageType = getPackageType(pkg);
366
- const isEsmPackage = isESModulePackage(packageType);
367
- const exportsConditions = resolvedWildcardExports != null ? resolvedWildcardExports : pkg.exports;
368
- if (exportsConditions) {
369
- const paths = parseExport(exportsConditions, packageType);
370
- pathsMap = {
371
- ...pathsMap,
372
- ...paths
373
- };
374
- }
375
- // main export '.' from main/module/typings
376
- let mainExportCondition;
377
- if (pkg.main) {
378
- const mainExportType = isEsmPackage ? hasCjsExtension(pkg.main) ? 'require' : 'import' : 'require';
379
- mainExportCondition = {
380
- [mainExportType]: pkg.main
381
- };
232
+ * map from export path to output path and export conditions
233
+ */ function parseExports(pkg) {
234
+ var _pkg_exports;
235
+ const exportsField = (_pkg_exports = pkg.exports) != null ? _pkg_exports : {};
236
+ var _pkg_bin;
237
+ const bins = (_pkg_bin = pkg.bin) != null ? _pkg_bin : {};
238
+ const exportToDist = new Map();
239
+ const isEsmPkg = isESModulePackage(pkg.type);
240
+ const defaultCondition = isEsmPkg ? 'import' : 'require';
241
+ let currentPath = '.';
242
+ if (typeof exportsField === 'string') {
243
+ const outputConditionPair = [
244
+ exportsField,
245
+ defaultCondition
246
+ ];
247
+ exportToDist.set(currentPath, [
248
+ outputConditionPair
249
+ ]);
250
+ } else {
251
+ // keys means unknown if they're relative path or export type
252
+ const exportConditionKeys = Object.keys(exportsField);
253
+ for (const exportKey of exportConditionKeys){
254
+ const exportValue = exportsField[exportKey];
255
+ const exportTypes = new Set();
256
+ const isExportPath = exportKey.startsWith('.');
257
+ const childPath = isExportPath ? joinRelativePath(currentPath, exportKey) : currentPath;
258
+ if (!isExportPath) {
259
+ exportTypes.add(exportKey);
260
+ }
261
+ collectExportPath(exportValue, exportKey, childPath, exportTypes, exportToDist);
262
+ }
382
263
  }
383
- const defaultMainExport = constructFullExportCondition({
384
- ...mainExportCondition,
385
- module: pkg.module,
386
- types: getPackageTypings(pkg)
387
- }, packageType);
388
- if (!isEsmPackage && ((_pathsMap_ = pathsMap['.']) == null ? void 0 : _pathsMap_['require'])) {
389
- // pathsMap's exports.require are prioritized.
390
- defaultMainExport['require'] = pathsMap['.']['require'];
391
- }
392
- // Merge the main export into '.' paths
393
- const mainExport = {
394
- ...pathsMap['.'],
395
- ...defaultMainExport
396
- };
397
- // main export is not empty
398
- if (Object.keys(mainExport).length > 0) {
399
- pathsMap['.'] = {
400
- ...pathsMap['.'],
401
- ...mainExport
402
- };
264
+ if (typeof bins === 'string') {
265
+ const outputConditionPair = [
266
+ bins,
267
+ defaultCondition
268
+ ];
269
+ exportToDist.set(BINARY_TAG, [
270
+ outputConditionPair
271
+ ]);
272
+ } else {
273
+ for (const binName of Object.keys(bins)){
274
+ const binDistPath = bins[binName];
275
+ const exportType = getExportTypeFromFile(binDistPath, pkg.type);
276
+ const exportPath = path.posix.join(BINARY_TAG, binName);
277
+ const outputConditionPair = [
278
+ binDistPath,
279
+ exportType
280
+ ];
281
+ exportToDist.set(exportPath, [
282
+ outputConditionPair
283
+ ]);
284
+ }
403
285
  }
404
- return pathsMap;
405
- }
406
- function getPackageType(pkg) {
407
- return pkg.type || 'commonjs';
408
- }
409
- function isESModulePackage(packageType) {
410
- return packageType === 'module';
286
+ // Handle package.json global exports fields
287
+ if (pkg.main || pkg.module || pkg.types) {
288
+ const mainExportPath = pkg.main;
289
+ const moduleExportPath = pkg.module;
290
+ const typesEntryPath = pkg.types;
291
+ const existingExportInfo = exportToDist.get('.');
292
+ exportToDist.set('.', [
293
+ ...existingExportInfo || [],
294
+ Boolean(mainExportPath) && [
295
+ mainExportPath,
296
+ getMainFieldExportType(pkg)
297
+ ],
298
+ Boolean(moduleExportPath) && [
299
+ moduleExportPath,
300
+ 'import'
301
+ ],
302
+ Boolean(typesEntryPath) && [
303
+ typesEntryPath,
304
+ 'types'
305
+ ]
306
+ ].filter(Boolean));
307
+ }
308
+ return exportToDist;
411
309
  }
412
310
  function getExportTypeFromFile(filename, pkgType) {
413
311
  const isESModule = isESModulePackage(pkgType);
@@ -420,7 +318,7 @@ function getExportTypeFromFile(filename, pkgType) {
420
318
  function lint$1(pkg) {
421
319
  const { name, main, exports } = pkg;
422
320
  const isESM = isESModulePackage(pkg.type);
423
- const exportPaths = getExportPaths(pkg);
321
+ const parsedExports = parseExports(pkg);
424
322
  if (!name) {
425
323
  logger.warn('Missing package name');
426
324
  }
@@ -456,16 +354,17 @@ function lint$1(pkg) {
456
354
  if (typeof exports !== 'object') {
457
355
  state.invalidExportsFieldType = true;
458
356
  } else {
459
- Object.keys(exportPaths).forEach((key)=>{
460
- const exportConditions = exportPaths[key];
461
- if (typeof exportConditions === 'object') {
462
- var // @ts-ignore TODO: fix the type
463
- _exportConditions_require, // @ts-ignore TODO: fix the type
464
- _exportConditions_import;
465
- var _exportConditions_require_default;
466
- const requirePath = (_exportConditions_require_default = (_exportConditions_require = exportConditions.require) == null ? void 0 : _exportConditions_require.default) != null ? _exportConditions_require_default : exportConditions.require;
467
- var _exportConditions_import_default;
468
- const importPath = (_exportConditions_import_default = (_exportConditions_import = exportConditions.import) == null ? void 0 : _exportConditions_import.default) != null ? _exportConditions_import_default : exportConditions.import;
357
+ parsedExports.forEach((outputPairs)=>{
358
+ for (const [outputPath, composedExportType] of outputPairs){
359
+ const exportTypes = new Set(composedExportType.split('.'));
360
+ let requirePath = '';
361
+ let importPath = '';
362
+ if (exportTypes.has('require')) {
363
+ requirePath = outputPath;
364
+ }
365
+ if (exportTypes.has('import')) {
366
+ importPath = outputPath;
367
+ }
469
368
  const requireExt = requirePath && path__default.default.extname(requirePath);
470
369
  const importExt = importPath && path__default.default.extname(importPath);
471
370
  if (requireExt === '.mjs' || requireExt === '.js') {
@@ -494,16 +393,17 @@ function lint$1(pkg) {
494
393
  if (typeof exports !== 'object') {
495
394
  state.invalidExportsFieldType = true;
496
395
  } else {
497
- Object.keys(exportPaths).forEach((key)=>{
498
- const exportConditions = exportPaths[key];
499
- if (typeof exportConditions === 'object') {
500
- var // @ts-ignore TODO: fix the type
501
- _exportConditions_require, // @ts-ignore TODO: fix the type
502
- _exportConditions_import;
503
- var _exportConditions_require_default;
504
- const requirePath = (_exportConditions_require_default = (_exportConditions_require = exportConditions.require) == null ? void 0 : _exportConditions_require.default) != null ? _exportConditions_require_default : exportConditions.require;
505
- var _exportConditions_import_default;
506
- const importPath = (_exportConditions_import_default = (_exportConditions_import = exportConditions.import) == null ? void 0 : _exportConditions_import.default) != null ? _exportConditions_import_default : exportConditions.import;
396
+ parsedExports.forEach((outputPairs)=>{
397
+ for (const [outputPath, composedExportType] of outputPairs){
398
+ const exportTypes = new Set(composedExportType.split('.'));
399
+ let requirePath = '';
400
+ let importPath = '';
401
+ if (exportTypes.has('require')) {
402
+ requirePath = outputPath;
403
+ }
404
+ if (exportTypes.has('import')) {
405
+ importPath = outputPath;
406
+ }
507
407
  const requireExt = requirePath && path__default.default.extname(requirePath);
508
408
  const importExt = importPath && path__default.default.extname(importPath);
509
409
  if (requireExt === '.mjs') {
@@ -558,7 +458,7 @@ function lint$1(pkg) {
558
458
  }
559
459
  }
560
460
 
561
- var version = "4.4.8";
461
+ var version = "5.0.0-beta.2";
562
462
 
563
463
  function relativify(path) {
564
464
  return path.startsWith('.') ? path : `./${path}`;
@@ -569,41 +469,73 @@ async function writeDefaultTsconfig(tsConfigPath) {
569
469
  logger.log(`Detected using TypeScript but tsconfig.json is missing, created a ${pc.blue('tsconfig.json')} for you.`);
570
470
  }
571
471
 
572
- // Output with posix style in package.json
573
- function getDistPath(...subPaths) {
574
- return `./${DIST}/${subPaths.join('/')}`;
472
+ // shared.ts -> ./shared
473
+ // shared.<export condition>.ts -> ./shared
474
+ // index.ts -> ./index
475
+ // index.development.ts -> ./index.development
476
+ function sourceFilenameToExportPath(filename) {
477
+ const baseName = baseNameWithoutExtension(filename);
478
+ let exportPath = baseName;
479
+ return relativify(exportPath);
575
480
  }
576
- const normalizeBaseNameToExportName = (baseName)=>{
577
- return /^index(\.|$)/.test(baseName) ? '.' : relativify(baseName);
578
- };
579
- function createExportCondition(exportName, sourceFile, moduleType) {
580
- const isTsSourceFile = isTypescriptFile(sourceFile);
581
- let cjsExtension = 'js';
582
- let esmExtension = 'mjs';
583
- if (moduleType === 'module') {
584
- cjsExtension = 'cjs';
585
- esmExtension = 'js';
481
+ // ./index -> import|require|default
482
+ // ./index.development -> development
483
+ // ./index.react-server -> react-server
484
+ function getExportTypeFromExportPath(exportPath) {
485
+ // Skip the first two segments: `.` and `index`
486
+ const exportTypes = exportPath.split('.').slice(2);
487
+ return getExportTypeFromExportTypes(exportTypes);
488
+ }
489
+ function getSpecialExportTypeFromExportPath(composedExportType) {
490
+ const exportTypes = composedExportType.split('.');
491
+ for (const exportType of exportTypes){
492
+ if (specialExportConventions.has(exportType)) {
493
+ return exportType;
494
+ }
586
495
  }
587
- if (isTsSourceFile) {
588
- return {
589
- import: {
590
- types: getDistPath('es', `${exportName}.${dtsExtensionsMap[esmExtension]}`),
591
- default: getDistPath('es', `${exportName}.${esmExtension}`)
592
- },
593
- require: {
594
- types: getDistPath('cjs', `${exportName}.${dtsExtensionsMap[cjsExtension]}`),
595
- default: getDistPath('cjs', `${exportName}.${cjsExtension}`)
596
- }
597
- };
496
+ return 'default';
497
+ }
498
+ function getExportTypeFromExportTypes(types) {
499
+ let exportType = 'default';
500
+ new Set(types).forEach((value)=>{
501
+ if (specialExportConventions.has(value)) {
502
+ exportType = value;
503
+ } else if (value === 'import' || value === 'require' || value === 'types') {
504
+ exportType = value;
505
+ }
506
+ });
507
+ return exportType;
508
+ }
509
+ // ./index -> .
510
+ // ./index.development -> .
511
+ // ./index.react-server -> .
512
+ // ./shared -> ./shared
513
+ // ./shared.development -> ./shared
514
+ // $binary -> $binary
515
+ // $binary/index -> $binary
516
+ // $binary/foo -> $binary/foo
517
+ function normalizeExportPath(exportPath) {
518
+ if (exportPath.startsWith(BINARY_TAG)) {
519
+ if (exportPath === `${BINARY_TAG}/index`) {
520
+ exportPath = BINARY_TAG;
521
+ }
522
+ return exportPath;
598
523
  }
599
- return {
600
- import: getDistPath(`${exportName}.mjs`),
601
- require: getDistPath(`${exportName}.${cjsExtension}`)
602
- };
524
+ const baseName = exportPath.split('.').slice(0, 2).join('.');
525
+ if (baseName === './index') {
526
+ return '.';
527
+ }
528
+ return baseName;
603
529
  }
604
530
  async function collectSourceEntries(sourceFolderPath) {
605
531
  const bins = new Map();
606
532
  const exportsEntries = new Map();
533
+ if (!fs__default.default.existsSync(sourceFolderPath)) {
534
+ return {
535
+ bins,
536
+ exportsEntries
537
+ };
538
+ }
607
539
  const entryFileDirentList = await fsp__default.default.readdir(sourceFolderPath, {
608
540
  withFileTypes: true
609
541
  });
@@ -616,18 +548,35 @@ async function collectSourceEntries(sourceFolderPath) {
616
548
  for (const binDirent of binDirentList){
617
549
  if (binDirent.isFile()) {
618
550
  const binFileAbsolutePath = path__default.default.join(sourceFolderPath, dirent.name, binDirent.name);
619
- const binName = baseNameWithoutExtension(binDirent.name);
551
+ const binExportPath = sourceFilenameToExportPath(binDirent.name);
620
552
  if (fs__default.default.existsSync(binFileAbsolutePath)) {
621
- bins.set(binName, binDirent.name);
553
+ bins.set(path.posix.join(BINARY_TAG, binExportPath), binFileAbsolutePath);
622
554
  }
623
555
  }
624
556
  }
625
557
  } else {
626
- // Search folder/<index>.<ext> convention entries
558
+ // Search folder/index.<ext> convention entries
627
559
  for (const extension of availableExtensions){
628
- const indexFile = path__default.default.join(dirent.name, `index.${extension}`);
629
- if (fs__default.default.existsSync(indexFile) && !isTestFile(indexFile)) {
630
- exportsEntries.set(dirent.name, indexFile);
560
+ const indexAbsoluteFile = path__default.default.join(dirent.path, dirent.name, `index.${extension}`);
561
+ // Search folder/index.<special type>.<ext> convention entries
562
+ for (const specialExportType of runtimeExportConventions){
563
+ const indexSpecialAbsoluteFile = path__default.default.join(dirent.path, dirent.name, `index.${specialExportType}.${extension}`);
564
+ if (fs__default.default.existsSync(indexSpecialAbsoluteFile)) {
565
+ // Add special export path
566
+ // { ./<export path>.<special cond>: { <special cond>: 'index.<special cond>.<ext>' } }
567
+ const exportPath = sourceFilenameToExportPath(dirent.name);
568
+ const specialExportPath = exportPath + '.' + specialExportType;
569
+ const sourceFilesMap = exportsEntries.get(specialExportPath) || {};
570
+ sourceFilesMap[specialExportType] = indexSpecialAbsoluteFile;
571
+ exportsEntries.set(specialExportPath, sourceFilesMap);
572
+ }
573
+ }
574
+ if (fs__default.default.existsSync(indexAbsoluteFile) && !isTestFile(indexAbsoluteFile)) {
575
+ const exportPath = sourceFilenameToExportPath(dirent.name);
576
+ const sourceFilesMap = exportsEntries.get(exportPath) || {};
577
+ const exportType = getExportTypeFromExportPath(exportPath);
578
+ sourceFilesMap[exportType] = indexAbsoluteFile;
579
+ exportsEntries.set(exportPath, sourceFilesMap);
631
580
  break;
632
581
  }
633
582
  }
@@ -635,13 +584,17 @@ async function collectSourceEntries(sourceFolderPath) {
635
584
  } else if (dirent.isFile()) {
636
585
  const isAvailableExtension = availableExtensions.has(path__default.default.extname(dirent.name).slice(1));
637
586
  if (isAvailableExtension) {
638
- const baseName = baseNameWithoutExtension(dirent.name);
639
- const isBinFile = baseName === 'bin';
587
+ const exportPath = sourceFilenameToExportPath(dirent.name);
588
+ const isBinFile = exportPath === './bin';
589
+ const fullPath = path__default.default.join(sourceFolderPath, dirent.name);
640
590
  if (isBinFile) {
641
- bins.set('.', dirent.name);
591
+ bins.set(BINARY_TAG, fullPath);
642
592
  } else {
643
593
  if (hasAvailableExtension(dirent.name) && !isTestFile(dirent.name)) {
644
- exportsEntries.set(baseName, dirent.name);
594
+ const sourceFilesMap = exportsEntries.get(exportPath) || {};
595
+ const exportType = getExportTypeFromExportPath(exportPath);
596
+ sourceFilesMap[exportType] = fullPath;
597
+ exportsEntries.set(exportPath, sourceFilesMap);
645
598
  }
646
599
  }
647
600
  }
@@ -652,25 +605,68 @@ async function collectSourceEntries(sourceFolderPath) {
652
605
  exportsEntries
653
606
  };
654
607
  }
608
+
609
+ // Output with posix style in package.json
610
+ function getDistPath(...subPaths) {
611
+ return relativify(path.posix.join(DIST, ...subPaths));
612
+ }
613
+ function stripeBinaryTag(exportName) {
614
+ // Add \ to decode leading $
615
+ return exportName.replace(/\$binary\//, '');
616
+ }
617
+ const normalizeBaseNameToExportName = (name)=>{
618
+ const baseName = stripeBinaryTag(name);
619
+ return /^\.\/index(\.|$)/.test(baseName) ? '.' : relativify(baseName);
620
+ };
621
+ function createExportCondition(exportName, sourceFile, moduleType) {
622
+ const isTsSourceFile = isTypescriptFile(sourceFile);
623
+ let cjsExtension = 'js';
624
+ let esmExtension = 'mjs';
625
+ if (moduleType === 'module') {
626
+ cjsExtension = 'cjs';
627
+ esmExtension = 'js';
628
+ }
629
+ if (exportName === '.') {
630
+ exportName = 'index';
631
+ }
632
+ if (isTsSourceFile) {
633
+ return {
634
+ import: {
635
+ types: getDistPath('es', `${exportName}.${dtsExtensionsMap[esmExtension]}`),
636
+ default: getDistPath('es', `${exportName}.${esmExtension}`)
637
+ },
638
+ require: {
639
+ types: getDistPath('cjs', `${exportName}.${dtsExtensionsMap[cjsExtension]}`),
640
+ default: getDistPath('cjs', `${exportName}.${cjsExtension}`)
641
+ }
642
+ };
643
+ }
644
+ return {
645
+ import: getDistPath(`${exportName}.mjs`),
646
+ require: getDistPath(`${exportName}.${cjsExtension}`)
647
+ };
648
+ }
655
649
  function createExportConditionPair(exportName, sourceFile, moduleType) {
656
650
  // <exportName>.<specialCondition>
657
651
  let specialCondition;
658
- let exportCondName;
659
- if (exportName.indexOf('.') > 0) {
660
- const [originExportName, specialConditionName] = exportName.split('.');
652
+ const specialConditionName = getSpecialExportTypeFromExportPath(exportName);
653
+ const normalizedExportPath = normalizeExportPath(exportName);
654
+ if (specialConditionName !== 'default') {
655
+ // e.g.
656
+ // ./index.develop -> index
657
+ // ./foo.react-server -> foo
658
+ const fileBaseName = exportName.split('.').slice(0, 2).join('.').replace('./', '');
661
659
  specialCondition = {
662
- [specialConditionName]: getDistPath('es', `${originExportName}-${specialConditionName}.mjs`)
660
+ [specialConditionName]: getDistPath('es', `${fileBaseName}-${specialConditionName}.mjs`)
663
661
  };
664
- exportCondName = normalizeBaseNameToExportName(originExportName);
665
662
  return [
666
- exportCondName,
663
+ normalizedExportPath,
667
664
  specialCondition
668
665
  ];
669
666
  }
670
- exportCondName = normalizeBaseNameToExportName(exportName);
671
667
  const exportCond = createExportCondition(exportName, sourceFile, moduleType);
672
668
  return [
673
- exportCondName,
669
+ normalizedExportPath,
674
670
  exportCond
675
671
  ];
676
672
  }
@@ -698,12 +694,17 @@ async function prepare(cwd) {
698
694
  // Collect bins and exports entries
699
695
  const { bins, exportsEntries } = await collectSourceEntries(sourceFolder);
700
696
  const tsConfigPath = path__default.default.join(cwd, 'tsconfig.json');
701
- const sourceFiles = [
697
+ const exportsSourceFiles = [
702
698
  ...exportsEntries.values()
703
- ].concat([
699
+ ].reduce((acc, sourceFiles)=>{
700
+ Object.values(sourceFiles).forEach((sourceFile)=>acc.add(sourceFile));
701
+ return acc;
702
+ }, new Set());
703
+ const allSourceFiles = [
704
+ ...exportsSourceFiles,
704
705
  ...bins.values()
705
- ]);
706
- const hasTypeScriptFiles = sourceFiles.some((filename)=>isTypescriptFile(filename));
706
+ ].map((absoluteFilePath)=>absoluteFilePath);
707
+ const hasTypeScriptFiles = allSourceFiles.some((filename)=>isTypescriptFile(filename));
707
708
  if (hasTypeScriptFiles) {
708
709
  isUsingTs = true;
709
710
  if (!fs__default.default.existsSync(tsConfigPath)) {
@@ -719,13 +720,14 @@ async function prepare(cwd) {
719
720
  const maxLengthOfBinName = Math.max(...Array.from(bins.keys()).map((binName)=>normalizeBaseNameToExportName(binName).length));
720
721
  for (const [binName, binFile] of bins.entries()){
721
722
  const spaces = ' '.repeat(Math.max(maxLengthOfBinName - normalizeBaseNameToExportName(binName).length, 0));
722
- logger.log(` ${normalizeBaseNameToExportName(binName)}${spaces}: ${binFile}`);
723
+ logger.log(` ${normalizeBaseNameToExportName(binName)}${spaces}: ${path__default.default.basename(binFile)}`);
723
724
  }
724
- if (bins.size === 1 && bins.has('.')) {
725
+ if (bins.size === 1 && bins.has(BINARY_TAG)) {
725
726
  pkgJson.bin = getDistPath('bin', 'index.js');
726
727
  } else {
727
728
  pkgJson.bin = {};
728
- for (const [binName] of bins.entries()){
729
+ for (const [binOriginName] of bins.entries()){
730
+ const binName = stripeBinaryTag(binOriginName);
729
731
  pkgJson.bin[binName === '.' ? pkgJson.name : binName] = getDistPath('bin', binName + '.js');
730
732
  }
731
733
  }
@@ -733,20 +735,24 @@ async function prepare(cwd) {
733
735
  if (exportsEntries.size > 0) {
734
736
  logger.log('Discovered exports entries:');
735
737
  const maxLengthOfExportName = Math.max(...Array.from(exportsEntries.keys()).map((exportName)=>normalizeBaseNameToExportName(exportName).length));
736
- for (const [exportName, exportFile] of exportsEntries.entries()){
738
+ for (const [exportName, sourceFilesMap] of exportsEntries.entries()){
737
739
  const spaces = ' '.repeat(Math.max(maxLengthOfExportName - normalizeBaseNameToExportName(exportName).length, 0));
738
- logger.log(` ${normalizeBaseNameToExportName(exportName)}${spaces}: ${exportFile}`);
740
+ for (const exportFile of Object.values(sourceFilesMap)){
741
+ logger.log(` ${normalizeBaseNameToExportName(exportName)}${spaces}: ${path__default.default.basename(exportFile)}`);
742
+ }
739
743
  }
740
744
  const pkgExports = {};
741
- for (const [exportName, sourceFile] of exportsEntries.entries()){
742
- const [key, value] = createExportConditionPair(exportName, sourceFile, pkgJson.type);
743
- pkgExports[key] = {
744
- ...value,
745
- ...pkgExports[key]
746
- };
745
+ for (const [exportName, sourceFilesMap] of exportsEntries.entries()){
746
+ for (const sourceFile of Object.values(sourceFilesMap)){
747
+ const [key, value] = createExportConditionPair(exportName, sourceFile, pkgJson.type);
748
+ pkgExports[key] = {
749
+ ...value,
750
+ ...pkgExports[key]
751
+ };
752
+ }
747
753
  }
748
754
  // Configure node10 module resolution
749
- if (exportsEntries.has('index')) {
755
+ if (exportsEntries.has('./index')) {
750
756
  const isESM = pkgJson.type === 'module';
751
757
  const mainExport = pkgExports['.'];
752
758
  const mainCondition = isESM ? 'import' : 'require';
@@ -793,7 +799,8 @@ Options:
793
799
  --env <env> inlined process env variables, separate by comma. default: NODE_ENV
794
800
  --cwd <cwd> specify current working directory
795
801
  --sourcemap enable sourcemap generation, default: false
796
- --dts determine if need to generate types, default: false
802
+ --dts determine if need to generate types, default: undefined
803
+ --no-dts do not generate types, default: undefined
797
804
  `;
798
805
  function help() {
799
806
  logger.log(helpMessage);
@@ -810,6 +817,7 @@ function parseCliArgs(argv) {
810
817
  args = arg__default.default({
811
818
  '--cwd': String,
812
819
  '--dts': Boolean,
820
+ '--no-dts': Boolean,
813
821
  '--output': String,
814
822
  '--format': String,
815
823
  '--watch': Boolean,
@@ -843,7 +851,7 @@ function parseCliArgs(argv) {
843
851
  minify: args['--minify'],
844
852
  sourcemap: !!args['--sourcemap'],
845
853
  cwd: args['--cwd'],
846
- dts: args['--dts'],
854
+ dts: args['--no-dts'] ? false : args['--dts'],
847
855
  help: args['--help'],
848
856
  version: args['--version'],
849
857
  runtime: args['--runtime'],
@@ -861,7 +869,7 @@ async function run(args) {
861
869
  const cwd = args.cwd || process.cwd();
862
870
  const file = args.file ? path__default.default.resolve(cwd, args.file) : undefined;
863
871
  const bundleConfig = {
864
- dts,
872
+ dts: typeof dts === 'boolean' ? dts : undefined,
865
873
  file,
866
874
  format,
867
875
  cwd,