@heyramzi/lint 1.34.0 → 2.0.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.
@@ -0,0 +1,206 @@
1
+ /**
2
+ * Code with comments and strings blanked to spaces at the same length, so a mask offset is a file
3
+ * offset. `old-names.js` reads names from what's left.
4
+ */
5
+
6
+ import { commentSpansFor, regexEnd, regexStarts } from "#lint/comment-length.js";
7
+
8
+ const JS_FAMILY = new Set(["ts", "tsx", "mts", "cts", "js", "jsx", "mjs", "cjs"]);
9
+
10
+ function blanker(src) {
11
+ const out = src.split("");
12
+ const blank = (from, to) => {
13
+ for (let k = from; k < Math.min(to, out.length); k += 1) if (out[k] !== "\n") out[k] = " ";
14
+ };
15
+ return { out, blank, text: () => out.join("") };
16
+ }
17
+
18
+ /** Comments, quoted strings, template text and regex literals. Code inside `${}` stays. */
19
+ export function maskJs(src) {
20
+ const { blank, text } = blanker(src);
21
+ const resume = [];
22
+ let depth = 0;
23
+ let i = 0;
24
+
25
+ const template = (start) => {
26
+ let j = start;
27
+ while (j < src.length) {
28
+ if (src[j] === "\\") j += 2;
29
+ else if (src[j] === "`") {
30
+ blank(start, j);
31
+ return j + 1;
32
+ } else if (src[j] === "$" && src[j + 1] === "{") {
33
+ blank(start, j + 2);
34
+ resume.push(depth);
35
+ depth += 1;
36
+ return j + 2;
37
+ } else j += 1;
38
+ }
39
+ blank(start, src.length);
40
+ return src.length;
41
+ };
42
+
43
+ while (i < src.length) {
44
+ const c = src[i];
45
+ const two = src.slice(i, i + 2);
46
+ if (two === "//") {
47
+ const end = src.indexOf("\n", i);
48
+ const stop = end === -1 ? src.length : end;
49
+ blank(i, stop);
50
+ i = stop;
51
+ } else if (two === "/*") {
52
+ const close = src.indexOf("*/", i + 2);
53
+ const stop = close === -1 ? src.length : close + 2;
54
+ blank(i, stop);
55
+ i = stop;
56
+ } else if (c === "`") {
57
+ i = template(i + 1);
58
+ } else if (c === '"' || c === "'") {
59
+ let j = i + 1;
60
+ while (j < src.length && src[j] !== c && src[j] !== "\n") j += src[j] === "\\" ? 2 : 1;
61
+ blank(i + 1, j);
62
+ i = j + 1;
63
+ } else if (c === "/" && src[i - 1] !== "<" && regexStarts(src, i)) {
64
+ const stop = regexEnd(src, i);
65
+ blank(i, stop);
66
+ i = stop;
67
+ } else if (c === "{") {
68
+ depth += 1;
69
+ i += 1;
70
+ } else if (c === "}") {
71
+ depth -= 1;
72
+ i = resume.length > 0 && depth === resume.at(-1) ? (resume.pop(), template(i + 1)) : i + 1;
73
+ } else {
74
+ i += 1;
75
+ }
76
+ }
77
+ return text();
78
+ }
79
+
80
+ /** Swift, Python, shell, CSS and SQL, through the comment gate's scanner. SQL double quotes name columns, so they stay. */
81
+ export function maskSimple(src, extension) {
82
+ const { blank, text } = blanker(src);
83
+ const strings = [];
84
+ const comments = commentSpansFor(src, extension, strings);
85
+ for (const span of comments) blank(span.start, span.end);
86
+ for (const span of strings) {
87
+ if (extension === "sql" && src[span.start] === '"') continue;
88
+ blank(span.start, span.end);
89
+ }
90
+ return text();
91
+ }
92
+
93
+ /** JSON and JSONC: keys are names, every value and comment is data. */
94
+ export function maskJson(src) {
95
+ const { blank, text } = blanker(src);
96
+ const token = /("(?:[^"\\\n]|\\.)*")|\/\/[^\n]*|\/\*[\s\S]*?\*\//g;
97
+ for (const match of src.matchAll(token)) {
98
+ const end = match.index + match[0].length;
99
+ const isKey = match[1] && /^\s*:/.test(src.slice(end, end + 40));
100
+ if (!isKey) blank(match.index, end);
101
+ }
102
+ return text();
103
+ }
104
+
105
+ const YAML_KEY = /^(\s*(?:-\s+)*)("[^"\n]+"|'[^'\n]+'|[\w./@$-][\w./@$ -]*?)(\s*:)(?=\s|$)/;
106
+ const TOML_KEY = /^(\s*)("[^"\n]+"|'[^'\n]+'|[\w.-]+(?:\s*\.\s*[\w-]+)*)(\s*=)/;
107
+ const TOML_TABLE = /^(\s*\[+\s*)([^\]\n]+)(\]+)/;
108
+
109
+ /** YAML and TOML: a key (or a TOML table header) is a name, the rest of the line is data. */
110
+ export function maskKeyed(src, extension) {
111
+ const keyed = extension === "toml" ? [TOML_TABLE, TOML_KEY] : [YAML_KEY];
112
+ return src
113
+ .split("\n")
114
+ .map((line) => {
115
+ for (const pattern of keyed) {
116
+ const match = pattern.exec(line);
117
+ if (!match) continue;
118
+ const kept = match[1].length + match[2].length;
119
+ const head = " ".repeat(match[1].length) + line.slice(match[1].length, kept);
120
+ return head.padEnd(line.length, " ");
121
+ }
122
+ return " ".repeat(line.length);
123
+ })
124
+ .join("\n");
125
+ }
126
+
127
+ const TAG_NAME = /^<\/?[A-Za-z][\w:.-]*/;
128
+
129
+ /** The end of a `{...}` expression that starts at `i`, counting nested braces and skipping quoted braces. */
130
+ function braceEnd(src, i) {
131
+ let depth = 0;
132
+ for (let j = i; j < src.length; j += 1) {
133
+ const c = src[j];
134
+ if (c === '"' || c === "'" || c === "`") {
135
+ const close = src.indexOf(c, j + 1);
136
+ if (close !== -1) j = close;
137
+ } else if (c === "{") depth += 1;
138
+ else if (c === "}" && (depth -= 1) === 0) return j + 1;
139
+ }
140
+ return src.length;
141
+ }
142
+
143
+ /** The end of a tag opened at `i`: quoted attribute values are blanked, `{...}` expressions stay. */
144
+ function tagEnd(src, i, blank, braces) {
145
+ let j = i + 1;
146
+ while (j < src.length && src[j] !== ">") {
147
+ const c = src[j];
148
+ if (c === '"' || c === "'") {
149
+ const close = src.indexOf(c, j + 1);
150
+ const stop = close === -1 ? src.length : close;
151
+ blank(j + 1, stop);
152
+ j = stop + 1;
153
+ } else if (c === "{" && braces) {
154
+ j = braceEnd(src, j);
155
+ } else j += 1;
156
+ }
157
+ return j + 1;
158
+ }
159
+
160
+ /** The inside of a `<script>` or `<style>` element, masked as its own language. Returns where the element's code ends. */
161
+ function maskBlock(src, out, from, name) {
162
+ const close = src.toLowerCase().indexOf(`</${name}`, from);
163
+ const stop = close === -1 ? src.length : close;
164
+ const body = src.slice(from, stop);
165
+ const inner = name === "style" ? maskSimple(body, "css") : maskJs(body);
166
+ for (let k = 0; k < inner.length; k += 1) out[from + k] = inner[k];
167
+ return stop;
168
+ }
169
+
170
+ /**
171
+ * Svelte and HTML. Tag names, attribute names and `{...}` expressions stay, and text, comments and
172
+ * quoted attribute values go. `<script>` is read as JS and `<style>` as CSS.
173
+ */
174
+ export function maskMarkup(src, { braces }) {
175
+ const { out, blank, text } = blanker(src);
176
+ let i = 0;
177
+ while (i < src.length) {
178
+ if (src.startsWith("<!--", i)) {
179
+ const close = src.indexOf("-->", i + 4);
180
+ const stop = close === -1 ? src.length : close + 3;
181
+ blank(i, stop);
182
+ i = stop;
183
+ } else if (src[i] === "<" && TAG_NAME.test(src.slice(i, i + 40))) {
184
+ const name = /^<([A-Za-z]+)/.exec(src.slice(i, i + 12))?.[1]?.toLowerCase();
185
+ i = tagEnd(src, i, blank, braces);
186
+ if (name === "script" || name === "style") i = maskBlock(src, out, i, name);
187
+ } else if (src[i] === "{" && braces) {
188
+ i = braceEnd(src, i);
189
+ } else {
190
+ blank(i, i + 1);
191
+ i += 1;
192
+ }
193
+ }
194
+ return text();
195
+ }
196
+
197
+ /** The code of a file with comments and values blanked, or null when the language isn't one we read. */
198
+ export function maskFor(src, extension) {
199
+ if (JS_FAMILY.has(extension)) return maskJs(src);
200
+ if (extension === "svelte") return maskMarkup(src, { braces: true });
201
+ if (extension === "html") return maskMarkup(src, { braces: false });
202
+ if (extension === "json" || extension === "jsonc") return maskJson(src);
203
+ if (extension === "yaml" || extension === "yml" || extension === "toml")
204
+ return maskKeyed(src, extension);
205
+ return maskSimple(src, extension === "bash" || extension === "zsh" ? "sh" : extension);
206
+ }
package/old-names.js ADDED
@@ -0,0 +1,145 @@
1
+ /**
2
+ * The old-names gate (Ramzi, 22 Oct 2026). The words sit in `vendor/old-names-words.js`, which it
3
+ * skips. Git and process live in `bin/heyramzi-old-names.js`.
4
+ */
5
+
6
+ import { generatedContent, generatedPath } from "#lint/file-tokens.js";
7
+ import { maskFor } from "#lint/old-names-mask.js";
8
+ import { PART_WORDS, SUBSTRING_WORD } from "#lint/vendor/old-names-words.js";
9
+
10
+ export const OLD_NAME_EXTENSIONS = [
11
+ "ts",
12
+ "tsx",
13
+ "mts",
14
+ "cts",
15
+ "js",
16
+ "jsx",
17
+ "mjs",
18
+ "cjs",
19
+ "svelte",
20
+ "swift",
21
+ "py",
22
+ "sql",
23
+ "sh",
24
+ "bash",
25
+ "zsh",
26
+ "css",
27
+ "html",
28
+ "json",
29
+ "jsonc",
30
+ "yaml",
31
+ "yml",
32
+ "toml",
33
+ ];
34
+
35
+ /** Applied migrations are history the database already ran, and drizzle-kit writes its output folder whole. */
36
+ const MIGRATION_TREES = new Set(["migrations", "drizzle"]);
37
+
38
+ /** Which of a repo's tracked files the gate reads: its own code, not a tool's output or a migration that already ran. */
39
+ export function selectFiles(tracked) {
40
+ const wanted = new Set(OLD_NAME_EXTENSIONS);
41
+ return tracked.filter((file) => {
42
+ if (!wanted.has(file.slice(file.lastIndexOf(".") + 1))) return false;
43
+ if (generatedPath(file) || /\.min\.(js|css)$/.test(file)) return false;
44
+ return !file
45
+ .split("/")
46
+ .slice(0, -1)
47
+ .some((part) => MIGRATION_TREES.has(part));
48
+ });
49
+ }
50
+
51
+ /** A name's word parts: `toCompat`, `api-shim` and `DEPRECATED_FIELD` all split where a person would. */
52
+ function partsOf(token) {
53
+ return (token.match(/[A-Z]+(?![a-z])|[A-Z]?[a-z]+|\d+/g) ?? []).map((part) => part.toLowerCase());
54
+ }
55
+
56
+ function bannedWords(token) {
57
+ const found = [];
58
+ if (token.toLowerCase().includes(SUBSTRING_WORD)) found.push(SUBSTRING_WORD);
59
+ for (const part of partsOf(token)) {
60
+ const base = part.replace(/s$/, "");
61
+ if (PART_WORDS.includes(base) && !found.includes(base)) found.push(base);
62
+ }
63
+ return found;
64
+ }
65
+
66
+ /** The directory and file names on a path that carry a banned word. A folder shows once, at the folder. */
67
+ export function nameHits(file) {
68
+ const parts = file.split("/");
69
+ return parts.flatMap((part, index) =>
70
+ bannedWords(part).map((banned) => ({
71
+ file: parts.slice(0, index + 1).join("/"),
72
+ line: 0,
73
+ word: banned,
74
+ token: part,
75
+ folder: index < parts.length - 1,
76
+ })),
77
+ );
78
+ }
79
+
80
+ const TOKEN = /[\w$-]+/g;
81
+
82
+ /** Every banned word in a file's text, with its line. The substring word anywhere, the part words in code. */
83
+ export function sourceHits(source, extension) {
84
+ const hits = [];
85
+ const seen = new Set();
86
+ const lines = source.split("\n");
87
+ const add = (line, banned, token) => {
88
+ const key = `${line}:${banned}:${token}`;
89
+ if (seen.has(key)) return;
90
+ seen.add(key);
91
+ hits.push({ line, word: banned, token, text: lines[line - 1].trim().slice(0, 100) });
92
+ };
93
+ if (source.toLowerCase().includes(SUBSTRING_WORD)) {
94
+ lines.forEach((text, index) => {
95
+ for (const token of text.match(TOKEN) ?? []) {
96
+ if (bannedWords(token).includes(SUBSTRING_WORD)) add(index + 1, SUBSTRING_WORD, token);
97
+ }
98
+ });
99
+ }
100
+ const masked = maskFor(source, extension);
101
+ masked.split("\n").forEach((text, index) => {
102
+ for (const token of text.match(TOKEN) ?? []) {
103
+ for (const banned of bannedWords(token)) {
104
+ if (banned !== SUBSTRING_WORD) add(index + 1, banned, token);
105
+ }
106
+ }
107
+ });
108
+ return hits.toSorted((a, b) => a.line - b.line);
109
+ }
110
+
111
+ /** Every hit in one file: its path first, then its text. A file a tool wrote, by its header, has none. */
112
+ export function scanFile(file, source) {
113
+ if (generatedContent(Buffer.from(source.slice(0, 2048)))) return [];
114
+ const extension = file.slice(file.lastIndexOf(".") + 1);
115
+ const inText = sourceHits(source, extension);
116
+ for (const hit of inText) hit.file = file;
117
+ return [...nameHits(file), ...inText];
118
+ }
119
+
120
+ /** Hits over many files, `sources` mapping path to text. A folder is named once, however many files sit in it. */
121
+ export function check(sources) {
122
+ const hits = [];
123
+ const named = new Set();
124
+ for (const [file, source] of Object.entries(sources)) {
125
+ for (const hit of scanFile(file, source)) {
126
+ const key = `${hit.file}:${hit.word}:${hit.line}:${hit.token}`;
127
+ if (hit.line === 0 && named.has(key)) continue;
128
+ named.add(key);
129
+ hits.push(hit);
130
+ }
131
+ }
132
+ return hits;
133
+ }
134
+
135
+ const ADVICE =
136
+ "Delete the old path and move every caller to the new one, or rename the thing to what it is now. A refactor leaves no alias export, no old field kept for a migration and no shim. There's no allowlist.";
137
+
138
+ /** The refusal. Each hit names the token, and the footer says what to do instead. */
139
+ export function report(hits) {
140
+ const lines = hits.map(({ file, line, word: banned, token, text, folder }) => {
141
+ if (line > 0) return `${file}:${line}: "${banned}" in ${token}: ${text}`;
142
+ return `${file}${folder ? "/" : ""}: "${banned}" in the ${folder ? "folder" : "file"} name ${token}`;
143
+ });
144
+ return [`old-names: ${hits.length} hit(s)`, ...lines, "", ADVICE].join("\n");
145
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heyramzi/lint",
3
- "version": "1.34.0",
3
+ "version": "2.0.0",
4
4
  "description": "Shared oxlint rules, base config and gates for Studio projects",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -9,11 +9,12 @@
9
9
  "directory": "packages/lint"
10
10
  },
