eslint-plugin-harlanzw 0.5.2 → 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.mjs +97 -64
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import process from 'node:process';
|
|
|
4
4
|
import { TextSourceCodeBase, ConfigCommentParser, Directive, VisitNodeStep } from '@eslint/plugin-kit';
|
|
5
5
|
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
6
6
|
|
|
7
|
-
const version = "0.5.
|
|
7
|
+
const version = "0.5.4";
|
|
8
8
|
|
|
9
9
|
const STRENGTH_PATTERNS = {
|
|
10
10
|
strong: ["never", "must", "always", "under no circumstances", "absolutely", "required", "mandatory", "forbidden", "prohibited"],
|
|
@@ -641,6 +641,10 @@ function parseFrontmatter(lines) {
|
|
|
641
641
|
return result;
|
|
642
642
|
}
|
|
643
643
|
|
|
644
|
+
const COMPILED$8 = AMBIGUOUS_QUANTIFIERS.map((quantifier) => {
|
|
645
|
+
const escaped = quantifier.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
646
|
+
return new RegExp(`\\b${escaped}\\b`, "gi");
|
|
647
|
+
});
|
|
644
648
|
const promptAmbiguousQuantifier = {
|
|
645
649
|
meta: {
|
|
646
650
|
type: "suggestion",
|
|
@@ -662,8 +666,9 @@ const promptAmbiguousQuantifier = {
|
|
|
662
666
|
if (shouldSkipLine(i, codeBlockLines, frontmatterEnd))
|
|
663
667
|
continue;
|
|
664
668
|
const line = lines[i];
|
|
665
|
-
for (
|
|
666
|
-
const regex =
|
|
669
|
+
for (let qi = 0; qi < COMPILED$8.length; qi++) {
|
|
670
|
+
const regex = COMPILED$8[qi];
|
|
671
|
+
regex.lastIndex = 0;
|
|
667
672
|
let match;
|
|
668
673
|
while ((match = regex.exec(line)) !== null) {
|
|
669
674
|
const suggestion = QUANTIFIER_SUGGESTIONS[match[0].toLowerCase()] ?? "a specific value";
|
|
@@ -689,6 +694,9 @@ const promptAmbiguousQuantifier = {
|
|
|
689
694
|
}
|
|
690
695
|
};
|
|
691
696
|
|
|
697
|
+
const COMPILED$7 = UNNECESSARY_ADVERBS.map((adverb) => {
|
|
698
|
+
return { regex: new RegExp(`\\b${adverb}\\s+`, "gi"), adverb };
|
|
699
|
+
});
|
|
692
700
|
const aiDeslopAdverbs = {
|
|
693
701
|
meta: {
|
|
694
702
|
type: "suggestion",
|
|
@@ -711,8 +719,8 @@ const aiDeslopAdverbs = {
|
|
|
711
719
|
continue;
|
|
712
720
|
const line = lines[i];
|
|
713
721
|
const lineNode = node.children[i];
|
|
714
|
-
for (const adverb of
|
|
715
|
-
|
|
722
|
+
for (const { regex, adverb } of COMPILED$7) {
|
|
723
|
+
regex.lastIndex = 0;
|
|
716
724
|
let match;
|
|
717
725
|
while ((match = regex.exec(line)) !== null) {
|
|
718
726
|
const startOffset = lineNode.position.start.offset + match.index;
|
|
@@ -838,7 +846,7 @@ const DEDUPED_ENTRIES = SORTED_ENTRIES$1.filter(([name, url]) => {
|
|
|
838
846
|
SEEN_URLS.set(url, name);
|
|
839
847
|
return true;
|
|
840
848
|
});
|
|
841
|
-
const COMPILED$
|
|
849
|
+
const COMPILED$6 = DEDUPED_ENTRIES.map(([name, url]) => {
|
|
842
850
|
const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
843
851
|
return { name, url, regex: new RegExp(`(?<!\\[)\\b${escaped}\\b(?!\\])(?!\\()`, "g") };
|
|
844
852
|
});
|
|
@@ -867,7 +875,7 @@ const aiDeslopAutolink = {
|
|
|
867
875
|
if (line.trimStart().startsWith("#"))
|
|
868
876
|
continue;
|
|
869
877
|
const lineNode = node.children[i];
|
|
870
|
-
for (const { name, url, regex } of COMPILED$
|
|
878
|
+
for (const { name, url, regex } of COMPILED$6) {
|
|
871
879
|
if (linkedUrls.has(url))
|
|
872
880
|
continue;
|
|
873
881
|
regex.lastIndex = 0;
|
|
@@ -909,6 +917,10 @@ const aiDeslopAutolink = {
|
|
|
909
917
|
};
|
|
910
918
|
|
|
911
919
|
const SORTED_PHRASES = Object.entries(BUZZWORD_PHRASES).sort((a, b) => b[0].length - a[0].length);
|
|
920
|
+
const COMPILED$5 = SORTED_PHRASES.map(([phrase, replacement]) => {
|
|
921
|
+
const escaped = phrase.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
922
|
+
return { regex: new RegExp(`\\b${escaped}\\b`, "gi"), phrase, replacement };
|
|
923
|
+
});
|
|
912
924
|
const aiDeslopBuzzwords = {
|
|
913
925
|
meta: {
|
|
914
926
|
type: "suggestion",
|
|
@@ -932,9 +944,8 @@ const aiDeslopBuzzwords = {
|
|
|
932
944
|
const line = lines[i];
|
|
933
945
|
const lineNode = node.children[i];
|
|
934
946
|
const matched = [];
|
|
935
|
-
for (const
|
|
936
|
-
|
|
937
|
-
const regex = new RegExp(`\\b${escaped}\\b`, "gi");
|
|
947
|
+
for (const { regex, replacement } of COMPILED$5) {
|
|
948
|
+
regex.lastIndex = 0;
|
|
938
949
|
let match;
|
|
939
950
|
while ((match = regex.exec(line)) !== null) {
|
|
940
951
|
const matchStart = match.index;
|
|
@@ -1294,7 +1305,7 @@ const CASING_DICTIONARY = {
|
|
|
1294
1305
|
};
|
|
1295
1306
|
|
|
1296
1307
|
const SORTED_ENTRIES = Object.entries(CASING_DICTIONARY).sort((a, b) => b[0].length - a[0].length);
|
|
1297
|
-
const COMPILED = SORTED_ENTRIES.map(([key, correct]) => {
|
|
1308
|
+
const COMPILED$4 = SORTED_ENTRIES.map(([key, correct]) => {
|
|
1298
1309
|
const escaped = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1299
1310
|
return { regex: new RegExp(`\\b${escaped}\\b`, "gi"), correct };
|
|
1300
1311
|
});
|
|
@@ -1321,7 +1332,7 @@ const aiDeslopCasing = {
|
|
|
1321
1332
|
const line = lines[i];
|
|
1322
1333
|
const lineNode = node.children[i];
|
|
1323
1334
|
const matched = [];
|
|
1324
|
-
for (const { regex, correct } of COMPILED) {
|
|
1335
|
+
for (const { regex, correct } of COMPILED$4) {
|
|
1325
1336
|
regex.lastIndex = 0;
|
|
1326
1337
|
let match;
|
|
1327
1338
|
while ((match = regex.exec(line)) !== null) {
|
|
@@ -1353,6 +1364,10 @@ const aiDeslopCasing = {
|
|
|
1353
1364
|
}
|
|
1354
1365
|
};
|
|
1355
1366
|
|
|
1367
|
+
const COMPILED$3 = FILLER_PHRASES.map((phrase) => {
|
|
1368
|
+
const escaped = phrase.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1369
|
+
return { regex: new RegExp(`\\b${escaped}\\s*,?\\s*`, "gi"), phrase };
|
|
1370
|
+
});
|
|
1356
1371
|
const aiDeslopFiller = {
|
|
1357
1372
|
meta: {
|
|
1358
1373
|
type: "suggestion",
|
|
@@ -1375,8 +1390,8 @@ const aiDeslopFiller = {
|
|
|
1375
1390
|
continue;
|
|
1376
1391
|
const line = lines[i];
|
|
1377
1392
|
const lineNode = node.children[i];
|
|
1378
|
-
for (const phrase of
|
|
1379
|
-
|
|
1393
|
+
for (const { regex, phrase } of COMPILED$3) {
|
|
1394
|
+
regex.lastIndex = 0;
|
|
1380
1395
|
let match;
|
|
1381
1396
|
while ((match = regex.exec(line)) !== null) {
|
|
1382
1397
|
const startOffset = lineNode.position.start.offset + match.index;
|
|
@@ -1412,6 +1427,10 @@ const aiDeslopFiller = {
|
|
|
1412
1427
|
}
|
|
1413
1428
|
};
|
|
1414
1429
|
|
|
1430
|
+
const COMPILED$2 = HEDGING_WORDS.map((word) => {
|
|
1431
|
+
const escaped = word.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1432
|
+
return { regex: new RegExp(`\\b${escaped}\\s+`, "gi"), word };
|
|
1433
|
+
});
|
|
1415
1434
|
const aiDeslopHedging = {
|
|
1416
1435
|
meta: {
|
|
1417
1436
|
type: "suggestion",
|
|
@@ -1434,9 +1453,8 @@ const aiDeslopHedging = {
|
|
|
1434
1453
|
continue;
|
|
1435
1454
|
const line = lines[i];
|
|
1436
1455
|
const lineNode = node.children[i];
|
|
1437
|
-
for (const word of
|
|
1438
|
-
|
|
1439
|
-
const regex = new RegExp(`\\b${escaped}\\s+`, "gi");
|
|
1456
|
+
for (const { regex, word } of COMPILED$2) {
|
|
1457
|
+
regex.lastIndex = 0;
|
|
1440
1458
|
let match;
|
|
1441
1459
|
while ((match = regex.exec(line)) !== null) {
|
|
1442
1460
|
const startOffset = lineNode.position.start.offset + match.index;
|
|
@@ -1902,6 +1920,10 @@ const poorlyTokenized = [
|
|
|
1902
1920
|
/\w{20,}/g,
|
|
1903
1921
|
/\d{10,}/g
|
|
1904
1922
|
];
|
|
1923
|
+
const COMPILED_PHRASES = Object.entries(INEFFICIENT_PHRASES).map(([phrase, replacement]) => {
|
|
1924
|
+
const escaped = phrase.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1925
|
+
return { regex: new RegExp(`\\b${escaped}\\b`, "gi"), replacement };
|
|
1926
|
+
});
|
|
1905
1927
|
const promptInefficientToken = {
|
|
1906
1928
|
meta: {
|
|
1907
1929
|
type: "suggestion",
|
|
@@ -1927,9 +1949,9 @@ const promptInefficientToken = {
|
|
|
1927
1949
|
const lineNode = node.children[i];
|
|
1928
1950
|
const reported = /* @__PURE__ */ new Set();
|
|
1929
1951
|
for (const pattern of poorlyTokenized) {
|
|
1930
|
-
|
|
1952
|
+
pattern.lastIndex = 0;
|
|
1931
1953
|
let match;
|
|
1932
|
-
while ((match =
|
|
1954
|
+
while ((match = pattern.exec(line)) !== null) {
|
|
1933
1955
|
const key = `${match.index}:${match[0].length}`;
|
|
1934
1956
|
if (reported.has(key))
|
|
1935
1957
|
continue;
|
|
@@ -1945,8 +1967,8 @@ const promptInefficientToken = {
|
|
|
1945
1967
|
});
|
|
1946
1968
|
}
|
|
1947
1969
|
}
|
|
1948
|
-
for (const
|
|
1949
|
-
|
|
1970
|
+
for (const { regex, replacement } of COMPILED_PHRASES) {
|
|
1971
|
+
regex.lastIndex = 0;
|
|
1950
1972
|
let match;
|
|
1951
1973
|
while ((match = regex.exec(line)) !== null) {
|
|
1952
1974
|
const startOffset = lineNode.position.start.offset + match.index;
|
|
@@ -2194,9 +2216,9 @@ const promptRedundantInstruction = {
|
|
|
2194
2216
|
for (let i = 0; i < lines.length; i++) {
|
|
2195
2217
|
if (shouldSkipLine(i, codeBlockLines, frontmatterEnd))
|
|
2196
2218
|
continue;
|
|
2197
|
-
|
|
2219
|
+
instructionRegex.lastIndex = 0;
|
|
2198
2220
|
let match;
|
|
2199
|
-
while ((match =
|
|
2221
|
+
while ((match = instructionRegex.exec(lines[i])) !== null) {
|
|
2200
2222
|
const normalized = match[1].toLowerCase().trim().replace(/\s+/g, " ");
|
|
2201
2223
|
if (normalized.length > 10) {
|
|
2202
2224
|
const existing = instructionPatterns.get(normalized) ?? [];
|
|
@@ -2568,9 +2590,9 @@ const promptUndefinedVariable = {
|
|
|
2568
2590
|
continue;
|
|
2569
2591
|
const line = lines[i];
|
|
2570
2592
|
for (const defPattern of definitionPatterns) {
|
|
2571
|
-
|
|
2593
|
+
defPattern.lastIndex = 0;
|
|
2572
2594
|
let match2;
|
|
2573
|
-
while ((match2 =
|
|
2595
|
+
while ((match2 = defPattern.exec(line)) !== null)
|
|
2574
2596
|
definedVars.add(match2[1].toLowerCase());
|
|
2575
2597
|
}
|
|
2576
2598
|
const varRegex = /\{\{(\w+)\}\}/g;
|
|
@@ -2629,9 +2651,9 @@ const promptUnresolvedReference = {
|
|
|
2629
2651
|
continue;
|
|
2630
2652
|
const line = lines[i];
|
|
2631
2653
|
for (const pattern of unresolvedPatterns) {
|
|
2632
|
-
|
|
2654
|
+
pattern.lastIndex = 0;
|
|
2633
2655
|
let match;
|
|
2634
|
-
while ((match =
|
|
2656
|
+
while ((match = pattern.exec(line)) !== null) {
|
|
2635
2657
|
context.report({
|
|
2636
2658
|
loc: {
|
|
2637
2659
|
start: { line: i + 1, column: match.index + 1 },
|
|
@@ -2648,6 +2670,9 @@ const promptUnresolvedReference = {
|
|
|
2648
2670
|
}
|
|
2649
2671
|
};
|
|
2650
2672
|
|
|
2673
|
+
const COMPILED$1 = VAGUE_TERMS.map((term) => {
|
|
2674
|
+
return new RegExp(`\\bbe ${term}\\b|\\bin a ${term}\\b`, "gi");
|
|
2675
|
+
});
|
|
2651
2676
|
const promptVagueTerm = {
|
|
2652
2677
|
meta: {
|
|
2653
2678
|
type: "suggestion",
|
|
@@ -2668,8 +2693,9 @@ const promptVagueTerm = {
|
|
|
2668
2693
|
if (shouldSkipLine(i, codeBlockLines, frontmatterEnd))
|
|
2669
2694
|
continue;
|
|
2670
2695
|
const line = lines[i];
|
|
2671
|
-
for (
|
|
2672
|
-
const regex =
|
|
2696
|
+
for (let vi = 0; vi < COMPILED$1.length; vi++) {
|
|
2697
|
+
const regex = COMPILED$1[vi];
|
|
2698
|
+
regex.lastIndex = 0;
|
|
2673
2699
|
let match;
|
|
2674
2700
|
while ((match = regex.exec(line)) !== null) {
|
|
2675
2701
|
context.report({
|
|
@@ -2688,6 +2714,10 @@ const promptVagueTerm = {
|
|
|
2688
2714
|
}
|
|
2689
2715
|
};
|
|
2690
2716
|
|
|
2717
|
+
const COMPILED = STRENGTH_PATTERNS.weak.map((pattern) => {
|
|
2718
|
+
const escaped = pattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2719
|
+
return new RegExp(`\\b${escaped}\\b`, "gi");
|
|
2720
|
+
});
|
|
2691
2721
|
const promptWeakInstruction = {
|
|
2692
2722
|
meta: {
|
|
2693
2723
|
type: "suggestion",
|
|
@@ -2709,8 +2739,9 @@ const promptWeakInstruction = {
|
|
|
2709
2739
|
if (shouldSkipLine(i, codeBlockLines, frontmatterEnd))
|
|
2710
2740
|
continue;
|
|
2711
2741
|
const line = lines[i];
|
|
2712
|
-
for (
|
|
2713
|
-
const regex =
|
|
2742
|
+
for (let wi = 0; wi < COMPILED.length; wi++) {
|
|
2743
|
+
const regex = COMPILED[wi];
|
|
2744
|
+
regex.lastIndex = 0;
|
|
2714
2745
|
let match;
|
|
2715
2746
|
while ((match = regex.exec(line)) !== null) {
|
|
2716
2747
|
const suggestion = WEAK_TO_STRONG[match[0].toLowerCase()] ?? "Must";
|
|
@@ -2778,12 +2809,21 @@ function hasJsxExternalAttr(attrs) {
|
|
|
2778
2809
|
(a) => a.type === "JSXAttribute" && a.name?.name === "external"
|
|
2779
2810
|
);
|
|
2780
2811
|
}
|
|
2812
|
+
const excludeCache = /* @__PURE__ */ new Map();
|
|
2813
|
+
function getExcludeRegex(pattern) {
|
|
2814
|
+
let regex = excludeCache.get(pattern);
|
|
2815
|
+
if (!regex) {
|
|
2816
|
+
regex = new RegExp(pattern);
|
|
2817
|
+
excludeCache.set(pattern, regex);
|
|
2818
|
+
}
|
|
2819
|
+
return regex;
|
|
2820
|
+
}
|
|
2781
2821
|
function shouldSkipLink(url, node, options) {
|
|
2782
2822
|
if (options.ignoreExternal && (isExternalUrl(url) || hasExternalAttr(node)))
|
|
2783
2823
|
return true;
|
|
2784
2824
|
if (options.exclude?.length) {
|
|
2785
2825
|
for (const pattern of options.exclude) {
|
|
2786
|
-
if (
|
|
2826
|
+
if (getExcludeRegex(pattern).test(url))
|
|
2787
2827
|
return true;
|
|
2788
2828
|
}
|
|
2789
2829
|
}
|
|
@@ -2794,7 +2834,7 @@ function shouldSkipJsxLink(url, attrs, options) {
|
|
|
2794
2834
|
return true;
|
|
2795
2835
|
if (options.exclude?.length) {
|
|
2796
2836
|
for (const pattern of options.exclude) {
|
|
2797
|
-
if (
|
|
2837
|
+
if (getExcludeRegex(pattern).test(url))
|
|
2798
2838
|
return true;
|
|
2799
2839
|
}
|
|
2800
2840
|
}
|
|
@@ -2883,16 +2923,6 @@ function isReturned(node) {
|
|
|
2883
2923
|
}
|
|
2884
2924
|
return false;
|
|
2885
2925
|
}
|
|
2886
|
-
function isInFunction(node) {
|
|
2887
|
-
let parent = node.parent;
|
|
2888
|
-
while (parent) {
|
|
2889
|
-
if (parent.type === "FunctionDeclaration" || parent.type === "FunctionExpression" || parent.type === "ArrowFunctionExpression") {
|
|
2890
|
-
return true;
|
|
2891
|
-
}
|
|
2892
|
-
parent = parent.parent;
|
|
2893
|
-
}
|
|
2894
|
-
return false;
|
|
2895
|
-
}
|
|
2896
2926
|
function isInAsyncFunction(node) {
|
|
2897
2927
|
let parent = node.parent;
|
|
2898
2928
|
while (parent) {
|
|
@@ -2906,18 +2936,18 @@ function isInAsyncFunction(node) {
|
|
|
2906
2936
|
function isFunctionCall(node, functionName) {
|
|
2907
2937
|
return node.callee.type === "Identifier" && node.callee.name === functionName;
|
|
2908
2938
|
}
|
|
2909
|
-
function
|
|
2939
|
+
function getNodeScope(node) {
|
|
2910
2940
|
let parent = node.parent;
|
|
2911
2941
|
while (parent) {
|
|
2912
|
-
if (parent.type === "Program") {
|
|
2913
|
-
return true;
|
|
2914
|
-
}
|
|
2915
2942
|
if (parent.type === "FunctionDeclaration" || parent.type === "FunctionExpression" || parent.type === "ArrowFunctionExpression") {
|
|
2916
|
-
return false;
|
|
2943
|
+
return { atTopLevel: false, inFunction: true };
|
|
2944
|
+
}
|
|
2945
|
+
if (parent.type === "Program") {
|
|
2946
|
+
return { atTopLevel: true, inFunction: false };
|
|
2917
2947
|
}
|
|
2918
2948
|
parent = parent.parent;
|
|
2919
2949
|
}
|
|
2920
|
-
return false;
|
|
2950
|
+
return { atTopLevel: false, inFunction: false };
|
|
2921
2951
|
}
|
|
2922
2952
|
function isCallExpression(node) {
|
|
2923
2953
|
return node.type === "CallExpression";
|
|
@@ -3109,17 +3139,15 @@ function isReactivityCall(node, vueImports) {
|
|
|
3109
3139
|
}
|
|
3110
3140
|
return false;
|
|
3111
3141
|
}
|
|
3142
|
+
const COMPOSABLE_RE = /^use[A-Z_]/;
|
|
3112
3143
|
function isComposableCall(node) {
|
|
3113
3144
|
if (node.callee.type === "Identifier") {
|
|
3114
|
-
return
|
|
3145
|
+
return COMPOSABLE_RE.test(node.callee.name);
|
|
3115
3146
|
}
|
|
3116
3147
|
return false;
|
|
3117
3148
|
}
|
|
3118
3149
|
function isComposableName(name) {
|
|
3119
|
-
return
|
|
3120
|
-
}
|
|
3121
|
-
function isInVueScriptSetup(node) {
|
|
3122
|
-
return isAtTopLevel(node);
|
|
3150
|
+
return COMPOSABLE_RE.test(name);
|
|
3123
3151
|
}
|
|
3124
3152
|
function isDefinePropsCall(node) {
|
|
3125
3153
|
return node.callee.type === "Identifier" && node.callee.name === "defineProps";
|
|
@@ -3963,9 +3991,8 @@ const nuxtAwaitNavigateTo = createEslintRule({
|
|
|
3963
3991
|
if (!isFunctionCall(node, "navigateTo")) {
|
|
3964
3992
|
return;
|
|
3965
3993
|
}
|
|
3966
|
-
const inFunction =
|
|
3967
|
-
|
|
3968
|
-
if (inVueScriptSetup && !inFunction) {
|
|
3994
|
+
const { inFunction, atTopLevel: inVueScriptSetup } = getNodeScope(node);
|
|
3995
|
+
if (inVueScriptSetup) {
|
|
3969
3996
|
if (!isAwaited(node)) {
|
|
3970
3997
|
context.report({
|
|
3971
3998
|
node,
|
|
@@ -4481,9 +4508,8 @@ ${indent}})`;
|
|
|
4481
4508
|
if (!isSideEffectCall(node)) {
|
|
4482
4509
|
return;
|
|
4483
4510
|
}
|
|
4484
|
-
const
|
|
4485
|
-
|
|
4486
|
-
if (inVueScriptSetup && !inFunction) {
|
|
4511
|
+
const { atTopLevel } = getNodeScope(node);
|
|
4512
|
+
if (atTopLevel) {
|
|
4487
4513
|
const functionName = node.callee.type === "Identifier" ? node.callee.name : "unknown";
|
|
4488
4514
|
reportSideEffect(node, functionName);
|
|
4489
4515
|
}
|
|
@@ -4492,9 +4518,8 @@ ${indent}})`;
|
|
|
4492
4518
|
if (node.callee.type !== "Identifier" || !SIDE_EFFECT_FUNCTIONS.has(node.callee.name)) {
|
|
4493
4519
|
return;
|
|
4494
4520
|
}
|
|
4495
|
-
const
|
|
4496
|
-
|
|
4497
|
-
if (inVueScriptSetup && !inFunction) {
|
|
4521
|
+
const { atTopLevel } = getNodeScope(node);
|
|
4522
|
+
if (atTopLevel) {
|
|
4498
4523
|
const functionName = node.callee.type === "Identifier" ? node.callee.name : "unknown";
|
|
4499
4524
|
reportSideEffect(node, functionName);
|
|
4500
4525
|
}
|
|
@@ -5317,6 +5342,8 @@ const vueNoTorefsOnProps = createEslintRule({
|
|
|
5317
5342
|
});
|
|
5318
5343
|
|
|
5319
5344
|
const RULE_NAME = "vue-require-composable-prefix";
|
|
5345
|
+
const DEFINE_RE = /^define[A-Z]/;
|
|
5346
|
+
const CREATE_RE = /^create[A-Z]/;
|
|
5320
5347
|
const vueRequireComposablePrefix = createEslintRule({
|
|
5321
5348
|
name: RULE_NAME,
|
|
5322
5349
|
meta: {
|
|
@@ -5340,7 +5367,7 @@ const vueRequireComposablePrefix = createEslintRule({
|
|
|
5340
5367
|
const candidateFunctions = /* @__PURE__ */ new Map();
|
|
5341
5368
|
const { hasReactivityInStatement, hasReactivityInExpression } = createReactivityChecker(vueImports, nonVueImports);
|
|
5342
5369
|
function isExcludedName(name) {
|
|
5343
|
-
return
|
|
5370
|
+
return DEFINE_RE.test(name) || CREATE_RE.test(name) || name === "setup";
|
|
5344
5371
|
}
|
|
5345
5372
|
function checkFunctionForReactivity(functionNode, idNode, functionName) {
|
|
5346
5373
|
if (!functionNode.body)
|
|
@@ -5531,6 +5558,7 @@ plugin.configs["prompt:skill"] = [
|
|
|
5531
5558
|
}
|
|
5532
5559
|
}
|
|
5533
5560
|
];
|
|
5561
|
+
const CODE_IGNORES = [".claude/**", ".cursor/**", ".github/copilot-instructions.md"];
|
|
5534
5562
|
const deslopRules = {
|
|
5535
5563
|
"harlanzw/ai-deslop-buzzwords": "error",
|
|
5536
5564
|
"harlanzw/ai-deslop-casing": "error",
|
|
@@ -5546,6 +5574,7 @@ plugin.configs.content = [
|
|
|
5546
5574
|
{
|
|
5547
5575
|
name: "harlanzw/content",
|
|
5548
5576
|
files: CONTENT_FILES,
|
|
5577
|
+
ignores: CODE_IGNORES,
|
|
5549
5578
|
language: "harlanzw/prompt",
|
|
5550
5579
|
plugins: { harlanzw: plugin },
|
|
5551
5580
|
rules: deslopRules
|
|
@@ -5565,6 +5594,7 @@ plugin.configs.link = [
|
|
|
5565
5594
|
{
|
|
5566
5595
|
name: "harlanzw/link",
|
|
5567
5596
|
files: LINK_FILES,
|
|
5597
|
+
ignores: CODE_IGNORES,
|
|
5568
5598
|
plugins: { harlanzw: plugin },
|
|
5569
5599
|
rules: {
|
|
5570
5600
|
"harlanzw/link-ascii-only": "warn",
|
|
@@ -5583,6 +5613,7 @@ plugin.configs.nuxt = [
|
|
|
5583
5613
|
{
|
|
5584
5614
|
name: "harlanzw/nuxt",
|
|
5585
5615
|
files: NUXT_VUE_FILES,
|
|
5616
|
+
ignores: CODE_IGNORES,
|
|
5586
5617
|
plugins: { harlanzw: plugin },
|
|
5587
5618
|
rules: {
|
|
5588
5619
|
"harlanzw/nuxt-await-navigate-to": "error",
|
|
@@ -5600,6 +5631,7 @@ plugin.configs.vue = [
|
|
|
5600
5631
|
{
|
|
5601
5632
|
name: "harlanzw/vue",
|
|
5602
5633
|
files: NUXT_VUE_FILES,
|
|
5634
|
+
ignores: CODE_IGNORES,
|
|
5603
5635
|
plugins: { harlanzw: plugin },
|
|
5604
5636
|
rules: {
|
|
5605
5637
|
"harlanzw/vue-no-faux-composables": "error",
|
|
@@ -5650,6 +5682,7 @@ function harlanzw(options = {}, ...extraConfigs) {
|
|
|
5650
5682
|
configs.push({
|
|
5651
5683
|
name: "harlanzw/link",
|
|
5652
5684
|
files: LINK_FILES,
|
|
5685
|
+
ignores: CODE_IGNORES,
|
|
5653
5686
|
plugins: { harlanzw: plugin },
|
|
5654
5687
|
rules: buildLinkRules(linkOpts)
|
|
5655
5688
|
});
|