@supacloud/compiler 0.13.0 → 0.14.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 +74 -2
- package/dist/cli.js +275 -99
- package/dist/config.d.ts +11 -1
- package/dist/graphql-client.d.ts +1 -1
- package/dist/graphql-runtime.d.ts +5 -0
- package/dist/index.js +230 -54
- package/package.json +3 -3
package/dist/cli.js
CHANGED
|
@@ -1213,11 +1213,11 @@ export function createGraphqlClient(options: GraphqlClientOptions) {
|
|
|
1213
1213
|
}
|
|
1214
1214
|
endpoint.pathname = endpoint.pathname.replace(/\\/$/, "") + "/graphql/v1";
|
|
1215
1215
|
const fetcher = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
1216
|
-
return getSdk<GraphqlRequestOptions>(async
|
|
1216
|
+
return getSdk<GraphqlRequestOptions>(async (
|
|
1217
1217
|
query: string,
|
|
1218
|
-
variables?:
|
|
1218
|
+
variables?: unknown,
|
|
1219
1219
|
request?: GraphqlRequestOptions,
|
|
1220
|
-
): Promise<
|
|
1220
|
+
): Promise<unknown> => {
|
|
1221
1221
|
const headers = new Headers({ "Content-Type": "application/json", Accept: "application/json" });
|
|
1222
1222
|
if (options.publishableKey) headers.set("apikey", options.publishableKey);
|
|
1223
1223
|
const token = await options.getAccessToken?.();
|
|
@@ -1226,7 +1226,7 @@ export function createGraphqlClient(options: GraphqlClientOptions) {
|
|
|
1226
1226
|
method: "POST",
|
|
1227
1227
|
headers,
|
|
1228
1228
|
body: JSON.stringify({ query, variables }),
|
|
1229
|
-
signal: request
|
|
1229
|
+
...(request?.signal ? { signal: request.signal } : {}),
|
|
1230
1230
|
redirect: "error",
|
|
1231
1231
|
});
|
|
1232
1232
|
if (!response.ok) {
|
|
@@ -1252,8 +1252,8 @@ export function createGraphqlClient(options: GraphqlClientOptions) {
|
|
|
1252
1252
|
if (!("data" in envelope) || !envelope.data || typeof envelope.data !== "object" || Array.isArray(envelope.data)) {
|
|
1253
1253
|
throw new GraphqlRequestError("invalid-response", "GraphQL returned no result object.", response.status);
|
|
1254
1254
|
}
|
|
1255
|
-
//
|
|
1256
|
-
return envelope.data
|
|
1255
|
+
// The operation-specific parser in getSdk validates selected field values.
|
|
1256
|
+
return envelope.data;
|
|
1257
1257
|
});
|
|
1258
1258
|
}
|
|
1259
1259
|
`;
|
|
@@ -1327,6 +1327,165 @@ var init_graphql_inputs = __esm(() => {
|
|
|
1327
1327
|
init_graphql_options();
|
|
1328
1328
|
});
|
|
1329
1329
|
|
|
1330
|
+
// src/graphql-runtime.ts
|
|
1331
|
+
import * as ts6 from "@typescript/typescript6";
|
|
1332
|
+
import { resolve as resolve4 } from "node:path";
|
|
1333
|
+
function renderGraphqlValidators(source, operationNames) {
|
|
1334
|
+
const fileName = resolve4("/__supacloud_graphql__/contracts.ts");
|
|
1335
|
+
const options = {
|
|
1336
|
+
strict: true,
|
|
1337
|
+
noUncheckedIndexedAccess: true,
|
|
1338
|
+
exactOptionalPropertyTypes: true,
|
|
1339
|
+
noImplicitOverride: true,
|
|
1340
|
+
noPropertyAccessFromIndexSignature: true,
|
|
1341
|
+
noFallthroughCasesInSwitch: true,
|
|
1342
|
+
skipLibCheck: false,
|
|
1343
|
+
target: ts6.ScriptTarget.ES2022,
|
|
1344
|
+
lib: ["lib.es2022.d.ts"],
|
|
1345
|
+
types: [],
|
|
1346
|
+
noEmit: true
|
|
1347
|
+
};
|
|
1348
|
+
const host = ts6.createCompilerHost(options);
|
|
1349
|
+
const getSourceFile = host.getSourceFile.bind(host);
|
|
1350
|
+
host.getSourceFile = (path, languageVersion, onError, shouldCreateNewSourceFile) => path === fileName ? ts6.createSourceFile(path, source, languageVersion, true) : getSourceFile(path, languageVersion, onError, shouldCreateNewSourceFile);
|
|
1351
|
+
const program = ts6.createProgram([fileName], options, host);
|
|
1352
|
+
const diagnostics = ts6.getPreEmitDiagnostics(program);
|
|
1353
|
+
if (diagnostics.length) {
|
|
1354
|
+
throw new Error(`Generated GraphQL types cannot be validated: ${diagnostics.map((item) => ts6.flattenDiagnosticMessageText(item.messageText, `
|
|
1355
|
+
`)).join("; ")}`);
|
|
1356
|
+
}
|
|
1357
|
+
const checker = program.getTypeChecker();
|
|
1358
|
+
const entry = program.getSourceFile(fileName);
|
|
1359
|
+
const module = entry && checker.getSymbolAtLocation(entry);
|
|
1360
|
+
if (!module)
|
|
1361
|
+
throw new Error("Generated GraphQL types have no module");
|
|
1362
|
+
const exports = new Map(checker.getExportsOfModule(module).map((symbol) => [symbol.name, symbol]));
|
|
1363
|
+
if (exports.has("GraphqlQueryResults")) {
|
|
1364
|
+
throw new Error("GraphQL type GraphqlQueryResults conflicts with the generated result registry.");
|
|
1365
|
+
}
|
|
1366
|
+
const names = new Map;
|
|
1367
|
+
const definitions = new Map;
|
|
1368
|
+
function unsupported(type) {
|
|
1369
|
+
throw new Error(`Unsupported GraphQL result wire type: ${checker.typeToString(type)}. Map custom scalars to JSON wire types or unknown.`);
|
|
1370
|
+
}
|
|
1371
|
+
function reference(type) {
|
|
1372
|
+
const existing = names.get(type);
|
|
1373
|
+
if (existing)
|
|
1374
|
+
return existing;
|
|
1375
|
+
const name = `checkGraphqlValue${names.size}`;
|
|
1376
|
+
names.set(type, name);
|
|
1377
|
+
definitions.set(name, "");
|
|
1378
|
+
definitions.set(name, `function ${name}(value: unknown): boolean {
|
|
1379
|
+
return ${expression(type)};
|
|
1380
|
+
}`);
|
|
1381
|
+
return name;
|
|
1382
|
+
}
|
|
1383
|
+
function expression(type) {
|
|
1384
|
+
if (type.flags & ts6.TypeFlags.Any)
|
|
1385
|
+
return unsupported(type);
|
|
1386
|
+
if (type.flags & ts6.TypeFlags.Unknown)
|
|
1387
|
+
return "true";
|
|
1388
|
+
if (type.flags & ts6.TypeFlags.Never)
|
|
1389
|
+
return "false";
|
|
1390
|
+
if (type.flags & ts6.TypeFlags.Null)
|
|
1391
|
+
return "value === null";
|
|
1392
|
+
if (type.flags & ts6.TypeFlags.Undefined)
|
|
1393
|
+
return "value === undefined";
|
|
1394
|
+
if (type.isStringLiteral() || type.isNumberLiteral())
|
|
1395
|
+
return `value === ${JSON.stringify(type.value)}`;
|
|
1396
|
+
if (type.flags & ts6.TypeFlags.BooleanLiteral)
|
|
1397
|
+
return `value === ${checker.typeToString(type)}`;
|
|
1398
|
+
if (type.flags & ts6.TypeFlags.String)
|
|
1399
|
+
return 'typeof value === "string"';
|
|
1400
|
+
if (type.flags & ts6.TypeFlags.Number)
|
|
1401
|
+
return 'typeof value === "number" && Number.isFinite(value)';
|
|
1402
|
+
if (type.flags & ts6.TypeFlags.Boolean)
|
|
1403
|
+
return 'typeof value === "boolean"';
|
|
1404
|
+
if (type.isUnion())
|
|
1405
|
+
return type.types.map((part) => `${reference(part)}(value)`).join(" || ");
|
|
1406
|
+
if (type.isIntersection())
|
|
1407
|
+
return type.types.map((part) => `${reference(part)}(value)`).join(" && ");
|
|
1408
|
+
if (checker.isTupleType(type))
|
|
1409
|
+
return unsupported(type);
|
|
1410
|
+
if (checker.isArrayType(type)) {
|
|
1411
|
+
const item = checker.getIndexTypeOfType(type, ts6.IndexKind.Number);
|
|
1412
|
+
if (!item)
|
|
1413
|
+
return unsupported(type);
|
|
1414
|
+
return `isGraphqlArray(value) && Array.from(value).every(${reference(item)})`;
|
|
1415
|
+
}
|
|
1416
|
+
if (type.flags & ts6.TypeFlags.Object) {
|
|
1417
|
+
if (type.getCallSignatures().length || type.getConstructSignatures().length)
|
|
1418
|
+
return unsupported(type);
|
|
1419
|
+
const indexes = checker.getIndexInfosOfType(type);
|
|
1420
|
+
if (indexes.some((index) => !(index.keyType.flags & ts6.TypeFlags.String)))
|
|
1421
|
+
return unsupported(type);
|
|
1422
|
+
const properties = checker.getPropertiesOfType(type).map((property) => {
|
|
1423
|
+
const declaration = property.valueDeclaration ?? property.declarations?.[0];
|
|
1424
|
+
if (!declaration)
|
|
1425
|
+
return unsupported(type);
|
|
1426
|
+
const check = reference(checker.getTypeOfSymbolAtLocation(property, declaration));
|
|
1427
|
+
const key = JSON.stringify(property.name);
|
|
1428
|
+
const present = `Object.prototype.hasOwnProperty.call(value, ${key})`;
|
|
1429
|
+
return property.flags & ts6.SymbolFlags.Optional ? `(!${present} || ${check}(value[${key}]))` : `(${present} && ${check}(value[${key}]))`;
|
|
1430
|
+
});
|
|
1431
|
+
const indexedValues = indexes.map((index) => `Object.values(value).every(${reference(index.type)})`);
|
|
1432
|
+
return ["isGraphqlRecord(value)", ...properties, ...indexedValues].join(" && ");
|
|
1433
|
+
}
|
|
1434
|
+
return unsupported(type);
|
|
1435
|
+
}
|
|
1436
|
+
const operations = [...operationNames].sort();
|
|
1437
|
+
const parsers = operations.map((name) => {
|
|
1438
|
+
const typeName = `${name}Query`;
|
|
1439
|
+
const symbol = exports.get(typeName);
|
|
1440
|
+
if (!symbol)
|
|
1441
|
+
throw new Error(`Missing generated operation type: ${typeName}`);
|
|
1442
|
+
const check = reference(checker.getDeclaredTypeOfSymbol(symbol));
|
|
1443
|
+
return `export function is${typeName}(value: unknown): value is ${typeName} {
|
|
1444
|
+
return ${check}(value);
|
|
1445
|
+
}
|
|
1446
|
+
export function parse${typeName}(value: unknown): ${typeName} {
|
|
1447
|
+
if (!is${typeName}(value)) {
|
|
1448
|
+
throw new GraphqlRequestError("invalid-response", ${JSON.stringify(`GraphQL result does not match ${name}.`)});
|
|
1449
|
+
}
|
|
1450
|
+
return value;
|
|
1451
|
+
}`;
|
|
1452
|
+
});
|
|
1453
|
+
return `
|
|
1454
|
+
function isGraphqlRecord(value: unknown): value is Record<string, unknown> {
|
|
1455
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1456
|
+
}
|
|
1457
|
+
function isGraphqlArray(value: unknown): value is unknown[] {
|
|
1458
|
+
return Array.isArray(value);
|
|
1459
|
+
}
|
|
1460
|
+
${[...definitions.values()].join(`
|
|
1461
|
+
`)}
|
|
1462
|
+
${parsers.join(`
|
|
1463
|
+
`)}
|
|
1464
|
+
export interface GraphqlQueryResults {
|
|
1465
|
+
${operations.map((name) => ` ${JSON.stringify(name)}: ${name}Query;`).join(`
|
|
1466
|
+
`)}
|
|
1467
|
+
}
|
|
1468
|
+
export function isGraphqlResult<Name extends keyof GraphqlQueryResults>(
|
|
1469
|
+
name: Name, value: unknown,
|
|
1470
|
+
): value is GraphqlQueryResults[Name] {
|
|
1471
|
+
switch (name) {
|
|
1472
|
+
${operations.map((name) => ` case ${JSON.stringify(name)}: return is${name}Query(value);`).join(`
|
|
1473
|
+
`)}
|
|
1474
|
+
default: return false;
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
export function parseGraphqlResult<Name extends keyof GraphqlQueryResults>(
|
|
1478
|
+
name: Name, value: unknown,
|
|
1479
|
+
): GraphqlQueryResults[Name] {
|
|
1480
|
+
if (!isGraphqlResult(name, value)) {
|
|
1481
|
+
throw new GraphqlRequestError("invalid-response", "GraphQL result does not match operation " + name + ".");
|
|
1482
|
+
}
|
|
1483
|
+
return value;
|
|
1484
|
+
}
|
|
1485
|
+
`;
|
|
1486
|
+
}
|
|
1487
|
+
var init_graphql_runtime = () => {};
|
|
1488
|
+
|
|
1330
1489
|
// src/graphql.ts
|
|
1331
1490
|
var exports_graphql = {};
|
|
1332
1491
|
__export(exports_graphql, {
|
|
@@ -1350,7 +1509,6 @@ import {
|
|
|
1350
1509
|
validateSchema
|
|
1351
1510
|
} from "graphql";
|
|
1352
1511
|
import { codegen } from "@graphql-codegen/core";
|
|
1353
|
-
import * as typescript from "@graphql-codegen/typescript";
|
|
1354
1512
|
import * as operations from "@graphql-codegen/typescript-operations";
|
|
1355
1513
|
async function renderGraphql(options) {
|
|
1356
1514
|
const result = { diagnostics: [], files: {} };
|
|
@@ -1456,9 +1614,8 @@ async function renderGraphql(options) {
|
|
|
1456
1614
|
try {
|
|
1457
1615
|
const config = {
|
|
1458
1616
|
useTypeImports: true,
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
onlyOperationTypes: true,
|
|
1617
|
+
nonOptionalTypename: false,
|
|
1618
|
+
enumType: "string-literal",
|
|
1462
1619
|
namingConvention: "keep",
|
|
1463
1620
|
dedupeOperationSuffix: false,
|
|
1464
1621
|
omitOperationSuffix: false,
|
|
@@ -1471,21 +1628,21 @@ async function renderGraphql(options) {
|
|
|
1471
1628
|
schemaAst: schema,
|
|
1472
1629
|
documents,
|
|
1473
1630
|
config,
|
|
1474
|
-
plugins: [{
|
|
1475
|
-
pluginMap: {
|
|
1631
|
+
plugins: [{ operations: {} }],
|
|
1632
|
+
pluginMap: { operations }
|
|
1476
1633
|
});
|
|
1477
1634
|
const separated = separateOperations(combined);
|
|
1478
1635
|
const methods = Object.entries(separated).sort(([a], [b]) => a.localeCompare(b)).map(([name, document]) => {
|
|
1479
1636
|
const operation = document.definitions.find((node) => node.kind === Kind.OPERATION_DEFINITION);
|
|
1480
|
-
if (operation.kind !== Kind.OPERATION_DEFINITION)
|
|
1637
|
+
if (!operation || operation.kind !== Kind.OPERATION_DEFINITION)
|
|
1481
1638
|
throw new Error("Missing query operation");
|
|
1482
1639
|
const required = operation.variableDefinitions?.some((variable) => variable.type.kind === Kind.NON_NULL_TYPE && !variable.defaultValue);
|
|
1483
|
-
return ` ${JSON.stringify(name)}(variables${required ? "" : "?"}: ${name}QueryVariables, options?: C): Promise<${name}Query> {
|
|
1484
|
-
return
|
|
1640
|
+
return ` async ${JSON.stringify(name)}(variables${required ? "" : "?"}: ${name}QueryVariables, options?: C): Promise<${name}Query> {
|
|
1641
|
+
return parse${name}Query(await requester(${JSON.stringify(print(document))}, variables, options));
|
|
1485
1642
|
}`;
|
|
1486
1643
|
});
|
|
1487
1644
|
const facade = `
|
|
1488
|
-
export type Requester<C> =
|
|
1645
|
+
export type Requester<C> = (query: string, variables?: unknown, options?: C) => Promise<unknown>;
|
|
1489
1646
|
export function getSdk<C>(requester: Requester<C>) {
|
|
1490
1647
|
return {
|
|
1491
1648
|
${methods.join(`,
|
|
@@ -1493,8 +1650,9 @@ ${methods.join(`,
|
|
|
1493
1650
|
};
|
|
1494
1651
|
}
|
|
1495
1652
|
`;
|
|
1653
|
+
const validators = renderGraphqlValidators(generated, queryEntries.map((entry) => entry.name));
|
|
1496
1654
|
result.files["graphql.ts"] = `// GENERATED BY @supacloud/compiler. DO NOT EDIT.
|
|
1497
|
-
` + generated + facade + GRAPHQL_CLIENT_SOURCE;
|
|
1655
|
+
` + generated + validators + facade + GRAPHQL_CLIENT_SOURCE;
|
|
1498
1656
|
if (options.graphql.typedDocuments) {
|
|
1499
1657
|
const typedDocuments = await import("@graphql-codegen/typed-document-node");
|
|
1500
1658
|
result.files["graphql.documents.ts"] = `// GENERATED BY @supacloud/compiler. DO NOT EDIT.
|
|
@@ -1504,8 +1662,8 @@ ${methods.join(`,
|
|
|
1504
1662
|
schemaAst: schema,
|
|
1505
1663
|
documents,
|
|
1506
1664
|
config,
|
|
1507
|
-
plugins: [{
|
|
1508
|
-
pluginMap: {
|
|
1665
|
+
plugins: [{ operations: {} }, { typedDocuments: {} }],
|
|
1666
|
+
pluginMap: { operations, typedDocuments }
|
|
1509
1667
|
});
|
|
1510
1668
|
}
|
|
1511
1669
|
result.files["graphql.manifest.json"] = JSON.stringify({
|
|
@@ -1523,6 +1681,7 @@ ${methods.join(`,
|
|
|
1523
1681
|
var init_graphql = __esm(() => {
|
|
1524
1682
|
init_graphql_inputs();
|
|
1525
1683
|
init_graphql_options();
|
|
1684
|
+
init_graphql_runtime();
|
|
1526
1685
|
});
|
|
1527
1686
|
|
|
1528
1687
|
// src/graphql-schema.ts
|
|
@@ -1532,7 +1691,7 @@ __export(exports_graphql_schema, {
|
|
|
1532
1691
|
});
|
|
1533
1692
|
import { mkdir as mkdir2, readFile as readFile4 } from "node:fs/promises";
|
|
1534
1693
|
import { createHash as createHash7 } from "node:crypto";
|
|
1535
|
-
import { dirname as dirname7, resolve as
|
|
1694
|
+
import { dirname as dirname7, resolve as resolve9 } from "node:path";
|
|
1536
1695
|
async function pullGraphqlSchema(options) {
|
|
1537
1696
|
assertGraphqlOptions({ schema: options.output });
|
|
1538
1697
|
const endpoint = new URL(options.url);
|
|
@@ -1572,7 +1731,7 @@ async function pullGraphqlSchema(options) {
|
|
|
1572
1731
|
throw new Error("GraphQL schema export failed. Verify caller grants and enable introspection only in the intended development environment.");
|
|
1573
1732
|
}
|
|
1574
1733
|
const schema = lexicographicSortSchema(buildClientSchema2(data));
|
|
1575
|
-
const path =
|
|
1734
|
+
const path = resolve9(options.output);
|
|
1576
1735
|
const content = path.endsWith(".json") ? JSON.stringify(introspectionFromSchema(schema), null, 2) + `
|
|
1577
1736
|
` : `# GENERATED BY supacloud-compiler graphql-schema. DO NOT EDIT.
|
|
1578
1737
|
# Database First: change database declarations, apply migrations, then re-export for the intended role.
|
|
@@ -1599,7 +1758,7 @@ var init_graphql_schema = __esm(() => {
|
|
|
1599
1758
|
});
|
|
1600
1759
|
|
|
1601
1760
|
// src/cli.ts
|
|
1602
|
-
import { resolve as
|
|
1761
|
+
import { resolve as resolve10 } from "node:path";
|
|
1603
1762
|
import { readFile as readFile5 } from "node:fs/promises";
|
|
1604
1763
|
|
|
1605
1764
|
// src/analyze.ts
|
|
@@ -5702,12 +5861,12 @@ function exportGraphDot(graph) {
|
|
|
5702
5861
|
|
|
5703
5862
|
// src/watch.ts
|
|
5704
5863
|
import { existsSync as existsSync5, watch } from "node:fs";
|
|
5705
|
-
import { dirname as dirname5, relative as relative7, resolve as
|
|
5864
|
+
import { dirname as dirname5, relative as relative7, resolve as resolve6, sep as sep7 } from "node:path";
|
|
5706
5865
|
|
|
5707
5866
|
// src/incremental.ts
|
|
5708
5867
|
import { createHash as createHash6 } from "node:crypto";
|
|
5709
5868
|
import { access as access2, readdir, readFile as readFile2 } from "node:fs/promises";
|
|
5710
|
-
import { isAbsolute, relative as relative6, resolve as
|
|
5869
|
+
import { isAbsolute, relative as relative6, resolve as resolve5, sep as sep6 } from "node:path";
|
|
5711
5870
|
init_graphql_inputs();
|
|
5712
5871
|
function createDependencyGraphCache() {
|
|
5713
5872
|
return {
|
|
@@ -5782,11 +5941,11 @@ function createIncrementalCompiler() {
|
|
|
5782
5941
|
};
|
|
5783
5942
|
}
|
|
5784
5943
|
async function updateSnapshot(previous, options, changedPaths) {
|
|
5785
|
-
const rootDir =
|
|
5786
|
-
const outDir =
|
|
5944
|
+
const rootDir = resolve5(options.rootDir);
|
|
5945
|
+
const outDir = resolve5(options.outDir);
|
|
5787
5946
|
const files = { ...previous.files };
|
|
5788
5947
|
for (const changedPath of changedPaths) {
|
|
5789
|
-
const absolutePath = isAbsolute(changedPath) ?
|
|
5948
|
+
const absolutePath = isAbsolute(changedPath) ? resolve5(changedPath) : resolve5(rootDir, changedPath);
|
|
5790
5949
|
const relativeChangedPath = relative6(rootDir, absolutePath);
|
|
5791
5950
|
if (relativeChangedPath === ".." || relativeChangedPath.startsWith(`..${sep6}`))
|
|
5792
5951
|
continue;
|
|
@@ -5804,8 +5963,8 @@ async function updateSnapshot(previous, options, changedPaths) {
|
|
|
5804
5963
|
return { files, optionsKey: optionsKeyOf(options) };
|
|
5805
5964
|
}
|
|
5806
5965
|
async function createSnapshot(options) {
|
|
5807
|
-
const rootDir =
|
|
5808
|
-
const outDir =
|
|
5966
|
+
const rootDir = resolve5(options.rootDir);
|
|
5967
|
+
const outDir = resolve5(options.outDir);
|
|
5809
5968
|
const paths = await listSourceFiles(rootDir, outDir);
|
|
5810
5969
|
const files = {};
|
|
5811
5970
|
for (const path of paths) {
|
|
@@ -5824,8 +5983,8 @@ async function createSnapshot(options) {
|
|
|
5824
5983
|
}
|
|
5825
5984
|
function optionsKeyOf(options) {
|
|
5826
5985
|
return JSON.stringify({
|
|
5827
|
-
rootDir:
|
|
5828
|
-
outDir:
|
|
5986
|
+
rootDir: resolve5(options.rootDir),
|
|
5987
|
+
outDir: resolve5(options.outDir),
|
|
5829
5988
|
include: options.include,
|
|
5830
5989
|
strict: options.strict,
|
|
5831
5990
|
writeOnError: options.writeOnError,
|
|
@@ -5847,7 +6006,7 @@ async function listSourceFiles(rootDir, outDir) {
|
|
|
5847
6006
|
const result = [];
|
|
5848
6007
|
const visit = async (directory) => {
|
|
5849
6008
|
for (const entry of await readdir(directory, { withFileTypes: true })) {
|
|
5850
|
-
const path =
|
|
6009
|
+
const path = resolve5(directory, entry.name);
|
|
5851
6010
|
if (entry.isDirectory()) {
|
|
5852
6011
|
if (entry.name === "node_modules" || entry.name === ".git" || path === outDir)
|
|
5853
6012
|
continue;
|
|
@@ -5971,8 +6130,8 @@ function findAffectedModules(previous, current, changedFiles) {
|
|
|
5971
6130
|
// src/watch.ts
|
|
5972
6131
|
var DEFAULT_DEBOUNCE_MS = 100;
|
|
5973
6132
|
function watchProject(options) {
|
|
5974
|
-
const rootDir =
|
|
5975
|
-
const outDir =
|
|
6133
|
+
const rootDir = resolve6(options.rootDir);
|
|
6134
|
+
const outDir = resolve6(options.outDir);
|
|
5976
6135
|
const debounceMs = options.debounceMs ?? DEFAULT_DEBOUNCE_MS;
|
|
5977
6136
|
let timer;
|
|
5978
6137
|
let closed = false;
|
|
@@ -5981,7 +6140,7 @@ function watchProject(options) {
|
|
|
5981
6140
|
const pendingPaths = new Set;
|
|
5982
6141
|
let watcher;
|
|
5983
6142
|
let schemaWatcher;
|
|
5984
|
-
const schemaPath = options.graphql ?
|
|
6143
|
+
const schemaPath = options.graphql ? resolve6(rootDir, options.graphql.schema) : undefined;
|
|
5985
6144
|
const incremental = createIncrementalCompiler();
|
|
5986
6145
|
let initialEvent;
|
|
5987
6146
|
let resolveReady = () => {
|
|
@@ -6058,7 +6217,7 @@ function watchProject(options) {
|
|
|
6058
6217
|
watcher = watch(rootDir, { recursive: true }, (_eventType, filename) => {
|
|
6059
6218
|
if (!filename)
|
|
6060
6219
|
return schedule();
|
|
6061
|
-
const changedPath =
|
|
6220
|
+
const changedPath = resolve6(rootDir, filename.toString());
|
|
6062
6221
|
const relativePath = relative7(outDir, changedPath);
|
|
6063
6222
|
if (!relativePath.startsWith("..") && relativePath !== "")
|
|
6064
6223
|
return;
|
|
@@ -6071,7 +6230,7 @@ function watchProject(options) {
|
|
|
6071
6230
|
while (!existsSync5(directory) && dirname5(directory) !== directory)
|
|
6072
6231
|
directory = dirname5(directory);
|
|
6073
6232
|
schemaWatcher = watch(directory, { recursive: true }, (_eventType, filename) => {
|
|
6074
|
-
if (!filename ||
|
|
6233
|
+
if (!filename || resolve6(directory, filename.toString()) === schemaPath)
|
|
6075
6234
|
schedule(schemaPath);
|
|
6076
6235
|
});
|
|
6077
6236
|
}
|
|
@@ -6098,7 +6257,7 @@ function watchProject(options) {
|
|
|
6098
6257
|
// src/config.ts
|
|
6099
6258
|
init_graphql_options();
|
|
6100
6259
|
import { existsSync as existsSync6 } from "node:fs";
|
|
6101
|
-
import { join as join6, resolve as
|
|
6260
|
+
import { join as join6, resolve as resolve7 } from "node:path";
|
|
6102
6261
|
import { pathToFileURL } from "node:url";
|
|
6103
6262
|
var DEFAULT_SUPACLOUD_CONFIG = {
|
|
6104
6263
|
graphql: false,
|
|
@@ -6115,6 +6274,7 @@ var DEFAULT_SUPACLOUD_CONFIG = {
|
|
|
6115
6274
|
function defineSupacloudConfig(config = {}) {
|
|
6116
6275
|
if (config.graphql !== undefined && config.graphql !== false)
|
|
6117
6276
|
assertGraphqlOptions(config.graphql);
|
|
6277
|
+
validateGovernanceConfig(config);
|
|
6118
6278
|
return {
|
|
6119
6279
|
...DEFAULT_SUPACLOUD_CONFIG,
|
|
6120
6280
|
...config,
|
|
@@ -6122,11 +6282,35 @@ function defineSupacloudConfig(config = {}) {
|
|
|
6122
6282
|
graphql: config.graphql ?? DEFAULT_SUPACLOUD_CONFIG.graphql
|
|
6123
6283
|
};
|
|
6124
6284
|
}
|
|
6285
|
+
function validateGovernanceConfig(config) {
|
|
6286
|
+
const isRecord = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
6287
|
+
const isStrings = (value) => Array.isArray(value) && Array.from(value).every((item) => typeof item === "string" && item.trim().length > 0);
|
|
6288
|
+
if (config.moduleBoundaries !== undefined) {
|
|
6289
|
+
if (!Array.isArray(config.moduleBoundaries))
|
|
6290
|
+
throw new Error("moduleBoundaries must be an array of module tag rules.");
|
|
6291
|
+
const rules = config.moduleBoundaries;
|
|
6292
|
+
for (const rule of rules) {
|
|
6293
|
+
if (!isRecord(rule) || typeof rule["sourceTag"] !== "string" || !rule["sourceTag"].trim() || Object.keys(rule).some((key) => !["sourceTag", "onlyDependOnLibsWithTags", "bannedDependenciesWithTags"].includes(key)) || rule["onlyDependOnLibsWithTags"] !== undefined && !isStrings(rule["onlyDependOnLibsWithTags"]) || rule["bannedDependenciesWithTags"] !== undefined && !isStrings(rule["bannedDependenciesWithTags"])) {
|
|
6294
|
+
throw new Error("moduleBoundaries rules require sourceTag and optional string arrays onlyDependOnLibsWithTags/bannedDependenciesWithTags.");
|
|
6295
|
+
}
|
|
6296
|
+
}
|
|
6297
|
+
}
|
|
6298
|
+
if (config.typeSafety !== undefined) {
|
|
6299
|
+
const rules = config.typeSafety;
|
|
6300
|
+
if (!isRecord(rules) || Object.keys(rules).some((key) => !["scanProductionSource", "noAnyInGenerated", "exclude"].includes(key)) || rules["scanProductionSource"] !== undefined && typeof rules["scanProductionSource"] !== "boolean" || rules["noAnyInGenerated"] !== undefined && typeof rules["noAnyInGenerated"] !== "boolean" || rules["exclude"] !== undefined && !isStrings(rules["exclude"])) {
|
|
6301
|
+
throw new Error("typeSafety accepts boolean scanProductionSource/noAnyInGenerated and a string array exclude.");
|
|
6302
|
+
}
|
|
6303
|
+
}
|
|
6304
|
+
for (const key of ["allowRouteCommandBindings", "disallowControllerDirectDb", "detectOrphanModules"]) {
|
|
6305
|
+
if (config[key] !== undefined && typeof config[key] !== "boolean")
|
|
6306
|
+
throw new Error(`${key} must be a boolean.`);
|
|
6307
|
+
}
|
|
6308
|
+
}
|
|
6125
6309
|
function resolveSupacloudConfig(config = {}, cwd = process.cwd()) {
|
|
6126
6310
|
const resolved = defineSupacloudConfig(config);
|
|
6127
6311
|
return {
|
|
6128
|
-
rootDir:
|
|
6129
|
-
outDir:
|
|
6312
|
+
rootDir: resolve7(cwd, resolved.root ?? DEFAULT_SUPACLOUD_CONFIG.root),
|
|
6313
|
+
outDir: resolve7(cwd, resolved.outDir ?? DEFAULT_SUPACLOUD_CONFIG.outDir),
|
|
6130
6314
|
include: resolved.include ?? [...DEFAULT_SUPACLOUD_CONFIG.include],
|
|
6131
6315
|
strict: resolved.strict ?? DEFAULT_SUPACLOUD_CONFIG.strict,
|
|
6132
6316
|
requireRouteContracts: resolved.requireRouteContracts ?? DEFAULT_SUPACLOUD_CONFIG.requireRouteContracts,
|
|
@@ -6134,10 +6318,15 @@ function resolveSupacloudConfig(config = {}, cwd = process.cwd()) {
|
|
|
6134
6318
|
generatePermissions: resolved.generatePermissions ?? DEFAULT_SUPACLOUD_CONFIG.generatePermissions,
|
|
6135
6319
|
moduleBoundaryPreset: resolved.moduleBoundaryPreset ?? DEFAULT_SUPACLOUD_CONFIG.moduleBoundaryPreset,
|
|
6136
6320
|
commandCapabilities: resolved.commandCapabilities,
|
|
6321
|
+
...resolved.moduleBoundaries ? { moduleBoundaries: resolved.moduleBoundaries } : {},
|
|
6322
|
+
...resolved.typeSafety ? { typeSafety: resolved.typeSafety } : {},
|
|
6323
|
+
...resolved.allowRouteCommandBindings === undefined ? {} : { allowRouteCommandBindings: resolved.allowRouteCommandBindings },
|
|
6324
|
+
...resolved.disallowControllerDirectDb === undefined ? {} : { disallowControllerDirectDb: resolved.disallowControllerDirectDb },
|
|
6325
|
+
...resolved.detectOrphanModules === undefined ? {} : { detectOrphanModules: resolved.detectOrphanModules },
|
|
6137
6326
|
treeShakeUnusedProviders: resolved.treeShakeUnusedProviders ?? DEFAULT_SUPACLOUD_CONFIG.treeShakeUnusedProviders,
|
|
6138
6327
|
graphql: resolved.graphql ? {
|
|
6139
6328
|
...resolved.graphql,
|
|
6140
|
-
schema:
|
|
6329
|
+
schema: resolve7(cwd, resolved.graphql.schema)
|
|
6141
6330
|
} : undefined
|
|
6142
6331
|
};
|
|
6143
6332
|
}
|
|
@@ -6155,32 +6344,19 @@ async function loadSupacloudConfig(cwd = process.cwd()) {
|
|
|
6155
6344
|
return defineSupacloudConfig(imported.default ?? {});
|
|
6156
6345
|
}
|
|
6157
6346
|
function compileOptionsFromConfig(config, cwd = process.cwd()) {
|
|
6158
|
-
|
|
6159
|
-
return {
|
|
6160
|
-
rootDir: resolved.rootDir,
|
|
6161
|
-
outDir: resolved.outDir,
|
|
6162
|
-
include: resolved.include,
|
|
6163
|
-
strict: resolved.strict,
|
|
6164
|
-
requireRouteContracts: resolved.requireRouteContracts,
|
|
6165
|
-
generateClient: resolved.generateClient,
|
|
6166
|
-
generatePermissions: resolved.generatePermissions,
|
|
6167
|
-
moduleBoundaryPreset: resolved.moduleBoundaryPreset,
|
|
6168
|
-
commandCapabilities: resolved.commandCapabilities,
|
|
6169
|
-
treeShakeUnusedProviders: resolved.treeShakeUnusedProviders,
|
|
6170
|
-
graphql: resolved.graphql
|
|
6171
|
-
};
|
|
6347
|
+
return resolveSupacloudConfig(config, cwd);
|
|
6172
6348
|
}
|
|
6173
6349
|
|
|
6174
6350
|
// src/fixes.ts
|
|
6175
6351
|
import { randomUUID } from "node:crypto";
|
|
6176
6352
|
import { lstat, readFile as readFile3, realpath, rename as rename2, unlink as unlink2, writeFile as writeFile2 } from "node:fs/promises";
|
|
6177
|
-
import { dirname as dirname6, isAbsolute as isAbsolute2, relative as relative8, resolve as
|
|
6178
|
-
import * as
|
|
6353
|
+
import { dirname as dirname6, isAbsolute as isAbsolute2, relative as relative8, resolve as resolve8, sep as sep8 } from "node:path";
|
|
6354
|
+
import * as ts7 from "@typescript/typescript6";
|
|
6179
6355
|
async function applyDiagnosticFix(fix, options = {}) {
|
|
6180
6356
|
if (!fix || typeof fix.targetFile !== "string")
|
|
6181
6357
|
throw new Error("Invalid DiagnosticFix");
|
|
6182
6358
|
const root = await realpath(options.rootDir ?? process.cwd());
|
|
6183
|
-
const file =
|
|
6359
|
+
const file = resolve8(root, fix.targetFile);
|
|
6184
6360
|
const stat = await lstat(file);
|
|
6185
6361
|
const resolved = await realpath(file);
|
|
6186
6362
|
const relativePath = relative8(root, resolved);
|
|
@@ -6200,7 +6376,7 @@ async function applyDiagnosticFix(fix, options = {}) {
|
|
|
6200
6376
|
if (!current || current.initializer.getText(source) !== fix.expectedExpression) {
|
|
6201
6377
|
throw new Error("Command mode changed since diagnosis; analyze the project again");
|
|
6202
6378
|
}
|
|
6203
|
-
content = replaceProperty(source, object, fix.property,
|
|
6379
|
+
content = replaceProperty(source, object, fix.property, ts7.factory.createStringLiteral(fix.value));
|
|
6204
6380
|
break;
|
|
6205
6381
|
}
|
|
6206
6382
|
case "add_module_import": {
|
|
@@ -6211,15 +6387,15 @@ async function applyDiagnosticFix(fix, options = {}) {
|
|
|
6211
6387
|
source = parse2(file, withImport);
|
|
6212
6388
|
const object = unique(moduleObjects(source).filter((candidate) => !fix.targetModule || stringProperty(candidate, "name") === fix.targetModule), "target module");
|
|
6213
6389
|
const imports = property(object, "imports");
|
|
6214
|
-
if (imports && !
|
|
6390
|
+
if (imports && !ts7.isArrayLiteralExpression(imports.initializer)) {
|
|
6215
6391
|
throw new Error("Module imports must be a static array");
|
|
6216
6392
|
}
|
|
6217
|
-
const values = imports &&
|
|
6218
|
-
if (values.some(
|
|
6393
|
+
const values = imports && ts7.isArrayLiteralExpression(imports.initializer) ? imports.initializer.elements : [];
|
|
6394
|
+
if (values.some(ts7.isSpreadElement))
|
|
6219
6395
|
throw new Error("Module imports cannot contain spread elements");
|
|
6220
|
-
content = values.some((value) =>
|
|
6396
|
+
content = values.some((value) => ts7.isIdentifier(value) && value.text === fix.symbol) ? withImport : replaceProperty(source, object, "imports", ts7.factory.createArrayLiteralExpression([
|
|
6221
6397
|
...values,
|
|
6222
|
-
|
|
6398
|
+
ts7.factory.createIdentifier(fix.symbol)
|
|
6223
6399
|
]));
|
|
6224
6400
|
break;
|
|
6225
6401
|
}
|
|
@@ -6231,24 +6407,24 @@ async function applyDiagnosticFix(fix, options = {}) {
|
|
|
6231
6407
|
const command = findClass(source, fix.command);
|
|
6232
6408
|
const object = decoratorObject(command, "Command");
|
|
6233
6409
|
const current = property(object, "permission");
|
|
6234
|
-
if (current && (!
|
|
6410
|
+
if (current && (!ts7.isStringLiteral(current.initializer) || current.initializer.text !== permission)) {
|
|
6235
6411
|
throw new Error("Command permission already exists with a different value");
|
|
6236
6412
|
}
|
|
6237
|
-
content = current ? original : replaceProperty(source, object, "permission",
|
|
6413
|
+
content = current ? original : replaceProperty(source, object, "permission", ts7.factory.createStringLiteral(permission));
|
|
6238
6414
|
break;
|
|
6239
6415
|
}
|
|
6240
6416
|
case "add_route_parameter_binding": {
|
|
6241
6417
|
const controller = findClass(source, fix.controller);
|
|
6242
|
-
const method = unique(controller.members.filter((member) =>
|
|
6243
|
-
const parameter = unique(method.parameters.filter((candidate) =>
|
|
6418
|
+
const method = unique(controller.members.filter((member) => ts7.isMethodDeclaration(member) && nameOf(member.name) === fix.route), "route handler");
|
|
6419
|
+
const parameter = unique(method.parameters.filter((candidate) => ts7.isIdentifier(candidate.name) && candidate.name.text === fix.parameter), "same-named route parameter");
|
|
6244
6420
|
const binding = fix.binding === "param" ? "Param" : fix.binding === "query" ? "Query" : undefined;
|
|
6245
6421
|
if (!binding)
|
|
6246
6422
|
throw new Error("Invalid route binding");
|
|
6247
|
-
const decorators =
|
|
6423
|
+
const decorators = ts7.getDecorators(parameter) ?? [];
|
|
6248
6424
|
if (decorators.length > 0)
|
|
6249
6425
|
throw new Error("Parameter already has a decorator");
|
|
6250
|
-
const framework = unique(source.statements.filter((statement) =>
|
|
6251
|
-
if (!
|
|
6426
|
+
const framework = unique(source.statements.filter((statement) => ts7.isImportDeclaration(statement) && statement.importClause?.namedBindings && ts7.isNamedImports(statement.importClause.namedBindings) && statement.importClause.namedBindings.elements.some((element) => ["Controller", "Get", "Post", "Put", "Patch", "Delete", "Head", "Options"].includes(element.name.text))), "framework import");
|
|
6427
|
+
if (!ts7.isImportDeclaration(framework) || !ts7.isStringLiteral(framework.moduleSpecifier)) {
|
|
6252
6428
|
throw new Error("Framework import must be static");
|
|
6253
6429
|
}
|
|
6254
6430
|
const edited = original.slice(0, parameter.getStart(source)) + `@${binding}(${JSON.stringify(fix.parameter)}) ` + original.slice(parameter.getStart(source));
|
|
@@ -6274,15 +6450,15 @@ async function applyDiagnosticFix(fix, options = {}) {
|
|
|
6274
6450
|
return result;
|
|
6275
6451
|
}
|
|
6276
6452
|
function parse2(file, text) {
|
|
6277
|
-
const result =
|
|
6453
|
+
const result = ts7.transpileModule(text, {
|
|
6278
6454
|
fileName: file,
|
|
6279
6455
|
reportDiagnostics: true,
|
|
6280
|
-
compilerOptions: { target:
|
|
6456
|
+
compilerOptions: { target: ts7.ScriptTarget.ESNext, experimentalDecorators: true }
|
|
6281
6457
|
});
|
|
6282
|
-
if (result.diagnostics?.some((item) => item.category ===
|
|
6458
|
+
if (result.diagnostics?.some((item) => item.category === ts7.DiagnosticCategory.Error)) {
|
|
6283
6459
|
throw new Error("Cannot fix syntactically invalid TypeScript");
|
|
6284
6460
|
}
|
|
6285
|
-
return
|
|
6461
|
+
return ts7.createSourceFile(file, text, ts7.ScriptTarget.Latest, true, ts7.ScriptKind.TS);
|
|
6286
6462
|
}
|
|
6287
6463
|
function unique(items, description) {
|
|
6288
6464
|
if (items.length !== 1)
|
|
@@ -6296,50 +6472,50 @@ function identifier(value) {
|
|
|
6296
6472
|
function nameOf(name) {
|
|
6297
6473
|
if (!name)
|
|
6298
6474
|
return "";
|
|
6299
|
-
return
|
|
6475
|
+
return ts7.isIdentifier(name) || ts7.isStringLiteral(name) || ts7.isNumericLiteral(name) ? name.text : "";
|
|
6300
6476
|
}
|
|
6301
6477
|
function property(object, key) {
|
|
6302
|
-
if (object.properties.some((item) => !
|
|
6478
|
+
if (object.properties.some((item) => !ts7.isPropertyAssignment(item) || ts7.isComputedPropertyName(item.name))) {
|
|
6303
6479
|
throw new Error("Fix requires explicit static object properties");
|
|
6304
6480
|
}
|
|
6305
|
-
const values = object.properties.filter((item) =>
|
|
6481
|
+
const values = object.properties.filter((item) => ts7.isPropertyAssignment(item) && nameOf(item.name) === key);
|
|
6306
6482
|
if (values.length > 1)
|
|
6307
6483
|
throw new Error(`Duplicate '${key}' property`);
|
|
6308
6484
|
return values[0];
|
|
6309
6485
|
}
|
|
6310
6486
|
function stringProperty(object, key) {
|
|
6311
6487
|
const value = property(object, key)?.initializer;
|
|
6312
|
-
return value &&
|
|
6488
|
+
return value && ts7.isStringLiteral(value) ? value.text : undefined;
|
|
6313
6489
|
}
|
|
6314
6490
|
function replaceProperty(source, object, key, value) {
|
|
6315
6491
|
const previous = property(object, key);
|
|
6316
|
-
const replacement =
|
|
6492
|
+
const replacement = ts7.factory.createPropertyAssignment(key, value);
|
|
6317
6493
|
const properties = object.properties.map((item) => item === previous ? replacement : item);
|
|
6318
6494
|
if (!previous)
|
|
6319
6495
|
properties.push(replacement);
|
|
6320
|
-
const updated =
|
|
6321
|
-
return source.text.slice(0, object.getStart(source)) +
|
|
6496
|
+
const updated = ts7.factory.updateObjectLiteralExpression(object, properties);
|
|
6497
|
+
return source.text.slice(0, object.getStart(source)) + ts7.createPrinter().printNode(ts7.EmitHint.Expression, updated, source) + source.text.slice(object.end);
|
|
6322
6498
|
}
|
|
6323
6499
|
function findClass(source, name) {
|
|
6324
|
-
return unique(source.statements.filter((statement) =>
|
|
6500
|
+
return unique(source.statements.filter((statement) => ts7.isClassDeclaration(statement) && statement.name?.text === name), `class '${name}'`);
|
|
6325
6501
|
}
|
|
6326
6502
|
function decoratorObject(node, name) {
|
|
6327
|
-
const decorator = unique((
|
|
6328
|
-
const argument =
|
|
6329
|
-
if (!argument || !
|
|
6503
|
+
const decorator = unique((ts7.getDecorators(node) ?? []).filter((item) => ts7.isCallExpression(item.expression) && item.expression.expression.getText() === name), `@${name} decorator`);
|
|
6504
|
+
const argument = ts7.isCallExpression(decorator.expression) ? decorator.expression.arguments[0] : undefined;
|
|
6505
|
+
if (!argument || !ts7.isObjectLiteralExpression(argument))
|
|
6330
6506
|
throw new Error(`@${name} requires a static object`);
|
|
6331
6507
|
return argument;
|
|
6332
6508
|
}
|
|
6333
6509
|
function moduleObjects(source) {
|
|
6334
6510
|
const result = [];
|
|
6335
6511
|
for (const statement of source.statements) {
|
|
6336
|
-
if (
|
|
6512
|
+
if (ts7.isClassDeclaration(statement) && (ts7.getDecorators(statement) ?? []).some((item) => ts7.isCallExpression(item.expression) && item.expression.expression.getText() === "Module")) {
|
|
6337
6513
|
result.push(decoratorObject(statement, "Module"));
|
|
6338
6514
|
}
|
|
6339
|
-
if (
|
|
6515
|
+
if (ts7.isVariableStatement(statement)) {
|
|
6340
6516
|
for (const declaration of statement.declarationList.declarations) {
|
|
6341
6517
|
const call = declaration.initializer;
|
|
6342
|
-
if (call &&
|
|
6518
|
+
if (call && ts7.isCallExpression(call) && ["defineModule", "defineFeatureSlice"].includes(call.expression.getText()) && call.arguments[0] && ts7.isObjectLiteralExpression(call.arguments[0])) {
|
|
6343
6519
|
result.push(call.arguments[0]);
|
|
6344
6520
|
}
|
|
6345
6521
|
}
|
|
@@ -6349,23 +6525,23 @@ function moduleObjects(source) {
|
|
|
6349
6525
|
}
|
|
6350
6526
|
function importSymbol(source, path, symbol) {
|
|
6351
6527
|
identifier(symbol);
|
|
6352
|
-
const current =
|
|
6353
|
-
const target =
|
|
6528
|
+
const current = resolve8(source.fileName).replace(/\.(tsx?|mts|cts)$/, "");
|
|
6529
|
+
const target = resolve8(dirname6(source.fileName), path).replace(/\.(tsx?|mts|cts)$/, "");
|
|
6354
6530
|
if (current === target)
|
|
6355
6531
|
return source.text;
|
|
6356
|
-
const matches = source.statements.filter((item) =>
|
|
6532
|
+
const matches = source.statements.filter((item) => ts7.isImportDeclaration(item) && ts7.isStringLiteral(item.moduleSpecifier) && item.moduleSpecifier.text === path);
|
|
6357
6533
|
if (matches.length > 1)
|
|
6358
6534
|
throw new Error(`Ambiguous imports from '${path}'`);
|
|
6359
6535
|
const match = matches[0];
|
|
6360
|
-
if (match &&
|
|
6536
|
+
if (match && ts7.isImportDeclaration(match) && match.importClause?.namedBindings && ts7.isNamedImports(match.importClause.namedBindings) && !match.importClause.isTypeOnly) {
|
|
6361
6537
|
if (match.importClause.namedBindings.elements.some((item) => item.name.text === symbol))
|
|
6362
6538
|
return source.text;
|
|
6363
6539
|
const bindings = match.importClause.namedBindings;
|
|
6364
|
-
const updated =
|
|
6540
|
+
const updated = ts7.factory.updateNamedImports(bindings, [
|
|
6365
6541
|
...bindings.elements,
|
|
6366
|
-
|
|
6542
|
+
ts7.factory.createImportSpecifier(false, undefined, ts7.factory.createIdentifier(symbol))
|
|
6367
6543
|
]);
|
|
6368
|
-
return source.text.slice(0, bindings.getStart(source)) +
|
|
6544
|
+
return source.text.slice(0, bindings.getStart(source)) + ts7.createPrinter().printNode(ts7.EmitHint.Unspecified, updated, source) + source.text.slice(bindings.end);
|
|
6369
6545
|
}
|
|
6370
6546
|
if (match)
|
|
6371
6547
|
throw new Error(`Import from '${path}' is not a named value import`);
|
|
@@ -6516,8 +6692,8 @@ async function run() {
|
|
|
6516
6692
|
if (checkSchema && command !== "graphql-schema")
|
|
6517
6693
|
throw new Error("--check is only supported by graphql-schema");
|
|
6518
6694
|
const defaults = resolveSupacloudConfig(loadedConfig, process.cwd());
|
|
6519
|
-
const resolvedRoot = rootDir ?
|
|
6520
|
-
const resolvedOut = outDir ?
|
|
6695
|
+
const resolvedRoot = rootDir ? resolve10(process.cwd(), rootDir) : defaults.rootDir;
|
|
6696
|
+
const resolvedOut = outDir ? resolve10(process.cwd(), outDir) : defaults.outDir;
|
|
6521
6697
|
const configured = compileOptionsFromConfig({
|
|
6522
6698
|
...loadedConfig,
|
|
6523
6699
|
root: resolvedRoot,
|
|
@@ -6558,7 +6734,7 @@ async function run() {
|
|
|
6558
6734
|
} else if (command === "fix") {
|
|
6559
6735
|
if (!query)
|
|
6560
6736
|
throw new Error("fix requires a JSON file containing one DiagnosticFix");
|
|
6561
|
-
const fix = JSON.parse(await readFile5(
|
|
6737
|
+
const fix = JSON.parse(await readFile5(resolve10(process.cwd(), query), "utf8"));
|
|
6562
6738
|
const result = await applyDiagnosticFix(fix, { rootDir: resolvedRoot, dryRun });
|
|
6563
6739
|
console.log(JSON.stringify({ ok: true, ...result }, null, 2));
|
|
6564
6740
|
} else if (command === "compile") {
|