@nx/js 20.5.0-beta.2 → 20.5.0-beta.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/js",
3
- "version": "20.5.0-beta.2",
3
+ "version": "20.5.0-beta.3",
4
4
  "private": false,
5
5
  "description": "The JS plugin for Nx contains executors and generators that provide the best experience for developing JavaScript and TypeScript projects. ",
6
6
  "repository": {
@@ -39,8 +39,8 @@
39
39
  "@babel/preset-env": "^7.23.2",
40
40
  "@babel/preset-typescript": "^7.22.5",
41
41
  "@babel/runtime": "^7.22.6",
42
- "@nx/devkit": "20.5.0-beta.2",
43
- "@nx/workspace": "20.5.0-beta.2",
42
+ "@nx/devkit": "20.5.0-beta.3",
43
+ "@nx/workspace": "20.5.0-beta.3",
44
44
  "@zkochan/js-yaml": "0.0.7",
45
45
  "babel-plugin-const-enum": "^1.0.1",
46
46
  "babel-plugin-macros": "^3.1.0",
@@ -88,7 +88,7 @@ async function* nodeExecutor(options, context) {
88
88
  start: async () => {
89
89
  // Wait for build to finish.
90
90
  const result = await buildResult;
91
- if (!result.success) {
91
+ if (result && !result.success) {
92
92
  // If in watch-mode, don't throw or else the process exits.
93
93
  if (options.watch) {
94
94
  if (!task.killed) {
@@ -8,7 +8,6 @@ const project_name_and_root_utils_1 = require("@nx/devkit/src/generators/project
8
8
  const prompt_1 = require("@nx/devkit/src/generators/prompt");
9
9
  const target_defaults_utils_1 = require("@nx/devkit/src/generators/target-defaults-utils");
10
10
  const log_show_project_command_1 = require("@nx/devkit/src/utils/log-show-project-command");
11
- const find_matching_projects_1 = require("nx/src/utils/find-matching-projects");
12
11
  const path_1 = require("path");
13
12
  const generator_prompts_1 = require("../../utils/generator-prompts");
14
13
  const update_package_json_1 = require("../../utils/package-json/update-package-json");
@@ -22,9 +21,9 @@ const ts_config_1 = require("../../utils/typescript/ts-config");
22
21
  const ts_solution_setup_1 = require("../../utils/typescript/ts-solution-setup");
23
22
  const versions_1 = require("../../utils/versions");
24
23
  const init_1 = require("../init/init");
25
- const generator_1 = require("../setup-verdaccio/generator");
26
24
  const sort_fields_1 = require("../../utils/package-json/sort-fields");
27
25
  const get_import_path_1 = require("../../utils/get-import-path");
26
+ const add_release_config_1 = require("./utils/add-release-config");
28
27
  const defaultOutputDirectory = 'dist';
29
28
  async function libraryGenerator(tree, schema) {
30
29
  return await libraryGeneratorInternal(tree, {
@@ -54,9 +53,6 @@ async function libraryGeneratorInternal(tree, schema) {
54
53
  if (!options.skipPackageJson) {
55
54
  tasks.push(addProjectDependencies(tree, options));
56
55
  }
57
- if (options.publishable) {
58
- tasks.push(await (0, generator_1.default)(tree, { ...options, skipFormat: true }));
59
- }
60
56
  if (options.bundler === 'rollup') {
61
57
  const { configurationGenerator } = (0, devkit_1.ensurePackage)('@nx/rollup', versions_1.nxVersion);
62
58
  await configurationGenerator(tree, {
@@ -151,9 +147,7 @@ async function libraryGeneratorInternal(tree, schema) {
151
147
  await (0, devkit_1.formatFiles)(tree);
152
148
  }
153
149
  if (options.publishable) {
154
- tasks.push(() => {
155
- logNxReleaseDocsInfo();
156
- });
150
+ tasks.push(await (0, add_release_config_1.releaseTasks)(tree));
157
151
  }
158
152
  // Always run install to link packages.
159
153
  if (options.isUsingTsSolutionConfig) {
@@ -220,26 +214,12 @@ async function configureProject(tree, options) {
220
214
  }
221
215
  }
222
216
  if (options.publishable) {
223
- if (!options.isUsingTsSolutionConfig) {
224
- const packageRoot = (0, devkit_1.joinPathFragments)(defaultOutputDirectory, '{projectRoot}');
225
- projectConfiguration.targets ??= {};
226
- projectConfiguration.targets['nx-release-publish'] = {
227
- options: {
228
- packageRoot,
229
- },
230
- };
231
- projectConfiguration.release = {
232
- version: {
233
- generatorOptions: {
234
- packageRoot,
235
- // using git tags to determine the current version is required here because
236
- // the version in the package root is overridden with every build
237
- currentVersionResolver: 'git-tag',
238
- },
239
- },
240
- };
217
+ if (options.isUsingTsSolutionConfig) {
218
+ await (0, add_release_config_1.addReleaseConfigForTsSolution)(tree, options.name, projectConfiguration);
219
+ }
220
+ else {
221
+ await (0, add_release_config_1.addReleaseConfigForNonTsSolution)(tree, options.name, projectConfiguration, defaultOutputDirectory);
241
222
  }
242
- await addProjectToNxReleaseConfig(tree, options, projectConfiguration);
243
223
  }
244
224
  if (!options.useProjectJson) {
245
225
  // we want the package.json as clean as possible, with the bare minimum
@@ -930,96 +910,6 @@ function determineEntryFields(options) {
930
910
  }
931
911
  }
932
912
  }
933
- function projectsConfigMatchesProject(projectsConfig, project) {
934
- if (!projectsConfig) {
935
- return false;
936
- }
937
- if (typeof projectsConfig === 'string') {
938
- projectsConfig = [projectsConfig];
939
- }
940
- const graph = {
941
- [project.name]: project,
942
- };
943
- const matchingProjects = (0, find_matching_projects_1.findMatchingProjects)(projectsConfig, graph);
944
- return matchingProjects.includes(project.name);
945
- }
946
- async function addProjectToNxReleaseConfig(tree, options, projectConfiguration) {
947
- const nxJson = (0, devkit_1.readNxJson)(tree);
948
- const addPreVersionCommand = () => {
949
- const pmc = (0, devkit_1.getPackageManagerCommand)();
950
- nxJson.release = {
951
- ...nxJson.release,
952
- version: {
953
- preVersionCommand: `${pmc.dlx} nx run-many -t build`,
954
- ...nxJson.release?.version,
955
- },
956
- };
957
- };
958
- if (!nxJson.release || (!nxJson.release.projects && !nxJson.release.groups)) {
959
- // skip adding any projects configuration since the new project should be
960
- // automatically included by nx release's default project detection logic
961
- addPreVersionCommand();
962
- (0, devkit_1.writeJson)(tree, 'nx.json', nxJson);
963
- return;
964
- }
965
- const project = {
966
- name: options.name,
967
- type: 'lib',
968
- data: {
969
- root: projectConfiguration.root,
970
- tags: projectConfiguration.tags,
971
- },
972
- };
973
- if (projectsConfigMatchesProject(nxJson.release.projects, project)) {
974
- devkit_1.output.log({
975
- title: `Project already included in existing release configuration`,
976
- });
977
- addPreVersionCommand();
978
- (0, devkit_1.writeJson)(tree, 'nx.json', nxJson);
979
- return;
980
- }
981
- if (Array.isArray(nxJson.release.projects)) {
982
- nxJson.release.projects.push(options.name);
983
- addPreVersionCommand();
984
- (0, devkit_1.writeJson)(tree, 'nx.json', nxJson);
985
- devkit_1.output.log({
986
- title: `Added project to existing release configuration`,
987
- });
988
- }
989
- if (nxJson.release.groups) {
990
- const allGroups = Object.entries(nxJson.release.groups);
991
- for (const [name, group] of allGroups) {
992
- if (projectsConfigMatchesProject(group.projects, project)) {
993
- addPreVersionCommand();
994
- (0, devkit_1.writeJson)(tree, 'nx.json', nxJson);
995
- return `Project already included in existing release configuration for group ${name}`;
996
- }
997
- }
998
- devkit_1.output.warn({
999
- title: `Could not find a release group that includes ${options.name}`,
1000
- bodyLines: [
1001
- `Ensure that ${options.name} is included in a release group's "projects" list in nx.json so it can be published with "nx release"`,
1002
- ],
1003
- });
1004
- addPreVersionCommand();
1005
- (0, devkit_1.writeJson)(tree, 'nx.json', nxJson);
1006
- return;
1007
- }
1008
- if (typeof nxJson.release.projects === 'string') {
1009
- nxJson.release.projects = [nxJson.release.projects, options.name];
1010
- addPreVersionCommand();
1011
- (0, devkit_1.writeJson)(tree, 'nx.json', nxJson);
1012
- devkit_1.output.log({
1013
- title: `Added project to existing release configuration`,
1014
- });
1015
- return;
1016
- }
1017
- }
1018
- function logNxReleaseDocsInfo() {
1019
- devkit_1.output.log({
1020
- title: `📦 To learn how to publish this library, see https://nx.dev/core-features/manage-releases.`,
1021
- });
1022
- }
1023
913
  function findRootJestPreset(tree) {
1024
914
  const ext = ['js', 'cjs', 'mjs'].find((ext) => tree.exists(`jest.preset.${ext}`));
1025
915
  return ext ? `jest.preset.${ext}` : null;
@@ -0,0 +1,11 @@
1
+ import { GeneratorCallback, ProjectConfiguration, Tree } from '@nx/devkit';
2
+ /**
3
+ * Adds release option in nx.json to build the project before versioning
4
+ */
5
+ export declare function addReleaseConfigForTsSolution(tree: Tree, projectName: string, projectConfiguration: ProjectConfiguration): Promise<void>;
6
+ /**
7
+ * Add release configuration for non-ts solution projects
8
+ * Add release option in project.json and add packageRoot to nx-release-publish target
9
+ */
10
+ export declare function addReleaseConfigForNonTsSolution(tree: Tree, projectName: string, projectConfiguration: ProjectConfiguration, defaultOutputDirectory?: string): Promise<ProjectConfiguration>;
11
+ export declare function releaseTasks(tree: Tree): Promise<GeneratorCallback>;
@@ -0,0 +1,136 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.addReleaseConfigForTsSolution = addReleaseConfigForTsSolution;
4
+ exports.addReleaseConfigForNonTsSolution = addReleaseConfigForNonTsSolution;
5
+ exports.releaseTasks = releaseTasks;
6
+ const devkit_1 = require("@nx/devkit");
7
+ const find_matching_projects_1 = require("nx/src/utils/find-matching-projects");
8
+ const generator_1 = require("../../setup-verdaccio/generator");
9
+ /**
10
+ * Adds release option in nx.json to build the project before versioning
11
+ */
12
+ async function addReleaseConfigForTsSolution(tree, projectName, projectConfiguration) {
13
+ const nxJson = (0, devkit_1.readNxJson)(tree);
14
+ const addPreVersionCommand = () => {
15
+ const pmc = (0, devkit_1.getPackageManagerCommand)();
16
+ nxJson.release = {
17
+ ...nxJson.release,
18
+ version: {
19
+ preVersionCommand: `${pmc.dlx} nx run-many -t build`,
20
+ ...nxJson.release?.version,
21
+ },
22
+ };
23
+ };
24
+ // if the release configuration does not exist, it will be created
25
+ if (!nxJson.release || (!nxJson.release.projects && !nxJson.release.groups)) {
26
+ // skip adding any projects configuration since the new project should be
27
+ // automatically included by nx release's default project detection logic
28
+ addPreVersionCommand();
29
+ (0, devkit_1.writeJson)(tree, 'nx.json', nxJson);
30
+ return;
31
+ }
32
+ const project = {
33
+ name: projectName,
34
+ type: 'lib',
35
+ data: {
36
+ root: projectConfiguration.root,
37
+ tags: projectConfiguration.tags,
38
+ },
39
+ };
40
+ // if the project is already included in the release configuration, it will not be added again
41
+ if (projectsConfigMatchesProject(nxJson.release.projects, project)) {
42
+ devkit_1.output.log({
43
+ title: `Project already included in existing release configuration`,
44
+ });
45
+ addPreVersionCommand();
46
+ (0, devkit_1.writeJson)(tree, 'nx.json', nxJson);
47
+ return;
48
+ }
49
+ // if the release configuration is a string, it will be converted to an array and added to it
50
+ if (Array.isArray(nxJson.release.projects)) {
51
+ nxJson.release.projects.push(projectName);
52
+ addPreVersionCommand();
53
+ (0, devkit_1.writeJson)(tree, 'nx.json', nxJson);
54
+ devkit_1.output.log({
55
+ title: `Added project to existing release configuration`,
56
+ });
57
+ }
58
+ if (nxJson.release.groups) {
59
+ const allGroups = Object.entries(nxJson.release.groups);
60
+ for (const [name, group] of allGroups) {
61
+ if (projectsConfigMatchesProject(group.projects, project)) {
62
+ addPreVersionCommand();
63
+ (0, devkit_1.writeJson)(tree, 'nx.json', nxJson);
64
+ devkit_1.output.log({
65
+ title: `Project already included in existing release configuration for group ${name}`,
66
+ });
67
+ return;
68
+ }
69
+ }
70
+ devkit_1.output.warn({
71
+ title: `Could not find a release group that includes ${projectName}`,
72
+ bodyLines: [
73
+ `Ensure that ${projectName} is included in a release group's "projects" list in nx.json so it can be published with "nx release"`,
74
+ ],
75
+ });
76
+ addPreVersionCommand();
77
+ (0, devkit_1.writeJson)(tree, 'nx.json', nxJson);
78
+ return;
79
+ }
80
+ if (typeof nxJson.release.projects === 'string') {
81
+ nxJson.release.projects = [nxJson.release.projects, projectName];
82
+ addPreVersionCommand();
83
+ (0, devkit_1.writeJson)(tree, 'nx.json', nxJson);
84
+ devkit_1.output.log({
85
+ title: `Added project to existing release configuration`,
86
+ });
87
+ return;
88
+ }
89
+ }
90
+ /**
91
+ * Add release configuration for non-ts solution projects
92
+ * Add release option in project.json and add packageRoot to nx-release-publish target
93
+ */
94
+ async function addReleaseConfigForNonTsSolution(tree, projectName, projectConfiguration, defaultOutputDirectory = 'dist') {
95
+ const packageRoot = (0, devkit_1.joinPathFragments)(defaultOutputDirectory, '{projectRoot}');
96
+ projectConfiguration.targets ??= {};
97
+ projectConfiguration.targets['nx-release-publish'] = {
98
+ options: {
99
+ packageRoot,
100
+ },
101
+ };
102
+ projectConfiguration.release = {
103
+ version: {
104
+ generatorOptions: {
105
+ packageRoot,
106
+ // using git tags to determine the current version is required here because
107
+ // the version in the package root is overridden with every build
108
+ currentVersionResolver: 'git-tag',
109
+ fallbackCurrentVersionResolver: 'disk',
110
+ },
111
+ },
112
+ };
113
+ await addReleaseConfigForTsSolution(tree, projectName, projectConfiguration);
114
+ return projectConfiguration;
115
+ }
116
+ function projectsConfigMatchesProject(projectsConfig, project) {
117
+ if (!projectsConfig) {
118
+ return false;
119
+ }
120
+ if (typeof projectsConfig === 'string') {
121
+ projectsConfig = [projectsConfig];
122
+ }
123
+ const graph = {
124
+ [project.name]: project,
125
+ };
126
+ const matchingProjects = (0, find_matching_projects_1.findMatchingProjects)(projectsConfig, graph);
127
+ return matchingProjects.includes(project.name);
128
+ }
129
+ async function releaseTasks(tree) {
130
+ return (0, devkit_1.runTasksInSerial)(await (0, generator_1.default)(tree, { skipFormat: true }), () => logNxReleaseDocsInfo());
131
+ }
132
+ function logNxReleaseDocsInfo() {
133
+ devkit_1.output.log({
134
+ title: `📦 To learn how to publish this library, see https://nx.dev/core-features/manage-releases.`,
135
+ });
136
+ }
@@ -6,20 +6,27 @@ const get_named_inputs_1 = require("@nx/devkit/src/utils/get-named-inputs");
6
6
  const minimatch_1 = require("minimatch");
7
7
  const node_fs_1 = require("node:fs");
8
8
  const node_path_1 = require("node:path");
9
+ const posix = require("node:path/posix");
9
10
  const file_hasher_1 = require("nx/src/hasher/file-hasher");
10
11
  // eslint-disable-next-line @typescript-eslint/no-restricted-imports
11
12
  const lock_file_1 = require("nx/src/plugins/js/lock-file/lock-file");
12
13
  const cache_directory_1 = require("nx/src/utils/cache-directory");
13
- const ts_config_1 = require("../../utils/typescript/ts-config");
14
14
  const util_1 = require("./util");
15
15
  const pmc = (0, devkit_1.getPackageManagerCommand)();
16
- function readTargetsCache(cachePath) {
17
- return process.env.NX_CACHE_PROJECT_GRAPH !== 'false' && (0, node_fs_1.existsSync)(cachePath)
18
- ? (0, devkit_1.readJsonFile)(cachePath)
19
- : {};
16
+ let tsConfigCache;
17
+ const tsConfigCachePath = (0, node_path_1.join)(cache_directory_1.workspaceDataDirectory, 'tsconfig-files.hash');
18
+ function readFromCache(cachePath) {
19
+ try {
20
+ return process.env.NX_CACHE_PROJECT_GRAPH !== 'false'
21
+ ? (0, devkit_1.readJsonFile)(cachePath)
22
+ : {};
23
+ }
24
+ catch {
25
+ return {};
26
+ }
20
27
  }
21
- function writeTargetsToCache(cachePath, results) {
22
- (0, devkit_1.writeJsonFile)(cachePath, results);
28
+ function writeToCache(cachePath, data) {
29
+ (0, devkit_1.writeJsonFile)(cachePath, data, { spaces: 0 });
23
30
  }
24
31
  /**
25
32
  * @deprecated The 'createDependencies' function is now a no-op. This functionality is included in 'createNodesV2'.
@@ -34,15 +41,33 @@ exports.createNodesV2 = [
34
41
  tsConfigGlob,
35
42
  async (configFilePaths, options, context) => {
36
43
  const optionsHash = (0, file_hasher_1.hashObject)(options);
37
- const cachePath = (0, node_path_1.join)(cache_directory_1.workspaceDataDirectory, `tsc-${optionsHash}.hash`);
38
- const targetsCache = readTargetsCache(cachePath);
44
+ const targetsCachePath = (0, node_path_1.join)(cache_directory_1.workspaceDataDirectory, `tsc-${optionsHash}.hash`);
45
+ const targetsCache = readFromCache(targetsCachePath);
46
+ tsConfigCache =
47
+ readFromCache(tsConfigCachePath);
39
48
  const normalizedOptions = normalizePluginOptions(options);
40
- const lockFileName = (0, lock_file_1.getLockFileName)((0, devkit_1.detectPackageManager)(context.workspaceRoot));
49
+ const lockFileHash = (0, file_hasher_1.hashFile)((0, node_path_1.join)(context.workspaceRoot, (0, lock_file_1.getLockFileName)((0, devkit_1.detectPackageManager)(context.workspaceRoot))));
50
+ const { configFilePaths: validConfigFilePaths, hashes, projectRoots, } = await resolveValidConfigFilesAndHashes(configFilePaths, optionsHash, lockFileHash, context);
41
51
  try {
42
- return await (0, devkit_1.createNodesFromFiles)((configFile, options, context) => createNodesInternal(configFile, options, context, lockFileName, targetsCache), configFilePaths, normalizedOptions, context);
52
+ return await (0, devkit_1.createNodesFromFiles)((configFilePath, options, context, idx) => {
53
+ const projectRoot = projectRoots[idx];
54
+ const hash = hashes[idx];
55
+ const cacheKey = `${hash}_${configFilePath}`;
56
+ targetsCache[cacheKey] ??= buildTscTargets((0, node_path_1.join)(context.workspaceRoot, configFilePath), projectRoot, options, context);
57
+ const { targets } = targetsCache[cacheKey];
58
+ return {
59
+ projects: {
60
+ [projectRoot]: {
61
+ projectType: 'library',
62
+ targets,
63
+ },
64
+ },
65
+ };
66
+ }, validConfigFilePaths, normalizedOptions, context);
43
67
  }
44
68
  finally {
45
- writeTargetsToCache(cachePath, targetsCache);
69
+ writeToCache(targetsCachePath, targetsCache);
70
+ writeToCache(tsConfigCachePath, tsConfigCache);
46
71
  }
47
72
  },
48
73
  ];
@@ -50,28 +75,93 @@ exports.createNodes = [
50
75
  tsConfigGlob,
51
76
  async (configFilePath, options, context) => {
52
77
  devkit_1.logger.warn('`createNodes` is deprecated. Update your plugin to utilize createNodesV2 instead. In Nx 20, this will change to the createNodesV2 API.');
78
+ const projectRoot = (0, node_path_1.dirname)(configFilePath);
79
+ if (!checkIfConfigFileShouldBeProject(configFilePath, projectRoot, context)) {
80
+ return {};
81
+ }
53
82
  const normalizedOptions = normalizePluginOptions(options);
54
- const lockFileName = (0, lock_file_1.getLockFileName)((0, devkit_1.detectPackageManager)(context.workspaceRoot));
55
- return createNodesInternal(configFilePath, normalizedOptions, context, lockFileName, {});
83
+ tsConfigCache =
84
+ readFromCache(tsConfigCachePath);
85
+ const { targets } = buildTscTargets((0, node_path_1.join)(context.workspaceRoot, configFilePath), projectRoot, normalizedOptions, context);
86
+ return {
87
+ projects: {
88
+ [projectRoot]: {
89
+ projectType: 'library',
90
+ targets,
91
+ },
92
+ },
93
+ };
56
94
  },
57
95
  ];
58
- async function createNodesInternal(configFilePath, options, context, lockFileName, targetsCache) {
59
- const projectRoot = (0, node_path_1.dirname)(configFilePath);
60
- const fullConfigPath = (0, devkit_1.joinPathFragments)(context.workspaceRoot, configFilePath);
96
+ async function resolveValidConfigFilesAndHashes(configFilePaths, optionsHash, lockFileHash, context) {
97
+ const validConfigFilePaths = [];
98
+ const hashes = [];
99
+ const projectRoots = [];
100
+ const fileHashesCache = {};
101
+ for await (const configFilePath of configFilePaths) {
102
+ const projectRoot = (0, node_path_1.dirname)(configFilePath);
103
+ if (!checkIfConfigFileShouldBeProject(configFilePath, projectRoot, context)) {
104
+ continue;
105
+ }
106
+ projectRoots.push(projectRoot);
107
+ validConfigFilePaths.push(configFilePath);
108
+ hashes.push(await getConfigFileHash(configFilePath, context.workspaceRoot, projectRoot, optionsHash, lockFileHash, fileHashesCache));
109
+ }
110
+ return { configFilePaths: validConfigFilePaths, hashes, projectRoots };
111
+ }
112
+ /**
113
+ * The cache key is composed by:
114
+ * - hashes of the content of the relevant files that can affect what's inferred by the plugin:
115
+ * - current config file
116
+ * - config files extended by the current config file (recursively up to the root config file)
117
+ * - referenced config files that are internal to the owning Nx project of the current config file,
118
+ * or is a shallow external reference of the owning Nx project
119
+ * - lock file
120
+ * - project's package.json
121
+ * - hash of the plugin options
122
+ * - current config file path
123
+ */
124
+ async function getConfigFileHash(configFilePath, workspaceRoot, projectRoot, optionsHash, lockFileHash, fileHashesCache) {
125
+ const fullConfigPath = (0, node_path_1.join)(workspaceRoot, configFilePath);
126
+ const tsConfig = readCachedTsConfig(fullConfigPath, workspaceRoot);
127
+ const extendedConfigFiles = getExtendedConfigFiles(fullConfigPath, tsConfig, workspaceRoot);
128
+ const internalReferencedFiles = resolveInternalProjectReferences(tsConfig, workspaceRoot, projectRoot);
129
+ const externalProjectReferences = resolveShallowExternalProjectReferences(tsConfig, workspaceRoot, projectRoot);
130
+ let packageJson = null;
131
+ try {
132
+ packageJson = (0, devkit_1.readJsonFile)((0, node_path_1.join)(workspaceRoot, projectRoot, 'package.json'));
133
+ }
134
+ catch { }
135
+ return (0, file_hasher_1.hashArray)([
136
+ ...[
137
+ fullConfigPath,
138
+ ...extendedConfigFiles.files,
139
+ ...Object.keys(internalReferencedFiles),
140
+ ...Object.keys(externalProjectReferences),
141
+ ].map((file) => {
142
+ fileHashesCache[file] ??= (0, file_hasher_1.hashFile)(file);
143
+ return fileHashesCache[file];
144
+ }),
145
+ lockFileHash,
146
+ optionsHash,
147
+ ...(packageJson ? [(0, file_hasher_1.hashObject)(packageJson)] : []),
148
+ ]);
149
+ }
150
+ function checkIfConfigFileShouldBeProject(configFilePath, projectRoot, context) {
61
151
  // Do not create a project for the workspace root tsconfig files.
62
152
  if (projectRoot === '.') {
63
- return {};
153
+ return false;
64
154
  }
65
155
  // Do not create a project if package.json and project.json isn't there.
66
156
  const siblingFiles = (0, node_fs_1.readdirSync)((0, node_path_1.join)(context.workspaceRoot, projectRoot));
67
157
  if (!siblingFiles.includes('package.json') &&
68
158
  !siblingFiles.includes('project.json')) {
69
- return {};
159
+ return false;
70
160
  }
71
161
  // Do not create a project if it's not a tsconfig.json and there is no tsconfig.json in the same directory
72
162
  if ((0, node_path_1.basename)(configFilePath) !== 'tsconfig.json' &&
73
163
  !siblingFiles.includes('tsconfig.json')) {
74
- return {};
164
+ return false;
75
165
  }
76
166
  // Do not create project for Next.js projects since they are not compatible with
77
167
  // project references and typecheck will fail.
@@ -79,53 +169,14 @@ async function createNodesInternal(configFilePath, options, context, lockFileNam
79
169
  siblingFiles.includes('next.config.cjs') ||
80
170
  siblingFiles.includes('next.config.mjs') ||
81
171
  siblingFiles.includes('next.config.ts')) {
82
- return {};
172
+ return false;
83
173
  }
84
- /**
85
- * The cache key is composed by:
86
- * - hashes of the content of the relevant files that can affect what's inferred by the plugin:
87
- * - current config file
88
- * - config files extended by the current config file (recursively up to the root config file)
89
- * - referenced config files that are internal to the owning Nx project of the current config file, or is a shallow external reference of the owning Nx project
90
- * - lock file
91
- * - hash of the plugin options
92
- * - current config file path
93
- */
94
- const tsConfig = readCachedTsConfig(fullConfigPath);
95
- const extendedConfigFiles = getExtendedConfigFiles(fullConfigPath, tsConfig);
96
- const internalReferencedFiles = resolveInternalProjectReferences(tsConfig, context.workspaceRoot, projectRoot);
97
- const externalProjectReferences = resolveShallowExternalProjectReferences(tsConfig, context.workspaceRoot, projectRoot);
98
- const packageJsonPath = (0, devkit_1.joinPathFragments)(projectRoot, 'package.json');
99
- const packageJson = (0, node_fs_1.existsSync)(packageJsonPath)
100
- ? (0, devkit_1.readJsonFile)(packageJsonPath)
101
- : null;
102
- const nodeHash = (0, file_hasher_1.hashArray)([
103
- ...[
104
- fullConfigPath,
105
- ...extendedConfigFiles.files,
106
- ...Object.keys(internalReferencedFiles),
107
- ...Object.keys(externalProjectReferences),
108
- (0, node_path_1.join)(context.workspaceRoot, lockFileName),
109
- ].map(file_hasher_1.hashFile),
110
- (0, file_hasher_1.hashObject)(options),
111
- ...(packageJson ? [(0, file_hasher_1.hashObject)(packageJson)] : []),
112
- ]);
113
- const cacheKey = `${nodeHash}_${configFilePath}`;
114
- targetsCache[cacheKey] ??= buildTscTargets(fullConfigPath, projectRoot, options, context);
115
- const { targets } = targetsCache[cacheKey];
116
- return {
117
- projects: {
118
- [projectRoot]: {
119
- projectType: 'library',
120
- targets,
121
- },
122
- },
123
- };
174
+ return true;
124
175
  }
125
176
  function buildTscTargets(configFilePath, projectRoot, options, context) {
126
177
  const targets = {};
127
178
  const namedInputs = (0, get_named_inputs_1.getNamedInputs)(projectRoot, context);
128
- const tsConfig = readCachedTsConfig(configFilePath);
179
+ const tsConfig = readCachedTsConfig(configFilePath, context.workspaceRoot);
129
180
  let internalProjectReferences;
130
181
  // Typecheck target
131
182
  if ((0, node_path_1.basename)(configFilePath) === 'tsconfig.json' && options.typecheck) {
@@ -196,7 +247,7 @@ function buildTscTargets(configFilePath, projectRoot, options, context) {
196
247
  function getInputs(namedInputs, configFilePath, tsConfig, internalProjectReferences, workspaceRoot, projectRoot) {
197
248
  const configFiles = new Set();
198
249
  const externalDependencies = ['typescript'];
199
- const extendedConfigFiles = getExtendedConfigFiles(configFilePath, tsConfig);
250
+ const extendedConfigFiles = getExtendedConfigFiles(configFilePath, tsConfig, workspaceRoot);
200
251
  extendedConfigFiles.files.forEach((configPath) => {
201
252
  configFiles.add(configPath);
202
253
  });
@@ -294,7 +345,9 @@ function getOutputs(configFilePath, tsConfig, internalProjectReferences, workspa
294
345
  outputs.add(pathToInputOrOutput((0, devkit_1.joinPathFragments)(config.options.outDir, relativeRootDir, `*.tsbuildinfo`), workspaceRoot, projectRoot));
295
346
  }
296
347
  }
297
- else if (config.fileNames.length) {
348
+ else if (config.raw?.include?.length ||
349
+ config.raw?.files?.length ||
350
+ (!config.raw?.include && !config.raw?.files)) {
298
351
  // tsc produce files in place when no outDir or outFile is set
299
352
  outputs.add((0, devkit_1.joinPathFragments)('{projectRoot}', '**/*.js'));
300
353
  outputs.add((0, devkit_1.joinPathFragments)('{projectRoot}', '**/*.cjs'));
@@ -407,7 +460,7 @@ function pathToInputOrOutput(path, workspaceRoot, projectRoot) {
407
460
  }
408
461
  return (0, devkit_1.joinPathFragments)('{projectRoot}', pathRelativeToProjectRoot);
409
462
  }
410
- function getExtendedConfigFiles(tsConfigPath, tsConfig) {
463
+ function getExtendedConfigFiles(tsConfigPath, tsConfig, workspaceRoot) {
411
464
  const extendedConfigFiles = new Set();
412
465
  const extendedExternalPackages = new Set();
413
466
  let currentConfigPath = tsConfigPath;
@@ -422,7 +475,7 @@ function getExtendedConfigFiles(tsConfigPath, tsConfig) {
422
475
  break;
423
476
  }
424
477
  extendedConfigFiles.add(extendedConfigPath.filePath);
425
- currentConfig = readCachedTsConfig(extendedConfigPath.filePath);
478
+ currentConfig = readCachedTsConfig(extendedConfigPath.filePath, workspaceRoot);
426
479
  currentConfigPath = extendedConfigPath.filePath;
427
480
  }
428
481
  return {
@@ -431,27 +484,31 @@ function getExtendedConfigFiles(tsConfigPath, tsConfig) {
431
484
  };
432
485
  }
433
486
  function resolveInternalProjectReferences(tsConfig, workspaceRoot, projectRoot, projectReferences = {}) {
434
- walkProjectReferences(tsConfig, workspaceRoot, projectRoot, (configPath, config) => {
435
- if (isExternalProjectReference(configPath, workspaceRoot, projectRoot)) {
436
- return false;
487
+ if (!tsConfig.projectReferences?.length) {
488
+ return {};
489
+ }
490
+ for (const ref of tsConfig.projectReferences) {
491
+ let refConfigPath = ref.path;
492
+ if (projectReferences[refConfigPath]) {
493
+ // Already resolved
494
+ continue;
437
495
  }
438
- else {
439
- projectReferences[configPath] = config;
496
+ if (!(0, node_fs_1.existsSync)(refConfigPath)) {
497
+ // the referenced tsconfig doesn't exist, ignore it
498
+ continue;
440
499
  }
441
- });
442
- return projectReferences;
443
- }
444
- function resolveShallowExternalProjectReferences(tsConfig, workspaceRoot, projectRoot, projectReferences = {}) {
445
- walkProjectReferences(tsConfig, workspaceRoot, projectRoot, (configPath, config) => {
446
- if (isExternalProjectReference(configPath, workspaceRoot, projectRoot)) {
447
- projectReferences[configPath] = config;
500
+ if (isExternalProjectReference(refConfigPath, workspaceRoot, projectRoot)) {
501
+ continue;
448
502
  }
449
- return false;
450
- });
503
+ if (!refConfigPath.endsWith('.json')) {
504
+ refConfigPath = (0, node_path_1.join)(refConfigPath, 'tsconfig.json');
505
+ }
506
+ projectReferences[refConfigPath] = readCachedTsConfig(refConfigPath, workspaceRoot);
507
+ resolveInternalProjectReferences(projectReferences[refConfigPath], workspaceRoot, projectRoot, projectReferences);
508
+ }
451
509
  return projectReferences;
452
510
  }
453
- function walkProjectReferences(tsConfig, workspaceRoot, projectRoot, visitor, // false stops recursion
454
- projectReferences = {}) {
511
+ function resolveShallowExternalProjectReferences(tsConfig, workspaceRoot, projectRoot, projectReferences = {}) {
455
512
  if (!tsConfig.projectReferences?.length) {
456
513
  return projectReferences;
457
514
  }
@@ -465,13 +522,11 @@ projectReferences = {}) {
465
522
  // the referenced tsconfig doesn't exist, ignore it
466
523
  continue;
467
524
  }
468
- if (!refConfigPath.endsWith('.json')) {
469
- refConfigPath = (0, node_path_1.join)(refConfigPath, 'tsconfig.json');
470
- }
471
- const refTsConfig = readCachedTsConfig(refConfigPath);
472
- const result = visitor(refConfigPath, refTsConfig);
473
- if (result !== false) {
474
- walkProjectReferences(refTsConfig, workspaceRoot, projectRoot, visitor);
525
+ if (isExternalProjectReference(refConfigPath, workspaceRoot, projectRoot)) {
526
+ if (!refConfigPath.endsWith('.json')) {
527
+ refConfigPath = (0, node_path_1.join)(refConfigPath, 'tsconfig.json');
528
+ }
529
+ projectReferences[refConfigPath] = readCachedTsConfig(refConfigPath, workspaceRoot);
475
530
  }
476
531
  }
477
532
  return projectReferences;
@@ -497,7 +552,7 @@ function hasExternalProjectReferences(tsConfigPath, tsConfig, workspaceRoot, pro
497
552
  if (!refConfigPath.endsWith('.json')) {
498
553
  refConfigPath = (0, node_path_1.join)(refConfigPath, 'tsconfig.json');
499
554
  }
500
- const refTsConfig = readCachedTsConfig(refConfigPath);
555
+ const refTsConfig = readCachedTsConfig(refConfigPath, workspaceRoot);
501
556
  const result = hasExternalProjectReferences(refConfigPath, refTsConfig, workspaceRoot, projectRoot, seen);
502
557
  if (result) {
503
558
  return true;
@@ -528,19 +583,32 @@ function getTsConfigDirName(tsConfigPath) {
528
583
  ? (0, node_path_1.dirname)(tsConfigPath)
529
584
  : (0, node_path_1.normalize)(tsConfigPath);
530
585
  }
531
- const tsConfigCache = new Map();
532
- function readCachedTsConfig(tsConfigPath) {
533
- const cacheKey = getTsConfigCacheKey(tsConfigPath);
534
- if (tsConfigCache.has(cacheKey)) {
535
- return tsConfigCache.get(cacheKey);
536
- }
537
- const tsConfig = (0, ts_config_1.readTsConfig)(tsConfigPath);
538
- tsConfigCache.set(cacheKey, tsConfig);
586
+ function readCachedTsConfig(tsConfigPath, workspaceRoot) {
587
+ const relativeTsConfigPath = posix.relative(workspaceRoot, tsConfigPath);
588
+ const timestamp = (0, node_fs_1.statSync)(tsConfigPath).mtimeMs;
589
+ if (tsConfigCache[relativeTsConfigPath]?.timestamp === timestamp) {
590
+ return tsConfigCache[relativeTsConfigPath].data;
591
+ }
592
+ const tsConfig = readTsConfig(tsConfigPath);
593
+ tsConfigCache[relativeTsConfigPath] = {
594
+ data: {
595
+ options: tsConfig.options,
596
+ projectReferences: tsConfig.projectReferences,
597
+ raw: tsConfig.raw,
598
+ },
599
+ timestamp,
600
+ };
539
601
  return tsConfig;
540
602
  }
541
- function getTsConfigCacheKey(tsConfigPath) {
542
- const timestamp = (0, node_fs_1.statSync)(tsConfigPath).mtimeMs;
543
- return `${tsConfigPath}-${timestamp}`;
603
+ let ts;
604
+ function readTsConfig(tsConfigPath) {
605
+ if (!ts) {
606
+ ts = require('typescript');
607
+ }
608
+ const readResult = ts.readConfigFile(tsConfigPath, ts.sys.readFile);
609
+ // read with a custom host that won't read directories which is only used
610
+ // to identify the filenames included in the program, which we won't use
611
+ return ts.parseJsonConfigFileContent(readResult.config, { ...ts.sys, readDirectory: () => [] }, (0, node_path_1.dirname)(tsConfigPath));
544
612
  }
545
613
  function normalizePluginOptions(pluginOptions = {}) {
546
614
  const defaultTypecheckTargetName = 'typecheck';
@@ -6,4 +6,5 @@ export declare function findNpmDependencies(workspaceRoot: string, sourceProject
6
6
  includeTransitiveDependencies?: boolean;
7
7
  ignoredFiles?: string[];
8
8
  useLocalPathsForWorkspaceDependencies?: boolean;
9
+ runtimeHelpers?: string[];
9
10
  }): Record<string, string>;
@@ -22,7 +22,7 @@ function findNpmDependencies(workspaceRoot, sourceProject, projectGraph, project
22
22
  return;
23
23
  seen?.add(currentProject.name);
24
24
  collectDependenciesFromFileMap(workspaceRoot, currentProject, projectGraph, projectFileMap, buildTarget, options.ignoredFiles, options.useLocalPathsForWorkspaceDependencies, collectedDeps);
25
- collectHelperDependencies(workspaceRoot, currentProject, projectGraph, buildTarget, collectedDeps);
25
+ collectHelperDependencies(workspaceRoot, currentProject, projectGraph, buildTarget, options.runtimeHelpers, collectedDeps);
26
26
  if (options.includeTransitiveDependencies) {
27
27
  const projectDeps = projectGraph.dependencies[currentProject.name];
28
28
  for (const dep of projectDeps) {
@@ -114,7 +114,17 @@ function readPackageJson(project, workspaceRoot) {
114
114
  return (0, devkit_1.readJsonFile)(packageJsonPath);
115
115
  return null;
116
116
  }
117
- function collectHelperDependencies(workspaceRoot, sourceProject, projectGraph, buildTarget, npmDeps) {
117
+ function collectHelperDependencies(workspaceRoot, sourceProject, projectGraph, buildTarget, runtimeHelpers, npmDeps) {
118
+ if (runtimeHelpers?.length > 0) {
119
+ for (const helper of runtimeHelpers) {
120
+ if (!npmDeps[helper] &&
121
+ projectGraph.externalNodes[`npm:${helper}`]?.type === 'npm') {
122
+ npmDeps[helper] =
123
+ projectGraph.externalNodes[`npm:${helper}`].data.version;
124
+ }
125
+ }
126
+ return;
127
+ }
118
128
  const target = sourceProject.data.targets[buildTarget];
119
129
  if (!target)
120
130
  return;
@@ -78,10 +78,7 @@ async function execAsync(command, cwd) {
78
78
  return new Promise((resolve, reject) => {
79
79
  (0, child_process_1.exec)(command, { cwd, windowsHide: false }, (error, stdout, stderr) => {
80
80
  if (error) {
81
- return reject(error);
82
- }
83
- if (stderr) {
84
- return reject(stderr);
81
+ return reject((stderr ? `${stderr}\n` : '') + error);
85
82
  }
86
83
  return resolve(stdout.trim());
87
84
  });
@@ -1,4 +1,4 @@
1
1
  import { type Tree } from '@nx/devkit';
2
2
  export declare const defaultExclude: string[];
3
- export declare function addSwcConfig(tree: Tree, projectDir: string, type?: 'commonjs' | 'es6', supportTsx?: boolean): void;
3
+ export declare function addSwcConfig(tree: Tree, projectDir: string, type?: 'commonjs' | 'es6', supportTsx?: boolean, swcName?: string, additionalExcludes?: string[]): void;
4
4
  export declare function addSwcTestConfig(tree: Tree, projectDir: string, type?: 'commonjs' | 'es6', supportTsx?: boolean): void;
@@ -43,11 +43,11 @@ const swcOptionsString = (type = 'commonjs', exclude, supportTsx) => `{
43
43
  "exclude": ${JSON.stringify(exclude)}
44
44
  }
45
45
  `;
46
- function addSwcConfig(tree, projectDir, type = 'commonjs', supportTsx = false) {
47
- const swcrcPath = (0, path_1.join)(projectDir, '.swcrc');
46
+ function addSwcConfig(tree, projectDir, type = 'commonjs', supportTsx = false, swcName = '.swcrc', additionalExcludes = []) {
47
+ const swcrcPath = (0, path_1.join)(projectDir, swcName);
48
48
  if (tree.exists(swcrcPath))
49
49
  return;
50
- tree.write(swcrcPath, swcOptionsString(type, exports.defaultExclude, supportTsx));
50
+ tree.write(swcrcPath, swcOptionsString(type, [...exports.defaultExclude, ...additionalExcludes], supportTsx));
51
51
  }
52
52
  function addSwcTestConfig(tree, projectDir, type = 'commonjs', supportTsx = false) {
53
53
  const swcrcPath = (0, path_1.join)(projectDir, '.spec.swcrc');