@saasmakers/eslint 1.0.26 → 1.0.28
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/eslint.config.cjs +1 -0
- package/dist/eslint.config.d.cts +1 -0
- package/dist/eslint.config.d.mts +1 -0
- package/dist/eslint.config.d.ts +1 -0
- package/dist/eslint.config.mjs +1 -0
- package/dist/index.cjs +191 -18
- package/dist/index.d.cts +2 -1
- package/dist/index.d.mts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.mjs +191 -18
- package/package.json +1 -1
package/dist/eslint.config.cjs
CHANGED
|
@@ -10872,6 +10872,7 @@ const eslint_config = antfu__default(
|
|
|
10872
10872
|
"saasmakers/ts-format-tests": "error",
|
|
10873
10873
|
"saasmakers/vue-format-i18n": ["error", { locales: shared.localeCodes }],
|
|
10874
10874
|
"saasmakers/vue-format-script": "error",
|
|
10875
|
+
"saasmakers/vue-format-style": "error",
|
|
10875
10876
|
"saasmakers/vue-format-template": "error"
|
|
10876
10877
|
}
|
|
10877
10878
|
},
|
package/dist/eslint.config.d.cts
CHANGED
|
@@ -152,6 +152,7 @@ var eslint_config = antfu(
|
|
|
152
152
|
"saasmakers/ts-format-tests": "error",
|
|
153
153
|
"saasmakers/vue-format-i18n": ["error", { locales: localeCodes }],
|
|
154
154
|
"saasmakers/vue-format-script": "error",
|
|
155
|
+
"saasmakers/vue-format-style": "error",
|
|
155
156
|
"saasmakers/vue-format-template": "error"
|
|
156
157
|
}
|
|
157
158
|
},
|
package/dist/eslint.config.d.mts
CHANGED
|
@@ -152,6 +152,7 @@ var eslint_config = antfu(
|
|
|
152
152
|
"saasmakers/ts-format-tests": "error",
|
|
153
153
|
"saasmakers/vue-format-i18n": ["error", { locales: localeCodes }],
|
|
154
154
|
"saasmakers/vue-format-script": "error",
|
|
155
|
+
"saasmakers/vue-format-style": "error",
|
|
155
156
|
"saasmakers/vue-format-template": "error"
|
|
156
157
|
}
|
|
157
158
|
},
|
package/dist/eslint.config.d.ts
CHANGED
|
@@ -152,6 +152,7 @@ var eslint_config = antfu(
|
|
|
152
152
|
"saasmakers/ts-format-tests": "error",
|
|
153
153
|
"saasmakers/vue-format-i18n": ["error", { locales: localeCodes }],
|
|
154
154
|
"saasmakers/vue-format-script": "error",
|
|
155
|
+
"saasmakers/vue-format-style": "error",
|
|
155
156
|
"saasmakers/vue-format-template": "error"
|
|
156
157
|
}
|
|
157
158
|
},
|
package/dist/eslint.config.mjs
CHANGED
|
@@ -10846,6 +10846,7 @@ const eslint_config = antfu(
|
|
|
10846
10846
|
"saasmakers/ts-format-tests": "error",
|
|
10847
10847
|
"saasmakers/vue-format-i18n": ["error", { locales: localeCodes }],
|
|
10848
10848
|
"saasmakers/vue-format-script": "error",
|
|
10849
|
+
"saasmakers/vue-format-style": "error",
|
|
10849
10850
|
"saasmakers/vue-format-template": "error"
|
|
10850
10851
|
}
|
|
10851
10852
|
},
|
package/dist/index.cjs
CHANGED
|
@@ -63,7 +63,7 @@ function checkUnion(context, node, maxLineLength, minItems) {
|
|
|
63
63
|
function collapseBlankLine(text) {
|
|
64
64
|
return text.replace(/\n[^\S\n]*\n[^\S\n]*/, "\n");
|
|
65
65
|
}
|
|
66
|
-
function expressionStartsWithIdentifier(node, identifier) {
|
|
66
|
+
function expressionStartsWithIdentifier$1(node, identifier) {
|
|
67
67
|
if (node.type === index$1.distExports.AST_NODE_TYPES.Identifier && node.name === identifier) {
|
|
68
68
|
return true;
|
|
69
69
|
}
|
|
@@ -73,17 +73,17 @@ function expressionStartsWithIdentifier(node, identifier) {
|
|
|
73
73
|
return true;
|
|
74
74
|
}
|
|
75
75
|
if (callee.type === index$1.distExports.AST_NODE_TYPES.MemberExpression) {
|
|
76
|
-
return expressionStartsWithIdentifier(callee.object, identifier);
|
|
76
|
+
return expressionStartsWithIdentifier$1(callee.object, identifier);
|
|
77
77
|
}
|
|
78
78
|
if (callee.type === index$1.distExports.AST_NODE_TYPES.ChainExpression) {
|
|
79
|
-
return expressionStartsWithIdentifier(callee.expression, identifier);
|
|
79
|
+
return expressionStartsWithIdentifier$1(callee.expression, identifier);
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
82
|
if (node.type === index$1.distExports.AST_NODE_TYPES.MemberExpression) {
|
|
83
|
-
return expressionStartsWithIdentifier(node.object, identifier);
|
|
83
|
+
return expressionStartsWithIdentifier$1(node.object, identifier);
|
|
84
84
|
}
|
|
85
85
|
if (node.type === index$1.distExports.AST_NODE_TYPES.ChainExpression) {
|
|
86
|
-
return expressionStartsWithIdentifier(node.expression, identifier);
|
|
86
|
+
return expressionStartsWithIdentifier$1(node.expression, identifier);
|
|
87
87
|
}
|
|
88
88
|
return false;
|
|
89
89
|
}
|
|
@@ -211,10 +211,10 @@ function hasLineCommentBetween(prevNode, nextNode, sourceCode) {
|
|
|
211
211
|
});
|
|
212
212
|
}
|
|
213
213
|
function isAssertExpression(expression) {
|
|
214
|
-
return expressionStartsWithIdentifier(expression, "assert");
|
|
214
|
+
return expressionStartsWithIdentifier$1(expression, "assert");
|
|
215
215
|
}
|
|
216
216
|
function isConsoleExpression(expression) {
|
|
217
|
-
return expressionStartsWithIdentifier(expression, "console");
|
|
217
|
+
return expressionStartsWithIdentifier$1(expression, "console");
|
|
218
218
|
}
|
|
219
219
|
function isDirectivePrologue(node) {
|
|
220
220
|
if (node.expression.type !== index$1.distExports.AST_NODE_TYPES.Literal) {
|
|
@@ -223,7 +223,7 @@ function isDirectivePrologue(node) {
|
|
|
223
223
|
return typeof node.expression.value === "string";
|
|
224
224
|
}
|
|
225
225
|
function isExpectExpression(expression) {
|
|
226
|
-
return expressionStartsWithIdentifier(expression, "expect");
|
|
226
|
+
return expressionStartsWithIdentifier$1(expression, "expect");
|
|
227
227
|
}
|
|
228
228
|
function isOwnLineComment(comment, sourceCode) {
|
|
229
229
|
if (comment.type !== "Line") {
|
|
@@ -253,7 +253,7 @@ function isThisReceiver(node) {
|
|
|
253
253
|
function isVoidExpression(expression) {
|
|
254
254
|
return expression.type === index$1.distExports.AST_NODE_TYPES.UnaryExpression && expression.operator === "void";
|
|
255
255
|
}
|
|
256
|
-
const rule$
|
|
256
|
+
const rule$5 = {
|
|
257
257
|
defaultOptions: [{}],
|
|
258
258
|
meta: {
|
|
259
259
|
docs: { description: "Format TypeScript layout: single/multiline ternaries and union types, and blank lines between statements" },
|
|
@@ -403,6 +403,7 @@ const rule$4 = {
|
|
|
403
403
|
}
|
|
404
404
|
};
|
|
405
405
|
|
|
406
|
+
const teardownViMethods = /* @__PURE__ */ new Set(["restoreAllMocks", "unstubAllGlobals", "useRealTimers"]);
|
|
406
407
|
function compareTests(testA, testB) {
|
|
407
408
|
const functionA = getFunctionName(testA);
|
|
408
409
|
const functionB = getFunctionName(testB);
|
|
@@ -418,6 +419,40 @@ function compareTests(testA, testB) {
|
|
|
418
419
|
const specificNameB = getSpecificName(testB);
|
|
419
420
|
return specificNameA.localeCompare(specificNameB);
|
|
420
421
|
}
|
|
422
|
+
function expressionStartsWithIdentifier(node, identifier) {
|
|
423
|
+
if (node.type === index$1.distExports.AST_NODE_TYPES.Identifier && node.name === identifier) {
|
|
424
|
+
return true;
|
|
425
|
+
}
|
|
426
|
+
if (node.type === index$1.distExports.AST_NODE_TYPES.CallExpression) {
|
|
427
|
+
const { callee } = node;
|
|
428
|
+
if (callee.type === index$1.distExports.AST_NODE_TYPES.Identifier && callee.name === identifier) {
|
|
429
|
+
return true;
|
|
430
|
+
}
|
|
431
|
+
if (callee.type === index$1.distExports.AST_NODE_TYPES.MemberExpression) {
|
|
432
|
+
return expressionStartsWithIdentifier(callee.object, identifier);
|
|
433
|
+
}
|
|
434
|
+
if (callee.type === index$1.distExports.AST_NODE_TYPES.ChainExpression) {
|
|
435
|
+
return expressionStartsWithIdentifier(callee.expression, identifier);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
if (node.type === index$1.distExports.AST_NODE_TYPES.MemberExpression) {
|
|
439
|
+
return expressionStartsWithIdentifier(node.object, identifier);
|
|
440
|
+
}
|
|
441
|
+
if (node.type === index$1.distExports.AST_NODE_TYPES.ChainExpression) {
|
|
442
|
+
return expressionStartsWithIdentifier(node.expression, identifier);
|
|
443
|
+
}
|
|
444
|
+
return false;
|
|
445
|
+
}
|
|
446
|
+
function getExpressionFromStatement(statement) {
|
|
447
|
+
if (statement.type !== index$1.distExports.AST_NODE_TYPES.ExpressionStatement) {
|
|
448
|
+
return null;
|
|
449
|
+
}
|
|
450
|
+
let { expression } = statement;
|
|
451
|
+
if (expression.type === index$1.distExports.AST_NODE_TYPES.AwaitExpression) {
|
|
452
|
+
expression = expression.argument;
|
|
453
|
+
}
|
|
454
|
+
return expression;
|
|
455
|
+
}
|
|
421
456
|
function getFunctionName(testName) {
|
|
422
457
|
const parts = testName.split(".");
|
|
423
458
|
return parts.slice(0, 2).join(".");
|
|
@@ -431,6 +466,20 @@ function getSpecificName(testName) {
|
|
|
431
466
|
}
|
|
432
467
|
return parts.slice(specialIndex + 1).join(".");
|
|
433
468
|
}
|
|
469
|
+
function getTestCallbackBlockBody(node) {
|
|
470
|
+
const callback = node.arguments[1];
|
|
471
|
+
if (!callback) {
|
|
472
|
+
return null;
|
|
473
|
+
}
|
|
474
|
+
if (callback.type !== index$1.distExports.AST_NODE_TYPES.FunctionExpression && callback.type !== index$1.distExports.AST_NODE_TYPES.ArrowFunctionExpression) {
|
|
475
|
+
return null;
|
|
476
|
+
}
|
|
477
|
+
const { body } = callback;
|
|
478
|
+
if (body.type !== index$1.distExports.AST_NODE_TYPES.BlockStatement) {
|
|
479
|
+
return null;
|
|
480
|
+
}
|
|
481
|
+
return body;
|
|
482
|
+
}
|
|
434
483
|
function getTestName(node) {
|
|
435
484
|
const firstArgument = node.arguments[0];
|
|
436
485
|
if (firstArgument?.type === index$1.distExports.AST_NODE_TYPES.Literal && typeof firstArgument.value === "string") {
|
|
@@ -451,12 +500,78 @@ function getTestPriority(testName) {
|
|
|
451
500
|
return 1;
|
|
452
501
|
}
|
|
453
502
|
}
|
|
454
|
-
|
|
503
|
+
function hasAssertMethodCall(expression) {
|
|
504
|
+
if (expression.type !== index$1.distExports.AST_NODE_TYPES.CallExpression) {
|
|
505
|
+
return false;
|
|
506
|
+
}
|
|
507
|
+
const { callee } = expression;
|
|
508
|
+
if (callee.type === index$1.distExports.AST_NODE_TYPES.MemberExpression && callee.property.type === index$1.distExports.AST_NODE_TYPES.Identifier && callee.property.name.startsWith("assert")) {
|
|
509
|
+
if (callee.object.type === index$1.distExports.AST_NODE_TYPES.Identifier && callee.object.name === "expect") {
|
|
510
|
+
return false;
|
|
511
|
+
}
|
|
512
|
+
return true;
|
|
513
|
+
}
|
|
514
|
+
return false;
|
|
515
|
+
}
|
|
516
|
+
function isAssertionCountExpression(expression) {
|
|
517
|
+
if (expression.type !== index$1.distExports.AST_NODE_TYPES.CallExpression) {
|
|
518
|
+
return false;
|
|
519
|
+
}
|
|
520
|
+
const { callee } = expression;
|
|
521
|
+
if (callee.type !== index$1.distExports.AST_NODE_TYPES.MemberExpression || callee.object.type !== index$1.distExports.AST_NODE_TYPES.Identifier || callee.property.type !== index$1.distExports.AST_NODE_TYPES.Identifier) {
|
|
522
|
+
return false;
|
|
523
|
+
}
|
|
524
|
+
if (callee.object.name === "expect" && (callee.property.name === "assertions" || callee.property.name === "hasAssertions")) {
|
|
525
|
+
return true;
|
|
526
|
+
}
|
|
527
|
+
return callee.object.name === "assert" && callee.property.name === "plan";
|
|
528
|
+
}
|
|
529
|
+
function isAssertionCountStatement(statement) {
|
|
530
|
+
const expression = getExpressionFromStatement(statement);
|
|
531
|
+
if (!expression) {
|
|
532
|
+
return false;
|
|
533
|
+
}
|
|
534
|
+
return isAssertionCountExpression(expression);
|
|
535
|
+
}
|
|
536
|
+
function isAssertionExpression(expression) {
|
|
537
|
+
if (isAssertionCountExpression(expression)) {
|
|
538
|
+
return false;
|
|
539
|
+
}
|
|
540
|
+
if (expressionStartsWithIdentifier(expression, "assert") || expressionStartsWithIdentifier(expression, "expect")) {
|
|
541
|
+
return true;
|
|
542
|
+
}
|
|
543
|
+
return hasAssertMethodCall(expression);
|
|
544
|
+
}
|
|
545
|
+
function isAssertionStatement(statement) {
|
|
546
|
+
const expression = getExpressionFromStatement(statement);
|
|
547
|
+
if (!expression) {
|
|
548
|
+
return false;
|
|
549
|
+
}
|
|
550
|
+
return isAssertionExpression(expression);
|
|
551
|
+
}
|
|
552
|
+
function isTeardownStatement(statement) {
|
|
553
|
+
const expression = getExpressionFromStatement(statement);
|
|
554
|
+
if (!expression || expression.type !== index$1.distExports.AST_NODE_TYPES.CallExpression) {
|
|
555
|
+
return false;
|
|
556
|
+
}
|
|
557
|
+
const { callee } = expression;
|
|
558
|
+
if (callee.type === index$1.distExports.AST_NODE_TYPES.Identifier && callee.name === "cleanup") {
|
|
559
|
+
return true;
|
|
560
|
+
}
|
|
561
|
+
if (callee.type === index$1.distExports.AST_NODE_TYPES.MemberExpression && callee.object.type === index$1.distExports.AST_NODE_TYPES.Identifier && callee.object.name === "vi" && callee.property.type === index$1.distExports.AST_NODE_TYPES.Identifier && teardownViMethods.has(callee.property.name)) {
|
|
562
|
+
return true;
|
|
563
|
+
}
|
|
564
|
+
return false;
|
|
565
|
+
}
|
|
566
|
+
const rule$4 = {
|
|
455
567
|
defaultOptions: [],
|
|
456
568
|
meta: {
|
|
457
|
-
docs: { description: "Enforce sorted test functions
|
|
569
|
+
docs: { description: "Enforce sorted test functions and setup-before-assertions layout in test bodies" },
|
|
458
570
|
fixable: "code",
|
|
459
|
-
messages: {
|
|
571
|
+
messages: {
|
|
572
|
+
setupAfterAssertion: "Setup statements must appear before assertions in test bodies.",
|
|
573
|
+
sortError: "Test functions should be grouped by method with sorted metrics, errors, exceptions and middlewares."
|
|
574
|
+
},
|
|
460
575
|
schema: [],
|
|
461
576
|
type: "suggestion"
|
|
462
577
|
},
|
|
@@ -464,6 +579,25 @@ const rule$3 = {
|
|
|
464
579
|
if (!context.filename.endsWith(".spec.ts") && !context.filename.endsWith(".test.ts")) {
|
|
465
580
|
return {};
|
|
466
581
|
}
|
|
582
|
+
function handleTestBody(node) {
|
|
583
|
+
const callbackBody = getTestCallbackBlockBody(node);
|
|
584
|
+
if (!callbackBody) {
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
const firstAssertionIndex = callbackBody.body.findIndex(isAssertionStatement);
|
|
588
|
+
if (firstAssertionIndex === -1) {
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
591
|
+
for (const statement of callbackBody.body.slice(firstAssertionIndex + 1)) {
|
|
592
|
+
if (isAssertionStatement(statement) || isAssertionCountStatement(statement) || isTeardownStatement(statement)) {
|
|
593
|
+
continue;
|
|
594
|
+
}
|
|
595
|
+
context.report({
|
|
596
|
+
messageId: "setupAfterAssertion",
|
|
597
|
+
node: statement
|
|
598
|
+
});
|
|
599
|
+
}
|
|
600
|
+
}
|
|
467
601
|
function handleTestGroup(node) {
|
|
468
602
|
const testGroup = node.arguments[0];
|
|
469
603
|
if (!testGroup || !node.arguments[1]) {
|
|
@@ -512,6 +646,8 @@ const rule$3 = {
|
|
|
512
646
|
}
|
|
513
647
|
return {
|
|
514
648
|
'CallExpression[callee.name="describe"]': handleTestGroup,
|
|
649
|
+
'CallExpression[callee.name="it"]': handleTestBody,
|
|
650
|
+
'CallExpression[callee.name="test"]': handleTestBody,
|
|
515
651
|
'CallExpression[callee.object.name="describe"][callee.property.name="concurrent"]': handleTestGroup,
|
|
516
652
|
'CallExpression[callee.object.name="test"][callee.property.name="group"]': handleTestGroup
|
|
517
653
|
};
|
|
@@ -668,7 +804,7 @@ function checkUnusedStrings(context, parsed, source, content, contentOffset) {
|
|
|
668
804
|
}
|
|
669
805
|
}
|
|
670
806
|
}
|
|
671
|
-
const rule$
|
|
807
|
+
const rule$3 = {
|
|
672
808
|
defaultOptions: [{ locales: defaultLocales }],
|
|
673
809
|
meta: {
|
|
674
810
|
docs: { description: "Format Vue i18n blocks: enforce valid/consistent locales, sorted keys, and no unused strings" },
|
|
@@ -736,7 +872,7 @@ const rule$2 = {
|
|
|
736
872
|
};
|
|
737
873
|
|
|
738
874
|
const untypedEmitsRegex = /const\s+emit\s*=\s*defineEmits\(\[([^\]]+)\]\)/g;
|
|
739
|
-
const rule$
|
|
875
|
+
const rule$2 = {
|
|
740
876
|
defaultOptions: [],
|
|
741
877
|
meta: {
|
|
742
878
|
docs: { description: "Format Vue component scripts: enforce multiline computed properties and typed emits" },
|
|
@@ -804,6 +940,42 @@ ${typedEvents}
|
|
|
804
940
|
}
|
|
805
941
|
};
|
|
806
942
|
|
|
943
|
+
const styleOpenTagRegex = /<style(?:\s[^>]*)?>/gi;
|
|
944
|
+
const rule$1 = {
|
|
945
|
+
defaultOptions: [],
|
|
946
|
+
meta: {
|
|
947
|
+
docs: { description: "Disallow <style> blocks in Vue SFCs. Styling must be done with Tailwind utility classes as much as possible." },
|
|
948
|
+
messages: { noStyleBlock: "Avoid <style> blocks in Vue components. Use Tailwind utility classes instead." },
|
|
949
|
+
schema: [],
|
|
950
|
+
type: "problem"
|
|
951
|
+
},
|
|
952
|
+
create(context) {
|
|
953
|
+
if (!context.filename.endsWith(".vue")) {
|
|
954
|
+
return {};
|
|
955
|
+
}
|
|
956
|
+
return {
|
|
957
|
+
Program() {
|
|
958
|
+
const sourceCode = context.sourceCode;
|
|
959
|
+
const source = sourceCode.getText();
|
|
960
|
+
styleOpenTagRegex.lastIndex = 0;
|
|
961
|
+
let styleMatch = styleOpenTagRegex.exec(source);
|
|
962
|
+
while (styleMatch !== null) {
|
|
963
|
+
const matchIndex = styleMatch.index;
|
|
964
|
+
const matchEnd = matchIndex + styleMatch[0].length;
|
|
965
|
+
context.report({
|
|
966
|
+
loc: {
|
|
967
|
+
end: sourceCode.getLocFromIndex(matchEnd),
|
|
968
|
+
start: sourceCode.getLocFromIndex(matchIndex)
|
|
969
|
+
},
|
|
970
|
+
messageId: "noStyleBlock"
|
|
971
|
+
});
|
|
972
|
+
styleMatch = styleOpenTagRegex.exec(source);
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
};
|
|
976
|
+
}
|
|
977
|
+
};
|
|
978
|
+
|
|
807
979
|
const templateRegex = /<template>([\s\S]*)<\/template>/i;
|
|
808
980
|
const templateTagLength = "<template>".length;
|
|
809
981
|
const propsPrefixRegex = /\$?props\.(\w+)/g;
|
|
@@ -1081,10 +1253,11 @@ const rule = {
|
|
|
1081
1253
|
|
|
1082
1254
|
const index = {
|
|
1083
1255
|
rules: {
|
|
1084
|
-
"ts-format-layout": rule$
|
|
1085
|
-
"ts-format-tests": rule$
|
|
1086
|
-
"vue-format-i18n": rule$
|
|
1087
|
-
"vue-format-script": rule$
|
|
1256
|
+
"ts-format-layout": rule$5,
|
|
1257
|
+
"ts-format-tests": rule$4,
|
|
1258
|
+
"vue-format-i18n": rule$3,
|
|
1259
|
+
"vue-format-script": rule$2,
|
|
1260
|
+
"vue-format-style": rule$1,
|
|
1088
1261
|
"vue-format-template": rule
|
|
1089
1262
|
}
|
|
1090
1263
|
};
|
package/dist/index.d.cts
CHANGED
|
@@ -5198,11 +5198,12 @@ declare const _default: {
|
|
|
5198
5198
|
maxLineLength?: number;
|
|
5199
5199
|
minItems?: number;
|
|
5200
5200
|
} | undefined)?], unknown, RuleListener>;
|
|
5201
|
-
'ts-format-tests': RuleModule<"sortError", [], unknown, RuleListener>;
|
|
5201
|
+
'ts-format-tests': RuleModule<"setupAfterAssertion" | "sortError", [], unknown, RuleListener>;
|
|
5202
5202
|
'vue-format-i18n': RuleModule<"sortError" | "indentError" | "invalidJson" | "invalidLocale" | "missingLocale" | "missingTranslations" | "unusedString", [({
|
|
5203
5203
|
locales?: string[];
|
|
5204
5204
|
} | undefined)?], unknown, RuleListener>;
|
|
5205
5205
|
'vue-format-script': RuleModule<"multilineComputed" | "untypedEmits", [], unknown, RuleListener>;
|
|
5206
|
+
'vue-format-style': RuleModule<"noStyleBlock", [], unknown, RuleListener>;
|
|
5206
5207
|
'vue-format-template': RuleModule<"dynamicClassMustBeObject" | "eventHandlerMustBeFunction" | "multilineClassObject" | "noPropsPrefix" | "prefixEventHandlerWithOn" | "removeTrueAttribute" | "singleLineClassObject" | "useT", [], unknown, RuleListener>;
|
|
5207
5208
|
};
|
|
5208
5209
|
};
|
package/dist/index.d.mts
CHANGED
|
@@ -5198,11 +5198,12 @@ declare const _default: {
|
|
|
5198
5198
|
maxLineLength?: number;
|
|
5199
5199
|
minItems?: number;
|
|
5200
5200
|
} | undefined)?], unknown, RuleListener>;
|
|
5201
|
-
'ts-format-tests': RuleModule<"sortError", [], unknown, RuleListener>;
|
|
5201
|
+
'ts-format-tests': RuleModule<"setupAfterAssertion" | "sortError", [], unknown, RuleListener>;
|
|
5202
5202
|
'vue-format-i18n': RuleModule<"sortError" | "indentError" | "invalidJson" | "invalidLocale" | "missingLocale" | "missingTranslations" | "unusedString", [({
|
|
5203
5203
|
locales?: string[];
|
|
5204
5204
|
} | undefined)?], unknown, RuleListener>;
|
|
5205
5205
|
'vue-format-script': RuleModule<"multilineComputed" | "untypedEmits", [], unknown, RuleListener>;
|
|
5206
|
+
'vue-format-style': RuleModule<"noStyleBlock", [], unknown, RuleListener>;
|
|
5206
5207
|
'vue-format-template': RuleModule<"dynamicClassMustBeObject" | "eventHandlerMustBeFunction" | "multilineClassObject" | "noPropsPrefix" | "prefixEventHandlerWithOn" | "removeTrueAttribute" | "singleLineClassObject" | "useT", [], unknown, RuleListener>;
|
|
5207
5208
|
};
|
|
5208
5209
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -5198,11 +5198,12 @@ declare const _default: {
|
|
|
5198
5198
|
maxLineLength?: number;
|
|
5199
5199
|
minItems?: number;
|
|
5200
5200
|
} | undefined)?], unknown, RuleListener>;
|
|
5201
|
-
'ts-format-tests': RuleModule<"sortError", [], unknown, RuleListener>;
|
|
5201
|
+
'ts-format-tests': RuleModule<"setupAfterAssertion" | "sortError", [], unknown, RuleListener>;
|
|
5202
5202
|
'vue-format-i18n': RuleModule<"sortError" | "indentError" | "invalidJson" | "invalidLocale" | "missingLocale" | "missingTranslations" | "unusedString", [({
|
|
5203
5203
|
locales?: string[];
|
|
5204
5204
|
} | undefined)?], unknown, RuleListener>;
|
|
5205
5205
|
'vue-format-script': RuleModule<"multilineComputed" | "untypedEmits", [], unknown, RuleListener>;
|
|
5206
|
+
'vue-format-style': RuleModule<"noStyleBlock", [], unknown, RuleListener>;
|
|
5206
5207
|
'vue-format-template': RuleModule<"dynamicClassMustBeObject" | "eventHandlerMustBeFunction" | "multilineClassObject" | "noPropsPrefix" | "prefixEventHandlerWithOn" | "removeTrueAttribute" | "singleLineClassObject" | "useT", [], unknown, RuleListener>;
|
|
5207
5208
|
};
|
|
5208
5209
|
};
|
package/dist/index.mjs
CHANGED
|
@@ -61,7 +61,7 @@ function checkUnion(context, node, maxLineLength, minItems) {
|
|
|
61
61
|
function collapseBlankLine(text) {
|
|
62
62
|
return text.replace(/\n[^\S\n]*\n[^\S\n]*/, "\n");
|
|
63
63
|
}
|
|
64
|
-
function expressionStartsWithIdentifier(node, identifier) {
|
|
64
|
+
function expressionStartsWithIdentifier$1(node, identifier) {
|
|
65
65
|
if (node.type === distExports.AST_NODE_TYPES.Identifier && node.name === identifier) {
|
|
66
66
|
return true;
|
|
67
67
|
}
|
|
@@ -71,17 +71,17 @@ function expressionStartsWithIdentifier(node, identifier) {
|
|
|
71
71
|
return true;
|
|
72
72
|
}
|
|
73
73
|
if (callee.type === distExports.AST_NODE_TYPES.MemberExpression) {
|
|
74
|
-
return expressionStartsWithIdentifier(callee.object, identifier);
|
|
74
|
+
return expressionStartsWithIdentifier$1(callee.object, identifier);
|
|
75
75
|
}
|
|
76
76
|
if (callee.type === distExports.AST_NODE_TYPES.ChainExpression) {
|
|
77
|
-
return expressionStartsWithIdentifier(callee.expression, identifier);
|
|
77
|
+
return expressionStartsWithIdentifier$1(callee.expression, identifier);
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
80
|
if (node.type === distExports.AST_NODE_TYPES.MemberExpression) {
|
|
81
|
-
return expressionStartsWithIdentifier(node.object, identifier);
|
|
81
|
+
return expressionStartsWithIdentifier$1(node.object, identifier);
|
|
82
82
|
}
|
|
83
83
|
if (node.type === distExports.AST_NODE_TYPES.ChainExpression) {
|
|
84
|
-
return expressionStartsWithIdentifier(node.expression, identifier);
|
|
84
|
+
return expressionStartsWithIdentifier$1(node.expression, identifier);
|
|
85
85
|
}
|
|
86
86
|
return false;
|
|
87
87
|
}
|
|
@@ -209,10 +209,10 @@ function hasLineCommentBetween(prevNode, nextNode, sourceCode) {
|
|
|
209
209
|
});
|
|
210
210
|
}
|
|
211
211
|
function isAssertExpression(expression) {
|
|
212
|
-
return expressionStartsWithIdentifier(expression, "assert");
|
|
212
|
+
return expressionStartsWithIdentifier$1(expression, "assert");
|
|
213
213
|
}
|
|
214
214
|
function isConsoleExpression(expression) {
|
|
215
|
-
return expressionStartsWithIdentifier(expression, "console");
|
|
215
|
+
return expressionStartsWithIdentifier$1(expression, "console");
|
|
216
216
|
}
|
|
217
217
|
function isDirectivePrologue(node) {
|
|
218
218
|
if (node.expression.type !== distExports.AST_NODE_TYPES.Literal) {
|
|
@@ -221,7 +221,7 @@ function isDirectivePrologue(node) {
|
|
|
221
221
|
return typeof node.expression.value === "string";
|
|
222
222
|
}
|
|
223
223
|
function isExpectExpression(expression) {
|
|
224
|
-
return expressionStartsWithIdentifier(expression, "expect");
|
|
224
|
+
return expressionStartsWithIdentifier$1(expression, "expect");
|
|
225
225
|
}
|
|
226
226
|
function isOwnLineComment(comment, sourceCode) {
|
|
227
227
|
if (comment.type !== "Line") {
|
|
@@ -251,7 +251,7 @@ function isThisReceiver(node) {
|
|
|
251
251
|
function isVoidExpression(expression) {
|
|
252
252
|
return expression.type === distExports.AST_NODE_TYPES.UnaryExpression && expression.operator === "void";
|
|
253
253
|
}
|
|
254
|
-
const rule$
|
|
254
|
+
const rule$5 = {
|
|
255
255
|
defaultOptions: [{}],
|
|
256
256
|
meta: {
|
|
257
257
|
docs: { description: "Format TypeScript layout: single/multiline ternaries and union types, and blank lines between statements" },
|
|
@@ -401,6 +401,7 @@ const rule$4 = {
|
|
|
401
401
|
}
|
|
402
402
|
};
|
|
403
403
|
|
|
404
|
+
const teardownViMethods = /* @__PURE__ */ new Set(["restoreAllMocks", "unstubAllGlobals", "useRealTimers"]);
|
|
404
405
|
function compareTests(testA, testB) {
|
|
405
406
|
const functionA = getFunctionName(testA);
|
|
406
407
|
const functionB = getFunctionName(testB);
|
|
@@ -416,6 +417,40 @@ function compareTests(testA, testB) {
|
|
|
416
417
|
const specificNameB = getSpecificName(testB);
|
|
417
418
|
return specificNameA.localeCompare(specificNameB);
|
|
418
419
|
}
|
|
420
|
+
function expressionStartsWithIdentifier(node, identifier) {
|
|
421
|
+
if (node.type === distExports.AST_NODE_TYPES.Identifier && node.name === identifier) {
|
|
422
|
+
return true;
|
|
423
|
+
}
|
|
424
|
+
if (node.type === distExports.AST_NODE_TYPES.CallExpression) {
|
|
425
|
+
const { callee } = node;
|
|
426
|
+
if (callee.type === distExports.AST_NODE_TYPES.Identifier && callee.name === identifier) {
|
|
427
|
+
return true;
|
|
428
|
+
}
|
|
429
|
+
if (callee.type === distExports.AST_NODE_TYPES.MemberExpression) {
|
|
430
|
+
return expressionStartsWithIdentifier(callee.object, identifier);
|
|
431
|
+
}
|
|
432
|
+
if (callee.type === distExports.AST_NODE_TYPES.ChainExpression) {
|
|
433
|
+
return expressionStartsWithIdentifier(callee.expression, identifier);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
if (node.type === distExports.AST_NODE_TYPES.MemberExpression) {
|
|
437
|
+
return expressionStartsWithIdentifier(node.object, identifier);
|
|
438
|
+
}
|
|
439
|
+
if (node.type === distExports.AST_NODE_TYPES.ChainExpression) {
|
|
440
|
+
return expressionStartsWithIdentifier(node.expression, identifier);
|
|
441
|
+
}
|
|
442
|
+
return false;
|
|
443
|
+
}
|
|
444
|
+
function getExpressionFromStatement(statement) {
|
|
445
|
+
if (statement.type !== distExports.AST_NODE_TYPES.ExpressionStatement) {
|
|
446
|
+
return null;
|
|
447
|
+
}
|
|
448
|
+
let { expression } = statement;
|
|
449
|
+
if (expression.type === distExports.AST_NODE_TYPES.AwaitExpression) {
|
|
450
|
+
expression = expression.argument;
|
|
451
|
+
}
|
|
452
|
+
return expression;
|
|
453
|
+
}
|
|
419
454
|
function getFunctionName(testName) {
|
|
420
455
|
const parts = testName.split(".");
|
|
421
456
|
return parts.slice(0, 2).join(".");
|
|
@@ -429,6 +464,20 @@ function getSpecificName(testName) {
|
|
|
429
464
|
}
|
|
430
465
|
return parts.slice(specialIndex + 1).join(".");
|
|
431
466
|
}
|
|
467
|
+
function getTestCallbackBlockBody(node) {
|
|
468
|
+
const callback = node.arguments[1];
|
|
469
|
+
if (!callback) {
|
|
470
|
+
return null;
|
|
471
|
+
}
|
|
472
|
+
if (callback.type !== distExports.AST_NODE_TYPES.FunctionExpression && callback.type !== distExports.AST_NODE_TYPES.ArrowFunctionExpression) {
|
|
473
|
+
return null;
|
|
474
|
+
}
|
|
475
|
+
const { body } = callback;
|
|
476
|
+
if (body.type !== distExports.AST_NODE_TYPES.BlockStatement) {
|
|
477
|
+
return null;
|
|
478
|
+
}
|
|
479
|
+
return body;
|
|
480
|
+
}
|
|
432
481
|
function getTestName(node) {
|
|
433
482
|
const firstArgument = node.arguments[0];
|
|
434
483
|
if (firstArgument?.type === distExports.AST_NODE_TYPES.Literal && typeof firstArgument.value === "string") {
|
|
@@ -449,12 +498,78 @@ function getTestPriority(testName) {
|
|
|
449
498
|
return 1;
|
|
450
499
|
}
|
|
451
500
|
}
|
|
452
|
-
|
|
501
|
+
function hasAssertMethodCall(expression) {
|
|
502
|
+
if (expression.type !== distExports.AST_NODE_TYPES.CallExpression) {
|
|
503
|
+
return false;
|
|
504
|
+
}
|
|
505
|
+
const { callee } = expression;
|
|
506
|
+
if (callee.type === distExports.AST_NODE_TYPES.MemberExpression && callee.property.type === distExports.AST_NODE_TYPES.Identifier && callee.property.name.startsWith("assert")) {
|
|
507
|
+
if (callee.object.type === distExports.AST_NODE_TYPES.Identifier && callee.object.name === "expect") {
|
|
508
|
+
return false;
|
|
509
|
+
}
|
|
510
|
+
return true;
|
|
511
|
+
}
|
|
512
|
+
return false;
|
|
513
|
+
}
|
|
514
|
+
function isAssertionCountExpression(expression) {
|
|
515
|
+
if (expression.type !== distExports.AST_NODE_TYPES.CallExpression) {
|
|
516
|
+
return false;
|
|
517
|
+
}
|
|
518
|
+
const { callee } = expression;
|
|
519
|
+
if (callee.type !== distExports.AST_NODE_TYPES.MemberExpression || callee.object.type !== distExports.AST_NODE_TYPES.Identifier || callee.property.type !== distExports.AST_NODE_TYPES.Identifier) {
|
|
520
|
+
return false;
|
|
521
|
+
}
|
|
522
|
+
if (callee.object.name === "expect" && (callee.property.name === "assertions" || callee.property.name === "hasAssertions")) {
|
|
523
|
+
return true;
|
|
524
|
+
}
|
|
525
|
+
return callee.object.name === "assert" && callee.property.name === "plan";
|
|
526
|
+
}
|
|
527
|
+
function isAssertionCountStatement(statement) {
|
|
528
|
+
const expression = getExpressionFromStatement(statement);
|
|
529
|
+
if (!expression) {
|
|
530
|
+
return false;
|
|
531
|
+
}
|
|
532
|
+
return isAssertionCountExpression(expression);
|
|
533
|
+
}
|
|
534
|
+
function isAssertionExpression(expression) {
|
|
535
|
+
if (isAssertionCountExpression(expression)) {
|
|
536
|
+
return false;
|
|
537
|
+
}
|
|
538
|
+
if (expressionStartsWithIdentifier(expression, "assert") || expressionStartsWithIdentifier(expression, "expect")) {
|
|
539
|
+
return true;
|
|
540
|
+
}
|
|
541
|
+
return hasAssertMethodCall(expression);
|
|
542
|
+
}
|
|
543
|
+
function isAssertionStatement(statement) {
|
|
544
|
+
const expression = getExpressionFromStatement(statement);
|
|
545
|
+
if (!expression) {
|
|
546
|
+
return false;
|
|
547
|
+
}
|
|
548
|
+
return isAssertionExpression(expression);
|
|
549
|
+
}
|
|
550
|
+
function isTeardownStatement(statement) {
|
|
551
|
+
const expression = getExpressionFromStatement(statement);
|
|
552
|
+
if (!expression || expression.type !== distExports.AST_NODE_TYPES.CallExpression) {
|
|
553
|
+
return false;
|
|
554
|
+
}
|
|
555
|
+
const { callee } = expression;
|
|
556
|
+
if (callee.type === distExports.AST_NODE_TYPES.Identifier && callee.name === "cleanup") {
|
|
557
|
+
return true;
|
|
558
|
+
}
|
|
559
|
+
if (callee.type === distExports.AST_NODE_TYPES.MemberExpression && callee.object.type === distExports.AST_NODE_TYPES.Identifier && callee.object.name === "vi" && callee.property.type === distExports.AST_NODE_TYPES.Identifier && teardownViMethods.has(callee.property.name)) {
|
|
560
|
+
return true;
|
|
561
|
+
}
|
|
562
|
+
return false;
|
|
563
|
+
}
|
|
564
|
+
const rule$4 = {
|
|
453
565
|
defaultOptions: [],
|
|
454
566
|
meta: {
|
|
455
|
-
docs: { description: "Enforce sorted test functions
|
|
567
|
+
docs: { description: "Enforce sorted test functions and setup-before-assertions layout in test bodies" },
|
|
456
568
|
fixable: "code",
|
|
457
|
-
messages: {
|
|
569
|
+
messages: {
|
|
570
|
+
setupAfterAssertion: "Setup statements must appear before assertions in test bodies.",
|
|
571
|
+
sortError: "Test functions should be grouped by method with sorted metrics, errors, exceptions and middlewares."
|
|
572
|
+
},
|
|
458
573
|
schema: [],
|
|
459
574
|
type: "suggestion"
|
|
460
575
|
},
|
|
@@ -462,6 +577,25 @@ const rule$3 = {
|
|
|
462
577
|
if (!context.filename.endsWith(".spec.ts") && !context.filename.endsWith(".test.ts")) {
|
|
463
578
|
return {};
|
|
464
579
|
}
|
|
580
|
+
function handleTestBody(node) {
|
|
581
|
+
const callbackBody = getTestCallbackBlockBody(node);
|
|
582
|
+
if (!callbackBody) {
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
const firstAssertionIndex = callbackBody.body.findIndex(isAssertionStatement);
|
|
586
|
+
if (firstAssertionIndex === -1) {
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
for (const statement of callbackBody.body.slice(firstAssertionIndex + 1)) {
|
|
590
|
+
if (isAssertionStatement(statement) || isAssertionCountStatement(statement) || isTeardownStatement(statement)) {
|
|
591
|
+
continue;
|
|
592
|
+
}
|
|
593
|
+
context.report({
|
|
594
|
+
messageId: "setupAfterAssertion",
|
|
595
|
+
node: statement
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
}
|
|
465
599
|
function handleTestGroup(node) {
|
|
466
600
|
const testGroup = node.arguments[0];
|
|
467
601
|
if (!testGroup || !node.arguments[1]) {
|
|
@@ -510,6 +644,8 @@ const rule$3 = {
|
|
|
510
644
|
}
|
|
511
645
|
return {
|
|
512
646
|
'CallExpression[callee.name="describe"]': handleTestGroup,
|
|
647
|
+
'CallExpression[callee.name="it"]': handleTestBody,
|
|
648
|
+
'CallExpression[callee.name="test"]': handleTestBody,
|
|
513
649
|
'CallExpression[callee.object.name="describe"][callee.property.name="concurrent"]': handleTestGroup,
|
|
514
650
|
'CallExpression[callee.object.name="test"][callee.property.name="group"]': handleTestGroup
|
|
515
651
|
};
|
|
@@ -666,7 +802,7 @@ function checkUnusedStrings(context, parsed, source, content, contentOffset) {
|
|
|
666
802
|
}
|
|
667
803
|
}
|
|
668
804
|
}
|
|
669
|
-
const rule$
|
|
805
|
+
const rule$3 = {
|
|
670
806
|
defaultOptions: [{ locales: defaultLocales }],
|
|
671
807
|
meta: {
|
|
672
808
|
docs: { description: "Format Vue i18n blocks: enforce valid/consistent locales, sorted keys, and no unused strings" },
|
|
@@ -734,7 +870,7 @@ const rule$2 = {
|
|
|
734
870
|
};
|
|
735
871
|
|
|
736
872
|
const untypedEmitsRegex = /const\s+emit\s*=\s*defineEmits\(\[([^\]]+)\]\)/g;
|
|
737
|
-
const rule$
|
|
873
|
+
const rule$2 = {
|
|
738
874
|
defaultOptions: [],
|
|
739
875
|
meta: {
|
|
740
876
|
docs: { description: "Format Vue component scripts: enforce multiline computed properties and typed emits" },
|
|
@@ -802,6 +938,42 @@ ${typedEvents}
|
|
|
802
938
|
}
|
|
803
939
|
};
|
|
804
940
|
|
|
941
|
+
const styleOpenTagRegex = /<style(?:\s[^>]*)?>/gi;
|
|
942
|
+
const rule$1 = {
|
|
943
|
+
defaultOptions: [],
|
|
944
|
+
meta: {
|
|
945
|
+
docs: { description: "Disallow <style> blocks in Vue SFCs. Styling must be done with Tailwind utility classes as much as possible." },
|
|
946
|
+
messages: { noStyleBlock: "Avoid <style> blocks in Vue components. Use Tailwind utility classes instead." },
|
|
947
|
+
schema: [],
|
|
948
|
+
type: "problem"
|
|
949
|
+
},
|
|
950
|
+
create(context) {
|
|
951
|
+
if (!context.filename.endsWith(".vue")) {
|
|
952
|
+
return {};
|
|
953
|
+
}
|
|
954
|
+
return {
|
|
955
|
+
Program() {
|
|
956
|
+
const sourceCode = context.sourceCode;
|
|
957
|
+
const source = sourceCode.getText();
|
|
958
|
+
styleOpenTagRegex.lastIndex = 0;
|
|
959
|
+
let styleMatch = styleOpenTagRegex.exec(source);
|
|
960
|
+
while (styleMatch !== null) {
|
|
961
|
+
const matchIndex = styleMatch.index;
|
|
962
|
+
const matchEnd = matchIndex + styleMatch[0].length;
|
|
963
|
+
context.report({
|
|
964
|
+
loc: {
|
|
965
|
+
end: sourceCode.getLocFromIndex(matchEnd),
|
|
966
|
+
start: sourceCode.getLocFromIndex(matchIndex)
|
|
967
|
+
},
|
|
968
|
+
messageId: "noStyleBlock"
|
|
969
|
+
});
|
|
970
|
+
styleMatch = styleOpenTagRegex.exec(source);
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
};
|
|
974
|
+
}
|
|
975
|
+
};
|
|
976
|
+
|
|
805
977
|
const templateRegex = /<template>([\s\S]*)<\/template>/i;
|
|
806
978
|
const templateTagLength = "<template>".length;
|
|
807
979
|
const propsPrefixRegex = /\$?props\.(\w+)/g;
|
|
@@ -1079,10 +1251,11 @@ const rule = {
|
|
|
1079
1251
|
|
|
1080
1252
|
const index = {
|
|
1081
1253
|
rules: {
|
|
1082
|
-
"ts-format-layout": rule$
|
|
1083
|
-
"ts-format-tests": rule$
|
|
1084
|
-
"vue-format-i18n": rule$
|
|
1085
|
-
"vue-format-script": rule$
|
|
1254
|
+
"ts-format-layout": rule$5,
|
|
1255
|
+
"ts-format-tests": rule$4,
|
|
1256
|
+
"vue-format-i18n": rule$3,
|
|
1257
|
+
"vue-format-script": rule$2,
|
|
1258
|
+
"vue-format-style": rule$1,
|
|
1086
1259
|
"vue-format-template": rule
|
|
1087
1260
|
}
|
|
1088
1261
|
};
|