@ttsc/lint 0.10.2 → 0.11.0-dev.20260517
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 +172 -33
- package/lib/defineConfig.d.ts +55 -0
- package/lib/defineConfig.js +39 -0
- package/lib/defineConfig.js.map +1 -0
- package/lib/index.d.ts +25 -1
- package/lib/index.js +622 -2
- package/lib/index.js.map +1 -1
- package/lib/structures/ITtscLintPlugin.d.ts +53 -0
- package/lib/structures/ITtscLintPlugin.js +3 -0
- package/lib/structures/ITtscLintPlugin.js.map +1 -0
- package/lib/structures/ITtscLintPluginConfig.d.ts +82 -5
- package/lib/structures/ITtscLintPluginMeta.d.ts +12 -0
- package/lib/structures/ITtscLintPluginMeta.js +3 -0
- package/lib/structures/ITtscLintPluginMeta.js.map +1 -0
- package/lib/structures/PluginRuleNames.d.ts +14 -0
- package/lib/structures/PluginRuleNames.js +3 -0
- package/lib/structures/PluginRuleNames.js.map +1 -0
- package/lib/structures/TtscLintConfig.d.ts +24 -8
- package/lib/structures/TtscLintConfigEntry.d.ts +39 -0
- package/lib/structures/TtscLintConfigEntry.js +3 -0
- package/lib/structures/TtscLintConfigEntry.js.map +1 -0
- package/lib/structures/TtscLintFormatConfig.d.ts +154 -0
- package/lib/structures/TtscLintFormatConfig.js +3 -0
- package/lib/structures/TtscLintFormatConfig.js.map +1 -0
- package/lib/structures/TtscLintPlugins.d.ts +9 -0
- package/lib/structures/TtscLintPlugins.js +3 -0
- package/lib/structures/TtscLintPlugins.js.map +1 -0
- package/lib/structures/TtscLintRule.d.ts +1 -1
- package/lib/structures/TtscLintRuleEntry.d.ts +22 -0
- package/lib/structures/TtscLintRuleEntry.js +3 -0
- package/lib/structures/TtscLintRuleEntry.js.map +1 -0
- package/lib/structures/TtscLintRuleMap.d.ts +44 -0
- package/lib/structures/TtscLintRuleMap.js +3 -0
- package/lib/structures/TtscLintRuleMap.js.map +1 -0
- package/lib/structures/TtscLintRuleOptions.d.ts +149 -0
- package/lib/structures/TtscLintRuleOptions.js +3 -0
- package/lib/structures/TtscLintRuleOptions.js.map +1 -0
- package/lib/structures/defaultFormat.d.ts +31 -0
- package/lib/structures/defaultFormat.js +35 -0
- package/lib/structures/defaultFormat.js.map +1 -0
- package/lib/structures/index.d.ts +10 -0
- package/lib/structures/index.js +10 -0
- package/lib/structures/index.js.map +1 -1
- package/{plugin → linthost}/ast_helpers.go +92 -1
- package/{plugin → linthost}/compile.go +1 -1
- package/{plugin → linthost}/config.go +583 -66
- package/linthost/config_format.go +360 -0
- package/linthost/contrib_adapter.go +134 -0
- package/{plugin → linthost}/directives.go +1 -1
- package/linthost/dispatch.go +62 -0
- package/{plugin → linthost}/engine.go +156 -11
- package/{plugin → linthost}/eslint_runtime.go +76 -2
- package/linthost/fix.go +249 -0
- package/linthost/format.go +107 -0
- package/{plugin → linthost}/host.go +1 -1
- package/linthost/print_dispatch.go +118 -0
- package/linthost/print_doc.go +168 -0
- package/linthost/print_engine.go +343 -0
- package/linthost/print_nodes_array.go +46 -0
- package/linthost/print_nodes_call.go +180 -0
- package/linthost/print_nodes_imports.go +171 -0
- package/linthost/print_nodes_list.go +64 -0
- package/linthost/print_nodes_object.go +51 -0
- package/{plugin → linthost}/rules_arrays.go +1 -1
- package/{plugin → linthost}/rules_console.go +1 -1
- package/{plugin → linthost}/rules_debugger.go +1 -1
- package/{plugin → linthost}/rules_dupes.go +1 -1
- package/{plugin → linthost}/rules_empty.go +1 -1
- package/linthost/rules_escape.go +238 -0
- package/{plugin → linthost}/rules_eval.go +1 -1
- package/{plugin → linthost}/rules_finally.go +1 -1
- package/linthost/rules_format_jsdoc.go +230 -0
- package/linthost/rules_format_print_width.go +332 -0
- package/linthost/rules_format_quotes.go +219 -0
- package/linthost/rules_format_semi.go +190 -0
- package/linthost/rules_format_sort_imports.go +462 -0
- package/linthost/rules_format_trailing_comma.go +460 -0
- package/{plugin → linthost}/rules_gap.go +101 -6
- package/linthost/rules_imports.go +101 -0
- package/{plugin → linthost}/rules_logic.go +55 -3
- package/{plugin → linthost}/rules_loops.go +1 -1
- package/{plugin → linthost}/rules_misc.go +1 -1
- package/linthost/rules_params.go +64 -0
- package/{plugin → linthost}/rules_problems.go +10 -2
- package/linthost/rules_promise.go +111 -0
- package/{plugin → linthost}/rules_protos.go +1 -1
- package/{plugin → linthost}/rules_self.go +1 -1
- package/{plugin → linthost}/rules_strings.go +1 -1
- package/{plugin → linthost}/rules_suggestions.go +51 -9
- package/{plugin → linthost}/rules_throw.go +1 -1
- package/{plugin → linthost}/rules_ts.go +12 -2
- package/{plugin → linthost}/rules_ts_extra.go +90 -4
- package/{plugin → linthost}/rules_var.go +36 -5
- package/package.json +8 -6
- package/plugin/main.go +14 -27
- package/rule/astutil/astutil.go +148 -0
- package/rule/rule.go +291 -0
- package/src/defineConfig.ts +69 -0
- package/src/index.ts +807 -3
- package/src/structures/ITtscLintPlugin.ts +56 -0
- package/src/structures/ITtscLintPluginConfig.ts +86 -5
- package/src/structures/ITtscLintPluginMeta.ts +14 -0
- package/src/structures/PluginRuleNames.ts +19 -0
- package/src/structures/TtscLintConfig.ts +27 -8
- package/src/structures/TtscLintConfigEntry.ts +50 -0
- package/src/structures/TtscLintFormatConfig.ts +169 -0
- package/src/structures/TtscLintPlugins.ts +10 -0
- package/src/structures/TtscLintRule.ts +14 -1
- package/src/structures/TtscLintRuleEntry.ts +28 -0
- package/src/structures/TtscLintRuleMap.ts +52 -0
- package/src/structures/TtscLintRuleOptions.ts +162 -0
- package/src/structures/defaultFormat.ts +33 -0
- package/src/structures/index.ts +10 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-rule option shapes used by `TtscLintRuleEntry` to type the second tuple
|
|
3
|
+
* slot.
|
|
4
|
+
*
|
|
5
|
+
* Each entry here maps a rule name to its option struct. Rule names that do not
|
|
6
|
+
* appear in this interface accept severity-only configuration (a `[severity]`
|
|
7
|
+
* tuple is _also_ allowed for them, with an empty options blob).
|
|
8
|
+
*
|
|
9
|
+
* The shapes are designed to match the analogous prettier / ESLint options
|
|
10
|
+
* where the rule absorbs an existing tool's behavior:
|
|
11
|
+
*
|
|
12
|
+
* - `format/semi` mirrors prettier `semi`.
|
|
13
|
+
* - `format/quotes` mirrors prettier `singleQuote` (inverted).
|
|
14
|
+
* - `format/trailing-comma` mirrors prettier `trailingComma`.
|
|
15
|
+
* - `format/sort-imports` mirrors `@trivago/prettier-plugin-sort-imports`
|
|
16
|
+
* (`importOrder`, `importOrderSeparation`, `importOrderSortSpecifiers`,
|
|
17
|
+
* `importOrderCaseInsensitive`).
|
|
18
|
+
* - `format/jsdoc` mirrors `prettier-plugin-jsdoc` (`tagSynonyms` layered onto
|
|
19
|
+
* the built-in synonym table, `sortTags` reserved for a future pass).
|
|
20
|
+
*
|
|
21
|
+
* Future option additions go here so the TypeScript autocomplete updates in one
|
|
22
|
+
* place. The Go side reads these as `json.RawMessage` and each rule decodes
|
|
23
|
+
* into its own struct.
|
|
24
|
+
*/
|
|
25
|
+
export declare namespace TtscLintRuleOptions {
|
|
26
|
+
/** `format/semi` options. */
|
|
27
|
+
interface Semi {
|
|
28
|
+
/**
|
|
29
|
+
* Whether trailing semicolons must be present on ASI statements.
|
|
30
|
+
*
|
|
31
|
+
* @default "always"
|
|
32
|
+
*/
|
|
33
|
+
prefer?: "always" | "never";
|
|
34
|
+
}
|
|
35
|
+
/** `format/quotes` options. */
|
|
36
|
+
interface Quotes {
|
|
37
|
+
/**
|
|
38
|
+
* Quote style for string literals. Template literals are always preserved
|
|
39
|
+
* regardless of this setting.
|
|
40
|
+
*
|
|
41
|
+
* @default "double"
|
|
42
|
+
*/
|
|
43
|
+
prefer?: "double" | "single";
|
|
44
|
+
}
|
|
45
|
+
/** `format/trailing-comma` options. */
|
|
46
|
+
interface TrailingComma {
|
|
47
|
+
/**
|
|
48
|
+
* Which multi-line lists receive a trailing comma. `"all"` matches
|
|
49
|
+
* prettier's modern default; `"es5"` skips function calls and type
|
|
50
|
+
* parameter lists; `"none"` disables the rule entirely.
|
|
51
|
+
*
|
|
52
|
+
* @default "all"
|
|
53
|
+
*/
|
|
54
|
+
mode?: "all" | "es5" | "none";
|
|
55
|
+
}
|
|
56
|
+
/** `format/sort-imports` options. */
|
|
57
|
+
interface SortImports {
|
|
58
|
+
/**
|
|
59
|
+
* Ordered list of regex strings (or the `<THIRD_PARTY_MODULES>`
|
|
60
|
+
* placeholder) defining the group order. Imports matching the first pattern
|
|
61
|
+
* land in group 0, the second in group 1, and so on. The placeholder
|
|
62
|
+
* absorbs any specifier that does not match another pattern. Mirrors
|
|
63
|
+
* trivago's `importOrder` semantics.
|
|
64
|
+
*/
|
|
65
|
+
importOrder?: readonly string[];
|
|
66
|
+
/**
|
|
67
|
+
* Insert a blank line between groups.
|
|
68
|
+
*
|
|
69
|
+
* @default true
|
|
70
|
+
*/
|
|
71
|
+
importOrderSeparation?: boolean;
|
|
72
|
+
/**
|
|
73
|
+
* Sort named import specifiers alphabetically within each declaration.
|
|
74
|
+
*
|
|
75
|
+
* @default true
|
|
76
|
+
*/
|
|
77
|
+
importOrderSortSpecifiers?: boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Treat `A` and `a` as equivalent when comparing module specifiers and
|
|
80
|
+
* specifier names. Mirrors trivago's `importOrderCaseInsensitive`.
|
|
81
|
+
*
|
|
82
|
+
* @default false
|
|
83
|
+
*/
|
|
84
|
+
importOrderCaseInsensitive?: boolean;
|
|
85
|
+
}
|
|
86
|
+
/** `format/print-width` options. */
|
|
87
|
+
interface PrintWidth {
|
|
88
|
+
/**
|
|
89
|
+
* Maximum column width before broken-form layout is chosen. Mirrors
|
|
90
|
+
* prettier's `printWidth`.
|
|
91
|
+
*
|
|
92
|
+
* @default 80
|
|
93
|
+
*/
|
|
94
|
+
printWidth?: number;
|
|
95
|
+
/**
|
|
96
|
+
* Indentation increment in columns. Mirrors prettier's `tabWidth`.
|
|
97
|
+
*
|
|
98
|
+
* @default 2
|
|
99
|
+
*/
|
|
100
|
+
tabWidth?: number;
|
|
101
|
+
/**
|
|
102
|
+
* Emit indentation as tab characters rather than spaces. Mirrors
|
|
103
|
+
* prettier's `useTabs`. Continuation alignment beyond the tab
|
|
104
|
+
* boundary still falls back to spaces, matching dprint's
|
|
105
|
+
* "indent with tabs, align with spaces" convention.
|
|
106
|
+
*
|
|
107
|
+
* @default false
|
|
108
|
+
*/
|
|
109
|
+
useTabs?: boolean;
|
|
110
|
+
/**
|
|
111
|
+
* Line-terminator emitted on every newline the printer inserts.
|
|
112
|
+
* Mirrors prettier's `endOfLine` `"lf"` and `"crlf"` modes.
|
|
113
|
+
*
|
|
114
|
+
* @default "lf"
|
|
115
|
+
*/
|
|
116
|
+
endOfLine?: "lf" | "crlf";
|
|
117
|
+
}
|
|
118
|
+
/** `format/jsdoc` options. */
|
|
119
|
+
interface JSDoc {
|
|
120
|
+
/**
|
|
121
|
+
* Extra `from → to` tag rewrites layered on top of the built-in synonym
|
|
122
|
+
* table (`@return → @returns`, `@arg → @param`, etc.). User-supplied
|
|
123
|
+
* entries win on key collision, so a `{"return": "RETURN"}` entry overrides
|
|
124
|
+
* the built-in default for `@return`.
|
|
125
|
+
*
|
|
126
|
+
* @default {} (use built-in table unchanged)
|
|
127
|
+
*/
|
|
128
|
+
tagSynonyms?: Record<string, string>;
|
|
129
|
+
/**
|
|
130
|
+
* Sort JSDoc tag blocks into the canonical order (`@description`, `@param`,
|
|
131
|
+
* `@returns`, …).
|
|
132
|
+
*
|
|
133
|
+
* @default false (deferred; MVP only normalizes tag names)
|
|
134
|
+
*/
|
|
135
|
+
sortTags?: boolean;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Index from rule name to its option struct. Used by `TtscLintRuleEntry<R>` to
|
|
140
|
+
* produce precise tuple types per rule.
|
|
141
|
+
*/
|
|
142
|
+
export interface TtscLintRuleOptionsMap {
|
|
143
|
+
"format/semi": TtscLintRuleOptions.Semi;
|
|
144
|
+
"format/quotes": TtscLintRuleOptions.Quotes;
|
|
145
|
+
"format/trailing-comma": TtscLintRuleOptions.TrailingComma;
|
|
146
|
+
"format/sort-imports": TtscLintRuleOptions.SortImports;
|
|
147
|
+
"format/jsdoc": TtscLintRuleOptions.JSDoc;
|
|
148
|
+
"format/print-width": TtscLintRuleOptions.PrintWidth;
|
|
149
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TtscLintRuleOptions.js","sourceRoot":"","sources":["../../src/structures/TtscLintRuleOptions.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Documented defaults for the `format` block's *always-on* rules
|
|
3
|
+
* (`format/semi`, `format/quotes`, `format/trailing-comma`,
|
|
4
|
+
* `format/print-width`).
|
|
5
|
+
*
|
|
6
|
+
* Exported so users can spread defaults next to overrides:
|
|
7
|
+
*
|
|
8
|
+
* import { defaultFormat, type TtscLintConfig } from "@ttsc/lint";
|
|
9
|
+
*
|
|
10
|
+
* export default {
|
|
11
|
+
* format: { ...defaultFormat, printWidth: 100 },
|
|
12
|
+
* } satisfies TtscLintConfig;
|
|
13
|
+
*
|
|
14
|
+
* The values mirror Prettier 1:1 except for the documented
|
|
15
|
+
* `endOfLine` narrowing (no `"cr"` / `"auto"`).
|
|
16
|
+
*
|
|
17
|
+
* Notably absent: `importOrder` and `jsdoc`. `format/sort-imports`
|
|
18
|
+
* and `format/jsdoc` are opt-in by setting their corresponding
|
|
19
|
+
* fields; the defaults const only seeds the rules that turn on
|
|
20
|
+
* unconditionally with a non-empty `format` block.
|
|
21
|
+
*/
|
|
22
|
+
export declare const defaultFormat: Readonly<{
|
|
23
|
+
severity: "warning";
|
|
24
|
+
semi: true;
|
|
25
|
+
singleQuote: false;
|
|
26
|
+
trailingComma: "all";
|
|
27
|
+
printWidth: number;
|
|
28
|
+
tabWidth: number;
|
|
29
|
+
useTabs: false;
|
|
30
|
+
endOfLine: "lf";
|
|
31
|
+
}>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.defaultFormat = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Documented defaults for the `format` block's *always-on* rules
|
|
6
|
+
* (`format/semi`, `format/quotes`, `format/trailing-comma`,
|
|
7
|
+
* `format/print-width`).
|
|
8
|
+
*
|
|
9
|
+
* Exported so users can spread defaults next to overrides:
|
|
10
|
+
*
|
|
11
|
+
* import { defaultFormat, type TtscLintConfig } from "@ttsc/lint";
|
|
12
|
+
*
|
|
13
|
+
* export default {
|
|
14
|
+
* format: { ...defaultFormat, printWidth: 100 },
|
|
15
|
+
* } satisfies TtscLintConfig;
|
|
16
|
+
*
|
|
17
|
+
* The values mirror Prettier 1:1 except for the documented
|
|
18
|
+
* `endOfLine` narrowing (no `"cr"` / `"auto"`).
|
|
19
|
+
*
|
|
20
|
+
* Notably absent: `importOrder` and `jsdoc`. `format/sort-imports`
|
|
21
|
+
* and `format/jsdoc` are opt-in by setting their corresponding
|
|
22
|
+
* fields; the defaults const only seeds the rules that turn on
|
|
23
|
+
* unconditionally with a non-empty `format` block.
|
|
24
|
+
*/
|
|
25
|
+
exports.defaultFormat = Object.freeze({
|
|
26
|
+
severity: "warning",
|
|
27
|
+
semi: true,
|
|
28
|
+
singleQuote: false,
|
|
29
|
+
trailingComma: "all",
|
|
30
|
+
printWidth: 80,
|
|
31
|
+
tabWidth: 2,
|
|
32
|
+
useTabs: false,
|
|
33
|
+
endOfLine: "lf",
|
|
34
|
+
});
|
|
35
|
+
//# sourceMappingURL=defaultFormat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaultFormat.js","sourceRoot":"","sources":["../../src/structures/defaultFormat.ts"],"names":[],"mappings":";;;AAEA;;;;;;;;;;;;;;;;;;;;GAoBG;AACU,QAAA,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC;IACzC,QAAQ,EAAE,SAAS;IACnB,IAAI,EAAE,IAAI;IACV,WAAW,EAAE,KAAK;IAClB,aAAa,EAAE,KAAK;IACpB,UAAU,EAAE,EAAE;IACd,QAAQ,EAAE,CAAC;IACX,OAAO,EAAE,KAAK;IACd,SAAS,EAAE,IAAI;CACe,CAAC,CAAC"}
|
|
@@ -1,4 +1,14 @@
|
|
|
1
|
+
export * from "./defaultFormat";
|
|
2
|
+
export * from "./ITtscLintPlugin";
|
|
1
3
|
export * from "./ITtscLintPluginConfig";
|
|
4
|
+
export * from "./ITtscLintPluginMeta";
|
|
5
|
+
export * from "./PluginRuleNames";
|
|
2
6
|
export * from "./TtscLintConfig";
|
|
7
|
+
export * from "./TtscLintConfigEntry";
|
|
8
|
+
export * from "./TtscLintFormatConfig";
|
|
9
|
+
export * from "./TtscLintPlugins";
|
|
3
10
|
export * from "./TtscLintRule";
|
|
11
|
+
export * from "./TtscLintRuleEntry";
|
|
12
|
+
export * from "./TtscLintRuleMap";
|
|
13
|
+
export * from "./TtscLintRuleOptions";
|
|
4
14
|
export * from "./TtscLintSeverity";
|
package/lib/structures/index.js
CHANGED
|
@@ -14,8 +14,18 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./defaultFormat"), exports);
|
|
18
|
+
__exportStar(require("./ITtscLintPlugin"), exports);
|
|
17
19
|
__exportStar(require("./ITtscLintPluginConfig"), exports);
|
|
20
|
+
__exportStar(require("./ITtscLintPluginMeta"), exports);
|
|
21
|
+
__exportStar(require("./PluginRuleNames"), exports);
|
|
18
22
|
__exportStar(require("./TtscLintConfig"), exports);
|
|
23
|
+
__exportStar(require("./TtscLintConfigEntry"), exports);
|
|
24
|
+
__exportStar(require("./TtscLintFormatConfig"), exports);
|
|
25
|
+
__exportStar(require("./TtscLintPlugins"), exports);
|
|
19
26
|
__exportStar(require("./TtscLintRule"), exports);
|
|
27
|
+
__exportStar(require("./TtscLintRuleEntry"), exports);
|
|
28
|
+
__exportStar(require("./TtscLintRuleMap"), exports);
|
|
29
|
+
__exportStar(require("./TtscLintRuleOptions"), exports);
|
|
20
30
|
__exportStar(require("./TtscLintSeverity"), exports);
|
|
21
31
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/structures/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0DAAwC;AACxC,mDAAiC;AACjC,iDAA+B;AAC/B,qDAAmC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/structures/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,kDAAgC;AAChC,oDAAkC;AAClC,0DAAwC;AACxC,wDAAsC;AACtC,oDAAkC;AAClC,mDAAiC;AACjC,wDAAsC;AACtC,yDAAuC;AACvC,oDAAkC;AAClC,iDAA+B;AAC/B,sDAAoC;AACpC,oDAAkC;AAClC,wDAAsC;AACtC,qDAAmC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
package
|
|
1
|
+
package linthost
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
4
|
"strings"
|
|
@@ -26,6 +26,97 @@ func nodeText(file *shimast.SourceFile, node *shimast.Node) string {
|
|
|
26
26
|
return strings.TrimRight(src[pos:end], " \t\r\n")
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
// keywordStart returns the source offset of a declaration keyword such as
|
|
30
|
+
// `var` or `let` at the start of a node after leading trivia.
|
|
31
|
+
func keywordStart(file *shimast.SourceFile, node *shimast.Node, keyword string) int {
|
|
32
|
+
if file == nil || node == nil || keyword == "" {
|
|
33
|
+
return -1
|
|
34
|
+
}
|
|
35
|
+
src := file.Text()
|
|
36
|
+
pos := shimscanner.SkipTrivia(src, node.Pos())
|
|
37
|
+
end := pos + len(keyword)
|
|
38
|
+
if pos < 0 || end > len(src) {
|
|
39
|
+
return -1
|
|
40
|
+
}
|
|
41
|
+
if strings.HasPrefix(src[pos:], keyword) && (end == len(src) || !isIdentifierPart(src[end])) {
|
|
42
|
+
return pos
|
|
43
|
+
}
|
|
44
|
+
limit := node.End()
|
|
45
|
+
if limit > len(src) {
|
|
46
|
+
limit = len(src)
|
|
47
|
+
}
|
|
48
|
+
for i := pos; i+len(keyword) <= limit && i < pos+32; i++ {
|
|
49
|
+
end = i + len(keyword)
|
|
50
|
+
if strings.HasPrefix(src[i:], keyword) &&
|
|
51
|
+
(i == 0 || !isIdentifierPart(src[i-1])) &&
|
|
52
|
+
(end == len(src) || !isIdentifierPart(src[end])) {
|
|
53
|
+
return i
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return -1
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// findKeyword scans [pos, end) for a keyword token whose lexeme is
|
|
60
|
+
// `keyword`. Returns the byte offset of the keyword's first character,
|
|
61
|
+
// or -1 if not found. Unlike keywordStart this is unbounded by a node's
|
|
62
|
+
// leading-trivia start, so it can locate `module` inside a
|
|
63
|
+
// ModuleDeclaration or insert points like the end of `import`.
|
|
64
|
+
//
|
|
65
|
+
// The match is identifier-aware: a hit must be preceded and followed by
|
|
66
|
+
// a non-identifier byte so that e.g. searching for `import` does not
|
|
67
|
+
// match the `import` prefix of `importStr`.
|
|
68
|
+
func findKeyword(file *shimast.SourceFile, pos, end int, keyword string) int {
|
|
69
|
+
if file == nil || keyword == "" {
|
|
70
|
+
return -1
|
|
71
|
+
}
|
|
72
|
+
src := file.Text()
|
|
73
|
+
if pos < 0 {
|
|
74
|
+
pos = 0
|
|
75
|
+
}
|
|
76
|
+
if end > len(src) {
|
|
77
|
+
end = len(src)
|
|
78
|
+
}
|
|
79
|
+
limit := end - len(keyword)
|
|
80
|
+
for i := pos; i <= limit; i++ {
|
|
81
|
+
if src[i] != keyword[0] {
|
|
82
|
+
continue
|
|
83
|
+
}
|
|
84
|
+
tail := i + len(keyword)
|
|
85
|
+
if src[i:tail] != keyword {
|
|
86
|
+
continue
|
|
87
|
+
}
|
|
88
|
+
if i > 0 && isIdentifierPart(src[i-1]) {
|
|
89
|
+
continue
|
|
90
|
+
}
|
|
91
|
+
if tail < len(src) && isIdentifierPart(src[tail]) {
|
|
92
|
+
continue
|
|
93
|
+
}
|
|
94
|
+
return i
|
|
95
|
+
}
|
|
96
|
+
return -1
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
func tokenRange(file *shimast.SourceFile, node *shimast.Node) (int, int) {
|
|
100
|
+
if file == nil || node == nil {
|
|
101
|
+
return -1, -1
|
|
102
|
+
}
|
|
103
|
+
src := file.Text()
|
|
104
|
+
pos := shimscanner.SkipTrivia(src, node.Pos())
|
|
105
|
+
end := node.End()
|
|
106
|
+
if pos < 0 || pos > len(src) || end < pos || end > len(src) {
|
|
107
|
+
return -1, -1
|
|
108
|
+
}
|
|
109
|
+
return pos, end
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
func isIdentifierPart(ch byte) bool {
|
|
113
|
+
return (ch >= 'a' && ch <= 'z') ||
|
|
114
|
+
(ch >= 'A' && ch <= 'Z') ||
|
|
115
|
+
(ch >= '0' && ch <= '9') ||
|
|
116
|
+
ch == '_' ||
|
|
117
|
+
ch == '$'
|
|
118
|
+
}
|
|
119
|
+
|
|
29
120
|
// identifierText returns the lexical name of an Identifier node, or "" if
|
|
30
121
|
// the node isn't an Identifier.
|
|
31
122
|
func identifierText(node *shimast.Node) string {
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// The split between this file and `engine.go` is deliberate: the engine
|
|
10
10
|
// is pure (rules + AST traversal), and this file owns every side effect
|
|
11
11
|
// (process flags, stderr/stdout, emit, exit codes).
|
|
12
|
-
package
|
|
12
|
+
package linthost
|
|
13
13
|
|
|
14
14
|
import (
|
|
15
15
|
"context"
|