@sjcx/vorma 0.0.0-pre.0 → 0.0.0-pre.1

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/dist/build/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { C as toContentDigest, S as encodeCanonicalJson, _ as compileServerApplication, a as acquireOutputOwnership, b as getClientViewEntries, c as writeAndCheckApplicationGeneration, d as withTypescriptProjects, f as inspectProjects, g as createClientPublicUrlPlugin, h as createCssPublicAssets, i as publishApplicationArtifacts, l as collectPublicAssets, m as resolveVormaConfig, n as loadApplicationSourceLayout, o as checkOutputPath, p as getGeneratedSourceDirectories, r as preparePublicOutput, s as assembleApplicationGeneration, t as buildApplication, u as readTypescriptProjectRoots, v as containsRelativePath, x as projectBrowserContracts, y as CLIENT_SHARED_PACKAGES } from "../build-JgARonaY.js";
2
+ import { C as encodeCanonicalJson, S as projectBrowserContracts, _ as createClientPublicUrlPlugin, a as acquireOutputOwnership, b as CLIENT_SHARED_PACKAGES, c as writeAndCheckApplicationGeneration, d as readTypescriptProjectRoots, f as runTypescriptOperation, g as createCssPublicAssets, h as resolveVormaConfig, i as publishApplicationArtifacts, l as collectPublicAssets, m as getGeneratedSourceDirectories, n as loadApplicationSourceLayout, o as checkOutputPath, p as withTypescriptProjects, r as preparePublicOutput, s as assembleApplicationGeneration, t as buildApplication, u as inspectProjects, v as compileServerApplication, w as toContentDigest, x as getClientViewEntries, y as containsRelativePath } from "../build-DcP5_DUV.js";
3
3
  import { g as DEVELOPMENT_PROTOCOL, y as FRAMEWORK_IDENTITY_PROTOCOL } from "../value-transport-Bst4Hk-n.js";
4
4
  import { t as VORMA_BUILD_PLUGIN_NAME } from "../build-invocation-D7Fu8gBK.js";
5
5
  import { VormaConfigSchema } from "../server/config/index.js";
@@ -510,22 +510,13 @@ function inspectDevelopmentSources(layout) {
510
510
  projects,
511
511
  layout
512
512
  });
