@ttsc/lint 0.10.1 → 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.
Files changed (113) hide show
  1. package/README.md +172 -33
  2. package/lib/defineConfig.d.ts +55 -0
  3. package/lib/defineConfig.js +39 -0
  4. package/lib/defineConfig.js.map +1 -0
  5. package/lib/index.d.ts +25 -1
  6. package/lib/index.js +622 -2
  7. package/lib/index.js.map +1 -1
  8. package/lib/structures/ITtscLintPlugin.d.ts +53 -0
  9. package/lib/structures/ITtscLintPlugin.js +3 -0
  10. package/lib/structures/ITtscLintPlugin.js.map +1 -0
  11. package/lib/structures/ITtscLintPluginConfig.d.ts +82 -5
  12. package/lib/structures/ITtscLintPluginMeta.d.ts +12 -0
  13. package/lib/structures/ITtscLintPluginMeta.js +3 -0
  14. package/lib/structures/ITtscLintPluginMeta.js.map +1 -0
  15. package/lib/structures/PluginRuleNames.d.ts +14 -0
  16. package/lib/structures/PluginRuleNames.js +3 -0
  17. package/lib/structures/PluginRuleNames.js.map +1 -0
  18. package/lib/structures/TtscLintConfig.d.ts +24 -8
  19. package/lib/structures/TtscLintConfigEntry.d.ts +39 -0
  20. package/lib/structures/TtscLintConfigEntry.js +3 -0
  21. package/lib/structures/TtscLintConfigEntry.js.map +1 -0
  22. package/lib/structures/TtscLintFormatConfig.d.ts +154 -0
  23. package/lib/structures/TtscLintFormatConfig.js +3 -0
  24. package/lib/structures/TtscLintFormatConfig.js.map +1 -0
  25. package/lib/structures/TtscLintPlugins.d.ts +9 -0
  26. package/lib/structures/TtscLintPlugins.js +3 -0
  27. package/lib/structures/TtscLintPlugins.js.map +1 -0
  28. package/lib/structures/TtscLintRule.d.ts +1 -1
  29. package/lib/structures/TtscLintRuleEntry.d.ts +22 -0
  30. package/lib/structures/TtscLintRuleEntry.js +3 -0
  31. package/lib/structures/TtscLintRuleEntry.js.map +1 -0
  32. package/lib/structures/TtscLintRuleMap.d.ts +44 -0
  33. package/lib/structures/TtscLintRuleMap.js +3 -0
  34. package/lib/structures/TtscLintRuleMap.js.map +1 -0
  35. package/lib/structures/TtscLintRuleOptions.d.ts +149 -0
  36. package/lib/structures/TtscLintRuleOptions.js +3 -0
  37. package/lib/structures/TtscLintRuleOptions.js.map +1 -0
  38. package/lib/structures/defaultFormat.d.ts +31 -0
  39. package/lib/structures/defaultFormat.js +35 -0
  40. package/lib/structures/defaultFormat.js.map +1 -0
  41. package/lib/structures/index.d.ts +10 -0
  42. package/lib/structures/index.js +10 -0
  43. package/lib/structures/index.js.map +1 -1
  44. package/{plugin → linthost}/ast_helpers.go +92 -1
  45. package/{plugin → linthost}/compile.go +1 -1
  46. package/{plugin → linthost}/config.go +583 -66
  47. package/linthost/config_format.go +360 -0
  48. package/linthost/contrib_adapter.go +134 -0
  49. package/{plugin → linthost}/directives.go +1 -1
  50. package/linthost/dispatch.go +62 -0
  51. package/{plugin → linthost}/engine.go +156 -11
  52. package/{plugin → linthost}/eslint_runtime.go +76 -2
  53. package/linthost/fix.go +249 -0
  54. package/linthost/format.go +107 -0
  55. package/{plugin → linthost}/host.go +1 -1
  56. package/linthost/print_dispatch.go +118 -0
  57. package/linthost/print_doc.go +168 -0
  58. package/linthost/print_engine.go +343 -0
  59. package/linthost/print_nodes_array.go +46 -0
  60. package/linthost/print_nodes_call.go +180 -0
  61. package/linthost/print_nodes_imports.go +171 -0
  62. package/linthost/print_nodes_list.go +64 -0
  63. package/linthost/print_nodes_object.go +51 -0
  64. package/{plugin → linthost}/rules_arrays.go +1 -1
  65. package/{plugin → linthost}/rules_console.go +1 -1
  66. package/{plugin → linthost}/rules_debugger.go +1 -1
  67. package/{plugin → linthost}/rules_dupes.go +1 -1
  68. package/{plugin → linthost}/rules_empty.go +1 -1
  69. package/linthost/rules_escape.go +238 -0
  70. package/{plugin → linthost}/rules_eval.go +1 -1
  71. package/{plugin → linthost}/rules_finally.go +1 -1
  72. package/linthost/rules_format_jsdoc.go +230 -0
  73. package/linthost/rules_format_print_width.go +332 -0
  74. package/linthost/rules_format_quotes.go +219 -0
  75. package/linthost/rules_format_semi.go +190 -0
  76. package/linthost/rules_format_sort_imports.go +462 -0
  77. package/linthost/rules_format_trailing_comma.go +460 -0
  78. package/{plugin → linthost}/rules_gap.go +101 -6
  79. package/linthost/rules_imports.go +101 -0
  80. package/{plugin → linthost}/rules_logic.go +55 -3
  81. package/{plugin → linthost}/rules_loops.go +1 -1
  82. package/{plugin → linthost}/rules_misc.go +1 -1
  83. package/linthost/rules_params.go +64 -0
  84. package/{plugin → linthost}/rules_problems.go +10 -2
  85. package/linthost/rules_promise.go +111 -0
  86. package/{plugin → linthost}/rules_protos.go +1 -1
  87. package/{plugin → linthost}/rules_self.go +1 -1
  88. package/{plugin → linthost}/rules_strings.go +1 -1
  89. package/{plugin → linthost}/rules_suggestions.go +51 -9
  90. package/{plugin → linthost}/rules_throw.go +1 -1
  91. package/{plugin → linthost}/rules_ts.go +12 -2
  92. package/{plugin → linthost}/rules_ts_extra.go +90 -4
  93. package/{plugin → linthost}/rules_var.go +36 -5
  94. package/package.json +8 -6
  95. package/plugin/main.go +14 -27
  96. package/rule/astutil/astutil.go +148 -0
  97. package/rule/rule.go +291 -0
  98. package/src/defineConfig.ts +69 -0
  99. package/src/index.ts +807 -3
  100. package/src/structures/ITtscLintPlugin.ts +56 -0
  101. package/src/structures/ITtscLintPluginConfig.ts +86 -5
  102. package/src/structures/ITtscLintPluginMeta.ts +14 -0
  103. package/src/structures/PluginRuleNames.ts +19 -0
  104. package/src/structures/TtscLintConfig.ts +27 -8
  105. package/src/structures/TtscLintConfigEntry.ts +50 -0
  106. package/src/structures/TtscLintFormatConfig.ts +169 -0
  107. package/src/structures/TtscLintPlugins.ts +10 -0
  108. package/src/structures/TtscLintRule.ts +14 -1
  109. package/src/structures/TtscLintRuleEntry.ts +28 -0
  110. package/src/structures/TtscLintRuleMap.ts +52 -0
  111. package/src/structures/TtscLintRuleOptions.ts +162 -0
  112. package/src/structures/defaultFormat.ts +33 -0
  113. 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,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=TtscLintRuleOptions.js.map
@@ -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";
@@ -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 main
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 main
12
+ package linthost
13
13
 
14
14
  import (
15
15
  "context"