@nx/js 23.2.0-beta.1 → 23.2.0-beta.11
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.
- package/README.md +2 -2
- package/dist/internal.d.ts +9 -3
- package/dist/internal.js +28 -17
- package/dist/src/executors/copy-workspace-modules/copy-workspace-modules.js +122 -21
- package/dist/src/executors/node/lib/output-file.js +4 -4
- package/dist/src/executors/node/node.impl.js +9 -10
- package/dist/src/executors/prune-lockfile/prune-lockfile.d.ts +1 -1
- package/dist/src/executors/prune-lockfile/prune-lockfile.js +40 -33
- package/dist/src/executors/tsc/lib/batch/watch.js +3 -3
- package/dist/src/executors/tsc/lib/typescript-compilation.js +1 -1
- package/dist/src/executors/tsc/tsc.batch-impl.d.ts +1 -1
- package/dist/src/executors/tsc/tsc.batch-impl.js +2 -2
- package/dist/src/executors/verdaccio/verdaccio.impl.js +8 -1
- package/dist/src/generators/init/init.js +32 -15
- package/dist/src/generators/init/schema.d.ts +1 -1
- package/dist/src/generators/init/schema.json +1 -1
- package/dist/src/generators/library/library.d.ts +1 -1
- package/dist/src/generators/library/library.js +34 -20
- package/dist/src/generators/library/schema.d.ts +12 -5
- package/dist/src/generators/library/schema.json +15 -4
- package/dist/src/generators/library/utils/add-release-config.js +2 -2
- package/dist/src/generators/setup-build/generator.js +2 -7
- package/dist/src/generators/typescript-sync/typescript-sync.d.ts +1 -1
- package/dist/src/generators/typescript-sync/typescript-sync.js +2 -2
- package/dist/src/index.d.ts +3 -2
- package/dist/src/index.js +8 -8
- package/dist/src/migrations/update-23-1-0/add-ignore-deprecations-for-ts6.d.ts +3 -2
- package/dist/src/migrations/update-23-1-0/add-ignore-deprecations-for-ts6.js +17 -11
- package/dist/src/migrations/update-23-2-0/add-pnpm-deploy-output-cache-inputs.d.ts +14 -0
- package/dist/src/migrations/update-23-2-0/add-pnpm-deploy-output-cache-inputs.js +242 -0
- package/dist/src/migrations/update-23-2-0/add-pnpm-deploy-output-cache-inputs.md +64 -0
- package/dist/src/migrations/update-23-2-0/add-pnpm-prune-lockfile-cache-config.d.ts +2 -0
- package/dist/src/migrations/update-23-2-0/add-pnpm-prune-lockfile-cache-config.js +305 -0
- package/dist/src/migrations/update-23-2-0/add-pnpm-prune-lockfile-cache-config.md +59 -0
- package/dist/src/plugins/typescript/plugin.js +9 -14
- package/dist/src/plugins/typescript/util.d.ts +1 -1
- package/dist/src/release/utils/update-lock-file.js +47 -8
- package/dist/src/release/version-actions.d.ts +12 -3
- package/dist/src/release/version-actions.js +236 -76
- package/dist/src/utils/add-linting-to-project.d.ts +46 -0
- package/dist/src/utils/add-linting-to-project.js +112 -0
- package/dist/src/utils/assets/copy-assets-handler.d.ts +1 -1
- package/dist/src/utils/assets/copy-assets-handler.js +2 -2
- package/dist/src/utils/buildable-libs-utils.js +10 -13
- package/dist/src/utils/find-npm-dependencies.js +7 -10
- package/dist/src/utils/formatter-setup.d.ts +26 -0
- package/dist/src/utils/formatter-setup.js +43 -0
- package/dist/src/utils/generate-globs.js +11 -14
- package/dist/src/utils/generator-prompts.d.ts +2 -1
- package/dist/src/utils/generator-prompts.js +23 -22
- package/dist/src/utils/get-main-file-dir.js +2 -2
- package/dist/src/utils/linter.d.ts +30 -0
- package/dist/src/utils/linter.js +43 -0
- package/dist/src/utils/npm-config.d.ts +1 -1
- package/dist/src/utils/nx-formatter-internals.d.ts +8 -0
- package/dist/src/utils/nx-formatter-internals.js +18 -0
- package/dist/src/utils/oxfmt.d.ts +4 -0
- package/dist/src/utils/oxfmt.js +35 -0
- package/dist/src/utils/package-json/update-package-json.d.ts +1 -1
- package/dist/src/utils/package-json/update-package-json.js +11 -22
- package/dist/src/utils/package-manager-workspaces.js +2 -2
- package/dist/src/utils/pnpm-deploy-output-cache-inputs.d.ts +29 -0
- package/dist/src/utils/pnpm-deploy-output-cache-inputs.js +177 -0
- package/dist/src/utils/pnpm-install-settings-inputs.d.ts +45 -0
- package/dist/src/utils/pnpm-install-settings-inputs.js +77 -0
- package/dist/src/utils/prettier.js +14 -33
- package/dist/src/utils/schema.d.ts +1 -2
- package/dist/src/utils/target-defaults-matching.d.ts +57 -0
- package/dist/src/utils/target-defaults-matching.js +126 -0
- package/dist/src/utils/typescript/configuration.js +3 -5
- package/dist/src/utils/typescript/create-ts-config.d.ts +1 -1
- package/dist/src/utils/typescript/create-ts-config.js +5 -5
- package/dist/src/utils/typescript/plugin.js +2 -2
- package/dist/src/utils/typescript/run-type-check.js +2 -2
- package/dist/src/utils/typescript/ts-config.d.ts +51 -1
- package/dist/src/utils/typescript/ts-config.js +114 -0
- package/dist/src/utils/typescript/ts-solution-setup.d.ts +1 -1
- package/dist/src/utils/typescript/ts-solution-setup.js +3 -3
- package/dist/src/utils/versions.d.ts +1 -0
- package/dist/src/utils/versions.js +2 -1
- package/dist/src/utils/watch-for-single-file-changes.js +2 -2
- package/dist/src/utils/workspace-module-sections.d.ts +16 -0
- package/dist/src/utils/workspace-module-sections.js +24 -0
- package/migrations.json +13 -1
- package/package.json +12 -5
|
@@ -5,11 +5,13 @@ const internal_1 = require("@nx/devkit/internal");
|
|
|
5
5
|
const devkit_1 = require("@nx/devkit");
|
|
6
6
|
const node_child_process_1 = require("node:child_process");
|
|
7
7
|
const node_path_1 = require("node:path");
|
|
8
|
+
const jsonc_parser_1 = require("jsonc-parser");
|
|
9
|
+
const semver_1 = require("semver");
|
|
8
10
|
const release_1 = require("nx/release");
|
|
9
11
|
const npm_config_1 = require("../utils/npm-config");
|
|
10
12
|
const update_lock_file_1 = require("./utils/update-lock-file");
|
|
11
13
|
const chalk = require("chalk");
|
|
12
|
-
const
|
|
14
|
+
const semver_2 = require("./utils/semver");
|
|
13
15
|
const afterAllProjectsVersioned = async (cwd, { rootVersionActionsOptions, ...opts }) => {
|
|
14
16
|
return {
|
|
15
17
|
changedFiles: await (0, update_lock_file_1.updateLockFile)(cwd, {
|
|
@@ -22,10 +24,14 @@ const afterAllProjectsVersioned = async (cwd, { rootVersionActionsOptions, ...op
|
|
|
22
24
|
exports.afterAllProjectsVersioned = afterAllProjectsVersioned;
|
|
23
25
|
// Cache at the module level to avoid re-detecting the package manager for each instance
|
|
24
26
|
let pm;
|
|
27
|
+
// Every project in a release receives the same ProjectGraph. Building these
|
|
28
|
+
// indexes once avoids turning dependency updates into quadratic graph scans.
|
|
29
|
+
const localDependencyProjectsByGraph = new WeakMap();
|
|
25
30
|
class JsVersionActions extends release_1.VersionActions {
|
|
26
31
|
constructor() {
|
|
27
32
|
super(...arguments);
|
|
28
33
|
this.validManifestFilenames = ['package.json'];
|
|
34
|
+
this.excludeManifestsFromFormatting = true;
|
|
29
35
|
}
|
|
30
36
|
async readCurrentVersionFromSourceManifest(tree) {
|
|
31
37
|
const sourcePackageJsonPath = (0, node_path_1.join)(this.projectGraphNode.data.root, 'package.json');
|
|
@@ -90,25 +96,26 @@ class JsVersionActions extends release_1.VersionActions {
|
|
|
90
96
|
async readCurrentVersionOfDependency(tree, projectGraph, dependencyProjectName) {
|
|
91
97
|
const sourcePackageJsonPath = (0, node_path_1.join)(this.projectGraphNode.data.root, 'package.json');
|
|
92
98
|
const json = (0, devkit_1.readJson)(tree, sourcePackageJsonPath);
|
|
93
|
-
// Resolve the package name from the project graph metadata, as it may not match the project name
|
|
94
|
-
const dependencyPackageName = projectGraph.nodes[dependencyProjectName].data.metadata?.js?.packageName;
|
|
95
99
|
const dependencyTypes = [
|
|
96
100
|
'dependencies',
|
|
97
101
|
'devDependencies',
|
|
98
102
|
'peerDependencies',
|
|
99
103
|
'optionalDependencies',
|
|
100
104
|
];
|
|
105
|
+
const dependencyPackageName = projectGraph.nodes[dependencyProjectName]?.data.metadata?.js?.packageName;
|
|
101
106
|
let currentVersion = null;
|
|
102
107
|
let dependencyCollection = null;
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
+
if (dependencyPackageName) {
|
|
109
|
+
for (const depType of dependencyTypes) {
|
|
110
|
+
if (json[depType]?.[dependencyPackageName]) {
|
|
111
|
+
currentVersion = json[depType][dependencyPackageName];
|
|
112
|
+
dependencyCollection = depType;
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
108
115
|
}
|
|
109
116
|
}
|
|
110
117
|
// Resolve catalog references if needed
|
|
111
|
-
if (currentVersion) {
|
|
118
|
+
if (currentVersion && dependencyPackageName) {
|
|
112
119
|
const catalogManager = (0, internal_1.getCatalogManager)(tree.root);
|
|
113
120
|
if (catalogManager?.isCatalogReference(currentVersion)) {
|
|
114
121
|
currentVersion = catalogManager.resolveCatalogReference(tree, dependencyPackageName, currentVersion);
|
|
@@ -122,100 +129,253 @@ class JsVersionActions extends release_1.VersionActions {
|
|
|
122
129
|
async updateProjectVersion(tree, newVersion) {
|
|
123
130
|
const logMessages = [];
|
|
124
131
|
for (const manifestToUpdate of this.manifestsToUpdate) {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
});
|
|
132
|
+
this.updateManifestValues(tree, manifestToUpdate.manifestPath, [
|
|
133
|
+
{ path: ['version'], value: newVersion },
|
|
134
|
+
]);
|
|
129
135
|
logMessages.push(`✍️ New version ${newVersion} written to manifest: ${manifestToUpdate.manifestPath}`);
|
|
130
136
|
}
|
|
131
137
|
return logMessages;
|
|
132
138
|
}
|
|
133
|
-
async updateProjectDependencies(tree, projectGraph, dependenciesToUpdate) {
|
|
134
|
-
|
|
135
|
-
|
|
139
|
+
async updateProjectDependencies(tree, projectGraph, dependenciesToUpdate, resolveVersionForDependency) {
|
|
140
|
+
if (Object.keys(dependenciesToUpdate).length === 0 &&
|
|
141
|
+
!resolveVersionForDependency) {
|
|
136
142
|
return [];
|
|
137
143
|
}
|
|
138
|
-
const
|
|
144
|
+
const dependencyTypes = [
|
|
145
|
+
'dependencies',
|
|
146
|
+
'devDependencies',
|
|
147
|
+
'peerDependencies',
|
|
148
|
+
'optionalDependencies',
|
|
149
|
+
];
|
|
150
|
+
const localDependencyProjects = this.getLocalDependencyProjectLookup(projectGraph);
|
|
151
|
+
for (const projectName of Object.keys(dependenciesToUpdate)) {
|
|
152
|
+
if (!projectGraph.nodes[projectName]?.data.metadata?.js?.packageName) {
|
|
153
|
+
throw new Error(`Unable to determine the package name for project "${projectName}" from the project graph metadata, please ensure that the "@nx/js" plugin is installed and the project graph has been built. If the issue persists, please report this issue on https://github.com/nrwl/nx/issues`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const resolvedVersions = new Map();
|
|
157
|
+
const resolveVersion = (projectName) => {
|
|
158
|
+
let resolution = resolvedVersions.get(projectName);
|
|
159
|
+
if (!resolution) {
|
|
160
|
+
if (!resolveVersionForDependency) {
|
|
161
|
+
throw new Error(`No version resolver was provided for dependency project "${projectName}".`);
|
|
162
|
+
}
|
|
163
|
+
resolution = resolveVersionForDependency(projectName);
|
|
164
|
+
resolvedVersions.set(projectName, resolution);
|
|
165
|
+
}
|
|
166
|
+
return resolution;
|
|
167
|
+
};
|
|
168
|
+
const manifestUpdates = [];
|
|
139
169
|
const catalogUpdates = [];
|
|
140
170
|
const catalogManager = (0, internal_1.getCatalogManager)(tree.root);
|
|
141
171
|
for (const manifestToUpdate of this.manifestsToUpdate) {
|
|
142
|
-
(0, devkit_1.
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
172
|
+
const json = (0, devkit_1.readJson)(tree, manifestToUpdate.manifestPath);
|
|
173
|
+
const updates = [];
|
|
174
|
+
const preserveMatchingDependencyRanges = this.finalConfigForProject.preserveMatchingDependencyRanges === true
|
|
175
|
+
? dependencyTypes
|
|
176
|
+
: this.finalConfigForProject.preserveMatchingDependencyRanges ===
|
|
177
|
+
false
|
|
178
|
+
? []
|
|
179
|
+
: this.finalConfigForProject.preserveMatchingDependencyRanges ||
|
|
180
|
+
dependencyTypes;
|
|
181
|
+
for (const depType of dependencyTypes) {
|
|
182
|
+
if (json[depType]) {
|
|
183
|
+
for (const [dependencyName, currentVersion] of Object.entries(json[depType])) {
|
|
184
|
+
const targetProject = localDependencyProjects.get(dependencyName);
|
|
185
|
+
if (!targetProject) {
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
let version = dependenciesToUpdate[targetProject.projectName];
|
|
189
|
+
if (version !== undefined) {
|
|
190
|
+
if (catalogManager?.isCatalogReference(currentVersion)) {
|
|
191
|
+
// collect the catalog updates so we can update the catalog definitions later
|
|
192
|
+
const catalogRef = catalogManager.parseCatalogReference(currentVersion);
|
|
193
|
+
catalogUpdates.push({
|
|
194
|
+
packageName: dependencyName,
|
|
195
|
+
version,
|
|
196
|
+
catalogName: catalogRef.catalogName,
|
|
197
|
+
});
|
|
198
|
+
continue;
|
|
163
199
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
200
|
+
if (manifestToUpdate.preserveLocalDependencyProtocols &&
|
|
201
|
+
this.isLocalDependencyProtocol(currentVersion)) {
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
if (this.isLocalDependencyProtocol(currentVersion)) {
|
|
205
|
+
version = this.applyVersionPrefix(currentVersion, version);
|
|
206
|
+
}
|
|
207
|
+
if (preserveMatchingDependencyRanges.includes(depType) &&
|
|
208
|
+
!this.isLocalDependencyProtocol(currentVersion)) {
|
|
209
|
+
// If the dependency is specified using a range, do some additional processing to determine whether to update the version
|
|
210
|
+
if ((0, semver_2.isValidRange)(currentVersion) &&
|
|
211
|
+
!(0, semver_2.isMatchingDependencyRange)(version, currentVersion)) {
|
|
212
|
+
throw new Error(`"preserveMatchingDependencyRanges" is enabled for "${depType}" and the new version "${version}" is outside the current range for "${dependencyName}" in manifest "${manifestToUpdate.manifestPath}". Please update the range before releasing.`);
|
|
176
213
|
}
|
|
177
|
-
|
|
178
|
-
else if (manifestToUpdate.preserveLocalDependencyProtocols &&
|
|
179
|
-
this.isLocalDependencyProtocol(currentVersion)) {
|
|
180
|
-
// Reduce the count appropriately to avoid confusing user-facing logs
|
|
181
|
-
numDependenciesToUpdate--;
|
|
214
|
+
else if ((0, semver_2.isValidRange)(currentVersion)) {
|
|
182
215
|
continue;
|
|
183
216
|
}
|
|
184
|
-
else if (preserveMatchingDependencyRanges.includes(depType) &&
|
|
185
|
-
!this.isLocalDependencyProtocol(currentVersion)) {
|
|
186
|
-
// If the dependency is specified using a range, do some additional processing to determine whether to update the version
|
|
187
|
-
if ((0, semver_1.isValidRange)(currentVersion) &&
|
|
188
|
-
!(0, semver_1.isMatchingDependencyRange)(version, currentVersion)) {
|
|
189
|
-
throw new Error(`"preserveMatchingDependencyRanges" is enabled for "${depType}" and the new version "${version}" is outside the current range for "${packageName}" in manifest "${manifestToUpdate.manifestPath}". Please update the range before releasing.`);
|
|
190
|
-
}
|
|
191
|
-
else if ((0, semver_1.isValidRange)(currentVersion)) {
|
|
192
|
-
// it is a range, but it is valid
|
|
193
|
-
continue;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
json[depType][packageName] = version;
|
|
197
217
|
}
|
|
198
218
|
}
|
|
219
|
+
else if (resolveVersionForDependency &&
|
|
220
|
+
!manifestToUpdate.preserveLocalDependencyProtocols &&
|
|
221
|
+
this.isLocalDependencyProtocol(currentVersion)) {
|
|
222
|
+
try {
|
|
223
|
+
version = await this.resolveLocalDependencySpecifier(dependencyName, currentVersion, targetProject, resolveVersion);
|
|
224
|
+
}
|
|
225
|
+
catch (error) {
|
|
226
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
227
|
+
throw new Error(`Unable to replace local dependency protocol "${currentVersion}" for "${dependencyName}" in manifest "${manifestToUpdate.manifestPath}". ${message}`);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
if (version !== undefined) {
|
|
231
|
+
updates.push({
|
|
232
|
+
path: [depType, dependencyName],
|
|
233
|
+
value: version,
|
|
234
|
+
});
|
|
235
|
+
}
|
|
199
236
|
}
|
|
200
237
|
}
|
|
201
|
-
|
|
238
|
+
}
|
|
239
|
+
manifestUpdates.push({
|
|
240
|
+
manifestPath: manifestToUpdate.manifestPath,
|
|
241
|
+
updates,
|
|
202
242
|
});
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
243
|
+
}
|
|
244
|
+
// Resolve every requested version before writing any manifest so one
|
|
245
|
+
// failed resolver cannot leave a partially updated set of manifests.
|
|
246
|
+
const logMessages = [];
|
|
247
|
+
for (const manifestUpdate of manifestUpdates) {
|
|
248
|
+
this.updateManifestValues(tree, manifestUpdate.manifestPath, manifestUpdate.updates);
|
|
249
|
+
if (manifestUpdate.updates.length > 0) {
|
|
250
|
+
const depText = manifestUpdate.updates.length === 1 ? 'dependency' : 'dependencies';
|
|
251
|
+
logMessages.push(`✍️ Updated ${manifestUpdate.updates.length} ${depText} in manifest: ${manifestUpdate.manifestPath}`);
|
|
206
252
|
}
|
|
207
|
-
const depText = numDependenciesToUpdate === 1 ? 'dependency' : 'dependencies';
|
|
208
|
-
logMessages.push(`✍️ Updated ${numDependenciesToUpdate} ${depText} in manifest: ${manifestToUpdate.manifestPath}`);
|
|
209
253
|
}
|
|
210
|
-
// Update catalog definitions in
|
|
254
|
+
// Update catalog definitions in the package manager's catalog file
|
|
211
255
|
if (catalogUpdates.length > 0) {
|
|
212
256
|
// catalogManager is guaranteed to be defined when there are catalog updates
|
|
213
257
|
catalogManager.updateCatalogVersions(tree, catalogUpdates);
|
|
214
258
|
const catalogText = catalogUpdates.length === 1 ? 'entry' : 'entries';
|
|
215
|
-
logMessages.push(`✍️ Updated ${catalogUpdates.length} catalog ${catalogText} in
|
|
259
|
+
logMessages.push(`✍️ Updated ${catalogUpdates.length} catalog ${catalogText} in ${catalogManager
|
|
260
|
+
.getCatalogDefinitionFilePaths()
|
|
261
|
+
.join(', ')}`);
|
|
216
262
|
}
|
|
217
263
|
return logMessages;
|
|
218
264
|
}
|
|
265
|
+
getLocalDependencyProjectLookup(projectGraph) {
|
|
266
|
+
let lookup = localDependencyProjectsByGraph.get(projectGraph);
|
|
267
|
+
if (lookup) {
|
|
268
|
+
return lookup;
|
|
269
|
+
}
|
|
270
|
+
// This lookup requires the dependency key to match the package name.
|
|
271
|
+
// Package aliases need relationship-specific manifest data that the
|
|
272
|
+
// project graph does not retain. Support is tracked in
|
|
273
|
+
// https://github.com/nrwl/nx/issues/36630.
|
|
274
|
+
lookup = new Map();
|
|
275
|
+
for (const [projectName, node] of Object.entries(projectGraph.nodes)) {
|
|
276
|
+
const packageName = node.data.metadata?.js?.packageName;
|
|
277
|
+
if (!packageName) {
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
lookup.set(packageName, { projectName });
|
|
281
|
+
}
|
|
282
|
+
localDependencyProjectsByGraph.set(projectGraph, lookup);
|
|
283
|
+
return lookup;
|
|
284
|
+
}
|
|
285
|
+
async resolveLocalDependencySpecifier(dependencyName, versionSpecifier, targetProject, resolveVersion) {
|
|
286
|
+
if (versionSpecifier.startsWith('file:')) {
|
|
287
|
+
const resolvedVersion = await resolveVersion(targetProject.projectName);
|
|
288
|
+
return this.applyVersionPrefix(versionSpecifier, resolvedVersion);
|
|
289
|
+
}
|
|
290
|
+
const range = versionSpecifier.slice('workspace:'.length);
|
|
291
|
+
if (range !== '' &&
|
|
292
|
+
range !== '*' &&
|
|
293
|
+
range !== '^' &&
|
|
294
|
+
range !== '~' &&
|
|
295
|
+
(0, semver_1.validRange)(range) !== null) {
|
|
296
|
+
return range;
|
|
297
|
+
}
|
|
298
|
+
const isRelativePath = range.startsWith('.');
|
|
299
|
+
if (!isRelativePath &&
|
|
300
|
+
range !== '' &&
|
|
301
|
+
range !== '*' &&
|
|
302
|
+
range !== '^' &&
|
|
303
|
+
range !== '~') {
|
|
304
|
+
throw new Error(`The workspace protocol used by "${dependencyName}" is not a supported range or relative workspace path.`);
|
|
305
|
+
}
|
|
306
|
+
const resolvedVersion = await resolveVersion(targetProject.projectName);
|
|
307
|
+
return this.applyVersionPrefix(isRelativePath ? 'workspace:*' : `workspace:${range}`, resolvedVersion);
|
|
308
|
+
}
|
|
309
|
+
applyVersionPrefix(versionSpecifier, resolvedVersion) {
|
|
310
|
+
const configuredPrefix = this.finalConfigForProject.versionPrefix;
|
|
311
|
+
let prefix = '';
|
|
312
|
+
if (configuredPrefix === '~' ||
|
|
313
|
+
configuredPrefix === '^' ||
|
|
314
|
+
configuredPrefix === '=') {
|
|
315
|
+
prefix = configuredPrefix;
|
|
316
|
+
}
|
|
317
|
+
else if (configuredPrefix === 'auto' &&
|
|
318
|
+
versionSpecifier.startsWith('workspace:')) {
|
|
319
|
+
const range = versionSpecifier.slice('workspace:'.length);
|
|
320
|
+
if (range.startsWith('^')) {
|
|
321
|
+
prefix = '^';
|
|
322
|
+
}
|
|
323
|
+
else if (range.startsWith('~')) {
|
|
324
|
+
prefix = '~';
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
return `${prefix}${resolvedVersion.replace(/^[~^=]/, '')}`;
|
|
328
|
+
}
|
|
329
|
+
updateManifestValues(tree, manifestPath, updates) {
|
|
330
|
+
if (updates.length === 0) {
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
let content = this.readAndValidateManifest(tree, manifestPath);
|
|
334
|
+
const formattingOptions = this.detectFormattingOptions(content);
|
|
335
|
+
for (const update of updates) {
|
|
336
|
+
content = (0, jsonc_parser_1.applyEdits)(content, (0, jsonc_parser_1.modify)(content, update.path, update.value, { formattingOptions }));
|
|
337
|
+
}
|
|
338
|
+
this.validateManifestUpdates(content, manifestPath, updates);
|
|
339
|
+
tree.write(manifestPath, content);
|
|
340
|
+
}
|
|
341
|
+
readAndValidateManifest(tree, manifestPath) {
|
|
342
|
+
const content = tree.read(manifestPath, 'utf-8');
|
|
343
|
+
try {
|
|
344
|
+
// Match readJson's support for comments and trailing commas while
|
|
345
|
+
// retaining the original text for targeted edits.
|
|
346
|
+
(0, devkit_1.parseJson)(content);
|
|
347
|
+
}
|
|
348
|
+
catch (error) {
|
|
349
|
+
throw new Error(`Cannot parse ${manifestPath}: ${error.message}`);
|
|
350
|
+
}
|
|
351
|
+
return content;
|
|
352
|
+
}
|
|
353
|
+
validateManifestUpdates(content, manifestPath, updates) {
|
|
354
|
+
const manifest = (0, devkit_1.parseJson)(content);
|
|
355
|
+
for (const update of updates) {
|
|
356
|
+
let actualValue = manifest;
|
|
357
|
+
for (const pathSegment of update.path) {
|
|
358
|
+
if (actualValue === null ||
|
|
359
|
+
typeof actualValue !== 'object' ||
|
|
360
|
+
!(pathSegment in actualValue)) {
|
|
361
|
+
actualValue = undefined;
|
|
362
|
+
break;
|
|
363
|
+
}
|
|
364
|
+
actualValue = actualValue[pathSegment];
|
|
365
|
+
}
|
|
366
|
+
if (actualValue !== update.value) {
|
|
367
|
+
throw new Error(`Cannot update ${manifestPath}: "${update.path.join('.')}" resolves to ${JSON.stringify(actualValue)} instead of ${JSON.stringify(update.value)} after editing. The manifest may contain duplicate keys.`);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
detectFormattingOptions(content) {
|
|
372
|
+
const indentation = content.match(/^[\t ]+(?=")/m)?.[0] ?? ' ';
|
|
373
|
+
const insertSpaces = !indentation.includes('\t');
|
|
374
|
+
return {
|
|
375
|
+
insertSpaces,
|
|
376
|
+
tabSize: insertSpaces ? indentation.length : 1,
|
|
377
|
+
};
|
|
378
|
+
}
|
|
219
379
|
// NOTE: The TODOs were carried over from the original implementation, they are not yet implemented
|
|
220
380
|
isLocalDependencyProtocol(versionSpecifier) {
|
|
221
381
|
const localPackageProtocols = [
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { GeneratorCallback, Tree } from '@nx/devkit';
|
|
2
|
+
import { type LinterType } from './linter';
|
|
3
|
+
export interface AddLintingToProjectOptions {
|
|
4
|
+
/** Required, but `undefined` still reaches here — see the normalization below. */
|
|
5
|
+
linter: LinterType | undefined;
|
|
6
|
+
project: string;
|
|
7
|
+
skipPackageJson?: boolean;
|
|
8
|
+
keepExistingVersions?: boolean;
|
|
9
|
+
addPlugin?: boolean;
|
|
10
|
+
/** ESLint-only. Ignored by other linters. */
|
|
11
|
+
tsConfigPaths?: string[];
|
|
12
|
+
unitTestRunner?: string;
|
|
13
|
+
/** ESLint-only. Ignored by other linters. */
|
|
14
|
+
rootProject?: boolean;
|
|
15
|
+
/** ESLint-only. Ignored by other linters. */
|
|
16
|
+
enableTypedLinting?: boolean;
|
|
17
|
+
/** ESLint-only. Oxlint is inference-only, so it writes no explicit target. */
|
|
18
|
+
addExplicitTargets?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* ESLint-only. The `@nx/dependency-checks` rule lints `package.json`, which
|
|
21
|
+
* Oxlint cannot read.
|
|
22
|
+
*/
|
|
23
|
+
addPackageJsonDependencyChecks?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Oxlint plugins to enable for this project, e.g. `['react', 'jsx-a11y']`.
|
|
26
|
+
* Ignored by other linters, which express framework presets differently.
|
|
27
|
+
*/
|
|
28
|
+
oxlintPlugins?: string[];
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Sets a project's linter up, dispatching to whichever linter the workspace
|
|
32
|
+
* asked for. Consumers call this instead of importing `lintProjectGenerator`
|
|
33
|
+
* from `@nx/eslint` directly, so adding a linter does not mean editing every
|
|
34
|
+
* generator. The two arms name different generators on purpose: `@nx/eslint`
|
|
35
|
+
* writes a lint target, while `@nx/oxlint` is inference-only and only
|
|
36
|
+
* configures the project.
|
|
37
|
+
*
|
|
38
|
+
* Scope is deliberately narrow: registering the linter and its project target.
|
|
39
|
+
* Linter-specific config shaping — ESLint framework presets, `extends`, ignore
|
|
40
|
+
* entries — stays at the call site guarded on `linter`, because none of it has
|
|
41
|
+
* a cross-linter equivalent.
|
|
42
|
+
*
|
|
43
|
+
* Both plugins are loaded through `ensurePackage`; a static import would be
|
|
44
|
+
* circular, since both depend on `@nx/js`.
|
|
45
|
+
*/
|
|
46
|
+
export declare function addLintingToProject(tree: Tree, options: AddLintingToProjectOptions): Promise<GeneratorCallback>;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.addLintingToProject = addLintingToProject;
|
|
4
|
+
const devkit_1 = require("@nx/devkit");
|
|
5
|
+
const internal_1 = require("@nx/devkit/internal");
|
|
6
|
+
const versions_1 = require("./versions");
|
|
7
|
+
const linter_1 = require("./linter");
|
|
8
|
+
/**
|
|
9
|
+
* Sets a project's linter up, dispatching to whichever linter the workspace
|
|
10
|
+
* asked for. Consumers call this instead of importing `lintProjectGenerator`
|
|
11
|
+
* from `@nx/eslint` directly, so adding a linter does not mean editing every
|
|
12
|
+
* generator. The two arms name different generators on purpose: `@nx/eslint`
|
|
13
|
+
* writes a lint target, while `@nx/oxlint` is inference-only and only
|
|
14
|
+
* configures the project.
|
|
15
|
+
*
|
|
16
|
+
* Scope is deliberately narrow: registering the linter and its project target.
|
|
17
|
+
* Linter-specific config shaping — ESLint framework presets, `extends`, ignore
|
|
18
|
+
* entries — stays at the call site guarded on `linter`, because none of it has
|
|
19
|
+
* a cross-linter equivalent.
|
|
20
|
+
*
|
|
21
|
+
* Both plugins are loaded through `ensurePackage`; a static import would be
|
|
22
|
+
* circular, since both depend on `@nx/js`.
|
|
23
|
+
*/
|
|
24
|
+
async function addLintingToProject(tree, options) {
|
|
25
|
+
// Callers should resolve this themselves, since their own guards need a
|
|
26
|
+
// concrete value. Resolving again here keeps a caller that forgets from
|
|
27
|
+
// silently getting ESLint in a workspace that uses something else.
|
|
28
|
+
const linter = options.linter ?? (0, linter_1.detectLinters)(tree)[0] ?? 'none';
|
|
29
|
+
if (linter === 'none') {
|
|
30
|
+
return () => { };
|
|
31
|
+
}
|
|
32
|
+
if (linter === 'oxlint') {
|
|
33
|
+
// `ensurePackage` installs by package name, so the subpath is required
|
|
34
|
+
// separately. `nx-ignore-next-line` keeps this out of the import graph, so
|
|
35
|
+
// the dependency stays a devDependency of this package rather than a runtime
|
|
36
|
+
// one. That devDependency is what makes the `js` <-> `@nx/oxlint` cycle,
|
|
37
|
+
// which is deliberate and recorded in `ignoredCircularDependencies` in the
|
|
38
|
+
// root eslint config.
|
|
39
|
+
(0, devkit_1.ensurePackage)('@nx/oxlint', versions_1.nxVersion);
|
|
40
|
+
// `@nx/oxlint` is the only ESM package under `packages/` and its
|
|
41
|
+
// `./generators` subpath has no `require` condition, so a bare `require()`
|
|
42
|
+
// throws ERR_REQUIRE_ESM below Node 20.19 / 22.12.
|
|
43
|
+
//
|
|
44
|
+
// Resolve to an absolute path before importing. `ensurePackage` exposes an
|
|
45
|
+
// on-demand install by adding a temp dir to NODE_PATH, which `require.resolve`
|
|
46
|
+
// honours and the ESM loader does not — so handing `import()` a bare specifier
|
|
47
|
+
// fails with ERR_MODULE_NOT_FOUND on exactly the Node band this indirection
|
|
48
|
+
// exists for. `load-resolved-plugin.ts` calls `handleImport` the same way.
|
|
49
|
+
// nx-ignore-next-line
|
|
50
|
+
const generatorsPath = require.resolve('@nx/oxlint/generators', {
|
|
51
|
+
paths: [devkit_1.workspaceRoot, __dirname],
|
|
52
|
+
});
|
|
53
|
+
const { configurationGenerator } = await (0, internal_1.handleImport)(generatorsPath);
|
|
54
|
+
return configurationGenerator(tree, {
|
|
55
|
+
project: options.project,
|
|
56
|
+
plugins: [
|
|
57
|
+
...(options.oxlintPlugins ?? []),
|
|
58
|
+
...oxlintTestPlugins(options.unitTestRunner),
|
|
59
|
+
],
|
|
60
|
+
skipFormat: true,
|
|
61
|
+
skipPackageJson: options.skipPackageJson,
|
|
62
|
+
keepExistingVersions: options.keepExistingVersions,
|
|
63
|
+
// No `addPlugin`: `@nx/oxlint` is inference-only, so it always registers.
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
if (linter === 'eslint') {
|
|
67
|
+
const { lintProjectGenerator } = (0, devkit_1.ensurePackage)('@nx/eslint', versions_1.nxVersion);
|
|
68
|
+
return lintProjectGenerator(tree, {
|
|
69
|
+
linter,
|
|
70
|
+
project: options.project,
|
|
71
|
+
tsConfigPaths: options.tsConfigPaths,
|
|
72
|
+
unitTestRunner: options.unitTestRunner,
|
|
73
|
+
rootProject: options.rootProject,
|
|
74
|
+
enableTypedLinting: options.enableTypedLinting,
|
|
75
|
+
addExplicitTargets: options.addExplicitTargets,
|
|
76
|
+
addPackageJsonDependencyChecks: options.addPackageJsonDependencyChecks,
|
|
77
|
+
skipFormat: true,
|
|
78
|
+
skipPackageJson: options.skipPackageJson,
|
|
79
|
+
keepExistingVersions: options.keepExistingVersions,
|
|
80
|
+
addPlugin: options.addPlugin,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
// Spelling ESLint out as its own branch rather than letting it be the
|
|
84
|
+
// fallthrough: a new `LinterType` member then fails to compile here instead of
|
|
85
|
+
// silently getting an ESLint setup.
|
|
86
|
+
const unhandled = linter;
|
|
87
|
+
throw new Error(`Unsupported linter: ${unhandled}`);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Which Oxlint plugins a test runner needs is the runner package's knowledge,
|
|
91
|
+
* so it is read from there rather than hardcoded here — this only maps the
|
|
92
|
+
* runner name to its package. Matched loosely because runners arrive with
|
|
93
|
+
* suffixes, e.g. Angular's `vitest-analog`. Both packages are already installed
|
|
94
|
+
* by the time the runner's own generator runs; `ensurePackage` keeps them out
|
|
95
|
+
* of the import graph, since both depend on `@nx/js`.
|
|
96
|
+
*/
|
|
97
|
+
function oxlintTestPlugins(unitTestRunner) {
|
|
98
|
+
const pkg = unitTestRunner?.includes('vitest')
|
|
99
|
+
? '@nx/vitest'
|
|
100
|
+
: unitTestRunner?.includes('jest')
|
|
101
|
+
? '@nx/jest'
|
|
102
|
+
: undefined;
|
|
103
|
+
if (!pkg) {
|
|
104
|
+
return [];
|
|
105
|
+
}
|
|
106
|
+
// `ensurePackage` installs by package name, so the `internal` subpath is
|
|
107
|
+
// required separately. Plain `require` holds only while both runners are CJS;
|
|
108
|
+
// `@nx/oxlint` is ESM, which is why the arm above needs `handleImport`.
|
|
109
|
+
(0, devkit_1.ensurePackage)(pkg, versions_1.nxVersion);
|
|
110
|
+
const { oxlintPlugins } = require(`${pkg}/internal`);
|
|
111
|
+
return oxlintPlugins ?? [];
|
|
112
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AssetGlob } from './assets';
|
|
2
2
|
import { normalizeAssets, getAssetOutputPath, NormalizedAssetEntry as AssetEntry } from './normalize-assets';
|
|
3
|
-
import { ChangedFile } from 'nx/
|
|
3
|
+
import { ChangedFile } from '@nx/devkit/internal';
|
|
4
4
|
export type { AssetEntry };
|
|
5
5
|
export { normalizeAssets, getAssetOutputPath };
|
|
6
6
|
export type FileEventType = 'create' | 'update' | 'delete';
|
|
@@ -12,7 +12,7 @@ const normalize_assets_1 = require("./normalize-assets");
|
|
|
12
12
|
Object.defineProperty(exports, "normalizeAssets", { enumerable: true, get: function () { return normalize_assets_1.normalizeAssets; } });
|
|
13
13
|
Object.defineProperty(exports, "getAssetOutputPath", { enumerable: true, get: function () { return normalize_assets_1.getAssetOutputPath; } });
|
|
14
14
|
const devkit_1 = require("@nx/devkit");
|
|
15
|
-
const
|
|
15
|
+
const internal_1 = require("@nx/devkit/internal");
|
|
16
16
|
const picocolors_1 = require("picocolors");
|
|
17
17
|
const defaultFileEventHandler = (events) => {
|
|
18
18
|
const dirs = new Set(events.map((event) => path.dirname(event.dest)));
|
|
@@ -93,7 +93,7 @@ class CopyAssetsHandler {
|
|
|
93
93
|
return ['**/node_modules/**', '**/.git/**'];
|
|
94
94
|
}
|
|
95
95
|
async watchAndProcessOnAssetChange() {
|
|
96
|
-
const unregisterFileWatcher = await
|
|
96
|
+
const unregisterFileWatcher = await internal_1.daemonClient.registerFileWatcher({
|
|
97
97
|
watchProjects: 'all',
|
|
98
98
|
includeGlobalWorkspaceFiles: true,
|
|
99
99
|
}, (err, data) => {
|