ranuts 0.2.0-alpha.1 → 0.4.0-alpha.1
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/CLAUDE.md +126 -24
- package/README.md +7 -5
- package/README.zh-CN.md +7 -5
- package/dist/chain-CTywmh_H.js +1 -0
- package/dist/{color-CRdlaDqQ.js → color-Dohr9BXX.js} +1 -1
- package/dist/enums-BAgbyGdH.js +1 -0
- package/dist/i18n-Cf5TtRb4.js +1 -0
- package/dist/index.d.ts +1 -5
- package/dist/index.js +1 -1
- package/dist/src/node/appendFile.d.ts +3 -3
- package/dist/src/node/fileInfo.d.ts +2 -2
- package/dist/src/node/index.js +1 -1
- package/dist/src/node/paresUrl.d.ts +1 -1
- package/dist/src/node/readFile.d.ts +3 -3
- package/dist/src/node/traverse.d.ts +2 -2
- package/dist/src/node/watchFile.d.ts +3 -3
- package/dist/src/node/writeFile.d.ts +3 -3
- package/dist/src/sw/index.d.ts +109 -0
- package/dist/src/sw/index.js +1 -0
- package/dist/src/utils/async.d.ts +81 -0
- package/dist/src/utils/audioRecorder.d.ts +1 -1
- package/dist/src/utils/behavior.d.ts +12 -3
- package/dist/src/utils/bom.d.ts +68 -178
- package/dist/src/utils/bridge.d.ts +153 -0
- package/dist/src/utils/canvas.d.ts +54 -0
- package/dist/src/utils/chain.d.ts +80 -0
- package/dist/src/utils/color.d.ts +76 -4
- package/dist/src/utils/compose.d.ts +1 -1
- package/dist/src/utils/console.d.ts +19 -1
- package/dist/src/utils/debounce.d.ts +27 -5
- package/dist/src/utils/device.d.ts +31 -3
- package/dist/src/utils/dom.d.ts +5 -84
- package/dist/src/utils/error.d.ts +18 -1
- package/dist/src/utils/event.d.ts +61 -0
- package/dist/src/utils/file.d.ts +35 -0
- package/dist/src/utils/i18n/index.js +1 -0
- package/dist/src/utils/i18n.d.ts +69 -0
- package/dist/src/utils/idb.d.ts +218 -0
- package/dist/src/utils/img.d.ts +60 -4
- package/dist/src/utils/index.d.ts +50 -16
- package/dist/src/utils/index.js +1 -1
- package/dist/src/utils/lang.d.ts +69 -0
- package/dist/src/utils/localePath.d.ts +62 -0
- package/dist/src/utils/memoize.d.ts +53 -5
- package/dist/src/utils/monitor.d.ts +55 -26
- package/dist/src/utils/number.d.ts +46 -9
- package/dist/src/utils/obj.d.ts +56 -31
- package/dist/src/utils/paginate.d.ts +73 -0
- package/dist/src/utils/prefetch.d.ts +81 -0
- package/dist/src/utils/queue.d.ts +53 -23
- package/dist/src/utils/report.d.ts +51 -3
- package/dist/src/utils/request.d.ts +26 -7
- package/dist/src/utils/script.d.ts +26 -4
- package/dist/src/utils/segment.d.ts +62 -0
- package/dist/src/utils/signal.d.ts +35 -3
- package/dist/src/utils/storage.d.ts +57 -0
- package/dist/src/utils/str.d.ts +112 -88
- package/dist/src/utils/style.d.ts +31 -0
- package/dist/src/utils/subscribe.d.ts +5 -5
- package/dist/src/utils/throttle.d.ts +26 -13
- package/dist/src/utils/time.d.ts +38 -6
- package/dist/src/utils/tween.d.ts +40 -0
- package/dist/src/utils/visual/application.d.ts +4 -4
- package/dist/src/utils/visual/enums.d.ts +4 -4
- package/dist/src/utils/visual/graphics/graphics.d.ts +25 -25
- package/dist/src/utils/visual/graphics/graphicsData.d.ts +1 -1
- package/dist/src/utils/visual/graphics/graphicsGeometry.d.ts +6 -6
- package/dist/src/utils/visual/index.js +1 -1
- package/dist/src/utils/visual/math/matrix.d.ts +8 -8
- package/dist/src/utils/visual/math/transform.d.ts +1 -1
- package/dist/src/utils/visual/render/batchRenderer.d.ts +20 -18
- package/dist/src/utils/visual/render/utils/batch/index.d.ts +13 -13
- package/dist/src/utils/visual/render/utils/float.d.ts +13 -13
- package/dist/src/utils/visual/render/utils/verticy.d.ts +3 -3
- package/dist/src/utils/visual/render/utils/webgl/initShader.d.ts +3 -2
- package/dist/src/utils/visual/render/utils/webgpu/shaders.d.ts +2 -2
- package/dist/src/utils/visual/render/webGPURenderer.d.ts +8 -8
- package/dist/src/utils/visual/vertex/container.d.ts +17 -16
- package/dist/src/utils/worker.d.ts +125 -0
- package/dist/src/utils/zip.d.ts +162 -0
- package/dist/src/vnode/index.d.ts +1 -1
- package/dist/src/vnode/index.js +1 -1
- package/dist/src/vnode/is.d.ts +4 -0
- package/dist/test/canvas.test.d.ts +1 -0
- package/dist/test/color.test.d.ts +1 -0
- package/dist/test/sw.test.d.ts +1 -0
- package/dist/test/tween.test.d.ts +1 -0
- package/dist/test/utils/async.test.d.ts +1 -0
- package/dist/test/utils/file-read.test.d.ts +1 -0
- package/dist/test/utils/format.test.d.ts +1 -0
- package/dist/test/utils/idb-collection.test.d.ts +1 -0
- package/dist/test/utils/idb.test.d.ts +1 -0
- package/dist/test/utils/instrumentation.test.d.ts +1 -0
- package/dist/test/utils/lang.test.d.ts +1 -0
- package/dist/test/utils/locale-path.test.d.ts +1 -0
- package/dist/test/utils/media-query.test.d.ts +1 -0
- package/dist/test/utils/number-parse.test.d.ts +1 -0
- package/dist/test/utils/paginate.test.d.ts +1 -0
- package/dist/test/utils/prefetch.test.d.ts +1 -0
- package/dist/test/utils/query-storage.test.d.ts +1 -0
- package/dist/test/utils/queue.test.d.ts +1 -0
- package/dist/test/utils/report-config.test.d.ts +1 -0
- package/dist/test/utils/report-image.test.d.ts +1 -0
- package/dist/test/utils/segment.test.d.ts +1 -0
- package/dist/test/utils/signal-once.test.d.ts +1 -0
- package/dist/test/utils/single-flight.test.d.ts +1 -0
- package/dist/test/utils/timing.test.d.ts +1 -0
- package/dist/test/utils/worker-client.test.d.ts +1 -0
- package/dist/test/utils/worker-serve.test.d.ts +1 -0
- package/dist/test/utils/zip.test.d.ts +1 -0
- package/dist/umd/index.umd.cjs +1 -1
- package/dist/umd/node/node.umd.cjs +1 -1
- package/dist/umd/utils/utils.umd.cjs +1 -1
- package/dist/utils-8TVtLBjA.js +1 -0
- package/docs/API.md +341 -147
- package/package.json +13 -6
- package/dist/src/vnode/chainDom.d.ts +0 -47
- package/dist/subscribe-CINWsor3.js +0 -1
- package/dist/utils-_OxsVZmz.js +0 -1
package/CLAUDE.md
CHANGED
|
@@ -27,13 +27,15 @@ from the **subpath that owns it** (below) — not from a deep source path.
|
|
|
27
27
|
Each subpath is an independent, tree-shakeable barrel. Import from the subpath, never from
|
|
28
28
|
`ranuts/dist/...` or `@/...` (that alias is internal to the source).
|
|
29
29
|
|
|
30
|
-
| Import from | Source | What | Runtime
|
|
31
|
-
| --------------- | --------------------------- | --------------------------------------------------- |
|
|
32
|
-
| `ranuts` | `index.ts` | Root barrel — re-exports the utils + visual surface | browser + node
|
|
33
|
-
| `ranuts/utils` | `src/utils/index.ts` | DOM/BOM, string, object, number, color, time, etc. | browser + node\*
|
|
34
|
-
| `ranuts/node` | `src/node/index.ts` | HTTP server, router, ws, fs, streams, middleware | **node only**
|
|
35
|
-
| `ranuts/visual` | `src/utils/visual/index.ts` | 2D rendering engine (Canvas / WebGL / WebGPU) | **browser only**
|
|
36
|
-
| `ranuts/
|
|
30
|
+
| Import from | Source | What | Runtime |
|
|
31
|
+
| --------------- | --------------------------- | --------------------------------------------------- | ------------------ |
|
|
32
|
+
| `ranuts` | `index.ts` | Root barrel — re-exports the utils + visual surface | browser + node |
|
|
33
|
+
| `ranuts/utils` | `src/utils/index.ts` | DOM/BOM, string, object, number, color, time, etc. | browser + node\* |
|
|
34
|
+
| `ranuts/node` | `src/node/index.ts` | HTTP server, router, ws, fs, streams, middleware | **node only** |
|
|
35
|
+
| `ranuts/visual` | `src/utils/visual/index.ts` | 2D rendering engine (Canvas / WebGL / WebGPU) | **browser only** |
|
|
36
|
+
| `ranuts/i18n` | `src/utils/i18n.ts` | `I18nCore` / `createI18n` / `useI18n` — DOM-free | browser + node |
|
|
37
|
+
| `ranuts/sw` | `src/sw/index.ts` | Cache strategies + the precache protocol's SW half | **service worker** |
|
|
38
|
+
| `ranuts/vnode` | `src/vnode/index.ts` | Snabbdom-style virtual DOM (`h`, `init`, modules) | browser |
|
|
37
39
|
|
|
38
40
|
\* `ranuts/utils` is broad: most functions are browser-oriented (touch `window`/`document`),
|
|
39
41
|
but pure helpers (`str`, `obj`, `number`, `compose`, `cloneDeep`, …) run anywhere. Functions
|
|
@@ -49,8 +51,25 @@ the same for any new code. **Do not import `ranuts/node` in browser code** — i
|
|
|
49
51
|
packages/ranuts/
|
|
50
52
|
├── index.ts # Root barrel (re-exports utils + visual + selected)
|
|
51
53
|
├── src/
|
|
52
|
-
│ ├── utils/ # ranuts/utils — the largest surface (~
|
|
54
|
+
│ ├── utils/ # ranuts/utils — the largest surface (~14k LOC)
|
|
53
55
|
│ │ ├── str.ts obj.ts number.ts color.ts bom.ts dom.ts time.ts …
|
|
56
|
+
│ │ ├── bridge.ts # postMessage request/response (split out of bom.ts)
|
|
57
|
+
│ │ ├── idb.ts # WebDB (declarative stores) + createHandoff (one-shot value handoff)
|
|
58
|
+
│ │ ├── worker.ts # WorkerClient — request/response over a Web Worker
|
|
59
|
+
│ │ ├── zip.ts # ZIP read/rewrite — crc32, inflateRaw, rewriteZip, createZip
|
|
60
|
+
│ │ ├── async.ts # deferred / withTimeout / withTimeoutFallback / delay
|
|
61
|
+
│ │ ├── storage.ts # localStorage* + createStore (prefixed JSON view)
|
|
62
|
+
│ │ ├── segment.ts # offsets ↔ chunks, range→segment splitting (highlights)
|
|
63
|
+
│ │ ├── localePath.ts # createLocalePath — i18n sub-directory URL maths
|
|
64
|
+
│ │ ├── prefetch.ts # whenIdle / networkAllowsDownload / prefetchUrls
|
|
65
|
+
│ │ ├── lang.ts # detectLanguage + resolveLocale (query→cookie→storage→navigator)
|
|
66
|
+
│ │ ├── file.ts # readFileAs* — FileReader promises
|
|
67
|
+
│ │ ├── i18n.ts # ranuts/i18n — I18nCore, {param} interpolation, locale persistence
|
|
68
|
+
│ │ ├── event.ts # EventManager — AbortController-scoped listeners + delegation
|
|
69
|
+
│ │ ├── chain.ts # Chain / create — chainable DOM builder (shared with vnode)
|
|
70
|
+
│ │ ├── style.ts # adoptStyles / adoptSheetText — Shadow DOM CSS injection
|
|
71
|
+
│ │ ├── canvas.ts # Canvas 2D geometry — roundRectByArc, fanShapedByArc, getLinearGradient
|
|
72
|
+
│ │ ├── tween.ts # easing curves (quad/cubic/quart/quint/sine/expo/circ)
|
|
54
73
|
│ │ ├── visual/ # ranuts/visual — 2D rendering engine (see below)
|
|
55
74
|
│ │ └── totp/ # TOTP + hand-rolled SHA
|
|
56
75
|
│ ├── node/ # ranuts/node — mini HTTP framework
|
|
@@ -99,12 +118,13 @@ Tests for the color pipeline and batch packing live next to the source as `*.tes
|
|
|
99
118
|
### Adding a function to an existing module
|
|
100
119
|
|
|
101
120
|
1. Write it in the right `src/<module>/*.ts` file with a JSDoc block. This codebase uses the
|
|
102
|
-
`@description:` tag
|
|
121
|
+
`@description:` tag for the summary — the generator reads it. **Comments and JSDoc are
|
|
122
|
+
written in English**; user-facing translations belong in `packages/docs`, not in source:
|
|
103
123
|
```ts
|
|
104
124
|
/**
|
|
105
|
-
* @description:
|
|
106
|
-
* @param fn
|
|
107
|
-
* @return
|
|
125
|
+
* @description: Debounce — run only the last call, `ms` after the calls stop.
|
|
126
|
+
* @param fn function to debounce
|
|
127
|
+
* @return wrapped function with cancel / flush / pending
|
|
108
128
|
*/
|
|
109
129
|
export const debounce = (fn, ms = 300) => { … };
|
|
110
130
|
```
|
|
@@ -126,7 +146,50 @@ Then `npm run doc:api`.
|
|
|
126
146
|
|
|
127
147
|
- Guard every `window`/`document`/`localStorage`/`navigator` access with `typeof … !== 'undefined'`
|
|
128
148
|
in code reachable from `ranuts/utils` (it's imported in node too).
|
|
129
|
-
-
|
|
149
|
+
- **Guard at call time, not module load.** `isClient` is a module-level constant evaluated when
|
|
150
|
+
the module is first imported, so it is `false` forever in any SSR-then-hydrate or
|
|
151
|
+
import-early/call-later flow — and it cannot be stubbed in tests. New code checks
|
|
152
|
+
`typeof window === 'undefined'` inside the function. `isClient` stays exported for
|
|
153
|
+
compatibility but should not be used for new branches.
|
|
154
|
+
- Never call `window.setTimeout` / `window.setInterval`. The bare globals work in Node, Web
|
|
155
|
+
Workers and the browser alike; the `window.`-prefixed ones throw `ReferenceError` outside a
|
|
156
|
+
document. (This is what made `throttle` unusable in SSR before 0.3.)
|
|
157
|
+
- Keep `ranuts/node` server-only; never import it from browser-facing modules. Same for
|
|
158
|
+
`ranuts/sw`: it runs in a `ServiceWorkerGlobalScope` with no `window`/`document`, which is
|
|
159
|
+
why it is its own entry rather than part of the utils barrel.
|
|
160
|
+
|
|
161
|
+
### Ship both halves of a protocol, or neither
|
|
162
|
+
|
|
163
|
+
`WorkerClient` without `serveWorker` meant every worker re-implemented the same id echo and
|
|
164
|
+
error envelope — and each got to invent its own bug (a sync throw escaping the handler, a
|
|
165
|
+
rejection with no id so the caller waits forever). Same for `prefetchUrls({ serviceWorkerMessage })`
|
|
166
|
+
without `servePrecache`. When a helper defines a message shape, the counterpart that answers
|
|
167
|
+
it belongs in the library too; a JSDoc block saying "just echo the id back" is not a substitute.
|
|
168
|
+
|
|
169
|
+
### Anything that installs something must return how to uninstall it
|
|
170
|
+
|
|
171
|
+
`debounce`, `throttle`, `watchMediaQuery`, `whenIdle`, `WorkerClient`, `QuestQueue` hand back
|
|
172
|
+
something holding a timer, a listener or a worker. `replaceOld`, `handleConsole`,
|
|
173
|
+
`handleFetchHook`, `handleXhrHook`, `handleError`, `handleClick`, `serveWorker`,
|
|
174
|
+
`servePrecache` and `Monitor.start()` patch a global or register a listener. **All of them
|
|
175
|
+
return a teardown function**, and callers are expected to use it.
|
|
176
|
+
|
|
177
|
+
A utility of this shape without a teardown path is incomplete. The failure modes are concrete:
|
|
178
|
+
a pending timer firing into a destroyed component; a hot reload re-patching an already-patched
|
|
179
|
+
`console` until every log is nested through a dozen wrappers and every event is reported N
|
|
180
|
+
times; a test that can never give the next test a clean global back.
|
|
181
|
+
|
|
182
|
+
`replaceOld`'s restore additionally checks that **its own** wrapper is still installed before
|
|
183
|
+
writing the original back — otherwise unwinding an inner layer would silently uninstall an
|
|
184
|
+
outer one.
|
|
185
|
+
|
|
186
|
+
### No hard-coded endpoints, cookie names or domains
|
|
187
|
+
|
|
188
|
+
A library cannot know where your telemetry goes or what your auth cookie is called. `report`
|
|
189
|
+
requires an endpoint (`setReportUrl` once, or per call) and returns `false` rather than
|
|
190
|
+
guessing; `createData` includes a user id only when `userIdCookie` is configured. This is what
|
|
191
|
+
`getHost` got wrong — it built a URL from a domain baked into this repo, and a stale edit had
|
|
192
|
+
already reduced its output to the unreachable literal `'//log.'`.
|
|
130
193
|
|
|
131
194
|
---
|
|
132
195
|
|
|
@@ -151,14 +214,53 @@ npm run doc:api # regenerate docs/API.md from source + JSDoc
|
|
|
151
214
|
|
|
152
215
|
## Gotchas
|
|
153
216
|
|
|
154
|
-
| Pitfall
|
|
155
|
-
|
|
|
156
|
-
| Importing from a deep source path or `@/…`
|
|
157
|
-
| Importing `ranuts/node` in browser code
|
|
158
|
-
| `new Application()` then `render()` with WebGPU
|
|
159
|
-
| Hand-editing `docs/API.md`
|
|
160
|
-
| Adding an export but it's missing from `docs/API.md`
|
|
161
|
-
| New entry point not importable as `ranuts/foo`
|
|
162
|
-
| `console.log` left in a function that a test calls
|
|
163
|
-
| Assuming a GPU/Canvas test can run in CI
|
|
164
|
-
| Passing a non-`#rrggbb` color to the GPU backend and expecting it to fail
|
|
217
|
+
| Pitfall | Fix |
|
|
218
|
+
| -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
|
|
219
|
+
| Importing from a deep source path or `@/…` | Import from the public subpath (`ranuts/utils`, `ranuts/visual`, …). `@/…` is build-internal only. |
|
|
220
|
+
| Importing `ranuts/node` in browser code | It externalizes `fs`/`http`/`child_process` — server-only. Use `ranuts/utils` for browser helpers. |
|
|
221
|
+
| `new Application()` then `render()` with WebGPU | Device init is async — use `await Application.create(...)`, then `app.start()`. |
|
|
222
|
+
| Hand-editing `docs/API.md` | It's generated. Edit the source JSDoc and run `npm run doc:api`. |
|
|
223
|
+
| Adding an export but it's missing from `docs/API.md` | Re-export it from the module's `index.ts` barrel, then `npm run doc:api`. |
|
|
224
|
+
| New entry point not importable as `ranuts/foo` | Wire all three: `package.json` exports + `vite.config.ts` es entry + generator `ENTRIES`. |
|
|
225
|
+
| `console.log` left in a function that a test calls | `vitest.config.ts` `onConsoleLog` throws — remove it or the test fails. |
|
|
226
|
+
| Assuming a GPU/Canvas test can run in CI | Test env is node (no DOM/GPU). Test pure logic; gate visual checks behind a browser demo. |
|
|
227
|
+
| Passing a non-`#rrggbb` color to the GPU backend and expecting it to fail | It won't — `getRgb` resolves any CSS color via the browser parser, matching the Canvas backend. |
|
|
228
|
+
| Branching on `isClient` in new code | It's a module-load-time constant — wrong after SSR, unstubbable in tests. Check `typeof window === 'undefined'` inside the function. |
|
|
229
|
+
| `window.setTimeout` in a `ranuts/utils` module | Throws outside a document. Use the bare `setTimeout`. |
|
|
230
|
+
| A module-level factory that keeps mutable state shared by everything it produces | Give each produced function its own state (this is why `generateThrottle` was removed). |
|
|
231
|
+
| Reaching for `memoize` expecting per-argument caching | It only runs once and ignores later arguments. Use `once` (its new name), `singleFlight` for async, or a `Map` for real keyed caching. |
|
|
232
|
+
| Assuming `createSignal` deep-compares | It uses `Object.is` since 0.3. Pass `{ equals: isEqual }` when you want deep comparison. |
|
|
233
|
+
| Testing a boolean URL flag with `getQuery(url).embed` | `?embed` (no value) is the usual spelling and reads as `''`, which is falsy. Use `queryFlag('embed')`. |
|
|
234
|
+
| `Promise.race([task, timeoutPromise])` for a deadline | Leaks the timer when the task wins. Use `withTimeout` / `withTimeoutFallback` — they always clear it. |
|
|
235
|
+
| Expecting `rewriteZip` to recompress | Rewritten and injected entries are written STORED, so the output is larger. Untouched entries keep their original compressed bytes. |
|
|
236
|
+
| Expecting `zip.ts` to open a >4 GiB archive | No ZIP64, no encryption, no multi-disk. `readZipEntries` returns `[]` for anything it cannot parse. |
|
|
237
|
+
| Calling `createHandoff().take()` twice | It is one-shot by design — the read and the delete share a transaction. The second call resolves `null`. |
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## Breaking changes in 0.3
|
|
242
|
+
|
|
243
|
+
The package is `0.x` and explicitly experimental, so these landed without a deprecation cycle.
|
|
244
|
+
Each fixed a defect rather than changing a preference.
|
|
245
|
+
|
|
246
|
+
| Symbol | Change | Migration |
|
|
247
|
+
| ------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
|
|
248
|
+
| `generateThrottle` | **Removed.** The factory's generated functions shared one timer and one timestamp, so unrelated throttled functions suppressed each other. | `const f = throttle(fn, delay)` |
|
|
249
|
+
| `memoize` | Renamed to `once`, kept as a deprecated alias. The old type declared zero arguments while forwarding them. | Prefer `once`; use `singleFlight` for the async case. |
|
|
250
|
+
| `createSignal` | `{ equals: true }` used to freeze the signal (it meant "always equal"); every write ran `cloneDeep` + `isEqual`, which overrode `equals` and put an O(size) copy on the write path. | Pass `{ equals: isEqual }` if you relied on deep comparison. |
|
|
251
|
+
| `QuestQueue` | Rewritten. `add()` never started anything, it popped LIFO, one promise carried unrelated tasks' results, and `allSettled` was off by one. The `total` constructor option is gone. | Use `await queue.add(task)`, `queue.allSettled(tasks)`, `queue.onIdle()`. |
|
|
252
|
+
| `report` | Return type narrowed to `boolean`; the image fallback is now reachable; **no default endpoint**. | `setReportUrl(url)` once, or pass `report({ url })`. |
|
|
253
|
+
| `debounce` / `throttle` | Now generically typed and return `cancel()` / `flush()` / `pending()`. | None; call `cancel()` on teardown. |
|
|
254
|
+
| `getHost` | **Removed.** Built a URL from a domain baked into this repo, and a stale edit had reduced its output to the unreachable literal `'//log.'`. | `setReportUrl` / `report({ url })`. |
|
|
255
|
+
| `createData` | No longer reads a hard-coded `chaxus_prod` cookie; `userId` appears only when configured. | `setReportUrl({ userIdCookie })`. |
|
|
256
|
+
| `formatJson` | Now `JSON.stringify` with lenient parsing in front. The old hand-rolled formatter corrupted braces/commas **inside string values** and mis-handled escaped quotes. Gained an `indent` param. | Output spacing now matches `JSON.stringify`. |
|
|
257
|
+
| `timestampToTime` | Deprecated in favour of `formatDate`. Chained case-insensitive `.replace()` calls made lowercase patterns like `yyyy-mm-dd` render as year-minute-day. | `formatDate(value, pattern)`. |
|
|
258
|
+
| `replaceOld` | Returns a restore function instead of `void`. | Additive; keep the returned function. |
|
|
259
|
+
| `handleConsole` / `handleFetchHook` / `handleXhrHook` / `handleError` / `handleClick` | Return a teardown function instead of `void`. | Additive; call it on teardown. |
|
|
260
|
+
| `Monitor` | No longer auto-starts from the constructor (it was gated on a global `window.ranlog`, so a second instance silently did nothing). Takes `{ url, channels, … }`; `start()` returns `stop()`. `createData()` is now evaluated per event, not captured at install time. | `new Monitor({ url }).start()`. |
|
|
261
|
+
| bridge symbols | Moved from `bom.ts` to `bridge.ts` (~600 lines of a different concern). | None — same barrel exports. |
|
|
262
|
+
| `getAllQueryString` / `getQuery` | Two byte-identical copies of a parser that **dropped every parameter without a value**, so `?embed` and `?readonly` read as absent. Rewritten once, aliased; bare flags now yield `''`, a fragment no longer leaks into the last value, and only the first `=` splits. | Use `queryFlag(key)` for boolean flags. |
|
|
263
|
+
| `localStorageGetItem` / `localStorageSetItem` | No longer branch on `isClient`, and no longer throw when storage access itself throws (blocked third-party frame, private mode, quota). | None. `createStore(prefix)` for JSON values. |
|
|
264
|
+
| `hexToRgb` | Return type narrowed from `RegExpExecArray \| null \| Array<number>` to `Array<number> \| null`, and 3-digit shorthand (`#abc`) is now expanded per CSS rules instead of failing to parse. | None — strictly more inputs accepted, narrower type. |
|
|
265
|
+
| `hsbToRgb` / `hsvToRgb` | Rounds instead of floors the final 0–255 channels. Flooring biased every channel down by up to 1, so `rgb → hsb → rgb` never converged (a colour picker lost saturation on repeated drags). | Values may differ by 1 per channel. None if you weren't asserting exact bytes. |
|
|
266
|
+
| `Chain` / `create` (`ranuts/vnode`) | `src/vnode/chainDom.ts` was a second copy missing SVG namespace support and listener management. Both entries now export the fuller `utils/chain` implementation. | None — the surviving one is a superset. |
|
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ npm install ranuts@latest --save
|
|
|
32
32
|
|
|
33
33
|
## Document
|
|
34
34
|
|
|
35
|
-
[Some commonly used functions and tools](https://chaxus.
|
|
35
|
+
[Some commonly used functions and tools](https://ran.chaxus.com/src/ranuts/)
|
|
36
36
|
|
|
37
37
|
**For AI agents / LLMs:** start from [CLAUDE.md](./CLAUDE.md) (orientation: entry points,
|
|
38
38
|
runtime constraints, conventions) and [docs/API.md](./docs/API.md) (generated reference of
|
|
@@ -53,14 +53,16 @@ Claude then uses it automatically (or invoke it as `/ranuts:ranuts`).
|
|
|
53
53
|
|
|
54
54
|
Import as required. You can select:
|
|
55
55
|
|
|
56
|
-
- ranuts/utils
|
|
57
|
-
- ranuts/node
|
|
58
|
-
- ranuts/
|
|
56
|
+
- `ranuts/utils` — DOM/BOM, string, object, number, colour, time, storage, i18n helpers
|
|
57
|
+
- `ranuts/node` — HTTP server, router, ws, fs, streams, middleware (**Node only**)
|
|
58
|
+
- `ranuts/visual` — 2D rendering engine (Canvas / WebGL / WebGPU, **browser only**)
|
|
59
|
+
- `ranuts/vnode` — Snabbdom-style virtual DOM
|
|
60
|
+
- `ranuts/i18n` — the i18n engine on its own, without the rest of `utils`
|
|
59
61
|
|
|
60
62
|
```js
|
|
61
63
|
import { str2Xml } from 'ranuts/utils';
|
|
62
64
|
import { readFile } from 'ranuts/node';
|
|
63
|
-
import {
|
|
65
|
+
import { createI18n } from 'ranuts/i18n';
|
|
64
66
|
```
|
|
65
67
|
|
|
66
68
|
Full import,(Full import will introduce many unnecessary modules. You are advised to import them on demand)
|
package/README.zh-CN.md
CHANGED
|
@@ -34,20 +34,22 @@ npm install ranuts@latest --save
|
|
|
34
34
|
|
|
35
35
|
## 文档
|
|
36
36
|
|
|
37
|
-
[一些常用的函数和工具](https://chaxus.
|
|
37
|
+
[一些常用的函数和工具](https://ran.chaxus.com/cn/src/ranuts/)
|
|
38
38
|
|
|
39
39
|
## 使用方式
|
|
40
40
|
|
|
41
41
|
按需导入。您可以选择:
|
|
42
42
|
|
|
43
|
-
- ranuts/utils
|
|
44
|
-
- ranuts/node
|
|
45
|
-
- ranuts/
|
|
43
|
+
- `ranuts/utils` —— DOM/BOM、字符串、对象、数字、颜色、时间、存储、i18n 等工具
|
|
44
|
+
- `ranuts/node` —— HTTP 服务、路由、ws、fs、流、中间件(**仅 Node**)
|
|
45
|
+
- `ranuts/visual` —— 2D 渲染引擎(Canvas / WebGL / WebGPU,**仅浏览器**)
|
|
46
|
+
- `ranuts/vnode` —— Snabbdom 风格的虚拟 DOM
|
|
47
|
+
- `ranuts/i18n` —— 单独的 i18n 引擎,不牵入 `utils` 的其余部分
|
|
46
48
|
|
|
47
49
|
```js
|
|
48
50
|
import { str2Xml } from 'ranuts/utils';
|
|
49
51
|
import { readFile } from 'ranuts/node';
|
|
50
|
-
import {
|
|
52
|
+
import { createI18n } from 'ranuts/i18n';
|
|
51
53
|
```
|
|
52
54
|
|
|
53
55
|
全量导入(全量导入会引入许多不必要的模块,建议按需导入)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e=["svg","path","g","circle","rect","line","polyline","polygon","ellipse","text","tspan","textPath","defs","marker","radialGradient","stop","linearGradient","clipPath","mask","pattern","image","use","symbol","foreignObject","feGaussianBlur","feColorMatrix"],t=class t{listener;element;constructor(e,t){this.element=this.create(e,t),this.listener=/* @__PURE__ */new Map}create=(t,n)=>e.includes(t)?document.createElementNS("http://www.w3.org/2000/svg",t,n):document.createElement(t,n);setAttribute=(e,t)=>(this.element.setAttribute(e,t),this);removeAttribute=e=>(this.element.removeAttribute(e),this);append=e=>(this.element.appendChild(e),this);remove=e=>(this.element.removeChild(e),this);setTextContent=e=>(this.element.textContent=e,this);setStyle=(e,t)=>(this.element.style.setProperty(e,t),this);addElementByType=(e,n)=>{e instanceof t&&n.appendChild(e.element),e instanceof HTMLElement&&n.appendChild(e)};addChild=e=>{if(Array.isArray(e)){const t=document.createDocumentFragment();e.forEach(e=>{this.addElementByType(e,t)}),this.element.appendChild(t)}else this.addElementByType(e,this.element);return this};listen=(e,t,n)=>{let s=this.listener.get(e);s||(s=/* @__PURE__ */new Map,this.listener.set(e,s));const i=s.get(t.name);return i===t&&console.warn(`${i.name} listener has been added to ${e} event, please remove it first.`),this.element.addEventListener(e,t,n),s.set(t.name,t),this};clearListener=(e,t,n)=>{this.element.removeEventListener(e,t,n);const s=this.listener.get(e);return s?s.delete(t.name):console.warn(`No ${e} event listener has been added.`),this};clearAllListener=()=>{for(const[e,t]of this.listener){for(const[n,s]of t)this.element.removeEventListener(e,s),t.delete(n);this.listener.delete(e)}return this}},n=(e,n)=>new t(e,n);export{n,t};
|