@codacy/analysis-runner 0.19.0 → 0.21.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/dist/index.d.ts +41 -1
- package/dist/index.js +158 -32
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -218,14 +218,54 @@ declare function readBaselineConfig(repositoryRoot: string, configFile?: string)
|
|
|
218
218
|
* {@link resolveBaselinePath}). No `.codacy/` side effects. Callers write this
|
|
219
219
|
* after every `init`/`update-config` so the next update diffs against the exact
|
|
220
220
|
* generator output. Returns the path written.
|
|
221
|
+
*
|
|
222
|
+
* Config paths are relativized exactly as in {@link writeCodacyConfigFile} — the
|
|
223
|
+
* baseline is compared against the config it snapshots, so the two must agree on
|
|
224
|
+
* the stored form.
|
|
221
225
|
*/
|
|
222
226
|
declare function writeBaselineConfig(repositoryRoot: string, config: CodacyConfig, configFile?: string): Promise<string>;
|
|
227
|
+
/**
|
|
228
|
+
* Rewrites every tool's `localConfigurationFile` to its repository-relative form,
|
|
229
|
+
* for serialization.
|
|
230
|
+
*
|
|
231
|
+
* Adapters detect their native config by joining `ctx.repositoryRoot`, so the
|
|
232
|
+
* in-memory value is absolute — and an absolute path names the machine that ran
|
|
233
|
+
* `init` (`/Users/someone/dev/repo/eslint.config.mjs`). Serializing it verbatim made
|
|
234
|
+
* `codacy.config.json` unshareable: committed and cloned elsewhere, every tool
|
|
235
|
+
* pointed at a directory that does not exist. The stored form is therefore relative
|
|
236
|
+
* (`eslint.config.mjs`), and {@link resolveLocalConfigPaths} restores absolute paths
|
|
237
|
+
* on read, so adapters see no difference.
|
|
238
|
+
*
|
|
239
|
+
* Returns a copy rather than mutating: `init` and `update-config` keep using the
|
|
240
|
+
* config object after writing it (baseline snapshot, summary output), and they need
|
|
241
|
+
* the resolved paths.
|
|
242
|
+
*/
|
|
243
|
+
declare function relativizeLocalConfigPaths(config: CodacyConfig, repositoryRoot: string): CodacyConfig;
|
|
244
|
+
/**
|
|
245
|
+
* Resolves every stored `localConfigurationFile` against `repositoryRoot`, so
|
|
246
|
+
* adapters always receive an absolute path regardless of how the file on disk
|
|
247
|
+
* stored it.
|
|
248
|
+
*
|
|
249
|
+
* `path.resolve` covers both forms with no branching: a repo-relative path is
|
|
250
|
+
* joined to the root, and a legacy absolute path — written by a CLI version that
|
|
251
|
+
* serialized paths verbatim — is returned unchanged. Such a path is only usable on
|
|
252
|
+
* the machine that produced it; that is the pre-existing breakage this normalization
|
|
253
|
+
* stops from spreading further, not one it can repair.
|
|
254
|
+
*
|
|
255
|
+
* Mutates in place, like {@link coerceParameterValues}: both run on a config that
|
|
256
|
+
* was just parsed and has no other owner yet.
|
|
257
|
+
*/
|
|
258
|
+
declare function resolveLocalConfigPaths(config: CodacyConfig, repositoryRoot: string): void;
|
|
223
259
|
/**
|
|
224
260
|
* Writes a CodacyConfig to disk at the exact resolved path, creating only the
|
|
225
261
|
* parent directory. Unlike {@link writeCodacyConfig}, this has NO `.codacy/`
|
|
226
262
|
* side effects, so it is safe to write to an arbitrary location (e.g. a scratch
|
|
227
263
|
* config a user is experimenting with).
|
|
228
264
|
*
|
|
265
|
+
* Per-tool `localConfigurationFile` paths are stored relative to `repositoryRoot`
|
|
266
|
+
* so the written file stays machine-independent — see
|
|
267
|
+
* {@link relativizeLocalConfigPaths}.
|
|
268
|
+
*
|
|
229
269
|
* Pass `configFile` to write to a non-default location.
|
|
230
270
|
*/
|
|
231
271
|
declare function writeCodacyConfigFile(repositoryRoot: string, config: CodacyConfig, configFile?: string): Promise<string>;
|
|
@@ -1184,4 +1224,4 @@ declare function buildPayloads(issues: NormalizedIssue[], resolveShortName: (too
|
|
|
1184
1224
|
*/
|
|
1185
1225
|
declare function uploadReport(options: UploadOptions): Promise<UploadResult>;
|
|
1186
1226
|
|
|
1187
|
-
export { type AdapterFactory, type AnalyzeOptions, type AutoFilters, type CategoryFilter, type CodacyYamlConfig, type CodacyYamlEngineConfig, type ConfigOperation, type DiscoverOptions, type DiscoveryExcludes, type ExecutionMode, type IgnoredFilesResult, type InitAutoStats, type InitDefaultStats, type InitDiscoveryOptions, type InitLocalStats, type InitRemoteStats, type LoggerOptions, type MergeOptions, type NormalizedIssue, type PatternMetadataLookup, type RemoteAuth, type SeverityFilter, type UploadAuth, type UploadOptions, type UploadResult, analyze, applyCodacyYamlExcludes, applyConfigOperation, buildPayloads, buildToolConfig, clearAdapters, computePatternSummary, configureApiToken, createCodacyConfig, createLogger, createNullLogger, deleteCredentials, detectLanguages, diffConfigs, discover, formatOutput, formatTextSummary, getAdapter, getKnownDisplayNames, getRegisteredAdapters, getRegisteredDescriptors, initAutoConfig, initContainerConfig, initDefaultConfig, initLocalConfig, initRemoteConfig, intersectConfigs, listDiffFiles, listIgnoredFiles, listPrFiles, listStagedFiles, loadCredentials, mergeConfigs, parseAutoFilters, parseReport, pruneEmptyTools, readBaselineConfig, readCodacyConfig, readCodacyYaml, registerAdapter, registerLazyAdapter, registerUnsupportedTool, resolveApiToken, resolveBaselinePath, resolveConfigPath, resolveDiscoveryExcludes, resolveEngineToAdapter, resolveHeadCommit, resolveRemoteAuth, resolveRepositoryRoot, resolveResultsApiBaseUrl, rotateLogFiles, saveCredentials, updateConfigIncremental, uploadReport, validateApiToken, writeBaselineConfig, writeCodacyConfig, writeCodacyConfigFile };
|
|
1227
|
+
export { type AdapterFactory, type AnalyzeOptions, type AutoFilters, type CategoryFilter, type CodacyYamlConfig, type CodacyYamlEngineConfig, type ConfigOperation, type DiscoverOptions, type DiscoveryExcludes, type ExecutionMode, type IgnoredFilesResult, type InitAutoStats, type InitDefaultStats, type InitDiscoveryOptions, type InitLocalStats, type InitRemoteStats, type LoggerOptions, type MergeOptions, type NormalizedIssue, type PatternMetadataLookup, type RemoteAuth, type SeverityFilter, type UploadAuth, type UploadOptions, type UploadResult, analyze, applyCodacyYamlExcludes, applyConfigOperation, buildPayloads, buildToolConfig, clearAdapters, computePatternSummary, configureApiToken, createCodacyConfig, createLogger, createNullLogger, deleteCredentials, detectLanguages, diffConfigs, discover, formatOutput, formatTextSummary, getAdapter, getKnownDisplayNames, getRegisteredAdapters, getRegisteredDescriptors, initAutoConfig, initContainerConfig, initDefaultConfig, initLocalConfig, initRemoteConfig, intersectConfigs, listDiffFiles, listIgnoredFiles, listPrFiles, listStagedFiles, loadCredentials, mergeConfigs, parseAutoFilters, parseReport, pruneEmptyTools, readBaselineConfig, readCodacyConfig, readCodacyYaml, registerAdapter, registerLazyAdapter, registerUnsupportedTool, relativizeLocalConfigPaths, resolveApiToken, resolveBaselinePath, resolveConfigPath, resolveDiscoveryExcludes, resolveEngineToAdapter, resolveHeadCommit, resolveLocalConfigPaths, resolveRemoteAuth, resolveRepositoryRoot, resolveResultsApiBaseUrl, rotateLogFiles, saveCredentials, updateConfigIncremental, uploadReport, validateApiToken, writeBaselineConfig, writeCodacyConfig, writeCodacyConfigFile };
|
package/dist/index.js
CHANGED
|
@@ -73,12 +73,14 @@ __export(index_exports, {
|
|
|
73
73
|
registerAdapter: () => registerAdapter,
|
|
74
74
|
registerLazyAdapter: () => registerLazyAdapter,
|
|
75
75
|
registerUnsupportedTool: () => registerUnsupportedTool,
|
|
76
|
+
relativizeLocalConfigPaths: () => relativizeLocalConfigPaths,
|
|
76
77
|
resolveApiToken: () => resolveApiToken,
|
|
77
78
|
resolveBaselinePath: () => resolveBaselinePath,
|
|
78
79
|
resolveConfigPath: () => resolveConfigPath,
|
|
79
80
|
resolveDiscoveryExcludes: () => resolveDiscoveryExcludes,
|
|
80
81
|
resolveEngineToAdapter: () => resolveEngineToAdapter,
|
|
81
82
|
resolveHeadCommit: () => resolveHeadCommit,
|
|
83
|
+
resolveLocalConfigPaths: () => resolveLocalConfigPaths,
|
|
82
84
|
resolveProxyConfig: () => import_tooling8.resolveProxyConfig,
|
|
83
85
|
resolveRemoteAuth: () => resolveRemoteAuth,
|
|
84
86
|
resolveRepositoryRoot: () => resolveRepositoryRoot,
|
|
@@ -177,7 +179,7 @@ function resolveBaselinePath(repositoryRoot, configFile) {
|
|
|
177
179
|
const stem = import_path.default.basename(configPath, ext);
|
|
178
180
|
return import_path.default.join(dir, `${stem}.baseline${ext}`);
|
|
179
181
|
}
|
|
180
|
-
async function readConfigAtPath(configPath) {
|
|
182
|
+
async function readConfigAtPath(configPath, repositoryRoot) {
|
|
181
183
|
let raw;
|
|
182
184
|
try {
|
|
183
185
|
raw = await import_promises.default.readFile(configPath, "utf-8");
|
|
@@ -192,21 +194,91 @@ async function readConfigAtPath(configPath) {
|
|
|
192
194
|
throw new Error(`Invalid config at ${configPath}: expected a JSON object`);
|
|
193
195
|
}
|
|
194
196
|
const config = parsed;
|
|
197
|
+
assertConfigShape(config, configPath);
|
|
195
198
|
coerceParameterValues(config);
|
|
199
|
+
resolveLocalConfigPaths(config, repositoryRoot);
|
|
196
200
|
return config;
|
|
197
201
|
}
|
|
202
|
+
function assertConfigShape(config, configPath) {
|
|
203
|
+
const fail = (detail) => {
|
|
204
|
+
throw new Error(`Invalid config at ${configPath}: ${detail}`);
|
|
205
|
+
};
|
|
206
|
+
const isStringArray = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
207
|
+
if (config.exclude !== void 0 && !isStringArray(config.exclude))
|
|
208
|
+
fail(`"exclude" must be an array of strings`);
|
|
209
|
+
if (config.includeFiles !== void 0 && !isStringArray(config.includeFiles))
|
|
210
|
+
fail(`"includeFiles" must be an array of strings`);
|
|
211
|
+
if (!Array.isArray(config.tools)) fail(`"tools" must be an array`);
|
|
212
|
+
config.tools.forEach((tool, i) => {
|
|
213
|
+
const at = `tools[${i}]`;
|
|
214
|
+
if (typeof tool !== "object" || tool === null || Array.isArray(tool))
|
|
215
|
+
fail(`${at} must be an object`);
|
|
216
|
+
if (typeof tool.toolId !== "string" || tool.toolId === "")
|
|
217
|
+
fail(`${at}.toolId must be a non-empty string`);
|
|
218
|
+
if (tool.localConfigurationFile !== void 0 && typeof tool.localConfigurationFile !== "string")
|
|
219
|
+
fail(`${at}.localConfigurationFile must be a string ("${tool.toolId}")`);
|
|
220
|
+
if (tool.exclude !== void 0 && !isStringArray(tool.exclude))
|
|
221
|
+
fail(`${at}.exclude must be an array of strings ("${tool.toolId}")`);
|
|
222
|
+
if (tool.extraFilePatterns !== void 0 && !isStringArray(tool.extraFilePatterns))
|
|
223
|
+
fail(`${at}.extraFilePatterns must be an array of strings ("${tool.toolId}")`);
|
|
224
|
+
if (!Array.isArray(tool.patterns)) fail(`${at}.patterns must be an array ("${tool.toolId}")`);
|
|
225
|
+
tool.patterns.forEach((pattern, j) => {
|
|
226
|
+
const patternAt = `${at}.patterns[${j}]`;
|
|
227
|
+
if (typeof pattern !== "object" || pattern === null || Array.isArray(pattern))
|
|
228
|
+
fail(`${patternAt} must be an object`);
|
|
229
|
+
if (typeof pattern.patternId !== "string" || pattern.patternId === "")
|
|
230
|
+
fail(`${patternAt}.patternId must be a non-empty string`);
|
|
231
|
+
if (pattern.parameters === void 0) return;
|
|
232
|
+
if (typeof pattern.parameters !== "object" || pattern.parameters === null || Array.isArray(pattern.parameters))
|
|
233
|
+
fail(`${patternAt}.parameters must be an object ("${pattern.patternId}")`);
|
|
234
|
+
for (const [name, value] of Object.entries(pattern.parameters)) {
|
|
235
|
+
const isPrimitive = typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
236
|
+
if (!isPrimitive)
|
|
237
|
+
fail(
|
|
238
|
+
`${patternAt}.parameters.${name} must be a string, number, or boolean ("${pattern.patternId}")`
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
});
|
|
243
|
+
}
|
|
198
244
|
async function readCodacyConfig(repositoryRoot, configFile) {
|
|
199
|
-
return readConfigAtPath(resolveConfigPath(repositoryRoot, configFile));
|
|
245
|
+
return readConfigAtPath(resolveConfigPath(repositoryRoot, configFile), repositoryRoot);
|
|
200
246
|
}
|
|
201
247
|
async function readBaselineConfig(repositoryRoot, configFile) {
|
|
202
|
-
return readConfigAtPath(resolveBaselinePath(repositoryRoot, configFile));
|
|
248
|
+
return readConfigAtPath(resolveBaselinePath(repositoryRoot, configFile), repositoryRoot);
|
|
203
249
|
}
|
|
204
250
|
async function writeBaselineConfig(repositoryRoot, config, configFile) {
|
|
205
251
|
const baselinePath = resolveBaselinePath(repositoryRoot, configFile);
|
|
252
|
+
const serializable = relativizeLocalConfigPaths(config, repositoryRoot);
|
|
206
253
|
await import_promises.default.mkdir(import_path.default.dirname(baselinePath), { recursive: true });
|
|
207
|
-
await import_promises.default.writeFile(baselinePath, JSON.stringify(
|
|
254
|
+
await import_promises.default.writeFile(baselinePath, JSON.stringify(serializable, null, 2) + "\n");
|
|
208
255
|
return baselinePath;
|
|
209
256
|
}
|
|
257
|
+
function toRepoRelativeConfigPath(configFilePath, repositoryRoot) {
|
|
258
|
+
const normalized = configFilePath.replace(/\\/g, "/");
|
|
259
|
+
if (!import_path.default.isAbsolute(configFilePath)) return normalized;
|
|
260
|
+
const relative = import_path.default.relative(repositoryRoot, configFilePath);
|
|
261
|
+
const escapesRoot = relative === ".." || relative.startsWith(`..${import_path.default.sep}`);
|
|
262
|
+
if (!relative || escapesRoot || import_path.default.isAbsolute(relative)) return normalized;
|
|
263
|
+
return relative.replace(/\\/g, "/");
|
|
264
|
+
}
|
|
265
|
+
function relativizeLocalConfigPaths(config, repositoryRoot) {
|
|
266
|
+
const root = import_path.default.resolve(repositoryRoot);
|
|
267
|
+
return {
|
|
268
|
+
...config,
|
|
269
|
+
tools: config.tools.map((tool) => {
|
|
270
|
+
if (!tool.localConfigurationFile) return tool;
|
|
271
|
+
const relative = toRepoRelativeConfigPath(tool.localConfigurationFile, root);
|
|
272
|
+
return relative === tool.localConfigurationFile ? tool : { ...tool, localConfigurationFile: relative };
|
|
273
|
+
})
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
function resolveLocalConfigPaths(config, repositoryRoot) {
|
|
277
|
+
for (const tool of config.tools) {
|
|
278
|
+
if (!tool.localConfigurationFile) continue;
|
|
279
|
+
tool.localConfigurationFile = import_path.default.resolve(repositoryRoot, tool.localConfigurationFile);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
210
282
|
function coerceParameterValues(config) {
|
|
211
283
|
for (const tool of config.tools) {
|
|
212
284
|
for (const pattern of tool.patterns) {
|
|
@@ -221,8 +293,9 @@ function coerceParameterValues(config) {
|
|
|
221
293
|
}
|
|
222
294
|
async function writeCodacyConfigFile(repositoryRoot, config, configFile) {
|
|
223
295
|
const configPath = resolveConfigPath(repositoryRoot, configFile);
|
|
296
|
+
const serializable = relativizeLocalConfigPaths(config, repositoryRoot);
|
|
224
297
|
await import_promises.default.mkdir(import_path.default.dirname(configPath), { recursive: true });
|
|
225
|
-
await import_promises.default.writeFile(configPath, JSON.stringify(
|
|
298
|
+
await import_promises.default.writeFile(configPath, JSON.stringify(serializable, null, 2) + "\n");
|
|
226
299
|
return configPath;
|
|
227
300
|
}
|
|
228
301
|
async function writeCodacyConfig(repositoryRoot, config, configFile) {
|
|
@@ -7990,13 +8063,15 @@ async function initAutoConfig(repositoryRoot, adapters, descriptors, filters, on
|
|
|
7990
8063
|
toolId: adapter.id,
|
|
7991
8064
|
patterns: selectedPatterns.map((p) => ({ patternId: p.id }))
|
|
7992
8065
|
};
|
|
7993
|
-
|
|
7994
|
-
await applyAdapterParameterSuggestions(
|
|
8066
|
+
await applyAdapterConfigSuggestions(
|
|
7995
8067
|
adapter,
|
|
7996
8068
|
toolEntry,
|
|
7997
8069
|
repositoryRoot,
|
|
7998
|
-
filesVisibleTo(adapter.id)
|
|
8070
|
+
filesVisibleTo(adapter.id),
|
|
8071
|
+
repoLanguages,
|
|
8072
|
+
filters
|
|
7999
8073
|
);
|
|
8074
|
+
if (toolEntry.patterns.length > 0) tools.push(toolEntry);
|
|
8000
8075
|
}
|
|
8001
8076
|
}
|
|
8002
8077
|
let selectedUnsupported = 0;
|
|
@@ -8049,8 +8124,8 @@ async function initAutoConfig(repositoryRoot, adapters, descriptors, filters, on
|
|
|
8049
8124
|
}
|
|
8050
8125
|
};
|
|
8051
8126
|
}
|
|
8052
|
-
async function
|
|
8053
|
-
if (!adapter.
|
|
8127
|
+
async function applyAdapterConfigSuggestions(adapter, toolEntry, repositoryRoot, repoFiles, repoLanguages, filters) {
|
|
8128
|
+
if (!adapter.suggestConfiguration) return;
|
|
8054
8129
|
const logger = {
|
|
8055
8130
|
debug() {
|
|
8056
8131
|
},
|
|
@@ -8075,15 +8150,38 @@ async function applyAdapterParameterSuggestions(adapter, toolEntry, repositoryRo
|
|
|
8075
8150
|
logger,
|
|
8076
8151
|
runner: "local"
|
|
8077
8152
|
};
|
|
8078
|
-
const
|
|
8079
|
-
if (!
|
|
8080
|
-
|
|
8081
|
-
|
|
8082
|
-
|
|
8083
|
-
|
|
8153
|
+
const suggestion = await adapter.suggestConfiguration(ctx);
|
|
8154
|
+
if (!suggestion) return;
|
|
8155
|
+
const staticSelection = toolEntry.patterns;
|
|
8156
|
+
if (suggestion.disablePatterns?.length) {
|
|
8157
|
+
const drop = new Set(suggestion.disablePatterns);
|
|
8158
|
+
toolEntry.patterns = toolEntry.patterns.filter((p) => !drop.has(p.patternId));
|
|
8159
|
+
}
|
|
8160
|
+
if (suggestion.enablePatterns?.length) {
|
|
8161
|
+
const { severityFilter, categoryFilter } = buildFilterLookups(filters);
|
|
8162
|
+
const metadata = new Map((adapter.patternsMetadata ?? []).map((p) => [p.id, p]));
|
|
8163
|
+
const present = new Set(toolEntry.patterns.map((p) => p.patternId));
|
|
8164
|
+
for (const patternId of suggestion.enablePatterns) {
|
|
8165
|
+
if (present.has(patternId)) continue;
|
|
8166
|
+
const pattern = metadata.get(patternId);
|
|
8167
|
+
if (!pattern) continue;
|
|
8168
|
+
if (!passesSelectionGates(pattern, repoLanguages, severityFilter, categoryFilter)) continue;
|
|
8169
|
+
toolEntry.patterns.push({ patternId });
|
|
8170
|
+
present.add(patternId);
|
|
8171
|
+
}
|
|
8172
|
+
}
|
|
8173
|
+
if (toolEntry.patterns.length === 0) {
|
|
8174
|
+
toolEntry.patterns = staticSelection;
|
|
8175
|
+
}
|
|
8176
|
+
if (suggestion.parameters) {
|
|
8177
|
+
for (const pattern of toolEntry.patterns) {
|
|
8178
|
+
const params = suggestion.parameters[pattern.patternId];
|
|
8179
|
+
if (!params) continue;
|
|
8180
|
+
pattern.parameters = { ...pattern.parameters, ...params };
|
|
8181
|
+
}
|
|
8084
8182
|
}
|
|
8085
8183
|
} catch (err) {
|
|
8086
|
-
logger.error("
|
|
8184
|
+
logger.error("suggestConfiguration failed", {
|
|
8087
8185
|
error: err instanceof Error ? err.message : String(err)
|
|
8088
8186
|
});
|
|
8089
8187
|
}
|
|
@@ -8109,6 +8207,13 @@ function deduplicateToolFamilies(candidates, localConfigs) {
|
|
|
8109
8207
|
continue;
|
|
8110
8208
|
}
|
|
8111
8209
|
const withConfig = group.filter((a) => localConfigs.has(a.id));
|
|
8210
|
+
const configuredFamilies = groupByToolFamily(withConfig);
|
|
8211
|
+
if (configuredFamilies.size > 1) {
|
|
8212
|
+
for (const members of configuredFamilies.values()) {
|
|
8213
|
+
result.push(members.length === 1 ? members[0] : highestVersion(members));
|
|
8214
|
+
}
|
|
8215
|
+
continue;
|
|
8216
|
+
}
|
|
8112
8217
|
const pool = withConfig.length > 0 ? withConfig : group;
|
|
8113
8218
|
if (pool.length === 1) {
|
|
8114
8219
|
result.push(pool[0]);
|
|
@@ -8123,17 +8228,27 @@ function deduplicateToolFamilies(candidates, localConfigs) {
|
|
|
8123
8228
|
group.filter((a) => a.alternativeGroupDefault).map((a) => toolFamily(a.id))
|
|
8124
8229
|
);
|
|
8125
8230
|
const defaultFamilyMembers = defaultFamilies.size === 1 ? pool.filter((a) => defaultFamilies.has(toolFamily(a.id))) : [];
|
|
8126
|
-
|
|
8127
|
-
(a, b) => {
|
|
8128
|
-
const majorA = parseInt(a.preferredVersion.split(".")[0], 10) || 0;
|
|
8129
|
-
const majorB = parseInt(b.preferredVersion.split(".")[0], 10) || 0;
|
|
8130
|
-
return majorB - majorA;
|
|
8131
|
-
}
|
|
8132
|
-
);
|
|
8133
|
-
result.push(ranked[0]);
|
|
8231
|
+
result.push(highestVersion(defaultFamilyMembers.length > 0 ? defaultFamilyMembers : pool));
|
|
8134
8232
|
}
|
|
8135
8233
|
return result;
|
|
8136
8234
|
}
|
|
8235
|
+
function groupByToolFamily(adapters) {
|
|
8236
|
+
const byFamily = /* @__PURE__ */ new Map();
|
|
8237
|
+
for (const adapter of adapters) {
|
|
8238
|
+
const family = toolFamily(adapter.id);
|
|
8239
|
+
const members = byFamily.get(family) ?? [];
|
|
8240
|
+
members.push(adapter);
|
|
8241
|
+
byFamily.set(family, members);
|
|
8242
|
+
}
|
|
8243
|
+
return byFamily;
|
|
8244
|
+
}
|
|
8245
|
+
function highestVersion(adapters) {
|
|
8246
|
+
return [...adapters].sort((a, b) => {
|
|
8247
|
+
const majorA = parseInt(a.preferredVersion.split(".")[0], 10) || 0;
|
|
8248
|
+
const majorB = parseInt(b.preferredVersion.split(".")[0], 10) || 0;
|
|
8249
|
+
return majorB - majorA;
|
|
8250
|
+
})[0];
|
|
8251
|
+
}
|
|
8137
8252
|
function filterAutoPatterns(patterns, mappings, detectedKeys, repoLanguages, filters) {
|
|
8138
8253
|
const allMappedPrefixes = [];
|
|
8139
8254
|
const prefixToKeys = /* @__PURE__ */ new Map();
|
|
@@ -8159,8 +8274,7 @@ function filterAutoPatterns(patterns, mappings, detectedKeys, repoLanguages, fil
|
|
|
8159
8274
|
}
|
|
8160
8275
|
}
|
|
8161
8276
|
}
|
|
8162
|
-
const severityFilter
|
|
8163
|
-
const categoryFilter = filters?.categories.length ? new Map(filters.categories.map((c) => [c.category, c.all])) : void 0;
|
|
8277
|
+
const { severityFilter, categoryFilter } = buildFilterLookups(filters);
|
|
8164
8278
|
const result = [];
|
|
8165
8279
|
for (const pattern of patterns) {
|
|
8166
8280
|
const matchedKeys = findMappedKeys(
|
|
@@ -8180,15 +8294,25 @@ function filterAutoPatterns(patterns, mappings, detectedKeys, repoLanguages, fil
|
|
|
8180
8294
|
}
|
|
8181
8295
|
}
|
|
8182
8296
|
}
|
|
8183
|
-
if (pattern
|
|
8184
|
-
if (!pattern.languages.some((lang) => repoLanguages.has(lang))) continue;
|
|
8185
|
-
}
|
|
8186
|
-
if (severityFilter && !severityFilter.has(pattern.severityLevel)) continue;
|
|
8187
|
-
if (categoryFilter && !categoryFilter.has(pattern.category)) continue;
|
|
8297
|
+
if (!passesSelectionGates(pattern, repoLanguages, severityFilter, categoryFilter)) continue;
|
|
8188
8298
|
result.push(pattern);
|
|
8189
8299
|
}
|
|
8190
8300
|
return result;
|
|
8191
8301
|
}
|
|
8302
|
+
function buildFilterLookups(filters) {
|
|
8303
|
+
return {
|
|
8304
|
+
severityFilter: filters?.severities.length ? new Map(filters.severities.map((s) => [s.level, s.all])) : void 0,
|
|
8305
|
+
categoryFilter: filters?.categories.length ? new Map(filters.categories.map((c) => [c.category, c.all])) : void 0
|
|
8306
|
+
};
|
|
8307
|
+
}
|
|
8308
|
+
function passesSelectionGates(pattern, repoLanguages, severityFilter, categoryFilter) {
|
|
8309
|
+
if (pattern.languages.length > 0 && repoLanguages.size > 0) {
|
|
8310
|
+
if (!pattern.languages.some((lang) => repoLanguages.has(lang))) return false;
|
|
8311
|
+
}
|
|
8312
|
+
if (severityFilter && !severityFilter.has(pattern.severityLevel)) return false;
|
|
8313
|
+
if (categoryFilter && !categoryFilter.has(pattern.category)) return false;
|
|
8314
|
+
return true;
|
|
8315
|
+
}
|
|
8192
8316
|
function findMappedKeys(patternId, patternTags, allPrefixes, prefixToKeys, allTags, tagToKeys) {
|
|
8193
8317
|
const matched = /* @__PURE__ */ new Set();
|
|
8194
8318
|
let longestPrefix = "";
|
|
@@ -8656,12 +8780,14 @@ async function safeReadBody(res) {
|
|
|
8656
8780
|
registerAdapter,
|
|
8657
8781
|
registerLazyAdapter,
|
|
8658
8782
|
registerUnsupportedTool,
|
|
8783
|
+
relativizeLocalConfigPaths,
|
|
8659
8784
|
resolveApiToken,
|
|
8660
8785
|
resolveBaselinePath,
|
|
8661
8786
|
resolveConfigPath,
|
|
8662
8787
|
resolveDiscoveryExcludes,
|
|
8663
8788
|
resolveEngineToAdapter,
|
|
8664
8789
|
resolveHeadCommit,
|
|
8790
|
+
resolveLocalConfigPaths,
|
|
8665
8791
|
resolveProxyConfig,
|
|
8666
8792
|
resolveRemoteAuth,
|
|
8667
8793
|
resolveRepositoryRoot,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codacy/analysis-runner",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.0",
|
|
4
4
|
"description": "Core orchestration engine for Codacy analysis",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -12,11 +12,11 @@
|
|
|
12
12
|
"cli-table3": "^0.6",
|
|
13
13
|
"minimatch": "10.2.4",
|
|
14
14
|
"yaml": "^2.6.0",
|
|
15
|
-
"@codacy/tooling": "0.
|
|
15
|
+
"@codacy/tooling": "0.21.0"
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
18
18
|
"@codacy/openapi-typescript-codegen": "0.0.9",
|
|
19
|
-
"@codacy/tools-dummy-1": "0.
|
|
19
|
+
"@codacy/tools-dummy-1": "0.21.0"
|
|
20
20
|
},
|
|
21
21
|
"license": "MIT",
|
|
22
22
|
"author": "Codacy <support@codacy.com> (https://www.codacy.com)",
|