@d3lm/lint-preset 1.5.6 → 1.6.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/README.md +40 -7
- package/dist/bin/comments.js +528 -113
- package/dist/bin/comments.js.map +1 -1
- package/dist/comments.cjs +433 -68
- package/dist/comments.cjs.map +1 -1
- package/dist/comments.d.cts +41 -17
- package/dist/comments.d.ts +41 -17
- package/dist/comments.js +435 -72
- package/dist/comments.js.map +1 -1
- package/native/comments.darwin-arm64.node +0 -0
- package/native/comments.darwin-x64.node +0 -0
- package/native/comments.linux-arm64-gnu.node +0 -0
- package/native/comments.linux-x64-gnu.node +0 -0
- package/package.json +9 -6
package/dist/comments.cjs
CHANGED
|
@@ -1,8 +1,75 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
|
|
2
|
+
|
|
3
|
+
var _chunk56WU3HSDcjs = require('./chunk-56WU3HSD.cjs');
|
|
2
4
|
|
|
3
5
|
// src/comments/analyze.ts
|
|
4
6
|
var _oxcparser = require('oxc-parser');
|
|
5
7
|
|
|
8
|
+
// src/comments/rust.ts
|
|
9
|
+
var _fs = require('fs');
|
|
10
|
+
var _module = require('module');
|
|
11
|
+
var _path = require('path'); var _path2 = _interopRequireDefault(_path);
|
|
12
|
+
var _url = require('url');
|
|
13
|
+
var BINARY_NAME = "comments";
|
|
14
|
+
function platformSuffixes() {
|
|
15
|
+
const { platform, arch } = process;
|
|
16
|
+
switch (platform) {
|
|
17
|
+
case "darwin": {
|
|
18
|
+
return [`darwin-${arch}`, "darwin-universal"];
|
|
19
|
+
}
|
|
20
|
+
case "linux": {
|
|
21
|
+
return arch === "arm" ? ["linux-arm-gnueabihf", "linux-arm-musleabihf"] : [`linux-${arch}-gnu`, `linux-${arch}-musl`];
|
|
22
|
+
}
|
|
23
|
+
case "win32": {
|
|
24
|
+
return [`win32-${arch}-msvc`, `win32-${arch}-gnu`];
|
|
25
|
+
}
|
|
26
|
+
default: {
|
|
27
|
+
return [`${platform}-${arch}`];
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function findBinaries() {
|
|
32
|
+
const names = platformSuffixes().map((suffix) => `${BINARY_NAME}.${suffix}.node`);
|
|
33
|
+
for (let directory = _path2.default.dirname(_url.fileURLToPath.call(void 0, _chunk56WU3HSDcjs.importMetaUrl)); ; directory = _path2.default.dirname(directory)) {
|
|
34
|
+
const found = names.map((name) => _path2.default.join(directory, "native", name)).filter((file) => _fs.existsSync.call(void 0, file));
|
|
35
|
+
if (found.length > 0) {
|
|
36
|
+
return found;
|
|
37
|
+
}
|
|
38
|
+
if (_path2.default.dirname(directory) === directory) {
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
var binding;
|
|
44
|
+
function loadBinding() {
|
|
45
|
+
if (binding) {
|
|
46
|
+
return binding;
|
|
47
|
+
}
|
|
48
|
+
const require2 = _module.createRequire.call(void 0, _chunk56WU3HSDcjs.importMetaUrl);
|
|
49
|
+
const errors = [];
|
|
50
|
+
for (const file of findBinaries()) {
|
|
51
|
+
try {
|
|
52
|
+
binding = require2(file);
|
|
53
|
+
return binding;
|
|
54
|
+
} catch (error) {
|
|
55
|
+
errors.push(`${file}: ${error.message}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const reason = errors.length > 0 ? `, and loading it failed (${errors.join("; ")})` : "";
|
|
59
|
+
throw new Error(
|
|
60
|
+
`comments: Rust files need the native addon for ${process.platform}-${process.arch}${reason}. Build it with \`pnpm run build:native\`, or leave \`.rs\` out of \`extensions\`.`
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
function scanRust(source) {
|
|
64
|
+
return loadBinding().scanRust(source);
|
|
65
|
+
}
|
|
66
|
+
function rustFingerprint(source) {
|
|
67
|
+
return loadBinding().rustFingerprint(source);
|
|
68
|
+
}
|
|
69
|
+
function isRustCode(text) {
|
|
70
|
+
return loadBinding().isRustCode(text);
|
|
71
|
+
}
|
|
72
|
+
|
|
6
73
|
// src/comments/style.ts
|
|
7
74
|
var BANNER = /^(?!#{1,6}\s)([-=*#_~+/\\])\1{3,}|([-=*#_~])\2{3,}\s*$/;
|
|
8
75
|
var COLUMN_RULE = /^([-=_~])\1*(?:\s+\1+)+$/;
|
|
@@ -126,12 +193,94 @@ function findCodeSpanEnd(text, start) {
|
|
|
126
193
|
}
|
|
127
194
|
return -1;
|
|
128
195
|
}
|
|
196
|
+
function isEscaped(text, index) {
|
|
197
|
+
let backslashes = 0;
|
|
198
|
+
while (text[index - 1 - backslashes] === "\\") {
|
|
199
|
+
backslashes += 1;
|
|
200
|
+
}
|
|
201
|
+
return backslashes % 2 === 1;
|
|
202
|
+
}
|
|
203
|
+
function findUnescaped(text, char, start) {
|
|
204
|
+
for (let index = start; index < text.length; index += 1) {
|
|
205
|
+
if (text[index] === "\\") {
|
|
206
|
+
index += 1;
|
|
207
|
+
} else if (text[index] === char) {
|
|
208
|
+
return index;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return -1;
|
|
212
|
+
}
|
|
213
|
+
function findClosingBracket(text, start) {
|
|
214
|
+
let depth = 0;
|
|
215
|
+
for (let index = start; index < text.length; index += 1) {
|
|
216
|
+
switch (text[index]) {
|
|
217
|
+
case "\\": {
|
|
218
|
+
index += 1;
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
case "`": {
|
|
222
|
+
const close = findCodeSpanEnd(text, index);
|
|
223
|
+
index = close === -1 ? index + backtickRun(text, index) - 1 : close;
|
|
224
|
+
break;
|
|
225
|
+
}
|
|
226
|
+
case "[": {
|
|
227
|
+
depth += 1;
|
|
228
|
+
break;
|
|
229
|
+
}
|
|
230
|
+
case "]": {
|
|
231
|
+
depth -= 1;
|
|
232
|
+
if (depth === 0) {
|
|
233
|
+
return index;
|
|
234
|
+
}
|
|
235
|
+
break;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return -1;
|
|
240
|
+
}
|
|
241
|
+
function findDestinationEnd(text, start) {
|
|
242
|
+
let depth = 0;
|
|
243
|
+
for (let index = start; index < text.length; index += 1) {
|
|
244
|
+
const char = text[index];
|
|
245
|
+
let close = -1;
|
|
246
|
+
if (char === "\\") {
|
|
247
|
+
index += 1;
|
|
248
|
+
} else if (char === "<" && text.slice(start + 1, index).trim() === "") {
|
|
249
|
+
close = findUnescaped(text, ">", index + 1);
|
|
250
|
+
} else if ((char === '"' || char === "'") && /\s/.test(text[index - 1])) {
|
|
251
|
+
close = findUnescaped(text, char, index + 1);
|
|
252
|
+
} else if (char === "(") {
|
|
253
|
+
depth += 1;
|
|
254
|
+
} else if (char === ")" && --depth === 0) {
|
|
255
|
+
return index;
|
|
256
|
+
}
|
|
257
|
+
index = close === -1 ? index : close;
|
|
258
|
+
}
|
|
259
|
+
return -1;
|
|
260
|
+
}
|
|
261
|
+
function findLinkEnd(text, start) {
|
|
262
|
+
const close = findClosingBracket(text, start);
|
|
263
|
+
if (close === -1 || text[close + 1] !== "(") {
|
|
264
|
+
return close;
|
|
265
|
+
}
|
|
266
|
+
const end = findDestinationEnd(text, close + 1);
|
|
267
|
+
return end === -1 ? close : end;
|
|
268
|
+
}
|
|
129
269
|
function tokenize(text) {
|
|
270
|
+
return splitWords(text, true);
|
|
271
|
+
}
|
|
272
|
+
function splitWords(text, keepLinks) {
|
|
130
273
|
const tokens = [];
|
|
131
274
|
let current = "";
|
|
132
275
|
let index = 0;
|
|
133
276
|
while (index < text.length) {
|
|
134
277
|
const char = text[index];
|
|
278
|
+
const linkEnd = keepLinks && char === "[" && !isEscaped(text, index) ? findLinkEnd(text, index) : -1;
|
|
279
|
+
if (linkEnd !== -1) {
|
|
280
|
+
current += splitWords(text.slice(index, linkEnd + 1), false).join(" ");
|
|
281
|
+
index = linkEnd + 1;
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
135
284
|
const close = char === "`" ? findCodeSpanEnd(text, index) : char === "{" ? findClosingBrace(text, index) : -1;
|
|
136
285
|
if (char === "`" && close === -1) {
|
|
137
286
|
const run = backtickRun(text, index);
|
|
@@ -227,7 +376,7 @@ function isOrphan(previous, token) {
|
|
|
227
376
|
return opensAside(token) || endsClause(previous) && !CLAUSE_END.test(token);
|
|
228
377
|
}
|
|
229
378
|
function startsBlock(token) {
|
|
230
|
-
return /^(
|
|
379
|
+
return /^(?:\+|-+|=+|\*+|_{3,}|\d+[.)]|#{1,6})$/.test(token) || /^(?:>|@[A-Za-z]|`{3}|~{3}|\||<(?:\/?[A-Za-z]|[!?]))/.test(token);
|
|
231
380
|
}
|
|
232
381
|
function bindLineStarts(tokens, startsLine2 = startsBlock) {
|
|
233
382
|
const units = [];
|
|
@@ -665,6 +814,7 @@ var NAMED_TAGS = /* @__PURE__ */ new Set(["arg", "argument", "param", "prop", "p
|
|
|
665
814
|
var LINE_DIRECTIVE = /^\s*(?:(?:eslint|oxlint|stylelint)-(?:disable(?:-next-line|-line)?|enable)\b|eslint-env\b|@ts-(?:ignore|expect-error|nocheck|check)\b|@jsx\w*\b|@vite-ignore\b|[@#]__[A-Z_]+__|@(?:vitest|jest)-environment\b|(?:istanbul|c8|v8)\s+ignore\b|prettier-ignore\b|biome-ignore\b|deno-(?:lint-ignore|fmt-ignore)(?:-file)?\b|tslint:|(?:c[sS]pell|spell-?checker)\s*:|(?:webpack|turbopack)[A-Z][a-zA-Z]*\s*:|vim?:\s|#(?:region|endregion)\b|<reference\s)/;
|
|
666
815
|
var BLOCK_DIRECTIVE = /^\s*(?:eslint\s|globals?\s|exported\s|jshint\s|jslint\s|type\s*:)/;
|
|
667
816
|
var LEGAL_COMMENT = /^!|@license\b|@preserve\b|\bcopyright\s+(?:\(c\)|©|\d{4})/i;
|
|
817
|
+
var RUST_LEGAL_COMMENT = /@license\b|@preserve\b|\bcopyright\s+(?:\(c\)|©|\d{4})/i;
|
|
668
818
|
var DEFINITION = /^(?:``|[\w$.[\]]+(?:[ -][\w$.[\]]+)?)(?: [-–]|:) \S/;
|
|
669
819
|
var BOX_DRAWING = /[\u2500-\u257F]/;
|
|
670
820
|
var TABLE_DELIMITER = /^\|?\s*:?-+:?\s*(?:\|\s*:?-+:?\s*)+\|?$/;
|
|
@@ -739,12 +889,35 @@ ${text}
|
|
|
739
889
|
}
|
|
740
890
|
return properties.length > 1 || text.trimEnd().endsWith(",") || properties.some((property) => property.type === "Property" && CODE_VALUES.has(property.value.type));
|
|
741
891
|
}
|
|
742
|
-
function isCode(texts) {
|
|
743
|
-
|
|
744
|
-
return parsesAsStatements(text) || parsesAsProperties(text);
|
|
892
|
+
function isCode(texts, language) {
|
|
893
|
+
return language.isCode(texts.map((line) => line.replace(LIST_MARKER, "")).join("\n"));
|
|
745
894
|
}
|
|
746
895
|
function isCodeLine(text) {
|
|
747
|
-
return text.endsWith("{") || text.endsWith(";") && (/[()[\]{}=<>]/.test(text) || !/\s/.test(text)) || /^[}\])]/.test(text)
|
|
896
|
+
return text.endsWith("{") || text.endsWith(";") && (/[()[\]{}=<>]/.test(text) || !/\s/.test(text)) || /^[}\])]/.test(text);
|
|
897
|
+
}
|
|
898
|
+
var JAVASCRIPT = {
|
|
899
|
+
name: "javascript",
|
|
900
|
+
isCode: (text) => parsesAsStatements(text) || parsesAsProperties(text),
|
|
901
|
+
isCodeLine: (text) => {
|
|
902
|
+
return isCodeLine(text) || /^(?:const|let|var)\s+[\w$]+\s*[:=]/.test(text) || /^(?:import|export)\s.*(?:\sfrom\s|[{}])/.test(text);
|
|
903
|
+
},
|
|
904
|
+
legal: LEGAL_COMMENT,
|
|
905
|
+
blockDirective: BLOCK_DIRECTIVE,
|
|
906
|
+
tags: true,
|
|
907
|
+
joinsCodeSpans: true
|
|
908
|
+
};
|
|
909
|
+
var RUST = {
|
|
910
|
+
name: "rust",
|
|
911
|
+
isCode: (text) => isRustCode(text),
|
|
912
|
+
isCodeLine: (text) => {
|
|
913
|
+
return isCodeLine(text) || /^let\s+(?:mut\s+)?\w+\s*[:=]/.test(text) || /^(?:pub(?:\([\w:\s]+\))?\s+)?(?:const|static(?:\s+mut)?)\s+[A-Z_\d]+\s*:/.test(text) || /^(?:pub(?:\([\w:\s]+\))?\s+)?use\s+[\w:]*::/.test(text) || /^#!?\[/.test(text);
|
|
914
|
+
},
|
|
915
|
+
legal: RUST_LEGAL_COMMENT,
|
|
916
|
+
tags: false,
|
|
917
|
+
joinsCodeSpans: false
|
|
918
|
+
};
|
|
919
|
+
function languageOf(filename) {
|
|
920
|
+
return filename.endsWith(".rs") ? RUST : JAVASCRIPT;
|
|
748
921
|
}
|
|
749
922
|
function layoutReason(prose, raw) {
|
|
750
923
|
if (prose.startsWith("|") || TABLE_DELIMITER.test(prose)) {
|
|
@@ -758,8 +931,10 @@ function layoutReason(prose, raw) {
|
|
|
758
931
|
}
|
|
759
932
|
return void 0;
|
|
760
933
|
}
|
|
934
|
+
var THEMATIC_BREAK = /^(?:(?:\*\s*){3,}|(?:-\s*){3,}|(?:_\s*){3,})$/;
|
|
761
935
|
function isMarkup(prose) {
|
|
762
|
-
|
|
936
|
+
const text = prose.replace(LIST_MARKER, "");
|
|
937
|
+
return /^#{1,6}(?:\s|$)/.test(text) || /^\[[^\]]+\]:/.test(text) || /^<(?:\/?[a-z]|[!?])/i.test(text) || text.startsWith(">") || /^(?:=+|-+)$/.test(prose) || THEMATIC_BREAK.test(prose);
|
|
763
938
|
}
|
|
764
939
|
function mask(text) {
|
|
765
940
|
return text.replaceAll(/[^\n]/g, "x");
|
|
@@ -786,11 +961,14 @@ function hasAlignedColumns(lines) {
|
|
|
786
961
|
}
|
|
787
962
|
return false;
|
|
788
963
|
}
|
|
789
|
-
function structureOf(lines) {
|
|
964
|
+
function structureOf(lines, language) {
|
|
790
965
|
const trimmed = lines.map((line) => line.text.trim()).join("\n");
|
|
791
966
|
const texts = replaceKeepingLines(trimmed, CODE_SPAN, "``").split("\n");
|
|
792
967
|
const proseLines = stripNonProse(trimmed).split("\n");
|
|
793
|
-
if (isCode(
|
|
968
|
+
if (isCode(
|
|
969
|
+
lines.map((line) => line.text.trim()),
|
|
970
|
+
language
|
|
971
|
+
)) {
|
|
794
972
|
return { tier: "code", reason: "code" };
|
|
795
973
|
}
|
|
796
974
|
let layout;
|
|
@@ -799,7 +977,7 @@ function structureOf(lines) {
|
|
|
799
977
|
for (const [position, line] of texts.entries()) {
|
|
800
978
|
const prose = proseLines[position].trim();
|
|
801
979
|
layout ??= layoutReason(prose, _nullishCoalesce(_optionalChain([lines, 'access', _6 => _6[position], 'optionalAccess', _7 => _7.text]), () => ( "")));
|
|
802
|
-
if (isCodeLine(line.trim())) {
|
|
980
|
+
if (language.isCodeLine(line.trim())) {
|
|
803
981
|
codeLike = true;
|
|
804
982
|
} else if (isMarkup(prose)) {
|
|
805
983
|
manual ??= "markup";
|
|
@@ -838,7 +1016,7 @@ var FenceTracker = class {
|
|
|
838
1016
|
return true;
|
|
839
1017
|
}
|
|
840
1018
|
};
|
|
841
|
-
function segment(lines) {
|
|
1019
|
+
function segment(lines, language) {
|
|
842
1020
|
const paragraphs = [];
|
|
843
1021
|
const fence = new FenceTracker();
|
|
844
1022
|
let current;
|
|
@@ -875,6 +1053,10 @@ function segment(lines) {
|
|
|
875
1053
|
continue;
|
|
876
1054
|
}
|
|
877
1055
|
if (line.verbatim) {
|
|
1056
|
+
if (fence.next(text)) {
|
|
1057
|
+
start("code", line, "", "code block");
|
|
1058
|
+
continue;
|
|
1059
|
+
}
|
|
878
1060
|
start("code", line, "", "directive");
|
|
879
1061
|
flush();
|
|
880
1062
|
continue;
|
|
@@ -899,7 +1081,7 @@ function segment(lines) {
|
|
|
899
1081
|
}
|
|
900
1082
|
continue;
|
|
901
1083
|
}
|
|
902
|
-
const tag = JSDOC_TAG.exec(text);
|
|
1084
|
+
const tag = language.tags ? JSDOC_TAG.exec(text) : null;
|
|
903
1085
|
if (tag) {
|
|
904
1086
|
start("tag", line, "", PROSE_TAGS.has(tag[1]) ? void 0 : `@${tag[1]} tag`);
|
|
905
1087
|
inCodeTag = CODE_TAGS.has(tag[1]);
|
|
@@ -1006,7 +1188,19 @@ function byLine(issues) {
|
|
|
1006
1188
|
function sameLayout(a, b) {
|
|
1007
1189
|
return a.length === b.length && a.every((words, position) => words.join(" ") === b[position].join(" "));
|
|
1008
1190
|
}
|
|
1009
|
-
function
|
|
1191
|
+
function splitTokenLine(lines, tokens) {
|
|
1192
|
+
let next = 0;
|
|
1193
|
+
return lines.findIndex((words) => {
|
|
1194
|
+
const line = words.join(" ");
|
|
1195
|
+
let text = "";
|
|
1196
|
+
while (text.length < line.length && next < tokens.length) {
|
|
1197
|
+
text += `${text ? " " : ""}${tokens[next]}`;
|
|
1198
|
+
next += 1;
|
|
1199
|
+
}
|
|
1200
|
+
return text !== line;
|
|
1201
|
+
});
|
|
1202
|
+
}
|
|
1203
|
+
function analyzeParagraph(paragraph, options, language) {
|
|
1010
1204
|
const first = paragraph.lines[0];
|
|
1011
1205
|
const last = _nullishCoalesce(paragraph.lines.at(-1), () => ( first));
|
|
1012
1206
|
const base = { kind: paragraph.kind, startLine: first.index + 1, endLine: last.index + 1 };
|
|
@@ -1033,7 +1227,8 @@ function analyzeParagraph(paragraph, options) {
|
|
|
1033
1227
|
const structure2 = structureOf(
|
|
1034
1228
|
prose.lines.map((line) => {
|
|
1035
1229
|
return { ...line, text: stripBlockSyntax(line.text) };
|
|
1036
|
-
})
|
|
1230
|
+
}),
|
|
1231
|
+
language
|
|
1037
1232
|
);
|
|
1038
1233
|
const issues2 = keptIssues(prose, structure2, options);
|
|
1039
1234
|
return { ...base, reflowable: false, reason: paragraph.reason, issues: issues2, suggestion: null };
|
|
@@ -1042,7 +1237,7 @@ function analyzeParagraph(paragraph, options) {
|
|
|
1042
1237
|
const issues2 = keptIssues(paragraph, structure2, options);
|
|
1043
1238
|
return { ...base, reflowable: false, reason: structure2.reason, issues: issues2, suggestion: null };
|
|
1044
1239
|
};
|
|
1045
|
-
const structure = structureOf(paragraph.lines);
|
|
1240
|
+
const structure = structureOf(paragraph.lines, language);
|
|
1046
1241
|
if (structure) {
|
|
1047
1242
|
return keep(structure);
|
|
1048
1243
|
}
|
|
@@ -1074,10 +1269,14 @@ function analyzeParagraph(paragraph, options) {
|
|
|
1074
1269
|
if (!units.every((unit) => staysInLimit(unit))) {
|
|
1075
1270
|
return keep({ tier: "manual", reason: "unbreakable text across lines" });
|
|
1076
1271
|
}
|
|
1272
|
+
const text = currentLines.map((words) => words.join(" ")).join("\n");
|
|
1273
|
+
if (!language.joinsCodeSpans && [...text.matchAll(CODE_SPAN)].some((span) => span[0].includes("\n"))) {
|
|
1274
|
+
return keep({ tier: "manual", reason: "code span across lines" });
|
|
1275
|
+
}
|
|
1077
1276
|
const bodyOf = (lines) => {
|
|
1078
1277
|
return lines.map((words, position) => {
|
|
1079
|
-
const
|
|
1080
|
-
return { ...first, text, verbatim: false, hardBreak: HARD_BREAK.test(
|
|
1278
|
+
const text2 = `${position === 0 ? paragraph.marker : hang}${words.join(" ")}`;
|
|
1279
|
+
return { ...first, text: text2, verbatim: false, hardBreak: HARD_BREAK.test(text2) };
|
|
1081
1280
|
});
|
|
1082
1281
|
};
|
|
1083
1282
|
const settle = (settings, extra = 0) => {
|
|
@@ -1085,11 +1284,11 @@ function analyzeParagraph(paragraph, options) {
|
|
|
1085
1284
|
let { even: even2, wrapped: wrapped2 } = layOut(current, settings, extra);
|
|
1086
1285
|
for (; ; ) {
|
|
1087
1286
|
const body = bodyOf(wrapped2);
|
|
1088
|
-
const rewrap = structureOf(body);
|
|
1287
|
+
const rewrap = structureOf(body, language);
|
|
1089
1288
|
if (!rewrap) {
|
|
1090
1289
|
return { even: even2, wrapped: wrapped2 };
|
|
1091
1290
|
}
|
|
1092
|
-
const tipping = body.findIndex((_, position) => structureOf(body.slice(0, position + 1)) !== void 0);
|
|
1291
|
+
const tipping = body.findIndex((_, position) => structureOf(body.slice(0, position + 1), language) !== void 0);
|
|
1093
1292
|
const start = wrapped2.slice(0, Math.max(tipping, 1)).flat().length;
|
|
1094
1293
|
const pair = `${current[start - 1]} ${current[start]}`;
|
|
1095
1294
|
if (body.length < 2 || !staysInLimit(pair)) {
|
|
@@ -1115,6 +1314,7 @@ function analyzeParagraph(paragraph, options) {
|
|
|
1115
1314
|
}
|
|
1116
1315
|
const { even, wrapped } = layout;
|
|
1117
1316
|
const matchesLayout = sameLayout(wrapped, currentLines);
|
|
1317
|
+
const isVerdict = (issue) => ISSUE_TIERS[issue.type] === "verdict";
|
|
1118
1318
|
const lineIssues = [];
|
|
1119
1319
|
const overflow = options.maxWidth === void 0 ? [] : overflowIssues(paragraph.lines, options);
|
|
1120
1320
|
if (!matchesLayout) {
|
|
@@ -1173,8 +1373,11 @@ function analyzeParagraph(paragraph, options) {
|
|
|
1173
1373
|
lineIssues.push({ type: "unbalanced", line });
|
|
1174
1374
|
}
|
|
1175
1375
|
}
|
|
1376
|
+
const splitLine = splitTokenLine(currentLines, tokens);
|
|
1377
|
+
if (splitLine !== -1 && overflow.length === 0 && !lineIssues.some((issue) => isVerdict(issue))) {
|
|
1378
|
+
lineIssues.push({ type: "unbalanced", line: splitLine });
|
|
1379
|
+
}
|
|
1176
1380
|
}
|
|
1177
|
-
const isVerdict = (issue) => ISSUE_TIERS[issue.type] === "verdict";
|
|
1178
1381
|
const matchesWiderLayout = () => {
|
|
1179
1382
|
for (let extra = 1; extra <= layoutOptions.tolerance; extra += 1) {
|
|
1180
1383
|
const wider = layoutAt(extra);
|
|
@@ -1193,6 +1396,18 @@ function analyzeParagraph(paragraph, options) {
|
|
|
1193
1396
|
const issues = byLine([...overflow, ...wrapIssues, ...styleIssues(paragraph, options)]);
|
|
1194
1397
|
return { ...base, reflowable: true, issues, suggestion };
|
|
1195
1398
|
}
|
|
1399
|
+
var LINE_COMMENT = "line comment";
|
|
1400
|
+
function analyzeLineParagraph(paragraph, options, language) {
|
|
1401
|
+
const first = paragraph.lines[0];
|
|
1402
|
+
const last = _nullishCoalesce(paragraph.lines.at(-1), () => ( first));
|
|
1403
|
+
const base = { kind: paragraph.kind, startLine: first.index + 1, endLine: last.index + 1 };
|
|
1404
|
+
if (paragraph.kind === "code") {
|
|
1405
|
+
return { ...base, reflowable: false, reason: paragraph.reason, issues: [], suggestion: null };
|
|
1406
|
+
}
|
|
1407
|
+
const tier = _optionalChain([structureOf, 'call', _41 => _41(paragraph.lines, language), 'optionalAccess', _42 => _42.tier]);
|
|
1408
|
+
const issues = tier === "code" || tier === "layout" ? [] : overflowIssues(paragraph.lines, options);
|
|
1409
|
+
return { ...base, reflowable: false, reason: LINE_COMMENT, issues, suggestion: null };
|
|
1410
|
+
}
|
|
1196
1411
|
function computeLineStarts(source) {
|
|
1197
1412
|
const starts = [0];
|
|
1198
1413
|
for (let index = 0; index < source.length; index += 1) {
|
|
@@ -1218,31 +1433,42 @@ function lineOf(lineStarts, offset) {
|
|
|
1218
1433
|
function stripCarriageReturn(line) {
|
|
1219
1434
|
return line.endsWith("\r") ? line.slice(0, -1) : line;
|
|
1220
1435
|
}
|
|
1221
|
-
function
|
|
1436
|
+
function blockKind(comment, language) {
|
|
1437
|
+
if (language.name === "rust") {
|
|
1438
|
+
return comment.doc ? `${comment.doc}-block-doc` : "block";
|
|
1439
|
+
}
|
|
1440
|
+
return comment.value.startsWith("*") ? "jsdoc" : "block";
|
|
1441
|
+
}
|
|
1442
|
+
function wholeComment(shape, lines, paragraphKind, reason) {
|
|
1443
|
+
const otherLines = lines.map((text, offset) => {
|
|
1444
|
+
return { index: shape.startLine + offset, prefix: "", text, verbatim: false, hardBreak: false };
|
|
1445
|
+
});
|
|
1446
|
+
return { ...shape, paragraphs: [{ kind: paragraphKind, marker: "", reason, lines: otherLines }] };
|
|
1447
|
+
}
|
|
1448
|
+
function isLegal(value, language) {
|
|
1449
|
+
return language.legal.test(replaceKeepingLines(value, CODE_SPAN, "``"));
|
|
1450
|
+
}
|
|
1451
|
+
function shapeBlock(comment, sourceLines, lineStarts, language) {
|
|
1222
1452
|
const startLine = lineOf(lineStarts, comment.start);
|
|
1223
1453
|
const endLine = lineOf(lineStarts, comment.end - 1);
|
|
1224
|
-
const
|
|
1454
|
+
const shape = { kind: blockKind(comment, language), startLine, endLine };
|
|
1225
1455
|
const lines = sourceLines.slice(startLine, endLine + 1);
|
|
1226
|
-
const
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
});
|
|
1230
|
-
return { kind, startLine, endLine, paragraphs: [{ kind: paragraphKind, marker: "", reason, lines: otherLines }] };
|
|
1231
|
-
};
|
|
1232
|
-
const value = comment.value.replace(/^\*/, "");
|
|
1233
|
-
if (LEGAL_COMMENT.test(replaceKeepingLines(comment.value, CODE_SPAN, "``"))) {
|
|
1234
|
-
return wholeComment("code", "legal comment");
|
|
1456
|
+
const value = comment.doc ? comment.value.slice(1) : comment.value.replace(/^\*/, "");
|
|
1457
|
+
if (isLegal(comment.value, language)) {
|
|
1458
|
+
return wholeComment(shape, lines, "code", "legal comment");
|
|
1235
1459
|
}
|
|
1236
|
-
if (LINE_DIRECTIVE.test(value) ||
|
|
1237
|
-
return wholeComment("code", "directive");
|
|
1460
|
+
if (LINE_DIRECTIVE.test(value) || _optionalChain([language, 'access', _43 => _43.blockDirective, 'optionalAccess', _44 => _44.test, 'call', _45 => _45(value)])) {
|
|
1461
|
+
return wholeComment(shape, lines, "code", "directive");
|
|
1238
1462
|
}
|
|
1239
1463
|
const other = () => {
|
|
1240
1464
|
return wholeComment(
|
|
1465
|
+
shape,
|
|
1466
|
+
lines,
|
|
1241
1467
|
"other",
|
|
1242
1468
|
startLine === endLine ? "single-line block comment" : "unsupported block comment layout"
|
|
1243
1469
|
);
|
|
1244
1470
|
};
|
|
1245
|
-
if (startLine === endLine || !/^\s
|
|
1471
|
+
if (startLine === endLine || !/^\s*\/\*[*!]?$/.test(lines[0]) || !/^\s*\*\/$/.test(_nullishCoalesce(lines.at(-1), () => ( "")))) {
|
|
1246
1472
|
return other();
|
|
1247
1473
|
}
|
|
1248
1474
|
const body = [];
|
|
@@ -1261,7 +1487,52 @@ function shapeBlock(comment, sourceLines, lineStarts) {
|
|
|
1261
1487
|
hardBreak: HARD_BREAK.test(text)
|
|
1262
1488
|
});
|
|
1263
1489
|
}
|
|
1264
|
-
return {
|
|
1490
|
+
return { ...shape, paragraphs: segment(body, language) };
|
|
1491
|
+
}
|
|
1492
|
+
function shapeLineRun(group, sourceLines, lineStarts, language) {
|
|
1493
|
+
const startLine = lineOf(lineStarts, group[0].start);
|
|
1494
|
+
const endLine = startLine + group.length - 1;
|
|
1495
|
+
const kind = group[0].doc === "inner" ? "inner-line-doc" : "outer-line-doc";
|
|
1496
|
+
const shape = { kind, startLine, endLine };
|
|
1497
|
+
const lines = sourceLines.slice(startLine, endLine + 1);
|
|
1498
|
+
const values = group.map((comment) => comment.value.slice(1));
|
|
1499
|
+
if (isLegal(values.join("\n"), language)) {
|
|
1500
|
+
return wholeComment(shape, lines, "code", "legal comment");
|
|
1501
|
+
}
|
|
1502
|
+
if (LINE_DIRECTIVE.test(values[0])) {
|
|
1503
|
+
return wholeComment(shape, lines, "code", "directive");
|
|
1504
|
+
}
|
|
1505
|
+
const body = lines.map((line, offset) => {
|
|
1506
|
+
const [, marker, space, text] = _nullishCoalesce(/^(\s*\/\/[/!])( ?)(.*)$/.exec(line), () => ( ["", "", "", line]));
|
|
1507
|
+
return {
|
|
1508
|
+
index: startLine + offset,
|
|
1509
|
+
prefix: `${marker} `,
|
|
1510
|
+
text: text.trimEnd(),
|
|
1511
|
+
verbatim: !space && text.length > 0 || LINE_DIRECTIVE.test(text),
|
|
1512
|
+
hardBreak: HARD_BREAK.test(text)
|
|
1513
|
+
};
|
|
1514
|
+
});
|
|
1515
|
+
return { ...shape, paragraphs: segment(body, language) };
|
|
1516
|
+
}
|
|
1517
|
+
function shapeLineComment(group, sourceLines, lineStarts, language) {
|
|
1518
|
+
const startLine = lineOf(lineStarts, group[0].start);
|
|
1519
|
+
const endLine = startLine + group.length - 1;
|
|
1520
|
+
const shape = { kind: "line", startLine, endLine };
|
|
1521
|
+
const lines = sourceLines.slice(startLine, endLine + 1);
|
|
1522
|
+
if (isLegal(group.map((comment) => comment.value).join("\n"), language)) {
|
|
1523
|
+
return wholeComment(shape, lines, "code", "legal comment");
|
|
1524
|
+
}
|
|
1525
|
+
const body = lines.map((line, offset) => {
|
|
1526
|
+
const [, marker, space, text] = _nullishCoalesce(/^(\s*\/\/[/!]*)( ?)(.*)$/.exec(line), () => ( ["", "", "", line]));
|
|
1527
|
+
return {
|
|
1528
|
+
index: startLine + offset,
|
|
1529
|
+
prefix: `${marker}${space}`,
|
|
1530
|
+
text: text.trimEnd(),
|
|
1531
|
+
verbatim: LINE_DIRECTIVE.test(text),
|
|
1532
|
+
hardBreak: HARD_BREAK.test(text)
|
|
1533
|
+
};
|
|
1534
|
+
});
|
|
1535
|
+
return { ...shape, paragraphs: segment(body, { ...language, tags: false }) };
|
|
1265
1536
|
}
|
|
1266
1537
|
function ownsLines(comment, source, lineStarts) {
|
|
1267
1538
|
const startLine = lineOf(lineStarts, comment.start);
|
|
@@ -1271,12 +1542,12 @@ function ownsLines(comment, source, lineStarts) {
|
|
|
1271
1542
|
const after = source.slice(comment.end, lineEnd);
|
|
1272
1543
|
return /^[\t ]*$/.test(before) && /^[\t ]*\r?\n?$/.test(after);
|
|
1273
1544
|
}
|
|
1274
|
-
function singleLineLength(paragraph, options) {
|
|
1545
|
+
function singleLineLength(paragraph, options, language) {
|
|
1275
1546
|
const [first] = paragraph.lines;
|
|
1276
1547
|
if (paragraph.kind === "other" && paragraph.reason === "single-line block comment") {
|
|
1277
1548
|
return sourceLineLength(first, options.tabWidth);
|
|
1278
1549
|
}
|
|
1279
|
-
if (paragraph.kind !== "prose" || structureOf(paragraph.lines)) {
|
|
1550
|
+
if (paragraph.kind !== "prose" || structureOf(paragraph.lines, language)) {
|
|
1280
1551
|
return Infinity;
|
|
1281
1552
|
}
|
|
1282
1553
|
const text = tokenize(paragraph.lines.map((line) => line.text).join(" ")).join(" ");
|
|
@@ -1288,9 +1559,61 @@ function parseSource(filename, source) {
|
|
|
1288
1559
|
}
|
|
1289
1560
|
function describeFailure(errors, lineStarts) {
|
|
1290
1561
|
const [first] = errors;
|
|
1291
|
-
const offset = _optionalChain([first, 'access',
|
|
1562
|
+
const offset = _optionalChain([first, 'access', _46 => _46.labels, 'access', _47 => _47.at, 'call', _48 => _48(0), 'optionalAccess', _49 => _49.start]);
|
|
1292
1563
|
return { message: first.message, line: offset === void 0 ? void 0 : lineOf(lineStarts, offset) + 1 };
|
|
1293
1564
|
}
|
|
1565
|
+
function scanJavaScript(filename, text, lineStarts) {
|
|
1566
|
+
const { program, comments, errors } = parseSource(filename, text);
|
|
1567
|
+
if (errors.length > 0 && program.body.length === 0) {
|
|
1568
|
+
return { comments: [], syntaxError: describeFailure(errors, lineStarts) };
|
|
1569
|
+
}
|
|
1570
|
+
return {
|
|
1571
|
+
comments: comments.filter((comment) => !(comment.start === 0 && text.startsWith("#!")))
|
|
1572
|
+
};
|
|
1573
|
+
}
|
|
1574
|
+
function scanRustSource(text, lineStarts) {
|
|
1575
|
+
const { comments, error } = scanRust(text);
|
|
1576
|
+
if (error) {
|
|
1577
|
+
return { comments: [], syntaxError: { message: error.message, line: lineOf(lineStarts, error.offset) + 1 } };
|
|
1578
|
+
}
|
|
1579
|
+
return {
|
|
1580
|
+
comments: comments.map((comment) => {
|
|
1581
|
+
return {
|
|
1582
|
+
type: comment.block ? "Block" : "Line",
|
|
1583
|
+
value: text.slice(comment.start + 2, comment.block ? comment.end - 2 : comment.end),
|
|
1584
|
+
start: comment.start,
|
|
1585
|
+
end: comment.end,
|
|
1586
|
+
doc: comment.doc
|
|
1587
|
+
};
|
|
1588
|
+
})
|
|
1589
|
+
};
|
|
1590
|
+
}
|
|
1591
|
+
function groupLineRuns(comments, text, lineStarts, markerOf) {
|
|
1592
|
+
const groups = [];
|
|
1593
|
+
let current;
|
|
1594
|
+
let previousLine = -1;
|
|
1595
|
+
let indent = "";
|
|
1596
|
+
let marker;
|
|
1597
|
+
for (const comment of comments) {
|
|
1598
|
+
const next = comment.type === "Line" ? markerOf(comment) : void 0;
|
|
1599
|
+
if (next === void 0 || !ownsLines(comment, text, lineStarts)) {
|
|
1600
|
+
current = void 0;
|
|
1601
|
+
continue;
|
|
1602
|
+
}
|
|
1603
|
+
const line = lineOf(lineStarts, comment.start);
|
|
1604
|
+
const before = text.slice(lineStarts[line], comment.start);
|
|
1605
|
+
if (current && line === previousLine + 1 && next === marker && before === indent) {
|
|
1606
|
+
current.push(comment);
|
|
1607
|
+
} else {
|
|
1608
|
+
current = [comment];
|
|
1609
|
+
indent = before;
|
|
1610
|
+
marker = next;
|
|
1611
|
+
groups.push(current);
|
|
1612
|
+
}
|
|
1613
|
+
previousLine = line;
|
|
1614
|
+
}
|
|
1615
|
+
return groups;
|
|
1616
|
+
}
|
|
1294
1617
|
function analyzeSource(source, filename, options) {
|
|
1295
1618
|
return inspectSource(source, filename, options).comments;
|
|
1296
1619
|
}
|
|
@@ -1299,39 +1622,66 @@ function inspectSource(source, filename, options) {
|
|
|
1299
1622
|
throw new Error("comments: maxWidth must be an integer at least as large as width");
|
|
1300
1623
|
}
|
|
1301
1624
|
const text = source.startsWith(BYTE_ORDER_MARK) ? source.slice(1) : source;
|
|
1302
|
-
const
|
|
1625
|
+
const language = languageOf(filename);
|
|
1303
1626
|
const lineStarts = computeLineStarts(text);
|
|
1304
|
-
|
|
1305
|
-
|
|
1627
|
+
const scanned = language.name === "rust" ? scanRustSource(text, lineStarts) : scanJavaScript(filename, text, lineStarts);
|
|
1628
|
+
if (scanned.syntaxError) {
|
|
1629
|
+
return { comments: [], syntaxError: scanned.syntaxError };
|
|
1306
1630
|
}
|
|
1307
1631
|
const sourceLines = text.split("\n").map((line) => stripCarriageReturn(line));
|
|
1308
|
-
const parsed = comments.filter((comment) => !(comment.start === 0 && text.startsWith("#!")));
|
|
1309
1632
|
const reports = [];
|
|
1310
|
-
const
|
|
1311
|
-
return
|
|
1312
|
-
});
|
|
1313
|
-
for (const block of blocks) {
|
|
1314
|
-
const shape = shapeBlock(block, sourceLines, lineStarts);
|
|
1315
|
-
const singleLineWidth = Math.max(
|
|
1316
|
-
options.width,
|
|
1317
|
-
Math.min(_nullishCoalesce(options.singleLineWidth, () => ( options.width)), _nullishCoalesce(options.maxWidth, () => ( Infinity)))
|
|
1318
|
-
);
|
|
1319
|
-
const singleLineLimit = Math.min(singleLineWidth + options.tolerance, _nullishCoalesce(options.maxWidth, () => ( Infinity)));
|
|
1320
|
-
const singleLine = shape.paragraphs.length === 1 ? singleLineLength(shape.paragraphs[0], options) : Infinity;
|
|
1321
|
-
const paragraphOptions = singleLine <= singleLineLimit ? { ...options, width: Math.max(singleLineWidth, singleLine) } : options;
|
|
1322
|
-
const lines = sourceLines.slice(shape.startLine, shape.endLine + 1);
|
|
1323
|
-
reports.push({
|
|
1633
|
+
const report = (shape, lines, paragraphs) => {
|
|
1634
|
+
return {
|
|
1324
1635
|
file: filename,
|
|
1325
1636
|
kind: shape.kind,
|
|
1326
1637
|
startLine: shape.startLine + 1,
|
|
1327
1638
|
endLine: shape.endLine + 1,
|
|
1328
|
-
indent: _nullishCoalesce(_optionalChain([/^[\t ]*/, 'access',
|
|
1639
|
+
indent: _nullishCoalesce(_optionalChain([/^[\t ]*/, 'access', _50 => _50.exec, 'call', _51 => _51(lines[0]), 'optionalAccess', _52 => _52[0]]), () => ( "")),
|
|
1329
1640
|
width: options.width,
|
|
1330
1641
|
maxWidth: options.maxWidth,
|
|
1331
1642
|
lengths: lines.map((line) => visualLength(line.trimEnd(), options.tabWidth)),
|
|
1332
1643
|
text: lines.join("\n"),
|
|
1333
|
-
paragraphs
|
|
1644
|
+
paragraphs
|
|
1645
|
+
};
|
|
1646
|
+
};
|
|
1647
|
+
const blocks = scanned.comments.filter((comment) => {
|
|
1648
|
+
return comment.type === "Block" && ownsLines(comment, text, lineStarts) && !comment.value.includes(IGNORE_DIRECTIVE);
|
|
1649
|
+
});
|
|
1650
|
+
const runs = (markerOf) => {
|
|
1651
|
+
return groupLineRuns(scanned.comments, text, lineStarts, markerOf).filter((group) => {
|
|
1652
|
+
return !group.some((comment) => comment.value.includes(IGNORE_DIRECTIVE));
|
|
1334
1653
|
});
|
|
1654
|
+
};
|
|
1655
|
+
const shapes = [
|
|
1656
|
+
...blocks.map((block) => shapeBlock(block, sourceLines, lineStarts, language)),
|
|
1657
|
+
...runs((comment) => comment.doc).map((group) => shapeLineRun(group, sourceLines, lineStarts, language)),
|
|
1658
|
+
...runs((comment) => comment.doc ? void 0 : "//").map(
|
|
1659
|
+
(group) => shapeLineComment(group, sourceLines, lineStarts, language)
|
|
1660
|
+
)
|
|
1661
|
+
].toSorted((a, b) => a.startLine - b.startLine);
|
|
1662
|
+
for (const shape of shapes) {
|
|
1663
|
+
const lines = sourceLines.slice(shape.startLine, shape.endLine + 1);
|
|
1664
|
+
if (shape.kind === "line") {
|
|
1665
|
+
const paragraphs = shape.paragraphs.map((paragraph) => analyzeLineParagraph(paragraph, options, language));
|
|
1666
|
+
if (paragraphs.some((paragraph) => paragraph.issues.length > 0)) {
|
|
1667
|
+
reports.push(report(shape, lines, paragraphs));
|
|
1668
|
+
}
|
|
1669
|
+
continue;
|
|
1670
|
+
}
|
|
1671
|
+
const singleLineWidth = Math.max(
|
|
1672
|
+
options.width,
|
|
1673
|
+
Math.min(_nullishCoalesce(options.singleLineWidth, () => ( options.width)), _nullishCoalesce(options.maxWidth, () => ( Infinity)))
|
|
1674
|
+
);
|
|
1675
|
+
const singleLineLimit = Math.min(singleLineWidth + options.tolerance, _nullishCoalesce(options.maxWidth, () => ( Infinity)));
|
|
1676
|
+
const singleLine = shape.paragraphs.length === 1 ? singleLineLength(shape.paragraphs[0], options, language) : Infinity;
|
|
1677
|
+
const paragraphOptions = singleLine <= singleLineLimit ? { ...options, width: Math.max(singleLineWidth, singleLine) } : options;
|
|
1678
|
+
reports.push(
|
|
1679
|
+
report(
|
|
1680
|
+
shape,
|
|
1681
|
+
lines,
|
|
1682
|
+
shape.paragraphs.map((paragraph) => analyzeParagraph(paragraph, paragraphOptions, language))
|
|
1683
|
+
)
|
|
1684
|
+
);
|
|
1335
1685
|
}
|
|
1336
1686
|
return { comments: reports };
|
|
1337
1687
|
}
|
|
@@ -1352,6 +1702,9 @@ function rewrapComment(report) {
|
|
|
1352
1702
|
}
|
|
1353
1703
|
var POSITION_KEYS = /* @__PURE__ */ new Set(["start", "end", "range", "loc"]);
|
|
1354
1704
|
function codeFingerprint(source, filename) {
|
|
1705
|
+
if (languageOf(filename).name === "rust") {
|
|
1706
|
+
return rustFingerprint(source);
|
|
1707
|
+
}
|
|
1355
1708
|
const { program, errors } = parseSource(filename, source);
|
|
1356
1709
|
if (errors.length > 0) {
|
|
1357
1710
|
return JSON.stringify({ source, errors: errors.map((error) => error.message) });
|
|
@@ -1364,8 +1717,8 @@ function codeFingerprint(source, filename) {
|
|
|
1364
1717
|
|
|
1365
1718
|
// src/comments/agent.ts
|
|
1366
1719
|
var _child_process = require('child_process');
|
|
1367
|
-
|
|
1368
|
-
|
|
1720
|
+
|
|
1721
|
+
|
|
1369
1722
|
var DEFAULT_RULES = `
|
|
1370
1723
|
# Comment rules
|
|
1371
1724
|
|
|
@@ -1373,7 +1726,7 @@ var DEFAULT_RULES = `
|
|
|
1373
1726
|
|
|
1374
1727
|
When rules pull in different directions, the earlier one wins.
|
|
1375
1728
|
|
|
1376
|
-
1. Keep code and exact text byte for byte, including every punctuation character in it. That covers code blocks, \`@example\`, code spans, identifiers, string literals like error messages, regexes, globs and other patterns like \`*test*\`, URLs, quoted text, titles,
|
|
1729
|
+
1. Keep code and exact text byte for byte, including every punctuation character in it. That covers code blocks, \`@example\`, code spans, identifiers, string literals like error messages, regexes, globs and other patterns like \`*test*\`, URLs, quoted text, titles, notation like \`host:port\`, and Rust intra-doc links (see below).
|
|
1377
1730
|
2. Keep the meaning. An edit may make a comment clearer, never different.
|
|
1378
1731
|
3. Follow the style preferences below.
|
|
1379
1732
|
4. Change as little as possible. Wording that already reads clearly stays, even when a note points at it.
|
|
@@ -1386,10 +1739,12 @@ When rules pull in different directions, the earlier one wins.
|
|
|
1386
1739
|
- A comment whose whole text is one paragraph stays on a single line when that line fits a separate, larger single-line width, even past the width. Only a longer comment wraps to the width.
|
|
1387
1740
|
- Separate paragraphs with an empty comment line.
|
|
1388
1741
|
- Never split a backtick code span across lines.
|
|
1742
|
+
- Never split a Markdown link across lines. A link is the text in brackets and the target right after it, like \`[the docs](https://example.com)\`, \`[the docs][label]\`, or \`[the docs]\`, and all of it stays on one line, from its first bracket to its last bracket or parenthesis. An editor can't follow a link that continues on the next line. When a line is too long, break it before or after the link.
|
|
1389
1743
|
- Keep code blocks, \`@example\`, lists, tables, box drawings, aligned columns, and Markdown hard line breaks (a line that ends with two spaces or a backslash) laid out as they are. List items wrap with their continuation lines indented to the item text, and a JSDoc tag description that doesn't fit continues on the next line without indentation.
|
|
1390
1744
|
- The tool measures every line, taking the tolerance and the parts it keeps as written into account, and the notes on each comment list what is still wrong. Act on those notes. Don't count columns, and don't apply a stricter limit than the notes show.
|
|
1391
1745
|
- The maximum is a hard limit for measured prose, including long tokens. If a URL, code span, or other exact text exceeds it, preserve that text and explain the unresolved overflow instead of changing its contents.
|
|
1392
1746
|
- The tool never rewraps the parts it keeps as written, like a single-line block comment, a paragraph with hard line breaks, or lines that may be laid out by hand. When a note says one of their prose lines is too long, break or shorten it yourself. Exact text and intentional layout win over the width, so keep code, code spans, and the layout in them intact, and if a note can only be fixed by changing them, leave it and say why in your reply.
|
|
1747
|
+
- The tool never rewraps a line comment (\`//\`) either. When a note says one of its lines is too long, shorten the wording so the comment fits on its line and still says the same thing. When it can't be shortened without losing meaning, turn it into a multi-line block comment instead: \`/**\` in JavaScript and TypeScript, or \`/*\` in Rust, on its own line, then the text on lines that start with \` * \`, then \` */\` on its own line, all at the indentation of the line comment. Like other block comments, it starts with a capital letter and ends with punctuation. Leave its line breaks to the tool, which rewraps it like any other block comment. Never split a line comment into more \`//\` lines.
|
|
1393
1748
|
|
|
1394
1749
|
## Style
|
|
1395
1750
|
|
|
@@ -1400,8 +1755,16 @@ These are preferences for comment prose. They never apply to code or exact text
|
|
|
1400
1755
|
- Prefer a sentence over a "Label: explanation" fragment, like \`...the socket. Optional: without it...\` or \`Default: refuse\` in the middle of prose. A colon is fine where it introduces a list, code block, or example, in a term's definition, in notation, in a quotation, and in a \`Note:\` or \`Optional:\` that starts a comment. A JSDoc tag like \`@note\` or \`@todo\` can replace a label, and \`@default\` fits a default value, not a description.
|
|
1401
1756
|
- Avoid asterisk emphasis like \`*this*\`, and use plain wording instead. A name or pattern in asterisks, like \`*test*\` or \`*.spec.ts\`, is a pattern, so keep its asterisks and wrap it in a code span, like \`\` \`*test*\` \`\`.
|
|
1402
1757
|
- Avoid section banner comments, i.e. dividers or headings made of dashes, equals signs, asterisks, or other repeated characters that split a file into visual sections. Let the code structure carry the grouping, or write one short, plain sentence comment (e.g. \`// handlers for control mode\`). Rules that belong to a diagram, a table, a box drawing, a Markdown document, an example, or a legal header aren't banners.
|
|
1403
|
-
- Block and
|
|
1404
|
-
- Never turn a block or JSDoc comment into \`//\` line comments, and never write a run of consecutive \`//\` lines.
|
|
1758
|
+
- Block, JSDoc, and Rust doc comments are capitalized and end with punctuation.
|
|
1759
|
+
- Never change the kind of a comment, except to turn a line comment that is too long into a block comment (see Layout). Don't turn a block or JSDoc comment into \`//\` line comments, and never write a run of consecutive \`//\` lines. In Rust, a run of \`///\` or \`//!\` lines is one doc comment, so keep its markers, and never turn a doc comment (\`///\`, \`//!\`, \`/**\`, \`/*!\`) into another kind, since that changes or removes documentation.
|
|
1760
|
+
|
|
1761
|
+
## Rust doc comments
|
|
1762
|
+
|
|
1763
|
+
Rust doc comments are Markdown that rustdoc renders.
|
|
1764
|
+
|
|
1765
|
+
- Intra-doc links are exact text. Keep their brackets, backticks, and targets, like \`\` [\`count_provider_reads\`] \`\`, \`\` [\`permissions\`](crate::permissions) \`\`, \`\` [the parser][\`Parser\`] \`\`, or \`[Vec<T>]\`, since rustdoc resolves the text in brackets, or the target after it, as a path. Each link stays on one line (see Layout), including a link with spaces in its text, like \`[the provider module](crate::provider)\`.
|
|
1766
|
+
- A link reference definition, like \`\` [\`Foo\`]: crate::Foo \`\`, stays on its own line as it is. Its colon is syntax, not a label.
|
|
1767
|
+
- Headings like \`# Examples\`, \`# Panics\`, \`# Errors\`, and \`# Safety\` are sections that rustdoc and readers look for, so keep them. Code blocks are doctests, so keep their lines, including hidden lines that start with \`#\`, exactly as they are.
|
|
1405
1768
|
|
|
1406
1769
|
## Editing
|
|
1407
1770
|
|
|
@@ -1411,10 +1774,10 @@ These are preferences for comment prose. They never apply to code or exact text
|
|
|
1411
1774
|
|
|
1412
1775
|
// src/comments/config.ts
|
|
1413
1776
|
|
|
1414
|
-
var _module = require('module');
|
|
1415
1777
|
|
|
1416
|
-
|
|
1417
|
-
|
|
1778
|
+
|
|
1779
|
+
|
|
1780
|
+
var DEFAULT_EXTENSIONS = Object.freeze([".js", ".jsx", ".mjs", ".cjs", ".ts", ".tsx", ".mts", ".cts", ".rs"]);
|
|
1418
1781
|
var CONFIG_FILES = [
|
|
1419
1782
|
"comments.config.ts",
|
|
1420
1783
|
"comments.config.mts",
|
|
@@ -1465,10 +1828,12 @@ function validateConfig(raw, filepath) {
|
|
|
1465
1828
|
assertType(config.avoidSentenceOrphans, "boolean", "avoidSentenceOrphans", filepath);
|
|
1466
1829
|
assertType(config.style, "boolean", "style", filepath);
|
|
1467
1830
|
assertType(config.extensions, "array", "extensions", filepath);
|
|
1831
|
+
assertType(config.include, "array", "include", filepath);
|
|
1468
1832
|
assertType(config.ignore, "array", "ignore", filepath);
|
|
1469
1833
|
assertType(config.agent, "object", "agent", filepath);
|
|
1470
1834
|
assertType(config.hook, "object", "hook", filepath);
|
|
1471
1835
|
assertStrings(config.extensions, "extensions", filepath);
|
|
1836
|
+
assertStrings(config.include, "include", filepath);
|
|
1472
1837
|
assertStrings(config.ignore, "ignore", filepath);
|
|
1473
1838
|
for (const key of ["width", "maxWidth", "singleLineWidth", "tolerance"]) {
|
|
1474
1839
|
const value = config[key];
|
|
@@ -1501,8 +1866,8 @@ function validateConfig(raw, filepath) {
|
|
|
1501
1866
|
}
|
|
1502
1867
|
assertType(agent.rules, "string", "agent.rules", filepath);
|
|
1503
1868
|
assertType(agent.instructions, "string", "agent.instructions", filepath);
|
|
1504
|
-
if (agent.scope !== void 0 &&
|
|
1505
|
-
throw new Error(`comments: \`agent.scope\` in ${filepath} must be
|
|
1869
|
+
if (agent.scope !== void 0 && !["suspicious", "failing", "all"].includes(agent.scope)) {
|
|
1870
|
+
throw new Error(`comments: \`agent.scope\` in ${filepath} must be one of suspicious, failing, all`);
|
|
1506
1871
|
}
|
|
1507
1872
|
const hook = _nullishCoalesce(config.hook, () => ( {}));
|
|
1508
1873
|
if (hook.mode !== void 0 && !["agent", "report", "off"].includes(hook.mode)) {
|