@saasmakers/eslint 1.0.27 → 1.0.29

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.
@@ -9,6 +9,7 @@ const index$1 = require('./shared/eslint.BqRQ4tAN.cjs');
9
9
  const path = require('node:path');
10
10
  const fs = require('node:fs');
11
11
  const node_module = require('node:module');
12
+ const playwright = require('eslint-plugin-playwright');
12
13
  const turbo = require('eslint-plugin-turbo');
13
14
  const zod = require('eslint-plugin-zod');
14
15
  require('eslint');
@@ -35,6 +36,7 @@ const vitest__default = /*#__PURE__*/_interopDefaultCompat(vitest);
35
36
  const packageJson__default = /*#__PURE__*/_interopDefaultCompat(packageJson);
36
37
  const path__namespace = /*#__PURE__*/_interopNamespaceCompat(path);
37
38
  const fs__namespace = /*#__PURE__*/_interopNamespaceCompat(fs);
39
+ const playwright__default = /*#__PURE__*/_interopDefaultCompat(playwright);
38
40
  const turbo__default = /*#__PURE__*/_interopDefaultCompat(turbo);
39
41
  const zod__default = /*#__PURE__*/_interopDefaultCompat(zod);
40
42
 
@@ -10872,6 +10874,7 @@ const eslint_config = antfu__default(
10872
10874
  "saasmakers/ts-format-tests": "error",
10873
10875
  "saasmakers/vue-format-i18n": ["error", { locales: shared.localeCodes }],
10874
10876
  "saasmakers/vue-format-script": "error",
10877
+ "saasmakers/vue-format-style": "error",
10875
10878
  "saasmakers/vue-format-template": "error"
10876
10879
  }
10877
10880
  },
@@ -10911,6 +10914,11 @@ const eslint_config = antfu__default(
10911
10914
  "vitest/prefer-describe-function-title": "off",
10912
10915
  "vitest/prefer-expect-assertions": "off"
10913
10916
  }
10917
+ },
10918
+ // Playwright
10919
+ {
10920
+ files: ["**/test/e2e/**/*.{ts,tsx}"],
10921
+ ...playwright__default.configs["flat/recommended"]
10914
10922
  }
10915
10923
  );
10916
10924
 
@@ -4,6 +4,7 @@ import { localeCodes } from '@saasmakers/shared';
4
4
  import vitest from '@vitest/eslint-plugin';
5
5
  import packageJson from 'eslint-plugin-package-json';
6
6
  import { Linter, ESLint } from 'eslint';
7
+ import playwright from 'eslint-plugin-playwright';
7
8
  import turbo from 'eslint-plugin-turbo';
8
9
  import zod from 'eslint-plugin-zod';
9
10
 
@@ -152,6 +153,7 @@ var eslint_config = antfu(
152
153
  "saasmakers/ts-format-tests": "error",
153
154
  "saasmakers/vue-format-i18n": ["error", { locales: localeCodes }],
154
155
  "saasmakers/vue-format-script": "error",
156
+ "saasmakers/vue-format-style": "error",
155
157
  "saasmakers/vue-format-template": "error"
156
158
  }
157
159
  },
@@ -191,6 +193,11 @@ var eslint_config = antfu(
191
193
  "vitest/prefer-describe-function-title": "off",
192
194
  "vitest/prefer-expect-assertions": "off"
193
195
  }
196
+ },
197
+ // Playwright
198
+ {
199
+ files: ["**/test/e2e/**/*.{ts,tsx}"],
200
+ ...playwright.configs["flat/recommended"]
194
201
  }
195
202
  );
196
203
 
@@ -4,6 +4,7 @@ import { localeCodes } from '@saasmakers/shared';
4
4
  import vitest from '@vitest/eslint-plugin';
5
5
  import packageJson from 'eslint-plugin-package-json';
6
6
  import { Linter, ESLint } from 'eslint';
7
+ import playwright from 'eslint-plugin-playwright';
7
8
  import turbo from 'eslint-plugin-turbo';
8
9
  import zod from 'eslint-plugin-zod';
9
10
 
@@ -152,6 +153,7 @@ var eslint_config = antfu(
152
153
  "saasmakers/ts-format-tests": "error",
153
154
  "saasmakers/vue-format-i18n": ["error", { locales: localeCodes }],
154
155
  "saasmakers/vue-format-script": "error",
156
+ "saasmakers/vue-format-style": "error",
155
157
  "saasmakers/vue-format-template": "error"
156
158
  }
