fg-devkit 1.0.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.
- package/.cursor/rules/core-coding-standards.mdc +203 -0
- package/LICENSE +19 -0
- package/README.md +13 -0
- package/configs/dependency-policy.vue-workspace.json +116 -0
- package/configs/eslint.config.base.js +262 -0
- package/configs/eslint.sync-stub.js +19 -0
- package/configs/prettier.config.js +16 -0
- package/configs/tsconfig.app.sync.json +38 -0
- package/configs/tsconfig.base.json +18 -0
- package/configs/vscode-settings.json +74 -0
- package/package.json +67 -0
- package/scripts/check-dependency-policy.mjs +135 -0
- package/scripts/cz/.cz-config.cjs +26 -0
- package/scripts/cz/cz-adapter.cjs +116 -0
- package/scripts/dependency-policy-pins.mjs +35 -0
- package/scripts/fg-devkit.mjs +247 -0
- package/scripts/refresh-dependency-policy-from-repos.mjs +191 -0
- package/scripts/release.sh +72 -0
- package/scripts/resolve-dependency-policy-path.mjs +32 -0
- package/scripts/sync-dependency-policy.mjs +123 -0
- package/scripts/sync-peers-from-dev.mjs +31 -0
- package/scripts/sync-project-configs.mjs +32 -0
- package/scripts/sync-tooling-configs.mjs +62 -0
- package/scripts/sync-vscode-settings.mjs +39 -0
- package/scripts/vuln-commit.mjs +142 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Core coding standards for Vue / fds-vue-core frontend projects
|
|
3
|
+
alwaysApply: true
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Core Coding Standards
|
|
7
|
+
|
|
8
|
+
## Keep changes focused
|
|
9
|
+
|
|
10
|
+
- Make the smallest safe change that solves the request.
|
|
11
|
+
- Avoid unrelated refactors in the same task.
|
|
12
|
+
- Preserve existing behavior unless a behavior change is requested.
|
|
13
|
+
|
|
14
|
+
## Communication efficiency
|
|
15
|
+
|
|
16
|
+
- Do not waste tokens: keep responses concise, high-signal, and scoped to the request.
|
|
17
|
+
- Prefer short summaries over long explanations unless deeper detail is explicitly requested.
|
|
18
|
+
|
|
19
|
+
## Evidence-first implementation
|
|
20
|
+
|
|
21
|
+
- Never guess or hallucinate APIs, component props, or framework behavior.
|
|
22
|
+
- Verify implementation details against authoritative sources first (official docs, project code, and library types/source).
|
|
23
|
+
- If documentation is missing or ambiguous, state uncertainty explicitly and choose the safest validated approach.
|
|
24
|
+
|
|
25
|
+
## Match project conventions
|
|
26
|
+
|
|
27
|
+
- Follow established naming, file structure, and component patterns.
|
|
28
|
+
- Reuse existing utilities and query/composable patterns before adding new ones.
|
|
29
|
+
- Keep TypeScript types explicit at API boundaries.
|
|
30
|
+
|
|
31
|
+
## Strict TypeScript
|
|
32
|
+
|
|
33
|
+
- Keep TypeScript and Vue template typing strict (`strict: true`, `strictTemplates: true`).
|
|
34
|
+
- Do not introduce `any`; use `unknown` for unsafe input and narrow before use.
|
|
35
|
+
- Type API boundaries explicitly (request payloads, response DTOs, mutation variables, callback contracts).
|
|
36
|
+
- Prefer named reusable types (for example under `src/types`) for shared domain shapes.
|
|
37
|
+
- Avoid non-null assertions unless guarded by `enabled` checks or equivalent runtime guarantees.
|
|
38
|
+
|
|
39
|
+
## API boundaries
|
|
40
|
+
|
|
41
|
+
- Components and views should not call low-level HTTP/API clients directly for feature data fetching.
|
|
42
|
+
- Centralize HTTP and endpoint wiring in a dedicated API layer (for example `src/api/endpoints/*` or the convention used in the repo).
|
|
43
|
+
- Consume server state through query/mutation hooks (for example `src/queries/*` or equivalent), not ad-hoc fetches in UI code.
|
|
44
|
+
|
|
45
|
+
## State-management boundaries
|
|
46
|
+
|
|
47
|
+
- Use TanStack Query (or the project’s chosen data library) for server state and caching.
|
|
48
|
+
- Use Pinia/Vuex only for client/app state that is not owned by the server.
|
|
49
|
+
- Do not duplicate the same state across the query cache and global stores unless the project explicitly documents that pattern.
|
|
50
|
+
|
|
51
|
+
## TanStack Query server-state conventions
|
|
52
|
+
|
|
53
|
+
- Use TanStack Query for server state; avoid duplicating server data in ad-hoc local state.
|
|
54
|
+
- Keep API calls in the API layer and expose query/mutation hooks from a dedicated hooks folder.
|
|
55
|
+
- Build query keys as stable arrays of serializable primitives; when using refs, key by `.value` in a computed key.
|
|
56
|
+
- Prefer shared query key constants/factories to keep invalidation and cache updates consistent.
|
|
57
|
+
- Add `enabled` guards for required IDs/paths to prevent invalid requests.
|
|
58
|
+
- Use `placeholderData: keepPreviousData` for paginated/filter-driven views to avoid UI flicker.
|
|
59
|
+
- Set `staleTime` intentionally per resource; keep `refetchOnWindowFocus` off unless fresh-on-focus behavior is required.
|
|
60
|
+
- On mutation success, update cache intentionally (`setQueryData`) and/or invalidate the narrowest matching keys.
|
|
61
|
+
- Respect shared query client retry behavior and only override retries when endpoint-specific behavior is needed.
|
|
62
|
+
|
|
63
|
+
## Mutation cache behavior
|
|
64
|
+
|
|
65
|
+
- Every mutation should define post-success cache behavior.
|
|
66
|
+
- Use `invalidateQueries` for stale collections and `setQueryData` for direct entity updates.
|
|
67
|
+
- Invalidate the narrowest query keys that match changed resources.
|
|
68
|
+
|
|
69
|
+
## Vue Router conventions
|
|
70
|
+
|
|
71
|
+
- Organize route definitions in modules (for example `src/router/modules/*`) composed from a single router entry (for example `src/router/index.ts`), matching the repo layout.
|
|
72
|
+
- Every user-facing route should define `meta.title`; provide breadcrumb metadata for detail/flow routes when needed.
|
|
73
|
+
- Use shared route guards for auth/anonymous access control instead of duplicating checks in views.
|
|
74
|
+
- Prefer `props: true` and typed route params in components instead of reading raw params everywhere.
|
|
75
|
+
- Prefer named-route navigation for internal flows (`{ name, params, query }`) and reserve raw path pushes for simple/static redirects.
|
|
76
|
+
- Preserve existing query params intentionally when updating filters, pagination, or tab state.
|
|
77
|
+
- Lazy-load route components with dynamic imports to keep initial bundles smaller.
|
|
78
|
+
|
|
79
|
+
## Vue and UI expectations
|
|
80
|
+
|
|
81
|
+
- Prefer clear, readable templates over compact but hard-to-follow expressions.
|
|
82
|
+
- Keep components focused; extract repeated UI blocks when duplication grows.
|
|
83
|
+
- Keep localization text in language files instead of hardcoded UI strings.
|
|
84
|
+
|
|
85
|
+
## FDS-first component usage
|
|
86
|
+
|
|
87
|
+
- Use `fds-vue-core` components as the default choice for UI building blocks.
|
|
88
|
+
- Before adding custom UI, check whether an FDS component already solves the use case.
|
|
89
|
+
- Prefer extending composition around FDS components over re-implementing design-system behavior.
|
|
90
|
+
- Keep visual consistency by matching FDS variants, spacing patterns, and interaction styles.
|
|
91
|
+
|
|
92
|
+
## Asset creation policy
|
|
93
|
+
|
|
94
|
+
- Do not create icons, images, illustrations, or placeholder content unless explicitly requested.
|
|
95
|
+
- Assume `fds-vue-core` provides the required visual assets and use those first.
|
|
96
|
+
- If a required asset appears missing, clearly point out the gap instead of inventing a replacement.
|
|
97
|
+
|
|
98
|
+
## FDS typography (fds-vue-core)
|
|
99
|
+
|
|
100
|
+
- For headings, use `FdsH1`, `FdsH2`, and `FdsH3` (not raw `h1/h2/h3`).
|
|
101
|
+
- `FdsH1/FdsH2/FdsH3` use the `text` prop for content and support `size` (`sm|md|lg|xl|responsive`).
|
|
102
|
+
- When layout spacing needs to be neutralized, reset heading spacing with `class="m-0"` (and add explicit margins as needed).
|
|
103
|
+
- Use `FdsLead` for intro/lead paragraphs, `FdsMeta` for metadata/secondary text, and `FdsLabel` for short labels.
|
|
104
|
+
- `FdsLead`, `FdsMeta`, and `FdsLabel` render slot content; prefer these over custom styled spans for text semantics.
|
|
105
|
+
|
|
106
|
+
## Tailwind (v4+)
|
|
107
|
+
|
|
108
|
+
- Use Tailwind v4 patterns and utilities (for example `tailwindcss@4` with `@tailwindcss/vite` where applicable).
|
|
109
|
+
- Prefer utility classes in templates; only add custom CSS when utilities cannot express the design.
|
|
110
|
+
- Follow existing FDS token/preset styling (`fds-vue-core` tokens and preset) instead of inventing parallel design tokens.
|
|
111
|
+
- Always use Tailwind/FDS design tokens for colors, spacing, typography, radius, and shadows.
|
|
112
|
+
- Never invent ad-hoc color values (for example hex/rgb/hsl literals) when a tokenized utility exists.
|
|
113
|
+
- Keep spacing and typography explicit in class names; avoid hidden styling in deep selectors.
|
|
114
|
+
- Use `!` utility overrides sparingly and only when a component default cannot be changed safely.
|
|
115
|
+
- For Tailwind v4 important modifiers, use postfix-important utility syntax (for example `grid-cols-1!`) instead of prefix syntax (for example `!grid-cols-1`).
|
|
116
|
+
|
|
117
|
+
## Figma MCP implementation workflow
|
|
118
|
+
|
|
119
|
+
- When using Figma MCP, implement the design as specified (layout, spacing, typography, states, and interactions).
|
|
120
|
+
- Treat the Figma file as source of truth for UI behavior unless product/technical constraints are explicitly documented.
|
|
121
|
+
- Primary choice for implementation is `fds-vue-core` components that best match the design intent.
|
|
122
|
+
- Only create custom UI when no suitable FDS component exists; keep custom parts minimal and design-token based.
|
|
123
|
+
- If any Figma detail cannot be implemented exactly, document the deviation and choose the closest FDS-aligned solution.
|
|
124
|
+
|
|
125
|
+
## i18n and content
|
|
126
|
+
|
|
127
|
+
- Do not hardcode user-facing copy in templates or script logic; use `t(...)` keys.
|
|
128
|
+
- Add or update locale entries under the project’s language folder (for example `src/lang/*.json`) when introducing new text.
|
|
129
|
+
- Keep translation keys descriptive and grouped by screen/feature.
|
|
130
|
+
- Avoid storing i18n keys inside data/definition arrays (e.g. `i18nKey`) and translating later via dynamic keys or large switch statements. Prefer building definitions with already-translated `label: t('...')` (often as a `computed`) so types stay strict and templates stay simple.
|
|
131
|
+
|
|
132
|
+
## Formatting and locale consistency
|
|
133
|
+
|
|
134
|
+
- Prefer shared formatting utilities for date/number/currency output instead of ad-hoc inline formatting.
|
|
135
|
+
- Use Swedish locale conventions (`sv-SE`) unless a feature explicitly requires another locale.
|
|
136
|
+
|
|
137
|
+
## Accessibility baseline
|
|
138
|
+
|
|
139
|
+
- Use semantic HTML and accessible FDS components first; avoid click-only `div`/`span` patterns.
|
|
140
|
+
- Ensure form controls have proper labels and required ARIA attributes when needed.
|
|
141
|
+
- All interactive elements must be keyboard reachable and show visible focus states.
|
|
142
|
+
- Provide meaningful accessible names for icon-only actions and links.
|
|
143
|
+
|
|
144
|
+
## Async UI states
|
|
145
|
+
|
|
146
|
+
- For data-driven screens, always handle loading, empty, error, and success states explicitly.
|
|
147
|
+
- Use consistent FDS-based feedback patterns for loaders, alerts, and empty-state messaging.
|
|
148
|
+
|
|
149
|
+
## Error handling UX
|
|
150
|
+
|
|
151
|
+
- Do not swallow errors silently; surface actionable feedback to users.
|
|
152
|
+
- Use consistent FDS feedback patterns for API failures (alerts/toasts/inline messages).
|
|
153
|
+
- Keep technical error details out of user-facing copy unless explicitly required.
|
|
154
|
+
|
|
155
|
+
## Performance guardrails
|
|
156
|
+
|
|
157
|
+
- Avoid unnecessary reactive churn (redundant watchers/computed chains in hot paths).
|
|
158
|
+
- Memoize expensive derived values and keep render-time computations lightweight.
|
|
159
|
+
- Keep route-level and heavy feature components lazy-loaded.
|
|
160
|
+
|
|
161
|
+
## Security and data handling
|
|
162
|
+
|
|
163
|
+
- Never commit or expose secrets, tokens, or sensitive identifiers in code, logs, or UI.
|
|
164
|
+
- Validate and sanitize untrusted values from route/query params before use.
|
|
165
|
+
- Type and validate outgoing payloads to prevent accidental over-posting.
|
|
166
|
+
|
|
167
|
+
## Testing expectations
|
|
168
|
+
|
|
169
|
+
- For non-trivial logic changes, add or update automated tests close to the affected feature.
|
|
170
|
+
- Validate critical flows for changed views: loading, empty, error, and success states.
|
|
171
|
+
- Keep tests behavior-focused and avoid brittle implementation-detail assertions.
|
|
172
|
+
|
|
173
|
+
## CI/CD
|
|
174
|
+
|
|
175
|
+
- Treat the repository’s CI configuration as the source of truth (`Jenkinsfile`, GitHub Actions, or equivalent).
|
|
176
|
+
- Prefer frozen lockfile installs in CI (for example `pnpm install --frozen-lockfile --prefer-offline`) so CI matches local installs.
|
|
177
|
+
- Keep build, lint, typecheck, and test stages deterministic; document any project-specific stages (security scans, i18n download, Docker publish) in the repo README or a dedicated rule file.
|
|
178
|
+
|
|
179
|
+
## Quality checks before finishing
|
|
180
|
+
|
|
181
|
+
- Run relevant checks for touched code (lint, typecheck, or tests when practical).
|
|
182
|
+
- Fix issues introduced by your change before handing off.
|
|
183
|
+
- Call out anything you could not verify.
|
|
184
|
+
|
|
185
|
+
## Definition of done
|
|
186
|
+
|
|
187
|
+
- Lint and type checks pass for touched code.
|
|
188
|
+
- UI matches Figma/FDS expectations and uses tokenized styling.
|
|
189
|
+
- i18n keys, async states, and cache behavior are handled for changed features.
|
|
190
|
+
- Note any constraints, deviations, or unverified parts in handoff.
|
|
191
|
+
|
|
192
|
+
## Legacy/deprecation policy
|
|
193
|
+
|
|
194
|
+
- For new work, follow the current preferred patterns in this document.
|
|
195
|
+
- Do not expand usage of known legacy patterns when a supported modern pattern exists.
|
|
196
|
+
- If migration is out of scope, isolate legacy touchpoints and avoid spreading them.
|
|
197
|
+
|
|
198
|
+
## Example: API data safety
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
// Prefer typed fallbacks when API data may be missing.
|
|
202
|
+
const total = response?.stats?.total ?? 0
|
|
203
|
+
```
|
package/LICENSE
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
PROPRIETARY LICENSE
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 the authors
|
|
4
|
+
|
|
5
|
+
All rights reserved.
|
|
6
|
+
|
|
7
|
+
This software and associated documentation files (the "Software") are the
|
|
8
|
+
proprietary and confidential property of the copyright holders.
|
|
9
|
+
|
|
10
|
+
The Software is protected by copyright laws and international copyright
|
|
11
|
+
treaties, as well as other intellectual property laws and treaties.
|
|
12
|
+
|
|
13
|
+
Unauthorized copying, modification, distribution, or use of this Software,
|
|
14
|
+
via any medium, is strictly prohibited and may result in severe civil and
|
|
15
|
+
criminal penalties.
|
|
16
|
+
|
|
17
|
+
The Software is provided "AS IS", without warranty of any kind, express or
|
|
18
|
+
implied, including but not limited to the warranties of merchantability,
|
|
19
|
+
fitness for a particular purpose and noninfringement.
|
package/README.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# fg-devkit
|
|
2
|
+
|
|
3
|
+
Shared settings and tools to improve the developer experience for Vue and TypeScript projects in the npm ecosystem.
|
|
4
|
+
|
|
5
|
+
## Quick command alias (zsh)
|
|
6
|
+
|
|
7
|
+
To run `fg` instead of `pnpm exec fg`, add this alias:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
echo "alias fg='pnpm exec fg'" >> ~/.zshrc && source ~/.zshrc
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
This works in repos where `fg-devkit` is installed.
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
{
|
|
2
|
+
"managedDependencies": {
|
|
3
|
+
"dependencies": {
|
|
4
|
+
"@element-plus/icons-vue": "2.3.2",
|
|
5
|
+
"@lexical/html": "0.30.0",
|
|
6
|
+
"@lexical/list": "0.30.0",
|
|
7
|
+
"@lexical/rich-text": "0.30.0",
|
|
8
|
+
"@piwikpro/vue-piwik-pro": "1.4.0",
|
|
9
|
+
"@sentry/browser": "7.67.0",
|
|
10
|
+
"@sentry/tracing": "7.37.2",
|
|
11
|
+
"@sentry/vue": "7.37.2",
|
|
12
|
+
"@sentry/wasm": "7.67.0",
|
|
13
|
+
"@tailwindcss/postcss": "4.2.2",
|
|
14
|
+
"@tanstack/vue-query": "5.96.2",
|
|
15
|
+
"@types/leaflet": "1.5.7",
|
|
16
|
+
"@unhead/vue": "2.0.5",
|
|
17
|
+
"@vue-leaflet/vue-leaflet": "0.10.1",
|
|
18
|
+
"@vuelidate/core": "2.0.3",
|
|
19
|
+
"@vuelidate/validators": "2.0.4",
|
|
20
|
+
"@vueuse/components": "12.7.0",
|
|
21
|
+
"@vueuse/core": "14.2.1",
|
|
22
|
+
"chart.js": "4.5.1",
|
|
23
|
+
"content-disposition-header": "0.6.0",
|
|
24
|
+
"date-fns": "4.1.0",
|
|
25
|
+
"element-plus": "2.9.7",
|
|
26
|
+
"fds-vue-core": "6.2.1",
|
|
27
|
+
"imask": "7.6.1",
|
|
28
|
+
"leaflet": "1.8.0",
|
|
29
|
+
"lexical": "0.30.0",
|
|
30
|
+
"lodash": "4.17.23",
|
|
31
|
+
"lodash-es": "4.18.1",
|
|
32
|
+
"markdown-it": "14.1.1",
|
|
33
|
+
"pinia": "3.0.4",
|
|
34
|
+
"playwright": "1.57.0",
|
|
35
|
+
"quill": "2.0.3",
|
|
36
|
+
"randexp": "0.5.3",
|
|
37
|
+
"register-service-worker": "1.7.2",
|
|
38
|
+
"vega-embed": "7.1.0",
|
|
39
|
+
"vega-lite": "6.4.1",
|
|
40
|
+
"vue-chartjs": "5.3.3",
|
|
41
|
+
"vue-i18n": "11.3.2",
|
|
42
|
+
"vue-quilly": "1.0.5",
|
|
43
|
+
"vue-router": "4.6.3",
|
|
44
|
+
"vue3-touch-keyboard": "1.3.9",
|
|
45
|
+
"vuex": "4.1.0",
|
|
46
|
+
"vuex-persist": "3.1.3",
|
|
47
|
+
"yup": "1.7.1"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@chromatic-com/storybook": "5.0.1",
|
|
51
|
+
"@eslint/js": "9.39.1",
|
|
52
|
+
"@intlify/eslint-plugin-vue-i18n": "4.3.0",
|
|
53
|
+
"@intlify/unplugin-vue-i18n": "11.0.7",
|
|
54
|
+
"@playwright/test": "1.59.1",
|
|
55
|
+
"@rushstack/eslint-patch": "1.16.1",
|
|
56
|
+
"@storybook/addon-a11y": "10.1.10",
|
|
57
|
+
"@storybook/addon-docs": "10.1.10",
|
|
58
|
+
"@storybook/addon-vitest": "10.2.12",
|
|
59
|
+
"@storybook/vue3": "10.2.12",
|
|
60
|
+
"@storybook/vue3-vite": "10.2.12",
|
|
61
|
+
"@tanstack/vue-query-devtools": "6.1.13",
|
|
62
|
+
"@tsconfig/node22": "22.0.5",
|
|
63
|
+
"@types/lodash-es": "4.17.12",
|
|
64
|
+
"@types/node": "22.16.5",
|
|
65
|
+
"@typescript-eslint/eslint-plugin": "8.57.2",
|
|
66
|
+
"@typescript-eslint/parser": "8.57.2",
|
|
67
|
+
"@vitest/browser": "3.2.4",
|
|
68
|
+
"@vitest/eslint-plugin": "1.6.14",
|
|
69
|
+
"@vue/compiler-dom": "3.5.29",
|
|
70
|
+
"@vue/eslint-config-prettier": "10.2.0",
|
|
71
|
+
"@vue/eslint-config-standard": "8.0.1",
|
|
72
|
+
"@vue/eslint-config-typescript": "14.7.0",
|
|
73
|
+
"@vue/server-renderer": "3.5.29",
|
|
74
|
+
"@vue/test-utils": "2.4.6",
|
|
75
|
+
"@vue/tsconfig": "0.8.1",
|
|
76
|
+
"@vuepic/vue-datepicker": "6.0.3",
|
|
77
|
+
"arg": "5.0.2",
|
|
78
|
+
"babel-eslint": "10.1.0",
|
|
79
|
+
"commitizen": "4.3.1",
|
|
80
|
+
"eslint": "10.0.2",
|
|
81
|
+
"eslint-plugin-prettier": "5.5.5",
|
|
82
|
+
"eslint-plugin-storybook": "10.1.10",
|
|
83
|
+
"eslint-plugin-vue": "10.8.0",
|
|
84
|
+
"globals": "15.11.0",
|
|
85
|
+
"husky": "9.1.6",
|
|
86
|
+
"jsdom": "26.1.0",
|
|
87
|
+
"jsonc-eslint-parser": "2.4.1",
|
|
88
|
+
"lint-staged": "16.4.0",
|
|
89
|
+
"postcss": "8.5.6",
|
|
90
|
+
"prettier": "3.8.1",
|
|
91
|
+
"sass": "1.97.3",
|
|
92
|
+
"start-server-and-test": "2.1.3",
|
|
93
|
+
"storybook": "10.2.12",
|
|
94
|
+
"tsx": "4.21.0",
|
|
95
|
+
"typescript": "5.9.3",
|
|
96
|
+
"vega": "6.2.0",
|
|
97
|
+
"vite-plugin-dts": "4.5.4",
|
|
98
|
+
"vite-plugin-vue-devtools": "8.0.7",
|
|
99
|
+
"vitest": "3.2.4",
|
|
100
|
+
"vue-eslint-parser": "10.4.0",
|
|
101
|
+
"vue-tsc": "3.2.6",
|
|
102
|
+
"yaml": "2.8.3",
|
|
103
|
+
"yaml-eslint-parser": "1.3.1"
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
"managedAnywhere": {
|
|
107
|
+
"@tailwindcss/vite": "4.2.2",
|
|
108
|
+
"@vitejs/plugin-vue": "6.0.5",
|
|
109
|
+
"axios": "1.15.0",
|
|
110
|
+
"dotenv": "16.4.5",
|
|
111
|
+
"qrcode.vue": "3.8.1",
|
|
112
|
+
"tailwindcss": "4.2.2",
|
|
113
|
+
"vite": "7.3.2",
|
|
114
|
+
"vue": "3.5.32"
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
// Base ESLint configuration for Vue / TypeScript FE repos
|
|
2
|
+
// Extend this in your project's eslint.config.js
|
|
3
|
+
|
|
4
|
+
import tseslint from '@typescript-eslint/eslint-plugin'
|
|
5
|
+
import tsparser from '@typescript-eslint/parser'
|
|
6
|
+
import pluginVitest from '@vitest/eslint-plugin'
|
|
7
|
+
import skipFormatting from '@vue/eslint-config-prettier/skip-formatting'
|
|
8
|
+
import pluginVue from 'eslint-plugin-vue'
|
|
9
|
+
import { globalIgnores } from 'eslint/config'
|
|
10
|
+
import vueParser from 'vue-eslint-parser'
|
|
11
|
+
|
|
12
|
+
export default function createBaseConfig(options = {}) {
|
|
13
|
+
const {
|
|
14
|
+
tsconfigRootDir = process.cwd(),
|
|
15
|
+
tsconfigFiles = ['./tsconfig.json'],
|
|
16
|
+
additionalIgnores = [],
|
|
17
|
+
extraNonTypeAwareFiles = [],
|
|
18
|
+
enablePrettier = false,
|
|
19
|
+
enableI18n = false,
|
|
20
|
+
i18nLocaleDir = './src/lang/*.json',
|
|
21
|
+
additionalRules = {},
|
|
22
|
+
additionalPlugins = {},
|
|
23
|
+
additionalSettings = {},
|
|
24
|
+
} = options
|
|
25
|
+
|
|
26
|
+
// Note: Optional plugins should be imported by the consuming project
|
|
27
|
+
// This config accepts them via additionalPlugins option
|
|
28
|
+
|
|
29
|
+
const defaultAdditionalIgnores = [
|
|
30
|
+
'test-results/**',
|
|
31
|
+
'playwright-report/**',
|
|
32
|
+
'blob-report/**',
|
|
33
|
+
'playwright/.cache/**',
|
|
34
|
+
'reports/**',
|
|
35
|
+
'**/fg-devkit/configs/**',
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
const configs = [
|
|
39
|
+
// Non-type-aware config for config files (must come first)
|
|
40
|
+
{
|
|
41
|
+
name: 'fg-devkit/config-files',
|
|
42
|
+
files: ['*.config.{ts,mts,js,mjs,cjs}', 'eslint.config.{js,ts}'],
|
|
43
|
+
languageOptions: {
|
|
44
|
+
parserOptions: {
|
|
45
|
+
project: null,
|
|
46
|
+
tsconfigRootDir,
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: 'fg-devkit/base',
|
|
52
|
+
files: ['**/*.{ts,mts,tsx,vue}'],
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: 'fg-devkit/vue-non-type-aware',
|
|
56
|
+
files: ['**/*.vue'],
|
|
57
|
+
languageOptions: {
|
|
58
|
+
parser: vueParser,
|
|
59
|
+
parserOptions: {
|
|
60
|
+
parser: tsparser,
|
|
61
|
+
project: null,
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: 'fg-devkit/typescript',
|
|
67
|
+
files: ['**/*.{ts,mts,tsx}'],
|
|
68
|
+
languageOptions: {
|
|
69
|
+
parser: tsparser,
|
|
70
|
+
parserOptions: {
|
|
71
|
+
project: null,
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
plugins: {
|
|
75
|
+
'@typescript-eslint': tseslint,
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
// Non-type-aware config for extra files outside tsconfig
|
|
79
|
+
...(extraNonTypeAwareFiles.length
|
|
80
|
+
? [
|
|
81
|
+
{
|
|
82
|
+
name: 'fg-devkit/extra-non-type-aware',
|
|
83
|
+
files: extraNonTypeAwareFiles,
|
|
84
|
+
languageOptions: {
|
|
85
|
+
parserOptions: {
|
|
86
|
+
project: null,
|
|
87
|
+
tsconfigRootDir,
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
]
|
|
92
|
+
: []),
|
|
93
|
+
// Type-aware config for TypeScript files (if tsconfig files provided)
|
|
94
|
+
...(tsconfigFiles && tsconfigFiles.length > 0
|
|
95
|
+
? [
|
|
96
|
+
{
|
|
97
|
+
name: 'fg-devkit/type-aware',
|
|
98
|
+
files: ['src/**/*.{ts,mts,tsx}'],
|
|
99
|
+
languageOptions: {
|
|
100
|
+
parser: tsparser,
|
|
101
|
+
parserOptions: {
|
|
102
|
+
project: tsconfigFiles,
|
|
103
|
+
tsconfigRootDir,
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
]
|
|
108
|
+
: []),
|
|
109
|
+
globalIgnores([
|
|
110
|
+
'**/dist/**',
|
|
111
|
+
'**/coverage/**',
|
|
112
|
+
'**/.storybook/**',
|
|
113
|
+
'**/node_modules/**',
|
|
114
|
+
'*.min.js',
|
|
115
|
+
'tsconfig.tsbuildinfo',
|
|
116
|
+
'.env.local',
|
|
117
|
+
'.env.*.local',
|
|
118
|
+
'*.config.cjs',
|
|
119
|
+
'.eslintrc.cjs',
|
|
120
|
+
...defaultAdditionalIgnores,
|
|
121
|
+
...additionalIgnores,
|
|
122
|
+
]),
|
|
123
|
+
...pluginVue.configs['flat/essential'],
|
|
124
|
+
{
|
|
125
|
+
...pluginVitest.configs.recommended,
|
|
126
|
+
files: ['**/__tests__/**', '**/*.test.*', '**/*.spec.*'],
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
name: 'fg-devkit/rules',
|
|
130
|
+
files: ['**/*.vue', '**/*.js', '**/*.jsx', '**/*.cjs', '**/*.mjs', '**/*.ts', '**/*.tsx', '**/*.cts', '**/*.mts'],
|
|
131
|
+
plugins: {
|
|
132
|
+
'@typescript-eslint': tseslint,
|
|
133
|
+
...additionalPlugins,
|
|
134
|
+
},
|
|
135
|
+
settings: {
|
|
136
|
+
...(enableI18n
|
|
137
|
+
? {
|
|
138
|
+
'vue-i18n': {
|
|
139
|
+
localeDir: {
|
|
140
|
+
pattern: i18nLocaleDir,
|
|
141
|
+
localeKey: 'file',
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
}
|
|
145
|
+
: {}),
|
|
146
|
+
...additionalSettings,
|
|
147
|
+
},
|
|
148
|
+
rules: {
|
|
149
|
+
'vue/multi-word-component-names': 'off',
|
|
150
|
+
'vue/comment-directive': 'off',
|
|
151
|
+
'vue/no-deprecated-slot-attribute': 'off',
|
|
152
|
+
'no-console': ['error', { allow: ['warn', 'error'] }],
|
|
153
|
+
'arrow-body-style': ['warn', 'as-needed', { requireReturnForObjectLiteral: false }],
|
|
154
|
+
// Vue component recognition - allow fds-* components and router components
|
|
155
|
+
'vue/no-undef-components': [
|
|
156
|
+
'error',
|
|
157
|
+
{
|
|
158
|
+
ignorePatterns: ['^fds-', '^router-', '^Router', '^VueQuery'],
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
'object-shorthand': ['error', 'always'],
|
|
162
|
+
'prefer-destructuring': [
|
|
163
|
+
'error',
|
|
164
|
+
{
|
|
165
|
+
array: false,
|
|
166
|
+
object: true,
|
|
167
|
+
},
|
|
168
|
+
],
|
|
169
|
+
'prefer-arrow-callback': 'error',
|
|
170
|
+
'prefer-template': 'error',
|
|
171
|
+
'no-unused-expressions': 'error',
|
|
172
|
+
'no-useless-return': 'error',
|
|
173
|
+
'no-useless-concat': 'error',
|
|
174
|
+
'@typescript-eslint/no-unused-vars': [
|
|
175
|
+
'error',
|
|
176
|
+
{
|
|
177
|
+
argsIgnorePattern: '^_',
|
|
178
|
+
varsIgnorePattern: '^_',
|
|
179
|
+
},
|
|
180
|
+
],
|
|
181
|
+
'@typescript-eslint/ban-ts-comment': 'off',
|
|
182
|
+
'@typescript-eslint/explicit-function-return-type': 'off',
|
|
183
|
+
'@typescript-eslint/no-var-requires': 'off',
|
|
184
|
+
'prefer-const': 'error',
|
|
185
|
+
'no-var': 'error',
|
|
186
|
+
'prefer-spread': 'error',
|
|
187
|
+
'prefer-rest-params': 'error',
|
|
188
|
+
'no-duplicate-imports': 'error',
|
|
189
|
+
'no-useless-rename': 'error',
|
|
190
|
+
'object-curly-spacing': ['error', 'always'],
|
|
191
|
+
'array-bracket-spacing': ['error', 'never'],
|
|
192
|
+
// Note: comma-dangle removed - Prettier handles trailing commas via trailingComma: 'all' setting
|
|
193
|
+
// skipFormatting at the end of config array disables formatting rules that conflict with Prettier
|
|
194
|
+
quotes: ['error', 'single', { avoidEscape: true }],
|
|
195
|
+
semi: ['error', 'never'],
|
|
196
|
+
'no-trailing-spaces': 'error',
|
|
197
|
+
'eol-last': 'error',
|
|
198
|
+
'no-lonely-if': 'error',
|
|
199
|
+
// Prettier integration (if enabled and plugin provided)
|
|
200
|
+
...(enablePrettier && additionalPlugins.prettier ? { 'prettier/prettier': 'warn' } : {}),
|
|
201
|
+
// i18n rules (if enabled and plugin provided)
|
|
202
|
+
...(enableI18n && additionalPlugins['@intlify/vue-i18n']
|
|
203
|
+
? {
|
|
204
|
+
'@intlify/vue-i18n/no-missing-keys': 'error',
|
|
205
|
+
'@intlify/vue-i18n/no-raw-text': [
|
|
206
|
+
'error',
|
|
207
|
+
{
|
|
208
|
+
attributes: {
|
|
209
|
+
'/.+/': [
|
|
210
|
+
'title',
|
|
211
|
+
'aria-label',
|
|
212
|
+
'aria-placeholder',
|
|
213
|
+
'aria-roledescription',
|
|
214
|
+
'aria-valuetext',
|
|
215
|
+
'label',
|
|
216
|
+
'placeholder',
|
|
217
|
+
'alt',
|
|
218
|
+
'meta',
|
|
219
|
+
],
|
|
220
|
+
input: ['placeholder'],
|
|
221
|
+
img: ['alt'],
|
|
222
|
+
},
|
|
223
|
+
ignorePattern: '^[-:/()%,.\'"]+$',
|
|
224
|
+
ignoreNodes: ['md-icon', 'v-icon', 'fds-icon'],
|
|
225
|
+
},
|
|
226
|
+
],
|
|
227
|
+
'@intlify/vue-i18n/no-unused-keys': [
|
|
228
|
+
'warn',
|
|
229
|
+
{
|
|
230
|
+
src: './src',
|
|
231
|
+
extensions: ['.js', '.vue', '.ts'],
|
|
232
|
+
enableFix: false,
|
|
233
|
+
},
|
|
234
|
+
],
|
|
235
|
+
'@intlify/vue-i18n/no-duplicate-keys-in-locale': 'error',
|
|
236
|
+
'@intlify/vue-i18n/no-dynamic-keys': 'warn',
|
|
237
|
+
'@intlify/vue-i18n/key-format-style': [
|
|
238
|
+
'warn',
|
|
239
|
+
'camelCase',
|
|
240
|
+
{
|
|
241
|
+
allowArray: false,
|
|
242
|
+
splitByDots: true,
|
|
243
|
+
},
|
|
244
|
+
],
|
|
245
|
+
}
|
|
246
|
+
: {}),
|
|
247
|
+
// Additional project-specific rules
|
|
248
|
+
...additionalRules,
|
|
249
|
+
},
|
|
250
|
+
},
|
|
251
|
+
// JS/CJS files config
|
|
252
|
+
{
|
|
253
|
+
files: ['**/*.js', '**/*.cjs'],
|
|
254
|
+
rules: {
|
|
255
|
+
'@typescript-eslint/no-var-requires': 'off',
|
|
256
|
+
},
|
|
257
|
+
},
|
|
258
|
+
skipFormatting,
|
|
259
|
+
]
|
|
260
|
+
|
|
261
|
+
return configs
|
|
262
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal ESLint flat config for apps using fg-devkit.
|
|
3
|
+
* Copied to eslint.config.js by sync-tooling-configs / sync-project-configs.
|
|
4
|
+
* Customize locally (plugins, rules) or pass options via createBaseConfig after syncing.
|
|
5
|
+
*/
|
|
6
|
+
import createBaseConfig from 'fg-devkit/eslint.config.base.js'
|
|
7
|
+
import { fileURLToPath } from 'node:url'
|
|
8
|
+
|
|
9
|
+
const tsconfigRootDir = fileURLToPath(new URL('.', import.meta.url))
|
|
10
|
+
|
|
11
|
+
export default [
|
|
12
|
+
{
|
|
13
|
+
ignores: ['.yalc/**', '**/node_modules/**'],
|
|
14
|
+
},
|
|
15
|
+
...createBaseConfig({
|
|
16
|
+
tsconfigRootDir,
|
|
17
|
+
tsconfigFiles: ['./tsconfig.json'],
|
|
18
|
+
}),
|
|
19
|
+
]
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default Prettier options for repos that extend fg-devkit. Import or re-export from your own prettier.config.
|
|
3
|
+
*/
|
|
4
|
+
export default {
|
|
5
|
+
semi: false,
|
|
6
|
+
singleQuote: true,
|
|
7
|
+
printWidth: 120,
|
|
8
|
+
trailingComma: 'all',
|
|
9
|
+
tabWidth: 2,
|
|
10
|
+
useTabs: false,
|
|
11
|
+
arrowParens: 'always',
|
|
12
|
+
endOfLine: 'lf',
|
|
13
|
+
singleAttributePerLine: false,
|
|
14
|
+
bracketSameLine: false,
|
|
15
|
+
htmlWhitespaceSensitivity: 'ignore',
|
|
16
|
+
}
|