bunchee 4.4.8 → 5.0.0-beta.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 (4) hide show
  1. package/README.md +0 -55
  2. package/dist/bin/cli.js +320 -317
  3. package/dist/index.js +439 -494
  4. package/package.json +14 -16
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,142 @@ 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
+ exportTypes.add(exportKey.startsWith('./') ? 'default' : exportKey);
193
+ const exportInfo = exportToDist.get(currentPath);
194
+ const exportCondition = Array.from(exportTypes).join('.');
195
+ if (!exportInfo) {
196
+ const outputConditionPair = [
197
+ exportValue,
198
+ exportCondition
199
+ ];
200
+ exportToDist.set(currentPath, [
201
+ outputConditionPair
202
+ ]);
227
203
  } 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
- }
204
+ exportInfo.push([
205
+ exportValue,
206
+ exportCondition
207
+ ]);
243
208
  }
244
209
  return;
245
210
  }
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);
211
+ const exportKeys = Object.keys(exportValue);
212
+ for (const exportKey of exportKeys){
213
+ // Clone the set to avoid modifying the parent set
214
+ const childExports = new Set(exportTypes);
215
+ // Normalize child export value to a map
216
+ const childExportValue = exportValue[exportKey];
217
+ // Visit export path: ./subpath, ./subpath2, ...
218
+ if (exportKey.startsWith('.')) {
219
+ const childPath = joinRelativePath(currentPath, exportKey);
220
+ collectExportPath(childExportValue, exportKey, childPath, childExports, exportToDist);
314
221
  } else {
315
- Object.keys(exportsCondition).forEach((key)=>{
316
- const exportCondition = exportsCondition[key];
317
- findExport(key, exportCondition, paths, packageType, initialPath);
318
- });
222
+ // Visit export type: import, require, ...
223
+ childExports.add(exportKey);
224
+ collectExportPath(childExportValue, exportKey, currentPath, childExports, exportToDist);
319
225
  }
320
226
  }
321
- return paths;
322
227
  }
323
228
  /**
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
- * ```
229
+ * parseExports - parse package.exports field and other fields like main,module to a map
344
230
  *
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
- };
231
+ * map from export path to output path and export conditions
232
+ */ function parseExports(pkg) {
233
+ var _pkg_exports;
234
+ const exportsField = (_pkg_exports = pkg.exports) != null ? _pkg_exports : {};
235
+ var _pkg_bin;
236
+ const bins = (_pkg_bin = pkg.bin) != null ? _pkg_bin : {};
237
+ const exportToDist = new Map();
238
+ const isEsmPkg = isESModulePackage(pkg.type);
239
+ const defaultCondition = isEsmPkg ? 'import' : 'require';
240
+ let currentPath = '.';
241
+ if (typeof exportsField === 'string') {
242
+ const outputConditionPair = [
243
+ exportsField,
244
+ defaultCondition
245
+ ];
246
+ exportToDist.set(currentPath, [
247
+ outputConditionPair
248
+ ]);
249
+ } else {
250
+ // keys means unknown if they're relative path or export type
251
+ const exportConditionKeys = Object.keys(exportsField);
252
+ for (const exportKey of exportConditionKeys){
253
+ const exportValue = exportsField[exportKey];
254
+ const exportTypes = new Set();
255
+ const isExportPath = exportKey.startsWith('.');
256
+ const childPath = isExportPath ? joinRelativePath(currentPath, exportKey) : currentPath;
257
+ collectExportPath(exportValue, exportKey, childPath, exportTypes, exportToDist);
258
+ }
382
259
  }
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
- };
260
+ if (typeof bins === 'string') {
261
+ const outputConditionPair = [
262
+ bins,
263
+ defaultCondition
264
+ ];
265
+ exportToDist.set(BINARY_TAG, [
266
+ outputConditionPair
267
+ ]);
268
+ } else {
269
+ for (const binName of Object.keys(bins)){
270
+ const binDistPath = bins[binName];
271
+ const exportType = getExportTypeFromFile(binDistPath, pkg.type);
272
+ const exportPath = path.posix.join(BINARY_TAG, binName);
273
+ const outputConditionPair = [
274
+ binDistPath,
275
+ exportType
276
+ ];
277
+ exportToDist.set(exportPath, [
278
+ outputConditionPair
279
+ ]);
280
+ }
403
281
  }