157
159
  },
@@ -191,6 +193,11 @@ var eslint_config = antfu(
191
193
  "vitest/prefer-describe-function-title": "off",
192
194
  "vitest/prefer-expect-assertions": "off"
193
195
  }
196
+ },
197
+ // Playwright
198
+ {
199
+ files: ["**/test/e2e/**/*.{ts,tsx}"],
200
+ ...playwright.configs["flat/recommended"]
194
201
  }
195
202
  );
196
203
 
@@ -4,6 +4,7 @@ import { localeCodes } from '@saasmakers/shared';
4
4
  import vitest from '@vitest/eslint-plugin';
5
5
  import packageJson from 'eslint-plugin-package-json';
6
6
  import { Linter, ESLint } from 'eslint';
7
+ import playwright from 'eslint-plugin-playwright';
7
8
  import turbo from 'eslint-plugin-turbo';
8
9
  import zod from 'eslint-plugin-zod';
9
10
 
@@ -152,6 +153,7 @@ var eslint_config = antfu(
152
153
  "saasmakers/ts-format-tests": "error",
153
154
  "saasmakers/vue-format-i18n": ["error", { locales: localeCodes }],
154
155
  "saasmakers/vue-format-script": "error",
156
+ "saasmakers/vue-format-style": "error",
155
157
  "saasmakers/vue-format-template": "error"
156
158
  }
157
159
  },
@@ -191,6 +193,11 @@ var eslint_config = antfu(
191
193
  "vitest/prefer-describe-function-title": "off",
192
194
  "vitest/prefer-expect-assertions": "off"
193
195
  }
196
+ },
197
+ // Playwright
198
+ {
199
+ files: ["**/test/e2e/**/*.{ts,tsx}"],
200
+ ...playwright.configs["flat/recommended"]
194
201
  }
195
202
  );
196
203
 
@@ -7,6 +7,7 @@ import { d as distExports } from './shared/eslint.DOaqyhfZ.mjs';
7
7
  import * as path from 'node:path';
8
8
  import * as fs from 'node:fs';
9
9
  import { createRequire, builtinModules } from 'node:module';
10
+ import playwright from 'eslint-plugin-playwright';
10
11
  import turbo from 'eslint-plugin-turbo';
11
12
  import zod from 'eslint-plugin-zod';
12
13
  import 'eslint';
@@ -10846,6 +10847,7 @@ const eslint_config = antfu(
10846
10847
  "saasmakers/ts-format-tests": "error",
10847
10848
  "saasmakers/vue-format-i18n": ["error", { locales: localeCodes }],
10848
10849
  "saasmakers/vue-format-script": "error",
10850
+ "saasmakers/vue-format-style": "error",
10849
10851
  "saasmakers/vue-format-template": "error"
10850
10852
  }
10851
10853
  },
@@ -10885,6 +10887,11 @@ const eslint_config = antfu(
10885
10887
  "vitest/prefer-describe-function-title": "off",
10886
10888
  "vitest/prefer-expect-assertions": "off"
10887
10889
  }
10890
+ },
10891
+ // Playwright
10892
+ {
10893
+ files: ["**/test/e2e/**/*.{ts,tsx}"],
10894
+ ...playwright.configs["flat/recommended"]
10888
10895
  }
10889
10896
  );
10890
10897
 
package/dist/index.cjs CHANGED
@@ -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$4 = {
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" },
@@ -563,7 +563,7 @@ function isTeardownStatement(statement) {
563
563
  }
564
564
  return false;
565
565
  }