11
11
  "bin": {
12
- "heyramzi-commit-msg": "./bin/heyramzi-commit-msg.js",
13
12
  "heyramzi-comment-length": "./bin/heyramzi-comment-length.js",
13
+ "heyramzi-commit-msg": "./bin/heyramzi-commit-msg.js",
14
14
  "heyramzi-file-tokens": "./bin/heyramzi-file-tokens.js",
15
15
  "heyramzi-inline-path": "./bin/heyramzi-inline-path.js",
16
16
  "heyramzi-jev-code": "./bin/heyramzi-jev-code.js",
17
+ "heyramzi-old-names": "./bin/heyramzi-old-names.js",
17
18
  "heyramzi-push-diff": "./bin/heyramzi-push-diff.js",
18
19
  "heyramzi-repo-rules": "./bin/heyramzi-repo-rules.js",
19
20
  "heyramzi-slop": "./bin/heyramzi-slop.js",
@@ -32,6 +33,8 @@
32
33
  "index.js",
33
34
  "jev.js",
34
35
  "jev-code.js",
36
+ "old-names.js",
37
+ "old-names-mask.js",
35
38
  "package.json",
36
39
  "processors",
37
40
  "push-diff.js",
@@ -39,6 +42,8 @@
39
42
  "slop.js",
40
43
  "slop-views.js",
41
44
  "ui-rules.js",
45
+ "ui-rules-css.js",
46
+ "ui-rules-markup.js",
42
47
  "svelte-markup.js",
43
48
  "svelte-template.js",
44
49
  "register.js",
@@ -46,6 +51,7 @@
46
51
  "repo-rules.js",
47
52
  "repo-rules",
48
53
  "scripts",
54
+ "vendor",
49
55
  "rules"
50
56
  ],