404
- return pathsMap;
405
- }
406
- function getPackageType(pkg) {
407
- return pkg.type || 'commonjs';
408
- }
409
- function isESModulePackage(packageType) {
410
- return packageType === 'module';
282
+ if (pkg.main || pkg.module) {
283
+ const mainExportPath = pkg.main;
284
+ const moduleExportPath = pkg.module;
285
+ const typesEntryPath = pkg.types;
286
+ const existingExportInfo = exportToDist.get('.');
287
+ exportToDist.set('.', [
288
+ ...existingExportInfo || [],
289
+ [
290
+ mainExportPath,
291
+ getMainFieldExportType(pkg)
292
+ ],
293
+ Boolean(moduleExportPath) && [
294
+ moduleExportPath,
295
+ 'import'
296
+ ],
297
+ Boolean(typesEntryPath) && [
298
+ typesEntryPath,
299
+ 'types'
300
+ ]
301
+ ].filter(Boolean));
302
+ }
303
+ return exportToDist;
411
304
  }
412
305
  function getExportTypeFromFile(filename, pkgType) {
413
306
  const isESModule = isESModulePackage(pkgType);
@@ -420,7 +313,7 @@ function getExportTypeFromFile(filename, pkgType) {
420
313
  function lint$1(pkg) {
421
314
  const { name, main, exports } = pkg;
422
315
  const isESM = isESModulePackage(pkg.type);
423
- const exportPaths = getExportPaths(pkg);
316
+ const parsedExports = parseExports(pkg);
424
317
  if (!name) {
425
318
  logger.warn('Missing package name');
426
319
  }
@@ -456,16 +349,17 @@ function lint$1(pkg) {
456
349
  if (typeof exports !== 'object') {
457
350
  state.invalidExportsFieldType = true;
458
351
  } 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;
352
+ parsedExports.forEach((outputPairs)=>{
353
+ for (const [outputPath, composedExportType] of outputPairs){
354
+ const exportTypes = new Set(composedExportType.split('.'));
355
+ let requirePath = '';
356
+ let importPath = '';
357
+ if (exportTypes.has('require')) {
358
+ requirePath = outputPath;
359
+ }
360
+ if (exportTypes.has('import')) {
361
+ importPath = outputPath;
362
+ }
469
363
  const requireExt = requirePath && path__default.default.extname(requirePath);
470
364
  const importExt = importPath && path__default.default.extname(importPath);
471
365
  if (requireExt === '.mjs' || requireExt === '.js') {
@@ -494,16 +388,17 @@ function lint$1(pkg) {
494
388
  if (typeof exports !== 'object') {
495
389
  state.invalidExportsFieldType = true;
496
390
  } 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;
391
+ parsedExports.forEach((outputPairs)=>{
392
+ for (const [outputPath, composedExportType] of outputPairs){
393
+ const exportTypes = new Set(composedExportType.split('.'));
394
+ let requirePath = '';
395
+ let importPath = '';
396
+ if (exportTypes.has('require')) {
397
+ requirePath = outputPath;
398
+ }
399
+ if (exportTypes.has('import')) {
400
+ importPath = outputPath;
401
+ }
507
402
  const requireExt = requirePath && path__default.default.extname(requirePath);
508
403
  const importExt = importPath && path__default.default.extname(importPath);
509
404
  if (requireExt === '.mjs') {
@@ -558,7 +453,7 @@ function lint$1(pkg) {
558
453
  }
559
454
  }
560
455
 
561
- var version = "4.4.8";
456
+ var version = "5.0.0-beta.1";
562
457
 
563
458
  function relativify(path) {
564
459
  return path.startsWith('.') ? path : `./${path}`;
@@ -569,41 +464,73 @@ async function writeDefaultTsconfig(tsConfigPath) {
569
464
  logger.log(`Detected using TypeScript but tsconfig.json is missing, created a ${pc.blue('tsconfig.json')} for you.`);
570
465
  }
571
466
 
572
- // Output with posix style in package.json
573
- function getDistPath(...subPaths) {
574
- return `./${DIST}/${subPaths.join('/')}`;
467
+ // shared.ts -> ./shared
468
+ // shared.<export condition>.ts -> ./shared
469
+ // index.ts -> ./index
470
+ // index.development.ts -> ./index.development
471
+ function sourceFilenameToExportPath(filename) {
472
+ const baseName = baseNameWithoutExtension(filename);
473
+ let exportPath = baseName;
474
+ return relativify(exportPath);
575
475
  }
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';
476
+ // ./index -> import|require|default
477
+ // ./index.development -> development
478
+ // ./index.react-server -> react-server
479
+ function getExportTypeFromExportPath(exportPath) {
480
+ // Skip the first two segments: `.` and `index`
481
+ const exportTypes = exportPath.split('.').slice(2);
482
+ return getExportTypeFromExportTypes(exportTypes);
483
+ }
484
+ function getSpecialExportTypeFromExportPath(composedExportType) {
485
+ const exportTypes = composedExportType.split('.');
486
+ for (const exportType of exportTypes){
487
+ if (specialExportConventions.has(exportType)) {
488
+ return exportType;
489
+ }
586
490
  }
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
- };
491
+ return 'default';
492
+ }
493
+ function getExportTypeFromExportTypes(types) {
494
+ let exportType = 'default';
495
+ new Set(types).forEach((value)=>{
496
+ if (specialExportConventions.has(value)) {
497
+ exportType = value;
498
+ } else if (value === 'import' || value === 'require') {
499
+ exportType = value;
500
+ }
501
+ });
502
+ return exportType;
503
+ }
504
+ // ./index -> .
505
+ // ./index.development -> .
506
+ // ./index.react-server -> .
507
+ // ./shared -> ./shared
508
+ // ./shared.development -> ./shared
509
+ // $binary -> $binary
510
+ // $binary/index -> $binary
511
+ // $binary/foo -> $binary/foo
512
+ function normalizeExportPath(exportPath) {
513
+ if (exportPath.startsWith(BINARY_TAG)) {
514
+ if (exportPath === `${BINARY_TAG}/index`) {
515
+ exportPath = BINARY_TAG;
516
+ }
517
+ return exportPath;
598
518
  }
599
- return {
600
- import: getDistPath(`${exportName}.mjs`),
601
- require: getDistPath(`${exportName}.${cjsExtension}`)
602
- };
519
+ const baseName = exportPath.split('.').slice(0, 2).join('.');
520
+ if (baseName === './index') {
521
+ return '.';
522
+ }
523
+ return baseName;
603
524
  }
604
525
  async function collectSourceEntries(sourceFolderPath) {
605
526
  const bins = new Map();
606
527
  const exportsEntries = new Map();
528
+ if (!fs__default.default.existsSync(sourceFolderPath)) {
529
+ return {
530
+ bins,
531
+ exportsEntries
532
+ };
533
+ }
607
534
  const entryFileDirentList = await fsp__default.default.readdir(sourceFolderPath, {
608
535
  withFileTypes: true
609
536
  });
@@ -616,18 +543,35 @@ async function collectSourceEntries(sourceFolderPath) {
616
543
  for (const binDirent of binDirentList){
617
544
  if (binDirent.isFile()) {
618
545
  const binFileAbsolutePath = path__default.default.join(sourceFolderPath, dirent.name, binDirent.name);
619
- const binName = baseNameWithoutExtension(binDirent.name);
546
+ const binExportPath = sourceFilenameToExportPath(binDirent.name);
620
547
  if (fs__default.default.existsSync(binFileAbsolutePath)) {
621
- bins.set(binName, binDirent.name);
548
+ bins.set(path.posix.join(BINARY_TAG, binExportPath), binFileAbsolutePath);
622
549
  }
623
550
  }
624
551
  }
625
552
  } else {
626
- // Search folder/<index>.<ext> convention entries
553
+ // Search folder/index.<ext> convention entries
627
554
  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);
555
+ const indexAbsoluteFile = path__default.default.join(dirent.path, dirent.name, `index.${extension}`);
556
+ // Search folder/index.<special type>.<ext> convention entries
557
+ for (const specialExportType of runtimeExportConventions){
558
+ const indexSpecialAbsoluteFile = path__default.default.join(dirent.path, dirent.name, `index.${specialExportType}.${extension}`);
559
+ if (fs__default.default.existsSync(indexSpecialAbsoluteFile)) {
560
+ // Add special export path
561
+ // { ./<export path>.<special cond>: { <special cond>: 'index.<special cond>.<ext>' } }
562
+ const exportPath = sourceFilenameToExportPath(dirent.name);
563
+ const specialExportPath = exportPath + '.' + specialExportType;
564
+ const sourceFilesMap = exportsEntries.get(specialExportPath) || {};
565
+ sourceFilesMap[specialExportType] = indexSpecialAbsoluteFile;
566
+ exportsEntries.set(specialExportPath, sourceFilesMap);
567
+ }
568
+ }
569
+ if (fs__default.default.existsSync(indexAbsoluteFile) && !isTestFile(indexAbsoluteFile)) {
570
+ const exportPath = sourceFilenameToExportPath(dirent.name);
571
+ const sourceFilesMap = exportsEntries.get(exportPath) || {};
572
+ const exportType = getExportTypeFromExportPath(exportPath);
573
+ sourceFilesMap[exportType] = indexAbsoluteFile;
574
+ exportsEntries.set(exportPath, sourceFilesMap);
631
575
  break;
632
576
  }
633
577
  }
@@ -635,13 +579,17 @@ async function collectSourceEntries(sourceFolderPath) {
635
579
  } else if (dirent.isFile()) {
636
580
  const isAvailableExtension = availableExtensions.has(path__default.default.extname(dirent.name).slice(1));
637
581
  if (isAvailableExtension) {
638
- const baseName = baseNameWithoutExtension(dirent.name);
639
- const isBinFile = baseName === 'bin';
582
+ const exportPath = sourceFilenameToExportPath(dirent.name);
583
+ const isBinFile = exportPath === './bin';
584
+ const fullPath = path__default.default.join(sourceFolderPath, dirent.name);
640
585
  if (isBinFile) {
641
- bins.set('.', dirent.name);
586
+ bins.set(BINARY_TAG, fullPath);
642
587
  } else {
643
588
  if (hasAvailableExtension(dirent.name) && !isTestFile(dirent.name)) {
644
- exportsEntries.set(baseName, dirent.name);
589
+ const sourceFilesMap = exportsEntries.get(exportPath) || {};
590
+ const exportType = getExportTypeFromExportPath(exportPath);
591
+ sourceFilesMap[exportType] = fullPath;
592
+ exportsEntries.set(exportPath, sourceFilesMap);
645
593
  }
646
594
  }
647
595
  }
@@ -652,25 +600,68 @@ async function collectSourceEntries(sourceFolderPath) {
652
600
  exportsEntries
653
601
  };
654
602
  }
603
+
604
+ // Output with posix style in package.json
605
+ function getDistPath(...subPaths) {
606
+ return relativify(path.posix.join(DIST, ...subPaths));
607
+ }
608
+ function stripeBinaryTag(exportName) {
609
+ // Add \ to decode leading $
610
+ return exportName.replace(/\$binary\//, '');
611
+ }
612
+ const normalizeBaseNameToExportName = (name)=>{
613
+ const baseName = stripeBinaryTag(name);
614
+ return /^\.\/index(\.|$)/.test(baseName) ? '.' : relativify(baseName);
615
+ };
616
+ function createExportCondition(exportName, sourceFile, moduleType) {
617
+ const isTsSourceFile = isTypescriptFile(sourceFile);
618
+ let cjsExtension = 'js';
619
+ let esmExtension = 'mjs';
620
+ if (moduleType === 'module') {
621
+ cjsExtension = 'cjs';
622
+ esmExtension = 'js';
623
+ }
624
+ if (exportName === '.') {
625
+ exportName = 'index';
626
+ }
627
+ if (isTsSourceFile) {
628
+ return {
629
+ import: {
630
+ types: getDistPath('es', `${exportName}.${dtsExtensionsMap[esmExtension]}`),
631
+ default: getDistPath('es', `${exportName}.${esmExtension}`)
632
+ },
633
+ require: {
634
+ types: getDistPath('cjs', `${exportName}.${dtsExtensionsMap[cjsExtension]}`),
635
+ default: getDistPath('cjs', `${exportName}.${cjsExtension}`)
636
+ }
637
+ };
638
+ }
639
+ return {
640
+ import: getDistPath(`${exportName}.mjs`),
641
+ require: getDistPath(`${exportName}.${cjsExtension}`)
642
+ };
643
+ }
655
644
  function createExportConditionPair(exportName, sourceFile, moduleType) {
656
645
  // <exportName>.<specialCondition>
657
646
  let specialCondition;
658
- let exportCondName;
659
- if (exportName.indexOf('.') > 0) {
660
- const [originExportName, specialConditionName] = exportName.split('.');
647
+ const specialConditionName = getSpecialExportTypeFromExportPath(exportName);
648
+ const normalizedExportPath = normalizeExportPath(exportName);
649
+ if (specialConditionName !== 'default') {
650
+ // e.g.
651
+ // ./index.develop -> index
652
+ // ./foo.react-server -> foo
653
+ const fileBaseName = exportName.split('.').slice(0, 2).join('.').replace('./', '');
661
654
  specialCondition = {
662
- [specialConditionName]: getDistPath('es', `${originExportName}-${specialConditionName}.mjs`)
655
+ [specialConditionName]: getDistPath('es', `${fileBaseName}-${specialConditionName}.mjs`)
663
656
  };
664
- exportCondName = normalizeBaseNameToExportName(originExportName);
665
657
  return [
666
- exportCondName,
658
+ normalizedExportPath,
667
659
  specialCondition
668
660
  ];
669
661
  }
670
- exportCondName = normalizeBaseNameToExportName(exportName);
671
662
  const exportCond = createExportCondition(exportName, sourceFile, moduleType);
672
663
  return [
673
- exportCondName,
664
+ normalizedExportPath,
674
665
  exportCond
675
666
  ];
676
667
  }
@@ -698,12 +689,17 @@ async function prepare(cwd) {
698
689
  // Collect bins and exports entries
699
690
  const { bins, exportsEntries } = await collectSourceEntries(sourceFolder);
700
691
  const tsConfigPath = path__default.default.join(cwd, 'tsconfig.json');
701
- const sourceFiles = [
692
+ const exportsSourceFiles = [
702
693
  ...exportsEntries.values()
703
- ].concat([
694
+ ].reduce((acc, sourceFiles)=>{
695
+ Object.values(sourceFiles).forEach((sourceFile)=>acc.add(sourceFile));
696
+ return acc;
697
+ }, new Set());
698
+ const allSourceFiles = [
699
+ ...exportsSourceFiles,
704
700
  ...bins.values()
705
- ]);
706
- const hasTypeScriptFiles = sourceFiles.some((filename)=>isTypescriptFile(filename));
701
+ ].map((absoluteFilePath)=>absoluteFilePath);
702
+ const hasTypeScriptFiles = allSourceFiles.some((filename)=>isTypescriptFile(filename));
707
703
  if (hasTypeScriptFiles) {
708
704
  isUsingTs = true;
709
705
  if (!fs__default.default.existsSync(tsConfigPath)) {
@@ -719,13 +715,14 @@ async function prepare(cwd) {
719
715
  const maxLengthOfBinName = Math.max(...Array.from(bins.keys()).map((binName)=>normalizeBaseNameToExportName(binName).length));
720
716
  for (const [binName, binFile] of bins.entries()){
721
717
  const spaces = ' '.repeat(Math.max(maxLengthOfBinName - normalizeBaseNameToExportName(binName).length, 0));
722
- logger.log(` ${normalizeBaseNameToExportName(binName)}${spaces}: ${binFile}`);
718
+ logger.log(` ${normalizeBaseNameToExportName(binName)}${spaces}: ${path__default.default.basename(binFile)}`);
723
719
  }
724
- if (bins.size === 1 && bins.has('.')) {
720
+ if (bins.size === 1 && bins.has(BINARY_TAG)) {
725
721
  pkgJson.bin = getDistPath('bin', 'index.js');
726
722
  } else {
727
723
  pkgJson.bin = {};
728
- for (const [binName] of bins.entries()){
724
+ for (const [binOriginName] of bins.entries()){
725
+ const binName = stripeBinaryTag(binOriginName);
729
726
  pkgJson.bin[binName === '.' ? pkgJson.name : binName] = getDistPath('bin', binName + '.js');
730
727
  }
731
728
  }
@@ -733,20 +730,24 @@ async function prepare(cwd) {
733
730
  if (exportsEntries.size > 0) {
734
731
  logger.log('Discovered exports entries:');
735
732
  const maxLengthOfExportName = Math.max(...Array.from(exportsEntries.keys()).map((exportName)=>normalizeBaseNameToExportName(exportName).length));
736
- for (const [exportName, exportFile] of exportsEntries.entries()){
733
+ for (const [exportName, sourceFilesMap] of exportsEntries.entries()){
737
734
  const spaces = ' '.repeat(Math.max(maxLengthOfExportName - normalizeBaseNameToExportName(exportName).length, 0));
738
- logger.log(` ${normalizeBaseNameToExportName(exportName)}${spaces}: ${exportFile}`);
735
+ for (const exportFile of Object.values(sourceFilesMap)){
736
+ logger.log(` ${normalizeBaseNameToExportName(exportName)}${spaces}: ${path__default.default.basename(exportFile)}`);
737
+ }
739
738
  }
740
739
  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
- };
740
+ for (const [exportName, sourceFilesMap] of exportsEntries.entries()){
741
+ for (const sourceFile of Object.values(sourceFilesMap)){
742
+ const [key, value] = createExportConditionPair(exportName, sourceFile, pkgJson.type);
743
+ pkgExports[key] = {
744
+ ...value,
745
+ ...pkgExports[key]
746
+ };
747
+ }
747
748
  }
748
749
  // Configure node10 module resolution
749
- if (exportsEntries.has('index')) {
750
+ if (exportsEntries.has('./index')) {
750
751
  const isESM = pkgJson.type === 'module';
751
752
  const mainExport = pkgExports['.'];
752
753
  const mainCondition = isESM ? 'import' : 'require';
@@ -793,7 +794,8 @@ Options:
793
794
  --env <env> inlined process env variables, separate by comma. default: NODE_ENV
794
795
  --cwd <cwd> specify current working directory
795
796
  --sourcemap enable sourcemap generation, default: false
796
- --dts determine if need to generate types, default: false
797
+ --dts determine if need to generate types, default: undefined
798
+ --no-dts do not generate types, default: undefined
797
799
  `;
798
800
  function help() {
799
801
  logger.log(helpMessage);
@@ -810,6 +812,7 @@ function parseCliArgs(argv) {
810
812
  args = arg__default.default({
811
813
  '--cwd': String,
812
814
  '--dts': Boolean,
815
+ '--no-dts': Boolean,
813
816
  '--output': String,
814
817
  '--format': String,
815
818
  '--watch': Boolean,
@@ -843,7 +846,7 @@ function parseCliArgs(argv) {
843
846
  minify: args['--minify'],
844
847
  sourcemap: !!args['--sourcemap'],
845
848
  cwd: args['--cwd'],
846
- dts: args['--dts'],
849
+ dts: args['--no-dts'] ? false : args['--dts'],
847
850
  help: args['--help'],
848
851
  version: args['--version'],
849
852
  runtime: args['--runtime'],
@@ -861,7 +864,7 @@ async function run(args) {
861
864
  const cwd = args.cwd || process.cwd();
862
865
  const file = args.file ? path__default.default.resolve(cwd, args.file) : undefined;
863
866
  const bundleConfig = {
864
- dts,
867
+ dts: typeof dts === 'boolean' ? dts : undefined,
865
868
  file,
866
869
  format,
867
870
  cwd,