566
- const rule$3 = {
566
+ const rule$4 = {
567
567
  defaultOptions: [],
568
568
  meta: {
569
569
  docs: { description: "Enforce sorted test functions and setup-before-assertions layout in test bodies" },
@@ -804,7 +804,7 @@ function checkUnusedStrings(context, parsed, source, content, contentOffset) {
804
804
  }
805
805
  }
806
806
  }
807
- const rule$2 = {
807
+ const rule$3 = {
808
808
  defaultOptions: [{ locales: defaultLocales }],
809
809
  meta: {
810
810
  docs: { description: "Format Vue i18n blocks: enforce valid/consistent locales, sorted keys, and no unused strings" },
@@ -872,7 +872,7 @@ const rule$2 = {
872
872
  };
873
873
 
874
874
  const untypedEmitsRegex = /const\s+emit\s*=\s*defineEmits\(\[([^\]]+)\]\)/g;
875
- const rule$1 = {
875
+ const rule$2 = {
876
876
  defaultOptions: [],
877
877
  meta: {
878
878
  docs: { description: "Format Vue component scripts: enforce multiline computed properties and typed emits" },
@@ -940,6 +940,42 @@ ${typedEvents}
940
940
  }
941
941
  };
942
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
+
943
979
  const templateRegex = /<template>([\s\S]*)<\/template>/i;
944
980
  const templateTagLength = "<template>".length;
945
981
  const propsPrefixRegex = /\$?props\.(\w+)/g;
@@ -1217,10 +1253,11 @@ const rule = {
1217
1253
 
1218
1254
  const index = {
1219
1255
  rules: {
1220
- "ts-format-layout": rule$4,
1221
- "ts-format-tests": rule$3,
1222
- "vue-format-i18n": rule$2,
1223
- "vue-format-script": rule$1,
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,
1224
1261
  "vue-format-template": rule
1225
1262
  }
1226
1263
  };
package/dist/index.d.cts CHANGED
@@ -5203,6 +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-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
@@ -5203,6 +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-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
@@ -5203,6 +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-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
@@ -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$4 = {
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" },
@@ -561,7 +561,7 @@ function isTeardownStatement(statement) {
561
561
  }
562
562
  return false;
563
563
  }
564
- const rule$3 = {
564
+ const rule$4 = {
565
565
  defaultOptions: [],
566
566
  meta: {
567
567
  docs: { description: "Enforce sorted test functions and setup-before-assertions layout in test bodies" },
@@ -802,7 +802,7 @@ function checkUnusedStrings(context, parsed, source, content, contentOffset) {
802
802
  }
803
803
  }
804
804
  }
805
- const rule$2 = {
805
+ const rule$3 = {
806
806
  defaultOptions: [{ locales: defaultLocales }],
807
807
  meta: {
808
808
  docs: { description: "Format Vue i18n blocks: enforce valid/consistent locales, sorted keys, and no unused strings" },
@@ -870,7 +870,7 @@ const rule$2 = {
870
870
  };
871
871
 
872
872
  const untypedEmitsRegex = /const\s+emit\s*=\s*defineEmits\(\[([^\]]+)\]\)/g;
873
- const rule$1 = {
873
+ const rule$2 = {
874
874
  defaultOptions: [],
875
875
  meta: {
876
876
  docs: { description: "Format Vue component scripts: enforce multiline computed properties and typed emits" },
@@ -938,6 +938,42 @@ ${typedEvents}
938
938
  }
939
939
  };
940
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
+
941
977
  const templateRegex = /<template>([\s\S]*)<\/template>/i;
942
978
  const templateTagLength = "<template>".length;
943
979
  const propsPrefixRegex = /\$?props\.(\w+)/g;
@@ -1215,10 +1251,11 @@ const rule = {
1215
1251
 
1216
1252
  const index = {
1217
1253
  rules: {
1218
- "ts-format-layout": rule$4,
1219
- "ts-format-tests": rule$3,
1220
- "vue-format-i18n": rule$2,
1221
- "vue-format-script": rule$1,
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,
1222
1259
  "vue-format-template": rule
1223
1260
  }
1224
1261
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saasmakers/eslint",
3
- "version": "1.0.27",
3
+ "version": "1.0.29",
4
4
  "private": false,
5
5
  "description": "Shared ESLint config and rules for SaaS Makers projects",
6
6
  "license": "MIT",
@@ -30,6 +30,7 @@
30
30
  "@unocss/eslint-plugin": "66.7.0",
31
31
  "@vitest/eslint-plugin": "1.6.20",
32
32
  "eslint-plugin-package-json": "0.31.0",
33
+ "eslint-plugin-playwright": "2.10.4",
33
34
  "eslint-plugin-turbo": "2.9.18",
34
35
  "eslint-plugin-zod": "3.4.0",
35
36
  "typescript-eslint": "8.61.0",