@davidsouther/jiffies 2026.24.0 → 2026.24.2

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 (226) hide show
  1. package/lib/esm/assert.d.ts +26 -0
  2. package/lib/esm/assert.js +38 -0
  3. package/lib/esm/awaitable.js +1 -0
  4. package/lib/esm/case.d.ts +1 -0
  5. package/lib/esm/case.js +5 -0
  6. package/lib/esm/components/accordion.d.ts +5 -0
  7. package/lib/esm/components/accordion.js +9 -0
  8. package/lib/esm/components/alert.d.ts +7 -0
  9. package/lib/esm/components/alert.js +31 -0
  10. package/lib/esm/components/button_bar.d.ts +8 -0
  11. package/lib/esm/components/button_bar.js +25 -0
  12. package/lib/esm/components/card.d.ts +8 -0
  13. package/lib/esm/components/card.js +31 -0
  14. package/lib/esm/components/children.d.ts +2 -0
  15. package/{src/components/children.ts → lib/esm/components/children.js} +2 -6
  16. package/lib/esm/components/form.d.ts +5 -0
  17. package/lib/esm/components/form.js +13 -0
  18. package/{src/components/index.ts → lib/esm/components/index.d.ts} +2 -15
  19. package/lib/esm/components/index.js +10 -0
  20. package/lib/esm/components/inline_edit.d.ts +12 -0
  21. package/lib/esm/components/inline_edit.js +48 -0
  22. package/lib/esm/components/link.d.ts +5 -0
  23. package/lib/esm/components/link.js +11 -0
  24. package/lib/esm/components/logger.d.ts +6 -0
  25. package/lib/esm/components/logger.js +22 -0
  26. package/lib/esm/components/modal.d.ts +2 -0
  27. package/{src/components/modal.ts → lib/esm/components/modal.js} +3 -8
  28. package/lib/esm/components/nav.d.ts +11 -0
  29. package/lib/esm/components/nav.js +27 -0
  30. package/lib/esm/components/property.d.ts +9 -0
  31. package/lib/esm/components/property.js +16 -0
  32. package/lib/esm/components/select.d.ts +10 -0
  33. package/lib/esm/components/select.js +3 -0
  34. package/lib/esm/components/tabs.d.ts +20 -0
  35. package/lib/esm/components/tabs.js +45 -0
  36. package/lib/esm/components/virtual_scroll.d.ts +42 -0
  37. package/lib/esm/components/virtual_scroll.js +94 -0
  38. package/lib/esm/debounce.d.ts +1 -0
  39. package/lib/esm/debounce.js +11 -0
  40. package/lib/esm/diff.d.ts +15 -0
  41. package/lib/esm/diff.js +50 -0
  42. package/lib/esm/display.d.ts +5 -0
  43. package/lib/esm/display.js +11 -0
  44. package/lib/esm/dom/css/border.d.ts +11 -0
  45. package/lib/esm/dom/css/border.js +27 -0
  46. package/lib/esm/dom/css/constants.d.ts +31 -0
  47. package/lib/esm/dom/css/constants.js +28 -0
  48. package/lib/esm/dom/css/core.d.ts +5 -0
  49. package/lib/esm/dom/css/core.js +24 -0
  50. package/lib/esm/dom/css/fstyle.d.ts +5 -0
  51. package/lib/esm/dom/css/fstyle.js +32 -0
  52. package/lib/esm/dom/css/sizing.d.ts +5 -0
  53. package/lib/esm/dom/css/sizing.js +10 -0
  54. package/lib/esm/dom/dom.d.ts +36 -0
  55. package/lib/esm/dom/dom.js +217 -0
  56. package/lib/esm/dom/fc.d.ts +10 -0
  57. package/lib/esm/dom/fc.js +32 -0
  58. package/lib/esm/dom/form/form.app.d.ts +1 -0
  59. package/lib/esm/dom/form/form.app.js +19 -0
  60. package/lib/esm/dom/form/form.d.ts +27 -0
  61. package/lib/esm/dom/form/form.js +65 -0
  62. package/lib/esm/dom/html.d.ts +112 -0
  63. package/{src/dom/html.ts → lib/esm/dom/html.js} +2 -14
  64. package/lib/esm/dom/hydrate.d.ts +39 -0
  65. package/lib/esm/dom/hydrate.js +187 -0
  66. package/lib/esm/dom/index.js +2 -0
  67. package/lib/esm/dom/navigation/index.d.ts +76 -0
  68. package/lib/esm/dom/navigation/index.js +292 -0
  69. package/lib/esm/dom/observable.d.ts +2 -0
  70. package/lib/esm/dom/observable.js +6 -0
  71. package/lib/esm/dom/provide.d.ts +3 -0
  72. package/lib/esm/dom/provide.js +7 -0
  73. package/lib/esm/dom/render.d.ts +8 -0
  74. package/lib/esm/dom/render.js +28 -0
  75. package/lib/esm/dom/router/link.d.ts +6 -0
  76. package/lib/esm/dom/router/link.js +3 -0
  77. package/lib/esm/dom/router/router.d.ts +13 -0
  78. package/lib/esm/dom/router/router.js +52 -0
  79. package/lib/esm/dom/svg.d.ts +64 -0
  80. package/{src/dom/svg.ts → lib/esm/dom/svg.js} +2 -19
  81. package/lib/esm/dom/types/css.d.ts +6590 -0
  82. package/lib/esm/dom/types/css.js +1 -0
  83. package/lib/esm/dom/types/dom.js +1 -0
  84. package/lib/esm/dom/types/html.d.ts +614 -0
  85. package/lib/esm/dom/types/html.js +1 -0
  86. package/lib/esm/dom/xml.d.ts +1 -0
  87. package/lib/esm/dom/xml.js +4 -0
  88. package/lib/esm/equal.d.ts +11 -0
  89. package/lib/esm/equal.js +43 -0
  90. package/lib/esm/fs.d.ts +72 -0
  91. package/lib/esm/fs.js +227 -0
  92. package/lib/esm/fs_node.d.ts +15 -0
  93. package/lib/esm/fs_node.js +45 -0
  94. package/lib/esm/generator.d.ts +1 -0
  95. package/lib/esm/generator.js +10 -0
  96. package/lib/esm/lock.d.ts +1 -0
  97. package/lib/esm/lock.js +23 -0
  98. package/lib/esm/log.d.ts +69 -0
  99. package/lib/esm/log.js +211 -0
  100. package/lib/esm/observable/event.d.ts +35 -0
  101. package/lib/esm/observable/event.js +46 -0
  102. package/lib/esm/observable/observable.d.ts +134 -0
  103. package/lib/esm/observable/observable.js +349 -0
  104. package/lib/esm/range.d.ts +1 -0
  105. package/lib/esm/range.js +7 -0
  106. package/lib/esm/result.d.ts +31 -0
  107. package/lib/esm/result.js +66 -0
  108. package/lib/esm/safe.d.ts +1 -0
  109. package/lib/esm/safe.js +10 -0
  110. package/lib/esm/server/http/apps.d.ts +5 -0
  111. package/lib/esm/server/http/apps.js +23 -0
  112. package/lib/esm/server/http/css.d.ts +5 -0
  113. package/lib/esm/server/http/css.js +43 -0
  114. package/lib/esm/server/http/index.d.ts +16 -0
  115. package/lib/esm/server/http/index.js +78 -0
  116. package/lib/esm/server/http/response.d.ts +4 -0
  117. package/lib/esm/server/http/response.js +43 -0
  118. package/lib/esm/server/http/sitemap.d.ts +2 -0
  119. package/lib/esm/server/http/sitemap.js +22 -0
  120. package/lib/esm/server/http/static.d.ts +2 -0
  121. package/lib/esm/server/http/static.js +22 -0
  122. package/lib/esm/server/http/typescript.d.ts +5 -0
  123. package/lib/esm/server/http/typescript.js +40 -0
  124. package/lib/esm/server/live-reload.d.ts +46 -0
  125. package/lib/esm/server/live-reload.js +161 -0
  126. package/lib/esm/server/main.d.ts +2 -0
  127. package/{src/server/main.ts → lib/esm/server/main.js} +8 -15
  128. package/lib/esm/server/ws/frame.d.ts +2 -0
  129. package/lib/esm/server/ws/frame.js +35 -0
  130. package/lib/esm/server/ws/handshake.d.ts +4 -0
  131. package/lib/esm/server/ws/handshake.js +32 -0
  132. package/lib/esm/server/ws/index.d.ts +14 -0
  133. package/lib/esm/server/ws/index.js +68 -0
  134. package/lib/esm/ssg/bundle.d.ts +14 -0
  135. package/lib/esm/ssg/bundle.js +73 -0
  136. package/lib/esm/ssg/copy-public.d.ts +6 -0
  137. package/lib/esm/ssg/copy-public.js +34 -0
  138. package/lib/esm/ssg/discover.d.ts +15 -0
  139. package/lib/esm/ssg/discover.js +117 -0
  140. package/lib/esm/ssg/main.d.ts +2 -0
  141. package/lib/esm/ssg/main.js +122 -0
  142. package/lib/esm/ssg/rewrite.d.ts +9 -0
  143. package/{src/ssg/rewrite.ts → lib/esm/ssg/rewrite.js} +6 -9
  144. package/lib/esm/ssg/ssg.d.ts +26 -0
  145. package/lib/esm/ssg/ssg.js +84 -0
  146. package/lib/esm/transpile.d.mts +3 -0
  147. package/lib/esm/transpile.mjs +12 -0
  148. package/package.json +11 -7
  149. package/src/404.html +0 -14
  150. package/src/assert.ts +0 -56
  151. package/src/case.ts +0 -5
  152. package/src/components/_notes +0 -33
  153. package/src/components/accordion.ts +0 -25
  154. package/src/components/alert.ts +0 -47
  155. package/src/components/button_bar.ts +0 -42
  156. package/src/components/card.ts +0 -54
  157. package/src/components/form.ts +0 -25
  158. package/src/components/inline_edit.ts +0 -78
  159. package/src/components/link.ts +0 -22
  160. package/src/components/logger.ts +0 -35
  161. package/src/components/nav.ts +0 -42
  162. package/src/components/property.ts +0 -32
  163. package/src/components/select.ts +0 -22
  164. package/src/components/tabs.ts +0 -82
  165. package/src/components/virtual_scroll.ts +0 -199
  166. package/src/debounce.ts +0 -14
  167. package/src/diff.ts +0 -82
  168. package/src/display.ts +0 -18
  169. package/src/dom/README.md +0 -107
  170. package/src/dom/SKILL.md +0 -201
  171. package/src/dom/css/border.ts +0 -47
  172. package/src/dom/css/constants.ts +0 -34
  173. package/src/dom/css/core.ts +0 -28
  174. package/src/dom/css/fstyle.ts +0 -42
  175. package/src/dom/css/sizing.ts +0 -11
  176. package/src/dom/dom.ts +0 -327
  177. package/src/dom/fc.ts +0 -81
  178. package/src/dom/form/form.app.ts +0 -44
  179. package/src/dom/form/form.ts +0 -151
  180. package/src/dom/form/index.html +0 -15
  181. package/src/dom/hydrate.ts +0 -206
  182. package/src/dom/navigation/index.ts +0 -349
  183. package/src/dom/observable.ts +0 -11
  184. package/src/dom/provide.ts +0 -11
  185. package/src/dom/render.ts +0 -41
  186. package/src/dom/router/link.ts +0 -14
  187. package/src/dom/router/router.ts +0 -72
  188. package/src/dom/types/css.ts +0 -10088
  189. package/src/dom/types/html.ts +0 -629
  190. package/src/dom/xml.ts +0 -11
  191. package/src/equal.ts +0 -66
  192. package/src/favicon.ico +0 -0
  193. package/src/fs.ts +0 -300
  194. package/src/fs_node.ts +0 -57
  195. package/src/generator.ts +0 -12
  196. package/src/hooks/_notes +0 -6
  197. package/src/lock.ts +0 -23
  198. package/src/log.ts +0 -307
  199. package/src/observable/_notes +0 -26
  200. package/src/observable/event.ts +0 -93
  201. package/src/observable/observable.ts +0 -484
  202. package/src/range.ts +0 -7
  203. package/src/result.ts +0 -107
  204. package/src/safe.ts +0 -12
  205. package/src/server/http/apps.ts +0 -26
  206. package/src/server/http/css.ts +0 -49
  207. package/src/server/http/index.ts +0 -127
  208. package/src/server/http/response.ts +0 -60
  209. package/src/server/http/sitemap.ts +0 -24
  210. package/src/server/http/static.ts +0 -28
  211. package/src/server/http/typescript.ts +0 -46
  212. package/src/server/live-reload.ts +0 -208
  213. package/src/server/ws/frame.ts +0 -36
  214. package/src/server/ws/handshake.ts +0 -42
  215. package/src/server/ws/index.ts +0 -100
  216. package/src/ssg/bundle.ts +0 -85
  217. package/src/ssg/copy-public.ts +0 -44
  218. package/src/ssg/discover.ts +0 -143
  219. package/src/ssg/main.ts +0 -168
  220. package/src/ssg/ssg.ts +0 -134
  221. package/src/transpile.mjs +0 -16
  222. package/src/zip/spec.txt +0 -3260
  223. package/tsconfig.json +0 -34
  224. /package/{src/awaitable.ts → lib/esm/awaitable.d.ts} +0 -0
  225. /package/{src/dom/index.ts → lib/esm/dom/index.d.ts} +0 -0
  226. /package/{src/dom/types/dom.ts → lib/esm/dom/types/dom.d.ts} +0 -0
