@nx/eslint-plugin 0.0.0-pr-22179-271588f

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.
Files changed (48) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +68 -0
  3. package/migrations.json +18 -0
  4. package/package.json +54 -0
  5. package/src/configs/angular-template.d.ts +20 -0
  6. package/src/configs/angular-template.js +21 -0
  7. package/src/configs/angular.d.ts +25 -0
  8. package/src/configs/angular.js +27 -0
  9. package/src/configs/javascript.d.ts +62 -0
  10. package/src/configs/javascript.js +70 -0
  11. package/src/configs/react-base.d.ts +112 -0
  12. package/src/configs/react-base.js +141 -0
  13. package/src/configs/react-jsx.d.ts +71 -0
  14. package/src/configs/react-jsx.js +64 -0
  15. package/src/configs/react-tmp.d.ts +12 -0
  16. package/src/configs/react-tmp.js +17 -0
  17. package/src/configs/react-typescript.d.ts +40 -0
  18. package/src/configs/react-typescript.js +54 -0
  19. package/src/configs/typescript.d.ts +44 -0
  20. package/src/configs/typescript.js +53 -0
  21. package/src/constants.d.ts +13 -0
  22. package/src/constants.js +18 -0
  23. package/src/index.d.ts +1 -0
  24. package/src/index.js +34 -0
  25. package/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.d.ts +2 -0
  26. package/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.js +43 -0
  27. package/src/migrations/update-17-2-6-rename-workspace-rules/rename-workspace-rules.d.ts +2 -0
  28. package/src/migrations/update-17-2-6-rename-workspace-rules/rename-workspace-rules.js +29 -0
  29. package/src/resolve-workspace-rules.d.ts +4 -0
  30. package/src/resolve-workspace-rules.js +38 -0
  31. package/src/rules/dependency-checks.d.ts +17 -0
  32. package/src/rules/dependency-checks.js +240 -0
  33. package/src/rules/enforce-module-boundaries.d.ts +18 -0
  34. package/src/rules/enforce-module-boundaries.js +480 -0
  35. package/src/rules/nx-plugin-checks.d.ts +21 -0
  36. package/src/rules/nx-plugin-checks.js +392 -0
  37. package/src/utils/ast-utils.d.ts +12 -0
  38. package/src/utils/ast-utils.js +220 -0
  39. package/src/utils/config-utils.d.ts +6 -0
  40. package/src/utils/config-utils.js +18 -0
  41. package/src/utils/graph-utils.d.ts +6 -0
  42. package/src/utils/graph-utils.js +129 -0
  43. package/src/utils/package-json-utils.d.ts +4 -0
  44. package/src/utils/package-json-utils.js +37 -0
  45. package/src/utils/project-graph-utils.d.ts +10 -0
  46. package/src/utils/project-graph-utils.js +53 -0
  47. package/src/utils/runtime-lint-utils.d.ts +88 -0
  48. package/src/utils/runtime-lint-utils.js +365 -0
