@gspothq/cli 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 (205) hide show
  1. package/README.md +58 -11
  2. package/configurations/database/postgres/manifest.toml +51 -57
  3. package/configurations/database/postgres/rules/POSTGRES.md +14 -13
  4. package/configurations/framework/astro/manifest.toml +33 -35
  5. package/configurations/framework/astro/rules/ASTRO.md +2 -2
  6. package/configurations/framework/expo/manifest.toml +19 -19
  7. package/configurations/framework/express/manifest.toml +10 -4
  8. package/configurations/framework/express/rules/EXPRESS.md +9 -7
  9. package/configurations/framework/fastapi/manifest.toml +9 -3
  10. package/configurations/framework/fastapi/rules/FASTAPI.md +19 -18
  11. package/configurations/framework/nestjs/manifest.toml +12 -12
  12. package/configurations/framework/nestjs/rules/NESTJS.md +9 -9
  13. package/configurations/framework/nextjs/manifest.toml +39 -79
  14. package/configurations/framework/nextjs/rules/NEXTJS.md +9 -7
  15. package/configurations/framework/nextjs/tool-files/semgrep/nextjs.yml +35 -0
  16. package/configurations/framework/react/manifest.toml +33 -43
  17. package/configurations/framework/react/rules/REACT.md +14 -20
  18. package/configurations/framework/react-dom/manifest.toml +6 -6
  19. package/configurations/framework/react-native/manifest.toml +11 -11
  20. package/configurations/framework/react-native/rules/REACT-NATIVE.md +3 -5
  21. package/configurations/framework/site/manifest.toml +57 -110
  22. package/configurations/framework/site/rules/SITE.md +1 -1
  23. package/configurations/framework/svelte/manifest.toml +29 -31
  24. package/configurations/framework/svelte/rules/SVELTE.md +6 -6
  25. package/configurations/framework/vue/manifest.toml +37 -37
  26. package/configurations/framework/vue/rules/VUE.md +6 -6
  27. package/configurations/general/commits/manifest.toml +20 -84
  28. package/configurations/general/commits/rules/GIT.md +24 -13
  29. package/configurations/general/coverage/manifest.toml +1 -1
  30. package/configurations/general/dependencies/manifest.toml +47 -107
  31. package/configurations/general/dependencies/rules/DEPENDENCIES.md +13 -7
  32. package/configurations/general/docs/manifest.toml +28 -43
  33. package/configurations/general/docs/rules/DOCS.md +16 -9
  34. package/configurations/general/duplication/manifest.toml +12 -14
  35. package/configurations/general/engineering/manifest.toml +6 -2
  36. package/configurations/general/engineering/rules/agent/PLANNING.md +9 -6
  37. package/configurations/general/engineering/rules/agent/SUPPRESSIONS.md +20 -11
  38. package/configurations/general/engineering/rules/agent/TASKS.md +6 -2
  39. package/configurations/general/engineering/rules/agent/WORKING.md +34 -29
  40. package/configurations/general/engineering/rules/code/ACCESSIBILITY.md +9 -7
  41. package/configurations/general/engineering/rules/code/CLI.md +12 -9
  42. package/configurations/general/engineering/rules/code/COMMENTS.md +11 -1
  43. package/configurations/general/engineering/rules/code/CONFIGURATION.md +2 -0
  44. package/configurations/general/engineering/rules/code/ERRORS.md +5 -3
  45. package/configurations/general/engineering/rules/code/HTTP.md +9 -10
  46. package/configurations/general/engineering/rules/code/LOGGING.md +10 -9
  47. package/configurations/general/engineering/rules/code/TESTING.md +18 -11
  48. package/configurations/general/files/manifest.toml +45 -73
  49. package/configurations/general/files/rules/YAML.md +20 -10
  50. package/configurations/general/format/manifest.toml +53 -106
  51. package/configurations/general/gspot/manifest.toml +19 -39
  52. package/configurations/general/gspot/rules/GENERATED.md +14 -4
  53. package/configurations/general/licenses/manifest.toml +12 -14
  54. package/configurations/general/naming/defaults.json +14 -13
  55. package/configurations/general/naming/manifest.toml +17 -17
  56. package/configurations/general/naming/rules/NAMING.md +87 -67
  57. package/configurations/general/prose/manifest.toml +166 -25
  58. package/configurations/general/prose/rules/WRITING.md +6 -2
  59. package/configurations/general/repository/manifest.toml +12 -12
  60. package/configurations/general/secrets/manifest.toml +52 -73
  61. package/configurations/general/secrets/rules/SECRETS.md +3 -1
  62. package/configurations/general/security/manifest.toml +29 -52
  63. package/configurations/general/security/rules/SECURITY.md +8 -6
  64. package/configurations/general/spelling/manifest.toml +15 -25
  65. package/configurations/general/structure/manifest.toml +31 -31
  66. package/configurations/infrastructure/ansible/manifest.toml +15 -15
  67. package/configurations/infrastructure/docker/manifest.toml +55 -67
  68. package/configurations/infrastructure/docker/rules/DOCKER.md +15 -13
  69. package/configurations/infrastructure/github-actions/manifest.toml +21 -41
  70. package/configurations/infrastructure/github-actions/rules/GITHUB-ACTIONS.md +16 -12
  71. package/configurations/infrastructure/github-actions/tool-files/zizmor.yml +5 -0
  72. package/configurations/infrastructure/nginx/manifest.toml +20 -20
  73. package/configurations/infrastructure/nginx/rules/NGINX.md +5 -4
  74. package/configurations/infrastructure/openapi/manifest.toml +20 -20
  75. package/configurations/infrastructure/openapi/rules/OPENAPI.md +3 -1
  76. package/configurations/infrastructure/xcode/manifest.toml +55 -75
  77. package/configurations/infrastructure/xcode/rules/XCODE.md +5 -3
  78. package/configurations/language/bash/manifest.toml +89 -170
  79. package/configurations/language/bash/rules/BASH.md +79 -17
  80. package/configurations/language/bash/rules/LANGUAGE.md +30 -26
  81. package/configurations/language/bash/rules/OPERATIONS.md +10 -8
  82. package/configurations/language/bash/rules/SAFETY.md +39 -35
  83. package/configurations/language/css/manifest.toml +22 -61
  84. package/configurations/language/css/rules/CSS.md +21 -2
  85. package/configurations/language/css/rules/TAILWIND.md +7 -5
  86. package/configurations/language/html/manifest.toml +16 -35
  87. package/configurations/language/html/rules/HTML.md +23 -5
  88. package/configurations/language/javascript/eslint-runtime-names.json +66 -61
  89. package/configurations/language/javascript/eslint-runtime.mjs +118 -0
  90. package/configurations/language/javascript/manifest.toml +135 -207
  91. package/configurations/language/javascript/rules/BUN.md +2 -2
  92. package/configurations/language/javascript/rules/COMPONENTS.md +4 -4
  93. package/configurations/language/javascript/rules/DENO.md +1 -1
  94. package/configurations/language/javascript/rules/JAVASCRIPT.md +30 -17
  95. package/configurations/language/javascript/rules/NODE.md +2 -2
  96. package/configurations/language/javascript/rules/PLAYWRIGHT.md +10 -9
  97. package/configurations/language/markdown/manifest.toml +20 -51
  98. package/configurations/language/python/manifest.toml +231 -342
  99. package/configurations/language/python/rules/DESIGN.md +40 -33
  100. package/configurations/language/python/rules/FLOW.md +8 -6
  101. package/configurations/language/python/rules/PACKAGING.md +14 -7
  102. package/configurations/language/python/rules/PYTHON.md +83 -33
  103. package/configurations/language/python/rules/TYPING.md +25 -23
  104. package/configurations/language/sql/manifest.toml +19 -37
  105. package/configurations/language/sql/rules/SQL.md +90 -2
  106. package/configurations/language/swift/manifest.toml +67 -78
  107. package/configurations/language/swift/rules/SWIFT.md +138 -40
  108. package/configurations/language/swift/rules/SWIFTUI.md +11 -9
  109. package/configurations/language/swift/rules/UIKIT.md +21 -19
  110. package/configurations/language/typescript/manifest.toml +34 -34
  111. package/configurations/language/typescript/rules/TYPESCRIPT.md +62 -10
  112. package/configurations/library/drizzle/manifest.toml +25 -38
  113. package/configurations/library/drizzle/rules/DRIZZLE.md +4 -2
  114. package/configurations/library/react-hook-form/manifest.toml +4 -4
  115. package/configurations/library/react-hook-form/rules/REACT-HOOK-FORM.md +15 -13
  116. package/configurations/library/tanstack-query/manifest.toml +6 -6
  117. package/configurations/library/tanstack-query/rules/TANSTACK-QUERY.md +5 -3
  118. package/configurations/library/testing-library/manifest.toml +6 -6
  119. package/configurations/library/translations/manifest.toml +22 -22
  120. package/configurations/library/translations/rules/NEXT-INTL.md +6 -8
  121. package/configurations/library/translations/rules/TRANSLATIONS.md +22 -23
  122. package/configurations/library/trpc/manifest.toml +3 -3
  123. package/configurations/library/trpc/rules/TRPC.md +8 -6
  124. package/configurations/library/zod/manifest.toml +6 -6
  125. package/configurations/library/zod/rules/ZOD.md +4 -2
  126. package/configurations/library/zustand/manifest.toml +4 -4
  127. package/configurations/library/zustand/rules/ZUSTAND.md +16 -14
  128. package/configurations/platform/cloudflare/manifest.toml +28 -47
  129. package/configurations/platform/cloudflare/rules/CLOUDFLARE.md +11 -6
  130. package/configurations/platform/supabase/manifest.toml +48 -61
  131. package/configurations/platform/supabase/rules/SUPABASE.md +27 -28
  132. package/configurations/testing/jest/manifest.toml +21 -22
  133. package/configurations/testing/pytest/manifest.toml +28 -28
  134. package/configurations/testing/swift-tests/manifest.toml +18 -29
  135. package/configurations/testing/swift-tests/rules/SWIFT-TESTS.md +7 -5
  136. package/configurations/testing/vitest/manifest.toml +32 -32
  137. package/configurations/testing/vitest/rules/VITEST.md +3 -1
  138. package/dist/gspot.js +22297 -24707
  139. package/dist/{linkinator-program.js → linkinator-process.js} +5 -7
  140. package/dist/{purgecss-program.js → purgecss-process.js} +12 -12
  141. package/package.json +7 -9
  142. package/configurations/infrastructure/github-actions/zizmor.yml +0 -3
  143. package/configurations/language/bash/rules/NAMING.md +0 -62
  144. package/configurations/language/css/rules/NAMING.md +0 -17
  145. package/configurations/language/html/rules/NAMING.md +0 -16
  146. package/configurations/language/javascript/rules/NAMING.md +0 -31
  147. package/configurations/language/markdown/markdownlint-cli2.mjs +0 -19
  148. package/configurations/language/python/rules/NAMING.md +0 -53
  149. package/configurations/language/sql/rules/NAMING.md +0 -90
  150. package/configurations/language/swift/rules/NAMING.md +0 -88
  151. package/configurations/language/typescript/rules/NAMING.md +0 -73
  152. package/configurations/library/swift-snapshot-testing/manifest.toml +0 -32
  153. package/dist/THIRD-PARTY-NOTICES.md +0 -25
  154. package/dist/eslint-rule-levels.json +0 -10
  155. package/dist/tool-versions.json +0 -3
  156. package/gspot.schema.json +0 -45991
  157. /package/{dist/LICENSE.md → LICENSE.md} +0 -0
  158. /package/configurations/framework/express/{semgrep → tool-files/semgrep}/express.yml +0 -0
  159. /package/configurations/framework/fastapi/{semgrep → tool-files/semgrep}/fastapi.yml +0 -0
  160. /package/configurations/general/dependencies/{syncpack.json → tool-files/syncpack.json} +0 -0
  161. /package/configurations/general/prose/{vale → tool-files/vale}/styles/LICENSES.md +0 -0
  162. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/ampm.yml +0 -0
  163. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/conscious-language.yml +0 -0
  164. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/contractions.yml +0 -0
  165. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/currency.yml +0 -0
  166. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/dashes.yml +0 -0
  167. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/date-ordinals.yml +0 -0
  168. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/dates.yml +0 -0
  169. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/file-paths.yml +0 -0
  170. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/future.yml +0 -0
  171. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/hedging.yml +0 -0
  172. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/history.yml +0 -0
  173. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/idioms.yml +0 -0
  174. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/interface-verbs.yml +0 -0
  175. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/jargon.yml +0 -0
  176. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/leading-conjunctions.yml +0 -0
  177. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/link-text.yml +0 -0
  178. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/locations.yml +0 -0
  179. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/marketing.yml +0 -0
  180. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/merge-conflict-markers.yml +0 -0
  181. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/militaristic-language.yml +0 -0
  182. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/modals.yml +0 -0
  183. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/numbered-units.yml +0 -0
  184. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/obvious-fields.yml +0 -0
  185. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/ordinal-adverbs.yml +0 -0
  186. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/percentage-numbers.yml +0 -0
  187. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/placeholders.yml +0 -0
  188. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/product-centric-writing.yml +0 -0
  189. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/punctuated-headings.yml +0 -0
  190. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/self-reference.yml +0 -0
  191. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/session-identifiers.yml +0 -0
  192. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/since.yml +0 -0
  193. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/straight-quotes.yml +0 -0
  194. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/suspended-hyphens.yml +0 -0
  195. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/symbols.yml +0 -0
  196. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/time-ranges.yml +0 -0
  197. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/url-prepositions.yml +0 -0
  198. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/version-range.yml +0 -0
  199. /package/configurations/general/secrets/{gitleaks.toml → tool-files/gitleaks.toml} +0 -0
  200. /package/configurations/infrastructure/docker/{trivyignore → tool-files/trivyignore} +0 -0
  201. /package/configurations/language/bash/{semgrep → tool-files/semgrep}/bash.yml +0 -0
  202. /package/configurations/language/javascript/{semgrep → tool-files/semgrep}/javascript.yml +0 -0
  203. /package/configurations/language/swift/{semgrep → tool-files/semgrep}/swift.yml +0 -0
  204. /package/configurations/platform/cloudflare/{semgrep → tool-files/semgrep}/cloudflare.yml +0 -0
  205. /package/configurations/platform/supabase/{semgrep → tool-files/semgrep}/supabase.yml +0 -0
