@saasmakers/eslint 1.0.22 → 1.0.24
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.cjs +35 -3
- package/dist/index.d.cts +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +35 -3
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const index$1 = require('./shared/eslint.BqRQ4tAN.cjs');
|
|
4
|
-
const shared = require('@saasmakers/shared');
|
|
5
4
|
require('eslint');
|
|
6
5
|
require('eslint/use-at-your-own-risk');
|
|
7
6
|
|
|
@@ -519,7 +518,7 @@ const rule$3 = {
|
|
|
519
518
|
}
|
|
520
519
|
};
|
|
521
520
|
|
|
522
|
-
const defaultLocales =
|
|
521
|
+
const defaultLocales = ["en", "fr"];
|
|
523
522
|
const indentSpaces = 2;
|
|
524
523
|
const i18nRegex = /(<i18n\s+lang=["']json["']>)([\s\S]*?)<\/i18n>/i;
|
|
525
524
|
const templateRegex$1 = /<template>([\s\S]*)<\/template>/i;
|
|
@@ -809,6 +808,11 @@ const templateRegex = /<template>([\s\S]*)<\/template>/i;
|
|
|
809
808
|
const templateTagLength = "<template>".length;
|
|
810
809
|
const propsPrefixRegex = /\$?props\.(\w+)/g;
|
|
811
810
|
const trueAttributeRegex = /(?<![\w-]):?(?!aria-)([a-z0-9-]+)="true"/gi;
|
|
811
|
+
const eventHandlerRegex = /(?:@|v-on:)[^\s="'<>/]+\s*=\s*"([^"]*)"/g;
|
|
812
|
+
const bareIdentifierRegex = /^[a-z_$][\w$]*$/i;
|
|
813
|
+
const singleCallRegex = /^([a-z_$][\w$]*)\s*\(.*\)$/is;
|
|
814
|
+
const onPrefixRegex = /^on[A-Z]/;
|
|
815
|
+
const exemptCallees = /* @__PURE__ */ new Set(["$emit", "emit"]);
|
|
812
816
|
const dollarTPatterns = [
|
|
813
817
|
{
|
|
814
818
|
pattern: / \$t\(/g,
|
|
@@ -834,10 +838,11 @@ const dollarTPatterns = [
|
|
|
834
838
|
const rule = {
|
|
835
839
|
defaultOptions: [],
|
|
836
840
|
meta: {
|
|
837
|
-
docs: { description: 'Format Vue templates: strip unnecessary props/$props prefixes, redundant ="true" attributes (except aria- attributes),
|
|
841
|
+
docs: { description: 'Format Vue templates: strip unnecessary props/$props prefixes, redundant ="true" attributes (except aria- attributes), enforce t() over $t(), and require "on" prefix on named event listener handlers' },
|
|
838
842
|
fixable: "code",
|
|
839
843
|
messages: {
|
|
840
844
|
noPropsPrefix: "Unnecessary props/$props prefix in template. Props are automatically available in template scope.",
|
|
845
|
+
prefixEventHandlerWithOn: 'Event listener handler "{{name}}" must be prefixed with "on" (e.g. @click="onClick").',
|
|
841
846
|
removeTrueAttribute: 'Unnecessary ="true" attribute. Use the attribute name directly instead.',
|
|
842
847
|
useT: "Use t() instead of $t() in Vue templates as it does not work with <i18n> tags."
|
|
843
848
|
},
|
|
@@ -912,6 +917,33 @@ const rule = {
|
|
|
912
917
|
dollarTMatch = pattern.exec(templateContent);
|
|
913
918
|
}
|
|
914
919
|
}
|
|
920
|
+
eventHandlerRegex.lastIndex = 0;
|
|
921
|
+
let eventHandlerMatch = eventHandlerRegex.exec(templateContent);
|
|
922
|
+
while (eventHandlerMatch !== null) {
|
|
923
|
+
const handlerValue = eventHandlerMatch[1].trim();
|
|
924
|
+
let handlerName;
|
|
925
|
+
if (bareIdentifierRegex.test(handlerValue)) {
|
|
926
|
+
handlerName = handlerValue;
|
|
927
|
+
} else {
|
|
928
|
+
const singleCallMatch = singleCallRegex.exec(handlerValue);
|
|
929
|
+
if (singleCallMatch) {
|
|
930
|
+
handlerName = singleCallMatch[1];
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
if (handlerName && !exemptCallees.has(handlerName) && !onPrefixRegex.test(handlerName)) {
|
|
934
|
+
const valueStart = templateStartIndex + eventHandlerMatch.index + eventHandlerMatch[0].length - 1 - eventHandlerMatch[1].length;
|
|
935
|
+
const valueEnd = valueStart + eventHandlerMatch[1].length;
|
|
936
|
+
context.report({
|
|
937
|
+
data: { name: handlerName },
|
|
938
|
+
loc: {
|
|
939
|
+
end: sourceCode.getLocFromIndex(valueEnd),
|
|
940
|
+
start: sourceCode.getLocFromIndex(valueStart)
|
|
941
|
+
},
|
|
942
|
+
messageId: "prefixEventHandlerWithOn"
|
|
943
|
+
});
|
|
944
|
+
}
|
|
945
|
+
eventHandlerMatch = eventHandlerRegex.exec(templateContent);
|
|
946
|
+
}
|
|
915
947
|
}
|
|
916
948
|
};
|
|
917
949
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -5203,7 +5203,7 @@ declare const _default: {
|
|
|
5203
5203
|
locales?: string[];
|
|
5204
5204
|
} | undefined)?], unknown, RuleListener>;
|
|
5205
5205
|
'vue-format-script': RuleModule<"multilineComputed" | "untypedEmits", [], unknown, RuleListener>;
|
|
5206
|
-
'vue-format-template': RuleModule<"noPropsPrefix" | "removeTrueAttribute" | "useT", [], unknown, RuleListener>;
|
|
5206
|
+
'vue-format-template': RuleModule<"noPropsPrefix" | "prefixEventHandlerWithOn" | "removeTrueAttribute" | "useT", [], unknown, RuleListener>;
|
|
5207
5207
|
};
|
|
5208
5208
|
};
|
|
5209
5209
|
|
package/dist/index.d.mts
CHANGED
|
@@ -5203,7 +5203,7 @@ declare const _default: {
|
|
|
5203
5203
|
locales?: string[];
|
|
5204
5204
|
} | undefined)?], unknown, RuleListener>;
|
|
5205
5205
|
'vue-format-script': RuleModule<"multilineComputed" | "untypedEmits", [], unknown, RuleListener>;
|
|
5206
|
-
'vue-format-template': RuleModule<"noPropsPrefix" | "removeTrueAttribute" | "useT", [], unknown, RuleListener>;
|
|
5206
|
+
'vue-format-template': RuleModule<"noPropsPrefix" | "prefixEventHandlerWithOn" | "removeTrueAttribute" | "useT", [], unknown, RuleListener>;
|
|
5207
5207
|
};
|
|
5208
5208
|
};
|
|
5209
5209
|
|
package/dist/index.d.ts
CHANGED
|
@@ -5203,7 +5203,7 @@ declare const _default: {
|
|
|
5203
5203
|
locales?: string[];
|
|
5204
5204
|
} | undefined)?], unknown, RuleListener>;
|
|
5205
5205
|
'vue-format-script': RuleModule<"multilineComputed" | "untypedEmits", [], unknown, RuleListener>;
|
|
5206
|
-
'vue-format-template': RuleModule<"noPropsPrefix" | "removeTrueAttribute" | "useT", [], unknown, RuleListener>;
|
|
5206
|
+
'vue-format-template': RuleModule<"noPropsPrefix" | "prefixEventHandlerWithOn" | "removeTrueAttribute" | "useT", [], unknown, RuleListener>;
|
|
5207
5207
|
};
|
|
5208
5208
|
};
|
|
5209
5209
|
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { d as distExports } from './shared/eslint.DOaqyhfZ.mjs';
|
|
2
|
-
import { localeCodes } from '@saasmakers/shared';
|
|
3
2
|
import 'eslint';
|
|
4
3
|
import 'eslint/use-at-your-own-risk';
|
|
5
4
|
|
|
@@ -517,7 +516,7 @@ const rule$3 = {
|
|
|
517
516
|
}
|
|
518
517
|
};
|
|
519
518
|
|
|
520
|
-
const defaultLocales =
|
|
519
|
+
const defaultLocales = ["en", "fr"];
|
|
521
520
|
const indentSpaces = 2;
|
|
522
521
|
const i18nRegex = /(<i18n\s+lang=["']json["']>)([\s\S]*?)<\/i18n>/i;
|
|
523
522
|
const templateRegex$1 = /<template>([\s\S]*)<\/template>/i;
|
|
@@ -807,6 +806,11 @@ const templateRegex = /<template>([\s\S]*)<\/template>/i;
|
|
|
807
806
|
const templateTagLength = "<template>".length;
|
|
808
807
|
const propsPrefixRegex = /\$?props\.(\w+)/g;
|
|
809
808
|
const trueAttributeRegex = /(?<![\w-]):?(?!aria-)([a-z0-9-]+)="true"/gi;
|
|
809
|
+
const eventHandlerRegex = /(?:@|v-on:)[^\s="'<>/]+\s*=\s*"([^"]*)"/g;
|
|
810
|
+
const bareIdentifierRegex = /^[a-z_$][\w$]*$/i;
|
|
811
|
+
const singleCallRegex = /^([a-z_$][\w$]*)\s*\(.*\)$/is;
|
|
812
|
+
const onPrefixRegex = /^on[A-Z]/;
|
|
813
|
+
const exemptCallees = /* @__PURE__ */ new Set(["$emit", "emit"]);
|
|
810
814
|
const dollarTPatterns = [
|
|
811
815
|
{
|
|
812
816
|
pattern: / \$t\(/g,
|
|
@@ -832,10 +836,11 @@ const dollarTPatterns = [
|
|
|
832
836
|
const rule = {
|
|
833
837
|
defaultOptions: [],
|
|
834
838
|
meta: {
|
|
835
|
-
docs: { description: 'Format Vue templates: strip unnecessary props/$props prefixes, redundant ="true" attributes (except aria- attributes),
|
|
839
|
+
docs: { description: 'Format Vue templates: strip unnecessary props/$props prefixes, redundant ="true" attributes (except aria- attributes), enforce t() over $t(), and require "on" prefix on named event listener handlers' },
|
|
836
840
|
fixable: "code",
|
|
837
841
|
messages: {
|
|
838
842
|
noPropsPrefix: "Unnecessary props/$props prefix in template. Props are automatically available in template scope.",
|
|
843
|
+
prefixEventHandlerWithOn: 'Event listener handler "{{name}}" must be prefixed with "on" (e.g. @click="onClick").',
|
|
839
844
|
removeTrueAttribute: 'Unnecessary ="true" attribute. Use the attribute name directly instead.',
|
|
840
845
|
useT: "Use t() instead of $t() in Vue templates as it does not work with <i18n> tags."
|
|
841
846
|
},
|
|
@@ -910,6 +915,33 @@ const rule = {
|
|
|
910
915
|
dollarTMatch = pattern.exec(templateContent);
|
|
911
916
|
}
|
|
912
917
|
}
|
|
918
|
+
eventHandlerRegex.lastIndex = 0;
|
|
919
|
+
let eventHandlerMatch = eventHandlerRegex.exec(templateContent);
|
|
920
|
+
while (eventHandlerMatch !== null) {
|
|
921
|
+
const handlerValue = eventHandlerMatch[1].trim();
|
|
922
|
+
let handlerName;
|
|
923
|
+
if (bareIdentifierRegex.test(handlerValue)) {
|
|
924
|
+
handlerName = handlerValue;
|
|
925
|
+
} else {
|
|
926
|
+
const singleCallMatch = singleCallRegex.exec(handlerValue);
|
|
927
|
+
if (singleCallMatch) {
|
|
928
|
+
handlerName = singleCallMatch[1];
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
if (handlerName && !exemptCallees.has(handlerName) && !onPrefixRegex.test(handlerName)) {
|
|
932
|
+
const valueStart = templateStartIndex + eventHandlerMatch.index + eventHandlerMatch[0].length - 1 - eventHandlerMatch[1].length;
|
|
933
|
+
const valueEnd = valueStart + eventHandlerMatch[1].length;
|
|
934
|
+
context.report({
|
|
935
|
+
data: { name: handlerName },
|
|
936
|
+
loc: {
|
|
937
|
+
end: sourceCode.getLocFromIndex(valueEnd),
|
|
938
|
+
start: sourceCode.getLocFromIndex(valueStart)
|
|
939
|
+
},
|
|
940
|
+
messageId: "prefixEventHandlerWithOn"
|
|
941
|
+
});
|
|
942
|
+
}
|
|
943
|
+
eventHandlerMatch = eventHandlerRegex.exec(templateContent);
|
|
944
|
+
}
|
|
913
945
|
}
|
|
914
946
|
};
|
|
915
947
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saasmakers/eslint",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.24",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Shared ESLint config and rules for SaaS Makers projects",
|
|
6
6
|
"license": "MIT",
|
|
@@ -27,13 +27,13 @@
|
|
|
27
27
|
],
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@antfu/eslint-config": "7.4.3",
|
|
30
|
-
"@saasmakers/shared": "0.2.8",
|
|
31
30
|
"@unocss/eslint-plugin": "66.7.0",
|
|
32
31
|
"@vitest/eslint-plugin": "1.6.20",
|
|
33
32
|
"eslint-plugin-package-json": "0.31.0",
|
|
34
33
|
"eslint-plugin-turbo": "2.9.18",
|
|
35
34
|
"eslint-plugin-zod": "3.4.0",
|
|
36
|
-
"typescript-eslint": "8.61.0"
|
|
35
|
+
"typescript-eslint": "8.61.0",
|
|
36
|
+
"@saasmakers/shared": "0.2.8"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@eslint/config-inspector": "1.4.2",
|