@aventara/cli 0.1.0-pilot.1 → 0.1.0-pilot.3
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 +12 -5
- package/dist/apply/app-module.anchor.d.ts +5 -11
- package/dist/apply/app-module.anchor.js +0 -23
- package/dist/apply/conflict.confirmer.d.ts +0 -9
- package/dist/apply/conflict.confirmer.js +0 -15
- package/dist/apply/e2e-spec.anchor.js +0 -17
- package/dist/apply/main-cors.anchor.d.ts +50 -0
- package/dist/apply/main-cors.anchor.js +60 -0
- package/dist/apply/manifest.merger.d.ts +17 -13
- package/dist/apply/manifest.merger.js +8 -18
- package/dist/aventara.bin.js +0 -10
- package/dist/catalog/adapter.catalog.generated.d.ts +1 -0
- package/dist/catalog/adapter.catalog.generated.js +1 -4
- package/dist/catalog/catalog-entry.interface.d.ts +21 -13
- package/dist/catalog/catalog.matcher.d.ts +7 -13
- package/dist/catalog/catalog.matcher.js +0 -3
- package/dist/catalog/range.reader.d.ts +4 -10
- package/dist/catalog/range.reader.js +0 -14
- package/dist/cli.d.ts +2 -3
- package/dist/cli.js +5 -8
- package/dist/command/command.parser.d.ts +11 -9
- package/dist/command/command.parser.js +24 -18
- package/dist/node-version.guard.js +0 -12
- package/dist/plan/project.planner.d.ts +7 -13
- package/dist/plan/project.planner.js +44 -35
- package/dist/project/package-manager.detector.d.ts +0 -7
- package/dist/project/package-manager.detector.js +0 -7
- package/dist/project/project.inspector.d.ts +3 -9
- package/dist/project/project.inspector.js +0 -10
- package/dist/project/service.detector.d.ts +5 -10
- package/dist/project/service.detector.js +0 -2
- package/dist/project/source.scanner.js +0 -13
- package/dist/run/command.runner.d.ts +4 -4
- package/dist/run/init.orchestrator.d.ts +4 -6
- package/dist/run/init.orchestrator.js +3 -16
- package/dist/run/new.orchestrator.d.ts +8 -9
- package/dist/run/new.orchestrator.js +10 -18
- package/dist/run/scaffold.committer.d.ts +28 -0
- package/dist/run/scaffold.committer.js +53 -0
- package/dist/templates/docs.links.d.ts +8 -0
- package/dist/templates/docs.links.js +2 -0
- package/dist/templates/prisma7/prisma7.templates.js +0 -27
- package/dist/templates/template.registry.d.ts +13 -17
- package/dist/templates/template.registry.js +0 -5
- package/dist/wizard/answer.resolver.d.ts +5 -7
- package/dist/wizard/answer.resolver.js +0 -10
- package/dist/wizard/readline.prompter.d.ts +5 -7
- package/dist/wizard/readline.prompter.js +0 -10
- package/dist/wizard/wizard.questions.d.ts +28 -22
- package/dist/wizard/wizard.questions.js +21 -49
- package/package.json +2 -2
|
@@ -1,29 +1,27 @@
|
|
|
1
1
|
import type { AdapterCatalog, CatalogEntry } from "../catalog/catalog-entry.interface.js";
|
|
2
2
|
import { type ExportReference, type ServiceScan } from "../project/service.detector.js";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* the
|
|
7
|
-
* from it, so a question cannot have a flag the parser does not know or a
|
|
8
|
-
* default the refusal does not mention.
|
|
4
|
+
* The command-line grammar, the TTY prompt, the `--yes` defaults and the
|
|
5
|
+
* non-interactive refusal sentence are all derived from it, so a question cannot
|
|
6
|
+
* have a flag the parser does not know or a default the refusal does not mention.
|
|
9
7
|
*
|
|
10
8
|
* Choices that are an adapter's facts — which ORMs and majors exist, which
|
|
11
|
-
* databases one supports — come from the generated catalog
|
|
12
|
-
*
|
|
9
|
+
* databases one supports — come from the generated catalog, never from a literal
|
|
10
|
+
* here.
|
|
13
11
|
*/
|
|
14
|
-
/**
|
|
12
|
+
/** Yarn is not supported. */
|
|
15
13
|
export declare const PACKAGE_MANAGERS: readonly ["npm", "pnpm"];
|
|
16
14
|
export type PackageManager = (typeof PACKAGE_MANAGERS)[number];
|
|
17
15
|
/** What the wizard settles. */
|
|
18
16
|
export type WizardAnswers = {
|
|
19
|
-
/** `new`'s project directory
|
|
17
|
+
/** `new`'s project directory. */
|
|
20
18
|
readonly name: string;
|
|
21
|
-
/** The ORM and major, as the catalog entry that serves it
|
|
19
|
+
/** The ORM and major, as the catalog entry that serves it. */
|
|
22
20
|
readonly orm: CatalogEntry;
|
|
23
|
-
/** One of `orm`'s providers
|
|
21
|
+
/** One of `orm`'s providers. */
|
|
24
22
|
readonly db: string;
|
|
25
23
|
readonly packageManager: PackageManager;
|
|
26
|
-
/** `init` over an existing ORM setup: the developer's service
|
|
24
|
+
/** `init` over an existing ORM setup: the developer's service. */
|
|
27
25
|
readonly service: ServiceChoice;
|
|
28
26
|
/** The Nest module that provides and exports it. */
|
|
29
27
|
readonly module: ExportReference;
|
|
@@ -36,7 +34,7 @@ export type ServiceChoice = ExportReference & {
|
|
|
36
34
|
readonly isNew: boolean;
|
|
37
35
|
};
|
|
38
36
|
export type QuestionId = keyof WizardAnswers;
|
|
39
|
-
/** What the scan of the developer's source found, for the service questions
|
|
37
|
+
/** What the scan of the developer's source found, for the service questions. */
|
|
40
38
|
export type ServiceContext = {
|
|
41
39
|
readonly scan: ServiceScan;
|
|
42
40
|
/** The ORM's client class, as the scan looked for it. */
|
|
@@ -52,14 +50,13 @@ export type ServiceContext = {
|
|
|
52
50
|
/** What a question may consult: the catalog, what was detected, what is already answered. */
|
|
53
51
|
export type WizardContext = {
|
|
54
52
|
readonly catalog: AdapterCatalog;
|
|
55
|
-
/** Q16-5's default: the lockfile, else the launching package manager (B11), else npm. */
|
|
56
53
|
readonly detectedPackageManager: PackageManager;
|
|
57
54
|
readonly answered: Partial<WizardAnswers>;
|
|
58
55
|
/** Present for `init` over an existing ORM setup. */
|
|
59
56
|
readonly services?: ServiceContext;
|
|
60
57
|
};
|
|
61
58
|
export type Choice = {
|
|
62
|
-
/** What the flag takes and the prompt accepts, e.g. `
|
|
59
|
+
/** What the flag takes and the prompt accepts, e.g. `prisma7`. */
|
|
63
60
|
readonly value: string;
|
|
64
61
|
/** How it is shown, e.g. `Prisma 7`. */
|
|
65
62
|
readonly label: string;
|
|
@@ -80,6 +77,11 @@ export type WizardQuestion<K extends QuestionId> = {
|
|
|
80
77
|
readonly after?: QuestionId;
|
|
81
78
|
/** The answers on offer, or `undefined` for free text. */
|
|
82
79
|
readonly choices: (context: WizardContext) => readonly Choice[] | undefined;
|
|
80
|
+
/**
|
|
81
|
+
* Every value its flag takes before anything is answered — what `--help`
|
|
82
|
+
* lists (pilot.3); absent for free text. From the catalog, never a literal.
|
|
83
|
+
*/
|
|
84
|
+
readonly accepts?: (catalog: AdapterCatalog) => readonly string[];
|
|
83
85
|
/** The answer `--yes` (or Enter at the prompt) takes; `undefined` when there is none. */
|
|
84
86
|
readonly defaultFor: (context: WizardContext) => string | undefined;
|
|
85
87
|
/** @throws WizardAnswerError when `raw` is not an answer to this question. */
|
|
@@ -90,25 +92,29 @@ export type WizardQuestion<K extends QuestionId> = {
|
|
|
90
92
|
export type AnyWizardQuestion = {
|
|
91
93
|
readonly [K in QuestionId]: WizardQuestion<K>;
|
|
92
94
|
}[QuestionId];
|
|
95
|
+
/**
|
|
96
|
+
* What `--orm` takes: each adapter's alias, with what it is — the refusal's words,
|
|
97
|
+
* and the usage's.
|
|
98
|
+
*/
|
|
99
|
+
export declare function ormAliasesSentence(catalog: AdapterCatalog): string;
|
|
93
100
|
export declare const NAME_QUESTION: WizardQuestion<"name">;
|
|
94
101
|
/**
|
|
95
|
-
*
|
|
96
|
-
* for the family's highest major (Q16-31).
|
|
102
|
+
* The prompt keeps the family-then-major order; every answer is an alias.
|
|
97
103
|
*/
|
|
98
104
|
export declare const ORM_QUESTION: WizardQuestion<"orm">;
|
|
99
|
-
/** R10 — the database, from the chosen entry's providers; the first is the default. */
|
|
100
105
|
export declare const DB_QUESTION: WizardQuestion<"db">;
|
|
101
|
-
/** Q16-5 — npm or pnpm; the default is detected. */
|
|
102
106
|
export declare const PACKAGE_MANAGER_QUESTION: WizardQuestion<"packageManager">;
|
|
103
|
-
/** R6, Q16-11 — the developer's service; a new one is written only when there is none. */
|
|
104
107
|
export declare const SERVICE_QUESTION: WizardQuestion<"service">;
|
|
105
108
|
/** The module that provides and exports the chosen service (or is @Global). */
|
|
106
109
|
export declare const MODULE_QUESTION: WizardQuestion<"module">;
|
|
107
110
|
/** `aventara new`'s questions, in the order they are asked. */
|
|
108
111
|
export declare const NEW_QUESTIONS: readonly [WizardQuestion<"name">, WizardQuestion<"orm">, WizardQuestion<"db">, WizardQuestion<"packageManager">];
|
|
109
|
-
/** `aventara init`'s questions when the project has no ORM
|
|
112
|
+
/** `aventara init`'s questions when the project has no ORM, in order. */
|
|
110
113
|
export declare const INIT_QUESTIONS: readonly [WizardQuestion<"orm">, WizardQuestion<"db">, WizardQuestion<"packageManager">];
|
|
111
|
-
/**
|
|
114
|
+
/**
|
|
115
|
+
* `aventara init`'s questions over an existing ORM setup: the ORM and database are
|
|
116
|
+
* read, not asked.
|
|
117
|
+
*/
|
|
112
118
|
export declare const REUSE_QUESTIONS: readonly [WizardQuestion<"service">, WizardQuestion<"module">, WizardQuestion<"packageManager">];
|
|
113
119
|
/** Every flag `aventara init` takes for a question, either way. */
|
|
114
120
|
export declare const INIT_FLAG_QUESTIONS: readonly [WizardQuestion<"orm">, WizardQuestion<"db">, WizardQuestion<"service">, WizardQuestion<"module">, WizardQuestion<"packageManager">];
|
|
@@ -1,33 +1,24 @@
|
|
|
1
1
|
import { modulesProviding, } from "../project/service.detector.js";
|
|
2
|
-
/**
|
|
3
|
-
* R5 — every question the two commands ask, in **one table**: its flag, its
|
|
4
|
-
* label, its choices and its default. The command-line grammar, the TTY prompt,
|
|
5
|
-
* the `--yes` defaults and the non-interactive refusal sentence are all derived
|
|
6
|
-
* from it, so a question cannot have a flag the parser does not know or a
|
|
7
|
-
* default the refusal does not mention.
|
|
8
|
-
*
|
|
9
|
-
* Choices that are an adapter's facts — which ORMs and majors exist, which
|
|
10
|
-
* databases one supports — come from the generated catalog (R14), never from a
|
|
11
|
-
* literal here.
|
|
12
|
-
*/
|
|
13
|
-
/** Q16-5 (a). Yarn is not supported (U1). */
|
|
14
2
|
export const PACKAGE_MANAGERS = ["npm", "pnpm"];
|
|
15
|
-
/** An answer the question cannot accept. A refusal: one sentence. */
|
|
16
3
|
export class WizardAnswerError extends Error {
|
|
17
4
|
name = "WizardAnswerError";
|
|
18
5
|
}
|
|
19
6
|
function ormLabel(entry) {
|
|
20
7
|
return `${entry.orm.label} ${entry.orm.major}`;
|
|
21
8
|
}
|
|
22
|
-
function
|
|
23
|
-
return
|
|
24
|
-
.
|
|
25
|
-
.join(", ")
|
|
9
|
+
function listed(items) {
|
|
10
|
+
return items.length <= 1
|
|
11
|
+
? items.join("")
|
|
12
|
+
: `${items.slice(0, -1).join(", ")} or ${items[items.length - 1]}`;
|
|
13
|
+
}
|
|
14
|
+
function families(catalog) {
|
|
15
|
+
return [...new Set(catalog.map((entry) => entry.orm.family))];
|
|
16
|
+
}
|
|
17
|
+
export function ormAliasesSentence(catalog) {
|
|
18
|
+
return `--orm takes ${listed(ormChoices(catalog).map((entry) => `${entry.alias} (${ormLabel(entry)}, ${entry.adapterPackage})`))}`;
|
|
26
19
|
}
|
|
27
|
-
/** Ordered for the wizard: by family as the catalog lists them, majors newest first. */
|
|
28
20
|
function ormChoices(catalog) {
|
|
29
|
-
|
|
30
|
-
return families.flatMap((family) => catalog
|
|
21
|
+
return families(catalog).flatMap((family) => catalog
|
|
31
22
|
.filter((entry) => entry.orm.family === family)
|
|
32
23
|
.sort((left, right) => right.orm.major - left.orm.major));
|
|
33
24
|
}
|
|
@@ -47,33 +38,21 @@ export const NAME_QUESTION = {
|
|
|
47
38
|
},
|
|
48
39
|
describe: (name) => name,
|
|
49
40
|
};
|
|
50
|
-
/**
|
|
51
|
-
* R14 — the ORM, from the catalog: `--orm <family>@<major>`, or `--orm <family>`
|
|
52
|
-
* for the family's highest major (Q16-31).
|
|
53
|
-
*/
|
|
54
41
|
export const ORM_QUESTION = {
|
|
55
42
|
id: "orm",
|
|
56
43
|
flag: "--orm",
|
|
57
44
|
label: "ORM",
|
|
58
45
|
choices: (context) => ormChoices(context.catalog).map((entry) => ({
|
|
59
|
-
value:
|
|
46
|
+
value: entry.alias,
|
|
60
47
|
label: ormLabel(entry),
|
|
61
48
|
})),
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
: undefined,
|
|
49
|
+
accepts: (catalog) => ormChoices(catalog).map((entry) => entry.alias),
|
|
50
|
+
defaultFor: (context) => context.catalog.length === 1 ? context.catalog[0]?.alias : undefined,
|
|
65
51
|
parse: (raw, context) => {
|
|
66
|
-
const
|
|
67
|
-
const
|
|
68
|
-
if (rest.length > 0 || offered.length === 0) {
|
|
69
|
-
throw new WizardAnswerError(`there is no Aventara adapter for the ORM ${JSON.stringify(raw)}; available: ${available(context.catalog)}`);
|
|
70
|
-
}
|
|
71
|
-
if (major === undefined) {
|
|
72
|
-
return offered[0];
|
|
73
|
-
}
|
|
74
|
-
const entry = offered.find((candidate) => String(candidate.orm.major) === major);
|
|
52
|
+
const alias = raw.trim().toLowerCase();
|
|
53
|
+
const entry = context.catalog.find((candidate) => candidate.alias === alias);
|
|
75
54
|
if (entry === undefined) {
|
|
76
|
-
throw new WizardAnswerError(`there is no Aventara adapter for ${
|
|
55
|
+
throw new WizardAnswerError(`there is no Aventara adapter for the ORM ${JSON.stringify(raw)}; ${ormAliasesSentence(context.catalog)}`);
|
|
77
56
|
}
|
|
78
57
|
return entry;
|
|
79
58
|
},
|
|
@@ -86,7 +65,6 @@ function requireOrm(context) {
|
|
|
86
65
|
}
|
|
87
66
|
return orm;
|
|
88
67
|
}
|
|
89
|
-
/** R10 — the database, from the chosen entry's providers; the first is the default. */
|
|
90
68
|
export const DB_QUESTION = {
|
|
91
69
|
id: "db",
|
|
92
70
|
flag: "--db",
|
|
@@ -96,6 +74,9 @@ export const DB_QUESTION = {
|
|
|
96
74
|
value: provider,
|
|
97
75
|
label: provider,
|
|
98
76
|
})),
|
|
77
|
+
accepts: (catalog) => [
|
|
78
|
+
...new Set(catalog.flatMap((entry) => entry.providers)),
|
|
79
|
+
],
|
|
99
80
|
defaultFor: (context) => requireOrm(context).providers[0],
|
|
100
81
|
parse: (raw, context) => {
|
|
101
82
|
const orm = requireOrm(context);
|
|
@@ -107,12 +88,12 @@ export const DB_QUESTION = {
|
|
|
107
88
|
},
|
|
108
89
|
describe: (db) => db,
|
|
109
90
|
};
|
|
110
|
-
/** Q16-5 — npm or pnpm; the default is detected. */
|
|
111
91
|
export const PACKAGE_MANAGER_QUESTION = {
|
|
112
92
|
id: "packageManager",
|
|
113
93
|
flag: "--package-manager",
|
|
114
94
|
label: "Package manager",
|
|
115
95
|
choices: () => PACKAGE_MANAGERS.map((manager) => ({ value: manager, label: manager })),
|
|
96
|
+
accepts: () => PACKAGE_MANAGERS,
|
|
116
97
|
defaultFor: (context) => context.detectedPackageManager,
|
|
117
98
|
parse: (raw) => {
|
|
118
99
|
const manager = PACKAGE_MANAGERS.find((candidate) => candidate === raw.trim().toLowerCase());
|
|
@@ -139,7 +120,6 @@ function requireServices(context) {
|
|
|
139
120
|
}
|
|
140
121
|
return context.services;
|
|
141
122
|
}
|
|
142
|
-
/** The services on offer: what the scan found, or — when it found none — the template's new file. */
|
|
143
123
|
function serviceOptions(services) {
|
|
144
124
|
const found = [
|
|
145
125
|
...services.scan.candidates.map((candidate) => ({
|
|
@@ -156,14 +136,11 @@ function serviceOptions(services) {
|
|
|
156
136
|
? found
|
|
157
137
|
: [{ ...services.newService, isNew: true }];
|
|
158
138
|
}
|
|
159
|
-
/** R6, Q16-11 — the developer's service; a new one is written only when there is none. */
|
|
160
139
|
export const SERVICE_QUESTION = {
|
|
161
140
|
id: "service",
|
|
162
141
|
flag: "--prisma-service",
|
|
163
142
|
placeholder: "<path#Export>",
|
|
164
143
|
label: "Service to give Aventara (file#Export)",
|
|
165
|
-
// With no service found, the offer to write one is a question with a default
|
|
166
|
-
// (asked on a terminal, taken by --yes), not a single choice taken silently.
|
|
167
144
|
choices: (context) => {
|
|
168
145
|
const options = serviceOptions(requireServices(context));
|
|
169
146
|
return options.every((option) => option.isNew)
|
|
@@ -198,7 +175,6 @@ export const SERVICE_QUESTION = {
|
|
|
198
175
|
},
|
|
199
176
|
describe: spelled,
|
|
200
177
|
};
|
|
201
|
-
/** The module that provides and exports the chosen service (or is @Global). */
|
|
202
178
|
export const MODULE_QUESTION = {
|
|
203
179
|
id: "module",
|
|
204
180
|
flag: "--prisma-module",
|
|
@@ -232,26 +208,22 @@ export const MODULE_QUESTION = {
|
|
|
232
208
|
},
|
|
233
209
|
describe: spelled,
|
|
234
210
|
};
|
|
235
|
-
/** `aventara new`'s questions, in the order they are asked. */
|
|
236
211
|
export const NEW_QUESTIONS = [
|
|
237
212
|
NAME_QUESTION,
|
|
238
213
|
ORM_QUESTION,
|
|
239
214
|
DB_QUESTION,
|
|
240
215
|
PACKAGE_MANAGER_QUESTION,
|
|
241
216
|
];
|
|
242
|
-
/** `aventara init`'s questions when the project has no ORM (S6), in order. */
|
|
243
217
|
export const INIT_QUESTIONS = [
|
|
244
218
|
ORM_QUESTION,
|
|
245
219
|
DB_QUESTION,
|
|
246
220
|
PACKAGE_MANAGER_QUESTION,
|
|
247
221
|
];
|
|
248
|
-
/** `aventara init`'s questions over an existing ORM setup (S7): the ORM and database are read, not asked. */
|
|
249
222
|
export const REUSE_QUESTIONS = [
|
|
250
223
|
SERVICE_QUESTION,
|
|
251
224
|
MODULE_QUESTION,
|
|
252
225
|
PACKAGE_MANAGER_QUESTION,
|
|
253
226
|
];
|
|
254
|
-
/** Every flag `aventara init` takes for a question, either way. */
|
|
255
227
|
export const INIT_FLAG_QUESTIONS = [
|
|
256
228
|
ORM_QUESTION,
|
|
257
229
|
DB_QUESTION,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aventara/cli",
|
|
3
|
-
"version": "0.1.0-pilot.
|
|
3
|
+
"version": "0.1.0-pilot.3",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE",
|
|
5
5
|
"description": "Scaffolds an Aventara server: `aventara new` for a new NestJS project, `aventara init` for an existing one.",
|
|
6
6
|
"type": "module",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
},
|
|
24
24
|
"scripts": {
|
|
25
25
|
"prebuild": "node scripts/adapter-catalog.generator.ts",
|
|
26
|
-
"build": "tsc -p tsconfig.json",
|
|
26
|
+
"build": "tsc -p tsconfig.json --removeComments --declaration false && tsc -p tsconfig.json --emitDeclarationOnly && node ../../scripts/build/declaration-comments.sanitizer.ts dist",
|
|
27
27
|
"typecheck": "tsc -p tsconfig.typecheck.json --noEmit",
|
|
28
28
|
"test": "vitest run --typecheck --config ../../vitest.config.mts --root .",
|
|
29
29
|
"lint": "biome lint src scripts"
|