@@ -1,40 +1,40 @@
1
1
  [configuration]
2
- title = "Translations"
3
- requires = ["javascript"]
4
2
  description = "Translated interfaces: no literal text in components, and message files that parse and stay complete in every locale."
3
+ requires = ["javascript"]
4
+ title = "Translations"
5
5
 
6
6
  [detect]
7
7
  dependencies = ["next-intl", "react-i18next", "i18next", "react-intl", "@lingui/core"]
8
8
 
9
+ [rules."NEXT-INTL.md"]
10
+ dependencies = ["next-intl"]
11
+
9
12
  [[tool]]
13
+ kind = "library"
10
14
  name = "eslint-plugin-i18next"
15
+ npm = "eslint-plugin-i18next"
11
16
  rule_prefix = "i18next"
12
- kind = "library"
13
17
  version = "6.1.5"
14
- npm = "eslint-plugin-i18next"
18
+
19
+ [eslint]
20
+ all_level_rules = ["i18next/no-literal-string"]
21
+
22
+ [[tool_file]]
23
+ fragment = true
24
+ required_tools = ["eslint-plugin-i18next"]
25
+ target = ".gspot/config/eslint.config.mjs"
26
+ tool = "eslint"
15
27
 
16
28
  [[check]]
17
- name = "messages"
18
- example = "If the base locale defines `welcome` but another required locale does not, the check reports the missing key. Add the translated message with matching interpolation arguments."
29
+ example = "When the base locale defines `welcome` and another lacks it, the check reports the missing key. Add the translation with the same placeholders."
30
+ help = "Correct the message, or add the missing key to the locale."
19
31
  level = "recommended"
