@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.
- package/dist/{templates-BbNsigQX.mjs → file-builders-BkbVW0kT.mjs} +2322 -383
- package/dist/file-builders-BkbVW0kT.mjs.map +1 -0
- package/dist/index-CEDWX5sL.d.mts +349 -0
- package/dist/index-CEDWX5sL.d.mts.map +1 -0
- package/dist/index.d.mts +42 -101
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +4492 -325
- package/dist/index.mjs.map +1 -1
- package/dist/src/file-builders/index.d.mts +2 -3
- package/dist/src/file-builders/index.mjs +2 -3
- package/dist/src/name-builders/index.d.mts +2 -2
- package/dist/src/name-builders/index.mjs +2 -146
- package/dist/src/templates/index.d.mts +34 -74
- 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 +6 -18
- package/dist/src/utils/index.d.mts.map +1 -1
- package/dist/src/utils/index.mjs +2 -380
- package/dist/{validation-Bpg_44mW.d.mts → validation-Z3z0BJlu.d.mts} +2 -2
- package/dist/{validation-Bpg_44mW.d.mts.map → validation-Z3z0BJlu.d.mts.map} +1 -1
- package/package.json +16 -9
- package/dist/file-builders-BV9wDPPZ.mjs +0 -1652
- package/dist/file-builders-BV9wDPPZ.mjs.map +0 -1
- package/dist/index-CHAnPBj2.d.mts +0 -199
- package/dist/index-CHAnPBj2.d.mts.map +0 -1
- package/dist/index-CJZGVSYg.d.mts +0 -65
- package/dist/index-CJZGVSYg.d.mts.map +0 -1
- package/dist/src/name-builders/index.mjs.map +0 -1
- package/dist/src/utils/index.mjs.map +0 -1
- package/dist/templates-BbNsigQX.mjs.map +0 -1
- package/dist/types-e2ztuDtG.d.mts +0 -87
- 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
|