@aventara/client 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.
Files changed (79) hide show
  1. package/README.md +44 -9
  2. package/dist/avclient.bin.js +0 -10
  3. package/dist/cli/command.parser.d.ts +15 -10
  4. package/dist/cli/command.parser.js +13 -19
  5. package/dist/cli/generate.command.js +0 -6
  6. package/dist/cli/generation-failure.renderer.js +0 -14
  7. package/dist/cli/generation-success.renderer.d.ts +4 -1
  8. package/dist/cli/generation-success.renderer.js +0 -13
  9. package/dist/cli/terminal.prompter.d.ts +1 -2
  10. package/dist/cli/warning.renderer.d.ts +2 -2
  11. package/dist/cli/warning.renderer.js +0 -8
  12. package/dist/cli.d.ts +8 -16
  13. package/dist/cli.js +5 -25
  14. package/dist/config/client-config.interface.d.ts +18 -16
  15. package/dist/config/client-config.interface.js +0 -13
  16. package/dist/config/config.loader.d.ts +34 -22
  17. package/dist/config/config.loader.js +49 -52
  18. package/dist/config/config.resolver.d.ts +13 -19
  19. package/dist/config/config.resolver.js +9 -48
  20. package/dist/config/env.cascade.d.ts +12 -14
  21. package/dist/config/env.cascade.js +0 -19
  22. package/dist/config/module-style.resolver.d.ts +52 -0
  23. package/dist/config/module-style.resolver.js +75 -0
  24. package/dist/config/tsconfig.locator.d.ts +45 -0
  25. package/dist/config/tsconfig.locator.js +52 -0
  26. package/dist/contract/contract.acceptance.d.ts +12 -26
  27. package/dist/contract/contract.acceptance.js +0 -54
  28. package/dist/contract/contract.fetcher.d.ts +12 -17
  29. package/dist/contract/contract.fetcher.js +0 -24
  30. package/dist/contract/contract.loader.d.ts +4 -5
  31. package/dist/contract/contract.loader.js +0 -10
  32. package/dist/emit/banner.emitter.d.ts +11 -12
  33. package/dist/emit/banner.emitter.js +0 -26
  34. package/dist/emit/client-surface.emitter.d.ts +17 -21
  35. package/dist/emit/client-surface.emitter.js +29 -55
  36. package/dist/emit/client-tree.emitter.d.ts +11 -20
  37. package/dist/emit/client-tree.emitter.js +12 -54
  38. package/dist/emit/contract-carrier.emitter.d.ts +5 -6
  39. package/dist/emit/contract-carrier.emitter.js +0 -28
  40. package/dist/emit/derivation.emitter.d.ts +7 -7
  41. package/dist/emit/derivation.emitter.js +2 -161
  42. package/dist/emit/descriptor.emitter.js +2 -28
  43. package/dist/emit/emitted-tree.interface.d.ts +40 -17
  44. package/dist/emit/emitted-tree.interface.js +6 -16
  45. package/dist/emit/enum.emitter.d.ts +4 -4
  46. package/dist/emit/enum.emitter.js +0 -24
  47. package/dist/emit/module-specifier.scanner.d.ts +25 -0
  48. package/dist/emit/module-specifier.scanner.js +160 -0
  49. package/dist/emit/module-style.interface.d.ts +58 -0
  50. package/dist/emit/module-style.interface.js +8 -0
  51. package/dist/emit/name.deriver.d.ts +33 -61
  52. package/dist/emit/name.deriver.js +0 -134
  53. package/dist/emit/named-type.emitter.d.ts +14 -21
  54. package/dist/emit/named-type.emitter.js +3 -30
  55. package/dist/emit/runtime.emitter.d.ts +23 -50
  56. package/dist/emit/runtime.emitter.js +68 -159
  57. package/dist/emit/scalar.codec.d.ts +20 -33
  58. package/dist/emit/scalar.codec.js +13 -69
  59. package/dist/emit/transaction.emitter.d.ts +6 -14
  60. package/dist/emit/transaction.emitter.js +24 -33
  61. package/dist/generate.d.ts +20 -34
  62. package/dist/generate.js +14 -22
  63. package/dist/index.js +0 -5
  64. package/dist/init/client-config.template.d.ts +6 -4
  65. package/dist/init/client-config.template.js +10 -13
  66. package/dist/init/client-init.errors.js +0 -3
  67. package/dist/init/client-init.orchestrator.js +8 -9
  68. package/dist/init/client-init.planner.d.ts +1 -9
  69. package/dist/init/client-init.planner.js +16 -24
  70. package/dist/init/client-init.questions.d.ts +8 -12
  71. package/dist/init/client-init.questions.js +0 -11
  72. package/dist/init/client-project.inspector.d.ts +6 -0
  73. package/dist/init/client-project.inspector.js +2 -2
  74. package/dist/node-version.guard.js +0 -12
  75. package/dist/output/output.validator.d.ts +49 -27
  76. package/dist/output/output.validator.js +113 -74
  77. package/dist/output/output.writer.d.ts +59 -52
  78. package/dist/output/output.writer.js +72 -134
  79. package/package.json +6 -4