20
- stage = "push"
32
+ name = "messages"
21
33
  runs = "scope"
22
- summary = "Checks next-intl JSON/ICU message files under translations.messages_folder: each message parses, none is empty, no key holds a dot, and every locale holds every key of the base."
23
- why = "This check compares every locale with the base locale, so missing keys and different interpolation arguments are found across files."
24
- help = "Correct the message, or add the missing key to the locale."
34
+ stage = "push"
35
+ summary = "Checks the next-intl JSON/ICU files under `translations.messages_folder`: each message parses, none stays empty, and each locale holds all keys of the base."
36
+ why = "next-intl loads one locale at a time, so only a comparison with the base finds a missing key."
25
37
 
26
38
  [check.when]
27
39
  dependencies = ["next-intl"]
28
40
  setting = "translations.messages_folder"
29
-
30
- [rules."NEXT-INTL.md"]
31
- dependencies = ["next-intl"]
32
-
33
- [eslint]
34
- all_level_rules = ["i18next/no-literal-string"]
35
-
36
- [[tool_file]]
37
- target = ".gspot/config/eslint.config.mjs"
38
- tool = "eslint"
39
- fragment = true
40
- required_tools = ["eslint-plugin-i18next"]
@@ -1,24 +1,22 @@
1
1
  # next-intl
2
2
 
3
- Rules for `next-intl` in a Next.js App Router application. The locale, catalog, and right-to-left (RTL) rules that
4
- hold for any framework appear in the shared translation rules; these add what the library dictates.
3
+ Read this rule when you change next-intl configuration or messages.
5
4
 
6
5
  ## Configuration
7
6
 
