Skip to content

Commit

Permalink
fix: add default exports to lwc @W-13710298 (#3997)
Browse files Browse the repository at this point in the history
* fix: include default exports in lwc re-exports

* test(lwc): validate default exports are re-exported; fixes #3605

* fix: remove stub test

oops

* test(lwc): skip testing index file; it's not a package

* fix: make tsconfig consistent with other packages

* chore: add comment explaining .cjs

* test(lwc): validate that all dependencies have an export declared

* test(lwc): use JSDOM so browser packages work

* fix(tests): detect "default" default export and skip it

* chore: use better test description

* chore: clarify comment
  • Loading branch information
wjhsf authored Feb 16, 2024
1 parent cd7ed65 commit a579fcc
Show file tree
Hide file tree
Showing 13 changed files with 117 additions and 9 deletions.
59 changes: 59 additions & 0 deletions packages/lwc/__tests__/default-exports.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright (c) 2024, Salesforce, Inc.
* All rights reserved.
* SPDX-License-Identifier: MIT
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
*/
import * as fs from 'node:fs';
import * as path from 'node:path';

const PACKAGE_ROOT = path.join(__dirname, '..');

const expectExportDefaultFromPackageInFile = (pkgName: string, ext: string) => {
const filename = path.join(PACKAGE_ROOT, pkgName + ext);
const contents = fs.readFileSync(filename, 'utf8');
const exportDefaultFromPackage = new RegExp(
`^export \\{ default \\} from '@lwc/${pkgName}';$`,
'm'
);
expect(contents).toMatch(exportDefaultFromPackage);
};

/**
* Jest uses CommonJS, which means that packages with no explicit export statements actually export
* the default `module.exports` empty object. That export is an empty object with the prototype set
* to an empty object with null prototype.
*/
const hasExplicitDefaultExport = (mod: object) => {
// No default export = self explanatory
if (!('default' in mod)) return false;
// If we have more than one export, then we must have explicitly declared them
if (Object.keys(mod).length > 1) return true;
const def = mod.default;
// If it's not an object, it must be an explicit export
if (typeof def !== 'object' || def === null) return true;
// If it's not an empty object, it's not the placeholder object
if (Object.keys(def).length > 0) return true;
const proto = Object.getPrototypeOf(def);
// If the prototype isn't an empty null-prototype object, it's not the placeholder object
if (Object.keys(proto).length > 0 || Object.getPrototypeOf(proto) !== null) return true;
// It must be the placeholder object!
return false;
};

describe('default exports are not forgotten', () => {
const allFiles = fs.readdirSync(PACKAGE_ROOT);
const packages = allFiles
.filter((f) => f.endsWith('.js') && f !== 'index.js')
.map((f) => f.slice(0, -3));
test.each(packages)('@lwc/%s', async (pkg) => {
const realModule = await import(`@lwc/${pkg}`);
// When jest properly supports ESM, this will be a lot simpler
// const aliasedModule = await import(`lwc/${pkg}`);
// expect(aliasedModule.default).toBe(realModule.default);
if (hasExplicitDefaultExport(realModule)) {
expectExportDefaultFromPackageInFile(pkg, '.d.ts');
expectExportDefaultFromPackageInFile(pkg, '.js');
}
});
});
16 changes: 16 additions & 0 deletions packages/lwc/__tests__/package-exports.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* Copyright (c) 2024, Salesforce, Inc.
* All rights reserved.
* SPDX-License-Identifier: MIT
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
*/
import { readFileSync } from 'node:fs';
import { join } from 'node:path';

describe('packaged dependencies are re-exported', () => {
const pkg = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf8'));
test.each(Object.keys(pkg.dependencies))(`%s is exported`, (name) => {
const relative = name.replace('@lwc', '.');
expect(pkg.exports[relative]).toBe(`${relative}.js`);
});
});
3 changes: 2 additions & 1 deletion packages/lwc/babel-plugin-component.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/*
* Copyright (c) 2023, salesforce.com, inc.
* Copyright (c) 2024, salesforce.com, inc.
* All rights reserved.
* SPDX-License-Identifier: MIT
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
*/
export type * from '@lwc/babel-plugin-component';
export { default } from '@lwc/babel-plugin-component';
3 changes: 2 additions & 1 deletion packages/lwc/babel-plugin-component.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/*
* Copyright (c) 2023, salesforce.com, inc.
* Copyright (c) 2024, salesforce.com, inc.
* All rights reserved.
* SPDX-License-Identifier: MIT
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
*/
export * from '@lwc/babel-plugin-component';
export { default } from '@lwc/babel-plugin-component';
3 changes: 2 additions & 1 deletion packages/lwc/features.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/*
* Copyright (c) 2023, salesforce.com, inc.
* Copyright (c) 2024, salesforce.com, inc.
* All rights reserved.
* SPDX-License-Identifier: MIT
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
*/
export type * from '@lwc/features';
export { default } from '@lwc/features';
3 changes: 2 additions & 1 deletion packages/lwc/features.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/*
* Copyright (c) 2023, salesforce.com, inc.
* Copyright (c) 2024, salesforce.com, inc.
* All rights reserved.
* SPDX-License-Identifier: MIT
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
*/
export * from '@lwc/features';
export { default } from '@lwc/features';
22 changes: 22 additions & 0 deletions packages/lwc/jest.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright (c) 2024, Salesforce, Inc.
* All rights reserved.
* SPDX-License-Identifier: MIT
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
*/
/* eslint-env node */

/**
* This is a .cjs file because this package is an ESM package, but jest needs CJS to work.
* If this file is ever changed to a .js file, add an exclusion to the package.json "files" list,
* so that this is not shipped as part of the package.
*/

// eslint-disable-next-line @typescript-eslint/no-var-requires
const BASE_CONFIG = require('../../scripts/jest/base.config');

module.exports = {
...BASE_CONFIG,
displayName: 'lwc',
testEnvironment: 'jsdom',
};
3 changes: 2 additions & 1 deletion packages/lwc/rollup-plugin.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/*
* Copyright (c) 2023, salesforce.com, inc.
* Copyright (c) 2024, salesforce.com, inc.
* All rights reserved.
* SPDX-License-Identifier: MIT
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
*/
export type * from '@lwc/rollup-plugin';
export { default } from '@lwc/rollup-plugin';
3 changes: 2 additions & 1 deletion packages/lwc/rollup-plugin.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/*
* Copyright (c) 2023, salesforce.com, inc.
* Copyright (c) 2024, salesforce.com, inc.
* All rights reserved.
* SPDX-License-Identifier: MIT
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
*/
export * from '@lwc/rollup-plugin';
export { default } from '@lwc/rollup-plugin';
3 changes: 2 additions & 1 deletion packages/lwc/template-compiler.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/*
* Copyright (c) 2023, salesforce.com, inc.
* Copyright (c) 2024, salesforce.com, inc.
* All rights reserved.
* SPDX-License-Identifier: MIT
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
*/
export type * from '@lwc/template-compiler';
export { default } from '@lwc/template-compiler';
3 changes: 2 additions & 1 deletion packages/lwc/template-compiler.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/*
* Copyright (c) 2023, salesforce.com, inc.
* Copyright (c) 2024, salesforce.com, inc.
* All rights reserved.
* SPDX-License-Identifier: MIT
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
*/
export * from '@lwc/template-compiler';
export { default } from '@lwc/template-compiler';
4 changes: 3 additions & 1 deletion packages/lwc/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
{
"extends": "../../tsconfig.json",

"compilerOptions": {
"lib": ["dom"]
"lib": ["dom", "es2021"]
}
}
1 change: 1 addition & 0 deletions scripts/jest/root.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ module.exports = {
'<rootDir>/packages/@lwc/synthetic-shadow',
'<rootDir>/packages/@lwc/template-compiler',
'<rootDir>/packages/@lwc/wire-service',
'<rootDir>/packages/lwc',
],
coverageThreshold: {
global: {
Expand Down

0 comments on commit a579fcc

Please sign in to comment.