Skip to content

Commit

Permalink
new: Ensure package exports conditions are sorted correctly. (#111)
Browse files Browse the repository at this point in the history
* Update swc.

* Add sorting.

* Run on repo.

* Add tests.
  • Loading branch information
milesj committed Apr 20, 2022
1 parent 702932a commit 51f5aa4
Show file tree
Hide file tree
Showing 13 changed files with 104 additions and 42 deletions.
8 changes: 4 additions & 4 deletions packages/babel-plugin-cjs-esm-interop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,12 @@
"exports": {
"./package.json": "./package.json",
"./*": {
"node": "./lib/*.js",
"types": "./dts/*.d.ts"
"types": "./dts/*.d.ts",
"node": "./lib/*.js"
},
".": {
"node": "./lib/index.js",
"types": "./dts/index.d.ts"
"types": "./dts/index.d.ts",
"node": "./lib/index.js"
}
}
}
8 changes: 4 additions & 4 deletions packages/babel-plugin-conditional-invariant/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@
"exports": {
"./package.json": "./package.json",
"./*": {
"node": "./lib/*.js",
"types": "./dts/*.d.ts"
"types": "./dts/*.d.ts",
"node": "./lib/*.js"
},
".": {
"node": "./lib/index.js",
"types": "./dts/index.d.ts"
"types": "./dts/index.d.ts",
"node": "./lib/index.js"
}
}
}
8 changes: 4 additions & 4 deletions packages/babel-plugin-env-constants/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@
"exports": {
"./package.json": "./package.json",
"./*": {
"node": "./lib/*.js",
"types": "./dts/*.d.ts"
"types": "./dts/*.d.ts",
"node": "./lib/*.js"
},
".": {
"node": "./lib/index.js",
"types": "./dts/index.d.ts"
"types": "./dts/index.d.ts",
"node": "./lib/index.js"
}
}
}
8 changes: 4 additions & 4 deletions packages/packemon/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@
"exports": {
"./package.json": "./package.json",
"./*": {
"node": "./lib/*.js",
"types": "./dts/*.d.ts"
"types": "./dts/*.d.ts",
"node": "./lib/*.js"
},
".": {
"node": "./lib/index.js",
"types": "./dts/index.d.ts"
"types": "./dts/index.d.ts",
"node": "./lib/index.js"
}
},
"engines": {
Expand Down
16 changes: 2 additions & 14 deletions packages/packemon/src/CodeArtifact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,17 +199,10 @@ export class CodeArtifact extends Artifact<CodeBuild> {

protected mapPackageExportsFromBuilds(outputName: string, exportMap: PackageExports) {
const paths: PackageExportPaths = {};
let libPath: PackageExportPaths | string = '';

this.builds.forEach(({ format }) => {
const entry = this.findEntryPoint([format], outputName);

// Must come after import/require
if (paths.default) {
libPath = paths.default;
delete paths.default;
}

switch (format) {
case 'mjs':
case 'esm':
Expand All @@ -226,23 +219,18 @@ export class CodeArtifact extends Artifact<CodeBuild> {
break;

case 'lib':
libPath = entry;
paths.default = entry;
break;

default:
break;
}
});

// Must come after import/require
if (libPath) {
paths.default = libPath;
}

// eslint-disable-next-line no-param-reassign
exportMap[outputName === 'index' ? '.' : `./${outputName}`] = {
[this.platform === 'native' ? 'react-native' : this.platform]:
Object.keys(paths).length === 1 && libPath ? libPath : paths,
Object.keys(paths).length === 1 && paths.default ? paths.default : paths,
};
}
}
7 changes: 7 additions & 0 deletions packages/packemon/src/Package.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
SUPPORT_PRIORITY,
} from './constants';
import { loadModule } from './helpers/loadModule';
import { sortExportConditions } from './helpers/sortExportConditions';
import { Project } from './Project';
import { packemonBlueprint } from './schemas';
import {
Expand Down Expand Up @@ -488,6 +489,12 @@ export class Package {
});
});

// Sort the condition paths
Object.entries(exportMap).forEach(([path, conditions]) => {
exportMap[path] =
typeof conditions === 'string' ? conditions : sortExportConditions(conditions);
});