8
7
  - One request configuration module owns locale resolution, message loading, time zone, and the
9
- `now` reference. It validates the candidate locale against the supported list before building a
10
- catalog import path. Nothing else resolves a locale.
8
+ `now` reference. Nothing else resolves a locale.
11
9
  - Define routing in one module: locales, default locale, prefix strategy, and pathnames
12
10
  that both the proxy and the navigation helpers import.
13
- - Use the library's navigation helpers such as `Link`, `redirect`, `usePathname`, `useRouter` for every
14
- internal link so locale prefixes and alternate metadata stay correct. Never `next/link` directly
11
+ - Use the library's navigation helpers such as `Link`, `redirect`, `usePathname`, and `useRouter` for every
12
+ internal link so locale prefixes and alternate metadata stay correct. Never use `next/link` directly
15
13
  in a localized route.
16
14
 
17
15
  ## Server and client boundaries
18
16
 
19
17
  - Use `getTranslations` in async Server Components. Non-async components can use
20
- `useTranslations`; the library selects its server or client implementation from the render context.
21
- - Keep `now` and `timeZone` identical between the server render and the first browser render so
18
+ `useTranslations`; the library picks its server or client implementation from the render context.
19
+ - Keep `now` and `timeZone` identical between the server and the first browser render, so
22
20
  formatted dates and relative times hydrate without mismatch.
23
21
  - Generate `alternates` and `canonical` metadata from the routing definition. Do not hand-write
24
22
  locale URLs in metadata.
@@ -1,24 +1,26 @@
1
1
  # Translations
2
2
 
3
+ Read this rule when you change translated text, locales, or language switching.
4
+
3
5
  Internationalization, or i18n, lets an application support different languages and regional formats.
4
6
  A locale names the language and formatting conventions, message catalogs hold the translated text,
5
7
  and International Components for Unicode (ICU) MessageFormat adds placeholders, plurals, and selection to messages.
6
8
 
7
9
  ## Locales and routing
8
10
 
9
- - Define the supported locales, the default locale, and locale selection in one place, with Best Current Practice (BCP) 47
11
+ - Define the supported locales, the default, and the selection logic in one place, with Best Current Practice (BCP) 47
10
12
  tags such as `en-GB`.
11
13
  - Check a locale from a URL, cookie, or header against the supported list before loading messages,
12
- and build catalog import paths from checked values only. Unsupported input gets the documented
14
+ and build catalog import paths from validated values only. Unsupported input gets the documented
13
15
  default or not-found behavior, not a failed dynamic import.
14
16
  - Choose the routing deliberately. A public site with locale-prefixed URLs needs locale-aware links,
15
17
  redirects, canonical URLs, alternate-language metadata, and sitemap entries. An application
16
- without indexed locale URLs can select the language by cookie or saved preference.
18
+ without indexed locale URLs can pick the language by cookie or saved preference.
17
19
  - Define the precedence among the URL, the saved preference, the negotiated header, and the
18
20
  default, without redirect loops.
19
- - A request-local i18n configuration owns resolution, and request handling and displayed content
20
- use the same locale. Never keep a user's locale in mutable server module state, and partition
21
- localized data in server, browser, and content delivery network (CDN) caches.
21
+ - A request-local i18n configuration owns resolution; handlers and displayed content use the
22
+ same locale. Never keep a user's locale in mutable server module state. Partition localized
23
+ data in server, browser, and content delivery network (CDN) caches.
22
24
 
23
25
  ## Messages and catalogs
24
26
 
@@ -39,23 +41,22 @@ arbitrary server string, a display name, or an English source sentence.
39
41
  - User-generated content, proper names, identifiers, and developer logs supply interpolation data,
40
42
  not message keys, and stay untranslated.
41
43
 
42
- Translate every application-authored string the application displays to the user. That covers headings, buttons,
44
+ Translate every string the application authors and displays to the user. That covers headings, buttons,
43
45
  placeholders, toasts, validation errors, accessible names, image alternatives, navigation,
44
46
  metadata, list status controls, and the empty, error, and loading states.
45
47
 
46
- Plural categories can differ by locale while every locale takes the same input value. Configure
48
+ Plural categories can differ by locale for the same input value. Configure
47
49
  the catalog loader for the application's format and namespace layout.
48
50
 
49
51
  Translations land in the same change as their call sites; an incomplete locale leaves the
50
52
  supported list instead. Checks validate catalog structure. List the locales and screens for the
51
- user to check for linguistic accuracy, dynamic keys, and untranslated UI text. Missing
52
- show keys during development, and make a production fallback intentional and observable, never
53
+ user to check for linguistic accuracy, dynamic keys, and untranslated UI text. Show missing keys during development. Make the production fallback deliberate and visible in the logs, never
53
54
  a silent `catch` that hides a missing catalog.
54
55
 
55
56
  ## Rendering and formatting
56
57
 
57
- - Use the framework's established i18n library. Translate on the server where rendering happens
58
- there, and give each client provider the scoped messages its interactive children need, never
58
+ - Use the framework's established i18n library. Translate on the server where it renders,
59
+ and give each client provider the scoped messages its interactive children need, never
59
60
  every locale or the whole catalog.
60
61
  - Format numbers, currencies, dates, relative times, and time zones through locale-aware APIs.
61
62
  Never infer currency or time zone from language alone.
@@ -66,24 +67,22 @@ a silent `catch` that hides a missing catalog.
66
67
 
67
68
  ## Changing the language
68
69
 
69
- 1. Keep the current resource, relevant search parameters, and hash where the routing supports them.
70
- 2. Persist the preference through the validated write owner when the product promises persistence.
71
- 3. Navigate through the locale-aware routing, so server-rendered content, client labels, and
72
- metadata agree.
73
- 4.
74
-
75
- Refresh locale-dependent query keys and results instead of keeping translated data under an
76
- identity without the locale. 5. Keep focus and scroll position sensible. 6. Report a failed preference write; never show a completed selection that reverts on refresh.
70
+ 1. Keep the current resource, the relevant search parameters, and the hash where the routing supports them.
71
+ 2. Save the preference through the code that validates and stores it, when the product promises to keep it.
72
+ 3. Navigate through the locale-aware routing, so that server-rendered content, client labels, and metadata agree.
73
+ 4. Refresh locale-dependent query keys and results. Do not keep translated data under a key without the locale.
74
+ 5. Keep the focus and the scroll position.
75
+ 6. Report a failed preference write. Never show a selection that reverts on refresh.
77
76
 
