@powerhousedao/codegen 6.0.0-dev.191 → 6.0.0-dev.192

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/dist/{templates-BbNsigQX.mjs → file-builders-BkbVW0kT.mjs} +2322 -383
  2. package/dist/file-builders-BkbVW0kT.mjs.map +1 -0
  3. package/dist/index-CEDWX5sL.d.mts +349 -0
  4. package/dist/index-CEDWX5sL.d.mts.map +1 -0
  5. package/dist/index.d.mts +42 -101
  6. package/dist/index.d.mts.map +1 -1
  7. package/dist/index.mjs +4492 -325
  8. package/dist/index.mjs.map +1 -1
  9. package/dist/src/file-builders/index.d.mts +2 -3
  10. package/dist/src/file-builders/index.mjs +2 -3
  11. package/dist/src/name-builders/index.d.mts +2 -2
  12. package/dist/src/name-builders/index.mjs +2 -146
  13. package/dist/src/templates/index.d.mts +34 -74
  14. package/dist/src/templates/index.d.mts.map +1 -1
  15. package/dist/src/templates/index.mjs +2 -2
  16. package/dist/src/utils/index.d.mts +6 -18
  17. package/dist/src/utils/index.d.mts.map +1 -1
  18. package/dist/src/utils/index.mjs +2 -380
  19. package/dist/{validation-Bpg_44mW.d.mts → validation-Z3z0BJlu.d.mts} +2 -2
  20. package/dist/{validation-Bpg_44mW.d.mts.map → validation-Z3z0BJlu.d.mts.map} +1 -1
  21. package/package.json +16 -9
  22. package/dist/file-builders-BV9wDPPZ.mjs +0 -1652
  23. package/dist/file-builders-BV9wDPPZ.mjs.map +0 -1
  24. package/dist/index-CHAnPBj2.d.mts +0 -199
  25. package/dist/index-CHAnPBj2.d.mts.map +0 -1
  26. package/dist/index-CJZGVSYg.d.mts +0 -65
  27. package/dist/index-CJZGVSYg.d.mts.map +0 -1
  28. package/dist/src/name-builders/index.mjs.map +0 -1
  29. package/dist/src/utils/index.mjs.map +0 -1
  30. package/dist/templates-BbNsigQX.mjs.map +0 -1
  31. package/dist/types-e2ztuDtG.d.mts +0 -87
  32. package/dist/types-e2ztuDtG.d.mts.map +0 -1