if (isObject(this.packageJson.exports)) {
Object.assign(this.packageJson.exports, exportMap);
} else {
Expand Down
32 changes: 32 additions & 0 deletions packages/packemon/src/helpers/sortExportConditions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { PackageExportPaths } from '../types';

// https://nodejs.org/api/packages.html#conditional-exports
const WEIGHTS = {
types: 10, // Types must always be first
misc: 20,
'node-addons': 30,
node: 31,
import: 40,
require: 50,
default: 100, // Default must be last
};

export function sortExportConditions(paths: PackageExportPaths): PackageExportPaths {
const pathsList: { weight: number; key: string; value: PackageExportPaths | string }[] = [];

Object.entries(paths).forEach(([key, value]) => {
pathsList.push({
weight: key in WEIGHTS ? WEIGHTS[key as 'misc'] : WEIGHTS.misc,
key,
value: typeof value === 'string' ? value : sortExportConditions(value),
});
});

pathsList.sort((a, d) => {
const diff = a.weight - d.weight;

return diff === 0 ? a.key.localeCompare(d.key) : diff;
});

return Object.fromEntries(pathsList.map((path) => [path.key, path.value]));
}
6 changes: 3 additions & 3 deletions packages/packemon/src/swc/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export function getSwcInputConfig(
jsc: {
parser: {
syntax: 'ecmascript',
jsx: features.react,
jsx: !!features.react,
dynamicImport: true,
},
transform,
Expand All @@ -109,7 +109,7 @@ export function getSwcInputConfig(
if (features.typescript) {
const parser: TsParserConfig = {
syntax: 'typescript',
tsx: features.react,
tsx: !!features.react,
dynamicImport: true,
};

Expand All @@ -124,7 +124,7 @@ export function getSwcInputConfig(
if (features.react) {
transform.react = {
development: __DEV__,
runtime: 'classic',
runtime: features.react,
throwIfNamespace: true,
};
}
Expand Down
8 changes: 8 additions & 0 deletions packages/packemon/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,21 @@ export interface PackageConfig {
// https://webpack.js.org/guides/package-exports

export type PackageExportConditions =
| 'asset'
| 'browser'
| 'default'
| 'deno'
| 'development'
| 'electron'
| 'import'
| 'module'
| 'node-addons'
| 'node'
| 'production'
| 'react-native'
| 'require'
| 'script'
| 'style'
| 'types';

export type PackageExportPaths = {
Expand Down
2 changes: 1 addition & 1 deletion packages/packemon/tests/examples/react.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ describe.skip('React/JSX', () => {
});

// Automatic only
testExampleOutput('react.tsx');
testExampleOutput('react.tsx', 'babel');
});
25 changes: 25 additions & 0 deletions packages/packemon/tests/helpers/sortExportConditions.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { sortExportConditions } from '../../src/helpers/sortExportConditions';

describe('sortExportConditions()', () => {
it('sorts in the correct order', () => {
const map = sortExportConditions({
default: '',
script: '',
import: '',
node: '',
require: '',
types: '',
browser: '',
});

expect(Object.keys(map)).toStrictEqual([
'types',
'browser',
'script',
'node',
'import',
'require',
'default',
]);
});
});
14 changes: 7 additions & 7 deletions packages/packemon/tests/swc/__snapshots__/config.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Object {
"loose": false,
"parser": Object {
"dynamicImport": true,
"jsx": undefined,
"jsx": false,
"syntax": "ecmascript",
},
"preserveAllComments": true,
Expand All @@ -39,7 +39,7 @@ Object {
"loose": false,
"parser": Object {
"dynamicImport": true,
"jsx": undefined,
"jsx": false,
"syntax": "ecmascript",
},
"preserveAllComments": true,
Expand All @@ -64,7 +64,7 @@ Object {
"loose": false,
"parser": Object {
"dynamicImport": true,
"jsx": undefined,
"jsx": false,
"syntax": "ecmascript",
},
"preserveAllComments": true,
Expand All @@ -82,7 +82,7 @@ Object {
"optimizer": undefined,
"react": Object {
"development": true,
"runtime": "classic",
"runtime": "automatic",
"throwIfNamespace": true,
},
}
Expand All @@ -102,7 +102,7 @@ Object {
"decorators": true,
"dynamicImport": true,
"syntax": "typescript",
"tsx": undefined,
"tsx": false,
},
"preserveAllComments": true,
"target": "es2022",
Expand All @@ -119,7 +119,7 @@ exports[`getSwcInputConfig() includes typescript parser if \`typescript\` featur
Object {
"dynamicImport": true,
"syntax": "typescript",
"tsx": undefined,
"tsx": false,
}
`;

Expand All @@ -137,7 +137,7 @@ Object {
"decorators": true,
"dynamicImport": true,
"syntax": "typescript",
"tsx": undefined,
"tsx": false,
},
"preserveAllComments": true,
"target": "es2022",
Expand Down
4 changes: 3 additions & 1 deletion packages/packemon/tests/swc/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ describe('getSwcInputConfig()', () => {
});

it('includes react transformer if `react` feature flag is true', () => {
expect(getSwcInputConfig(bundleArtifact, { react: true }).jsc?.transform).toMatchSnapshot();
expect(
getSwcInputConfig(bundleArtifact, { react: 'automatic' }).jsc?.transform,
).toMatchSnapshot();
});

it('includes typescript parser if `typescript` feature flag is true', () => {
Expand Down

0 comments on commit 51f5aa4

Please sign in to comment.