78
- A language menu names each language with a clear label, commonly its native name, not a flag.
77
+ A language menu names each language as its speakers write it, not with a flag.
79
78
  Treat region and currency as separate choices when the product offers them.
80
79
 
81
80
  ## Right-to-left layout
82
81
 
83
- Set the document's `lang` and `dir` for the selected locale. List supported right-to-left (RTL)
82
+ Set the document's `lang` and `dir` for the active locale. List supported right-to-left (RTL)
84
83
  locales and affected screens for the user to check. Use logical spacing and alignment properties, and mirror an icon or image only when
85
84
  its meaning requires it. Focus order and horizontal scrolling follow the direction, and record data
86
- never reverses to display RTL text. Include identifiers and URLs inside translated sentences in that list because their directions mix.
85
+ never reverses to display RTL text. Add translated sentences that hold identifiers or URLs to that list, because their text directions mix.
87
86
 
88
87
  ## Verification
89
88
 
@@ -1,14 +1,14 @@
1
1
  allowed_words = ["tRPC"]
2
2
 
3
3
  [configuration]
4
- title = "tRPC"
4
+ description = "tRPC routers: every procedure validates its input, and client code imports the server module as a type only. Name that module `server` in `[[architecture.module]]`."
5
5
  requires = ["javascript"]
6
- description = "tRPC routers: every procedure validates its input, and client code imports the declared server module as a type only. Name your server module `server` in `[[architecture.module]]`."
6
+ title = "tRPC"
7
7
 
8
8
  [detect]
9
9
  dependencies = ["@trpc/server"]
10
10
 
11
11
  [[eslint.selectors]]
12
- selector = "CallExpression[callee.property.name=/^(query|mutation|subscription)$/]:not(:has(CallExpression[callee.property.name='input']))"
13
12
  message = "Give the procedure an input schema before its resolver, even when the input is nothing."
14
13
  role = "routers"
14
+ selector = "CallExpression[callee.property.name=/^(query|mutation|subscription)$/]:not(:has(CallExpression[callee.property.name='input']))"
@@ -1,18 +1,20 @@
1
1
  # tRPC
2
2
 
3
- Use the client integration the project has. Do not mix the classic and TanStack-native clients.
3
+ Read this rule when you change tRPC procedures or their client.
4
+
5
+ Use the client integration the project has. Do not mix the classic client with the TanStack one.
4
6
  Check the installed release before using a version-specific API.
5
7
 
6
8
  ## Request ownership
7
9
 
8
10
  Create context from verified identity for each request. Context creation can run during prefetching,
9
11
  so it performs no writes. Each operation in a batch authorizes itself; a batch does not create a transaction.
10
- Authentication proves identity, and resource authorization proves access to the named resource.
12
+ Authentication proves identity, and authorization proves access to the named resource.
11
13
  Neither a valid input nor a procedure named public proves permission.
12
14
 
13
15
  Direct callers receive verified context explicitly. Never store a session in a process-wide
14
16
  variable or cast a direct caller into an HTTP request. Procedures that share logic call the same
15
- authorized domain operation rather than calling each other.
17
+ authorized domain operation rather than each other.
16
18
 
