@codacy/tools-jackson 0.2.2 → 0.4.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.js +124 -12
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -86,8 +86,7 @@ var adapter = {
|
|
|
86
86
|
* scanning for duplicate object keys (duplicate-keys).
|
|
87
87
|
*
|
|
88
88
|
* Config filtering: when `codacyConfig.patterns` is non-empty, only the
|
|
89
|
-
* enabled patterns are checked. If patterns is empty
|
|
90
|
-
* both checks run.
|
|
89
|
+
* enabled patterns are checked. If patterns is empty, analysis is skipped.
|
|
91
90
|
*
|
|
92
91
|
* For each file:
|
|
93
92
|
* - If the file cannot be read, an AnalysisError with kind "FileReadError" is recorded.
|
|
@@ -105,11 +104,70 @@ var adapter = {
|
|
|
105
104
|
const startedAt = /* @__PURE__ */ new Date();
|
|
106
105
|
const issues = [];
|
|
107
106
|
const errors = [];
|
|
107
|
+
if (codacyConfig.patterns.length === 0) {
|
|
108
|
+
ctx.logger.info("Skipping analysis: no patterns enabled", { toolId: TOOL_ID });
|
|
109
|
+
const completedAt2 = /* @__PURE__ */ new Date();
|
|
110
|
+
return {
|
|
111
|
+
metadata: {
|
|
112
|
+
startedAt: startedAt.toISOString(),
|
|
113
|
+
completedAt: completedAt2.toISOString(),
|
|
114
|
+
durationMs: completedAt2.getTime() - startedAt.getTime()
|
|
115
|
+
},
|
|
116
|
+
issues,
|
|
117
|
+
errors,
|
|
118
|
+
summary: {
|
|
119
|
+
toolId: TOOL_ID,
|
|
120
|
+
status: "success",
|
|
121
|
+
issueCount: 0,
|
|
122
|
+
errorCount: 0,
|
|
123
|
+
durationMs: completedAt2.getTime() - startedAt.getTime(),
|
|
124
|
+
filesAnalyzed: ctx.targetFiles.length
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
}
|
|
108
128
|
const enabledPatterns = new Set(codacyConfig.patterns.map((p) => p.patternId));
|
|
109
|
-
const checkParseError = enabledPatterns.
|
|
110
|
-
const checkDuplicateKeys = enabledPatterns.
|
|
129
|
+
const checkParseError = enabledPatterns.has(PATTERN_PARSE_ERROR);
|
|
130
|
+
const checkDuplicateKeys = enabledPatterns.has(PATTERN_DUPLICATE_KEYS);
|
|
131
|
+
let rootReal;
|
|
132
|
+
try {
|
|
133
|
+
rootReal = await import_promises.default.realpath(ctx.repositoryRoot);
|
|
134
|
+
} catch (err) {
|
|
135
|
+
errors.push({
|
|
136
|
+
toolId: TOOL_ID,
|
|
137
|
+
phase: "toolInvoke",
|
|
138
|
+
kind: "FileReadError",
|
|
139
|
+
message: `Cannot resolve repository root: ${err instanceof Error ? err.message : String(err)}`,
|
|
140
|
+
level: "error"
|
|
141
|
+
});
|
|
142
|
+
return buildResult(startedAt, /* @__PURE__ */ new Date(), issues, errors, ctx.targetFiles.length);
|
|
143
|
+
}
|
|
111
144
|
for (const relPath of ctx.targetFiles) {
|
|
112
145
|
const absPath = import_path.default.resolve(ctx.repositoryRoot, relPath);
|
|
146
|
+
const relToRoot = import_path.default.relative(ctx.repositoryRoot, absPath);
|
|
147
|
+
if (relToRoot === ".." || relToRoot.startsWith(`..${import_path.default.sep}`) || import_path.default.isAbsolute(relToRoot)) {
|
|
148
|
+
errors.push({
|
|
149
|
+
toolId: TOOL_ID,
|
|
150
|
+
phase: "toolInvoke",
|
|
151
|
+
kind: "FileReadError",
|
|
152
|
+
message: `Refusing path outside repository root: ${relPath}`,
|
|
153
|
+
level: "warning",
|
|
154
|
+
filePath: relPath
|
|
155
|
+
});
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
const fileReal = await import_promises.default.realpath(absPath).catch(() => null);
|
|
159
|
+
const realRelative = fileReal ? import_path.default.relative(rootReal, fileReal) : null;
|
|
160
|
+
if (realRelative !== null && (realRelative === ".." || realRelative.startsWith(`..${import_path.default.sep}`) || import_path.default.isAbsolute(realRelative))) {
|
|
161
|
+
errors.push({
|
|
162
|
+
toolId: TOOL_ID,
|
|
163
|
+
phase: "toolInvoke",
|
|
164
|
+
kind: "FileReadError",
|
|
165
|
+
message: `Refusing path outside repository root: ${relPath}`,
|
|
166
|
+
level: "warning",
|
|
167
|
+
filePath: relPath
|
|
168
|
+
});
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
113
171
|
let content;
|
|
114
172
|
try {
|
|
115
173
|
content = await import_promises.default.readFile(absPath, "utf-8");
|
|
@@ -124,14 +182,15 @@ var adapter = {
|
|
|
124
182
|
});
|
|
125
183
|
continue;
|
|
126
184
|
}
|
|
127
|
-
|
|
128
|
-
|
|
185
|
+
const strippedContent = stripJsonComments(content);
|
|
186
|
+
let syntaxValid = true;
|
|
187
|
+
if (checkParseError || checkDuplicateKeys) {
|
|
129
188
|
try {
|
|
130
|
-
JSON.parse(
|
|
189
|
+
JSON.parse(strippedContent);
|
|
131
190
|
} catch (err) {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
const { line, column } = extractPosition(err.message,
|
|
191
|
+
syntaxValid = false;
|
|
192
|
+
if (checkParseError && err instanceof SyntaxError) {
|
|
193
|
+
const { line, column } = extractPosition(err.message, strippedContent);
|
|
135
194
|
const lines = content.split("\n");
|
|
136
195
|
const lineContent = lines[line - 1] ?? "";
|
|
137
196
|
issues.push({
|
|
@@ -148,8 +207,8 @@ var adapter = {
|
|
|
148
207
|
}
|
|
149
208
|
}
|
|
150
209
|
}
|
|
151
|
-
if (checkDuplicateKeys &&
|
|
152
|
-
const duplicates = findDuplicateKeys(
|
|
210
|
+
if (checkDuplicateKeys && syntaxValid) {
|
|
211
|
+
const duplicates = findDuplicateKeys(strippedContent);
|
|
153
212
|
const lines = content.split("\n");
|
|
154
213
|
for (const dup of duplicates) {
|
|
155
214
|
const lineContent = lines[dup.line - 1] ?? "";
|
|
@@ -193,6 +252,59 @@ var adapter = {
|
|
|
193
252
|
};
|
|
194
253
|
}
|
|
195
254
|
};
|
|
255
|
+
function stripJsonComments(source) {
|
|
256
|
+
const len = source.length;
|
|
257
|
+
const result = new Array(len);
|
|
258
|
+
let i = 0;
|
|
259
|
+
while (i < len) {
|
|
260
|
+
const ch = source[i];
|
|
261
|
+
if (ch === '"') {
|
|
262
|
+
result[i] = ch;
|
|
263
|
+
i++;
|
|
264
|
+
while (i < len) {
|
|
265
|
+
const sc = source[i];
|
|
266
|
+
result[i] = sc;
|
|
267
|
+
i++;
|
|
268
|
+
if (sc === "\\" && i < len) {
|
|
269
|
+
result[i] = source[i];
|
|
270
|
+
i++;
|
|
271
|
+
} else if (sc === '"') {
|
|
272
|
+
break;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
if (ch === "/" && i + 1 < len && source[i + 1] === "*") {
|
|
278
|
+
result[i] = " ";
|
|
279
|
+
result[i + 1] = " ";
|
|
280
|
+
i += 2;
|
|
281
|
+
while (i < len) {
|
|
282
|
+
if (source[i] === "*" && i + 1 < len && source[i + 1] === "/") {
|
|
283
|
+
result[i] = " ";
|
|
284
|
+
result[i + 1] = " ";
|
|
285
|
+
i += 2;
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
288
|
+
result[i] = source[i] === "\n" ? "\n" : " ";
|
|
289
|
+
i++;
|
|
290
|
+
}
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
if (ch === "/" && i + 1 < len && source[i + 1] === "/") {
|
|
294
|
+
result[i] = " ";
|
|
295
|
+
result[i + 1] = " ";
|
|
296
|
+
i += 2;
|
|
297
|
+
while (i < len && source[i] !== "\n") {
|
|
298
|
+
result[i] = " ";
|
|
299
|
+
i++;
|
|
300
|
+
}
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
result[i] = ch;
|
|
304
|
+
i++;
|
|
305
|
+
}
|
|
306
|
+
return result.join("");
|
|
307
|
+
}
|
|
196
308
|
function extractPosition(message, source) {
|
|
197
309
|
const posMatch = message.match(/position (\d+)/);
|
|
198
310
|
if (posMatch) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codacy/tools-jackson",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Jackson Linter adapter — pure TypeScript JSON syntax validator",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"dist"
|
|
9
9
|
],
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@codacy/tooling": "0.
|
|
11
|
+
"@codacy/tooling": "0.4.0"
|
|
12
12
|
},
|
|
13
13
|
"license": "MIT",
|
|
14
14
|
"author": "Codacy <support@codacy.com> (https://www.codacy.com)",
|