first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,82 @@
# Config loader — `config.ts`
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
`loadConfig(cliArgs, deps?)` builds an `ElectrobunConfig` by layering
hard-coded defaults, an optional on-disk `.suaveplan-electrobun.json`,
and CLI argument overrides on top of one another. The loader sits on
`@suaveplan/config`'s five-layer pipeline (defaults / file / object /
env / CLI), wiring three of the five for the scaffolder's needs.
The `--name`, `--id`, `--icon`, and `--version` CLI flags map to the
`name`, `identifier`, `iconSource`, and `version` fields respectively.
Defaults fill `version="0.0.1"`, `features=[]`,
`networkingComplexity="basic"`, and `r3fModules=[]` so callers can rely
on the final shape having those fields populated even when no file or
flag supplies them.
The `ConfigDiscoveryAdapter` seam (defined in `src/fs/fs.ts`) controls
where the loader looks for the config file. Tests inject an in-memory
adapter; production code uses the default `nodeConfigDiscoveryAdapter`
that probes `process.cwd()` then `homedir()` via real `node:fs` calls.
## Features
- Three-layer build: defaults → file → CLI.
- Synchronous (no async lift required by callers).
- Wraps malformed JSON as `ELECTROBUN.CONFIG_PARSE_FAILED`.
- Pluggable file discovery through `ConfigDiscoveryAdapter`.
- Exported `CLI_MAPPING` constant so consumers can introspect the flag
set (used by the `--help` text builder).
## Usage: Basic
```ts
import { loadConfig } from "@suaveplan/electrobun/config";
const cfg = loadConfig(process.argv.slice(2));
console.log(cfg.name ?? "(no name set)");
```
## Usage: Advanced
```ts
import { loadConfig } from "@suaveplan/electrobun/config";
import type { ConfigDiscoveryAdapter } from "@suaveplan/electrobun/fs";
const inMemory: ConfigDiscoveryAdapter = {
cwd: () => "/proj",
homedir: () => "/home/user",
exists: (p) => p === "/proj/.suaveplan-electrobun.json",
readFile: () => JSON.stringify({ name: "ci-app", features: ["api"] }),
};
const cfg = loadConfig(["--icon", "/icons/app.png"], {
discovery: inMemory,
});
// cfg.name === "ci-app"; cfg.iconSource === "/icons/app.png"
```
## API Reference
- `loadConfig(cliArgs: readonly string[] = [], deps?: { discovery?:
ConfigDiscoveryAdapter }): ElectrobunConfig`.
- `HARDCODED_DEFAULTS: ElectrobunConfig` — frozen defaults applied at
the bottom of the layer stack.
- `CLI_MAPPING: Record<string, string>` — exact flag-to-field mapping
used by the CLI layer.
## Implementation Notes
`@suaveplan/config`'s `cliLayer` takes mapping keys without the leading
`--`; the constants here mirror that contract verbatim. `coerceValue`
inside the cli layer parses booleans, numbers, and JSON literals, so a
caller can pass `--features '["api","i18n"]'` and have the array land
on the right field without bespoke wiring.
The file layer is skipped entirely when `findConfigFile` returns
`undefined`. This keeps the layer stack short for the common "no config
file" case and avoids a no-op fileLayer reload subscription.