@akanjs/devkit 3.0.0-alpha.50 → 3.0.0-alpha.51

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/biome.base.json CHANGED
@@ -178,6 +178,10 @@
178
178
  "includes": ["{apps,libs}/**/*.Util.tsx", "{apps,libs}/**/*.Zone.tsx"],
179
179
  "plugins": ["./node_modules/@akanjs/devkit/lint/no-model-type-in-util-zone.grit"]
180
180
  },
181
+ {
182
+ "includes": ["{apps,libs}/**/ui/**/*.tsx", "!**/*.test.tsx", "!**/*.spec.tsx"],
183
+ "plugins": ["./node_modules/@akanjs/devkit/lint/no-async-component-in-ui.grit"]
184
+ },
181
185
  {
182
186
  "includes": ["{apps,libs}/**/*.tsx", "!**/*.test.tsx", "!**/*.spec.tsx"],
183
187
  "plugins": ["./node_modules/@akanjs/devkit/lint/no-unpublished-form-setter.grit"]
@@ -0,0 +1,35 @@
1
+ engine biome(1.0)
2
+ language js(typescript, jsx)
3
+
4
+ // React has no async client component: an async body is a server-only shape, so a `ui/` component that
5
+ // awaits stops rendering the moment any client parent imports it — and `ui/` is written to be reachable
6
+ // from both sides. It also moves the load below the route, where the framework can no longer start it
7
+ // before the first byte. Awaiting belongs to `page/**`, which passes the resolved data down as props.
8
+ //
9
+ // Component-ness is a PascalCase regex on the binding, the same test `no-model-type-in-util-zone.grit`
10
+ // uses. The declarator regex anchors `async` to the initializer position (`[^=]*` cannot cross an `=`),
11
+ // so an async handler declared inside a synchronous component is not read as the component's own body;
12
+ // `not within JsFunctionBody()` drops every nested declaration for the same reason. Out of scope by
13
+ // construction, since neither is a named binding at statement level: an inline `onClick={async () => …}`
14
+ // and an async member of an object literal.
15
+ JsIdentifierBinding() as $name where {
16
+ $name <: r"[A-Z][A-Za-z0-9_$]*",
17
+ not $name <: within JsFunctionBody(),
18
+ not $name <: within JsFormalParameter(),
19
+ or {
20
+ $name <: within JsVariableDeclarator() as $decl where {
21
+ $decl <: r"[A-Z][A-Za-z0-9_$]*\s*(?::[^=]*)?=\s*async[\s\S]*"
22
+ },
23
+ $name <: within JsFunctionDeclaration() as $fn where {
24
+ $fn <: r"(?:export\s+)?(?:default\s+)?async\s+function[\s\S]*"
25
+ },
26
+ $name <: within JsFunctionExportDefaultDeclaration() as $default where {
27
+ $default <: r"(?:export\s+)?(?:default\s+)?async\s+function[\s\S]*"
28
+ }
29
+ },
30
+ register_diagnostic(
31
+ span = $name,
32
+ message = "An async component belongs in page/. React has no async client component, so a ui/ component that awaits breaks as soon as a client parent renders it, and the route can no longer start the load before the first byte. Await in the page — or hand an unawaited fetch.* to a Zone as an init / view prop — and take the resolved data as a prop.",
33
+ severity = "error"
34
+ )
35
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akanjs/devkit",
3
- "version": "3.0.0-alpha.50",
3
+ "version": "3.0.0-alpha.51",
4
4
  "sourceType": "module",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -45,7 +45,7 @@
45
45
  "@langchain/openai": "^1.4.6",
46
46
  "@tailwindcss/node": "^4.3.0",
47
47
  "@trapezedev/project": "^7.1.4",
48
- "akanjs": "3.0.0-alpha.50",
48
+ "akanjs": "3.0.0-alpha.51",
49
49
  "chalk": "^5.6.2",
50
50
  "commander": "^14.0.3",
51
51
  "dayjs": "^1.11.20",