@@ -1,36 +1,11 @@
1
1
  import { isOperationVariantAvailable, } from "@aventara/core";
2
2
  import { ownPropertyKey } from "./name.deriver.js";
3
- /**
4
- * `generated/runtime/descriptor.ts` — what the RUNTIME needs of the ClientContract,
5
- * as data (P1, P4). A projection of the same accepted contract the carrier
6
- * (`generated/contract.ts`) holds, derived in the same run, so it is not a second
7
- * source: `descriptor.emitter.spec.ts` regenerates it from the parsed carrier and
8
- * compares.
9
- *
10
- * - **The decode table (P1).** Encoding is decidable by a value's runtime class;
11
- * decoding is not — a wire `"12"` is a `string`, a `bigint` or a `decimal`
12
- * depending only on the field (M13). So per Resource the table names each
13
- * result field whose wire string is revived (`bigint`, `decimal`, `datetime`,
14
- * `bytes`, §6.2) and each relation with its target and whether it is to-many,
15
- * which the decode walk recurses into (S5 added `many`: a to-one record may
16
- * itself hold a `data` and a `count` field, so the shape alone cannot say). Every other key passes through untouched; `json` is never
17
- * revived.
18
- * - **The advertised operations (P4).** Read here through core's
19
- * `isOperationVariantAvailable`, emitted as `[resource, family, variant]`; the
20
- * type grammar reads the carrier's `operations` keys. They agree while present
21
- * ⇔ advertised (Phase 10 A3), and a gate asserts it over both pilots.
22
- *
23
- * Every registry is walked in UTF-16 code-unit order, so the key order a
24
- * contract arrives in never reaches the bytes (C-843).
25
- */
26
- /** The scalars whose wire form a decoder revives into another runtime class (§6.2). */
27
3
  const REVIVED_SCALARS = new Set([
28
4
  "bigint",
29
5
  "bytes",
30
6
  "datetime",
31
7
  "decimal",
32
8
  ]);
