@powerhousedao/codegen 6.2.2-dev.8 → 6.2.2-dev.81
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/{file-builders-Btk4MK1I.mjs → file-builders-BZEQ9XnO.mjs} +665 -98
- package/dist/file-builders-BZEQ9XnO.mjs.map +1 -0
- package/dist/{index-CG0iB8e-.d.mts → index-CWgCjPT3.d.mts} +53 -3
- package/dist/index-CWgCjPT3.d.mts.map +1 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +832 -179
- package/dist/index.mjs.map +1 -1
- package/dist/src/file-builders/index.d.mts +2 -2
- package/dist/src/file-builders/index.mjs +2 -2
- package/dist/src/name-builders/index.d.mts +1 -1
- package/dist/src/name-builders/index.mjs +1 -1
- package/dist/src/templates/index.d.mts +45 -3
- package/dist/src/templates/index.d.mts.map +1 -1
- package/dist/src/templates/index.mjs +2 -2
- package/dist/src/utils/index.d.mts +46 -4
- package/dist/src/utils/index.d.mts.map +1 -1
- package/dist/src/utils/index.mjs +2 -2
- package/package.json +4 -4
- package/dist/file-builders-Btk4MK1I.mjs.map +0 -1
- package/dist/index-CG0iB8e-.d.mts.map +0 -1
|
@@ -5,21 +5,23 @@ import path, { join } from "path";
|
|
|
5
5
|
import { DocumentModelGlobalStateSchema, ManifestSchema } from "@powerhousedao/shared/document-model";
|
|
6
6
|
import fs, { copyFile, mkdir, readdir, writeFile } from "node:fs/promises";
|
|
7
7
|
import { camelCase, capitalCase, constantCase, kebabCase, pascalCase } from "change-case";
|
|
8
|
+
import { DEFAULT_SWITCHBOARD_PORT } from "@powerhousedao/shared/clis/constants";
|
|
9
|
+
import { deriveProjectPorts } from "@powerhousedao/shared/clis/project-ports";
|
|
8
10
|
import { DEFAULT_CONNECT_CONFIG } from "@powerhousedao/shared/connect";
|
|
9
11
|
import { DEFAULT_REGISTRY_URL } from "@powerhousedao/shared/registry";
|
|
10
12
|
import { capitalize, concat, conditional, constant, endsWith, filter, find, first, flatMap, forEach, isDefined, isIncludedIn, isNonNullish, isNot, isStrictEqual, isString, isTruthy, last, map, mapValues, merge, pipe, prop, sort, split, startsWith, subtract, unique, uniqueBy, when } from "remeda";
|
|
11
|
-
import { IndentationText, Project, SyntaxKind, VariableDeclarationKind, ts } from "ts-morph";
|
|
13
|
+
import { FileSystemRefreshResult, IndentationText, Project, SyntaxKind, VariableDeclarationKind, ts } from "ts-morph";
|
|
12
14
|
import arg from "arg";
|
|
13
15
|
import { format } from "oxfmt";
|
|
14
16
|
import { z } from "zod";
|
|
15
17
|
import { loadJsonFile, loadJsonFileSync } from "load-json-file";
|
|
18
|
+
import { existsSync, realpathSync } from "node:fs";
|
|
16
19
|
import { writeJsonFile } from "write-json-file";
|
|
17
20
|
import { stripVTControlCharacters } from "node:util";
|
|
18
21
|
import path$1, { join as join$1, relative } from "node:path";
|
|
19
22
|
import { generate } from "@graphql-codegen/cli";
|
|
20
|
-
import { generatorTypeDefs, validationSchema } from "@powerhousedao/document-engineering/graphql";
|
|
21
|
-
import { Kind, parse } from "graphql";
|
|
22
|
-
import { realpathSync } from "node:fs";
|
|
23
|
+
import { generatorTypeDefs, getPHCustomScalarByTypeName, validationSchema } from "@powerhousedao/document-engineering/graphql";
|
|
24
|
+
import { Kind, parse, print } from "graphql";
|
|
23
25
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
24
26
|
function isEOL(c) {
|
|
25
27
|
return c === 10 || c === 13;
|
|
@@ -2153,12 +2155,22 @@ This project creates document models, editors, processors and subgraphs for the
|
|
|
2153
2155
|
- **Reactor Package**: A deployable bundle that extends the Reactor. It contains one or more document models, editors, processors, and subgraphs. A Vetra project generates a Reactor Package.
|
|
2154
2156
|
- **Connect**: The Powerhouse web application for document management. End users open Connect to browse drives, create documents, and interact with editors.
|
|
2155
2157
|
- **Switchboard**: The Powerhouse API service. It exposes GraphQL and MCP endpoints so external tools can read/write documents programmatically.
|
|
2156
|
-
- **Vetra**: The local development environment for building Reactor Packages. It includes Vetra Studio (a local Connect instance) and Vetra Switchboard (a local Switchboard with reactor-mcp).
|
|
2158
|
+
- **Vetra**: The local development environment for building Reactor Packages. It includes Vetra Studio (a local Connect instance) and Vetra Switchboard (a local Switchboard with reactor-mcp). **You start it yourself** with \`ph vetra --strictPort --watch\` as a background process — see the MCP rules below. Its ports are assigned per project in \`powerhouse.config.json\`, so they never collide with another project's.
|
|
2157
2159
|
|
|
2158
2160
|
## CRITICAL: MCP Tool Usage Rules
|
|
2159
2161
|
|
|
2160
2162
|
**MANDATORY**: The \`reactor-mcp\` MUST BE USED when handling documents or document-models for the Powerhouse/Vetra ecosystem.
|
|
2161
|
-
If the \`reactor-mcp\` server is unavailable,
|
|
2163
|
+
If the \`reactor-mcp\` server is unavailable, **start Vetra yourself** — do not ask the user to do it:
|
|
2164
|
+
|
|
2165
|
+
1. **Check for a running instance.** If \`.ph/vetra-runtime.json\` exists and describes a live instance, Vetra is already up: report its Connect URL and stop. Never start a second one — a project must have exactly one reactor, because two would contend for the same \`.ph/\` storage and leave you with two drives that diverge.
|
|
2166
|
+
2. **Start it in the background:** \`ph vetra --strictPort --watch\`. Pass no port flags. The project's ports live in \`powerhouse.config.json\` and are already what \`.mcp.json\` points at; choosing your own port is how you end up talking to a different project's reactor. \`--strictPort\` makes a genuine conflict fail loudly instead of silently binding a neighbouring port.
|
|
2167
|
+
3. **Wait for readiness.** Poll \`GET http://localhost:<port>/ready\` until it returns 200, for at most 60 seconds, where \`<port>\` is the one in \`.mcp.json\`. Poll that port specifically: it is the only one your MCP client will ever use, so a timeout there is the correct signal even if Vetra came up somewhere else.
|
|
2168
|
+
4. **Tell the user the Connect URL** so they can watch their editors render.
|
|
2169
|
+
5. **Reconnect to the MCP server** and continue the task.
|
|
2170
|
+
|
|
2171
|
+
Escalate to the user only when startup actually fails — \`--strictPort\` rejected the port, \`/ready\` never returned 200, or the process crashed — and include the real error output.
|
|
2172
|
+
|
|
2173
|
+
**Never edit \`.mcp.json\` to chase a port.** A mismatch between it and the running switchboard is a bug worth reporting, not routing around; \`ph vetra\` owns that reconciliation and will rewrite the file itself when a local override moves the port.
|
|
2162
2174
|
|
|
2163
2175
|
### Key Requirements:
|
|
2164
2176
|
|
|
@@ -2881,16 +2893,18 @@ const claudeSettingsLocalTemplate = json`
|
|
|
2881
2893
|
`.raw;
|
|
2882
2894
|
//#endregion
|
|
2883
2895
|
//#region src/templates/boilerplate/cursor/mcp.json.ts
|
|
2884
|
-
|
|
2896
|
+
/** Cursor's copy of the MCP config. Same literal-port reasoning as `.mcp.json`. */
|
|
2897
|
+
const buildCursorMcpTemplate = (port) => json`
|
|
2885
2898
|
{
|
|
2886
2899
|
"mcpServers": {
|
|
2887
2900
|
"reactor-mcp": {
|
|
2888
2901
|
"type": "http",
|
|
2889
|
-
"url": "http://localhost
|
|
2902
|
+
"url": "http://localhost:${String(port)}/mcp"
|
|
2890
2903
|
}
|
|
2891
2904
|
}
|
|
2892
2905
|
}
|
|
2893
2906
|
`.raw;
|
|
2907
|
+
const cursorMcpTemplate = buildCursorMcpTemplate(DEFAULT_SWITCHBOARD_PORT);
|
|
2894
2908
|
//#endregion
|
|
2895
2909
|
//#region src/templates/boilerplate/docker/connect-entrypoint.sh.ts
|
|
2896
2910
|
const connectEntrypointTemplate = `#!/bin/sh
|
|
@@ -4446,16 +4460,25 @@ const { updateLocalPackage } = startConnect(localPackage);
|
|
|
4446
4460
|
`.raw;
|
|
4447
4461
|
//#endregion
|
|
4448
4462
|
//#region src/templates/boilerplate/mcp.json.ts
|
|
4449
|
-
|
|
4463
|
+
/**
|
|
4464
|
+
* Render `.mcp.json` for a project whose switchboard listens on `port`.
|
|
4465
|
+
*
|
|
4466
|
+
* The port is a literal rather than an env reference on purpose: an MCP
|
|
4467
|
+
* client resolves this file at session start and cannot read `.env` or
|
|
4468
|
+
* `powerhouse.config.json`. `ph vetra` reconciles the literal if an override
|
|
4469
|
+
* moves the port.
|
|
4470
|
+
*/
|
|
4471
|
+
const buildMcpTemplate = (port) => json`
|
|
4450
4472
|
{
|
|
4451
4473
|
"mcpServers": {
|
|
4452
4474
|
"reactor-mcp": {
|
|
4453
4475
|
"type": "http",
|
|
4454
|
-
"url": "http://localhost
|
|
4476
|
+
"url": "http://localhost:${String(port)}/mcp"
|
|
4455
4477
|
}
|
|
4456
4478
|
}
|
|
4457
4479
|
}
|
|
4458
4480
|
`.raw;
|
|
4481
|
+
const mcpTemplate = buildMcpTemplate(DEFAULT_SWITCHBOARD_PORT);
|
|
4459
4482
|
//#endregion
|
|
4460
4483
|
//#region src/templates/boilerplate/npmrc.ts
|
|
4461
4484
|
const npmrcTemplate = `@jsr:registry=https://npm.jsr.io`;
|
|
@@ -4482,9 +4505,9 @@ const packageJsonTemplate = (projectName, peerDependencies, devDependencies) =>
|
|
|
4482
4505
|
${exportsTemplate}
|
|
4483
4506
|
},
|
|
4484
4507
|
"scripts": {
|
|
4485
|
-
"test": "vitest run",
|
|
4508
|
+
"test": "vitest run --passWithNoTests",
|
|
4486
4509
|
"test:watch": "vitest",
|
|
4487
|
-
"test:coverage": "vitest run --coverage",
|
|
4510
|
+
"test:coverage": "vitest run --coverage --passWithNoTests",
|
|
4488
4511
|
"lint": "oxlint --type-aware --type-check",
|
|
4489
4512
|
"lint:fix": "oxlint --type-aware --type-check --fix",
|
|
4490
4513
|
"format": "oxfmt",
|
|
@@ -4578,22 +4601,25 @@ const packageJsonExportsTemplate = {
|
|
|
4578
4601
|
* see fully-defined values instead of `undefined`.
|
|
4579
4602
|
*/
|
|
4580
4603
|
async function buildPowerhouseConfigTemplate(args) {
|
|
4604
|
+
const ports = deriveProjectPorts(args.name);
|
|
4581
4605
|
const config = {
|
|
4582
4606
|
$schema: "https://raw.githubusercontent.com/powerhouse-inc/powerhouse/main/packages/shared/clis/source-config.schema.json",
|
|
4583
4607
|
documentModelsDir: "./document-models",
|
|
4584
4608
|
editorsDir: "./editors",
|
|
4585
4609
|
processorsDir: "./processors",
|
|
4586
4610
|
subgraphsDir: "./subgraphs",
|
|
4587
|
-
studio: { port:
|
|
4588
|
-
reactor: { port:
|
|
4611
|
+
studio: { port: ports.studioPort },
|
|
4612
|
+
reactor: { port: ports.switchboardPort },
|
|
4589
4613
|
packages: [],
|
|
4590
4614
|
packageRegistryUrl: DEFAULT_REGISTRY_URL,
|
|
4591
4615
|
connect: DEFAULT_CONNECT_CONFIG
|
|
4592
4616
|
};
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
4617
|
+
const vetra = { connectPort: ports.vetraConnectPort };
|
|
4618
|
+
if (args.remoteDrive) {
|
|
4619
|
+
vetra.driveId = args.remoteDrive.split("/").pop() ?? "";
|
|
4620
|
+
vetra.driveUrl = args.remoteDrive;
|
|
4621
|
+
}
|
|
4622
|
+
config.vetra = vetra;
|
|
4597
4623
|
return `${JSON.stringify(config, null, 2)}\n`;
|
|
4598
4624
|
}
|
|
4599
4625
|
//#endregion
|
|
@@ -5185,36 +5211,88 @@ ${buildCreatorsExports(v.specification.modules, v.camelCaseDocumentType)}
|
|
|
5185
5211
|
`.raw;
|
|
5186
5212
|
//#endregion
|
|
5187
5213
|
//#region src/templates/document-model/gen/document-schema.ts
|
|
5188
|
-
|
|
5214
|
+
function priorVersions(versions, currentVersion) {
|
|
5215
|
+
return versions.filter((k) => k < currentVersion);
|
|
5216
|
+
}
|
|
5217
|
+
function makeOlderStateSchemaImports(versions, currentVersion, phStateName) {
|
|
5218
|
+
return priorVersions(versions, currentVersion).map((k) => `import { ${phStateName}Schema as ${phStateName}SchemaV${k} } from "../../v${k}/gen/document-schema.js";`).join("\n");
|
|
5219
|
+
}
|
|
5220
|
+
function makeStateSchemasByVersion(versions, currentVersion, phStateName) {
|
|
5221
|
+
return `{ ${versions.filter((k) => k <= currentVersion).map((k) => {
|
|
5222
|
+
return `${k}: ${k === currentVersion ? `${phStateName}Schema` : `${phStateName}SchemaV${k}`}`;
|
|
5223
|
+
}).join(", ")} }`;
|
|
5224
|
+
}
|
|
5225
|
+
function makeDocumentSchemasByVersion(versions, currentVersion, v) {
|
|
5226
|
+
return `{ ${versions.filter((k) => k <= currentVersion).map((k) => {
|
|
5227
|
+
if (k === currentVersion) return `${k}: ${v.phDocumentSchemaName}`;
|
|
5228
|
+
return `${k}: z.object({ header: ${v.phDocumentTypeName}HeaderSchema, state: ${v.phStateName}SchemaV${k}, initialState: ${v.phStateName}SchemaV${k} })`;
|
|
5229
|
+
}).join(", ")} }`;
|
|
5230
|
+
}
|
|
5189
5231
|
/**
|
|
5190
|
-
|
|
5191
|
-
|
|
5192
|
-
|
|
5193
|
-
|
|
5194
|
-
|
|
5195
|
-
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
import { ${v.documentTypeVariableName} } from "./document-type.js";
|
|
5199
|
-
import { ${v.stateSchemaName} } from "./schema/zod.js";
|
|
5200
|
-
import type { ${v.phDocumentTypeName}, ${v.phStateName} } from "./types.js";
|
|
5232
|
+
* Version-aware validators are only emitted for versions with released
|
|
5233
|
+
* predecessors: a document is validated against the schema of the version it
|
|
5234
|
+
* is stamped with, so a later version may add non-nullable fields without
|
|
5235
|
+
* rejecting documents that have not been upgraded yet.
|
|
5236
|
+
*/
|
|
5237
|
+
function makeVersionAwareValidators(v) {
|
|
5238
|
+
return `
|
|
5239
|
+
const ${v.phStateName}SchemasByVersion: Record<number, z.ZodType> = ${makeStateSchemasByVersion(v.versions, v.version, v.phStateName)};
|
|
5201
5240
|
|
|
5202
|
-
|
|
5203
|
-
export const ${v.phDocumentTypeName}HeaderSchema = BaseDocumentHeaderSchema.extend({
|
|
5204
|
-
documentType: z.literal(${v.documentTypeVariableName}),
|
|
5205
|
-
});
|
|
5241
|
+
const ${v.phDocumentSchemaName}sByVersion: Record<number, z.ZodType> = ${makeDocumentSchemasByVersion(v.versions, v.version, v)};
|
|
5206
5242
|
|
|
5207
|
-
/**
|
|
5208
|
-
|
|
5209
|
-
|
|
5210
|
-
});
|
|
5243
|
+
/** The document model version stamped in a state's document scope. States stamped with 0 or nothing predate versioning and are treated as version 1. */
|
|
5244
|
+
function stampedDocumentModelVersion(state: unknown): number {
|
|
5245
|
+
if (typeof state !== "object" || state === null) return 1;
|
|
5246
|
+
const documentScope = (state as { document?: unknown }).document;
|
|
5247
|
+
if (typeof documentScope !== "object" || documentScope === null) return 1;
|
|
5248
|
+
const version = (documentScope as { version?: unknown }).version;
|
|
5249
|
+
return normalizeDocumentModelVersion(typeof version === "number" ? version : undefined);
|
|
5250
|
+
}
|
|
5211
5251
|
|
|
5212
|
-
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
|
|
5216
|
-
|
|
5252
|
+
function resolve${v.phStateName}Schema(state: unknown): z.ZodType {
|
|
5253
|
+
const schema = ${v.phStateName}SchemasByVersion[stampedDocumentModelVersion(state)];
|
|
5254
|
+
return schema ?? ${v.phStateName}Schema;
|
|
5255
|
+
}
|
|
5256
|
+
|
|
5257
|
+
function resolve${v.phDocumentSchemaName}(document: unknown): z.ZodType {
|
|
5258
|
+
const state = typeof document === "object" && document !== null
|
|
5259
|
+
? (document as { state?: unknown }).state
|
|
5260
|
+
: undefined;
|
|
5261
|
+
const schema = ${v.phDocumentSchemaName}sByVersion[stampedDocumentModelVersion(state)];
|
|
5262
|
+
return schema ?? ${v.phDocumentSchemaName};
|
|
5263
|
+
}
|
|
5264
|
+
|
|
5265
|
+
/** Simple helper function to check if a state object is a ${v.pascalCaseDocumentType} document state object. Validates against the schema of the version the state is stamped with. */
|
|
5266
|
+
export function ${v.isPhStateOfTypeFunctionName}(
|
|
5267
|
+
state: unknown,
|
|
5268
|
+
): state is ${v.phStateName} {
|
|
5269
|
+
return resolve${v.phStateName}Schema(state).safeParse(state).success;
|
|
5270
|
+
}
|
|
5271
|
+
|
|
5272
|
+
/** Simple helper function to assert that a document state object is a ${v.pascalCaseDocumentType} document state object. Validates against the schema of the version the state is stamped with. */
|
|
5273
|
+
export function ${v.assertIsPhStateOfTypeFunctionName}(
|
|
5274
|
+
state: unknown,
|
|
5275
|
+
): asserts state is ${v.phStateName} {
|
|
5276
|
+
resolve${v.phStateName}Schema(state).parse(state);
|
|
5277
|
+
}
|
|
5278
|
+
|
|
5279
|
+
/** Simple helper function to check if a document is a ${v.pascalCaseDocumentType} document. Validates against the schema of the version the document is stamped with, so documents on older versions remain valid until they are upgraded. */
|
|
5280
|
+
export function ${v.isPhDocumentOfTypeFunctionName}(
|
|
5281
|
+
document: unknown,
|
|
5282
|
+
): document is ${v.phDocumentTypeName} {
|
|
5283
|
+
return resolve${v.phDocumentSchemaName}(document).safeParse(document).success;
|
|
5284
|
+
}
|
|
5217
5285
|
|
|
5286
|
+
/** Simple helper function to assert that a document is a ${v.pascalCaseDocumentType} document. Validates against the schema of the version the document is stamped with, so documents on older versions remain valid until they are upgraded. */
|
|
5287
|
+
export function ${v.assertIsPhDocumentOfTypeFunctionName}(
|
|
5288
|
+
document: unknown,
|
|
5289
|
+
): asserts document is ${v.phDocumentTypeName} {
|
|
5290
|
+
resolve${v.phDocumentSchemaName}(document).parse(document);
|
|
5291
|
+
}
|
|
5292
|
+
`;
|
|
5293
|
+
}
|
|
5294
|
+
function makeSingleVersionValidators(v) {
|
|
5295
|
+
return `
|
|
5218
5296
|
/** Simple helper function to check if a state object is a ${v.pascalCaseDocumentType} document state object */
|
|
5219
5297
|
export function ${v.isPhStateOfTypeFunctionName}(
|
|
5220
5298
|
state: unknown,
|
|
@@ -5242,7 +5320,42 @@ export function ${v.assertIsPhDocumentOfTypeFunctionName}(
|
|
|
5242
5320
|
): asserts document is ${v.phDocumentTypeName} {
|
|
5243
5321
|
${v.phDocumentSchemaName}.parse(document);
|
|
5244
5322
|
}
|
|
5245
|
-
|
|
5323
|
+
`;
|
|
5324
|
+
}
|
|
5325
|
+
const documentModelDocumentSchemaFileTemplate = (v) => {
|
|
5326
|
+
const olderImports = makeOlderStateSchemaImports(v.versions, v.version, v.phStateName);
|
|
5327
|
+
const hasPriorVersions = olderImports.length > 0;
|
|
5328
|
+
return ts$1`
|
|
5329
|
+
/**
|
|
5330
|
+
* WARNING: DO NOT EDIT
|
|
5331
|
+
* This file is auto-generated and updated by codegen
|
|
5332
|
+
*/
|
|
5333
|
+
import {
|
|
5334
|
+
BaseDocumentHeaderSchema,
|
|
5335
|
+
BaseDocumentStateSchema,${hasPriorVersions ? "\n normalizeDocumentModelVersion," : ""}
|
|
5336
|
+
} from "document-model";
|
|
5337
|
+
import { z } from "zod";
|
|
5338
|
+
import { ${v.documentTypeVariableName} } from "./document-type.js";
|
|
5339
|
+
import { ${v.stateSchemaName} } from "./schema/zod.js";
|
|
5340
|
+
import type { ${v.phDocumentTypeName}, ${v.phStateName} } from "./types.js";
|
|
5341
|
+
${hasPriorVersions ? olderImports + "\n" : ""}
|
|
5342
|
+
/** Schema for validating the header object of a ${v.pascalCaseDocumentType} document */
|
|
5343
|
+
export const ${v.phDocumentTypeName}HeaderSchema = BaseDocumentHeaderSchema.extend({
|
|
5344
|
+
documentType: z.literal(${v.documentTypeVariableName}),
|
|
5345
|
+
});
|
|
5346
|
+
|
|
5347
|
+
/** Schema for validating the state object of a ${v.pascalCaseDocumentType} document */
|
|
5348
|
+
export const ${v.phStateName}Schema = BaseDocumentStateSchema.extend({
|
|
5349
|
+
global: ${v.stateSchemaName}(),
|
|
5350
|
+
});
|
|
5351
|
+
|
|
5352
|
+
export const ${v.phDocumentSchemaName} = z.object({
|
|
5353
|
+
header: ${v.phDocumentTypeName}HeaderSchema,
|
|
5354
|
+
state: ${v.phStateName}Schema,
|
|
5355
|
+
initialState: ${v.phStateName}Schema,
|
|
5356
|
+
});
|
|
5357
|
+
${hasPriorVersions ? makeVersionAwareValidators(v) : makeSingleVersionValidators(v)}`.raw;
|
|
5358
|
+
};
|
|
5246
5359
|
//#endregion
|
|
5247
5360
|
//#region src/templates/document-model/gen/document-type.ts
|
|
5248
5361
|
const documentModelDocumentTypeTemplate = (v) => ts$1`
|
|
@@ -6198,7 +6311,7 @@ const documentModelOperationsModuleTestFileTemplate = (v) => ts$1`
|
|
|
6198
6311
|
*/
|
|
6199
6312
|
|
|
6200
6313
|
import { describe, it, expect } from 'vitest';
|
|
6201
|
-
import { generateMock } from 'document-model';
|
|
6314
|
+
import { generateMock } from 'document-model/mock';
|
|
6202
6315
|
import {
|
|
6203
6316
|
reducer,
|
|
6204
6317
|
utils,
|
|
@@ -6231,11 +6344,66 @@ const upgradeManifestTemplate = (v) => ts$1`
|
|
|
6231
6344
|
`.raw;
|
|
6232
6345
|
//#endregion
|
|
6233
6346
|
//#region src/templates/document-model/upgrades/upgrade-transition.ts
|
|
6234
|
-
|
|
6347
|
+
/**
|
|
6348
|
+
* The generated v{N}.ts upgrade transition. Written once and never
|
|
6349
|
+
* overwritten, so hand edits survive regeneration.
|
|
6350
|
+
*
|
|
6351
|
+
* For mechanical schema changes the migration is derived: fields added in
|
|
6352
|
+
* the new version are initialized (from the new version's initial value or
|
|
6353
|
+
* the schema's zero value) and existing data is preserved. When the change
|
|
6354
|
+
* cannot be derived — a field changed type, a nested type changed shape —
|
|
6355
|
+
* the reducer throws until the migration is hand-written: silently running
|
|
6356
|
+
* a no-op migration would stamp documents with a version whose schema their
|
|
6357
|
+
* state does not satisfy, crashing every consumer that validates them.
|
|
6358
|
+
*/
|
|
6359
|
+
const upgradeTransitionTemplate = (v) => {
|
|
6360
|
+
const body = v.plan.kind === "manual" ? manualReducer(v, v.plan.reason) : fillReducer(v, v.plan.fills);
|
|
6361
|
+
return ts$1`
|
|
6362
|
+
/**
|
|
6363
|
+
* WARNING: DO NOT EDIT
|
|
6364
|
+
* This file is auto-generated and updated by codegen
|
|
6365
|
+
*/
|
|
6235
6366
|
import type { Action, PHDocument, UpgradeTransition } from "document-model";
|
|
6236
6367
|
import type { ${v.phStateName} as StateV${v.version - 1} } from "${v.documentModelImportPath}/v${v.version - 1}";
|
|
6237
6368
|
import type { ${v.phStateName} as StateV${v.version} } from "${v.documentModelImportPath}/v${v.version}";
|
|
6238
6369
|
|
|
6370
|
+
${body}
|
|
6371
|
+
|
|
6372
|
+
export const v${v.version}: UpgradeTransition = {
|
|
6373
|
+
toVersion: ${v.version},
|
|
6374
|
+
upgradeReducer,
|
|
6375
|
+
description: "",
|
|
6376
|
+
};
|
|
6377
|
+
`.raw;
|
|
6378
|
+
};
|
|
6379
|
+
function manualReducer(v, reason) {
|
|
6380
|
+
const message = `The ${v.documentModelState.id} v${v.version} migration is not implemented: ${reason}. Implement it in document-models/${v.documentModelDirName}/upgrades/v${v.version}.ts.`;
|
|
6381
|
+
return `
|
|
6382
|
+
/*
|
|
6383
|
+
* This migration could not be derived automatically: ${reason}.
|
|
6384
|
+
* Implement it (migrate BOTH state and initialState), then remove the throw.
|
|
6385
|
+
*/
|
|
6386
|
+
function upgradeReducer(
|
|
6387
|
+
document: PHDocument<StateV${v.version - 1}>,
|
|
6388
|
+
action: Action,
|
|
6389
|
+
): PHDocument<StateV${v.version}> {
|
|
6390
|
+
throw new Error(${JSON.stringify(message)});
|
|
6391
|
+
}
|
|
6392
|
+
`;
|
|
6393
|
+
}
|
|
6394
|
+
function fillReducer(v, fills) {
|
|
6395
|
+
const fillConsts = [];
|
|
6396
|
+
const scopeLines = (source) => ["global", "local"].filter((scope) => fills[scope]).map((scope) => ` ${scope}: { ...added${capitalize$1(scope)}Fields, ...document.${source}.${scope} },`).join("\n");
|
|
6397
|
+
for (const scope of ["global", "local"]) {
|
|
6398
|
+
const fill = fills[scope];
|
|
6399
|
+
if (!fill) continue;
|
|
6400
|
+
fillConsts.push(`const added${capitalize$1(scope)}Fields = ${JSON.stringify(fill, null, 2)} satisfies Partial<StateV${v.version}["${scope}"]>;`);
|
|
6401
|
+
}
|
|
6402
|
+
if (fillConsts.length === 0) return `
|
|
6403
|
+
/*
|
|
6404
|
+
* No fields were added between v${v.version - 1} and v${v.version}, so existing state
|
|
6405
|
+
* carries over unchanged.
|
|
6406
|
+
*/
|
|
6239
6407
|
function upgradeReducer(
|
|
6240
6408
|
document: PHDocument<StateV${v.version - 1}>,
|
|
6241
6409
|
action: Action,
|
|
@@ -6244,13 +6412,37 @@ function upgradeReducer(
|
|
|
6244
6412
|
...document,
|
|
6245
6413
|
};
|
|
6246
6414
|
}
|
|
6415
|
+
`;
|
|
6416
|
+
return `
|
|
6417
|
+
${fillConsts.join("\n\n")}
|
|
6247
6418
|
|
|
6248
|
-
|
|
6249
|
-
|
|
6250
|
-
|
|
6251
|
-
|
|
6252
|
-
|
|
6253
|
-
|
|
6419
|
+
/*
|
|
6420
|
+
* Fields added in v${v.version} are initialized from the new version's initial
|
|
6421
|
+
* value (or the schema's zero value); existing data wins for every field
|
|
6422
|
+
* that already existed. Both state and initialState are migrated so a
|
|
6423
|
+
* rebuild from the operation log converges with the stored state.
|
|
6424
|
+
*/
|
|
6425
|
+
function upgradeReducer(
|
|
6426
|
+
document: PHDocument<StateV${v.version - 1}>,
|
|
6427
|
+
action: Action,
|
|
6428
|
+
): PHDocument<StateV${v.version}> {
|
|
6429
|
+
return {
|
|
6430
|
+
...document,
|
|
6431
|
+
state: {
|
|
6432
|
+
...document.state,
|
|
6433
|
+
${scopeLines("state")}
|
|
6434
|
+
},
|
|
6435
|
+
initialState: {
|
|
6436
|
+
...document.initialState,
|
|
6437
|
+
${scopeLines("initialState")}
|
|
6438
|
+
},
|
|
6439
|
+
};
|
|
6440
|
+
}
|
|
6441
|
+
`;
|
|
6442
|
+
}
|
|
6443
|
+
function capitalize$1(value) {
|
|
6444
|
+
return value.charAt(0).toUpperCase() + value.slice(1);
|
|
6445
|
+
}
|
|
6254
6446
|
//#endregion
|
|
6255
6447
|
//#region src/templates/document-model/utils.ts
|
|
6256
6448
|
const documentModelUtilsTemplate = ({ phStateName, pascalCaseDocumentType }) => ts$1`
|
|
@@ -6268,9 +6460,23 @@ export const utils: DocumentModelUtils<${phStateName}> = { ...genUtils, ...custo
|
|
|
6268
6460
|
`.raw;
|
|
6269
6461
|
//#endregion
|
|
6270
6462
|
//#region src/templates/processors/utils.ts
|
|
6271
|
-
|
|
6272
|
-
|
|
6273
|
-
|
|
6463
|
+
const FILTER_FIELD_ORDER = [
|
|
6464
|
+
"branch",
|
|
6465
|
+
"documentId",
|
|
6466
|
+
"documentType",
|
|
6467
|
+
"scope"
|
|
6468
|
+
];
|
|
6469
|
+
/** Splits, trims and compacts one filter field, so `-t a -t b` and
|
|
6470
|
+
* `-t "a,b"` mean the same thing instead of the latter yielding one value. */
|
|
6471
|
+
function parseFilterValues(values) {
|
|
6472
|
+
return (values ?? []).flatMap((value) => value.split(",")).map((value) => value.trim()).filter((value) => value.length > 0);
|
|
6473
|
+
}
|
|
6474
|
+
/** Renders a generated factory's `ProcessorFilter`, omitting empty fields:
|
|
6475
|
+
* only `documentId` honours `"*"`, so `["*"]` elsewhere matches nothing. */
|
|
6476
|
+
function renderProcessorFilter(fields) {
|
|
6477
|
+
const properties = FILTER_FIELD_ORDER.map((name) => [name, parseFilterValues(fields[name])]).filter(([, values]) => values.length > 0).map(([name, values]) => ` ${name}: [${values.map((value) => `"${value}"`).join(", ")}],`);
|
|
6478
|
+
if (properties.length === 0) return "{}";
|
|
6479
|
+
return `{\n${properties.join("\n")}\n}`;
|
|
6274
6480
|
}
|
|
6275
6481
|
//#endregion
|
|
6276
6482
|
//#region src/templates/processors/analytics/factory.ts
|
|
@@ -6288,12 +6494,12 @@ export const ${v.camelCaseName}FactoryBuilder: ProcessorFactoryBuilder = (module
|
|
|
6288
6494
|
return [
|
|
6289
6495
|
{
|
|
6290
6496
|
processor: new ${v.pascalCaseName}(module.analyticsStore),
|
|
6291
|
-
|
|
6292
|
-
|
|
6293
|
-
|
|
6294
|
-
|
|
6295
|
-
|
|
6296
|
-
|
|
6497
|
+
// An omitted field matches every value. Only \`documentId\` honours "*".
|
|
6498
|
+
filter: ${renderProcessorFilter({
|
|
6499
|
+
branch: ["main"],
|
|
6500
|
+
documentId: ["*"],
|
|
6501
|
+
documentType: v.documentTypes
|
|
6502
|
+
})},
|
|
6297
6503
|
},
|
|
6298
6504
|
];
|
|
6299
6505
|
}
|
|
@@ -6347,7 +6553,7 @@ const factoryBuildersTemplate = ts$1`
|
|
|
6347
6553
|
* WARNING: DO NOT EDIT
|
|
6348
6554
|
* This file is auto-generated and updated by codegen
|
|
6349
6555
|
*/
|
|
6350
|
-
import type { ProcessorFactoryBuilder } from "@powerhousedao/reactor";
|
|
6556
|
+
import type { ProcessorFactoryBuilder } from "@powerhousedao/reactor-browser";
|
|
6351
6557
|
|
|
6352
6558
|
export const processorFactoryBuilders: ProcessorFactoryBuilder[] = [];
|
|
6353
6559
|
`.raw;
|
|
@@ -6421,16 +6627,22 @@ export const ${v.camelCaseName}FactoryBuilder: ProcessorFactoryBuilder = (module
|
|
|
6421
6627
|
namespace,
|
|
6422
6628
|
);
|
|
6423
6629
|
|
|
6424
|
-
// Create a filter for the processor
|
|
6425
|
-
|
|
6426
|
-
|
|
6427
|
-
|
|
6428
|
-
|
|
6429
|
-
|
|
6430
|
-
|
|
6630
|
+
// Create a filter for the processor. An omitted field matches every value.
|
|
6631
|
+
// Only \`documentId\` honours "*", so "*" elsewhere would match nothing.
|
|
6632
|
+
const filter: ProcessorFilter = ${renderProcessorFilter({
|
|
6633
|
+
branch: ["main"],
|
|
6634
|
+
documentId: ["*"],
|
|
6635
|
+
documentType: v.documentTypes,
|
|
6636
|
+
scope: ["global"]
|
|
6637
|
+
})};
|
|
6431
6638
|
|
|
6432
6639
|
// Create the processor
|
|
6433
6640
|
const processor = new ${v.pascalCaseName}(namespace, filter, store);
|
|
6641
|
+
|
|
6642
|
+
// Run the processor's migrations. Nothing in the runtime calls this, so
|
|
6643
|
+
// without it the first write hits a database with no tables.
|
|
6644
|
+
await processor.initAndUpgrade();
|
|
6645
|
+
|
|
6434
6646
|
return [
|
|
6435
6647
|
{
|
|
6436
6648
|
processor,
|
|
@@ -6659,8 +6871,47 @@ async function formatSafe(sourceText, parser = "typescript") {
|
|
|
6659
6871
|
return sourceText;
|
|
6660
6872
|
}
|
|
6661
6873
|
}
|
|
6874
|
+
/**
|
|
6875
|
+
* Formats the current working directory with the pinned oxfmt version.
|
|
6876
|
+
* The pin matters when the project was scaffolded with skipInstall: with no
|
|
6877
|
+
* local oxfmt, a bare `npx oxfmt` downloads the latest release, whose
|
|
6878
|
+
* behavior can drift from the version the boilerplate depends on.
|
|
6879
|
+
*/
|
|
6662
6880
|
async function runOxfmt() {
|
|
6663
|
-
await spawnAsync("npx", [
|
|
6881
|
+
await spawnAsync("npx", [`oxfmt@${externalDevDependencies.oxfmt}`, "."]);
|
|
6882
|
+
}
|
|
6883
|
+
//#endregion
|
|
6884
|
+
//#region src/utils/generate-mock-import.ts
|
|
6885
|
+
const GENERATE_MOCK_NAME = "generateMock";
|
|
6886
|
+
const GENERATE_MOCK_MODULE_SPECIFIER = "document-model/mock";
|
|
6887
|
+
/**
|
|
6888
|
+
* Points every `generateMock` import at its subpath. An import that also
|
|
6889
|
+
* brings in other names keeps them where they are and gets a separate
|
|
6890
|
+
* `generateMock` import added.
|
|
6891
|
+
*/
|
|
6892
|
+
function fixGenerateMockImports(sourceFile) {
|
|
6893
|
+
for (const importDeclaration of sourceFile.getImportDeclarations()) {
|
|
6894
|
+
const namedImports = importDeclaration.getNamedImports();
|
|
6895
|
+
const generateMockSpecifier = namedImports.find((namedImport) => namedImport.getName() === GENERATE_MOCK_NAME);
|
|
6896
|
+
if (!generateMockSpecifier) continue;
|
|
6897
|
+
if (importDeclaration.getModuleSpecifierValue() === "document-model/mock") continue;
|
|
6898
|
+
if (namedImports.length === 1 && !importDeclaration.getDefaultImport() && !importDeclaration.getNamespaceImport()) {
|
|
6899
|
+
importDeclaration.setModuleSpecifier(GENERATE_MOCK_MODULE_SPECIFIER);
|
|
6900
|
+
continue;
|
|
6901
|
+
}
|
|
6902
|
+
const alias = generateMockSpecifier.getAliasNode()?.getText();
|
|
6903
|
+
generateMockSpecifier.remove();
|
|
6904
|
+
sourceFile.addImportDeclaration({
|
|
6905
|
+
namedImports: [{
|
|
6906
|
+
name: GENERATE_MOCK_NAME,
|
|
6907
|
+
alias
|
|
6908
|
+
}],
|
|
6909
|
+
moduleSpecifier: GENERATE_MOCK_MODULE_SPECIFIER
|
|
6910
|
+
});
|
|
6911
|
+
}
|
|
6912
|
+
}
|
|
6913
|
+
function hasGenerateMockImport(sourceFile) {
|
|
6914
|
+
return sourceFile.getImportDeclarations().some((importDeclaration) => importDeclaration.getNamedImports().some((namedImport) => namedImport.getName() === GENERATE_MOCK_NAME));
|
|
6664
6915
|
}
|
|
6665
6916
|
//#endregion
|
|
6666
6917
|
//#region src/utils/get-editor-metadata.ts
|
|
@@ -6713,20 +6964,52 @@ function getSubgraphMetadata(project, dirName) {
|
|
|
6713
6964
|
//#region src/utils/source-files.ts
|
|
6714
6965
|
/** Gets a SourceFile by name in a ts-morph Project, or creates a new one
|
|
6715
6966
|
* if none with that path exists.
|
|
6967
|
+
*
|
|
6968
|
+
* "Exists" has to mean *on disk*, not merely "already loaded in this Project".
|
|
6969
|
+
* Projects here are built with `skipAddingFilesFromTsConfig` (see
|
|
6970
|
+
* `buildTsMorphProject`), so they start empty and `getSourceFile` alone reports
|
|
6971
|
+
* every existing file as missing. Combined with `overwrite: true` that silently
|
|
6972
|
+
* discarded whatever the user had written — `alreadyExists` was always `false`,
|
|
6973
|
+
* so builders that scaffold-once-then-amend (tests, reducers, subgraphs,
|
|
6974
|
+
* editors, processors) re-scaffolded from scratch on every run and hand-written
|
|
6975
|
+
* code was lost on `project.save()`.
|
|
6976
|
+
*
|
|
6977
|
+
* Reading the file in when it is on disk but not yet loaded mirrors what
|
|
6978
|
+
* `DirectoryManager.createSourceFile` already does. Files that codegen fully
|
|
6979
|
+
* owns are unaffected: they call `replaceWithText` immediately afterwards.
|
|
6980
|
+
*
|
|
6981
|
+
* The rule has to hold on the cache-hit path too, which is the other half of
|
|
6982
|
+
* the same data loss. `ph vetra` builds one Project per process and reuses it
|
|
6983
|
+
* for every codegen run, and nothing ever refreshes it, so a SourceFile loaded
|
|
6984
|
+
* by an earlier run keeps the text it had then: codegen scaffolds a reducer
|
|
6985
|
+
* with TODO stubs, the user writes the real body on disk, and the next run in
|
|
6986
|
+
* that session still sees the stubs and writes them back on `project.save()`.
|
|
6987
|
+
* A fresh process (`ph generate`) never hit this — the cache miss forced a read
|
|
6988
|
+
* from disk. Refreshing a cached SourceFile before handing it out makes the
|
|
6989
|
+
* long-lived Project behave like a fresh one. Only cached files are refreshed;
|
|
6990
|
+
* `addSourceFileAtPathIfExists` has just read disk, so refreshing that again
|
|
6991
|
+
* would be I/O for a guaranteed `NoChange`.
|
|
6716
6992
|
*/
|
|
6717
6993
|
function getOrCreateSourceFile(project, filePath) {
|
|
6718
6994
|
const dirName = path.dirname(filePath);
|
|
6719
6995
|
if (!project.getDirectory(dirName)) project.createDirectory(dirName);
|
|
6720
|
-
const
|
|
6996
|
+
const cachedSourceFile = project.getSourceFile(filePath);
|
|
6997
|
+
const sourceFile = cachedSourceFile ? refreshCachedSourceFile(cachedSourceFile) : project.addSourceFileAtPathIfExists(filePath);
|
|
6721
6998
|
if (!sourceFile) return {
|
|
6722
6999
|
alreadyExists: false,
|
|
6723
|
-
sourceFile: project.createSourceFile(filePath, "", { overwrite:
|
|
7000
|
+
sourceFile: project.createSourceFile(filePath, "", { overwrite: false })
|
|
6724
7001
|
};
|
|
6725
7002
|
return {
|
|
6726
7003
|
alreadyExists: true,
|
|
6727
7004
|
sourceFile
|
|
6728
7005
|
};
|
|
6729
7006
|
}
|
|
7007
|
+
/** Re-reads a cached SourceFile from disk, `undefined` once it is gone from
|
|
7008
|
+
* disk (ts-morph forgets it then, so the caller re-creates it). */
|
|
7009
|
+
function refreshCachedSourceFile(sourceFile) {
|
|
7010
|
+
if (!sourceFile.isSaved()) return sourceFile;
|
|
7011
|
+
return sourceFile.refreshFromFileSystemSync() === FileSystemRefreshResult.Deleted ? void 0 : sourceFile;
|
|
7012
|
+
}
|
|
6730
7013
|
/** Gets a Directory by name in a ts-morph Project, or creates a new one
|
|
6731
7014
|
* if none with that path exists.
|
|
6732
7015
|
*/
|
|
@@ -7249,7 +7532,7 @@ async function writeAiConfigFiles(projectDir = process.cwd()) {
|
|
|
7249
7532
|
await writeFileEnsuringDir(join(projectDir, ".cursor/mcp.json"), cursorMcpTemplate.trimStart());
|
|
7250
7533
|
await writeFileEnsuringDir(join(projectDir, ".claude/settings.local.json"), claudeSettingsLocalTemplate.trimStart());
|
|
7251
7534
|
}
|
|
7252
|
-
async function writeProjectRootFiles(args,
|
|
7535
|
+
async function writeProjectRootFiles(args, _projectDir = process.cwd()) {
|
|
7253
7536
|
const { name, tag, version, remoteDrive, packageManager } = args;
|
|
7254
7537
|
await writeFileEnsuringDir("LICENSE", licenseTemplate);
|
|
7255
7538
|
await writeFileEnsuringDir("README.md", readmeTemplate);
|
|
@@ -7261,15 +7544,12 @@ async function writeProjectRootFiles(args, projectDir = process.cwd()) {
|
|
|
7261
7544
|
version
|
|
7262
7545
|
});
|
|
7263
7546
|
await writeFileEnsuringDir("powerhouse.config.json", await buildPowerhouseConfigTemplate({
|
|
7547
|
+
name,
|
|
7264
7548
|
tag,
|
|
7265
7549
|
version,
|
|
7266
7550
|
remoteDrive
|
|
7267
7551
|
}));
|
|
7268
7552
|
await writeFileEnsuringDir("package.json", packageJson);
|
|
7269
|
-
await applyProjectCustomizations({
|
|
7270
|
-
name,
|
|
7271
|
-
projectDir
|
|
7272
|
-
});
|
|
7273
7553
|
}
|
|
7274
7554
|
/**
|
|
7275
7555
|
* Per-project customizations applied to a project directory — the parts
|
|
@@ -7286,14 +7566,32 @@ async function applyProjectCustomizations(args) {
|
|
|
7286
7566
|
pkg.name = name;
|
|
7287
7567
|
await writeJsonFile(pkgPath, pkg, { indent: 2 });
|
|
7288
7568
|
await createOrUpdateManifest({ name }, projectDir);
|
|
7569
|
+
const ports = deriveProjectPorts(name);
|
|
7570
|
+
const configPath = join(projectDir, "powerhouse.config.json");
|
|
7571
|
+
const config = await loadJsonFile(configPath);
|
|
7572
|
+
config.studio = {
|
|
7573
|
+
...config.studio,
|
|
7574
|
+
port: ports.studioPort
|
|
7575
|
+
};
|
|
7576
|
+
config.reactor = {
|
|
7577
|
+
...config.reactor,
|
|
7578
|
+
port: ports.switchboardPort
|
|
7579
|
+
};
|
|
7580
|
+
const vetra = {
|
|
7581
|
+
...config.vetra,
|
|
7582
|
+
connectPort: ports.vetraConnectPort
|
|
7583
|
+
};
|
|
7289
7584
|
if (remoteDrive) {
|
|
7290
|
-
|
|
7291
|
-
|
|
7292
|
-
|
|
7293
|
-
|
|
7294
|
-
|
|
7295
|
-
|
|
7296
|
-
|
|
7585
|
+
vetra.driveId = remoteDrive.split("/").pop() ?? "";
|
|
7586
|
+
vetra.driveUrl = remoteDrive;
|
|
7587
|
+
}
|
|
7588
|
+
config.vetra = vetra;
|
|
7589
|
+
await writeJsonFile(configPath, config, { indent: 2 });
|
|
7590
|
+
const mcpFiles = [[".mcp.json", buildMcpTemplate(ports.switchboardPort)], [join(".cursor", "mcp.json"), buildCursorMcpTemplate(ports.switchboardPort)]];
|
|
7591
|
+
for (const [rel, contents] of mcpFiles) {
|
|
7592
|
+
const target = join(projectDir, rel);
|
|
7593
|
+
if (!existsSync(target)) continue;
|
|
7594
|
+
await writeFileEnsuringDir(target, contents.trimStart());
|
|
7297
7595
|
}
|
|
7298
7596
|
}
|
|
7299
7597
|
async function writeCIFiles(projectDir = process.cwd()) {
|
|
@@ -7453,7 +7751,9 @@ const DATE_LIKE_SCALARS = new Set(["Date", "DateTime"]);
|
|
|
7453
7751
|
const SCALAR_MOCK_OVERRIDES = {
|
|
7454
7752
|
Date: `"2024-01-01T00:00:00.000Z"`,
|
|
7455
7753
|
DateTime: `"2024-01-01T00:00:00.000Z"`,
|
|
7456
|
-
URL: `"https://example.com"
|
|
7754
|
+
URL: `"https://example.com"`,
|
|
7755
|
+
AttachmentRef: `"attachment://v1:${"a".repeat(64)}"`,
|
|
7756
|
+
Address: `"eip155:0x${"0".repeat(40)}"`
|
|
7457
7757
|
};
|
|
7458
7758
|
function unwrapNamedTypeName(type) {
|
|
7459
7759
|
if (type.kind === Kind.NAMED_TYPE) return type.name.value;
|
|
@@ -7803,8 +8103,8 @@ async function makeReducerOperationHandlerForModule({ project, module, version,
|
|
|
7803
8103
|
const operationsInterfaceTypeName = `${pascalCaseDocumentType}${pascalCaseModuleName}Operations`;
|
|
7804
8104
|
const operationsInterfaceVariableName = `${camelCaseDocumentType}${pascalCaseModuleName}Operations`;
|
|
7805
8105
|
const existingOperationsInterfaceTypeImport = sourceFile.getImportDeclaration((importDeclaration) => !!importDeclaration.getNamedImports().find((importSpecifier) => importSpecifier.getName() === operationsInterfaceTypeName));
|
|
7806
|
-
if (existingOperationsInterfaceTypeImport) existingOperationsInterfaceTypeImport.
|
|
7807
|
-
sourceFile.addImportDeclaration({
|
|
8106
|
+
if (existingOperationsInterfaceTypeImport) existingOperationsInterfaceTypeImport.setModuleSpecifier(versionImportPath);
|
|
8107
|
+
else sourceFile.addImportDeclaration({
|
|
7808
8108
|
namedImports: [operationsInterfaceTypeName],
|
|
7809
8109
|
moduleSpecifier: versionImportPath,
|
|
7810
8110
|
isTypeOnly: true
|
|
@@ -7915,7 +8215,7 @@ async function makeOperationModuleTestFile(args) {
|
|
|
7915
8215
|
version
|
|
7916
8216
|
});
|
|
7917
8217
|
} else sourceFile.replaceWithText(ts$1`
|
|
7918
|
-
import { generateMock } from "document-model";
|
|
8218
|
+
import { generateMock } from "document-model/mock";
|
|
7919
8219
|
import { describe, expect, it } from "vitest";
|
|
7920
8220
|
|
|
7921
8221
|
describe("${moduleOperationsTypeName}", () => {
|
|
@@ -7967,13 +8267,13 @@ async function makeOperationModuleTestFile(args) {
|
|
|
7967
8267
|
})));
|
|
7968
8268
|
}));
|
|
7969
8269
|
describeCallBody.addStatements(testCasesToAdd);
|
|
7970
|
-
|
|
7971
|
-
|
|
7972
|
-
|
|
7973
|
-
|
|
7974
|
-
|
|
7975
|
-
|
|
7976
|
-
}
|
|
8270
|
+
if (sourceFile.getText().includes("generateMock")) {
|
|
8271
|
+
fixGenerateMockImports(sourceFile);
|
|
8272
|
+
if (!hasGenerateMockImport(sourceFile)) sourceFile.addImportDeclaration({
|
|
8273
|
+
namedImports: [GENERATE_MOCK_NAME],
|
|
8274
|
+
moduleSpecifier: GENERATE_MOCK_MODULE_SPECIFIER
|
|
8275
|
+
});
|
|
8276
|
+
}
|
|
7977
8277
|
sourceFile.fixUnusedIdentifiers();
|
|
7978
8278
|
await formatSourceFileWithPrettier(sourceFile);
|
|
7979
8279
|
}
|
|
@@ -7992,13 +8292,253 @@ async function makeDocumentModelTestFile(args) {
|
|
|
7992
8292
|
await formatSourceFileWithPrettier(sourceFile);
|
|
7993
8293
|
}
|
|
7994
8294
|
//#endregion
|
|
8295
|
+
//#region src/file-builders/document-model/upgrade-migration.ts
|
|
8296
|
+
/**
|
|
8297
|
+
* Derives the migration between two consecutive spec versions. Mechanical
|
|
8298
|
+
* changes — field additions on the scope's state type (initialized from the
|
|
8299
|
+
* new version's initial value, falling back to the schema's zero value) and
|
|
8300
|
+
* field removals — produce a "fill" plan. Anything else (changed field
|
|
8301
|
+
* types, edits to nested types that pre-existing documents reference,
|
|
8302
|
+
* additions codegen cannot synthesize a value for) produces a "manual" plan.
|
|
8303
|
+
*/
|
|
8304
|
+
function buildMigrationPlan(args) {
|
|
8305
|
+
const { previousSpec, specification, stateName, localStateName } = args;
|
|
8306
|
+
if (!previousSpec) return {
|
|
8307
|
+
kind: "manual",
|
|
8308
|
+
reason: "the previous specification version is not available"
|
|
8309
|
+
};
|
|
8310
|
+
const fills = {};
|
|
8311
|
+
const scopes = [{
|
|
8312
|
+
scope: "global",
|
|
8313
|
+
typeName: stateName
|
|
8314
|
+
}, {
|
|
8315
|
+
scope: "local",
|
|
8316
|
+
typeName: localStateName
|
|
8317
|
+
}];
|
|
8318
|
+
for (const { scope, typeName } of scopes) {
|
|
8319
|
+
const oldState = previousSpec.state[scope];
|
|
8320
|
+
const newState = specification.state[scope];
|
|
8321
|
+
const analysis = analyzeScope({
|
|
8322
|
+
oldSchema: oldState?.schema ?? "",
|
|
8323
|
+
newSchema: newState?.schema ?? "",
|
|
8324
|
+
newInitialValue: newState?.initialValue ?? "",
|
|
8325
|
+
typeName,
|
|
8326
|
+
scope
|
|
8327
|
+
});
|
|
8328
|
+
if (analysis.kind === "manual") return analysis;
|
|
8329
|
+
if (analysis.fill && Object.keys(analysis.fill).length > 0) fills[scope] = analysis.fill;
|
|
8330
|
+
}
|
|
8331
|
+
return {
|
|
8332
|
+
kind: "fill",
|
|
8333
|
+
fills
|
|
8334
|
+
};
|
|
8335
|
+
}
|
|
8336
|
+
function analyzeScope(args) {
|
|
8337
|
+
const { oldSchema, newSchema, newInitialValue, typeName, scope } = args;
|
|
8338
|
+
const oldDoc = safeParseSdl(oldSchema);
|
|
8339
|
+
const newDoc = safeParseSdl(newSchema);
|
|
8340
|
+
if (oldSchema.trim() && !oldDoc) return {
|
|
8341
|
+
kind: "manual",
|
|
8342
|
+
reason: `the previous ${scope} state schema could not be parsed`
|
|
8343
|
+
};
|
|
8344
|
+
if (newSchema.trim() && !newDoc) return {
|
|
8345
|
+
kind: "manual",
|
|
8346
|
+
reason: `the new ${scope} state schema could not be parsed`
|
|
8347
|
+
};
|
|
8348
|
+
const oldType = oldDoc ? findObjectType(oldDoc, typeName) : void 0;
|
|
8349
|
+
const newType = newDoc ? findObjectType(newDoc, typeName) : void 0;
|
|
8350
|
+
if (!newType || !newDoc) return {
|
|
8351
|
+
kind: "fill",
|
|
8352
|
+
fill: void 0
|
|
8353
|
+
};
|
|
8354
|
+
if (oldType && oldDoc) {
|
|
8355
|
+
const oldReachable = collectReachableTypes(oldDoc, typeName);
|
|
8356
|
+
for (const [name, oldDefinition] of oldReachable) {
|
|
8357
|
+
if (name === typeName) continue;
|
|
8358
|
+
const newDefinition = findTypeDefinition(newDoc, name);
|
|
8359
|
+
if (!newDefinition) continue;
|
|
8360
|
+
if (print(oldDefinition) !== print(newDefinition)) return {
|
|
8361
|
+
kind: "manual",
|
|
8362
|
+
reason: `the ${scope} state type "${name}" changed between versions`
|
|
8363
|
+
};
|
|
8364
|
+
}
|
|
8365
|
+
}
|
|
8366
|
+
const oldFields = new Map((oldType?.fields ?? []).map((field) => [field.name.value, field]));
|
|
8367
|
+
const newFields = newType.fields ?? [];
|
|
8368
|
+
const initialValueObject = safeParseJsonRecord(newInitialValue);
|
|
8369
|
+
const fill = {};
|
|
8370
|
+
for (const field of newFields) {
|
|
8371
|
+
const fieldName = field.name.value;
|
|
8372
|
+
const oldField = oldFields.get(fieldName);
|
|
8373
|
+
if (oldField) {
|
|
8374
|
+
if (print(oldField.type) !== print(field.type)) return {
|
|
8375
|
+
kind: "manual",
|
|
8376
|
+
reason: `the ${scope} state field "${fieldName}" changed type between versions`
|
|
8377
|
+
};
|
|
8378
|
+
continue;
|
|
8379
|
+
}
|
|
8380
|
+
if (initialValueObject && fieldName in initialValueObject) {
|
|
8381
|
+
fill[fieldName] = initialValueObject[fieldName];
|
|
8382
|
+
continue;
|
|
8383
|
+
}
|
|
8384
|
+
const zero = zeroValueForType(field.type, newDoc, /* @__PURE__ */ new Set());
|
|
8385
|
+
if (!zero.ok) return {
|
|
8386
|
+
kind: "manual",
|
|
8387
|
+
reason: `no initial value could be derived for the added ${scope} state field "${fieldName}"`
|
|
8388
|
+
};
|
|
8389
|
+
fill[fieldName] = zero.value;
|
|
8390
|
+
}
|
|
8391
|
+
return {
|
|
8392
|
+
kind: "fill",
|
|
8393
|
+
fill
|
|
8394
|
+
};
|
|
8395
|
+
}
|
|
8396
|
+
function zeroValueForType(typeNode, schemaDoc, visitedTypes) {
|
|
8397
|
+
if (typeNode.kind !== Kind.NON_NULL_TYPE) return {
|
|
8398
|
+
ok: true,
|
|
8399
|
+
value: null
|
|
8400
|
+
};
|
|
8401
|
+
const inner = typeNode.type;
|
|
8402
|
+
if (inner.kind === Kind.LIST_TYPE) return {
|
|
8403
|
+
ok: true,
|
|
8404
|
+
value: []
|
|
8405
|
+
};
|
|
8406
|
+
const name = inner.name.value;
|
|
8407
|
+
switch (name) {
|
|
8408
|
+
case "String":
|
|
8409
|
+
case "ID": return {
|
|
8410
|
+
ok: true,
|
|
8411
|
+
value: ""
|
|
8412
|
+
};
|
|
8413
|
+
case "Int":
|
|
8414
|
+
case "Float": return {
|
|
8415
|
+
ok: true,
|
|
8416
|
+
value: 0
|
|
8417
|
+
};
|
|
8418
|
+
case "Boolean": return {
|
|
8419
|
+
ok: true,
|
|
8420
|
+
value: false
|
|
8421
|
+
};
|
|
8422
|
+
}
|
|
8423
|
+
const definition = findTypeDefinition(schemaDoc, name);
|
|
8424
|
+
if (!definition) {
|
|
8425
|
+
const defaultValue = getPHCustomScalarByTypeName(name)?.getDefaultValue?.();
|
|
8426
|
+
if (defaultValue !== void 0) return {
|
|
8427
|
+
ok: true,
|
|
8428
|
+
value: defaultValue
|
|
8429
|
+
};
|
|
8430
|
+
return { ok: false };
|
|
8431
|
+
}
|
|
8432
|
+
if (definition.kind === Kind.ENUM_TYPE_DEFINITION) return zeroValueForEnum(definition);
|
|
8433
|
+
if (definition.kind === Kind.OBJECT_TYPE_DEFINITION) {
|
|
8434
|
+
if (visitedTypes.has(name)) return { ok: false };
|
|
8435
|
+
visitedTypes.add(name);
|
|
8436
|
+
const value = {};
|
|
8437
|
+
for (const field of definition.fields ?? []) {
|
|
8438
|
+
const fieldZero = zeroValueForType(field.type, schemaDoc, visitedTypes);
|
|
8439
|
+
if (!fieldZero.ok) return { ok: false };
|
|
8440
|
+
value[field.name.value] = fieldZero.value;
|
|
8441
|
+
}
|
|
8442
|
+
visitedTypes.delete(name);
|
|
8443
|
+
return {
|
|
8444
|
+
ok: true,
|
|
8445
|
+
value
|
|
8446
|
+
};
|
|
8447
|
+
}
|
|
8448
|
+
if (definition.kind === Kind.SCALAR_TYPE_DEFINITION) {
|
|
8449
|
+
const defaultValue = getPHCustomScalarByTypeName(name)?.getDefaultValue?.();
|
|
8450
|
+
if (defaultValue !== void 0) return {
|
|
8451
|
+
ok: true,
|
|
8452
|
+
value: defaultValue
|
|
8453
|
+
};
|
|
8454
|
+
return { ok: false };
|
|
8455
|
+
}
|
|
8456
|
+
return { ok: false };
|
|
8457
|
+
}
|
|
8458
|
+
function zeroValueForEnum(definition) {
|
|
8459
|
+
const first = definition.values?.[0]?.name.value;
|
|
8460
|
+
if (first === void 0) return { ok: false };
|
|
8461
|
+
return {
|
|
8462
|
+
ok: true,
|
|
8463
|
+
value: first
|
|
8464
|
+
};
|
|
8465
|
+
}
|
|
8466
|
+
function collectReachableTypes(schemaDoc, rootTypeName) {
|
|
8467
|
+
const reachable = /* @__PURE__ */ new Map();
|
|
8468
|
+
const queue = [rootTypeName];
|
|
8469
|
+
while (queue.length > 0) {
|
|
8470
|
+
const name = queue.shift();
|
|
8471
|
+
if (reachable.has(name)) continue;
|
|
8472
|
+
const definition = findTypeDefinition(schemaDoc, name);
|
|
8473
|
+
if (!definition) continue;
|
|
8474
|
+
reachable.set(name, definition);
|
|
8475
|
+
if (definition.kind === Kind.OBJECT_TYPE_DEFINITION) for (const field of definition.fields ?? []) queue.push(namedTypeOf(field.type));
|
|
8476
|
+
else if (definition.kind === Kind.UNION_TYPE_DEFINITION) for (const member of definition.types ?? []) queue.push(member.name.value);
|
|
8477
|
+
}
|
|
8478
|
+
return reachable;
|
|
8479
|
+
}
|
|
8480
|
+
function namedTypeOf(typeNode) {
|
|
8481
|
+
let node = typeNode;
|
|
8482
|
+
while (node.kind !== Kind.NAMED_TYPE) node = node.type;
|
|
8483
|
+
return node.name.value;
|
|
8484
|
+
}
|
|
8485
|
+
function findObjectType(schemaDoc, name) {
|
|
8486
|
+
const definition = findTypeDefinition(schemaDoc, name);
|
|
8487
|
+
return definition?.kind === Kind.OBJECT_TYPE_DEFINITION ? definition : void 0;
|
|
8488
|
+
}
|
|
8489
|
+
function findTypeDefinition(schemaDoc, name) {
|
|
8490
|
+
for (const definition of schemaDoc.definitions) switch (definition.kind) {
|
|
8491
|
+
case Kind.OBJECT_TYPE_DEFINITION:
|
|
8492
|
+
case Kind.ENUM_TYPE_DEFINITION:
|
|
8493
|
+
case Kind.SCALAR_TYPE_DEFINITION:
|
|
8494
|
+
case Kind.UNION_TYPE_DEFINITION:
|
|
8495
|
+
case Kind.INTERFACE_TYPE_DEFINITION:
|
|
8496
|
+
case Kind.INPUT_OBJECT_TYPE_DEFINITION: if (definition.name.value === name) return definition;
|
|
8497
|
+
}
|
|
8498
|
+
}
|
|
8499
|
+
function safeParseSdl(sdl) {
|
|
8500
|
+
if (!sdl.trim()) return null;
|
|
8501
|
+
try {
|
|
8502
|
+
return parse(sdl);
|
|
8503
|
+
} catch {
|
|
8504
|
+
return null;
|
|
8505
|
+
}
|
|
8506
|
+
}
|
|
8507
|
+
function safeParseJsonRecord(json) {
|
|
8508
|
+
if (!json.trim()) return null;
|
|
8509
|
+
try {
|
|
8510
|
+
const parsed = JSON.parse(json);
|
|
8511
|
+
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) return parsed;
|
|
8512
|
+
return null;
|
|
8513
|
+
} catch {
|
|
8514
|
+
return null;
|
|
8515
|
+
}
|
|
8516
|
+
}
|
|
8517
|
+
/**
|
|
8518
|
+
* Serializes a fill value to TypeScript source. Fill values come from JSON
|
|
8519
|
+
* (initial values) or the zero-value synthesizer, so JSON serialization is
|
|
8520
|
+
* sufficient.
|
|
8521
|
+
*/
|
|
8522
|
+
function fillToTsLiteral(fill) {
|
|
8523
|
+
return JSON.stringify(fill, null, 2);
|
|
8524
|
+
}
|
|
8525
|
+
//#endregion
|
|
7995
8526
|
//#region src/file-builders/document-model/upgrades-dir.ts
|
|
7996
8527
|
async function makeUpgradeFile(args) {
|
|
7997
8528
|
const { project, version, upgradesDirPath } = args;
|
|
7998
8529
|
if (version < 2) return;
|
|
7999
8530
|
const { alreadyExists, sourceFile } = getOrCreateSourceFile(project, path.join(upgradesDirPath, `v${version}.ts`));
|
|
8000
8531
|
if (alreadyExists) return;
|
|
8001
|
-
const
|
|
8532
|
+
const plan = buildMigrationPlan({
|
|
8533
|
+
previousSpec: args.documentModelState.specifications.find((specification) => specification.version === version - 1),
|
|
8534
|
+
specification: args.specification,
|
|
8535
|
+
stateName: args.stateName,
|
|
8536
|
+
localStateName: args.localStateName
|
|
8537
|
+
});
|
|
8538
|
+
const template = upgradeTransitionTemplate({
|
|
8539
|
+
...args,
|
|
8540
|
+
plan
|
|
8541
|
+
});
|
|
8002
8542
|
sourceFile.replaceWithText(template);
|
|
8003
8543
|
await formatSourceFileWithPrettier(sourceFile);
|
|
8004
8544
|
}
|
|
@@ -8280,6 +8820,10 @@ async function makeDocumentModelsIndexFile(args) {
|
|
|
8280
8820
|
moduleSpecifier
|
|
8281
8821
|
});
|
|
8282
8822
|
}));
|
|
8823
|
+
sourceFile.addExportDeclaration({
|
|
8824
|
+
namedExports: ["upgradeManifests"],
|
|
8825
|
+
moduleSpecifier: "./upgrade-manifests.js"
|
|
8826
|
+
});
|
|
8283
8827
|
await formatSourceFileWithPrettier(sourceFile);
|
|
8284
8828
|
}
|
|
8285
8829
|
/** Writes a json file derived from a `documentModelState` */
|
|
@@ -8592,6 +9136,29 @@ function getFactoryBuildersArray(sourceFile, name) {
|
|
|
8592
9136
|
return sourceFile.getDescendantsOfKind(ts.SyntaxKind.VariableStatement).flatMap((d) => d.getDescendantsOfKind(ts.SyntaxKind.VariableDeclaration)).find((d) => d.getName() === name)?.getDescendantsOfKind(ts.SyntaxKind.ArrayLiteralExpression).at(0);
|
|
8593
9137
|
}
|
|
8594
9138
|
//#endregion
|
|
9139
|
+
//#region src/file-builders/project-index.ts
|
|
9140
|
+
const AI_TOOLS_MODULE_SPECIFIER = "./ai/tools.js";
|
|
9141
|
+
/**
|
|
9142
|
+
* Idempotently syncs the optional `aiTools` export in the project's root
|
|
9143
|
+
* `index.ts`: the line is present if and only if `ai/tools.ts` exists.
|
|
9144
|
+
* The export is how the host app (Connect) discovers the tool descriptors
|
|
9145
|
+
* this package offers to the in-browser AI assistant.
|
|
9146
|
+
*/
|
|
9147
|
+
function syncProjectAiToolsExport(project) {
|
|
9148
|
+
const { directory: documentModelsDir } = getOrCreateDirectory(project, "document-models");
|
|
9149
|
+
const projectDir = documentModelsDir.getParentOrThrow().getPath();
|
|
9150
|
+
const indexPath = join$1(projectDir, "index.ts");
|
|
9151
|
+
if (!existsSync(indexPath)) return;
|
|
9152
|
+
const { sourceFile } = getOrCreateSourceFile(project, indexPath);
|
|
9153
|
+
const hasAiToolsFile = existsSync(join$1(projectDir, "ai", "tools.ts"));
|
|
9154
|
+
const existing = sourceFile.getExportDeclarations().find((declaration) => declaration.getModuleSpecifier()?.getText().trim() === `"${AI_TOOLS_MODULE_SPECIFIER}"` && declaration.getNamedExports().some((exported) => exported.getText() === "aiTools"));
|
|
9155
|
+
if (hasAiToolsFile && !existing) sourceFile.addExportDeclarations([{
|
|
9156
|
+
namedExports: ["aiTools"],
|
|
9157
|
+
moduleSpecifier: AI_TOOLS_MODULE_SPECIFIER
|
|
9158
|
+
}]);
|
|
9159
|
+
else if (!hasAiToolsFile && existing) existing.remove();
|
|
9160
|
+
}
|
|
9161
|
+
//#endregion
|
|
8595
9162
|
//#region src/file-builders/subgraphs.ts
|
|
8596
9163
|
async function tsMorphGenerateSubgraph(args) {
|
|
8597
9164
|
const { subgraphName, project } = args;
|
|
@@ -8658,6 +9225,6 @@ async function makeSubgraphsIndexFile(args) {
|
|
|
8658
9225
|
await formatSourceFileWithPrettier(sourceFile);
|
|
8659
9226
|
}
|
|
8660
9227
|
//#endregion
|
|
8661
|
-
export {
|
|
9228
|
+
export { getProperyAssignmentByName as $, indexHtmlTemplate as $n, documentModelModuleFileTemplate as $t, writeCIFiles as A, documentEditorEditorFileTemplate as An, relationalDbSchemaTemplate as At, makeEditorsFile as B, packageJsonExportsTemplate as Bn, analyticsFactoryTemplate as Bt, getCommandsHelpInfo as C, documentModelDocumentTypeTemplate as Cn, appFilesFileTemplate as Cr, configSpec as Ct, applyProjectCustomizations as D, documentModelGenActionsFileTemplate as Dn, createDocumentFileTemplate as Dr, customSubgraphSchemaTemplate as Dt, buildBoilerplatePackageJson as E, documentModelGenControllerFileTemplate as En, appDriveContentsFileTemplate as Er, customSubgraphResolversTemplate as Et, writeGeneratedSubgraphsFiles as F, subgraphsIndexTemplate as Fn, processorsIndexTemplate as Ft, DEFAULT_PROJECT_OPTIONS as G, npmrcTemplate as Gn, upgradeManifestTemplate as Gt, validateDocumentModelState as H, pnpmWorkspaceTemplate as Hn, renderProcessorFilter as Ht, writeModuleFiles as I, styleTemplate as In, processorsFactoryTemplate as It, getAllImportModuleSpecifiers as J, mainTsxTemplate as Jn, makeOperationsImports as Jt, buildTsMorphProject as K, buildMcpTemplate as Kn, documentModelOperationsModuleTestFileTemplate as Kt, writeProjectRootFiles as L, readmeTemplate as Ln, factoryBuildersTemplate as Lt, writeGeneratedEditorsFiles as M, vitestConfigTemplate as Mn, relationalDbMigrationsTemplate as Mt, writeGeneratedProcessorsFiles as N, tsConfigTemplate as Nn, relationalDbIndexTemplate as Nt, writeAiConfigFiles as O, documentModelRootActionsFileTemplate as On, subgraphLibFileTemplate as Ot, writeGeneratedProjectRootFiles as P, tsconfigPathsTemplate as Pn, relationalDbFactoryTemplate as Pt, getObjectProperty as Q, legacyIndexHtmlTemplate as Qn, documentModelSrcIndexFileTemplate as Qt, tsMorphGenerateApp as R, ManifestTemplate as Rn, analyticsProcessorTemplate as Rt, getCommandHelpInfo as S, documentModelGenIndexFileTemplate as Sn, appFoldersFileTemplate as Sr, documentModelDocumentTypeMetadata as St, writeCliDocsMarkdownFile as T, documentModelGenCreatorsFileTemplate as Tn, driveExplorerFileTemplate as Tr, parseConfig as Tt, updateVersionedImports as U, exportsTemplate as Un, documentModelUtilsTemplate as Ut, makeEditorsIndexFile as V, packageJsonScriptsTemplate as Vn, parseFilterValues as Vt, getInitialStates as W, packageJsonTemplate as Wn, upgradeTransitionTemplate as Wt, getBooleanPropertyValue as X, reactorTsTemplate as Xn, documentModelTestFileTemplate as Xt, getAllImportNames as Y, licenseTemplate as Yn, makeTestCaseForOperation as Yt, getObjectLiteral as Z, indexTsTemplate as Zn, documentModelSrcUtilsTemplate as Zt, getInputFieldNames as _, getLatestDocumentModelSpecVersionNumber as _n, agentsTemplate as _r, hasGenerateMockImport as _t, createOrUpdateManifest as a, documentModelGenReducerFileTemplate as an, editorsIndexTemplate as ar, buildStringLiteral as at, scalarsValidation as b, getActionType as bn, driveExplorerNavigationBreadcrumbsFileTemplate as br, runOxfmt as bt, makeModulesIndexFile as c, documentModelOperationsModuleErrorFileTemplate as cn, documentModelsIndexTemplate as cr, getOrCreateSourceFile as ct, tsMorphGenerateDocumentModel as d, getModuleExportType as dn, nginxConfTemplate as dr, getProcessorMetadata as dt, documentModelIndexTemplate as en, gitIgnoreTemplate as er, getStringArrayPropertyElements as et, buildMigrationPlan as f, getDocumentModelDirName as fn, dockerfileTemplate as fr, getAppMetadata as ft, getDateLikeFieldNames as g, getLatestDocumentModelSpec as gn, claudeSettingsLocalTemplate as gr, fixGenerateMockImports as gt, generateTypesAndZodSchemasFromGraphql as h, getEditorVariableNames as hn, cursorMcpTemplate as hr, GENERATE_MOCK_NAME as ht, tsMorphGenerateProcessor as i, documentModelSchemaIndexTemplate as in, oxlintConfigTemplate as ir, buildObjectLiteral as it, writeGeneratedDocumentModelsFiles as j, docsFromCliHelpTemplate as jn, relationalDbProcessorTemplate as jt, writeAllGeneratedProjectFiles as k, documentEditorModuleFileTemplate as kn, subgraphIndexFileTemplate as kt, operationHasEmptyInput as l, documentModelOperationsModuleCreatorsFileTemplate as ln, documentModelsTemplate as lr, getPreviousVersionSourceFile as lt, generateDocumentModelZodSchemas as m, getDocumentModelVariableNames as mn, buildCursorMcpTemplate as mr, GENERATE_MOCK_MODULE_SPECIFIER as mt, tsMorphGenerateSubgraph as n, documentModelGenUtilsTemplate as nn, geminiSettingsTemplate as nr, getVariableDeclarationByTypeName as nt, getOrCreateManifestFile as o, documentModelPhFactoriesFileTemplate as on, editorsTemplate as or, ensureDirectoriesExist as ot, fillToTsLiteral as p, getDocumentModelSpecByVersionNumber as pn, connectEntrypointTemplate as pr, getEditorMetadata as pt, getDefaultProjectOptions as q, mcpTemplate as qn, makeOperationImportNames as qt, syncProjectAiToolsExport as r, documentModelGenTypesTemplate as rn, oxfmtConfigTemplate as rr, loadDocumentModelInDir as rt, pruneManifestSection as s, documentModelOperationsModuleOperationsFileTemplate as sn, upgradeManifestsTemplate as sr, getOrCreateDirectory as st, makeSubgraphsIndexFile as t, documentModelHooksFileTemplate as tn, syncAndPublishWorkflowTemplate as tr, getStringPropertyValue as tt, operationHasInput as u, documentModelOperationModuleActionsFileTemplate as un, switchboardEntrypointTemplate as ur, getSubgraphMetadata as ut, getMockOverrideFieldNames as v, getActionInputName as vn, appEditorFileTemplate as vr, formatSafe as vt, makeCliDocsFromHelp as w, documentModelDocumentSchemaFileTemplate as wn, emptyStateFileTemplate as wr, parseArgs as wt, tsMorphGenerateDocumentEditor as x, getActionTypeName as xn, folderTreeFileTemplate as xr, getDocumentTypeMetadata as xt, scalars as y, getActionInputTypeNames as yn, appConfigFileTemplate as yr, formatSourceFileWithPrettier as yt, makeEditorModuleFile as z, buildPowerhouseConfigTemplate as zn, analyticsIndexTemplate as zt };
|
|
8662
9229
|
|
|
8663
|
-
//# sourceMappingURL=file-builders-
|
|
9230
|
+
//# sourceMappingURL=file-builders-BZEQ9XnO.mjs.map
|