17
19
  See [authorization](https://trpc.io/docs/server/authorization)
18
20
  and [server callers](https://trpc.io/docs/server/server-side-calls).
@@ -22,18 +24,18 @@ and [server callers](https://trpc.io/docs/server/server-side-calls).
22
24
  Use generated query options and keys. A mutation key identifies a write, not the queries to
23
25
  invalidate. Server rendering and browser consumption use the same QueryClient and serialization
24
26
  contract; private results stay out of dehydration. A rendered server total and client-query rows
25
- need one data owner or coordinated refresh.
27
+ need one source of the data or coordinated refresh.
26
28
 
27
29
  Cookie-setting operations use a transport that can finish headers before streaming. Configure
28
30
  serialization at both ends and preserve transformer metadata. Bound batch sizes and expensive
29
- work. One layer owns retries, and retries of a write require an idempotency contract.
31
+ work. One layer owns retries, and a retried write requires an idempotency contract.
30
32
 
31
33
  See [TanStack integration](https://trpc.io/docs/client/tanstack-react-query/setup)
32
34
  and [links](https://trpc.io/docs/client/links).
33
35
 
34
36
  ## Cancellation and events
35
37
 
36
- Forward cancellation to the work owner and release listeners and streams. A disconnected client
38
+ Forward cancellation to the code that does the work and release listeners and streams. A disconnected client
37
39
  does not prove that a write failed; recover its state by operation identity before retrying.
38
40
  Late responses must not update another resource or session.
39
41
 
@@ -1,25 +1,25 @@
1
1
  allowed_words = ["Zod"]
2
2
 
3
3
  [configuration]
4
- title = "Zod"
4
+ description = "Zod: ESLint rules reject unsafe schema APIs and name the replacement for each deprecated one."
5
5
  requires = ["javascript"]
6
- description = "Zod schemas: ESLint rules reject unsafe schema APIs and recommend replacements for deprecated APIs."
6
+ title = "Zod"
7
7
 
8
8
  [detect]
9
9
  dependencies = ["zod"]
10
10
 
11
11
  [[tool]]
12
+ kind = "library"
12
13
  name = "eslint-plugin-zod"
14
+ npm = "eslint-plugin-zod"
13
15
  rule_prefix = "zod"
14
- kind = "library"
15
16
  version = "4.12.0"
16
- npm = "eslint-plugin-zod"
17
17
 
18
18
  [eslint]
19
19
  all_level_rules = ["zod/no-any-schema", "zod/no-native-enum", "zod/prefer-meta-last", "zod/prefer-strict-object"]
20
20
 
21
21
  [[tool_file]]
22
- target = ".gspot/config/eslint.config.mjs"
23
- tool = "eslint"
24
22
  fragment = true
25
23
  required_tools = ["eslint-plugin-zod"]
24
+ target = ".gspot/config/eslint.config.mjs"
25
+ tool = "eslint"
@@ -1,5 +1,7 @@
1
1
  # Zod
2
2
 
3
+ Read this rule when you write or change a Zod schema.
4
+
3
5
  Check the installed release and its consumers before choosing an API. Put a runtime schema with
4
6
  the feature that owns the contract. Infer input and output types from it rather than keeping a
5
7
  second handwritten contract.
@@ -8,7 +10,7 @@ second handwritten contract.
8
10
 
9
11
  Parse values at the boundary that receives them and pass the parsed result inward. Static types,
10
12
  a constructed validator, and successful client validation do not validate a server request.
11
- An invalid provider response shows an integration failure, not invalid user input. A valid identifier
13
+ An invalid provider response shows an integration failure, not bad user input. A valid identifier
12
14
  proves no access.
13
15
 
14
16
  Choose thrown or returned validation issues to match the boundary. Async checks need async parsing;
@@ -37,7 +39,7 @@ boundary without mutating global locale state for one request.
37
39
 
38
40
  A JSON Schema projection cannot represent every runtime contract. Keep runtime validation and
39
41
  verify the exported dialect against meaningful examples. Use an explicit transport schema for
40
- non-JSON values instead of allowing every value in the projection. Regenerate consumers when the
42
+ non-JSON values instead of allowing anything in the projection. Regenerate consumers when the
41
43
  contract changes, and check omitted fields, defaults, patches, and date handling after an upgrade.
42
44
 
43
45
  See [error customization](https://zod.dev/error-customization)
@@ -1,18 +1,18 @@
1
1
  allowed_words = ["Zustand"]
2
2
 
3
3
  [configuration]
4
- title = "Zustand"
4
+ description = "Zustand: state lives in store files, and components read it through a selector."
5
5
  requires = ["javascript"]
6
- description = "Zustand stores: a store is created in a store file, and a component reads it through a selector."
6
+ title = "Zustand"
7
7
 
8
8
  [detect]
9
9
  dependencies = ["zustand"]
10
10
 
11
11
  [[eslint.selectors]]
12
- selector = "CallExpression[callee.name=/^use[A-Z]\\w*Store$/][arguments.length=0]"
13
12
  message = "Pass a selector to the store hook, so the component renders when its slice changes and at no other time."
13
+ selector = "CallExpression[callee.name=/^use[A-Z]\\w*Store$/][arguments.length=0]"
14
14
 
15
15
  [[tool_file]]
16
+ fragment = true
16
17
  target = ".gspot/config/eslint.config.mjs"
17
18
  tool = "eslint"
18
- fragment = true
@@ -1,5 +1,7 @@
1
1
  # Zustand
2
2
 
3
+ Read this rule when you change a Zustand store.
4
+
3
5
  Zustand holds client state that several components share when local or form state cannot serve them.
4
6
  Fetched server data stays in the query cache.
5
7
 
@@ -13,20 +15,20 @@ Fetched server data stays in the query cache.
13
15
  - In a server-rendered app, create request-dependent stores per request. Never share a store
14
16
  initialized with one user's identity across requests.
15
17
  - An action called outside React uses the intended store instance, passed in, never a hidden
16
- global store that bypasses request or provider scope.
18
+ global one that bypasses request or provider scope.
17
19
  - In a server-rendered app, the provider takes an initial snapshot that matches the first browser
18
20
  render. Browser storage, random values, and current timestamps stay out of that snapshot.
19
- - In a Next.js App Router project, Server Components read authorized server data rather than using
20
- the client store to pass data between requests.
21
+ - In a Next.js App Router project, Server Components read authorized server data rather than passing
22
+ it between requests through the client store.
21
23
  - Place the provider where the state lives: a shared layout keeps state across navigation, and a
22
24
  page or keyed resource provider resets it.
23
- - New initialization props do not reinitialize an existing store. Define a reconciliation action or
25
+ - New initial props do not reinitialize an existing store. Define a reconciliation action or
24
26
  remount at a changed resource boundary, keeping drafts when the interaction needs them.
25
27
 
26
28
  ## Select narrowly and keep results stable
27
29
 
28
30
  - Components select the specific values and actions they read. A large layout or every list row
29
- never subscribes to the whole store through an unselected hook.
31
+ never subscribes to the whole store through a hook without a selector.
30
32
  - Select a primitive, stored entity, or stable action directly when the consumer needs only that value.
31
33
  A selector that returns a tuple, array, or object of several values uses `useShallow` from a
32
34
  supported entry point such as `zustand/react/shallow`.
@@ -35,17 +37,17 @@ Fetched server data stays in the query cache.
35
37
  fresh empty callback.
36
38
  - Custom equality goes through `zustand/traditional` and its peer dependency; the standard `create`
37
39
  takes no equality argument.
38
- - Subscribe rows by entity ID. The list owner subscribes to ordering and paging instead of every
40
+ - Subscribe rows by entity ID. The list component subscribes to ordering and paging instead of every
39
41
  record's content.
40
42
  - Derive values through selectors or computations over authoritative state, never synchronized counts,
41
- array copies, or flags that disagree after a deletion, rollback, or reset.
43
+ array copies, or flags that diverge after a deletion, rollback, or reset.
42
44
  - `getState()` reads an imperative snapshot without a subscription, so rendered values come from
43
45
  selectors. Release manual subscriptions with their owning component or service.
44
46
 
45
47
  ## Update without losing fields
46
48
 
47
49
  - Use a functional `set` when the result depends on current state. Zustand merges the returned
48
- object at the top level only, so a nested change copies each changed ancestor and keeps unchanged
50
+ object at the top level only, so a nested update copies each changed ancestor and keeps the other
49
51
  siblings and references.
50
52
  - Shallow comparison does not inspect nested values: replace a changed object, Map, Set, or array instead of mutating
51
53
  it. Copy an edited record inside a Map too, because a new Map holding the same mutated record
@@ -54,7 +56,7 @@ Fetched server data stays in the query cache.
54
56
  assertion. New stores and resets create fresh collections.
55
57
  - Use `replace: true` only for a complete replacement that keeps the store's shape, actions
56
58
  included. A reset changes the domain state and leaves a usable store.
57
- - A store that already uses Immer changes only the provided draft. It configures Map and Set
59
+ - A store that already uses Immer changes only the draft it receives. It configures Map and Set
58
60
  support where the installed Immer requires it and keeps non-draftable external objects out of
59
61
  drafts.
60
62
  - One store uses one update method, and an immutable-update library joins only when it saves real
@@ -66,8 +68,8 @@ Fetched server data stays in the query cache.
66
68
  confirmed save. They live beside their state and keep its validation and related field changes.
67
69
  - Changes that form one invariant go in one `set` call. Two actions in sequence make two store
68
70
  transitions, and React render batching does not merge them.
69
- - Slices organize one cohesive store, with one owner for each field and action, so spreading slices
70
- cannot silently overwrite names. Middleware wraps the completed store, not each slice, and slice
71
+ - Slices organize one cohesive store, and each field and action lives in exactly one, so spreading
72
+ them cannot silently overwrite names. Middleware wraps the whole store, not each slice, and slice
71
73
  creator types stay compatible with it.
72
74
  - Asynchronous actions keep request identity and cancellation explicit. A delayed action never
73
75
  updates the next resource after the reader moves on.
@@ -77,13 +79,13 @@ Fetched server data stays in the query cache.
77
79
  - `persist` takes a unique storage name and a `partialize` allowlist of durable fields. Actions,
78
80
  request flags, live handles, access tokens, and credentials stay out.
79
81
  - Maps, Sets, and other values that JSON loses get explicit serialization.
80
- - Persist the current shape. When it changes, reset disposable cached state instead of migrating old
81
- shapes, and move required user-authored records to the current shape. Missing, malformed, or
82
+ - Persist the current shape. When it changes, reset disposable cached state instead of migrating
83
+ it, and move required user-authored records to the new shape. Missing, malformed, or
82
84
  unavailable storage yields the initial state.
83
85
  - In a server-rendered app, browser restoration stays apart from the first snapshot. Use
84
86
  `skipHydration` and an explicit `rehydrate()` when automatic restoration changes it.
85
87
  - Track hydration through the supported callbacks or subscriptions, not one read of
86
- `hasHydrated()`, and release the listeners when their owner unmounts.
88
+ `hasHydrated()`, and release the listeners when the component that added them unmounts.
87
89
  - Sign-out and identity or tenant changes reset live private state and clear or partition its
88
90
  persisted copy. Clearing storage alone leaves the in-memory store unchanged.
89
91
  - A pending restoration never reapplies the previous identity's data.
@@ -2,93 +2,74 @@ allowed_words = ["Cloudflare"]
2
2
  generated = ["worker-configuration.d.ts"]
3
3
 
4
4
  [configuration]
5
- title = "Cloudflare"
5
+ description = "Cloudflare Pages and Workers: valid headers and redirects files, current binding types, and Semgrep rules for worker code."
6
6
  requires = ["javascript"]
7
7
  suggests = []
8
- description = "Cloudflare Pages and Workers: a wrangler configuration that parses and pins its date, headers and redirects files Cloudflare can read, fresh binding types, and the Semgrep rules for workers."
8
+ title = "Cloudflare"
9
9
 
10
10
  [detect]
11
+ dependencies = ["wrangler", "@opennextjs/cloudflare"]
11
12
  filenames = ["wrangler.toml", "wrangler.json", "wrangler.jsonc", "_worker.js"]
12
13
  paths = ["**/functions/_middleware.{js,ts}"]
13
- dependencies = ["wrangler", "@opennextjs/cloudflare"]
14
14
 
15
15
  [files]
16
16
  extensions = [".d.ts"]
17
17
  filenames = ["wrangler.toml", "wrangler.json", "wrangler.jsonc", "_headers", "_redirects"]
18
18
 
19
19
  [[tool]]
20
- name = "wrangler"
21
20
  install_hint = "Run: npm install --save-dev wrangler"
22
- system = true
23
- version_command = ["--version"]
24
21
  min_version = "3.78.3"
22
+ name = "wrangler"
25
23
  npm = "wrangler"
26
-
27
- [[tool]]
28
- name = "v8r"
24
+ system = true
25
+ version_command = ["--version"]
29
26
 
30
27
  [[tool_file]]
31
- source = "semgrep/cloudflare.yml"
28
+ level = "all"
29
+ per_scope = true
32
30
  target = ".gspot/config/semgrep/cloudflare.yml"
33
31
  tool = "semgrep"
34
- rule_keys = ["rules"]
35
- per_scope = true
36
32
  when = { configuration = "security" }
37
- level = "all"
38
33
 
39
34
  [[check]]
40
- name = "wrangler"
41
- tool = ["wrangler", "v8r"]
42
- command = ["v8r", "--schema", "{wrangler_schema}", "--ignore-errors", "--output-format", "text", "{files}"]
43
- output = { format = "regex", pattern = "^(?<file>[^#\\s]+)#(?<message>.+)$" }
44
- files = { filenames = ["wrangler.toml", "wrangler.json", "wrangler.jsonc"] }
45
- example = "A Wrangler configuration without `compatibility_date` reports the missing date. Add a reviewed date in `YYYY-MM-DD` form, such as `2025-01-31`, and test the Worker against that runtime behavior."
35
+ example = "An indented `X-Frame-Options: DENY` at the top of `_headers` reports a header with no path. Put a path such as `/*` on an unindented line above it."
36
+ help = "Write each block as a path, then indented lines of a name, a colon, and a value."
46
37
  level = "recommended"
47
- stage = "commit"
48
- runs = "scope"
49
- summary = "Checks that every wrangler configuration parses, names the worker, and pins a compatibility date."
50
- why = "Without a pinned date the runtime changes behavior under a deployed worker."
51
- help = "Add the name and a compatibility_date in the form 2025-01-31."
52
-
53
- [[check]]
54
38
  name = "headers"
55
- example = "An indented `X-Frame-Options: DENY` line before any path in `_headers` reports that the header sits under no path. Put the intended path, such as `/*`, on the preceding unindented line."
56
- level = "recommended"
57
- stage = "commit"
58
39
  runs = "scope"
59
- summary = "Checks that the headers file is blocks of a path line and indented header lines."
40
+ stage = "commit"
41
+ summary = "Checks that `_headers` holds only blocks of a path followed by indented name-value lines."
60
42
  why = "Cloudflare skips a line it cannot read, so a typo silently drops a security header."
61
- help = "Write each block as a path, then indented lines of a name, a colon, and a value."
62
43
 
63
44
  [[check]]
64
- name = "redirects"
65
- example = "The `_redirects` line `/old /new 999` reports an unsupported redirect status. For an intended permanent redirect, change it to `/old /new 301`."
45
+ example = "The `_redirects` line `/old /new 999` reports an unsupported redirect status. For a permanent redirect, change it to `/old /new 301`."
46
+ help = "Write the rule as source, destination, and status."
66
47
  level = "recommended"
67
- stage = "commit"
48
+ name = "redirects"
68
49
  runs = "scope"
50
+ stage = "commit"
69
51
  summary = "Checks each redirect source, destination, and optional status: 200, 301, 302, 303, 307, or 308, without a force suffix."
70
- why = "A redirect Cloudflare cannot read is dropped, and the old address starts to answer 404."
71
- help = "Write the rule as source, destination, status."
52
+ why = "Cloudflare drops a redirect it cannot parse, and the old address starts to answer 404."
72
53
 
73
54
  [[check]]
74
- name = "stale-types"
75
55
  command = ["wrangler", "types", "{file}", "--env-interface", "{setting:cloudflare.types_interface}"]
76
- generated_paths = [{ pattern = "**/{setting:cloudflare.types_file}" }]
77
- example = "A generated Worker environment type file that differs from `wrangler types` output reports drift. Regenerate it using the configured Wrangler project, inspect the changes, and rerun."
56
+ example = "A Worker types file that differs from the output of `wrangler types` reports drift. Run `wrangler types`, and commit the new file."
57
+ generator_outputs = [{ pattern = "**/{setting:cloudflare.types_file}" }]
58
+ help = "Run `wrangler types` and commit the file."
78
59
  level = "recommended"
79
- stage = "push"
60
+ name = "stale-types"
80
61
  runs = "scope"
81
- tool = "wrangler"
62
+ stage = "push"
82
63
  summary = "Checks that a tracked environment types file matches what wrangler writes."
64
+ tool = "wrangler"
83
65
  why = "Stale binding types let code compile against a binding the configuration dropped."
84
- help = "Run wrangler types and commit the file."
85
66
 
86
67
  [[check]]
87
- name = "security-headers"
88
- example = "A configured response-header block without a required security header reports the missing header. Add that header to every governed path block using the value required by settings."
68
+ example = "A path block without a required security header reports it as missing. Add the header, with the value from the settings, to every path block."
69
+ help = "Add the header to the block for every path."
89
70
  level = "recommended"
90
- stage = "commit"
71
+ name = "security-headers"
91
72
  runs = "scope"
73
+ stage = "commit"
92
74
  summary = "Checks that the headers file sets the content type, referrer, and framing headers for every path."
93
- why = "A site of files has no server code, so the headers file is the only place these protections can live."
94
- help = "Add the header to the block for every path."
75
+ why = "A static site has no server code, so these protections can live only in the headers file."
@@ -1,6 +1,6 @@
1
- # Workers
1
+ # Cloudflare Workers
2
2
 
3
- Rules that hold because the code runs on a V8 isolate runtime such as Cloudflare Workers.
3
+ Read this rule when code runs on Cloudflare Workers.
4
4
 
5
5
  ## Global variables
6
6
 
@@ -9,15 +9,20 @@ Rules that hold because the code runs on a V8 isolate runtime such as Cloudflare
9
9
  runtime before using `node:` imports or `process.env`.
10
10
  - Bindings can come from handler arguments, supported entrypoint properties, or `env` imported
11
11
  from `cloudflare:workers`. Build a client from `env` inside the request.
12
- - Module-scope binding access does not permit request-only I/O outside a request context.
12
+ - Code at module scope can read a binding from `env`, but it cannot do I/O with it, such as a KV read. Do I/O inside a request handler.
13
13
 
14
14
  ## Lifetime
15
15
 
16
- - The runtime can reuse or discard isolates. Module state provides neither durable storage nor a safe place
16
+ - The runtime can reuse or discard isolates. Module state offers neither durable storage nor a safe place
17
17
  for request-specific user data.
18
- - Share immutable configuration. Keep mutable request state isolated and persist durable
19
- state through the application's storage contract.
18
+ - Share immutable configuration. Keep mutable request state isolated, and persist durable
19
+ data through the application's storage contract.
20
20
  - Use `ctx.waitUntil()` for work after the response. Use a Queue or Workflow for work that must finish.
21
21
 
22
+ ## Repository
23
+
24
+ - Keep `.wrangler/` and `.dev.vars*` out of Git.
25
+ - Deploy through a task. When CI deploys, its job runs the same task.
26
+
22
27
  See the Cloudflare [Node process support](https://developers.cloudflare.com/workers/runtime-apis/nodejs/process/)
23
28
  and [binding access](https://developers.cloudflare.com/workers/runtime-apis/bindings/).