package/src/fs.ts DELETED
@@ -1,300 +0,0 @@
1
- import { assertExists } from "./assert.ts";
2
-
3
- // Treat localstorage as a file system
4
- export type PathLike = string;
5
-
6
- export interface PlatformParts {
7
- SEP: string;
8
- WD: string;
9
- isAbsolute(path: PathLike): boolean;
10
- }
11
-
12
- export const PLATFORM_PARTS_WIN: PlatformParts = {
13
- SEP: "\\",
14
- WD: "C:\\\\",
15
- isAbsolute: (path) => Boolean(path.match(/^[a-zA-Z]:\\/)),
16
- };
17
-
18
- export const PLATFORM_PARTS_UNIX: PlatformParts = {
19
- SEP: "/",
20
- WD: "/",
21
- isAbsolute: (path) => path[0] === "/",
22
- };
23
-
24
- export const PLATFORM_PARTS: PlatformParts =
25
- typeof process !== "undefined" && process.platform === "win32"
26
- ? PLATFORM_PARTS_WIN
27
- : PLATFORM_PARTS_UNIX;
28
-
29
- export const SEP = PLATFORM_PARTS.SEP;
30
- export const WD = PLATFORM_PARTS.WD;
31
- export const isAbsolute = PLATFORM_PARTS.isAbsolute;
32
-
33
- // Compatible with Node's fs.Dirent
34
- export interface Stats {
35
- isDirectory(): boolean;
36
- isFile(): boolean;
37
- name: string;
38
- }
39
-
40
- export function basename(filename: PathLike): string {
41
- if (filename.endsWith(SEP)) {
42
- filename = filename.substring(0, filename.length - 1);
43
- }
44
- const basename = filename.split(SEP).at(-1) ?? "";
45
- return basename;
46
- }
47
-
48
- function join(...paths: string[]): string {
49
- const pathParts: string[] = [];
50
- for (const path of paths) {
51
- for (const part of path.split(SEP)) {
52
- switch (part) {
53
- case "":
54
- case ".":
55
- break;
56
- case "..":
57
- pathParts.pop();
58
- break;
59
- default:
60
- pathParts.push(part);
61
- }
62
- }
63
- }
64
- return (
65
- (PLATFORM_PARTS === PLATFORM_PARTS_UNIX ? SEP : "") + pathParts.join(SEP)
66
- );
67
- }
68
-
69
- export interface FileSystemAdapter {
70
- stat(path: PathLike): Promise<Stats>;
71
- readdir(path: PathLike): Promise<string[]>;
72
- scandir(path: PathLike): Promise<Stats[]>;
73
- mkdir(path: PathLike): Promise<void>;
74
- copyFile(from: PathLike, to: PathLike): Promise<void>;
75
- readFile(path: PathLike): Promise<string>;
76
- writeFile(path: PathLike, contents: string): Promise<void>;
77
- rm(path: PathLike): Promise<void>;
78
- }
79
-
80
- export class FileSystem implements FileSystemAdapter {
81
- protected wd = WD;
82
- protected stack: string[] = [];
83
- protected adapter: FileSystemAdapter;
84
-
85
- constructor(adapter: FileSystemAdapter = new RecordFileSystemAdapter()) {
86
- this.adapter = adapter;
87
- }
88
-
89
- cwd(): string {
90
- return this.wd;
91
- }
92
-
93
- cd(dir: string) {
94
- this.wd = this.p(dir);
95
- }
96
-
97
- pushd(dir: string) {
98
- this.stack.push(this.wd);
99
- this.cd(dir);
100
- }
101
-
102
- popd() {
103
- if (this.stack.length > 0) {
104
- this.wd = assertExists(this.stack.pop());
105
- }
106
- }
107
-
108
- stat(path: PathLike): Promise<Stats> {
109
- return this.adapter.stat(this.p(path));
110
- }
111
-
112
- scandir(path: PathLike): Promise<Stats[]> {
113
- return this.adapter.scandir(this.p(path));
114
- }
115
-
116
- readdir(path: PathLike): Promise<string[]> {
117
- return this.adapter.readdir(this.p(path));
118
- }
119
-
120
- mkdir(path: string): Promise<void> {
121
- return this.adapter.mkdir(this.p(path));
122
- }
123
-
124
- copyFile(from: PathLike, to: PathLike): Promise<void> {
125
- return this.adapter.copyFile(this.p(from), this.p(to));
126
- }
127
-
128
- readFile(path: PathLike): Promise<string> {
129
- return this.adapter.readFile(this.p(path));
130
- }
131
-
132
- writeFile(path: PathLike, contents: string): Promise<void> {
133
- return this.adapter.writeFile(this.p(path), contents);
134
- }
135
-
136
- rm(path: PathLike): Promise<void> {
137
- return this.adapter.rm(this.p(path));
138
- }
139
-
140
- private p(path: PathLike): string {
141
- return isAbsolute(path) ? path : join(this.cwd(), path);
142
- }
143
- }
144
-
145
- export class RecordFileSystemAdapter implements FileSystemAdapter {
146
- private fs: Record<string, string>;
147
- constructor(fs: Record<string, string> = {}) {
148
- this.fs = fs;
149
- }
150
-
151
- stat(path: PathLike): Promise<Stats> {
152
- return new Promise((resolve, reject) => {
153
- if (this.fs[path]) {
154
- return resolve({
155
- name: basename(path),
156
- isDirectory() {
157
- return false;
158
- },
159
- isFile() {
160
- return true;
161
- },
162
- });
163
- }
164
-
165
- if (!path.endsWith(SEP)) path += SEP;
166
- for (const filename of Object.keys(this.fs)) {
167
- if (filename.startsWith(path)) {
168
- return resolve({
169
- name: basename(path),
170
- isDirectory() {
171
- return true;
172
- },
173
- isFile() {
174
- return false;
175
- },
176
- });
177
- }
178
- }
179
-
180
- reject();
181
- });
182
- }
183
-
184
- async scandir(path: PathLike): Promise<Stats[]> {
185
- return (await this.readdir(path)).map<Stats>((name) => {
186
- const isFile = this.fs[join(path, name)] !== undefined;
187
- return {
188
- name,
189
- isDirectory() {
190
- return !isFile;
191
- },
192
- isFile() {
193
- return isFile;
194
- },
195
- };
196
- });
197
- }
198
-
199
- readdir(path: PathLike): Promise<string[]> {
200
- if (!path.endsWith(SEP)) path += SEP;
201
- return new Promise((resolve) => {
202
- const dir = new Set<string>();
203
- for (const filename of Object.keys(this.fs)) {
204
- if (filename.startsWith(path)) {
205
- const end = filename.indexOf(SEP, path.length + 1);
206
- const basename = filename.substring(
207
- path.length,
208
- end === -1 ? undefined : end,
209
- );
210
- dir.add(basename);
211
- }
212
- }
213
- return resolve([...dir].sort());
214
- });
215
- }
216
-
217
- mkdir(_path: string): Promise<void> {
218
- return Promise.resolve();
219
- }
220
-
221
- copyFile(from: PathLike, to: PathLike): Promise<void> {
222
- return new Promise((resolve) => {
223
- this.fs[to] = this.fs[from];
224
- resolve();
225
- });
226
- }
227
-
228
- readFile(path: PathLike): Promise<string> {
229
- return new Promise((resolve, reject) => {
230
- const file = this.fs[path];
231
- if (file === undefined) {
232
- const error = new Error(`File Not Found ${path}`);
233
- reject(error);
234
- } else {
235
- resolve(file);
236
- }
237
- });
238
- }
239
-
240
- writeFile(path: PathLike, contents: string): Promise<void> {
241
- return new Promise((resolve) => {
242
- this.fs[path] = contents;
243
- resolve();
244
- });
245
- }
246
-
247
- rm(path: PathLike): Promise<void> {
248
- return new Promise((resolve) => {
249
- delete this.fs[path];
250
- resolve();
251
- });
252
- }
253
- }
254
-
255
- export class LocalStorageFileSystemAdapter extends RecordFileSystemAdapter {
256
- constructor() {
257
- super(window.localStorage);
258
- }
259
- }
260
-
261
- export type ObjectFileSystem = { [k: string]: string | ObjectFileSystem };
262
- export class ObjectFileSystemAdapter extends RecordFileSystemAdapter {
263
- constructor(object: ObjectFileSystem) {
264
- super(reduceObjectFileSystem(object));
265
- }
266
- }
267
-
268
- function reduceObjectFileSystem(
269
- object: ObjectFileSystem,
270
- ): Record<string, string> {
271
- const level: Record<string, string> = {};
272
-
273
- for (const [k, v] of Object.entries(object)) {
274
- if (typeof v === "string") {
275
- level[`/${k}`] = v;
276
- } else {
277
- for (const [k2, v2] of Object.entries(reduceObjectFileSystem(v))) {
278
- level[`/${k}${k2}`] = v2;
279
- }
280
- }
281
- }
282
-
283
- return level;
284
- }
285
-
286
- export interface Tree {
287
- [k: string]: string | Tree;
288
- }
289
-
290
- export async function reset(fs: FileSystem, tree: Tree): Promise<void> {
291
- for (const [path, file] of Object.entries(tree)) {
292
- if (typeof file === "string") {
293
- await fs.writeFile(path, file);
294
- } else {
295
- fs.cd(path);
296
- await reset(fs, file);
297
- fs.cd("..");
298
- }
299
- }
300
- }
package/src/fs_node.ts DELETED
@@ -1,57 +0,0 @@
1
- import {
2
- copyFile,
3
- mkdir,
4
- readdir,
5
- readFile,
6
- rm,
7
- stat,
8
- writeFile,
9
- } from "node:fs/promises";
10
- import { basename, join } from "node:path";
11
- import { FileSystem, type FileSystemAdapter, type Stats } from "./fs.ts";
12
-
13
- export class NodeFileSystem extends FileSystem {
14
- constructor(cd: string = process.cwd()) {
15
- super(new NodeFileSystemAdapter());
16
- this.cd(cd);
17
- }
18
- }
19
-
20
- /** Jiffies FileSystemAdapter using NodeJS' fs/promises. */
21
- export class NodeFileSystemAdapter implements FileSystemAdapter {
22
- async stat(path: string): Promise<Stats> {
23
- const fsStat = await stat(path);
24
- return {
25
- name: basename(path),
26
- isDirectory() {
27
- return fsStat.isDirectory();
28
- },
29
- isFile() {
30
- return !fsStat.isDirectory();
31
- },
32
- };
33
- }
34
- readdir(path: string): Promise<string[]> {
35
- return readdir(path);
36
- }
37
- async mkdir(path: string): Promise<void> {
38
- await mkdir(path, { recursive: true });
39
- }
40
- async scandir(path: string): Promise<Stats[]> {
41
- return Promise.all(
42
- (await this.readdir(path)).map((name) => this.stat(join(path, name))),
43
- );
44
- }
45
- copyFile(from: string, to: string): Promise<void> {
46
- return copyFile(from, to);
47
- }
48
- readFile(path: string): Promise<string> {
49
- return readFile(path, "utf-8");
50
- }
51
- writeFile(path: string, contents: string): Promise<void> {
52
- return writeFile(path, contents, "utf-8");
53
- }
54
- rm(path: string): Promise<void> {
55
- return rm(path, { force: true, recursive: true });
56
- }
57
- }
package/src/generator.ts DELETED
@@ -1,12 +0,0 @@
1
- export function* takeWhile<T>(
2
- predicate: (t: T) => boolean,
3
- iterator: Iterable<T>,
4
- ) {
5
- for (const x of iterator) {
6
- if (predicate(x)) {
7
- yield x;
8
- } else {
9
- return;
10
- }
11
- }
12
- }
package/src/hooks/_notes DELETED
@@ -1,6 +0,0 @@
1
- useEffect
2
- useState
3
- useContext
4
-
5
-
6
- signal(n) => n, setN
package/src/lock.ts DELETED
@@ -1,23 +0,0 @@
1
- const locks = new WeakSet<CallableFunction>();
2
-
3
- export function lock<CF extends (...args: unknown[]) => unknown>(fn: CF): CF {
4
- const lockingFn = (...args: unknown[]): ReturnType<CF> => {
5
- let ret: ReturnType<CF>;
6
- let ex = null;
7
- if (!locks.has(fn)) {
8
- locks.add(fn);
9
- try {
10
- ret = fn(...args) as ReturnType<CF>;
11
- } catch (e) {
12
- ex = e;
13
- }
14
- }
15
- locks.delete(fn);
16
- if (ex !== null) {
17
- throw ex;
18
- }
19
- // @ts-expect-error 2454 can't track ret's assignment
20
- return ret;
21
- };
22
- return lockingFn as CF;
23
- }
package/src/log.ts DELETED
@@ -1,307 +0,0 @@
1
- import { type Display, display } from "./display.ts";
2
-
3
- export type Log = (message: Display, data?: object) => void;
4
-
5
- export interface Logger {
6
- logAt: (level: number, prefix: string, fn?: (logLine: string) => void) => Log;
7
- level: number;
8
- format: <
9
- D extends {
10
- name: string;
11
- prefix: string;
12
- level: number;
13
- message: string;
14
- source: string;
15
- },
16
- >(
17
- data: D,
18
- ) => string;
19
- console: Console;
20
- default: (logLine: string) => void;
21
- debug: Log;
22
- info: Log;
23
- warn: Log;
24
- error: Log;
25
- }
26
-
27
- export const LEVEL = {
28
- UNKNOWN: 2,
29
- DEBUG: 1,
30
- VERBOSE: 1,
31
- INFO: 2,
32
- WARN: 3,
33
- ERROR: 4,
34
- SILENT: 5,
35
- };
36
-
37
- export const LEVELS: Record<string, number> = {
38
- unknown: LEVEL.UNKNOWN,
39
- debug: LEVEL.DEBUG,
40
- verbose: LEVEL.VERBOSE,
41
- info: LEVEL.INFO,
42
- warn: LEVEL.WARN,
43
- error: LEVEL.ERROR,
44
- silent: LEVEL.SILENT,
45
- };
46
-
47
- export function getLogLevel(level = ""): number {
48
- return (
49
- LEVELS[level.toLowerCase()] ??
50
- (!Number.isNaN(+level) ? Number(level) : LEVEL.INFO)
51
- );
52
- }
53
-
54
- export function basicLogFormatter(data: {
55
- name: string;
56
- prefix: string;
57
- level: number;
58
- message: string;
59
- source: string;
60
- }): string {
61
- return `${data.prefix}: ${data.message}`;
62
- }
63
-
64
- function findSource() {
65
- const err = new Error();
66
- // Stack will be:
67
- // findSource
68
- // logAt
69
- // {source}
70
- const lines = err.stack?.split("\n") ?? [];
71
- const atLines = lines.filter((line) => line.match(/^\s*at/));
72
- return atLines[2]?.trim().slice("at ".length) ?? "(unknown)";
73
- }
74
-
75
- export type LoggerFormatFn = <
76
- D extends {
77
- name: string;
78
- prefix: string;
79
- level: number;
80
- message: string;
81
- source: string;
82
- },
83
- >(
84
- data: D,
85
- ) => string;
86
-
87
- // ── prettyLogFormatter ──────────────────────────────────────────────────────
88
- // A TTY-aware formatter: compact, color-and-glyph-coded human lines on a
89
- // terminal, byte-identical JSON.stringify when piped/redirected so machine
90
- // tooling is unchanged. See docs/developer/2026-06-09-A-log-formatter/design.md.
91
-
92
- // Raw ANSI escapes; no color/log runtime dependency in this library.
93
- const ANSI = {
94
- reset: "\x1b[0m",
95
- dim: "\x1b[2m",
96
- bold: "\x1b[1m",
97
- green: "\x1b[32m",
98
- yellow: "\x1b[33m",
99
- red: "\x1b[31m",
100
- cyan: "\x1b[36m",
101
- white: "\x1b[37m",
102
- } as const;
103
- type AnsiCode = keyof typeof ANSI;
104
-
105
- // HH:MM:SS.mmm sliced from a UTC ISO 8601 string. Timezone-stable by
106
- // construction: it never reads local-time accessors, so output depends only on
107
- // the ISO input, not the runner's TZ.
108
- function shortClock(iso: string): string {
109
- return iso.slice(11, 23);
110
- }
111
-
112
- // Glyph + color per severity, keyed on the numeric level (DEBUG 1, INFO 2,
113
- // WARN 3, ERROR 4). Fixed single-column glyph so messages align vertically.
114
- function levelGlyph(level: number): { glyph: string; color: AnsiCode } {
115
- if (level <= LEVEL.DEBUG) return { glyph: "·", color: "dim" };
116
- if (level === LEVEL.INFO) return { glyph: "ℹ", color: "green" };
117
- if (level === LEVEL.WARN) return { glyph: "⚠", color: "yellow" };
118
- return { glyph: "✖", color: "red" };
119
- }
120
-
121
- function methodColor(method: string): AnsiCode {
122
- switch (method) {
123
- case "GET":
124
- return "cyan";
125
- case "POST":
126
- return "green";
127
- case "PUT":
128
- case "PATCH":
129
- return "yellow";
130
- case "DELETE":
131
- return "red";
132
- default:
133
- return "white";
134
- }
135
- }
136
-
137
- function statusColor(status: number): AnsiCode {
138
- if (status >= 500) return "red";
139
- if (status >= 400) return "yellow";
140
- if (status >= 300) return "cyan";
141
- return "green";
142
- }
143
-
144
- // Fields that are pure metadata noise on a human terminal: `name`/`level` are
145
- // constant or duplicate `prefix`, and `source` resolves to the info() wrapper.
146
- // `message` is rendered on its own, never echoed into the trailing tail.
147
- const HUMAN_DROP = new Set(["name", "prefix", "level", "source", "message"]);
148
-
149
- export interface PrettyLogOptions {
150
- /** Render colored, human-shaped lines. Default: !!process.stdout.isTTY. */
151
- tty?: boolean;
152
- /** Emit ANSI color escapes. Default: same as `tty`. */
153
- color?: boolean;
154
- /** Injectable clock for deterministic timestamps in tests. Default: new Date. */
155
- now?: () => Date;
156
- }
157
-
158
- /**
159
- * Factory returning a {@link LoggerFormatFn} that is pretty + colored on a TTY
160
- * and falls back to `JSON.stringify` when not. Options resolve once at
161
- * construction (`tty` reads `process.stdout.isTTY`), so production piped output
162
- * stays JSON; tests inject `tty`/`color`/`now` for a deterministic colorless
163
- * layout assertable without a real terminal.
164
- */
165
- export function prettyLogFormatter(
166
- options: PrettyLogOptions = {},
167
- ): LoggerFormatFn {
168
- const tty = options.tty ?? !!process.stdout.isTTY;
169
- const color = options.color ?? tty;
170
- const now = options.now ?? (() => new Date());
171
- const paint = (code: AnsiCode, s: string): string =>
172
- color ? `${ANSI[code]}${s}${ANSI.reset}` : s;
173
-
174
- return <
175
- D extends {
176
- name: string;
177
- prefix: string;
178
- level: number;
179
- message: string;
180
- source: string;
181
- },
182
- >(
183
- data: D,
184
- ): string => {
185
- if (!tty) return JSON.stringify(data);
186
-
187
- const record = data as unknown as Record<string, unknown>;
188
- const { glyph, color: glyphColor } = levelGlyph(data.level);
189
- const mark = paint(glyphColor, glyph);
190
-
191
- // Access-log shape: `<glyph> <clock> <METHOD> <path> <client> [status] [ms]`.
192
- // Clock comes from the request's `when` ISO (UTC slice), not now().
193
- if (data.message === "Request") {
194
- const when = typeof record.when === "string" ? record.when : "";
195
- const how = typeof record.how === "string" ? record.how : "";
196
- const space = how.indexOf(" ");
197
- const method = space === -1 ? how : how.slice(0, space);
198
- const path = space === -1 ? "" : how.slice(space + 1);
199
- const segments = [
200
- mark,
201
- paint("dim", shortClock(when || now().toISOString())),
202
- paint(methodColor(method), method),
203
- paint("bold", path),
204
- ];
205
- if (record.who !== undefined) {
206
- segments.push(paint("dim", String(record.who)));
207
- }
208
- if (record.status !== undefined) {
209
- segments.push(
210
- paint(statusColor(Number(record.status)), String(record.status)),
211
- );
212
- }
213
- if (record.ms !== undefined) {
214
- segments.push(paint("dim", `${record.ms}ms`));
215
- }
216
- return segments.filter((s) => s !== "").join(" ");
217
- }
218
-
219
- // Generic shape: `<glyph> <clock> <message> <dim key=value …>`.
220
- const tail = Object.entries(record)
221
- .filter(([key]) => !HUMAN_DROP.has(key))
222
- .map(([key, value]) =>
223
- paint(
224
- "dim",
225
- `${key}=${typeof value === "string" ? value : JSON.stringify(value)}`,
226
- ),
227
- );
228
- return [
229
- mark,
230
- paint("dim", shortClock(now().toISOString())),
231
- paint("bold", data.message),
232
- ...tail,
233
- ].join(" ");
234
- };
235
- }
236
-
237
- export function getLogger(
238
- name: string,
239
- args: LoggerFormatFn | { format?: LoggerFormatFn; console?: Console } = {
240
- format: JSON.stringify,
241
- console,
242
- },
243
- ): Logger {
244
- if (args instanceof Function) {
245
- args = { format: args };
246
- }
247
- const defaultLog = (logLine: string): void => {
248
- logger.console.info(logLine);
249
- };
250
- const logAt =
251
- (
252
- level: number,
253
- prefix: string,
254
- fn: (logLine: string) => void = defaultLog,
255
- ): Log =>
256
- (message: Display, data?: object) =>
257
- level >= (logger.level ?? LEVEL.SILENT)
258
- ? fn(
259
- logger.format?.({
260
- name,
261
- prefix,
262
- level,
263
- message: display(message),
264
- ...data,
265
- source: findSource(),
266
- }),
267
- )
268
- : undefined;
269
-
270
- const logger: Logger = {
271
- logAt,
272
- default: defaultLog,
273
- level: LEVEL.INFO,
274
- format: args.format ?? JSON.stringify,
275
- console: args.console ?? global.console,
276
- debug: logAt(LEVEL.DEBUG, "DEBUG", (l) => logger.console.debug(l)),
277
- info: logAt(LEVEL.INFO, "INFO", (l) => logger.console.info(l)),
278
- warn: logAt(LEVEL.WARN, "WARN", (l) => logger.console.warn(l)),
279
- error: logAt(LEVEL.ERROR, "ERR", (l) => logger.console.error(l)),
280
- };
281
-
282
- return logger as Logger;
283
- }
284
-
285
- export const DEFAULT_LOGGER = getLogger("default", {
286
- format: prettyLogFormatter(),
287
- });
288
-
289
- export function debug(message: Display, data?: object) {
290
- if (data) DEFAULT_LOGGER.debug(message, data);
291
- else DEFAULT_LOGGER.debug(message);
292
- }
293
-
294
- export function info(message: Display, data?: object) {
295
- if (data) DEFAULT_LOGGER.info(message, data);
296
- else DEFAULT_LOGGER.info(message);
297
- }
298
-
299
- export function warn(message: Display, data?: object) {
300
- if (data) DEFAULT_LOGGER.warn(message, data);
301
- else DEFAULT_LOGGER.warn(message);
302
- }
303
-
304
- export function error(message: Display, data?: object) {
305
- if (data) DEFAULT_LOGGER.error(message, data);
306
- else DEFAULT_LOGGER.error(message);
307
- }