|
1 |
| -import {createRequire} from 'module'; |
2 |
| -import Path from 'path'; |
3 |
| - |
4 |
| -import {globSync} from 'glob'; |
5 |
| -import importFrom from 'import-from'; |
6 |
| -import semver from 'semver'; |
7 |
| - |
8 |
| -const require = createRequire(import.meta.url); |
| 1 | +import path from 'node:path'; |
| 2 | +import fs from 'node:fs/promises'; |
| 3 | +import fg from 'fast-glob'; |
| 4 | +import configWorkspaceScopes from '@commitlint/config-workspace-scopes'; |
9 | 5 |
|
10 | 6 | export default {
|
11 |
| - utils: {getPackages}, |
| 7 | + utils: {getProjects}, |
12 | 8 | rules: {
|
13 | 9 | 'scope-enum': (ctx) =>
|
14 |
| - getPackages(ctx).then((packages) => [2, 'always', packages]), |
| 10 | + getProjects(ctx).then((packages) => [2, 'always', packages]), |
15 | 11 | },
|
16 | 12 | };
|
17 | 13 |
|
18 |
| -function getPackages(context) { |
19 |
| - return Promise.resolve() |
20 |
| - .then(() => { |
21 |
| - const ctx = context || {}; |
22 |
| - const cwd = ctx.cwd || process.cwd(); |
23 |
| - |
24 |
| - const {workspaces} = require(Path.join(cwd, 'package.json')); |
25 |
| - if (Array.isArray(workspaces) && workspaces.length) { |
26 |
| - // use yarn workspaces |
| 14 | +/** |
| 15 | + * Turn glob paths with potential 'package.json' ending always into paths |
| 16 | + * with a package.json ending to find monorepo packages |
| 17 | + * @param {string[]} patterns |
| 18 | + * @returns A list of glob paths to resolve package.json files |
| 19 | + */ |
| 20 | +function normalizePatterns(patterns) { |
| 21 | + const normalizedPatterns = []; |
| 22 | + for (const pattern of patterns) { |
| 23 | + normalizedPatterns.push(pattern.replace(/\/?$/, '/package.json')); |
| 24 | + } |
| 25 | + return normalizedPatterns; |
| 26 | +} |
27 | 27 |
|
28 |
| - const wsGlobs = workspaces.flatMap((ws) => { |
29 |
| - const path = Path.posix.join(ws, 'package.json'); |
30 |
| - return globSync(path, {cwd, ignore: ['**/node_modules/**']}); |
31 |
| - }); |
| 28 | +/** |
| 29 | + * Find all package.json contents in the defined cwd |
| 30 | + * @param {string} cwd |
| 31 | + * @returns A list of parsed package.json files as objects |
| 32 | + */ |
| 33 | +async function findPackages(cwd) { |
| 34 | + const json = await fs.readFile(path.join(cwd, 'lerna.json'), { |
| 35 | + encoding: 'utf-8', |
| 36 | + }); |
32 | 37 |
|
33 |
| - return wsGlobs.map((pJson) => require(Path.join(cwd, pJson))); |
34 |
| - } |
| 38 | + const packages = JSON.parse(json)?.packages || []; |
| 39 | + if (packages.length === 0) { |
| 40 | + return []; |
| 41 | + } |
35 | 42 |
|
36 |
| - const lernaVersion = getLernaVersion(cwd); |
37 |
| - if (semver.lt(lernaVersion, '3.0.0')) { |
38 |
| - const Repository = importFrom(cwd, 'lerna/lib/Repository'); |
39 |
| - const PackageUtilities = importFrom(cwd, 'lerna/lib/PackageUtilities'); |
| 43 | + const patterns = normalizePatterns(packages); |
| 44 | + const entries = await fg(patterns, { |
| 45 | + cwd, |
| 46 | + ignore: ['**/node_modules/**', '**/bower_components/**'], |
| 47 | + }); |
40 | 48 |
|
41 |
| - const repository = new Repository(cwd); |
42 |
| - return PackageUtilities.getPackages({ |
43 |
| - packageConfigs: repository.packageConfigs, |
44 |
| - rootPath: cwd, |
45 |
| - }); |
46 |
| - } |
| 49 | + const pkgJsons = await Promise.all( |
| 50 | + Array.from(new Set(entries.map((entry) => path.join(cwd, entry)))).map( |
| 51 | + (pkgPath) => fs.readFile(pkgPath, {encoding: 'utf-8'}) |
| 52 | + ) |
| 53 | + ); |
47 | 54 |
|
48 |
| - const {getPackages} = importFrom(cwd, '@lerna/project'); |
49 |
| - return getPackages(cwd); |
50 |
| - }) |
51 |
| - .then((packages) => { |
52 |
| - return packages |
53 |
| - .map((pkg) => pkg.name) |
54 |
| - .filter(Boolean) |
55 |
| - .map((name) => (name.charAt(0) === '@' ? name.split('/')[1] : name)); |
56 |
| - }); |
| 55 | + return pkgJsons.map((pkgJson) => JSON.parse(pkgJson) || {}); |
57 | 56 | }
|
58 | 57 |
|
59 |
| -function getLernaVersion(cwd) { |
60 |
| - const moduleEntrypoint = require.resolve('lerna', { |
61 |
| - paths: [cwd], |
| 58 | +async function getProjects(context) { |
| 59 | + const ctx = context || {}; |
| 60 | + const cwd = ctx.cwd || process.cwd(); |
| 61 | + |
| 62 | + // try to read workspaces for backwards compatibility |
| 63 | + const workspacePackages = await configWorkspaceScopes.utils.getPackages({ |
| 64 | + cwd, |
62 | 65 | });
|
63 |
| - const moduleDir = Path.join( |
64 |
| - moduleEntrypoint.slice(0, moduleEntrypoint.lastIndexOf('node_modules')), |
65 |
| - 'node_modules', |
66 |
| - 'lerna' |
67 |
| - ); |
68 |
| - const modulePackageJson = Path.join(moduleDir, 'package.json'); |
69 |
| - return require(modulePackageJson).version; |
| 66 | + // native npm/yarn workspaces detected, inform user to use new package instead |
| 67 | + if (workspacePackages.length > 0) { |
| 68 | + console.warn( |
| 69 | + [ |
| 70 | + `It seems that you are using npm/yarn workspaces instead of lernas "packages" declaration.`, |
| 71 | + `Support for workspaces will be removed in a future major version of this package.`, |
| 72 | + `Please make sure to transition to "@commitlint/config-workspace-scopes" in the near future.`, |
| 73 | + ].join('\n') |
| 74 | + ); |
| 75 | + return workspacePackages; |
| 76 | + } |
| 77 | + |
| 78 | + const packages = await findPackages(cwd); |
| 79 | + |
| 80 | + return packages |
| 81 | + .reduce((pkgNames, pkg) => { |
| 82 | + const name = pkg.name; |
| 83 | + if (name) { |
| 84 | + pkgNames.push(name.charAt(0) === '@' ? name.split('/')[1] : name); |
| 85 | + } |
| 86 | + return pkgNames; |
| 87 | + }, []) |
| 88 | + .sort(); |
70 | 89 | }
|
0 commit comments