@@ -0,0 +1,392 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateVersionJsonExpression = exports.validatePackageGroup = exports.validateImplemenationNode = exports.validateEntry = exports.checkCollectionNode = exports.checkCollectionFileNode = exports.RULE_NAME = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const utils_1 = require("@typescript-eslint/utils");
6
+ const devkit_1 = require("@nx/devkit");
7
+ const runtime_lint_utils_1 = require("../utils/runtime-lint-utils");
8
+ const fs_1 = require("fs");
9
+ const internal_1 = require("@nx/js/src/internal");
10
+ const path = tslib_1.__importStar(require("path"));
11
+ const path_1 = require("path");
12
+ const project_graph_utils_1 = require("../utils/project-graph-utils");
13
+ const semver_1 = require("semver");
14
+ const DEFAULT_OPTIONS = {
15
+ generatorsJson: 'generators.json',
16
+ executorsJson: 'executors.json',
17
+ migrationsJson: 'migrations.json',
18
+ packageJson: 'package.json',
19
+ allowedVersionStrings: ['*', 'latest', 'next'],
20
+ };
21
+ exports.RULE_NAME = 'nx-plugin-checks';
22
+ exports.default = utils_1.ESLintUtils.RuleCreator(() => ``)({
23
+ name: exports.RULE_NAME,
24
+ meta: {
25
+ docs: {
26
+ description: 'Checks common nx-plugin configuration files for validity',
27
+ recommended: 'recommended',
28
+ },
29
+ schema: [
30
+ {
31
+ type: 'object',
32
+ properties: {
33
+ generatorsJson: {
34
+ type: 'string',
35
+ description: "The path to the project's generators.json file, relative to the project root",
36
+ },
37
+ executorsJson: {
38
+ type: 'string',
39
+ description: "The path to the project's executors.json file, relative to the project root",
40
+ },
41
+ migrationsJson: {
42
+ type: 'string',
43
+ description: "The path to the project's migrations.json file, relative to the project root",
44
+ },
45
+ packageJson: {
46
+ type: 'string',
47
+ description: "The path to the project's package.json file, relative to the project root",
48
+ },
49
+ allowedVersionStrings: {
50
+ type: 'array',
51
+ description: 'A list of specifiers that are valid for versions within package group. Defaults to ["*", "latest", "next"]',
52
+ items: { type: 'string' },
53
+ },
54
+ },
55
+ additionalProperties: false,
56
+ },
57
+ ],
58
+ type: 'problem',
59
+ messages: {
60
+ invalidSchemaPath: 'Schema path should point to a valid file',
61
+ invalidImplementationPath: '{{ key }}: Implementation path should point to a valid file',
62
+ invalidImplementationModule: '{{ key }}: Unable to find export {{ identifier }} in implementation module',
63
+ unableToReadImplementationExports: '{{ key }}: Unable to read exports for implementation module',
64
+ invalidVersion: '{{ key }}: Version should be a valid semver',
65
+ noGeneratorsOrSchematicsFound: 'Unable to find `generators` or `schematics` property',
66
+ noExecutorsOrBuildersFound: 'Unable to find `executors` or `builders` property',
67
+ valueShouldBeObject: '{{ key }} should be an object',
68
+ missingRequiredSchema: '{{ key }}: Missing required property - `schema`',
69
+ missingImplementation: '{{ key }}: Missing required property - `implementation`',
70
+ missingVersion: '{{ key }}: Missing required property - `version`',
71
+ },
72
+ },
73
+ defaultOptions: [DEFAULT_OPTIONS],
74
+ create(context) {
75
+ // jsonc-eslint-parser adds this property to parserServices where appropriate
76
+ if (!context.parserServices.isJSON) {
77
+ return {};
78
+ }
79
+ const { projectGraph, projectRootMappings } = (0, project_graph_utils_1.readProjectGraph)(exports.RULE_NAME);
80
+ const sourceFilePath = (0, runtime_lint_utils_1.getSourceFilePath)(context.getFilename(), devkit_1.workspaceRoot);
81
+ const sourceProject = (0, runtime_lint_utils_1.findProject)(projectGraph, projectRootMappings, sourceFilePath);
82
+ // If source is not part of an nx workspace, return.
83
+ if (!sourceProject) {
84
+ return {};
85
+ }
86
+ const options = normalizeOptions(sourceProject, context.options[0]);
87
+ context.options[0] = options;
88
+ const { generatorsJson, executorsJson, migrationsJson, packageJson } = options;
89
+ if (![generatorsJson, executorsJson, migrationsJson, packageJson].includes(sourceFilePath)) {
90
+ return {};
91
+ }
92
+ if (!global.tsProjectRegistered) {
93
+ (0, internal_1.registerTsProject)((0, path_1.join)(devkit_1.workspaceRoot, 'tsconfig.base.json'));
94
+ global.tsProjectRegistered = true;
95
+ }
96
+ return {
97
+ ['JSONExpressionStatement > JSONObjectExpression'](node) {
98
+ if (sourceFilePath === generatorsJson) {
99
+ checkCollectionFileNode(node, 'generator', context);
100
+ }
101
+ else if (sourceFilePath === migrationsJson) {
102
+ checkCollectionFileNode(node, 'migration', context);
103
+ }
104
+ else if (sourceFilePath === executorsJson) {
105
+ checkCollectionFileNode(node, 'executor', context);
106
+ }
107
+ else if (sourceFilePath === packageJson) {
108
+ validatePackageGroup(node, context);
109
+ }
110
+ },
111
+ };
112
+ },
113
+ });
114
+ function normalizeOptions(sourceProject, options) {
115
+ const base = { ...DEFAULT_OPTIONS, ...options };
116
+ const pathPrefix = sourceProject.data.root !== '.' ? `${sourceProject.data.root}/` : '';
117
+ return {
118
+ ...base,
119
+ executorsJson: base.executorsJson
120
+ ? `${pathPrefix}${base.executorsJson}`
121
+ : undefined,
122
+ generatorsJson: base.generatorsJson
123
+ ? `${pathPrefix}${base.generatorsJson}`
124
+ : undefined,
125
+ migrationsJson: base.migrationsJson
126
+ ? `${pathPrefix}${base.migrationsJson}`
127
+ : undefined,
128
+ packageJson: base.packageJson
129
+ ? `${pathPrefix}${base.packageJson}`
130
+ : undefined,
131
+ };
132
+ }
133
+ function checkCollectionFileNode(baseNode, mode, context) {
134
+ const schematicsRootNode = baseNode.properties.find((x) => x.key.type === 'JSONLiteral' && x.key.value === 'schematics');
135
+ const generatorsRootNode = baseNode.properties.find((x) => x.key.type === 'JSONLiteral' && x.key.value === 'generators');
136
+ const executorsRootNode = baseNode.properties.find((x) => x.key.type === 'JSONLiteral' && x.key.value === 'executors');
137
+ const buildersRootNode = baseNode.properties.find((x) => x.key.type === 'JSONLiteral' && x.key.value === 'builders');
138
+ if (!schematicsRootNode && !generatorsRootNode && mode !== 'executor') {
139
+ context.report({
140
+ messageId: 'noGeneratorsOrSchematicsFound',
141
+ node: baseNode,
142
+ });
143
+ return;
144
+ }
145
+ if (!executorsRootNode && !buildersRootNode && mode === 'executor') {
146
+ context.report({
147
+ messageId: 'noExecutorsOrBuildersFound',
148
+ node: baseNode,
149
+ });
150
+ return;
151
+ }
152
+ const collectionNodes = [
153
+ { collectionNode: schematicsRootNode, key: 'schematics' },
154
+ { collectionNode: generatorsRootNode, key: 'generators' },
155
+ { collectionNode: executorsRootNode, key: 'executors' },
156
+ { collectionNode: buildersRootNode, key: 'builders' },
157
+ ].filter(({ collectionNode }) => !!collectionNode);
158
+ for (const { collectionNode, key } of collectionNodes) {
159
+ if (collectionNode.value.type !== 'JSONObjectExpression') {
160
+ context.report({
161
+ messageId: 'valueShouldBeObject',
162
+ data: { key },
163
+ node: schematicsRootNode,
164
+ });
165
+ }
166
+ else {
167
+ checkCollectionNode(collectionNode.value, mode, context);
168
+ }
169
+ }
170
+ }
171
+ exports.checkCollectionFileNode = checkCollectionFileNode;
172
+ function checkCollectionNode(baseNode, mode, context) {
173
+ const entries = baseNode.properties;
174
+ for (const entryNode of entries) {
175
+ if (entryNode.value.type !== 'JSONObjectExpression') {
176
+ context.report({
177
+ messageId: 'valueShouldBeObject',
178
+ data: { key: entryNode.key.value },
179
+ node: entryNode,
180
+ });
181
+ }
182
+ else if (entryNode.key.type === 'JSONLiteral') {
183
+ validateEntry(entryNode.value, entryNode.key.value.toString(), mode, context);
184
+ }
185
+ }
186
+ }
187
+ exports.checkCollectionNode = checkCollectionNode;
188
+ function validateEntry(baseNode, key, mode, context) {
189
+ const schemaNode = baseNode.properties.find((x) => x.key.type === 'JSONLiteral' && x.key.value === 'schema');
190
+ if (mode !== 'migration' && !schemaNode) {
191
+ context.report({
192
+ messageId: 'missingRequiredSchema',
193
+ data: {
194
+ key,
195
+ },
196
+ node: baseNode,
197
+ });
198
+ }
199
+ else if (schemaNode) {
200
+ if (schemaNode.value.type !== 'JSONLiteral' ||
201
+ typeof schemaNode.value.value !== 'string') {
202
+ context.report({
203
+ messageId: 'invalidSchemaPath',
204
+ node: schemaNode.value,
205
+ });
206
+ }
207
+ else {
208
+ const schemaFilePath = path.join(path.dirname(context.getFilename()), schemaNode.value.value);
209
+ if (!(0, fs_1.existsSync)(schemaFilePath)) {
210
+ context.report({
211
+ messageId: 'invalidSchemaPath',
212
+ node: schemaNode.value,
213
+ });
214
+ }
215
+ else {
216
+ try {
217
+ (0, devkit_1.readJsonFile)(schemaFilePath);
218
+ }
219
+ catch (e) {
220
+ context.report({
221
+ messageId: 'invalidSchemaPath',
222
+ node: schemaNode.value,
223
+ });
224
+ }
225
+ }
226
+ }
227
+ }
228
+ const implementationNode = baseNode.properties.find((x) => x.key.type === 'JSONLiteral' &&
229
+ (x.key.value === 'implementation' || x.key.value === 'factory'));
230
+ if (!implementationNode) {
231
+ context.report({
232
+ messageId: 'missingImplementation',
233
+ data: {
234
+ key,
235
+ },
236
+ node: baseNode,
237
+ });
238
+ }
239
+ else {
240
+ validateImplemenationNode(implementationNode, key, context);
241
+ }
242
+ if (mode === 'migration') {
243
+ const versionNode = baseNode.properties.find((x) => x.key.type === 'JSONLiteral' && x.key.value === 'version');
244
+ if (!versionNode) {
245
+ context.report({
246
+ messageId: 'missingVersion',
247
+ data: {
248
+ key,
249
+ },
250
+ node: baseNode,
251
+ });
252
+ }
253
+ else if (versionNode.value.type !== 'JSONLiteral' ||
254
+ typeof versionNode.value.value !== 'string') {
255
+ context.report({
256
+ messageId: 'invalidVersion',
257
+ data: {
258
+ key,
259
+ },
260
+ node: versionNode.value,
261
+ });
262
+ }
263
+ else {
264
+ const specifiedVersion = versionNode.value.value;
265
+ if (!(0, semver_1.valid)(specifiedVersion)) {
266
+ context.report({
267
+ messageId: 'invalidVersion',
268
+ data: {
269
+ key,
270
+ },
271
+ node: versionNode.value,
272
+ });
273
+ }
274
+ }
275
+ }
276
+ }
277
+ exports.validateEntry = validateEntry;
278
+ function validateImplemenationNode(implementationNode, key, context) {
279
+ if (implementationNode.value.type !== 'JSONLiteral' ||
280
+ typeof implementationNode.value.value !== 'string') {
281
+ context.report({
282
+ messageId: 'invalidImplementationPath',
283
+ data: {
284
+ key,
285
+ },
286
+ node: implementationNode.value,
287
+ });
288
+ }
289
+ else {
290
+ const [implementationPath, identifier] = implementationNode.value.value.split('#');
291
+ let resolvedPath;
292
+ const modulePath = path.join(path.dirname(context.getFilename()), implementationPath);
293
+ try {
294
+ resolvedPath = require.resolve(modulePath);
295
+ }
296
+ catch (e) {
297
+ context.report({
298
+ messageId: 'invalidImplementationPath',
299
+ data: {
300
+ key,
301
+ },
302
+ node: implementationNode.value,
303
+ });
304
+ }
305
+ if (identifier) {
306
+ try {
307
+ const m = require(resolvedPath);
308
+ if (!(identifier in m && typeof m[identifier] === 'function')) {
309
+ context.report({
310
+ messageId: 'invalidImplementationModule',
311
+ node: implementationNode.value,
312
+ data: {
313
+ identifier,
314
+ key,
315
+ },
316
+ });
317
+ }
318
+ }
319
+ catch {
320
+ context.report({
321
+ messageId: 'unableToReadImplementationExports',
322
+ node: implementationNode.value,
323
+ data: {
324
+ key,
325
+ },
326
+ });
327
+ }
328
+ }
329
+ }
330
+ }
331
+ exports.validateImplemenationNode = validateImplemenationNode;
332
+ function validatePackageGroup(baseNode, context) {
333
+ const migrationsNode = baseNode.properties.find((x) => x.key.type === 'JSONLiteral' &&
334
+ x.value.type === 'JSONObjectExpression' &&
335
+ (x.key.value === 'nx-migrations' ||
336
+ x.key.value === 'ng-update' ||
337
+ x.key.value === 'migrations'))?.value;
338
+ const packageGroupNode = migrationsNode?.properties.find((x) => x.key.type === 'JSONLiteral' && x.key.value === 'packageGroup');
339
+ if (packageGroupNode) {
340
+ // Package group is defined as an array
341
+ if (packageGroupNode.value.type === 'JSONArrayExpression') {
342
+ // Look at entries which are an object
343
+ const members = packageGroupNode.value.elements.filter((x) => x.type === 'JSONObjectExpression');
344
+ // validate that the version property exists and is valid
345
+ for (const member of members) {
346
+ const versionPropertyNode = member.properties.find((x) => x.key.type === 'JSONLiteral' && x.key.value === 'version');
347
+ const packageNode = member.properties.find((x) => x.key.type === 'JSONLiteral' && x.key.value === 'package');
348
+ const key = packageNode?.value?.value ?? 'unknown';
349
+ if (versionPropertyNode) {
350
+ if (!validateVersionJsonExpression(versionPropertyNode.value, context))
351
+ context.report({
352
+ messageId: 'invalidVersion',
353
+ data: { key },
354
+ node: versionPropertyNode.value,
355
+ });
356
+ }
357
+ else {
358
+ context.report({
359
+ messageId: 'missingVersion',
360
+ data: { key },
361
+ node: member,
362
+ });
363
+ }
364
+ }
365
+ // Package group is defined as an object (Record<PackageName, Version>)
366
+ }
367
+ else if (packageGroupNode.value.type === 'JSONObjectExpression') {
368
+ const properties = packageGroupNode.value.properties;
369
+ // For each property, ensure its value is a valid version
370
+ for (const propertyNode of properties) {
371
+ if (!validateVersionJsonExpression(propertyNode.value, context)) {
372
+ context.report({
373
+ messageId: 'invalidVersion',
374
+ data: {
375
+ key: propertyNode.key.value,
376
+ },
377
+ node: propertyNode.value,
378
+ });
379
+ }
380
+ }
381
+ }
382
+ }
383
+ }
384
+ exports.validatePackageGroup = validatePackageGroup;
385
+ function validateVersionJsonExpression(node, context) {
386
+ return (node &&
387
+ node.type === 'JSONLiteral' &&
388
+ typeof node.value === 'string' &&
389
+ ((0, semver_1.valid)(node.value) ||
390
+ context.options[0]?.allowedVersionStrings.includes(node.value)));
391
+ }
392
+ exports.validateVersionJsonExpression = validateVersionJsonExpression;
@@ -0,0 +1,12 @@
1
+ import { ProjectGraphProjectNode } from '@nx/devkit';
2
+ /**
3
+ *
4
+ * @param importScope like `@myorg/somelib`
5
+ * @returns
6
+ */
7
+ export declare function getBarrelEntryPointByImportScope(importScope: string): string[];
8
+ export declare function getBarrelEntryPointProjectNode(projectNode: ProjectGraphProjectNode): {
9
+ path: string;
10
+ importScope: string;
11
+ }[] | null;
12
+ export declare function getRelativeImportPath(exportedMember: any, filePath: any, basePath: any): any;
@@ -0,0 +1,220 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getRelativeImportPath = exports.getBarrelEntryPointProjectNode = exports.getBarrelEntryPointByImportScope = void 0;
4
+ const devkit_1 = require("@nx/devkit");
5
+ const js_1 = require("@nx/js");
6
+ const type_utils_1 = require("@typescript-eslint/type-utils");
7
+ const fs_1 = require("fs");
8
+ const path_1 = require("path");
9
+ const ts = require("typescript");
10
+ function tryReadBaseJson() {
11
+ try {
12
+ return (0, devkit_1.readJsonFile)((0, devkit_1.joinPathFragments)(devkit_1.workspaceRoot, 'tsconfig.base.json'));
13
+ }
14
+ catch (e) {
15
+ devkit_1.logger.warn(`Error reading "tsconfig.base.json": \n${JSON.stringify(e)}`);
16
+ return null;
17
+ }
18
+ }
19
+ /**
20
+ *
21
+ * @param importScope like `@myorg/somelib`
22
+ * @returns
23
+ */
24
+ function getBarrelEntryPointByImportScope(importScope) {
25
+ const tryPaths = (paths, importScope) => {
26
+ // TODO check and warn that the entries of paths[importScope] have no wildcards; that'd be user misconfiguration
27
+ if (paths[importScope])
28
+ return paths[importScope];
29
+ // accommodate wildcards (it's not glob) https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping
30
+ const result = new Set(); // set ensures there are no duplicates
31
+ for (const [alias, targets] of Object.entries(paths)) {
32
+ if (!alias.endsWith('*')) {
33
+ continue;
34
+ }
35
+ const strippedAlias = alias.slice(0, -1); // remove asterisk
36
+ if (!importScope.startsWith(strippedAlias)) {
37
+ continue;
38
+ }
39
+ const dynamicPart = importScope.slice(strippedAlias.length);
40
+ targets.forEach((target) => {
41
+ result.add(target.replace('*', dynamicPart)); // add interpolated value
42
+ });
43
+ // we found the entry for importScope; an import scope not supposed and has no sense having > 1 Aliases; TODO warn on duplicated entries
44
+ break;
45
+ }
46
+ return Array.from(result);
47
+ };
48
+ const tsConfigBase = tryReadBaseJson();
49
+ if (!tsConfigBase?.compilerOptions?.paths)
50
+ return [];
51
+ return tryPaths(tsConfigBase.compilerOptions.paths, importScope);
52
+ }
53
+ exports.getBarrelEntryPointByImportScope = getBarrelEntryPointByImportScope;
54
+ function getBarrelEntryPointProjectNode(projectNode) {
55
+ const tsConfigBase = tryReadBaseJson();
56
+ if (tsConfigBase?.compilerOptions?.paths) {
57
+ const potentialEntryPoints = Object.keys(tsConfigBase.compilerOptions.paths)
58
+ .filter((entry) => {
59
+ const sourceFolderPaths = tsConfigBase.compilerOptions.paths[entry];
60
+ return sourceFolderPaths.some((sourceFolderPath) => {
61
+ return (sourceFolderPath === projectNode.data.sourceRoot ||
62
+ sourceFolderPath.indexOf(`${projectNode.data.sourceRoot}/`) === 0);
63
+ });
64
+ })
65
+ .map((entry) => tsConfigBase.compilerOptions.paths[entry].map((x) => ({
66
+ path: x,
67
+ importScope: entry,
68
+ })));
69
+ return potentialEntryPoints.flat();
70
+ }
71
+ return null;
72
+ }
73
+ exports.getBarrelEntryPointProjectNode = getBarrelEntryPointProjectNode;
74
+ function hasMemberExport(exportedMember, filePath) {
75
+ const fileContent = (0, fs_1.readFileSync)(filePath, 'utf8');
76
+ // use the TypeScript AST to find the path to the file where exportedMember is defined
77
+ const sourceFile = ts.createSourceFile(filePath, fileContent, ts.ScriptTarget.Latest, true);
78
+ // search whether there is already an export with our node
79
+ return ((0, js_1.findNodes)(sourceFile, ts.SyntaxKind.Identifier).filter((identifier) => identifier.text === exportedMember).length > 0);
80
+ }
81
+ function getRelativeImportPath(exportedMember, filePath, basePath) {
82
+ const status = (0, fs_1.lstatSync)(filePath, {
83
+ throwIfNoEntry: false,
84
+ });
85
+ if (!status /*not existed, but probably not full file with an extension*/) {
86
+ // try to find an extension that exists
87
+ const ext = ['.ts', '.tsx', '.js', '.jsx'].find((ext) => (0, fs_1.lstatSync)(filePath + ext, { throwIfNoEntry: false }));
88
+ if (ext) {
89
+ filePath += ext;
90
+ }
91
+ }
92
+ else if (status.isDirectory()) {
93
+ const file = (0, fs_1.readdirSync)(filePath).find((file) => /^index\.[jt]sx?$/.exec(file));
94
+ if (file) {
95
+ filePath = (0, devkit_1.joinPathFragments)(filePath, file);
96
+ }
97
+ else {
98
+ return;
99
+ }
100
+ }
101
+ const fileContent = (0, fs_1.readFileSync)(filePath, 'utf8');
102
+ // use the TypeScript AST to find the path to the file where exportedMember is defined
103
+ const sourceFile = ts.createSourceFile(filePath, fileContent, ts.ScriptTarget.Latest, true);
104
+ // Search in the current file whether there's an export already!
105
+ const memberNodes = (0, js_1.findNodes)(sourceFile, ts.SyntaxKind.Identifier).filter((identifier) => identifier.text === exportedMember);
106
+ let hasExport = false;
107
+ for (const memberNode of memberNodes || []) {
108
+ if (memberNode) {
109
+ // recursively navigate upwards to find the ExportKey modifier
110
+ let parent = memberNode;
111
+ do {
112
+ parent = parent.parent;
113
+ if (parent) {
114
+ // if we are inside a parameter list or decorator or param assignment
115
+ // then this is not what we're searching for, so break :)
116
+ if (parent.kind === ts.SyntaxKind.Parameter ||
117
+ parent.kind === ts.SyntaxKind.PropertyAccessExpression ||
118
+ parent.kind === ts.SyntaxKind.TypeReference ||
119
+ parent.kind === ts.SyntaxKind.HeritageClause ||
120
+ parent.kind === ts.SyntaxKind.Decorator) {
121
+ hasExport = false;
122
+ break;
123
+ }
124
+ // if our identifier is within an ExportDeclaration but is not just
125
+ // a re-export of some other module, we're good
126
+ if (parent.kind === ts.SyntaxKind.ExportDeclaration &&
127
+ !parent.moduleSpecifier) {
128
+ hasExport = true;
129
+ break;
130
+ }
131
+ if ((0, type_utils_1.getModifiers)(parent)?.find((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword)) {
132
+ /**
133
+ * if we get to a function export declaration we need to verify whether the
134
+ * exported function is actually the member we are searching for. Otherwise
135
+ * we might end up finding a function that just uses our searched identifier
136
+ * internally.
137
+ *
138
+ * Example: assume we try to find a constant member: `export const SOME_CONSTANT = 'bla'`
139
+ *
140
+ * Then we might end up in a file that uses it like
141
+ *
142
+ * import { SOME_CONSTANT } from '@myorg/samelib'
143
+ *
144
+ * export function someFunction() {
145
+ * return `Hi, ${SOME_CONSTANT}`
146
+ * }
147
+ *
148
+ * We want to avoid accidentally picking the someFunction export since we're searching upwards
149
+ * starting from `SOME_CONSTANT` identifier usages.
150
+ */
151
+ if (parent.kind === ts.SyntaxKind.FunctionDeclaration) {
152
+ const parentName = parent.name?.text;
153
+ if (parentName === exportedMember) {
154
+ hasExport = true;
155
+ break;
156
+ }
157
+ }
158
+ else {
159
+ hasExport = true;
160
+ break;
161
+ }
162
+ }
163
+ }
164
+ } while (!!parent);
165
+ }
166
+ if (hasExport) {
167
+ break;
168
+ }
169
+ }
170
+ if (hasExport) {
171
+ // we found the file, now grab the path
172
+ return filePath;
173
+ }
174
+ // if we didn't find an export, let's try to follow
175
+ // all export declarations and see whether any of those
176
+ // exports the node we're searching for
177
+ const exportDeclarations = (0, js_1.findNodes)(sourceFile, ts.SyntaxKind.ExportDeclaration);
178
+ for (const exportDeclaration of exportDeclarations) {
179
+ if (exportDeclaration.moduleSpecifier) {
180
+ // verify whether the export declaration we're looking at is a named export
181
+ // cause in that case we need to check whether our searched member is
182
+ // part of the exports
183
+ if (exportDeclaration.exportClause &&
184
+ (0, js_1.findNodes)(exportDeclaration, ts.SyntaxKind.Identifier).filter((identifier) => identifier.text === exportedMember).length === 0) {
185
+ continue;
186
+ }
187
+ const modulePath = exportDeclaration.moduleSpecifier.text;
188
+ let moduleFilePath;
189
+ if (modulePath.endsWith('.js') || modulePath.endsWith('.jsx')) {
190
+ moduleFilePath = (0, devkit_1.joinPathFragments)((0, path_1.dirname)(filePath), modulePath);
191
+ if (!(0, fs_1.existsSync)(moduleFilePath)) {
192
+ const tsifiedModulePath = modulePath.replace(/\.js(x?)$/, '.ts$1');
193
+ moduleFilePath = (0, devkit_1.joinPathFragments)((0, path_1.dirname)(filePath), `${tsifiedModulePath}`);
194
+ }
195
+ }
196
+ else if (modulePath.endsWith('.ts') || modulePath.endsWith('.tsx')) {
197
+ moduleFilePath = (0, devkit_1.joinPathFragments)((0, path_1.dirname)(filePath), modulePath);
198
+ }
199
+ else {
200
+ moduleFilePath = (0, devkit_1.joinPathFragments)((0, path_1.dirname)(filePath), `${modulePath}.ts`);
201
+ if (!(0, fs_1.existsSync)(moduleFilePath)) {
202
+ // might be a tsx file
203
+ moduleFilePath = (0, devkit_1.joinPathFragments)((0, path_1.dirname)(filePath), `${modulePath}.tsx`);
204
+ }
205
+ }
206
+ if (!(0, fs_1.existsSync)(moduleFilePath)) {
207
+ // might be an index.ts
208
+ moduleFilePath = (0, devkit_1.joinPathFragments)((0, path_1.dirname)(filePath), `${modulePath}/index.ts`);
209
+ }
210
+ if (hasMemberExport(exportedMember, moduleFilePath)) {
211
+ const foundFilePath = getRelativeImportPath(exportedMember, moduleFilePath, basePath);
212
+ if (foundFilePath) {
213
+ return foundFilePath;
214
+ }
215
+ }
216
+ }
217
+ }
218
+ return null;
219
+ }
220
+ exports.getRelativeImportPath = getRelativeImportPath;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Checks if package is available
3
+ * @param name name of the package
4
+ * @returns
5
+ */
6
+ export declare function packageExists(name: string): boolean;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.packageExists = void 0;
4
+ /**
5
+ * Checks if package is available
6
+ * @param name name of the package
7
+ * @returns
8
+ */
9
+ function packageExists(name) {
10
+ try {
11
+ require.resolve(name);
12
+ return true;
13
+ }
14
+ catch {
15
+ return false;
16
+ }
17
+ }
18
+ exports.packageExists = packageExists;
@@ -0,0 +1,6 @@
1
+ import type { FileData, ProjectFileMap, ProjectGraph, ProjectGraphProjectNode } from '@nx/devkit';
2
+ export declare function getPath(graph: ProjectGraph, sourceProjectName: string, targetProjectName: string): Array<ProjectGraphProjectNode>;
3
+ export declare function pathExists(graph: ProjectGraph, sourceProjectName: string, targetProjectName: string): boolean;
4
+ export declare function checkCircularPath(graph: ProjectGraph, sourceProject: ProjectGraphProjectNode, targetProject: ProjectGraphProjectNode): ProjectGraphProjectNode[];
5
+ export declare function findFilesInCircularPath(projectFileMap: ProjectFileMap, circularPath: ProjectGraphProjectNode[]): Array<string[]>;
6
+ export declare function findFilesWithDynamicImports(projectFileMap: ProjectFileMap, sourceProjectName: string, targetProjectName: string): FileData[];