{"id":50961079,"url":"https://github.com/diphyx/eslint-plugin","last_synced_at":"2026-06-20T16:01:00.651Z","repository":{"id":364739962,"uuid":"1268956132","full_name":"diphyx/eslint-plugin","owner":"diphyx","description":"Shared ESLint plugin + flat config for DiPhyx Nuxt/Vue + Harlemify projects.","archived":false,"fork":false,"pushed_at":"2026-06-15T16:32:26.000Z","size":107,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-18T14:29:52.831Z","etag":null,"topics":["diphyx","eslint","eslint-plugin","eslintplugin","harlemify","nuxt","vue"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/diphyx.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-14T06:05:32.000Z","updated_at":"2026-06-15T16:32:28.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/diphyx/eslint-plugin","commit_stats":null,"previous_names":["diphyx/eslint-plugin"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/diphyx/eslint-plugin","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diphyx%2Feslint-plugin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diphyx%2Feslint-plugin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diphyx%2Feslint-plugin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diphyx%2Feslint-plugin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/diphyx","download_url":"https://codeload.github.com/diphyx/eslint-plugin/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diphyx%2Feslint-plugin/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34536283,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-19T02:00:06.005Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["diphyx","eslint","eslint-plugin","eslintplugin","harlemify","nuxt","vue"],"created_at":"2026-06-18T14:03:12.921Z","updated_at":"2026-06-19T15:01:14.635Z","avatar_url":"https://github.com/diphyx.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @diphyx/eslint-plugin\n\nOpinionated ESLint rules and a ready-to-use flat config that capture DiPhyx's Nuxt/Vue + [Harlemify](https://github.com/diphyx/harlemify) conventions — so every DiPhyx app lints the same way from a single dependency.\n\nA stock `eslint-plugin-vue` setup checks general Vue style; this plugin adds the project-specific patterns it can't know about — where template directives belong, how `\u003cscript setup\u003e` is ordered and written, the exact shape of a Harlemify `createStore`, composable naming, and reaching for [radash](https://radash-docs.vercel.app) / [VueUse](https://vueuse.org) instead of hand-rolled code.\n\n## Highlights\n\n- **35 custom rules** covering SFC templates, `\u003cscript setup\u003e` structure, Harlemify stores, composable naming, code layout, and radash / VueUse usage.\n- **One-line preset** — `configs.recommended` wires up the TypeScript + Vue parsers, the relevant `eslint-plugin-vue` rules, file-naming, and every custom rule.\n- **No extra peer deps** — the parsers and plugins ship inside this package; you only install `eslint` itself.\n- **Guidance, not gates** — every rule reports as a warning and none auto-fix, so it nudges without blocking commits.\n- **Modern toolchain** — flat config, ESLint 9+, ESM only.\n\n## Install\n\n```bash\npnpm add -D @diphyx/eslint-plugin eslint\n```\n\nThe plugin ships its own parser/plugin dependencies (`@typescript-eslint/*`, `vue-eslint-parser`, `eslint-plugin-vue`, `eslint-plugin-check-file`), so you only need `eslint` itself as a peer.\n\n## Usage\n\n`eslint.config.mjs`:\n\n```js\nimport diphyx from \"@diphyx/eslint-plugin\";\n\nexport default [\n    ...diphyx.configs.recommended,\n\n    // project-specific overrides / ignores\n    {\n        ignores: [\"node_modules/**\", \".nuxt/**\", \".output/**\", \"dist/**\", \"**/*.d.ts\"],\n    },\n];\n```\n\n### Picking rules à la carte\n\nIf you don't want the preset, register the plugin and turn on rules yourself:\n\n```js\nimport diphyx from \"@diphyx/eslint-plugin\";\n\nexport default [\n    {\n        files: [\"**/*.vue\"],\n        plugins: { \"@diphyx\": diphyx },\n        rules: {\n            \"@diphyx/template-v-if\": \"warn\",\n            \"@diphyx/template-text\": \"warn\",\n        },\n    },\n];\n```\n\n## Rules\n\nAll rules are report-only (warnings); none auto-fix. Each rule has its own page\nunder [`docs/rules/`](./docs/rules) (also linked from the rule's `meta.docs.url`).\n\n### Template (`*.vue`)\n\n| Rule                    | Enforces                                                              |\n| ----------------------- | --------------------------------------------------------------------- |\n| `template-v-if`         | `v-if` must be on a `\u003ctemplate\u003e` wrapper                              |\n| `template-v-else`       | `v-else` / `v-else-if` must be on a `\u003ctemplate\u003e` wrapper              |\n| `template-v-for`        | `v-for` must be on a `\u003ctemplate\u003e` wrapper                             |\n| `template-text`         | bare text must be wrapped in an HTML tag                              |\n| `template-props-prefix` | props must be read via `props.` in the template, not the bare binding |\n\n### Script (`*.vue`)\n\n| Rule                   | Enforces                                                                                                                        |\n| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------- |\n| `script-section-order` | script-setup section order: import → props → model → emit → composable → state → computed → watch → method → lifecycle → expose |\n| `script-define-object` | `define*` macros must declare their shape with a runtime object, not the type-only form                                         |\n| `script-define-const`  | `define*` macros must be assigned to a const with the conventional name (`props` / `model` / `emit` / `slots`)                  |\n\n### Store — Harlemify `createStore`\n\n| Rule                                                                  | Enforces                                                   |\n| --------------------------------------------------------------------- | ---------------------------------------------------------- |\n| `store-require-name`                                                  | config has a required `name` property                      |\n| `store-require-model` / `store-require-view` / `store-require-action` | required sections are present                              |\n| `store-section-function`                                              | sections are functions                                     |\n| `store-section-method`                                                | sections use method shorthand (not arrow functions)        |\n| `store-section-return-shorthand`                                      | sections return a shorthand object of named consts         |\n| `store-config-order`                                                  | key order: name → model → view → action → compose → lazy   |\n| `store-no-unknown-key`                                                | no unknown config keys                                     |\n| `store-suffix`                                                        | store variable ends in `Store`                             |\n| `store-name-match`                                                    | `name` matches the variable (`accountStore` → `\"account\"`) |\n| `store-shape-suffix`                                                  | `shape()` result is named `*Shape`                         |\n| `store-mode-enum`                                                     | `mode` uses a `ModelMode` enum, not a string literal       |\n\n### Composable (`app/composables/*.ts`)\n\n| Rule                | Enforces                             |\n| ------------------- | ------------------------------------ |\n| `composable-naming` | exported composables follow `useXxx` |\n\n### Radash preferences (`*.ts`, `*.vue`)\n\nPrefer [radash](https://radash-docs.vercel.app) helpers over hand-rolled equivalents.\n\n| Rule                   | Enforces                                                                        |\n| ---------------------- | ------------------------------------------------------------------------------- |\n| `radash-prefer-is`     | prefer radash `is*` helpers over `typeof` comparisons                           |\n| `radash-prefer-call`   | prefer radash helpers over native global calls (`Promise.all`, `Array.isArray`) |\n| `radash-prefer-clone`  | prefer `clone()` over `JSON.parse(JSON.stringify())`                            |\n| `radash-prefer-unique` | prefer `unique()` over spreading a `new Set()`                                  |\n| `radash-prefer-sum`    | prefer `sum()` over a `reduce` that adds values                                 |\n| `radash-prefer-sleep`  | prefer `sleep()` over wrapping `setTimeout` in a Promise                        |\n\n### VueUse preferences (`*.ts`, `*.vue`)\n\nPrefer [VueUse](https://vueuse.org) composables (with automatic lifecycle cleanup) over raw browser APIs.\n\nThese rules only report inside a Vue effect scope — a `.vue` `\u003cscript setup\u003e`, a component `setup()`, or a `use*` composable — because that is where VueUse's `onScopeDispose` cleanup actually runs. Plain TypeScript modules, utility functions, and non-component classes are left alone.\n\n| Rule                        | Enforces                                                                                             |\n| --------------------------- | ---------------------------------------------------------------------------------------------------- |\n| `vueuse-prefer-storage`     | prefer `useLocalStorage` / `useSessionStorage` over raw Web Storage                                  |\n| `vueuse-prefer-member-call` | prefer VueUse composables over raw DOM/window method calls (`addEventListener`, `matchMedia`)        |\n| `vueuse-prefer-timer`       | prefer VueUse timer composables over native timers (`setInterval`)                                   |\n| `vueuse-prefer-observer`    | prefer VueUse observer composables over raw observers                                                |\n| `vueuse-prefer-clipboard`   | prefer `useClipboard()` over `navigator.clipboard`                                                   |\n| `vueuse-prefer-route`       | prefer `useRouteQuery` / `useRouteParams` / `useRouteHash` over `useRoute().query`/`.params`/`.hash` |\n\n### Layout (`*.ts`, `*.vue`)\n\nKeep multi-line statements visually separated in script/TypeScript code.\n\n| Rule                      | Enforces                                                   |\n| ------------------------- | ---------------------------------------------------------- |\n| `multiline-block-padding` | require a blank line between multi-line sibling statements |\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiphyx%2Feslint-plugin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdiphyx%2Feslint-plugin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiphyx%2Feslint-plugin/lists"}