dependency-cruiser 12.4.0 → 12.5.0-beta-2
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/cache/cache.js +73 -60
- package/src/cache/content-strategy.js +215 -0
- package/src/cache/metadata-strategy.js +90 -0
- package/src/cache/options-compatible.js +5 -5
- package/src/cache/utl.js +85 -2
- package/src/main/index.js +6 -10
- package/src/meta.js +1 -1
- package/types/cache-options.d.ts +3 -3
- package/src/cache/git-revision-data.js +0 -106
package/package.json
CHANGED
package/src/cache/cache.js
CHANGED
|
@@ -2,73 +2,86 @@ const { readFileSync, mkdirSync, writeFileSync } = require("fs");
|
|
|
2
2
|
const { join } = require("path");
|
|
3
3
|
const meta = require("../extract/transpile/meta");
|
|
4
4
|
const { optionsAreCompatible } = require("./options-compatible");
|
|
5
|
-
const
|
|
5
|
+
const metadataStrategy = require("./metadata-strategy");
|
|
6
|
+
const contentStrategy = require("./content-strategy");
|
|
6
7
|
|
|
7
8
|
const CACHE_FILE_NAME = "cache.json";
|
|
8
|
-
let gRevisionData = null;
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
writeFileSync(
|
|
20
|
-
join(pCacheFolder, CACHE_FILE_NAME),
|
|
21
|
-
JSON.stringify(
|
|
22
|
-
lRevisionData
|
|
23
|
-
? {
|
|
24
|
-
...pCruiseResult,
|
|
25
|
-
revisionData: lRevisionData,
|
|
26
|
-
}
|
|
27
|
-
: pCruiseResult
|
|
28
|
-
),
|
|
29
|
-
"utf8"
|
|
30
|
-
);
|
|
31
|
-
}
|
|
10
|
+
module.exports = class Cache {
|
|
11
|
+
/**
|
|
12
|
+
* @param {import("../../types/cache-options").cacheStrategyType=} pCacheStrategy
|
|
13
|
+
*/
|
|
14
|
+
constructor(pCacheStrategy) {
|
|
15
|
+
this.revisionData = null;
|
|
16
|
+
this.cacheStrategy =
|
|
17
|
+
pCacheStrategy === "content" ? contentStrategy : metadataStrategy;
|
|
18
|
+
}
|
|
32
19
|
|
|
33
|
-
/**
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
20
|
+
/**
|
|
21
|
+
* @param {import("../../types/strict-options").IStrictCruiseOptions} pCruiseOptions
|
|
22
|
+
* @param {import("../..").ICruiseResult} pCachedCruiseResult
|
|
23
|
+
* @param {import("../..").IRevisionData=} pRevisionData
|
|
24
|
+
* @returns {boolean}
|
|
25
|
+
*/
|
|
26
|
+
canServeFromCache(pCruiseOptions, pCachedCruiseResult, pRevisionData) {
|
|
27
|
+
this.revisionData =
|
|
28
|
+
pRevisionData ??
|
|
29
|
+
this.cacheStrategy.getRevisionData(
|
|
30
|
+
".",
|
|
31
|
+
pCachedCruiseResult,
|
|
32
|
+
pCruiseOptions,
|
|
33
|
+
{
|
|
34
|
+
extensions: new Set(
|
|
35
|
+
meta.scannableExtensions.concat(
|
|
36
|
+
pCruiseOptions.extraExtensionsToScan
|
|
37
|
+
)
|
|
38
|
+
),
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
return (
|
|
42
|
+
this.cacheStrategy.revisionDataEqual(
|
|
43
|
+
pCachedCruiseResult.revisionData,
|
|
44
|
+
this.revisionData
|
|
45
|
+
) &&
|
|
46
|
+
optionsAreCompatible(
|
|
47
|
+
pCachedCruiseResult.summary.optionsUsed,
|
|
48
|
+
pCruiseOptions
|
|
49
|
+
)
|
|
41
50
|
);
|
|
42
|
-
} catch (pError) {
|
|
43
|
-
return { modules: [], summary: {} };
|
|
44
51
|
}
|
|
45
|
-
}
|
|
46
52
|
|
|
47
|
-
/**
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
revisionDataEqual(pCachedCruiseResult.revisionData, gRevisionData) &&
|
|
61
|
-
optionsAreCompatible(pCachedCruiseResult.summary.optionsUsed, pOptions)
|
|
62
|
-
);
|
|
63
|
-
}
|
|
53
|
+
/**
|
|
54
|
+
* @param {string} pCacheFolder
|
|
55
|
+
* @returns {import("../..").ICruiseResult}
|
|
56
|
+
*/
|
|
57
|
+
read(pCacheFolder) {
|
|
58
|
+
try {
|
|
59
|
+
return JSON.parse(
|
|
60
|
+
readFileSync(join(pCacheFolder, CACHE_FILE_NAME), "utf8")
|
|
61
|
+
);
|
|
62
|
+
} catch (pError) {
|
|
63
|
+
return { modules: [], summary: {} };
|
|
64
|
+
}
|
|
65
|
+
}
|
|
64
66
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
67
|
+
/**
|
|
68
|
+
* @param {string} pCacheFolder
|
|
69
|
+
* @param {import("../..").ICruiseResult} pCruiseResult
|
|
70
|
+
* @param {import("../..").IRevisionData=} pRevisionData
|
|
71
|
+
*/
|
|
72
|
+
write(pCacheFolder, pCruiseResult, pRevisionData) {
|
|
73
|
+
const lRevisionData = pRevisionData ?? this.revisionData;
|
|
68
74
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
mkdirSync(pCacheFolder, { recursive: true });
|
|
76
|
+
writeFileSync(
|
|
77
|
+
join(pCacheFolder, CACHE_FILE_NAME),
|
|
78
|
+
JSON.stringify(
|
|
79
|
+
this.cacheStrategy.prepareRevisionDataForSaving(
|
|
80
|
+
pCruiseResult,
|
|
81
|
+
lRevisionData
|
|
82
|
+
)
|
|
83
|
+
),
|
|
84
|
+
"utf8"
|
|
85
|
+
);
|
|
86
|
+
}
|
|
74
87
|
};
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
const { isDeepStrictEqual } = require("util");
|
|
2
|
+
const bus = require("../utl/bus");
|
|
3
|
+
const { DEBUG } = require("../utl/bus-log-levels");
|
|
4
|
+
const findAllFiles = require("../utl/find-all-files");
|
|
5
|
+
const {
|
|
6
|
+
getFileHash,
|
|
7
|
+
excludeFilter,
|
|
8
|
+
includeOnlyFilter,
|
|
9
|
+
isInterestingChangeType,
|
|
10
|
+
hasInterestingExtension,
|
|
11
|
+
addCheckSumToChange,
|
|
12
|
+
} = require("./utl");
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @param {Set<string>} pFileSet
|
|
16
|
+
* @param {typeof getFileHash} pFileHashFunction
|
|
17
|
+
* @returns {import('../..').IRevisionChange}
|
|
18
|
+
*/
|
|
19
|
+
function diffCachedModuleAgainstFileSet(
|
|
20
|
+
pFileSet,
|
|
21
|
+
pFileHashFunction = getFileHash
|
|
22
|
+
) {
|
|
23
|
+
// eslint-disable-next-line complexity
|
|
24
|
+
return (pModule) => {
|
|
25
|
+
if (
|
|
26
|
+
!pModule.consolidated &&
|
|
27
|
+
!pModule.coreModule &&
|
|
28
|
+
!pModule.couldNotResolve &&
|
|
29
|
+
!pModule.matchesDoNotFollow
|
|
30
|
+
) {
|
|
31
|
+
if (!pFileSet.has(pModule.source)) {
|
|
32
|
+
return { name: pModule.source, changeType: "deleted" };
|
|
33
|
+
}
|
|
34
|
+
const lNewCheckSum = pFileHashFunction(pModule.source);
|
|
35
|
+
if (lNewCheckSum !== pModule.checksum) {
|
|
36
|
+
return {
|
|
37
|
+
name: pModule.source,
|
|
38
|
+
changeType: "modified",
|
|
39
|
+
checksum: lNewCheckSum,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
name: pModule.source,
|
|
45
|
+
changeType: "unmodified",
|
|
46
|
+
checksum: pModule.checksum,
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
We can run into these scenarios:
|
|
53
|
+
- there is no cache yet:
|
|
54
|
+
modules will === []; all files will be marked as 'added'
|
|
55
|
+
- there is a cache and it contains checksums:
|
|
56
|
+
- existing files that are not in the cache => added
|
|
57
|
+
- modules that are in the cache:
|
|
58
|
+
- don't exist anymore => deleted TODO:
|
|
59
|
+
we might wrongly bump into this for files that are gitignored and that don't have an interesting extension
|
|
60
|
+
- cached checksum === current checksum => not a change; left out
|
|
61
|
+
- cached checksum !== current checksum => modified
|
|
62
|
+
- there is a cache, but it doesn't contain checksums => same as before, except
|
|
63
|
+
all files will be marked as 'modified'
|
|
64
|
+
* @param {string} pDirectory
|
|
65
|
+
* @param {import("../..").ICruiseResult} pCachedCruiseResult
|
|
66
|
+
* @param {Object} pOptions
|
|
67
|
+
* @param {Set<string>} pOptions.extensions
|
|
68
|
+
* @param {string} pOptions.baseDir
|
|
69
|
+
* @returns {{source: string; changeType: import("watskeburt").changeTypeType; checksum: string}[]}
|
|
70
|
+
*/
|
|
71
|
+
function findChanges(pDirectory, pCachedCruiseResult, pOptions) {
|
|
72
|
+
bus.emit("progress", "cache: - hauling revision data", { level: DEBUG });
|
|
73
|
+
const lFileSet = new Set(
|
|
74
|
+
findAllFiles(pDirectory, {
|
|
75
|
+
baseDir: pOptions.baseDir,
|
|
76
|
+
})
|
|
77
|
+
.filter(excludeFilter(pOptions.exclude))
|
|
78
|
+
.filter(includeOnlyFilter(pOptions.includeOnly))
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
bus.emit("progress", "cache: - determining cached vs new", { level: DEBUG });
|
|
82
|
+
const lDiffCachedVsNew = pCachedCruiseResult.modules.map(
|
|
83
|
+
diffCachedModuleAgainstFileSet(lFileSet)
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
bus.emit("progress", "cache: - determining new vs cached", { level: DEBUG });
|
|
87
|
+
lDiffCachedVsNew.forEach(({ name }) => lFileSet.delete(name));
|
|
88
|
+
|
|
89
|
+
const lDiffNewVsCached = [];
|
|
90
|
+
for (let lFileName of lFileSet) {
|
|
91
|
+
lDiffNewVsCached.push({
|
|
92
|
+
name: lFileName,
|
|
93
|
+
changeType: "added",
|
|
94
|
+
checksum: getFileHash(lFileName),
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
bus.emit("progress", "cache: - returning revision data", { level: DEBUG });
|
|
99
|
+
return lDiffCachedVsNew
|
|
100
|
+
.concat(lDiffNewVsCached)
|
|
101
|
+
.filter(hasInterestingExtension(pOptions.extensions));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
*
|
|
106
|
+
* @param {string} pDirectory
|
|
107
|
+
* @param {import("../..").ICruiseResult} pCachedCruiseResult
|
|
108
|
+
* @param {import("../../types/strict-options").IStrictCruiseOptions} pCruiseOptions
|
|
109
|
+
* @param {Object} pOptions
|
|
110
|
+
* @param {Set<string>} pOptions.extensions
|
|
111
|
+
* @param {Set<import("watskeburt").changeTypeType>} pOptions.interestingChangeTypes
|
|
112
|
+
* @param {string} pOptions.baseDir
|
|
113
|
+
* @param {(pString:string) => Array<import("watskeburt").IChange>} pOptions.diffListFn
|
|
114
|
+
* @param {(import("watskeburt").IChange) => import("../..").IRevisionChange} pOptions.checksumFn
|
|
115
|
+
* @returns {import("../..").IRevisionData}
|
|
116
|
+
*/
|
|
117
|
+
function getRevisionData(
|
|
118
|
+
pDirectory,
|
|
119
|
+
pCachedCruiseResult,
|
|
120
|
+
pCruiseOptions,
|
|
121
|
+
pOptions
|
|
122
|
+
) {
|
|
123
|
+
const lOptions = {
|
|
124
|
+
diffListFn: findChanges,
|
|
125
|
+
checksumFn: addCheckSumToChange,
|
|
126
|
+
baseDir: process.cwd(),
|
|
127
|
+
...pOptions,
|
|
128
|
+
};
|
|
129
|
+
return {
|
|
130
|
+
SHA1: "unknown-in-content-cache-strategy",
|
|
131
|
+
changes: lOptions
|
|
132
|
+
.diffListFn(pDirectory, pCachedCruiseResult, {
|
|
133
|
+
baseDir: lOptions.baseDir,
|
|
134
|
+
extensions: lOptions.extensions,
|
|
135
|
+
includeOnly: pCruiseOptions.includeOnly,
|
|
136
|
+
exclude: pCruiseOptions.exclude,
|
|
137
|
+
})
|
|
138
|
+
.filter(isInterestingChangeType(lOptions.interestingChangeTypes)),
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* @param {import("../..").IRevisionData} pExistingRevisionData
|
|
144
|
+
* @param {import("../..").IRevisionData} pNewRevisionData
|
|
145
|
+
* @returns {boolean}
|
|
146
|
+
*/
|
|
147
|
+
function revisionDataEqual(pExistingRevisionData, pNewRevisionData) {
|
|
148
|
+
return (
|
|
149
|
+
Boolean(pExistingRevisionData) &&
|
|
150
|
+
Boolean(pNewRevisionData) &&
|
|
151
|
+
isDeepStrictEqual(pExistingRevisionData.changes, pNewRevisionData.changes)
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* @param {import("../..").IModule} pModule
|
|
157
|
+
* @param {import("../..").IRevisionChange}
|
|
158
|
+
*/
|
|
159
|
+
function addCheckSumToModule(pModule) {
|
|
160
|
+
if (
|
|
161
|
+
!pModule.consolidated &&
|
|
162
|
+
!pModule.coreModule &&
|
|
163
|
+
!pModule.couldNotResolve &&
|
|
164
|
+
!pModule.matchesDoNotFollow
|
|
165
|
+
) {
|
|
166
|
+
return {
|
|
167
|
+
...pModule,
|
|
168
|
+
checksum: getFileHash(pModule.source),
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
return pModule;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* @param {import("../..").IRevisionChange[]} pChanges
|
|
176
|
+
* @param {import("../..").IModule[]} pModules
|
|
177
|
+
* @returns {import("../..").IRevisionChange[]}
|
|
178
|
+
*/
|
|
179
|
+
function refreshChanges(pChanges, pModules) {
|
|
180
|
+
return pChanges.filter(
|
|
181
|
+
(pChange) =>
|
|
182
|
+
!pModules.some(
|
|
183
|
+
(pModule) =>
|
|
184
|
+
pModule.source === pChange.name &&
|
|
185
|
+
pModule.checksum === pChange.checksum
|
|
186
|
+
)
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* @param {import("../..").ICruiseResult} pCruiseResult
|
|
192
|
+
* @param {import("../..").IRevisionData} pRevisionData
|
|
193
|
+
* @returns {import("../..").ICruiseResult}
|
|
194
|
+
*/
|
|
195
|
+
function prepareRevisionDataForSaving(pCruiseResult, pRevisionData) {
|
|
196
|
+
const lModulesWithCheckSum = pCruiseResult.modules.map(addCheckSumToModule);
|
|
197
|
+
const lRevisionData = {
|
|
198
|
+
...pRevisionData,
|
|
199
|
+
changes: refreshChanges(pRevisionData.changes, lModulesWithCheckSum),
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
return pRevisionData
|
|
203
|
+
? {
|
|
204
|
+
...pCruiseResult,
|
|
205
|
+
modules: lModulesWithCheckSum,
|
|
206
|
+
revisionData: lRevisionData,
|
|
207
|
+
}
|
|
208
|
+
: pCruiseResult;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
module.exports = {
|
|
212
|
+
getRevisionData,
|
|
213
|
+
revisionDataEqual,
|
|
214
|
+
prepareRevisionDataForSaving,
|
|
215
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
const { isDeepStrictEqual } = require("util");
|
|
2
|
+
const { getSHASync, listSync } = require("watskeburt");
|
|
3
|
+
const {
|
|
4
|
+
isInterestingChangeType,
|
|
5
|
+
addCheckSumToChange,
|
|
6
|
+
excludeFilter,
|
|
7
|
+
includeOnlyFilter,
|
|
8
|
+
hasInterestingExtension,
|
|
9
|
+
} = require("./utl");
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {Set<string>} pExtensions
|
|
13
|
+
* @param {Set<import("watskeburt").changeTypeType>} pInterestingChangeTypes
|
|
14
|
+
* @param {import("../../types/strict-options").IStrictCruiseOptions} pCruiseOptions
|
|
15
|
+
* @param {Object} pOptions
|
|
16
|
+
* @param {Set<string>} pOptions.extensions
|
|
17
|
+
* @param {Set<import("watskeburt").changeTypeType>} pOptions.interestingChangeTypes
|
|
18
|
+
* @param {() => string} pOptions.shaRetrievalFn
|
|
19
|
+
* @param {(pString:string) => Array<import("watskeburt").IChange>} pOptions.diffListFn
|
|
20
|
+
* @param {(import("watskeburt").IChange) => import("../..").IRevisionChange} pOptions.checksumFn
|
|
21
|
+
* @returns {import("../..").IRevisionData}
|
|
22
|
+
*/
|
|
23
|
+
function getRevisionData(
|
|
24
|
+
pDirectory,
|
|
25
|
+
pCachedCruiseResult,
|
|
26
|
+
pCruiseOptions,
|
|
27
|
+
pOptions
|
|
28
|
+
) {
|
|
29
|
+
const lOptions = {
|
|
30
|
+
shaRetrievalFn: getSHASync,
|
|
31
|
+
diffListFn: listSync,
|
|
32
|
+
checksumFn: addCheckSumToChange,
|
|
33
|
+
...pOptions,
|
|
34
|
+
};
|
|
35
|
+
try {
|
|
36
|
+
const lSHA = lOptions.shaRetrievalFn();
|
|
37
|
+
return {
|
|
38
|
+
SHA1: lSHA,
|
|
39
|
+
changes: lOptions
|
|
40
|
+
.diffListFn(lSHA)
|
|
41
|
+
.filter(({ name }) => excludeFilter(pCruiseOptions.exclude)(name))
|
|
42
|
+
.filter(({ name }) =>
|
|
43
|
+
includeOnlyFilter(pCruiseOptions.includeOnly)(name)
|
|
44
|
+
)
|
|
45
|
+
.filter(hasInterestingExtension(lOptions.extensions))
|
|
46
|
+
.filter(isInterestingChangeType(lOptions.interestingChangeTypes))
|
|
47
|
+
.map(lOptions.checksumFn),
|
|
48
|
+
};
|
|
49
|
+
} catch (pError) {
|
|
50
|
+
throw new Error(
|
|
51
|
+
"The --cache option works in concert with git - and it seems either the " +
|
|
52
|
+
"current folder isn't version managed or git isn't installed. Error:" +
|
|
53
|
+
`\n\n ${pError}\n`
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @param {import("../..").IRevisionData} pExistingRevisionData
|
|
60
|
+
* @param {import("../..").IRevisionData} pNewRevisionData
|
|
61
|
+
* @returns {boolean}
|
|
62
|
+
*/
|
|
63
|
+
function revisionDataEqual(pExistingRevisionData, pNewRevisionData) {
|
|
64
|
+
return (
|
|
65
|
+
Boolean(pExistingRevisionData) &&
|
|
66
|
+
Boolean(pNewRevisionData) &&
|
|
67
|
+
pExistingRevisionData.SHA1 === pNewRevisionData.SHA1 &&
|
|
68
|
+
isDeepStrictEqual(pExistingRevisionData.changes, pNewRevisionData.changes)
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @param {import("../..").ICruiseResult} pCruiseResult
|
|
74
|
+
* @param {import("../..").IRevisionData} pRevisionData
|
|
75
|
+
* @returns {import("../..").ICruiseResult}
|
|
76
|
+
*/
|
|
77
|
+
function prepareRevisionDataForSaving(pCruiseResult, pRevisionData) {
|
|
78
|
+
return pRevisionData
|
|
79
|
+
? {
|
|
80
|
+
...pCruiseResult,
|
|
81
|
+
revisionData: pRevisionData,
|
|
82
|
+
}
|
|
83
|
+
: pCruiseResult;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
module.exports = {
|
|
87
|
+
getRevisionData,
|
|
88
|
+
revisionDataEqual,
|
|
89
|
+
prepareRevisionDataForSaving,
|
|
90
|
+
};
|
|
@@ -6,7 +6,7 @@ const { isDeepStrictEqual } = require("util");
|
|
|
6
6
|
-i, --info
|
|
7
7
|
-V, --version
|
|
8
8
|
-h, --help
|
|
9
|
-
-T, --output-type <type> unless counting implicit shizzle like
|
|
9
|
+
-T, --output-type <type> unless counting implicit shizzle like dependents, metrics calculation
|
|
10
10
|
-f, --output-to <file>
|
|
11
11
|
-p, --progress [type]
|
|
12
12
|
-P, --prefix <prefix>
|
|
@@ -123,9 +123,9 @@ function optionsAreCompatible(pOldOptions, pNewOptions) {
|
|
|
123
123
|
|
|
124
124
|
module.exports = {
|
|
125
125
|
optionsAreCompatible,
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
126
|
+
optionIsCompatible,
|
|
127
|
+
limitIsCompatible,
|
|
128
|
+
metricsIsCompatible,
|
|
129
|
+
includeOnlyIsCompatible,
|
|
130
130
|
cacheOptionIsCompatible,
|
|
131
131
|
};
|
package/src/cache/utl.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
const { createHash } = require("crypto");
|
|
2
2
|
const { readFileSync } = require("fs");
|
|
3
|
+
const path = require("path");
|
|
4
|
+
const memoize = require("lodash/memoize");
|
|
5
|
+
const { filenameMatchesPattern } = require("../graph-utl/match-facade");
|
|
3
6
|
|
|
4
7
|
/**
|
|
5
8
|
* @param {string} pString
|
|
@@ -13,7 +16,7 @@ function hash(pString) {
|
|
|
13
16
|
* @param {import("fs").PathOrFileDescriptor} pFileName
|
|
14
17
|
* @returns {string}
|
|
15
18
|
*/
|
|
16
|
-
function
|
|
19
|
+
function _getFileHash(pFileName) {
|
|
17
20
|
try {
|
|
18
21
|
return hash(readFileSync(pFileName, "utf8"));
|
|
19
22
|
} catch (pError) {
|
|
@@ -21,4 +24,84 @@ function getFileHash(pFileName) {
|
|
|
21
24
|
}
|
|
22
25
|
}
|
|
23
26
|
|
|
24
|
-
|
|
27
|
+
const getFileHash = memoize(_getFileHash);
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @param {import("watskeburt").IChange} pChange
|
|
31
|
+
* @param {import("../..").IRevisionChange}
|
|
32
|
+
*/
|
|
33
|
+
function addCheckSumToChange(pChange) {
|
|
34
|
+
return {
|
|
35
|
+
...pChange,
|
|
36
|
+
checksum: getFileHash(pChange.name),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
*
|
|
42
|
+
* @param {import("../../types/strict-filter-types").IStrictExcludeType} pExcludeOption
|
|
43
|
+
* @returns {(pFileName: string) => boolean}
|
|
44
|
+
*/
|
|
45
|
+
function excludeFilter(pExcludeOption) {
|
|
46
|
+
return (pFileName) => {
|
|
47
|
+
if (pExcludeOption.path) {
|
|
48
|
+
return !filenameMatchesPattern(pFileName, pExcludeOption.path);
|
|
49
|
+
}
|
|
50
|
+
return true;
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @param {import("../../types/strict-filter-types").IStrictIncludeOnlyType} pIncludeOnlyFilter
|
|
56
|
+
* @returns {(pFileName: string) => boolean}
|
|
57
|
+
*/
|
|
58
|
+
function includeOnlyFilter(pIncludeOnlyFilter) {
|
|
59
|
+
return (pFileName) => {
|
|
60
|
+
if (pIncludeOnlyFilter) {
|
|
61
|
+
return filenameMatchesPattern(pFileName, pIncludeOnlyFilter.path);
|
|
62
|
+
}
|
|
63
|
+
return true;
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @param {Set<string>} pExtensions
|
|
69
|
+
* @returns {(pChange: import("watskeburt").IChange) => boolean}
|
|
70
|
+
*/
|
|
71
|
+
function hasInterestingExtension(pExtensions) {
|
|
72
|
+
return (pChange) =>
|
|
73
|
+
pExtensions.has(path.extname(pChange.name)) ||
|
|
74
|
+
(pChange.oldName && pExtensions.has(path.extname(pChange.oldName)));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// skipping: "pairing broken", "unmodified", "unmerged", "type changed"
|
|
78
|
+
const DEFAULT_INTERESTING_CHANGE_TYPES = new Set([
|
|
79
|
+
"added",
|
|
80
|
+
"copied",
|
|
81
|
+
"deleted",
|
|
82
|
+
"ignored",
|
|
83
|
+
"modified",
|
|
84
|
+
"renamed",
|
|
85
|
+
"unmerged",
|
|
86
|
+
"untracked",
|
|
87
|
+
]);
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* @param {Set<import("watskeburt").changeTypeType>} pInterestingChangeTypes
|
|
91
|
+
* @returns {(pChange: import("watskeburt").IChange) => boolean}
|
|
92
|
+
*/
|
|
93
|
+
function isInterestingChangeType(pInterestingChangeTypes) {
|
|
94
|
+
return (pChange) =>
|
|
95
|
+
(pInterestingChangeTypes ?? DEFAULT_INTERESTING_CHANGE_TYPES).has(
|
|
96
|
+
pChange.changeType
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
module.exports = {
|
|
101
|
+
getFileHash,
|
|
102
|
+
excludeFilter,
|
|
103
|
+
includeOnlyFilter,
|
|
104
|
+
hasInterestingExtension,
|
|
105
|
+
isInterestingChangeType,
|
|
106
|
+
addCheckSumToChange,
|
|
107
|
+
};
|
package/src/main/index.js
CHANGED
|
@@ -6,12 +6,7 @@ const enrich = require("../enrich");
|
|
|
6
6
|
const cruiseResultSchema = require("../schema/cruise-result.schema.js");
|
|
7
7
|
const meta = require("../extract/transpile/meta");
|
|
8
8
|
const bus = require("../utl/bus");
|
|
9
|
-
const
|
|
10
|
-
canServeFromCache,
|
|
11
|
-
readCache,
|
|
12
|
-
writeCache,
|
|
13
|
-
clearCache,
|
|
14
|
-
} = require("../cache/cache");
|
|
9
|
+
const Cache = require("../cache/cache");
|
|
15
10
|
const normalizeFilesAndDirectories = require("./files-and-dirs/normalize");
|
|
16
11
|
const validateRuleSet = require("./rule-set/validate");
|
|
17
12
|
const normalizeRuleSet = require("./rule-set/normalize");
|
|
@@ -65,13 +60,15 @@ function futureCruise(
|
|
|
65
60
|
validateCruiseOptions(pCruiseOptions),
|
|
66
61
|
pFileAndDirectoryArray
|
|
67
62
|
);
|
|
63
|
+
let lCache = null;
|
|
68
64
|
|
|
69
65
|
if (lCruiseOptions.cache) {
|
|
70
66
|
bus.emit("progress", "cache: checking freshness", c(2));
|
|
71
67
|
|
|
72
|
-
|
|
68
|
+
lCache = new Cache(lCruiseOptions?.cache.strategy);
|
|
69
|
+
const lCachedResults = lCache.read(lCruiseOptions.cache.folder);
|
|
73
70
|
|
|
74
|
-
if (canServeFromCache(lCruiseOptions, lCachedResults)) {
|
|
71
|
+
if (lCache.canServeFromCache(lCruiseOptions, lCachedResults)) {
|
|
75
72
|
bus.emit("progress", "cache: reporting from cache", c(8));
|
|
76
73
|
return reportWrap(lCachedResults, lCruiseOptions);
|
|
77
74
|
}
|
|
@@ -112,8 +109,7 @@ function futureCruise(
|
|
|
112
109
|
|
|
113
110
|
if (lCruiseOptions.cache) {
|
|
114
111
|
bus.emit("progress", "cache: saving", c(7));
|
|
115
|
-
|
|
116
|
-
clearCache();
|
|
112
|
+
lCache.write(lCruiseOptions.cache.folder, lCruiseResult);
|
|
117
113
|
}
|
|
118
114
|
|
|
119
115
|
bus.emit("progress", "reporting", c(8));
|
package/src/meta.js
CHANGED
package/types/cache-options.d.ts
CHANGED
|
@@ -12,9 +12,9 @@ export interface ICacheOptions {
|
|
|
12
12
|
* - 'metadata': use git metadata to detect changes;
|
|
13
13
|
* - 'content': use (a checksum of) the contents of files to detect changes.
|
|
14
14
|
*
|
|
15
|
-
*
|
|
16
|
-
* (which is typical on CI's). Trade-of:
|
|
17
|
-
*
|
|
15
|
+
* 'content'is useful if you're not on git or work on partial clones
|
|
16
|
+
* (which is typical on CI's). Trade-of: the 'content' strategy is typically
|
|
17
|
+
* slower.
|
|
18
18
|
*
|
|
19
19
|
* Defaults to 'metadata'
|
|
20
20
|
*/
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
const { extname } = require("path");
|
|
2
|
-
const { isDeepStrictEqual } = require("util");
|
|
3
|
-
const { getSHASync, listSync } = require("watskeburt");
|
|
4
|
-
const { getFileHash } = require("./utl");
|
|
5
|
-
|
|
6
|
-
// skipping: "pairing broken", "unmodified", "unmerged", "type changed"
|
|
7
|
-
const DEFAULT_INTERESTING_CHANGE_TYPES = new Set([
|
|
8
|
-
"added",
|
|
9
|
-
"copied",
|
|
10
|
-
"deleted",
|
|
11
|
-
"ignored",
|
|
12
|
-
"modified",
|
|
13
|
-
"renamed",
|
|
14
|
-
"unmerged",
|
|
15
|
-
"untracked",
|
|
16
|
-
]);
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
*
|
|
20
|
-
* @param {Set<string>} pExtensions
|
|
21
|
-
* @returns {(pChange: import("watskeburt").IChange) => boolean}
|
|
22
|
-
*/
|
|
23
|
-
function hasInterestingExtension(pExtensions) {
|
|
24
|
-
return (pChange) =>
|
|
25
|
-
pExtensions.has(extname(pChange.name)) ||
|
|
26
|
-
(pChange.oldName && pExtensions.has(extname(pChange.oldName)));
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
*
|
|
31
|
-
* @param {Set<import("watskeburt").changeTypeType>} pInterestingChangeTypes
|
|
32
|
-
* @returns {(pChange: import("watskeburt").IChange) => boolean}
|
|
33
|
-
*/
|
|
34
|
-
function isInterestingChangeType(pInterestingChangeTypes) {
|
|
35
|
-
return (pChange) => pInterestingChangeTypes.has(pChange.changeType);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* @param {import("watskeburt").IChange} pChange
|
|
40
|
-
* @param {import("../../types/dependency-cruiser").IRevisionChange}
|
|
41
|
-
*/
|
|
42
|
-
function addChecksum(pChange) {
|
|
43
|
-
return {
|
|
44
|
-
...pChange,
|
|
45
|
-
checksum: getFileHash(pChange.name),
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
*
|
|
51
|
-
* @param {Set<string>} pExtensions
|
|
52
|
-
* @param {Set<import("watskeburt").changeTypeType>} pInterestingChangeTypes
|
|
53
|
-
* @param {Object} pOptions
|
|
54
|
-
* @param {() => string} pOptions.shaRetrievalFn
|
|
55
|
-
* @param {(pString:string) => Array<import("watskeburt").IChange>} pOptions.diffListFn
|
|
56
|
-
* @param {(import("watskeburt").IChange) => import("../..").IRevisionChange} pOptions.checkSumFn
|
|
57
|
-
* @returns {import("../../types/dependency-cruiser").IRevisionData}
|
|
58
|
-
*/
|
|
59
|
-
function getRevisionData(
|
|
60
|
-
pExtensions,
|
|
61
|
-
pInterestingChangeTypes = DEFAULT_INTERESTING_CHANGE_TYPES,
|
|
62
|
-
pOptions
|
|
63
|
-
) {
|
|
64
|
-
const lOptions = {
|
|
65
|
-
shaRetrievalFn: getSHASync,
|
|
66
|
-
diffListFn: listSync,
|
|
67
|
-
checkSumFn: addChecksum,
|
|
68
|
-
...pOptions,
|
|
69
|
-
};
|
|
70
|
-
try {
|
|
71
|
-
const lSHA = lOptions.shaRetrievalFn();
|
|
72
|
-
return {
|
|
73
|
-
SHA1: lSHA,
|
|
74
|
-
changes: lOptions
|
|
75
|
-
.diffListFn(lSHA)
|
|
76
|
-
.filter(hasInterestingExtension(pExtensions))
|
|
77
|
-
.filter(isInterestingChangeType(pInterestingChangeTypes))
|
|
78
|
-
.map(lOptions.checkSumFn),
|
|
79
|
-
};
|
|
80
|
-
} catch (pError) {
|
|
81
|
-
throw new Error(
|
|
82
|
-
"The --cache option works in concert with git - and it seems either the " +
|
|
83
|
-
"current folder isn't version managed or git isn't installed. Error:" +
|
|
84
|
-
`\n\n ${pError}\n`
|
|
85
|
-
);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* @param {import("../../types/dependency-cruiser").IRevisionData} pExistingRevisionData
|
|
91
|
-
* @param {import("../../types/dependency-cruiser").IRevisionData} pNewRevisionData
|
|
92
|
-
* @returns {boolean}
|
|
93
|
-
*/
|
|
94
|
-
function revisionDataEqual(pExistingRevisionData, pNewRevisionData) {
|
|
95
|
-
return (
|
|
96
|
-
Boolean(pExistingRevisionData) &&
|
|
97
|
-
Boolean(pNewRevisionData) &&
|
|
98
|
-
pExistingRevisionData.SHA1 === pNewRevisionData.SHA1 &&
|
|
99
|
-
isDeepStrictEqual(pExistingRevisionData.changes, pNewRevisionData.changes)
|
|
100
|
-
);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
module.exports = {
|
|
104
|
-
getRevisionData,
|
|
105
|
-
revisionDataEqual,
|
|
106
|
-
};
|