@phsd/lint 0.1.1 → 0.2.0

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.
Files changed (3) hide show
  1. package/dist/index.d.mts +3973 -1496
  2. package/dist/index.mjs +246 -32
  3. package/package.json +11 -7
package/dist/index.mjs CHANGED
@@ -34,6 +34,7 @@ const GLOB_JSONC = "**/*.jsonc";
34
34
  const GLOB_MARKDOWN = "**/*.md";
35
35
  const GLOB_MARKDOWN_IN_MARKDOWN = "**/*.md/*.md";
36
36
  const GLOB_SVELTE = "**/*.svelte";
37
+ const GLOB_VUE = "**/*.vue";
37
38
  const GLOB_YAML = "**/*.y?(a)ml";
38
39
  const GLOB_TOML = "**/*.toml";
39
40
  const GLOB_XML = "**/*.xml";
@@ -225,18 +226,11 @@ const StylisticConfigDefaults = {
225
226
  semi: true
226
227
  };
227
228
  async function stylistic(options = {}) {
228
- const { indent, jsx: jsx$1, overrides = {}, quotes, semi } = {
229
+ const { indent, jsx: jsx$1, opinionated, overrides = {}, quotes, semi } = {
229
230
  ...StylisticConfigDefaults,
230
231
  ...options
231
232
  };
232
233
  const pluginStylistic = await interopDefault(import("@stylistic/eslint-plugin"));
233
- const config = pluginStylistic.configs.customize({
234
- indent,
235
- jsx: jsx$1,
236
- pluginName: "style",
237
- quotes,
238
- semi
239
- });
240
234
  return [{
241
235
  name: "phs/stylistic/rules",
242
236
  plugins: {
@@ -244,7 +238,13 @@ async function stylistic(options = {}) {
244
238
  style: pluginStylistic
245
239
  },
246
240
  rules: {
247
- ...config.rules,
241
+ ...opinionated ? pluginStylistic.configs.customize({
242
+ indent,
243
+ jsx: jsx$1,
244
+ pluginName: "style",
245
+ quotes,
246
+ semi
247
+ }).rules : {},
248
248
  "antfu/consistent-chaining": "error",
249
249
  "antfu/consistent-list-newline": "error",
250
250
  "antfu/if-newline": "error",
@@ -253,6 +253,11 @@ async function stylistic(options = {}) {
253
253
  after: true,
254
254
  before: false
255
255
  }],
256
+ "style/jsx-curly-brace-presence": ["error", {
257
+ children: "never",
258
+ propElementValues: "always",
259
+ props: "never"
260
+ }],
256
261
  "style/quote-props": ["error", "as-needed"],
257
262
  "style/yield-star-spacing": ["error", {
258
263
  after: true,
@@ -7888,7 +7893,7 @@ async function svelte(options = {}) {
7888
7893
  //#endregion
7889
7894
  //#region src/configs/tailwind.ts
7890
7895
  async function tailwind(options = {}) {
7891
- const { attributes = [], callees = [], overrides = {}, tags = [], tailwindConfig, variables = [] } = options;
7896
+ const { allowClasses, attributes = [], callees = [], forceRegisteredClasses = true, overrides = {}, tags = [], tailwindConfig, variables = [] } = options;
7892
7897
  const { getDefaultAttributes, getDefaultCallees, getDefaultTags, getDefaultVariables } = await import("eslint-plugin-better-tailwindcss/api/defaults");
7893
7898
  const defaults = {
7894
7899
  attributes: [...getDefaultAttributes(), ...attributes],
@@ -7925,11 +7930,12 @@ async function tailwind(options = {}) {
7925
7930
  allowMultiline: true,
7926
7931
  ...defaults
7927
7932
  }],
7928
- "tw/no-unregistered-classes": ["error", {
7929
- detectComponentClasses: false,
7933
+ ...forceRegisteredClasses ? { "tw/no-unregistered-classes": ["error", {
7934
+ detectComponentClasses: true,
7930
7935
  entryPoint: tailwindConfig,
7936
+ ignore: allowClasses ?? [],
7931
7937
  ...defaults
7932
- }],
7938
+ }] } : {},
7933
7939
  ...overrides
7934
7940
  },
7935
7941
  settings: { "better-tailwindcss": { entryPoint: tailwindConfig } }
@@ -8023,7 +8029,7 @@ async function typescript(options = {}) {
8023
8029
  ];
8024
8030
  const filesTypeAware = options.filesTypeAware ?? [GLOB_TS, GLOB_TSX];
8025
8031
  const ignoresTypeAware = options.ignoresTypeAware ?? [`${GLOB_MARKDOWN}/**`, GLOB_ASTRO_TS];
8026
- const tsconfigPath = options?.tsconfigPath ? options.tsconfigPath : void 0;
8032
+ const tsconfigPath = options.tsconfigPath;
8027
8033
  const isTypeAware = !!tsconfigPath;
8028
8034
  const typeAwareRules = {
8029
8035
  "dot-notation": "off",
@@ -8034,20 +8040,16 @@ async function typescript(options = {}) {
8034
8040
  "ts/no-for-in-array": "error",
8035
8041
  "ts/no-implied-eval": "error",
8036
8042
  "ts/no-misused-promises": "error",
8043
+ "ts/no-unnecessary-condition": "error",
8044
+ "ts/no-unnecessary-template-expression": "error",
8045
+ "ts/no-unnecessary-type-arguments": "error",
8037
8046
  "ts/no-unnecessary-type-assertion": "error",
8038
- "ts/no-unsafe-argument": "error",
8039
- "ts/no-unsafe-assignment": "error",
8040
- "ts/no-unsafe-call": "error",
8041
- "ts/no-unsafe-member-access": "error",
8042
- "ts/no-unsafe-return": "error",
8047
+ "ts/no-unnecessary-type-conversion": "error",
8048
+ "ts/prefer-optional-chain": "error",
8043
8049
  "ts/promise-function-async": "error",
8044
8050
  "ts/restrict-plus-operands": "error",
8045
8051
  "ts/restrict-template-expressions": "error",
8046
8052
  "ts/return-await": ["error", "in-try-catch"],
8047
- "ts/strict-boolean-expressions": ["error", {
8048
- allowNullableBoolean: true,
8049
- allowNullableObject: true
8050
- }],
8051
8053
  "ts/switch-exhaustiveness-check": "error",
8052
8054
  "ts/unbound-method": "error"
8053
8055
  };
@@ -8176,6 +8178,211 @@ async function unicorn(options = {}) {
8176
8178
  }];
8177
8179
  }
8178
8180
 
8181
+ //#endregion
8182
+ //#region src/configs/vue.ts
8183
+ async function vue(options = {}) {
8184
+ const { a11y = false, files = [GLOB_VUE], overrides = {}, stylistic: stylistic$1 = true, vueVersion = 3 } = options;
8185
+ const sfcBlocks = options.sfcBlocks === true ? {} : options.sfcBlocks ?? {};
8186
+ const { indent = 2 } = typeof stylistic$1 === "boolean" ? {} : stylistic$1;
8187
+ const [pluginVue, parserVue, processorVueBlocks, pluginVueA11y] = await Promise.all([
8188
+ interopDefault(import("eslint-plugin-vue")),
8189
+ interopDefault(import("vue-eslint-parser")),
8190
+ interopDefault(import("eslint-processor-vue-blocks")),
8191
+ ...a11y ? [interopDefault(import("eslint-plugin-vuejs-accessibility"))] : []
8192
+ ]);
8193
+ return [{
8194
+ languageOptions: { globals: {
8195
+ computed: "readonly",
8196
+ defineEmits: "readonly",
8197
+ defineExpose: "readonly",
8198
+ defineProps: "readonly",
8199
+ onMounted: "readonly",
8200
+ onUnmounted: "readonly",
8201
+ reactive: "readonly",
8202
+ ref: "readonly",
8203
+ shallowReactive: "readonly",
8204
+ shallowRef: "readonly",
8205
+ toRef: "readonly",
8206
+ toRefs: "readonly",
8207
+ watch: "readonly",
8208
+ watchEffect: "readonly"
8209
+ } },
8210
+ name: "phs/vue/setup",
8211
+ plugins: {
8212
+ vue: pluginVue,
8213
+ ...a11y ? { "vue-a11y": pluginVueA11y } : {}
8214
+ }
8215
+ }, {
8216
+ files,
8217
+ languageOptions: {
8218
+ parser: parserVue,
8219
+ parserOptions: {
8220
+ ecmaFeatures: { jsx: true },
8221
+ extraFileExtensions: [".vue"],
8222
+ parser: options.typescript ? await interopDefault(import("@typescript-eslint/parser")) : null,
8223
+ sourceType: "module"
8224
+ }
8225
+ },
8226
+ name: "phs/vue/rules",
8227
+ processor: sfcBlocks === false ? pluginVue.processors[".vue"] : mergeProcessors([pluginVue.processors[".vue"], processorVueBlocks({
8228
+ ...sfcBlocks,
8229
+ blocks: {
8230
+ styles: true,
8231
+ ...sfcBlocks.blocks
8232
+ }
8233
+ })]),
8234
+ rules: {
8235
+ ...pluginVue.configs.base.rules,
8236
+ ...vueVersion === 2 ? {
8237
+ ...pluginVue.configs["vue2-essential"].rules,
8238
+ ...pluginVue.configs["vue2-strongly-recommended"].rules,
8239
+ ...pluginVue.configs["vue2-recommended"].rules
8240
+ } : {
8241
+ ...pluginVue.configs["flat/essential"].map((c) => c.rules).reduce((acc, c) => ({
8242
+ ...acc,
8243
+ ...c
8244
+ }), {}),
8245
+ ...pluginVue.configs["flat/strongly-recommended"].map((c) => c.rules).reduce((acc, c) => ({
8246
+ ...acc,
8247
+ ...c
8248
+ }), {}),
8249
+ ...pluginVue.configs["flat/recommended"].map((c) => c.rules).reduce((acc, c) => ({
8250
+ ...acc,
8251
+ ...c
8252
+ }), {})
8253
+ },
8254
+ "antfu/no-top-level-await": "off",
8255
+ "node/prefer-global/process": "off",
8256
+ "ts/explicit-function-return-type": "off",
8257
+ "vue/block-order": ["error", { order: [
8258
+ "script",
8259
+ "template",
8260
+ "style"
8261
+ ] }],
8262
+ "vue/component-name-in-template-casing": ["error", "PascalCase"],
8263
+ "vue/component-options-name-casing": ["error", "PascalCase"],
8264
+ "vue/component-tags-order": "off",
8265
+ "vue/custom-event-name-casing": ["error", "camelCase"],
8266
+ "vue/define-macros-order": ["error", { order: [
8267
+ "defineOptions",
8268
+ "defineProps",
8269
+ "defineEmits",
8270
+ "defineSlots"
8271
+ ] }],
8272
+ "vue/dot-location": ["error", "property"],
8273
+ "vue/dot-notation": ["error", { allowKeywords: true }],
8274
+ "vue/eqeqeq": ["error", "smart"],
8275
+ "vue/html-indent": ["error", indent],
8276
+ "vue/html-quotes": ["error", "double"],
8277
+ "vue/max-attributes-per-line": "off",
8278
+ "vue/multi-word-component-names": "off",
8279
+ "vue/no-dupe-keys": "off",
8280
+ "vue/no-empty-pattern": "error",
8281
+ "vue/no-irregular-whitespace": "error",
8282
+ "vue/no-loss-of-precision": "error",
8283
+ "vue/no-restricted-syntax": [
8284
+ "error",
8285
+ "DebuggerStatement",
8286
+ "LabeledStatement",
8287
+ "WithStatement"
8288
+ ],
8289
+ "vue/no-restricted-v-bind": ["error", "/^v-/"],
8290
+ "vue/no-setup-props-reactivity-loss": "off",
8291
+ "vue/no-sparse-arrays": "error",
8292
+ "vue/no-unused-refs": "error",
8293
+ "vue/no-useless-v-bind": "error",
8294
+ "vue/no-v-html": "off",
8295
+ "vue/object-shorthand": [
8296
+ "error",
8297
+ "always",
8298
+ {
8299
+ avoidQuotes: true,
8300
+ ignoreConstructors: false
8301
+ }
8302
+ ],
8303
+ "vue/prefer-separate-static-class": "error",
8304
+ "vue/prefer-template": "error",
8305
+ "vue/prop-name-casing": ["error", "camelCase"],
8306
+ "vue/require-default-prop": "off",
8307
+ "vue/require-prop-types": "off",
8308
+ "vue/space-infix-ops": "error",
8309
+ "vue/space-unary-ops": ["error", {
8310
+ nonwords: false,
8311
+ words: true
8312
+ }],
8313
+ ...stylistic$1 ? {
8314
+ "vue/array-bracket-spacing": ["error", "never"],
8315
+ "vue/arrow-spacing": ["error", {
8316
+ after: true,
8317
+ before: true
8318
+ }],
8319
+ "vue/block-spacing": ["error", "always"],
8320
+ "vue/block-tag-newline": ["error", {
8321
+ multiline: "always",
8322
+ singleline: "always"
8323
+ }],
8324
+ "vue/brace-style": [
8325
+ "error",
8326
+ "stroustrup",
8327
+ { allowSingleLine: true }
8328
+ ],
8329
+ "vue/comma-dangle": ["error", "always-multiline"],
8330
+ "vue/comma-spacing": ["error", {
8331
+ after: true,
8332
+ before: false
8333
+ }],
8334
+ "vue/comma-style": ["error", "last"],
8335
+ "vue/html-comment-content-spacing": [
8336
+ "error",
8337
+ "always",
8338
+ { exceptions: ["-"] }
8339
+ ],
8340
+ "vue/key-spacing": ["error", {
8341
+ afterColon: true,
8342
+ beforeColon: false
8343
+ }],
8344
+ "vue/keyword-spacing": ["error", {
8345
+ after: true,
8346
+ before: true
8347
+ }],
8348
+ "vue/object-curly-newline": "off",
8349
+ "vue/object-curly-spacing": ["error", "always"],
8350
+ "vue/object-property-newline": ["error", { allowAllPropertiesOnSameLine: true }],
8351
+ "vue/operator-linebreak": ["error", "before"],
8352
+ "vue/padding-line-between-blocks": ["error", "always"],
8353
+ "vue/quote-props": ["error", "consistent-as-needed"],
8354
+ "vue/space-in-parens": ["error", "never"],
8355
+ "vue/template-curly-spacing": "error"
8356
+ } : {},
8357
+ ...a11y ? {
8358
+ "vue-a11y/alt-text": "error",
8359
+ "vue-a11y/anchor-has-content": "error",
8360
+ "vue-a11y/aria-props": "error",
8361
+ "vue-a11y/aria-role": "error",
8362
+ "vue-a11y/aria-unsupported-elements": "error",
8363
+ "vue-a11y/click-events-have-key-events": "error",
8364
+ "vue-a11y/form-control-has-label": "error",
8365
+ "vue-a11y/heading-has-content": "error",
8366
+ "vue-a11y/iframe-has-title": "error",
8367
+ "vue-a11y/interactive-supports-focus": "error",
8368
+ "vue-a11y/label-has-for": "error",
8369
+ "vue-a11y/media-has-caption": "warn",
8370
+ "vue-a11y/mouse-events-have-key-events": "error",
8371
+ "vue-a11y/no-access-key": "error",
8372
+ "vue-a11y/no-aria-hidden-on-focusable": "error",
8373
+ "vue-a11y/no-autofocus": "warn",
8374
+ "vue-a11y/no-distracting-elements": "error",
8375
+ "vue-a11y/no-redundant-roles": "error",
8376
+ "vue-a11y/no-role-presentation-on-focusable": "error",
8377
+ "vue-a11y/no-static-element-interactions": "error",
8378
+ "vue-a11y/role-has-required-aria-props": "error",
8379
+ "vue-a11y/tabindex-no-positive": "warn"
8380
+ } : {},
8381
+ ...overrides
8382
+ }
8383
+ }];
8384
+ }
8385
+
8179
8386
  //#endregion
8180
8387
  //#region src/configs/yaml.ts
8181
8388
  async function yaml(options = {}) {
@@ -8294,7 +8501,7 @@ function getOverrides(options, key) {
8294
8501
  * The merged ESLint configurations.
8295
8502
  */
8296
8503
  function phs(options = {}, ...userConfigs) {
8297
- const { astro: enableAstro = false, autoRenamePlugins = true, componentExts = [], gitignore: enableGitignore = true, imports: enableImports = true, jsx: enableJsx = false, pnpm: enableCatalogs = false, react: enableReact = false, regexp: enableRegexp = true, sort: enableSort = true, svelte: enableSvelte = false, test: enableTest = false, typescript: enableTypeScript = true, unicorn: enableUnicorn = true } = options;
8504
+ const { astro: enableAstro = false, autoRenamePlugins = true, componentExts = [], gitignore: enableGitignore = true, imports: enableImports = true, jsx: enableJsx = false, pnpm: enableCatalogs = false, react: enableReact = false, regexp: enableRegexp = true, sort: enableSort = true, svelte: enableSvelte = false, test: enableTest = false, typescript: enableTypeScript = true, unicorn: enableUnicorn = true, vue: enableVue = false } = options;
8298
8505
  const stylisticOptions = !options.stylistic ? false : typeof options.stylistic === "object" ? options.stylistic : {};
8299
8506
  if (stylisticOptions && !("jsx" in stylisticOptions)) stylisticOptions.jsx = enableJsx;
8300
8507
  const configs$1 = [];
@@ -8315,6 +8522,7 @@ function phs(options = {}, ...userConfigs) {
8315
8522
  ...enableImports
8316
8523
  }));
8317
8524
  if (enableUnicorn) configs$1.push(unicorn(enableUnicorn === true ? {} : enableUnicorn));
8525
+ if (enableVue) componentExts.push("vue");
8318
8526
  if (enableJsx) configs$1.push(jsx());
8319
8527
  if (enableTypeScript) configs$1.push(typescript({
8320
8528
  ...typescriptOptions,
@@ -8322,23 +8530,29 @@ function phs(options = {}, ...userConfigs) {
8322
8530
  overrides: getOverrides(options, "typescript"),
8323
8531
  type: options.type
8324
8532
  }));
8325
- if (stylisticOptions) configs$1.push(stylistic({
8533
+ configs$1.push(stylistic({
8326
8534
  ...stylisticOptions,
8327
8535
  overrides: getOverrides(options, "stylistic")
8328
8536
  }));
8329
8537
  if (enableRegexp) configs$1.push(regexp(typeof enableRegexp === "boolean" ? {} : enableRegexp));
8330
8538
  if (enableTest) configs$1.push(test({ overrides: getOverrides(options, "test") }));
8331
- if (enableReact) configs$1.push(react({
8332
- ...typescriptOptions,
8333
- ...resolveSubOptions(options, "react"),
8334
- overrides: getOverrides(options, "react"),
8335
- tsconfigPath
8539
+ if (enableVue) configs$1.push(vue({
8540
+ ...resolveSubOptions(options, "vue"),
8541
+ overrides: getOverrides(options, "vue"),
8542
+ stylistic: stylisticOptions,
8543
+ typescript: !!enableTypeScript
8336
8544
  }));
8337
8545
  if (enableSvelte) configs$1.push(svelte({
8338
8546
  overrides: getOverrides(options, "svelte"),
8339
8547
  stylistic: stylisticOptions,
8340
8548
  typescript: !!enableTypeScript
8341
8549
  }));
8550
+ if (enableReact) configs$1.push(react({
8551
+ ...typescriptOptions,
8552
+ ...resolveSubOptions(options, "react"),
8553
+ overrides: getOverrides(options, "react"),
8554
+ tsconfigPath
8555
+ }));
8342
8556
  if (enableAstro) configs$1.push(astro({
8343
8557
  overrides: getOverrides(options, "astro"),
8344
8558
  stylistic: stylisticOptions
@@ -8361,7 +8575,7 @@ function phs(options = {}, ...userConfigs) {
8361
8575
  componentExts,
8362
8576
  overrides: getOverrides(options, "markdown")
8363
8577
  }));
8364
- if (options.formatters) configs$1.push(formatters(options.formatters || true, typeof stylisticOptions === "boolean" ? {} : stylisticOptions));
8578
+ if (options.formatters) configs$1.push(formatters(options.formatters, typeof stylisticOptions === "boolean" ? {} : stylisticOptions));
8365
8579
  if ("files" in options) throw new Error("The first argument should not contain the \"files\" property as the options are supposed to be global. Place it in the second or later config instead.");
8366
8580
  const fusedConfig = flatConfigProps.reduce((acc, key) => {
8367
8581
  if (key in options) acc[key] = options[key];
@@ -8378,4 +8592,4 @@ function resolveSubOptions(options, key) {
8378
8592
  }
8379
8593
 
8380
8594
  //#endregion
8381
- export { StylisticConfigDefaults, astro, combine, formatters, ignores, imports, interopDefault, javascript, jsdoc, jsonc, jsx, markdown, node, parserPlain, perfectionist, phs, pnpm, react, regexp, renamePluginInConfigs, renameRules, sortPackageJson, sortTsconfig, sortTurboConfig, stylistic, svelte, tailwind, test, toArray, toml, typescript, unicorn, yaml };
8595
+ export { StylisticConfigDefaults, astro, combine, formatters, ignores, imports, interopDefault, javascript, jsdoc, jsonc, jsx, markdown, node, parserPlain, perfectionist, phs, pnpm, react, regexp, renamePluginInConfigs, renameRules, sortPackageJson, sortTsconfig, sortTurboConfig, stylistic, svelte, tailwind, test, toArray, toml, typescript, unicorn, vue, yaml };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@phsd/lint",
3
3
  "type": "module",
4
- "version": "0.1.1",
4
+ "version": "0.2.0",
5
5
  "exports": {
6
6
  "./eslint": {
7
7
  "types": "./dist/index.d.mts",
@@ -13,7 +13,7 @@
13
13
  "dist"
14
14
  ],
15
15
  "dependencies": {
16
- "@eslint-react/eslint-plugin": "^2.5.3",
16
+ "@eslint-react/eslint-plugin": "^2.5.4",
17
17
  "@eslint/js": "^9.39.2",
18
18
  "@eslint/markdown": "^7.5.1",
19
19
  "@stylistic/eslint-plugin": "5.2.3",
@@ -41,10 +41,13 @@
41
41
  "eslint-plugin-react-refresh": "^0.4.26",
42
42
  "eslint-plugin-regexp": "^2.10.0",
43
43
  "eslint-plugin-svelte": "^3.14.0",
44
- "eslint-plugin-toml": "^0.13.0",
44
+ "eslint-plugin-toml": "^0.13.1",
45
45
  "eslint-plugin-unicorn": "^62.0.0",
46
46
  "eslint-plugin-unused-imports": "^4.3.0",
47
+ "eslint-plugin-vue": "^10.7.0",
48
+ "eslint-plugin-vuejs-accessibility": "^2.4.1",
47
49
  "eslint-plugin-yml": "^1.19.1",
50
+ "eslint-processor-vue-blocks": "^2.0.0",
48
51
  "eslint-typegen": "^2.3.0",
49
52
  "globals": "^17.0.0",
50
53
  "jsonc-eslint-parser": "^2.4.2",
@@ -52,20 +55,21 @@
52
55
  "prettier-plugin-svelte": "^3.4.1",
53
56
  "publint": "^0.3.16",
54
57
  "svelte-eslint-parser": "^1.4.1",
55
- "toml-eslint-parser": "^0.11.0",
58
+ "toml-eslint-parser": "^1.0.0",
56
59
  "typescript-eslint": "^8.52.0",
60
+ "vue-eslint-parser": "^10.2.0",
57
61
  "yaml-eslint-parser": "^1.3.2"
58
62
  },
59
63
  "devDependencies": {
60
- "@types/node": "^25.0.3",
64
+ "@types/node": "^25.0.5",
61
65
  "local-pkg": "^1.1.2",
62
66
  "prettier": "^3.7.4",
63
67
  "tailwindcss": "^4.1.18",
64
- "tsdown": "^0.18.4",
68
+ "tsdown": "^0.19.0",
65
69
  "tsx": "^4.21.0",
66
70
  "typescript": "^5.9.3",
67
71
  "@phsd/format": "0.0.4",
68
- "@phsd/typescript": "0.0.1"
72
+ "@phsd/typescript": "0.3.1"
69
73
  },
70
74
  "scripts": {
71
75
  "start": "pnpm dev",