@saasmakers/eslint 0.1.34 → 0.1.36

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  import { AST_NODE_TYPES } from '@typescript-eslint/utils';
2
2
 
3
- const rule$e = {
3
+ const rule$c = {
4
4
  meta: {
5
5
  docs: {
6
6
  category: "Stylistic Issues",
@@ -63,7 +63,7 @@ const rule$e = {
63
63
  }
64
64
  };
65
65
 
66
- const rule$d = {
66
+ const rule$b = {
67
67
  meta: {
68
68
  docs: {
69
69
  category: "Stylistic Issues",
@@ -121,7 +121,12 @@ const rule$d = {
121
121
  reportAndFix(
122
122
  node,
123
123
  "singleLine",
124
- (fixer) => fixer.replaceText(node, unionText.replaceAll(/\s+\|\s+/g, " | "))
124
+ (fixer) => {
125
+ let singleLineText = unionText.replaceAll(/[ \t\n]+/g, " ");
126
+ singleLineText = singleLineText.replaceAll(" |", "|").replaceAll("|", " |");
127
+ singleLineText = singleLineText.replaceAll(" ", " ");
128
+ return fixer.replaceText(node, singleLineText);
129
+ }
125
130
  );
126
131
  }
127
132
  }
@@ -175,7 +180,7 @@ function getTestPriority(testName) {
175
180
  return 1;
176
181
  }
177
182
  }
178
- const rule$c = {
183
+ const rule$a = {
179
184
  meta: {
180
185
  docs: {
181
186
  category: "Best Practices",
@@ -245,6 +250,77 @@ const rule$c = {
245
250
  }
246
251
  };
247
252
 
253
+ function checkInvalidLocales(context, parsed, locales, startOffset, i18nContent) {
254
+ for (const locale of Object.keys(parsed)) {
255
+ if (!locales.includes(locale)) {
256
+ const escapedLocale = locale.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`);
257
+ const localeMatch = new RegExp(String.raw`"${escapedLocale}"\s*:`, "g").exec(i18nContent);
258
+ if (localeMatch) {
259
+ const localeOffset = startOffset + localeMatch.index;
260
+ context.report({
261
+ data: {
262
+ allowed: locales.join(", "),
263
+ locale
264
+ },
265
+ loc: {
266
+ end: context.sourceCode.getLocFromIndex(localeOffset + locale.length + 2),
267
+ start: context.sourceCode.getLocFromIndex(localeOffset)
268
+ },
269
+ messageId: "invalidLocale"
270
+ });
271
+ }
272
+ }
273
+ }
274
+ }
275
+ function checkMissingLocales(context, parsed, locales, startOffset, i18nContent) {
276
+ for (const locale of locales) {
277
+ if (!parsed[locale]) {
278
+ context.report({
279
+ data: { locale },
280
+ loc: {
281
+ end: context.sourceCode.getLocFromIndex(startOffset + i18nContent.length),
282
+ start: context.sourceCode.getLocFromIndex(startOffset)
283
+ },
284
+ messageId: "missingLocale"
285
+ });
286
+ }
287
+ }
288
+ }
289
+ function checkMissingTranslations(context, parsed, locales, startOffset, i18nContent) {
290
+ const allKeys = /* @__PURE__ */ new Set();
291
+ for (const locale of locales) {
292
+ if (parsed[locale]) {
293
+ const keys = getAllKeys$1(parsed[locale]);
294
+ for (const key of keys) allKeys.add(key);
295
+ }
296
+ }
297
+ for (const locale of locales) {
298
+ if (!parsed[locale]) {
299
+ continue;
300
+ }
301
+ const localeKeys = getAllKeys$1(parsed[locale]);
302
+ const missingKeys = [...allKeys].filter((key) => !localeKeys.includes(key));
303
+ if (missingKeys.length === 0) {
304
+ continue;
305
+ }
306
+ const escapedLocale = locale.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`);
307
+ const localeMatch = new RegExp(String.raw`"${escapedLocale}"\s*:\s*\{`, "g").exec(i18nContent);
308
+ if (localeMatch) {
309
+ const localeOffset = startOffset + localeMatch.index;
310
+ context.report({
311
+ data: {
312
+ locale,
313
+ missing: missingKeys.join(", ")
314
+ },
315
+ loc: {
316
+ end: context.sourceCode.getLocFromIndex(localeOffset + locale.length + 2),
317
+ start: context.sourceCode.getLocFromIndex(localeOffset)
318
+ },
319
+ messageId: "missingTranslations"
320
+ });
321
+ }
322
+ }
323
+ }
248
324
  function getAllKeys$1(object, prefix = "") {
249
325
  let keys = [];
250
326
  for (const key in object) {
@@ -257,7 +333,7 @@ function getAllKeys$1(object, prefix = "") {
257
333
  }
258
334
  return keys;
259
335
  }
260
- const rule$b = {
336
+ const rule$9 = {
261
337
  meta: {
262
338
  docs: {
263
339
  category: "Possible Errors",
@@ -292,91 +368,36 @@ const rule$b = {
292
368
  return {
293
369
  Program() {
294
370
  const source = context.sourceCode.getText();
295
- const i18nMatch = source.match(/(<i18n\s+lang=["']json["']>)([\s\S]*?)(<\/i18n>)/i);
296
- if (i18nMatch && i18nMatch.index !== void 0) {
297
- const startOffset = i18nMatch.index + i18nMatch[1].length;
298
- const i18nContent = i18nMatch[2].trim();
299
- try {
300
- const parsed = JSON.parse(i18nContent);
301
- for (const locale of locales) {
302
- if (!parsed[locale]) {
303
- context.report({
304
- data: { locale },
305
- loc: {
306
- end: context.sourceCode.getLocFromIndex(startOffset + i18nContent.length),
307
- start: context.sourceCode.getLocFromIndex(startOffset)
308
- },
309
- messageId: "missingLocale"
310
- });
311
- }
312
- }
313
- for (const locale of Object.keys(parsed)) {
314
- if (!locales.includes(locale)) {
315
- const localeMatch = new RegExp(String.raw`"${locale}"\s*:`, "g").exec(i18nContent);
316
- if (localeMatch) {
317
- const localeOffset = startOffset + localeMatch.index;
318
- context.report({
319
- data: {
320
- allowed: locales.join(", "),
321
- locale
322
- },
323
- loc: {
324
- end: context.sourceCode.getLocFromIndex(localeOffset + locale.length + 2),
325
- start: context.sourceCode.getLocFromIndex(localeOffset)
326
- },
327
- messageId: "invalidLocale"
328
- });
329
- }
330
- }
331
- }
332
- const allKeys = /* @__PURE__ */ new Set();
333
- for (const locale of locales) {
334
- if (parsed[locale]) {
335
- const keys = getAllKeys$1(parsed[locale]);
336
- for (const key of keys) allKeys.add(key);
337
- }
338
- }
339
- for (const locale of locales) {
340
- if (parsed[locale]) {
341
- const localeKeys = getAllKeys$1(parsed[locale]);
342
- const missingKeys = [...allKeys].filter((key) => !localeKeys.includes(key));
343
- if (missingKeys.length > 0) {
344
- const localeMatch = new RegExp(String.raw`"${locale}"\s*:\s*{`, "g").exec(i18nContent);
345
- if (localeMatch) {
346
- const localeOffset = startOffset + localeMatch.index;
347
- context.report({
348
- data: {
349
- locale,
350
- missing: missingKeys.join(", ")
351
- },
352
- loc: {
353
- end: context.sourceCode.getLocFromIndex(localeOffset + locale.length + 2),
354
- start: context.sourceCode.getLocFromIndex(localeOffset)
355
- },
356
- messageId: "missingTranslations"
357
- });
358
- }
359
- }
360
- }
361
- }
362
- } catch (error) {
363
- const errorMessage = error instanceof Error ? error.message : String(error);
364
- context.report({
365
- data: { error: errorMessage },
366
- loc: {
367
- end: context.sourceCode.getLocFromIndex(startOffset + i18nContent.length),
368
- start: context.sourceCode.getLocFromIndex(startOffset)
369
- },
370
- messageId: "invalidJson"
371
- });
372
- }
371
+ const i18nRegex = /<i18n\s+lang=["']json["']>([\s\S]*?)<\/i18n>/i;
372
+ const i18nMatch = i18nRegex.exec(source);
373
+ if (!i18nMatch) {
374
+ return;
375
+ }
376
+ const tagLength = source.indexOf(">", i18nMatch.index) + 1 - i18nMatch.index;
377
+ const startOffset = i18nMatch.index + tagLength;
378
+ const i18nContent = i18nMatch[1].trim();
379
+ try {
380
+ const parsed = JSON.parse(i18nContent);
381
+ checkMissingLocales(context, parsed, locales, startOffset, i18nContent);
382
+ checkInvalidLocales(context, parsed, locales, startOffset, i18nContent);
383
+ checkMissingTranslations(context, parsed, locales, startOffset, i18nContent);
384
+ } catch (error) {
385
+ const errorMessage = error instanceof Error ? error.message : String(error);
386
+ context.report({
387
+ data: { error: errorMessage },
388
+ loc: {
389
+ end: context.sourceCode.getLocFromIndex(startOffset + i18nContent.length),
390
+ start: context.sourceCode.getLocFromIndex(startOffset)
391
+ },
392
+ messageId: "invalidJson"
393
+ });
373
394
  }
374
395
  }
375
396
  };
376
397
  }
377
398
  };
378
399
 
379
- const rule$a = {
400
+ const rule$8 = {
380
401
  meta: {
381
402
  docs: {
382
403
  category: "Best Practices",
@@ -396,8 +417,9 @@ const rule$a = {
396
417
  Program() {
397
418
  const sourceCode = context.sourceCode;
398
419
  const source = sourceCode.getText();
399
- const templateMatch = source.match(/<template>([\s\S]*)<\/template>/i);
400
- if (!templateMatch || templateMatch.index === void 0) {
420
+ const templateRegex = /<template>([\s\S]*)<\/template>/i;
421
+ const templateMatch = templateRegex.exec(source);
422
+ if (!templateMatch) {
401
423
  return;
402
424
  }
403
425
  const templateContent = templateMatch[1];
@@ -451,7 +473,7 @@ function sortObjectKeys(object) {
451
473
  return object.map((item) => sortObjectKeys(item));
452
474
  }
453
475
  if (object && typeof object === "object") {
454
- const sortedKeys = Object.keys(object).toSorted();
476
+ const sortedKeys = Object.keys(object).toSorted((key1, key2) => key1.localeCompare(key2));
455
477
  const result = {};
456
478
  const obj = object;
457
479
  for (const key of sortedKeys) {
@@ -461,7 +483,7 @@ function sortObjectKeys(object) {
461
483
  }
462
484
  return object;
463
485
  }
464
- const rule$9 = {
486
+ const rule$7 = {
465
487
  meta: {
466
488
  docs: {
467
489
  category: "Best Practices",
@@ -484,8 +506,9 @@ const rule$9 = {
484
506
  return {
485
507
  Program() {
486
508
  const source = context.sourceCode.getText();
487
- const i18nMatch = source.match(/(<i18n\s+lang=["']json["']>)([\s\S]*?)(<\/i18n>)/i);
488
- if (i18nMatch && i18nMatch.index !== void 0) {
509
+ const i18nRegex = /(<i18n\s+lang=["']json["']>)([\s\S]*?)(<\/i18n>)/i;
510
+ const i18nMatch = i18nRegex.exec(source);
511
+ if (i18nMatch) {
489
512
  const startOffset = i18nMatch.index + i18nMatch[1].length;
490
513
  const i18nContent = i18nMatch[2];
491
514
  try {
@@ -542,7 +565,7 @@ function getAllKeys(object, prefix = "") {
542
565
  }
543
566
  return keys;
544
567
  }
545
- const rule$8 = {
568
+ const rule$6 = {
546
569
  meta: {
547
570
  docs: {
548
571
  category: "Best Practices",
@@ -563,8 +586,9 @@ const rule$8 = {
563
586
  return {
564
587
  Program() {
565
588
  const source = context.sourceCode.getText();
566
- const i18nMatch = source.match(/(<i18n\s+lang=["']json["']>)([\s\S]*?)(<\/i18n>)/i);
567
- if (!i18nMatch || i18nMatch.index === void 0) {
589
+ const i18nRegex = /(<i18n\s+lang=["']json["']>)([\s\S]*?)(<\/i18n>)/i;
590
+ const i18nMatch = i18nRegex.exec(source);
591
+ if (!i18nMatch) {
568
592
  return;
569
593
  }
570
594
  const startOffset = i18nMatch.index + i18nMatch[1].length;
@@ -574,9 +598,11 @@ const rule$8 = {
574
598
  if (!parsed.en) {
575
599
  return;
576
600
  }
577
- const templateMatch = source.match(/<template>([\s\S]*)<\/template>/i);
601
+ const templateRegex = /<template>([\s\S]*)<\/template>/i;
602
+ const templateMatch = templateRegex.exec(source);
578
603
  const templateContent = templateMatch ? templateMatch[1] : "";
579
- const scriptMatch = source.match(/<script[^>]*>([\s\S]*?)<\/script>/i);
604
+ const scriptRegex = /<script[^>]*>([\s\S]*?)<\/script>/i;
605
+ const scriptMatch = scriptRegex.exec(source);
580
606
  const scriptContent = scriptMatch ? scriptMatch[1] : "";
581
607
  const enKeys = getAllKeys(parsed.en);
582
608
  for (const key of enKeys) {
@@ -612,7 +638,7 @@ const rule$8 = {
612
638
  }
613
639
  };
614
640
 
615
- const rule$7 = {
641
+ const rule$5 = {
616
642
  defaultOptions: [],
617
643
  meta: {
618
644
  docs: { description: "Enforce multiline style for Vue computed properties" },
@@ -651,7 +677,7 @@ const rule$7 = {
651
677
  }
652
678
  };
653
679
 
654
- const rule$6 = {
680
+ const rule$4 = {
655
681
  meta: {
656
682
  docs: {
657
683
  category: "Best Practices",
@@ -701,165 +727,7 @@ ${typedEvents}
701
727
  }
702
728
  };
703
729
 
704
- const rule$5 = {
705
- meta: {
706
- docs: {
707
- category: "Best Practices",
708
- description: "Prevent comments, empty lines, redundant required: false, enforce default: undefined for single-key props, and detect unused props inside defineProps",
709
- recommended: true
710
- },
711
- fixable: "code",
712
- messages: {
713
- noCommentsInProps: "Comments are not allowed inside defineProps.",
714
- noEmptyLinesInProps: "Empty lines are not allowed between props in defineProps.",
715
- noRedundantRequired: "required: false is redundant in props. Props are optional by default.",
716
- singleKeyProp: "Props with only one key should have default: undefined for better readability.",
717
- unusedProp: 'Unused prop: "{{propName}}"'
718
- },
719
- schema: [],
720
- type: "problem"
721
- },
722
- create(context) {
723
- if (!context.filename.endsWith(".vue")) {
724
- return {};
725
- }
726
- return {
727
- CallExpression(node) {
728
- if (node.callee.type !== "Identifier" || node.callee.name !== "defineProps") {
729
- return;
730
- }
731
- const sourceCode = context.sourceCode;
732
- const propsArg = node.arguments[0];
733
- if (!propsArg?.range) {
734
- return;
735
- }
736
- const propsArgRange = propsArg.range;
737
- const commentsInProps = [
738
- ...sourceCode.getCommentsBefore(propsArg),
739
- ...sourceCode.getCommentsInside(propsArg)
740
- ].filter((comment) => {
741
- return comment.range !== void 0 && comment.range[0] >= propsArgRange[0] && comment.range[1] <= propsArgRange[1];
742
- });
743
- for (const comment of commentsInProps) {
744
- context.report({
745
- fix: (fixer) => {
746
- return fixer.removeRange(comment.range);
747
- },
748
- loc: comment.loc ?? node.loc ?? {
749
- end: {
750
- column: 0,
751
- line: 0
752
- },
753
- start: {
754
- column: 0,
755
- line: 0
756
- }
757
- },
758
- messageId: "noCommentsInProps"
759
- });
760
- }
761
- const propsText = sourceCode.getText(propsArg);
762
- const emptyLineRegex = /(?:{\s*\n\s*\n|,\s*\n\s*\n)\s*(?:([a-zA-Z])|(?:\s*}))/g;
763
- let emptyLineMatch = emptyLineRegex.exec(propsText);
764
- while (emptyLineMatch !== null) {
765
- const matchIndex = emptyLineMatch.index;
766
- const matchLength = emptyLineMatch[0].length;
767
- const lastChar = emptyLineMatch[0].trim().charAt(0);
768
- const isEndBrace = emptyLineMatch[0].trim().endsWith("}");
769
- const firstLetter = emptyLineMatch[1];
770
- const startIndex = propsArg.range[0] + matchIndex;
771
- const endIndex = startIndex + matchLength;
772
- context.report({
773
- fix: (fixer) => {
774
- const replacement = isEndBrace ? "\n}" : (lastChar === "{" ? "{\n " : ",\n ") + firstLetter;
775
- return fixer.replaceTextRange([startIndex, endIndex], replacement);
776
- },
777
- loc: {
778
- end: sourceCode.getLocFromIndex(endIndex),
779
- start: sourceCode.getLocFromIndex(startIndex)
780
- },
781
- messageId: "noEmptyLinesInProps"
782
- });
783
- emptyLineMatch = emptyLineRegex.exec(propsText);
784
- }
785
- const redundantRequiredRegex = /required:\s*false\s*,?/g;
786
- let redundantMatch = redundantRequiredRegex.exec(propsText);
787
- while (redundantMatch !== null) {
788
- const matchIndex = redundantMatch.index;
789
- const matchLength = redundantMatch[0].length;
790
- const startIndex = propsArg.range[0] + matchIndex;
791
- const endIndex = startIndex + matchLength;
792
- context.report({
793
- fix: (fixer) => {
794
- return fixer.removeRange([startIndex, endIndex]);
795
- },
796
- loc: {
797
- end: sourceCode.getLocFromIndex(endIndex),
798
- start: sourceCode.getLocFromIndex(startIndex)
799
- },
800
- messageId: "noRedundantRequired"
801
- });
802
- redundantMatch = redundantRequiredRegex.exec(propsText);
803
- }
804
- const source = sourceCode.getText();
805
- const templateMatch = source.match(/<template>([\s\S]*)<\/template>/i);
806
- const templateContent = templateMatch ? templateMatch[1] : "";
807
- const scriptMatch = source.match(/<script[^>]*>([\s\S]*?)<\/script>/i);
808
- const scriptContent = scriptMatch ? scriptMatch[1] : "";
809
- const propDefinitions = propsText.match(/(\w+):\s*{([^}]+)}/g) ?? [];
810
- for (const propDef of propDefinitions) {
811
- const propNameMatch = propDef.match(/^(\w+):\s*{([^}]+)}/);
812
- if (!propNameMatch) {
813
- continue;
814
- }
815
- const propName = propNameMatch[1];
816
- const propContent = propNameMatch[2].trim();
817
- const hasDefault = propContent.includes("default:");
818
- const hasRequired = propContent.includes("required:");
819
- if (!hasDefault && !hasRequired && propContent.includes("type:")) {
820
- const fullPropRegex = new RegExp(String.raw`${propName}:\s*{[^}]+}`, "g");
821
- const fullMatch = propsText.match(fullPropRegex);
822
- if (!fullMatch) {
823
- continue;
824
- }
825
- const fullPropDef = fullMatch[0];
826
- const matchIndex = propsText.indexOf(fullPropDef);
827
- const matchLength = fullPropDef.length;
828
- const startIndex = propsArg.range[0] + matchIndex;
829
- const endIndex = startIndex + matchLength;
830
- context.report({
831
- fix: (fixer) => {
832
- const newText = fullPropDef.replace(/{\s*type:/, "{\n default: undefined,\n type:").replace(/,\s*\n\s*}/, "}");
833
- return fixer.replaceTextRange([startIndex, endIndex], newText);
834
- },
835
- loc: {
836
- end: sourceCode.getLocFromIndex(endIndex),
837
- start: sourceCode.getLocFromIndex(startIndex)
838
- },
839
- messageId: "singleKeyProp"
840
- });
841
- }
842
- const isUsedInTemplate = templateContent.includes(propName);
843
- const isUsedInScript = scriptContent.replace(propsText, "").includes(propName);
844
- if (!isUsedInTemplate && !isUsedInScript) {
845
- const propStartIndex = propsArg.range[0] + propsText.indexOf(propDef);
846
- const propEndIndex = propStartIndex + propDef.length;
847
- context.report({
848
- data: { propName },
849
- loc: {
850
- end: sourceCode.getLocFromIndex(propEndIndex),
851
- start: sourceCode.getLocFromIndex(propStartIndex)
852
- },
853
- messageId: "unusedProp"
854
- });
855
- }
856
- }
857
- }
858
- };
859
- }
860
- };
861
-
862
- const rule$4 = {
730
+ const rule$3 = {
863
731
  meta: {
864
732
  docs: {
865
733
  category: "Best Practices",
@@ -884,64 +752,6 @@ const rule$4 = {
884
752
  }
885
753
  };
886
754
 
887
- const rule$3 = {
888
- meta: {
889
- docs: {
890
- category: "Best Practices",
891
- description: 'Prevent empty lines inside :class="{ bindings in Vue template tags',
892
- recommended: true
893
- },
894
- fixable: "code",
895
- messages: { noEmptyLinesInClass: 'Empty lines are not allowed inside :class="{ bindings.' },
896
- schema: [],
897
- type: "problem"
898
- },
899
- create(context) {
900
- if (!context.filename.endsWith(".vue")) {
901
- return {};
902
- }
903
- return {
904
- Program() {
905
- const sourceCode = context.sourceCode;
906
- const source = sourceCode.getText();
907
- const templateMatch = source.match(/<template>([\s\S]*)<\/template>/i);
908
- if (!templateMatch) {
909
- return;
910
- }
911
- const templateContent = templateMatch[1];
912
- const classBindingRegex = /:class="\{([\s\S]*?)\}"/g;
913
- let classBindingMatch;
914
- while ((classBindingMatch = classBindingRegex.exec(templateContent)) !== null) {
915
- const classContent = classBindingMatch[1];
916
- const emptyLineRegex = /\n\s*\n/g;
917
- let emptyLineMatch;
918
- while ((emptyLineMatch = emptyLineRegex.exec(classContent)) !== null) {
919
- const matchIndex = emptyLineMatch.index;
920
- const matchLength = emptyLineMatch[0].length;
921
- const templateStartIndex = source.indexOf(templateContent);
922
- const classBindingStartIndex = templateStartIndex + classBindingMatch.index;
923
- const classContentStartIndex = classBindingStartIndex + 8;
924
- const startIndex = classContentStartIndex + matchIndex;
925
- const endIndex = startIndex + matchLength;
926
- context.report({
927
- // TODO: Uncomment this when we want to fix the issue
928
- // fix: (fixer) => {
929
- // // Replace consecutive newlines with a single newline
930
- // return fixer.replaceTextRange([startIndex, endIndex], '\n')
931
- // },
932
- loc: {
933
- end: sourceCode.getLocFromIndex(endIndex),
934
- start: sourceCode.getLocFromIndex(startIndex)
935
- },
936
- messageId: "noEmptyLinesInClass"
937
- });
938
- }
939
- }
940
- }
941
- };
942
- }
943
- };
944
-
945
755
  const rule$2 = {
946
756
  meta: {
947
757
  docs: {
@@ -965,8 +775,9 @@ const rule$2 = {
965
775
  }
966
776
  const sourceCode = context.sourceCode;
967
777
  const source = sourceCode.getText();
968
- const templateMatch = source.match(/<template>([\s\S]*)<\/template>/i);
969
- if (!templateMatch || templateMatch.index === void 0) {
778
+ const templateRegex = /<template>([\s\S]*)<\/template>/i;
779
+ const templateMatch = templateRegex.exec(source);
780
+ if (!templateMatch) {
970
781
  return;
971
782
  }
972
783
  const templateContent = templateMatch[1];
@@ -1016,8 +827,9 @@ const rule$1 = {
1016
827
  Program() {
1017
828
  const sourceCode = context.sourceCode;
1018
829
  const source = sourceCode.getText();
1019
- const templateMatch = source.match(/<template>([\s\S]*)<\/template>/i);
1020
- if (!templateMatch || templateMatch.index === void 0) {
830
+ const templateRegex = /<template>([\s\S]*)<\/template>/i;
831
+ const templateMatch = templateRegex.exec(source);
832
+ if (!templateMatch) {
1021
833
  return;
1022
834
  }
1023
835
  const templateContent = templateMatch[1];
@@ -1093,8 +905,9 @@ const rule = {
1093
905
  Program() {
1094
906
  const sourceCode = context.sourceCode;
1095
907
  const source = sourceCode.getText();
1096
- const templateMatch = source.match(/<template>([\s\S]*)<\/template>/i);
1097
- if (!templateMatch || templateMatch.index === void 0) {
908
+ const templateRegex = /<template>([\s\S]*)<\/template>/i;
909
+ const templateMatch = templateRegex.exec(source);
910
+ if (!templateMatch) {
1098
911
  return;
1099
912
  }
1100
913
  const templateContent = templateMatch[1];
@@ -1132,18 +945,16 @@ const rule = {
1132
945
 
1133
946
  const saasmakers = {
1134
947
  rules: {
1135
- "ts-multiline-ternary": rule$e,
1136
- "ts-multiline-union": rule$d,
1137
- "ts-sort-tests": rule$c,
1138
- "vue-i18n-consistent-locales": rule$b,
1139
- "vue-i18n-consistent-t": rule$a,
1140
- "vue-i18n-sort-keys": rule$9,
1141
- "vue-i18n-unused-strings": rule$8,
1142
- "vue-script-format-computed": rule$7,
1143
- "vue-script-format-emits": rule$6,
1144
- "vue-script-format-props": rule$5,
1145
- "vue-script-order": rule$4,
1146
- "vue-template-format-classes": rule$3,
948
+ "ts-multiline-ternary": rule$c,
949
+ "ts-multiline-union": rule$b,
950
+ "ts-sort-tests": rule$a,
951
+ "vue-i18n-consistent-locales": rule$9,
952
+ "vue-i18n-consistent-t": rule$8,
953
+ "vue-i18n-sort-keys": rule$7,
954
+ "vue-i18n-unused-strings": rule$6,
955
+ "vue-script-format-computed": rule$5,
956
+ "vue-script-format-emits": rule$4,
957
+ "vue-script-order": rule$3,
1147
958
  "vue-template-format-props": rule$2,
1148
959
  "vue-template-remove-comments": rule$1,
1149
960
  "vue-template-remove-true-attributes": rule
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saasmakers/eslint",
3
- "version": "0.1.34",
3
+ "version": "0.1.36",
4
4
  "private": false,
5
5
  "description": "Shared ESLint config and rules for SaaS Makers projects",
6
6
  "repository": {
@@ -37,11 +37,14 @@
37
37
  "@typescript-eslint/utils": "8.51.0",
38
38
  "@unocss/eslint-config": "66.5.12",
39
39
  "eslint-merge-processors": "2.0.0",
40
+ "eslint-plugin-jsonc": "2.21.0",
40
41
  "eslint-plugin-n": "17.23.1",
41
42
  "eslint-plugin-no-only-tests": "3.3.0",
43
+ "eslint-plugin-no-secrets": "2.2.1",
42
44
  "eslint-plugin-package-json": "0.87.0",
43
45
  "eslint-plugin-perfectionist": "5.1.0",
44
46
  "eslint-plugin-pnpm": "1.4.3",
47
+ "eslint-plugin-sonarjs": "3.0.5",
45
48
  "eslint-plugin-sort-class-members": "1.21.0",
46
49
  "eslint-plugin-storybook": "9.1.16",
47
50
  "eslint-plugin-turbo": "2.7.2",
@@ -50,8 +53,9 @@
50
53
  "eslint-plugin-vue": "10.6.2",
51
54
  "eslint-plugin-vuejs-accessibility": "2.4.1",
52
55
  "eslint-processor-vue-blocks": "2.0.0",
56
+ "jsonc-eslint-parser": "2.4.2",
53
57
  "typescript-eslint": "8.51.0",
54
- "@saasmakers/config": "0.1.25"
58
+ "@saasmakers/config": "0.1.26"
55
59
  },
56
60
  "devDependencies": {
57
61
  "@eslint/config-inspector": "1.4.2",