@supacloud/compiler 0.56.0 → 0.57.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -14
- package/dist/api-source.d.ts +6 -5
- package/dist/cli.js +2064 -1829
- package/dist/command-boundary.d.ts +2 -2
- package/dist/database-contracts.d.ts +2 -2
- package/dist/delivery-bundle-worker.js +118 -78
- package/dist/delivery-imports.d.ts +1 -1
- package/dist/di-resolution.d.ts +39 -0
- package/dist/diagnostics.js +62 -22
- package/dist/graphql-runtime.d.ts +1 -1
- package/dist/http-provider-migration.d.ts +3 -3
- package/dist/incremental.d.ts +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2055 -1820
- package/dist/inspect.d.ts +1 -1
- package/dist/migration-app-version.d.ts +1 -1
- package/dist/migration-elysia-version.d.ts +1 -1
- package/dist/migrations.d.ts +2 -2
- package/dist/program.d.ts +7 -19
- package/dist/reactive-analysis.d.ts +2 -2
- package/dist/source-semantics.d.ts +2 -2
- package/dist/sql-safety.d.ts +3 -3
- package/dist/static-di.d.ts +2 -2
- package/dist/traits.d.ts +1 -1
- package/dist/type-safety.d.ts +2 -2
- package/dist/types.d.ts +20 -3
- package/dist/typescript.d.ts +1 -0
- package/package.json +12 -10
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import * as ts from "@typescript
|
|
1
|
+
import * as ts from "@supacloud/db/typescript";
|
|
2
2
|
import type { Diagnostic } from "./types";
|
|
3
3
|
interface GovernedClass {
|
|
4
4
|
declaration: ts.ClassDeclaration;
|
|
5
5
|
name: string;
|
|
6
6
|
}
|
|
7
7
|
/** A conservative source check for typed command references, not a JavaScript sandbox. */
|
|
8
|
-
export declare function scanCommandBoundaries(source: ts.SourceFile, file: string, checker: ts.TypeChecker, commands: readonly GovernedClass[], boundRoutes: ReadonlyMap<ts.MethodDeclaration, string>): Diagnostic[]
|
|
8
|
+
export declare function scanCommandBoundaries(source: ts.SourceFile, file: string, checker: ts.TypeChecker, commands: readonly GovernedClass[], boundRoutes: ReadonlyMap<ts.MethodDeclaration, string>): Promise<Diagnostic[]>;
|
|
9
9
|
export {};
|
|
@@ -5,8 +5,8 @@ export interface DatabaseContractsOptions {
|
|
|
5
5
|
outDir: string;
|
|
6
6
|
/** Official PostgREST snapshot. Omit when the project does not use PostgREST. */
|
|
7
7
|
postgrestTypes?: string;
|
|
8
|
-
/**
|
|
9
|
-
|
|
8
|
+
/** ZenStack query-builder module. Omit when the project does not use ZenStack. */
|
|
9
|
+
modelSchema?: string;
|
|
10
10
|
/** Explicit identity/role label for reviewing snapshot provenance. Not an authorization proof. */
|
|
11
11
|
role: string;
|
|
12
12
|
/** Role-scoped pg_graphql snapshot exported by graphql-schema. Omit when GraphQL is unused. */
|
|
@@ -23,6 +23,43 @@ var __esm = (fn, res, err) => () => {
|
|
|
23
23
|
throw err[0];
|
|
24
24
|
return res;
|
|
25
25
|
};
|
|
26
|
+
var __dispose = Symbol.dispose || /* @__PURE__ */ Symbol.for("Symbol.dispose");
|
|
27
|
+
var __asyncDispose = Symbol.asyncDispose || /* @__PURE__ */ Symbol.for("Symbol.asyncDispose");
|
|
28
|
+
var __using = (stack, value, async) => {
|
|
29
|
+
if (value != null) {
|
|
30
|
+
if (typeof value !== "object" && typeof value !== "function")
|
|
31
|
+
throw TypeError('Object expected to be assigned to "using" declaration');
|
|
32
|
+
var dispose;
|
|
33
|
+
if (async)
|
|
34
|
+
dispose = value[__asyncDispose];
|
|
35
|
+
if (dispose === undefined)
|
|
36
|
+
dispose = value[__dispose];
|
|
37
|
+
if (typeof dispose !== "function")
|
|
38
|
+
throw TypeError("Object not disposable");
|
|
39
|
+
stack.push([async, dispose, value]);
|
|
40
|
+
} else if (async) {
|
|
41
|
+
stack.push([async]);
|
|
42
|
+
}
|
|
43
|
+
return value;
|
|
44
|
+
};
|
|
45
|
+
var __callDispose = (stack, error, hasError) => {
|
|
46
|
+
var E = typeof SuppressedError === "function" ? SuppressedError : function(e, s, m, _) {
|
|
47
|
+
return _ = Error(m), _.name = "SuppressedError", _.error = e, _.suppressed = s, _;
|
|
48
|
+
}, fail = (e) => error = hasError ? new E(e, error, "An error was suppressed during disposal") : (hasError = true, e), next = (it) => {
|
|
49
|
+
while (it = stack.pop()) {
|
|
50
|
+
try {
|
|
51
|
+
var result = it[1] && it[1].call(it[2]);
|
|
52
|
+
if (it[0])
|
|
53
|
+
return Promise.resolve(result).then(next, (e) => (fail(e), next()));
|
|
54
|
+
} catch (e) {
|
|
55
|
+
fail(e);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (hasError)
|
|
59
|
+
throw error;
|
|
60
|
+
};
|
|
61
|
+
return next();
|
|
62
|
+
};
|
|
26
63
|
|
|
27
64
|
// node_modules/typebox/build/system/arguments/arguments.mjs
|
|
28
65
|
function Match(args, match) {
|
|
@@ -10513,88 +10550,91 @@ init_delivery_files2();
|
|
|
10513
10550
|
import { isBuiltin } from "node:module";
|
|
10514
10551
|
import { readFile as readFile2 } from "node:fs/promises";
|
|
10515
10552
|
import { join as join2, resolve as resolve3 } from "node:path";
|
|
10516
|
-
import * as ts2 from "@typescript
|
|
10553
|
+
import * as ts2 from "@supacloud/db/typescript";
|
|
10517
10554
|
|
|
10518
10555
|
// src/delivery-imports.ts
|
|
10519
|
-
import * as ts from "@typescript
|
|
10520
|
-
function staticDeliveryImports(path, contents) {
|
|
10521
|
-
|
|
10522
|
-
|
|
10523
|
-
|
|
10524
|
-
|
|
10525
|
-
|
|
10526
|
-
|
|
10527
|
-
|
|
10528
|
-
|
|
10529
|
-
|
|
10530
|
-
|
|
10531
|
-
|
|
10532
|
-
|
|
10533
|
-
scan(source);
|
|
10534
|
-
if (computed.length === 0)
|
|
10535
|
-
return contents;
|
|
10536
|
-
const reject = () => {
|
|
10537
|
-
throw new Error("Computed module loading is not supported in independent delivery bundles.");
|
|
10538
|
-
};
|
|
10539
|
-
if (!ts.isExternalModule(source))
|
|
10540
|
-
return reject();
|
|
10541
|
-
const host = ts.createCompilerHost({ noLib: true, noResolve: true, allowJs: true });
|
|
10542
|
-
host.getSourceFile = (name) => name === path ? source : undefined;
|
|
10543
|
-
const checker = ts.createProgram([path], { noLib: true, noResolve: true, allowJs: true }, host).getTypeChecker();
|
|
10544
|
-
const replacements = new Map;
|
|
10545
|
-
const removed = new Set;
|
|
10546
|
-
for (const call of computed) {
|
|
10547
|
-
let visit = function(node) {
|
|
10548
|
-
const referenced = ts.isIdentifier(node) ? ts.isShorthandPropertyAssignment(node.parent) ? checker.getShorthandAssignmentValueSymbol(node.parent) : ts.isExportSpecifier(node.parent) ? checker.getExportSpecifierLocalTargetSymbol(node.parent) : checker.getSymbolAtLocation(node) : undefined;
|
|
10549
|
-
if (ts.isIdentifier(node) && node !== declarationName && referenced === symbol) {
|
|
10550
|
-
const use = node.parent;
|
|
10551
|
-
if (!ts.isCallExpression(use) || use.expression !== node || use.arguments.length !== 1 || use.questionDotToken || use.typeArguments?.length)
|
|
10552
|
-
return reject();
|
|
10553
|
-
const value = use.arguments[0];
|
|
10554
|
-
if (!value || !ts.isStringLiteral(value) && !ts.isNoSubstitutionTemplateLiteral(value))
|
|
10555
|
-
return reject();
|
|
10556
|
-
references++;
|
|
10557
|
-
replacements.set(use, ts.factory.createCallExpression(call.expression, undefined, [value]));
|
|
10556
|
+
import * as ts from "@supacloud/db/typescript";
|
|
10557
|
+
async function staticDeliveryImports(path, contents) {
|
|
10558
|
+
let __stack = [];
|
|
10559
|
+
try {
|
|
10560
|
+
if (!/\.[cm]?[jt]sx?$/.test(path))
|
|
10561
|
+
return contents;
|
|
10562
|
+
const syntax = await ts.createSourceFile(path, new TextDecoder().decode(contents));
|
|
10563
|
+
let source = syntax;
|
|
10564
|
+
const computed = [];
|
|
10565
|
+
function scan(node) {
|
|
10566
|
+
if (ts.isCallExpression(node) && (node.expression.kind === ts.SyntaxKind.ImportKeyword || ts.isIdentifier(node.expression) && node.expression.text === "require")) {
|
|
10567
|
+
const argument = node.arguments[0];
|
|
10568
|
+
if (!argument || !ts.isStringLiteral(argument) && !ts.isNoSubstitutionTemplateLiteral(argument))
|
|
10569
|
+
computed.push(node);
|
|
10558
10570
|
}
|
|
10559
|
-
ts.forEachChild(node,
|
|
10571
|
+
ts.forEachChild(node, scan);
|
|
10572
|
+
}
|
|
10573
|
+
scan(source);
|
|
10574
|
+
if (computed.length === 0)
|
|
10575
|
+
return contents;
|
|
10576
|
+
const reject = () => {
|
|
10577
|
+
throw new Error("Computed module loading is not supported in independent delivery bundles.");
|
|
10560
10578
|
};
|
|
10561
|
-
|
|
10562
|
-
const block = statement.parent;
|
|
10563
|
-
const declaration = block.parent;
|
|
10564
|
-
if (call.expression.kind !== ts.SyntaxKind.ImportKeyword || call.arguments.length !== 1 || !ts.isReturnStatement(statement) || !ts.isBlock(block) || block.statements.length !== 1 || !ts.isFunctionDeclaration(declaration) || declaration.parent !== source || !declaration.name || declaration.modifiers?.length || declaration.asteriskToken || declaration.typeParameters?.length || declaration.parameters.length !== 1)
|
|
10565
|
-
return reject();
|
|
10566
|
-
const parameter = declaration.parameters[0];
|
|
10567
|
-
const argument = call.arguments[0];
|
|
10568
|
-
if (!parameter || !ts.isIdentifier(parameter.name) || parameter.initializer || parameter.dotDotDotToken || !argument || !ts.isIdentifier(argument) || checker.getSymbolAtLocation(argument) !== checker.getSymbolAtLocation(parameter.name))
|
|
10569
|
-
return reject();
|
|
10570
|
-
const symbol = checker.getSymbolAtLocation(declaration.name);
|
|
10571
|
-
if (!symbol || symbol.declarations?.length !== 1)
|
|
10579
|
+
if (!ts.isExternalModule(source))
|
|
10572
10580
|
return reject();
|
|
10573
|
-
const
|
|
10574
|
-
|
|
10575
|
-
|
|
10576
|
-
if (references === 0)
|
|
10577
|
-
return reject();
|
|
10578
|
-
removed.add(declaration);
|
|
10579
|
-
}
|
|
10580
|
-
const transformed = ts.transform(source, [(context) => {
|
|
10581
|
-
const visit = (node) => {
|
|
10582
|
-
if (ts.isFunctionDeclaration(node) && removed.has(node))
|
|
10583
|
-
return;
|
|
10584
|
-
const replacement = ts.isCallExpression(node) ? replacements.get(node) : undefined;
|
|
10585
|
-
if (replacement)
|
|
10586
|
-
return replacement;
|
|
10587
|
-
return ts.visitEachChild(node, visit, context);
|
|
10588
|
-
};
|
|
10589
|
-
return (node) => ts.visitNode(node, visit, ts.isSourceFile) ?? node;
|
|
10590
|
-
}]);
|
|
10591
|
-
try {
|
|
10592
|
-
const transformedSource = transformed.transformed[0];
|
|
10593
|
-
if (!transformedSource)
|
|
10581
|
+
const program = __using(__stack, await ts.createProgram([path], { noLib: true, noResolve: true, allowJs: true }, { sources: new Map([[path, source.text]]) }), 1);
|
|
10582
|
+
const boundSource = program.getSourceFile(path);
|
|
10583
|
+
if (!boundSource)
|
|
10594
10584
|
return reject();
|
|
10595
|
-
|
|
10585
|
+
computed.length = 0;
|
|
10586
|
+
source = boundSource;
|
|
10587
|
+
scan(source);
|
|
10588
|
+
const checker = program.getTypeChecker();
|
|
10589
|
+
const replacements = new Map;
|
|
10590
|
+
const removed = new Set;
|
|
10591
|
+
for (const call of computed) {
|
|
10592
|
+
const statement = call.parent;
|
|
10593
|
+
const block = statement.parent;
|
|
10594
|
+
const declaration = block.parent;
|
|
10595
|
+
if (call.expression.kind !== ts.SyntaxKind.ImportKeyword || call.arguments.length !== 1 || !ts.isReturnStatement(statement) || !ts.isBlock(block) || block.statements.length !== 1 || !ts.isFunctionDeclaration(declaration) || declaration.parent !== source || !declaration.name || declaration.modifiers?.length || declaration.asteriskToken || declaration.typeParameters?.length || declaration.parameters.length !== 1)
|
|
10596
|
+
return reject();
|
|
10597
|
+
const parameter = declaration.parameters[0];
|
|
10598
|
+
const argument = call.arguments[0];
|
|
10599
|
+
if (!parameter || !ts.isIdentifier(parameter.name) || parameter.initializer || parameter.dotDotDotToken || !argument || !ts.isIdentifier(argument) || await checker.getSymbolAtLocation(argument) !== await checker.getSymbolAtLocation(parameter.name))
|
|
10600
|
+
return reject();
|
|
10601
|
+
const symbol = await checker.getSymbolAtLocation(declaration.name);
|
|
10602
|
+
if (!symbol || symbol.declarations?.length !== 1)
|
|
10603
|
+
return reject();
|
|
10604
|
+
const declarationName = declaration.name;
|
|
10605
|
+
let references = 0;
|
|
10606
|
+
async function visit(node) {
|
|
10607
|
+
const referenced = ts.isIdentifier(node) ? ts.isShorthandPropertyAssignment(node.parent) ? await checker.getShorthandAssignmentValueSymbol(node.parent) : ts.isExportSpecifier(node.parent) ? await checker.getExportSpecifierLocalTargetSymbol(node.parent) : await checker.getSymbolAtLocation(node) : undefined;
|
|
10608
|
+
if (ts.isIdentifier(node) && node !== declarationName && referenced === symbol) {
|
|
10609
|
+
const use = node.parent;
|
|
10610
|
+
if (!ts.isCallExpression(use) || use.expression !== node || use.arguments.length !== 1 || use.questionDotToken || use.typeArguments?.length)
|
|
10611
|
+
return reject();
|
|
10612
|
+
const value = use.arguments[0];
|
|
10613
|
+
if (!value || !ts.isStringLiteral(value) && !ts.isNoSubstitutionTemplateLiteral(value))
|
|
10614
|
+
return reject();
|
|
10615
|
+
references++;
|
|
10616
|
+
replacements.set(use, `import(${value.getText(source)})`);
|
|
10617
|
+
}
|
|
10618
|
+
await ts.forEachChildAsync(node, visit);
|
|
10619
|
+
}
|
|
10620
|
+
await visit(source);
|
|
10621
|
+
if (references === 0)
|
|
10622
|
+
return reject();
|
|
10623
|
+
removed.add(declaration);
|
|
10624
|
+
}
|
|
10625
|
+
const edits = [
|
|
10626
|
+
...[...removed].map((node) => ({ start: node.getStart(source), end: node.end, text: "" })),
|
|
10627
|
+
...[...replacements].map(([node, text]) => ({ start: node.getStart(source), end: node.end, text }))
|
|
10628
|
+
].sort((a, b) => b.start - a.start);
|
|
10629
|
+
let output = source.text;
|
|
10630
|
+
for (const edit of edits)
|
|
10631
|
+
output = output.slice(0, edit.start) + edit.text + output.slice(edit.end);
|
|
10632
|
+
return new TextEncoder().encode(output);
|
|
10633
|
+
} catch (_catch) {
|
|
10634
|
+
var _err = _catch, _hasErr = 1;
|
|
10596
10635
|
} finally {
|
|
10597
|
-
|
|
10636
|
+
var _promise = __callDispose(__stack, _err, _hasErr);
|
|
10637
|
+
_promise && await _promise;
|
|
10598
10638
|
}
|
|
10599
10639
|
}
|
|
10600
10640
|
|
|
@@ -10718,7 +10758,7 @@ async function bundleDeliveryTargetInProcess(name, code, project, generatedDirec
|
|
|
10718
10758
|
return { contents: code, loader: "ts" };
|
|
10719
10759
|
const bytes = await readFile2(args.path);
|
|
10720
10760
|
inputs.set(resolve3(args.path), digest(bytes));
|
|
10721
|
-
return { contents: staticDeliveryImports(args.path, bytes), loader: args.loader };
|
|
10761
|
+
return { contents: await staticDeliveryImports(args.path, bytes), loader: args.loader };
|
|
10722
10762
|
});
|
|
10723
10763
|
}
|
|
10724
10764
|
}]
|
|
@@ -10746,7 +10786,7 @@ async function bundleDeliveryTargetInProcess(name, code, project, generatedDirec
|
|
|
10746
10786
|
if (/\.[cm]?js$/.test(path)) {
|
|
10747
10787
|
let check = function(node) {
|
|
10748
10788
|
const specifier = ts2.isImportDeclaration(node) || ts2.isExportDeclaration(node) ? node.moduleSpecifier : ts2.isCallExpression(node) && (node.expression.kind === ts2.SyntaxKind.ImportKeyword || ts2.isIdentifier(node.expression) && /^(?:__)?require$/.test(node.expression.text) || ts2.isPropertyAccessExpression(node.expression) && node.expression.name.text === "require" && ts2.isMetaProperty(node.expression.expression) && node.expression.expression.keywordToken === ts2.SyntaxKind.ImportKeyword) ? node.arguments[0] : undefined;
|
|
10749
|
-
if (specifier && ts2.
|
|
10789
|
+
if (specifier && ts2.isStringLiteralLikeNode(specifier)) {
|
|
10750
10790
|
if (!isBuiltin(specifier.text) && specifier.text !== "bun" && !specifier.text.startsWith("bun:")) {
|
|
10751
10791
|
throw new Error("Independent bundles cannot retain external package imports.");
|
|
10752
10792
|
}
|
|
@@ -10754,7 +10794,7 @@ async function bundleDeliveryTargetInProcess(name, code, project, generatedDirec
|
|
|
10754
10794
|
}
|
|
10755
10795
|
ts2.forEachChild(node, check);
|
|
10756
10796
|
};
|
|
10757
|
-
const source = ts2.createSourceFile(path, new TextDecoder().decode(bytes), ts2.ScriptTarget.Latest, true);
|
|
10797
|
+
const source = await ts2.createSourceFile(path, new TextDecoder().decode(bytes), ts2.ScriptTarget.Latest, true);
|
|
10758
10798
|
check(source);
|
|
10759
10799
|
}
|
|
10760
10800
|
files.set(`bundle/${path}`, bytes);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** Resolve private literal-only import wrappers without permitting an open dependency set. */
|
|
2
|
-
export declare function staticDeliveryImports(path: string, contents: Uint8Array): Uint8Array
|
|
2
|
+
export declare function staticDeliveryImports(path: string, contents: Uint8Array): Promise<Uint8Array>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { ApplicationGraph, ControllerNode, Diagnostic, ModuleNode, ProviderNode, Scope } from "./types";
|
|
2
|
+
export interface DependencyFlags {
|
|
3
|
+
self?: boolean;
|
|
4
|
+
skipSelf?: boolean;
|
|
5
|
+
}
|
|
6
|
+
export interface StaticProvider {
|
|
7
|
+
module: ModuleNode;
|
|
8
|
+
provider: ProviderNode;
|
|
9
|
+
}
|
|
10
|
+
export type DependencyResolution = {
|
|
11
|
+
kind: "provider";
|
|
12
|
+
relation: "local" | "imported" | "root";
|
|
13
|
+
target: StaticProvider;
|
|
14
|
+
} | {
|
|
15
|
+
kind: "context";
|
|
16
|
+
scope: "request" | "job";
|
|
17
|
+
} | {
|
|
18
|
+
kind: "external";
|
|
19
|
+
} | {
|
|
20
|
+
kind: "missing";
|
|
21
|
+
} | {
|
|
22
|
+
kind: "ambiguous";
|
|
23
|
+
candidates: StaticProvider[];
|
|
24
|
+
};
|
|
25
|
+
export declare function dependencyFlags(owner: Pick<ProviderNode | ControllerNode, "dependencyOptions" | "optionalDeps" | "selfDeps" | "skipSelfDeps" | "hostDeps">, token: string, index?: number): {
|
|
26
|
+
optional: boolean;
|
|
27
|
+
self: boolean;
|
|
28
|
+
skipSelf: boolean;
|
|
29
|
+
host: boolean;
|
|
30
|
+
};
|
|
31
|
+
/** Follow only explicit public exports; a diamond preserves the original instance. */
|
|
32
|
+
export declare function exportedProviders(graph: ApplicationGraph, module: ModuleNode, token: string, seen?: Set<string>): StaticProvider[];
|
|
33
|
+
/** One compile-time resolution rule for validation, generated factories and manifests. */
|
|
34
|
+
export declare function resolveDependency(graph: ApplicationGraph, module: ModuleNode, token: string, scope?: Scope, flags?: DependencyFlags): DependencyResolution;
|
|
35
|
+
/** Includes implicit root dependencies required before a module factory can run. */
|
|
36
|
+
export declare function moduleDependencies(graph: ApplicationGraph, module: ModuleNode): string[];
|
|
37
|
+
export declare function scopeCanDependOn(owner: Scope, dependency: Scope): boolean;
|
|
38
|
+
/** Invalid static wiring never becomes an executable artifact, including writeOnError. */
|
|
39
|
+
export declare function blocksStaticCompilation(diagnostic: Diagnostic): boolean;
|
package/dist/diagnostics.js
CHANGED
|
@@ -23,6 +23,43 @@ var __esm = (fn, res, err) => () => {
|
|
|
23
23
|
throw err[0];
|
|
24
24
|
return res;
|
|
25
25
|
};
|
|
26
|
+
var __dispose = Symbol.dispose || /* @__PURE__ */ Symbol.for("Symbol.dispose");
|
|
27
|
+
var __asyncDispose = Symbol.asyncDispose || /* @__PURE__ */ Symbol.for("Symbol.asyncDispose");
|
|
28
|
+
var __using = (stack, value, async) => {
|
|
29
|
+
if (value != null) {
|
|
30
|
+
if (typeof value !== "object" && typeof value !== "function")
|
|
31
|
+
throw TypeError('Object expected to be assigned to "using" declaration');
|
|
32
|
+
var dispose;
|
|
33
|
+
if (async)
|
|
34
|
+
dispose = value[__asyncDispose];
|
|
35
|
+
if (dispose === undefined)
|
|
36
|
+
dispose = value[__dispose];
|
|
37
|
+
if (typeof dispose !== "function")
|
|
38
|
+
throw TypeError("Object not disposable");
|
|
39
|
+
stack.push([async, dispose, value]);
|
|
40
|
+
} else if (async) {
|
|
41
|
+
stack.push([async]);
|
|
42
|
+
}
|
|
43
|
+
return value;
|
|
44
|
+
};
|
|
45
|
+
var __callDispose = (stack, error, hasError) => {
|
|
46
|
+
var E = typeof SuppressedError === "function" ? SuppressedError : function(e, s, m, _) {
|
|
47
|
+
return _ = Error(m), _.name = "SuppressedError", _.error = e, _.suppressed = s, _;
|
|
48
|
+
}, fail = (e) => error = hasError ? new E(e, error, "An error was suppressed during disposal") : (hasError = true, e), next = (it) => {
|
|
49
|
+
while (it = stack.pop()) {
|
|
50
|
+
try {
|
|
51
|
+
var result = it[1] && it[1].call(it[2]);
|
|
52
|
+
if (it[0])
|
|
53
|
+
return Promise.resolve(result).then(next, (e) => (fail(e), next()));
|
|
54
|
+
} catch (e) {
|
|
55
|
+
fail(e);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (hasError)
|
|
59
|
+
throw error;
|
|
60
|
+
};
|
|
61
|
+
return next();
|
|
62
|
+
};
|
|
26
63
|
|
|
27
64
|
// src/repair-plan.ts
|
|
28
65
|
function createDiagnosticRepairPlan(diagnostics) {
|
|
@@ -71,7 +108,7 @@ function classifyFix(fix) {
|
|
|
71
108
|
import { createHash, randomUUID } from "node:crypto";
|
|
72
109
|
import { lstat, readFile, realpath, rename, unlink, writeFile } from "node:fs/promises";
|
|
73
110
|
import { dirname, isAbsolute, relative, resolve, sep } from "node:path";
|
|
74
|
-
import * as ts from "@typescript
|
|
111
|
+
import * as ts from "@supacloud/db/typescript";
|
|
75
112
|
async function applyDiagnosticFix(fix, options = {}) {
|
|
76
113
|
if (!fix || typeof fix.targetFile !== "string")
|
|
77
114
|
throw new Error("Invalid DiagnosticFix");
|
|
@@ -88,7 +125,8 @@ async function applyDiagnosticFix(fix, options = {}) {
|
|
|
88
125
|
if (options.expectedSourceHash !== undefined && options.expectedSourceHash !== sourceHash) {
|
|
89
126
|
throw new Error("Fix source changed since preview; analyze the project again");
|
|
90
127
|
}
|
|
91
|
-
|
|
128
|
+
const originalSource = await parse(file, original);
|
|
129
|
+
let source = originalSource;
|
|
92
130
|
let content;
|
|
93
131
|
switch (fix.type) {
|
|
94
132
|
case "set_command_mode": {
|
|
@@ -100,15 +138,16 @@ async function applyDiagnosticFix(fix, options = {}) {
|
|
|
100
138
|
if (!current || current.initializer.getText(source) !== fix.expectedExpression) {
|
|
101
139
|
throw new Error("Command mode changed since diagnosis; analyze the project again");
|
|
102
140
|
}
|
|
103
|
-
content = replaceProperty(source, object, fix.property, ts.factory.createStringLiteral(fix.value));
|
|
141
|
+
content = await replaceProperty(source, object, fix.property, ts.factory.createStringLiteral(fix.value, ts.TokenFlags.None));
|
|
104
142
|
break;
|
|
105
143
|
}
|
|
106
144
|
case "add_module_import": {
|
|
107
145
|
if (!fix.importPath || !fix.symbol)
|
|
108
146
|
throw new Error("Module fix requires importPath and symbol");
|
|
109
147
|
identifier(fix.symbol);
|
|
110
|
-
const withImport = importSymbol(source, fix.importPath, fix.symbol);
|
|
111
|
-
|
|
148
|
+
const withImport = await importSymbol(source, fix.importPath, fix.symbol);
|
|
149
|
+
const importedSource = await parse(file, withImport);
|
|
150
|
+
source = importedSource;
|
|
112
151
|
const object = unique(moduleObjects(source).filter((candidate) => !fix.targetModule || stringProperty(candidate, "name") === fix.targetModule), "target module");
|
|
113
152
|
const imports = property(object, "imports");
|
|
114
153
|
if (imports && !ts.isArrayLiteralExpression(imports.initializer)) {
|
|
@@ -117,7 +156,7 @@ async function applyDiagnosticFix(fix, options = {}) {
|
|
|
117
156
|
const values = imports && ts.isArrayLiteralExpression(imports.initializer) ? imports.initializer.elements : [];
|
|
118
157
|
if (values.some(ts.isSpreadElement))
|
|
119
158
|
throw new Error("Module imports cannot contain spread elements");
|
|
120
|
-
content = values.some((value) => ts.isIdentifier(value) && value.text === fix.symbol) ? withImport : replaceProperty(source, object, "imports", ts.factory.createArrayLiteralExpression([
|
|
159
|
+
content = values.some((value) => ts.isIdentifier(value) && value.text === fix.symbol) ? withImport : await replaceProperty(source, object, "imports", ts.factory.createArrayLiteralExpression([
|
|
121
160
|
...values,
|
|
122
161
|
ts.factory.createIdentifier(fix.symbol)
|
|
123
162
|
]));
|
|
@@ -134,7 +173,7 @@ async function applyDiagnosticFix(fix, options = {}) {
|
|
|
134
173
|
if (current && (!ts.isStringLiteral(current.initializer) || current.initializer.text !== permission)) {
|
|
135
174
|
throw new Error("Command permission already exists with a different value");
|
|
136
175
|
}
|
|
137
|
-
content = current ? original : replaceProperty(source, object, "permission", ts.factory.createStringLiteral(permission));
|
|
176
|
+
content = current ? original : await replaceProperty(source, object, "permission", ts.factory.createStringLiteral(permission, ts.TokenFlags.None));
|
|
138
177
|
break;
|
|
139
178
|
}
|
|
140
179
|
case "add_route_parameter_binding": {
|
|
@@ -152,13 +191,14 @@ async function applyDiagnosticFix(fix, options = {}) {
|
|
|
152
191
|
throw new Error("Framework import must be static");
|
|
153
192
|
}
|
|
154
193
|
const edited = original.slice(0, parameter.getStart(source)) + `@${binding}(${JSON.stringify(fix.parameter)}) ` + original.slice(parameter.getStart(source));
|
|
155
|
-
|
|
194
|
+
const editedSource = await parse(file, edited);
|
|
195
|
+
content = await importSymbol(editedSource, framework.moduleSpecifier.text, binding);
|
|
156
196
|
break;
|
|
157
197
|
}
|
|
158
198
|
default:
|
|
159
199
|
throw new Error(`Diagnostic fix '${fix.type}' requires a manual semantic decision; no files changed`);
|
|
160
200
|
}
|
|
161
|
-
parse(file, content);
|
|
201
|
+
await parse(file, content);
|
|
162
202
|
const result = { file, changed: content !== original, content, sourceHash };
|
|
163
203
|
if (options.dryRun === false && result.changed) {
|
|
164
204
|
const temporary = `${file}.supacloud-fix-${randomUUID()}`;
|
|
@@ -173,8 +213,8 @@ async function applyDiagnosticFix(fix, options = {}) {
|
|
|
173
213
|
}
|
|
174
214
|
return result;
|
|
175
215
|
}
|
|
176
|
-
function parse(file, text) {
|
|
177
|
-
const result = ts.transpileModule(text, {
|
|
216
|
+
async function parse(file, text) {
|
|
217
|
+
const result = await ts.transpileModule(text, {
|
|
178
218
|
fileName: file,
|
|
179
219
|
reportDiagnostics: true,
|
|
180
220
|
compilerOptions: { target: ts.ScriptTarget.ESNext, experimentalDecorators: true }
|
|
@@ -182,7 +222,7 @@ function parse(file, text) {
|
|
|
182
222
|
if (result.diagnostics?.some((item) => item.category === ts.DiagnosticCategory.Error)) {
|
|
183
223
|
throw new Error("Cannot fix syntactically invalid TypeScript");
|
|
184
224
|
}
|
|
185
|
-
return ts.createSourceFile(file, text, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
225
|
+
return await ts.createSourceFile(file, text, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
186
226
|
}
|
|
187
227
|
function unique(items, description) {
|
|
188
228
|
const [item] = items;
|
|
@@ -213,14 +253,14 @@ function stringProperty(object, key) {
|
|
|
213
253
|
const value = property(object, key)?.initializer;
|
|
214
254
|
return value && ts.isStringLiteral(value) ? value.text : undefined;
|
|
215
255
|
}
|
|
216
|
-
function replaceProperty(source, object, key, value) {
|
|
256
|
+
async function replaceProperty(source, object, key, value) {
|
|
217
257
|
const previous = property(object, key);
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
const
|
|
223
|
-
return source.text.slice(0,
|
|
258
|
+
const text = await ts.printNode(value);
|
|
259
|
+
if (previous)
|
|
260
|
+
return source.text.slice(0, previous.initializer.getStart(source)) + text + source.text.slice(previous.initializer.end);
|
|
261
|
+
const position = object.end - 1;
|
|
262
|
+
const separator = object.properties.length && !object.properties.hasTrailingComma ? "," : "";
|
|
263
|
+
return source.text.slice(0, position) + `${separator} ${key}: ${text}` + source.text.slice(position);
|
|
224
264
|
}
|
|
225
265
|
function findClass(source, name) {
|
|
226
266
|
return unique(source.statements.filter((statement) => ts.isClassDeclaration(statement) && statement.name?.text === name), `class '${name}'`);
|
|
@@ -249,7 +289,7 @@ function moduleObjects(source) {
|
|
|
249
289
|
}
|
|
250
290
|
return result;
|
|
251
291
|
}
|
|
252
|
-
function importSymbol(source, path, symbol) {
|
|
292
|
+
async function importSymbol(source, path, symbol) {
|
|
253
293
|
identifier(symbol);
|
|
254
294
|
const current = resolve(source.fileName).replace(/\.(tsx?|mts|cts)$/, "");
|
|
255
295
|
const target = resolve(dirname(source.fileName), path).replace(/\.(tsx?|mts|cts)$/, "");
|
|
@@ -259,7 +299,7 @@ function importSymbol(source, path, symbol) {
|
|
|
259
299
|
if (matches.length > 1)
|
|
260
300
|
throw new Error(`Ambiguous imports from '${path}'`);
|
|
261
301
|
const match = matches[0];
|
|
262
|
-
if (match && ts.isImportDeclaration(match) && match.importClause?.namedBindings && ts.isNamedImports(match.importClause.namedBindings) &&
|
|
302
|
+
if (match && ts.isImportDeclaration(match) && match.importClause?.namedBindings && ts.isNamedImports(match.importClause.namedBindings) && match.importClause.phaseModifier !== ts.SyntaxKind.TypeKeyword) {
|
|
263
303
|
if (match.importClause.namedBindings.elements.some((item) => item.name.text === symbol))
|
|
264
304
|
return source.text;
|
|
265
305
|
const bindings = match.importClause.namedBindings;
|
|
@@ -267,7 +307,7 @@ function importSymbol(source, path, symbol) {
|
|
|
267
307
|
...bindings.elements,
|
|
268
308
|
ts.factory.createImportSpecifier(false, undefined, ts.factory.createIdentifier(symbol))
|
|
269
309
|
]);
|
|
270
|
-
return source.text.slice(0, bindings.getStart(source)) + ts.
|
|
310
|
+
return source.text.slice(0, bindings.getStart(source)) + await ts.printNode(updated) + source.text.slice(bindings.end);
|
|
271
311
|
}
|
|
272
312
|
if (match)
|
|
273
313
|
throw new Error(`Import from '${path}' is not a named value import`);
|
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
* selections, fragments and conditional fields. Unsupported wire types fail closed.
|
|
4
4
|
*/
|
|
5
5
|
export type GraphqlOperationKind = "query" | "mutation";
|
|
6
|
-
export declare function renderGraphqlValidators(source: string, operationNames: readonly string[], operationKinds?: ReadonlyMap<string, GraphqlOperationKind>): string
|
|
6
|
+
export declare function renderGraphqlValidators(source: string, operationNames: readonly string[], operationKinds?: ReadonlyMap<string, GraphqlOperationKind>): Promise<string>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import * as ts from "@typescript
|
|
1
|
+
import * as ts from "@supacloud/db/typescript";
|
|
2
2
|
import type { SourceMigrationResult } from "./migrations";
|
|
3
3
|
import type { Diagnostic } from "./types";
|
|
4
4
|
/** Never replaces the root array helper in constructor/custom pipeline usages. */
|
|
5
|
-
export declare function migrateHttpProviderImports(source: string, fileName: string): SourceMigrationResult
|
|
6
|
-
export declare function scanHttpProviderImports(source: ts.SourceFile, file: string): Diagnostic[]
|
|
5
|
+
export declare function migrateHttpProviderImports(source: string, fileName: string): Promise<SourceMigrationResult>;
|
|
6
|
+
export declare function scanHttpProviderImports(source: ts.SourceFile, file: string): Promise<Diagnostic[]>;
|
package/dist/incremental.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export interface IncrementalCompileResult extends CompileResult {
|
|
|
4
4
|
}
|
|
5
5
|
export interface IncrementalCompiler {
|
|
6
6
|
compile(options: CompileOptions, changedPaths?: string[]): Promise<IncrementalCompileResult>;
|
|
7
|
-
reset(): void
|
|
7
|
+
reset(): Promise<void>;
|
|
8
8
|
getCache?(): DependencyGraphCache;
|
|
9
9
|
}
|
|
10
10
|
export declare function createDependencyGraphCache(): DependencyGraphCache;
|
package/dist/index.d.ts
CHANGED
|
@@ -48,12 +48,12 @@ export type { MigrateFileResult, MigrateProjectOptions, MigrateProjectResult, So
|
|
|
48
48
|
export { validateGraph, COMPILER_DIAGNOSTIC_CODES } from "./validate";
|
|
49
49
|
export { scanGeneratedArtifacts, scanProductionSource, TYPE_SAFETY_DIAGNOSTIC_CODES } from "./type-safety";
|
|
50
50
|
export type { TypeSafetyScanOptions } from "./type-safety";
|
|
51
|
-
export {
|
|
51
|
+
export { scanQuerySql, SQL_SAFETY_DIAGNOSTIC_CODES } from "./sql-safety";
|
|
52
52
|
export { DEFAULT_SUPACLOUD_CONFIG, compileOptionsFromConfig, defineSupacloudConfig, loadSupacloudConfig, resolveSupacloudConfig, } from "./config";
|
|
53
53
|
export type { SupaCloudConfig } from "./config";
|
|
54
54
|
export { camelName } from "./util";
|
|
55
55
|
export { ANGULAR_ENTERPRISE_RULES, CLEAN_ARCHITECTURE_RULES, MODULAR_MONOLITH_RULES, MODULE_BOUNDARY_PROFILES, getModuleBoundaryPreset, getModuleBoundaryProfile, resolveModuleBoundaries, } from "./profiles";
|
|
56
|
-
export type { ApplicationGraph, AspectRefNode, CachedModuleEntry, CheckProjectResult, CommandExecutionCapabilities, CommandNode, CompileOptions, DatabaseGovernanceOptions, CompileResult, CompileStats, CompiledExecutionManifest, ExecutionPlanCommand, ExecutionPlanJob, ExecutionPlanModule, ExecutionPlanProvider, ExecutionPlanProviderEdge, ExecutionPlanRoute, ControllerNode, DependencyGraphCache, DependencyGraphIndex, Diagnostic, DiagnosticFix, EffectCompilerOptions, EffectErrorMappingNode, EffectRetryPolicy, EffectRouteNode, ModuleBoundaryPresetName, ModuleBoundaryProfile, ModuleBoundaryRule, ModuleNode, JobNode, ProviderKind, ProviderNode, QueryNode, RouteNode, Scope, TokenKind, TypeSafetyOptions, ValidateOptions, WatchEvent, WatchHandle, WatchOptions, FeatureSpecNode, FeatureTransitionNode, FeatureDatabaseSourceNode, FeaturePersistenceNode, GraphqlOptions, GraphqlContractSummary, OpenApiOptions, OpenApiSecurityScheme, OpenApiServer, } from "./types";
|
|
56
|
+
export type { ApplicationGraph, AspectRefNode, CachedModuleEntry, CheckProjectResult, CommandExecutionCapabilities, CommandNode, CompileOptions, DatabaseGovernanceOptions, CompileResult, CompileStats, CompiledExecutionManifest, ExecutionPlanCommand, ExecutionPlanJob, ExecutionPlanModule, ExecutionPlanProvider, ExecutionPlanProviderEdge, ExecutionPlanRoute, ControllerNode, DependencyGraphCache, DependencyOptions, DependencyGraphIndex, Diagnostic, DiagnosticFix, EffectCompilerOptions, EffectErrorMappingNode, EffectRetryPolicy, EffectRouteNode, ModuleBoundaryPresetName, ModuleBoundaryProfile, ModuleBoundaryRule, ModuleNode, JobNode, ProviderKind, ProviderNode, QueryNode, RouteNode, Scope, TokenKind, TypeSafetyOptions, ValidateOptions, WatchEvent, WatchHandle, WatchOptions, FeatureSpecNode, FeatureTransitionNode, FeatureDatabaseSourceNode, FeaturePersistenceNode, GraphqlOptions, GraphqlContractSummary, OpenApiOptions, OpenApiSecurityScheme, OpenApiServer, } from "./types";
|
|
57
57
|
export { inspectRouteContracts, validateRouteContracts } from "./route-contracts";
|
|
58
58
|
export { validateEffectPolicies, validateJobPolicies } from "./effect-governance";
|
|
59
59
|
export { pullGraphqlSchema } from "./graphql-schema";
|