33
- /** `generated/runtime/descriptor.ts`, before the banner. */
34
9
  export function emitDescriptorModule(contract) {
35
10
  const resources = codeUnitOrder(Object.keys(contract.resources));
36
11
  const table = resources.map((name) => {
@@ -55,9 +30,9 @@ export function emitDescriptorModule(contract) {
55
30
  return {
56
31
  path: "runtime/descriptor.ts",
57
32
  source: "/**\n" +
58
- " * A result field the decoder revives from its wire string (§6.2), or a relation\n" +
33
+ " * A result field the decoder revives from its wire string, or a relation\n" +
59
34
  " * it recurses into, read as the relation's target Resource — `many` saying the\n" +
60
- " * value is a list, `{ data, count }` or `{ count }` rather than one record (P1).\n" +
35
+ " * value is a list, `{ data, count }` or `{ count }` rather than one record.\n" +
61
36
  " */\n" +
62
37
  "export type FieldDecoding =\n" +
63
38
  '\t| "bigint"\n' +
@@ -79,7 +54,6 @@ export function emitDescriptorModule(contract) {
79
54
  `])[] = [${advertised.length === 0 ? "" : `\n${advertised.join("")}`}];\n`,
80
55
  };
81
56
  }
82
- /** The table entry a field needs, as source, or `undefined` when it passes through. */
83
57
  function decodingOf(field) {
84
58
  if (field === undefined) {
85
59
  return undefined;
@@ -1,37 +1,58 @@
1
1
  /**
2
- * The generator's output as a VALUE before it is a filesystem effect (plan §7,
3
- * group 3). Byte-equality is therefore testable without touching disk, and
4
- * temp → validate → replace (S7) is a property of the writer alone rather than of
5
- * every emitter.
2
+ * The generator's output as a VALUE before it is a filesystem effect.
3
+ * Byte-equality is therefore testable without touching disk, and temp → validate →
4
+ * replace is a property of the writer alone rather than of every emitter.
6
5
  */
6
+ import type { ClientModuleStyle } from "./module-style.interface.js";
7
7
  /**
8
- * The output layout (architect, 2026-10-04): the consumer names a directory,
9
- * `generateAt`, which is SHARED — they may keep their own files there. The
10
- * generator owns exactly two entries in it:
8
+ * The output layout: the consumer names a directory, `generateAt`, which is SHARED
9
+ * — they may keep their own files there. The generator owns exactly two entries in
10
+ * it:
11
11
  *
12
12
  * - `AvClient.ts`, the entry point a consumer imports;
13
13
  * - `generated/`, every other module, owned and replaced whole.
14
+ *
15
+ * The tree is TypeScript source that the developer's own toolchain compiles like
16
+ * their own files — `tsc`, Next.js (Turbopack or webpack), Vite, `tsx`, Node's
17
+ * type stripping. pilot.1's tree always spelled its internal imports NodeNext's
18
+ * way (`./generated/client.js`), which a bundler that does not map `.js` back to
19
+ * `.ts` (Turbopack) and plain Node could not follow. Now those specifiers are the
20
+ * project's: extensionless, `.js` or `.ts`, as its `tsconfig.json` decides
21
+ * (`module-style.interface.ts`, Prisma 7's rules). A consumer imports the entry as
22
+ * they import their own files — `./api/AvClient`, `./api/AvClient.js` or
23
+ * `./api/AvClient.ts`.
14
24
  */
15
25
  /** The entry point, at the root of `generateAt`. */
16
26
  export declare const CLIENT_ENTRY_FILE = "AvClient.ts";
27
+ /** The files the generator owns at the root of `generateAt`. */
28
+ export declare const CLIENT_ENTRY_FILES: readonly ["AvClient.ts"];
29
+ /** One of the entry point's files. */
30
+ export type ClientEntryFile = (typeof CLIENT_ENTRY_FILES)[number];
31
+ /**
32
+ * Entry files an unreleased build of this generator wrote — JavaScript beside
33
+ * declarations, never published. Each is the generator's only while it carries
34
+ * the ownership line: a generation removes it then, so no stale `AvClient.mjs`
35
+ * is left beside the `AvClient.ts` it was replaced by. One without the line is
36
+ * the developer's file, and nothing reads, refuses on or removes it. (pilot.0's
37
+ * and pilot.1's entry is `AvClient.ts` itself, replaced in place.)
38
+ */
39
+ export declare const LEGACY_CLIENT_ENTRY_FILES: readonly string[];
17
40
  /** The directory holding every other emitted module, under `generateAt`. */
18
41
  export declare const GENERATED_DIRECTORY = "generated";
19
42
  /**
20
43
  * One of core's published declaration files, copied under `generated/derivation/`
21
- * at its path relative to core's `dist` (Q1 = A, `derivation.emitter.ts`).
44
+ * at its path relative to core's `dist`.
22
45
  */
23
46
  export type DerivationModulePath = `derivation/${string}.d.ts`;
24
47
  /**
25
- * The modules under `generated/`: the emitted sources, the carrier
26
- * (`contract.ts`, Q4), the typed surface (`client.ts`) and named types
27
- * (`types.d.ts`, S4 — a declaration file, architect 2026-10-05), and core's declarations under `derivation/`. §15.4's
28
- * `runtime/transaction.ts` and `runtime/fingerprint.ts` exist iff transactions
29
- * are interactive (S6, P3); `resources/` and `runtime/projection.ts` are not
30
- * emitted (plan §7).
31
- *
32
48
  * Relative to `generated/`, POSIX-separated.
33
49
  */
34
50
  export type GeneratedModulePath = DerivationModulePath | "client.ts" | "contract.ts" | "enums.ts" | "metadata.ts" | "runtime/codec.ts" | "runtime/decimal.ts" | "runtime/descriptor.ts" | "runtime/errors.ts" | "runtime/fingerprint.ts" | "runtime/transaction.ts" | "runtime/transport.ts" | "types.d.ts";
51
+ /**
52
+ * The carrier: the ClientContract the tree was generated against, under
53
+ * `generated/` — the module a rerun reads back to ask for a `304`.
54
+ */
55
+ export declare const CONTRACT_CARRIER_MODULE = "contract.ts";
35
56
  /** A path in the emitted tree: relative to `generateAt`, POSIX-separated. */
36
57
  export type EmittedFilePath = typeof CLIENT_ENTRY_FILE | `${typeof GENERATED_DIRECTORY}/${GeneratedModulePath}`;
37
58
  /** One module's TypeScript source under `generated/`, before the banner and before encoding. */
@@ -46,8 +67,8 @@ export interface EmittedFile {
46
67
  }
47
68
  /**
48
69
  * Every file one generation emits, in UTF-16 code-unit order of `path`, each path
49
- * once — `AvClient.ts` first, then `generated/**`. Replaced, never merged
50
- * (§15.3): `generated/` whole, `AvClient.ts` as one file.
70
+ * once — `AvClient.ts` first, then `generated/**`. Replaced, never merged:
71
+ * `generated/` whole, `AvClient.ts` as one file.
51
72
  */
52
73
  export type EmittedTree = readonly EmittedFile[];
53
74
  /**
@@ -57,5 +78,7 @@ export type EmittedTree = readonly EmittedFile[];
57
78
  */
58
79
  export interface ClientEmission {
59
80
  readonly tree: EmittedTree;
81
+ /** The project's spelling the tree was emitted in, and is validated in. */
82
+ readonly style: ClientModuleStyle;
60
83
  readonly warnings: readonly string[];
61
84
  }
@@ -1,18 +1,8 @@
1
- /**
2
- * The generator's output as a VALUE before it is a filesystem effect (plan §7,
3
- * group 3). Byte-equality is therefore testable without touching disk, and
4
- * temp → validate → replace (S7) is a property of the writer alone rather than of
5
- * every emitter.
6
- */
7
- /**
8
- * The output layout (architect, 2026-10-04): the consumer names a directory,
9
- * `generateAt`, which is SHARED — they may keep their own files there. The
10
- * generator owns exactly two entries in it:
11
- *
12
- * - `AvClient.ts`, the entry point a consumer imports;
13
- * - `generated/`, every other module, owned and replaced whole.
14
- */
15
- /** The entry point, at the root of `generateAt`. */
16
1
  export const CLIENT_ENTRY_FILE = "AvClient.ts";
17
- /** The directory holding every other emitted module, under `generateAt`. */
2
+ export const CLIENT_ENTRY_FILES = [CLIENT_ENTRY_FILE];
3
+ export const LEGACY_CLIENT_ENTRY_FILES = [
4
+ "AvClient.d.mts",
5
+ "AvClient.mjs",
6
+ ];
18
7
  export const GENERATED_DIRECTORY = "generated";
8
+ export const CONTRACT_CARRIER_MODULE = "contract.ts";
@@ -3,7 +3,7 @@ import type { EmittedModule } from "./emitted-tree.interface.js";
3
3
  import { type EmittedNames } from "./name.deriver.js";
4
4
  /**
5
5
  * `enums.ts`: per enum, a string-literal union type and a same-named `as const`
6
- * object (§15.4's "enum types"; architect decision, 2026-10-04):
6
+ * object:
7
7
  *
8
8
  * ```ts
9
9
  * export type Role = "ADMIN" | "USER";
@@ -17,8 +17,8 @@ import { type EmittedNames } from "./name.deriver.js";
17
17
  * renamed.
18
18
  *
19
19
  * Enums come in the order `names` gives them — UTF-16 code units of the contract
20
- * name — so the key order a contract arrives in never reaches the bytes (C-843).
21
- * An enum's VALUES keep their declared order, in the type and in the object: that
22
- * order is meaning, and canonical form keeps it too.
20
+ * name — so the key order a contract arrives in never reaches the bytes. An enum's
21
+ * VALUES keep their declared order, in the type and in the object: that order is
22
+ * meaning, and canonical form keeps it too.
23
23
  */
24
24
  export declare function emitEnumsModule(contract: Pick<ClientContract, "enums">, names: EmittedNames): EmittedModule;
@@ -1,24 +1,4 @@
1
1
  import { ownPropertyKey } from "./name.deriver.js";
2
- /**
3
- * `enums.ts`: per enum, a string-literal union type and a same-named `as const`
4
- * object (§15.4's "enum types"; architect decision, 2026-10-04):
5
- *
6
- * ```ts
7
- * export type Role = "ADMIN" | "USER";
8
- * export const Role = { ADMIN: "ADMIN", USER: "USER" } as const;
9
- * ```
10
- *
11
- * The type is what every later emitter references; the object gives a consumer a
12
- * value to name a member by and to enumerate. Both are declared under the enum's
13
- * emitted identifier, which differs from its contract name only when the name was
14
- * renamed (`name.deriver.ts`). The values are the wire values and are never
15
- * renamed.
16
- *
17
- * Enums come in the order `names` gives them — UTF-16 code units of the contract
18
- * name — so the key order a contract arrives in never reaches the bytes (C-843).
19
- * An enum's VALUES keep their declared order, in the type and in the object: that
20
- * order is meaning, and canonical form keeps it too.
21
- */
22
2
  export function emitEnumsModule(contract, names) {
23
3
  const declarations = names.enums.map(({ contractName, identifier }) => {
24
4
  const values = contract.enums[contractName]?.values ?? [];
@@ -33,10 +13,6 @@ export function emitEnumsModule(contract, names) {
33
13
  });
34
14
  return {
35
15
  path: "enums.ts",
36
- // Without an import or export, a consumer whose config treats such a file
37
- // as a script (`moduleResolution: "bundler"` outside a `"type": "module"`
38
- // package, measured) fails `AvClient.ts`'s `export *` with TS2306 — so a
39
- // contract without enums still emits a module.
40
16
  source: declarations.length === 0 ? "export {};\n" : declarations.join("\n"),
41
17
  };
42
18
  }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Which modules a file names, read without `typescript`: the derivation's copy
3
+ * walks core's declaration closure by it (`derivation.emitter.ts`), and the output
4
+ * validator checks by it that every module the emitted tree names is a file of the
5
+ * tree, spelled the project's way — with or without a compiler.
6
+ */
7
+ export interface ScannedModule {
8
+ /**
9
+ * Every module specifier: a `from` clause's, a side-effect `import`'s, and an
10
+ * `import()` type query's.
11
+ */
12
+ readonly specifiers: readonly string[];
13
+ /** Whether the file carries a `/// <reference …/>` directive. */
14
+ readonly references: boolean;
15
+ }
16
+ /**
17
+ * The specifiers one module names — a declaration file or JavaScript — read by a
18
+ * small lexer rather than by `typescript` (an optional peer, absent from a
19
+ * consumer's install): comments, string literals, template literals and
20
+ * regular-expression literals are skipped as units, so text inside them is never
21
+ * mistaken for an import. Agrees with TypeScript's own pre-processor over core's
22
+ * closure (`derivation.emitter.spec.ts`) and over every emitted file
23
+ * (`module-specifier.scanner.spec.ts`).
24
+ */
25
+ export declare function scanModuleSpecifiers(text: string): ScannedModule;
@@ -0,0 +1,160 @@
1
+ const SPECIFIER_KEYWORD = /^(?:from|import)$/;
2
+ const EXPRESSION_KEYWORDS = new Set([
3
+ "case",
4
+ "delete",
5
+ "do",
6
+ "else",
7
+ "in",
8
+ "instanceof",
9
+ "new",
10
+ "of",
11
+ "return",
12
+ "throw",
13
+ "typeof",
14
+ "void",
15
+ "yield",
16
+ ]);
17
+ export function scanModuleSpecifiers(text) {
18
+ const tokens = [];
19
+ let references = false;
20
+ let index = 0;
21
+ const readQuoted = (quote) => {
22
+ let value = "";
23
+ index += 1;
24
+ while (index < text.length && text[index] !== quote) {
25
+ if (text[index] === "\\") {
26
+ value += text[index + 1] ?? "";
27
+ index += 2;
28
+ continue;
29
+ }
30
+ value += text[index];
31
+ index += 1;
32
+ }
33
+ index += 1;
34
+ return value;
35
+ };
36
+ const scanCode = (inPlaceholder) => {
37
+ let depth = 0;
38
+ while (index < text.length) {
39
+ const character = text[index];
40
+ const next = text[index + 1];
41
+ if (character === "/" && next === "/") {
42
+ const end = text.indexOf("\n", index);
43
+ const line = text.slice(index, end === -1 ? text.length : end);
44
+ if (/^\/\/\/\s*<reference\b/.test(line)) {
45
+ references = true;
46
+ }
47
+ index = end === -1 ? text.length : end + 1;
48
+ }
49
+ else if (character === "/" && next === "*") {
50
+ const end = text.indexOf("*/", index + 2);
51
+ index = end === -1 ? text.length : end + 2;
52
+ }
53
+ else if (character === "/" && opensRegularExpression(tokens.at(-1))) {
54
+ skipRegularExpression();
55
+ }
56
+ else if (character === '"' || character === "'") {
57
+ tokens.push({ kind: "string", value: readQuoted(character) });
58
+ }
59
+ else if (character === "`") {
60
+ scanTemplate();
61
+ }
62
+ else if (/[A-Za-z_$]/.test(character)) {
63
+ const start = index;
64
+ while (index < text.length && /[\w$]/.test(text[index])) {
65
+ index += 1;
66
+ }
67
+ tokens.push({ kind: "word", value: text.slice(start, index) });
68
+ }
69
+ else if (/\s/.test(character)) {
70
+ index += 1;
71
+ }
72
+ else {
73
+ if (inPlaceholder && character === "{") {
74
+ depth += 1;
75
+ }
76
+ else if (inPlaceholder && character === "}") {
77
+ if (depth === 0) {
78
+ index += 1;
79
+ return;
80
+ }
81
+ depth -= 1;
82
+ }
83
+ tokens.push({ kind: "punctuation", value: character });
84
+ index += 1;
85
+ }
86
+ }
87
+ };
88
+ const skipRegularExpression = () => {
89
+ index += 1;
90
+ let inClass = false;
91
+ while (index < text.length && text[index] !== "\n") {
92
+ const character = text[index];
93
+ if (character === "\\") {
94
+ index += 2;
95
+ continue;
96
+ }
97
+ index += 1;
98
+ if (character === "[") {
99
+ inClass = true;
100
+ }
101
+ else if (character === "]") {
102
+ inClass = false;
103
+ }
104
+ else if (character === "/" && !inClass) {
105
+ break;
106
+ }
107
+ }
108
+ while (index < text.length && /[a-z]/.test(text[index])) {
109
+ index += 1;
110
+ }
111
+ tokens.push({ kind: "punctuation", value: "/" });
112
+ };
113
+ const scanTemplate = () => {
114
+ index += 1;
115
+ while (index < text.length && text[index] !== "`") {
116
+ if (text[index] === "\\") {
117
+ index += 2;
118
+ }
119
+ else if (text[index] === "$" && text[index + 1] === "{") {
120
+ index += 2;
121
+ scanCode(true);
122
+ }
123
+ else {
124
+ index += 1;
125
+ }
126
+ }
127
+ index += 1;
128
+ tokens.push({ kind: "punctuation", value: "`" });
129
+ };
130
+ scanCode(false);
131
+ const specifiers = [];
132
+ tokens.forEach((token, at) => {
133
+ const following = tokens[at + 1];
134
+ if (token.kind !== "word") {
135
+ return;
136
+ }
137
+ if (SPECIFIER_KEYWORD.test(token.value) && following?.kind === "string") {
138
+ specifiers.push(following.value);
139
+ }
140
+ else if (token.value === "import" &&
141
+ following?.kind === "punctuation" &&
142
+ following.value === "(" &&
143
+ tokens[at + 2]?.kind === "string") {
144
+ specifiers.push(tokens[at + 2].value);
145
+ }
146
+ });
147
+ return { specifiers, references };
148
+ }
149
+ function opensRegularExpression(previous) {
150
+ if (previous === undefined) {
151
+ return true;
152
+ }
153
+ if (previous.kind === "word") {
154
+ return EXPRESSION_KEYWORDS.has(previous.value);
155
+ }
156
+ return (previous.kind === "punctuation" &&
157
+ previous.value !== ")" &&
158
+ previous.value !== "]" &&
159
+ previous.value !== "`");
160
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * How the generated client's modules are spelled for the project that compiles
3
+ * them. The client is TypeScript source — `.ts` files — and the developer's own
4
+ * toolchain compiles it like their own files, so the relative specifiers by which
5
+ * its modules name each other, and the module format they are checked in, follow
6
+ * that project's rules. The names and the rules are Prisma 7's `prisma-client`
7
+ * generator's (`importFileExtension`, `moduleFormat`), inferred from the project's
8
+ * `tsconfig.json` (`config/module-style.resolver.ts`).
9
+ */
10
+ /**
11
+ * The extension a relative import inside the generated client is written with:
12
+ *
13
+ * - `""` — extensionless, `./generated/client`: a bundler (`moduleResolution:
14
+ * "bundler"`) or CommonJS (`module: "commonjs"`) project, where the developer's
15
+ * own imports carry none;
16
+ * - `"js"` — `./generated/client.js`: Node's ES module resolution
17
+ * (`node16`/`nodenext`), where the import names the file `tsc` will emit;
18
+ * - `"ts"` — `./generated/client.ts`: a project that imports TypeScript files by
19
+ * their own name (`allowImportingTsExtensions`, `rewriteRelativeImportExtensions`)
20
+ * — Node's type stripping, Deno, Bun.
21
+ *
22
+ * Prisma's list is wider (`mts`, `cts`, `mjs`, `cjs`): those pair with a
23
+ * generated `.mts` or `.cts`, and this generator emits `.ts` only.
24
+ */
25
+ export type ImportFileExtension = "" | "js" | "ts";
26
+ /**
27
+ * The module format the project compiles the generated `.ts` files to: what
28
+ * its `tsconfig.json` says (`module`), or, under `node16`/`nodenext`, what the
29
+ * nearest `package.json`'s `"type"` says. The emitted bytes are the same in
30
+ * either — they use no construct one format lacks — but the output validator
31
+ * type-checks them in this one, as the project will.
32
+ */
33
+ export type ModuleFormat = "esm" | "cjs";
34
+ /** One project's spelling of the generated client, resolved once per run. */
35
+ export interface ClientModuleStyle {
36
+ readonly importFileExtension: ImportFileExtension;
37
+ readonly moduleFormat: ModuleFormat;
38
+ }
39
+ /**
40
+ * A relative module path without an extension — `./contract`,
41
+ * `../metadata`, `./derivation/operations/operation-call` — as an emitter names
42
+ * the module it imports.
43
+ */
44
+ export type ExtensionlessModulePath = `./${string}` | `../${string}`;
45
+ /**
46
+ * The specifier a generated module imports `module` by, in this style. One rule
47
+ * for every target, `.ts` source and `.d.ts` declaration alike: TypeScript
48
+ * resolves an extensionless, a `.js` and a `.ts` specifier to either (measured
49
+ * under `nodenext` and `bundler`, TypeScript 5.9, 6 and 7).
50
+ */
51
+ export declare function importSpecifier(module: ExtensionlessModulePath, style: Pick<ClientModuleStyle, "importFileExtension">): string;
52
+ /**
53
+ * Writes the quoted specifier an emitted `import`/`export … from` names a
54
+ * module by: `importSpecifier`, as a string literal of the generated source.
55
+ */
56
+ export type ModuleSpecifierWriter = (module: ExtensionlessModulePath) => string;
57
+ /** The {@link ModuleSpecifierWriter} of one style. */
58
+ export declare function moduleSpecifierWriter(style: Pick<ClientModuleStyle, "importFileExtension">): ModuleSpecifierWriter;
@@ -0,0 +1,8 @@
1
+ export function importSpecifier(module, style) {
2
+ return style.importFileExtension === ""
3
+ ? module
4
+ : `${module}.${style.importFileExtension}`;
5
+ }
6
+ export function moduleSpecifierWriter(style) {
7
+ return (module) => JSON.stringify(importSpecifier(module, style));
8
+ }
@@ -2,15 +2,10 @@ import { type ClientContract, type OperationFamily } from "@aventara/core";
2
2
  /**
3
3
  * Name derivation and the rename ladder for the emitted tree.
4
4
  *
5
- * # Renamed, not refused (architect decision, 2026-10-04)
6
- *
7
- * S4 shipped "verbatim, or refused — never renamed". The architect overturned it:
8
- * a Contract name the emitted TypeScript cannot declare as-is is RENAMED, and the
9
- * rename is the TypeScript identifier's alone. The name the server uses — the
10
- * wire name a Resource is addressed by — is kept beside it unchanged
11
- * (`EmittedName.contractName`), so a later emitter that sends a request reads that,
12
- * never the identifier. Every rename is one warning line on the result; generation
13
- * does not print.
5
+ * The name the server uses — the wire name a Resource is addressed by — is kept
6
+ * beside it unchanged (`EmittedName.contractName`), so a later emitter that sends
7
+ * a request reads that, never the identifier. Every rename is one warning line on
8
+ * the result; generation does not print.
14
9
  *
15
10
  * A name is unusable as-is when it is not an identifier, is a reserved word, is a
16
11
  * predefined type's name, is a name the generated runtime owns, or — an enum only
@@ -20,66 +15,44 @@ import { type ClientContract, type OperationFamily } from "@aventara/core";
20
15
  * - Resource `X`: `XModel` → `ResourceX` → `X_` → `_X` → `_X_` → refused;
21
16
  * - enum `X`: `XEnum` → `EnumX` → `X_` → refused.
22
17
  *
23
- * Only a name whose whole ladder is unusable or taken is refused, in one sentence —
24
- * and a name no rename can repair, which is refused without trying a rung: the
18
+ * Only a name whose whole ladder is unusable or taken is refused, in one sentence
19
+ * — and a name no rename can repair, which is refused without trying a rung: the
25
20
  * empty name. Every rung of its ladder is a bare affix (`Model`, `Enum`, `_`) that
26
21
  * names nothing on the server, so "renaming" it would invent an identifier rather
27
- * than repair one (architect's rule, 2026-10-04: refuse when unrepairable).
22
+ * than repair one.
28
23
  *
29
24
  * # Determinism
30
25
  *
31
26
  * The same Contract always yields the same names, whatever order its keys arrive
32
- * in: every name usable as-is is claimed first (so a usable name is never displaced
33
- * by another's rename), then Resources are renamed, then enums, each registry in
34
- * UTF-16 code-unit order of its contract names. An enum sharing a Resource's name
35
- * walks its ladder and the Resource keeps the name.
27
+ * in: every name usable as-is is claimed first (so a usable name is never
28
+ * displaced by another's rename), then Resources are renamed, then enums, each
29
+ * registry in UTF-16 code-unit order of its contract names. An enum sharing a
30
+ * Resource's name walks its ladder and the Resource keeps the name.
36
31
  *
37
32
  * # One namespace
38
33
  *
39
- * Enum and Resource identifiers share the generated client's root namespace with
40
- * each other and with the runtime's own exports. §15.6 names a Resource's type by
41
- * the Resource's name (`Spell`), so that namespace is claimed now, before the
42
- * Resource types are emitted. Names are case-sensitive.
43
- *
44
- * # Derived names (Phase 12-rest Q10; the ladder rule, a plan ruling)
45
- *
46
- * §15.6 derives named types from a Resource (`SpellWhere`, `SpellOrderBy`, …;
47
- * {@link RESOURCE_NAMED_TYPES}), each only when the operation it reads is
48
- * advertised. A Resource's base name is taken at the first rung — its own name
49
- * first, when usable — where the base AND every name derived from it are free of
50
- * every other emitted name: `User` beside a Resource `UserWhere` walks to
51
- * `UserModel`, one warning. Derived names a Resource claims are claimed for good,
52
- * so a later Resource or enum never takes one. The generated modules that declare
53
- * these names use no global type a Resource could shadow (`types.d.ts` imports two
54
- * helpers, which are reserved).
34
+ * Names are case-sensitive.
55
35
  *
56
- * # Properties (Phase 12-rest Q12)
36
+ * A Resource's base name is taken at the first rung — its own name first, when
37
+ * usable — where the base AND every name derived from it are free of every other
38
+ * emitted name: `User` beside a Resource `UserWhere` walks to `UserModel`, one
39
+ * warning. Derived names a Resource claims are claimed for good, so a later
40
+ * Resource or enum never takes one. The generated modules that declare these names
41
+ * use no global type a Resource could shadow (`types.d.ts` imports two helpers,
42
+ * which are reserved).
57
43
  *
58
- * A Resource is reached as a property of the client, named by its contract name.
59
- * A contract name equal to one of the client's own members
60
- * ({@link CLIENT_MEMBER_NAMES}) walks the Resource ladder for its PROPERTY only,
61
- * one warning; the wire name, and the TypeScript type names, are unaffected.
44
+ * A Resource is reached as a property of the client, named by its contract name. A
45
+ * contract name equal to one of the client's own members ({@link
46
+ * CLIENT_MEMBER_NAMES}) walks the Resource ladder for its PROPERTY only, one
47
+ * warning; the wire name, and the TypeScript type names, are unaffected.
62
48
  *
63
49
  * Reads registry KEYS and which operations are advertised. No capability member.
64
50
  */
65
51
  /**
66
- * The names the generated client declares in the root namespace: those §15.4
67
- * and §13.4 give it, under the architect's names (Phase 12-rest Q7–Q9) — the
68
- * `avClient` singleton, `AvClient`, `AvClientOptions`, `CallOptions`, `Fetch`,
69
- * `Decimal`, `FrameworkError`, `NotFoundError`, `TransportError`,
70
- * `OperationCode`/`ValidationCode` and `Operation<T>`, plus `Cause` and
71
- * `ValidationIssue` (public by the architect's decision of 2026-10-04) — every
72
- * `FrameworkError` subclass Q2 adds, read from the runtime emitter that declares
73
- * them, and the two helpers `types.d.ts` imports to declare the named types
74
- * (`ResourceArgument`, `ResourceRecord`). A Contract name equal to one of them
75
- * walks its rename ladder. In UTF-16 code-unit order.
52
+ * A Contract name equal to one of them walks its rename ladder. In UTF-16
53
+ * code-unit order.
76
54
  */
77
55
  export declare const RESERVED_EMITTED_NAMES: readonly string[];
78
- /**
79
- * One of §15.6's named Resource types (Q10 = a): the suffix it adds to the
80
- * Resource's name, the operation it reads — it exists only when that operation is
81
- * advertised — and the argument it names, or none for the default record.
82
- */
83
56
  export interface ResourceNamedType {
84
57
  readonly suffix: string;
85
58
  readonly family: OperationFamily;
@@ -87,18 +60,17 @@ export interface ResourceNamedType {
87
60
  /** The argument it names; absent for `X`, the default record. */
88
61
  readonly argument?: "where" | "orderBy" | "data" | "select" | "include";
89
62
  }
90
- /** §15.6's set exactly (Q10 = a), in §15.6's order. */
91
63
  export declare const RESOURCE_NAMED_TYPES: readonly ResourceNamedType[];
92
64
  /** The named types a Resource with `operations` gets: those whose operation it advertises. */
93
65
  export declare function namedTypesOf(operations: unknown): readonly ResourceNamedType[];
94
66
  /**
95
- * The client's own members, which a Resource property must not shadow (Q12):
96
- * `tx` and `transaction` (reserved whether or not the contract advertises
97
- * transactions, so a property never moves with `transactions`), `then` — a client
98
- * with a `then` is a thenable, and `await` would call it — and every name
99
- * `Object.prototype` carries in ES2022, `constructor` among them. Fixed here, not
100
- * read from the running Node, so the output never moves with the generator's
101
- * runtime. In UTF-16 code-unit order.
67
+ * The client's own members, which a Resource property must not shadow: `tx` and
68
+ * `transaction` (reserved whether or not the contract advertises transactions, so
69
+ * a property never moves with `transactions`), `then` — a client with a `then` is
70
+ * a thenable, and `await` would call it — and every name `Object.prototype`
71
+ * carries in ES2022, `constructor` among them. Fixed here, not read from the
72
+ * running Node, so the output never moves with the generator's runtime. In UTF-16
73
+ * code-unit order.
102
74
  */
103
75
  export declare const CLIENT_MEMBER_NAMES: readonly string[];
104
76
  /** One Contract name and the TypeScript identifier the tree declares it under. */
@@ -108,7 +80,7 @@ export interface EmittedName {
108
80
  /** The identifier the emitted TypeScript declares; `contractName` unless renamed. */
109
81
  readonly identifier: string;
110
82
  }
111
- /** A Resource's property on the client: its contract name unless a member owns it (Q12). */
83
+ /** A Resource's property on the client: its contract name unless a member owns it. */
112
84
  export interface EmittedProperty {
113
85
  /** The name the server uses. Never renamed. */
114
86
  readonly contractName: string;