dependency-cruiser 18.2.0-beta-2 → 18.2.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dependency-cruiser",
3
- "version": "18.2.0-beta-2",
3
+ "version": "18.2.0",
4
4
  "description": "Validate and visualize dependencies. With your rules. JavaScript, TypeScript, CoffeeScript. ES6, CommonJS, AMD.",
5
5
  "keywords": [
6
6
  "static analysis",
package/src/meta.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  /* generated - don't edit */
2
2
  module.exports = {
3
- version: "18.2.0-beta-2",
3
+ version: "18.2.0",
4
4
  engines: {
5
5
  node: "^22||^24||>=26",
6
6
  },
@@ -1,5 +1,5 @@
1
1
  import { readdirSync, statSync, readFileSync } from "node:fs";
2
- import { join } from "node:path";
2
+ import { join, relative } from "node:path/posix";
3
3
  import ignore from "ignore";
4
4
  import pathToPosix from "./path-to-posix.mjs";
5
5
 
@@ -7,6 +7,10 @@ import pathToPosix from "./path-to-posix.mjs";
7
7
  * @typedef {(pString:string, pIndex: number, pArray: string[]) => boolean} FilterFunctionType
8
8
  */
9
9
 
10
+ /**
11
+ * @typedef {{directoryName: string; ignoreMatcher: import("ignore").Ignore}} IgnoreRuleType
12
+ */
13
+
10
14
  /**
11
15
  * @param {string} pFullPathToFile
12
16
  * @param {string} pBaseDirectory
@@ -19,18 +23,200 @@ function fileIsDirectory(pFullPathToFile, pBaseDirectory) {
19
23
  return lStat?.isDirectory() ?? false;
20
24
  }
21
25
 
26
+ /**
27
+ * @param {string} pFileName
28
+ * @returns {string}
29
+ */
30
+ function readIgnoreFile(pFileName) {
31
+ try {
32
+ return readFileSync(pFileName, "utf8");
33
+ } catch {
34
+ return "";
35
+ }
36
+ }
37
+
38
+ /**
39
+ * @param {string} pDirectoryName
40
+ * @param {string} pBaseDirectory
41
+ * @returns {string}
42
+ */
43
+ function normalizeDirectoryName(pDirectoryName, pBaseDirectory) {
44
+ return pathToPosix(
45
+ relative(pBaseDirectory, join(pBaseDirectory, pDirectoryName)),
46
+ );
47
+ }
48
+
49
+ /**
50
+ * @param {string} pDirectoryName
51
+ * @param {string} pIgnoreFileContents
52
+ * @param {string[]=} pAdditionalIgnorePatterns
53
+ * @returns {IgnoreRuleType}
54
+ */
55
+ function createIgnoreRule(
56
+ pDirectoryName,
57
+ pIgnoreFileContents,
58
+ pAdditionalIgnorePatterns = [],
59
+ ) {
60
+ return {
61
+ directoryName: pDirectoryName,
62
+ ignoreMatcher: ignore()
63
+ .add(pIgnoreFileContents)
64
+ .add(pAdditionalIgnorePatterns),
65
+ };
66
+ }
67
+
22
68
  /**
23
69
  * @param {string} pDirectoryName
24
- * @param {{baseDir: string; ignoreFilterFn: FilterFunctionType; excludeFilterFn: FilterFunctionType; includeOnlyFilterFn: FilterFunctionType}} pOptions
70
+ * @param {string} pBaseDirectory
71
+ * @param {{ignoreFileContents?: string}} pOptions
72
+ * @returns {IgnoreRuleType}
73
+ */
74
+ function createIgnoreRuleForDirectory(
75
+ pDirectoryName,
76
+ pBaseDirectory,
77
+ pOptions,
78
+ ) {
79
+ const lIgnoreFileContents =
80
+ pOptions.ignoreFileContents === undefined
81
+ ? readIgnoreFile(join(pBaseDirectory, pDirectoryName, ".gitignore"))
82
+ : pOptions.ignoreFileContents;
83
+
84
+ return createIgnoreRule(pDirectoryName, lIgnoreFileContents);
85
+ }
86
+
87
+ /**
88
+ * @param {string[]} pAncestorDirectoryNames
89
+ * @param {string} pBaseDirectory
90
+ * @returns {IgnoreRuleType[]}
91
+ */
92
+ function createIgnoreRulesFromDirectoryNames(
93
+ pAncestorDirectoryNames,
94
+ pBaseDirectory,
95
+ ) {
96
+ return pAncestorDirectoryNames.map((pAncestorDirectoryName) =>
97
+ createIgnoreRuleForDirectory(pAncestorDirectoryName, pBaseDirectory, {}),
98
+ );
99
+ }
100
+
101
+ /**
102
+ * @param {string} pDirectoryName
103
+ * @param {string} pBaseDirectory
104
+ * @returns {IgnoreRuleType[]}
105
+ */
106
+ function createIgnoreRulesBeforeDirectory(pDirectoryName, pBaseDirectory) {
107
+ const lNormalizedDirectoryName = normalizeDirectoryName(
108
+ pDirectoryName,
109
+ pBaseDirectory,
110
+ );
111
+
112
+ if (lNormalizedDirectoryName === "") {
113
+ return [];
114
+ }
115
+
116
+ const lDirectorySegments = lNormalizedDirectoryName.split("/");
117
+ const lAncestorDirectoryNames = [""];
118
+ let lCurrentDirectoryName = "";
119
+
120
+ for (const lDirectorySegment of lDirectorySegments.slice(0, -1)) {
121
+ lCurrentDirectoryName = lCurrentDirectoryName
122
+ ? join(lCurrentDirectoryName, lDirectorySegment)
123
+ : lDirectorySegment;
124
+ lAncestorDirectoryNames.push(pathToPosix(lCurrentDirectoryName));
125
+ }
126
+
127
+ return createIgnoreRulesFromDirectoryNames(
128
+ lAncestorDirectoryNames,
129
+ pBaseDirectory,
130
+ );
131
+ }
132
+
133
+ /**
134
+ * @param {string} pFilePath
135
+ * @param {IgnoreRuleType[]} pIgnoreRules
136
+ * @param {IgnoreRuleType} pMandatoryIgnoreRule
137
+ * @returns {boolean}
138
+ */
139
+ function fileShouldBeKept(pFilePath, pIgnoreRules, pMandatoryIgnoreRule) {
140
+ let lFileIsIgnored = false;
141
+
142
+ for (const lIgnoreRule of pIgnoreRules) {
143
+ const lDirectoryName = lIgnoreRule.directoryName;
144
+ const lIgnoreMatcher = lIgnoreRule.ignoreMatcher;
145
+ let lRelativePath = null;
146
+
147
+ if (lDirectoryName === "") {
148
+ lRelativePath = pFilePath;
149
+ } else if (pFilePath.startsWith(`${lDirectoryName}/`)) {
150
+ lRelativePath = pFilePath.slice(lDirectoryName.length + 1);
151
+ }
152
+
153
+ if (lRelativePath !== null) {
154
+ const { ignored: lIgnored, unignored: lUnignored } =
155
+ lIgnoreMatcher.test(lRelativePath);
156
+
157
+ if (lIgnored) {
158
+ lFileIsIgnored = true;
159
+ }
160
+ if (lUnignored) {
161
+ lFileIsIgnored = false;
162
+ }
163
+ }
164
+ }
165
+
166
+ const { ignored: lIgnored, unignored: lUnignored } =
167
+ pMandatoryIgnoreRule.ignoreMatcher.test(pFilePath);
168
+
169
+ if (lIgnored) {
170
+ lFileIsIgnored = true;
171
+ }
172
+ if (lUnignored) {
173
+ lFileIsIgnored = false;
174
+ }
175
+
176
+ return !lFileIsIgnored;
177
+ }
178
+
179
+ /**
180
+ * @type FilterFunctionType
181
+ */
182
+
183
+ function identityFilter(_pString, _pIndex, _pArray) {
184
+ return true;
185
+ }
186
+
187
+ /**
188
+ * @param {string} pDirectoryName
189
+ * @param {{baseDir: string; ignoreRules: IgnoreRuleType[]; mandatoryIgnoreRule: IgnoreRuleType; startDirectoryName: string; startDirectoryIgnoreFileContents?: string; excludeFilterFn: FilterFunctionType; includeOnlyFilterFn: FilterFunctionType}}
190
+ * pOptions
25
191
  * @returns {string[]}
26
192
  */
27
193
  function walk(
28
194
  pDirectoryName,
29
- { baseDir, ignoreFilterFn, excludeFilterFn, includeOnlyFilterFn },
195
+ {
196
+ baseDir,
197
+ ignoreRules,
198
+ mandatoryIgnoreRule,
199
+ startDirectoryName,
200
+ startDirectoryIgnoreFileContents,
201
+ excludeFilterFn,
202
+ includeOnlyFilterFn,
203
+ },
30
204
  ) {
205
+ const lCurrentDirectoryName = normalizeDirectoryName(pDirectoryName, baseDir);
206
+ const lCurrentIgnoreRules = ignoreRules.concat(
207
+ createIgnoreRuleForDirectory(lCurrentDirectoryName, baseDir, {
208
+ ...(lCurrentDirectoryName === startDirectoryName &&
209
+ startDirectoryIgnoreFileContents !== undefined
210
+ ? { ignoreFileContents: startDirectoryIgnoreFileContents }
211
+ : {}),
212
+ }),
213
+ );
214
+
31
215
  const lFilesInCurrentDirectory = readdirSync(join(baseDir, pDirectoryName))
32
216
  .map((pFileName) => join(pDirectoryName, pFileName))
33
- .filter(ignoreFilterFn)
217
+ .filter((pFilePath) =>
218
+ fileShouldBeKept(pFilePath, lCurrentIgnoreRules, mandatoryIgnoreRule),
219
+ )
34
220
  .filter(excludeFilterFn)
35
221
  .filter(includeOnlyFilterFn);
36
222
 
@@ -40,7 +226,10 @@ function walk(
40
226
  lFiles.push(
41
227
  ...walk(lFile, {
42
228
  baseDir,
43
- ignoreFilterFn,
229
+ ignoreRules: lCurrentIgnoreRules,
230
+ mandatoryIgnoreRule,
231
+ startDirectoryName,
232
+ startDirectoryIgnoreFileContents,
44
233
  excludeFilterFn,
45
234
  includeOnlyFilterFn,
46
235
  }),
@@ -53,25 +242,10 @@ function walk(
53
242
  return lFiles;
54
243
  }
55
244
 
56
- function readIgnoreFile(pFileName) {
57
- try {
58
- return readFileSync(pFileName, "utf8");
59
- } catch {
60
- return "";
61
- }
62
- }
63
-
64
- /**
65
- * @type FilterFunctionType
66
- */
67
-
68
- function identityFilter(_pString, _pIndex, _pArray) {
69
- return true;
70
- }
71
-
72
245
  /**
73
246
  * @param {string} pDirectoryName
74
- * @param {{baseDir: string; ignoreFileContents?: string; additionalIgnorePatterns?: string[]; excludeFilterFn?: FilterFunctionType; includeOnlyFilterFn?: FilterFunctionType}} pOptions
247
+ * @param {{baseDir: string; ignoreFileContents?: string; additionalIgnorePatterns?: string[]; excludeFilterFn?: FilterFunctionType; includeOnlyFilterFn?: FilterFunctionType}}
248
+ * pOptions
75
249
  * @returns {string[]}
76
250
  */
77
251
  export default function findAllFiles(
@@ -84,17 +258,24 @@ export default function findAllFiles(
84
258
  includeOnlyFilterFn,
85
259
  },
86
260
  ) {
87
- const lIgnoreFileContents =
88
- ignoreFileContents ?? readIgnoreFile(join(baseDir, ".gitignore"));
89
261
  const lAdditionalIgnorePatterns = additionalIgnorePatterns ?? [".git"];
90
- const lIgnoreFilterFunction = ignore()
91
- .add(lIgnoreFileContents)
92
- .add(lAdditionalIgnorePatterns)
93
- .createFilter();
262
+ const lStartDirectoryName = normalizeDirectoryName(pDirectoryName, baseDir);
263
+ const lMandatoryIgnoreRule = createIgnoreRule(
264
+ "",
265
+ "",
266
+ lAdditionalIgnorePatterns,
267
+ );
268
+ const lIgnoreRules = createIgnoreRulesBeforeDirectory(
269
+ pDirectoryName,
270
+ baseDir,
271
+ );
94
272
 
95
273
  return walk(pDirectoryName, {
96
274
  baseDir,
97
- ignoreFilterFn: lIgnoreFilterFunction,
275
+ ignoreRules: lIgnoreRules,
276
+ mandatoryIgnoreRule: lMandatoryIgnoreRule,
277
+ startDirectoryName: lStartDirectoryName,
278
+ startDirectoryIgnoreFileContents: ignoreFileContents,
98
279
  excludeFilterFn: excludeFilterFn ?? identityFilter,
99
280
  includeOnlyFilterFn: includeOnlyFilterFn ?? identityFilter,
100
281
  });