@ms-cloudpack/esbuild-node-helpers 0.1.0

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 (54) hide show
  1. package/README.md +8 -0
  2. package/lib/bundleNode.d.ts +37 -0
  3. package/lib/bundleNode.d.ts.map +1 -0
  4. package/lib/bundleNode.js +135 -0
  5. package/lib/bundleNode.js.map +1 -0
  6. package/lib/index.d.ts +7 -0
  7. package/lib/index.d.ts.map +1 -0
  8. package/lib/index.js +6 -0
  9. package/lib/index.js.map +1 -0
  10. package/lib/license/analyzeLicenses.d.ts +12 -0
  11. package/lib/license/analyzeLicenses.d.ts.map +1 -0
  12. package/lib/license/analyzeLicenses.js +148 -0
  13. package/lib/license/analyzeLicenses.js.map +1 -0
  14. package/lib/license/licensePlugin.d.ts +20 -0
  15. package/lib/license/licensePlugin.d.ts.map +1 -0
  16. package/lib/license/licensePlugin.js +66 -0
  17. package/lib/license/licensePlugin.js.map +1 -0
  18. package/lib/license/types.d.ts +33 -0
  19. package/lib/license/types.d.ts.map +1 -0
  20. package/lib/license/types.js +2 -0
  21. package/lib/license/types.js.map +1 -0
  22. package/lib/license/unacceptableLicenseTest.d.ts +8 -0
  23. package/lib/license/unacceptableLicenseTest.d.ts.map +1 -0
  24. package/lib/license/unacceptableLicenseTest.js +12 -0
  25. package/lib/license/unacceptableLicenseTest.js.map +1 -0
  26. package/lib/license/writeNotice.d.ts +7 -0
  27. package/lib/license/writeNotice.d.ts.map +1 -0
  28. package/lib/license/writeNotice.js +34 -0
  29. package/lib/license/writeNotice.js.map +1 -0
  30. package/lib/types.d.ts +27 -0
  31. package/lib/types.d.ts.map +1 -0
  32. package/lib/types.js +2 -0
  33. package/lib/types.js.map +1 -0
  34. package/lib/utils/BundleError.d.ts +11 -0
  35. package/lib/utils/BundleError.d.ts.map +1 -0
  36. package/lib/utils/BundleError.js +12 -0
  37. package/lib/utils/BundleError.js.map +1 -0
  38. package/lib/utils/checkForDuplicateDeps.d.ts +13 -0
  39. package/lib/utils/checkForDuplicateDeps.d.ts.map +1 -0
  40. package/lib/utils/checkForDuplicateDeps.js +94 -0
  41. package/lib/utils/checkForDuplicateDeps.js.map +1 -0
  42. package/lib/utils/findRealPackageJson.d.ts +12 -0
  43. package/lib/utils/findRealPackageJson.d.ts.map +1 -0
  44. package/lib/utils/findRealPackageJson.js +36 -0
  45. package/lib/utils/findRealPackageJson.js.map +1 -0
  46. package/lib/utils/logHelpers.d.ts +14 -0
  47. package/lib/utils/logHelpers.d.ts.map +1 -0
  48. package/lib/utils/logHelpers.js +26 -0
  49. package/lib/utils/logHelpers.js.map +1 -0
  50. package/lib/utils/verifyPackageJson.d.ts +28 -0
  51. package/lib/utils/verifyPackageJson.d.ts.map +1 -0
  52. package/lib/utils/verifyPackageJson.js +47 -0
  53. package/lib/utils/verifyPackageJson.js.map +1 -0
  54. package/package.json +46 -0