513
- const sources = yield* Effect.try({
514
- try: () => {
515
- return {
516
- serverRootFiles: new Set(projects.server.rootFiles.map(normalizePath)),
517
- clientRootFiles: new Set(projects.client.rootFiles.map(normalizePath)),
518
- serverFiles: new Set(projects.server.program.getSourceFileNames().map(normalizePath)),
519
- clientFiles: new Set(projects.client.program.getSourceFileNames().map(normalizePath))
520
- };
521
- },
522
- catch: (cause) => {
523
- return {
524
- _tag: "TypescriptProjectError",
525
- message: "Could not read TypeScript development inputs",
526
- cause
527
- };
528
- }
513
+ const sources = yield* runTypescriptOperation(async () => {
514
+ return {
515
+ serverRootFiles: new Set(projects.server.rootFiles.map(normalizePath)),
516
+ clientRootFiles: new Set(projects.client.rootFiles.map(normalizePath)),
517
+ serverFiles: new Set((await projects.server.program.getSourceFileNames()).map(normalizePath)),
518
+ clientFiles: new Set((await projects.client.program.getSourceFileNames()).map(normalizePath))
519
+ };
529
520
  });
530
521
  return {
531
522
  inspection,
@@ -1,6 +1,5 @@
1
1
  import { Effect, Path } from "effect";
2
2
  import type { ApplicationSourceLayout } from "./source-layout.ts";
3
- import { type TypescriptProjectError } from "./typescript-projects.ts";
4
3
  export type DevelopmentSourceInputs = {
5
4
  readonly serverFiles: ReadonlySet<string>;
6
5
  readonly clientFiles: ReadonlySet<string>;
@@ -15,7 +14,7 @@ export type DevelopmentSourceInputs = {
15
14
  export declare function inspectDevelopmentSources(layout: ApplicationSourceLayout): Effect.Effect<{
16
15
  inspection: import("./inspect-projects.ts").InspectedProjects;
17
16
  inputs: DevelopmentSourceInputs;
18
- }, import("./inspect-projects.ts").InspectionIssue | TypescriptProjectError, Path.Path>;
17
+ }, import("./inspect-projects.ts").InspectionIssue | import("./typescript-projects.ts").TypescriptProjectError, Path.Path>;
19
18
  /** Watches native compiler inputs while keeping generated writes out of the event stream. */
20
19
  export declare function getDevelopmentSourceWatchPaths(input: {
21
20
  readonly layout: ApplicationSourceLayout;
@@ -1,2 +1,2 @@
1
- import { t as buildApplication } from "../build-JgARonaY.js";
1
+ import { t as buildApplication } from "../build-DcP5_DUV.js";
2
2
  export { buildApplication };
@@ -3,7 +3,7 @@ import * as Path from "effect/Path";
3
3
  import type { HttpMethod, InputTransport } from "../server/graph/declarations.ts";
4
4
  import type { EffectTransportMarkKind } from "../universal/value-transport.ts";
5
5
  import type { ApplicationSourceLayout } from "./source-layout.ts";
6
- import type { TypescriptProjects } from "./typescript-projects.ts";
6
+ import { type TypescriptProjectError, type TypescriptProjects } from "./typescript-projects.ts";
7
7
  export type DeclarationSource = {
8
8
  readonly filePath: string;
9
9
  readonly exportName: string;
@@ -66,4 +66,4 @@ export type InspectionIssue = {
66
66
  export declare function inspectProjects(input: {
67
67
  readonly projects: TypescriptProjects;
68
68
  readonly layout: ApplicationSourceLayout;
69
- }): Effect.Effect<InspectedProjects, InspectionIssue, Path.Path>;
69
+ }): Effect.Effect<InspectedProjects, InspectionIssue | TypescriptProjectError, Path.Path>;
@@ -1,5 +1,5 @@
1
1
  import { Result } from "effect";
2
- import { type Checker, type Emitter, type Program, type Symbol as TypeSymbol, type Type } from "typescript/unstable/sync";
2
+ import { type Checker, type Emitter, type Program, type Symbol as TypeSymbol, type Type } from "typescript/unstable/async";
3
3
  import type { EffectTransportMarkKind } from "../universal/value-transport.ts";
4
4
  export type TypeRenderIssue = {
5
5
  readonly _tag: "UnrenderableContractType";
@@ -11,7 +11,7 @@ export type TypeRenderer = {
11
11
  readonly renderType: (input: {
12
12
  readonly type: Type;
13
13
  readonly depth: number;
14
- }) => Result.Result<string, TypeRenderIssue>;
14
+ }) => Promise<Result.Result<string, TypeRenderIssue>>;
15
15
  /** The alias declarations that rendering needed, each at depth zero. */
16
16
  readonly renderAliases: () => ReadonlyArray<string>;
17
17
  /** The Effect modules that rendered text names, for the generated file's type imports. */
@@ -23,9 +23,9 @@ export type TypeRenderer = {
23
23
  export declare function matchesLibrarySymbol(input: {
24
24
  readonly program: Program;
25
25
  readonly symbol: TypeSymbol;
26
- }): boolean;
26
+ }): Promise<boolean>;
27
27
  export declare function createTypeRenderer(input: {
28
28
  readonly checker: Checker;
29
29
  readonly program: Program;
30
30
  readonly emitter: Emitter;
31
- }): TypeRenderer;
31
+ }): Promise<TypeRenderer>;
@@ -1,5 +1,5 @@
1
1
  import { Effect } from "effect";
2
- import { type APIOptions, type Project } from "typescript/unstable/sync";
2
+ import { type APIOptions, type Project } from "typescript/unstable/async";
3
3
  export type TypescriptProjectError = {
4
4
  readonly _tag: "TypescriptProjectError";
5
5
  readonly message: string;
@@ -34,3 +34,5 @@ export declare function withTypescriptProjects<A, E, R>(input: {
34
34
  readonly fileSystem?: APIOptions["fs"];
35
35
  readonly useFn: (projects: TypescriptProjects) => Effect.Effect<A, E, R>;
36
36
  }): Effect.Effect<A, E | TypescriptProjectError, R>;
37
+ /** Native compiler operations have no cancellation API; settle each operation before its session can close. */
38
+ export declare function runTypescriptOperation<Value>(fn: () => Promise<Value>): Effect.Effect<Value, TypescriptProjectError, never>;
@@ -12,7 +12,7 @@ import { RolldownMagicString, build as build$1 } from "rolldown";
12
12
  import { readFile } from "node:fs/promises";
13
13
  import * as Path$1 from "effect/Path";
14
14
  import { SyntaxKind, TokenFlags, isAsExpression, isCallExpression, isElementAccessExpression, isExportSpecifier, isIdentifier, isImportClause, isImportSpecifier, isNamespaceImport, isNoSubstitutionTemplateLiteral, isNonNullExpression, isParenthesizedExpression, isPropertyAccessExpression, isSatisfiesExpression, isStringLiteral, isTypeAssertion, isTypeNode } from "typescript/unstable/ast";
15
- import { API, ElementFlags, SignatureKind, SymbolFlags } from "typescript/unstable/sync";
15
+ import { API, ElementFlags, SignatureKind, SymbolFlags } from "typescript/unstable/async";
16
16
  import { createTemplateHead, createTemplateMiddle, createTemplateTail } from "typescript/unstable/ast/factory";
17
17
  import * as FileSystem$1 from "effect/FileSystem";
18
18
  import { pid, platform } from "node:process";
@@ -455,8 +455,8 @@ function toRelativeSpecifier(relativePath) {
455
455
  //#endregion
456
456
  //#region src/build/render-types.ts
457
457
  /** Removes the checker's missing-value marker, which is distinct from the ordinary `undefined` type. */
458
- function withoutAbsence(input) {
459
- const members = input.type.isUnionType() ? input.type.getTypes() : [input.type];
458
+ async function withoutAbsence(input) {
459
+ const members = input.type.isUnionType() ? await input.type.getTypes() : [input.type];
460
460
  const present = members.filter((member) => {
461
461
  return !(member.isIntrinsicType() && member.intrinsicName === "undefined" && member.id !== input.undefinedType.id);
462
462
  });
@@ -543,26 +543,26 @@ function sortProperties(properties) {
543
543
  });
544
544
  }
545
545
  /** True when a symbol is declared outside the application: in a default library or an installed package. */
546
- function matchesLibrarySymbol(input) {
546
+ async function matchesLibrarySymbol(input) {
547
547
  const declaration = input.symbol.declarations[0];
548
548
  if (declaration === void 0) return false;
549
549
  const declarationPath = String(declaration.path);
550
- const metadata = input.program.getSourceFileMetadata(declarationPath);
550
+ const metadata = await input.program.getSourceFileMetadata(declarationPath);
551
551
  return metadata !== void 0 && (metadata.isDefaultLibrary || metadata.isFromExternalLibrary || declarationPath.includes("/node_modules/"));
552
552
  }
553
- function createTypeRenderer(input) {
553
+ async function createTypeRenderer(input) {
554
554
  const { checker, program, emitter } = input;
555
- const undefinedType = checker.getUndefinedType();
555
+ const undefinedType = await checker.getUndefinedType();
556
556
  const aliases = /* @__PURE__ */ new Map();
557
557
  const rendered = [];
558
558
  const visiting = /* @__PURE__ */ new Set();
559
559
  const effectModules = /* @__PURE__ */ new Set();
560
560
  const transportTypeNames = /* @__PURE__ */ new Set();
561
- function fail(type, reason) {
561
+ async function fail(type, reason) {
562
562
  return Result.fail({
563
563
  _tag: "UnrenderableContractType",
564
564
  reason,
565
- typeText: checker.typeToString(type)
565
+ typeText: await checker.typeToString(type)
566
566
  });
567
567
  }
568
568
  function getDeclarationPath(symbol) {
@@ -576,72 +576,72 @@ function createTypeRenderer(input) {
576
576
  return entry.symbolName === symbol.name && declarationPath.endsWith(`/effect/dist/${entry.module}.d.ts`);
577
577
  });
578
578
  }
579
- function matchesReadonlyProperty(property) {
579
+ async function matchesReadonlyProperty(property) {
580
580
  if ((property.checkFlags & CHECK_FLAG_READONLY) !== 0) return true;
581
- const declaration = property.valueDeclaration?.resolve();
581
+ const declaration = await property.valueDeclaration?.resolve();
582
582
  if (declaration === void 0) return false;
583
583
  const modifiers = declaration.modifiers;
584
584
  return modifiers !== void 0 && modifiers.some((modifier) => {
585
585
  return modifier.kind === SyntaxKind.ReadonlyKeyword;
586
586
  });
587
587
  }
588
- function renderTypeArguments(type, depth) {
588
+ async function renderTypeArguments(type, depth) {
589
589
  const parts = [];
590
- for (const argument of checker.getTypeArguments(type)) {
591
- const text = renderNode(argument, depth);
590
+ for (const argument of await checker.getTypeArguments(type)) {
591
+ const text = await renderNode(argument, depth);
592
592
  if (Result.isFailure(text)) return text;
593
593
  parts.push(text.success);
594
594
  }
595
595
  return Result.succeed(parts.length === 0 ? "" : `<${parts.join(", ")}>`);
596
596
  }
597
- function renderNamedType(type, depth) {
598
- const aliasSymbol = type.getAliasSymbol();
599
- const symbol = type.getSymbol();
597
+ async function renderNamedType(type, depth) {
598
+ const aliasSymbol = await type.getAliasSymbol();
599
+ const symbol = await type.getSymbol();
600
600
  for (const candidate of [aliasSymbol, symbol]) {
601
601
  if (candidate === void 0) continue;
602
602
  const effectType = matchesEffectType(candidate);
603
603
  if (effectType !== void 0) {
604
604
  effectModules.add(effectType.module);
605
605
  transportTypeNames.add(effectType.kind);
606
- const argumentTypes = candidate === aliasSymbol ? type.getAliasTypeArguments() : type.isTypeReference() ? checker.getTypeArguments(type) : [];
606
+ const argumentTypes = candidate === aliasSymbol ? await type.getAliasTypeArguments() : type.isTypeReference() ? await checker.getTypeArguments(type) : [];
607
607
  const parts = [];
608
608
  for (const argument of argumentTypes) {
609
- const text = renderNode(argument, depth);
609
+ const text = await renderNode(argument, depth);
610
610
  if (Result.isFailure(text)) return text;
611
611
  parts.push(text.success);
612
612
  }
613
613
  return Result.succeed(parts.length === 0 ? effectType.printedName : `${effectType.printedName}<${parts.join(", ")}>`);
614
614
  }
615
615
  }
616
- if (symbol !== void 0 && PLATFORM_TYPE_NAMES.has(symbol.name) && matchesLibrarySymbol({
616
+ if (symbol !== void 0 && PLATFORM_TYPE_NAMES.has(symbol.name) && await matchesLibrarySymbol({
617
617
  program,
618
618
  symbol
619
619
  })) {
620
- const argumentsText = type.isTypeReference() ? renderTypeArguments(type, depth) : Result.succeed("");
620
+ const argumentsText = type.isTypeReference() ? await renderTypeArguments(type, depth) : Result.succeed("");
621
621
  return Result.map(argumentsText, (text) => `${symbol.name}${text}`);
622
622
  }
623
623
  return Result.succeed(null);
624
624
  }
625
- function renderProperty(input) {
626
- if (checker.getSignaturesOfType(input.propertyType, SignatureKind.Call).length > 0) return fail(input.propertyType, `the property ${input.property.name} is a function, which cannot cross the wire`);
625
+ async function renderProperty(input) {
626
+ if ((await checker.getSignaturesOfType(input.propertyType, SignatureKind.Call)).length > 0) return await fail(input.propertyType, `the property ${input.property.name} is a function, which cannot cross the wire`);
627
627
  const optional = (input.property.flags & SymbolFlags.Optional) !== 0;
628
- const text = optional ? renderOptionalType(input.propertyType, input.depth) : renderNode(input.propertyType, input.depth);
628
+ const text = optional ? await renderOptionalType(input.propertyType, input.depth) : await renderNode(input.propertyType, input.depth);
629
629
  if (Result.isFailure(text)) return text;
630
- const readonly = matchesReadonlyProperty(input.property) ? "readonly " : "";
630
+ const readonly = await matchesReadonlyProperty(input.property) ? "readonly " : "";
631
631
  return Result.succeed(`${toIndent(input.depth)}${readonly}${renderPropertyName(input.property.name)}${optional ? "?" : ""}: ${text.success};`);
632
632
  }
633
633
  /** A class instance crosses the wire as the record of its schema fields; the fields come from the class's static `fields`. */
634
- function renderClassInstance(type, classSymbol, depth) {
635
- const constructorType = checker.getTypeOfSymbol(classSymbol);
636
- const fields = constructorType === void 0 ? void 0 : checker.getPropertyOfType(constructorType, "fields");
637
- const fieldsType = fields === void 0 ? void 0 : checker.getTypeOfSymbol(fields);
638
- if (fieldsType === void 0) return fail(type, `the class ${classSymbol.name} is not an Effect Schema class, so its wire form is unknown`);
634
+ async function renderClassInstance(type, classSymbol, depth) {
635
+ const constructorType = await checker.getTypeOfSymbol(classSymbol);
636
+ const fields = constructorType === void 0 ? void 0 : await checker.getPropertyOfType(constructorType, "fields");
637
+ const fieldsType = fields === void 0 ? void 0 : await checker.getTypeOfSymbol(fields);
638
+ if (fieldsType === void 0) return await fail(type, `the class ${classSymbol.name} is not an Effect Schema class, so its wire form is unknown`);
639
639
  const lines = [];
640
- for (const field of sortProperties(checker.getPropertiesOfType(fieldsType))) {
641
- const property = checker.getPropertyOfType(type, field.name);
642
- const propertyType = property === void 0 ? void 0 : checker.getTypeOfSymbol(property);
643
- if (property === void 0 || propertyType === void 0) return fail(type, `the class ${classSymbol.name} declares the field ${field.name} without a property of that name`);
644
- const line = renderProperty({
640
+ for (const field of sortProperties(await checker.getPropertiesOfType(fieldsType))) {
641
+ const property = await checker.getPropertyOfType(type, field.name);
642
+ const propertyType = property === void 0 ? void 0 : await checker.getTypeOfSymbol(property);
643
+ if (property === void 0 || propertyType === void 0) return await fail(type, `the class ${classSymbol.name} declares the field ${field.name} without a property of that name`);
644
+ const line = await renderProperty({
645
645
  property,
646
646
  propertyType,
647
647
  depth: depth + 1
@@ -655,16 +655,16 @@ function createTypeRenderer(input) {
655
655
  `${toIndent(depth)}}`
656
656
  ].join("\n"));
657
657
  }
658
- function renderObject(type, depth) {
659
- const symbol = type.getSymbol();
660
- if (symbol !== void 0 && (symbol.flags & SymbolFlags.Class) !== 0) return renderClassInstance(type, symbol, depth);
661
- if (checker.getSignaturesOfType(type, SignatureKind.Call).length > 0 || checker.getSignaturesOfType(type, SignatureKind.Construct).length > 0) return fail(type, "a function cannot cross the wire");
658
+ async function renderObject(type, depth) {
659
+ const symbol = await type.getSymbol();
660
+ if (symbol !== void 0 && (symbol.flags & SymbolFlags.Class) !== 0) return await renderClassInstance(type, symbol, depth);
661
+ if ((await checker.getSignaturesOfType(type, SignatureKind.Call)).length > 0 || (await checker.getSignaturesOfType(type, SignatureKind.Construct)).length > 0) return await fail(type, "a function cannot cross the wire");
662
662
  const lines = [];
663
- for (const property of sortProperties(checker.getPropertiesOfType(type))) {
663
+ for (const property of sortProperties(await checker.getPropertiesOfType(type))) {
664
664
  if (String(property.escapedName).startsWith("__@")) continue;
665
- const propertyType = checker.getTypeOfSymbol(property);
666
- if (propertyType === void 0) return fail(type, `the property ${property.name} has no type`);
667
- const line = renderProperty({
665
+ const propertyType = await checker.getTypeOfSymbol(property);
666
+ if (propertyType === void 0) return await fail(type, `the property ${property.name} has no type`);
667
+ const line = await renderProperty({
668
668
  property,
669
669
  propertyType,
670
670
  depth: depth + 1
@@ -672,10 +672,10 @@ function createTypeRenderer(input) {
672
672
  if (Result.isFailure(line)) return line;
673
673
  lines.push(line.success);
674
674
  }
675
- for (const signature of checker.getIndexInfosOfType(type)) {
676
- const keyText = renderNode(signature.keyType, depth + 1);
675
+ for (const signature of await checker.getIndexInfosOfType(type)) {
676
+ const keyText = await renderNode(signature.keyType, depth + 1);
677
677
  if (Result.isFailure(keyText)) return keyText;
678
- const valueText = renderNode(signature.valueType, depth + 1);
678
+ const valueText = await renderNode(signature.valueType, depth + 1);
679
679
  if (Result.isFailure(valueText)) return valueText;
680
680
  lines.push(`${toIndent(depth + 1)}${signature.isReadonly ? "readonly " : ""}[key: ${keyText.success}]: ${valueText.success};`);
681
681
  }
@@ -685,19 +685,19 @@ function createTypeRenderer(input) {
685
685
  `${toIndent(depth)}}`
686
686
  ].join("\n"));
687
687
  }
688
- function renderOptionalType(type, depth) {
689
- const present = withoutAbsence({
688
+ async function renderOptionalType(type, depth) {
689
+ const present = await withoutAbsence({
690
690
  type,
691
691
  undefinedType
692
692
  });
693
- return present === void 0 ? renderNode(type, depth) : present.length === 1 && present[0] !== void 0 ? renderNode(present[0], depth) : renderUnion(present, depth, " | ");
693
+ return present === void 0 ? await renderNode(type, depth) : present.length === 1 && present[0] !== void 0 ? await renderNode(present[0], depth) : await renderUnion(present, depth, " | ");
694
694
  }
695
- function renderTuple(type, depth) {
696
- const target = type.getTarget();
695
+ async function renderTuple(type, depth) {
696
+ const target = await type.getTarget();
697
697
  const members = [];
698
- for (const [index, element] of checker.getTypeArguments(type).entries()) {
698
+ for (const [index, element] of (await checker.getTypeArguments(type)).entries()) {
699
699
  const flags = target.elementFlags[index] ?? ElementFlags.Required;
700
- const text = (flags & ElementFlags.Optional) !== 0 ? renderOptionalType(element, depth) : renderNode(element, depth);
700
+ const text = (flags & ElementFlags.Optional) !== 0 ? await renderOptionalType(element, depth) : await renderNode(element, depth);
701
701
  if (Result.isFailure(text)) return text;
702
702
  if ((flags & ElementFlags.Rest) !== 0) members.push(`...Array<${text.success}>`);
703
703
  else if ((flags & ElementFlags.Variadic) !== 0) members.push(`...(${text.success})`);
@@ -706,7 +706,7 @@ function createTypeRenderer(input) {
706
706
  }
707
707
  return Result.succeed(`${target.readonly ? "readonly " : ""}[${members.join(", ")}]`);
708
708
  }
709
- function renderUnion(members, depth, separator) {
709
+ async function renderUnion(members, depth, separator) {
710
710
  const parts = [];
711
711
  let sawTrue = false;
712
712
  let sawFalse = false;
@@ -716,7 +716,7 @@ function createTypeRenderer(input) {
716
716
  else sawFalse = true;
717
717
  continue;
718
718
  }
719
- const text = renderNode(member, depth);
719
+ const text = await renderNode(member, depth);
720
720
  if (Result.isFailure(text)) return text;
721
721
  parts.push(separator === " & " && member.isUnionType() ? `(${text.success})` : text.success);
722
722
  }
@@ -732,26 +732,26 @@ function createTypeRenderer(input) {
732
732
  return Result.succeed(parts.length === 0 ? "never" : parts.join(separator));
733
733
  }
734
734
  /** Keeps literal contents independent of indentation in the containing declaration. */
735
- function renderTemplateToken(node) {
736
- return emitter.printNode(node).replaceAll("\r", "\\r").replaceAll("\n", "\\n");
735
+ async function renderTemplateToken(node) {
736
+ return (await emitter.printNode(node)).replaceAll("\r", "\\r").replaceAll("\n", "\\n");
737
737
  }
738
- function renderTemplateLiteral(type, depth) {
739
- if (!type.isTemplateLiteralType()) return fail(type, "not a template literal type");
738
+ async function renderTemplateLiteral(type, depth) {
739
+ if (!type.isTemplateLiteralType()) return await fail(type, "not a template literal type");
740
740
  const spans = [];
741
- for (const span of type.getTypes()) {
742
- const text = renderNode(span, depth);
741
+ for (const span of await type.getTypes()) {
742
+ const text = await renderNode(span, depth);
743
743
  if (Result.isFailure(text)) return text;
744
744
  spans.push(text.success);
745
745
  }
746
746
  const [head, ...tail] = type.texts;
747
- let text = renderTemplateToken(createTemplateHead(head ?? "", "", TokenFlags.None));
747
+ let text = await renderTemplateToken(createTemplateHead(head ?? "", "", TokenFlags.None));
748
748
  for (const [index, span] of spans.entries()) {
749
749
  const createLiteral = index === spans.length - 1 ? createTemplateTail : createTemplateMiddle;
750
- text += span + renderTemplateToken(createLiteral(tail[index] ?? "", "", TokenFlags.None));
750
+ text += span + await renderTemplateToken(createLiteral(tail[index] ?? "", "", TokenFlags.None));
751
751
  }
752
752
  return Result.succeed(text);
753
753
  }
754
- function renderNode(type, depth) {
754
+ async function renderNode(type, depth) {
755
755
  const existingAlias = aliases.get(type.id);
756
756
  if (existingAlias !== void 0) return Result.succeed(existingAlias);
757
757
  if (visiting.has(type.id)) {
@@ -760,41 +760,41 @@ function createTypeRenderer(input) {
760
760
  return Result.succeed(name);
761
761
  }
762
762
  visiting.add(type.id);
763
- const text = renderTypeStructure(type, depth);
763
+ const text = await renderTypeStructure(type, depth);
764
764
  visiting.delete(type.id);
765
765
  if (Result.isFailure(text)) return text;
766
766
  const createdAlias = aliases.get(type.id);
767
767
  if (createdAlias === void 0) return text;
768
- const declared = depth === 0 ? text : renderTypeStructure(type, 0);
768
+ const declared = depth === 0 ? text : await renderTypeStructure(type, 0);
769
769
  if (Result.isFailure(declared)) return declared;
770
770
  rendered.push(`type ${createdAlias} = ${declared.success};`);
771
771
  return Result.succeed(createdAlias);
772
772
  }
773
- function renderTypeStructure(type, depth) {
774
- if (type.isErrorType()) return fail(type, "the type could not be resolved");
773
+ async function renderTypeStructure(type, depth) {
774
+ if (type.isErrorType()) return await fail(type, "the type could not be resolved");
775
775
  if (type.isStringLiteralType()) return Result.succeed(JSON.stringify(type.value));
776
776
  if (type.isNumberLiteralType()) return Result.succeed(String(type.value));
777
777
  if (type.isBigIntLiteralType()) return Result.succeed(`${type.value}n`);
778
778
  if (type.isBooleanLiteralType()) return Result.succeed(type.value ? "true" : "false");
779
779
  if (type.isIntrinsicType()) return Result.succeed(type.intrinsicName);
780
- const named = renderNamedType(type, depth);
780
+ const named = await renderNamedType(type, depth);
781
781
  if (Result.isFailure(named)) return Result.fail(named.failure);
782
782
  if (named.success !== null) return Result.succeed(named.success);
783
- if (type.isTemplateLiteralType()) return renderTemplateLiteral(type, depth);
784
- if (type.isUnionType()) return renderUnion(type.getTypes(), depth, " | ");
785
- if (type.isIntersectionType()) return renderUnion(type.getTypes(), depth, " & ");
786
- if (type.isTypeParameter()) return fail(type, "a contract type cannot be generic");
787
- if (!type.isObjectType()) return fail(type, "the type has no wire form");
788
- if (checker.isArrayType(type) && type.isTypeReference()) {
789
- const [element] = checker.getTypeArguments(type);
790
- if (element === void 0) return fail(type, "an array type without an element type");
791
- const text = renderNode(element, depth);
783
+ if (type.isTemplateLiteralType()) return await renderTemplateLiteral(type, depth);
784
+ if (type.isUnionType()) return await renderUnion(await type.getTypes(), depth, " | ");
785
+ if (type.isIntersectionType()) return await renderUnion(await type.getTypes(), depth, " & ");
786
+ if (type.isTypeParameter()) return await fail(type, "a contract type cannot be generic");
787
+ if (!type.isObjectType()) return await fail(type, "the type has no wire form");
788
+ if (await checker.isArrayType(type) && type.isTypeReference()) {
789
+ const [element] = await checker.getTypeArguments(type);
790
+ if (element === void 0) return await fail(type, "an array type without an element type");
791
+ const text = await renderNode(element, depth);
792
792
  if (Result.isFailure(text)) return text;
793
- const wrapper = type.getSymbol()?.name === "ReadonlyArray" ? "ReadonlyArray" : "Array";
793
+ const wrapper = (await type.getSymbol())?.name === "ReadonlyArray" ? "ReadonlyArray" : "Array";
794
794
  return Result.succeed(`${wrapper}<${text.success}>`);
795
795
  }
796
- if (checker.isTupleType(type) && type.isTypeReference()) return renderTuple(type, depth);
797
- return renderObject(type, depth);
796
+ if (await checker.isTupleType(type) && type.isTypeReference()) return await renderTuple(type, depth);
797
+ return await renderObject(type, depth);
798
798
  }
799
799
  return {
800
800
  renderType: (input) => renderNode(input.type, input.depth),
@@ -923,37 +923,146 @@ function makePublicAssetsBasePathError(cause) {
923
923
  };
924
924
  }
925
925
  //#endregion
926
+ //#region src/build/typescript-projects.ts
927
+ /** Reads native project membership without loading programs or declaration types. */
928
+ function readTypescriptProjectRoots(input) {
929
+ return withTypescriptApi({
930
+ configDirectory: input.configDirectory,
931
+ useFn: (api) => {
932
+ return runTypescriptOperation(async () => {
933
+ return {
934
+ server: (await api.parseConfigFile(input.serverTsconfigFilePath)).fileNames,
935
+ client: (await api.parseConfigFile(input.clientTsconfigFilePath)).fileNames
936
+ };
937
+ });
938
+ }
939
+ });
940
+ }
941
+ /** Checks actual compiler membership after generation, including restrictive files/include/exclude settings. */
942
+ function checkGeneratedTypeInclusion(input) {
943
+ return withTypescriptProjects({
944
+ ...input,
945
+ useFn: (projects) => {
946
+ return Effect.gen(function* () {
947
+ const missing = yield* runTypescriptOperation(async () => {
948
+ const missing = [];
949
+ for (const [project, files, config] of [[
950
+ projects.server,
951
+ input.serverFiles,
952
+ input.serverTsconfigFilePath
953
+ ], [
954
+ projects.client,
955
+ input.clientFiles,
956
+ input.clientTsconfigFilePath
957
+ ]]) for (const file of files) if (await project.program.getSourceFileMetadata(file) === void 0) missing.push({
958
+ project: config,
959
+ file
960
+ });
961
+ return missing;
962
+ });
963
+ return yield* missing.length === 0 ? Effect.void : Effect.fail({
964
+ _tag: "TypescriptProjectError",
965
+ message: missing.map(({ project, file }) => `${project} does not include generated type file ${file}. Include the entry's _vorma directory in that TypeScript project.`).join("\n")
966
+ });
967
+ });
968
+ }
969
+ });
970
+ }
971
+ /** Opens the two configured TypeScript projects for the duration of `useFn`, then closes the checker session. */
972
+ function withTypescriptProjects(input) {
973
+ return withTypescriptApi({
974
+ ...input,
975
+ useFn: (api) => {
976
+ return Effect.scoped(Effect.gen(function* () {
977
+ const projects = findProjects({
978
+ snapshot: yield* Effect.acquireRelease(runTypescriptOperation(() => {
979
+ return api.updateSnapshot({ openProjects: [input.serverTsconfigFilePath, input.clientTsconfigFilePath] });
980
+ }), (snapshot) => Effect.promise(() => snapshot.dispose())),
981
+ ...input
982
+ });
983
+ return yield* Result.isFailure(projects) ? Effect.fail(projects.failure) : input.useFn(projects.success);
984
+ }));
985
+ }
986
+ });
987
+ }
988
+ /** Native compiler operations have no cancellation API; settle each operation before its session can close. */
989
+ function runTypescriptOperation(fn) {
990
+ return Effect.tryPromise({
991
+ try: fn,
992
+ catch: (cause) => {
993
+ return {
994
+ _tag: "TypescriptProjectError",
995
+ message: "Vorma could not read the application's TypeScript projects",
996
+ cause
997
+ };
998
+ }
999
+ }).pipe(Effect.uninterruptible);
1000
+ }
1001
+ function withTypescriptApi(input) {
1002
+ return Effect.scoped(Effect.gen(function* () {
1003
+ const api = yield* Effect.acquireRelease(runTypescriptOperation(async () => {
1004
+ return new API({
1005
+ cwd: input.configDirectory,
1006
+ ...input.fileSystem === void 0 ? {} : { fs: input.fileSystem }
1007
+ });
1008
+ }), (api) => Effect.promise(() => api.close()));
1009
+ return yield* input.useFn(api);
1010
+ }));
1011
+ }
1012
+ function findProjects(input) {
1013
+ const server = input.snapshot.getProject(input.serverTsconfigFilePath);
1014
+ const client = input.snapshot.getProject(input.clientTsconfigFilePath);
1015
+ if (server === void 0 || client === void 0) return Result.fail({
1016
+ _tag: "TypescriptProjectError",
1017
+ message: `TypeScript did not load ${server === void 0 ? input.serverTsconfigFilePath : input.clientTsconfigFilePath}`
1018
+ });
1019
+ return Result.succeed({
1020
+ server,
1021
+ client
1022
+ });
1023
+ }
1024
+ //#endregion
926
1025
  //#region src/build/inspect-projects.ts
927
1026
  /** Reads every registerable declaration, view, the client application, and every public URL call from the two projects. */
928
1027
  function inspectProjects(input) {
929
1028
  return Effect.gen(function* () {
930
1029
  const path = yield* Path$1.Path;
931
1030
  const excludedDirectories = getGeneratedSourceDirectories(input.layout);
932
- const serverFiles = listOwnSourceFiles({
933
- project: input.projects.server,
934
- excludedDirectories,
935
- path
1031
+ const serverFiles = yield* runTypescriptOperation(() => {
1032
+ return listOwnSourceFiles({
1033
+ project: input.projects.server,
1034
+ excludedDirectories,
1035
+ path
1036
+ });
936
1037
  });
937
- const clientFiles = listOwnSourceFiles({
938
- project: input.projects.client,
939
- excludedDirectories,
940
- path
1038
+ const clientFiles = yield* runTypescriptOperation(() => {
1039
+ return listOwnSourceFiles({
1040
+ project: input.projects.client,
1041
+ excludedDirectories,
1042
+ path
1043
+ });
941
1044
  });
942
- const serverRenderer = createTypeRenderer({
943
- checker: input.projects.server.checker,
944
- program: input.projects.server.program,
945
- emitter: input.projects.server.emitter
1045
+ const serverRenderer = yield* runTypescriptOperation(() => {
1046
+ return createTypeRenderer({
1047
+ checker: input.projects.server.checker,
1048
+ program: input.projects.server.program,
1049
+ emitter: input.projects.server.emitter
1050
+ });
946
1051
  });
947
- const serverDeclarations = yield* Effect.fromResult(inspectServerDeclarations({
948
- checker: input.projects.server.checker,
949
- program: input.projects.server.program,
950
- files: serverFiles,
951
- renderer: serverRenderer
1052
+ const serverDeclarations = yield* Effect.fromResult(yield* runTypescriptOperation(() => {
1053
+ return inspectServerDeclarations({
1054
+ checker: input.projects.server.checker,
1055
+ program: input.projects.server.program,
1056
+ files: serverFiles,
1057
+ renderer: serverRenderer
1058
+ });
952
1059
  }));
953
- const client = yield* Effect.fromResult(inspectClientProject({
954
- checker: input.projects.client.checker,
955
- files: clientFiles,
956
- clientEntryFilePath: input.layout.clientEntryFilePath
1060
+ const client = yield* Effect.fromResult(yield* runTypescriptOperation(() => {
1061
+ return inspectClientProject({
1062
+ checker: input.projects.client.checker,
1063
+ files: clientFiles,
1064
+ clientEntryFilePath: input.layout.clientEntryFilePath
1065
+ });
957
1066
  }));
958
1067
  return {
959
1068
  serverDeclarations,
@@ -968,10 +1077,10 @@ function inspectProjects(input) {
968
1077
  });
969
1078
  }
970
1079
  /** The project's own modules: not a library, not a declaration file, and not under a Vorma output directory. */
971
- function listOwnSourceFiles(input) {
1080
+ async function listOwnSourceFiles(input) {
972
1081
  const { program } = input.project;
973
1082
  const files = [];
974
- for (const fileName of program.getSourceFileNames()) {
1083
+ for (const fileName of await program.getSourceFileNames()) {
975
1084
  if (fileName.includes("/node_modules/") || input.excludedDirectories.some((directory) => {
976
1085
  const relativePath = input.path.relative(directory, fileName);
977
1086
  return containsRelativePath({
@@ -980,9 +1089,9 @@ function listOwnSourceFiles(input) {
980
1089
  absolute: input.path.isAbsolute(relativePath)
981
1090
  });
982
1091
  })) continue;
983
- const metadata = program.getSourceFileMetadata(fileName);
1092
+ const metadata = await program.getSourceFileMetadata(fileName);
984
1093
  if (metadata?.isDefaultLibrary || metadata?.isFromExternalLibrary) continue;
985
- const sourceFile = program.getSourceFile(fileName);
1094
+ const sourceFile = await program.getSourceFile(fileName);
986
1095
  if (sourceFile === void 0 || sourceFile.isDeclarationFile) continue;
987
1096
  files.push(sourceFile);
988
1097
  }
@@ -994,15 +1103,15 @@ function listOwnSourceFiles(input) {
994
1103
  });
995
1104
  }
996
1105
  /** Export bindings retain their public names while aliases resolve to one declaration identity. */
997
- function listModuleExports(input) {
1106
+ async function listModuleExports(input) {
998
1107
  const { checker, sourceFile } = input;
999
- const moduleSymbol = checker.getSymbolAtLocation(sourceFile);
1108
+ const moduleSymbol = await checker.getSymbolAtLocation(sourceFile);
1000
1109
  if (moduleSymbol === void 0) return [];
1001
1110
  const exports = [];
1002
- for (const exported of checker.getExportsOfModule(moduleSymbol)) {
1003
- const symbol = (exported.flags & SymbolFlags.Alias) !== 0 ? checker.getAliasedSymbol(exported) : exported;
1004
- if (checker.isUnknownSymbol(symbol)) continue;
1005
- const type = checker.getTypeOfSymbol(symbol);
1111
+ for (const exported of await checker.getExportsOfModule(moduleSymbol)) {
1112
+ const symbol = (exported.flags & SymbolFlags.Alias) !== 0 ? await checker.getAliasedSymbol(exported) : exported;
1113
+ if (await checker.isUnknownSymbol(symbol)) continue;
1114
+ const type = await checker.getTypeOfSymbol(symbol);
1006
1115
  if (type === void 0) continue;
1007
1116
  exports.push({
1008
1117
  exportName: exported.name,
@@ -1013,9 +1122,9 @@ function listModuleExports(input) {
1013
1122
  return exports;
1014
1123
  }
1015
1124
  /** Prefer a declaration's own exported module so a re-export barrel does not enlarge a view's import closure. */
1016
- function listRegistrationExports(input) {
1125
+ async function listRegistrationExports(input) {
1017
1126
  const exports = /* @__PURE__ */ new Map();
1018
- for (const sourceFile of input.files) for (const moduleExport of listModuleExports({
1127
+ for (const sourceFile of input.files) for (const moduleExport of await listModuleExports({
1019
1128
  checker: input.checker,
1020
1129
  sourceFile
1021
1130
  })) {
@@ -1030,55 +1139,55 @@ function listRegistrationExports(input) {
1030
1139
  return [...exports.values()];
1031
1140
  }
1032
1141
  /** The phantom property that carries a definition's static types, by the unique symbol that keys it. */
1033
- function findPhantomProperty(input) {
1142
+ async function findPhantomProperty(input) {
1034
1143
  const prefix = `__@${input.symbolName}@`;
1035
- return input.checker.getPropertiesOfType(input.type).find((property) => String(property.escapedName).startsWith(prefix));
1144
+ return (await input.checker.getPropertiesOfType(input.type)).find((property) => String(property.escapedName).startsWith(prefix));
1036
1145
  }
1037
- function readPropertyType(input) {
1038
- const property = input.checker.getPropertyOfType(input.type, input.name);
1039
- return property === void 0 ? void 0 : input.checker.getTypeOfSymbol(property);
1146
+ async function readPropertyType(input) {
1147
+ const property = await input.checker.getPropertyOfType(input.type, input.name);
1148
+ return property === void 0 ? void 0 : await input.checker.getTypeOfSymbol(property);
1040
1149
  }
1041
- function readLiteralProperty(input) {
1042
- const propertyType = readPropertyType(input);
1150
+ async function readLiteralProperty(input) {
1151
+ const propertyType = await readPropertyType(input);
1043
1152
  if (propertyType === void 0) return Result.fail(`the declaration has no ${input.name} property`);
1044
- if (!propertyType.isStringLiteralType()) return Result.fail(`${input.name} must have a literal type; its type is ${input.checker.typeToString(propertyType)}`);
1153
+ if (!propertyType.isStringLiteralType()) return Result.fail(`${input.name} must have a literal type; its type is ${await input.checker.typeToString(propertyType)}`);
1045
1154
  return Result.succeed(propertyType.value);
1046
1155
  }
1047
1156
  function matchesUndefinedType(type) {
1048
1157
  return type.isIntrinsicType() && type.intrinsicName === "undefined";
1049
1158
  }
1050
- function inspectServerDeclarations(input) {
1159
+ async function inspectServerDeclarations(input) {
1051
1160
  const { checker, program, renderer } = input;
1052
1161
  const declarations = [];
1053
1162
  const candidates = [];
1054
- for (const { sourceFile, moduleExport } of listRegistrationExports(input)) {
1163
+ for (const { sourceFile, moduleExport } of await listRegistrationExports(input)) {
1055
1164
  const source = {
1056
1165
  filePath: sourceFile.fileName,
1057
1166
  exportName: moduleExport.exportName
1058
1167
  };
1059
- const phantom = findPhantomProperty({
1168
+ const phantom = await findPhantomProperty({
1060
1169
  checker,
1061
1170
  type: moduleExport.type,
1062
1171
  symbolName: "DEFINITION_TYPES"
1063
1172
  });
1064
1173
  if (phantom === void 0) continue;
1065
- const tag = readPropertyType({
1174
+ const tag = await readPropertyType({
1066
1175
  checker,
1067
1176
  type: moduleExport.type,
1068
1177
  name: "_tag"
1069
1178
  });
1070
1179
  if (tag === void 0 || !tag.isStringLiteralType()) continue;
1071
1180
  if (tag.value !== "UiLoader" && tag.value !== "Endpoint") continue;
1072
- const phantomType = checker.getTypeOfSymbol(phantom);
1073
- const types = phantomType === void 0 ? void 0 : checker.getNonNullableType(phantomType);
1181
+ const phantomType = await checker.getTypeOfSymbol(phantom);
1182
+ const types = phantomType === void 0 ? void 0 : await checker.getNonNullableType(phantomType);
1074
1183
  if (types === void 0) return Result.fail(makeIssue(source, "the definition carries no static types"));
1075
- const pattern = readLiteralProperty({
1184
+ const pattern = await readLiteralProperty({
1076
1185
  checker,
1077
1186
  type: moduleExport.type,
1078
1187
  name: "pattern"
1079
1188
  });
1080
1189
  if (Result.isFailure(pattern)) return Result.fail(makeIssue(source, pattern.failure));
1081
- const method = readPropertyType({
1190
+ const method = await readPropertyType({
1082
1191
  checker,
1083
1192
  type: moduleExport.type,
1084
1193
  name: "method"
@@ -1102,13 +1211,13 @@ function inspectServerDeclarations(input) {
1102
1211
  });
1103
1212
  });
1104
1213
  for (const { source, kind, type, types } of candidates) {
1105
- const inspected = kind === "UiLoader" ? inspectUiLoader({
1214
+ const inspected = kind === "UiLoader" ? await inspectUiLoader({
1106
1215
  checker,
1107
1216
  renderer,
1108
1217
  source,
1109
1218
  type,
1110
1219
  types
1111
- }) : inspectEndpoint({
1220
+ }) : await inspectEndpoint({
1112
1221
  checker,
1113
1222
  program,
1114
1223
  renderer,
@@ -1129,8 +1238,8 @@ function makeIssue(source, message) {
1129
1238
  message: `${source.filePath} (export ${source.exportName}): ${message}`
1130
1239
  };
1131
1240
  }
1132
- function renderContract(input) {
1133
- return Result.mapError(input.renderer.renderType({
1241
+ async function renderContract(input) {
1242
+ return Result.mapError(await input.renderer.renderType({
1134
1243
  type: input.type,
1135
1244
  depth: 2
1136
1245
  }), (issue) => {
@@ -1138,27 +1247,27 @@ function renderContract(input) {
1138
1247
  });
1139
1248
  }
1140
1249
  /** A contract's text, or `undefined` for the absent contract that the type `undefined` denotes. */
1141
- function renderOptionalContract(input) {
1142
- const type = readPropertyType({
1250
+ async function renderOptionalContract(input) {
1251
+ const type = await readPropertyType({
1143
1252
  checker: input.checker,
1144
1253
  type: input.types,
1145
1254
  name: input.field
1146
1255
  });
1147
1256
  if (type === void 0 || matchesUndefinedType(type)) return Result.succeed(void 0);
1148
- return renderContract({
1257
+ return await renderContract({
1149
1258
  ...input,
1150
1259
  type
1151
1260
  });
1152
1261
  }
1153
- function inspectUiLoader(input) {
1262
+ async function inspectUiLoader(input) {
1154
1263
  const { checker, renderer, source } = input;
1155
- const pattern = readLiteralProperty({
1264
+ const pattern = await readLiteralProperty({
1156
1265
  checker,
1157
1266
  type: input.type,
1158
1267
  name: "pattern"
1159
1268
  });
1160
1269
  if (Result.isFailure(pattern)) return Result.fail(makeIssue(source, pattern.failure));
1161
- const loaderInput = renderOptionalContract({
1270
+ const loaderInput = await renderOptionalContract({
1162
1271
  checker,
1163
1272
  renderer,
1164
1273
  source,
@@ -1166,13 +1275,13 @@ function inspectUiLoader(input) {
1166
1275
  types: input.types
1167
1276
  });
1168
1277
  if (Result.isFailure(loaderInput)) return Result.fail(loaderInput.failure);
1169
- const outputType = readPropertyType({
1278
+ const outputType = await readPropertyType({
1170
1279
  checker,
1171
1280
  type: input.types,
1172
1281
  name: "output"
1173
1282
  });
1174
1283
  if (outputType === void 0) return Result.fail(makeIssue(source, "a UI loader must have an output contract"));
1175
- const output = renderContract({
1284
+ const output = await renderContract({
1176
1285
  renderer,
1177
1286
  source,
1178
1287
  field: "output",
@@ -1187,7 +1296,7 @@ function inspectUiLoader(input) {
1187
1296
  output: output.success
1188
1297
  });
1189
1298
  }
1190
- function inspectEndpoint(input) {
1299
+ async function inspectEndpoint(input) {
1191
1300
  const { checker, program, renderer, source } = input;
1192
1301
  const literals = {
1193
1302
  kind: "",
@@ -1199,7 +1308,7 @@ function inspectEndpoint(input) {
1199
1308
  "method",
1200
1309
  "pattern"
1201
1310
  ]) {
1202
- const literal = readLiteralProperty({
1311
+ const literal = await readLiteralProperty({
1203
1312
  checker,
1204
1313
  type: input.type,
1205
1314
  name
@@ -1212,25 +1321,25 @@ function inspectEndpoint(input) {
1212
1321
  if (operation !== "query" && operation !== "mutation") return Result.fail(makeIssue(source, `unknown endpoint kind ${operation}`));
1213
1322
  const method = literals.method;
1214
1323
  if (!matchesHttpMethod(method)) return Result.fail(makeIssue(source, `unknown endpoint method ${method}`));
1215
- const inputType = readPropertyType({
1324
+ const inputType = await readPropertyType({
1216
1325
  checker,
1217
1326
  type: input.types,
1218
1327
  name: "input"
1219
1328
  });
1220
1329
  const hasInput = inputType !== void 0 && !matchesUndefinedType(inputType);
1221
- const inputTransport = !hasInput ? "none" : method === "GET" ? "search" : matchesFormInput({
1330
+ const inputTransport = !hasInput ? "none" : method === "GET" ? "search" : await matchesFormInput({
1222
1331
  checker,
1223
1332
  program,
1224
1333
  types: input.types
1225
1334
  }) ? "formData" : "json";
1226
- const endpointInput = inputType === void 0 || !hasInput || inputTransport === "formData" ? Result.succeed(void 0) : renderContract({
1335
+ const endpointInput = inputType === void 0 || !hasInput || inputTransport === "formData" ? Result.succeed(void 0) : await renderContract({
1227
1336
  renderer,
1228
1337
  source,
1229
1338
  field: "input",
1230
1339
  type: inputType
1231
1340
  });
1232
1341
  if (Result.isFailure(endpointInput)) return Result.fail(endpointInput.failure);
1233
- const output = renderOptionalContract({
1342
+ const output = await renderOptionalContract({
1234
1343
  checker,
1235
1344
  renderer,
1236
1345
  source,
@@ -1238,7 +1347,7 @@ function inspectEndpoint(input) {
1238
1347
  types: input.types
1239
1348
  });
1240
1349
  if (Result.isFailure(output)) return Result.fail(output.failure);
1241
- const event = renderOptionalContract({
1350
+ const event = await renderOptionalContract({
1242
1351
  checker,
1243
1352
  renderer,
1244
1353
  source,
@@ -1246,7 +1355,7 @@ function inspectEndpoint(input) {
1246
1355
  types: input.types
1247
1356
  });
1248
1357
  if (Result.isFailure(event)) return Result.fail(event.failure);
1249
- const errors = inspectEndpointErrors({
1358
+ const errors = await inspectEndpointErrors({
1250
1359
  checker,
1251
1360
  renderer,
1252
1361
  source,
@@ -1271,51 +1380,52 @@ function inspectEndpoint(input) {
1271
1380
  * form-transport marker carried by Vorma's FormData schema and its derived
1272
1381
  * codecs. The runtime recognizes the same factory's schema annotation.
1273
1382
  */
1274
- function matchesFormInput(input) {
1275
- const symbol = readPropertyType({
1383
+ async function matchesFormInput(input) {
1384
+ const symbol = await (await readPropertyType({
1276
1385
  checker: input.checker,
1277
1386
  type: input.types,
1278
1387
  name: "inputEncoded"
1279
- })?.getSymbol();
1388
+ }))?.getSymbol();
1280
1389
  return symbol !== void 0 && symbol.name === "FormDataEncoded" && symbol.declarations.some((declaration) => {
1281
1390
  return /\/vorma\/(?:src|dist)\/server\/form-data\.(?:d\.)?ts$/.test(String(declaration.path));
1282
- }) && matchesLibrarySymbol({
1391
+ }) && await matchesLibrarySymbol({
1283
1392
  program: input.program,
1284
1393
  symbol
1285
1394
  });
1286
1395
  }
1287
1396
  /** Each declared error: its decoded `_tag` and transportable schema fields. */
1288
- function inspectEndpointErrors(input) {
1397
+ async function inspectEndpointErrors(input) {
1289
1398
  const { checker, renderer, source } = input;
1290
- const errorsType = readPropertyType({
1399
+ const errorsType = await readPropertyType({
1291
1400
  checker,
1292
1401
  type: input.types,
1293
1402
  name: "errors"
1294
1403
  });
1295
1404
  if (errorsType === void 0) return Result.succeed([]);
1296
- const elementType = checker.getIndexInfosOfType(errorsType).find((index) => {
1297
- return index.keyType.id === checker.getNumberType().id;
1405
+ const numberType = await checker.getNumberType();
1406
+ const elementType = (await checker.getIndexInfosOfType(errorsType)).find((index) => {
1407
+ return index.keyType.id === numberType.id;
1298
1408
  })?.valueType;
1299
1409
  if (elementType === void 0) return Result.fail(makeIssue(source, "declared errors must have an array element type"));
1300
1410
  const errors = [];
1301
1411
  const variantsByTag = [];
1302
- const elements = elementType.isUnionType() ? elementType.getTypes() : [elementType];
1412
+ const elements = elementType.isUnionType() ? await elementType.getTypes() : [elementType];
1303
1413
  for (const element of elements) {
1304
1414
  if (element.isIntrinsicType() && element.intrinsicName === "never") continue;
1305
- const schemaType = readPropertyType({
1415
+ const schemaType = await readPropertyType({
1306
1416
  checker,
1307
1417
  type: element,
1308
1418
  name: "schema"
1309
1419
  });
1310
- const decodedType = schemaType === void 0 ? void 0 : readPropertyType({
1420
+ const decodedType = schemaType === void 0 ? void 0 : await readPropertyType({
1311
1421
  checker,
1312
1422
  type: schemaType,
1313
1423
  name: "Type"
1314
1424
  });
1315
1425
  if (decodedType === void 0) return Result.fail(makeIssue(source, "each declared error's schema must expose its decoded Type"));
1316
- const variants = decodedType.isUnionType() ? decodedType.getTypes() : [decodedType];
1426
+ const variants = decodedType.isUnionType() ? await decodedType.getTypes() : [decodedType];
1317
1427
  for (const variant of variants) {
1318
- const tag = readLiteralProperty({
1428
+ const tag = await readLiteralProperty({
1319
1429
  checker,
1320
1430
  type: variant,
1321
1431
  name: "_tag"
@@ -1334,7 +1444,7 @@ function inspectEndpointErrors(input) {
1334
1444
  });
1335
1445
  });
1336
1446
  for (const variant of variantsByTag) {
1337
- const fields = renderContract({
1447
+ const fields = await renderContract({
1338
1448
  renderer,
1339
1449
  source,
1340
1450
  field: `error ${variant.tag}`,
@@ -1348,23 +1458,23 @@ function inspectEndpointErrors(input) {
1348
1458
  }
1349
1459
  return Result.succeed(errors);
1350
1460
  }
1351
- function inspectClientProject(input) {
1461
+ async function inspectClientProject(input) {
1352
1462
  const { checker } = input;
1353
1463
  const views = [];
1354
1464
  const applications = /* @__PURE__ */ new Map();
1355
1465
  const publicUrlSites = [];
1356
1466
  const sourceTexts = /* @__PURE__ */ new Map();
1357
- for (const { sourceFile, moduleExport } of listRegistrationExports(input)) {
1467
+ for (const { sourceFile, moduleExport } of await listRegistrationExports(input)) {
1358
1468
  const source = {
1359
1469
  filePath: sourceFile.fileName,
1360
1470
  exportName: moduleExport.exportName
1361
1471
  };
1362
- if (findPhantomProperty({
1472
+ if (await findPhantomProperty({
1363
1473
  checker,
1364
1474
  type: moduleExport.type,
1365
1475
  symbolName: "UI_VIEW_TYPES"
1366
1476
  }) !== void 0) {
1367
- const pattern = readLiteralProperty({
1477
+ const pattern = await readLiteralProperty({
1368
1478
  checker,
1369
1479
  type: moduleExport.type,
1370
1480
  name: "pattern"
@@ -1378,10 +1488,10 @@ function inspectClientProject(input) {
1378
1488
  }
1379
1489
  for (const sourceFile of input.files) {
1380
1490
  if (sourceFile.fileName === input.clientEntryFilePath) {
1381
- for (const moduleExport of listModuleExports({
1491
+ for (const moduleExport of await listModuleExports({
1382
1492
  checker,
1383
1493
  sourceFile
1384
- })) if (findPhantomProperty({
1494
+ })) if (await findPhantomProperty({
1385
1495
  checker,
1386
1496
  type: moduleExport.type,
1387
1497
  symbolName: "CLIENT_APPLICATION_TYPES"
@@ -1390,7 +1500,7 @@ function inspectClientProject(input) {
1390
1500
  exportName: moduleExport.exportName
1391
1501
  });
1392
1502
  }
1393
- const sites = collectPublicUrlSites({
1503
+ const sites = await collectPublicUrlSites({
1394
1504
  checker,
1395
1505
  sourceFile
1396
1506
  });
@@ -1414,14 +1524,14 @@ function inspectClientProject(input) {
1414
1524
  });
1415
1525
  }
1416
1526
  /** Whether a symbol is the `getPublicUrl` declared by `vorma/client`, however the module reached it. */
1417
- function matchesPublicUrlSymbol(input) {
1418
- const symbol = (input.symbol.flags & SymbolFlags.Alias) !== 0 ? input.checker.getAliasedSymbol(input.symbol) : input.symbol;
1527
+ async function matchesPublicUrlSymbol(input) {
1528
+ const symbol = (input.symbol.flags & SymbolFlags.Alias) !== 0 ? await input.checker.getAliasedSymbol(input.symbol) : input.symbol;
1419
1529
  if (symbol.name !== "getPublicUrl") return false;
1420
1530
  const declaration = symbol.declarations[0];
1421
1531
  return declaration !== void 0 && String(declaration.path).endsWith("/vorma/dist/client/index.d.ts");
1422
1532
  }
1423
1533
  /** Every call of `getPublicUrl` in one file. A use that is not a direct call with a string literal cannot be replaced by the build. */
1424
- function collectPublicUrlSites(input) {
1534
+ async function collectPublicUrlSites(input) {
1425
1535
  const { checker, sourceFile } = input;
1426
1536
  const sites = [];
1427
1537
  let issue;
@@ -1437,16 +1547,16 @@ function collectPublicUrlSites(input) {
1437
1547
  };
1438
1548
  }
1439
1549
  }
1440
- function visit(node) {
1550
+ async function visit(node) {
1441
1551
  if (issue !== void 0 || isTypeNode(node)) return;
1442
1552
  if (isIdentifier(node) || isPropertyAccessExpression(node) || isElementAccessExpression(node)) {
1443
1553
  const parent = node.parent;
1444
1554
  if (isImportSpecifier(parent) || isImportClause(parent) || isNamespaceImport(parent) || isExportSpecifier(parent)) return;
1445
- const symbol = isElementAccessExpression(node) ? getElementAccessSymbol({
1555
+ const symbol = isElementAccessExpression(node) ? await getElementAccessSymbol({
1446
1556
  checker,
1447
1557
  node
1448
- }) : checker.getSymbolAtLocation(node);
1449
- if (symbol !== void 0 && matchesPublicUrlSymbol({
1558
+ }) : await checker.getSymbolAtLocation(node);
1559
+ if (symbol !== void 0 && await matchesPublicUrlSymbol({
1450
1560
  checker,
1451
1561
  symbol
1452
1562
  })) {
@@ -1472,9 +1582,13 @@ function collectPublicUrlSites(input) {
1472
1582
  return;
1473
1583
  }
1474
1584
  }
1475
- node.forEachChild(visit);
1585
+ const children = [];
1586
+ node.forEachChild((child) => {
1587
+ children.push(child);
1588
+ });
1589
+ for (const child of children) await visit(child);
1476
1590
  }
1477
- visit(sourceFile);
1591
+ await visit(sourceFile);
1478
1592
  return issue === void 0 ? Result.succeed(sites) : Result.fail(issue);
1479
1593
  }
1480
1594
  /** Parentheses and erased TypeScript wrappers preserve the underlying expression. */
@@ -1485,105 +1599,10 @@ function unwrapExpression(node) {
1485
1599
  while (matchesTransparentExpression(node)) node = node.expression;
1486
1600
  return node;
1487
1601
  }
1488
- function getElementAccessSymbol(input) {
1489
- const objectType = input.checker.getTypeAtLocation(input.node.expression);
1490
- const keyType = input.checker.getTypeAtLocation(input.node.argumentExpression);
1491
- return objectType !== void 0 && keyType?.isStringLiteralType() ? input.checker.getPropertyOfType(objectType, keyType.value) : void 0;
1492
- }
1493
- //#endregion
1494
- //#region src/build/typescript-projects.ts
1495
- /** Reads native project membership without loading programs or declaration types. */
1496
- function readTypescriptProjectRoots(input) {
1497
- return withTypescriptApi({
1498
- configDirectory: input.configDirectory,
1499
- useFn: (api) => {
1500
- return openCompilerResource(() => {
1501
- return {
1502
- server: api.parseConfigFile(input.serverTsconfigFilePath).fileNames,
1503
- client: api.parseConfigFile(input.clientTsconfigFilePath).fileNames
1504
- };
1505
- });
1506
- }
1507
- });
1508
- }
1509
- /** Checks actual compiler membership after generation, including restrictive files/include/exclude settings. */
1510
- function checkGeneratedTypeInclusion(input) {
1511
- return withTypescriptProjects({
1512
- ...input,
1513
- useFn: (projects) => {
1514
- const missing = [...input.serverFiles.filter((file) => {
1515
- return projects.server.program.getSourceFileMetadata(file) === void 0;
1516
- }).map((file) => {
1517
- return {
1518
- project: input.serverTsconfigFilePath,
1519
- file
1520
- };
1521
- }), ...input.clientFiles.filter((file) => {
1522
- return projects.client.program.getSourceFileMetadata(file) === void 0;
1523
- }).map((file) => {
1524
- return {
1525
- project: input.clientTsconfigFilePath,
1526
- file
1527
- };
1528
- })];
1529
- return missing.length === 0 ? Effect.void : Effect.fail({
1530
- _tag: "TypescriptProjectError",
1531
- message: missing.map(({ project, file }) => `${project} does not include generated type file ${file}. Include the entry's _vorma directory in that TypeScript project.`).join("\n")
1532
- });
1533
- }
1534
- });
1535
- }
1536
- /** Opens the two configured TypeScript projects for the duration of `useFn`, then closes the checker session. */
1537
- function withTypescriptProjects(input) {
1538
- return withTypescriptApi({
1539
- ...input,
1540
- useFn: (api) => {
1541
- return Effect.scoped(Effect.gen(function* () {
1542
- const projects = findProjects({
1543
- snapshot: yield* Effect.acquireRelease(openCompilerResource(() => {
1544
- return api.updateSnapshot({ openProjects: [input.serverTsconfigFilePath, input.clientTsconfigFilePath] });
1545
- }), (snapshot) => Effect.sync(() => snapshot.dispose())),
1546
- ...input
1547
- });
1548
- return yield* Result.isFailure(projects) ? Effect.fail(projects.failure) : input.useFn(projects.success);
1549
- }));
1550
- }
1551
- });
1552
- }
1553
- function openCompilerResource(fn) {
1554
- return Effect.try({
1555
- try: fn,
1556
- catch: (cause) => {
1557
- return {
1558
- _tag: "TypescriptProjectError",
1559
- message: "Vorma could not read the application's TypeScript projects",
1560
- cause
1561
- };
1562
- }
1563
- });
1564
- }
1565
- function withTypescriptApi(input) {
1566
- return Effect.scoped(Effect.gen(function* () {
1567
- const api = yield* Effect.acquireRelease(openCompilerResource(() => {
1568
- return new API({
1569
- cwd: input.configDirectory,
1570
- ...input.fileSystem === void 0 ? {} : { fs: input.fileSystem }
1571
- });
1572
- }), (api) => Effect.sync(() => api.close()));
1573
- return yield* input.useFn(api);
1574
- }));
1575
- }
1576
- function findProjects(input) {
1577
- const server = input.snapshot.getProject(input.serverTsconfigFilePath);
1578
- const client = input.snapshot.getProject(input.clientTsconfigFilePath);
1579
- if (server === void 0 || client === void 0) return Result.fail({
1580
- _tag: "TypescriptProjectError",
1581
- message: `TypeScript did not load ${server === void 0 ? input.serverTsconfigFilePath : input.clientTsconfigFilePath}`
1582
- });
1583
- return Result.succeed({
1584
- server,
1585
- client
1586
- });
1602
+ async function getElementAccessSymbol(input) {
1603
+ const objectType = await input.checker.getTypeAtLocation(input.node.expression);
1604
+ const keyType = await input.checker.getTypeAtLocation(input.node.argumentExpression);
1605
+ return objectType !== void 0 && keyType?.isStringLiteralType() ? await input.checker.getPropertyOfType(objectType, keyType.value) : void 0;
1587
1606
  }
1588
1607
  //#endregion
1589
1608
  //#region src/build/compile-application.ts
@@ -3211,4 +3230,4 @@ function buildApplication(input) {
3211
3230
  }));
3212
3231
  }
3213
3232
  //#endregion
3214
- export { toContentDigest as C, encodeCanonicalJson as S, compileServerApplication as _, acquireOutputOwnership as a, getClientViewEntries as b, writeAndCheckApplicationGeneration as c, withTypescriptProjects as d, inspectProjects as f, createClientPublicUrlPlugin as g, createCssPublicAssets as h, publishApplicationArtifacts as i, collectPublicAssets as l, resolveVormaConfig as m, loadApplicationSourceLayout as n, checkOutputPath as o, getGeneratedSourceDirectories as p, preparePublicOutput as r, assembleApplicationGeneration as s, buildApplication as t, readTypescriptProjectRoots as u, containsRelativePath as v, projectBrowserContracts as x, CLIENT_SHARED_PACKAGES as y };
3233
+ export { encodeCanonicalJson as C, projectBrowserContracts as S, createClientPublicUrlPlugin as _, acquireOutputOwnership as a, CLIENT_SHARED_PACKAGES as b, writeAndCheckApplicationGeneration as c, readTypescriptProjectRoots as d, runTypescriptOperation as f, createCssPublicAssets as g, resolveVormaConfig as h, publishApplicationArtifacts as i, collectPublicAssets as l, getGeneratedSourceDirectories as m, loadApplicationSourceLayout as n, checkOutputPath as o, withTypescriptProjects as p, preparePublicOutput as r, assembleApplicationGeneration as s, buildApplication as t, inspectProjects as u, compileServerApplication as v, toContentDigest as w, getClientViewEntries as x, containsRelativePath as y };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sjcx/vorma",
3
- "version": "0.0.0-pre.0",
3
+ "version": "0.0.0-pre.1",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "license": "MIT",
@@ -42,7 +42,7 @@
42
42
  "@effect/platform-node-shared": "^4.0.0-rc.115",
43
43
  "@noble/hashes": "^2.4.0",
44
44
  "@scure/base": "^2.4.0",
45
- "@vorma/primitives": "npm:@sjcx/vorma-primitives@0.0.0-pre.0",
45
+ "@vorma/primitives": "npm:@sjcx/vorma-primitives@0.0.0-pre.1",
46
46
  "chokidar": "^5.0.0",
47
47
  "lightningcss": "^1.33.0",
48
48
  "rolldown": "^1.2.6",