toiljs 0.0.14 → 0.0.16

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 (225) hide show
  1. package/.babelrc +13 -13
  2. package/.gitattributes +2 -2
  3. package/.github/ISSUE_TEMPLATE/bug_report.md +38 -38
  4. package/.github/ISSUE_TEMPLATE/bug_report.yml +90 -90
  5. package/.github/ISSUE_TEMPLATE/config.yml +8 -8
  6. package/.github/ISSUE_TEMPLATE/feature_request.md +20 -20
  7. package/.github/PULL_REQUEST_TEMPLATE.md +43 -43
  8. package/.github/changelog-config.json +45 -45
  9. package/.github/dependabot.yml +27 -27
  10. package/.github/workflows/ci.yml +191 -191
  11. package/.prettierrc.json +11 -11
  12. package/.vscode/settings.json +9 -9
  13. package/CHANGELOG.md +5 -5
  14. package/LICENSE +187 -187
  15. package/README.md +339 -315
  16. package/as-pect.asconfig.json +34 -34
  17. package/as-pect.config.js +65 -65
  18. package/assets/logo.svg +36 -36
  19. package/build/backend/.tsbuildinfo +1 -1
  20. package/build/cli/.tsbuildinfo +1 -1
  21. package/build/cli/index.js +2926 -191
  22. package/build/client/.tsbuildinfo +1 -1
  23. package/build/client/dev/devtools.d.ts +6 -0
  24. package/build/client/dev/devtools.js +442 -0
  25. package/build/client/dev/error-overlay.d.ts +9 -0
  26. package/build/client/dev/error-overlay.js +19 -4
  27. package/build/client/head/metadata.d.ts +3 -1
  28. package/build/client/head/metadata.js +8 -0
  29. package/build/client/index.d.ts +4 -4
  30. package/build/client/index.js +2 -2
  31. package/build/client/navigation/navigation.d.ts +2 -0
  32. package/build/client/navigation/navigation.js +9 -1
  33. package/build/client/navigation/prefetch.d.ts +1 -0
  34. package/build/client/navigation/prefetch.js +35 -0
  35. package/build/client/routing/Router.js +1 -1
  36. package/build/client/routing/hooks.js +6 -2
  37. package/build/client/routing/loader.d.ts +25 -0
  38. package/build/client/routing/loader.js +53 -7
  39. package/build/client/routing/mount.js +4 -3
  40. package/build/compiler/.tsbuildinfo +1 -1
  41. package/build/compiler/config.d.ts +18 -0
  42. package/build/compiler/config.js +8 -0
  43. package/build/compiler/docs.js +16 -16
  44. package/build/compiler/generate.js +3 -0
  45. package/build/compiler/index.d.ts +2 -2
  46. package/build/compiler/index.js +3 -1
  47. package/build/compiler/plugin.js +156 -0
  48. package/build/compiler/prerender.d.ts +1 -0
  49. package/build/compiler/prerender.js +2 -1
  50. package/build/compiler/seo.d.ts +2 -2
  51. package/build/compiler/seo.js +8 -6
  52. package/build/compiler/ssg.d.ts +5 -0
  53. package/build/compiler/ssg.js +121 -0
  54. package/build/io/.tsbuildinfo +1 -1
  55. package/build/logger/.tsbuildinfo +1 -1
  56. package/build/shared/.tsbuildinfo +1 -1
  57. package/eslint.config.js +48 -48
  58. package/examples/basic/client/404.tsx +11 -11
  59. package/examples/basic/client/components/.gitkeep +1 -1
  60. package/examples/basic/client/global-error.tsx +13 -13
  61. package/examples/basic/client/layout.tsx +25 -25
  62. package/examples/basic/client/public/images/.gitkeep +1 -1
  63. package/examples/basic/client/public/images/logo.svg +36 -36
  64. package/examples/basic/client/public/robots.txt +2 -2
  65. package/examples/basic/client/routes/docs/[...slug].tsx +12 -12
  66. package/examples/basic/client/routes/features/error/error.tsx +16 -16
  67. package/examples/basic/client/routes/features/template/b.tsx +14 -14
  68. package/examples/basic/client/routes/files/[[...slug]].tsx +21 -21
  69. package/examples/basic/client/routes/gallery/layout.tsx +13 -13
  70. package/examples/basic/client/routes/io.tsx +24 -24
  71. package/examples/basic/client/routes/loader-demo/loading.tsx +13 -13
  72. package/examples/basic/client/routes/search.tsx +61 -61
  73. package/examples/basic/client/toil.tsx +5 -5
  74. package/package.json +155 -147
  75. package/presets/eslint.js +88 -88
  76. package/presets/no-uint8array-tostring.js +200 -200
  77. package/presets/prettier.json +18 -18
  78. package/presets/tsconfig.json +37 -37
  79. package/src/backend/index.ts +160 -160
  80. package/src/cli/proc.ts +50 -50
  81. package/src/cli/updates.ts +69 -69
  82. package/src/cli/validate.ts +31 -31
  83. package/src/client/channel/channel.ts +146 -146
  84. package/src/client/components/Form.tsx +65 -65
  85. package/src/client/components/Script.tsx +113 -113
  86. package/src/client/components/Slot.tsx +21 -21
  87. package/src/client/dev/devtools.tsx +973 -0
  88. package/src/client/dev/error-overlay.tsx +30 -4
  89. package/src/client/head/head.ts +167 -167
  90. package/src/client/head/metadata.ts +19 -1
  91. package/src/client/index.ts +19 -9
  92. package/src/client/navigation/NavLink.tsx +86 -86
  93. package/src/client/navigation/navigation.ts +25 -5
  94. package/src/client/navigation/prefetch.ts +169 -130
  95. package/src/client/navigation/scroll.ts +53 -53
  96. package/src/client/routing/Router.tsx +8 -2
  97. package/src/client/routing/action.ts +122 -122
  98. package/src/client/routing/error-boundary.tsx +43 -43
  99. package/src/client/routing/hooks.ts +21 -6
  100. package/src/client/routing/loader.ts +325 -225
  101. package/src/client/routing/match.ts +47 -47
  102. package/src/client/routing/mount.tsx +54 -52
  103. package/src/client/routing/params-context.ts +10 -10
  104. package/src/client/routing/slot-context.ts +7 -7
  105. package/src/client/search/search.ts +189 -189
  106. package/src/client/search/use-page-search.ts +73 -73
  107. package/src/client/types.ts +73 -73
  108. package/src/compiler/config.ts +47 -1
  109. package/src/compiler/docs.ts +228 -228
  110. package/src/compiler/generate.ts +394 -391
  111. package/src/compiler/index.ts +64 -54
  112. package/src/compiler/pages.ts +70 -70
  113. package/src/compiler/plugin.ts +170 -2
  114. package/src/compiler/prerender.ts +5 -1
  115. package/src/compiler/seo.ts +23 -7
  116. package/src/compiler/ssg.ts +162 -0
  117. package/src/io/BinaryReader.ts +340 -340
  118. package/src/io/BinaryWriter.ts +385 -385
  119. package/src/io/FastMap.ts +127 -127
  120. package/src/io/index.ts +11 -11
  121. package/src/io/lengths.ts +14 -14
  122. package/src/io/types.ts +18 -18
  123. package/src/logger/index.ts +22 -22
  124. package/src/server/index.ts +10 -10
  125. package/src/server/main.ts +13 -13
  126. package/src/server/tsconfig.json +4 -4
  127. package/src/shared/index.ts +10 -10
  128. package/std/client/index.d.ts +15 -15
  129. package/std/client/package.json +3 -3
  130. package/test/assembly/example.spec.ts +7 -7
  131. package/test/channel.test.ts +21 -21
  132. package/test/dom/Link.test.tsx +47 -47
  133. package/test/dom/NavLink.test.tsx +37 -37
  134. package/test/dom/error-overlay.test.tsx +44 -44
  135. package/test/dom/loader.test.tsx +121 -121
  136. package/test/dom/navigation.test.ts +59 -59
  137. package/test/dom/revalidate.test.tsx +38 -38
  138. package/test/dom/route-head.test.tsx +78 -78
  139. package/test/dom/router-loading.test.tsx +44 -44
  140. package/test/dom/scroll.test.ts +56 -56
  141. package/test/dom/use-metadata.test.tsx +58 -0
  142. package/test/io.test.ts +93 -93
  143. package/test/navlink.test.ts +28 -28
  144. package/test/placeholder.test.ts +9 -9
  145. package/test/routes.test.ts +76 -76
  146. package/test/seo.test.ts +175 -164
  147. package/test/slot-layouts.test.ts +69 -69
  148. package/test/ssg.test.ts +36 -0
  149. package/test/update.test.ts +44 -44
  150. package/test/validate.test.ts +42 -42
  151. package/toil-routes.d.ts +7 -0
  152. package/toilconfig.json +30 -30
  153. package/tsconfig.backend.json +13 -13
  154. package/tsconfig.base.json +35 -35
  155. package/tsconfig.cli.json +13 -13
  156. package/tsconfig.client.json +14 -14
  157. package/tsconfig.compiler.json +13 -13
  158. package/tsconfig.io.json +12 -12
  159. package/tsconfig.json +22 -22
  160. package/tsconfig.logger.json +12 -12
  161. package/tsconfig.server.json +10 -10
  162. package/tsconfig.shared.json +12 -12
  163. package/vitest.config.ts +26 -26
  164. package/.idea/codeStyles/Project.xml +0 -54
  165. package/.idea/codeStyles/codeStyleConfig.xml +0 -5
  166. package/.idea/inspectionProfiles/Project_Default.xml +0 -6
  167. package/.idea/modules.xml +0 -8
  168. package/.idea/prettier.xml +0 -7
  169. package/.idea/toiljs.iml +0 -8
  170. package/.idea/vcs.xml +0 -6
  171. package/.toil/entry.tsx +0 -9
  172. package/.toil/index.html +0 -12
  173. package/.toil/routes.ts +0 -9
  174. package/build/cli/configure.d.ts +0 -16
  175. package/build/cli/configure.js +0 -272
  176. package/build/cli/create.d.ts +0 -16
  177. package/build/cli/create.js +0 -420
  178. package/build/cli/diagnostics.d.ts +0 -55
  179. package/build/cli/diagnostics.js +0 -333
  180. package/build/cli/doctor.d.ts +0 -6
  181. package/build/cli/doctor.js +0 -249
  182. package/build/cli/features.d.ts +0 -25
  183. package/build/cli/features.js +0 -107
  184. package/build/cli/index.d.ts +0 -2
  185. package/build/cli/proc.d.ts +0 -6
  186. package/build/cli/proc.js +0 -31
  187. package/build/cli/ui.d.ts +0 -9
  188. package/build/cli/ui.js +0 -75
  189. package/build/cli/update.d.ts +0 -7
  190. package/build/cli/update.js +0 -117
  191. package/build/cli/updates.d.ts +0 -10
  192. package/build/cli/updates.js +0 -45
  193. package/build/cli/validate.d.ts +0 -4
  194. package/build/cli/validate.js +0 -19
  195. package/build/client/Link.d.ts +0 -8
  196. package/build/client/Link.js +0 -44
  197. package/build/client/NavLink.d.ts +0 -14
  198. package/build/client/NavLink.js +0 -37
  199. package/build/client/Router.d.ts +0 -7
  200. package/build/client/Router.js +0 -55
  201. package/build/client/channel.d.ts +0 -23
  202. package/build/client/channel.js +0 -94
  203. package/build/client/error-boundary.d.ts +0 -16
  204. package/build/client/error-boundary.js +0 -19
  205. package/build/client/head.d.ts +0 -26
  206. package/build/client/head.js +0 -87
  207. package/build/client/hooks.d.ts +0 -17
  208. package/build/client/hooks.js +0 -48
  209. package/build/client/lazy.d.ts +0 -16
  210. package/build/client/lazy.js +0 -53
  211. package/build/client/match.d.ts +0 -2
  212. package/build/client/match.js +0 -32
  213. package/build/client/mount.d.ts +0 -2
  214. package/build/client/mount.js +0 -13
  215. package/build/client/navigation.d.ts +0 -13
  216. package/build/client/navigation.js +0 -97
  217. package/build/client/params-context.d.ts +0 -2
  218. package/build/client/params-context.js +0 -2
  219. package/build/client/prefetch.d.ts +0 -11
  220. package/build/client/prefetch.js +0 -100
  221. package/build/client/runtime.d.ts +0 -31
  222. package/build/client/runtime.js +0 -112
  223. package/build/client/scroll.d.ts +0 -8
  224. package/build/client/scroll.js +0 -36
  225. package/toil-env.d.ts +0 -16
