@wictorwilen/cocogen 1.0.0 → 1.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +88 -35
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +84 -14
- package/dist/cli.js.map +1 -1
- package/dist/init/init.d.ts.map +1 -1
- package/dist/init/init.js +302 -156
- package/dist/init/init.js.map +1 -1
- package/dist/init/templates/dotnet/AGENTS.md.ejs +20 -0
- package/dist/init/templates/dotnet/Core/ConnectorCore.cs.ejs +602 -0
- package/dist/init/templates/dotnet/Datasource/CsvItemSource.cs.ejs +12 -3
- package/dist/init/templates/dotnet/Datasource/IItemSource.cs.ejs +10 -4
- package/dist/init/templates/dotnet/Generated/Constants.cs.ejs +5 -1
- package/dist/init/templates/dotnet/Generated/CsvParser.cs.ejs +61 -0
- package/dist/init/templates/dotnet/Generated/FromCsvRow.cs.ejs +11 -3
- package/dist/init/templates/dotnet/Generated/ItemPayload.cs.ejs +13 -3
- package/dist/init/templates/dotnet/Generated/Model.cs.ejs +5 -22
- package/dist/init/templates/dotnet/Generated/PropertyTransformBase.cs.ejs +45 -0
- package/dist/init/templates/dotnet/Generated/SchemaPayload.cs.ejs +9 -1
- package/dist/init/templates/dotnet/Program.commandline.cs.ejs +76 -278
- package/dist/init/templates/dotnet/PropertyTransform.cs.ejs +10 -0
- package/dist/init/templates/dotnet/README.md.ejs +6 -7
- package/dist/init/templates/dotnet/appsettings.json.ejs +1 -1
- package/dist/init/templates/ts/.env.example.ejs +1 -1
- package/dist/init/templates/ts/AGENTS.md.ejs +20 -0
- package/dist/init/templates/ts/README.md.ejs +6 -7
- package/dist/init/templates/ts/src/cli.ts.ejs +85 -173
- package/dist/init/templates/ts/src/core/connectorCore.ts.ejs +384 -0
- package/dist/init/templates/ts/src/datasource/csvItemSource.ts.ejs +12 -4
- package/dist/init/templates/ts/src/datasource/itemSource.ts.ejs +12 -5
- package/dist/init/templates/ts/src/generated/constants.ts.ejs +16 -0
- package/dist/init/templates/ts/src/generated/csv.ts.ejs +10 -0
- package/dist/init/templates/ts/src/generated/fromCsvRow.ts.ejs +12 -37
- package/dist/init/templates/ts/src/generated/index.ts.ejs +3 -0
- package/dist/init/templates/ts/src/generated/itemPayload.ts.ejs +12 -3
- package/dist/init/templates/ts/src/generated/model.ts.ejs +3 -11
- package/dist/init/templates/ts/src/generated/propertyTransformBase.ts.ejs +40 -0
- package/dist/init/templates/ts/src/generated/schemaPayload.ts.ejs +3 -0
- package/dist/init/templates/ts/src/index.ts.ejs +4 -1
- package/dist/init/templates/ts/src/propertyTransform.ts.ejs +16 -0
- package/dist/ir.d.ts +2 -0
- package/dist/ir.d.ts.map +1 -1
- package/dist/tsp/init-tsp.d.ts.map +1 -1
- package/dist/tsp/init-tsp.js +50 -7
- package/dist/tsp/init-tsp.js.map +1 -1
- package/dist/tsp/loader.d.ts.map +1 -1
- package/dist/tsp/loader.js +23 -9
- package/dist/tsp/loader.js.map +1 -1
- package/dist/typespec/decorators.d.ts +1 -0
- package/dist/typespec/decorators.d.ts.map +1 -1
- package/dist/typespec/decorators.js +7 -2
- package/dist/typespec/decorators.js.map +1 -1
- package/dist/typespec/state.d.ts +2 -0
- package/dist/typespec/state.d.ts.map +1 -1
- package/dist/typespec/state.js +1 -0
- package/dist/typespec/state.js.map +1 -1
- package/dist/validate/validator.d.ts.map +1 -1
- package/dist/validate/validator.js +127 -14
- package/dist/validate/validator.js.map +1 -1
- package/package.json +2 -1
- package/typespec/main.tsp +6 -2
- package/dist/init/templates/dotnet/Generated/PersonEntityDefaults.cs.ejs +0 -48
- package/dist/init/templates/dotnet/Generated/PropertyTransforms.cs.ejs +0 -22
- package/dist/init/templates/dotnet/PersonEntityOverrides.cs.ejs +0 -49
- package/dist/init/templates/dotnet/Program.cs.ejs +0 -487
- package/dist/init/templates/ts/src/generated/personEntityDefaults.ts.ejs +0 -33
- package/dist/init/templates/ts/src/generated/propertyTransforms.ts.ejs +0 -23
- package/dist/init/templates/ts/src/personEntityOverrides.ts.ejs +0 -36
package/dist/init/init.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
1
2
|
import { access, copyFile, mkdir, readdir, readFile, writeFile } from "node:fs/promises";
|
|
2
3
|
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
3
5
|
import { loadIrFromTypeSpec } from "../tsp/loader.js";
|
|
4
6
|
import { validateIr } from "../validate/validator.js";
|
|
5
7
|
import { renderTemplate } from "./template.js";
|
|
@@ -59,10 +61,26 @@ function toCsIdentifier(name) {
|
|
|
59
61
|
return pascal || "Item";
|
|
60
62
|
}
|
|
61
63
|
function toTsIdentifier(name) {
|
|
62
|
-
const
|
|
64
|
+
const parts = name.split(/[^A-Za-z0-9]+/g).filter(Boolean);
|
|
65
|
+
if (parts.length === 0)
|
|
66
|
+
return "Item";
|
|
67
|
+
const pascal = parts.map((part) => part.slice(0, 1).toUpperCase() + part.slice(1)).join("");
|
|
68
|
+
const sanitized = pascal.replaceAll(/[^A-Za-z0-9_]/g, "_");
|
|
69
|
+
return /^[A-Za-z_]/.test(sanitized) ? sanitized : `_${sanitized}`;
|
|
70
|
+
}
|
|
71
|
+
function toSchemaFolderName(connectionName) {
|
|
72
|
+
const cleaned = (connectionName ?? "").trim();
|
|
73
|
+
if (!cleaned)
|
|
74
|
+
return "Schema";
|
|
75
|
+
const candidate = toCsIdentifier(cleaned);
|
|
76
|
+
return candidate || "Schema";
|
|
77
|
+
}
|
|
78
|
+
function toTsSchemaFolderName(connectionName) {
|
|
79
|
+
const cleaned = (connectionName ?? "").trim();
|
|
63
80
|
if (!cleaned)
|
|
64
|
-
return "
|
|
65
|
-
|
|
81
|
+
return "schema";
|
|
82
|
+
const candidate = toTsIdentifier(cleaned);
|
|
83
|
+
return candidate || "schema";
|
|
66
84
|
}
|
|
67
85
|
function toCsNamespace(projectName) {
|
|
68
86
|
const cleaned = projectName
|
|
@@ -85,7 +103,10 @@ function graphBaseUrl(ir) {
|
|
|
85
103
|
}
|
|
86
104
|
function schemaPayload(ir) {
|
|
87
105
|
return {
|
|
88
|
-
|
|
106
|
+
baseType: "microsoft.graph.externalItem",
|
|
107
|
+
properties: ir.properties
|
|
108
|
+
.filter((p) => p.name !== ir.item.contentPropertyName)
|
|
109
|
+
.map((p) => ({
|
|
89
110
|
name: p.name,
|
|
90
111
|
type: p.type,
|
|
91
112
|
labels: p.labels.length > 0 ? p.labels : undefined,
|
|
@@ -99,11 +120,43 @@ function schemaPayload(ir) {
|
|
|
99
120
|
})),
|
|
100
121
|
};
|
|
101
122
|
}
|
|
123
|
+
function getGeneratorVersion() {
|
|
124
|
+
try {
|
|
125
|
+
const dir = path.dirname(fileURLToPath(import.meta.url));
|
|
126
|
+
const candidates = [
|
|
127
|
+
path.resolve(dir, "..", "package.json"),
|
|
128
|
+
path.resolve(dir, "..", "..", "package.json"),
|
|
129
|
+
path.resolve(dir, "..", "..", "..", "package.json"),
|
|
130
|
+
path.resolve(process.cwd(), "package.json"),
|
|
131
|
+
];
|
|
132
|
+
for (const pkgPath of candidates) {
|
|
133
|
+
try {
|
|
134
|
+
const raw = readFileSync(pkgPath, "utf8");
|
|
135
|
+
const parsed = JSON.parse(raw);
|
|
136
|
+
const name = parsed.name?.trim();
|
|
137
|
+
if (name && name !== "@wictorwilen/cocogen" && name !== "cocogen") {
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
if (parsed.version && parsed.version.trim().length > 0) {
|
|
141
|
+
return parsed.version.trim();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
// Ignore version lookup errors.
|
|
151
|
+
}
|
|
152
|
+
return "0.0.0";
|
|
153
|
+
}
|
|
102
154
|
function projectConfigContents(outDir, tspPath, lang) {
|
|
103
155
|
const rel = path.relative(outDir, path.resolve(tspPath)).replaceAll(path.sep, "/");
|
|
104
156
|
const config = {
|
|
105
157
|
lang,
|
|
106
158
|
tsp: rel || "./schema.tsp",
|
|
159
|
+
cocogenVersion: getGeneratorVersion(),
|
|
107
160
|
};
|
|
108
161
|
return JSON.stringify(config, null, 2) + "\n";
|
|
109
162
|
}
|
|
@@ -127,15 +180,22 @@ async function loadProjectConfig(outDir) {
|
|
|
127
180
|
if ((parsed.lang !== "ts" && parsed.lang !== "dotnet") || typeof parsed.tsp !== "string") {
|
|
128
181
|
throw new Error(`Invalid ${COCOGEN_CONFIG_FILE}. Re-run cocogen init or fix the file.`);
|
|
129
182
|
}
|
|
130
|
-
return {
|
|
183
|
+
return {
|
|
184
|
+
config: {
|
|
185
|
+
lang: parsed.lang,
|
|
186
|
+
tsp: parsed.tsp,
|
|
187
|
+
...(parsed.cocogenVersion ? { cocogenVersion: parsed.cocogenVersion } : {}),
|
|
188
|
+
},
|
|
189
|
+
};
|
|
131
190
|
}
|
|
132
|
-
async function writeGeneratedTs(outDir, ir) {
|
|
133
|
-
await mkdir(path.join(outDir, "src",
|
|
191
|
+
async function writeGeneratedTs(outDir, ir, schemaFolderName) {
|
|
192
|
+
await mkdir(path.join(outDir, "src", schemaFolderName), { recursive: true });
|
|
193
|
+
await mkdir(path.join(outDir, "src", "core"), { recursive: true });
|
|
134
194
|
const modelProperties = ir.properties.map((p) => ({
|
|
135
195
|
name: p.name,
|
|
136
196
|
tsType: toTsType(p.type),
|
|
137
197
|
}));
|
|
138
|
-
const
|
|
198
|
+
const transformProperties = ir.properties.map((p) => {
|
|
139
199
|
const parser = (() => {
|
|
140
200
|
switch (p.type) {
|
|
141
201
|
case "stringCollection":
|
|
@@ -168,40 +228,33 @@ async function writeGeneratedTs(outDir, ir) {
|
|
|
168
228
|
source: field.source,
|
|
169
229
|
}))))
|
|
170
230
|
: null;
|
|
231
|
+
const isPeopleLabel = p.labels.some((label) => label.startsWith("person"));
|
|
232
|
+
const needsManualEntity = isPeopleLabel && !p.personEntity;
|
|
233
|
+
const noSource = Boolean(p.source.noSource);
|
|
234
|
+
const expression = needsManualEntity
|
|
235
|
+
? `(() => { throw new Error("Missing @coco.source(..., to) mappings for people entity '${p.name}'. Implement transform in propertyTransform.ts."); })()`
|
|
236
|
+
: personEntity
|
|
237
|
+
? personEntity
|
|
238
|
+
: noSource
|
|
239
|
+
? `undefined as unknown as ${toTsType(p.type)}`
|
|
240
|
+
: `${parser}(readSourceValue(row, ${JSON.stringify(p.source.csvHeaders)}))`;
|
|
171
241
|
return {
|
|
172
242
|
name: p.name,
|
|
173
|
-
csvHeaders: p.source.csvHeaders,
|
|
174
243
|
parser,
|
|
175
|
-
expression
|
|
244
|
+
expression,
|
|
176
245
|
isCollection: p.type === "stringCollection",
|
|
177
|
-
isExplicitSource: p.source.explicit ?? false,
|
|
178
246
|
transformName: toTsIdentifier(p.name),
|
|
179
247
|
tsType: toTsType(p.type),
|
|
180
248
|
};
|
|
181
249
|
});
|
|
182
|
-
|
|
183
|
-
.filter((p) => p.personEntity)
|
|
184
|
-
.map((p) => ({
|
|
185
|
-
name: p.name,
|
|
186
|
-
isCollection: p.type === "stringCollection",
|
|
187
|
-
expression: p.type === "stringCollection"
|
|
188
|
-
? buildTsPersonEntityCollectionExpression((p.personEntity?.fields ?? []).map((field) => ({
|
|
189
|
-
path: field.path,
|
|
190
|
-
source: field.source,
|
|
191
|
-
})))
|
|
192
|
-
: buildTsPersonEntityExpression((p.personEntity?.fields ?? []).map((field) => ({
|
|
193
|
-
path: field.path,
|
|
194
|
-
source: field.source,
|
|
195
|
-
}))),
|
|
196
|
-
}));
|
|
197
|
-
const propertyTransforms = fromCsvProperties.filter((p) => !p.expression);
|
|
198
|
-
await writeFile(path.join(outDir, "src", "schema", "model.ts"), await renderTemplate("ts/src/generated/model.ts.ejs", {
|
|
250
|
+
await writeFile(path.join(outDir, "src", schemaFolderName, "model.ts"), await renderTemplate("ts/src/generated/model.ts.ejs", {
|
|
199
251
|
itemTypeName: ir.item.typeName,
|
|
200
252
|
properties: modelProperties,
|
|
201
253
|
}), "utf8");
|
|
202
|
-
await writeFile(path.join(outDir, "src",
|
|
254
|
+
await writeFile(path.join(outDir, "src", schemaFolderName, "constants.ts"), await renderTemplate("ts/src/generated/constants.ts.ejs", {
|
|
203
255
|
graphApiVersion: ir.connection.graphApiVersion,
|
|
204
256
|
contentCategory: ir.connection.contentCategory ?? null,
|
|
257
|
+
connectionName: ir.connection.connectionName ?? null,
|
|
205
258
|
connectionId: ir.connection.connectionId ?? null,
|
|
206
259
|
connectionDescription: ir.connection.connectionDescription ?? null,
|
|
207
260
|
profileSourceWebUrl: ir.connection.profileSource?.webUrl ?? null,
|
|
@@ -211,35 +264,26 @@ async function writeGeneratedTs(outDir, ir) {
|
|
|
211
264
|
idPropertyName: ir.item.idPropertyName,
|
|
212
265
|
contentPropertyName: ir.item.contentPropertyName ?? null,
|
|
213
266
|
}), "utf8");
|
|
214
|
-
await writeFile(path.join(outDir, "src",
|
|
267
|
+
await writeFile(path.join(outDir, "src", schemaFolderName, "schemaPayload.ts"), await renderTemplate("ts/src/generated/schemaPayload.ts.ejs", {
|
|
215
268
|
schemaPayloadJson: JSON.stringify(schemaPayload(ir), null, 2),
|
|
216
269
|
}), "utf8");
|
|
217
270
|
await writeFile(path.join(outDir, "src", "datasource", "csv.ts"), await renderTemplate("ts/src/generated/csv.ts.ejs", {}), "utf8");
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
properties: propertyTransforms,
|
|
221
|
-
}), "utf8");
|
|
222
|
-
}
|
|
223
|
-
await writeFile(path.join(outDir, "src", "schema", "fromCsvRow.ts"), await renderTemplate("ts/src/generated/fromCsvRow.ts.ejs", {
|
|
224
|
-
properties: fromCsvProperties,
|
|
225
|
-
hasPersonEntities: personEntityDefaults.length > 0,
|
|
226
|
-
propertyTransforms,
|
|
271
|
+
await writeFile(path.join(outDir, "src", schemaFolderName, "propertyTransformBase.ts"), await renderTemplate("ts/src/generated/propertyTransformBase.ts.ejs", {
|
|
272
|
+
properties: transformProperties,
|
|
227
273
|
}), "utf8");
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
await access(overridesPath);
|
|
235
|
-
}
|
|
236
|
-
catch {
|
|
237
|
-
await writeFile(overridesPath, await renderTemplate("ts/src/personEntityOverrides.ts.ejs", {
|
|
238
|
-
names: personEntityDefaults.map((p) => p.name),
|
|
239
|
-
}), "utf8");
|
|
240
|
-
}
|
|
274
|
+
const transformOverridesPath = path.join(outDir, "src", schemaFolderName, "propertyTransform.ts");
|
|
275
|
+
try {
|
|
276
|
+
await access(transformOverridesPath);
|
|
277
|
+
}
|
|
278
|
+
catch {
|
|
279
|
+
await writeFile(transformOverridesPath, await renderTemplate("ts/src/propertyTransform.ts.ejs", {}), "utf8");
|
|
241
280
|
}
|
|
281
|
+
await writeFile(path.join(outDir, "src", schemaFolderName, "fromCsvRow.ts"), await renderTemplate("ts/src/generated/fromCsvRow.ts.ejs", {
|
|
282
|
+
properties: transformProperties,
|
|
283
|
+
itemTypeName: ir.item.typeName,
|
|
284
|
+
}), "utf8");
|
|
242
285
|
const propertiesObjectLines = ir.properties
|
|
286
|
+
.filter((p) => p.name !== ir.item.contentPropertyName)
|
|
243
287
|
.flatMap((p) => {
|
|
244
288
|
const lines = [];
|
|
245
289
|
const odataType = toOdataCollectionType(p.type);
|
|
@@ -253,11 +297,16 @@ async function writeGeneratedTs(outDir, ir) {
|
|
|
253
297
|
const contentBlock = ir.item.contentPropertyName
|
|
254
298
|
? `,\n content: {\n type: \"text\",\n value: String((item as any)[contentPropertyName ?? \"\"] ?? \"\"),\n }`
|
|
255
299
|
: "";
|
|
256
|
-
await writeFile(path.join(outDir, "src",
|
|
300
|
+
await writeFile(path.join(outDir, "src", schemaFolderName, "itemPayload.ts"), await renderTemplate("ts/src/generated/itemPayload.ts.ejs", {
|
|
257
301
|
propertiesObjectLines,
|
|
258
302
|
contentBlock,
|
|
303
|
+
itemTypeName: ir.item.typeName,
|
|
304
|
+
}), "utf8");
|
|
305
|
+
await writeFile(path.join(outDir, "src", schemaFolderName, "index.ts"), await renderTemplate("ts/src/generated/index.ts.ejs", {}), "utf8");
|
|
306
|
+
await writeFile(path.join(outDir, "src", "core", "connectorCore.ts"), await renderTemplate("ts/src/core/connectorCore.ts.ejs", {
|
|
307
|
+
itemTypeName: ir.item.typeName,
|
|
308
|
+
isPeopleConnector: ir.connection.contentCategory === "people",
|
|
259
309
|
}), "utf8");
|
|
260
|
-
await writeFile(path.join(outDir, "src", "schema", "index.ts"), await renderTemplate("ts/src/generated/index.ts.ejs", {}), "utf8");
|
|
261
310
|
}
|
|
262
311
|
function toGraphPropertyTypeEnumName(type) {
|
|
263
312
|
switch (type) {
|
|
@@ -361,20 +410,48 @@ function buildObjectTree(fields) {
|
|
|
361
410
|
}
|
|
362
411
|
function buildTsPersonEntityExpression(fields) {
|
|
363
412
|
const tree = buildObjectTree(fields);
|
|
364
|
-
const
|
|
413
|
+
const indentUnit = " ";
|
|
414
|
+
const renderNode = (node, level) => {
|
|
415
|
+
const indent = indentUnit.repeat(level);
|
|
416
|
+
const childIndent = indentUnit.repeat(level + 1);
|
|
365
417
|
const entries = Object.entries(node).map(([key, value]) => {
|
|
366
418
|
if (typeof value === "object" && value && "path" in value) {
|
|
367
419
|
const field = value;
|
|
368
420
|
const headers = JSON.stringify(field.source.csvHeaders);
|
|
369
|
-
return `${JSON.stringify(key)}: parseString(readSourceValue(row, ${headers}))`;
|
|
421
|
+
return `${childIndent}${JSON.stringify(key)}: parseString(readSourceValue(row, ${headers}))`;
|
|
370
422
|
}
|
|
371
|
-
return `${JSON.stringify(key)}: ${renderNode(value)}`;
|
|
423
|
+
return `${childIndent}${JSON.stringify(key)}: ${renderNode(value, level + 1)}`;
|
|
372
424
|
});
|
|
373
|
-
return `{
|
|
425
|
+
return `{
|
|
426
|
+
${entries.join(",\n")}
|
|
427
|
+
${indent}}`;
|
|
374
428
|
};
|
|
375
|
-
|
|
429
|
+
const rendered = renderNode(tree, 2);
|
|
430
|
+
return `JSON.stringify(\n${indentUnit.repeat(2)}${rendered}\n${indentUnit.repeat(2)})`;
|
|
376
431
|
}
|
|
377
432
|
function buildTsPersonEntityCollectionExpression(fields) {
|
|
433
|
+
const indentUnit = " ";
|
|
434
|
+
const renderNode = (node, level, valueVar) => {
|
|
435
|
+
const indent = indentUnit.repeat(level);
|
|
436
|
+
const childIndent = indentUnit.repeat(level + 1);
|
|
437
|
+
const entries = Object.entries(node).map(([key, value]) => {
|
|
438
|
+
if (typeof value === "object" && value && "path" in value) {
|
|
439
|
+
return `${childIndent}${JSON.stringify(key)}: ${valueVar}`;
|
|
440
|
+
}
|
|
441
|
+
return `${childIndent}${JSON.stringify(key)}: ${renderNode(value, level + 1, valueVar)}`;
|
|
442
|
+
});
|
|
443
|
+
return `{
|
|
444
|
+
${entries.join(",\n")}
|
|
445
|
+
${indent}}`;
|
|
446
|
+
};
|
|
447
|
+
if (fields.length === 1) {
|
|
448
|
+
const tree = buildObjectTree(fields);
|
|
449
|
+
const field = fields[0];
|
|
450
|
+
const headers = JSON.stringify(field.source.csvHeaders);
|
|
451
|
+
const rendered = renderNode(tree, 2, "value");
|
|
452
|
+
return `parseStringCollection(readSourceValue(row, ${headers}))
|
|
453
|
+
.map((value) => JSON.stringify(\n${indentUnit.repeat(2)}${rendered}\n${indentUnit.repeat(2)}))`;
|
|
454
|
+
}
|
|
378
455
|
const tree = buildObjectTree(fields);
|
|
379
456
|
const fieldVarByPath = new Map();
|
|
380
457
|
const fieldLines = fields.map((field, index) => {
|
|
@@ -383,39 +460,66 @@ function buildTsPersonEntityCollectionExpression(fields) {
|
|
|
383
460
|
const headers = JSON.stringify(field.source.csvHeaders);
|
|
384
461
|
return ` const ${varName} = parseStringCollection(readSourceValue(row, ${headers}));`;
|
|
385
462
|
});
|
|
386
|
-
const
|
|
463
|
+
const renderNodeMany = (node) => {
|
|
387
464
|
const entries = Object.entries(node).map(([key, value]) => {
|
|
388
465
|
if (typeof value === "object" && value && "path" in value) {
|
|
389
466
|
const field = value;
|
|
390
467
|
const varName = fieldVarByPath.get(field.path) ?? "";
|
|
391
|
-
return `${JSON.stringify(key)}: getValue(${varName}, index)`;
|
|
468
|
+
return `${indentUnit.repeat(2)}${JSON.stringify(key)}: getValue(${varName}, index)`;
|
|
392
469
|
}
|
|
393
|
-
return `${JSON.stringify(key)}: ${
|
|
470
|
+
return `${indentUnit.repeat(2)}${JSON.stringify(key)}: ${renderNodeMany(value)}`;
|
|
394
471
|
});
|
|
395
|
-
return `{
|
|
472
|
+
return `{
|
|
473
|
+
${entries.join(",\n")}
|
|
474
|
+
${indentUnit}}`;
|
|
396
475
|
};
|
|
397
476
|
const fieldVars = [...fieldVarByPath.values()].join(", ");
|
|
398
477
|
const lengthVars = fieldVars
|
|
399
478
|
? `const lengths = [${fieldVars}].map((value) => value.length);`
|
|
400
479
|
: "const lengths = [0];";
|
|
401
|
-
return `(() => {\n${fieldLines.join("\n")}\n${lengthVars}\n const maxLen = Math.max(0, ...lengths);\n const getValue = (values: string[], index: number): string => {\n if (values.length === 0) return \"\";\n if (values.length === 1) return values[0] ?? \"\";\n return values[index] ?? \"\";\n };\n const results: string[] = [];\n for (let index = 0; index < maxLen; index++) {\n results.push(JSON.stringify(${
|
|
480
|
+
return `(() => {\n${fieldLines.join("\n")}\n${lengthVars}\n const maxLen = Math.max(0, ...lengths);\n const getValue = (values: string[], index: number): string => {\n if (values.length === 0) return \"\";\n if (values.length === 1) return values[0] ?? \"\";\n return values[index] ?? \"\";\n };\n const results: string[] = [];\n for (let index = 0; index < maxLen; index++) {\n results.push(JSON.stringify(\n ${renderNodeMany(tree)}\n ));\n }\n return results;\n})()`;
|
|
402
481
|
}
|
|
403
482
|
function buildCsPersonEntityExpression(fields) {
|
|
404
483
|
const tree = buildObjectTree(fields);
|
|
405
|
-
const
|
|
484
|
+
const indentUnit = " ";
|
|
485
|
+
const renderNode = (node, level) => {
|
|
486
|
+
const indent = indentUnit.repeat(level);
|
|
487
|
+
const childIndent = indentUnit.repeat(level + 1);
|
|
406
488
|
const entries = Object.entries(node).map(([key, value]) => {
|
|
407
489
|
if (typeof value === "object" && value && "path" in value) {
|
|
408
490
|
const field = value;
|
|
409
491
|
const headers = `new[] { ${field.source.csvHeaders.map((h) => JSON.stringify(h)).join(", ")} }`;
|
|
410
|
-
return
|
|
492
|
+
return `${childIndent}[${JSON.stringify(key)}] = CsvParser.ParseString(row, ${headers})`;
|
|
411
493
|
}
|
|
412
|
-
return
|
|
494
|
+
return `${childIndent}[${JSON.stringify(key)}] = ${renderNode(value, level + 1)}`;
|
|
413
495
|
});
|
|
414
|
-
return `new Dictionary<string, object
|
|
496
|
+
return `new Dictionary<string, object?>\n${indent}{\n${entries.join(",\n")}\n${indent}}`;
|
|
415
497
|
};
|
|
416
|
-
|
|
498
|
+
const rendered = renderNode(tree, 2);
|
|
499
|
+
return `JsonSerializer.Serialize(\n${indentUnit.repeat(2)}${rendered}\n${indentUnit.repeat(2)})`;
|
|
417
500
|
}
|
|
418
501
|
function buildCsPersonEntityCollectionExpression(fields) {
|
|
502
|
+
const indentUnit = " ";
|
|
503
|
+
const renderNode = (node, level, valueVar) => {
|
|
504
|
+
const indent = indentUnit.repeat(level);
|
|
505
|
+
const childIndent = indentUnit.repeat(level + 1);
|
|
506
|
+
const entries = Object.entries(node).map(([key, value]) => {
|
|
507
|
+
if (typeof value === "object" && value && "path" in value) {
|
|
508
|
+
return `${childIndent}[${JSON.stringify(key)}] = ${valueVar}`;
|
|
509
|
+
}
|
|
510
|
+
return `${childIndent}[${JSON.stringify(key)}] = ${renderNode(value, level + 1, valueVar)}`;
|
|
511
|
+
});
|
|
512
|
+
return `new Dictionary<string, object?>\n${indent}{\n${entries.join(",\n")}\n${indent}}`;
|
|
513
|
+
};
|
|
514
|
+
if (fields.length === 1) {
|
|
515
|
+
const tree = buildObjectTree(fields);
|
|
516
|
+
const field = fields[0];
|
|
517
|
+
const headers = `new[] { ${field.source.csvHeaders.map((h) => JSON.stringify(h)).join(", ")} }`;
|
|
518
|
+
const rendered = renderNode(tree, 3, "value");
|
|
519
|
+
return `CsvParser.ParseStringCollection(row, ${headers})
|
|
520
|
+
.Select(value => JsonSerializer.Serialize(\n${indentUnit.repeat(3)}${rendered}\n${indentUnit.repeat(3)}))
|
|
521
|
+
.ToList()`;
|
|
522
|
+
}
|
|
419
523
|
const tree = buildObjectTree(fields);
|
|
420
524
|
const fieldVarByPath = new Map();
|
|
421
525
|
const fieldLines = fields.map((field, index) => {
|
|
@@ -424,22 +528,22 @@ function buildCsPersonEntityCollectionExpression(fields) {
|
|
|
424
528
|
const headers = `new[] { ${field.source.csvHeaders.map((h) => JSON.stringify(h)).join(", ")} }`;
|
|
425
529
|
return ` var ${varName} = CsvParser.ParseStringCollection(row, ${headers});`;
|
|
426
530
|
});
|
|
427
|
-
const
|
|
531
|
+
const renderNodeMany = (node) => {
|
|
428
532
|
const entries = Object.entries(node).map(([key, value]) => {
|
|
429
533
|
if (typeof value === "object" && value && "path" in value) {
|
|
430
534
|
const field = value;
|
|
431
535
|
const varName = fieldVarByPath.get(field.path) ?? "";
|
|
432
|
-
return
|
|
536
|
+
return `${indentUnit.repeat(3)}[${JSON.stringify(key)}] = GetValue(${varName}, index)`;
|
|
433
537
|
}
|
|
434
|
-
return
|
|
538
|
+
return `${indentUnit.repeat(3)}[${JSON.stringify(key)}] = ${renderNodeMany(value)}`;
|
|
435
539
|
});
|
|
436
|
-
return `new Dictionary<string, object
|
|
540
|
+
return `new Dictionary<string, object?>\n${indentUnit.repeat(2)}{\n${entries.join(",\n")}\n${indentUnit.repeat(2)}}`;
|
|
437
541
|
};
|
|
438
542
|
const fieldVars = [...fieldVarByPath.values()];
|
|
439
543
|
const lengthLines = fieldVars.length > 0
|
|
440
544
|
? ` var maxLen = new[] { ${fieldVars.map((v) => `${v}.Count`).join(", ")} }.Max();`
|
|
441
545
|
: " var maxLen = 0;";
|
|
442
|
-
return `new Func<List<string>>(() =>\n {\n${fieldLines.join("\n")}\n string GetValue(List<string> values, int index)\n {\n if (values.Count == 0) return \"\";\n if (values.Count == 1) return values[0] ?? \"\";\n return index < values.Count ? (values[index] ?? \"\") : \"\";\n }\n${lengthLines}\n var results = new List<string>();\n for (var index = 0; index < maxLen; index++)\n {\n results.Add(JsonSerializer.Serialize(${
|
|
546
|
+
return `new Func<List<string>>(() =>\n {\n${fieldLines.join("\n")}\n string GetValue(List<string> values, int index)\n {\n if (values.Count == 0) return \"\";\n if (values.Count == 1) return values[0] ?? \"\";\n return index < values.Count ? (values[index] ?? \"\") : \"\";\n }\n${lengthLines}\n var results = new List<string>();\n for (var index = 0; index < maxLen; index++)\n {\n results.Add(JsonSerializer.Serialize(${renderNodeMany(tree)}));\n }\n return results;\n }).Invoke()`;
|
|
443
547
|
}
|
|
444
548
|
function csvEscape(value) {
|
|
445
549
|
if (value.includes("\n") || value.includes("\r") || value.includes(",") || value.includes("\"")) {
|
|
@@ -466,7 +570,7 @@ function sampleValueForType(type) {
|
|
|
466
570
|
case "dateTimeCollection":
|
|
467
571
|
return "2024-01-01T00:00:00Z;2024-01-02T00:00:00Z";
|
|
468
572
|
case "principal":
|
|
469
|
-
return '
|
|
573
|
+
return 'alice@contoso.com';
|
|
470
574
|
case "string":
|
|
471
575
|
default:
|
|
472
576
|
return "sample";
|
|
@@ -542,16 +646,14 @@ function buildSampleCsv(ir) {
|
|
|
542
646
|
const valueLine = headers.map((h) => csvEscape(valueByHeader.get(h) ?? "sample")).join(",");
|
|
543
647
|
return `${headerLine}\n${valueLine}\n`;
|
|
544
648
|
}
|
|
545
|
-
async function writeGeneratedDotnet(outDir, ir, namespaceName) {
|
|
546
|
-
await mkdir(path.join(outDir,
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
isCollection: p.type === "stringCollection",
|
|
554
|
-
personEntity: p.personEntity
|
|
649
|
+
async function writeGeneratedDotnet(outDir, ir, namespaceName, schemaFolderName, schemaNamespace) {
|
|
650
|
+
await mkdir(path.join(outDir, schemaFolderName), { recursive: true });
|
|
651
|
+
await mkdir(path.join(outDir, "Core"), { recursive: true });
|
|
652
|
+
const properties = ir.properties.map((p) => {
|
|
653
|
+
const parseFn = toCsParseFunction(p.type);
|
|
654
|
+
const csvHeadersLiteral = `new[] { ${p.source.csvHeaders.map((h) => JSON.stringify(h)).join(", ")} }`;
|
|
655
|
+
const isCollection = p.type === "stringCollection";
|
|
656
|
+
const personEntity = p.personEntity
|
|
555
657
|
? {
|
|
556
658
|
entity: p.personEntity.entity,
|
|
557
659
|
fields: p.personEntity.fields.map((field) => ({
|
|
@@ -559,16 +661,40 @@ async function writeGeneratedDotnet(outDir, ir, namespaceName) {
|
|
|
559
661
|
source: field.source,
|
|
560
662
|
})),
|
|
561
663
|
}
|
|
562
|
-
: null
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
664
|
+
: null;
|
|
665
|
+
const isPeopleLabel = p.labels.some((label) => label.startsWith("person"));
|
|
666
|
+
const needsManualEntity = isPeopleLabel && !p.personEntity;
|
|
667
|
+
const noSource = Boolean(p.source.noSource);
|
|
668
|
+
const transformExpression = needsManualEntity
|
|
669
|
+
? `throw new NotImplementedException("Missing @coco.source(..., to) mappings for people entity '${p.name}'. Implement in PropertyTransform.cs.")`
|
|
670
|
+
: personEntity
|
|
671
|
+
? isCollection
|
|
672
|
+
? buildCsPersonEntityCollectionExpression(personEntity.fields)
|
|
673
|
+
: buildCsPersonEntityExpression(personEntity.fields)
|
|
674
|
+
: noSource
|
|
675
|
+
? "default!"
|
|
676
|
+
: `${parseFn}(row, ${csvHeadersLiteral})`;
|
|
677
|
+
return {
|
|
678
|
+
name: p.name,
|
|
679
|
+
csName: toCsIdentifier(p.name),
|
|
680
|
+
csType: toCsType(p.type),
|
|
681
|
+
csvHeaders: p.source.csvHeaders,
|
|
682
|
+
csvHeadersLiteral,
|
|
683
|
+
isCollection,
|
|
684
|
+
personEntity,
|
|
685
|
+
parseFn,
|
|
686
|
+
transformExpression,
|
|
687
|
+
transformThrows: needsManualEntity,
|
|
688
|
+
graphTypeEnumName: toGraphPropertyTypeEnumName(p.type),
|
|
689
|
+
description: p.description,
|
|
690
|
+
labels: p.labels,
|
|
691
|
+
aliases: p.aliases,
|
|
692
|
+
search: p.search,
|
|
693
|
+
type: p.type,
|
|
694
|
+
};
|
|
695
|
+
});
|
|
571
696
|
const schemaPropertyLines = properties
|
|
697
|
+
.filter((p) => p.name !== ir.item.contentPropertyName)
|
|
572
698
|
.map((p) => {
|
|
573
699
|
const labels = p.labels.length > 0
|
|
574
700
|
? `new List<string> { ${p.labels.map((l) => JSON.stringify(l)).join(", ")} }`
|
|
@@ -615,29 +741,11 @@ async function writeGeneratedDotnet(outDir, ir, namespaceName) {
|
|
|
615
741
|
const constructorArgLines = properties
|
|
616
742
|
.map((p, index) => {
|
|
617
743
|
const comma = index < properties.length - 1 ? "," : "";
|
|
618
|
-
|
|
619
|
-
const method = p.isCollection ? "TransformCollection" : "Transform";
|
|
620
|
-
const defaults = p.isCollection ? "BuildDefaultCollection" : "BuildDefault";
|
|
621
|
-
return ` PersonEntityOverrides.${method}(${JSON.stringify(p.name)}, row, PersonEntityDefaults.${defaults}(${JSON.stringify(p.name)}, row))${comma}`;
|
|
622
|
-
}
|
|
623
|
-
const headersLiteral = `new[] { ${p.csvHeaders.map((h) => JSON.stringify(h)).join(", ")} }`;
|
|
624
|
-
if (p.isExplicitSource) {
|
|
625
|
-
return ` PropertyTransforms.Transform${p.csName}(CsvParser.ReadValue(row, ${headersLiteral}))${comma}`;
|
|
626
|
-
}
|
|
627
|
-
return ` PropertyTransforms.Transform${p.csName}(row)${comma}`;
|
|
744
|
+
return ` (${p.csType})transforms.TransformProperty(${JSON.stringify(p.name)}, row)${comma}`;
|
|
628
745
|
})
|
|
629
746
|
.join("\n");
|
|
630
|
-
const personEntityDefaults = properties
|
|
631
|
-
.filter((p) => p.personEntity)
|
|
632
|
-
.map((p) => ({
|
|
633
|
-
name: p.name,
|
|
634
|
-
isCollection: p.isCollection,
|
|
635
|
-
expression: p.isCollection
|
|
636
|
-
? buildCsPersonEntityCollectionExpression(p.personEntity.fields)
|
|
637
|
-
: buildCsPersonEntityExpression(p.personEntity.fields),
|
|
638
|
-
}));
|
|
639
|
-
const propertyTransforms = properties.filter((p) => !p.personEntity);
|
|
640
747
|
const propertiesObjectLines = properties
|
|
748
|
+
.filter((p) => p.name !== ir.item.contentPropertyName)
|
|
641
749
|
.flatMap((p) => {
|
|
642
750
|
const lines = [];
|
|
643
751
|
const odataType = toOdataCollectionType(p.type);
|
|
@@ -659,15 +767,16 @@ async function writeGeneratedDotnet(outDir, ir, namespaceName) {
|
|
|
659
767
|
" };",
|
|
660
768
|
].join("\n")
|
|
661
769
|
: "";
|
|
662
|
-
await writeFile(path.join(outDir,
|
|
663
|
-
|
|
770
|
+
await writeFile(path.join(outDir, schemaFolderName, "Model.cs"), await renderTemplate("dotnet/Generated/Model.cs.ejs", {
|
|
771
|
+
schemaNamespace,
|
|
664
772
|
itemTypeName: ir.item.typeName,
|
|
665
773
|
properties: properties.map((p) => ({ csName: p.csName, csType: p.csType })),
|
|
666
774
|
}), "utf8");
|
|
667
|
-
await writeFile(path.join(outDir,
|
|
668
|
-
|
|
775
|
+
await writeFile(path.join(outDir, schemaFolderName, "Constants.cs"), await renderTemplate("dotnet/Generated/Constants.cs.ejs", {
|
|
776
|
+
schemaNamespace,
|
|
669
777
|
graphApiVersion: ir.connection.graphApiVersion,
|
|
670
778
|
contentCategory: ir.connection.contentCategory ?? null,
|
|
779
|
+
connectionName: ir.connection.connectionName ?? null,
|
|
671
780
|
profileSourceWebUrl: ir.connection.profileSource?.webUrl ?? null,
|
|
672
781
|
profileSourceDisplayName: ir.connection.profileSource?.displayName ?? null,
|
|
673
782
|
profileSourcePriority: ir.connection.profileSource?.priority ?? null,
|
|
@@ -675,47 +784,50 @@ async function writeGeneratedDotnet(outDir, ir, namespaceName) {
|
|
|
675
784
|
idPropertyName: ir.item.idPropertyName,
|
|
676
785
|
contentPropertyName: ir.item.contentPropertyName ?? null,
|
|
677
786
|
}), "utf8");
|
|
678
|
-
await writeFile(path.join(outDir,
|
|
679
|
-
|
|
787
|
+
await writeFile(path.join(outDir, schemaFolderName, "SchemaPayload.cs"), await renderTemplate("dotnet/Generated/SchemaPayload.cs.ejs", {
|
|
788
|
+
schemaNamespace,
|
|
680
789
|
schemaPropertyLines,
|
|
681
790
|
graphApiVersion: ir.connection.graphApiVersion,
|
|
682
791
|
}), "utf8");
|
|
683
792
|
await writeFile(path.join(outDir, "Datasource", "CsvParser.cs"), await renderTemplate("dotnet/Generated/CsvParser.cs.ejs", {
|
|
684
793
|
namespaceName,
|
|
685
794
|
}), "utf8");
|
|
686
|
-
|
|
687
|
-
await writeFile(path.join(outDir, "Schema", "PropertyTransforms.cs"), await renderTemplate("dotnet/Generated/PropertyTransforms.cs.ejs", {
|
|
688
|
-
namespaceName,
|
|
689
|
-
properties: propertyTransforms,
|
|
690
|
-
}), "utf8");
|
|
691
|
-
}
|
|
692
|
-
await writeFile(path.join(outDir, "Schema", "FromCsvRow.cs"), await renderTemplate("dotnet/Generated/FromCsvRow.cs.ejs", {
|
|
795
|
+
await writeFile(path.join(outDir, schemaFolderName, "PropertyTransformBase.cs"), await renderTemplate("dotnet/Generated/PropertyTransformBase.cs.ejs", {
|
|
693
796
|
namespaceName,
|
|
694
|
-
|
|
797
|
+
schemaNamespace,
|
|
798
|
+
properties,
|
|
799
|
+
usesPersonEntity: properties.some((p) => p.personEntity),
|
|
695
800
|
}), "utf8");
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
801
|
+
const transformOverridesPath = path.join(outDir, schemaFolderName, "PropertyTransform.cs");
|
|
802
|
+
try {
|
|
803
|
+
await access(transformOverridesPath);
|
|
804
|
+
}
|
|
805
|
+
catch {
|
|
806
|
+
await writeFile(transformOverridesPath, await renderTemplate("dotnet/PropertyTransform.cs.ejs", {
|
|
807
|
+
schemaNamespace,
|
|
700
808
|
}), "utf8");
|
|
701
|
-
const overridesPath = path.join(outDir, "Schema", "PersonEntityOverrides.cs");
|
|
702
|
-
try {
|
|
703
|
-
await access(overridesPath);
|
|
704
|
-
}
|
|
705
|
-
catch {
|
|
706
|
-
await writeFile(overridesPath, await renderTemplate("dotnet/PersonEntityOverrides.cs.ejs", {
|
|
707
|
-
namespaceName,
|
|
708
|
-
names: personEntityDefaults.map((p) => p.name),
|
|
709
|
-
}), "utf8");
|
|
710
|
-
}
|
|
711
809
|
}
|
|
712
|
-
await writeFile(path.join(outDir,
|
|
810
|
+
await writeFile(path.join(outDir, schemaFolderName, "FromCsvRow.cs"), await renderTemplate("dotnet/Generated/FromCsvRow.cs.ejs", {
|
|
713
811
|
namespaceName,
|
|
812
|
+
schemaNamespace,
|
|
813
|
+
itemTypeName: ir.item.typeName,
|
|
814
|
+
constructorArgLines,
|
|
815
|
+
}), "utf8");
|
|
816
|
+
await writeFile(path.join(outDir, schemaFolderName, "ItemPayload.cs"), await renderTemplate("dotnet/Generated/ItemPayload.cs.ejs", {
|
|
817
|
+
schemaNamespace,
|
|
818
|
+
itemTypeName: ir.item.typeName,
|
|
714
819
|
itemIdExpression,
|
|
715
820
|
propertiesObjectLines,
|
|
716
821
|
contentBlock,
|
|
717
822
|
graphApiVersion: ir.connection.graphApiVersion,
|
|
718
823
|
}), "utf8");
|
|
824
|
+
await writeFile(path.join(outDir, "Core", "ConnectorCore.cs"), await renderTemplate("dotnet/Core/ConnectorCore.cs.ejs", {
|
|
825
|
+
namespaceName,
|
|
826
|
+
schemaNamespace,
|
|
827
|
+
itemTypeName: ir.item.typeName,
|
|
828
|
+
isPeopleConnector: ir.connection.contentCategory === "people",
|
|
829
|
+
graphApiVersion: ir.connection.graphApiVersion,
|
|
830
|
+
}), "utf8");
|
|
719
831
|
}
|
|
720
832
|
function formatValidationErrors(ir) {
|
|
721
833
|
const issues = validateIr(ir);
|
|
@@ -741,7 +853,8 @@ export async function updateTsProject(options) {
|
|
|
741
853
|
if (validationMessage) {
|
|
742
854
|
throw new Error(`Schema validation failed:\n${validationMessage}`);
|
|
743
855
|
}
|
|
744
|
-
|
|
856
|
+
const schemaFolderName = toTsSchemaFolderName(ir.connection.connectionName);
|
|
857
|
+
await writeGeneratedTs(outDir, ir, schemaFolderName);
|
|
745
858
|
if (options.tspPath) {
|
|
746
859
|
await writeFile(path.join(outDir, COCOGEN_CONFIG_FILE), projectConfigContents(outDir, tspPath, "ts"), "utf8");
|
|
747
860
|
}
|
|
@@ -763,7 +876,9 @@ export async function updateDotnetProject(options) {
|
|
|
763
876
|
throw new Error(`Schema validation failed:\n${validationMessage}`);
|
|
764
877
|
}
|
|
765
878
|
const namespaceName = toCsNamespace(path.basename(outDir));
|
|
766
|
-
|
|
879
|
+
const schemaFolderName = toSchemaFolderName(ir.connection.connectionName);
|
|
880
|
+
const schemaNamespace = `${namespaceName}.${schemaFolderName}`;
|
|
881
|
+
await writeGeneratedDotnet(outDir, ir, namespaceName, schemaFolderName, schemaNamespace);
|
|
767
882
|
if (options.tspPath) {
|
|
768
883
|
await writeFile(path.join(outDir, COCOGEN_CONFIG_FILE), projectConfigContents(outDir, tspPath, "dotnet"), "utf8");
|
|
769
884
|
}
|
|
@@ -789,9 +904,10 @@ export async function initTsProject(options) {
|
|
|
789
904
|
throw new Error(`Schema validation failed:\n${validationMessage}`);
|
|
790
905
|
}
|
|
791
906
|
const projectName = options.projectName ?? path.basename(outDir);
|
|
907
|
+
const schemaFolderName = toTsSchemaFolderName(ir.connection.connectionName);
|
|
792
908
|
await mkdir(path.join(outDir, "src"), { recursive: true });
|
|
793
909
|
await mkdir(path.join(outDir, "src", "datasource"), { recursive: true });
|
|
794
|
-
await mkdir(path.join(outDir, "src",
|
|
910
|
+
await mkdir(path.join(outDir, "src", schemaFolderName), { recursive: true });
|
|
795
911
|
await writeFile(path.join(outDir, "package.json"), await renderTemplate("ts/package.json.ejs", {
|
|
796
912
|
projectName,
|
|
797
913
|
isPeopleConnector: ir.connection.contentCategory === "people",
|
|
@@ -801,13 +917,18 @@ export async function initTsProject(options) {
|
|
|
801
917
|
await writeFile(path.join(outDir, ".env.example"), await renderTemplate("ts/.env.example.ejs", {
|
|
802
918
|
itemTypeName: ir.item.typeName,
|
|
803
919
|
isPeopleConnector: ir.connection.contentCategory === "people",
|
|
920
|
+
connectionName: ir.connection.connectionName ?? null,
|
|
804
921
|
connectionId: ir.connection.connectionId ?? null,
|
|
805
922
|
connectionDescription: ir.connection.connectionDescription ?? null,
|
|
806
923
|
profileSourceWebUrl: ir.connection.profileSource?.webUrl ?? null,
|
|
807
924
|
profileSourceDisplayName: ir.connection.profileSource?.displayName ?? null,
|
|
808
925
|
profileSourcePriority: ir.connection.profileSource?.priority ?? null,
|
|
809
926
|
}), "utf8");
|
|
810
|
-
await writeFile(path.join(outDir, "README.md"), await renderTemplate("ts/README.md.ejs", {
|
|
927
|
+
await writeFile(path.join(outDir, "README.md"), await renderTemplate("ts/README.md.ejs", {
|
|
928
|
+
isPeopleConnector: ir.connection.contentCategory === "people",
|
|
929
|
+
itemTypeName: ir.item.typeName,
|
|
930
|
+
schemaFolderName,
|
|
931
|
+
}), "utf8");
|
|
811
932
|
const copiedTspPath = path.join(outDir, "schema.tsp");
|
|
812
933
|
await copyFile(path.resolve(options.tspPath), copiedTspPath);
|
|
813
934
|
await writeFile(path.join(outDir, COCOGEN_CONFIG_FILE), projectConfigContents(outDir, copiedTspPath, "ts"), "utf8");
|
|
@@ -828,12 +949,20 @@ export async function initTsProject(options) {
|
|
|
828
949
|
await writeFile(path.join(outDir, "src", "cli.ts"), await renderTemplate("ts/src/cli.ts.ejs", {
|
|
829
950
|
graphBaseUrl: graphBaseUrl(ir),
|
|
830
951
|
isPeopleConnector: ir.connection.contentCategory === "people",
|
|
952
|
+
itemTypeName: ir.item.typeName,
|
|
953
|
+
schemaFolderName,
|
|
954
|
+
}), "utf8");
|
|
955
|
+
await writeFile(path.join(outDir, "src", "datasource", "itemSource.ts"), await renderTemplate("ts/src/datasource/itemSource.ts.ejs", {
|
|
956
|
+
itemTypeName: ir.item.typeName,
|
|
957
|
+
schemaFolderName,
|
|
958
|
+
}), "utf8");
|
|
959
|
+
await writeFile(path.join(outDir, "src", "datasource", "csvItemSource.ts"), await renderTemplate("ts/src/datasource/csvItemSource.ts.ejs", {
|
|
960
|
+
itemTypeName: ir.item.typeName,
|
|
961
|
+
schemaFolderName,
|
|
831
962
|
}), "utf8");
|
|
832
|
-
await writeFile(path.join(outDir, "src", "datasource", "itemSource.ts"), await renderTemplate("ts/src/datasource/itemSource.ts.ejs", {}), "utf8");
|
|
833
|
-
await writeFile(path.join(outDir, "src", "datasource", "csvItemSource.ts"), await renderTemplate("ts/src/datasource/csvItemSource.ts.ejs", {}), "utf8");
|
|
834
963
|
await writeFile(path.join(outDir, "data.csv"), buildSampleCsv(ir), "utf8");
|
|
835
|
-
await writeGeneratedTs(outDir, ir);
|
|
836
|
-
await writeFile(path.join(outDir, "src", "index.ts"), await renderTemplate("ts/src/index.ts.ejs", {}), "utf8");
|
|
964
|
+
await writeGeneratedTs(outDir, ir, schemaFolderName);
|
|
965
|
+
await writeFile(path.join(outDir, "src", "index.ts"), await renderTemplate("ts/src/index.ts.ejs", { schemaFolderName }), "utf8");
|
|
837
966
|
return { outDir, ir };
|
|
838
967
|
}
|
|
839
968
|
export async function initDotnetProject(options) {
|
|
@@ -849,8 +978,10 @@ export async function initDotnetProject(options) {
|
|
|
849
978
|
}
|
|
850
979
|
const projectName = options.projectName ?? path.basename(outDir);
|
|
851
980
|
const namespaceName = toCsNamespace(projectName);
|
|
981
|
+
const schemaFolderName = toSchemaFolderName(ir.connection.connectionName);
|
|
982
|
+
const schemaNamespace = `${namespaceName}.${schemaFolderName}`;
|
|
852
983
|
await mkdir(path.join(outDir, "Datasource"), { recursive: true });
|
|
853
|
-
await mkdir(path.join(outDir,
|
|
984
|
+
await mkdir(path.join(outDir, schemaFolderName), { recursive: true });
|
|
854
985
|
await writeFile(path.join(outDir, `${projectName}.csproj`), await renderTemplate("dotnet/project.csproj.ejs", {
|
|
855
986
|
graphApiVersion: ir.connection.graphApiVersion,
|
|
856
987
|
}), "utf8");
|
|
@@ -860,15 +991,26 @@ export async function initDotnetProject(options) {
|
|
|
860
991
|
await writeFile(path.join(outDir, "tspconfig.yaml"), await renderTemplate("dotnet/tspconfig.yaml.ejs", {}), "utf8");
|
|
861
992
|
await writeFile(path.join(outDir, "Program.cs"), await renderTemplate("dotnet/Program.commandline.cs.ejs", {
|
|
862
993
|
namespaceName,
|
|
994
|
+
schemaNamespace,
|
|
995
|
+
itemTypeName: ir.item.typeName,
|
|
863
996
|
isPeopleConnector: ir.connection.contentCategory === "people",
|
|
864
997
|
graphApiVersion: ir.connection.graphApiVersion,
|
|
865
998
|
}), "utf8");
|
|
866
|
-
await writeFile(path.join(outDir, "Datasource", "IItemSource.cs"), await renderTemplate("dotnet/Datasource/IItemSource.cs.ejs", {
|
|
867
|
-
|
|
999
|
+
await writeFile(path.join(outDir, "Datasource", "IItemSource.cs"), await renderTemplate("dotnet/Datasource/IItemSource.cs.ejs", {
|
|
1000
|
+
namespaceName,
|
|
1001
|
+
schemaNamespace,
|
|
1002
|
+
itemTypeName: ir.item.typeName,
|
|
1003
|
+
}), "utf8");
|
|
1004
|
+
await writeFile(path.join(outDir, "Datasource", "CsvItemSource.cs"), await renderTemplate("dotnet/Datasource/CsvItemSource.cs.ejs", {
|
|
1005
|
+
namespaceName,
|
|
1006
|
+
schemaNamespace,
|
|
1007
|
+
itemTypeName: ir.item.typeName,
|
|
1008
|
+
}), "utf8");
|
|
868
1009
|
await writeFile(path.join(outDir, "data.csv"), buildSampleCsv(ir), "utf8");
|
|
869
1010
|
await writeFile(path.join(outDir, "appsettings.json"), await renderTemplate("dotnet/appsettings.json.ejs", {
|
|
870
1011
|
itemTypeName: ir.item.typeName,
|
|
871
1012
|
isPeopleConnector: ir.connection.contentCategory === "people",
|
|
1013
|
+
connectionName: ir.connection.connectionName ?? null,
|
|
872
1014
|
connectionId: ir.connection.connectionId ?? null,
|
|
873
1015
|
connectionDescription: ir.connection.connectionDescription ?? null,
|
|
874
1016
|
profileSourceWebUrl: ir.connection.profileSource?.webUrl ?? null,
|
|
@@ -876,11 +1018,15 @@ export async function initDotnetProject(options) {
|
|
|
876
1018
|
profileSourcePriority: ir.connection.profileSource?.priority ?? null,
|
|
877
1019
|
}), "utf8");
|
|
878
1020
|
await writeFile(path.join(outDir, ".gitignore"), await renderTemplate("dotnet/.gitignore.ejs", {}), "utf8");
|
|
879
|
-
await writeFile(path.join(outDir, "README.md"), await renderTemplate("dotnet/README.md.ejs", {
|
|
1021
|
+
await writeFile(path.join(outDir, "README.md"), await renderTemplate("dotnet/README.md.ejs", {
|
|
1022
|
+
isPeopleConnector: ir.connection.contentCategory === "people",
|
|
1023
|
+
itemTypeName: ir.item.typeName,
|
|
1024
|
+
schemaFolderName,
|
|
1025
|
+
}), "utf8");
|
|
880
1026
|
const copiedTspPath = path.join(outDir, "schema.tsp");
|
|
881
1027
|
await copyFile(path.resolve(options.tspPath), copiedTspPath);
|
|
882
1028
|
await writeFile(path.join(outDir, COCOGEN_CONFIG_FILE), projectConfigContents(outDir, copiedTspPath, "dotnet"), "utf8");
|
|
883
|
-
await writeGeneratedDotnet(outDir, ir, namespaceName);
|
|
1029
|
+
await writeGeneratedDotnet(outDir, ir, namespaceName, schemaFolderName, schemaNamespace);
|
|
884
1030
|
return { outDir, ir };
|
|
885
1031
|
}
|
|
886
1032
|
//# sourceMappingURL=init.js.map
|