@codacy/tools-jackson 0.3.0 → 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.
Files changed (2) hide show
  1. package/dist/index.js +100 -8
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -128,8 +128,46 @@ var adapter = {
128
128
  const enabledPatterns = new Set(codacyConfig.patterns.map((p) => p.patternId));
129
129
  const checkParseError = enabledPatterns.has(PATTERN_PARSE_ERROR);
130
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
+ }
131
144
  for (const relPath of ctx.targetFiles) {
132
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
+ }
133
171
  let content;
134
172
  try {
135
173
  content = await import_promises.default.readFile(absPath, "utf-8");
@@ -144,14 +182,15 @@ var adapter = {
144
182
  });
145
183
  continue;
146
184
  }
147
- let parseFailed = false;
148
- if (checkParseError) {
185
+ const strippedContent = stripJsonComments(content);
186
+ let syntaxValid = true;
187
+ if (checkParseError || checkDuplicateKeys) {
149
188
  try {
150
- JSON.parse(content);
189
+ JSON.parse(strippedContent);
151
190
  } catch (err) {
152
- if (err instanceof SyntaxError) {
153
- parseFailed = true;
154
- const { line, column } = extractPosition(err.message, content);
191
+ syntaxValid = false;
192
+ if (checkParseError && err instanceof SyntaxError) {
193
+ const { line, column } = extractPosition(err.message, strippedContent);
155
194
  const lines = content.split("\n");
156
195
  const lineContent = lines[line - 1] ?? "";
157
196
  issues.push({
@@ -168,8 +207,8 @@ var adapter = {
168
207
  }
169
208
  }
170
209
  }
171
- if (checkDuplicateKeys && !parseFailed) {
172
- const duplicates = findDuplicateKeys(content);
210
+ if (checkDuplicateKeys && syntaxValid) {
211
+ const duplicates = findDuplicateKeys(strippedContent);
173
212
  const lines = content.split("\n");
174
213
  for (const dup of duplicates) {
175
214
  const lineContent = lines[dup.line - 1] ?? "";
@@ -213,6 +252,59 @@ var adapter = {
213
252
  };
214
253
  }
215
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
+ }
216
308
  function extractPosition(message, source) {
217
309
  const posMatch = message.match(/position (\d+)/);
218
310
  if (posMatch) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codacy/tools-jackson",
3
- "version": "0.3.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.3.0"
11
+ "@codacy/tooling": "0.4.0"
12
12
  },
13
13
  "license": "MIT",
14
14
  "author": "Codacy <support@codacy.com> (https://www.codacy.com)",