@human-synthesis/norns 0.0.7 → 0.0.8
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/README.md +83 -14
- package/package.json +1 -1
- package/src/auto-import.js +11 -1
- package/src/config.js +1 -1
- package/src/server/validate.js +1 -1
- package/src/vite.js +0 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**AI-driven software architecture and development framework, based on Svelte.**
|
|
4
4
|
|
|
5
|
-
SvelteKit with **Pug + Civet** and the `.n` / `.c` file extensions — preconfigured. The `.c` extension is recognised as an alias for `.civet`; both compile through Civet.
|
|
5
|
+
SvelteKit with **Pug + Civet** and the `.n` / `.c` file extensions — preconfigured. The `.c` extension is recognised as an alias for `.civet`; both compile through Civet.
|
|
6
6
|
|
|
7
7
|
Includes a small runtime layer: feature-folder modularity, a DI container, route/page wrappers with valibot validation, and a migrations CLI.
|
|
8
8
|
|
|
@@ -63,7 +63,7 @@ export default defineConfig({
|
|
|
63
63
|
|
|
64
64
|
## Auto-imports
|
|
65
65
|
|
|
66
|
-
`nornsAutoImport()` returns an object that's both a Svelte preprocessor (for `.n` / `.svelte` files) and a Vite plugin (for standalone `.c` / `.civet` modules). Wire it in both places:
|
|
66
|
+
`nornsAutoImport()` returns an object that's both a Svelte preprocessor (for `.n` / `.svelte` files) and a Vite plugin (for standalone `.c` / `.civet` modules). The same instance has all four resolvers: framework helpers, project components, project utilities, and library presets. Wire it in both places — Svelte's compiler ignores the Vite hooks, Vite ignores the Svelte hooks:
|
|
67
67
|
|
|
68
68
|
```js
|
|
69
69
|
// svelte.config.js
|
|
@@ -72,7 +72,13 @@ import { nornsPreprocess } from '@human-synthesis/norns/preprocess';
|
|
|
72
72
|
import { nornsAutoImport } from '@human-synthesis/norns/auto-import';
|
|
73
73
|
|
|
74
74
|
export default nornsConfig({
|
|
75
|
-
preprocess: [
|
|
75
|
+
preprocess: [
|
|
76
|
+
...nornsPreprocess(),
|
|
77
|
+
nornsAutoImport({
|
|
78
|
+
componentDirs: ['src/lib/components', 'src/routes'],
|
|
79
|
+
exportDirs: ['src/lib', 'src/routes']
|
|
80
|
+
})
|
|
81
|
+
]
|
|
76
82
|
});
|
|
77
83
|
```
|
|
78
84
|
|
|
@@ -81,24 +87,87 @@ export default nornsConfig({
|
|
|
81
87
|
import { nornsCivetPlugin } from '@human-synthesis/norns/vite';
|
|
82
88
|
import { nornsAutoImport } from '@human-synthesis/norns/auto-import';
|
|
83
89
|
|
|
84
|
-
export default {
|
|
90
|
+
export default {
|
|
91
|
+
plugins: [
|
|
92
|
+
nornsCivetPlugin(),
|
|
93
|
+
nornsAutoImport({ exportDirs: ['src/lib', 'src/routes'] }),
|
|
94
|
+
sveltekit()
|
|
95
|
+
]
|
|
96
|
+
};
|
|
85
97
|
```
|
|
86
98
|
|
|
87
|
-
|
|
99
|
+
### What gets auto-imported
|
|
88
100
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
-
|
|
92
|
-
|
|
93
|
-
|
|
101
|
+
| Layer | Resolves | Examples |
|
|
102
|
+
|-------|----------|----------|
|
|
103
|
+
| Helpers | Hardcoded module-name lists, optionally path-gated | `onMount` from `svelte`, `redirect` from `@sveltejs/kit`, `page` from `$app/state` (client) or `@human-synthesis/norns/server` (server) |
|
|
104
|
+
| Components (dir scan) | Capitalised basenames in `componentDirs` | `<Card>` → `$lib/components/Card.svelte`; `<Game>` → `./Game.n` (route-colocated, importer-relative) |
|
|
105
|
+
| Components (preset map) | Bare-specifier `Record<name, importPath>` from a UI library | `<Btn>` → `'@human-synthesis/norns-ui/components/Btn.n'` (used verbatim) |
|
|
106
|
+
| Project utilities | Named exports (`export const X`, `export X := …`, `export { a, b }`) discovered in `exportDirs` | `notes` from `$lib/notes/server/public`; `scheduleAiMove` from `./ai` (sibling) |
|
|
94
107
|
|
|
95
|
-
|
|
108
|
+
Resolution priority is **helpers → component dir → component preset → exports**. A name picked up earlier shadows a later match silently — first-match-wins lets you override a library preset by dropping a file under your own `componentDirs`.
|
|
109
|
+
|
|
110
|
+
Path emission:
|
|
111
|
+
|
|
112
|
+
- Files inside `$lib` emit `$lib/...` paths (portable, friendly to the dts file).
|
|
113
|
+
- Files outside `$lib` emit a path relative to the importer.
|
|
114
|
+
- Project-utility paths are stripped of their file extension to match Norns/SvelteKit convention (`'$lib/notes/server/public'`, not `…/public.c`); the configured `extensions` array does the rest.
|
|
115
|
+
|
|
116
|
+
Files without a `<script>` block get one prepended automatically when a known component is referenced from markup. Runes (`$state`, `$derived`, `$effect`, `$props`) are Svelte compiler globals — no import needed; the plugin doesn't touch them.
|
|
117
|
+
|
|
118
|
+
### Defaults
|
|
119
|
+
|
|
120
|
+
- **Helpers**: `svelte`, `svelte/store`, `@sveltejs/kit`, `$app/state` (non-server paths), `@human-synthesis/norns/server` (server paths only).
|
|
121
|
+
- **Component dirs**: `['src/lib/components']`.
|
|
122
|
+
- **Component extensions**: `['.svelte', '.n']`.
|
|
123
|
+
- **Export dirs**: `false` (off) — opt in. SvelteKit route/hook files (`+*.{c,svelte,n}`, `hooks.*`) are excluded from the export scan since their named exports (`load`, `actions`, `handle`, …) are framework-consumed.
|
|
124
|
+
- **Export extensions**: `['.c', '.civet', '.js']`. `.ts` is excluded by default — regex-based scanning can't reliably tell value exports from type-only ones under `verbatimModuleSyntax`.
|
|
125
|
+
|
|
126
|
+
### UI library presets
|
|
127
|
+
|
|
128
|
+
A preset is a function returning a config slice — typically a `components` map. Compose it with your own config:
|
|
129
|
+
|
|
130
|
+
```js
|
|
131
|
+
// vite.config.js
|
|
132
|
+
import { presetUI } from '@human-synthesis/norns-ui/auto-import';
|
|
133
|
+
|
|
134
|
+
const ui = presetUI();
|
|
135
|
+
|
|
136
|
+
export default {
|
|
137
|
+
plugins: [
|
|
138
|
+
nornsCivetPlugin(),
|
|
139
|
+
nornsAutoImport({
|
|
140
|
+
exportDirs: ['src/lib', 'src/routes'],
|
|
141
|
+
components: ui.components // { Btn: '@human-synthesis/norns-ui/components/Btn.n', … }
|
|
142
|
+
}),
|
|
143
|
+
sveltekit()
|
|
144
|
+
]
|
|
145
|
+
};
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Drop `src/lib/components/Btn.n` in your project and it shadows the preset's `Btn` silently — `componentDirs` resolves first.
|
|
149
|
+
|
|
150
|
+
> **Roadmap.** Helpers from a preset (e.g. `toast()` from a UI library) currently can't merge with the defaults — passing `helpers` to `nornsAutoImport` _replaces_ the default list. A `presets` (or `additionalHelpers`) option to extend without replacing is a planned follow-up; for now, presets only deliver components.
|
|
151
|
+
|
|
152
|
+
### Full options reference
|
|
153
|
+
|
|
154
|
+
| Option | Default | Notes |
|
|
155
|
+
|--------|---------|-------|
|
|
156
|
+
| `helpers` | `DEFAULT_HELPERS` (5 modules) | Pass `false` to disable. Each entry: `{ from, imports[], match? }` where `match` is a regex tested against the filename. |
|
|
157
|
+
| `componentDirs` | `['src/lib/components']` | `false` or `[]` to disable. |
|
|
158
|
+
| `componentExtensions` | `['.svelte', '.n']` | |
|
|
159
|
+
| `components` | `null` | `Record<name, importPath>` — bare-specifier preset map. |
|
|
160
|
+
| `exportDirs` | `false` | Off by default. Opt in with e.g. `['src/lib', 'src/routes']`. |
|
|
161
|
+
| `exportExtensions` | `['.c', '.civet', '.js']` | |
|
|
162
|
+
| `libRoot` | `'src/lib'` | Project-relative root that `libAlias` maps to. |
|
|
163
|
+
| `libAlias` | `'$lib'` | Alias prefix emitted in import paths. |
|
|
164
|
+
| `root` | `process.cwd()` | Project root. |
|
|
96
165
|
|
|
97
166
|
## Runtime — feature folders + DI
|
|
98
167
|
|
|
99
168
|
Wire your hooks once:
|
|
100
169
|
|
|
101
|
-
```
|
|
170
|
+
```civet
|
|
102
171
|
# src/hooks.server.c
|
|
103
172
|
import { boot } from '@human-synthesis/norns/server'
|
|
104
173
|
|
|
@@ -124,7 +193,7 @@ src/lib/notes/
|
|
|
124
193
|
|
|
125
194
|
Routes use thin wrappers from `@human-synthesis/norns/server`:
|
|
126
195
|
|
|
127
|
-
```
|
|
196
|
+
```civet
|
|
128
197
|
# src/routes/notes/+page.server.c
|
|
129
198
|
import { page } from '@human-synthesis/norns/server'
|
|
130
199
|
import { notes } from '$lib/notes/server/public'
|
|
@@ -160,7 +229,7 @@ v1 supports SQLite via `better-sqlite3`. For Cloudflare D1 use `wrangler d1 migr
|
|
|
160
229
|
|
|
161
230
|
The `db` helpers wire Drizzle across multiple targets:
|
|
162
231
|
|
|
163
|
-
```
|
|
232
|
+
```civet
|
|
164
233
|
# module.c — Node + better-sqlite3 in dev
|
|
165
234
|
import { betterSqlite } from '@human-synthesis/norns/server'
|
|
166
235
|
db := await betterSqlite 'data/app.db', { pragma: ['journal_mode = WAL'] }
|
package/package.json
CHANGED
package/src/auto-import.js
CHANGED
|
@@ -208,11 +208,20 @@ function extractExports(source) {
|
|
|
208
208
|
return out;
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
+
// SvelteKit route conventions (`+page.server.c`, `+layout.c`, `+server.c`,
|
|
212
|
+
// `+error.svelte`, …) and hooks (`hooks.server.c`, `hooks.client.c`) export
|
|
213
|
+
// names like `load`, `actions`, `GET`, `handle`, `prerender` that are
|
|
214
|
+
// CONSUMED BY THE FRAMEWORK — never meant to be imported by other code. If
|
|
215
|
+
// they entered the export map, a user identifier called `load` would
|
|
216
|
+
// auto-import a random route's load function. Excluded by basename.
|
|
217
|
+
const ROUTE_FILE_RE = /^(\+|hooks\.)/;
|
|
218
|
+
|
|
211
219
|
/**
|
|
212
220
|
* Walk `dirs` and build a name → absolute-file-path map of every named
|
|
213
221
|
* value export found. First-match-wins on collisions (same as the component
|
|
214
222
|
* scanner) — silent because warnings would noise up the dev server on
|
|
215
|
-
* intentional re-exports.
|
|
223
|
+
* intentional re-exports. SvelteKit route/hook files are excluded by
|
|
224
|
+
* basename so framework-consumed exports don't leak into the map.
|
|
216
225
|
*
|
|
217
226
|
* @param {string} root
|
|
218
227
|
* @param {string[]} dirs
|
|
@@ -225,6 +234,7 @@ function buildExportMap(root, dirs, exts) {
|
|
|
225
234
|
for (const d of dirs) {
|
|
226
235
|
const abs = resolve(root, d);
|
|
227
236
|
for (const file of walk(abs, exts)) {
|
|
237
|
+
if (ROUTE_FILE_RE.test(basename(file))) continue;
|
|
228
238
|
let source;
|
|
229
239
|
try {
|
|
230
240
|
source = readFileSync(file, 'utf8');
|
package/src/config.js
CHANGED
|
@@ -14,7 +14,7 @@ import { nornsPreprocess } from '@human-synthesis/norns-core/preprocess';
|
|
|
14
14
|
* `.ts` for hooks (it doesn't honor `moduleExtensions`), so the explicit
|
|
15
15
|
* path is the non-invasive way to make `.c`/`.civet` hooks discoverable.
|
|
16
16
|
* Same for the client and universal counterparts.
|
|
17
|
-
* - `preprocess: nornsPreprocess()` —
|
|
17
|
+
* - `preprocess: nornsPreprocess()` — Pug + Civet
|
|
18
18
|
*
|
|
19
19
|
* Spread your own overrides at the call site to extend or replace defaults.
|
|
20
20
|
*
|
package/src/server/validate.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Validation glue. Norns doesn't bundle a schema library — it speaks the
|
|
3
3
|
* Standard Schema interface (https://github.com/standard-schema/standard-schema)
|
|
4
4
|
* supported by Valibot, Zod 3.24+, ArkType, etc. A plain function (`input -> parsed`)
|
|
5
|
-
* also works, for ad-hoc cases or simple
|
|
5
|
+
* also works, for ad-hoc cases or simple hand-rolled parsers.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
/** @typedef {{ '~standard': { validate: (input: unknown) => any } }} StandardSchema */
|
package/src/vite.js
CHANGED
|
@@ -68,7 +68,6 @@ async function resolveWorkspaceFrameworkSrcs(root) {
|
|
|
68
68
|
* Node's ESM module cache survives `server.restart()`.
|
|
69
69
|
*
|
|
70
70
|
* `.c` is recognised as an alias for `.civet` — both compile through Civet.
|
|
71
|
-
* CoffeeScript is no longer supported.
|
|
72
71
|
*
|
|
73
72
|
* @returns {import('vite').Plugin}
|
|
74
73
|
*/
|