package/README.md ADDED
@@ -0,0 +1,8 @@
1
+ # @ms-cloudpack/esbuild-node-helpers
2
+
3
+ Helpers for creating Node bundles with `esbuild`, intended for use either within Cloudpack or in other repos.
4
+
5
+ See individual API docs for full details, but in brief:
6
+
7
+ - `bundleNode`: Bundle a package with `esbuild`, externalizing `dependencies` but bundling all other referenced deps. It also checks for duplicate dependencies and writes a `NOTICE.txt` file with licenses.
8
+ - `licensePlugin`: Generate a `NOTICE.txt` file at the package root with license information for all dependencies that are included in the bundle (excluding any packages from the same repo).
@@ -0,0 +1,37 @@
1
+ import * as esbuild from 'esbuild';
2
+ import type { LicensePluginOptions } from './license/types.ts';
3
+ import { type VerifyPackageJsonOptions } from './utils/verifyPackageJson.ts';
4
+ export interface BundleNodeOptions extends VerifyPackageJsonOptions, Pick<LicensePluginOptions, 'unacceptableLicenseTest'> {
5
+ /** Working directory, usually the package root (it will find the actual root from here) */
6
+ cwd: string;
7
+ /** Clean output before building (highly recommended due to hashed filenames) @default true */
8
+ clean?: boolean;
9
+ /** Extra options for esbuild */
10
+ esbuildOptions?: Omit<esbuild.BuildOptions, 'absWorkingDir' | 'bundle' | 'entryPoints' | 'metafile' | 'outdir' | 'platform'>;
11
+ /** Error if there are duplicate packages matching any of these regexps */
12
+ errorDupePackages?: RegExp[];
13
+ /** If true, write esbuild's metafile and analysis to disk under `<packageRoot>/temp` */
14
+ writeMetafile?: boolean;
15
+ }
16
+ /**
17
+ * Bundle a node package with esbuild. By default it creates an ESM bundle for Node 22+.
18
+ * `dependencies` will be externalized, but all other referenced deps will be bundled.
19
+ *
20
+ * It also writes a `NOTICE.txt` file at the package root with license information for dependencies
21
+ * from outside the current repo, and if `options.unacceptableLicenseTest` is provided, errors if
22
+ * any packages have disallowed licenses. It also errors if a package is missing license info.
23
+ *
24
+ * Before bundling, it checks for proper configuration of `package.json`:
25
+ * - `NOTICE.txt` and the output directory are included in `files`
26
+ * - If `verifyExportPaths` is set, `exports` are correctly mapped
27
+ * - If `verifyTypesInFiles` is true, `lib/** /*.d.ts` is included in `files`
28
+ *
29
+ * After bundling, it checks for duplicate dependencies:
30
+ * - Always error if there are multiple copies of the same version of a dependency
31
+ * - Optionally error if any dependencies match the regexps provided in `errorDupePackages`
32
+ *
33
+ * (Some of the current logic and messages assume the consuming repo is using yarn v4, likely
34
+ * with `nodeLinker: 'pnpm'`, but it can be updated as needed for other linkers and/or managers.)
35
+ */
36
+ export declare function bundleNode(options: BundleNodeOptions): Promise<void>;
37
+ //# sourceMappingURL=bundleNode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundleNode.d.ts","sourceRoot":"","sources":["../src/bundleNode.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AAInC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAK/D,OAAO,EAAqB,KAAK,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAEhG,MAAM,WAAW,iBACf,SAAQ,wBAAwB,EAAE,IAAI,CAAC,oBAAoB,EAAE,yBAAyB,CAAC;IACvF,2FAA2F;IAC3F,GAAG,EAAE,MAAM,CAAC;IAEZ,8FAA8F;IAC9F,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB,gCAAgC;IAChC,cAAc,CAAC,EAAE,IAAI,CACnB,OAAO,CAAC,YAAY,EACpB,eAAe,GAAG,QAAQ,GAAG,aAAa,GAAG,UAAU,GAAG,QAAQ,GAAG,UAAU,CAChF,CAAC;IAEF,0EAA0E;IAC1E,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAE7B,wFAAwF;IACxF,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAiBD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CA0G1E"}
@@ -0,0 +1,135 @@
1
+ import * as esbuild from 'esbuild';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import { licensePlugin } from "./license/licensePlugin.js";
5
+ import { BundleError } from "./utils/BundleError.js";
6
+ import { checkForDuplicateDeps } from "./utils/checkForDuplicateDeps.js";
7
+ import { findRealPackageJson } from "./utils/findRealPackageJson.js";
8
+ import { colors, logError } from "./utils/logHelpers.js";
9
+ import { verifyPackageJson } from "./utils/verifyPackageJson.js";
10
+ /**
11
+ * This is added at the top of every file and makes CJS globals work in esbuild output.
12
+ * We need `require()` for bundled CJS that loads Node internals or native packages.
13
+ * The bundled CJS deps also use `__filename` and `__dirname` in a couple places.
14
+ * https://github.com/evanw/esbuild/issues/946#issuecomment-814703190
15
+ */
16
+ const requireHeader = `// @ts-nocheck
17
+ /* eslint-disable */
18
+ import { createRequire as topLevelCreateRequire } from 'node:module';
19
+ import topLevelPath from 'node:path';
20
+ import topLevelUrl from 'node:url';
21
+ const require = topLevelCreateRequire(import.meta.url);
22
+ const __filename = topLevelUrl.fileURLToPath(import.meta.url);
23
+ const __dirname = topLevelPath.dirname(__filename);`;
24
+ /**
25
+ * Bundle a node package with esbuild. By default it creates an ESM bundle for Node 22+.
26
+ * `dependencies` will be externalized, but all other referenced deps will be bundled.
27
+ *
28
+ * It also writes a `NOTICE.txt` file at the package root with license information for dependencies
29
+ * from outside the current repo, and if `options.unacceptableLicenseTest` is provided, errors if
30
+ * any packages have disallowed licenses. It also errors if a package is missing license info.
31
+ *
32
+ * Before bundling, it checks for proper configuration of `package.json`:
33
+ * - `NOTICE.txt` and the output directory are included in `files`
34
+ * - If `verifyExportPaths` is set, `exports` are correctly mapped
35
+ * - If `verifyTypesInFiles` is true, `lib/** /*.d.ts` is included in `files`
36
+ *
37
+ * After bundling, it checks for duplicate dependencies:
38
+ * - Always error if there are multiple copies of the same version of a dependency
39
+ * - Optionally error if any dependencies match the regexps provided in `errorDupePackages`
40
+ *
41
+ * (Some of the current logic and messages assume the consuming repo is using yarn v4, likely
42
+ * with `nodeLinker: 'pnpm'`, but it can be updated as needed for other linkers and/or managers.)
43
+ */
44
+ export async function bundleNode(options) {
45
+ const { cwd, entryPoints, outDir, errorDupePackages, esbuildOptions, clean = true } = options;
46
+ console.log();
47
+ console.log('Bundling package with esbuild...\n');
48
+ const { packageJson, packageRoot } = findRealPackageJson(cwd);
49
+ verifyPackageJson(options, packageJson);
50
+ if (clean) {
51
+ // Remove old output. This is more important with esbuild due to hashed filenames.
52
+ fs.rmSync(path.join(packageRoot, outDir), { force: true, recursive: true });
53
+ }
54
+ // The header defining require() is needed with ESM output, but not if the user changed the format
55
+ const format = esbuildOptions?.format ?? 'esm';
56
+ const jsBanner = format === 'esm' ? requireHeader : undefined;
57
+ let result;
58
+ try {
59
+ result = await esbuild.build({
60
+ splitting: format === 'esm',
61
+ treeShaking: true,
62
+ target: ['node22'],
63
+ // some packages rely on specific names in instanceof checks
64
+ keepNames: true,
65
+ // log errors, warnings, and a summary (which includes the output file sizes)
66
+ logLevel: 'info',
67
+ // less important if not minifying, and bloats package size
68
+ // sourcemap: true,
69
+ ...esbuildOptions,
70
+ // Critical options
71
+ absWorkingDir: packageRoot,
72
+ entryPoints: entryPoints,
73
+ outdir: outDir,
74
+ platform: 'node',
75
+ bundle: true,
76
+ format,
77
+ // Exclude non-dev dependencies from the bundle. In a bundled package, generally the only
78
+ // dependencies should be other internal packages and anything with native binaries.
79
+ // (It appears node built-ins are automatically externalized with platform: 'node'.)
80
+ external: [
81
+ ...Object.keys({
82
+ ...packageJson.dependencies,
83
+ ...packageJson.peerDependencies,
84
+ ...packageJson.optionalDependencies,
85
+ }),
86
+ ...(esbuildOptions?.external || []),
87
+ ],
88
+ plugins: [
89
+ licensePlugin({
90
+ packageName: packageJson.name,
91
+ packageRoot,
92
+ absOutDir: packageRoot,
93
+ unacceptableLicenseTest: options.unacceptableLicenseTest,
94
+ }),
95
+ ...(esbuildOptions?.plugins || []),
96
+ ],
97
+ banner: {
98
+ ...esbuildOptions?.banner,
99
+ js: [esbuildOptions?.banner?.js, jsBanner].filter(Boolean).join('\n'),
100
+ },
101
+ metafile: true,
102
+ });
103
+ }
104
+ catch (err) {
105
+ const failure = err;
106
+ if (failure.errors.some((e) => e.text.includes('Could not resolve') && e.location?.file.includes('.store'))) {
107
+ console.log(`\n${colors.red(colors.bold('NOTE:'))} Packages that could not be found are usually missing peers, ` +
108
+ `which may not be specified properly for strict installation layouts. ` +
109
+ `You can work around this by updating ${colors.bold('yarnrc.yml packageExtensions')} to ` +
110
+ `include the missing package as a dependency or peerDependency of the importing package.`);
111
+ }
112
+ const msg = `Bundling failed with ${failure.errors.length} error(s)!`;
113
+ logError(colors.red(colors.bold(msg + '\n')));
114
+ throw new BundleError(msg, { alreadyLogged: true, cause: err });
115
+ }
116
+ if (options.writeMetafile) {
117
+ // Write the metafile and analysis to disk for inspection.
118
+ const tmpDir = path.join(packageRoot, 'temp');
119
+ fs.mkdirSync(tmpDir, { recursive: true }); // do nothing if it exists
120
+ fs.writeFileSync(path.join(tmpDir, 'esbuild-metafile.json'), JSON.stringify(result.metafile, null, 2));
121
+ const analysis = await esbuild.analyzeMetafile(result.metafile, { verbose: true });
122
+ fs.writeFileSync(path.join(tmpDir, 'esbuild-metafile-analysis.txt'), analysis);
123
+ }
124
+ // Check for duplicate dependencies in the bundle.
125
+ const { errorDupeDeps, warnDupeDeps, sameVersionDupes } = checkForDuplicateDeps(packageRoot, Object.keys(result.metafile.inputs), errorDupePackages);
126
+ if (errorDupeDeps.length || sameVersionDupes.length) {
127
+ throw new BundleError('Duplicate dependencies detected (see above)', { alreadyLogged: true });
128
+ }
129
+ const hasDupeWarnings = !!warnDupeDeps.length;
130
+ const hasWarnings = hasDupeWarnings || !!result.warnings.length;
131
+ const color = hasWarnings ? 'yellow' : 'green';
132
+ // With logLevel set to 'info', esbuild will handle the basic logging.
133
+ console.log(colors[color](colors.bold(`Bundling completed${hasWarnings ? ' with warnings (see above)' : '!'}\n`)));
134
+ }
135
+ //# sourceMappingURL=bundleNode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundleNode.js","sourceRoot":"","sources":["../src/bundleNode.ts"],"names":[],"mappings":"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","sourcesContent":["import * as esbuild from 'esbuild';\nimport fs from 'fs';\nimport path from 'path';\nimport { licensePlugin } from './license/licensePlugin.ts';\nimport type { LicensePluginOptions } from './license/types.ts';\nimport { BundleError } from './utils/BundleError.ts';\nimport { checkForDuplicateDeps } from './utils/checkForDuplicateDeps.ts';\nimport { findRealPackageJson } from './utils/findRealPackageJson.ts';\nimport { colors, logError } from './utils/logHelpers.ts';\nimport { verifyPackageJson, type VerifyPackageJsonOptions } from './utils/verifyPackageJson.ts';\n\nexport interface BundleNodeOptions\n extends VerifyPackageJsonOptions, Pick<LicensePluginOptions, 'unacceptableLicenseTest'> {\n /** Working directory, usually the package root (it will find the actual root from here) */\n cwd: string;\n\n /** Clean output before building (highly recommended due to hashed filenames) @default true */\n clean?: boolean;\n\n /** Extra options for esbuild */\n esbuildOptions?: Omit<\n esbuild.BuildOptions,\n 'absWorkingDir' | 'bundle' | 'entryPoints' | 'metafile' | 'outdir' | 'platform'\n >;\n\n /** Error if there are duplicate packages matching any of these regexps */\n errorDupePackages?: RegExp[];\n\n /** If true, write esbuild's metafile and analysis to disk under `<packageRoot>/temp` */\n writeMetafile?: boolean;\n}\n\n/**\n * This is added at the top of every file and makes CJS globals work in esbuild output.\n * We need `require()` for bundled CJS that loads Node internals or native packages.\n * The bundled CJS deps also use `__filename` and `__dirname` in a couple places.\n * https://github.com/evanw/esbuild/issues/946#issuecomment-814703190\n */\nconst requireHeader = `// @ts-nocheck\n/* eslint-disable */\nimport { createRequire as topLevelCreateRequire } from 'node:module';\nimport topLevelPath from 'node:path';\nimport topLevelUrl from 'node:url';\nconst require = topLevelCreateRequire(import.meta.url);\nconst __filename = topLevelUrl.fileURLToPath(import.meta.url);\nconst __dirname = topLevelPath.dirname(__filename);`;\n\n/**\n * Bundle a node package with esbuild. By default it creates an ESM bundle for Node 22+.\n * `dependencies` will be externalized, but all other referenced deps will be bundled.\n *\n * It also writes a `NOTICE.txt` file at the package root with license information for dependencies\n * from outside the current repo, and if `options.unacceptableLicenseTest` is provided, errors if\n * any packages have disallowed licenses. It also errors if a package is missing license info.\n *\n * Before bundling, it checks for proper configuration of `package.json`:\n * - `NOTICE.txt` and the output directory are included in `files`\n * - If `verifyExportPaths` is set, `exports` are correctly mapped\n * - If `verifyTypesInFiles` is true, `lib/** /*.d.ts` is included in `files`\n *\n * After bundling, it checks for duplicate dependencies:\n * - Always error if there are multiple copies of the same version of a dependency\n * - Optionally error if any dependencies match the regexps provided in `errorDupePackages`\n *\n * (Some of the current logic and messages assume the consuming repo is using yarn v4, likely\n * with `nodeLinker: 'pnpm'`, but it can be updated as needed for other linkers and/or managers.)\n */\nexport async function bundleNode(options: BundleNodeOptions): Promise<void> {\n const { cwd, entryPoints, outDir, errorDupePackages, esbuildOptions, clean = true } = options;\n\n console.log();\n console.log('Bundling package with esbuild...\\n');\n\n const { packageJson, packageRoot } = findRealPackageJson(cwd);\n\n verifyPackageJson(options, packageJson);\n\n if (clean) {\n // Remove old output. This is more important with esbuild due to hashed filenames.\n fs.rmSync(path.join(packageRoot, outDir), { force: true, recursive: true });\n }\n\n // The header defining require() is needed with ESM output, but not if the user changed the format\n const format = esbuildOptions?.format ?? 'esm';\n const jsBanner = format === 'esm' ? requireHeader : undefined;\n\n let result: esbuild.BuildResult<esbuild.BuildOptions & { metafile: true }>;\n try {\n result = await esbuild.build({\n splitting: format === 'esm',\n treeShaking: true,\n target: ['node22'],\n // some packages rely on specific names in instanceof checks\n keepNames: true,\n // log errors, warnings, and a summary (which includes the output file sizes)\n logLevel: 'info',\n // less important if not minifying, and bloats package size\n // sourcemap: true,\n\n ...esbuildOptions,\n\n // Critical options\n absWorkingDir: packageRoot,\n entryPoints: entryPoints,\n outdir: outDir,\n platform: 'node',\n bundle: true,\n format,\n // Exclude non-dev dependencies from the bundle. In a bundled package, generally the only\n // dependencies should be other internal packages and anything with native binaries.\n // (It appears node built-ins are automatically externalized with platform: 'node'.)\n external: [\n ...Object.keys({\n ...packageJson.dependencies,\n ...packageJson.peerDependencies,\n ...packageJson.optionalDependencies,\n }),\n ...(esbuildOptions?.external || []),\n ],\n plugins: [\n licensePlugin({\n packageName: packageJson.name,\n packageRoot,\n absOutDir: packageRoot,\n unacceptableLicenseTest: options.unacceptableLicenseTest,\n }),\n ...(esbuildOptions?.plugins || []),\n ],\n banner: {\n ...esbuildOptions?.banner,\n js: [esbuildOptions?.banner?.js, jsBanner].filter(Boolean).join('\\n'),\n },\n metafile: true,\n });\n } catch (err) {\n const failure = err as esbuild.BuildFailure;\n if (failure.errors.some((e) => e.text.includes('Could not resolve') && e.location?.file.includes('.store'))) {\n console.log(\n `\\n${colors.red(colors.bold('NOTE:'))} Packages that could not be found are usually missing peers, ` +\n `which may not be specified properly for strict installation layouts. ` +\n `You can work around this by updating ${colors.bold('yarnrc.yml packageExtensions')} to ` +\n `include the missing package as a dependency or peerDependency of the importing package.`,\n );\n }\n const msg = `Bundling failed with ${failure.errors.length} error(s)!`;\n logError(colors.red(colors.bold(msg + '\\n')));\n throw new BundleError(msg, { alreadyLogged: true, cause: err });\n }\n\n if (options.writeMetafile) {\n // Write the metafile and analysis to disk for inspection.\n const tmpDir = path.join(packageRoot, 'temp');\n fs.mkdirSync(tmpDir, { recursive: true }); // do nothing if it exists\n fs.writeFileSync(path.join(tmpDir, 'esbuild-metafile.json'), JSON.stringify(result.metafile, null, 2));\n const analysis = await esbuild.analyzeMetafile(result.metafile, { verbose: true });\n fs.writeFileSync(path.join(tmpDir, 'esbuild-metafile-analysis.txt'), analysis);\n }\n\n // Check for duplicate dependencies in the bundle.\n const { errorDupeDeps, warnDupeDeps, sameVersionDupes } = checkForDuplicateDeps(\n packageRoot,\n Object.keys(result.metafile.inputs),\n errorDupePackages,\n );\n if (errorDupeDeps.length || sameVersionDupes.length) {\n throw new BundleError('Duplicate dependencies detected (see above)', { alreadyLogged: true });\n }\n const hasDupeWarnings = !!warnDupeDeps.length;\n\n const hasWarnings = hasDupeWarnings || !!result.warnings.length;\n const color = hasWarnings ? 'yellow' : 'green';\n // With logLevel set to 'info', esbuild will handle the basic logging.\n console.log(colors[color](colors.bold(`Bundling completed${hasWarnings ? ' with warnings (see above)' : '!'}\\n`)));\n}\n"]}
package/lib/index.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ export { bundleNode, type BundleNodeOptions } from './bundleNode.ts';
2
+ export { licensePlugin } from './license/licensePlugin.ts';
3
+ export { unacceptableLicenseTest } from './license/unacceptableLicenseTest.ts';
4
+ export type { Dependency, LicensePluginOptions } from './license/types.ts';
5
+ export { noticeFilename, writeNotice } from './license/writeNotice.ts';
6
+ export { BundleError } from './utils/BundleError.ts';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAC;AAC/E,YAAY,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC3E,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvE,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC"}
package/lib/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export { bundleNode } from "./bundleNode.js";
2
+ export { licensePlugin } from "./license/licensePlugin.js";
3
+ export { unacceptableLicenseTest } from "./license/unacceptableLicenseTest.js";
4
+ export { noticeFilename, writeNotice } from "./license/writeNotice.js";
5
+ export { BundleError } from "./utils/BundleError.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAA0B,MAAM,iBAAiB,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAC;AAE/E,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvE,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC","sourcesContent":["export { bundleNode, type BundleNodeOptions } from './bundleNode.ts';\nexport { licensePlugin } from './license/licensePlugin.ts';\nexport { unacceptableLicenseTest } from './license/unacceptableLicenseTest.ts';\nexport type { Dependency, LicensePluginOptions } from './license/types.ts';\nexport { noticeFilename, writeNotice } from './license/writeNotice.ts';\nexport { BundleError } from './utils/BundleError.ts';\n"]}
@@ -0,0 +1,12 @@
1
+ import type { PackageJson } from '../types.ts';
2
+ import type { Dependency, LicensePluginOptions } from './types.ts';
3
+ /**
4
+ * Analyze licenses for all included packages.
5
+ * @param includedPackages Mapping from package root to package.json for all packages in the bundle
6
+ */
7
+ export declare function analyzeLicenses(includedPackages: Record<string, PackageJson>, options: Pick<LicensePluginOptions, 'packageRoot' | 'unacceptableLicenseTest'>): {
8
+ dependencies: Dependency[];
9
+ } | {
10
+ error: string;
11
+ };
12
+ //# sourceMappingURL=analyzeLicenses.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyzeLicenses.d.ts","sourceRoot":"","sources":["../../src/license/analyzeLicenses.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAqB,MAAM,aAAa,CAAC;AAGlE,OAAO,KAAK,EAAE,UAAU,EAAmB,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEpF;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EAC7C,OAAO,EAAE,IAAI,CAAC,oBAAoB,EAAE,aAAa,GAAG,yBAAyB,CAAC,GAC7E;IAAE,YAAY,EAAE,UAAU,EAAE,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAsBpD"}
@@ -0,0 +1,148 @@
1
+ import fs from 'fs';
2
+ import hostedGitInfo from 'hosted-git-info';
3
+ import path from 'path';
4
+ import validateLicense from 'validate-npm-package-license';
5
+ import { BundleError } from "../utils/BundleError.js";
6
+ import { bulletedList, colors, logError } from "../utils/logHelpers.js";
7
+ /**
8
+ * Analyze licenses for all included packages.
9
+ * @param includedPackages Mapping from package root to package.json for all packages in the bundle
10
+ */
11
+ export function analyzeLicenses(includedPackages, options) {
12
+ let dependencies;
13
+ let errorDependencies;
14
+ try {
15
+ ({ dependencies, errorDependencies } = readAndValidateLicenses(includedPackages, options));
16
+ }
17
+ catch (err) {
18
+ // this would be due to some issue reading a file (the function isn't intended to throw)
19
+ // but we need to catch it for clear error reporting in the esbuild onEnd context
20
+ logError(`Unexpected error during license analysis: ${err.stack || err}`);
21
+ throw new BundleError('Unexpected error during license analysis', { alreadyLogged: true, cause: err });
22
+ }
23
+ if (errorDependencies.length) {
24
+ // Return the formatted string from the function to verify the output formatting
25
+ // (it's hard to test this via the esbuild plugin)
26
+ const errors = errorDependencies.map((dep) => [`${dep.name}@${dep.version} (${dep.path})`, dep.issues]).flat(1);
27
+ return {
28
+ error: colors.red(`${colors.bold('ERROR:')} Found dependencies with license issues:\n${bulletedList(errors)}`),
29
+ };
30
+ }
31
+ return { dependencies };
32
+ }
33
+ /**
34
+ * Check the license specified in package.json, and if it's valid, read the license and notice text.
35
+ */
36
+ function readAndValidateLicenses(includedPackages, options) {
37
+ const dependencies = [];
38
+ const errorDependencies = [];
39
+ const sortedEntries = Object.entries(includedPackages).sort((a, b) => a[1].name.localeCompare(b[1].name));
40
+ for (const [depPkgRoot, depPkgJson] of sortedEntries) {
41
+ const pkgMeta = {
42
+ name: depPkgJson.name,
43
+ version: depPkgJson.version,
44
+ path: path.relative(options.packageRoot, depPkgRoot).replace(/\\/g, '/'),
45
+ };
46
+ const license = depPkgJson.license;
47
+ if (!license || typeof license !== 'string') {
48
+ errorDependencies.push({
49
+ ...pkgMeta,
50
+ issues: [license ? `Unexpected "license" format ${JSON.stringify(license)}` : 'Missing "license"'],
51
+ });
52
+ continue;
53
+ }
54
+ const licenseResult = validateLicense(license);
55
+ if (!licenseResult.validForNewPackages) {
56
+ errorDependencies.push({
57
+ ...pkgMeta,
58
+ issues: [`Invalid "license" value ${JSON.stringify(license)}`, ...(licenseResult.warnings || [])],
59
+ });
60
+ continue;
61
+ }
62
+ const licenseInFilePath = licenseResult.inFile && path.join(depPkgRoot, licenseResult.inFile);
63
+ if (licenseInFilePath && !fs.existsSync(licenseInFilePath)) {
64
+ errorDependencies.push({
65
+ ...pkgMeta,
66
+ issues: [`License file "${licenseResult.inFile}" (specified by "SEE LICENSE IN") not found`],
67
+ });
68
+ continue;
69
+ }
70
+ if (options.unacceptableLicenseTest?.(license)) {
71
+ errorDependencies.push({
72
+ ...pkgMeta,
73
+ issues: [
74
+ `License ${JSON.stringify(license)} is not allowed (if incorrect, update the unacceptableLicenseTest setting)`,
75
+ ],
76
+ });
77
+ continue;
78
+ }
79
+ const files = fs.readdirSync(depPkgRoot);
80
+ // Read the license from either "SEE LICENSE IN ___" or a file named LICENSE*
81
+ let licenseText;
82
+ if (licenseInFilePath) {
83
+ licenseText = fs.readFileSync(licenseInFilePath, 'utf8');
84
+ }
85
+ else {
86
+ licenseText = findFile(/^license/i, files, depPkgRoot) || findFile(/^copying/i, files, depPkgRoot);
87
+ }
88
+ // Just look for a "notice" file at the root for notices
89
+ const noticeText = findFile(/^notice/i, files, depPkgRoot);
90
+ // Get author from package.json and/or "authors" file
91
+ let author = personToString(depPkgJson.author);
92
+ const authorsText = findFile(/^authors/i, files, depPkgRoot);
93
+ if (authorsText) {
94
+ author = (author ? author + '\n' : '') + authorsText;
95
+ }
96
+ // Same with contributors
97
+ let contributors = depPkgJson.contributors?.map(personToString).filter(Boolean).join('\n');
98
+ const contributorsText = findFile(/^contributors?/i, files, depPkgRoot);
99
+ if (contributorsText) {
100
+ contributors = (contributors ? contributors + '\n' : '') + contributorsText;
101
+ }
102
+ const maintainers = depPkgJson.maintainers?.map(personToString).join('\n');
103
+ // Following CG, use "homepage" by default, followed by "repository"
104
+ let url = depPkgJson.homepage;
105
+ const repository = depPkgJson.repository;
106
+ if (!url && repository) {
107
+ url = typeof repository === 'string' ? repository : repository.url;
108
+ const gitInfo = hostedGitInfo.fromUrl(url);
109
+ if (gitInfo) {
110
+ url = gitInfo.browse();
111
+ }
112
+ }
113
+ dependencies.push({
114
+ name: pkgMeta.name,
115
+ version: pkgMeta.version,
116
+ author,
117
+ contributors,
118
+ maintainers,
119
+ url,
120
+ license,
121
+ licenseText,
122
+ noticeText,
123
+ });
124
+ }
125
+ return { dependencies, errorDependencies };
126
+ }
127
+ /**
128
+ * Convert a person field to a string
129
+ */
130
+ function personToString(person) {
131
+ if (!person || typeof person === 'string') {
132
+ return person;
133
+ }
134
+ const { name, email, url } = person;
135
+ return `${name}${email ? ` <${email}>` : ''}${url ? ` (${url})` : ''}`;
136
+ }
137
+ /**
138
+ * Find and read a file in a directory that matches a specific pattern.
139
+ * @param isMatch - The function or regexp to match the file name.
140
+ * @param files - The list of files to search.
141
+ * @param dir - The parent directory path.
142
+ * @returns The file contents if found (whitespace trimmed), otherwise undefined.
143
+ */
144
+ function findFile(isMatch, files, dir) {
145
+ const match = files.find(typeof isMatch === 'function' ? isMatch : (file) => isMatch.test(file));
146
+ return match && fs.readFileSync(path.join(dir, match), 'utf8').trim();
147
+ }
148
+ //# sourceMappingURL=analyzeLicenses.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyzeLicenses.js","sourceRoot":"","sources":["../../src/license/analyzeLicenses.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'fs';\nimport hostedGitInfo from 'hosted-git-info';\nimport path from 'path';\nimport validateLicense from 'validate-npm-package-license';\nimport type { PackageJson, PackageJsonPerson } from '../types.ts';\nimport { BundleError } from '../utils/BundleError.ts';\nimport { bulletedList, colors, logError } from '../utils/logHelpers.ts';\nimport type { Dependency, ErrorDependency, LicensePluginOptions } from './types.ts';\n\n/**\n * Analyze licenses for all included packages.\n * @param includedPackages Mapping from package root to package.json for all packages in the bundle\n */\nexport function analyzeLicenses(\n includedPackages: Record<string, PackageJson>,\n options: Pick<LicensePluginOptions, 'packageRoot' | 'unacceptableLicenseTest'>,\n): { dependencies: Dependency[] } | { error: string } {\n let dependencies: Dependency[];\n let errorDependencies: ErrorDependency[];\n try {\n ({ dependencies, errorDependencies } = readAndValidateLicenses(includedPackages, options));\n } catch (err) {\n // this would be due to some issue reading a file (the function isn't intended to throw)\n // but we need to catch it for clear error reporting in the esbuild onEnd context\n logError(`Unexpected error during license analysis: ${(err as Error).stack || err}`);\n throw new BundleError('Unexpected error during license analysis', { alreadyLogged: true, cause: err });\n }\n\n if (errorDependencies.length) {\n // Return the formatted string from the function to verify the output formatting\n // (it's hard to test this via the esbuild plugin)\n const errors = errorDependencies.map((dep) => [`${dep.name}@${dep.version} (${dep.path})`, dep.issues]).flat(1);\n return {\n error: colors.red(`${colors.bold('ERROR:')} Found dependencies with license issues:\\n${bulletedList(errors)}`),\n };\n }\n\n return { dependencies };\n}\n\n/**\n * Check the license specified in package.json, and if it's valid, read the license and notice text.\n */\nfunction readAndValidateLicenses(\n includedPackages: Record<string, PackageJson>,\n options: Pick<LicensePluginOptions, 'packageRoot' | 'unacceptableLicenseTest'>,\n): { dependencies: Dependency[]; errorDependencies: ErrorDependency[] } {\n const dependencies: Dependency[] = [];\n const errorDependencies: ErrorDependency[] = [];\n\n const sortedEntries = Object.entries(includedPackages).sort((a, b) => a[1].name.localeCompare(b[1].name));\n for (const [depPkgRoot, depPkgJson] of sortedEntries) {\n const pkgMeta = {\n name: depPkgJson.name,\n version: depPkgJson.version,\n path: path.relative(options.packageRoot, depPkgRoot).replace(/\\\\/g, '/'),\n };\n const license = depPkgJson.license;\n if (!license || typeof license !== 'string') {\n errorDependencies.push({\n ...pkgMeta,\n issues: [license ? `Unexpected \"license\" format ${JSON.stringify(license)}` : 'Missing \"license\"'],\n });\n continue;\n }\n\n const licenseResult = validateLicense(license);\n if (!licenseResult.validForNewPackages) {\n errorDependencies.push({\n ...pkgMeta,\n issues: [`Invalid \"license\" value ${JSON.stringify(license)}`, ...(licenseResult.warnings || [])],\n });\n continue;\n }\n const licenseInFilePath = licenseResult.inFile && path.join(depPkgRoot, licenseResult.inFile);\n if (licenseInFilePath && !fs.existsSync(licenseInFilePath)) {\n errorDependencies.push({\n ...pkgMeta,\n issues: [`License file \"${licenseResult.inFile}\" (specified by \"SEE LICENSE IN\") not found`],\n });\n continue;\n }\n\n if (options.unacceptableLicenseTest?.(license)) {\n errorDependencies.push({\n ...pkgMeta,\n issues: [\n `License ${JSON.stringify(license)} is not allowed (if incorrect, update the unacceptableLicenseTest setting)`,\n ],\n });\n continue;\n }\n\n const files = fs.readdirSync(depPkgRoot);\n // Read the license from either \"SEE LICENSE IN ___\" or a file named LICENSE*\n let licenseText: string | undefined;\n if (licenseInFilePath) {\n licenseText = fs.readFileSync(licenseInFilePath, 'utf8');\n } else {\n licenseText = findFile(/^license/i, files, depPkgRoot) || findFile(/^copying/i, files, depPkgRoot);\n }\n // Just look for a \"notice\" file at the root for notices\n const noticeText = findFile(/^notice/i, files, depPkgRoot);\n\n // Get author from package.json and/or \"authors\" file\n let author = personToString(depPkgJson.author);\n const authorsText = findFile(/^authors/i, files, depPkgRoot);\n if (authorsText) {\n author = (author ? author + '\\n' : '') + authorsText;\n }\n\n // Same with contributors\n let contributors = depPkgJson.contributors?.map(personToString).filter(Boolean).join('\\n');\n const contributorsText = findFile(/^contributors?/i, files, depPkgRoot);\n if (contributorsText) {\n contributors = (contributors ? contributors + '\\n' : '') + contributorsText;\n }\n\n const maintainers = depPkgJson.maintainers?.map(personToString).join('\\n');\n\n // Following CG, use \"homepage\" by default, followed by \"repository\"\n let url = depPkgJson.homepage;\n const repository = depPkgJson.repository;\n if (!url && repository) {\n url = typeof repository === 'string' ? repository : repository.url;\n const gitInfo = hostedGitInfo.fromUrl(url);\n if (gitInfo) {\n url = gitInfo.browse();\n }\n }\n\n dependencies.push({\n name: pkgMeta.name,\n version: pkgMeta.version,\n author,\n contributors,\n maintainers,\n url,\n license,\n licenseText,\n noticeText,\n });\n }\n\n return { dependencies, errorDependencies };\n}\n\n/**\n * Convert a person field to a string\n */\nfunction personToString(person: PackageJsonPerson | undefined): string | undefined {\n if (!person || typeof person === 'string') {\n return person;\n }\n const { name, email, url } = person;\n return `${name}${email ? ` <${email}>` : ''}${url ? ` (${url})` : ''}`;\n}\n\n/**\n * Find and read a file in a directory that matches a specific pattern.\n * @param isMatch - The function or regexp to match the file name.\n * @param files - The list of files to search.\n * @param dir - The parent directory path.\n * @returns The file contents if found (whitespace trimmed), otherwise undefined.\n */\nfunction findFile(isMatch: RegExp | ((file: string) => boolean), files: string[], dir: string): string | undefined {\n const match = files.find(typeof isMatch === 'function' ? isMatch : (file) => isMatch.test(file));\n return match && fs.readFileSync(path.join(dir, match), 'utf8').trim();\n}\n"]}
@@ -0,0 +1,20 @@
1
+ import type { Plugin } from 'esbuild';
2
+ import type { LicensePluginOptions } from './types.ts';
3
+ /**
4
+ * esbuild plugin to generate a NOTICE.txt file with license information for all dependencies
5
+ * that are included in the bundle (excluding any packages from the same repo).
6
+ *
7
+ * This relies on the info published with the package (in package.json or certain predefined files)
8
+ * and doesn't check github for other related files that aren't published.
9
+ *
10
+ * Other implementations:
11
+ * - There's a service [ClearlyDefined](https://clearlydefined.io) which is made by Microsoft
12
+ * and used by CG to generate notices, and is more comprehensive with checking npm/github.
13
+ * However, the public API is badly-documented, subject to unclear rate limits, and not reliable
14
+ * (can't find some packages for the notice even though they exist in its database in the UI).
15
+ * - https://github.com/upupming/esbuild-plugin-license (only writes name, version, license type)
16
+ * - https://github.com/mhassan1/yarn-plugin-licenses (covers whole repo; similar formatting used here)
17
+ * - https://github.com/codepunkt/webpack-license-plugin (json output for webpack only)
18
+ */
19
+ export declare function licensePlugin(options: LicensePluginOptions): Plugin;
20
+ //# sourceMappingURL=licensePlugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"licensePlugin.d.ts","sourceRoot":"","sources":["../../src/license/licensePlugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAQtC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAGvD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,MAAM,CA8CnE"}
@@ -0,0 +1,66 @@
1
+ import fs from 'fs';
2
+ import { fileURLToPath } from 'url';
3
+ import { findRealPackageJson } from "../utils/findRealPackageJson.js";
4
+ import { logError } from "../utils/logHelpers.js";
5
+ import { writeNotice } from "./writeNotice.js";
6
+ import { BundleError } from "../utils/BundleError.js";
7
+ import { analyzeLicenses } from "./analyzeLicenses.js";
8
+ /**
9
+ * esbuild plugin to generate a NOTICE.txt file with license information for all dependencies
10
+ * that are included in the bundle (excluding any packages from the same repo).
11
+ *
12
+ * This relies on the info published with the package (in package.json or certain predefined files)
13
+ * and doesn't check github for other related files that aren't published.
14
+ *
15
+ * Other implementations:
16
+ * - There's a service [ClearlyDefined](https://clearlydefined.io) which is made by Microsoft
17
+ * and used by CG to generate notices, and is more comprehensive with checking npm/github.
18
+ * However, the public API is badly-documented, subject to unclear rate limits, and not reliable
19
+ * (can't find some packages for the notice even though they exist in its database in the UI).
20
+ * - https://github.com/upupming/esbuild-plugin-license (only writes name, version, license type)
21
+ * - https://github.com/mhassan1/yarn-plugin-licenses (covers whole repo; similar formatting used here)
22
+ * - https://github.com/codepunkt/webpack-license-plugin (json output for webpack only)
23
+ */
24
+ export function licensePlugin(options) {
25
+ const includedPackages = {};
26
+ const packageCache = new Map();
27
+ return {
28
+ name: 'cloudpack-license-plugin',
29
+ setup(build) {
30
+ // On load, track all the packages that are included
31
+ // (any errors will be caught and logged by esbuild itself)
32
+ build.onLoad({ filter: /.*/ }, (args) => {
33
+ // esbuild docs make it sound like this can be a file URL or arbitrary URL
34
+ let filePath = args.path.startsWith('file://') ? fileURLToPath(args.path) : args.path;
35
+ // if this is something besides a filesystem path, ignore it
36
+ if (!fs.existsSync(filePath)) {
37
+ return null;
38
+ }
39
+ // use the realpath for deduping store files
40
+ filePath = fs.realpathSync(filePath);
41
+ if (!filePath.includes('node_modules')) {
42
+ return null;
43
+ }
44
+ const { packageRoot, packageJson } = findRealPackageJson(filePath, packageCache);
45
+ if (!includedPackages[packageRoot] && packageJson.name !== options.packageName) {
46
+ includedPackages[packageRoot] = packageJson;
47
+ }
48
+ return null;
49
+ });
50
+ build.onEnd(() => {
51
+ // We have to catch any errors and explicitly log them since esbuild doesn't automatically
52
+ // log thrown errors at this point, and our wrapper that calls esbuild assumes errors have
53
+ // already been logged.
54
+ const licenseResult = analyzeLicenses(includedPackages, options);
55
+ if ('error' in licenseResult) {
56
+ const errorStr = licenseResult.error;
57
+ logError(errorStr + '\n');
58
+ // Include the full text despite having logged it since this can make debugging easier
59
+ throw new BundleError(errorStr, { alreadyLogged: true });
60
+ }
61
+ writeNotice(licenseResult.dependencies, options.absOutDir);
62
+ });
63
+ },
64
+ };
65
+ }
66
+ //# sourceMappingURL=licensePlugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"licensePlugin.js","sourceRoot":"","sources":["../../src/license/licensePlugin.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAEpC,OAAO,EAAE,mBAAmB,EAA0B,MAAM,iCAAiC,CAAC;AAC9F,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAEtD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,aAAa,CAAC,OAA6B;IACzD,MAAM,gBAAgB,GAAgC,EAAE,CAAC;IACzD,MAAM,YAAY,GAAG,IAAI,GAAG,EAAoC,CAAC;IAEjE,OAAO;QACL,IAAI,EAAE,0BAA0B;QAChC,KAAK,CAAC,KAAK;YACT,oDAAoD;YACpD,2DAA2D;YAC3D,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE;gBACtC,0EAA0E;gBAC1E,IAAI,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;gBACtF,4DAA4D;gBAC5D,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;oBAC7B,OAAO,IAAI,CAAC;gBACd,CAAC;gBACD,4CAA4C;gBAC5C,QAAQ,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;gBAErC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;oBACvC,OAAO,IAAI,CAAC;gBACd,CAAC;gBAED,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,GAAG,mBAAmB,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;gBACjF,IAAI,CAAC,gBAAgB,CAAC,WAAW,CAAC,IAAI,WAAW,CAAC,IAAI,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC;oBAC/E,gBAAgB,CAAC,WAAW,CAAC,GAAG,WAAW,CAAC;gBAC9C,CAAC;gBACD,OAAO,IAAI,CAAC;YACd,CAAC,CAAC,CAAC;YAEH,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE;gBACf,0FAA0F;gBAC1F,0FAA0F;gBAC1F,uBAAuB;gBACvB,MAAM,aAAa,GAAG,eAAe,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC;gBACjE,IAAI,OAAO,IAAI,aAAa,EAAE,CAAC;oBAC7B,MAAM,QAAQ,GAAG,aAAa,CAAC,KAAK,CAAC;oBACrC,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;oBAC1B,sFAAsF;oBACtF,MAAM,IAAI,WAAW,CAAC,QAAQ,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC3D,CAAC;gBAED,WAAW,CAAC,aAAa,CAAC,YAAY,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;YAC7D,CAAC,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import type { Plugin } from 'esbuild';\nimport fs from 'fs';\nimport { fileURLToPath } from 'url';\nimport type { PackageJson } from '../types.ts';\nimport { findRealPackageJson, type PackageJsonResult } from '../utils/findRealPackageJson.ts';\nimport { logError } from '../utils/logHelpers.ts';\nimport { writeNotice } from './writeNotice.ts';\nimport { BundleError } from '../utils/BundleError.ts';\nimport type { LicensePluginOptions } from './types.ts';\nimport { analyzeLicenses } from './analyzeLicenses.ts';\n\n/**\n * esbuild plugin to generate a NOTICE.txt file with license information for all dependencies\n * that are included in the bundle (excluding any packages from the same repo).\n *\n * This relies on the info published with the package (in package.json or certain predefined files)\n * and doesn't check github for other related files that aren't published.\n *\n * Other implementations:\n * - There's a service [ClearlyDefined](https://clearlydefined.io) which is made by Microsoft\n * and used by CG to generate notices, and is more comprehensive with checking npm/github.\n * However, the public API is badly-documented, subject to unclear rate limits, and not reliable\n * (can't find some packages for the notice even though they exist in its database in the UI).\n * - https://github.com/upupming/esbuild-plugin-license (only writes name, version, license type)\n * - https://github.com/mhassan1/yarn-plugin-licenses (covers whole repo; similar formatting used here)\n * - https://github.com/codepunkt/webpack-license-plugin (json output for webpack only)\n */\nexport function licensePlugin(options: LicensePluginOptions): Plugin {\n const includedPackages: Record<string, PackageJson> = {};\n const packageCache = new Map<string, PackageJsonResult | null>();\n\n return {\n name: 'cloudpack-license-plugin',\n setup(build) {\n // On load, track all the packages that are included\n // (any errors will be caught and logged by esbuild itself)\n build.onLoad({ filter: /.*/ }, (args) => {\n // esbuild docs make it sound like this can be a file URL or arbitrary URL\n let filePath = args.path.startsWith('file://') ? fileURLToPath(args.path) : args.path;\n // if this is something besides a filesystem path, ignore it\n if (!fs.existsSync(filePath)) {\n return null;\n }\n // use the realpath for deduping store files\n filePath = fs.realpathSync(filePath);\n\n if (!filePath.includes('node_modules')) {\n return null;\n }\n\n const { packageRoot, packageJson } = findRealPackageJson(filePath, packageCache);\n if (!includedPackages[packageRoot] && packageJson.name !== options.packageName) {\n includedPackages[packageRoot] = packageJson;\n }\n return null;\n });\n\n build.onEnd(() => {\n // We have to catch any errors and explicitly log them since esbuild doesn't automatically\n // log thrown errors at this point, and our wrapper that calls esbuild assumes errors have\n // already been logged.\n const licenseResult = analyzeLicenses(includedPackages, options);\n if ('error' in licenseResult) {\n const errorStr = licenseResult.error;\n logError(errorStr + '\\n');\n // Include the full text despite having logged it since this can make debugging easier\n throw new BundleError(errorStr, { alreadyLogged: true });\n }\n\n writeNotice(licenseResult.dependencies, options.absOutDir);\n });\n },\n };\n}\n"]}
@@ -0,0 +1,33 @@
1
+ export interface LicensePluginOptions {
2
+ /** Name of the package being bundled */
3
+ packageName: string;
4
+ /** Root directory of the package being bundled */
5
+ packageRoot: string;
6
+ /** Absolute output directory for the NOTICE.txt file */
7
+ absOutDir: string;
8
+ /**
9
+ * Return true if the license is unacceptable.
10
+ * You can use `unacceptableLicenseTest` exported from this package as a default.
11
+ *
12
+ * @param licenseName A valid SPDX license expression (without "LicenseRef"), "UNLICENSED",
13
+ * "SEE LICENSE IN <filename>", or null if no valid license info was found in package.json.
14
+ */
15
+ unacceptableLicenseTest?: (licenseName: string | null) => boolean;
16
+ }
17
+ /** Dependency format used internally by `licensePlugin` */
18
+ export interface Dependency {
19
+ name: string;
20
+ version: string;
21
+ author: string | undefined;
22
+ maintainers: string | undefined;
23
+ contributors: string | undefined;
24
+ url: string | undefined;
25
+ license: string | null;
26
+ licenseText: string | undefined;
27
+ noticeText: string | undefined;
28
+ }
29
+ export interface ErrorDependency extends Pick<Dependency, 'name' | 'version'> {
30
+ path: string;
31
+ issues: string[];
32
+ }
33
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/license/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,oBAAoB;IACnC,wCAAwC;IACxC,WAAW,EAAE,MAAM,CAAC;IAEpB,kDAAkD;IAClD,WAAW,EAAE,MAAM,CAAC;IAEpB,wDAAwD;IACxD,SAAS,EAAE,MAAM,CAAC;IAElB;;;;;;OAMG;IACH,uBAAuB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,KAAK,OAAO,CAAC;CACnE;AAED,2DAA2D;AAC3D,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC;AAED,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3E,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/license/types.ts"],"names":[],"mappings":"","sourcesContent":["export interface LicensePluginOptions {\n /** Name of the package being bundled */\n packageName: string;\n\n /** Root directory of the package being bundled */\n packageRoot: string;\n\n /** Absolute output directory for the NOTICE.txt file */\n absOutDir: string;\n\n /**\n * Return true if the license is unacceptable.\n * You can use `unacceptableLicenseTest` exported from this package as a default.\n *\n * @param licenseName A valid SPDX license expression (without \"LicenseRef\"), \"UNLICENSED\",\n * \"SEE LICENSE IN <filename>\", or null if no valid license info was found in package.json.\n */\n unacceptableLicenseTest?: (licenseName: string | null) => boolean;\n}\n\n/** Dependency format used internally by `licensePlugin` */\nexport interface Dependency {\n name: string;\n version: string;\n author: string | undefined;\n maintainers: string | undefined;\n contributors: string | undefined;\n url: string | undefined;\n license: string | null;\n licenseText: string | undefined;\n noticeText: string | undefined;\n}\n\nexport interface ErrorDependency extends Pick<Dependency, 'name' | 'version'> {\n path: string;\n issues: string[];\n}\n"]}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * A default license plugin check for unacceptable licenses.
3
+ * It requires a license to be defined and only allows a predefined expected list
4
+ * (which could be expanded if new acceptable licenses are encountered).
5
+ * @returns true if the license is **un**acceptable
6
+ */
7
+ export declare function unacceptableLicenseTest(license: string | null): boolean;
8
+ //# sourceMappingURL=unacceptableLicenseTest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unacceptableLicenseTest.d.ts","sourceRoot":"","sources":["../../src/license/unacceptableLicenseTest.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAIvE"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * A default license plugin check for unacceptable licenses.
3
+ * It requires a license to be defined and only allows a predefined expected list
4
+ * (which could be expanded if new acceptable licenses are encountered).
5
+ * @returns true if the license is **un**acceptable
6
+ */
7
+ export function unacceptableLicenseTest(license) {
8
+ // Conservatively list only the licenses we expect today.
9
+ // Additional licenses could be added if encountered and acceptable.
10
+ return !license || !['0BSD', 'Apache-2.0', 'BSD-2-Clause', 'BSD-3-Clause', 'ISC', 'MIT'].includes(license);
11
+ }
12
+ //# sourceMappingURL=unacceptableLicenseTest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unacceptableLicenseTest.js","sourceRoot":"","sources":["../../src/license/unacceptableLicenseTest.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,OAAsB;IAC5D,yDAAyD;IACzD,oEAAoE;IACpE,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC,MAAM,EAAE,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AAC7G,CAAC","sourcesContent":["/**\n * A default license plugin check for unacceptable licenses.\n * It requires a license to be defined and only allows a predefined expected list\n * (which could be expanded if new acceptable licenses are encountered).\n * @returns true if the license is **un**acceptable\n */\nexport function unacceptableLicenseTest(license: string | null): boolean {\n // Conservatively list only the licenses we expect today.\n // Additional licenses could be added if encountered and acceptable.\n return !license || !['0BSD', 'Apache-2.0', 'BSD-2-Clause', 'BSD-3-Clause', 'ISC', 'MIT'].includes(license);\n}\n"]}
@@ -0,0 +1,7 @@
1
+ import type { Dependency } from './types.ts';
2
+ export declare const noticeFilename = "NOTICE.txt";
3
+ /**
4
+ * Write NOTICE.txt with license and author info for the given dependencies.
5
+ */
6
+ export declare function writeNotice(dependencies: Dependency[], absOutDir: string): void;
7
+ //# sourceMappingURL=writeNotice.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writeNotice.d.ts","sourceRoot":"","sources":["../../src/license/writeNotice.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,eAAO,MAAM,cAAc,eAAe,CAAC;AAE3C;;GAEG;AACH,wBAAgB,WAAW,CAAC,YAAY,EAAE,UAAU,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CA2B/E"}
@@ -0,0 +1,34 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ export const noticeFilename = 'NOTICE.txt';
4
+ /**
5
+ * Write NOTICE.txt with license and author info for the given dependencies.
6
+ */
7
+ export function writeNotice(dependencies, absOutDir) {
8
+ if (!dependencies.length)
9
+ return;
10
+ const noticeText = [
11
+ `NOTICES\n\nThis package incorporates material as listed below or described in the code.`,
12
+ ...dependencies.map((dep) => {
13
+ const shortLicense = dep.license ? (/^see license/i.test(dep.license) ? '' : dep.license) : 'unknown license';
14
+ return [
15
+ `${dep.name} ${dep.version}${shortLicense ? ` - ${shortLicense}` : ''}${dep.url ? `\n${dep.url}` : ''}`,
16
+ // Unclear which author/maintainer/contributor info is required, so include all of them
17
+ dep.author && `Author: ${dep.author}`,
18
+ dep.maintainers && `Maintainers:\n${dep.maintainers}`,
19
+ dep.contributors && `Contributors:\n${dep.contributors}`,
20
+ // The license text typically includes the official copyright notice
21
+ dep.licenseText,
22
+ // As of writing we don't use any packages that publish NOTICES
23
+ dep.noticeText && `NOTICES:\n\n${dep.noticeText}`,
24
+ ]
25
+ .filter(Boolean)
26
+ .join('\n\n');
27
+ }),
28
+ ].join('\n\n----\n\n');
29
+ const outFile = path.join(absOutDir, noticeFilename);
30
+ fs.mkdirSync(absOutDir, { recursive: true });
31
+ fs.writeFileSync(outFile, noticeText, 'utf8');
32
+ console.log(`Wrote license notices to ${outFile}\n`);
33
+ }
34
+ //# sourceMappingURL=writeNotice.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writeNotice.js","sourceRoot":"","sources":["../../src/license/writeNotice.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAGxB,MAAM,CAAC,MAAM,cAAc,GAAG,YAAY,CAAC;AAE3C;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,YAA0B,EAAE,SAAiB;IACvE,IAAI,CAAC,YAAY,CAAC,MAAM;QAAE,OAAO;IAEjC,MAAM,UAAU,GAAG;QACjB,yFAAyF;QACzF,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;YAC1B,MAAM,YAAY,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC;YAC9G,OAAO;gBACL,GAAG,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,OAAO,GAAG,YAAY,CAAC,CAAC,CAAC,MAAM,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE;gBACvG,uFAAuF;gBACvF,GAAG,CAAC,MAAM,IAAI,WAAW,GAAG,CAAC,MAAM,EAAE;gBACrC,GAAG,CAAC,WAAW,IAAI,iBAAiB,GAAG,CAAC,WAAW,EAAE;gBACrD,GAAG,CAAC,YAAY,IAAI,kBAAkB,GAAG,CAAC,YAAY,EAAE;gBACxD,oEAAoE;gBACpE,GAAG,CAAC,WAAW;gBACf,+DAA+D;gBAC/D,GAAG,CAAC,UAAU,IAAI,eAAe,GAAG,CAAC,UAAU,EAAE;aAClD;iBACE,MAAM,CAAC,OAAO,CAAC;iBACf,IAAI,CAAC,MAAM,CAAC,CAAC;QAClB,CAAC,CAAC;KACH,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAEvB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IACrD,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;IAC9C,OAAO,CAAC,GAAG,CAAC,4BAA4B,OAAO,IAAI,CAAC,CAAC;AACvD,CAAC","sourcesContent":["import fs from 'fs';\nimport path from 'path';\nimport type { Dependency } from './types.ts';\n\nexport const noticeFilename = 'NOTICE.txt';\n\n/**\n * Write NOTICE.txt with license and author info for the given dependencies.\n */\nexport function writeNotice(dependencies: Dependency[], absOutDir: string): void {\n if (!dependencies.length) return;\n\n const noticeText = [\n `NOTICES\\n\\nThis package incorporates material as listed below or described in the code.`,\n ...dependencies.map((dep) => {\n const shortLicense = dep.license ? (/^see license/i.test(dep.license) ? '' : dep.license) : 'unknown license';\n return [\n `${dep.name} ${dep.version}${shortLicense ? ` - ${shortLicense}` : ''}${dep.url ? `\\n${dep.url}` : ''}`,\n // Unclear which author/maintainer/contributor info is required, so include all of them\n dep.author && `Author: ${dep.author}`,\n dep.maintainers && `Maintainers:\\n${dep.maintainers}`,\n dep.contributors && `Contributors:\\n${dep.contributors}`,\n // The license text typically includes the official copyright notice\n dep.licenseText,\n // As of writing we don't use any packages that publish NOTICES\n dep.noticeText && `NOTICES:\\n\\n${dep.noticeText}`,\n ]\n .filter(Boolean)\n .join('\\n\\n');\n }),\n ].join('\\n\\n----\\n\\n');\n\n const outFile = path.join(absOutDir, noticeFilename);\n fs.mkdirSync(absOutDir, { recursive: true });\n fs.writeFileSync(outFile, noticeText, 'utf8');\n console.log(`Wrote license notices to ${outFile}\\n`);\n}\n"]}
package/lib/types.d.ts ADDED
@@ -0,0 +1,27 @@
1
+ export type PackageJsonPerson = string | {
2
+ name: string;
3
+ email?: string;
4
+ url?: string;
5
+ };
6
+ export interface PackageJson {
7
+ name: string;
8
+ version: string;
9
+ dependencies?: Record<string, string>;
10
+ peerDependencies?: Record<string, string>;
11
+ devDependencies?: Record<string, string>;
12
+ optionalDependencies?: Record<string, string>;
13
+ exports?: unknown;
14
+ files?: string[];
15
+ bin?: string | Record<string, string>;
16
+ types?: string;
17
+ author?: PackageJsonPerson;
18
+ contributors?: PackageJsonPerson[];
19
+ maintainers?: PackageJsonPerson[];
20
+ homepage?: string;
21
+ license?: string;
22
+ repository?: string | {
23
+ type: string;
24
+ url: string;
25
+ };
26
+ }
27
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAExF,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,YAAY,CAAC,EAAE,iBAAiB,EAAE,CAAC;IACnC,WAAW,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;CACrD"}
package/lib/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["export type PackageJsonPerson = string | { name: string; email?: string; url?: string };\n\nexport interface PackageJson {\n name: string;\n version: string;\n dependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n optionalDependencies?: Record<string, string>;\n exports?: unknown;\n files?: string[];\n bin?: string | Record<string, string>;\n types?: string;\n author?: PackageJsonPerson;\n contributors?: PackageJsonPerson[];\n maintainers?: PackageJsonPerson[];\n homepage?: string;\n license?: string;\n repository?: string | { type: string; url: string };\n}\n"]}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Thrown by `bundleNode`. Check the `alreadyLogged` property to see if the message
3
+ * has already been logged to the console.
4
+ */
5
+ export declare class BundleError extends Error {
6
+ readonly alreadyLogged: boolean;
7
+ constructor(message: string, options?: ErrorOptions & {
8
+ alreadyLogged?: boolean;
9
+ });
10
+ }
11
+ //# sourceMappingURL=BundleError.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BundleError.d.ts","sourceRoot":"","sources":["../../src/utils/BundleError.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,qBAAa,WAAY,SAAQ,KAAK;IACpC,SAAgB,aAAa,EAAE,OAAO,CAAC;gBAE3B,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG;QAAE,aAAa,CAAC,EAAE,OAAO,CAAA;KAAE;CAIlF"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Thrown by `bundleNode`. Check the `alreadyLogged` property to see if the message
3
+ * has already been logged to the console.
4
+ */
5
+ export class BundleError extends Error {
6
+ alreadyLogged;
7
+ constructor(message, options) {
8
+ super(message, { cause: options?.cause });
9
+ this.alreadyLogged = !!options?.alreadyLogged;
10
+ }
11
+ }
12
+ //# sourceMappingURL=BundleError.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BundleError.js","sourceRoot":"","sources":["../../src/utils/BundleError.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,OAAO,WAAY,SAAQ,KAAK;IACpB,aAAa,CAAU;IAEvC,YAAY,OAAe,EAAE,OAAoD;QAC/E,KAAK,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QAC1C,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC,OAAO,EAAE,aAAa,CAAC;IAChD,CAAC;CACF","sourcesContent":["/**\n * Thrown by `bundleNode`. Check the `alreadyLogged` property to see if the message\n * has already been logged to the console.\n */\nexport class BundleError extends Error {\n public readonly alreadyLogged: boolean;\n\n constructor(message: string, options?: ErrorOptions & { alreadyLogged?: boolean }) {\n super(message, { cause: options?.cause });\n this.alreadyLogged = !!options?.alreadyLogged;\n }\n}\n"]}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Check the metafile to determine if there are any duplicate dependencies in the bundle
3
+ * @param packageRoot The root directory of the package being bundled
4
+ * @param inputPaths List of input paths detected by esbuild (keys of `metafile.inputs`)
5
+ * @param errorDupePackages List of regex patterns for packages that should trigger an error if
6
+ * duplicates are found
7
+ */
8
+ export declare function checkForDuplicateDeps(packageRoot: string, inputPaths: string[], errorDupePackages: RegExp[] | undefined): {
9
+ errorDupeDeps: [string, string[][]][];
10
+ warnDupeDeps: [string, string[][]][];
11
+ sameVersionDupes: [string, string[][]][];
12
+ };
13
+ //# sourceMappingURL=checkForDuplicateDeps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkForDuplicateDeps.d.ts","sourceRoot":"","sources":["../../src/utils/checkForDuplicateDeps.ts"],"names":[],"mappings":"AAKA;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAAE,EACpB,iBAAiB,EAAE,MAAM,EAAE,GAAG,SAAS,GACtC;IACD,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC;IACtC,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC;IACrC,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC;CAC1C,CAkGA"}
@@ -0,0 +1,94 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { bulletedList, colors, logError } from "./logHelpers.js";
4
+ /**
5
+ * Check the metafile to determine if there are any duplicate dependencies in the bundle
6
+ * @param packageRoot The root directory of the package being bundled
7
+ * @param inputPaths List of input paths detected by esbuild (keys of `metafile.inputs`)
8
+ * @param errorDupePackages List of regex patterns for packages that should trigger an error if
9
+ * duplicates are found
10
+ */
11
+ export function checkForDuplicateDeps(packageRoot, inputPaths, errorDupePackages) {
12
+ // Find all the paths to external dependencies.
13
+ // There may be multiple files from the same dep, so the set dedupes them.
14
+ const depPackages = new Set();
15
+ for (const input of inputPaths) {
16
+ const pathParts = input.split('/');
17
+ const storeIndex = pathParts.indexOf('.store');
18
+ const nodeModulesIndex = pathParts.indexOf('node_modules');
19
+ if (storeIndex !== -1) {
20
+ depPackages.add(pathParts.slice(0, storeIndex + 2).join('/') + '/package');
21
+ }
22
+ else if (nodeModulesIndex !== -1) {
23
+ const pkgSegment = pathParts[nodeModulesIndex + 1];
24
+ const depPath = pathParts.slice(0, nodeModulesIndex + (pkgSegment.startsWith('@') ? 3 : 2)).join('/');
25
+ depPackages.add(depPath);
26
+ }
27
+ }
28
+ if (depPackages.size) {
29
+ console.log(`Included external dependencies:\n${bulletedList([...depPackages].sort())}\n`);
30
+ }
31
+ // Make a mapping from dependency name to versions in case there are multiple versions.
32
+ const depPaths = {};
33
+ for (const depPath of depPackages) {
34
+ const pkg = JSON.parse(fs.readFileSync(path.resolve(packageRoot, depPath, 'package.json'), 'utf8'));
35
+ depPaths[pkg.name] ??= [];
36
+ depPaths[pkg.name].push({ version: pkg.version, path: depPath });
37
+ }
38
+ // If there are multiple versions of a package, this isn't ideal but can sometimes be necessary
39
+ // (different things depending on incompatible versions).
40
+ const allDupeDeps = Object.entries(depPaths)
41
+ .filter(([_, paths]) => paths.length > 1)
42
+ .map(([name, versions]) => [name, [versions.map((pkg) => `${pkg.version} ${pkg.path}`)]]);
43
+ const errorDupeDeps = errorDupePackages
44
+ ? allDupeDeps.filter(([name]) => errorDupePackages?.some((re) => re.test(name)))
45
+ : [];
46
+ const warnDupeDeps = allDupeDeps.filter((d) => !errorDupeDeps.includes(d));
47
+ if (warnDupeDeps.length) {
48
+ console.warn(colors.yellow(`${colors.bold('Warning:')} Found multiple versions of the following dependencies in the bundle ` +
49
+ '(this is not ideal but may be unavoidable if deps in the tree use incompatible semver specs):'));
50
+ console.warn(colors.yellow(bulletedList(warnDupeDeps.flat(1)) + '\n'));
51
+ }
52
+ if (errorDupeDeps.length) {
53
+ logError(colors.red(`${colors.bold('ERROR:')} Found multiple versions of the following critical dependencies:`));
54
+ console.error(colors.red(bulletedList(errorDupeDeps.flat(1))));
55
+ console.error(colors.red(
56
+ // Exceptions can be added if it's not possible to avoid the duplicates.
57
+ '\nPlease attempt to remove these dupes using "yarn set resolution", strategic dep upgrades, ' +
58
+ 'or possibly package.json resolutions.\n'));
59
+ }
60
+ // Check for multiple physical copies of the same dependency version (usually caused by different
61
+ // peer dependency permutations--see error message below for more details)
62
+ const sameVersionDupes = Object.entries(depPaths)
63
+ .map(([name, versions]) => {
64
+ // most common case: there's only one of a given dep
65
+ if (versions.length === 1) {
66
+ return undefined;
67
+ }
68
+ // Get the version of each copy of the package and group by version.
69
+ const versionsToPaths = {};
70
+ for (const pkg of versions) {
71
+ versionsToPaths[pkg.version] ??= [];
72
+ versionsToPaths[pkg.version].push(pkg.path);
73
+ }
74
+ // Return versions with more than one physical copy.
75
+ return Object.values(versionsToPaths).some((vpaths) => vpaths.length > 1)
76
+ ? [name, Object.entries(versionsToPaths)]
77
+ : undefined;
78
+ })
79
+ .filter(Boolean);
80
+ if (sameVersionDupes.length) {
81
+ logError(colors.red(`${colors.bold('ERROR:')} Found multiple copies of the same dependency version:`));
82
+ console.error(colors.red(bulletedList(sameVersionDupes.flat(1))));
83
+ console.error(colors.red(
84
+ // Past duplicated packages had peer deps on @opentelemetry/api, and the difference was that
85
+ // for some reason the node_modules of one copy was missing @opentelemetry/api.
86
+ // Using packageExtensions to add @opentelemetry/api as a *dependency* got rid of the dupes.
87
+ '\nThis may be caused by the yarn pnpm linker making multiple "virtual" folders for the same package ' +
88
+ 'version when different permutations of peer deps and/or resolutions are present.' +
89
+ '\n\nPossible fix: look in yarn.lock to see if the duplicated package has any peer deps, ' +
90
+ 'and use yarnrc.yml packageExtensions to add the peer as a dependency.\n'));
91
+ }
92
+ return { errorDupeDeps, warnDupeDeps, sameVersionDupes };
93
+ }
94
+ //# sourceMappingURL=checkForDuplicateDeps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkForDuplicateDeps.js","sourceRoot":"","sources":["../../src/utils/checkForDuplicateDeps.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'fs';\nimport path from 'path';\nimport type { PackageJson } from '../types.ts';\nimport { bulletedList, colors, logError } from './logHelpers.ts';\n\n/**\n * Check the metafile to determine if there are any duplicate dependencies in the bundle\n * @param packageRoot The root directory of the package being bundled\n * @param inputPaths List of input paths detected by esbuild (keys of `metafile.inputs`)\n * @param errorDupePackages List of regex patterns for packages that should trigger an error if\n * duplicates are found\n */\nexport function checkForDuplicateDeps(\n packageRoot: string,\n inputPaths: string[],\n errorDupePackages: RegExp[] | undefined,\n): {\n errorDupeDeps: [string, string[][]][];\n warnDupeDeps: [string, string[][]][];\n sameVersionDupes: [string, string[][]][];\n} {\n // Find all the paths to external dependencies.\n // There may be multiple files from the same dep, so the set dedupes them.\n const depPackages = new Set<string>();\n for (const input of inputPaths) {\n const pathParts = input.split('/');\n const storeIndex = pathParts.indexOf('.store');\n const nodeModulesIndex = pathParts.indexOf('node_modules');\n if (storeIndex !== -1) {\n depPackages.add(pathParts.slice(0, storeIndex + 2).join('/') + '/package');\n } else if (nodeModulesIndex !== -1) {\n const pkgSegment = pathParts[nodeModulesIndex + 1];\n const depPath = pathParts.slice(0, nodeModulesIndex + (pkgSegment.startsWith('@') ? 3 : 2)).join('/');\n depPackages.add(depPath);\n }\n }\n if (depPackages.size) {\n console.log(`Included external dependencies:\\n${bulletedList([...depPackages].sort())}\\n`);\n }\n\n // Make a mapping from dependency name to versions in case there are multiple versions.\n const depPaths: Record<string, { version: string; path: string }[]> = {};\n for (const depPath of depPackages) {\n const pkg = JSON.parse(fs.readFileSync(path.resolve(packageRoot, depPath, 'package.json'), 'utf8')) as PackageJson;\n depPaths[pkg.name] ??= [];\n depPaths[pkg.name].push({ version: pkg.version, path: depPath });\n }\n\n // If there are multiple versions of a package, this isn't ideal but can sometimes be necessary\n // (different things depending on incompatible versions).\n const allDupeDeps = Object.entries(depPaths)\n .filter(([_, paths]) => paths.length > 1)\n .map(([name, versions]) => [name, [versions.map((pkg) => `${pkg.version} ${pkg.path}`)]] as [string, string[][]]);\n const errorDupeDeps = errorDupePackages\n ? allDupeDeps.filter(([name]) => errorDupePackages?.some((re) => re.test(name)))\n : [];\n const warnDupeDeps = allDupeDeps.filter((d) => !errorDupeDeps.includes(d));\n if (warnDupeDeps.length) {\n console.warn(\n colors.yellow(\n `${colors.bold('Warning:')} Found multiple versions of the following dependencies in the bundle ` +\n '(this is not ideal but may be unavoidable if deps in the tree use incompatible semver specs):',\n ),\n );\n console.warn(colors.yellow(bulletedList(warnDupeDeps.flat(1)) + '\\n'));\n }\n\n if (errorDupeDeps.length) {\n logError(colors.red(`${colors.bold('ERROR:')} Found multiple versions of the following critical dependencies:`));\n console.error(colors.red(bulletedList(errorDupeDeps.flat(1))));\n console.error(\n colors.red(\n // Exceptions can be added if it's not possible to avoid the duplicates.\n '\\nPlease attempt to remove these dupes using \"yarn set resolution\", strategic dep upgrades, ' +\n 'or possibly package.json resolutions.\\n',\n ),\n );\n }\n\n // Check for multiple physical copies of the same dependency version (usually caused by different\n // peer dependency permutations--see error message below for more details)\n const sameVersionDupes = Object.entries(depPaths)\n .map(([name, versions]) => {\n // most common case: there's only one of a given dep\n if (versions.length === 1) {\n return undefined;\n }\n\n // Get the version of each copy of the package and group by version.\n const versionsToPaths: Record<string, string[]> = {};\n for (const pkg of versions) {\n versionsToPaths[pkg.version] ??= [];\n versionsToPaths[pkg.version].push(pkg.path);\n }\n // Return versions with more than one physical copy.\n return Object.values(versionsToPaths).some((vpaths) => vpaths.length > 1)\n ? [name, Object.entries(versionsToPaths)]\n : undefined;\n })\n .filter(Boolean) as [string, string[][]][];\n\n if (sameVersionDupes.length) {\n logError(colors.red(`${colors.bold('ERROR:')} Found multiple copies of the same dependency version:`));\n console.error(colors.red(bulletedList(sameVersionDupes.flat(1))));\n console.error(\n colors.red(\n // Past duplicated packages had peer deps on @opentelemetry/api, and the difference was that\n // for some reason the node_modules of one copy was missing @opentelemetry/api.\n // Using packageExtensions to add @opentelemetry/api as a *dependency* got rid of the dupes.\n '\\nThis may be caused by the yarn pnpm linker making multiple \"virtual\" folders for the same package ' +\n 'version when different permutations of peer deps and/or resolutions are present.' +\n '\\n\\nPossible fix: look in yarn.lock to see if the duplicated package has any peer deps, ' +\n 'and use yarnrc.yml packageExtensions to add the peer as a dependency.\\n',\n ),\n );\n }\n\n return { errorDupeDeps, warnDupeDeps, sameVersionDupes };\n}\n"]}
@@ -0,0 +1,12 @@
1
+ import type { PackageJson } from '../types.ts';
2
+ export interface PackageJsonResult {
3
+ packageRoot: string;
4
+ packageJson: PackageJson;
5
+ }
6
+ /**
7
+ * Find the actual package.json (the one with a name) for the current file.
8
+ * This implementation accounts for intermediate package.json files with just a "type", no name.
9
+ * @param cache Optional cache if iterating over multiple files which may be from the same package
10
+ */
11
+ export declare function findRealPackageJson(fileRealpath: string, cache?: Map<string, PackageJsonResult | null>): PackageJsonResult;
12
+ //# sourceMappingURL=findRealPackageJson.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"findRealPackageJson.d.ts","sourceRoot":"","sources":["../../src/utils/findRealPackageJson.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,WAAW,CAAC;CAC1B;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,MAAM,EACpB,KAAK,wCAA8C,GAClD,iBAAiB,CA+BnB"}
@@ -0,0 +1,36 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ /**
4
+ * Find the actual package.json (the one with a name) for the current file.
5
+ * This implementation accounts for intermediate package.json files with just a "type", no name.
6
+ * @param cache Optional cache if iterating over multiple files which may be from the same package
7
+ */
8
+ export function findRealPackageJson(fileRealpath, cache = new Map()) {
9
+ const root = path.parse(fileRealpath).root;
10
+ // Start with the path itself in case it's already a directory
11
+ let dir = fileRealpath;
12
+ const dirs = [];
13
+ while (dir !== root) {
14
+ dirs.push(dir);
15
+ if (cache.has(dir)) {
16
+ break;
17
+ }
18
+ if (fs.existsSync(path.join(dir, 'package.json'))) {
19
+ const packageJson = JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf8'));
20
+ if (packageJson.name) {
21
+ cache.set(dir, { packageRoot: dir, packageJson });
22
+ break;
23
+ }
24
+ }
25
+ dir = path.dirname(dir);
26
+ }
27
+ const result = cache.get(dir) || null;
28
+ for (const d of dirs) {
29
+ cache.set(d, result);
30
+ }
31
+ if (result) {
32
+ return result;
33
+ }
34
+ throw new Error('Unable to find package.json for ' + fileRealpath);
35
+ }
36
+ //# sourceMappingURL=findRealPackageJson.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"findRealPackageJson.js","sourceRoot":"","sources":["../../src/utils/findRealPackageJson.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAQxB;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CACjC,YAAoB,EACpB,QAAQ,IAAI,GAAG,EAAoC;IAEnD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC;IAC3C,8DAA8D;IAC9D,IAAI,GAAG,GAAG,YAAY,CAAC;IACvB,MAAM,IAAI,GAAa,EAAE,CAAC;IAE1B,OAAO,GAAG,KAAK,IAAI,EAAE,CAAC;QACpB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACf,IAAI,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACnB,MAAM;QACR,CAAC;QAED,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC;YAClD,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAgB,CAAC;YACvG,IAAI,WAAW,CAAC,IAAI,EAAE,CAAC;gBACrB,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC,CAAC;gBAClD,MAAM;YACR,CAAC;QACH,CAAC;QAED,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;IAED,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC;IACtC,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IACvB,CAAC;IACD,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,kCAAkC,GAAG,YAAY,CAAC,CAAC;AACrE,CAAC","sourcesContent":["import fs from 'fs';\nimport path from 'path';\nimport type { PackageJson } from '../types.ts';\n\nexport interface PackageJsonResult {\n packageRoot: string;\n packageJson: PackageJson;\n}\n\n/**\n * Find the actual package.json (the one with a name) for the current file.\n * This implementation accounts for intermediate package.json files with just a \"type\", no name.\n * @param cache Optional cache if iterating over multiple files which may be from the same package\n */\nexport function findRealPackageJson(\n fileRealpath: string,\n cache = new Map<string, PackageJsonResult | null>(),\n): PackageJsonResult {\n const root = path.parse(fileRealpath).root;\n // Start with the path itself in case it's already a directory\n let dir = fileRealpath;\n const dirs: string[] = [];\n\n while (dir !== root) {\n dirs.push(dir);\n if (cache.has(dir)) {\n break;\n }\n\n if (fs.existsSync(path.join(dir, 'package.json'))) {\n const packageJson = JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf8')) as PackageJson;\n if (packageJson.name) {\n cache.set(dir, { packageRoot: dir, packageJson });\n break;\n }\n }\n\n dir = path.dirname(dir);\n }\n\n const result = cache.get(dir) || null;\n for (const d of dirs) {\n cache.set(d, result);\n }\n if (result) {\n return result;\n }\n throw new Error('Unable to find package.json for ' + fileRealpath);\n}\n"]}
@@ -0,0 +1,14 @@
1
+ /** picocolors instance that's disabled in jest */
2
+ export declare const colors: import("picocolors/types.js").Colors;
3
+ /**
4
+ * Log an error, with a special error prefix if running in github or ADO.
5
+ *
6
+ * If `message` is an Error object, it will log the stack.
7
+ */
8
+ export declare function logError(message: unknown): void;
9
+ /**
10
+ * Format a nested bulleted list.
11
+ */
12
+ export type BulletList = (string | undefined | BulletList)[];
13
+ export declare function bulletedList(lines: BulletList, indent?: number): string;
14
+ //# sourceMappingURL=logHelpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logHelpers.d.ts","sourceRoot":"","sources":["../../src/utils/logHelpers.ts"],"names":[],"mappings":"AAKA,kDAAkD;AAClD,eAAO,MAAM,MAAM,sCAA+D,CAAC;AAInF;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAE/C;AAED;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,MAAM,GAAG,SAAS,GAAG,UAAU,CAAC,EAAE,CAAC;AAE7D,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,SAAI,GAAG,MAAM,CAUlE"}
@@ -0,0 +1,26 @@
1
+ import { environmentInfo } from '@ms-cloudpack/environment';
2
+ import defaultColors, { createColors } from 'picocolors';
3
+ // This package uses some custom helpers instead of task-reporter since it may be used elsewhere
4
+ /** picocolors instance that's disabled in jest */
5
+ export const colors = environmentInfo.isJest ? createColors(false) : defaultColors;
6
+ const errorPrefix = environmentInfo.ado ? '##vso[task.logissue type=error]' : environmentInfo.isCI ? '::error::' : '';
7
+ /**
8
+ * Log an error, with a special error prefix if running in github or ADO.
9
+ *
10
+ * If `message` is an Error object, it will log the stack.
11
+ */
12
+ export function logError(message) {
13
+ console.error(`${errorPrefix}${String((message instanceof Error && message.stack) || message)}`);
14
+ }
15
+ export function bulletedList(lines, indent = 1) {
16
+ const indentString = ' '.repeat(indent * 2);
17
+ return lines
18
+ .reduce((result, curr) => {
19
+ if (curr) {
20
+ result.push(Array.isArray(curr) ? bulletedList(curr, indent + 1) : `${indentString}- ${curr}`);
21
+ }
22
+ return result;
23
+ }, [])
24
+ .join('\n');
25
+ }
26
+ //# sourceMappingURL=logHelpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logHelpers.js","sourceRoot":"","sources":["../../src/utils/logHelpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,aAAa,EAAE,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEzD,gGAAgG;AAEhG,kDAAkD;AAClD,MAAM,CAAC,MAAM,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC;AAEnF,MAAM,WAAW,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,iCAAiC,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;AAEtH;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,OAAgB;IACvC,OAAO,CAAC,KAAK,CAAC,GAAG,WAAW,GAAG,MAAM,CAAC,CAAC,OAAO,YAAY,KAAK,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,EAAE,CAAC,CAAC;AACnG,CAAC;AAOD,MAAM,UAAU,YAAY,CAAC,KAAiB,EAAE,MAAM,GAAG,CAAC;IACxD,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC5C,OAAO,KAAK;SACT,MAAM,CAAC,CAAC,MAAgB,EAAE,IAAI,EAAE,EAAE;QACjC,IAAI,IAAI,EAAE,CAAC;YACT,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,YAAY,KAAK,IAAI,EAAE,CAAC,CAAC;QACjG,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC,EAAE,EAAE,CAAC;SACL,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC","sourcesContent":["import { environmentInfo } from '@ms-cloudpack/environment';\nimport defaultColors, { createColors } from 'picocolors';\n\n// This package uses some custom helpers instead of task-reporter since it may be used elsewhere\n\n/** picocolors instance that's disabled in jest */\nexport const colors = environmentInfo.isJest ? createColors(false) : defaultColors;\n\nconst errorPrefix = environmentInfo.ado ? '##vso[task.logissue type=error]' : environmentInfo.isCI ? '::error::' : '';\n\n/**\n * Log an error, with a special error prefix if running in github or ADO.\n *\n * If `message` is an Error object, it will log the stack.\n */\nexport function logError(message: unknown): void {\n console.error(`${errorPrefix}${String((message instanceof Error && message.stack) || message)}`);\n}\n\n/**\n * Format a nested bulleted list.\n */\nexport type BulletList = (string | undefined | BulletList)[];\n\nexport function bulletedList(lines: BulletList, indent = 1): string {\n const indentString = ' '.repeat(indent * 2);\n return lines\n .reduce((result: string[], curr) => {\n if (curr) {\n result.push(Array.isArray(curr) ? bulletedList(curr, indent + 1) : `${indentString}- ${curr}`);\n }\n return result;\n }, [])\n .join('\\n');\n}\n"]}
@@ -0,0 +1,28 @@
1
+ import type { PackageJson } from '../types.ts';
2
+ export interface VerifyPackageJsonOptions {
3
+ /**
4
+ * Mapping from path under `outDir` to original file path. Original paths are usually relative to
5
+ * the package root (with forward slashes) but could also be files in other packages.
6
+ */
7
+ entryPoints: Record<string, string>;
8
+ /** Relative directory for output files with forward slashes */
9
+ outDir: string;
10
+ /**
11
+ * If set, verify that the output file is correctly referenced in package.json `exports`.
12
+ * Top-level keys match `entry`. Next level keys match package.json `exports` keys.
13
+ * Value is the condition for that export key (use `'default'` to allow paths with no condition).
14
+ */
15
+ verifyExportPaths?: {
16
+ [entryKey: string]: {
17
+ key: string;
18
+ condition: string;
19
+ };
20
+ };
21
+ /**
22
+ * If true, verify `lib/** /*.d.ts` (without the space) is included in package.json `files`.
23
+ * If a string, verify it's included in `files`.
24
+ */
25
+ verifyTypesInFiles?: true | string;
26
+ }
27
+ export declare function verifyPackageJson(options: VerifyPackageJsonOptions, packageJson: PackageJson): void;
28
+ //# sourceMappingURL=verifyPackageJson.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verifyPackageJson.d.ts","sourceRoot":"","sources":["../../src/utils/verifyPackageJson.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI/C,MAAM,WAAW,wBAAwB;IACvC;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEpC,+DAA+D;IAC/D,MAAM,EAAE,MAAM,CAAC;IAEf;;;;OAIG;IACH,iBAAiB,CAAC,EAAE;QAAE,CAAC,QAAQ,EAAE,MAAM,GAAG;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,SAAS,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC;IAE/E;;;OAGG;IACH,kBAAkB,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;CACpC;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,EAAE,WAAW,EAAE,WAAW,GAAG,IAAI,CA4DnG"}
@@ -0,0 +1,47 @@
1
+ import { BundleError } from "./BundleError.js";
2
+ import { noticeFilename } from "../license/writeNotice.js";
3
+ export function verifyPackageJson(options, packageJson) {
4
+ const { entryPoints, outDir, verifyExportPaths, verifyTypesInFiles } = options;
5
+ if (!packageJson.files) {
6
+ throw new BundleError('package.json is missing "files" field');
7
+ }
8
+ if (verifyTypesInFiles) {
9
+ const typesGlob = typeof verifyTypesInFiles === 'string' ? verifyTypesInFiles : 'lib/**/*.d.ts';
10
+ if (!packageJson.files?.includes(typesGlob)) {
11
+ throw new BundleError(`package.json "files" must include "${typesGlob}"`);
12
+ }
13
+ }
14
+ if (!packageJson.files?.includes(noticeFilename)) {
15
+ throw new BundleError(`package.json "files" must include "${noticeFilename}"`);
16
+ }
17
+ if (!packageJson.files?.includes(outDir) && !packageJson.files?.some((f) => f.startsWith(`${outDir}/`))) {
18
+ throw new BundleError(`package.json "files" must include "${outDir}"`);
19
+ }
20
+ if (verifyExportPaths) {
21
+ // Verify the package.json exports map and published files are set up properly
22
+ const exports = packageJson.exports;
23
+ if (!exports || typeof exports === 'string') {
24
+ throw new BundleError(`package.json "exports" must be an object when verifyExportPaths option is enabled (current: ${exports && JSON.stringify(exports)})`);
25
+ }
26
+ const entryKeys = new Set(Object.keys(entryPoints));
27
+ for (const [entryKey, { key, condition }] of Object.entries(verifyExportPaths)) {
28
+ if (!entryKeys.delete(entryKey)) {
29
+ throw new BundleError(`verifyExportPaths includes a key "${entryKey}" that is missing from entryPoints`);
30
+ }
31
+ const outFile = `${outDir}/${entryKey}.js`;
32
+ const exportsValue = exports[key];
33
+ const exportsFile = typeof exportsValue === 'string'
34
+ ? condition === 'default'
35
+ ? exportsValue
36
+ : undefined
37
+ : exportsValue?.[condition];
38
+ if (exportsFile !== `./${outFile}`) {
39
+ throw new BundleError(`package.json exports["${key}"] must include { "${condition}": "./${outFile}" } (current: ${exportsValue && JSON.stringify(exportsValue)})`);
40
+ }
41
+ }
42
+ if (entryKeys.size) {
43
+ throw new BundleError(`verifyExportPaths did not reference the following entry points: ${[...entryKeys].join(', ')}`);
44
+ }
45
+ }
46
+ }
47
+ //# sourceMappingURL=verifyPackageJson.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verifyPackageJson.js","sourceRoot":"","sources":["../../src/utils/verifyPackageJson.ts"],"names":[],"mappings":"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","sourcesContent":["import type { PackageJson } from '../types.ts';\nimport { BundleError } from './BundleError.ts';\nimport { noticeFilename } from '../license/writeNotice.ts';\n\nexport interface VerifyPackageJsonOptions {\n /**\n * Mapping from path under `outDir` to original file path. Original paths are usually relative to\n * the package root (with forward slashes) but could also be files in other packages.\n */\n entryPoints: Record<string, string>;\n\n /** Relative directory for output files with forward slashes */\n outDir: string;\n\n /**\n * If set, verify that the output file is correctly referenced in package.json `exports`.\n * Top-level keys match `entry`. Next level keys match package.json `exports` keys.\n * Value is the condition for that export key (use `'default'` to allow paths with no condition).\n */\n verifyExportPaths?: { [entryKey: string]: { key: string; condition: string } };\n\n /**\n * If true, verify `lib/** /*.d.ts` (without the space) is included in package.json `files`.\n * If a string, verify it's included in `files`.\n */\n verifyTypesInFiles?: true | string;\n}\n\nexport function verifyPackageJson(options: VerifyPackageJsonOptions, packageJson: PackageJson): void {\n const { entryPoints, outDir, verifyExportPaths, verifyTypesInFiles } = options;\n\n if (!packageJson.files) {\n throw new BundleError('package.json is missing \"files\" field');\n }\n\n if (verifyTypesInFiles) {\n const typesGlob = typeof verifyTypesInFiles === 'string' ? verifyTypesInFiles : 'lib/**/*.d.ts';\n if (!packageJson.files?.includes(typesGlob)) {\n throw new BundleError(`package.json \"files\" must include \"${typesGlob}\"`);\n }\n }\n\n if (!packageJson.files?.includes(noticeFilename)) {\n throw new BundleError(`package.json \"files\" must include \"${noticeFilename}\"`);\n }\n\n if (!packageJson.files?.includes(outDir) && !packageJson.files?.some((f) => f.startsWith(`${outDir}/`))) {\n throw new BundleError(`package.json \"files\" must include \"${outDir}\"`);\n }\n\n if (verifyExportPaths) {\n // Verify the package.json exports map and published files are set up properly\n const exports = packageJson.exports as string | Record<string, string | Record<string, string>> | undefined;\n if (!exports || typeof exports === 'string') {\n throw new BundleError(\n `package.json \"exports\" must be an object when verifyExportPaths option is enabled (current: ${exports && JSON.stringify(exports)})`,\n );\n }\n\n const entryKeys = new Set(Object.keys(entryPoints));\n\n for (const [entryKey, { key, condition }] of Object.entries(verifyExportPaths)) {\n if (!entryKeys.delete(entryKey)) {\n throw new BundleError(`verifyExportPaths includes a key \"${entryKey}\" that is missing from entryPoints`);\n }\n\n const outFile = `${outDir}/${entryKey}.js`;\n const exportsValue = exports[key];\n\n const exportsFile =\n typeof exportsValue === 'string'\n ? condition === 'default'\n ? exportsValue\n : undefined\n : exportsValue?.[condition];\n if (exportsFile !== `./${outFile}`) {\n throw new BundleError(\n `package.json exports[\"${key}\"] must include { \"${condition}\": \"./${outFile}\" } (current: ${exportsValue && JSON.stringify(exportsValue)})`,\n );\n }\n }\n\n if (entryKeys.size) {\n throw new BundleError(\n `verifyExportPaths did not reference the following entry points: ${[...entryKeys].join(', ')}`,\n );\n }\n }\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@ms-cloudpack/esbuild-node-helpers",
3
+ "version": "0.1.0",
4
+ "description": "Helpers for creating a bundle for Node with esbuild",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "types": "./lib/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./lib/index.d.ts",
11
+ "import": "./lib/index.js"
12
+ }
13
+ },
14
+ "engines": {
15
+ "node": ">=22.18.0"
16
+ },
17
+ "scripts": {
18
+ "api": "cloudpack-scripts api",
19
+ "build": "cloudpack-scripts build",
20
+ "lint": "cloudpack-scripts lint",
21
+ "test:update": "cloudpack-scripts test-update",
22
+ "test:watch": "cloudpack-scripts test-watch",
23
+ "test": "cloudpack-scripts test"
24
+ },
25
+ "dependencies": {
26
+ "@ms-cloudpack/environment": "workspace:^",
27
+ "hosted-git-info": "^9.0.0",
28
+ "picocolors": "^1.1.1",
29
+ "validate-npm-package-license": "^3.0.4"
30
+ },
31
+ "peerDependencies": {
32
+ "esbuild": ">=0.28.0"
33
+ },
34
+ "devDependencies": {
35
+ "@ms-cloudpack/environment": "workspace:^",
36
+ "@ms-cloudpack/eslint-plugin-internal": "workspace:^",
37
+ "@ms-cloudpack/scripts": "workspace:^",
38
+ "@ms-cloudpack/test-utilities": "workspace:^",
39
+ "@types/hosted-git-info": "^3.0.5",
40
+ "@types/validate-npm-package-license": "^3.0.0",
41
+ "esbuild": "^0.28.0"
42
+ },
43
+ "files": [
44
+ "lib/**/!(*.test.*)"
45
+ ]
46
+ }