@nx/devkit 0.0.0-pr-31222-862e973 → 0.0.0-pr-31313-387cdca
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/LICENSE +1 -1
- package/README.md +1 -1
- package/migrations.json +1 -14
- package/package.json +5 -6
- package/src/executors/parse-target-string.d.ts +0 -4
- package/src/executors/read-target-options.js +3 -3
- package/src/generators/artifact-name-and-directory-utils.d.ts +23 -18
- package/src/generators/artifact-name-and-directory-utils.js +79 -205
- package/src/generators/format-files.d.ts +7 -1
- package/src/generators/format-files.js +17 -2
- package/src/generators/project-name-and-root-utils.d.ts +11 -16
- package/src/generators/project-name-and-root-utils.js +68 -230
- package/src/generators/prompt.d.ts +2 -0
- package/src/generators/prompt.js +14 -0
- package/src/generators/target-defaults-utils.js +1 -1
- package/src/generators/update-ts-configs-to-js.js +17 -22
- package/src/tasks/install-packages-task.js +1 -1
- package/src/utils/add-plugin.js +20 -8
- package/src/utils/async-iterable/create-async-iterable.d.ts +1 -0
- package/src/utils/async-iterable/create-async-iterable.js +10 -0
- package/src/utils/binary-extensions.js +1 -0
- package/src/utils/calculate-hash-for-create-nodes.d.ts +1 -0
- package/src/utils/calculate-hash-for-create-nodes.js +13 -0
- package/src/utils/config-utils.js +61 -33
- package/src/utils/package-json.js +12 -8
- package/src/utils/replace-package.js +1 -0
- package/src/utils/versions.d.ts +1 -1
- package/src/utils/versions.js +1 -1
- package/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.d.ts +0 -2
- package/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.js +0 -9
- package/src/migrations/update-16-9-0/migrate-mf-util-usage.d.ts +0 -3
- package/src/migrations/update-16-9-0/migrate-mf-util-usage.js +0 -200
|
@@ -5,37 +5,59 @@ exports.loadConfigFile = loadConfigFile;
|
|
|
5
5
|
exports.getRootTsConfigPath = getRootTsConfigPath;
|
|
6
6
|
exports.getRootTsConfigFileName = getRootTsConfigFileName;
|
|
7
7
|
exports.clearRequireCache = clearRequireCache;
|
|
8
|
-
const path_1 = require("path");
|
|
9
8
|
const fs_1 = require("fs");
|
|
10
9
|
const node_url_1 = require("node:url");
|
|
11
10
|
const devkit_exports_1 = require("nx/src/devkit-exports");
|
|
12
11
|
const devkit_internals_1 = require("nx/src/devkit-internals");
|
|
12
|
+
const path_1 = require("path");
|
|
13
13
|
exports.dynamicImport = new Function('modulePath', 'return import(modulePath);');
|
|
14
14
|
async function loadConfigFile(configFilePath) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
15
|
+
const extension = (0, path_1.extname)(configFilePath);
|
|
16
|
+
const module = await loadModule(configFilePath, extension);
|
|
17
|
+
return module.default ?? module;
|
|
18
|
+
}
|
|
19
|
+
async function loadModule(path, extension) {
|
|
20
|
+
if (isTypeScriptFile(extension)) {
|
|
21
|
+
return await loadTypeScriptModule(path, extension);
|
|
22
|
+
}
|
|
23
|
+
return await loadJavaScriptModule(path, extension);
|
|
24
|
+
}
|
|
25
|
+
function isTypeScriptFile(extension) {
|
|
26
|
+
return extension.endsWith('ts');
|
|
27
|
+
}
|
|
28
|
+
async function loadTypeScriptModule(path, extension) {
|
|
29
|
+
const tsConfigPath = getTypeScriptConfigPath(path);
|
|
30
|
+
if (tsConfigPath) {
|
|
31
|
+
const unregisterTsProject = (0, devkit_internals_1.registerTsProject)(tsConfigPath);
|
|
32
|
+
try {
|
|
33
|
+
return await loadModuleByExtension(path, extension);
|
|
34
34
|
}
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
finally {
|
|
36
|
+
unregisterTsProject();
|
|
37
37
|
}
|
|
38
|
-
|
|
38
|
+
}
|
|
39
|
+
return await loadModuleByExtension(path, extension);
|
|
40
|
+
}
|
|
41
|
+
function getTypeScriptConfigPath(path) {
|
|
42
|
+
const siblingFiles = (0, fs_1.readdirSync)((0, path_1.dirname)(path));
|
|
43
|
+
return siblingFiles.includes('tsconfig.json')
|
|
44
|
+
? (0, path_1.join)((0, path_1.dirname)(path), 'tsconfig.json')
|
|
45
|
+
: getRootTsConfigPath();
|
|
46
|
+
}
|
|
47
|
+
async function loadJavaScriptModule(path, extension) {
|
|
48
|
+
return await loadModuleByExtension(path, extension);
|
|
49
|
+
}
|
|
50
|
+
async function loadModuleByExtension(path, extension) {
|
|
51
|
+
switch (extension) {
|
|
52
|
+
case '.cts':
|
|
53
|
+
case '.cjs':
|
|
54
|
+
return await loadCommonJS(path);
|
|
55
|
+
case '.mjs':
|
|
56
|
+
return await loadESM(path);
|
|
57
|
+
default:
|
|
58
|
+
// For both .ts and .mts files, try to load them as CommonJS first, then try ESM.
|
|
59
|
+
// It's possible that the file is written like ESM (e.g. using `import`) but uses CJS features like `__dirname` or `__filename`.
|
|
60
|
+
return await load(path);
|
|
39
61
|
}
|
|
40
62
|
}
|
|
41
63
|
function getRootTsConfigPath() {
|
|
@@ -62,26 +84,32 @@ function clearRequireCache() {
|
|
|
62
84
|
}
|
|
63
85
|
}
|
|
64
86
|
}
|
|
65
|
-
/**
|
|
66
|
-
* Load the module after ensuring that the require cache is cleared.
|
|
67
|
-
*/
|
|
68
87
|
async function load(path) {
|
|
69
|
-
// Clear cache if the path is in the cache
|
|
70
|
-
if (require.cache[path]) {
|
|
71
|
-
clearRequireCache();
|
|
72
|
-
}
|
|
73
88
|
try {
|
|
74
89
|
// Try using `require` first, which works for CJS modules.
|
|
75
90
|
// Modules are CJS unless it is named `.mjs` or `package.json` sets type to "module".
|
|
76
|
-
return
|
|
91
|
+
return loadCommonJS(path);
|
|
77
92
|
}
|
|
78
93
|
catch (e) {
|
|
79
94
|
if (e.code === 'ERR_REQUIRE_ESM') {
|
|
80
95
|
// If `require` fails to load ESM, try dynamic `import()`. ESM requires file url protocol for handling absolute paths.
|
|
81
|
-
|
|
82
|
-
return await (0, exports.dynamicImport)(`${pathAsFileUrl}?t=${Date.now()}`);
|
|
96
|
+
return loadESM(path);
|
|
83
97
|
}
|
|
84
98
|
// Re-throw all other errors
|
|
85
99
|
throw e;
|
|
86
100
|
}
|
|
87
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* Load the module after ensuring that the require cache is cleared.
|
|
104
|
+
*/
|
|
105
|
+
async function loadCommonJS(path) {
|
|
106
|
+
// Clear cache if the path is in the cache
|
|
107
|
+
if (require.cache[path]) {
|
|
108
|
+
clearRequireCache();
|
|
109
|
+
}
|
|
110
|
+
return require(path);
|
|
111
|
+
}
|
|
112
|
+
async function loadESM(path) {
|
|
113
|
+
const pathAsFileUrl = (0, node_url_1.pathToFileURL)(path).pathname;
|
|
114
|
+
return await (0, exports.dynamicImport)(`${pathAsFileUrl}?t=${Date.now()}`);
|
|
115
|
+
}
|
|
@@ -176,14 +176,18 @@ function removeDependenciesFromPackageJson(tree, dependencies, devDependencies,
|
|
|
176
176
|
const currentPackageJson = (0, devkit_exports_1.readJson)(tree, packageJsonPath);
|
|
177
177
|
if (requiresRemovingOfPackages(currentPackageJson, dependencies, devDependencies)) {
|
|
178
178
|
(0, devkit_exports_1.updateJson)(tree, packageJsonPath, (json) => {
|
|
179
|
-
|
|
180
|
-
|
|
179
|
+
if (json.dependencies) {
|
|
180
|
+
for (const dep of dependencies) {
|
|
181
|
+
delete json.dependencies[dep];
|
|
182
|
+
}
|
|
183
|
+
json.dependencies = sortObjectByKeys(json.dependencies);
|
|
181
184
|
}
|
|
182
|
-
|
|
183
|
-
|
|
185
|
+
if (json.devDependencies) {
|
|
186
|
+
for (const devDep of devDependencies) {
|
|
187
|
+
delete json.devDependencies[devDep];
|
|
188
|
+
}
|
|
189
|
+
json.devDependencies = sortObjectByKeys(json.devDependencies);
|
|
184
190
|
}
|
|
185
|
-
json.dependencies = sortObjectByKeys(json.dependencies);
|
|
186
|
-
json.devDependencies = sortObjectByKeys(json.devDependencies);
|
|
187
191
|
return json;
|
|
188
192
|
});
|
|
189
193
|
}
|
|
@@ -305,7 +309,7 @@ function ensurePackage(pkgOrTree, requiredVersionOrPackage, maybeRequiredVersion
|
|
|
305
309
|
(0, child_process_1.execSync)(preInstallCommand, {
|
|
306
310
|
cwd: tempDir,
|
|
307
311
|
stdio: isVerbose ? 'inherit' : 'ignore',
|
|
308
|
-
windowsHide:
|
|
312
|
+
windowsHide: false,
|
|
309
313
|
});
|
|
310
314
|
}
|
|
311
315
|
let addCommand = (0, devkit_exports_1.getPackageManagerCommand)(packageManager).addDev;
|
|
@@ -315,7 +319,7 @@ function ensurePackage(pkgOrTree, requiredVersionOrPackage, maybeRequiredVersion
|
|
|
315
319
|
(0, child_process_1.execSync)(`${addCommand} ${pkg}@${requiredVersion}`, {
|
|
316
320
|
cwd: tempDir,
|
|
317
321
|
stdio: isVerbose ? 'inherit' : 'ignore',
|
|
318
|
-
windowsHide:
|
|
322
|
+
windowsHide: false,
|
|
319
323
|
});
|
|
320
324
|
addToNodePath((0, path_1.join)(devkit_exports_1.workspaceRoot, 'node_modules'));
|
|
321
325
|
addToNodePath((0, path_1.join)(tempDir, 'node_modules'));
|
package/src/utils/versions.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const typescriptVersion = "~5.
|
|
1
|
+
export declare const typescriptVersion = "~5.7.2";
|
package/src/utils/versions.js
CHANGED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.default = replacePackage;
|
|
4
|
-
const format_files_1 = require("../../generators/format-files");
|
|
5
|
-
const replace_package_1 = require("../../utils/replace-package");
|
|
6
|
-
async function replacePackage(tree) {
|
|
7
|
-
await (0, replace_package_1.replaceNrwlPackageWithNxPackage)(tree, '@nrwl/devkit', '@nx/devkit');
|
|
8
|
-
await (0, format_files_1.formatFiles)(tree);
|
|
9
|
-
}
|
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const visit_not_ignored_files_1 = require("../../generators/visit-not-ignored-files");
|
|
4
|
-
const format_files_1 = require("../../generators/format-files");
|
|
5
|
-
const package_json_1 = require("../../utils/package-json");
|
|
6
|
-
const versions_1 = require("../../utils/versions");
|
|
7
|
-
const devkit_exports_1 = require("nx/src/devkit-exports");
|
|
8
|
-
let tsModule;
|
|
9
|
-
const MODULE_FEDERATION_PUBLIC_TOKENS = [
|
|
10
|
-
'AdditionalSharedConfig',
|
|
11
|
-
'ModuleFederationConfig',
|
|
12
|
-
'SharedLibraryConfig',
|
|
13
|
-
'SharedWorkspaceLibraryConfig',
|
|
14
|
-
'WorkspaceLibrary',
|
|
15
|
-
'SharedFunction',
|
|
16
|
-
'WorkspaceLibrarySecondaryEntryPoint',
|
|
17
|
-
'Remotes',
|
|
18
|
-
'ModuleFederationLibrary',
|
|
19
|
-
'applySharedFunction',
|
|
20
|
-
'applyAdditionalShared',
|
|
21
|
-
'getNpmPackageSharedConfig',
|
|
22
|
-
'shareWorkspaceLibraries',
|
|
23
|
-
'sharePackages',
|
|
24
|
-
'mapRemotes',
|
|
25
|
-
'mapRemotesForSSR',
|
|
26
|
-
'getDependentPackagesForProject',
|
|
27
|
-
'readRootPackageJson',
|
|
28
|
-
];
|
|
29
|
-
exports.default = async (tree) => {
|
|
30
|
-
let hasFileToMigrate = false;
|
|
31
|
-
(0, visit_not_ignored_files_1.visitNotIgnoredFiles)(tree, '/', (path) => {
|
|
32
|
-
if (!path.endsWith('.ts') && !path.endsWith('.js')) {
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
let fileContents = tree.read(path, 'utf-8');
|
|
36
|
-
if (MODULE_FEDERATION_PUBLIC_TOKENS.every((token) => !fileContents.includes(token))) {
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
hasFileToMigrate = true;
|
|
40
|
-
fileContents = replaceTSImports(tree, path, fileContents);
|
|
41
|
-
fileContents = replaceRequireCalls(tree, path, fileContents);
|
|
42
|
-
fileContents = replaceJSDoc(tree, path, fileContents);
|
|
43
|
-
tree.write(path, fileContents);
|
|
44
|
-
});
|
|
45
|
-
if (hasFileToMigrate) {
|
|
46
|
-
await (0, format_files_1.formatFiles)(tree);
|
|
47
|
-
const pkgJson = (0, devkit_exports_1.readJson)(tree, 'package.json');
|
|
48
|
-
const nxVersion = pkgJson.devDependencies?.['nx'] ??
|
|
49
|
-
pkgJson.dependencies?.['nx'] ??
|
|
50
|
-
'17.0.0';
|
|
51
|
-
return (0, package_json_1.addDependenciesToPackageJson)(tree, {}, { '@nx/webpack': nxVersion });
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
function replaceJSDoc(tree, path, fileContents) {
|
|
55
|
-
let newFileContents = fileContents;
|
|
56
|
-
for (const token of MODULE_FEDERATION_PUBLIC_TOKENS) {
|
|
57
|
-
newFileContents = newFileContents.replaceAll(new RegExp(`(@type)+\\s({)+(\\s)*(import\\(('|")+@nx\/devkit('|")+\\)\.)+(${token})+\\s*(})+`, 'g'), `@type {import('@nx/webpack').${token}}`);
|
|
58
|
-
}
|
|
59
|
-
return newFileContents;
|
|
60
|
-
}
|
|
61
|
-
function replaceRequireCalls(tree, path, fileContents) {
|
|
62
|
-
if (!tsModule) {
|
|
63
|
-
tsModule = (0, package_json_1.ensurePackage)('typescript', versions_1.typescriptVersion);
|
|
64
|
-
}
|
|
65
|
-
const sourceFile = tsModule.createSourceFile(path, fileContents, tsModule.ScriptTarget.Latest, true);
|
|
66
|
-
const allDevkitRequires = findNodes(sourceFile, tsModule.SyntaxKind.VariableStatement)
|
|
67
|
-
.filter((node) => [`require("@nx/devkit")`, `require('@nx/devkit')`].some((r) => node.getText().includes(r)))
|
|
68
|
-
.filter((node) => findNodes(node, tsModule.SyntaxKind.ObjectBindingPattern).length);
|
|
69
|
-
const mfUtilRequires = allDevkitRequires.filter((node) => MODULE_FEDERATION_PUBLIC_TOKENS.some((token) => node.getText().includes(token)));
|
|
70
|
-
if (!mfUtilRequires.length) {
|
|
71
|
-
return fileContents;
|
|
72
|
-
}
|
|
73
|
-
const mfUtilTokens = mfUtilRequires.map((node) => {
|
|
74
|
-
const allTokens = findNodes(node, tsModule.SyntaxKind.BindingElement);
|
|
75
|
-
const mfTokens = allTokens.filter((node) => MODULE_FEDERATION_PUBLIC_TOKENS.some((token) => node.getText() === token));
|
|
76
|
-
return {
|
|
77
|
-
requireNode: node,
|
|
78
|
-
onlyMf: allTokens.length === mfTokens.length,
|
|
79
|
-
mfTokens,
|
|
80
|
-
};
|
|
81
|
-
});
|
|
82
|
-
const changes = [];
|
|
83
|
-
for (const mfUtilRequireData of mfUtilTokens) {
|
|
84
|
-
if (mfUtilRequireData.onlyMf) {
|
|
85
|
-
changes.push({
|
|
86
|
-
startPosition: mfUtilRequireData.requireNode.getStart(),
|
|
87
|
-
endPosition: mfUtilRequireData.requireNode.getEnd(),
|
|
88
|
-
content: '',
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
else {
|
|
92
|
-
for (const mfToken of mfUtilRequireData.mfTokens) {
|
|
93
|
-
const replaceTrailingComma = mfToken.getText().charAt(mfToken.getEnd() + 1) === ',';
|
|
94
|
-
changes.push({
|
|
95
|
-
startPosition: mfToken.getStart(),
|
|
96
|
-
endPosition: replaceTrailingComma
|
|
97
|
-
? mfToken.getEnd() + 1
|
|
98
|
-
: mfToken.getEnd(),
|
|
99
|
-
content: '',
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
changes.push({
|
|
105
|
-
startPosition: mfUtilTokens[mfUtilTokens.length - 1].requireNode.getEnd(),
|
|
106
|
-
content: `\nconst { ${mfUtilTokens
|
|
107
|
-
.map((mfUtilToken) => mfUtilToken.mfTokens.map((node) => node.getText()))
|
|
108
|
-
.join(', ')} } = require('@nx/webpack');`,
|
|
109
|
-
});
|
|
110
|
-
let newFileContents = fileContents;
|
|
111
|
-
while (changes.length) {
|
|
112
|
-
const change = changes.pop();
|
|
113
|
-
newFileContents = `${newFileContents.substring(0, change.startPosition)}${change.content}${newFileContents.substring(change.endPosition ? change.endPosition : change.startPosition)}`;
|
|
114
|
-
}
|
|
115
|
-
return newFileContents;
|
|
116
|
-
}
|
|
117
|
-
function replaceTSImports(tree, path, fileContents) {
|
|
118
|
-
if (!tsModule) {
|
|
119
|
-
tsModule = (0, package_json_1.ensurePackage)('typescript', versions_1.typescriptVersion);
|
|
120
|
-
}
|
|
121
|
-
const sourceFile = tsModule.createSourceFile(path, fileContents, tsModule.ScriptTarget.Latest, true);
|
|
122
|
-
const allImports = findNodes(sourceFile, tsModule.SyntaxKind.ImportDeclaration);
|
|
123
|
-
const devkitImports = allImports.filter((i) => i.getText().includes(`'@nx/devkit';`));
|
|
124
|
-
const mfUtilsImports = devkitImports.filter((i) => MODULE_FEDERATION_PUBLIC_TOKENS.some((token) => i.getText().includes(token)));
|
|
125
|
-
if (!mfUtilsImports.length) {
|
|
126
|
-
return fileContents;
|
|
127
|
-
}
|
|
128
|
-
const mfUtilsWithMultipleImports = mfUtilsImports.map((i) => {
|
|
129
|
-
const importSpecifierNodes = findNodes(i, tsModule.SyntaxKind.ImportSpecifier);
|
|
130
|
-
const mfImportSpecifierNodes = importSpecifierNodes.filter((node) => MODULE_FEDERATION_PUBLIC_TOKENS.some((token) => node.getText().includes(token)));
|
|
131
|
-
return {
|
|
132
|
-
importDeclarationNode: i,
|
|
133
|
-
onlyMf: mfImportSpecifierNodes.length === importSpecifierNodes.length,
|
|
134
|
-
mfImportSpecifierNodes,
|
|
135
|
-
};
|
|
136
|
-
});
|
|
137
|
-
const changes = [];
|
|
138
|
-
for (const importDeclaration of mfUtilsWithMultipleImports) {
|
|
139
|
-
if (importDeclaration.onlyMf) {
|
|
140
|
-
changes.push({
|
|
141
|
-
startPosition: importDeclaration.importDeclarationNode.getStart(),
|
|
142
|
-
endPosition: importDeclaration.importDeclarationNode.getEnd(),
|
|
143
|
-
content: '',
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
else {
|
|
147
|
-
for (const mfImportSpecifierNodes of importDeclaration.mfImportSpecifierNodes) {
|
|
148
|
-
const replaceTrailingComma = importDeclaration.importDeclarationNode
|
|
149
|
-
.getText()
|
|
150
|
-
.charAt(mfImportSpecifierNodes.getEnd() + 1) === ',';
|
|
151
|
-
changes.push({
|
|
152
|
-
startPosition: mfImportSpecifierNodes.getStart(),
|
|
153
|
-
endPosition: replaceTrailingComma
|
|
154
|
-
? mfImportSpecifierNodes.getEnd() + 1
|
|
155
|
-
: mfImportSpecifierNodes.getEnd(),
|
|
156
|
-
content: '',
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
changes.push({
|
|
162
|
-
startPosition: mfUtilsWithMultipleImports[mfUtilsWithMultipleImports.length - 1].importDeclarationNode.getEnd(),
|
|
163
|
-
content: `\nimport { ${mfUtilsWithMultipleImports
|
|
164
|
-
.map((importDeclaration) => importDeclaration.mfImportSpecifierNodes.map((node) => node.getText()))
|
|
165
|
-
.join(', ')} } from '@nx/webpack';`,
|
|
166
|
-
});
|
|
167
|
-
let newFileContents = fileContents;
|
|
168
|
-
while (changes.length) {
|
|
169
|
-
const change = changes.pop();
|
|
170
|
-
newFileContents = `${newFileContents.substring(0, change.startPosition)}${change.content}${newFileContents.substring(change.endPosition ? change.endPosition : change.startPosition)}`;
|
|
171
|
-
}
|
|
172
|
-
return newFileContents;
|
|
173
|
-
}
|
|
174
|
-
function findNodes(node, kind, max = Infinity) {
|
|
175
|
-
if (!node || max == 0) {
|
|
176
|
-
return [];
|
|
177
|
-
}
|
|
178
|
-
const arr = [];
|
|
179
|
-
const hasMatch = Array.isArray(kind)
|
|
180
|
-
? kind.includes(node.kind)
|
|
181
|
-
: node.kind === kind;
|
|
182
|
-
if (hasMatch) {
|
|
183
|
-
arr.push(node);
|
|
184
|
-
max--;
|
|
185
|
-
}
|
|
186
|
-
if (max > 0) {
|
|
187
|
-
for (const child of node.getChildren()) {
|
|
188
|
-
findNodes(child, kind, max).forEach((node) => {
|
|
189
|
-
if (max > 0) {
|
|
190
|
-
arr.push(node);
|
|
191
|
-
}
|
|
192
|
-
max--;
|
|
193
|
-
});
|
|
194
|
-
if (max <= 0) {
|
|
195
|
-
break;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
return arr;
|
|
200
|
-
}
|