odoro 1.0.9 → 2.0.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/README.md +94 -0
- package/client.d.ts +90 -16
- package/dist/build-LZAUDJST.js +5 -0
- package/dist/{chunk-34RGOZFA.js → chunk-4D56Z7G3.js} +49 -50
- package/dist/{chunk-JMEHF3KN.js → chunk-7ZB5MAM6.js} +4 -4
- package/dist/{chunk-LHZGX5ML.js → chunk-OMHEQVIW.js} +295 -160
- package/dist/{chunk-3SZIN6VG.js → chunk-P3DJITWE.js} +10 -10
- package/dist/{chunk-ZVL7EXJO.js → chunk-PRWVZ2SM.js} +22 -14
- package/dist/chunk-Q2KCMTB5.js +741 -0
- package/dist/chunk-QOVBLN7A.js +241 -0
- package/dist/chunk-WWTDEV4Y.js +604 -0
- package/dist/cli.d.ts +12 -13
- package/dist/cli.js +84 -63
- package/dist/{commands-4JRBD55Z.js → commands-EUGVLQWL.js} +44 -45
- package/dist/{commands-AHMXBWQQ.js → commands-GYA7NTCX.js} +124 -124
- package/dist/{create-CYVSVDAD.js → create-QX5LEWMS.js} +158 -154
- package/dist/index.d.ts +603 -151
- package/dist/index.js +6 -6
- package/dist/{package-EIDLKAA6.js → package-T4Z7OBOH.js} +5 -5
- package/dist/preview-P4WY5GEY.js +4 -0
- package/dist/registry/index.d.ts +75 -76
- package/dist/registry/index.js +1 -1
- package/dist/{server-4UGN3SFS.js → server-2WP562EV.js} +3 -3
- package/package.json +5 -5
- package/templates/react-ts/README.md +71 -35
- package/templates/react-ts/_env.example +9 -0
- package/templates/react-ts/_variants/with-engine/src/background.tsx +118 -0
- package/templates/react-ts/_variants/without-libs/src/App.tsx +380 -0
- package/templates/react-ts/_variants/without-libs/src/background.tsx +24 -0
- package/templates/react-ts/_variants/without-libs/src/entry-server.tsx +39 -0
- package/templates/react-ts/_variants/without-libs/src/main.tsx +26 -0
- package/templates/{react-ts-server/_variantes/sans-libs/client → react-ts/_variants/without-libs}/src/styles.css +137 -137
- package/templates/react-ts/{_variantes/sans-routeur → _variants/without-router}/src/App.tsx +141 -141
- package/templates/react-ts/_variants/without-router/src/entry-server.tsx +39 -0
- package/templates/react-ts/index.html +4 -4
- package/templates/react-ts/odoro.config.ts +5 -0
- package/templates/react-ts/src/App.tsx +219 -209
- package/templates/react-ts/src/background.tsx +66 -0
- package/templates/react-ts/src/entry-server.tsx +85 -0
- package/templates/react-ts/src/main.tsx +13 -4
- package/templates/react-ts/src/router.tsx +65 -45
- package/templates/react-ts/src/styles.css +5 -5
- package/templates/react-ts-server/Dockerfile +9 -9
- package/templates/react-ts-server/README.md +97 -45
- package/templates/react-ts-server/_env.example +31 -33
- package/templates/react-ts-server/_variants/with-engine/client/src/background.tsx +118 -0
- package/templates/react-ts-server/_variants/without-libs/client/src/App.tsx +380 -0
- package/templates/react-ts-server/_variants/without-libs/client/src/background.tsx +24 -0
- package/templates/react-ts-server/_variants/without-libs/client/src/entry-server.tsx +39 -0
- package/templates/react-ts-server/_variants/without-libs/client/src/main.tsx +26 -0
- package/templates/{react-ts/_variantes/sans-libs → react-ts-server/_variants/without-libs/client}/src/styles.css +137 -137
- package/templates/react-ts-server/{_variantes/sans-routeur → _variants/without-router}/client/src/App.tsx +141 -141
- package/templates/react-ts-server/_variants/without-router/client/src/entry-server.tsx +39 -0
- package/templates/react-ts-server/client/index.html +4 -4
- package/templates/react-ts-server/client/src/App.tsx +228 -210
- package/templates/react-ts-server/client/src/account.tsx +267 -0
- package/templates/react-ts-server/client/src/auth.tsx +139 -0
- package/templates/react-ts-server/client/src/background.tsx +66 -0
- package/templates/react-ts-server/client/src/entry-server.tsx +92 -0
- package/templates/react-ts-server/client/src/main.tsx +17 -5
- package/templates/react-ts-server/client/src/router.tsx +77 -45
- package/templates/react-ts-server/client/src/styles.css +5 -5
- package/templates/react-ts-server/odoro.config.ts +7 -4
- package/templates/react-ts-server/package.json +2 -0
- package/templates/react-ts-server/scripts/dev.mjs +14 -14
- package/templates/react-ts-server/server/src/main.ts +119 -45
- package/templates/react-ts-server/server/src/modules/auth/index.ts +238 -0
- package/templates/react-ts-server/server/src/modules/auth/password.ts +122 -0
- package/templates/react-ts-server/server/src/modules/auth/store.ts +193 -0
- package/templates/react-ts-server/server/src/modules/health/index.ts +45 -46
- package/dist/build-JFQHODAT.js +0 -5
- package/dist/chunk-22KJTV2R.js +0 -380
- package/dist/chunk-DL3NPC4H.js +0 -113
- package/dist/chunk-TQUJ3MFS.js +0 -268
- package/dist/preview-7DKEAQOQ.js +0 -4
- package/templates/react-ts/_variantes/avec-moteur/src/fond.tsx +0 -118
- package/templates/react-ts/_variantes/sans-libs/src/App.tsx +0 -382
- package/templates/react-ts/_variantes/sans-libs/src/fond.tsx +0 -23
- package/templates/react-ts/_variantes/sans-libs/src/main.tsx +0 -17
- package/templates/react-ts/src/fond.tsx +0 -66
- package/templates/react-ts-server/_variantes/avec-moteur/client/src/fond.tsx +0 -118
- package/templates/react-ts-server/_variantes/sans-libs/client/src/App.tsx +0 -382
- package/templates/react-ts-server/_variantes/sans-libs/client/src/fond.tsx +0 -23
- package/templates/react-ts-server/_variantes/sans-libs/client/src/main.tsx +0 -17
- package/templates/react-ts-server/client/src/fond.tsx +0 -66
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { writeDatabaseUrl, assertEnvIgnored, PROVIDER_PENDING, checkDatabaseUrl } from './chunk-
|
|
2
|
+
import { writeDatabaseUrl, assertEnvIgnored, PROVIDER_PENDING, checkDatabaseUrl } from './chunk-P3DJITWE.js';
|
|
3
3
|
import { execSync, spawn } from 'child_process';
|
|
4
4
|
import { existsSync, statSync, readdirSync, readFileSync } from 'fs';
|
|
5
5
|
import { resolve, basename, dirname, join } from 'path';
|
|
@@ -14,86 +14,86 @@ var MODULES = [
|
|
|
14
14
|
id: "libs",
|
|
15
15
|
label: "Libraries",
|
|
16
16
|
hint: "styles, tokens, UI and motion",
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
ticked: true,
|
|
18
|
+
packageName: "@odoro-cli/libs"
|
|
19
19
|
},
|
|
20
20
|
{
|
|
21
21
|
id: "router",
|
|
22
22
|
label: "Router",
|
|
23
23
|
hint: "ships with the libraries \u2014 wires up the pages",
|
|
24
|
-
|
|
24
|
+
ticked: true
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
27
|
id: "icons",
|
|
28
28
|
label: "Icons",
|
|
29
29
|
hint: "five families, imported one by one",
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
ticked: true,
|
|
31
|
+
packageName: "@odoro-cli/icons"
|
|
32
32
|
},
|
|
33
33
|
{
|
|
34
34
|
id: "engine",
|
|
35
35
|
label: "Engine",
|
|
36
36
|
hint: "WebGL, surfaces and motion policy",
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
ticked: false,
|
|
38
|
+
packageName: "@odoro-cli/engine"
|
|
39
39
|
},
|
|
40
40
|
{
|
|
41
41
|
id: "registre",
|
|
42
42
|
label: "Component registry",
|
|
43
43
|
hint: "copied by `odoro add` \u2014 pulls in the engine",
|
|
44
|
-
|
|
44
|
+
ticked: false
|
|
45
45
|
}
|
|
46
46
|
];
|
|
47
|
-
var MODULE_IDS = MODULES.map((
|
|
48
|
-
var
|
|
49
|
-
(
|
|
50
|
-
).map((
|
|
51
|
-
function
|
|
52
|
-
const
|
|
53
|
-
const
|
|
54
|
-
if (
|
|
55
|
-
|
|
56
|
-
|
|
47
|
+
var MODULE_IDS = MODULES.map((module) => module.id);
|
|
48
|
+
var DEFAULT_MODULES = MODULES.filter(
|
|
49
|
+
(module) => module.ticked
|
|
50
|
+
).map((module) => module.id);
|
|
51
|
+
function resolveModules(selection) {
|
|
52
|
+
const chosen = new Set(selection);
|
|
53
|
+
const warnings = [];
|
|
54
|
+
if (chosen.has("router") && !chosen.has("libs")) {
|
|
55
|
+
chosen.delete("router");
|
|
56
|
+
warnings.push(
|
|
57
57
|
"The router lives in the libraries (@odoro-cli/libs/router) \u2014 without them it is dropped."
|
|
58
58
|
);
|
|
59
59
|
}
|
|
60
|
-
if (
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
if (chosen.has("registre") && !chosen.has("engine")) {
|
|
61
|
+
chosen.add("engine");
|
|
62
|
+
warnings.push(
|
|
63
63
|
"Almost every registry entry imports @odoro-cli/engine, so the engine was added."
|
|
64
64
|
);
|
|
65
65
|
}
|
|
66
|
-
return { modules: MODULE_IDS.filter((id) =>
|
|
66
|
+
return { modules: MODULE_IDS.filter((id) => chosen.has(id)), warnings };
|
|
67
67
|
}
|
|
68
|
-
function
|
|
69
|
-
const
|
|
70
|
-
return MODULES.filter(
|
|
71
|
-
(
|
|
72
|
-
);
|
|
68
|
+
function packagesFor(modules) {
|
|
69
|
+
const chosen = new Set(modules);
|
|
70
|
+
return MODULES.filter(
|
|
71
|
+
(module) => module.packageName !== void 0 && chosen.has(module.id)
|
|
72
|
+
).map((module) => module.packageName);
|
|
73
73
|
}
|
|
74
|
-
function
|
|
75
|
-
const
|
|
76
|
-
const
|
|
77
|
-
if (!
|
|
78
|
-
else if (!
|
|
79
|
-
if (
|
|
80
|
-
return
|
|
74
|
+
function variantsFor(modules) {
|
|
75
|
+
const chosen = new Set(modules);
|
|
76
|
+
const variants = [];
|
|
77
|
+
if (!chosen.has("libs")) variants.push("without-libs");
|
|
78
|
+
else if (!chosen.has("router")) variants.push("without-router");
|
|
79
|
+
if (chosen.has("engine")) variants.push("with-engine");
|
|
80
|
+
return variants;
|
|
81
81
|
}
|
|
82
|
-
function
|
|
82
|
+
function keepsRoutes(modules) {
|
|
83
83
|
return modules.includes("router");
|
|
84
84
|
}
|
|
85
|
-
function
|
|
86
|
-
const
|
|
87
|
-
if (
|
|
85
|
+
function readModules(value) {
|
|
86
|
+
const raw = value.split(",").map((part) => part.trim()).filter((part) => part !== "");
|
|
87
|
+
if (raw.length === 1 && (raw[0] === "none" || raw[0] === "aucun")) {
|
|
88
88
|
return { modules: [] };
|
|
89
89
|
}
|
|
90
|
-
const
|
|
91
|
-
if (
|
|
90
|
+
const unknown = raw.find((part) => !MODULE_IDS.includes(part));
|
|
91
|
+
if (unknown !== void 0) {
|
|
92
92
|
return {
|
|
93
|
-
|
|
93
|
+
error: `Unknown module: "${unknown}". Available: ${MODULE_IDS.join(", ")}, or "none".`
|
|
94
94
|
};
|
|
95
95
|
}
|
|
96
|
-
return { modules:
|
|
96
|
+
return { modules: raw };
|
|
97
97
|
}
|
|
98
98
|
var PACKAGE_MANAGERS = ["pnpm", "npm", "yarn", "bun"];
|
|
99
99
|
function detectPackageManager(userAgent = process.env["npm_config_user_agent"]) {
|
|
@@ -111,18 +111,18 @@ function toPackageName(input) {
|
|
|
111
111
|
return input.trim().toLowerCase().replace(/^[._]+/, "").replace(/[^a-z0-9\-~]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 214) || "odoro-app";
|
|
112
112
|
}
|
|
113
113
|
function validatePackageName(name) {
|
|
114
|
-
if (name.trim() === "") return "
|
|
115
|
-
if (name.length > 214) return "
|
|
116
|
-
if (/^[._]/.test(name)) return '
|
|
114
|
+
if (name.trim() === "") return "The project name cannot be empty.";
|
|
115
|
+
if (name.length > 214) return "The project name cannot exceed 214 characters.";
|
|
116
|
+
if (/^[._]/.test(name)) return 'The project name cannot start with "." or "_".';
|
|
117
117
|
if (!/^[a-z0-9\-~][a-z0-9\-._~]*$/.test(name)) {
|
|
118
|
-
return "
|
|
118
|
+
return "The name must be lowercase, without spaces or special characters.";
|
|
119
119
|
}
|
|
120
120
|
return void 0;
|
|
121
121
|
}
|
|
122
122
|
function inspectTarget(directory) {
|
|
123
123
|
if (!existsSync(directory)) return "absent";
|
|
124
124
|
const entries = readdirSync(directory).filter((entry) => entry !== ".git");
|
|
125
|
-
return entries.length === 0 ? "
|
|
125
|
+
return entries.length === 0 ? "empty" : "occupied";
|
|
126
126
|
}
|
|
127
127
|
function targetFileName(name) {
|
|
128
128
|
return name.startsWith("_") ? `.${name.slice(1)}` : name;
|
|
@@ -136,29 +136,29 @@ function templatesRoot(from = fileURLToPath(import.meta.url)) {
|
|
|
136
136
|
if (parent === directory) break;
|
|
137
137
|
directory = parent;
|
|
138
138
|
}
|
|
139
|
-
throw new Error("[odoro]
|
|
139
|
+
throw new Error("[odoro] Templates directory not found from " + from);
|
|
140
140
|
}
|
|
141
141
|
function availableTemplates(root = templatesRoot()) {
|
|
142
142
|
return readdirSync(root).filter((entry) => statSync(resolve(root, entry)).isDirectory()).sort();
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
-
// src/scaffold/versions
|
|
146
|
-
var
|
|
147
|
-
"@odoro-cli/engine": "
|
|
148
|
-
"@odoro-cli/icons": "
|
|
149
|
-
"@odoro-cli/libs": "
|
|
150
|
-
"@odoro-cli/server": "1.0
|
|
151
|
-
"create-odoro": "1.0.
|
|
152
|
-
"odoro": "
|
|
145
|
+
// src/scaffold/family-versions.generated.ts
|
|
146
|
+
var FAMILY_VERSIONS = {
|
|
147
|
+
"@odoro-cli/engine": "2.0.0",
|
|
148
|
+
"@odoro-cli/icons": "2.0.0",
|
|
149
|
+
"@odoro-cli/libs": "2.0.0",
|
|
150
|
+
"@odoro-cli/server": "1.1.0",
|
|
151
|
+
"create-odoro": "1.0.10",
|
|
152
|
+
"odoro": "2.0.0"
|
|
153
153
|
};
|
|
154
154
|
|
|
155
155
|
// src/scaffold/scaffold.ts
|
|
156
|
-
var
|
|
157
|
-
var
|
|
156
|
+
var VARIANTS_DIRECTORY = "_variants";
|
|
157
|
+
var OPTIONAL_PACKAGES = ["@odoro-cli/libs", "@odoro-cli/icons", "@odoro-cli/engine"];
|
|
158
158
|
function cliVersion() {
|
|
159
159
|
try {
|
|
160
|
-
const
|
|
161
|
-
const { version } = JSON.parse(readFileSync(
|
|
160
|
+
const manifest = join(dirname(templatesRoot()), "package.json");
|
|
161
|
+
const { version } = JSON.parse(readFileSync(manifest, "utf8"));
|
|
162
162
|
return version;
|
|
163
163
|
} catch {
|
|
164
164
|
return "latest";
|
|
@@ -167,7 +167,7 @@ function cliVersion() {
|
|
|
167
167
|
async function copyDirectory(from, to, written, prefix = "") {
|
|
168
168
|
await mkdir(to, { recursive: true });
|
|
169
169
|
for (const entry of await readdir(from, { withFileTypes: true })) {
|
|
170
|
-
if (prefix === "" && entry.name ===
|
|
170
|
+
if (prefix === "" && entry.name === VARIANTS_DIRECTORY) continue;
|
|
171
171
|
const source = join(from, entry.name);
|
|
172
172
|
const name = targetFileName(entry.name);
|
|
173
173
|
const destination = join(to, name);
|
|
@@ -183,11 +183,11 @@ async function copyDirectory(from, to, written, prefix = "") {
|
|
|
183
183
|
function isOdoroPackage(name) {
|
|
184
184
|
return name === "odoro" || name.startsWith("@odoro-cli/");
|
|
185
185
|
}
|
|
186
|
-
function
|
|
187
|
-
if (
|
|
188
|
-
if (
|
|
189
|
-
const
|
|
190
|
-
return
|
|
186
|
+
function requestedVersion(name, cli) {
|
|
187
|
+
if (cli === "latest") return "latest";
|
|
188
|
+
if (name === "odoro") return `^${cli}`;
|
|
189
|
+
const collected = FAMILY_VERSIONS[name];
|
|
190
|
+
return collected === void 0 ? "latest" : `^${collected}`;
|
|
191
191
|
}
|
|
192
192
|
function alignOdoroVersions(manifest, version) {
|
|
193
193
|
const aligned = { ...manifest };
|
|
@@ -196,18 +196,18 @@ function alignOdoroVersions(manifest, version) {
|
|
|
196
196
|
if (typeof deps !== "object" || deps === null) continue;
|
|
197
197
|
const next = {};
|
|
198
198
|
for (const [name, range] of Object.entries(deps)) {
|
|
199
|
-
next[name] = isOdoroPackage(name) ?
|
|
199
|
+
next[name] = isOdoroPackage(name) ? requestedVersion(name, version) : range;
|
|
200
200
|
}
|
|
201
201
|
aligned[field] = next;
|
|
202
202
|
}
|
|
203
203
|
return aligned;
|
|
204
204
|
}
|
|
205
|
-
function
|
|
206
|
-
const
|
|
205
|
+
function adjustModules(manifest, modules) {
|
|
206
|
+
const wanted = new Set(packagesFor(modules));
|
|
207
207
|
const deps = { ...manifest["dependencies"] ?? {} };
|
|
208
|
-
for (const
|
|
209
|
-
if (
|
|
210
|
-
else delete deps[
|
|
208
|
+
for (const packageName of OPTIONAL_PACKAGES) {
|
|
209
|
+
if (wanted.has(packageName)) deps[packageName] ??= "latest";
|
|
210
|
+
else delete deps[packageName];
|
|
211
211
|
}
|
|
212
212
|
return {
|
|
213
213
|
...manifest,
|
|
@@ -216,21 +216,21 @@ function ajusterModules(manifest, modules) {
|
|
|
216
216
|
)
|
|
217
217
|
};
|
|
218
218
|
}
|
|
219
|
-
async function
|
|
220
|
-
const
|
|
221
|
-
if (!existsSync(
|
|
222
|
-
throw new Error(`[odoro]
|
|
219
|
+
async function layVariant(source, target, name) {
|
|
220
|
+
const root = join(source, VARIANTS_DIRECTORY, name);
|
|
221
|
+
if (!existsSync(root)) {
|
|
222
|
+
throw new Error(`[odoro] Template variant not found: "${name}".`);
|
|
223
223
|
}
|
|
224
|
-
const
|
|
225
|
-
await copyDirectory(
|
|
226
|
-
return
|
|
224
|
+
const laid = [];
|
|
225
|
+
await copyDirectory(root, target, laid);
|
|
226
|
+
return laid;
|
|
227
227
|
}
|
|
228
228
|
async function renamePackage(target, packageName, version, modules) {
|
|
229
229
|
const file = join(target, "package.json");
|
|
230
230
|
if (!existsSync(file)) return;
|
|
231
231
|
const manifest = JSON.parse(await readFile(file, "utf8"));
|
|
232
|
-
const
|
|
233
|
-
const renamed = alignOdoroVersions(
|
|
232
|
+
const adjusted = adjustModules({ ...manifest, name: packageName }, modules);
|
|
233
|
+
const renamed = alignOdoroVersions(adjusted, version);
|
|
234
234
|
await writeFile(file, `${JSON.stringify(renamed, null, 2)}
|
|
235
235
|
`, "utf8");
|
|
236
236
|
}
|
|
@@ -238,7 +238,7 @@ async function scaffold(options) {
|
|
|
238
238
|
const root = options.root ?? templatesRoot();
|
|
239
239
|
const source = join(root, options.template);
|
|
240
240
|
if (!existsSync(source)) {
|
|
241
|
-
throw new Error(`[odoro]
|
|
241
|
+
throw new Error(`[odoro] Unknown template: "${options.template}".`);
|
|
242
242
|
}
|
|
243
243
|
if (options.overwrite === "ecraser" && existsSync(options.target)) {
|
|
244
244
|
for (const entry of await readdir(options.target)) {
|
|
@@ -246,17 +246,17 @@ async function scaffold(options) {
|
|
|
246
246
|
await rm(join(options.target, entry), { recursive: true, force: true });
|
|
247
247
|
}
|
|
248
248
|
}
|
|
249
|
-
const modules = options.modules ??
|
|
249
|
+
const modules = options.modules ?? DEFAULT_MODULES;
|
|
250
250
|
const files = [];
|
|
251
251
|
await copyDirectory(source, options.target, files);
|
|
252
|
-
if (!
|
|
253
|
-
for (const
|
|
254
|
-
await rm(join(options.target,
|
|
252
|
+
if (!keepsRoutes(modules)) {
|
|
253
|
+
for (const file of ["src/router.tsx", "client/src/router.tsx"]) {
|
|
254
|
+
await rm(join(options.target, file), { force: true });
|
|
255
255
|
}
|
|
256
256
|
}
|
|
257
|
-
const
|
|
258
|
-
for (const
|
|
259
|
-
|
|
257
|
+
const laid = [];
|
|
258
|
+
for (const variant of variantsFor(modules)) {
|
|
259
|
+
laid.push(...await layVariant(source, options.target, variant));
|
|
260
260
|
}
|
|
261
261
|
await renamePackage(
|
|
262
262
|
options.target,
|
|
@@ -264,17 +264,17 @@ async function scaffold(options) {
|
|
|
264
264
|
options.version ?? cliVersion(),
|
|
265
265
|
modules
|
|
266
266
|
);
|
|
267
|
-
const
|
|
268
|
-
const
|
|
269
|
-
...files.filter((
|
|
270
|
-
...
|
|
267
|
+
const removed = /* @__PURE__ */ new Set(["src/router.tsx", "client/src/router.tsx"]);
|
|
268
|
+
const listed = /* @__PURE__ */ new Set([
|
|
269
|
+
...files.filter((file) => keepsRoutes(modules) || !removed.has(file)),
|
|
270
|
+
...laid
|
|
271
271
|
]);
|
|
272
|
-
return { files: [...
|
|
272
|
+
return { files: [...listed].sort() };
|
|
273
273
|
}
|
|
274
274
|
|
|
275
275
|
// src/commands/create.ts
|
|
276
|
-
var
|
|
277
|
-
var
|
|
276
|
+
var LAST_LINES = 8;
|
|
277
|
+
var LINE_WIDTH = 64;
|
|
278
278
|
var TEMPLATE_LABELS = {
|
|
279
279
|
"react-ts": "Single-page app \u2014 React, TypeScript, Odoro router and motion",
|
|
280
280
|
"react-ts-server": "Client and server \u2014 the same app, plus a modular @odoro-cli/server base and a Dockerfile"
|
|
@@ -301,94 +301,98 @@ async function askDatabase() {
|
|
|
301
301
|
);
|
|
302
302
|
if (choice === "provider") {
|
|
303
303
|
prompts.log.warn(PROVIDER_PENDING);
|
|
304
|
-
return { choice, note: "
|
|
304
|
+
return { choice, note: "Run `odoro db:create` as soon as the platform is there." };
|
|
305
305
|
}
|
|
306
306
|
if (choice === "later") {
|
|
307
307
|
return {
|
|
308
308
|
choice,
|
|
309
|
-
note: "
|
|
309
|
+
note: "No database: the client will start, and /api/ready will answer 503 saying what is missing."
|
|
310
310
|
};
|
|
311
311
|
}
|
|
312
312
|
const url = ensure(
|
|
313
313
|
await prompts.text({
|
|
314
314
|
message: "PostgreSQL URL",
|
|
315
|
-
placeholder: "postgres://
|
|
315
|
+
placeholder: "postgres://user:password@host:5432/database?sslmode=require",
|
|
316
316
|
validate: (value) => checkDatabaseUrl(value ?? "")
|
|
317
317
|
})
|
|
318
318
|
);
|
|
319
319
|
return {
|
|
320
320
|
choice,
|
|
321
321
|
url: url.trim(),
|
|
322
|
-
//
|
|
323
|
-
//
|
|
324
|
-
note: "
|
|
322
|
+
// Only the shape was checked: say so, rather than letting one believe the
|
|
323
|
+
// connection was established.
|
|
324
|
+
note: "URL shape checked. The connection will be established on the first start."
|
|
325
325
|
};
|
|
326
326
|
}
|
|
327
327
|
async function askModules(options) {
|
|
328
328
|
if (options.modules !== void 0) {
|
|
329
|
-
const
|
|
330
|
-
if (
|
|
331
|
-
prompts.cancel(
|
|
329
|
+
const read = readModules(options.modules);
|
|
330
|
+
if (read.error !== void 0) {
|
|
331
|
+
prompts.cancel(read.error);
|
|
332
332
|
return void 0;
|
|
333
333
|
}
|
|
334
|
-
return
|
|
334
|
+
return announce(resolveModules(read.modules));
|
|
335
335
|
}
|
|
336
|
-
if (options.yes === true) return
|
|
337
|
-
const
|
|
336
|
+
if (options.yes === true) return DEFAULT_MODULES;
|
|
337
|
+
const chosen = ensure(
|
|
338
338
|
await prompts.multiselect({
|
|
339
339
|
message: "What goes in the project?",
|
|
340
|
-
initialValues: [...
|
|
340
|
+
initialValues: [...DEFAULT_MODULES],
|
|
341
341
|
required: false,
|
|
342
|
-
options: MODULES.map((
|
|
342
|
+
options: MODULES.map((module) => ({
|
|
343
|
+
value: module.id,
|
|
344
|
+
label: module.label,
|
|
345
|
+
hint: module.hint
|
|
346
|
+
}))
|
|
343
347
|
})
|
|
344
348
|
);
|
|
345
|
-
return
|
|
349
|
+
return announce(resolveModules(chosen));
|
|
346
350
|
}
|
|
347
|
-
function
|
|
348
|
-
for (const
|
|
351
|
+
function announce(resolution) {
|
|
352
|
+
for (const warning of resolution.warnings) prompts.log.warn(warning);
|
|
349
353
|
return resolution.modules;
|
|
350
354
|
}
|
|
351
|
-
async function
|
|
352
|
-
const [
|
|
353
|
-
if (
|
|
354
|
-
const
|
|
355
|
-
|
|
356
|
-
const
|
|
357
|
-
const
|
|
358
|
-
for (const
|
|
359
|
-
const
|
|
360
|
-
if (
|
|
361
|
-
|
|
362
|
-
if (
|
|
363
|
-
|
|
355
|
+
async function installDependencies(target, manager) {
|
|
356
|
+
const [command, ...args] = installCommand(manager).split(" ");
|
|
357
|
+
if (command === void 0) return false;
|
|
358
|
+
const bar = prompts.spinner({ indicator: "timer" });
|
|
359
|
+
bar.start(`Installing dependencies with ${manager}`);
|
|
360
|
+
const tail = [];
|
|
361
|
+
const keep = (block) => {
|
|
362
|
+
for (const line of block.split("\n")) {
|
|
363
|
+
const clean = line.trim();
|
|
364
|
+
if (clean === "" || !/[a-z0-9]/i.test(clean)) continue;
|
|
365
|
+
tail.push(clean);
|
|
366
|
+
if (tail.length > LAST_LINES) tail.shift();
|
|
367
|
+
bar.message(`${manager} \xB7 ${clean.slice(0, LINE_WIDTH)}`);
|
|
364
368
|
}
|
|
365
369
|
};
|
|
366
370
|
const code = await new Promise((resolve_) => {
|
|
367
|
-
const
|
|
371
|
+
const child = spawn(command, args, {
|
|
368
372
|
cwd: target,
|
|
369
373
|
shell: process.platform === "win32"
|
|
370
374
|
});
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
375
|
+
child.stdout?.setEncoding("utf8").on("data", keep);
|
|
376
|
+
child.stderr?.setEncoding("utf8").on("data", keep);
|
|
377
|
+
child.on("error", () => {
|
|
374
378
|
resolve_(-1);
|
|
375
379
|
});
|
|
376
|
-
|
|
377
|
-
resolve_(
|
|
380
|
+
child.on("close", (status) => {
|
|
381
|
+
resolve_(status ?? -1);
|
|
378
382
|
});
|
|
379
383
|
});
|
|
380
384
|
if (code === 0) {
|
|
381
|
-
|
|
385
|
+
bar.stop(`Dependencies installed with ${manager}`);
|
|
382
386
|
return true;
|
|
383
387
|
}
|
|
384
|
-
|
|
385
|
-
for (const
|
|
388
|
+
bar.stop(`${manager} install failed`, 1);
|
|
389
|
+
for (const line of tail) prompts.log.error(colors.dim(line));
|
|
386
390
|
return false;
|
|
387
391
|
}
|
|
388
|
-
function
|
|
392
|
+
function cliVersion2() {
|
|
389
393
|
try {
|
|
390
|
-
const
|
|
391
|
-
const { version } = JSON.parse(readFileSync(
|
|
394
|
+
const manifest = join(dirname(templatesRoot()), "package.json");
|
|
395
|
+
const { version } = JSON.parse(readFileSync(manifest, "utf8"));
|
|
392
396
|
return version;
|
|
393
397
|
} catch {
|
|
394
398
|
return "?";
|
|
@@ -406,12 +410,12 @@ async function createCommand(options) {
|
|
|
406
410
|
const templates = availableTemplates(root);
|
|
407
411
|
const defaultTemplate = templates[0] ?? "react-ts";
|
|
408
412
|
prompts.intro(
|
|
409
|
-
`${colors.bgBlue(colors.black(" ODORO "))} ${colors.dim(`v${
|
|
413
|
+
`${colors.bgBlue(colors.black(" ODORO "))} ${colors.dim(`v${cliVersion2()}`)}`
|
|
410
414
|
);
|
|
411
415
|
const rawName = options.name ?? (options.yes === true ? "odoro-app" : ensure(
|
|
412
416
|
await prompts.text({
|
|
413
417
|
message: "Project name",
|
|
414
|
-
placeholder: "
|
|
418
|
+
placeholder: "my-site",
|
|
415
419
|
defaultValue: "odoro-app",
|
|
416
420
|
validate: (value) => value === "" ? void 0 : validatePackageName(toPackageName(value))
|
|
417
421
|
})
|
|
@@ -425,7 +429,7 @@ async function createCommand(options) {
|
|
|
425
429
|
}
|
|
426
430
|
let overwrite = options.overwrite;
|
|
427
431
|
const state = inspectTarget(target);
|
|
428
|
-
if (state === "
|
|
432
|
+
if (state === "occupied" && overwrite === void 0) {
|
|
429
433
|
if (options.yes === true) {
|
|
430
434
|
prompts.cancel(
|
|
431
435
|
`Folder "${basename(target)}" is not empty. Pass --overwrite or --merge.`
|
|
@@ -436,14 +440,14 @@ async function createCommand(options) {
|
|
|
436
440
|
await prompts.select({
|
|
437
441
|
message: `Folder "${basename(target)}" is not empty.`,
|
|
438
442
|
options: [
|
|
439
|
-
{ value: "
|
|
443
|
+
{ value: "cancel", label: "Cancel" },
|
|
440
444
|
{ value: "fusionner", label: "Merge \u2014 overwrites files of the same name" },
|
|
441
445
|
{ value: "ecraser", label: "Empty the folder, then create the project" }
|
|
442
446
|
]
|
|
443
447
|
})
|
|
444
448
|
);
|
|
445
|
-
if (choice === "
|
|
446
|
-
prompts.cancel("Creation
|
|
449
|
+
if (choice === "cancel") {
|
|
450
|
+
prompts.cancel("Creation cancelled.");
|
|
447
451
|
return 0;
|
|
448
452
|
}
|
|
449
453
|
overwrite = choice;
|
|
@@ -513,12 +517,12 @@ async function createCommand(options) {
|
|
|
513
517
|
if (database?.url !== void 0) {
|
|
514
518
|
await writeDatabaseUrl(target, database.url);
|
|
515
519
|
prompts.log.success("Database URL written to .env");
|
|
516
|
-
const
|
|
517
|
-
if (
|
|
520
|
+
const risk = await assertEnvIgnored(target);
|
|
521
|
+
if (risk !== void 0) prompts.log.warn(risk);
|
|
518
522
|
}
|
|
519
523
|
if (database !== void 0) prompts.log.info(database.note);
|
|
520
524
|
if (modules.includes("registre")) {
|
|
521
|
-
const { initCommand } = await import('./commands-
|
|
525
|
+
const { initCommand } = await import('./commands-GYA7NTCX.js');
|
|
522
526
|
const code = await initCommand({ root: target, yes: true });
|
|
523
527
|
if (code !== 0) {
|
|
524
528
|
prompts.log.warn(
|
|
@@ -526,14 +530,14 @@ async function createCommand(options) {
|
|
|
526
530
|
);
|
|
527
531
|
}
|
|
528
532
|
}
|
|
529
|
-
const
|
|
533
|
+
const installed = withInstall ? await installDependencies(target, manager) : false;
|
|
530
534
|
const steps = [
|
|
531
535
|
`cd ${basename(target)}`,
|
|
532
|
-
//
|
|
533
|
-
//
|
|
534
|
-
...
|
|
535
|
-
// `odoro.json`
|
|
536
|
-
//
|
|
536
|
+
// When the install failed, the command comes back into the steps: the
|
|
537
|
+
// project is written, it is only missing its dependencies.
|
|
538
|
+
...installed ? [] : [installCommand(manager)],
|
|
539
|
+
// `odoro.json` has just been written: what remains to show is the command
|
|
540
|
+
// that uses it.
|
|
537
541
|
...modules.includes("registre") ? ["odoro add text/count-up"] : [],
|
|
538
542
|
runCommand(manager, "dev")
|
|
539
543
|
];
|