odoro 1.0.0 → 1.0.2
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 +73 -0
- package/dist/cli.js +3 -3
- package/dist/{commands-PT3NS65O.js → commands-AHMXBWQQ.js} +25 -5
- package/dist/{create-IOFAPDBO.js → create-GD6O2TPL.js} +118 -70
- package/dist/{package-6ADADETZ.js → package-VMTZDORI.js} +1 -1
- package/dist/registry/index.d.ts +2 -2
- package/package.json +1 -1
- package/templates/react-ts/_variantes/avec-moteur/src/fond.tsx +118 -0
- package/templates/react-ts/_variantes/sans-libs/src/App.tsx +245 -45
- package/templates/react-ts/_variantes/sans-libs/src/fond.tsx +23 -0
- package/templates/react-ts/_variantes/sans-libs/src/styles.css +357 -42
- package/templates/react-ts/_variantes/sans-routeur/src/App.tsx +305 -62
- package/templates/react-ts/public/favicon.svg +2 -3
- package/templates/react-ts/src/App.tsx +443 -43
- package/templates/react-ts/src/fond.tsx +42 -0
- package/templates/react-ts/src/router.tsx +72 -0
- package/templates/react-ts/src/styles.css +4 -5
- package/templates/react-ts-server/_variantes/avec-moteur/client/src/fond.tsx +118 -0
- package/templates/react-ts-server/_variantes/sans-libs/client/src/App.tsx +245 -45
- package/templates/react-ts-server/_variantes/sans-libs/client/src/fond.tsx +23 -0
- package/templates/react-ts-server/_variantes/sans-libs/client/src/styles.css +357 -42
- package/templates/react-ts-server/_variantes/sans-routeur/client/src/App.tsx +305 -62
- package/templates/react-ts-server/client/public/favicon.svg +2 -3
- package/templates/react-ts-server/client/src/App.tsx +443 -43
- package/templates/react-ts-server/client/src/fond.tsx +42 -0
- package/templates/react-ts-server/client/src/router.tsx +72 -0
- package/templates/react-ts-server/client/src/styles.css +4 -5
- package/templates/react-ts/src/routes/About.tsx +0 -19
- package/templates/react-ts/src/routes/Home.tsx +0 -80
- package/templates/react-ts/src/routes/NotFound.tsx +0 -14
- package/templates/react-ts-server/client/src/routes/About.tsx +0 -19
- package/templates/react-ts-server/client/src/routes/Home.tsx +0 -148
- package/templates/react-ts-server/client/src/routes/NotFound.tsx +0 -14
package/README.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# odoro
|
|
2
|
+
|
|
3
|
+
The Odoro engine: a development server with hot reload, a production build, and
|
|
4
|
+
the component registry client.
|
|
5
|
+
|
|
6
|
+
```sh
|
|
7
|
+
npm create odoro@latest
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
That single command scaffolds a project and installs everything below. This
|
|
11
|
+
package is what it installs.
|
|
12
|
+
|
|
13
|
+
## Commands
|
|
14
|
+
|
|
15
|
+
| Command | What it does |
|
|
16
|
+
| ---------------- | --------------------------------------------------------- |
|
|
17
|
+
| `odoro dev` | Development server with hot module replacement. |
|
|
18
|
+
| `odoro build` | Production build into `dist/`. |
|
|
19
|
+
| `odoro preview` | Serves `dist/` the way a static host would. |
|
|
20
|
+
| `odoro create` | Scaffolds a project — same thing as `npm create odoro`. |
|
|
21
|
+
| `odoro init` | Writes `odoro.json` so `odoro add` knows where to write. |
|
|
22
|
+
| `odoro add <id>` | Copies a registry component into your project. |
|
|
23
|
+
| `odoro list` | Prints the registry catalogue. |
|
|
24
|
+
| `odoro diff` | Compares what is installed with what the registry serves. |
|
|
25
|
+
| `odoro doctor` | Checks that the project is in a fit state. |
|
|
26
|
+
|
|
27
|
+
Run `odoro --help` for the full list, including the database commands.
|
|
28
|
+
|
|
29
|
+
## Configuration
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
// odoro.config.ts
|
|
33
|
+
import { defineConfig } from 'odoro'
|
|
34
|
+
|
|
35
|
+
export default defineConfig({
|
|
36
|
+
alias: { '@': 'src' },
|
|
37
|
+
server: { port: 5180 },
|
|
38
|
+
})
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## The registry is not a dependency
|
|
42
|
+
|
|
43
|
+
`odoro add text/count-up` **copies the source into your project**. The code is
|
|
44
|
+
then yours: read it, change it, delete it. Nothing updates behind your back, and
|
|
45
|
+
there is no package to keep in step.
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
odoro add text/count-up
|
|
49
|
+
# + src/odoro/hooks/useInView.ts
|
|
50
|
+
# + src/odoro/text/CountUp.tsx
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Entries that need an npm package say so, and `odoro add` tells you which one is
|
|
54
|
+
missing before you find out at build time.
|
|
55
|
+
|
|
56
|
+
## Hot reload keeps your state
|
|
57
|
+
|
|
58
|
+
Editing a component swaps its code without unmounting the tree: a counter's
|
|
59
|
+
value, the text in a field, the open tab all survive the edit. A stylesheet is
|
|
60
|
+
swapped without a reload.
|
|
61
|
+
|
|
62
|
+
A module that exports something other than components reloads the page, and that
|
|
63
|
+
is correct — nothing would let us propagate the change safely.
|
|
64
|
+
|
|
65
|
+
## Links
|
|
66
|
+
|
|
67
|
+
- Documentation — <https://odoro.dev/docs>
|
|
68
|
+
- Component registry — <https://odoro.dev/docs/registry>
|
|
69
|
+
- Source — <https://github.com/ODORO-CLI/OdoroKit>
|
|
70
|
+
|
|
71
|
+
## Licence
|
|
72
|
+
|
|
73
|
+
UNLICENSED. Copyright (c) BouBouw. See `LICENSE`.
|
package/dist/cli.js
CHANGED
|
@@ -131,7 +131,7 @@ function rootFrom(flags, positional) {
|
|
|
131
131
|
async function run(argv) {
|
|
132
132
|
const { command, positional, flags } = parseArgs(argv);
|
|
133
133
|
if (flags["version"] === true) {
|
|
134
|
-
const manifest = await import('./package-
|
|
134
|
+
const manifest = await import('./package-VMTZDORI.js');
|
|
135
135
|
console.log(manifest.default.version);
|
|
136
136
|
return 0;
|
|
137
137
|
}
|
|
@@ -142,7 +142,7 @@ async function run(argv) {
|
|
|
142
142
|
switch (command) {
|
|
143
143
|
case "create":
|
|
144
144
|
case "new": {
|
|
145
|
-
const { createCommand } = await import('./create-
|
|
145
|
+
const { createCommand } = await import('./create-GD6O2TPL.js');
|
|
146
146
|
const options = {};
|
|
147
147
|
if (positional[0] !== void 0) options.name = positional[0];
|
|
148
148
|
if (typeof flags["template"] === "string") options.template = flags["template"];
|
|
@@ -180,7 +180,7 @@ async function run(argv) {
|
|
|
180
180
|
case "list":
|
|
181
181
|
case "diff":
|
|
182
182
|
case "doctor": {
|
|
183
|
-
const registry = await import('./commands-
|
|
183
|
+
const registry = await import('./commands-AHMXBWQQ.js');
|
|
184
184
|
const options = {
|
|
185
185
|
root: typeof flags["root"] === "string" ? flags["root"] : process.cwd(),
|
|
186
186
|
registry: typeof flags["registry"] === "string" ? flags["registry"] : void 0,
|
|
@@ -89,9 +89,29 @@ async function saveProject(root, config) {
|
|
|
89
89
|
|
|
90
90
|
// src/add/rewrite.ts
|
|
91
91
|
var REGISTRY_TOKEN = "@registre";
|
|
92
|
-
function
|
|
92
|
+
function estUnAlias(prefix) {
|
|
93
|
+
return /^[@~#]/.test(prefix);
|
|
94
|
+
}
|
|
95
|
+
function cheminRelatif(depuis, vers) {
|
|
96
|
+
const segmentsDepuis = depuis.split("/").slice(0, -1);
|
|
97
|
+
const segmentsVers = vers.split("/");
|
|
98
|
+
let commun = 0;
|
|
99
|
+
while (commun < segmentsDepuis.length && commun < segmentsVers.length - 1 && segmentsDepuis[commun] === segmentsVers[commun]) {
|
|
100
|
+
commun += 1;
|
|
101
|
+
}
|
|
102
|
+
const montees = segmentsDepuis.length - commun;
|
|
103
|
+
const descente = segmentsVers.slice(commun).join("/");
|
|
104
|
+
return montees === 0 ? `./${descente}` : `${"../".repeat(montees)}${descente}`;
|
|
105
|
+
}
|
|
106
|
+
function rewriteImports(source, importPrefix, target) {
|
|
93
107
|
const prefix = importPrefix.replace(/\/$/, "");
|
|
94
|
-
|
|
108
|
+
if (estUnAlias(prefix) || target === void 0) {
|
|
109
|
+
return source.split(`${REGISTRY_TOKEN}/`).join(`${prefix}/`);
|
|
110
|
+
}
|
|
111
|
+
return source.replaceAll(
|
|
112
|
+
new RegExp(`${REGISTRY_TOKEN}/([^'"\\s]+)`, "g"),
|
|
113
|
+
(_tout, chemin) => cheminRelatif(target, chemin)
|
|
114
|
+
);
|
|
95
115
|
}
|
|
96
116
|
function usedTokens(source) {
|
|
97
117
|
const pattern = new RegExp(`${REGISTRY_TOKEN}/([\\w./-]+)`, "g");
|
|
@@ -134,7 +154,7 @@ async function inspectEntry(root, config, id, upstream) {
|
|
|
134
154
|
if (source !== void 0) {
|
|
135
155
|
served.set(
|
|
136
156
|
join(config.aliases.directory, file.target).replaceAll("\\", "/"),
|
|
137
|
-
rewriteImports(source, config.aliases.import)
|
|
157
|
+
rewriteImports(source, config.aliases.import, file.target)
|
|
138
158
|
);
|
|
139
159
|
}
|
|
140
160
|
}
|
|
@@ -401,7 +421,7 @@ async function planInstall(root, config, entries) {
|
|
|
401
421
|
await planWrite(
|
|
402
422
|
root,
|
|
403
423
|
targetPath(config, file.target),
|
|
404
|
-
rewriteImports(source, config.aliases.import),
|
|
424
|
+
rewriteImports(source, config.aliases.import, file.target),
|
|
405
425
|
entry.id
|
|
406
426
|
)
|
|
407
427
|
);
|
|
@@ -505,7 +525,7 @@ async function initCommand(options) {
|
|
|
505
525
|
const suggested = defaultAliases(guess);
|
|
506
526
|
if (guess === null) {
|
|
507
527
|
warn(
|
|
508
|
-
`Aucun alias trouve dans tsconfig.json : les
|
|
528
|
+
`Aucun alias trouve dans tsconfig.json : les composants iront dans ${colors.cyan(suggested.directory)}/ et s importeront entre eux en relatif.`
|
|
509
529
|
);
|
|
510
530
|
} else {
|
|
511
531
|
info(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { writeDatabaseUrl, assertEnvIgnored, PROVIDER_PENDING, checkDatabaseUrl } from './chunk-3SZIN6VG.js';
|
|
3
|
-
import { execSync } from 'child_process';
|
|
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';
|
|
6
6
|
import * as prompts from '@clack/prompts';
|
|
@@ -12,35 +12,35 @@ import { fileURLToPath } from 'url';
|
|
|
12
12
|
var MODULES = [
|
|
13
13
|
{
|
|
14
14
|
id: "libs",
|
|
15
|
-
label: "
|
|
16
|
-
hint: "
|
|
15
|
+
label: "Libraries",
|
|
16
|
+
hint: "styles, tokens, UI and motion",
|
|
17
17
|
defaut: true,
|
|
18
18
|
paquet: "@odoro-cli/libs"
|
|
19
19
|
},
|
|
20
20
|
{
|
|
21
21
|
id: "router",
|
|
22
|
-
label: "
|
|
23
|
-
hint: "
|
|
22
|
+
label: "Router",
|
|
23
|
+
hint: "ships with the libraries \u2014 wires up the pages",
|
|
24
24
|
defaut: true
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
27
|
id: "icons",
|
|
28
|
-
label: "
|
|
29
|
-
hint: "
|
|
28
|
+
label: "Icons",
|
|
29
|
+
hint: "five families, imported one by one",
|
|
30
30
|
defaut: true,
|
|
31
31
|
paquet: "@odoro-cli/icons"
|
|
32
32
|
},
|
|
33
33
|
{
|
|
34
34
|
id: "engine",
|
|
35
|
-
label: "
|
|
36
|
-
hint: "WebGL, surfaces
|
|
35
|
+
label: "Engine",
|
|
36
|
+
hint: "WebGL, surfaces and motion policy",
|
|
37
37
|
defaut: false,
|
|
38
38
|
paquet: "@odoro-cli/engine"
|
|
39
39
|
},
|
|
40
40
|
{
|
|
41
41
|
id: "registre",
|
|
42
|
-
label: "
|
|
43
|
-
hint: "
|
|
42
|
+
label: "Component registry",
|
|
43
|
+
hint: "copied by `odoro add` \u2014 pulls in the engine",
|
|
44
44
|
defaut: false
|
|
45
45
|
}
|
|
46
46
|
];
|
|
@@ -54,13 +54,13 @@ function resoudre(selection) {
|
|
|
54
54
|
if (choisis.has("router") && !choisis.has("libs")) {
|
|
55
55
|
choisis.delete("router");
|
|
56
56
|
avertissements.push(
|
|
57
|
-
"
|
|
57
|
+
"The router lives in the libraries (@odoro-cli/libs/router) \u2014 without them it is dropped."
|
|
58
58
|
);
|
|
59
59
|
}
|
|
60
60
|
if (choisis.has("registre") && !choisis.has("engine")) {
|
|
61
61
|
choisis.add("engine");
|
|
62
62
|
avertissements.push(
|
|
63
|
-
"
|
|
63
|
+
"Almost every registry entry imports @odoro-cli/engine, so the engine was added."
|
|
64
64
|
);
|
|
65
65
|
}
|
|
66
66
|
return { modules: MODULE_IDS.filter((id) => choisis.has(id)), avertissements };
|
|
@@ -71,22 +71,26 @@ function paquetsDe(modules) {
|
|
|
71
71
|
(m) => m.paquet
|
|
72
72
|
);
|
|
73
73
|
}
|
|
74
|
-
function
|
|
74
|
+
function variantesDe(modules) {
|
|
75
75
|
const choisis = new Set(modules);
|
|
76
|
-
|
|
77
|
-
if (!choisis.has("
|
|
78
|
-
|
|
76
|
+
const variantes = [];
|
|
77
|
+
if (!choisis.has("libs")) variantes.push("sans-libs");
|
|
78
|
+
else if (!choisis.has("router")) variantes.push("sans-routeur");
|
|
79
|
+
if (choisis.has("engine")) variantes.push("avec-moteur");
|
|
80
|
+
return variantes;
|
|
79
81
|
}
|
|
80
82
|
function gardeLesRoutes(modules) {
|
|
81
83
|
return modules.includes("router");
|
|
82
84
|
}
|
|
83
85
|
function lireModules(valeur) {
|
|
84
86
|
const brut = valeur.split(",").map((part) => part.trim()).filter((part) => part !== "");
|
|
85
|
-
if (brut.length === 1 && brut[0] === "
|
|
87
|
+
if (brut.length === 1 && (brut[0] === "none" || brut[0] === "aucun")) {
|
|
88
|
+
return { modules: [] };
|
|
89
|
+
}
|
|
86
90
|
const inconnu = brut.find((part) => !MODULE_IDS.includes(part));
|
|
87
91
|
if (inconnu !== void 0) {
|
|
88
92
|
return {
|
|
89
|
-
erreur: `
|
|
93
|
+
erreur: `Unknown module: "${inconnu}". Available: ${MODULE_IDS.join(", ")}, or "none".`
|
|
90
94
|
};
|
|
91
95
|
}
|
|
92
96
|
return { modules: brut };
|
|
@@ -230,49 +234,52 @@ async function scaffold(options) {
|
|
|
230
234
|
const files = [];
|
|
231
235
|
await copyDirectory(source, options.target, files);
|
|
232
236
|
if (!gardeLesRoutes(modules)) {
|
|
233
|
-
for (const
|
|
234
|
-
await rm(join(options.target,
|
|
237
|
+
for (const fichier of ["src/router.tsx", "client/src/router.tsx"]) {
|
|
238
|
+
await rm(join(options.target, fichier), { force: true });
|
|
235
239
|
}
|
|
236
240
|
}
|
|
237
|
-
const
|
|
238
|
-
const
|
|
241
|
+
const poses = [];
|
|
242
|
+
for (const variante of variantesDe(modules)) {
|
|
243
|
+
poses.push(...await poserVariante(source, options.target, variante));
|
|
244
|
+
}
|
|
239
245
|
await renamePackage(
|
|
240
246
|
options.target,
|
|
241
247
|
options.packageName,
|
|
242
248
|
options.version ?? cliVersion(),
|
|
243
249
|
modules
|
|
244
250
|
);
|
|
251
|
+
const retires = /* @__PURE__ */ new Set(["src/router.tsx", "client/src/router.tsx"]);
|
|
245
252
|
const listes = /* @__PURE__ */ new Set([
|
|
246
|
-
...files.filter(
|
|
247
|
-
(f) => !f.startsWith("src/routes/") && !f.startsWith("client/src/routes/")
|
|
248
|
-
),
|
|
253
|
+
...files.filter((f) => gardeLesRoutes(modules) || !retires.has(f)),
|
|
249
254
|
...poses
|
|
250
255
|
]);
|
|
251
256
|
return { files: [...listes].sort() };
|
|
252
257
|
}
|
|
253
258
|
|
|
254
259
|
// src/commands/create.ts
|
|
260
|
+
var DERNIERES_LIGNES = 8;
|
|
261
|
+
var LARGEUR_LIGNE = 64;
|
|
255
262
|
var TEMPLATE_LABELS = {
|
|
256
|
-
"react-ts": "
|
|
257
|
-
"react-ts-server": "Client
|
|
263
|
+
"react-ts": "Single-page app \u2014 React, TypeScript, Odoro router and motion",
|
|
264
|
+
"react-ts-server": "Client and server \u2014 the same app, plus a modular @odoro-cli/server base and a Dockerfile"
|
|
258
265
|
};
|
|
259
266
|
async function askDatabase() {
|
|
260
267
|
const choice = ensure(
|
|
261
268
|
await prompts.select({
|
|
262
|
-
message: "
|
|
269
|
+
message: "Database",
|
|
263
270
|
initialValue: "url",
|
|
264
271
|
options: [
|
|
265
272
|
{
|
|
266
273
|
value: "provider",
|
|
267
|
-
label: "
|
|
268
|
-
hint: "
|
|
274
|
+
label: "Odoro provider",
|
|
275
|
+
hint: "automatic provisioning \u2014 coming soon"
|
|
269
276
|
},
|
|
270
277
|
{
|
|
271
278
|
value: "url",
|
|
272
|
-
label: "
|
|
273
|
-
hint: "Neon, Supabase, RDS,
|
|
279
|
+
label: "Existing PostgreSQL URL",
|
|
280
|
+
hint: "Neon, Supabase, RDS, your own"
|
|
274
281
|
},
|
|
275
|
-
{ value: "later", label: "
|
|
282
|
+
{ value: "later", label: "Set up later", hint: ".env.example only" }
|
|
276
283
|
]
|
|
277
284
|
})
|
|
278
285
|
);
|
|
@@ -288,7 +295,7 @@ async function askDatabase() {
|
|
|
288
295
|
}
|
|
289
296
|
const url = ensure(
|
|
290
297
|
await prompts.text({
|
|
291
|
-
message: "URL
|
|
298
|
+
message: "PostgreSQL URL",
|
|
292
299
|
placeholder: "postgres://utilisateur:motdepasse@hote:5432/base?sslmode=require",
|
|
293
300
|
validate: (value) => checkDatabaseUrl(value ?? "")
|
|
294
301
|
})
|
|
@@ -313,7 +320,7 @@ async function askModules(options) {
|
|
|
313
320
|
if (options.yes === true) return MODULES_PAR_DEFAUT;
|
|
314
321
|
const choisis = ensure(
|
|
315
322
|
await prompts.multiselect({
|
|
316
|
-
message: "
|
|
323
|
+
message: "What goes in the project?",
|
|
317
324
|
initialValues: [...MODULES_PAR_DEFAUT],
|
|
318
325
|
required: false,
|
|
319
326
|
options: MODULES.map((m) => ({ value: m.id, label: m.label, hint: m.hint }))
|
|
@@ -325,9 +332,55 @@ function annoncer(resolution) {
|
|
|
325
332
|
for (const mot of resolution.avertissements) prompts.log.warn(mot);
|
|
326
333
|
return resolution.modules;
|
|
327
334
|
}
|
|
335
|
+
async function installerDependances(target, manager) {
|
|
336
|
+
const [commande, ...args] = installCommand(manager).split(" ");
|
|
337
|
+
if (commande === void 0) return false;
|
|
338
|
+
const barre = prompts.spinner({ indicator: "timer" });
|
|
339
|
+
barre.start(`Installing dependencies with ${manager}`);
|
|
340
|
+
const fin = [];
|
|
341
|
+
const garder = (bloc) => {
|
|
342
|
+
for (const ligne of bloc.split("\n")) {
|
|
343
|
+
const propre = ligne.trim();
|
|
344
|
+
if (propre === "" || !/[a-z0-9]/i.test(propre)) continue;
|
|
345
|
+
fin.push(propre);
|
|
346
|
+
if (fin.length > DERNIERES_LIGNES) fin.shift();
|
|
347
|
+
barre.message(`${manager} \xB7 ${propre.slice(0, LARGEUR_LIGNE)}`);
|
|
348
|
+
}
|
|
349
|
+
};
|
|
350
|
+
const code = await new Promise((resolve_) => {
|
|
351
|
+
const processus = spawn(commande, args, {
|
|
352
|
+
cwd: target,
|
|
353
|
+
shell: process.platform === "win32"
|
|
354
|
+
});
|
|
355
|
+
processus.stdout?.setEncoding("utf8").on("data", garder);
|
|
356
|
+
processus.stderr?.setEncoding("utf8").on("data", garder);
|
|
357
|
+
processus.on("error", () => {
|
|
358
|
+
resolve_(-1);
|
|
359
|
+
});
|
|
360
|
+
processus.on("close", (sortie) => {
|
|
361
|
+
resolve_(sortie ?? -1);
|
|
362
|
+
});
|
|
363
|
+
});
|
|
364
|
+
if (code === 0) {
|
|
365
|
+
barre.stop(`Dependencies installed with ${manager}`);
|
|
366
|
+
return true;
|
|
367
|
+
}
|
|
368
|
+
barre.stop(`${manager} install failed`, 1);
|
|
369
|
+
for (const ligne of fin) prompts.log.error(colors.dim(ligne));
|
|
370
|
+
return false;
|
|
371
|
+
}
|
|
372
|
+
function versionCli() {
|
|
373
|
+
try {
|
|
374
|
+
const manifeste = join(dirname(templatesRoot()), "package.json");
|
|
375
|
+
const { version } = JSON.parse(readFileSync(manifeste, "utf8"));
|
|
376
|
+
return version;
|
|
377
|
+
} catch {
|
|
378
|
+
return "?";
|
|
379
|
+
}
|
|
380
|
+
}
|
|
328
381
|
function ensure(value) {
|
|
329
382
|
if (prompts.isCancel(value)) {
|
|
330
|
-
prompts.cancel("
|
|
383
|
+
prompts.cancel("Cancelled.");
|
|
331
384
|
process.exit(0);
|
|
332
385
|
}
|
|
333
386
|
return value;
|
|
@@ -336,10 +389,12 @@ async function createCommand(options) {
|
|
|
336
389
|
const root = templatesRoot();
|
|
337
390
|
const templates = availableTemplates(root);
|
|
338
391
|
const defaultTemplate = templates[0] ?? "react-ts";
|
|
339
|
-
prompts.intro(
|
|
392
|
+
prompts.intro(
|
|
393
|
+
`${colors.bgBlue(colors.black(" ODORO "))} ${colors.dim(`v${versionCli()}`)}`
|
|
394
|
+
);
|
|
340
395
|
const rawName = options.name ?? (options.yes === true ? "odoro-app" : ensure(
|
|
341
396
|
await prompts.text({
|
|
342
|
-
message: "
|
|
397
|
+
message: "Project name",
|
|
343
398
|
placeholder: "mon-site",
|
|
344
399
|
defaultValue: "odoro-app",
|
|
345
400
|
validate: (value) => value === "" ? void 0 : validatePackageName(toPackageName(value))
|
|
@@ -357,17 +412,17 @@ async function createCommand(options) {
|
|
|
357
412
|
if (state === "occupe" && overwrite === void 0) {
|
|
358
413
|
if (options.yes === true) {
|
|
359
414
|
prompts.cancel(
|
|
360
|
-
`
|
|
415
|
+
`Folder "${basename(target)}" is not empty. Pass --overwrite or --merge.`
|
|
361
416
|
);
|
|
362
417
|
return 1;
|
|
363
418
|
}
|
|
364
419
|
const choice = ensure(
|
|
365
420
|
await prompts.select({
|
|
366
|
-
message: `
|
|
421
|
+
message: `Folder "${basename(target)}" is not empty.`,
|
|
367
422
|
options: [
|
|
368
|
-
{ value: "annuler", label: "
|
|
369
|
-
{ value: "fusionner", label: "
|
|
370
|
-
{ value: "ecraser", label: "
|
|
423
|
+
{ value: "annuler", label: "Cancel" },
|
|
424
|
+
{ value: "fusionner", label: "Merge \u2014 overwrites files of the same name" },
|
|
425
|
+
{ value: "ecraser", label: "Empty the folder, then create the project" }
|
|
371
426
|
]
|
|
372
427
|
})
|
|
373
428
|
);
|
|
@@ -390,7 +445,7 @@ async function createCommand(options) {
|
|
|
390
445
|
));
|
|
391
446
|
if (!templates.includes(template)) {
|
|
392
447
|
prompts.cancel(
|
|
393
|
-
`
|
|
448
|
+
`Unknown template: "${template}". Available: ${templates.join(", ")}.`
|
|
394
449
|
);
|
|
395
450
|
return 1;
|
|
396
451
|
}
|
|
@@ -399,28 +454,28 @@ async function createCommand(options) {
|
|
|
399
454
|
const detected = detectPackageManager();
|
|
400
455
|
const manager = options.pm ?? (options.yes === true ? detected : ensure(
|
|
401
456
|
await prompts.select({
|
|
402
|
-
message: "
|
|
457
|
+
message: "Package manager",
|
|
403
458
|
initialValue: detected,
|
|
404
459
|
options: PACKAGE_MANAGERS.map((name) => ({
|
|
405
460
|
value: name,
|
|
406
461
|
label: name,
|
|
407
|
-
hint: name === detected ? "
|
|
462
|
+
hint: name === detected ? "detected" : void 0
|
|
408
463
|
}))
|
|
409
464
|
})
|
|
410
465
|
));
|
|
411
466
|
if (!PACKAGE_MANAGERS.includes(manager)) {
|
|
412
|
-
prompts.cancel(`
|
|
467
|
+
prompts.cancel(`Unknown package manager: "${manager}".`);
|
|
413
468
|
return 1;
|
|
414
469
|
}
|
|
415
470
|
const database = template === "react-ts-server" && options.yes !== true ? await askDatabase() : void 0;
|
|
416
|
-
const withGit = options.git ?? (options.yes === true ? true : ensure(await prompts.confirm({ message: "
|
|
471
|
+
const withGit = options.git ?? (options.yes === true ? true : ensure(await prompts.confirm({ message: "Initialize a git repository?" })));
|
|
417
472
|
const withInstall = options.install ?? (options.yes === true ? true : ensure(
|
|
418
473
|
await prompts.confirm({
|
|
419
|
-
message: `
|
|
474
|
+
message: `Install dependencies with ${manager}?`
|
|
420
475
|
})
|
|
421
476
|
));
|
|
422
477
|
const spinner2 = prompts.spinner();
|
|
423
|
-
spinner2.start("
|
|
478
|
+
spinner2.start("Writing files");
|
|
424
479
|
const scaffoldOptions = {
|
|
425
480
|
target,
|
|
426
481
|
template,
|
|
@@ -430,51 +485,44 @@ async function createCommand(options) {
|
|
|
430
485
|
if (overwrite !== void 0) scaffoldOptions.overwrite = overwrite;
|
|
431
486
|
scaffoldOptions.modules = modules;
|
|
432
487
|
const { files } = await scaffold(scaffoldOptions);
|
|
433
|
-
spinner2.stop(`${files.length}
|
|
488
|
+
spinner2.stop(`${String(files.length)} files written to ${colors.cyan(basename(target))}`);
|
|
434
489
|
if (withGit && !existsSync(resolve(target, ".git"))) {
|
|
435
490
|
try {
|
|
436
491
|
execSync("git init -q", { cwd: target, stdio: "ignore" });
|
|
437
|
-
prompts.log.success("
|
|
492
|
+
prompts.log.success("Git repository initialized.");
|
|
438
493
|
} catch {
|
|
439
|
-
prompts.log.warn("git
|
|
494
|
+
prompts.log.warn("git was not found \u2014 repository not initialized.");
|
|
440
495
|
}
|
|
441
496
|
}
|
|
442
497
|
if (database?.url !== void 0) {
|
|
443
498
|
await writeDatabaseUrl(target, database.url);
|
|
444
|
-
prompts.log.success("URL
|
|
499
|
+
prompts.log.success("Database URL written to .env");
|
|
445
500
|
const risque = await assertEnvIgnored(target);
|
|
446
501
|
if (risque !== void 0) prompts.log.warn(risque);
|
|
447
502
|
}
|
|
448
503
|
if (database !== void 0) prompts.log.info(database.note);
|
|
449
504
|
if (modules.includes("registre")) {
|
|
450
|
-
const { initCommand } = await import('./commands-
|
|
505
|
+
const { initCommand } = await import('./commands-AHMXBWQQ.js');
|
|
451
506
|
const code = await initCommand({ root: target, yes: true });
|
|
452
507
|
if (code !== 0) {
|
|
453
508
|
prompts.log.warn(
|
|
454
|
-
"
|
|
509
|
+
"The registry could not be configured. Run `odoro init` in the project."
|
|
455
510
|
);
|
|
456
511
|
}
|
|
457
512
|
}
|
|
458
|
-
|
|
459
|
-
const install = prompts.spinner();
|
|
460
|
-
install.start(`Installation avec ${manager}`);
|
|
461
|
-
try {
|
|
462
|
-
execSync(installCommand(manager), { cwd: target, stdio: "ignore" });
|
|
463
|
-
install.stop("Dependances installees.");
|
|
464
|
-
} catch {
|
|
465
|
-
install.stop("Installation echouee \u2014 a relancer a la main.");
|
|
466
|
-
}
|
|
467
|
-
}
|
|
513
|
+
const installe = withInstall ? await installerDependances(target, manager) : false;
|
|
468
514
|
const steps = [
|
|
469
515
|
`cd ${basename(target)}`,
|
|
470
|
-
|
|
516
|
+
// Si l'installation a echoue, la commande revient dans les etapes : le
|
|
517
|
+
// projet est ecrit, il ne lui manque que ses dependances.
|
|
518
|
+
...installe ? [] : [installCommand(manager)],
|
|
471
519
|
// `odoro.json` vient d'etre ecrit : ce qui reste a montrer, c'est la
|
|
472
520
|
// commande qui s'en sert.
|
|
473
521
|
...modules.includes("registre") ? ["odoro add text/count-up"] : [],
|
|
474
522
|
runCommand(manager, "dev")
|
|
475
523
|
];
|
|
476
|
-
prompts.note(steps.join("\n"), "
|
|
477
|
-
prompts.outro(colors.green("
|
|
524
|
+
prompts.note(steps.join("\n"), "Next steps");
|
|
525
|
+
prompts.outro(colors.green("Happy building."));
|
|
478
526
|
return 0;
|
|
479
527
|
}
|
|
480
528
|
|
package/dist/registry/index.d.ts
CHANGED
|
@@ -94,10 +94,10 @@ declare const baseSchema: z.ZodMiniObject<{
|
|
|
94
94
|
}>]>>;
|
|
95
95
|
notes: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
96
96
|
fallback: z.ZodMiniOptional<z.ZodMiniEnum<{
|
|
97
|
+
none: "none";
|
|
97
98
|
poster: "poster";
|
|
98
99
|
gradient: "gradient";
|
|
99
100
|
static: "static";
|
|
100
|
-
none: "none";
|
|
101
101
|
}>>;
|
|
102
102
|
}, z.core.$strip>;
|
|
103
103
|
}, z.core.$strip>;
|
|
@@ -165,10 +165,10 @@ declare const metaSchema: z.ZodMiniObject<{
|
|
|
165
165
|
}>]>>;
|
|
166
166
|
notes: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
167
167
|
fallback: z.ZodMiniOptional<z.ZodMiniEnum<{
|
|
168
|
+
none: "none";
|
|
168
169
|
poster: "poster";
|
|
169
170
|
gradient: "gradient";
|
|
170
171
|
static: "static";
|
|
171
|
-
none: "none";
|
|
172
172
|
}>>;
|
|
173
173
|
}, z.core.$strip>;
|
|
174
174
|
}, z.core.$strip>;
|