51
57
  "type": "module",
package/push-diff.js CHANGED
@@ -4,7 +4,6 @@
4
4
  */
5
5
  import { commentSpans } from "#lint/comment-length.js";
6
6
 
7
-
8
7
  /** The registry the add-ons persist under: `enum StorageKey {…}` or `const StorageKey = {…}`. */
9
8
  const REGISTRY = /(?:\benum\s+StorageKey\s*\{|\bStorageKey\s*(?::[^=\n]+)?=\s*\{)/;
10
9
 
@@ -27,7 +26,8 @@ export function storageKeysOf(source) {
27
26
  end += 1;
28
27
  }
29
28
  const body = clean.slice(open.index + open[0].length, end);
30
- const entry = /(?:^|[\s,{])(["']?)([A-Za-z_$][\w$]*)\1\s*[:=]\s*(["'`])((?:\\.|(?!\3)[^\\\n])*)\3/g;
29
+ const entry =
30
+ /(?:^|[\s,{])(["']?)([A-Za-z_$][\w$]*)\1\s*[:=]\s*(["'`])((?:\\.|(?!\3)[^\\\n])*)\3/g;
31
31
  // A template that only splices string literals, `a_${"b"}`, is the same string at runtime.
32
32
  const literal = (value) => value.replace(/\$\{\s*(["'])((?:(?!\1).)*)\1\s*\}/g, "$2");
33
33
  for (const match of body.matchAll(entry)) keys.set(match[2], literal(match[4]));
@@ -141,22 +141,22 @@ export function npmrcCredentials(tree) {
141
141
  return found;
142
142
  }
143
143
 
144
- const LEGACY_TOKEN = ["GITHUB", "PRIVATE", "PACKAGES", "TOKEN"].join("_");
144
+ const DEAD_TOKEN = ["GITHUB", "PRIVATE", "PACKAGES", "TOKEN"].join("_");
145
145
  const INSTALL_FILES =
146
146
  /(^|\/)(\.npmrc|\.env[^/]*|Dockerfile[^/]*|(docker-)?compose[^/]*\.ya?ml|wrangler\.jsonc?|[^/]+\.sh|\.github\/workflows\/[^/]+\.ya?ml)$/;
147
147
 
148
- export function legacyTokenName(tree) {
148
+ export function deadTokenName(tree) {
149
149
  const found = [];
150
150
  for (const file of tree.touchedMatching(INSTALL_FILES)) {
151
151
  tree
152
152
  .text(file)
153
153
  .split("\n")
154
154
  .forEach((line, index) => {
155
- if (!line.includes(LEGACY_TOKEN)) return;
155
+ if (!line.includes(DEAD_TOKEN)) return;
156
156
  found.push({
157
157
  file,
158
- rule: "legacy-token-name",
159
- message: `Line ${index + 1} names ${LEGACY_TOKEN}, a dead variable that 403s against the package registry. The package-install token is GH_PRIVATE_PACKAGES_TOKEN everywhere: .npmrc, workflow env, the shell. Leave secrets.GITHUB_TOKEN alone, it's the Actions built-in that release-please, GoReleaser and gh need.`,
158
+ rule: "dead-token-name",
159
+ message: `Line ${index + 1} names ${DEAD_TOKEN}, a dead variable that 403s against the package registry. The package-install token is GH_PRIVATE_PACKAGES_TOKEN everywhere: .npmrc, workflow env, the shell. Leave secrets.GITHUB_TOKEN alone, it's the Actions built-in that release-please, GoReleaser and gh need.`,
160
160
  });
161
161
  });
162
162
  }
package/repo-rules.js CHANGED
@@ -7,7 +7,7 @@ import { composeImages, fossilNames } from "#lint/repo-rules/paths.js";
7
7
  import {
8
8
  heyramziLinks,
9
9
  heyramziTarballs,
10
- legacyTokenName,
10
+ deadTokenName,
11
11
  npmrcCredentials,
12
12
  pnpmOnly,
13
13
  srcImportMaps,
@@ -28,7 +28,7 @@ export const RULES = [
28
28
  heyramziTarballs,
29
29
  srcImportMaps,
30
30
  npmrcCredentials,
31
- legacyTokenName,
31
+ deadTokenName,
32
32
  workflows,
33
33
  foreignTools,
34
34
  fallowShape,
@@ -6,7 +6,9 @@ import { propertyName } from "#lint/rules/convex-ast.js";
6
6
  export default {
7
7
  meta: {
8
8
  type: "problem",
9
- docs: { description: "Require index names to start with `by_` and list every field with `_and_`." },
9
+ docs: {
10
+ description: "Require index names to start with `by_` and list every field with `_and_`.",
11
+ },
10
12
  messages: {
11
13
  badName:
12
14
  'Index "{{ name }}" covers {{ count }} field(s) but its name lists {{ listed }}. Name it `by_` plus every field joined with `_and_`, like `by_channel_and_author`, and update its `withIndex` calls.',
@@ -29,7 +29,8 @@ export default {
29
29
  create(context) {
30
30
  const jobs = new Set(["crons"]);
31
31
  let httpDepth = 0;
32
- const report = (node, where) => context.report({ node, messageId: "publicRef", data: { where } });
32
+ const report = (node, where) =>
33
+ context.report({ node, messageId: "publicRef", data: { where } });
33
34
  return {
34
35
  VariableDeclarator(node) {
35
36
  const init = node.init;
@@ -1,19 +1,20 @@
1
1
  /**
2
- * `crons.hourly` and `crons.daily` are the deprecated helpers.
2
+ * `crons.hourly` and `crons.daily` are the helpers Convex replaced.
3
3
  */
4
4
  import { propertyName } from "#lint/rules/convex-ast.js";
5
5
 
6
- const DEPRECATED = new Set(["hourly", "daily"]);
6
+ const REPLACED_HELPERS = new Set(["hourly", "daily"]);
7
7
 
8
8
  export default {
9
9
  meta: {
10
10
  type: "problem",
11
11
  docs: {
12
- description: "Disallow the deprecated cron helpers. Use `crons.interval` or `crons.cron`.",
12
+ description:
13
+ "Disallow `crons.hourly` and `crons.daily`. Use `crons.interval` or `crons.cron`.",
13
14
  },
14
15
  messages: {
15
- deprecated:
16
- "`crons.{{ method }}` is deprecated. Use `crons.cron(name, '30 3 * * *', internal.x.y, {})` or `crons.interval(name, { hours: 6 }, internal.x.y, {})`. Both run in UTC.",
16
+ replacedHelper:
17
+ "`crons.{{ method }}` is a replaced helper. Use `crons.cron(name, '30 3 * * *', internal.x.y, {})` or `crons.interval(name, { hours: 6 }, internal.x.y, {})`. Both run in UTC.",
17
18
  },
18
19
  schema: [],
19
20
  },
@@ -29,10 +30,10 @@ export default {
29
30
  },
30
31
  CallExpression(node) {
31
32
  const method = propertyName(node.callee);
32
- if (!method || !DEPRECATED.has(method)) return;
33
+ if (!method || !REPLACED_HELPERS.has(method)) return;
33
34
  const owner = node.callee.object;
34
35
  if (owner.type === "Identifier" && jobs.has(owner.name)) {
35
- context.report({ node, messageId: "deprecated", data: { method } });
36
+ context.report({ node, messageId: "replacedHelper", data: { method } });
36
37
  }
37
38
  },
38
39
  };
@@ -41,7 +41,8 @@ export default {
41
41
  CallExpression(node) {
42
42
  if (!useNode) return;
43
43
  const name = registerName(node);
44
- if (name && NODE_ONLY.has(name)) context.report({ node, messageId: "actionsOnly", data: { name } });
44
+ if (name && NODE_ONLY.has(name))
45
+ context.report({ node, messageId: "actionsOnly", data: { name } });
45
46
  },
46
47
  };
47
48
  },
@@ -1,5 +1,5 @@
1
1
  /**
2
- * A re-export renamed to a leading `_` keeps a dead name alive. Compat words in comments are
2
+ * A re-export renamed to a leading `_` keeps a dead name alive. Old-name words in comments are
3
3
  * the comment gate's job: `comment-length.js`.
4
4
  */
5
5
  export default {