@codacy/tools-jackson 0.3.0 → 0.5.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 CHANGED
@@ -38,20 +38,27 @@ var import_tooling = require("@codacy/tooling");
38
38
  // src/adapter.ts
39
39
  var import_promises = __toESM(require("fs/promises"));
40
40
  var import_path = __toESM(require("path"));
41
- var TOOL_ID = "jackson";
42
- var PATTERN_PARSE_ERROR = `${TOOL_ID}_parse-error`;
43
- var PATTERN_DUPLICATE_KEYS = `${TOOL_ID}_duplicate-keys`;
44
- var adapter = {
45
- id: TOOL_ID,
41
+
42
+ // src/metadata.ts
43
+ var descriptor = {
44
+ id: "jackson",
46
45
  displayName: "Jackson Linter",
47
46
  preferredVersion: "1.0.0",
48
- compatibleVersions: ">=1.0.0",
49
- website: "https://github.com/FasterXML/jackson-core",
50
47
  languages: ["JSON"],
51
48
  filePatterns: ["**/*.json"],
52
49
  supportedOS: ["linux", "darwin", "win32"],
53
50
  supportedArch: ["x64", "arm64"],
54
- supportedRunners: ["local", "container"],
51
+ supportedRunners: ["local", "container"]
52
+ };
53
+
54
+ // src/adapter.ts
55
+ var TOOL_ID = "jackson";
56
+ var PATTERN_PARSE_ERROR = `${TOOL_ID}_parse-error`;
57
+ var PATTERN_DUPLICATE_KEYS = `${TOOL_ID}_duplicate-keys`;
58
+ var adapter = {
59
+ ...descriptor,
60
+ compatibleVersions: ">=1.0.0",
61
+ website: "https://github.com/FasterXML/jackson-core",
55
62
  prerequisites: [],
56
63
  /**
57
64
  * Always available — this adapter uses only Node's built-in JSON.parse.
@@ -104,32 +111,49 @@ var adapter = {
104
111
  const startedAt = /* @__PURE__ */ new Date();
105
112
  const issues = [];
106
113
  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
- }
128
114
  const enabledPatterns = new Set(codacyConfig.patterns.map((p) => p.patternId));
129
115
  const checkParseError = enabledPatterns.has(PATTERN_PARSE_ERROR);
130
116
  const checkDuplicateKeys = enabledPatterns.has(PATTERN_DUPLICATE_KEYS);
117
+ let rootReal;
118
+ try {
119
+ rootReal = await import_promises.default.realpath(ctx.repositoryRoot);
120
+ } catch (err) {
121
+ errors.push({
122
+ toolId: TOOL_ID,
123
+ phase: "toolInvoke",
124
+ kind: "FileReadError",
125
+ message: `Cannot resolve repository root: ${err instanceof Error ? err.message : String(err)}`,
126
+ level: "error"
127
+ });
128
+ return buildResult(startedAt, /* @__PURE__ */ new Date(), issues, errors, ctx.targetFiles.length);
129
+ }
131
130
  for (const relPath of ctx.targetFiles) {
132
131
  const absPath = import_path.default.resolve(ctx.repositoryRoot, relPath);
132
+ const relToRoot = import_path.default.relative(ctx.repositoryRoot, absPath);
133
+ if (relToRoot === ".." || relToRoot.startsWith(`..${import_path.default.sep}`) || import_path.default.isAbsolute(relToRoot)) {
134
+ errors.push({
135
+ toolId: TOOL_ID,
136
+ phase: "toolInvoke",
137
+ kind: "FileReadError",
138
+ message: `Refusing path outside repository root: ${relPath}`,
139
+ level: "warning",
140
+ filePath: relPath
141
+ });
142
+ continue;
143
+ }
144
+ const fileReal = await import_promises.default.realpath(absPath).catch(() => null);
145
+ const realRelative = fileReal ? import_path.default.relative(rootReal, fileReal) : null;
146
+ if (realRelative !== null && (realRelative === ".." || realRelative.startsWith(`..${import_path.default.sep}`) || import_path.default.isAbsolute(realRelative))) {
147
+ errors.push({
148
+ toolId: TOOL_ID,
149
+ phase: "toolInvoke",
150
+ kind: "FileReadError",
151
+ message: `Refusing path outside repository root: ${relPath}`,
152
+ level: "warning",
153
+ filePath: relPath
154
+ });
155
+ continue;
156
+ }
133
157
  let content;
134
158
  try {
135
159
  content = await import_promises.default.readFile(absPath, "utf-8");
@@ -144,14 +168,15 @@ var adapter = {
144
168
  });
145
169
  continue;
146
170
  }
147
- let parseFailed = false;
148
- if (checkParseError) {
171
+ const strippedContent = stripJsonComments(content);
172
+ let syntaxValid = true;
173
+ if (checkParseError || checkDuplicateKeys) {
149
174
  try {
150
- JSON.parse(content);
175
+ JSON.parse(strippedContent);
151
176
  } catch (err) {
152
- if (err instanceof SyntaxError) {
153
- parseFailed = true;
154
- const { line, column } = extractPosition(err.message, content);
177
+ syntaxValid = false;
178
+ if (checkParseError && err instanceof SyntaxError) {
179
+ const { line, column } = extractPosition(err.message, strippedContent);
155
180
  const lines = content.split("\n");
156
181
  const lineContent = lines[line - 1] ?? "";
157
182
  issues.push({
@@ -168,8 +193,8 @@ var adapter = {
168
193
  }
169
194
  }
170
195
  }
171
- if (checkDuplicateKeys && !parseFailed) {
172
- const duplicates = findDuplicateKeys(content);
196
+ if (checkDuplicateKeys && syntaxValid) {
197
+ const duplicates = findDuplicateKeys(strippedContent);
173
198
  const lines = content.split("\n");
174
199
  for (const dup of duplicates) {
175
200
  const lineContent = lines[dup.line - 1] ?? "";
@@ -213,6 +238,59 @@ var adapter = {
213
238
  };
214
239
  }
215
240
  };
241
+ function stripJsonComments(source) {
242
+ const len = source.length;
243
+ const result = new Array(len);
244
+ let i = 0;
245
+ while (i < len) {
246
+ const ch = source[i];
247
+ if (ch === '"') {
248
+ result[i] = ch;
249
+ i++;
250
+ while (i < len) {
251
+ const sc = source[i];
252
+ result[i] = sc;
253
+ i++;
254
+ if (sc === "\\" && i < len) {
255
+ result[i] = source[i];
256
+ i++;
257
+ } else if (sc === '"') {
258
+ break;
259
+ }
260
+ }
261
+ continue;
262
+ }
263
+ if (ch === "/" && i + 1 < len && source[i + 1] === "*") {
264
+ result[i] = " ";
265
+ result[i + 1] = " ";
266
+ i += 2;
267
+ while (i < len) {
268
+ if (source[i] === "*" && i + 1 < len && source[i + 1] === "/") {
269
+ result[i] = " ";
270
+ result[i + 1] = " ";
271
+ i += 2;
272
+ break;
273
+ }
274
+ result[i] = source[i] === "\n" ? "\n" : " ";
275
+ i++;
276
+ }
277
+ continue;
278
+ }
279
+ if (ch === "/" && i + 1 < len && source[i + 1] === "/") {
280
+ result[i] = " ";
281
+ result[i + 1] = " ";
282
+ i += 2;
283
+ while (i < len && source[i] !== "\n") {
284
+ result[i] = " ";
285
+ i++;
286
+ }
287
+ continue;
288
+ }
289
+ result[i] = ch;
290
+ i++;
291
+ }
292
+ return result.join("");
293
+ }
216
294
  function extractPosition(message, source) {
217
295
  const posMatch = message.match(/position (\d+)/);
218
296
  if (posMatch) {
@@ -0,0 +1,13 @@
1
+ import { AdapterDescriptor } from '@codacy/tooling';
2
+
3
+ /**
4
+ * Lightweight adapter descriptor for lazy loading.
5
+ *
6
+ * This module contains only plain-data metadata fields and has zero heavy
7
+ * imports (no patterns.json, no runtime utilities). The CLI imports this
8
+ * at startup for adapter registration without loading the full adapter module.
9
+ */
10
+
11
+ declare const descriptor: AdapterDescriptor;
12
+
13
+ export { descriptor };
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/metadata.ts
21
+ var metadata_exports = {};
22
+ __export(metadata_exports, {
23
+ descriptor: () => descriptor
24
+ });
25
+ module.exports = __toCommonJS(metadata_exports);
26
+ var descriptor = {
27
+ id: "jackson",
28
+ displayName: "Jackson Linter",
29
+ preferredVersion: "1.0.0",
30
+ languages: ["JSON"],
31
+ filePatterns: ["**/*.json"],
32
+ supportedOS: ["linux", "darwin", "win32"],
33
+ supportedArch: ["x64", "arm64"],
34
+ supportedRunners: ["local", "container"]
35
+ };
36
+ // Annotate the CommonJS export names for ESM import in node:
37
+ 0 && (module.exports = {
38
+ descriptor
39
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codacy/tools-jackson",
3
- "version": "0.3.0",
3
+ "version": "0.5.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.5.0"
12
12
  },
13
13
  "license": "MIT",
14
14
  "author": "Codacy <support@codacy.com> (https://www.codacy.com)",
@@ -21,8 +21,18 @@
21
21
  "engines": {
22
22
  "node": ">=20.0.0"
23
23
  },
24
+ "exports": {
25
+ ".": {
26
+ "types": "./dist/index.d.ts",
27
+ "default": "./dist/index.js"
28
+ },
29
+ "./metadata": {
30
+ "types": "./dist/metadata.d.ts",
31
+ "default": "./dist/metadata.js"
32
+ }
33
+ },
24
34
  "scripts": {
25
- "build": "tsup src/index.ts --format cjs --dts --clean",
35
+ "build": "tsup src/index.ts src/metadata.ts --format cjs --dts --clean",
26
36
  "test": "vitest run",
27
37
  "lint": "eslint src/",
28
38
  "clean": "rm -rf dist",