Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .git2gus/config.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"productTag": "a1aB0000000g309IAA",
"defaultBuild": "256",
"defaultBuild": "258",
"hideWorkItemUrl": true
}
2 changes: 1 addition & 1 deletion .github/workflows/unit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ jobs:
- name: Check package.json integrity
run: node ./scripts/tasks/check-and-rewrite-package-json.js --test
- name: Check licenses are up to date
run: node ./scripts/tasks/generate-license-files.js --test
run: node ./scripts/tasks/generate-license-files.mjs --test
- name: Verify @lwc/shared is tree-shakable
run: node ./scripts/tasks/verify-treeshakable.mjs ./packages/@lwc/shared/dist/index.js
- name: Verify that dependencies are declared
Expand Down
2 changes: 1 addition & 1 deletion .husky/pre-push
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
set -e
node ./scripts/tasks/check-and-rewrite-package-json.js --test
node ./scripts/tasks/generate-license-files.js --test
node ./scripts/tasks/generate-license-files.mjs --test
node ./scripts/tasks/verify-treeshakable.mjs ./packages/@lwc/shared/dist/index.js
node ./scripts/tasks/check-imports-are-declared-dependencies.js
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
"*.{js,mjs,ts,only,skip}": "eslint --cache",
"*.{css,js,json,md,mjs,ts,yaml,yml}": "prettier --check",
"{packages/**/package.json,scripts/tasks/check-and-rewrite-package-json.js}": "node ./scripts/tasks/check-and-rewrite-package-json.js --test",
"{LICENSE-CORE.md,**/LICENSE.md,yarn.lock,scripts/tasks/generate-license-files.js,scripts/shared/bundled-dependencies.js}": "node ./scripts/tasks/generate-license-files.js --test"
"{LICENSE-CORE.md,**/LICENSE.md,yarn.lock,scripts/tasks/generate-license-files.mjs,scripts/shared/bundled-dependencies.js}": "node ./scripts/tasks/generate-license-files.mjs --test"
},
"workspaces": [
"packages/@lwc/*",
Expand Down
100 changes: 0 additions & 100 deletions scripts/tasks/generate-license-files.js

This file was deleted.

122 changes: 122 additions & 0 deletions scripts/tasks/generate-license-files.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import path from 'node:path';
import { readFile, writeFile, stat, readdir } from 'node:fs/promises';
import { createRequire } from 'node:module';
import { fileURLToPath } from 'node:url';
import prettier from 'prettier';
import { BUNDLED_DEPENDENCIES } from '../shared/bundled-dependencies.js';

// We're using ESM here, but some packages still only export CJS, so we also need `require`
const require = createRequire(import.meta.url);

const atLwcPackages = (await readdir('packages/@lwc'))
// skip dotfiles like .DS_Store
.filter((_) => !_.startsWith('.'))
.map((_) => `@lwc/${_}`);

// Generate our LICENSE files for each package, including any bundled dependencies
// This is modeled after how Rollup does it:
// https://github.com/rollup/rollup/blob/0b665c3/build-plugins/generate-license-file.ts

// Async fs.existsSync
async function exists(filename) {
try {
await stat(filename);
return true;
} catch (_err) {
return false;
}
}

/**
* Tries `require.resolve` with additional paths (`packages/@lwc/___/node_modules`)
* and `import.meta.resolve` (unmodified) to find a package's entrypoint.
*/
function tryResolve(specifier) {
try {
// As far as I can tell, there's no way to modify the `import` lookup paths
return fileURLToPath(import.meta.resolve(specifier));
} catch (err) {
// We expect to see missing packages, but throw other errors
if (err.code !== 'ERR_MODULE_NOT_FOUND') {
throw err;
}
}
// `require.resolve` accepts a second parameter of additional places to look
return require.resolve(specifier, {
paths: atLwcPackages.map((pkg) => path.join('packages', pkg, 'node_modules')),
});
}

/**
* Finds a dependency in our monorepo.
* @param {string} specifier - package name to find
*/
function findPackageDirectory(specifier) {
const resolved = tryResolve(specifier);
// An import can resolve to a nested directory, e.g. dist/index.js. We want the package
// root, which will always be the last node_modules/${specifier}.
const lookup = path.join('/node_modules', specifier);
return resolved.slice(0, resolved.lastIndexOf(lookup) + lookup.length);
}

async function findLicenseText(depName) {
// Iterate through possible names for the license file
const names = ['LICENSE', 'LICENSE.md', 'LICENSE.txt'];

const resolvedDepPath = findPackageDirectory(depName);

for (const name of names) {
const fullFilePath = path.join(resolvedDepPath, name);
if (await exists(fullFilePath)) {
return (await readFile(fullFilePath, 'utf-8')).trim();
}
}

// Get the license from the package.json if we can't find it elsewhere
const { license, version } = JSON.parse(
await readFile(path.join(resolvedDepPath, 'package.json'), 'utf-8')
);

return `${license} license defined in package.json in v${version}.`;
}

const coreLicense = await readFile('LICENSE-CORE.md', 'utf-8');

const bundledLicenses = await Promise.all(
BUNDLED_DEPENDENCIES.map(async (depName) => {
return `## ${depName}\n\n` + (await findLicenseText(depName));
})
);
const newLicense =
`# LWC core license\n\n${coreLicense}\n# Licenses of bundled dependencies\n\n${bundledLicenses.join(
'\n'
)}`.trim() + '\n';

const formattedLicense = await prettier.format(newLicense, {
parser: 'markdown',
});

// Check against current top-level license for changes
const shouldWarnChanges =
process.argv.includes('--test') && formattedLicense !== (await readFile('LICENSE.md', 'utf-8'));

// Top level license
await writeFile('LICENSE.md', formattedLicense, 'utf-8');

// License file for each package as well, so that we publish it to npm

const packages = ['lwc', ...atLwcPackages];

await Promise.all(
packages.map(async (pkg) => {
await writeFile(path.join('packages/', pkg, 'LICENSE.md'), formattedLicense, 'utf-8');
})
);

if (shouldWarnChanges) {
const relativeFilename = path.relative(process.cwd(), import.meta.filename);
throw new Error(
'Either the LWC core license or the license of a bundled dependency has been updated.\n' +
`Please run \`node ${relativeFilename}\` and commit the result.`
);
}