@aventara/build 1.0.0-rc.14 → 1.0.0-rc.15
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/CHANGELOG.md +27 -0
- package/README.md +3 -2
- package/dist/cli.js +28 -5
- package/dist/client/client-file.js +10 -7
- package/dist/computed/computed-fields-file.js +8 -3
- package/dist/contracts/prebuilt-contracts.compiler.js +1 -0
- package/dist/facts/config-facts-file.js +50 -0
- package/dist/project/generated-files.resolver.js +1 -0
- package/dist/resources/resources-file.js +18 -4
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# @aventara/build
|
|
2
2
|
|
|
3
|
+
## 1.0.0-rc.15
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- aab6d72: The client `avclient generate` writes now passes a default `biome check` as written, on Biome 2.4.0 and later (Biome's default rules; an opt-in rule or assist such as `useSortedKeys` is not covered): every generated file opens with `biome-ignore-all` lines for formatting, lint and import order (`organizeImports`), core's copied declarations have a blank line after their imports, the copied field-check evaluator carries no line suppression that the file-wide one makes unused, and each file ends without a final line break, which Biome 2.4.0 to 2.4.10 reported on every file under `biome-ignore-all format`. `aventara-build`'s own files pass too, in NestJS and Next.js projects: `resources.generated.ts`, `computed-fields.generated.ts` and `contracts.generated.ts` now open with the same suppressions and end without a final line break, and `--client`'s `src/aventara/client.ts` and `src/aventara/universal.ts` are written the same way. The discovery artifact `aventara-prisma7-generate` writes passes too. A file an earlier version wrote is reported stale by `aventara-build --check` and replaced by the next run. A client `avclient generate` wrote before is replaced on its next run. The client skill now says the generated files need no exclusion under Biome's default rules, and how to skip them in another linter or formatter.
|
|
8
|
+
- bf98da7: A pipeline stage's types now know the root's field definitions. `aventara-build` writes `src/generated/aventara/config-facts.generated.ts` after it compiles the Contracts, and the discovery artifact puts it on the model's type:
|
|
9
|
+
|
|
10
|
+
- A Json field the root shapes reads as its shape in a stage's `ctx` calls, in `tx` and in compute's read-only `ctx`: `ctx.Product.find.many({ select: ["name"] })` types `name` as `{ ar: string; en: string }`. A read gives the shape's own type, the same as `framework.application`'s.
|
|
11
|
+
- A `VIRTUAL` field the root adds is in a variant's typed `ctx.$args` (`ctx.$args.data.tenderedMinor`), and a `ctx` create must write a non-null added input it can create.
|
|
12
|
+
- A variant's hooks and interceptors are told resolved arguments: their `ctx.$args` holds no `$ref` (an `AvTransactionReference`), since references are resolved before they run. Guards, pipes and filters still may see one.
|
|
13
|
+
- A write takes a shaped Json value read-only, deep, on every surface (`framework.application`, `ctx`, the generated client too), so a frozen value, such as a stage's `ctx.$args`, fits as well as a mutable one.
|
|
14
|
+
- A compute stage on a shaped Json field returns the shape's type. A compute stage on an added field returns the type its generated fact states, read from the model instead of the configuration. Without the generated file, its return is not typed.
|
|
15
|
+
|
|
16
|
+
The server warns at startup (`AVENTARA_STALE_GENERATED_TYPES`) when the configuration's definitions differ from the ones the generated types were written with, naming each field. It is the same one warning as for stale computed fields: one stale build gives one warning, with a paragraph for each part that is stale, including a facts file it cannot read. `aventara-build --check` also fails on a stale file. Run `aventara:prepare` after you change a `definition`.
|
|
17
|
+
|
|
18
|
+
The discovery artifact's format is now 5: regenerate it with `aventara:prepare` (an artifact of format 4 is refused, as before). The Json Shape type emitter the client generator uses now lives in `@aventara/core`; the generated clients are unchanged. The CLI's agent skill says this in `SKILL.md` and `reference/stages.md`.
|
|
19
|
+
|
|
20
|
+
- `aventara-build` no longer logs `unchanged:` for `computed-fields.generated.ts` when it keeps that file because the configuration does not type-check: it logs `kept (configuration does not type-check): <file>`, after the type errors, since the kept file may be an earlier version's. The exit code is unchanged (0), so the `postinstall` that runs `aventara:prepare` still completes; fix the errors, then run `aventara:prepare` again.
|
|
21
|
+
- Updated dependencies [aab6d72]
|
|
22
|
+
- Updated dependencies [bf98da7]
|
|
23
|
+
- Updated dependencies [f8cd860]
|
|
24
|
+
- Updated dependencies [8a64af2]
|
|
25
|
+
- Updated dependencies [548881c]
|
|
26
|
+
- Updated dependencies [62fa91f]
|
|
27
|
+
- @aventara/client@1.0.0-rc.15
|
|
28
|
+
- @aventara/core@1.0.0-rc.15
|
|
29
|
+
|
|
3
30
|
## 1.0.0-rc.14
|
|
4
31
|
|
|
5
32
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ aventara-prisma7-generate … && aventara-build
|
|
|
17
17
|
|
|
18
18
|
## What it reads and writes
|
|
19
19
|
|
|
20
|
-
Run it from the project's root. It writes
|
|
20
|
+
Run it from the project's root. It writes four files, in this order, each from what the one before wrote, so a fresh
|
|
21
21
|
install is right on its first `aventara:prepare`. They go to the directory your configuration imports
|
|
22
22
|
`aventaraResources` from, beside the discovery artifact: `src/generated/aventara/` normally, `src/aventara/` when
|
|
23
23
|
`aventara init` found Prisma's client generated into `src/generated` (which `prisma generate` would empty). A
|
|
@@ -27,6 +27,7 @@ configuration that imports no tree keeps `src/generated/aventara/`.
|
|
|
27
27
|
|---|---|
|
|
28
28
|
| `resources.generated.ts` | `aventaraResources`: every Resource your `src/resources/**/*.resource.ts` files define, one `resources` tree per layer |
|
|
29
29
|
| `computed-fields.generated.ts` | `computedFields` (typed `AvComputedFields`): which fields the configuration's write compute fills, read off its type |
|
|
30
|
+
| `config-facts.generated.ts` | `configFacts`: the Json shapes and the fields the root's definitions add, read off the compiled Contracts; the discovery artifact puts them on the model's type, so a pipeline stage's `ctx` and `ctx.$args` know them |
|
|
30
31
|
| `contracts.generated.ts` | `aventaraContracts` (typed `AvPrebuiltContracts`): the compiled Contracts |
|
|
31
32
|
|
|
32
33
|
### The Resource tree
|
|
@@ -189,7 +190,7 @@ aventara-build --check
|
|
|
189
190
|
aventara-build --check --client
|
|
190
191
|
```
|
|
191
192
|
|
|
192
|
-
Writes nothing. It exits 0 when the
|
|
193
|
+
Writes nothing. It exits 0 when the four files on disk are the ones a build would write now, and 1 on the first that is
|
|
193
194
|
missing or stale, naming it (and, for the Contracts, the Resources whose configuration or model changed). With
|
|
194
195
|
`--client`, the browser client's files are checked too, after the Contracts: a missing or stale file, or one an earlier
|
|
195
196
|
ClientContract's client left, exits 1. Run it in CI before a deploy.
|
package/dist/cli.js
CHANGED
|
@@ -6,6 +6,7 @@ import { readConfigComputedFields } from "./computed/computed-fields.reader.js";
|
|
|
6
6
|
import { emitComputedFieldsModule } from "./computed/computed-fields-file.js";
|
|
7
7
|
import { checkContractsFile } from "./contracts/contracts-file.js";
|
|
8
8
|
import { compilePrebuiltContracts } from "./contracts/prebuilt-contracts.compiler.js";
|
|
9
|
+
import { emitConfigFactsModule, emitUnreadConfigFactsModule, } from "./facts/config-facts-file.js";
|
|
9
10
|
import { acquireBuildLock } from "./project/build.lock.js";
|
|
10
11
|
import { generatedFileBatch, readGeneratedFile, } from "./project/generated-file.js";
|
|
11
12
|
import { DEFAULT_GENERATED_FILES, resolveGeneratedFiles, } from "./project/generated-files.resolver.js";
|
|
@@ -18,7 +19,7 @@ import { emitResourcesModule } from "./resources/resources-file.js";
|
|
|
18
19
|
const USAGE = `aventara-build — compile this project's Aventara Contracts ahead of time.
|
|
19
20
|
|
|
20
21
|
Usage:
|
|
21
|
-
aventara-build write the
|
|
22
|
+
aventara-build write the four files below
|
|
22
23
|
aventara-build --client also write a Next.js app's browser client
|
|
23
24
|
aventara-build --check [--client] write nothing; exit 1 when one is missing or stale
|
|
24
25
|
|
|
@@ -29,10 +30,13 @@ Run it from the project's root. It writes, in this order:
|
|
|
29
30
|
${RESOURCES_GLOB} export, one \`resources\` tree per layer;
|
|
30
31
|
${DEFAULT_GENERATED_FILES.computedFields}
|
|
31
32
|
which fields the configuration computes, read off its type;
|
|
33
|
+
${DEFAULT_GENERATED_FILES.configFacts}
|
|
34
|
+
the Json shapes and the fields the configuration's definitions add,
|
|
35
|
+
read off the compiled Contracts, which pipeline stages' types read;
|
|
32
36
|
${DEFAULT_GENERATED_FILES.contracts}
|
|
33
37
|
the compiled Contracts, \`aventaraContracts\`.
|
|
34
38
|
|
|
35
|
-
All
|
|
39
|
+
All four go to the directory the configuration imports \`aventaraResources\`
|
|
36
40
|
from (src/aventara/ when \`aventara init\` found the ORM's client generated into
|
|
37
41
|
src/generated), else to ${PROJECT_LAYOUTS.nest.generated}/ (${PROJECT_LAYOUTS.next.generated}/
|
|
38
42
|
in a Next.js project).
|
|
@@ -188,6 +192,14 @@ export async function runBuild(argv, projectDirectory, output) {
|
|
|
188
192
|
else {
|
|
189
193
|
noteWrite(wrote(batch.write(generated.resources, tree), generated.resources, counted(found.definitions.length)));
|
|
190
194
|
}
|
|
195
|
+
const hadFacts = readGeneratedFile(projectDirectory, generated.configFacts) !== undefined;
|
|
196
|
+
if (check && !hadFacts) {
|
|
197
|
+
output.stderr(refusal({ file: generated.configFacts, what: "is missing" }));
|
|
198
|
+
return 1;
|
|
199
|
+
}
|
|
200
|
+
if (!check && !hadFacts) {
|
|
201
|
+
batch.write(generated.configFacts, emitUnreadConfigFactsModule(files.configFile, "the build has not compiled the Contracts yet"));
|
|
202
|
+
}
|
|
191
203
|
const hadComputed = readGeneratedFile(projectDirectory, generated.computedFields) !==
|
|
192
204
|
undefined;
|
|
193
205
|
if (check && !hadComputed) {
|
|
@@ -218,7 +230,7 @@ export async function runBuild(argv, projectDirectory, output) {
|
|
|
218
230
|
return 1;
|
|
219
231
|
}
|
|
220
232
|
if (kept) {
|
|
221
|
-
noteWrite(
|
|
233
|
+
noteWrite(`aventara-build: kept (configuration does not type-check): ${generated.computedFields}.`);
|
|
222
234
|
}
|
|
223
235
|
else if (check) {
|
|
224
236
|
const stale = checked(projectDirectory, generated.computedFields, computed, "the fields the configuration computes changed since it was written");
|
|
@@ -236,6 +248,17 @@ export async function runBuild(argv, projectDirectory, output) {
|
|
|
236
248
|
const project = await loadProjectModules(projectDirectory, files);
|
|
237
249
|
const compiled = await compilePrebuiltContracts(project);
|
|
238
250
|
const resources = Object.keys(compiled.prebuilt.fingerprints.resources).length;
|
|
251
|
+
const facts = emitConfigFactsModule(files.configFile, project.internal.configFactsOf(compiled.core), project.internal);
|
|
252
|
+
if (check) {
|
|
253
|
+
const stale = checked(projectDirectory, generated.configFacts, facts, "the Json shapes or the fields the configuration's definitions add changed since it was written");
|
|
254
|
+
if (stale !== undefined) {
|
|
255
|
+
output.stderr(refusal(stale));
|
|
256
|
+
return 1;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
noteWrite(wrote(batch.write(generated.configFacts, facts), generated.configFacts));
|
|
261
|
+
}
|
|
239
262
|
const browserClient = clientLayout === undefined
|
|
240
263
|
? undefined
|
|
241
264
|
: await emitBrowserClient(projectDirectory, clientLayout, {
|
|
@@ -268,8 +291,8 @@ export async function runBuild(argv, projectDirectory, output) {
|
|
|
268
291
|
return 1;
|
|
269
292
|
}
|
|
270
293
|
note(browserClient === undefined
|
|
271
|
-
? `aventara-build: ${generated.resources}, ${generated.computedFields} and ${generated.contracts} are up to date.`
|
|
272
|
-
: `aventara-build: ${generated.resources}, ${generated.computedFields}, ${generated.contracts} and the browser client (${browserClient.files[0]?.file}, ${browserClient.files[1]?.file} and ${browserClient.tree}/) are up to date.`);
|
|
294
|
+
? `aventara-build: ${generated.resources}, ${generated.computedFields}, ${generated.configFacts} and ${generated.contracts} are up to date.`
|
|
295
|
+
: `aventara-build: ${generated.resources}, ${generated.computedFields}, ${generated.configFacts}, ${generated.contracts} and the browser client (${browserClient.files[0]?.file}, ${browserClient.files[1]?.file} and ${browserClient.tree}/) are up to date.`);
|
|
273
296
|
return 0;
|
|
274
297
|
}
|
|
275
298
|
output.stderr(refusal({
|
|
@@ -8,6 +8,7 @@ export const REGENERATE = "`aventara-build --client` (the project's `aventara:pr
|
|
|
8
8
|
const ENTRY_BANNER = [
|
|
9
9
|
"// biome-ignore-all format: generated output",
|
|
10
10
|
"// biome-ignore-all lint: generated output",
|
|
11
|
+
"// biome-ignore-all assist/source/organizeImports: generated output",
|
|
11
12
|
"/* !!! Generated by @aventara/build. Do not edit. !!! */",
|
|
12
13
|
`/* Regenerate with ${REGENERATE}. */`,
|
|
13
14
|
].join("\n");
|
|
@@ -145,6 +146,9 @@ const HOOKS: Pick<AvClientOptions, "onCall" | "onSuccess" | "onError"> = {
|
|
|
145
146
|
onError: (call, error) => clientOptions()?.onError?.(call, error),
|
|
146
147
|
};
|
|
147
148
|
`;
|
|
149
|
+
function withoutFinalLineBreak(text) {
|
|
150
|
+
return text.replace(/\n+$/, "");
|
|
151
|
+
}
|
|
148
152
|
function optionsImport(options) {
|
|
149
153
|
return options === undefined
|
|
150
154
|
? ""
|
|
@@ -158,9 +162,9 @@ function entrySource(style, accessVerbs, options) {
|
|
|
158
162
|
.join(" | ");
|
|
159
163
|
return `${ENTRY_BANNER}
|
|
160
164
|
|
|
161
|
-
import { AvClient${options === undefined ? "" : ", type AvClientOptions"} } from ${from(`./${GENERATED_DIRECTORY}/client`)};
|
|
165
|
+
${optionsImport(options)}import { AvClient${options === undefined ? "" : ", type AvClientOptions"} } from ${from(`./${GENERATED_DIRECTORY}/client`)};
|
|
162
166
|
import { type AvBuiltInScalar, decodeScalar } from ${from(`./${GENERATED_DIRECTORY}/runtime/codec`)};
|
|
163
|
-
|
|
167
|
+
|
|
164
168
|
${clientEntryReExports(style, "type", accessVerbs)}
|
|
165
169
|
/** What a call made on the server is refused with. */
|
|
166
170
|
const SERVER_CALL = ${JSON.stringify(SERVER_CALL_REFUSAL)};
|
|
@@ -284,10 +288,9 @@ function universalSource(style, accessVerbs, options) {
|
|
|
284
288
|
|
|
285
289
|
import { io } from ${JSON.stringify(style.importFileExtension === "" ? "next/cache" : "next/cache.js")};
|
|
286
290
|
import { cache } from "react";
|
|
287
|
-
import { AvClient${options === undefined ? "" : ", type AvClientOptions"} } from ${from(`./${GENERATED_DIRECTORY}/client`)};
|
|
288
|
-
import type { AvFetch } from ${from(`./${GENERATED_DIRECTORY}/runtime/transport`)};
|
|
289
|
-
${optionsImport(options)}
|
|
291
|
+
${optionsImport(options)}import { AvClient${options === undefined ? "" : ", type AvClientOptions"} } from ${from(`./${GENERATED_DIRECTORY}/client`)};
|
|
290
292
|
import { avLazy as lazyCall } from ${from(`./${GENERATED_DIRECTORY}/runtime/operation-set`)};
|
|
293
|
+
import type { AvFetch } from ${from(`./${GENERATED_DIRECTORY}/runtime/transport`)};
|
|
291
294
|
|
|
292
295
|
/** The key the server's in-process path is registered under, on globalThis, by ready() from @aventara/next. */
|
|
293
296
|
const SERVER_PATH = Symbol.for(${JSON.stringify(UNIVERSAL_PATH_KEY)});
|
|
@@ -474,11 +477,11 @@ export async function emitBrowserClient(projectDirectory, layout, source) {
|
|
|
474
477
|
files: [
|
|
475
478
|
{
|
|
476
479
|
file: `${layout.folder}/${layout.entry}`,
|
|
477
|
-
text: entrySource(style, accessVerbs, options),
|
|
480
|
+
text: withoutFinalLineBreak(entrySource(style, accessVerbs, options)),
|
|
478
481
|
},
|
|
479
482
|
{
|
|
480
483
|
file: `${layout.folder}/${layout.universal}`,
|
|
481
|
-
text: universalSource(style, accessVerbs, options),
|
|
484
|
+
text: withoutFinalLineBreak(universalSource(style, accessVerbs, options)),
|
|
482
485
|
},
|
|
483
486
|
...tree,
|
|
484
487
|
],
|
|
@@ -9,7 +9,12 @@ function literal(computedFields) {
|
|
|
9
9
|
return JSON.stringify(ordered, null, "\t");
|
|
10
10
|
}
|
|
11
11
|
export function emitComputedFieldsModule(configFile, reading) {
|
|
12
|
-
const header =
|
|
12
|
+
const header = [
|
|
13
|
+
"// biome-ignore-all format: generated output",
|
|
14
|
+
"// biome-ignore-all lint: generated output",
|
|
15
|
+
"// biome-ignore-all assist/source/organizeImports: generated output",
|
|
16
|
+
`// Generated by aventara-build from the type of ${configFile}. Do not edit: regenerate it (aventara:prepare).`,
|
|
17
|
+
].join("\n");
|
|
13
18
|
const type = [
|
|
14
19
|
"",
|
|
15
20
|
"// What an adapter's discovery artifact carries on its model's type for the stages that run before compute.",
|
|
@@ -26,7 +31,7 @@ export function emitComputedFieldsModule(configFile, reading) {
|
|
|
26
31
|
"// What an adapter's discovery artifact carries on its model's type for the stages that run before compute:",
|
|
27
32
|
"// nothing, so they may leave any create field out.",
|
|
28
33
|
"export type AvComputedFields = undefined;",
|
|
29
|
-
].join("\n")}
|
|
34
|
+
].join("\n")}`;
|
|
30
35
|
}
|
|
31
36
|
return `${[
|
|
32
37
|
header,
|
|
@@ -36,5 +41,5 @@ export function emitComputedFieldsModule(configFile, reading) {
|
|
|
36
41
|
"// Resource. The framework compares it with the configuration at startup and warns when they differ.",
|
|
37
42
|
`export const computedFields = ${literal(reading.computedFields)} as const satisfies AvConfigComputedFields;`,
|
|
38
43
|
...type,
|
|
39
|
-
].join("\n")}
|
|
44
|
+
].join("\n")}`;
|
|
40
45
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
const key = (name) => JSON.stringify(name);
|
|
2
|
+
function shapeTypes(json, jsonSchemaType) {
|
|
3
|
+
const resources = Object.keys(json);
|
|
4
|
+
if (resources.length === 0) {
|
|
5
|
+
return "Record<never, never>";
|
|
6
|
+
}
|
|
7
|
+
const blocks = resources.map((resource) => {
|
|
8
|
+
const fields = json[resource] ?? {};
|
|
9
|
+
const members = Object.keys(fields).map((field) => `\t\t\treadonly ${key(field)}: ${jsonSchemaType(fields[field])};`);
|
|
10
|
+
return `\t\treadonly ${key(resource)}: {\n${members.join("\n")}\n\t\t};`;
|
|
11
|
+
});
|
|
12
|
+
return `{\n${blocks.join("\n")}\n\t}`;
|
|
13
|
+
}
|
|
14
|
+
const headerOf = (configFile) => [
|
|
15
|
+
"// biome-ignore-all format: generated output",
|
|
16
|
+
"// biome-ignore-all lint: generated output",
|
|
17
|
+
"// biome-ignore-all assist/source/organizeImports: generated output",
|
|
18
|
+
`// Generated by aventara-build from the Contracts compiled from ${configFile}. Do not edit: regenerate it (aventara:prepare).`,
|
|
19
|
+
].join("\n");
|
|
20
|
+
export function emitUnreadConfigFactsModule(configFile, reason) {
|
|
21
|
+
return `${[
|
|
22
|
+
headerOf(configFile),
|
|
23
|
+
"",
|
|
24
|
+
`// Not read: ${reason.replaceAll("\n", " ")}. Pipeline stages see the model's own fields:`,
|
|
25
|
+
"// Json fields unshaped, no field the configuration adds.",
|
|
26
|
+
"export const configFacts = null;",
|
|
27
|
+
"",
|
|
28
|
+
"// What an adapter's discovery artifact carries on its model's type for pipeline stages' ctx and arguments:",
|
|
29
|
+
"// nothing.",
|
|
30
|
+
"export type AvConfigFacts = undefined;",
|
|
31
|
+
].join("\n")}`;
|
|
32
|
+
}
|
|
33
|
+
export function emitConfigFactsModule(configFile, facts, writers) {
|
|
34
|
+
const literal = JSON.stringify(JSON.parse(writers.canonicalJson(facts)), null, "\t");
|
|
35
|
+
return `${[
|
|
36
|
+
headerOf(configFile),
|
|
37
|
+
"",
|
|
38
|
+
"// The Json shapes and added fields the root's definitions state: per Resource, each shaped field's JSON Schema",
|
|
39
|
+
"// and each added field's Contract field. The framework compares it with the configuration at startup and warns",
|
|
40
|
+
"// when they differ.",
|
|
41
|
+
`export const configFacts = ${literal} as const;`,
|
|
42
|
+
"",
|
|
43
|
+
"// What an adapter's discovery artifact carries on its model's type for pipeline stages' ctx and arguments:",
|
|
44
|
+
"// each added field, and each shaped Json field's value type.",
|
|
45
|
+
"export type AvConfigFacts = {",
|
|
46
|
+
'\treadonly added: (typeof configFacts)["added"];',
|
|
47
|
+
`\treadonly json: ${shapeTypes(facts.json, writers.jsonSchemaType)};`,
|
|
48
|
+
"};",
|
|
49
|
+
].join("\n")}`;
|
|
50
|
+
}
|
|
@@ -8,6 +8,7 @@ function filesIn(directory) {
|
|
|
8
8
|
return {
|
|
9
9
|
resources: `${directory}/${TREE_MODULE}.ts`,
|
|
10
10
|
computedFields: `${directory}/computed-fields.generated.ts`,
|
|
11
|
+
configFacts: `${directory}/config-facts.generated.ts`,
|
|
11
12
|
contracts: `${directory}/contracts.generated.ts`,
|
|
12
13
|
};
|
|
13
14
|
}
|
|
@@ -18,13 +18,24 @@ function localNames(definitions) {
|
|
|
18
18
|
export function emitResourcesModule(projectDirectory, resourcesFile, definitions, suffix) {
|
|
19
19
|
const file = path.join(projectDirectory, resourcesFile);
|
|
20
20
|
const names = localNames(definitions);
|
|
21
|
-
const imports = definitions
|
|
21
|
+
const imports = definitions
|
|
22
|
+
.map((definition, index) => {
|
|
22
23
|
const local = names[index];
|
|
23
24
|
const imported = definition.exportName === local
|
|
24
25
|
? local
|
|
25
26
|
: `${definition.exportName} as ${local}`;
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
const specifier = relativeSpecifier(file, path.join(projectDirectory, definition.file), suffix);
|
|
28
|
+
return {
|
|
29
|
+
specifier,
|
|
30
|
+
line: `import { ${imported} } from ${JSON.stringify(specifier)};`,
|
|
31
|
+
};
|
|
32
|
+
})
|
|
33
|
+
.sort((left, right) => left.specifier < right.specifier
|
|
34
|
+
? -1
|
|
35
|
+
: left.specifier > right.specifier
|
|
36
|
+
? 1
|
|
37
|
+
: 0)
|
|
38
|
+
.map(({ line }) => line);
|
|
28
39
|
const layers = DEFINITION_LAYERS.flatMap((layer) => {
|
|
29
40
|
const spreads = definitions.flatMap((definition, index) => definition.layers.includes(layer)
|
|
30
41
|
? [`...${names[index]}.${layer}`]
|
|
@@ -36,6 +47,9 @@ export function emitResourcesModule(projectDirectory, resourcesFile, definitions
|
|
|
36
47
|
: [];
|
|
37
48
|
});
|
|
38
49
|
return `${[
|
|
50
|
+
"// biome-ignore-all format: generated output",
|
|
51
|
+
"// biome-ignore-all lint: generated output",
|
|
52
|
+
"// biome-ignore-all assist/source/organizeImports: generated output",
|
|
39
53
|
`// Generated by aventara-build from ${RESOURCES_GLOB}. Do not edit: regenerate it (aventara:prepare).`,
|
|
40
54
|
...imports,
|
|
41
55
|
"",
|
|
@@ -44,5 +58,5 @@ export function emitResourcesModule(projectDirectory, resourcesFile, definitions
|
|
|
44
58
|
"export const aventaraResources = {",
|
|
45
59
|
...layers,
|
|
46
60
|
"} as const;",
|
|
47
|
-
].join("\n")}
|
|
61
|
+
].join("\n")}`;
|
|
48
62
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aventara/build",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.15",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE",
|
|
5
5
|
"description": "Compiles an Aventara application's Contracts at build time, for serverless and edge cold starts.",
|
|
6
6
|
"type": "module",
|
|
@@ -16,18 +16,18 @@
|
|
|
16
16
|
"CHANGELOG.md"
|
|
17
17
|
],
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@aventara/client": "1.0.0-rc.
|
|
19
|
+
"@aventara/client": "1.0.0-rc.15",
|
|
20
20
|
"jiti": "2.7.0"
|
|
21
21
|
},
|
|
22
22
|
"peerDependencies": {
|
|
23
|
-
"@aventara/core": "1.0.0-rc.
|
|
23
|
+
"@aventara/core": "1.0.0-rc.15",
|
|
24
24
|
"typescript": ">=5.7.0 <7"
|
|
25
25
|
},
|
|
26
26
|
"publishConfig": {
|
|
27
27
|
"access": "public"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@aventara/core": "1.0.0-rc.
|
|
30
|
+
"@aventara/core": "1.0.0-rc.15",
|
|
31
31
|
"@types/node": "24.10.1",
|
|
32
32
|
"typescript": "^5.9.2"
|
|
33
33
|
},
|