@human-synthesis/norns-tron 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.
- package/package.json +1 -1
- package/src/spec.d.ts +7 -1
- package/src/spec.js +25 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@human-synthesis/norns-tron",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "TRON serialization for the Norns ecosystem — token-efficient, faster-than-JSON wire format for APIs and LLM-facing output.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Daniel Teodoroiu (https://humansynthesis.ai)",
|
package/src/spec.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
export const SPEC_EXT: '.
|
|
1
|
+
export const SPEC_EXT: '.t';
|
|
2
|
+
/** Accepted spec extensions, in preference order — `.t` is the default. */
|
|
3
|
+
export const SPEC_EXTS: readonly ['.t', '.tron'];
|
|
2
4
|
export const APP_SPEC: 'app';
|
|
3
5
|
|
|
6
|
+
/** On-disk filename for a module: its existing file, else `<name>.t`. */
|
|
7
|
+
export function specFilename(name: string, files?: Record<string, string>): string;
|
|
8
|
+
|
|
4
9
|
/** sha256 hex of a value's canonical text — the unit of change detection. */
|
|
5
10
|
export function specHash(value: unknown): string;
|
|
6
11
|
|
|
@@ -20,6 +25,7 @@ export function writeSpec(
|
|
|
20
25
|
export function readSpecs(dir: string): {
|
|
21
26
|
app: unknown;
|
|
22
27
|
modules: Record<string, unknown>;
|
|
28
|
+
files: Record<string, string>;
|
|
23
29
|
hashes: Record<string, string>;
|
|
24
30
|
version: string;
|
|
25
31
|
};
|
package/src/spec.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Spec-file helpers — server-side only (`@human-synthesis/norns-tron/spec`).
|
|
3
3
|
*
|
|
4
|
-
* A Norns app's canonical spec lives in `specs/` as one `.
|
|
5
|
-
* module plus `app.
|
|
4
|
+
* A Norns app's canonical spec lives in `specs/` as one `.t` file per
|
|
5
|
+
* module plus `app.t`, written in canonical form (see canonical.js). The
|
|
6
|
+
* long-form `.tron` extension is accepted too; `.t` is the default for new
|
|
7
|
+
* files, matching the other Norns extensions (`.n`, `.c`, `.p`).
|
|
6
8
|
* These helpers read/write that directory and compute the content-addressed
|
|
7
9
|
* version hashes used by `ifVersion` optimistic checks and incremental
|
|
8
10
|
* generation.
|
|
@@ -15,9 +17,16 @@ import { basename, dirname, join } from 'node:path';
|
|
|
15
17
|
import { formatCanonical } from './canonical.js';
|
|
16
18
|
import * as AUTO from './core/tron-auto.js';
|
|
17
19
|
|
|
18
|
-
export const SPEC_EXT = '.
|
|
20
|
+
export const SPEC_EXT = '.t';
|
|
21
|
+
/** Accepted spec extensions, in preference order — `.t` is the default. */
|
|
22
|
+
export const SPEC_EXTS = ['.t', '.tron'];
|
|
19
23
|
export const APP_SPEC = 'app';
|
|
20
24
|
|
|
25
|
+
/** On-disk filename for a module: its existing file, else `<name>.t`. */
|
|
26
|
+
export function specFilename(name, files) {
|
|
27
|
+
return files?.[name] ?? name + SPEC_EXT;
|
|
28
|
+
}
|
|
29
|
+
|
|
21
30
|
/** sha256 hex of a value's canonical text — the unit of change detection. */
|
|
22
31
|
export function specHash(value) {
|
|
23
32
|
return createHash('sha256').update(formatCanonical(value), 'utf-8').digest('hex');
|
|
@@ -55,27 +64,36 @@ export function writeSpec(file, value) {
|
|
|
55
64
|
*
|
|
56
65
|
* @param {string} dir
|
|
57
66
|
* @returns {{
|
|
58
|
-
* app: *, // app
|
|
67
|
+
* app: *, // app spec contents (null if absent)
|
|
59
68
|
* modules: Record<string, *>, // module name -> spec value
|
|
69
|
+
* files: Record<string, string>, // module name -> on-disk filename
|
|
60
70
|
* hashes: Record<string, string>, // per-file canonical hash (incl. 'app')
|
|
61
71
|
* version: string // hash over all files — the app version
|
|
62
72
|
* }}
|
|
63
73
|
*/
|
|
64
74
|
export function readSpecs(dir) {
|
|
65
75
|
const names = readdirSync(dir)
|
|
66
|
-
.filter((f) => f.endsWith(
|
|
76
|
+
.filter((f) => SPEC_EXTS.some((ext) => f.endsWith(ext)))
|
|
67
77
|
.sort();
|
|
68
78
|
const modules = {};
|
|
79
|
+
const files = {};
|
|
69
80
|
const hashes = {};
|
|
70
81
|
let app = null;
|
|
71
82
|
for (const f of names) {
|
|
72
|
-
const
|
|
83
|
+
const ext = SPEC_EXTS.find((e) => f.endsWith(e));
|
|
84
|
+
const name = basename(f, ext);
|
|
85
|
+
if (files[name] !== undefined) {
|
|
86
|
+
throw new Error(
|
|
87
|
+
`duplicate spec for "${name}": ${files[name]} and ${f} — keep one (\`.t\` is the default)`
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
files[name] = f;
|
|
73
91
|
const value = readSpec(join(dir, f));
|
|
74
92
|
hashes[name] = specHash(value);
|
|
75
93
|
if (name === APP_SPEC) app = value;
|
|
76
94
|
else modules[name] = value;
|
|
77
95
|
}
|
|
78
|
-
return { app, modules, hashes, version: combineHashes(hashes) };
|
|
96
|
+
return { app, modules, files, hashes, version: combineHashes(hashes) };
|
|
79
97
|
}
|
|
80
98
|
|
|
81
99
|
/**
|