@@ -1,1652 +0,0 @@
1
- import { A as documentModelHooksFileTemplate, Bt as appDriveContentsFileTemplate, D as documentModelSrcIndexFileTemplate, E as documentModelSrcUtilsTemplate, F as documentModelPhFactoriesFileTemplate, Ft as folderTreeFileTemplate, G as documentModelGenControllerFileTemplate, H as documentModelDocumentTypeTemplate, Ht as ts$1, I as documentModelOperationsModuleOperationsFileTemplate, It as appFoldersFileTemplate, J as documentEditorModuleFileTemplate, K as documentModelGenActionsFileTemplate, L as documentModelOperationsModuleErrorFileTemplate, Lt as appFilesFileTemplate, M as documentModelGenTypesTemplate, Mt as appEditorFileTemplate, N as documentModelSchemaIndexTemplate, Nt as appConfigFileTemplate, O as documentModelModuleFileTemplate, P as documentModelGenReducerFileTemplate, Pt as driveExplorerNavigationBreadcrumbsFileTemplate, R as documentModelOperationsModuleCreatorsFileTemplate, Rt as emptyStateFileTemplate, S as makeActionImportNames, T as documentModelTestFileTemplate, U as documentModelDocumentSchemaFileTemplate, V as documentModelGenIndexFileTemplate, Vt as createDocumentFileTemplate, W as documentModelGenCreatorsFileTemplate, X as docsFromCliHelpTemplate, Y as documentEditorEditorFileTemplate, _ as analyticsFactoryTemplate, a as subgraphLibFileTemplate, b as upgradeManifestTemplate, c as relationalDbProcessorTemplate, d as relationalDbFactoryTemplate, g as analyticsIndexTemplate, h as analyticsProcessorTemplate, i as customSubgraphSchemaTemplate, j as documentModelGenUtilsTemplate, k as documentModelIndexTemplate, l as relationalDbMigrationsTemplate, lt as packageJsonTemplate, m as factoryBuildersTemplate, n as documentModelSubgraphSchemaTemplate, o as subgraphIndexFileTemplate, q as documentModelRootActionsFileTemplate, r as customSubgraphResolversTemplate, s as relationalDbSchemaTemplate, t as documentModelSubgraphResolversTemplate, u as relationalDbIndexTemplate, v as documentModelUtilsTemplate, w as makeTestCaseForAction, y as upgradeTransitionTemplate, z as documentModelOperationModuleActionsFileTemplate, zt as driveExplorerFileTemplate } from "./templates-BbNsigQX.mjs";
2
- import { getDocumentModelDirName, getDocumentModelOperationsModuleVariableNames, getDocumentModelVariableNames, getEditorVariableNames } from "./src/name-builders/index.mjs";
3
- import { applyGraphQLTypePrefixes, buildObjectLiteral, buildTsMorphProject, ensureDirectoriesExist, extractTypeNames, formatSourceFileWithPrettier, getDocumentTypeMetadata, getInitialStates, getObjectLiteral, getOrCreateDirectory, getOrCreateSourceFile, getPreviousVersionSourceFile, getVariableDeclarationByTypeName } from "./src/utils/index.mjs";
4
- import { VERSIONED_DEPENDENCIES, VERSIONED_DEV_DEPENDENCIES, directoryExists, fileExists, makeVersionedDependencies } from "@powerhousedao/shared/clis";
5
- import { camelCase, kebabCase, pascalCase } from "change-case";
6
- import path from "path";
7
- import { IndentationText, Project, SyntaxKind, VariableDeclarationKind, ts } from "ts-morph";
8
- import { format } from "prettier";
9
- import path$1 from "node:path";
10
- import fs, { copyFile, mkdir, readdir, rename, writeFile } from "node:fs/promises";
11
- import { stripVTControlCharacters } from "node:util";
12
- import { generate } from "@graphql-codegen/cli";
13
- import { generatorTypeDefs, validationSchema } from "@powerhousedao/document-engineering/graphql";
14
- import { existsSync } from "fs";
15
- //#region src/file-builders/editor-common.ts
16
- /** Generates the `module.ts` file for a document editor or app */
17
- function makeEditorModuleFile({ project, editorDirPath, editorName, documentModelId, editorId, legacyMultipleDocumentTypes }) {
18
- if (documentModelId && !!legacyMultipleDocumentTypes) throw new Error("Cannot specify both documentModelId and legacyMultipleDocumentTypes");
19
- const { sourceFile } = getOrCreateSourceFile(project, path.join(editorDirPath, "module.ts"));
20
- sourceFile.replaceWithText("");
21
- const template = documentEditorModuleFileTemplate({
22
- editorName,
23
- editorId,
24
- pascalCaseEditorName: pascalCase(editorName),
25
- documentTypes: documentModelId ? `["${documentModelId}"]` : JSON.stringify(legacyMultipleDocumentTypes)
26
- });
27
- sourceFile.replaceWithText(template);
28
- }
29
- //#endregion
30
- //#region src/file-builders/index-files.ts
31
- /**
32
- * Makes a legacy index.ts file for the modules file which exports the modules as individual exports instead of an array of named exports.
33
- */
34
- function makeLegacyIndexFile({ project, modulesDirPath, modules }) {
35
- const indexSourceFilePath = path$1.join(modulesDirPath, "index.ts");
36
- let indexSourceFile = project.getSourceFile(indexSourceFilePath);
37
- if (!indexSourceFile) indexSourceFile = project.createSourceFile(indexSourceFilePath, "");
38
- else indexSourceFile.replaceWithText("");
39
- indexSourceFile.addExportDeclarations(modules.map(({ versionedName, unversionedName, moduleSpecifier }) => ({
40
- namedExports: [versionedName ? `${unversionedName} as ${versionedName}` : unversionedName],
41
- moduleSpecifier
42
- })));
43
- }
44
- //#endregion
45
- //#region src/file-builders/module-files.ts
46
- /**
47
- * Makes a file which exports the modules from the module.ts files in the given directory as a variable declaration.
48
- */
49
- async function makeModulesFile({ project, modulesDirPath, outputFileName, typeName, variableName, variableType, shouldMakeLegacyIndexFile = true, moduleFileName = "module.ts" }) {
50
- await ensureDirectoriesExist(project, modulesDirPath);
51
- const modulesSourceFilesPath = path$1.join(modulesDirPath, "**/*");
52
- project.addSourceFilesAtPaths(modulesSourceFilesPath);
53
- const { directory: modulesDir } = getOrCreateDirectory(project, modulesDirPath);
54
- const modules = modulesDir.getDescendantSourceFiles().filter((file) => file.getBaseName().includes(moduleFileName)).map((file) => getVariableDeclarationByTypeName(file, typeName)).filter((v) => v !== void 0).map((module) => {
55
- const sourceFile = module.getSourceFile();
56
- const moduleSpecifier = modulesDir.getRelativePathAsModuleSpecifierTo(sourceFile.getFilePath()) + ".js";
57
- const versionDir = getVersionDirFromModuleSpecifier(moduleSpecifier);
58
- const unversionedName = module.getName();
59
- return {
60
- versionedName: versionDir ? `${unversionedName}${pascalCase(versionDir)}` : void 0,
61
- unversionedName,
62
- moduleSpecifier
63
- };
64
- });
65
- const { sourceFile: moduleExportsSourceFile } = getOrCreateSourceFile(project, path$1.join(modulesDirPath, outputFileName));
66
- moduleExportsSourceFile.replaceWithText("");
67
- const importDeclarations = [{
68
- namedImports: [typeName],
69
- moduleSpecifier: "document-model",
70
- isTypeOnly: true
71
- }, ...modules.map(({ versionedName, unversionedName, moduleSpecifier }) => ({
72
- namedImports: [versionedName ? `${unversionedName} as ${versionedName}` : unversionedName],
73
- moduleSpecifier
74
- }))];
75
- for (const declaration of importDeclarations) if (!moduleExportsSourceFile.getImportDeclaration((importDeclaration) => importDeclaration.getNamedImports().some((importSpecifier) => declaration.namedImports.includes(importSpecifier.getName())))) moduleExportsSourceFile.addImportDeclaration(declaration);
76
- const moduleExportsVariableStatementInput = {
77
- isExported: true,
78
- declarationKind: VariableDeclarationKind.Const,
79
- declarations: [{
80
- name: variableName,
81
- type: variableType,
82
- initializer: `[]`
83
- }]
84
- };
85
- let moduleExportsVariableStatement = moduleExportsSourceFile.getVariableStatement(variableName);
86
- if (!moduleExportsVariableStatement) moduleExportsVariableStatement = moduleExportsSourceFile.addVariableStatement(moduleExportsVariableStatementInput);
87
- else moduleExportsVariableStatement.set(moduleExportsVariableStatementInput);
88
- (moduleExportsVariableStatement.getDeclarations().at(0)?.getInitializerIfKind(SyntaxKind.ArrayLiteralExpression))?.addElements(modules.map((module) => module.versionedName ?? module.unversionedName), { useNewLines: true });
89
- if (shouldMakeLegacyIndexFile) makeLegacyIndexFile({
90
- project,
91
- modulesDirPath,
92
- modules
93
- });
94
- await project.save();
95
- }
96
- async function makeUpgradeManifestsFile(args) {
97
- const { project, projectDir } = args;
98
- await makeModulesFile({
99
- project,
100
- modulesDirPath: path$1.join(projectDir, "document-models"),
101
- outputFileName: "upgrade-manifests.ts",
102
- typeName: "UpgradeManifest",
103
- variableName: "upgradeManifests",
104
- variableType: "UpgradeManifest<readonly number[]>[]",
105
- moduleFileName: "upgrade-manifest.ts",
106
- shouldMakeLegacyIndexFile: false
107
- });
108
- }
109
- /** Generates the `document-models.ts` file which exports the document models defined in each document model dir's `module.ts` file */
110
- async function makeDocumentModelModulesFile({ project, projectDir }) {
111
- await makeModulesFile({
112
- project,
113
- modulesDirPath: path$1.join(projectDir, "document-models"),
114
- outputFileName: "document-models.ts",
115
- typeName: "DocumentModelModule",
116
- variableName: "documentModels",
117
- variableType: "DocumentModelModule<any>[]"
118
- });
119
- }
120
- /** Generates the `editors.ts` file which exports the editors defined in each editor dir's `module.ts` file */
121
- async function makeEditorsModulesFile(project, projectDir) {
122
- await makeModulesFile({
123
- project,
124
- modulesDirPath: path$1.join(projectDir, "editors"),
125
- outputFileName: "editors.ts",
126
- typeName: "EditorModule",
127
- variableName: "editors",
128
- variableType: "EditorModule[]"
129
- });
130
- }
131
- function getVersionDirFromModuleSpecifier(moduleSpecifier) {
132
- return moduleSpecifier.match(/\/(v\d+)(?=\/)/)?.[1];
133
- }
134
- /**
135
- * Adds the upgradeManifests export to an existing document-models.ts file.
136
- * Searches for upgrade-manifest.ts files in each document model's upgrades directory,
137
- * adds imports for each, and creates the upgradeManifests array export.
138
- */
139
- function makeUpgradeManifestsExport({ project, modulesDirPath, outputFilePath, variableName, variableType, typeName }) {
140
- const absoluteModulesDirPath = path$1.resolve(modulesDirPath);
141
- const absoluteOutputFilePath = path$1.resolve(outputFilePath);
142
- const upgradeManifestGlob = `${absoluteModulesDirPath}/**/upgrade-manifest.ts`;
143
- project.addSourceFilesAtPaths(upgradeManifestGlob);
144
- const upgradeManifestFiles = project.getSourceFiles().filter((file) => file.getFilePath().includes("upgrade-manifest.ts")).filter((file) => file.getFilePath().startsWith(absoluteModulesDirPath));
145
- if (upgradeManifestFiles.length === 0) return;
146
- let outputSourceFile = project.getSourceFile(absoluteOutputFilePath);
147
- if (outputSourceFile) outputSourceFile.refreshFromFileSystemSync();
148
- else {
149
- project.addSourceFilesAtPaths(absoluteOutputFilePath);
150
- outputSourceFile = project.getSourceFile(absoluteOutputFilePath);
151
- }
152
- if (!outputSourceFile) return;
153
- const modulesDir = project.getDirectory(absoluteModulesDirPath);
154
- if (!modulesDir) return;
155
- const manifests = upgradeManifestFiles.map((file) => {
156
- const filePath = file.getFilePath();
157
- const pathParts = filePath.split("/");
158
- const upgradesIndex = pathParts.indexOf("upgrades");
159
- const documentModelName = upgradesIndex > 0 ? pathParts[upgradesIndex - 1] : "unknown";
160
- const moduleSpecifier = modulesDir.getRelativePathAsModuleSpecifierTo(filePath) + ".js";
161
- return {
162
- originalName: "upgradeManifest",
163
- aliasedName: `${camelCase(documentModelName)}UpgradeManifest`,
164
- moduleSpecifier
165
- };
166
- });
167
- const existingTypeImport = outputSourceFile.getImportDeclarations().find((imp) => imp.getModuleSpecifierValue() === "document-model" && imp.isTypeOnly());
168
- if (existingTypeImport) {
169
- if (!existingTypeImport.getNamedImports().some((ni) => ni.getName() === typeName)) existingTypeImport.addNamedImport(typeName);
170
- }
171
- const existingImports = outputSourceFile.getImportDeclarations();
172
- const lastImport = existingImports[existingImports.length - 1];
173
- if (lastImport) {
174
- const insertText = "\n" + manifests.map(({ originalName, aliasedName, moduleSpecifier }) => `import { ${originalName} as ${aliasedName} } from "${moduleSpecifier}";`).join("\n");
175
- const insertPos = lastImport.getEnd();
176
- outputSourceFile.insertText(insertPos, insertText);
177
- }
178
- const variableStatementInput = {
179
- isExported: true,
180
- declarationKind: VariableDeclarationKind.Const,
181
- declarations: [{
182
- name: variableName,
183
- type: variableType,
184
- initializer: `[]`
185
- }]
186
- };
187
- (outputSourceFile.addVariableStatement(variableStatementInput).getDeclarations().at(0)?.getInitializerIfKind(SyntaxKind.ArrayLiteralExpression))?.addElements(manifests.map((m) => m.aliasedName), { useNewLines: true });
188
- }
189
- //#endregion
190
- //#region src/file-builders/app.ts
191
- /** Generates a app with the configs for `allowedDocumentModelIds` and `isDragAndDropEnabled` */
192
- async function tsMorphGenerateApp({ projectDir, editorDir, editorName, editorId, allowedDocumentModelIds, isDragAndDropEnabled }) {
193
- const documentModelsDirPath = path.join(projectDir, "document-models");
194
- const documentModelsSourceFilesPath = path.join(documentModelsDirPath, "/**/*");
195
- const editorsDirPath = path.join(projectDir, "editors");
196
- const editorSourceFilesPath = path.join(editorsDirPath, "/**/*");
197
- const editorDirPath = path.join(editorsDirPath, editorDir);
198
- const editorComponentsDirPath = path.join(editorDirPath, "components");
199
- const project = buildTsMorphProject(projectDir);
200
- await ensureDirectoriesExist(project, documentModelsDirPath, editorsDirPath, editorDirPath, editorComponentsDirPath);
201
- project.addSourceFilesAtPaths(documentModelsSourceFilesPath);
202
- project.addSourceFilesAtPaths(editorSourceFilesPath);
203
- await makeNavigationBreadcrumbsFile({
204
- project,
205
- editorComponentsDirPath
206
- });
207
- await makeCreateDocumentFile({
208
- project,
209
- editorComponentsDirPath
210
- });
211
- await makeEmptyStateFile({
212
- project,
213
- editorComponentsDirPath
214
- });
215
- await makeFoldersFile({
216
- project,
217
- editorComponentsDirPath
218
- });
219
- await makeFolderTreeFile({
220
- project,
221
- editorComponentsDirPath
222
- });
223
- await makeFilesFile({
224
- project,
225
- editorComponentsDirPath
226
- });
227
- await makeDriveExplorerFile({
228
- project,
229
- editorComponentsDirPath
230
- });
231
- await makeDriveContentsFile({
232
- project,
233
- editorComponentsDirPath
234
- });
235
- await makeAppComponent({
236
- project,
237
- editorDirPath
238
- });
239
- await makeAppConfigFile({
240
- project,
241
- allowedDocumentModelIds,
242
- isDragAndDropEnabled,
243
- editorDirPath
244
- });
245
- makeEditorModuleFile({
246
- project,
247
- editorName,
248
- editorId,
249
- editorDirPath,
250
- documentModelId: "powerhouse/document-drive"
251
- });
252
- await makeEditorsModulesFile(project, projectDir);
253
- await project.save();
254
- }
255
- async function makeAppComponent({ project, editorDirPath }) {
256
- const { alreadyExists, sourceFile } = getOrCreateSourceFile(project, path.join(editorDirPath, "editor.tsx"));
257
- if (alreadyExists) {
258
- const editorFunction = sourceFile.getFunction("Editor");
259
- if (editorFunction) {
260
- if (!editorFunction.isDefaultExport()) editorFunction.setIsDefaultExport(true);
261
- return;
262
- }
263
- }
264
- const template = appEditorFileTemplate();
265
- sourceFile.replaceWithText(template);
266
- await formatSourceFileWithPrettier(sourceFile);
267
- }
268
- async function makeAppConfigFile({ project, editorDirPath, allowedDocumentModelIds, isDragAndDropEnabled }) {
269
- const { sourceFile } = getOrCreateSourceFile(project, path.join(editorDirPath, "config.ts"));
270
- const allowedDocumentTypesString = JSON.stringify(allowedDocumentModelIds);
271
- const template = appConfigFileTemplate({
272
- isDragAndDropEnabledString: isDragAndDropEnabled ? "true" : "false",
273
- allowedDocumentTypesString
274
- });
275
- sourceFile.replaceWithText(template);
276
- await formatSourceFileWithPrettier(sourceFile);
277
- }
278
- async function makeDriveContentsFile({ project, editorComponentsDirPath }) {
279
- const { alreadyExists, sourceFile } = getOrCreateSourceFile(project, path.join(editorComponentsDirPath, "DriveContents.tsx"));
280
- if (alreadyExists) return;
281
- const template = appDriveContentsFileTemplate();
282
- sourceFile.replaceWithText(template);
283
- await formatSourceFileWithPrettier(sourceFile);
284
- }
285
- async function makeNavigationBreadcrumbsFile({ project, editorComponentsDirPath }) {
286
- const { alreadyExists, sourceFile } = getOrCreateSourceFile(project, path.join(editorComponentsDirPath, "NavigationBreadcrumbs.tsx"));
287
- if (alreadyExists) return;
288
- sourceFile.replaceWithText(driveExplorerNavigationBreadcrumbsFileTemplate());
289
- await formatSourceFileWithPrettier(sourceFile);
290
- }
291
- async function makeFoldersFile({ project, editorComponentsDirPath }) {
292
- const { alreadyExists, sourceFile } = getOrCreateSourceFile(project, path.join(editorComponentsDirPath, "Folders.tsx"));
293
- if (alreadyExists) return;
294
- const template = appFoldersFileTemplate();
295
- sourceFile.replaceWithText(template);
296
- await formatSourceFileWithPrettier(sourceFile);
297
- }
298
- async function makeFilesFile({ project, editorComponentsDirPath }) {
299
- const { alreadyExists, sourceFile } = getOrCreateSourceFile(project, path.join(editorComponentsDirPath, "Files.tsx"));
300
- if (alreadyExists) return;
301
- const template = appFilesFileTemplate();
302
- sourceFile.replaceWithText(template);
303
- await formatSourceFileWithPrettier(sourceFile);
304
- }
305
- async function makeDriveExplorerFile({ project, editorComponentsDirPath }) {
306
- const { alreadyExists, sourceFile } = getOrCreateSourceFile(project, path.join(editorComponentsDirPath, "DriveExplorer.tsx"));
307
- if (alreadyExists) return;
308
- sourceFile.replaceWithText(driveExplorerFileTemplate);
309
- await formatSourceFileWithPrettier(sourceFile);
310
- }
311
- async function makeFolderTreeFile({ project, editorComponentsDirPath }) {
312
- const { alreadyExists, sourceFile } = getOrCreateSourceFile(project, path.join(editorComponentsDirPath, "FolderTree.tsx"));
313
- if (alreadyExists) return;
314
- sourceFile.replaceWithText(folderTreeFileTemplate);
315
- await formatSourceFileWithPrettier(sourceFile);
316
- }
317
- async function makeEmptyStateFile({ project, editorComponentsDirPath }) {
318
- const { alreadyExists, sourceFile } = getOrCreateSourceFile(project, path.join(editorComponentsDirPath, "EmptyState.tsx"));
319
- if (alreadyExists) return;
320
- sourceFile.replaceWithText(emptyStateFileTemplate);
321
- await formatSourceFileWithPrettier(sourceFile);
322
- }
323
- async function makeCreateDocumentFile({ project, editorComponentsDirPath }) {
324
- const { alreadyExists, sourceFile } = getOrCreateSourceFile(project, path.join(editorComponentsDirPath, "CreateDocument.tsx"));
325
- if (alreadyExists) return;
326
- sourceFile.replaceWithText(createDocumentFileTemplate);
327
- await formatSourceFileWithPrettier(sourceFile);
328
- }
329
- //#endregion
330
- //#region src/file-builders/boilerplate/package.json.ts
331
- async function buildBoilerplatePackageJson(args) {
332
- const { name, tag, version, workspace } = args;
333
- return packageJsonTemplate(name, await makeVersionedDependencies({
334
- names: VERSIONED_DEPENDENCIES,
335
- tag,
336
- version
337
- }), await makeVersionedDependencies({
338
- names: VERSIONED_DEV_DEPENDENCIES,
339
- tag,
340
- version
341
- }));
342
- }
343
- //#endregion
344
- //#region src/file-builders/clis/generate-cli-docs.ts
345
- function getCommandHelpInfo(entry) {
346
- return {
347
- name: entry.name,
348
- description: entry.command.description ?? "",
349
- helpTopics: entry.command.helpTopics?.() ?? []
350
- };
351
- }
352
- function getCommandsHelpInfo(entries) {
353
- return entries.map(getCommandHelpInfo);
354
- }
355
- function makeCliDocsFromHelp(args) {
356
- const { cliDescription, docsIntroduction, docsTitle, entries } = args;
357
- return stripVTControlCharacters(docsFromCliHelpTemplate({
358
- cliDescription,
359
- docsIntroduction,
360
- docsTitle,
361
- commandsHelpInfo: getCommandsHelpInfo(entries)
362
- }));
363
- }
364
- async function writeCliDocsMarkdownFile(args) {
365
- const { filePath, ...restArgs } = args;
366
- await writeFile(filePath, makeCliDocsFromHelp(restArgs), { encoding: "utf-8" });
367
- }
368
- //#endregion
369
- //#region src/file-builders/document-editor.ts
370
- /** Generates a document editor for the given `documentModelId` (also called `documentType`) */
371
- async function tsMorphGenerateDocumentEditor({ projectDir, editorDir, editorName, editorId, documentModelId }) {
372
- const documentModelsDirPath = path.join(projectDir, "document-models");
373
- const editorsDirPath = path.join(projectDir, "editors");
374
- const editorDirPath = path.join(editorsDirPath, editorDir);
375
- const componentsDirPath = path.join(editorDirPath, "components");
376
- const editorSourceFilesPath = path.join(editorsDirPath, "/**/*");
377
- const documentModelsSourceFilesPath = path.join(documentModelsDirPath, "/**/*");
378
- const project = buildTsMorphProject(projectDir);
379
- await ensureDirectoriesExist(project, documentModelsDirPath, editorsDirPath, editorDirPath, componentsDirPath);
380
- project.addSourceFilesAtPaths(documentModelsSourceFilesPath);
381
- project.addSourceFilesAtPaths(editorSourceFilesPath);
382
- const documentTypeMetadata = getDocumentTypeMetadata({
383
- project,
384
- documentModelId,
385
- documentModelsDirPath
386
- });
387
- const editorVariableNames = getEditorVariableNames(documentTypeMetadata);
388
- await makeEditorComponent({
389
- project,
390
- editorDirPath,
391
- ...documentTypeMetadata,
392
- ...editorVariableNames
393
- });
394
- makeEditorModuleFile({
395
- project,
396
- editorName,
397
- editorId,
398
- documentModelId,
399
- editorDirPath
400
- });
401
- await makeEditorsModulesFile(project, projectDir);
402
- await project.save();
403
- }
404
- async function makeEditorComponent(args) {
405
- const { project, editorDirPath } = args;
406
- const { alreadyExists, sourceFile } = getOrCreateSourceFile(project, path.join(editorDirPath, "editor.tsx"));
407
- if (alreadyExists) {
408
- const functionDeclaration = sourceFile.getFunction("Editor");
409
- if (functionDeclaration) {
410
- if (!functionDeclaration.isDefaultExport()) functionDeclaration.setIsDefaultExport(true);
411
- return;
412
- }
413
- }
414
- const template = documentEditorEditorFileTemplate(args);
415
- sourceFile.replaceWithText(template);
416
- await formatSourceFileWithPrettier(sourceFile);
417
- }
418
- //#endregion
419
- //#region src/codegen/graphql.ts
420
- const getDirectories = async (source) => {
421
- return (await fs.readdir(source, { withFileTypes: true })).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent);
422
- };
423
- const scalars = {
424
- Unknown: "unknown",
425
- DateTime: "string",
426
- Attachment: "string",
427
- Address: "`${string}:0x${string}`",
428
- ...generatorTypeDefs
429
- };
430
- const scalarsValidation = {
431
- Unknown: "z.unknown()",
432
- DateTime: "z.string().datetime()",
433
- Attachment: "z.string()",
434
- Address: "z.custom<`${string}:0x${string}`>((val) => /^[a-zA-Z0-9]+:0x[a-fA-F0-9]{40}$/.test(val as string))",
435
- ...validationSchema
436
- };
437
- const avoidOptionals = {
438
- field: true,
439
- inputValue: false
440
- };
441
- const maybeValue = "T | null | undefined";
442
- const typescriptConfig = {
443
- avoidOptionals,
444
- scalars,
445
- strictScalars: true,
446
- enumsAsTypes: true,
447
- skipTypename: true,
448
- maybeValue
449
- };
450
- const validationSchemaConfig = {
451
- avoidOptionals,
452
- scalars,
453
- strictScalars: true,
454
- enumsAsTypes: true,
455
- skipTypename: true,
456
- importFrom: `./types.js`,
457
- schema: "zodv4",
458
- useTypeImports: true,
459
- scalarSchemas: scalarsValidation,
460
- directives: { equals: { value: ["regex", "/^$1$/"] } },
461
- withObjectType: true,
462
- maybeValue
463
- };
464
- function buildSchemasForModules(modules) {
465
- const schemaStrings = [];
466
- for (const module of modules) {
467
- schemaStrings.push(`# ${module.name}`);
468
- const operationsSchemas = module.operations.map((operation) => operation.schema).filter((schema) => schema !== null);
469
- schemaStrings.push(...operationsSchemas);
470
- }
471
- return schemaStrings;
472
- }
473
- function buildGraphqlDocumentStringForSpecification(specification) {
474
- const customScalarSchemas = Object.keys(scalars).map((k) => `scalar ${k}`).join("\n");
475
- const stateSchemas = Object.values(specification.state).map((state) => state.schema);
476
- const moduleSchemas = buildSchemasForModules(specification.modules);
477
- return [
478
- customScalarSchemas,
479
- ...stateSchemas,
480
- ...moduleSchemas
481
- ];
482
- }
483
- async function formatContentWithPrettier(path, content) {
484
- return await format(content, { parser: "typescript" });
485
- }
486
- async function generateTypesAndZodSchemasFromGraphql(args) {
487
- const { dirName, schema, skipFormat, writeFile, watch } = args;
488
- await generate({
489
- overwrite: true,
490
- watch,
491
- hooks: { beforeOneFileWrite: skipFormat ? void 0 : formatContentWithPrettier },
492
- generates: {
493
- [`${dirName}/gen/schema/types.ts`]: {
494
- schema,
495
- config: typescriptConfig,
496
- plugins: [{ typescript: typescriptConfig }]
497
- },
498
- [`${dirName}/gen/schema/zod.ts`]: {
499
- schema,
500
- config: validationSchemaConfig,
501
- plugins: [{ add: { content: "/* eslint-disable @typescript-eslint/no-empty-object-type */" } }, { "graphql-codegen-typescript-validation-schema": validationSchemaConfig }]
502
- }
503
- }
504
- }, writeFile);
505
- }
506
- async function generateDocumentModelZodSchemas(args) {
507
- const { documentModelDirPath, specification, writeFile = true, skipFormat = false, watch = false } = args;
508
- const schema = buildGraphqlDocumentStringForSpecification(specification).filter(Boolean).join("\n\n");
509
- await generateTypesAndZodSchemasFromGraphql({
510
- dirName: documentModelDirPath,
511
- schema,
512
- writeFile,
513
- skipFormat,
514
- watch
515
- });
516
- await fs.writeFile(path$1.join(documentModelDirPath, "schema.graphql"), schema);
517
- }
518
- const generateSchemas = async (inDir, { watch = false, skipFormat = false, writeFile = true, outDir = inDir } = {}) => {
519
- const dirs = await getDirectories(inDir);
520
- const inputs = await Promise.all(dirs.map(async (dir) => {
521
- const documentModelJsonFile = await fs.readFile(path$1.join(dir.parentPath, dir.name, `${dir.name}.json`), "utf-8");
522
- const parsedJson = JSON.parse(documentModelJsonFile);
523
- const latestSpecification = parsedJson.specifications[parsedJson.specifications.length - 1];
524
- const schema = buildGraphqlDocumentStringForSpecification(latestSpecification).filter(Boolean).join("\n\n");
525
- return {
526
- dirName: path$1.join(outDir, dir.name),
527
- schema
528
- };
529
- }));
530
- await Promise.all(inputs.map(async ({ schema, dirName }) => {
531
- await generateTypesAndZodSchemasFromGraphql({
532
- schema,
533
- dirName,
534
- writeFile,
535
- skipFormat,
536
- watch
537
- });
538
- }));
539
- };
540
- //#endregion
541
- //#region src/file-builders/document-model/gen-dir.ts
542
- async function makeGenDirFiles(fileMakerArgs) {
543
- await makeDocumentModelSchemaIndexFile(fileMakerArgs);
544
- await makeDocumentModelGenUtilsFile(fileMakerArgs);
545
- await makeDocumentModelGenTypesFile(fileMakerArgs);
546
- await makeDocumentModelGenCreatorsFile(fileMakerArgs);
547
- await makeDocumentModelGenActionsFile(fileMakerArgs);
548
- await makeDocumentModelGenDocumentSchemaFile(fileMakerArgs);
549
- await makeDocumentModelGenReducerFile(fileMakerArgs);
550
- await makeDocumentModelDocumentTypeFile(fileMakerArgs);
551
- await makeDocumentModelGenIndexFile(fileMakerArgs);
552
- await makeDocumentModelGenDocumentModelFile(fileMakerArgs);
553
- await makeDocumentModelGenPhFactoriesFile(fileMakerArgs);
554
- await makeDocumentModelGenControllerFile(fileMakerArgs);
555
- const modules = fileMakerArgs.modules;
556
- for (const module of modules) {
557
- const operationsModuleVariableNames = getDocumentModelOperationsModuleVariableNames(module);
558
- await makeGenDirOperationModuleFiles({
559
- module,
560
- ...fileMakerArgs,
561
- ...operationsModuleVariableNames
562
- });
563
- }
564
- }
565
- async function makeGenDirOperationModuleFiles(fileMakerArgs) {
566
- await makeOperationModuleGenActionsFile(fileMakerArgs);
567
- await makeOperationModuleGenCreatorsFile(fileMakerArgs);
568
- await makeOperationModuleGenOperationsFile(fileMakerArgs);
569
- await makeOperationModuleGenErrorFile(fileMakerArgs);
570
- }
571
- async function makeDocumentModelGenUtilsFile(args) {
572
- const template = documentModelGenUtilsTemplate(args);
573
- const { project, genDirPath } = args;
574
- const { sourceFile } = getOrCreateSourceFile(project, path.join(genDirPath, "utils.ts"));
575
- sourceFile.replaceWithText(template);
576
- await formatSourceFileWithPrettier(sourceFile);
577
- }
578
- async function makeDocumentModelDocumentTypeFile(args) {
579
- const template = documentModelDocumentTypeTemplate(args);
580
- const { project, genDirPath } = args;
581
- const { sourceFile } = getOrCreateSourceFile(project, path.join(genDirPath, "document-type.ts"));
582
- sourceFile.replaceWithText(template);
583
- await formatSourceFileWithPrettier(sourceFile);
584
- }
585
- async function makeDocumentModelSchemaIndexFile(args) {
586
- const template = documentModelSchemaIndexTemplate;
587
- const { project, schemaDirPath } = args;
588
- const { sourceFile } = getOrCreateSourceFile(project, path.join(schemaDirPath, "index.ts"));
589
- sourceFile.replaceWithText(template);
590
- await formatSourceFileWithPrettier(sourceFile);
591
- }
592
- async function makeDocumentModelGenTypesFile(args) {
593
- const template = documentModelGenTypesTemplate(args);
594
- const { project, genDirPath } = args;
595
- const { sourceFile } = getOrCreateSourceFile(project, path.join(genDirPath, "types.ts"));
596
- sourceFile.replaceWithText(template);
597
- await formatSourceFileWithPrettier(sourceFile);
598
- }
599
- async function makeDocumentModelGenDocumentModelFile(args) {
600
- const { project, genDirPath, documentModelState } = args;
601
- const { sourceFile } = getOrCreateSourceFile(project, path.join(genDirPath, "document-model.ts"));
602
- sourceFile.replaceWithText("");
603
- sourceFile.addImportDeclaration({
604
- namedImports: ["DocumentModelGlobalState"],
605
- moduleSpecifier: "document-model",
606
- isTypeOnly: true
607
- });
608
- const documentModelStateString = buildObjectLiteral(documentModelState, sourceFile);
609
- sourceFile.addVariableStatement({
610
- declarationKind: VariableDeclarationKind.Const,
611
- isExported: true,
612
- declarations: [{
613
- name: "documentModel",
614
- type: "DocumentModelGlobalState",
615
- initializer: documentModelStateString
616
- }]
617
- });
618
- await formatSourceFileWithPrettier(sourceFile);
619
- }
620
- async function makeDocumentModelGenDocumentSchemaFile(args) {
621
- const template = documentModelDocumentSchemaFileTemplate(args);
622
- const { project, genDirPath } = args;
623
- const { sourceFile } = getOrCreateSourceFile(project, path.join(genDirPath, "document-schema.ts"));
624
- sourceFile.replaceWithText(template);
625
- await formatSourceFileWithPrettier(sourceFile);
626
- }
627
- async function makeDocumentModelGenCreatorsFile(args) {
628
- const template = documentModelGenCreatorsFileTemplate(args);
629
- const { project, genDirPath } = args;
630
- const { sourceFile } = getOrCreateSourceFile(project, path.join(genDirPath, "creators.ts"));
631
- sourceFile.replaceWithText(template);
632
- await formatSourceFileWithPrettier(sourceFile);
633
- }
634
- async function makeDocumentModelGenPhFactoriesFile(args) {
635
- const template = documentModelPhFactoriesFileTemplate(args);
636
- const { project, genDirPath } = args;
637
- const { sourceFile } = getOrCreateSourceFile(project, path.join(genDirPath, "ph-factories.ts"));
638
- sourceFile.replaceWithText(template);
639
- await formatSourceFileWithPrettier(sourceFile);
640
- }
641
- async function makeDocumentModelGenControllerFile(args) {
642
- const template = documentModelGenControllerFileTemplate(args);
643
- const { project, genDirPath } = args;
644
- const { sourceFile } = getOrCreateSourceFile(project, path.join(genDirPath, "controller.ts"));
645
- sourceFile.replaceWithText(template);
646
- await formatSourceFileWithPrettier(sourceFile);
647
- }
648
- async function makeDocumentModelGenIndexFile(args) {
649
- const template = documentModelGenIndexFileTemplate(args);
650
- const { project, genDirPath } = args;
651
- const { sourceFile } = getOrCreateSourceFile(project, path.join(genDirPath, "index.ts"));
652
- sourceFile.replaceWithText(template);
653
- await formatSourceFileWithPrettier(sourceFile);
654
- }
655
- async function makeDocumentModelGenActionsFile(args) {
656
- const template = documentModelGenActionsFileTemplate(args);
657
- const { project, genDirPath } = args;
658
- const { sourceFile } = getOrCreateSourceFile(project, path.join(genDirPath, "actions.ts"));
659
- sourceFile.replaceWithText(template);
660
- await formatSourceFileWithPrettier(sourceFile);
661
- }
662
- async function makeDocumentModelGenReducerFile(args) {
663
- const template = documentModelGenReducerFileTemplate(args);
664
- const { project, genDirPath } = args;
665
- const { sourceFile } = getOrCreateSourceFile(project, path.join(genDirPath, "reducer.ts"));
666
- sourceFile.replaceWithText(template);
667
- await formatSourceFileWithPrettier(sourceFile);
668
- }
669
- async function makeOperationModuleGenActionsFile(args) {
670
- const { module } = args;
671
- const { actions } = getDocumentModelOperationsModuleVariableNames(module);
672
- const pascalCaseModuleName = pascalCase(module.name);
673
- const kebabCaseModuleName = kebabCase(module.name);
674
- const template = documentModelOperationModuleActionsFileTemplate({
675
- ...args,
676
- actions,
677
- pascalCaseModuleName
678
- });
679
- const { project, genDirPath } = args;
680
- const dirPath = path.join(genDirPath, kebabCaseModuleName);
681
- const { sourceFile } = getOrCreateSourceFile(project, path.join(dirPath, "actions.ts"));
682
- sourceFile.replaceWithText(template);
683
- await formatSourceFileWithPrettier(sourceFile);
684
- }
685
- async function makeOperationModuleGenCreatorsFile(args) {
686
- const { module } = args;
687
- const moduleVariableNames = getDocumentModelOperationsModuleVariableNames(module);
688
- const kebabCaseModuleName = kebabCase(module.name);
689
- const template = documentModelOperationsModuleCreatorsFileTemplate({
690
- ...args,
691
- ...moduleVariableNames
692
- });
693
- const { project, genDirPath } = args;
694
- const dirPath = path.join(genDirPath, kebabCaseModuleName);
695
- const { sourceFile } = getOrCreateSourceFile(project, path.join(dirPath, "creators.ts"));
696
- sourceFile.replaceWithText(template);
697
- await formatSourceFileWithPrettier(sourceFile);
698
- }
699
- async function makeOperationModuleGenOperationsFile(args) {
700
- const { module } = args;
701
- const moduleVariableNames = getDocumentModelOperationsModuleVariableNames(module);
702
- const kebabCaseModuleName = kebabCase(module.name);
703
- const template = documentModelOperationsModuleOperationsFileTemplate({
704
- ...args,
705
- ...moduleVariableNames
706
- });
707
- const { project, genDirPath } = args;
708
- const dirPath = path.join(genDirPath, kebabCaseModuleName);
709
- const { sourceFile } = getOrCreateSourceFile(project, path.join(dirPath, "operations.ts"));
710
- sourceFile.replaceWithText(template);
711
- await formatSourceFileWithPrettier(sourceFile);
712
- }
713
- async function makeOperationModuleGenErrorFile(args) {
714
- const { module } = args;
715
- const moduleVariableNames = getDocumentModelOperationsModuleVariableNames(module);
716
- const kebabCaseModuleName = kebabCase(module.name);
717
- const template = documentModelOperationsModuleErrorFileTemplate({
718
- ...args,
719
- ...moduleVariableNames
720
- });
721
- const { project, genDirPath } = args;
722
- const dirPath = path.join(genDirPath, kebabCaseModuleName);
723
- const { sourceFile } = getOrCreateSourceFile(project, path.join(dirPath, "error.ts"));
724
- sourceFile.replaceWithText(template);
725
- await formatSourceFileWithPrettier(sourceFile);
726
- }
727
- //#endregion
728
- //#region src/file-builders/document-model/migrate-legacy.ts
729
- /**
730
- * Detects whether a document model directory has a legacy (non-versioned)
731
- * structure and migrates it to the versioned layout expected by `--use-versioning`.
732
- *
733
- * Detection: a directory is "legacy" when `src/reducers/` exists at root level
734
- * AND no `v1/` directory exists yet.
735
- *
736
- * Migration steps:
737
- * 1. Move legacy root-level items (`gen/`, `src/`, `tests/`, and known root files)
738
- * into a `legacy/` subfolder for reference / backup.
739
- * 2. Copy custom source files (reducers, tests, utils) from `legacy/` into the
740
- * soon-to-be-created `v1/` directory so that ts-morph picks them up during
741
- * generation and preserves business logic.
742
- *
743
- * This function is idempotent — calling it on an already-migrated directory is a
744
- * no-op.
745
- */
746
- async function migrateLegacyToVersioned(documentModelDirPath) {
747
- const srcReducersPath = path.join(documentModelDirPath, "src", "reducers");
748
- const v1Path = path.join(documentModelDirPath, "v1");
749
- const legacyPath = path.join(documentModelDirPath, "legacy");
750
- const hasSrcReducers = await directoryExists(srcReducersPath);
751
- const hasV1 = await directoryExists(v1Path);
752
- if (!hasSrcReducers || hasV1) return;
753
- console.log(`[migrate-legacy] Detected legacy structure in ${documentModelDirPath}`);
754
- await mkdir(legacyPath, { recursive: true });
755
- const dirsToMove = [
756
- "gen",
757
- "src",
758
- "tests"
759
- ];
760
- const filesToMove = [
761
- "module.ts",
762
- "actions.ts",
763
- "hooks.ts",
764
- "utils.ts",
765
- "index.ts",
766
- "schema.graphql"
767
- ];
768
- for (const dirName of dirsToMove) {
769
- const srcPath = path.join(documentModelDirPath, dirName);
770
- if (await directoryExists(srcPath)) {
771
- await rename(srcPath, path.join(legacyPath, dirName));
772
- console.log(`[migrate-legacy] Moved ${dirName}/ → legacy/${dirName}/`);
773
- }
774
- }
775
- for (const fileName of filesToMove) {
776
- const srcPath = path.join(documentModelDirPath, fileName);
777
- if (await fileExists(srcPath)) {
778
- await rename(srcPath, path.join(legacyPath, fileName));
779
- console.log(`[migrate-legacy] Moved ${fileName} → legacy/${fileName}`);
780
- }
781
- }
782
- const v1SrcReducersPath = path.join(v1Path, "src", "reducers");
783
- const v1SrcPath = path.join(v1Path, "src");
784
- const v1TestsPath = path.join(v1Path, "tests");
785
- const legacySrcReducersPath = path.join(legacyPath, "src", "reducers");
786
- if (await directoryExists(legacySrcReducersPath)) {
787
- await mkdir(v1SrcReducersPath, { recursive: true });
788
- await copyDirectoryFiles(legacySrcReducersPath, v1SrcReducersPath);
789
- console.log(`[migrate-legacy] Copied src/reducers/ → v1/src/reducers/`);
790
- }
791
- const legacySrcTestsPath = path.join(legacyPath, "src", "tests");
792
- if (await directoryExists(legacySrcTestsPath)) {
793
- const v1SrcTestsPath = path.join(v1SrcPath, "tests");
794
- await mkdir(v1SrcTestsPath, { recursive: true });
795
- await copyDirectoryFiles(legacySrcTestsPath, v1SrcTestsPath);
796
- console.log(`[migrate-legacy] Copied src/tests/ → v1/src/tests/`);
797
- }
798
- const legacyTestsPath = path.join(legacyPath, "tests");
799
- if (await directoryExists(legacyTestsPath)) {
800
- await mkdir(v1TestsPath, { recursive: true });
801
- await copyDirectoryFiles(legacyTestsPath, v1TestsPath);
802
- console.log(`[migrate-legacy] Copied tests/ → v1/tests/`);
803
- }
804
- const legacyUtilsPath = path.join(legacyPath, "src", "utils.ts");
805
- if (await fileExists(legacyUtilsPath)) {
806
- await mkdir(v1SrcPath, { recursive: true });
807
- await copyFile(legacyUtilsPath, path.join(v1SrcPath, "utils.ts"));
808
- console.log(`[migrate-legacy] Copied src/utils.ts → v1/src/utils.ts`);
809
- }
810
- console.log(`[migrate-legacy] Migration complete for ${documentModelDirPath}`);
811
- }
812
- /** Copy all files (non-recursive) from srcDir to destDir */
813
- async function copyDirectoryFiles(srcDir, destDir) {
814
- const entries = await readdir(srcDir, { withFileTypes: true });
815
- for (const entry of entries) if (entry.isFile()) await copyFile(path.join(srcDir, entry.name), path.join(destDir, entry.name));
816
- }
817
- //#endregion
818
- //#region src/file-builders/document-model/root-dir.ts
819
- async function makeRootDirFiles(fileMakerArgs) {
820
- await makeDocumentModelVersionIndexFile(fileMakerArgs);
821
- await makeDocumentModelRootActionsFile(fileMakerArgs);
822
- await makeDocumentModelModuleFile(fileMakerArgs);
823
- await makeDocumentModelUtilsFile(fileMakerArgs);
824
- await makeDocumentModelHooksFile(fileMakerArgs);
825
- }
826
- async function makeDocumentModelVersionIndexFile(args) {
827
- const template = documentModelIndexTemplate;
828
- const { project, documentModelVersionDirPath } = args;
829
- const { sourceFile } = getOrCreateSourceFile(project, path.join(documentModelVersionDirPath, "index.ts"));
830
- sourceFile.replaceWithText(template);
831
- await formatSourceFileWithPrettier(sourceFile);
832
- }
833
- async function makeDocumentModelUtilsFile(args) {
834
- const template = documentModelUtilsTemplate(args);
835
- const { project, documentModelVersionDirPath } = args;
836
- const { sourceFile } = getOrCreateSourceFile(project, path.join(documentModelVersionDirPath, "utils.ts"));
837
- sourceFile.replaceWithText(template);
838
- await formatSourceFileWithPrettier(sourceFile);
839
- }
840
- async function makeDocumentModelRootActionsFile(args) {
841
- const template = documentModelRootActionsFileTemplate(args);
842
- const { project, documentModelVersionDirPath } = args;
843
- const { sourceFile } = getOrCreateSourceFile(project, path.join(documentModelVersionDirPath, "actions.ts"));
844
- sourceFile.replaceWithText(template);
845
- await formatSourceFileWithPrettier(sourceFile);
846
- }
847
- async function makeDocumentModelHooksFile(args) {
848
- const template = documentModelHooksFileTemplate(args);
849
- const { project, documentModelVersionDirPath } = args;
850
- const { sourceFile } = getOrCreateSourceFile(project, path.join(documentModelVersionDirPath, "hooks.ts"));
851
- sourceFile.replaceWithText(template);
852
- await formatSourceFileWithPrettier(sourceFile);
853
- }
854
- async function makeDocumentModelModuleFile(args) {
855
- const { project, documentModelVersionDirPath } = args;
856
- const template = documentModelModuleFileTemplate(args);
857
- const { sourceFile } = getOrCreateSourceFile(project, path.join(documentModelVersionDirPath, "module.ts"));
858
- sourceFile.replaceWithText(template);
859
- await formatSourceFileWithPrettier(sourceFile);
860
- }
861
- //#endregion
862
- //#region src/file-builders/document-model/src-dir.ts
863
- async function makeSrcDirFiles(fileMakerArgs) {
864
- await makeDocumentModelSrcIndexFile(fileMakerArgs);
865
- await makeDocumentModelSrcUtilsFile(fileMakerArgs);
866
- await makeReducerOperationHandlersForModules(fileMakerArgs);
867
- }
868
- async function makeReducerOperationHandlersForModules(fileMakerArgs) {
869
- const { modules } = fileMakerArgs;
870
- for (const module of modules) await makeReducerOperationHandlerForModule({
871
- ...fileMakerArgs,
872
- module
873
- });
874
- }
875
- async function makeReducerOperationHandlerForModule({ project, module, version, reducersDirPath, pascalCaseDocumentType, camelCaseDocumentType, versionedDocumentModelPackageImportPath }) {
876
- const kebabCaseModuleName = kebabCase(module.name);
877
- const pascalCaseModuleName = pascalCase(module.name);
878
- const filePath = path.join(reducersDirPath, `${kebabCaseModuleName}.ts`);
879
- const { alreadyExists, sourceFile } = getOrCreateSourceFile(project, filePath);
880
- if (!alreadyExists) {
881
- const previousVersionFile = getPreviousVersionSourceFile({
882
- project,
883
- version,
884
- filePath
885
- });
886
- if (previousVersionFile) sourceFile.replaceWithText(previousVersionFile.getText());
887
- }
888
- const operationsInterfaceTypeName = `${pascalCaseDocumentType}${pascalCaseModuleName}Operations`;
889
- const operationsInterfaceVariableName = `${camelCaseDocumentType}${pascalCaseModuleName}Operations`;
890
- const existingOperationsInterfaceTypeImport = sourceFile.getImportDeclaration((importDeclaration) => !!importDeclaration.getNamedImports().find((importSpecifier) => importSpecifier.getName() === operationsInterfaceTypeName));
891
- if (existingOperationsInterfaceTypeImport) existingOperationsInterfaceTypeImport.remove();
892
- const operationsInterfaceTypeProperties = sourceFile.addImportDeclaration({
893
- namedImports: [operationsInterfaceTypeName],
894
- moduleSpecifier: versionedDocumentModelPackageImportPath,
895
- isTypeOnly: true
896
- }).getNamedImports().find((value) => value.getName() === operationsInterfaceTypeName)?.getNameNode().getType().getProperties().map((symbol) => symbol.getName());
897
- if (!operationsInterfaceTypeProperties) throw new Error("Failed to create operation handler object");
898
- let operationsInterfaceVariableStatement = sourceFile.getVariableStatement(operationsInterfaceVariableName);
899
- if (!operationsInterfaceVariableStatement) operationsInterfaceVariableStatement = sourceFile.addVariableStatement({
900
- declarationKind: VariableDeclarationKind.Const,
901
- isExported: true,
902
- declarations: [{
903
- name: operationsInterfaceVariableName,
904
- type: operationsInterfaceTypeName,
905
- initializer: "{}"
906
- }]
907
- });
908
- const operationsInterfaceObject = getObjectLiteral(operationsInterfaceVariableStatement);
909
- if (!operationsInterfaceObject) throw new Error("Failed to build reducer object");
910
- const operationsByMethodName = /* @__PURE__ */ new Map();
911
- for (const operation of module.operations) if (operation.name) {
912
- const methodName = `${camelCase(operation.name)}Operation`;
913
- operationsByMethodName.set(methodName, operation);
914
- }
915
- for (const name of operationsInterfaceTypeProperties) {
916
- if (operationsInterfaceObject.getProperty(name)) continue;
917
- const reducerCode = operationsByMethodName.get(name)?.reducer?.trim();
918
- operationsInterfaceObject.addMethod({
919
- name,
920
- parameters: [{ name: "state" }, { name: "action" }],
921
- statements: reducerCode ? [reducerCode] : [`// TODO: implement ${name} reducer`, ts$1`throw new Error("Reducer for '${name}' not implemented.")`.raw]
922
- });
923
- }
924
- addErrorImportsForModule(sourceFile, module);
925
- await formatSourceFileWithPrettier(sourceFile);
926
- }
927
- async function makeDocumentModelSrcIndexFile({ project, ...variableNames }) {
928
- const template = documentModelSrcIndexFileTemplate;
929
- const { srcDirPath } = variableNames;
930
- const { sourceFile } = getOrCreateSourceFile(project, path.join(srcDirPath, "index.ts"));
931
- sourceFile.replaceWithText(template);
932
- await formatSourceFileWithPrettier(sourceFile);
933
- }
934
- async function makeDocumentModelSrcUtilsFile({ project, srcDirPath, version }) {
935
- const template = documentModelSrcUtilsTemplate;
936
- const filePath = path.join(srcDirPath, "utils.ts");
937
- const { alreadyExists, sourceFile } = getOrCreateSourceFile(project, filePath);
938
- if (!alreadyExists) {
939
- const previousVersionSourceFile = getPreviousVersionSourceFile({
940
- project,
941
- version,
942
- filePath
943
- });
944
- if (previousVersionSourceFile) sourceFile.replaceWithText(previousVersionSourceFile.getText());
945
- else sourceFile.replaceWithText(template);
946
- }
947
- await formatSourceFileWithPrettier(sourceFile);
948
- }
949
- function addErrorImportsForModule(sourceFile, module) {
950
- const allErrors = [];
951
- for (const operation of module.operations) if (Array.isArray(operation.errors)) {
952
- for (const error of operation.errors) if (error.name && !allErrors.find((e) => e.name === error.name)) allErrors.push({ name: error.name });
953
- }
954
- if (allErrors.length === 0) return;
955
- const sourceFileContent = sourceFile.getFullText();
956
- const usedErrors = [];
957
- for (const error of allErrors) if (new RegExp(`\\b${error.name}\\b`, "g").test(sourceFileContent)) usedErrors.push(error.name);
958
- if (usedErrors.length === 0) return;
959
- const errorImportPath = `../../gen/${kebabCase(module.name)}/error.js`;
960
- const existingErrorImport = sourceFile.getImportDeclarations().find((importDecl) => importDecl.getModuleSpecifierValue() === errorImportPath);
961
- if (existingErrorImport) {
962
- const existingNamedImports = existingErrorImport.getNamedImports().map((namedImport) => namedImport.getName());
963
- const newErrorsToImport = usedErrors.filter((errorName) => !existingNamedImports.includes(errorName));
964
- if (newErrorsToImport.length > 0) existingErrorImport.addNamedImports(newErrorsToImport);
965
- } else sourceFile.addImportDeclaration({
966
- namedImports: usedErrors,
967
- moduleSpecifier: errorImportPath
968
- });
969
- }
970
- //#endregion
971
- //#region src/file-builders/document-model/tests-dir.ts
972
- async function makeTestsDirFiles(fileMakerArgs) {
973
- await makeDocumentModelTestFile(fileMakerArgs);
974
- const modules = fileMakerArgs.modules;
975
- for (const module of modules) await makeOperationModuleTestFile({
976
- ...fileMakerArgs,
977
- module
978
- });
979
- }
980
- async function makeOperationModuleTestFile(args) {
981
- const { project, module, version, testsDirPath, documentModelPackageImportPath, versionedDocumentModelPackageImportPath, isPhDocumentOfTypeFunctionName } = args;
982
- const moduleVariableNames = getDocumentModelOperationsModuleVariableNames(module);
983
- const { actions } = moduleVariableNames;
984
- const kebabCaseModuleName = kebabCase(module.name);
985
- const moduleOperationsTypeName = `${pascalCase(module.name)}Operations`;
986
- const filePath = path.join(testsDirPath, `${kebabCaseModuleName}.test.ts`);
987
- const { alreadyExists, sourceFile } = getOrCreateSourceFile(project, filePath);
988
- if (!alreadyExists) {
989
- const previousVersionSourceFile = getPreviousVersionSourceFile({
990
- project,
991
- version,
992
- filePath
993
- });
994
- if (previousVersionSourceFile) sourceFile.replaceWithText(previousVersionSourceFile.getText());
995
- else sourceFile.replaceWithText(ts$1`
996
- import { generateMock } from "document-model";
997
- import { describe, expect, it } from "vitest";
998
-
999
- describe("${moduleOperationsTypeName}", () => {
1000
-
1001
- });
1002
- `.raw);
1003
- }
1004
- const importNames = makeActionImportNames({
1005
- ...args,
1006
- ...moduleVariableNames
1007
- });
1008
- const namedImports = importNames.map((name) => ({ name }));
1009
- let actionsImportDeclaration = sourceFile.getImportDeclarations().filter((i) => !i.isTypeOnly()).find((importDeclaration) => importDeclaration.getModuleSpecifier().getText().includes(documentModelPackageImportPath));
1010
- if (!actionsImportDeclaration) actionsImportDeclaration = sourceFile.addImportDeclaration({
1011
- namedImports,
1012
- moduleSpecifier: versionedDocumentModelPackageImportPath
1013
- });
1014
- else {
1015
- actionsImportDeclaration.setModuleSpecifier(versionedDocumentModelPackageImportPath);
1016
- const existingNamedImports = actionsImportDeclaration.getNamedImports().map((value) => value.getName());
1017
- for (const name of importNames) if (!existingNamedImports.includes(name)) actionsImportDeclaration.addNamedImport(name);
1018
- }
1019
- const describeCall = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression).find((call) => {
1020
- const expressionText = call.getExpression().getText();
1021
- const firstArg = call.getArguments()[0];
1022
- return expressionText === "describe" && pascalCase(firstArg.getText()).includes(moduleOperationsTypeName);
1023
- });
1024
- if (!describeCall) {
1025
- console.error(`Test file at path ${filePath} has no describe block for ${moduleOperationsTypeName}`);
1026
- return;
1027
- }
1028
- const describeCallBody = describeCall.getArguments()[1].asKindOrThrow(SyntaxKind.ArrowFunction);
1029
- const testCaseNames = describeCall.getDescendantsOfKind(SyntaxKind.CallExpression).filter((call) => {
1030
- const expressionText = call.getExpression().getText();
1031
- return expressionText === "it" || expressionText === "test";
1032
- }).map((c) => c.getArguments()[0].getText());
1033
- const testCasesToAdd = actions.filter((action) => {
1034
- const camelCaseActionName = camelCase(action.name);
1035
- return !testCaseNames.some((c) => c.includes(camelCaseActionName));
1036
- }).map((action) => makeTestCaseForAction(action, isPhDocumentOfTypeFunctionName));
1037
- describeCallBody.addStatements(testCasesToAdd);
1038
- const GENERATE_MOCK_NAME = "generateMock";
1039
- const GENERATE_MOCK_MODULE_SPECIFIER = "@powerhousedao/codegen";
1040
- const generateMockImport = sourceFile.getImportDeclaration((i) => i.getNamedImports().some((v) => v.getText().includes(GENERATE_MOCK_NAME)));
1041
- if (sourceFile.getText().includes(GENERATE_MOCK_NAME) && !generateMockImport) sourceFile.addImportDeclaration({
1042
- namedImports: [GENERATE_MOCK_NAME],
1043
- moduleSpecifier: GENERATE_MOCK_MODULE_SPECIFIER
1044
- });
1045
- sourceFile.fixUnusedIdentifiers();
1046
- await formatSourceFileWithPrettier(sourceFile);
1047
- }
1048
- async function makeDocumentModelTestFile(args) {
1049
- const { project, testsDirPath } = args;
1050
- const template = documentModelTestFileTemplate(args);
1051
- const { alreadyExists, sourceFile } = getOrCreateSourceFile(project, path.join(testsDirPath, "document-model.test.ts"));
1052
- if (alreadyExists) return;
1053
- sourceFile.replaceWithText(template);
1054
- await formatSourceFileWithPrettier(sourceFile);
1055
- }
1056
- //#endregion
1057
- //#region src/file-builders/document-model/upgrades-dir.ts
1058
- async function makeUpgradeFile(args) {
1059
- const { project, version, upgradesDirPath, documentModelPackageImportPath, phStateName } = args;
1060
- if (version < 2) return;
1061
- const { alreadyExists, sourceFile } = getOrCreateSourceFile(project, path.join(upgradesDirPath, `v${version}.ts`));
1062
- if (alreadyExists) return;
1063
- const template = upgradeTransitionTemplate({
1064
- version,
1065
- previousVersion: version - 1,
1066
- documentModelPackageImportPath,
1067
- phStateName
1068
- });
1069
- sourceFile.replaceWithText(template);
1070
- await formatSourceFileWithPrettier(sourceFile);
1071
- }
1072
- async function createOrUpdateUpgradeManifestFile(args) {
1073
- const { project, specVersions, upgradesDirPath, documentModelId, upgradeManifestName } = args;
1074
- const { sourceFile } = getOrCreateSourceFile(project, path.join(upgradesDirPath, "upgrade-manifest.ts"));
1075
- const template = upgradeManifestTemplate({
1076
- documentModelId,
1077
- upgradeManifestName
1078
- });
1079
- sourceFile.replaceWithText(template);
1080
- const upgradeTransitionImports = buildUpgradeTransitionImports(specVersions);
1081
- sourceFile.addImportDeclarations(upgradeTransitionImports);
1082
- const upgradeManifestStatement = getVariableDeclarationByTypeName(sourceFile, "UpgradeManifest")?.getVariableStatementOrThrow();
1083
- const upgradesProperty = getObjectLiteral(upgradeManifestStatement)?.getProperty("upgrades");
1084
- const upgrades = buildUpgrades(specVersions);
1085
- upgradesProperty?.replaceWithText(upgrades);
1086
- await formatSourceFileWithPrettier(sourceFile);
1087
- }
1088
- function buildUpgrades(specVersions) {
1089
- const upgradeStrings = [];
1090
- for (const version of specVersions) {
1091
- if (version < 2) continue;
1092
- upgradeStrings.push(`v${version}`);
1093
- }
1094
- return `upgrades: { ${upgradeStrings.join(",\n")} }`;
1095
- }
1096
- function buildUpgradeTransitionImports(specVersions) {
1097
- const imports = [];
1098
- for (const version of specVersions) {
1099
- if (version < 2) continue;
1100
- const namedImports = [`v${version}`];
1101
- const moduleSpecifier = `./v${version}.js`;
1102
- imports.push({
1103
- namedImports,
1104
- moduleSpecifier
1105
- });
1106
- }
1107
- return imports;
1108
- }
1109
- async function createOrUpdateVersionConstantsFile({ specVersions, latestVersion, project, upgradesDirPath }) {
1110
- const SUPPORTED_VERSIONS = "supportedVersions";
1111
- const LATEST_VERSION = "latestVersion";
1112
- const { sourceFile } = getOrCreateSourceFile(project, path.join(upgradesDirPath, "versions.ts"));
1113
- sourceFile.replaceWithText("");
1114
- const latestVersionIndex = specVersions.indexOf(latestVersion);
1115
- const versionInitializer = `[${specVersions.join(", ")}] as const;`;
1116
- const latestInitializer = `${SUPPORTED_VERSIONS}[${latestVersionIndex}];`;
1117
- sourceFile.addVariableStatement({
1118
- declarationKind: VariableDeclarationKind.Const,
1119
- isExported: true,
1120
- declarations: [{
1121
- name: SUPPORTED_VERSIONS,
1122
- initializer: versionInitializer
1123
- }]
1124
- });
1125
- sourceFile.addVariableStatement({
1126
- declarationKind: VariableDeclarationKind.Const,
1127
- isExported: true,
1128
- declarations: [{
1129
- name: LATEST_VERSION,
1130
- initializer: latestInitializer
1131
- }]
1132
- });
1133
- await formatSourceFileWithPrettier(sourceFile);
1134
- }
1135
- async function makeUpgradesIndexFile({ project, upgradesDirPath, specVersions, upgradeManifestName }) {
1136
- const { sourceFile } = getOrCreateSourceFile(project, path.join(upgradesDirPath, "index.ts"));
1137
- sourceFile.replaceWithText("");
1138
- const upgradeReducerExports = makeUpgradeReducerExports(specVersions);
1139
- sourceFile.addExportDeclarations([
1140
- {
1141
- namedExports: [upgradeManifestName],
1142
- moduleSpecifier: "./upgrade-manifest.js"
1143
- },
1144
- {
1145
- namedExports: ["supportedVersions", "latestVersion"],
1146
- moduleSpecifier: "./versions.js"
1147
- },
1148
- ...upgradeReducerExports
1149
- ]);
1150
- await formatSourceFileWithPrettier(sourceFile);
1151
- }
1152
- function makeUpgradeReducerExports(specVersions) {
1153
- const exports = [];
1154
- for (const version of specVersions) {
1155
- if (version < 2) continue;
1156
- const namedExports = [`v${version}`];
1157
- const moduleSpecifier = `./v${version}.js`;
1158
- exports.push({
1159
- namedExports,
1160
- moduleSpecifier
1161
- });
1162
- }
1163
- return exports;
1164
- }
1165
- //#endregion
1166
- //#region src/file-builders/document-model/document-model.ts
1167
- /** Generates a document model from the given `documentModelState`
1168
- *
1169
- * If `useVersioning` is set to true, it will generate versioned document model code
1170
- * for each `specification` in the `documentModelState`
1171
- */
1172
- async function tsMorphGenerateDocumentModel({ projectDir, documentModelState, useVersioning, migrateLegacy }) {
1173
- if (migrateLegacy) await migrateLegacyToVersioned(path.join(projectDir, "document-models", getDocumentModelDirName(documentModelState)));
1174
- const project = buildTsMorphProject(projectDir);
1175
- const documentModelsSourceFilesPath = path.join(projectDir, "document-models/**/*");
1176
- const documentModelsDirPath = path.join(projectDir, "document-models");
1177
- const documentModelDirName = getDocumentModelDirName(documentModelState);
1178
- const documentModelDirPath = path.join(documentModelsDirPath, documentModelDirName);
1179
- const upgradesDirPath = path.join(documentModelDirPath, "upgrades");
1180
- const documentModelVariableNames = getDocumentModelVariableNames(documentModelState.name);
1181
- await ensureDirectoriesExist(project, documentModelsDirPath, documentModelDirPath);
1182
- if (useVersioning) await ensureDirectoriesExist(project, upgradesDirPath);
1183
- project.addSourceFilesAtPaths(documentModelsSourceFilesPath);
1184
- const documentModelPackageImportPath = path.join("document-models", documentModelDirName);
1185
- const specVersions = [...new Set([...documentModelState.specifications.map((spec) => spec.version)])].toSorted();
1186
- if (specVersions.length !== documentModelState.specifications.length) throw new Error("Document model specifications array is misconfigured. Length is not match with spec versions.");
1187
- const latestVersion = specVersions[specVersions.length - 1];
1188
- if (documentModelState.specifications[documentModelState.specifications.length - 1].version !== latestVersion) throw new Error("Document model has incorrect version at the latest version index");
1189
- await writeDocumentModelStateJsonFile({
1190
- documentModelState,
1191
- documentModelDirName,
1192
- documentModelDirPath
1193
- });
1194
- if (useVersioning) {
1195
- await Promise.all(specVersions.map(async (version) => await generateDocumentModelForSpec({
1196
- project,
1197
- version,
1198
- useVersioning: true,
1199
- documentModelState,
1200
- projectDir,
1201
- documentModelsDirPath,
1202
- documentModelDirName,
1203
- documentModelDirPath,
1204
- documentModelPackageImportPath,
1205
- ...documentModelVariableNames
1206
- })));
1207
- for (const version of specVersions) await makeUpgradeFile({
1208
- version,
1209
- upgradesDirPath,
1210
- project,
1211
- documentModelPackageImportPath,
1212
- ...documentModelVariableNames
1213
- });
1214
- await makeDocumentModelIndexFile({
1215
- project,
1216
- documentModelDirPath,
1217
- latestVersion
1218
- });
1219
- await createOrUpdateVersionConstantsFile({
1220
- project,
1221
- specVersions,
1222
- latestVersion,
1223
- upgradesDirPath
1224
- });
1225
- await createOrUpdateUpgradeManifestFile({
1226
- project,
1227
- specVersions,
1228
- latestVersion,
1229
- upgradesDirPath,
1230
- documentModelId: documentModelState.id,
1231
- ...documentModelVariableNames
1232
- });
1233
- await makeUpgradesIndexFile({
1234
- project,
1235
- upgradesDirPath,
1236
- specVersions,
1237
- ...documentModelVariableNames
1238
- });
1239
- } else await generateDocumentModelForSpec({
1240
- project,
1241
- useVersioning: false,
1242
- version: latestVersion,
1243
- documentModelState,
1244
- projectDir,
1245
- documentModelsDirPath,
1246
- documentModelDirName,
1247
- documentModelDirPath,
1248
- documentModelPackageImportPath,
1249
- ...documentModelVariableNames
1250
- });
1251
- await project.save();
1252
- }
1253
- /** Generates document model code for a given `specification` from a `documentModelState` object */
1254
- async function generateDocumentModelForSpec({ project, projectDir, documentModelState, documentModelPackageImportPath, documentModelsDirPath, documentModelDirName, documentModelDirPath, useVersioning, version, ...documentModelVariableNames }) {
1255
- const specification = documentModelState.specifications.find((spec) => spec.version === version);
1256
- if (!specification) throw new Error(`Document model specifications array is misconfigured, no specification found for version: ${version}`);
1257
- const versionDirName = useVersioning ? `v${version}` : "";
1258
- const documentModelVersionDirName = path.join(documentModelDirName, versionDirName);
1259
- const documentModelVersionDirPath = path.join(documentModelDirPath, versionDirName);
1260
- const versionedDocumentModelPackageImportPath = path.join(documentModelPackageImportPath, versionDirName);
1261
- const fileExtension = documentModelState.extension;
1262
- const documentTypeId = documentModelState.id;
1263
- const srcDirPath = path.join(documentModelVersionDirPath, "src");
1264
- const reducersDirPath = path.join(srcDirPath, "reducers");
1265
- const testsDirPath = path.join(documentModelVersionDirPath, "tests");
1266
- const genDirPath = path.join(documentModelVersionDirPath, "gen");
1267
- const schemaDirPath = path.join(genDirPath, "schema");
1268
- const { initialGlobalState, initialLocalState } = getInitialStates(specification.state);
1269
- const hasLocalSchema = specification.state.local.schema !== "";
1270
- const modules = specification.modules;
1271
- await ensureDirectoriesExist(project, documentModelVersionDirPath, reducersDirPath, testsDirPath, schemaDirPath, ...modules.map((module) => path.join(genDirPath, kebabCase(module.name))));
1272
- const fileMakerArgs = {
1273
- project,
1274
- projectDir,
1275
- version,
1276
- useVersioning,
1277
- documentTypeId,
1278
- documentModelState,
1279
- initialGlobalState,
1280
- initialLocalState,
1281
- modules,
1282
- hasLocalSchema,
1283
- documentModelsDirPath,
1284
- documentModelDirPath,
1285
- documentModelDirName,
1286
- documentModelVersionDirName,
1287
- documentModelVersionDirPath,
1288
- documentModelPackageImportPath,
1289
- versionedDocumentModelPackageImportPath,
1290
- srcDirPath,
1291
- genDirPath,
1292
- testsDirPath,
1293
- schemaDirPath,
1294
- reducersDirPath,
1295
- fileExtension,
1296
- ...documentModelVariableNames
1297
- };
1298
- await generateDocumentModelZodSchemas({
1299
- documentModelDirPath: documentModelVersionDirPath,
1300
- specification
1301
- });
1302
- await makeRootDirFiles(fileMakerArgs);
1303
- await makeGenDirFiles(fileMakerArgs);
1304
- await makeSrcDirFiles(fileMakerArgs);
1305
- await makeTestsDirFiles(fileMakerArgs);
1306
- await makeDocumentModelModulesFile(fileMakerArgs);
1307
- if (!useVersioning) return;
1308
- await makeUpgradeManifestsFile({
1309
- project,
1310
- projectDir
1311
- });
1312
- const previousVersionDirPath = getPreviousVersionDirPath(documentModelDirPath, version);
1313
- if (!previousVersionDirPath) return;
1314
- await persistCustomFilesFromPreviousVersion({
1315
- currentVersionDirPath: documentModelVersionDirPath,
1316
- previousVersionDirPath
1317
- });
1318
- }
1319
- /** Writes a json file derived from a `documentModelState` */
1320
- async function writeDocumentModelStateJsonFile({ documentModelState, documentModelDirName, documentModelDirPath }) {
1321
- await writeFile(path.join(documentModelDirPath, `${documentModelDirName}.json`), JSON.stringify(documentModelState, null, 2));
1322
- }
1323
- function getPreviousVersionDirPath(documentModelDirPath, version) {
1324
- const previousVersion = version - 1;
1325
- if (previousVersion < 1) return;
1326
- const previousVersionDirName = `v${previousVersion}`;
1327
- return path.join(documentModelDirPath, previousVersionDirName);
1328
- }
1329
- async function makeDocumentModelIndexFile(args) {
1330
- const { project, documentModelDirPath, latestVersion } = args;
1331
- const { sourceFile } = getOrCreateSourceFile(project, path.join(documentModelDirPath, "index.ts"));
1332
- sourceFile.replaceWithText("");
1333
- sourceFile.addExportDeclarations([{ moduleSpecifier: `./v${latestVersion}/index.js` }, { moduleSpecifier: `./upgrades/index.js` }]);
1334
- await formatSourceFileWithPrettier(sourceFile);
1335
- }
1336
- async function persistCustomFilesFromPreviousVersion(args) {
1337
- const { currentVersionDirPath, previousVersionDirPath } = args;
1338
- if (!await directoryExists(previousVersionDirPath)) return;
1339
- const previousVersionFiles = (await readdir(previousVersionDirPath, {
1340
- withFileTypes: true,
1341
- recursive: true
1342
- })).filter((dirEnt) => dirEnt.isFile()).map(({ name, parentPath }) => ({
1343
- name,
1344
- parentPath,
1345
- relativePath: path.relative(previousVersionDirPath, parentPath)
1346
- }));
1347
- for (const { name, relativePath } of previousVersionFiles) {
1348
- const filePathInCurrentVersionDir = path.join(currentVersionDirPath, relativePath, name);
1349
- const filePathInPreviousVersionDir = path.join(previousVersionDirPath, relativePath, name);
1350
- const existsInPreviousVersionDir = await fileExists(filePathInPreviousVersionDir);
1351
- const existsInCurrentVersionDir = await fileExists(filePathInCurrentVersionDir);
1352
- if (existsInPreviousVersionDir && !existsInCurrentVersionDir) {
1353
- console.log(`Persisting file "${path.join(relativePath, name)}" from previous version directory.`);
1354
- await mkdir(path.join(currentVersionDirPath, relativePath), { recursive: true });
1355
- await copyFile(filePathInPreviousVersionDir, filePathInCurrentVersionDir);
1356
- }
1357
- }
1358
- }
1359
- //#endregion
1360
- //#region src/file-builders/processors/analytics.ts
1361
- async function tsMorphGenerateAnalyticsProcessor(args) {
1362
- const { project, documentTypes, pascalCaseName, dirPath, camelCaseName } = args;
1363
- await makeIndexFile$1({
1364
- project,
1365
- pascalCaseName,
1366
- dirPath
1367
- });
1368
- await makeProcessorFile$1({
1369
- project,
1370
- pascalCaseName,
1371
- dirPath
1372
- });
1373
- await makeFactoryFile$1({
1374
- project,
1375
- pascalCaseName,
1376
- camelCaseName,
1377
- dirPath,
1378
- documentTypes
1379
- });
1380
- }
1381
- async function makeIndexFile$1(v) {
1382
- const template = analyticsIndexTemplate;
1383
- const { alreadyExists, sourceFile } = getOrCreateSourceFile(v.project, path.join(v.dirPath, "index.ts"));
1384
- if (alreadyExists) return;
1385
- sourceFile.replaceWithText(template);
1386
- await formatSourceFileWithPrettier(sourceFile);
1387
- }
1388
- async function makeProcessorFile$1(v) {
1389
- const template = analyticsProcessorTemplate(v);
1390
- const { alreadyExists, sourceFile } = getOrCreateSourceFile(v.project, path.join(v.dirPath, "processor.ts"));
1391
- if (alreadyExists) return;
1392
- sourceFile.replaceWithText(template);
1393
- await formatSourceFileWithPrettier(sourceFile);
1394
- }
1395
- async function makeFactoryFile$1(v) {
1396
- const template = analyticsFactoryTemplate(v);
1397
- const { alreadyExists, sourceFile } = getOrCreateSourceFile(v.project, path.join(v.dirPath, "factory.ts"));
1398
- if (alreadyExists) return;
1399
- sourceFile.replaceWithText(template);
1400
- await formatSourceFileWithPrettier(sourceFile);
1401
- }
1402
- //#endregion
1403
- //#region src/file-builders/processors/relational-db.ts
1404
- async function tsMorphGenerateRelationalDbProcessor(args) {
1405
- const { project, documentTypes, camelCaseName, pascalCaseName, dirPath } = args;
1406
- await makeIndexFile({
1407
- project,
1408
- pascalCaseName,
1409
- dirPath
1410
- });
1411
- await makeProcessorFile({
1412
- project,
1413
- pascalCaseName,
1414
- dirPath
1415
- });
1416
- await makeFactoryFile({
1417
- project,
1418
- pascalCaseName,
1419
- camelCaseName,
1420
- dirPath,
1421
- documentTypes
1422
- });
1423
- await makeMigrationsFile({
1424
- project,
1425
- dirPath
1426
- });
1427
- await makeSchemaFile({
1428
- project,
1429
- dirPath
1430
- });
1431
- }
1432
- async function makeIndexFile(v) {
1433
- const template = relationalDbIndexTemplate;
1434
- const { alreadyExists, sourceFile } = getOrCreateSourceFile(v.project, path.join(v.dirPath, "index.ts"));
1435
- if (alreadyExists) return;
1436
- sourceFile.replaceWithText(template);
1437
- await formatSourceFileWithPrettier(sourceFile);
1438
- }
1439
- async function makeProcessorFile(v) {
1440
- const template = relationalDbProcessorTemplate(v);
1441
- const { alreadyExists, sourceFile } = getOrCreateSourceFile(v.project, path.join(v.dirPath, "processor.ts"));
1442
- if (alreadyExists) return;
1443
- sourceFile.replaceWithText(template);
1444
- await formatSourceFileWithPrettier(sourceFile);
1445
- }
1446
- async function makeFactoryFile(v) {
1447
- const template = relationalDbFactoryTemplate(v);
1448
- const { alreadyExists, sourceFile } = getOrCreateSourceFile(v.project, path.join(v.dirPath, "factory.ts"));
1449
- if (alreadyExists) return;
1450
- sourceFile.replaceWithText(template);
1451
- await formatSourceFileWithPrettier(sourceFile);
1452
- }
1453
- async function makeSchemaFile(v) {
1454
- const template = relationalDbSchemaTemplate();
1455
- const { alreadyExists, sourceFile } = getOrCreateSourceFile(v.project, path.join(v.dirPath, "schema.ts"));
1456
- if (alreadyExists) return;
1457
- sourceFile.replaceWithText(template);
1458
- await formatSourceFileWithPrettier(sourceFile);
1459
- }
1460
- async function makeMigrationsFile(v) {
1461
- const template = relationalDbMigrationsTemplate();
1462
- const { alreadyExists, sourceFile } = getOrCreateSourceFile(v.project, path.join(v.dirPath, "migrations.ts"));
1463
- if (alreadyExists) return;
1464
- sourceFile.replaceWithText(template);
1465
- await formatSourceFileWithPrettier(sourceFile);
1466
- }
1467
- //#endregion
1468
- //#region src/file-builders/processors/processor.ts
1469
- async function tsMorphGenerateProcessor(args) {
1470
- const { processorName, documentTypes, rootDir, processorType, processorApps } = args;
1471
- const kebabCaseName = kebabCase(processorName);
1472
- const camelCaseName = camelCase(processorName);
1473
- const pascalCaseName = pascalCase(processorName);
1474
- const processorsDirPath = path.join(rootDir, "processors");
1475
- const dirPath = path.join(processorsDirPath, kebabCaseName);
1476
- const sourceFilesPath = path.join(processorsDirPath, "**/*");
1477
- const project = buildTsMorphProject(rootDir);
1478
- await ensureDirectoriesExist(project, processorsDirPath, dirPath);
1479
- project.addSourceFilesAtPaths(sourceFilesPath);
1480
- if (processorType === "analytics") await tsMorphGenerateAnalyticsProcessor({
1481
- processorName,
1482
- documentTypes,
1483
- rootDir,
1484
- camelCaseName,
1485
- dirPath,
1486
- kebabCaseName,
1487
- pascalCaseName,
1488
- processorsDirPath,
1489
- project
1490
- });
1491
- else await tsMorphGenerateRelationalDbProcessor({
1492
- processorName,
1493
- documentTypes,
1494
- rootDir,
1495
- camelCaseName,
1496
- dirPath,
1497
- kebabCaseName,
1498
- pascalCaseName,
1499
- processorsDirPath,
1500
- project
1501
- });
1502
- for (const processorApp of processorApps) await updateFactoryBuildersFile({
1503
- processorsDirPath,
1504
- processorApp,
1505
- project,
1506
- camelCaseName,
1507
- kebabCaseName
1508
- });
1509
- await project.save();
1510
- }
1511
- async function updateFactoryBuildersFile(v) {
1512
- const { project, processorsDirPath, processorApp, camelCaseName, kebabCaseName } = v;
1513
- const template = factoryBuildersTemplate;
1514
- const { alreadyExists, sourceFile } = getOrCreateSourceFile(project, path.join(processorsDirPath, `${processorApp}.ts`));
1515
- if (!alreadyExists) sourceFile.replaceWithText(template);
1516
- const name = `${camelCaseName}FactoryBuilder`;
1517
- const moduleSpecifier = path.join("processors", kebabCaseName);
1518
- const factoriesArrayName = "processorFactoryBuilders";
1519
- let factoryBuildersArray = getFactoryBuildersArray(sourceFile, factoriesArrayName);
1520
- if (!factoryBuildersArray) {
1521
- sourceFile.replaceWithText(template);
1522
- factoryBuildersArray = getFactoryBuildersArray(sourceFile, factoriesArrayName);
1523
- }
1524
- if (!factoryBuildersArray) throw new Error(`Could not get factory builders array in file ${processorApp}.ts`);
1525
- if (!sourceFile.getImportDeclarations().flatMap((importDeclaration) => importDeclaration.getNamedImports().map((n) => n.getText())).find((n) => n === name)) sourceFile.addImportDeclaration({
1526
- namedImports: [name],
1527
- moduleSpecifier
1528
- });
1529
- if (!factoryBuildersArray.getElements().map((e) => e.getText()).includes(name)) factoryBuildersArray.addElement(name);
1530
- await formatSourceFileWithPrettier(sourceFile);
1531
- }
1532
- function getFactoryBuildersArray(sourceFile, name) {
1533
- return sourceFile.getDescendantsOfKind(ts.SyntaxKind.VariableStatement).flatMap((d) => d.getDescendantsOfKind(ts.SyntaxKind.VariableDeclaration)).find((d) => d.getName() === name)?.getDescendantsOfKind(ts.SyntaxKind.ArrayLiteralExpression).at(0);
1534
- }
1535
- //#endregion
1536
- //#region src/file-builders/subgraph.ts
1537
- async function tsMorphGenerateSubgraph(args) {
1538
- const { subgraphsDir, subgraphName, documentModel } = args;
1539
- const project = new Project({
1540
- skipAddingFilesFromTsConfig: true,
1541
- skipLoadingLibFiles: true
1542
- });
1543
- const kebabCaseName = kebabCase(subgraphName);
1544
- const pascalCaseName = pascalCase(subgraphName);
1545
- const camelCaseName = camelCase(subgraphName);
1546
- const subgraphDir = path.join(subgraphsDir, kebabCaseName);
1547
- if (existsSync(subgraphDir)) for (const name of [
1548
- "index.ts",
1549
- "lib.ts",
1550
- "schema.ts",
1551
- "resolvers.ts"
1552
- ]) {
1553
- const filePath = path.join(subgraphDir, name);
1554
- if (existsSync(filePath)) project.addSourceFileAtPath(filePath);
1555
- }
1556
- await makeBaseSubgraphIndexFile(project, subgraphDir, {
1557
- pascalCaseName,
1558
- kebabCaseName
1559
- });
1560
- await makeBaseSubgraphLibFile(project, subgraphDir);
1561
- if (documentModel !== null) await makeDocumentModelSubgraphFiles(project, subgraphDir, documentModel);
1562
- else await makeCustomSubgraphFiles(project, subgraphDir, {
1563
- pascalCaseName,
1564
- camelCaseName
1565
- });
1566
- await project.save();
1567
- }
1568
- async function makeBaseSubgraphIndexFile(project, dirPath, v) {
1569
- const { alreadyExists, sourceFile } = getOrCreateSourceFile(project, path.join(dirPath, "index.ts"));
1570
- if (alreadyExists) return;
1571
- sourceFile.replaceWithText(subgraphIndexFileTemplate(v));
1572
- await formatSourceFileWithPrettier(sourceFile);
1573
- }
1574
- async function makeBaseSubgraphLibFile(project, dirPath) {
1575
- const { alreadyExists, sourceFile } = getOrCreateSourceFile(project, path.join(dirPath, "lib.ts"));
1576
- if (alreadyExists) return;
1577
- sourceFile.replaceWithText(subgraphLibFileTemplate());
1578
- await formatSourceFileWithPrettier(sourceFile);
1579
- }
1580
- async function makeCustomSubgraphFiles(project, dirPath, v) {
1581
- const schema = getOrCreateSourceFile(project, path.join(dirPath, "schema.ts"));
1582
- if (!schema.alreadyExists) schema.sourceFile.replaceWithText(customSubgraphSchemaTemplate(v));
1583
- const resolvers = getOrCreateSourceFile(project, path.join(dirPath, "resolvers.ts"));
1584
- if (!resolvers.alreadyExists) {
1585
- resolvers.sourceFile.replaceWithText(customSubgraphResolversTemplate(v));
1586
- await formatSourceFileWithPrettier(resolvers.sourceFile);
1587
- }
1588
- }
1589
- async function makeDocumentModelSubgraphFiles(project, dirPath, documentModel) {
1590
- const latestSpec = documentModel.specifications[documentModel.specifications.length - 1];
1591
- const documentType = documentModel.name;
1592
- const pascalCaseDocumentType = pascalCase(documentType);
1593
- const camelCaseDocumentType = camelCase(documentType);
1594
- const phDocumentTypeName = `${pascalCaseDocumentType}Document`;
1595
- const documentTypeVariableName = `${camelCaseDocumentType}DocumentType`;
1596
- const documentModelDir = `document-models/${kebabCase(documentType)}`;
1597
- const stateSchema = latestSpec.state.global.schema;
1598
- const stateTypeNames = extractTypeNames(stateSchema);
1599
- const modules = latestSpec.modules.filter((m) => m.name !== null).map((m) => ({
1600
- name: kebabCase(m.name),
1601
- operations: m.operations.filter((op) => op.name !== null).map((op) => ({
1602
- name: op.name,
1603
- schema: applyGraphQLTypePrefixes(op.schema ?? "", pascalCaseDocumentType, stateTypeNames)
1604
- }))
1605
- }));
1606
- getOrCreateSourceFile(project, path.join(dirPath, "schema.ts")).sourceFile.replaceWithText(documentModelSubgraphSchemaTemplate({
1607
- pascalCaseDocumentType,
1608
- modules
1609
- }));
1610
- getOrCreateSourceFile(project, path.join(dirPath, "resolvers.ts")).sourceFile.replaceWithText(documentModelSubgraphResolversTemplate({
1611
- pascalCaseDocumentType,
1612
- camelCaseDocumentType,
1613
- phDocumentTypeName,
1614
- documentTypeVariableName,
1615
- documentModelDir,
1616
- modules
1617
- }));
1618
- }
1619
- //#endregion
1620
- //#region src/file-builders/subgraphs.ts
1621
- async function makeSubgraphsIndexFile({ projectDir }) {
1622
- const project = new Project({
1623
- tsConfigFilePath: path.join(projectDir, "tsconfig.json"),
1624
- skipAddingFilesFromTsConfig: true,
1625
- skipLoadingLibFiles: true,
1626
- manipulationSettings: {
1627
- useTrailingCommas: true,
1628
- indentationText: IndentationText.TwoSpaces
1629
- }
1630
- });
1631
- project.addSourceFilesAtPaths(`${projectDir}/subgraphs/**/*`);
1632
- const subgraphsSubdirs = project.getDirectory(path.join(projectDir, "subgraphs"))?.getDirectories() ?? [];
1633
- let subgraphsIndexSourceFile = project.getSourceFile(path.join(projectDir, "subgraphs/index.ts"));
1634
- if (!subgraphsIndexSourceFile) subgraphsIndexSourceFile = project.createSourceFile(path.join(projectDir, "subgraphs/index.js"), "");
1635
- for (const subgraphSubdir of subgraphsSubdirs) {
1636
- const subgraphIndexSourceFilePath = `${subgraphSubdir.getPath()}/index.ts`;
1637
- const subgraphIndexSourceFile = project.getSourceFile(subgraphIndexSourceFilePath);
1638
- if (!subgraphIndexSourceFile) continue;
1639
- const subgraphClassName = subgraphIndexSourceFile.getClasses().find((c) => c.getBaseClass()?.getText().includes("BaseSubgraph"))?.getName();
1640
- if (!subgraphClassName) continue;
1641
- if (subgraphsIndexSourceFile.getExportDeclarations().map((e) => e.getNamespaceExport()?.getText()).filter((e) => e !== void 0).join().includes(subgraphClassName)) continue;
1642
- subgraphsIndexSourceFile.addExportDeclaration({
1643
- namespaceExport: subgraphClassName,
1644
- moduleSpecifier: `./${subgraphSubdir.getBaseName()}/index.js`
1645
- });
1646
- }
1647
- await project.save();
1648
- }
1649
- //#endregion
1650
- export { makeEditorModuleFile as C, makeLegacyIndexFile as S, makeDocumentModelModulesFile as _, generateDocumentModelZodSchemas as a, makeUpgradeManifestsExport as b, scalars as c, getCommandHelpInfo as d, getCommandsHelpInfo as f, tsMorphGenerateApp as g, buildBoilerplatePackageJson as h, tsMorphGenerateDocumentModel as i, scalarsValidation as l, writeCliDocsMarkdownFile as m, tsMorphGenerateSubgraph as n, generateSchemas as o, makeCliDocsFromHelp as p, tsMorphGenerateProcessor as r, generateTypesAndZodSchemasFromGraphql as s, makeSubgraphsIndexFile as t, tsMorphGenerateDocumentEditor as u, makeEditorsModulesFile as v, makeUpgradeManifestsFile as x, makeModulesFile as y };
1651
-
1652
- //# sourceMappingURL=file-builders-BV9wDPPZ.mjs.map