@nx/js 23.2.0-beta.6 → 23.2.0-beta.8
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/dist/internal.d.ts +2 -0
- package/dist/internal.js +6 -2
- package/dist/src/executors/copy-workspace-modules/copy-workspace-modules.js +1 -2
- package/dist/src/executors/node/node.impl.js +9 -10
- package/dist/src/executors/prune-lockfile/prune-lockfile.js +4 -7
- package/dist/src/executors/verdaccio/verdaccio.impl.js +1 -2
- package/dist/src/generators/library/library.js +30 -14
- package/dist/src/generators/library/schema.d.ts +6 -3
- package/dist/src/generators/library/schema.json +2 -2
- package/dist/src/index.d.ts +1 -0
- package/dist/src/plugins/typescript/plugin.js +9 -14
- package/dist/src/release/utils/update-lock-file.js +1 -2
- 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/generator-prompts.d.ts +2 -1
- package/dist/src/utils/generator-prompts.js +23 -22
- package/dist/src/utils/linter.d.ts +30 -0
- package/dist/src/utils/linter.js +43 -0
- package/dist/src/utils/package-json/update-package-json.js +3 -6
- package/package.json +11 -4
package/dist/internal.d.ts
CHANGED
|
@@ -21,6 +21,8 @@ export { getProjectPackageManagerWorkspaceState, getProjectPackageManagerWorkspa
|
|
|
21
21
|
export { findNpmDependencies } from './src/utils/find-npm-dependencies';
|
|
22
22
|
export { addBuildAndWatchDepsTargets, isValidPackageJsonBuildConfig, } from './src/plugins/typescript/util';
|
|
23
23
|
export { normalizeLinterOption, normalizeUnitTestRunnerOption, } from './src/utils/generator-prompts';
|
|
24
|
+
export { detectLinters } from './src/utils/linter';
|
|
25
|
+
export { addLintingToProject, type AddLintingToProjectOptions, } from './src/utils/add-linting-to-project';
|
|
24
26
|
export { createGlobPatternsForDependencies } from './src/utils/generate-globs';
|
|
25
27
|
export { getImportPath } from './src/utils/get-import-path';
|
|
26
28
|
export { stripGlobToBaseDir } from './src/utils/strip-glob-to-base-dir';
|
package/dist/internal.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
// internal consumers and may change without semver protection. Consider it
|
|
6
6
|
// the @nx/js equivalent of `@nx/devkit/internal`.
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.
|
|
9
|
-
exports.typesNodeVersion = exports.tsLibVersion = exports.swcNodeVersion = exports.swcHelpersVersion = exports.swcCoreVersion = exports.swcCliVersion = exports.prettierVersion = exports.esbuildVersion = exports.nxVersion = exports.releaseTasks = exports.addReleaseConfigForTsSolution = exports.addReleaseConfigForNonTsSolution = void 0;
|
|
8
|
+
exports.getImportPath = exports.createGlobPatternsForDependencies = exports.addLintingToProject = exports.detectLinters = exports.normalizeUnitTestRunnerOption = exports.normalizeLinterOption = exports.isValidPackageJsonBuildConfig = exports.addBuildAndWatchDepsTargets = exports.findNpmDependencies = exports.getProjectPackageManagerWorkspaceStateWarningTask = exports.getProjectPackageManagerWorkspaceState = exports.getNpmScope = exports.sortPackageJsonFields = exports.CopyAssetsHandler = exports.addSwcRegisterDependencies = exports.addSwcDependencies = exports.addSwcTestConfig = exports.addSwcConfig = exports.createTmpTsConfig = exports.computeCompilerOptionsPaths = exports.calculateProjectDependencies = exports.calculateProjectBuildableDependencies = exports.compileTypeScript = exports.getNeededCompilerOptionOverrides = exports.isTypescriptVersionAtLeast = exports.getTsConfigModuleResolution = exports.getRangeMinimum = exports.ensureTypescript = exports.createTreeParseConfigHost = exports.getTsConfigBaseOptions = exports.updateTsconfigFiles = exports.shouldConfigureTsSolutionSetup = exports.isUsingTsSolutionSetup = exports.getProjectType = exports.getProjectSourceRoot = exports.getDefinedCustomConditionName = exports.findRuntimeTsConfigName = exports.assertNotUsingTsSolutionSetup = exports.addProjectToTsSolutionWorkspace = exports.TS_SOLUTION_SETUP_TSCONFIG_INPUT = exports.isEsmProject = exports.walkTsconfigExtendsChain = exports.findProjectsNpmDependencies = exports.isBuiltinModuleImport = exports.TargetProjectLocator = exports.requireWithTsconfigFallback = exports.registerTsConfigPaths = exports.registerTsProject = exports.loadTsFile = exports.forceRegisterEsmLoader = void 0;
|
|
9
|
+
exports.typesNodeVersion = exports.tsLibVersion = exports.swcNodeVersion = exports.swcHelpersVersion = exports.swcCoreVersion = exports.swcCliVersion = exports.prettierVersion = exports.esbuildVersion = exports.nxVersion = exports.releaseTasks = exports.addReleaseConfigForTsSolution = exports.addReleaseConfigForNonTsSolution = exports.addLocalRegistryScripts = exports.stripGlobToBaseDir = void 0;
|
|
10
10
|
// Re-exports of nx-source internals.
|
|
11
11
|
var internal_1 = require("@nx/devkit/internal");
|
|
12
12
|
Object.defineProperty(exports, "forceRegisterEsmLoader", { enumerable: true, get: function () { return internal_1.forceRegisterEsmLoader; } });
|
|
@@ -89,6 +89,10 @@ Object.defineProperty(exports, "isValidPackageJsonBuildConfig", { enumerable: tr
|
|
|
89
89
|
var generator_prompts_1 = require("./src/utils/generator-prompts");
|
|
90
90
|
Object.defineProperty(exports, "normalizeLinterOption", { enumerable: true, get: function () { return generator_prompts_1.normalizeLinterOption; } });
|
|
91
91
|
Object.defineProperty(exports, "normalizeUnitTestRunnerOption", { enumerable: true, get: function () { return generator_prompts_1.normalizeUnitTestRunnerOption; } });
|
|
92
|
+
var linter_1 = require("./src/utils/linter");
|
|
93
|
+
Object.defineProperty(exports, "detectLinters", { enumerable: true, get: function () { return linter_1.detectLinters; } });
|
|
94
|
+
var add_linting_to_project_1 = require("./src/utils/add-linting-to-project");
|
|
95
|
+
Object.defineProperty(exports, "addLintingToProject", { enumerable: true, get: function () { return add_linting_to_project_1.addLintingToProject; } });
|
|
92
96
|
var generate_globs_1 = require("./src/utils/generate-globs");
|
|
93
97
|
Object.defineProperty(exports, "createGlobPatternsForDependencies", { enumerable: true, get: function () { return generate_globs_1.createGlobPatternsForDependencies; } });
|
|
94
98
|
var get_import_path_1 = require("./src/utils/get-import-path");
|
|
@@ -6,7 +6,6 @@ const internal_1 = require("@nx/devkit/internal");
|
|
|
6
6
|
const node_fs_1 = require("node:fs");
|
|
7
7
|
const path_1 = require("path");
|
|
8
8
|
const fs_1 = require("fs");
|
|
9
|
-
const internal_2 = require("@nx/devkit/internal");
|
|
10
9
|
const strip_glob_to_base_dir_1 = require("../../utils/strip-glob-to-base-dir");
|
|
11
10
|
async function copyWorkspaceModules(schema, context) {
|
|
12
11
|
devkit_1.logger.log('Copying Workspace Modules to Build Directory...');
|
|
@@ -21,7 +20,7 @@ function handleWorkspaceModules(outputDirectory, packageJson, projectGraph) {
|
|
|
21
20
|
if (!packageJson.dependencies) {
|
|
22
21
|
return;
|
|
23
22
|
}
|
|
24
|
-
const workspaceModules = (0,
|
|
23
|
+
const workspaceModules = (0, internal_1.getWorkspacePackagesFromGraph)(projectGraph);
|
|
25
24
|
const processedModules = new Set();
|
|
26
25
|
const workspaceModulesDir = (0, path_1.join)(outputDirectory, 'workspace_modules');
|
|
27
26
|
function calculateRelativePath(fromPkgName, toPkgName) {
|
|
@@ -6,16 +6,12 @@ const internal_1 = require("@nx/devkit/internal");
|
|
|
6
6
|
const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
7
7
|
const child_process_1 = require("child_process");
|
|
8
8
|
const devkit_1 = require("@nx/devkit");
|
|
9
|
-
const internal_2 = require("@nx/devkit/internal");
|
|
10
9
|
const crypto_1 = require("crypto");
|
|
11
10
|
const path = tslib_1.__importStar(require("path"));
|
|
12
11
|
const path_1 = require("path");
|
|
13
12
|
const buildable_libs_utils_1 = require("../../utils/buildable-libs-utils");
|
|
14
|
-
const internal_3 = require("@nx/devkit/internal");
|
|
15
13
|
const line_aware_writer_1 = require("./lib/line-aware-writer");
|
|
16
14
|
const coalescing_debounce_1 = require("./lib/coalescing-debounce");
|
|
17
|
-
const internal_4 = require("@nx/devkit/internal");
|
|
18
|
-
const internal_5 = require("@nx/devkit/internal");
|
|
19
15
|
const detect_module_format_1 = require("./lib/detect-module-format");
|
|
20
16
|
const output_file_1 = require("./lib/output-file");
|
|
21
17
|
const strip_glob_to_base_dir_1 = require("../../utils/strip-glob-to-base-dir");
|
|
@@ -175,7 +171,7 @@ async function* nodeExecutor(options, context) {
|
|
|
175
171
|
// Windows cannot deliver graceful signals through this API, so
|
|
176
172
|
// skip the grace period and force-kill immediately (matching the
|
|
177
173
|
// previous taskkill /F behavior).
|
|
178
|
-
await (0,
|
|
174
|
+
await (0, internal_1.killProcessTreeGraceful)(task.childProcess.pid, signal, process.platform === 'win32' ? 0 : undefined);
|
|
179
175
|
}
|
|
180
176
|
if (task.id === globalLineAwareWriter.currentProcessId) {
|
|
181
177
|
globalLineAwareWriter.setActiveProcess(null);
|
|
@@ -237,7 +233,7 @@ async function* nodeExecutor(options, context) {
|
|
|
237
233
|
await debouncedProcessQueue.trigger();
|
|
238
234
|
};
|
|
239
235
|
if ((0, devkit_1.isDaemonEnabled)()) {
|
|
240
|
-
additionalExitHandler = await
|
|
236
|
+
additionalExitHandler = await internal_1.daemonClient.registerFileWatcher({
|
|
241
237
|
watchProjects: [context.projectName],
|
|
242
238
|
includeDependencies: true,
|
|
243
239
|
}, async (err, data) => {
|
|
@@ -279,9 +275,12 @@ async function* nodeExecutor(options, context) {
|
|
|
279
275
|
}, context);
|
|
280
276
|
while (true) {
|
|
281
277
|
const event = await output.next();
|
|
278
|
+
if (event.done) {
|
|
279
|
+
break;
|
|
280
|
+
}
|
|
282
281
|
await addToQueue(null, Promise.resolve(event.value));
|
|
283
282
|
await debouncedProcessQueue.trigger();
|
|
284
|
-
if (
|
|
283
|
+
if (!options.watch) {
|
|
285
284
|
break;
|
|
286
285
|
}
|
|
287
286
|
}
|
|
@@ -337,7 +336,7 @@ function getFileToRun(context, project, buildOptions, buildTargetExecutor) {
|
|
|
337
336
|
// {workspaceRoot}/dist/{projectRoot} -> dist/my-app
|
|
338
337
|
const outputPath = project.data.targets[buildOptions.target]?.outputs?.[0];
|
|
339
338
|
if (outputPath) {
|
|
340
|
-
const outputFilePath = (0,
|
|
339
|
+
const outputFilePath = (0, internal_1.interpolate)(outputPath, {
|
|
341
340
|
projectName: project.name,
|
|
342
341
|
projectRoot: project.data.root,
|
|
343
342
|
workspaceRoot: context.root,
|
|
@@ -366,12 +365,12 @@ function getFileToRun(context, project, buildOptions, buildTargetExecutor) {
|
|
|
366
365
|
return (0, path_1.join)(context.root, buildOptions.outputPath, outputFileName);
|
|
367
366
|
}
|
|
368
367
|
function fileToRunCorrectPath(fileToRun) {
|
|
369
|
-
if ((0,
|
|
368
|
+
if ((0, internal_1.fileExists)(fileToRun))
|
|
370
369
|
return fileToRun;
|
|
371
370
|
const extensionsToTry = ['.cjs', '.mjs', '.cjs.js', '.esm.js'];
|
|
372
371
|
for (const ext of extensionsToTry) {
|
|
373
372
|
const file = fileToRun.replace(/\.js$/, ext);
|
|
374
|
-
if ((0,
|
|
373
|
+
if ((0, internal_1.fileExists)(file))
|
|
375
374
|
return file;
|
|
376
375
|
}
|
|
377
376
|
throw new Error(`Could not find ${fileToRun}. Make sure your build succeeded.`);
|
|
@@ -6,9 +6,6 @@ const devkit_1 = require("@nx/devkit");
|
|
|
6
6
|
const internal_1 = require("@nx/devkit/internal");
|
|
7
7
|
const fs_1 = require("fs");
|
|
8
8
|
const path_1 = require("path");
|
|
9
|
-
const internal_2 = require("@nx/devkit/internal");
|
|
10
|
-
const internal_3 = require("@nx/devkit/internal");
|
|
11
|
-
const internal_4 = require("@nx/devkit/internal");
|
|
12
9
|
const strip_glob_to_base_dir_1 = require("../../utils/strip-glob-to-base-dir");
|
|
13
10
|
async function pruneLockfileExecutor(schema, context) {
|
|
14
11
|
devkit_1.logger.log('Pruning lockfile...');
|
|
@@ -33,9 +30,9 @@ async function pruneLockfileExecutor(schema, context) {
|
|
|
33
30
|
}
|
|
34
31
|
function createPrunedLockfile(packageJson, graph) {
|
|
35
32
|
const packageManager = (0, devkit_1.detectPackageManager)(devkit_1.workspaceRoot);
|
|
36
|
-
const lockfileName = (0,
|
|
37
|
-
const lockFile = (0,
|
|
38
|
-
const workspacePackages = (0,
|
|
33
|
+
const lockfileName = (0, internal_1.getLockFileName)(packageManager);
|
|
34
|
+
const lockFile = (0, internal_1.createLockFile)(packageJson, graph, packageManager);
|
|
35
|
+
const workspacePackages = (0, internal_1.getWorkspacePackagesFromGraph)(graph);
|
|
39
36
|
for (const [pkgName, pkgVersion] of Object.entries(packageJson.dependencies ?? {})) {
|
|
40
37
|
if (pkgVersion.startsWith('workspace:') ||
|
|
41
38
|
pkgVersion.startsWith('file:') ||
|
|
@@ -125,7 +122,7 @@ function getOutputDir(schema, context) {
|
|
|
125
122
|
if (!maybeOutputPath) {
|
|
126
123
|
throw new Error(`Could not infer an output directory from the '${schema.buildTarget}' target. Please provide 'outputPath'.`);
|
|
127
124
|
}
|
|
128
|
-
maybeOutputPath = (0,
|
|
125
|
+
maybeOutputPath = (0, internal_1.interpolate)(maybeOutputPath, {
|
|
129
126
|
workspaceRoot: devkit_1.workspaceRoot,
|
|
130
127
|
projectRoot: project.root,
|
|
131
128
|
projectName: project.name,
|
|
@@ -7,7 +7,6 @@ const internal_1 = require("@nx/devkit/internal");
|
|
|
7
7
|
const child_process_1 = require("child_process");
|
|
8
8
|
const detect_port_1 = tslib_1.__importDefault(require("detect-port"));
|
|
9
9
|
const node_fs_1 = require("node:fs");
|
|
10
|
-
const internal_2 = require("@nx/devkit/internal");
|
|
11
10
|
const path_1 = require("path");
|
|
12
11
|
const semver_1 = require("semver");
|
|
13
12
|
let childProcess;
|
|
@@ -68,7 +67,7 @@ async function verdaccioExecutor(options, context) {
|
|
|
68
67
|
};
|
|
69
68
|
}
|
|
70
69
|
function getVerdaccioBinPath() {
|
|
71
|
-
const { packageJson, path: packageJsonPath } = (0,
|
|
70
|
+
const { packageJson, path: packageJsonPath } = (0, internal_1.readModulePackageJson)('verdaccio');
|
|
72
71
|
const bin = typeof packageJson.bin === 'string'
|
|
73
72
|
? packageJson.bin
|
|
74
73
|
: packageJson.bin['verdaccio'];
|
|
@@ -7,6 +7,7 @@ const tslib_1 = require("tslib");
|
|
|
7
7
|
const internal_1 = require("@nx/devkit/internal");
|
|
8
8
|
const devkit_1 = require("@nx/devkit");
|
|
9
9
|
const path_1 = require("path");
|
|
10
|
+
const add_linting_to_project_1 = require("../../utils/add-linting-to-project");
|
|
10
11
|
const assert_supported_typescript_version_1 = require("../../utils/assert-supported-typescript-version");
|
|
11
12
|
const generator_prompts_1 = require("../../utils/generator-prompts");
|
|
12
13
|
const sort_fields_1 = require("../../utils/package-json/sort-fields");
|
|
@@ -110,6 +111,8 @@ async function libraryGeneratorInternal(tree, schema) {
|
|
|
110
111
|
testEnvironment: options.testEnvironment,
|
|
111
112
|
runtimeTsconfigFileName: 'tsconfig.lib.json',
|
|
112
113
|
compiler: options.compiler === 'swc' ? 'swc' : 'babel',
|
|
114
|
+
passWithNoTests: options.passWithNoTests,
|
|
115
|
+
skipPackageJson: options.skipPackageJson,
|
|
113
116
|
addPlugin: options.addPlugin,
|
|
114
117
|
});
|
|
115
118
|
tasks.push(vitestTask);
|
|
@@ -248,6 +251,17 @@ async function configureProject(tree, options) {
|
|
|
248
251
|
}
|
|
249
252
|
}
|
|
250
253
|
async function addLint(tree, options) {
|
|
254
|
+
// Everything below reaches into `@nx/eslint`'s config utilities, which have
|
|
255
|
+
// no equivalent for other linters. Dispatch before touching any of it.
|
|
256
|
+
if (options.linter !== 'eslint') {
|
|
257
|
+
return (0, add_linting_to_project_1.addLintingToProject)(tree, {
|
|
258
|
+
linter: options.linter,
|
|
259
|
+
project: options.name,
|
|
260
|
+
addPlugin: options.addPlugin,
|
|
261
|
+
rootProject: options.rootProject,
|
|
262
|
+
unitTestRunner: options.unitTestRunner,
|
|
263
|
+
});
|
|
264
|
+
}
|
|
251
265
|
const { lintProjectGenerator } = (0, devkit_1.ensurePackage)('@nx/eslint', versions_1.nxVersion);
|
|
252
266
|
const { addOverrideToLintConfig, lintConfigHasOverride, isEslintConfigSupported, updateOverrideInLintConfig, addIgnoresToLintConfig, isTypedLintingEnabled,
|
|
253
267
|
// nx-ignore-next-line
|
|
@@ -548,22 +562,20 @@ async function normalizeOptions(tree, options) {
|
|
|
548
562
|
const hasPlugin = (0, ts_solution_setup_1.isUsingTypeScriptPlugin)(tree);
|
|
549
563
|
const isUsingTsSolutionConfig = (0, ts_solution_setup_1.isUsingTsSolutionSetup)(tree);
|
|
550
564
|
if (isUsingTsSolutionConfig) {
|
|
551
|
-
options.unitTestRunner ??=
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
}, { unitTestRunner: 'none' }).then(({ unitTestRunner }) => unitTestRunner);
|
|
565
|
+
options.unitTestRunner ??= (0, internal_1.isInteractive)()
|
|
566
|
+
? await (0, internal_1.selectPrompt)({
|
|
567
|
+
message: `Which unit test runner would you like to use?`,
|
|
568
|
+
choices: [{ value: 'none' }, { value: 'vitest' }, { value: 'jest' }],
|
|
569
|
+
})
|
|
570
|
+
: 'none';
|
|
558
571
|
}
|
|
559
572
|
else {
|
|
560
|
-
options.unitTestRunner ??=
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
}, { unitTestRunner: undefined }).then(({ unitTestRunner }) => unitTestRunner);
|
|
573
|
+
options.unitTestRunner ??= (0, internal_1.isInteractive)()
|
|
574
|
+
? await (0, internal_1.selectPrompt)({
|
|
575
|
+
message: `Which unit test runner would you like to use?`,
|
|
576
|
+
choices: [{ value: 'jest' }, { value: 'vitest' }, { value: 'none' }],
|
|
577
|
+
})
|
|
578
|
+
: undefined;
|
|
567
579
|
if (!options.unitTestRunner && options.bundler === 'vite') {
|
|
568
580
|
options.unitTestRunner = 'vitest';
|
|
569
581
|
}
|
|
@@ -638,6 +650,10 @@ async function normalizeOptions(tree, options) {
|
|
|
638
650
|
isUsingTsSolutionConfig;
|
|
639
651
|
return {
|
|
640
652
|
...options,
|
|
653
|
+
// Read from `options`, not a hoisted local: the `npm-scripts` block resets
|
|
654
|
+
// it to 'none' after `normalizeLinterOption` runs. Naming the key also
|
|
655
|
+
// satisfies the normalized type, since the spread carries `linter?`.
|
|
656
|
+
linter: options.linter,
|
|
641
657
|
fileName,
|
|
642
658
|
name: isUsingTsSolutionConfig && !options.name ? importPath : projectName,
|
|
643
659
|
projectNames,
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { ProjectNameAndRootOptions } from '@nx/devkit/internal';
|
|
2
|
-
|
|
3
|
-
const { Linter, LinterType } = require('@nx/eslint'); // use require to import to avoid circular dependency
|
|
2
|
+
import type { LinterType } from '../../utils/linter';
|
|
4
3
|
import type { ProjectPackageManagerWorkspaceState } from '../../utils/package-manager-workspaces';
|
|
5
4
|
|
|
6
5
|
export type Compiler = 'tsc' | 'swc';
|
|
@@ -15,7 +14,7 @@ export interface LibraryGeneratorSchema {
|
|
|
15
14
|
skipPackageJson?: boolean;
|
|
16
15
|
includeBabelRc?: boolean;
|
|
17
16
|
unitTestRunner?: 'jest' | 'vitest' | 'none';
|
|
18
|
-
linter?:
|
|
17
|
+
linter?: LinterType;
|
|
19
18
|
testEnvironment?: 'jsdom' | 'node';
|
|
20
19
|
importPath?: string;
|
|
21
20
|
js?: boolean;
|
|
@@ -37,11 +36,15 @@ export interface LibraryGeneratorSchema {
|
|
|
37
36
|
addPlugin?: boolean;
|
|
38
37
|
useProjectJson?: boolean;
|
|
39
38
|
useTscExecutor?: boolean;
|
|
39
|
+
/** @internal Only honored by the vitest setup. */
|
|
40
|
+
passWithNoTests?: boolean;
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
export interface NormalizedLibraryGeneratorOptions
|
|
43
44
|
extends LibraryGeneratorSchema {
|
|
44
45
|
name: string;
|
|
46
|
+
/** `normalizeOptions` always resolves this, so it is no longer optional. */
|
|
47
|
+
linter: LinterType;
|
|
45
48
|
projectNames: ProjectNameAndRootOptions['names'];
|
|
46
49
|
fileName: string;
|
|
47
50
|
projectRoot: string;
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
"x-priority": "important"
|
|
30
30
|
},
|
|
31
31
|
"linter": {
|
|
32
|
-
"description": "The tool to use for running lint checks.",
|
|
32
|
+
"description": "The tool to use for running lint checks. Defaults to the linter the workspace already uses.",
|
|
33
33
|
"type": "string",
|
|
34
|
-
"enum": ["none", "eslint"],
|
|
34
|
+
"enum": ["none", "eslint", "oxlint"],
|
|
35
35
|
"x-priority": "important"
|
|
36
36
|
},
|
|
37
37
|
"unitTestRunner": {
|
package/dist/src/index.d.ts
CHANGED
|
@@ -16,5 +16,6 @@ export { initGenerator } from './generators/init/init';
|
|
|
16
16
|
export { setupPrettierGenerator } from './generators/setup-prettier/generator';
|
|
17
17
|
export { setupVerdaccio } from './generators/setup-verdaccio/generator';
|
|
18
18
|
export { isValidVariable } from './utils/is-valid-variable';
|
|
19
|
+
export { type LinterType } from './utils/linter';
|
|
19
20
|
export { createLockFile, getLockFileName } from '@nx/devkit/internal';
|
|
20
21
|
export { createPackageJson } from '@nx/devkit/internal';
|
|
@@ -5,12 +5,7 @@ const internal_1 = require("@nx/devkit/internal");
|
|
|
5
5
|
const devkit_1 = require("@nx/devkit");
|
|
6
6
|
const node_fs_1 = require("node:fs");
|
|
7
7
|
const node_path_1 = require("node:path");
|
|
8
|
-
const devkit_2 = require("@nx/devkit");
|
|
9
|
-
const internal_2 = require("@nx/devkit/internal");
|
|
10
8
|
const picomatch = require("picomatch");
|
|
11
|
-
const internal_3 = require("@nx/devkit/internal");
|
|
12
|
-
const internal_4 = require("@nx/devkit/internal");
|
|
13
|
-
const internal_5 = require("@nx/devkit/internal");
|
|
14
9
|
const util_1 = require("./util");
|
|
15
10
|
let ts;
|
|
16
11
|
const resolvedTypescriptPaths = {};
|
|
@@ -20,12 +15,12 @@ function resolveTypescriptPath(projectRoot, workspaceRoot) {
|
|
|
20
15
|
// path is outside the workspace tree (e.g. pnpm's enableGlobalVirtualStore),
|
|
21
16
|
// since typescript is not a declared dep.
|
|
22
17
|
resolvedTypescriptPaths[projectRoot] ??= require.resolve('typescript', {
|
|
23
|
-
paths: [projectRoot, ...(0,
|
|
18
|
+
paths: [projectRoot, ...(0, internal_1.getNxRequirePaths)(workspaceRoot), __dirname],
|
|
24
19
|
});
|
|
25
20
|
return resolvedTypescriptPaths[projectRoot];
|
|
26
21
|
}
|
|
27
22
|
const TSCONFIG_CACHE_VERSION = 2;
|
|
28
|
-
const TS_CONFIG_CACHE_PATH = (0, node_path_1.join)(
|
|
23
|
+
const TS_CONFIG_CACHE_PATH = (0, node_path_1.join)(internal_1.workspaceDataDirectory, 'tsconfig-files.hash');
|
|
29
24
|
// Module-level cache store — each invocation gets a unique Symbol key
|
|
30
25
|
const cacheStore = new Map();
|
|
31
26
|
// Shared tsconfig cache — initialized once per batch, persisted to disk
|
|
@@ -117,8 +112,8 @@ const tsConfigGlob = '**/tsconfig*.json';
|
|
|
117
112
|
exports.createNodesV2 = [
|
|
118
113
|
tsConfigGlob,
|
|
119
114
|
async (configFilePaths, options, context) => {
|
|
120
|
-
const optionsHash = (0,
|
|
121
|
-
const targetsCachePath = (0, node_path_1.join)(
|
|
115
|
+
const optionsHash = (0, internal_1.hashObject)(options);
|
|
116
|
+
const targetsCachePath = (0, node_path_1.join)(internal_1.workspaceDataDirectory, `tsc-${optionsHash}.hash`);
|
|
122
117
|
const targetsCache = readFromCache(targetsCachePath);
|
|
123
118
|
// Each invocation gets a unique Symbol key — guaranteed no collisions
|
|
124
119
|
const cacheKey = Symbol('tsc-invocation');
|
|
@@ -136,7 +131,7 @@ exports.createNodesV2 = [
|
|
|
136
131
|
const normalizedOptions = normalizePluginOptions(options);
|
|
137
132
|
const packageManager = (0, devkit_1.detectPackageManager)(context.workspaceRoot);
|
|
138
133
|
const pmc = (0, devkit_1.getPackageManagerCommand)(packageManager);
|
|
139
|
-
const lockFileName = (0,
|
|
134
|
+
const lockFileName = (0, internal_1.getLockFileName)(packageManager);
|
|
140
135
|
const { configFilePaths: validConfigFilePaths, hashes, projectRoots, } = await resolveValidConfigFilesAndHashes(configFilePaths, normalizedOptions, optionsHash, context, cache, lockFileName);
|
|
141
136
|
try {
|
|
142
137
|
return await (0, devkit_1.createNodesFromFiles)((configFilePath, options, context, idx) => {
|
|
@@ -171,7 +166,7 @@ exports.createNodesV2 = [
|
|
|
171
166
|
];
|
|
172
167
|
exports.createNodes = exports.createNodesV2;
|
|
173
168
|
async function resolveValidConfigFilesAndHashes(configFilePaths, options, optionsHash, context, cache, lockFileName) {
|
|
174
|
-
const lockFileHash = (0,
|
|
169
|
+
const lockFileHash = (0, internal_1.hashFile)((0, node_path_1.join)(context.workspaceRoot, lockFileName)) ?? '';
|
|
175
170
|
const validConfigFilePaths = [];
|
|
176
171
|
const hashes = [];
|
|
177
172
|
const projectRoots = [];
|
|
@@ -218,7 +213,7 @@ async function getConfigFileHash(configFilePath, workspaceRoot, project, options
|
|
|
218
213
|
packageJson = (0, devkit_1.readJsonFile)((0, node_path_1.join)(workspaceRoot, project.root, 'package.json'));
|
|
219
214
|
}
|
|
220
215
|
catch { }
|
|
221
|
-
return (0,
|
|
216
|
+
return (0, devkit_1.hashArray)([
|
|
222
217
|
...[
|
|
223
218
|
fullConfigPath,
|
|
224
219
|
...extendedConfigFiles.files.sort(),
|
|
@@ -228,7 +223,7 @@ async function getConfigFileHash(configFilePath, workspaceRoot, project, options
|
|
|
228
223
|
...extendedConfigFiles.packages.sort(),
|
|
229
224
|
lockFileHash,
|
|
230
225
|
optionsHash,
|
|
231
|
-
...(packageJson ? [(0,
|
|
226
|
+
...(packageJson ? [(0, internal_1.hashObject)(packageJson)] : []),
|
|
232
227
|
]);
|
|
233
228
|
}
|
|
234
229
|
function checkIfConfigFileShouldBeProject(config, cache) {
|
|
@@ -956,7 +951,7 @@ function getFileHash(filePath, workspaceRoot, cache) {
|
|
|
956
951
|
const relativePath = posixRelative(workspaceRoot, filePath);
|
|
957
952
|
if (!cache.fileHashes[relativePath]) {
|
|
958
953
|
const content = readFile(filePath, workspaceRoot, cache);
|
|
959
|
-
cache.fileHashes[relativePath] = (0,
|
|
954
|
+
cache.fileHashes[relativePath] = (0, devkit_1.hashArray)([content]);
|
|
960
955
|
}
|
|
961
956
|
return cache.fileHashes[relativePath];
|
|
962
957
|
}
|
|
@@ -4,7 +4,6 @@ exports.updateLockFile = updateLockFile;
|
|
|
4
4
|
const devkit_1 = require("@nx/devkit");
|
|
5
5
|
const child_process_1 = require("child_process");
|
|
6
6
|
const internal_1 = require("@nx/devkit/internal");
|
|
7
|
-
const internal_2 = require("@nx/devkit/internal");
|
|
8
7
|
const semver_1 = require("semver");
|
|
9
8
|
async function updateLockFile(cwd, { dryRun, verbose, options, }) {
|
|
10
9
|
if (options?.skipLockFileUpdate) {
|
|
@@ -47,7 +46,7 @@ async function updateLockFile(cwd, { dryRun, verbose, options, }) {
|
|
|
47
46
|
installArgs = `${installArgs} --ignore-scripts`.trim();
|
|
48
47
|
}
|
|
49
48
|
}
|
|
50
|
-
const lockFile = (0,
|
|
49
|
+
const lockFile = (0, internal_1.getLockFileName)(packageManager);
|
|
51
50
|
const command = `${packageManagerCommands.updateLockFile} ${installArgs}`.trim();
|
|
52
51
|
if (verbose) {
|
|
53
52
|
if (dryRun) {
|
|
@@ -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,3 +1,4 @@
|
|
|
1
1
|
import type { Tree } from '@nx/devkit';
|
|
2
|
-
|
|
2
|
+
import { type LinterType } from './linter';
|
|
3
|
+
export declare function normalizeLinterOption(tree: Tree, linter: undefined | LinterType): Promise<LinterType>;
|
|
3
4
|
export declare function normalizeUnitTestRunnerOption<T extends 'none' | 'jest' | 'vitest'>(tree: Tree, unitTestRunner: undefined | T, testRunners?: Array<'jest' | 'vitest'>): Promise<T>;
|
|
@@ -4,37 +4,38 @@ exports.normalizeLinterOption = normalizeLinterOption;
|
|
|
4
4
|
exports.normalizeUnitTestRunnerOption = normalizeUnitTestRunnerOption;
|
|
5
5
|
const internal_1 = require("@nx/devkit/internal");
|
|
6
6
|
const ts_solution_setup_1 = require("./typescript/ts-solution-setup");
|
|
7
|
+
const linter_1 = require("./linter");
|
|
7
8
|
async function normalizeLinterOption(tree, linter) {
|
|
8
9
|
if (linter) {
|
|
9
10
|
return linter;
|
|
10
11
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
12
|
+
// Following the workspace is not a question. When it already has a linter,
|
|
13
|
+
// use it — including in a hybrid workspace, where `detectLinters` puts the
|
|
14
|
+
// one being migrated *to* first. Pass `--linter` to choose something else.
|
|
15
|
+
const [detected] = (0, linter_1.detectLinters)(tree);
|
|
16
|
+
if (detected) {
|
|
17
|
+
return detected;
|
|
18
|
+
}
|
|
19
|
+
// Nothing to follow, so this is a real choice. `none` is the non-interactive
|
|
20
|
+
// answer, and leads the list so the interactive default matches it.
|
|
21
|
+
return (0, internal_1.isInteractive)()
|
|
22
|
+
? (0, internal_1.selectPrompt)({
|
|
23
|
+
message: `Which linter would you like to use?`,
|
|
24
|
+
choices: [{ value: 'none' }, { value: 'eslint' }, { value: 'oxlint' }],
|
|
25
|
+
})
|
|
26
|
+
: 'none';
|
|
23
27
|
}
|
|
24
28
|
async function normalizeUnitTestRunnerOption(tree, unitTestRunner, testRunners = ['jest', 'vitest']) {
|
|
25
29
|
if (unitTestRunner) {
|
|
26
30
|
return unitTestRunner;
|
|
27
31
|
}
|
|
28
32
|
const isTsSolutionSetup = (0, ts_solution_setup_1.isUsingTsSolutionSetup)(tree);
|
|
29
|
-
const choices = isTsSolutionSetup
|
|
30
|
-
? [{ name: 'none' }, ...testRunners.map((runner) => ({ name: runner }))]
|
|
31
|
-
: [...testRunners.map((runner) => ({ name: runner })), { name: 'none' }];
|
|
33
|
+
const choices = (isTsSolutionSetup ? ['none', ...testRunners] : [...testRunners, 'none']).map((value) => ({ value: value }));
|
|
32
34
|
const defaultValue = (isTsSolutionSetup ? 'none' : testRunners[0]);
|
|
33
|
-
return
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}, { unitTestRunner: defaultValue }).then(({ unitTestRunner }) => unitTestRunner);
|
|
35
|
+
return (0, internal_1.isInteractive)()
|
|
36
|
+
? (0, internal_1.selectPrompt)({
|
|
37
|
+
message: `Which unit test runner would you like to use?`,
|
|
38
|
+
choices,
|
|
39
|
+
})
|
|
40
|
+
: defaultValue;
|
|
40
41
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type Tree } from '@nx/devkit';
|
|
2
|
+
/**
|
|
3
|
+
* The linters Nx generators can set up for a project.
|
|
4
|
+
*
|
|
5
|
+
* Canonical home. `@nx/eslint` re-exports this for back-compat. Two standalone
|
|
6
|
+
* copies exist because neither package can depend on `@nx/js`: `@nx/workspace`
|
|
7
|
+
* (which `@nx/js` itself depends on) and `LINTERS` in `create-nx-workspace`.
|
|
8
|
+
* The assertion below pins the first; `create-nx-workspace` has no edge to
|
|
9
|
+
* assert across, so that one is still kept in sync by hand.
|
|
10
|
+
*/
|
|
11
|
+
export type LinterType = 'eslint' | 'oxlint' | 'none';
|
|
12
|
+
/**
|
|
13
|
+
* Every linter the workspace has installed, most-preferred first — so `[0]` is
|
|
14
|
+
* the one a generator should follow when it was not told which to set up, and
|
|
15
|
+
* `.includes(x)` answers whether the workspace uses `x` at all. Those differ in
|
|
16
|
+
* a workspace part-way through a migration: it has both, and a project
|
|
17
|
+
* generated for Oxlint still lives under the root ESLint config.
|
|
18
|
+
*
|
|
19
|
+
* Oxlint sorts first when both are present. A workspace with both has adopted
|
|
20
|
+
* Oxlint alongside its existing ESLint setup, and new projects should follow
|
|
21
|
+
* the direction of travel rather than the setup being migrated away from.
|
|
22
|
+
*
|
|
23
|
+
* Empty means the workspace opted out of linting; callers that need a concrete
|
|
24
|
+
* answer should read that as `none` rather than inferring ESLint for it.
|
|
25
|
+
*
|
|
26
|
+
* Reads the tree, never the generator's own module resolution: `eslint` is a
|
|
27
|
+
* peer dependency of several first-party plugins, so it resolves from disk in
|
|
28
|
+
* workspaces that do not use it.
|
|
29
|
+
*/
|
|
30
|
+
export declare function detectLinters(tree: Tree): Exclude<LinterType, 'none'>[];
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.detectLinters = detectLinters;
|
|
4
|
+
const devkit_1 = require("@nx/devkit");
|
|
5
|
+
function hasPlugin(tree, plugin) {
|
|
6
|
+
const nxJson = (0, devkit_1.readNxJson)(tree);
|
|
7
|
+
return !!nxJson?.plugins?.some((p) => typeof p === 'string' ? p === plugin : p.plugin === plugin);
|
|
8
|
+
}
|
|
9
|
+
function hasAnyDependency(tree, packages) {
|
|
10
|
+
return packages.some((pkg) => Boolean((0, devkit_1.getDependencyVersionFromPackageJson)(tree, pkg)));
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Every linter the workspace has installed, most-preferred first — so `[0]` is
|
|
14
|
+
* the one a generator should follow when it was not told which to set up, and
|
|
15
|
+
* `.includes(x)` answers whether the workspace uses `x` at all. Those differ in
|
|
16
|
+
* a workspace part-way through a migration: it has both, and a project
|
|
17
|
+
* generated for Oxlint still lives under the root ESLint config.
|
|
18
|
+
*
|
|
19
|
+
* Oxlint sorts first when both are present. A workspace with both has adopted
|
|
20
|
+
* Oxlint alongside its existing ESLint setup, and new projects should follow
|
|
21
|
+
* the direction of travel rather than the setup being migrated away from.
|
|
22
|
+
*
|
|
23
|
+
* Empty means the workspace opted out of linting; callers that need a concrete
|
|
24
|
+
* answer should read that as `none` rather than inferring ESLint for it.
|
|
25
|
+
*
|
|
26
|
+
* Reads the tree, never the generator's own module resolution: `eslint` is a
|
|
27
|
+
* peer dependency of several first-party plugins, so it resolves from disk in
|
|
28
|
+
* workspaces that do not use it.
|
|
29
|
+
*/
|
|
30
|
+
function detectLinters(tree) {
|
|
31
|
+
const linters = [];
|
|
32
|
+
if (hasPlugin(tree, '@nx/oxlint') ||
|
|
33
|
+
hasAnyDependency(tree, ['@nx/oxlint', 'oxlint'])) {
|
|
34
|
+
linters.push('oxlint');
|
|
35
|
+
}
|
|
36
|
+
// `@nx/eslint` registers its inference plugin as `@nx/eslint/plugin`, unlike
|
|
37
|
+
// `@nx/oxlint`, which registers under its bare package name.
|
|
38
|
+
if (hasPlugin(tree, '@nx/eslint/plugin') ||
|
|
39
|
+
hasAnyDependency(tree, ['@nx/eslint', 'eslint'])) {
|
|
40
|
+
linters.push('eslint');
|
|
41
|
+
}
|
|
42
|
+
return linters;
|
|
43
|
+
}
|
|
@@ -5,21 +5,18 @@ exports.getExports = getExports;
|
|
|
5
5
|
exports.getUpdatedPackageJsonContent = getUpdatedPackageJsonContent;
|
|
6
6
|
exports.getOutputDir = getOutputDir;
|
|
7
7
|
const internal_1 = require("@nx/devkit/internal");
|
|
8
|
-
const internal_2 = require("@nx/devkit/internal");
|
|
9
8
|
const devkit_1 = require("@nx/devkit");
|
|
10
9
|
const node_fs_1 = require("node:fs");
|
|
11
10
|
const path_1 = require("path");
|
|
12
|
-
const internal_3 = require("@nx/devkit/internal");
|
|
13
|
-
const internal_4 = require("@nx/devkit/internal");
|
|
14
11
|
const get_main_file_dir_1 = require("../get-main-file-dir");
|
|
15
12
|
const strip_glob_to_base_dir_1 = require("../strip-glob-to-base-dir");
|
|
16
13
|
function updatePackageJson(options, context, target, dependencies, fileMap = null) {
|
|
17
14
|
let packageJson;
|
|
18
15
|
if (fileMap == null) {
|
|
19
|
-
fileMap = (0,
|
|
16
|
+
fileMap = (0, internal_1.readFileMapCache)()?.fileMap?.projectFileMap || {};
|
|
20
17
|
}
|
|
21
18
|
if (options.updateBuildableProjectDepsInPackageJson) {
|
|
22
|
-
packageJson = (0,
|
|
19
|
+
packageJson = (0, internal_1.createPackageJson)(context.projectName, context.projectGraph, {
|
|
23
20
|
target: context.targetName,
|
|
24
21
|
root: context.root,
|
|
25
22
|
// By default we remove devDependencies since this is a production build.
|
|
@@ -32,7 +29,7 @@ function updatePackageJson(options, context, target, dependencies, fileMap = nul
|
|
|
32
29
|
}
|
|
33
30
|
else {
|
|
34
31
|
const pathToPackageJson = (0, path_1.join)(context.root, options.projectRoot, 'package.json');
|
|
35
|
-
packageJson = (0,
|
|
32
|
+
packageJson = (0, internal_1.fileExists)(pathToPackageJson)
|
|
36
33
|
? (0, devkit_1.readJsonFile)(pathToPackageJson)
|
|
37
34
|
: { name: context.projectName, version: '0.0.1' };
|
|
38
35
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nx/js",
|
|
3
|
-
"version": "23.2.0-beta.
|
|
3
|
+
"version": "23.2.0-beta.8",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"files": [
|
|
@@ -147,11 +147,18 @@
|
|
|
147
147
|
"source-map-support": "0.5.19",
|
|
148
148
|
"tinyglobby": "^0.2.12",
|
|
149
149
|
"tslib": "^2.3.0",
|
|
150
|
-
"@nx/devkit": "23.2.0-beta.
|
|
151
|
-
"@nx/workspace": "23.2.0-beta.
|
|
150
|
+
"@nx/devkit": "23.2.0-beta.8",
|
|
151
|
+
"@nx/workspace": "23.2.0-beta.8"
|
|
152
152
|
},
|
|
153
153
|
"devDependencies": {
|
|
154
|
-
"nx": "23.2.0-beta.
|
|
154
|
+
"@nx/esbuild": "23.2.0-beta.8",
|
|
155
|
+
"@nx/eslint": "23.2.0-beta.8",
|
|
156
|
+
"@nx/jest": "23.2.0-beta.8",
|
|
157
|
+
"@nx/oxlint": "23.2.0-beta.8",
|
|
158
|
+
"@nx/vite": "23.2.0-beta.8",
|
|
159
|
+
"@nx/rollup": "23.2.0-beta.8",
|
|
160
|
+
"@nx/vitest": "23.2.0-beta.8",
|
|
161
|
+
"nx": "23.2.0-beta.8"
|
|
155
162
|
},
|
|
156
163
|
"peerDependencies": {
|
|
157
164
|
"@swc/cli": ">=0.6.0 <0.9.0",
|