dependency-cruiser 16.7.0-beta-2 → 16.7.0
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 +1 -1
- package/src/cli/init-config/build-config.mjs +15 -0
- package/src/cli/init-config/config-template.mjs +2 -2
- package/src/cli/init-config/get-user-input.mjs +7 -0
- package/src/cli/init-config/index.mjs +1 -0
- package/src/cli/init-config/write-run-scripts-to-manifest.mjs +0 -5
- package/src/extract/resolve/resolve.mjs +11 -9
- package/src/extract/tsc/extract-typescript-deps.mjs +57 -23
- package/src/meta.cjs +1 -1
package/package.json
CHANGED
|
@@ -62,6 +62,17 @@ function buildTsPreCompilationDepsAttribute(pInitOptions) {
|
|
|
62
62
|
: "// tsPreCompilationDeps: false,";
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
/**
|
|
66
|
+
*
|
|
67
|
+
* @param {IInitConfig} pInitOptions
|
|
68
|
+
* @returns {string}
|
|
69
|
+
*/
|
|
70
|
+
function buildDetectJSDocumentImportsAttribute(pInitOptions) {
|
|
71
|
+
return pInitOptions.detectJSDocImports
|
|
72
|
+
? "detectJSDocImports: true,"
|
|
73
|
+
: "// detectJSDocImports: true,";
|
|
74
|
+
}
|
|
75
|
+
|
|
65
76
|
/**
|
|
66
77
|
* @param {IInitConfig} pInitOptions
|
|
67
78
|
* @returns {string}
|
|
@@ -168,6 +179,10 @@ export default function buildConfig(pInitOptions) {
|
|
|
168
179
|
extensionsToString(pInitOptions.resolutionExtensions),
|
|
169
180
|
)
|
|
170
181
|
.replace("{{notToTestRule}}", buildNotToTestRule(pInitOptions))
|
|
182
|
+
.replace(
|
|
183
|
+
"{{detectJSDocImportsAttribute}}",
|
|
184
|
+
buildDetectJSDocumentImportsAttribute(pInitOptions),
|
|
185
|
+
)
|
|
171
186
|
.replace(
|
|
172
187
|
"{{tsPreCompilationDepsAttribute}}",
|
|
173
188
|
buildTsPreCompilationDepsAttribute(pInitOptions),
|
|
@@ -229,7 +229,7 @@ module.exports = {
|
|
|
229
229
|
// moduleSystems: ['cjs', 'es6'],
|
|
230
230
|
|
|
231
231
|
/*
|
|
232
|
-
false: don't look at JSDoc imports
|
|
232
|
+
false: don't look at JSDoc imports (the default)
|
|
233
233
|
true: dependency-cruiser will detect dependencies in JSDoc-style
|
|
234
234
|
import statements. Implies "parser": "tsc", so the dependency-cruiser
|
|
235
235
|
will use the typescript parser for JavaScript files.
|
|
@@ -237,7 +237,7 @@ module.exports = {
|
|
|
237
237
|
For this to work the typescript compiler will need to be installed in the
|
|
238
238
|
same spot as you're running dependency-cruiser from.
|
|
239
239
|
*/
|
|
240
|
-
|
|
240
|
+
{{detectJSDocImportsAttribute}}
|
|
241
241
|
|
|
242
242
|
/* prefix for links in html and svg output (e.g. 'https://github.com/you/yourrepo/blob/main/'
|
|
243
243
|
to open it on your online repo or \`vscode://file/$\{process.cwd()}/\` to
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
getWebpackConfigCandidates,
|
|
19
19
|
} from "./environment-helpers.mjs";
|
|
20
20
|
import { validateLocation } from "./validators.mjs";
|
|
21
|
+
import { isAvailable as tscIsAvailable } from "#extract/tsc/parse.mjs";
|
|
21
22
|
|
|
22
23
|
function toPromptChoice(pString) {
|
|
23
24
|
return {
|
|
@@ -108,6 +109,12 @@ const QUESTIONS = [
|
|
|
108
109
|
message: "Full path to your 'tsconfig.json",
|
|
109
110
|
choices: getTSConfigCandidates().map(toPromptChoice),
|
|
110
111
|
},
|
|
112
|
+
{
|
|
113
|
+
name: "detectJSDocImports",
|
|
114
|
+
type: () => (tscIsAvailable() ? "confirm" : false),
|
|
115
|
+
message: "Do you want to detect JSDoc imports as well (slower)?",
|
|
116
|
+
initial: false,
|
|
117
|
+
},
|
|
111
118
|
{
|
|
112
119
|
name: "tsPreCompilationDeps",
|
|
113
120
|
type: (_, pAnswers) => (pAnswers.useTsConfig ? "confirm" : false),
|
|
@@ -43,6 +43,7 @@ function getOneShotConfig(pOneShotConfigId) {
|
|
|
43
43
|
jsConfig: getJSConfigCandidates().shift(),
|
|
44
44
|
useTsConfig: hasTSConfigCandidates(),
|
|
45
45
|
tsConfig: getTSConfigCandidates().shift(),
|
|
46
|
+
detectJSDocImports: false,
|
|
46
47
|
tsPreCompilationDeps: hasTSConfigCandidates(),
|
|
47
48
|
useWebpackConfig: hasWebpackConfigCandidates(),
|
|
48
49
|
webpackConfig: getWebpackConfigCandidates().shift(),
|
|
@@ -2,17 +2,19 @@ import enhancedResolve from "enhanced-resolve";
|
|
|
2
2
|
import { stripQueryParameters } from "../helpers.mjs";
|
|
3
3
|
import pathToPosix from "#utl/path-to-posix.mjs";
|
|
4
4
|
|
|
5
|
-
let gResolvers =
|
|
6
|
-
let gInitialized =
|
|
5
|
+
let gResolvers = new Map();
|
|
6
|
+
let gInitialized = new Map();
|
|
7
7
|
|
|
8
8
|
function init(pEHResolveOptions, pCachingContext) {
|
|
9
|
-
if (!gInitialized
|
|
9
|
+
if (!gInitialized.get(pCachingContext) || pEHResolveOptions.bustTheCache) {
|
|
10
10
|
// assuming the cached file system here
|
|
11
11
|
pEHResolveOptions.fileSystem.purge();
|
|
12
|
-
gResolvers
|
|
13
|
-
|
|
12
|
+
gResolvers.set(
|
|
13
|
+
pCachingContext,
|
|
14
|
+
enhancedResolve.ResolverFactory.createResolver(pEHResolveOptions),
|
|
15
|
+
);
|
|
14
16
|
/* eslint security/detect-object-injection:0 */
|
|
15
|
-
gInitialized
|
|
17
|
+
gInitialized.set(pCachingContext, true);
|
|
16
18
|
}
|
|
17
19
|
}
|
|
18
20
|
|
|
@@ -35,7 +37,7 @@ export function resolve(
|
|
|
35
37
|
init(pResolveOptions, pCachingContext);
|
|
36
38
|
|
|
37
39
|
return stripQueryParameters(
|
|
38
|
-
gResolvers
|
|
40
|
+
gResolvers.get(pCachingContext).resolveSync(
|
|
39
41
|
{},
|
|
40
42
|
// lookupStartPath
|
|
41
43
|
pathToPosix(pFileDirectory),
|
|
@@ -46,6 +48,6 @@ export function resolve(
|
|
|
46
48
|
}
|
|
47
49
|
|
|
48
50
|
export function clearCache() {
|
|
49
|
-
gInitialized
|
|
50
|
-
gResolvers
|
|
51
|
+
gInitialized.clear();
|
|
52
|
+
gResolvers.clear();
|
|
51
53
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable security/detect-object-injection */
|
|
1
2
|
/* eslint-disable unicorn/prevent-abbreviations */
|
|
2
3
|
/* eslint-disable max-lines */
|
|
3
4
|
/* eslint-disable no-inline-comments */
|
|
@@ -263,7 +264,7 @@ function extractJSDocImportTags(pJSDocTags) {
|
|
|
263
264
|
.filter(
|
|
264
265
|
(pTag) =>
|
|
265
266
|
pTag.tagName.escapedText === "import" &&
|
|
266
|
-
pTag.moduleSpecifier
|
|
267
|
+
pTag.moduleSpecifier &&
|
|
267
268
|
typescript.SyntaxKind[pTag.moduleSpecifier.kind] === "StringLiteral" &&
|
|
268
269
|
pTag.moduleSpecifier.text,
|
|
269
270
|
)
|
|
@@ -275,26 +276,64 @@ function extractJSDocImportTags(pJSDocTags) {
|
|
|
275
276
|
}));
|
|
276
277
|
}
|
|
277
278
|
|
|
279
|
+
function isJSDocImport(pTypeNode) {
|
|
280
|
+
// import('./hello.mjs') within jsdoc
|
|
281
|
+
return (
|
|
282
|
+
typescript.SyntaxKind[pTypeNode?.kind] === "LastTypeNode" &&
|
|
283
|
+
typescript.SyntaxKind[pTypeNode.argument?.kind] === "LiteralType" &&
|
|
284
|
+
typescript.SyntaxKind[pTypeNode.argument?.literal?.kind] ===
|
|
285
|
+
"StringLiteral" &&
|
|
286
|
+
pTypeNode.argument.literal.text
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function keyInJSDocIsIgnorable(pKey) {
|
|
291
|
+
return [
|
|
292
|
+
"parent",
|
|
293
|
+
"pos",
|
|
294
|
+
"end",
|
|
295
|
+
"flags",
|
|
296
|
+
"emitNode",
|
|
297
|
+
"modifierFlagsCache",
|
|
298
|
+
"transformFlags",
|
|
299
|
+
"id",
|
|
300
|
+
"flowNode",
|
|
301
|
+
"symbol",
|
|
302
|
+
"original",
|
|
303
|
+
].includes(pKey);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
export function walkJSDoc(pObject, pCollection = new Set()) {
|
|
307
|
+
if (isJSDocImport(pObject)) {
|
|
308
|
+
pCollection.add(pObject.argument.literal.text);
|
|
309
|
+
} else if (Array.isArray(pObject)) {
|
|
310
|
+
pObject.forEach((pValue) => walkJSDoc(pValue, pCollection));
|
|
311
|
+
} else if (typeof pObject === "object") {
|
|
312
|
+
for (const lKey in pObject) {
|
|
313
|
+
if (!keyInJSDocIsIgnorable(lKey) && pObject[lKey]) {
|
|
314
|
+
walkJSDoc(pObject[lKey], pCollection);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
export function getJSDocImports(pTagNode) {
|
|
321
|
+
const lCollection = new Set();
|
|
322
|
+
walkJSDoc(pTagNode, lCollection);
|
|
323
|
+
return Array.from(lCollection);
|
|
324
|
+
}
|
|
325
|
+
|
|
278
326
|
function extractJSDocBracketImports(pJSDocTags) {
|
|
327
|
+
// https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html
|
|
279
328
|
return pJSDocTags
|
|
280
329
|
.filter(
|
|
281
330
|
(pTag) =>
|
|
282
331
|
pTag.tagName.escapedText !== "import" &&
|
|
283
|
-
|
|
284
|
-
typescript.SyntaxKind[pTag.typeExpression?.kind ?? -1] ===
|
|
285
|
-
"FirstJSDocNode" &&
|
|
286
|
-
typescript.SyntaxKind[pTag.typeExpression.type?.kind ?? -1] ===
|
|
287
|
-
"LastTypeNode" &&
|
|
288
|
-
typescript.SyntaxKind[pTag.typeExpression.type.argument?.kind ?? -1] ===
|
|
289
|
-
"LiteralType" &&
|
|
290
|
-
typescript.SyntaxKind[
|
|
291
|
-
pTag.typeExpression.type.argument?.literal?.kind ?? -1
|
|
292
|
-
] === "StringLiteral" &&
|
|
293
|
-
/* c8 ignore stop*/
|
|
294
|
-
pTag.typeExpression.type.argument.literal.text,
|
|
332
|
+
typescript.SyntaxKind[pTag.typeExpression?.kind] === "FirstJSDocNode",
|
|
295
333
|
)
|
|
296
|
-
.
|
|
297
|
-
|
|
334
|
+
.flatMap((pTag) => getJSDocImports(pTag))
|
|
335
|
+
.map((pImportName) => ({
|
|
336
|
+
module: pImportName,
|
|
298
337
|
moduleSystem: "es6",
|
|
299
338
|
exoticallyRequired: false,
|
|
300
339
|
dependencyTypes: ["type-only", "import", "jsdoc", "jsdoc-bracket-import"],
|
|
@@ -302,6 +341,7 @@ function extractJSDocBracketImports(pJSDocTags) {
|
|
|
302
341
|
}
|
|
303
342
|
|
|
304
343
|
function extractJSDocImports(pJSDocNodes) {
|
|
344
|
+
// https://devblogs.microsoft.com/typescript/announcing-typescript-5-5/#the-jsdoc-import-tag
|
|
305
345
|
const lJSDocNodesWithTags = pJSDocNodes.filter(
|
|
306
346
|
(pJSDocLine) => pJSDocLine.tags,
|
|
307
347
|
);
|
|
@@ -371,14 +411,8 @@ function walk(pResult, pExoticRequireStrings, pDetectJSDocImports) {
|
|
|
371
411
|
});
|
|
372
412
|
}
|
|
373
413
|
|
|
374
|
-
// /** @import thing from './module' */
|
|
375
|
-
// /** @
|
|
376
|
-
// /** @import * as thing from './module' */
|
|
377
|
-
// see https://devblogs.microsoft.com/typescript/announcing-typescript-5-5/#the-jsdoc-import-tag
|
|
378
|
-
//
|
|
379
|
-
// TODO: all the kinds of tags that can have import statements as type declarations
|
|
380
|
-
// (e.g. @type, @param, @returns, @typedef, @property, @prop, @arg, ...)
|
|
381
|
-
// https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html
|
|
414
|
+
// /** @import thing from './module' */ etc
|
|
415
|
+
// /** @type {import('module').thing}*/ etc
|
|
382
416
|
if (pDetectJSDocImports && pASTNode.jsDoc) {
|
|
383
417
|
const lJSDocImports = extractJSDocImports(pASTNode.jsDoc);
|
|
384
418
|
|