@@ -1,113 +1,113 @@
1
- import { useEffect, type ReactNode } from 'react';
2
-
3
- /**
4
- * When a {@link Script} is injected, relative to the app becoming interactive:
5
- * - `afterInteractive` (default), on mount, once the app is running. Good for analytics, widgets.
6
- * - `lazyOnload`, deferred until the browser is idle (after `window.load`). For low-priority scripts.
7
- * - `beforeInteractive`, as early as possible. In a client-only SPA there is no SSR, so this still
8
- * runs after hydration, but synchronously on first mount with high fetch priority.
9
- */
10
- export type ScriptStrategy = 'beforeInteractive' | 'afterInteractive' | 'lazyOnload';
11
-
12
- /** Props for {@link Script}. Provide either `src` (external) or inline `children` (script body). */
13
- export interface ScriptProps {
14
- /** URL of an external script. Omit when providing an inline script body via `children`. */
15
- src?: string;
16
- /** When to load the script. Default `'afterInteractive'`. */
17
- strategy?: ScriptStrategy;
18
- /** Stable identity for dedup (required for inline scripts; defaults to `src` for external ones). */
19
- id?: string;
20
- /** `type` attribute (e.g. `'module'`, `'application/json'`). */
21
- type?: string;
22
- /** Fired once the script has loaded (external) or been inserted (inline). */
23
- onLoad?: () => void;
24
- /** Fired after load, and on every later mount once the script is already loaded. */
25
- onReady?: () => void;
26
- /** Fired if an external script fails to load. */
27
- onError?: (error: unknown) => void;
28
- /** Inline script body. Mutually exclusive with `src`. */
29
- children?: string;
30
- }
31
-
32
- type LoadState = 'loading' | 'ready';
33
- /** Module-level registry so a given script is injected/executed at most once across the app. */
34
- const registry = new Map<string, LoadState>();
35
-
36
- function inject(props: ScriptProps, key: string): void {
37
- const { src, type, onLoad, onReady, onError, children } = props;
38
- const el = document.createElement('script');
39
- el.dataset.toilScript = key;
40
- if (type !== undefined) el.type = type;
41
-
42
- if (src !== undefined) {
43
- el.src = src;
44
- el.async = true;
45
- el.addEventListener('load', () => {
46
- registry.set(key, 'ready');
47
- onLoad?.();
48
- onReady?.();
49
- });
50
- el.addEventListener('error', (event) => {
51
- registry.delete(key); // allow a later remount to retry
52
- onError?.(event);
53
- });
54
- document.head.appendChild(el);
55
- } else {
56
- el.textContent = children ?? '';
57
- document.head.appendChild(el);
58
- registry.set(key, 'ready');
59
- onLoad?.();
60
- onReady?.();
61
- }
62
- }
63
-
64
- /**
65
- * Loads an external or inline `<script>` with a load `strategy`, deduplicated across the app so the
66
- * same script never executes twice. Renders nothing. Mirrors the ergonomics of Next.js `next/script`
67
- * for a client-only SPA.
68
- */
69
- export function Script(props: ScriptProps): ReactNode {
70
- const { src, id, strategy = 'afterInteractive', onReady } = props;
71
- const key = id ?? src;
72
-
73
- useEffect(() => {
74
- if (key === undefined) {
75
- // No id and no src: nothing to dedup or load (an inline script needs at least an id).
76
- return;
77
- }
78
-
79
- const state = registry.get(key);
80
- if (state === 'ready') {
81
- onReady?.();
82
- return;
83
- }
84
- if (state === 'loading') {
85
- return; // another instance is already injecting it
86
- }
87
-
88
- registry.set(key, 'loading');
89
- const run = (): void => {
90
- inject(props, key);
91
- };
92
-
93
- if (strategy === 'lazyOnload') {
94
- if (document.readyState === 'complete') {
95
- const idle = window.requestIdleCallback?.bind(window);
96
- if (idle) idle(run);
97
- else setTimeout(run, 0);
98
- } else {
99
- window.addEventListener('load', run, { once: true });
100
- }
101
- return () => {
102
- window.removeEventListener('load', run);
103
- };
104
- }
105
-
106
- // beforeInteractive + afterInteractive: inject now (on mount).
107
- run();
108
- // Intentionally keyed on identity only: inject once per script key; later prop changes
109
- // (handlers, body) are read at inject time and must not re-run/re-inject the script.
110
- }, [key, strategy]);
111
-
112
- return null;
113
- }
1
+ import { useEffect, type ReactNode } from 'react';
2
+
3
+ /**
4
+ * When a {@link Script} is injected, relative to the app becoming interactive:
5
+ * - `afterInteractive` (default), on mount, once the app is running. Good for analytics, widgets.
6
+ * - `lazyOnload`, deferred until the browser is idle (after `window.load`). For low-priority scripts.
7
+ * - `beforeInteractive`, as early as possible. In a client-only SPA there is no SSR, so this still
8
+ * runs after hydration, but synchronously on first mount with high fetch priority.
9
+ */
10
+ export type ScriptStrategy = 'beforeInteractive' | 'afterInteractive' | 'lazyOnload';
11
+
12
+ /** Props for {@link Script}. Provide either `src` (external) or inline `children` (script body). */
13
+ export interface ScriptProps {
14
+ /** URL of an external script. Omit when providing an inline script body via `children`. */
15
+ src?: string;
16
+ /** When to load the script. Default `'afterInteractive'`. */
17
+ strategy?: ScriptStrategy;
18
+ /** Stable identity for dedup (required for inline scripts; defaults to `src` for external ones). */
19
+ id?: string;
20
+ /** `type` attribute (e.g. `'module'`, `'application/json'`). */
21
+ type?: string;
22
+ /** Fired once the script has loaded (external) or been inserted (inline). */
23
+ onLoad?: () => void;
24
+ /** Fired after load, and on every later mount once the script is already loaded. */
25
+ onReady?: () => void;
26
+ /** Fired if an external script fails to load. */
27
+ onError?: (error: unknown) => void;
28
+ /** Inline script body. Mutually exclusive with `src`. */
29
+ children?: string;
30
+ }
31
+
32
+ type LoadState = 'loading' | 'ready';
33
+ /** Module-level registry so a given script is injected/executed at most once across the app. */
34
+ const registry = new Map<string, LoadState>();
35
+
36
+ function inject(props: ScriptProps, key: string): void {
37
+ const { src, type, onLoad, onReady, onError, children } = props;
38
+ const el = document.createElement('script');
39
+ el.dataset.toilScript = key;
40
+ if (type !== undefined) el.type = type;
41
+
42
+ if (src !== undefined) {
43
+ el.src = src;
44
+ el.async = true;
45
+ el.addEventListener('load', () => {
46
+ registry.set(key, 'ready');
47
+ onLoad?.();
48
+ onReady?.();
49
+ });
50
+ el.addEventListener('error', (event) => {
51
+ registry.delete(key); // allow a later remount to retry
52
+ onError?.(event);
53
+ });
54
+ document.head.appendChild(el);
55
+ } else {
56
+ el.textContent = children ?? '';
57
+ document.head.appendChild(el);
58
+ registry.set(key, 'ready');
59
+ onLoad?.();
60
+ onReady?.();
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Loads an external or inline `<script>` with a load `strategy`, deduplicated across the app so the
66
+ * same script never executes twice. Renders nothing. Mirrors the ergonomics of Next.js `next/script`
67
+ * for a client-only SPA.
68
+ */
69
+ export function Script(props: ScriptProps): ReactNode {
70
+ const { src, id, strategy = 'afterInteractive', onReady } = props;
71
+ const key = id ?? src;
72
+
73
+ useEffect(() => {
74
+ if (key === undefined) {
75
+ // No id and no src: nothing to dedup or load (an inline script needs at least an id).
76
+ return;
77
+ }
78
+
79
+ const state = registry.get(key);
80
+ if (state === 'ready') {
81
+ onReady?.();
82
+ return;
83
+ }
84
+ if (state === 'loading') {
85
+ return; // another instance is already injecting it
86
+ }
87
+
88
+ registry.set(key, 'loading');
89
+ const run = (): void => {
90
+ inject(props, key);
91
+ };
92
+
93
+ if (strategy === 'lazyOnload') {
94
+ if (document.readyState === 'complete') {
95
+ const idle = window.requestIdleCallback?.bind(window);
96
+ if (idle) idle(run);
97
+ else setTimeout(run, 0);
98
+ } else {
99
+ window.addEventListener('load', run, { once: true });
100
+ }
101
+ return () => {
102
+ window.removeEventListener('load', run);
103
+ };
104
+ }
105
+
106
+ // beforeInteractive + afterInteractive: inject now (on mount).
107
+ run();
108
+ // Intentionally keyed on identity only: inject once per script key; later prop changes
109
+ // (handlers, body) are read at inject time and must not re-run/re-inject the script.
110
+ }, [key, strategy]);
111
+
112
+ return null;
113
+ }
@@ -1,21 +1,21 @@
1
- import { useContext, type ReactNode } from 'react';
2
-
3
- import { SlotContext } from '../routing/slot-context.js';
4
-
5
- /** Props for {@link Slot}. */
6
- export interface SlotProps {
7
- /** The parallel-slot name, the `@name` directory under `routes/` (without the `@`). */
8
- name: string;
9
- /** Rendered when the slot has no match for the current URL. Default `null`. */
10
- fallback?: ReactNode;
11
- }
12
-
13
- /**
14
- * Renders the parallel-route slot named `name` for the current URL. Place it in a layout or page to
15
- * show an `@name` route tree alongside the main content (e.g. a persistent sidebar, or a modal that
16
- * an intercepting route fills). Renders `fallback` (default nothing) when no slot route matches.
17
- */
18
- export function Slot({ name, fallback = null }: SlotProps): ReactNode {
19
- const slots = useContext(SlotContext);
20
- return slots[name] ?? fallback;
21
- }
1
+ import { useContext, type ReactNode } from 'react';
2
+
3
+ import { SlotContext } from '../routing/slot-context.js';
4
+
5
+ /** Props for {@link Slot}. */
6
+ export interface SlotProps {
7
+ /** The parallel-slot name, the `@name` directory under `routes/` (without the `@`). */
8
+ name: string;
9
+ /** Rendered when the slot has no match for the current URL. Default `null`. */
10
+ fallback?: ReactNode;
11
+ }
12
+
13
+ /**
14
+ * Renders the parallel-route slot named `name` for the current URL. Place it in a layout or page to
15
+ * show an `@name` route tree alongside the main content (e.g. a persistent sidebar, or a modal that
16
+ * an intercepting route fills). Renders `fallback` (default nothing) when no slot route matches.
17
+ */
18
+ export function Slot({ name, fallback = null }: SlotProps): ReactNode {
19
+ const slots = useContext(SlotContext);
20
+ return slots[name] ?? fallback;
21
+ }