@madojs/mado 0.5.1 → 0.6.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/AGENTS.md +26 -0
- package/CHANGELOG.md +265 -0
- package/MADO_V1_PLAN.md +179 -0
- package/README.md +31 -13
- package/ROADMAP.md +28 -7
- package/TODO.md +72 -0
- package/dist/src/forms.d.ts +37 -4
- package/dist/src/forms.js +331 -57
- package/dist/src/forms.js.map +1 -1
- package/dist/src/html/bindings.d.ts +41 -0
- package/dist/src/html/bindings.js +163 -6
- package/dist/src/html/bindings.js.map +1 -1
- package/dist/src/html.d.ts +2 -0
- package/dist/src/html.js +1 -0
- package/dist/src/html.js.map +1 -1
- package/dist/src/index.d.ts +6 -6
- package/dist/src/index.js +2 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/page.d.ts +56 -0
- package/dist/src/page.js +17 -0
- package/dist/src/page.js.map +1 -1
- package/dist/src/resource.js +11 -0
- package/dist/src/resource.js.map +1 -1
- package/dist/src/router/manifest.d.ts +16 -1
- package/dist/src/router/manifest.js +210 -40
- package/dist/src/router/manifest.js.map +1 -1
- package/dist/src/router/match.d.ts +7 -2
- package/dist/src/router/match.js +14 -4
- package/dist/src/router/match.js.map +1 -1
- package/dist/src/router/navigation.d.ts +10 -0
- package/dist/src/router/navigation.js +71 -3
- package/dist/src/router/navigation.js.map +1 -1
- package/dist/src/signal.d.ts +15 -1
- package/dist/src/signal.js +112 -16
- package/dist/src/signal.js.map +1 -1
- package/docs/en/02-project-layout.md +99 -40
- package/docs/en/10-app-architecture.md +141 -0
- package/docs/en/11-layouts.md +115 -0
- package/docs/en/12-auth-and-api.md +217 -0
- package/docs/en/13-deployment.md +192 -0
- package/docs/en/14-testing.md +82 -0
- package/docs/en/15-error-handling.md +100 -0
- package/docs/en/16-bake-cookbook.md +93 -0
- package/docs/en/README.md +7 -0
- package/docs/fr/10-app-architecture.md +61 -0
- package/docs/fr/11-layouts.md +35 -0
- package/docs/fr/12-auth-and-api.md +35 -0
- package/docs/fr/13-deployment.md +39 -0
- package/docs/fr/14-testing.md +41 -0
- package/docs/fr/15-error-handling.md +50 -0
- package/docs/fr/16-bake-cookbook.md +35 -0
- package/docs/fr/README.md +7 -0
- package/docs/ru/10-app-architecture.md +100 -0
- package/docs/ru/11-layouts.md +47 -0
- package/docs/ru/12-auth-and-api.md +53 -0
- package/docs/ru/13-deployment.md +60 -0
- package/docs/ru/14-testing.md +50 -0
- package/docs/ru/15-error-handling.md +56 -0
- package/docs/ru/16-bake-cookbook.md +55 -0
- package/docs/ru/README.md +7 -0
- package/docs/uk/10-app-architecture.md +56 -0
- package/docs/uk/11-layouts.md +34 -0
- package/docs/uk/12-auth-and-api.md +34 -0
- package/docs/uk/13-deployment.md +39 -0
- package/docs/uk/14-testing.md +34 -0
- package/docs/uk/15-error-handling.md +32 -0
- package/docs/uk/16-bake-cookbook.md +36 -0
- package/docs/uk/README.md +7 -0
- package/llms.txt +9 -1
- package/package.json +3 -1
- package/scripts/_config.mjs +224 -0
- package/scripts/bake.mjs +266 -121
- package/scripts/bundle.mjs +133 -67
- package/scripts/cli.mjs +195 -27
- package/scripts/preview.mjs +125 -21
- package/server/serve.mjs +161 -10
- package/starters/admin/README.md +63 -0
- package/starters/admin/index.html +28 -0
- package/starters/admin/mado.config.json +22 -0
- package/starters/admin/package.json +24 -0
- package/starters/admin/public/favicon.svg +4 -0
- package/starters/admin/src/components/x-button.ts +55 -0
- package/starters/admin/src/components/x-input.ts +74 -0
- package/starters/admin/src/layouts/app.ts +101 -0
- package/starters/admin/src/layouts/auth.ts +41 -0
- package/starters/admin/src/lib/api.ts +133 -0
- package/starters/admin/src/lib/auth.ts +83 -0
- package/starters/admin/src/main.ts +15 -0
- package/starters/admin/src/pages/admin/dashboard.ts +48 -0
- package/starters/admin/src/pages/admin/order-detail.ts +80 -0
- package/starters/admin/src/pages/admin/orders.ts +117 -0
- package/starters/admin/src/pages/home.ts +34 -0
- package/starters/admin/src/pages/login.ts +70 -0
- package/starters/admin/src/pages/not-found.ts +12 -0
- package/starters/admin/src/routes.ts +40 -0
- package/starters/admin/src/styles/global.ts +86 -0
- package/starters/admin/tsconfig.json +15 -0
- package/starters/crud/index.html +12 -4
- package/starters/crud/mado.config.json +20 -0
- package/starters/crud/package.json +9 -3
- package/starters/crud/src/pages/home.ts +16 -0
- package/starters/crud/src/routes.ts +4 -2
- package/starters/minimal/index.html +12 -4
- package/starters/minimal/mado.config.json +20 -0
- package/starters/minimal/package.json +9 -3
- package/starters/minimal/src/pages/home.ts +17 -0
- package/starters/minimal/src/routes.ts +4 -2
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
// Mado configuration loader.
|
|
2
|
+
//
|
|
3
|
+
// Single source of project configuration for `mado dev`, `mado build`,
|
|
4
|
+
// `mado bundle`, `mado bake`, `mado preview`, `mado release`.
|
|
5
|
+
//
|
|
6
|
+
// Lookup order (first hit wins):
|
|
7
|
+
// 1. `mado.config.json` in PROJECT_ROOT (recommended)
|
|
8
|
+
// 2. built-in defaults
|
|
9
|
+
//
|
|
10
|
+
// CLI flags always override file values, file values override defaults.
|
|
11
|
+
//
|
|
12
|
+
// Context detection:
|
|
13
|
+
// - "app" : a user project that depends on `@madojs/mado`
|
|
14
|
+
// - "repo" : the framework repository itself (has src/index.ts and examples/)
|
|
15
|
+
//
|
|
16
|
+
// In app-mode, defaults assume the canonical layout from MADO_V1_PLAN.md:
|
|
17
|
+
// src/routes.ts index.html public/ dist/ out/
|
|
18
|
+
|
|
19
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
20
|
+
import { dirname, join, resolve } from "node:path";
|
|
21
|
+
import { fileURLToPath } from "node:url";
|
|
22
|
+
|
|
23
|
+
const PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @typedef {Object} MadoDevConfig
|
|
27
|
+
* @property {number} [port]
|
|
28
|
+
* @property {Record<string,string>} [proxy] // path → upstream base URL
|
|
29
|
+
*
|
|
30
|
+
* @typedef {Object} MadoBuildConfig
|
|
31
|
+
* @property {string} [out] // deploy artifact dir (default: "out")
|
|
32
|
+
* @property {string} [dist] // tsc output dir (default: "dist")
|
|
33
|
+
* @property {string} [publicDir] // static assets dir (default: "public")
|
|
34
|
+
*
|
|
35
|
+
* @typedef {Object} MadoBakeConfig
|
|
36
|
+
* @property {string} [entry] // routes module (default: "src/routes.ts")
|
|
37
|
+
* @property {string} [template] // SPA shell html (default: "index.html")
|
|
38
|
+
* @property {string} [baseUrl] // canonical/sitemap base
|
|
39
|
+
* @property {string} [outDir] // override (default: build.out + "/baked")
|
|
40
|
+
*
|
|
41
|
+
* @typedef {Object} MadoBundleConfig
|
|
42
|
+
* @property {boolean} [splitting]
|
|
43
|
+
* @property {Array<"gz"|"br">} [compress]
|
|
44
|
+
*
|
|
45
|
+
* @typedef {Object} MadoConfig
|
|
46
|
+
* @property {"app"|"repo"} context
|
|
47
|
+
* @property {string} projectRoot
|
|
48
|
+
* @property {MadoDevConfig} dev
|
|
49
|
+
* @property {MadoBuildConfig} build
|
|
50
|
+
* @property {MadoBakeConfig} bake
|
|
51
|
+
* @property {MadoBundleConfig} bundle
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Detect whether we are inside the framework repository or inside a user app.
|
|
56
|
+
*
|
|
57
|
+
* Heuristic: the framework repo has both `src/index.ts` and an `examples/`
|
|
58
|
+
* directory at PROJECT_ROOT. Anything else is treated as an app.
|
|
59
|
+
*
|
|
60
|
+
* @param {string} projectRoot
|
|
61
|
+
* @returns {"app"|"repo"}
|
|
62
|
+
*/
|
|
63
|
+
export function detectContext(projectRoot) {
|
|
64
|
+
const looksLikeRepo =
|
|
65
|
+
existsSync(join(projectRoot, "src/index.ts")) &&
|
|
66
|
+
existsSync(join(projectRoot, "examples")) &&
|
|
67
|
+
existsSync(join(projectRoot, "package.json")) &&
|
|
68
|
+
safeReadJson(join(projectRoot, "package.json"))?.name === "@madojs/mado";
|
|
69
|
+
return looksLikeRepo ? "repo" : "app";
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Built-in defaults per context.
|
|
74
|
+
*
|
|
75
|
+
* @param {"app"|"repo"} context
|
|
76
|
+
* @returns {MadoConfig}
|
|
77
|
+
*/
|
|
78
|
+
function defaults(context) {
|
|
79
|
+
if (context === "repo") {
|
|
80
|
+
return {
|
|
81
|
+
context,
|
|
82
|
+
projectRoot: "",
|
|
83
|
+
dev: { port: 5173, proxy: {} },
|
|
84
|
+
build: { out: "out", dist: "dist", publicDir: "public" },
|
|
85
|
+
bake: {
|
|
86
|
+
entry: "examples/basic/routes.ts",
|
|
87
|
+
template: "examples/index.html",
|
|
88
|
+
baseUrl: "https://example.com",
|
|
89
|
+
},
|
|
90
|
+
bundle: { splitting: true, compress: ["gz", "br"] },
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
context,
|
|
95
|
+
projectRoot: "",
|
|
96
|
+
dev: { port: 5173, proxy: {} },
|
|
97
|
+
build: { out: "out", dist: "dist", publicDir: "public" },
|
|
98
|
+
bake: {
|
|
99
|
+
entry: "src/routes.ts",
|
|
100
|
+
template: "index.html",
|
|
101
|
+
baseUrl: "https://example.com",
|
|
102
|
+
},
|
|
103
|
+
bundle: { splitting: true, compress: ["gz", "br"] },
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Load and merge configuration for the given project root.
|
|
109
|
+
*
|
|
110
|
+
* Precedence (low → high): defaults, mado.config.json, CLI overrides.
|
|
111
|
+
*
|
|
112
|
+
* @param {Object} [opts]
|
|
113
|
+
* @param {string} [opts.projectRoot=process.cwd()]
|
|
114
|
+
* @param {Partial<MadoConfig>} [opts.overrides]
|
|
115
|
+
* @returns {MadoConfig}
|
|
116
|
+
*/
|
|
117
|
+
export function loadConfig(opts = {}) {
|
|
118
|
+
const projectRoot = resolve(opts.projectRoot ?? process.cwd());
|
|
119
|
+
const context = detectContext(projectRoot);
|
|
120
|
+
const base = defaults(context);
|
|
121
|
+
base.projectRoot = projectRoot;
|
|
122
|
+
|
|
123
|
+
const file = join(projectRoot, "mado.config.json");
|
|
124
|
+
const fromFile = existsSync(file) ? safeReadJson(file) ?? {} : {};
|
|
125
|
+
|
|
126
|
+
const merged = deepMerge(base, fromFile);
|
|
127
|
+
if (opts.overrides) deepMerge(merged, opts.overrides);
|
|
128
|
+
|
|
129
|
+
merged.context = context;
|
|
130
|
+
merged.projectRoot = projectRoot;
|
|
131
|
+
return merged;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Resolve a project-relative path against `projectRoot`. Absolute paths are
|
|
136
|
+
* returned unchanged.
|
|
137
|
+
*
|
|
138
|
+
* @param {MadoConfig} cfg
|
|
139
|
+
* @param {string} p
|
|
140
|
+
* @returns {string}
|
|
141
|
+
*/
|
|
142
|
+
export function resolveProjectPath(cfg, p) {
|
|
143
|
+
if (!p) return cfg.projectRoot;
|
|
144
|
+
return resolve(cfg.projectRoot, p);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* @param {MadoConfig} cfg
|
|
149
|
+
* @returns {string}
|
|
150
|
+
*/
|
|
151
|
+
export function getPackageRoot() {
|
|
152
|
+
return PACKAGE_ROOT;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// ---------- helpers ----------
|
|
156
|
+
|
|
157
|
+
function safeReadJson(path) {
|
|
158
|
+
try {
|
|
159
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
160
|
+
} catch (err) {
|
|
161
|
+
console.warn(`[mado] failed to parse ${path}: ${err.message}`);
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Shallow-deep merge: objects are merged recursively, arrays and primitives
|
|
168
|
+
* are replaced. Mutates `target` and returns it.
|
|
169
|
+
*/
|
|
170
|
+
function deepMerge(target, source) {
|
|
171
|
+
if (!source || typeof source !== "object") return target;
|
|
172
|
+
for (const [k, v] of Object.entries(source)) {
|
|
173
|
+
if (v === undefined) continue;
|
|
174
|
+
if (
|
|
175
|
+
v !== null &&
|
|
176
|
+
typeof v === "object" &&
|
|
177
|
+
!Array.isArray(v) &&
|
|
178
|
+
target[k] &&
|
|
179
|
+
typeof target[k] === "object" &&
|
|
180
|
+
!Array.isArray(target[k])
|
|
181
|
+
) {
|
|
182
|
+
deepMerge(target[k], v);
|
|
183
|
+
} else {
|
|
184
|
+
target[k] = v;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return target;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Tiny argv parser shared by CLI subcommands.
|
|
192
|
+
*
|
|
193
|
+
* Recognises `--key=value`, `--key value`, and `--flag` (boolean).
|
|
194
|
+
* Unknown leading positionals are returned in `positional`.
|
|
195
|
+
*
|
|
196
|
+
* @param {string[]} argv
|
|
197
|
+
* @returns {{ flags: Record<string, string|boolean>, positional: string[] }}
|
|
198
|
+
*/
|
|
199
|
+
export function parseFlags(argv) {
|
|
200
|
+
const flags = {};
|
|
201
|
+
const positional = [];
|
|
202
|
+
for (let i = 0; i < argv.length; i++) {
|
|
203
|
+
const a = argv[i];
|
|
204
|
+
if (a === "--") continue;
|
|
205
|
+
if (a.startsWith("--")) {
|
|
206
|
+
const eq = a.indexOf("=");
|
|
207
|
+
if (eq > -1) {
|
|
208
|
+
flags[a.slice(2, eq)] = a.slice(eq + 1);
|
|
209
|
+
} else {
|
|
210
|
+
const name = a.slice(2);
|
|
211
|
+
const next = argv[i + 1];
|
|
212
|
+
if (next !== undefined && !next.startsWith("-")) {
|
|
213
|
+
flags[name] = next;
|
|
214
|
+
i++;
|
|
215
|
+
} else {
|
|
216
|
+
flags[name] = true;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
} else {
|
|
220
|
+
positional.push(a);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return { flags, positional };
|
|
224
|
+
}
|