@ingestron/cli 0.0.0-stage → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/NOTICE +4 -0
- package/README.md +43 -2
- package/dist/args.d.ts +105 -0
- package/dist/args.d.ts.map +1 -0
- package/dist/args.js +161 -0
- package/dist/args.js.map +1 -0
- package/dist/ask.d.ts +5 -0
- package/dist/ask.d.ts.map +1 -0
- package/dist/ask.js +17 -0
- package/dist/ask.js.map +1 -0
- package/dist/compare.d.ts +13 -0
- package/dist/compare.d.ts.map +1 -0
- package/dist/compare.js +92 -0
- package/dist/compare.js.map +1 -0
- package/dist/environments.d.ts +6 -0
- package/dist/environments.d.ts.map +1 -0
- package/dist/environments.js +25 -0
- package/dist/environments.js.map +1 -0
- package/dist/generate.d.ts +16 -0
- package/dist/generate.d.ts.map +1 -0
- package/dist/generate.js +118 -0
- package/dist/generate.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +46 -0
- package/dist/index.js.map +1 -0
- package/dist/init-choice.d.ts +10 -0
- package/dist/init-choice.d.ts.map +1 -0
- package/dist/init-choice.js +36 -0
- package/dist/init-choice.js.map +1 -0
- package/dist/init-preflight.d.ts +4 -0
- package/dist/init-preflight.d.ts.map +1 -0
- package/dist/init-preflight.js +18 -0
- package/dist/init-preflight.js.map +1 -0
- package/dist/init.d.ts +5 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +136 -0
- package/dist/init.js.map +1 -0
- package/dist/io.d.ts +8 -0
- package/dist/io.d.ts.map +1 -0
- package/dist/io.js +3 -0
- package/dist/io.js.map +1 -0
- package/dist/main.d.ts +3 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +11 -0
- package/dist/main.js.map +1 -0
- package/dist/outputs.d.ts +12 -0
- package/dist/outputs.d.ts.map +1 -0
- package/dist/outputs.js +53 -0
- package/dist/outputs.js.map +1 -0
- package/dist/packs.d.ts +4 -0
- package/dist/packs.d.ts.map +1 -0
- package/dist/packs.js +5 -0
- package/dist/packs.js.map +1 -0
- package/dist/project-choices.d.ts +27 -0
- package/dist/project-choices.d.ts.map +1 -0
- package/dist/project-choices.js +44 -0
- package/dist/project-choices.js.map +1 -0
- package/dist/project-questions.d.ts +5 -0
- package/dist/project-questions.d.ts.map +1 -0
- package/dist/project-questions.js +43 -0
- package/dist/project-questions.js.map +1 -0
- package/dist/project-recipes.d.ts +14 -0
- package/dist/project-recipes.d.ts.map +1 -0
- package/dist/project-recipes.js +115 -0
- package/dist/project-recipes.js.map +1 -0
- package/dist/request.d.ts +13 -0
- package/dist/request.d.ts.map +1 -0
- package/dist/request.js +114 -0
- package/dist/request.js.map +1 -0
- package/dist/sample-contract.d.ts +11 -0
- package/dist/sample-contract.d.ts.map +1 -0
- package/dist/sample-contract.js +91 -0
- package/dist/sample-contract.js.map +1 -0
- package/dist/sample-read.d.ts +8 -0
- package/dist/sample-read.d.ts.map +1 -0
- package/dist/sample-read.js +89 -0
- package/dist/sample-read.js.map +1 -0
- package/dist/samples.d.ts +33 -0
- package/dist/samples.d.ts.map +1 -0
- package/dist/samples.js +108 -0
- package/dist/samples.js.map +1 -0
- package/dist/scaffold.d.ts +34 -0
- package/dist/scaffold.d.ts.map +1 -0
- package/dist/scaffold.js +106 -0
- package/dist/scaffold.js.map +1 -0
- package/dist/schemas.d.ts +5 -0
- package/dist/schemas.d.ts.map +1 -0
- package/dist/schemas.js +39 -0
- package/dist/schemas.js.map +1 -0
- package/dist/sources.d.ts +17 -0
- package/dist/sources.d.ts.map +1 -0
- package/dist/sources.js +103 -0
- package/dist/sources.js.map +1 -0
- package/dist/templates.d.ts +64 -0
- package/dist/templates.d.ts.map +1 -0
- package/dist/templates.js +88 -0
- package/dist/templates.js.map +1 -0
- package/package.json +68 -3
- package/project-templates/kafka/README.md +12 -0
- package/project-templates/kafka/connections/events.yaml +8 -0
- package/project-templates/kafka/contracts/page_views.yaml +13 -0
- package/project-templates/kafka/contracts/purchases.yaml +13 -0
- package/project-templates/kafka/flows/events.yaml +10 -0
- package/project-templates/kafka/project.yaml +10 -0
- package/project-templates/kafka/standard.yaml +4 -0
- package/project-templates/kafka/template.yaml +3 -0
- package/project-templates/minimal/README.md +10 -0
- package/project-templates/minimal/connections/shop.yaml +7 -0
- package/project-templates/minimal/contracts/orders.yaml +14 -0
- package/project-templates/minimal/flows/orders.yaml +6 -0
- package/project-templates/minimal/project.yaml +11 -0
- package/project-templates/minimal/standard.yaml +4 -0
- package/project-templates/minimal/template.yaml +7 -0
- package/project-templates/private-files/README.md +29 -0
- package/project-templates/private-files/connections/share.yaml +10 -0
- package/project-templates/private-files/contracts/sales.yaml +14 -0
- package/project-templates/private-files/contracts/stock.yaml +14 -0
- package/project-templates/private-files/flows/stores.yaml +9 -0
- package/project-templates/private-files/platform.yaml +11 -0
- package/project-templates/private-files/project.yaml +19 -0
- package/project-templates/private-files/standard.yaml +11 -0
- package/project-templates/private-files/template.yaml +10 -0
- package/project-templates/private-sql-server/README.md +25 -0
- package/project-templates/private-sql-server/connections/erp.yaml +10 -0
- package/project-templates/private-sql-server/contracts/customers.yaml +14 -0
- package/project-templates/private-sql-server/contracts/invoices.yaml +15 -0
- package/project-templates/private-sql-server/flows/erp.yaml +13 -0
- package/project-templates/private-sql-server/platform.yaml +11 -0
- package/project-templates/private-sql-server/project.yaml +19 -0
- package/project-templates/private-sql-server/standard.yaml +17 -0
- package/project-templates/private-sql-server/template.yaml +10 -0
- package/project-templates/pyspark/README.md +12 -0
- package/project-templates/pyspark/connections/billing.yaml +7 -0
- package/project-templates/pyspark/contracts/invoices.yaml +16 -0
- package/project-templates/pyspark/contracts/monthly_revenue.yaml +14 -0
- package/project-templates/pyspark/flows/billing.yaml +6 -0
- package/project-templates/pyspark/project.yaml +11 -0
- package/project-templates/pyspark/standard.yaml +4 -0
- package/project-templates/pyspark/template.yaml +3 -0
- package/project-templates/pyspark/transforms/monthly_revenue.py +10 -0
- package/project-templates/pyspark/transforms/monthly_revenue.yaml +10 -0
- package/project-templates/retail/README.md +22 -0
- package/project-templates/retail/connections/shop.yaml +8 -0
- package/project-templates/retail/contracts/customers.yaml +12 -0
- package/project-templates/retail/contracts/daily_sales.yaml +19 -0
- package/project-templates/retail/contracts/orders.yaml +16 -0
- package/project-templates/retail/flows/shop.yaml +18 -0
- package/project-templates/retail/platform.yaml +21 -0
- package/project-templates/retail/project.yaml +18 -0
- package/project-templates/retail/standard.yaml +15 -0
- package/project-templates/retail/template.yaml +10 -0
- package/project-templates/retail/transforms/daily_sales.sql +7 -0
- package/project-templates/retail/transforms/daily_sales.yaml +7 -0
- package/project-templates/salesforce/README.md +6 -0
- package/project-templates/salesforce/connections/salesforce.yaml +7 -0
- package/project-templates/salesforce/contracts/accounts.yaml +13 -0
- package/project-templates/salesforce/contracts/opportunities.yaml +14 -0
- package/project-templates/salesforce/flows/salesforce.yaml +7 -0
- package/project-templates/salesforce/project.yaml +9 -0
- package/project-templates/salesforce/standard.yaml +4 -0
- package/project-templates/salesforce/template.yaml +3 -0
- package/project-templates/sql-server/README.md +17 -0
- package/project-templates/sql-server/connections/erp.yaml +8 -0
- package/project-templates/sql-server/contracts/customer_balances.yaml +13 -0
- package/project-templates/sql-server/contracts/customers.yaml +13 -0
- package/project-templates/sql-server/contracts/invoices.yaml +14 -0
- package/project-templates/sql-server/flows/erp.yaml +13 -0
- package/project-templates/sql-server/platform.yaml +6 -0
- package/project-templates/sql-server/project.yaml +13 -0
- package/project-templates/sql-server/standard.yaml +9 -0
- package/project-templates/sql-server/template.yaml +3 -0
- package/project-templates/sql-server/transforms/customer_balances.sql +5 -0
- package/project-templates/sql-server/transforms/customer_balances.yaml +6 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// ingestron contract <sample>: a draft ODCS contract from a sample file, with
|
|
2
|
+
// each column's name and inferred logical type and no sample values. Keys,
|
|
3
|
+
// required columns and descriptions are left to the person reviewing it.
|
|
4
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { basename, dirname, join, relative, resolve } from "node:path";
|
|
6
|
+
import { stringify } from "yaml";
|
|
7
|
+
import { readSample } from "./sample-read.js";
|
|
8
|
+
/** Writes contracts/<name>.yaml from the sample. Returns the exit code. */
|
|
9
|
+
export function draftContract(options, io) {
|
|
10
|
+
const sample = resolve(io.cwd, options.sample ?? "");
|
|
11
|
+
if (!options.sample || !existsSync(sample)) {
|
|
12
|
+
io.write(`contract needs a sample file: ingestron contract <file.csv|file.json>\n`);
|
|
13
|
+
return 2;
|
|
14
|
+
}
|
|
15
|
+
const name = options.init.name ?? objectName(sample);
|
|
16
|
+
const target = join(resolve(io.cwd, options.definitions), "contracts", `${name}.yaml`);
|
|
17
|
+
const shown = relative(io.cwd, target);
|
|
18
|
+
if (existsSync(target)) {
|
|
19
|
+
io.write(`${shown} already exists; nothing written.\n`);
|
|
20
|
+
return 1;
|
|
21
|
+
}
|
|
22
|
+
mkdirSync(dirname(target), { recursive: true });
|
|
23
|
+
writeFileSync(target, contractFromSample(readFileSync(sample, "utf8"), basename(sample), name));
|
|
24
|
+
io.write(`Wrote ${shown}. Review the types, then add keys, required columns and descriptions.\n`);
|
|
25
|
+
return 0;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The contract text for a sample's columns, with the object named after the file.
|
|
29
|
+
* @example
|
|
30
|
+
* contractFromSample("id,name\n1,a\n", "customers.csv", "shop.customers");
|
|
31
|
+
*/
|
|
32
|
+
export function contractFromSample(text, file, id) {
|
|
33
|
+
const { columns, rows } = readSample(text, file);
|
|
34
|
+
const properties = columns.map((column) => ` - { name: ${scalar(column)}, logicalType: ${typeOf(rows.map((row) => row[column]))} }`);
|
|
35
|
+
return [
|
|
36
|
+
`# Drafted from ${file} (${rows.length} ${rows.length === 1 ? "row" : "rows"}): names and types only. Review the`,
|
|
37
|
+
"# types, then add primaryKey, required and descriptions before use.",
|
|
38
|
+
"apiVersion: v3.1.0",
|
|
39
|
+
"kind: DataContract",
|
|
40
|
+
`id: ${scalar(id)}`,
|
|
41
|
+
"version: 0.1.0",
|
|
42
|
+
"status: draft",
|
|
43
|
+
"schema:",
|
|
44
|
+
` - name: ${scalar(objectName(file))}`,
|
|
45
|
+
" logicalType: object",
|
|
46
|
+
" properties:",
|
|
47
|
+
...properties,
|
|
48
|
+
"",
|
|
49
|
+
].join("\n");
|
|
50
|
+
}
|
|
51
|
+
/** `Daily Sales.csv` → `daily_sales`. */
|
|
52
|
+
function objectName(file) {
|
|
53
|
+
return basename(file)
|
|
54
|
+
.replace(/\.[^.]+$/, "")
|
|
55
|
+
.toLowerCase()
|
|
56
|
+
.replace(/[^a-z0-9]+/g, "_")
|
|
57
|
+
.replace(/^_|_$/g, "");
|
|
58
|
+
}
|
|
59
|
+
function scalar(text) {
|
|
60
|
+
return stringify(text).trimEnd();
|
|
61
|
+
}
|
|
62
|
+
const patterns = [
|
|
63
|
+
["integer", /^-?\d+$/],
|
|
64
|
+
["number", /^-?\d+(\.\d+)?([eE][-+]?\d+)?$/],
|
|
65
|
+
["boolean", /^(true|false)$/i],
|
|
66
|
+
["date", /^\d{4}-\d{2}-\d{2}$/],
|
|
67
|
+
["timestamp", /^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}(:\d{2}(\.\d+)?)?(Z|[+-]\d{2}:?\d{2})?$/],
|
|
68
|
+
];
|
|
69
|
+
/** The narrowest logical type every non-empty value fits; integers widen to number. */
|
|
70
|
+
function typeOf(values) {
|
|
71
|
+
const types = new Set(values.filter((value) => value !== "" && value != null).map(typeOfValue));
|
|
72
|
+
if (types.size === 1)
|
|
73
|
+
return [...types][0];
|
|
74
|
+
return types.size === 2 && types.has("integer") && types.has("number") ? "number" : "string";
|
|
75
|
+
}
|
|
76
|
+
function typeOfValue(value) {
|
|
77
|
+
if (typeof value === "number")
|
|
78
|
+
return Number.isInteger(value) ? "integer" : "number";
|
|
79
|
+
if (typeof value === "boolean")
|
|
80
|
+
return "boolean";
|
|
81
|
+
if (Array.isArray(value))
|
|
82
|
+
return "array";
|
|
83
|
+
if (typeof value === "object")
|
|
84
|
+
return "object";
|
|
85
|
+
const text = String(value);
|
|
86
|
+
// A code such as 00123 is an identifier: as a number it would lose its zeros.
|
|
87
|
+
if (/^-?0\d/.test(text))
|
|
88
|
+
return "string";
|
|
89
|
+
return patterns.find(([, pattern]) => pattern.test(text))?.[0] ?? "string";
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=sample-contract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sample-contract.js","sourceRoot":"","sources":["../src/sample-contract.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,2EAA2E;AAC3E,yEAAyE;AACzE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACvE,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAGjC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,2EAA2E;AAC3E,MAAM,UAAU,aAAa,CAAC,OAAgB,EAAE,EAAM;IACpD,MAAM,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;IACrD,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3C,EAAE,CAAC,KAAK,CAAC,yEAAyE,CAAC,CAAC;QACpF,OAAO,CAAC,CAAC;IACX,CAAC;IACD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;IACrD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,CAAC,WAAW,CAAC,EAAE,WAAW,EAAE,GAAG,IAAI,OAAO,CAAC,CAAC;IACvF,MAAM,KAAK,GAAG,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACvC,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACvB,EAAE,CAAC,KAAK,CAAC,GAAG,KAAK,qCAAqC,CAAC,CAAC;QACxD,OAAO,CAAC,CAAC;IACX,CAAC;IACD,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,aAAa,CAAC,MAAM,EAAE,kBAAkB,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;IAChG,EAAE,CAAC,KAAK,CAAC,SAAS,KAAK,yEAAyE,CAAC,CAAC;IAClG,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY,EAAE,IAAY,EAAE,EAAU;IACvE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACjD,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAC5B,CAAC,MAAM,EAAE,EAAE,CACT,mBAAmB,MAAM,CAAC,MAAM,CAAC,kBAAkB,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAChG,CAAC;IACF,OAAO;QACL,kBAAkB,IAAI,KAAK,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,qCAAqC;QACjH,qEAAqE;QACrE,oBAAoB;QACpB,oBAAoB;QACpB,OAAO,MAAM,CAAC,EAAE,CAAC,EAAE;QACnB,gBAAgB;QAChB,eAAe;QACf,SAAS;QACT,aAAa,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE;QACvC,yBAAyB;QACzB,iBAAiB;QACjB,GAAG,UAAU;QACb,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,yCAAyC;AACzC,SAAS,UAAU,CAAC,IAAY;IAC9B,OAAO,QAAQ,CAAC,IAAI,CAAC;SAClB,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;SACvB,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AAC3B,CAAC;AAED,SAAS,MAAM,CAAC,IAAY;IAC1B,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;AACnC,CAAC;AAED,MAAM,QAAQ,GAAuB;IACnC,CAAC,SAAS,EAAE,SAAS,CAAC;IACtB,CAAC,QAAQ,EAAE,gCAAgC,CAAC;IAC5C,CAAC,SAAS,EAAE,iBAAiB,CAAC;IAC9B,CAAC,MAAM,EAAE,qBAAqB,CAAC;IAC/B,CAAC,WAAW,EAAE,0EAA0E,CAAC;CAC1F,CAAC;AAEF,uFAAuF;AACvF,SAAS,MAAM,CAAC,MAAiB;IAC/B,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,EAAE,IAAI,KAAK,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC;IAChG,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAE,CAAC;IAC5C,OAAO,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC/F,CAAC;AAED,SAAS,WAAW,CAAC,KAAc;IACjC,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC;IACrF,IAAI,OAAO,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACjD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,OAAO,CAAC;IACzC,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC/C,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC3B,8EAA8E;IAC9E,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,QAAQ,CAAC;IACzC,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC;AAC7E,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** The column names in order, and each row's values by name. */
|
|
2
|
+
export interface Sample {
|
|
3
|
+
columns: string[];
|
|
4
|
+
rows: Record<string, unknown>[];
|
|
5
|
+
}
|
|
6
|
+
/** Reads `text` as CSV, or as JSON when the file name ends in .json, .jsonl or .ndjson. */
|
|
7
|
+
export declare function readSample(text: string, file: string, limit?: number): Sample;
|
|
8
|
+
//# sourceMappingURL=sample-read.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sample-read.d.ts","sourceRoot":"","sources":["../src/sample-read.ts"],"names":[],"mappings":"AAGA,gEAAgE;AAChE,MAAM,WAAW,MAAM;IACrB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;CACjC;AAED,2FAA2F;AAC3F,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,SAAO,GAAG,MAAM,CAE3E"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// Rows of a sample file: CSV (comma, semicolon or tab, with quotes) or JSON
|
|
2
|
+
// (an array of objects, or one object per line). At most `limit` rows.
|
|
3
|
+
/** Reads `text` as CSV, or as JSON when the file name ends in .json, .jsonl or .ndjson. */
|
|
4
|
+
export function readSample(text, file, limit = 1000) {
|
|
5
|
+
return /\.(json|jsonl|ndjson)$/i.test(file) ? jsonSample(text, limit) : csvSample(text, limit);
|
|
6
|
+
}
|
|
7
|
+
function jsonSample(text, limit) {
|
|
8
|
+
const trimmed = text.trim();
|
|
9
|
+
const items = trimmed.startsWith("[")
|
|
10
|
+
? JSON.parse(trimmed)
|
|
11
|
+
: trimmed
|
|
12
|
+
.split(/\r?\n/)
|
|
13
|
+
.filter(Boolean)
|
|
14
|
+
.slice(0, limit)
|
|
15
|
+
.map((line) => JSON.parse(line));
|
|
16
|
+
const rows = items
|
|
17
|
+
.slice(0, limit)
|
|
18
|
+
.filter((item) => typeof item === "object" && item !== null);
|
|
19
|
+
const columns = [...new Set(rows.flatMap((row) => Object.keys(row)))];
|
|
20
|
+
return { columns, rows };
|
|
21
|
+
}
|
|
22
|
+
function csvSample(text, limit) {
|
|
23
|
+
const firstLine = text.slice(0, text.search(/\r?\n|$/));
|
|
24
|
+
const delimiter = [",", ";", "\t"].reduce((best, candidate) => firstLine.split(candidate).length > firstLine.split(best).length ? candidate : best);
|
|
25
|
+
const [header = [], ...records] = csvRecords(text, delimiter, limit + 1);
|
|
26
|
+
const rows = records
|
|
27
|
+
.filter((record) => record.some((value) => value !== ""))
|
|
28
|
+
.map((record) => Object.fromEntries(header.map((name, index) => [name, record[index] ?? ""])));
|
|
29
|
+
return { columns: header, rows };
|
|
30
|
+
}
|
|
31
|
+
/** RFC 4180 records: quoted fields may hold the delimiter, line breaks and "" for a quote. */
|
|
32
|
+
function csvRecords(text, delimiter, limit) {
|
|
33
|
+
const reader = new CsvReader(delimiter);
|
|
34
|
+
for (let at = 0; at < text.length && reader.records.length < limit; at += 1)
|
|
35
|
+
at += reader.read(text[at], text[at + 1]);
|
|
36
|
+
reader.end(limit);
|
|
37
|
+
return reader.records;
|
|
38
|
+
}
|
|
39
|
+
/** Reads one character at a time; `read` returns how many extra characters it used. */
|
|
40
|
+
class CsvReader {
|
|
41
|
+
delimiter;
|
|
42
|
+
records = [];
|
|
43
|
+
record = [];
|
|
44
|
+
field = "";
|
|
45
|
+
quoted = false;
|
|
46
|
+
constructor(delimiter) {
|
|
47
|
+
this.delimiter = delimiter;
|
|
48
|
+
}
|
|
49
|
+
read(char, next) {
|
|
50
|
+
if (this.quoted)
|
|
51
|
+
return this.inQuotes(char, next);
|
|
52
|
+
if (char === '"')
|
|
53
|
+
this.quoted = true;
|
|
54
|
+
else if (char === this.delimiter)
|
|
55
|
+
this.endField();
|
|
56
|
+
else if (char === "\n" || char === "\r")
|
|
57
|
+
return this.endRecord(char, next);
|
|
58
|
+
else
|
|
59
|
+
this.field += char;
|
|
60
|
+
return 0;
|
|
61
|
+
}
|
|
62
|
+
/** The last record, when the text does not end with a line break. */
|
|
63
|
+
end(limit) {
|
|
64
|
+
if ((this.field !== "" || this.record.length > 0) && this.records.length < limit)
|
|
65
|
+
this.endRecord("\n", undefined);
|
|
66
|
+
}
|
|
67
|
+
inQuotes(char, next) {
|
|
68
|
+
if (char === '"' && next === '"') {
|
|
69
|
+
this.field += '"';
|
|
70
|
+
return 1;
|
|
71
|
+
}
|
|
72
|
+
if (char === '"')
|
|
73
|
+
this.quoted = false;
|
|
74
|
+
else
|
|
75
|
+
this.field += char;
|
|
76
|
+
return 0;
|
|
77
|
+
}
|
|
78
|
+
endField() {
|
|
79
|
+
this.record.push(this.field);
|
|
80
|
+
this.field = "";
|
|
81
|
+
}
|
|
82
|
+
endRecord(char, next) {
|
|
83
|
+
this.endField();
|
|
84
|
+
this.records.push(this.record);
|
|
85
|
+
this.record = [];
|
|
86
|
+
return char === "\r" && next === "\n" ? 1 : 0;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=sample-read.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sample-read.js","sourceRoot":"","sources":["../src/sample-read.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** One sample: where it is, what kind, and how it is listed. */
|
|
2
|
+
export interface Sample {
|
|
3
|
+
name: string;
|
|
4
|
+
kind: "starter" | "guide";
|
|
5
|
+
folder: string;
|
|
6
|
+
title: string;
|
|
7
|
+
summary: string;
|
|
8
|
+
}
|
|
9
|
+
/** What a sample's project uses, across its environments. */
|
|
10
|
+
export interface SampleFacts {
|
|
11
|
+
packs: string[];
|
|
12
|
+
connectors: string[];
|
|
13
|
+
connectivity: string[];
|
|
14
|
+
methods: string[];
|
|
15
|
+
environments: string[];
|
|
16
|
+
/** Such as "quality checks", "transforms", "change data" or "several packs". */
|
|
17
|
+
features: string[];
|
|
18
|
+
}
|
|
19
|
+
/** The starters' folder: `project-templates/` beside `dist/`, in the repository and installed. */
|
|
20
|
+
export declare const templatesFolder: string;
|
|
21
|
+
/**
|
|
22
|
+
* The samples in `folder`: starters, smallest first, or guides in their order.
|
|
23
|
+
* @example listSamples().map((sample) => sample.name) // ["minimal", …]
|
|
24
|
+
*/
|
|
25
|
+
export declare function listSamples(folder?: string, kind?: Sample["kind"]): Sample[];
|
|
26
|
+
/** The packs, connectors, connectivity, methods, environments and features a sample uses. */
|
|
27
|
+
export declare function sampleFacts(folder: string): SampleFacts;
|
|
28
|
+
/**
|
|
29
|
+
* One sample folder, listed from its `template.yaml` (starter) or `sample.yaml` (guide).
|
|
30
|
+
* @example readSample(folder, "guide").title
|
|
31
|
+
*/
|
|
32
|
+
export declare function readSample(folder: string, kind: Sample["kind"]): Sample;
|
|
33
|
+
//# sourceMappingURL=samples.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"samples.d.ts","sourceRoot":"","sources":["../src/samples.ts"],"names":[],"mappings":"AAYA,gEAAgE;AAChE,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,6DAA6D;AAC7D,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,gFAAgF;IAChF,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAID,kGAAkG;AAClG,eAAO,MAAM,eAAe,QAAyC,CAAC;AAEtE;;;GAGG;AACH,wBAAgB,WAAW,CAAC,MAAM,SAAkB,EAAE,IAAI,GAAE,MAAM,CAAC,MAAM,CAAa,GAAG,MAAM,EAAE,CAOhG;AAED,6FAA6F;AAC7F,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,CA+BvD;AAkCD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,CAWvE"}
|
package/dist/samples.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// The samples users read and start from. Starters are complete projects that
|
|
2
|
+
// `ingestron init` and VS Code create a project from (each has template.yaml),
|
|
3
|
+
// in this package's project-templates/. Guides are small projects that each
|
|
4
|
+
// show one idea (each has sample.yaml); the documentation keeps its own and
|
|
5
|
+
// lists them with the same functions. What a sample uses is found by resolving it.
|
|
6
|
+
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
7
|
+
import { dirname, join } from "node:path";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
import { loadDefinitions } from "@ingestron/definitions";
|
|
10
|
+
import { parse } from "yaml";
|
|
11
|
+
import { packs } from "./packs.js";
|
|
12
|
+
const packageRoot = join(dirname(fileURLToPath(import.meta.url)), "..");
|
|
13
|
+
/** The starters' folder: `project-templates/` beside `dist/`, in the repository and installed. */
|
|
14
|
+
export const templatesFolder = join(packageRoot, "project-templates");
|
|
15
|
+
/**
|
|
16
|
+
* The samples in `folder`: starters, smallest first, or guides in their order.
|
|
17
|
+
* @example listSamples().map((sample) => sample.name) // ["minimal", …]
|
|
18
|
+
*/
|
|
19
|
+
export function listSamples(folder = templatesFolder, kind = "starter") {
|
|
20
|
+
const folders = foldersIn(folder);
|
|
21
|
+
return kind === "starter"
|
|
22
|
+
? folders
|
|
23
|
+
.map((path) => readSample(path, kind))
|
|
24
|
+
.sort((a, b) => size(a.folder) - size(b.folder) || a.name.localeCompare(b.name))
|
|
25
|
+
: folders.sort((a, b) => orderOf(a) - orderOf(b)).map((path) => readSample(path, kind));
|
|
26
|
+
}
|
|
27
|
+
/** The packs, connectors, connectivity, methods, environments and features a sample uses. */
|
|
28
|
+
export function sampleFacts(folder) {
|
|
29
|
+
const manifest = parse(readFileSync(join(folder, "project.yaml"), "utf8"));
|
|
30
|
+
const environments = Object.keys(manifest.environments ?? {});
|
|
31
|
+
const models = (environments.length > 0 ? environments : [undefined]).flatMap((environment) => {
|
|
32
|
+
const { model } = loadDefinitions(folder, {
|
|
33
|
+
packs,
|
|
34
|
+
environment,
|
|
35
|
+
envvars: {},
|
|
36
|
+
});
|
|
37
|
+
return model ? [model] : [];
|
|
38
|
+
});
|
|
39
|
+
const all = (pick) => [...new Set(models.flatMap(pick))];
|
|
40
|
+
const tables = models.flatMap((model) => model.tables);
|
|
41
|
+
return {
|
|
42
|
+
packs: all((model) => model.standard.packs.map((pack) => pack.split("@")[0])),
|
|
43
|
+
connectors: all((model) => model.tables.flatMap((table) => table.ingest?.connection.connector ?? [])),
|
|
44
|
+
connectivity: all((model) => model.tables.flatMap((table) => table.ingest?.connection.connectivity ?? [])),
|
|
45
|
+
methods: all((model) => model.tables.flatMap((table) => [table.ingest, table.transform, table.store].flatMap((step) => step?.method ?? []))),
|
|
46
|
+
environments,
|
|
47
|
+
features: features(models, tables),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function features(models, tables) {
|
|
51
|
+
const manage = models.flatMap((model) => Object.entries(model.platform.manage).flatMap(([id, on]) => (on ? [`manages ${id}`] : [])));
|
|
52
|
+
return [
|
|
53
|
+
...new Set([
|
|
54
|
+
// Its own rules, not the not-null checks every required column gets.
|
|
55
|
+
...(tables.some((table) => table.expectations.some((item) => item.from === "definition") ||
|
|
56
|
+
table.contract.checks.length + table.contract.tableChecks.length > 0)
|
|
57
|
+
? ["quality checks"]
|
|
58
|
+
: []),
|
|
59
|
+
...(tables.some((table) => table.transform) ? ["transforms"] : []),
|
|
60
|
+
...(tables.some((table) => ["upsert", "history"].includes(String(table.store?.settings.mode)))
|
|
61
|
+
? ["change data"]
|
|
62
|
+
: []),
|
|
63
|
+
...(models.some((model) => model.standard.packs.length > 1) ? ["several packs"] : []),
|
|
64
|
+
...(models.some((model) => model.platform.schedule) ? ["schedule"] : []),
|
|
65
|
+
...manage,
|
|
66
|
+
]),
|
|
67
|
+
];
|
|
68
|
+
}
|
|
69
|
+
function foldersIn(folder) {
|
|
70
|
+
if (!existsSync(folder))
|
|
71
|
+
return [];
|
|
72
|
+
return readdirSync(folder, { withFileTypes: true })
|
|
73
|
+
.filter((entry) => entry.isDirectory())
|
|
74
|
+
.map((entry) => join(folder, entry.name));
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* One sample folder, listed from its `template.yaml` (starter) or `sample.yaml` (guide).
|
|
78
|
+
* @example readSample(folder, "guide").title
|
|
79
|
+
*/
|
|
80
|
+
export function readSample(folder, kind) {
|
|
81
|
+
const file = kind === "starter" ? "template.yaml" : "sample.yaml";
|
|
82
|
+
const data = (parse(readFileSync(join(folder, file), "utf8")) ?? {});
|
|
83
|
+
const name = folder.split(/[\\/]/).pop();
|
|
84
|
+
return {
|
|
85
|
+
name,
|
|
86
|
+
kind,
|
|
87
|
+
folder,
|
|
88
|
+
title: String(data.title ?? name),
|
|
89
|
+
summary: String(data.summary ?? ""),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function orderOf(folder) {
|
|
93
|
+
const data = parse(readFileSync(join(folder, "sample.yaml"), "utf8"));
|
|
94
|
+
return data.order ?? Number.MAX_SAFE_INTEGER;
|
|
95
|
+
}
|
|
96
|
+
/** Definition files, so the smallest starter comes first. */
|
|
97
|
+
function size(folder) {
|
|
98
|
+
const files = (path) => readdirSync(path, { withFileTypes: true })
|
|
99
|
+
.filter((entry) => entry.name !== "build")
|
|
100
|
+
.reduce((sum, entry) => sum +
|
|
101
|
+
(entry.isDirectory()
|
|
102
|
+
? files(join(path, entry.name))
|
|
103
|
+
: /\.ya?ml$/.test(entry.name)
|
|
104
|
+
? 1
|
|
105
|
+
: 0), 0);
|
|
106
|
+
return files(folder);
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=samples.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"samples.js","sourceRoot":"","sources":["../src/samples.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,+EAA+E;AAC/E,4EAA4E;AAC5E,4EAA4E;AAC5E,mFAAmF;AACnF,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,eAAe,EAAsB,MAAM,wBAAwB,CAAC;AAC7E,OAAO,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAsBnC,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;AAExE,kGAAkG;AAClG,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,CAAC,WAAW,EAAE,mBAAmB,CAAC,CAAC;AAEtE;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,MAAM,GAAG,eAAe,EAAE,OAAuB,SAAS;IACpF,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;IAClC,OAAO,IAAI,KAAK,SAAS;QACvB,CAAC,CAAC,OAAO;aACJ,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;aACrC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACpF,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;AAC5F,CAAC;AAED,6FAA6F;AAC7F,MAAM,UAAU,WAAW,CAAC,MAAc;IACxC,MAAM,QAAQ,GAAG,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAExE,CAAC;IACF,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC;IAC9D,MAAM,MAAM,GAAG,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,EAAE;QAC5F,MAAM,EAAE,KAAK,EAAE,GAAG,eAAe,CAAC,MAAM,EAAE;YACxC,KAAK;YACL,WAAW;YACX,OAAO,EAAE,EAAE;SACZ,CAAC,CAAC;QACH,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9B,CAAC,CAAC,CAAC;IACH,MAAM,GAAG,GAAG,CAAI,IAAmC,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC3F,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACvD,OAAO;QACL,KAAK,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC;QAC9E,UAAU,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACxB,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC,SAAS,IAAI,EAAE,CAAC,CAC1E;QACD,YAAY,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAC1B,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC,YAAY,IAAI,EAAE,CAAC,CAC7E;QACD,OAAO,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACrB,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAC7B,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,IAAI,EAAE,CAAC,CACnF,CACF;QACD,YAAY;QACZ,QAAQ,EAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;KACnC,CAAC;AACJ,CAAC;AAED,SAAS,QAAQ,CAAC,MAAuB,EAAE,MAA+B;IACxE,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CACtC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAC3F,CAAC;IACF,OAAO;QACL,GAAG,IAAI,GAAG,CAAC;YACT,qEAAqE;YACrE,GAAG,CAAC,MAAM,CAAC,IAAI,CACb,CAAC,KAAK,EAAE,EAAE,CACR,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,YAAY,CAAC;gBAC7D,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CACvE;gBACC,CAAC,CAAC,CAAC,gBAAgB,CAAC;gBACpB,CAAC,CAAC,EAAE,CAAC;YACP,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAClE,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;gBAC5F,CAAC,CAAC,CAAC,aAAa,CAAC;gBACjB,CAAC,CAAC,EAAE,CAAC;YACP,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACrF,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACxE,GAAG,MAAM;SACV,CAAC;KACH,CAAC;AACJ,CAAC;AAED,SAAS,SAAS,CAAC,MAAc;IAC/B,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,CAAC;IACnC,OAAO,WAAW,CAAC,MAAM,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;SAChD,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;SACtC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;AAC9C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,MAAc,EAAE,IAAoB;IAC7D,MAAM,IAAI,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,aAAa,CAAC;IAClE,MAAM,IAAI,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAA4B,CAAC;IAChG,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,EAAG,CAAC;IAC1C,OAAO;QACL,IAAI;QACJ,IAAI;QACJ,MAAM;QACN,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC;QACjC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC;KACpC,CAAC;AACJ,CAAC;AAED,SAAS,OAAO,CAAC,MAAc;IAC7B,MAAM,IAAI,GAAG,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,CAAC,CAAuB,CAAC;IAC5F,OAAO,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,gBAAgB,CAAC;AAC/C,CAAC;AAED,6DAA6D;AAC7D,SAAS,IAAI,CAAC,MAAc;IAC1B,MAAM,KAAK,GAAG,CAAC,IAAY,EAAU,EAAE,CACrC,WAAW,CAAC,IAAI,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;SACvC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC;SACzC,MAAM,CACL,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CACb,GAAG;QACH,CAAC,KAAK,CAAC,WAAW,EAAE;YAClB,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YAC/B,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;gBAC3B,CAAC,CAAC,CAAC;gBACH,CAAC,CAAC,CAAC,CAAC,EACV,CAAC,CACF,CAAC;IACN,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC;AACvB,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Template } from "./templates.js";
|
|
2
|
+
/** What the user chose. */
|
|
3
|
+
export interface Answers {
|
|
4
|
+
name: string;
|
|
5
|
+
environments: string[];
|
|
6
|
+
values: Record<string, string>;
|
|
7
|
+
/** Another standard to use instead of the template's: its file and where it came from. */
|
|
8
|
+
standard?: {
|
|
9
|
+
file: string;
|
|
10
|
+
source: string;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
/** A file's content: text for the files init edits, bytes for everything else. */
|
|
14
|
+
export type Content = string | Buffer;
|
|
15
|
+
/** Files to write, path → content; throws on a symbolic link in the template. */
|
|
16
|
+
export declare function scaffoldFiles(template: Template, answers: Answers, prepared?: Record<string, Content>): Record<string, Content>;
|
|
17
|
+
/**
|
|
18
|
+
* Writes the files under `target`, or returns what is in the way and writes
|
|
19
|
+
* nothing: an existing entry at a path (a link too, never followed), or one
|
|
20
|
+
* that is not a folder where the template needs a folder.
|
|
21
|
+
*/
|
|
22
|
+
export declare function writeScaffold(target: string, files: Record<string, Content>): {
|
|
23
|
+
written: string[];
|
|
24
|
+
} | {
|
|
25
|
+
clashes: string[];
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Why a project or environment name is not valid, with a valid suggestion, or
|
|
29
|
+
* undefined when it is. One rule for the command, its questions and editors.
|
|
30
|
+
*/
|
|
31
|
+
export declare function nameProblem(text: string, what: "project" | "environment"): string | undefined;
|
|
32
|
+
/** A valid project id from a folder name: lowercase, other characters to `_`, a letter first. */
|
|
33
|
+
export declare function projectId(text: string): string;
|
|
34
|
+
//# sourceMappingURL=scaffold.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,2BAA2B;AAC3B,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,0FAA0F;IAC1F,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7C;AAYD,kFAAkF;AAClF,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AAEtC,iFAAiF;AACjF,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,EAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAWzB;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B;IAAE,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAU/C;AAcD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,aAAa,GAAG,MAAM,GAAG,SAAS,CAG7F;AAED,iGAAiG;AACjG,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM9C"}
|
package/dist/scaffold.js
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// A new project from a template: the files to write, then writing them
|
|
2
|
+
// without ever replacing a file that is already there.
|
|
3
|
+
import { lstatSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { dirname, join, relative } from "node:path";
|
|
5
|
+
import { isMap, isScalar, parseDocument, YAMLMap } from "yaml";
|
|
6
|
+
/** Never copied: the template's own description and README, and anything generated. */
|
|
7
|
+
const skipped = new Set([
|
|
8
|
+
"template.yaml",
|
|
9
|
+
"README.md",
|
|
10
|
+
"build",
|
|
11
|
+
".generated.json",
|
|
12
|
+
".git",
|
|
13
|
+
".ingestron",
|
|
14
|
+
]);
|
|
15
|
+
/** Files to write, path → content; throws on a symbolic link in the template. */
|
|
16
|
+
export function scaffoldFiles(template, answers, prepared) {
|
|
17
|
+
const files = { ...prepared };
|
|
18
|
+
if (!prepared)
|
|
19
|
+
for (const path of templateFiles(template, template.folder))
|
|
20
|
+
files[path] = readFileSync(join(template.folder, path));
|
|
21
|
+
files["project.yaml"] = projectText(files["project.yaml"]?.toString() ?? "", answers);
|
|
22
|
+
if (answers.standard) {
|
|
23
|
+
const text = readFileSync(answers.standard.file, "utf8");
|
|
24
|
+
files["standard.yaml"] = `# From ${answers.standard.source}\n${text}`;
|
|
25
|
+
}
|
|
26
|
+
return files;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Writes the files under `target`, or returns what is in the way and writes
|
|
30
|
+
* nothing: an existing entry at a path (a link too, never followed), or one
|
|
31
|
+
* that is not a folder where the template needs a folder.
|
|
32
|
+
*/
|
|
33
|
+
export function writeScaffold(target, files) {
|
|
34
|
+
const paths = Object.keys(files).sort();
|
|
35
|
+
const clashes = [...new Set(paths.flatMap((path) => inTheWay(target, path)))].sort();
|
|
36
|
+
if (clashes.length > 0)
|
|
37
|
+
return { clashes };
|
|
38
|
+
for (const path of paths) {
|
|
39
|
+
mkdirSync(dirname(join(target, path)), { recursive: true });
|
|
40
|
+
// "wx": never replace a file that appeared after the check.
|
|
41
|
+
writeFileSync(join(target, path), files[path], { flag: "wx" });
|
|
42
|
+
}
|
|
43
|
+
return { written: paths };
|
|
44
|
+
}
|
|
45
|
+
/** The path itself if anything is there, or a parent that exists but is not a folder. */
|
|
46
|
+
function inTheWay(target, path) {
|
|
47
|
+
const parts = path.split("/");
|
|
48
|
+
for (let index = 1; index <= parts.length; index += 1) {
|
|
49
|
+
const prefix = parts.slice(0, index).join("/");
|
|
50
|
+
const stat = lstatSync(join(target, prefix), { throwIfNoEntry: false });
|
|
51
|
+
if (!stat)
|
|
52
|
+
return [];
|
|
53
|
+
if (index === parts.length || !stat.isDirectory())
|
|
54
|
+
return [prefix];
|
|
55
|
+
}
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Why a project or environment name is not valid, with a valid suggestion, or
|
|
60
|
+
* undefined when it is. One rule for the command, its questions and editors.
|
|
61
|
+
*/
|
|
62
|
+
export function nameProblem(text, what) {
|
|
63
|
+
if (projectId(text) === text)
|
|
64
|
+
return undefined;
|
|
65
|
+
return `"${text}" is not a valid ${what} name: use lowercase letters, digits and underscores, starting with a letter. Try "${projectId(text)}".`;
|
|
66
|
+
}
|
|
67
|
+
/** A valid project id from a folder name: lowercase, other characters to `_`, a letter first. */
|
|
68
|
+
export function projectId(text) {
|
|
69
|
+
const id = text
|
|
70
|
+
.toLowerCase()
|
|
71
|
+
.replace(/[^a-z0-9_]+/g, "_")
|
|
72
|
+
.replace(/^_+|_+$/g, "");
|
|
73
|
+
return /^[a-z]/.test(id) ? id : `p_${id}`;
|
|
74
|
+
}
|
|
75
|
+
function templateFiles(template, folder) {
|
|
76
|
+
return readdirSync(folder).flatMap((entry) => {
|
|
77
|
+
if (skipped.has(entry))
|
|
78
|
+
return [];
|
|
79
|
+
const path = join(folder, entry);
|
|
80
|
+
const stat = lstatSync(path);
|
|
81
|
+
if (stat.isSymbolicLink())
|
|
82
|
+
throw new Error(`Template "${template.name}" has a symbolic link: ${relative(template.folder, path)}. Templates may only hold regular files.`);
|
|
83
|
+
if (stat.isDirectory())
|
|
84
|
+
return templateFiles(template, path);
|
|
85
|
+
return stat.isFile() ? [relative(template.folder, path)] : [];
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
/** project.yaml with the name, environments and answers; comments are kept. */
|
|
89
|
+
function projectText(text, answers) {
|
|
90
|
+
const document = parseDocument(text);
|
|
91
|
+
document.set("id", answers.name);
|
|
92
|
+
const existing = document.get("environments");
|
|
93
|
+
const environments = isMap(existing) ? existing : new YAMLMap();
|
|
94
|
+
// Edit the template's map in place, so comments on its environments stay.
|
|
95
|
+
for (const pair of [...environments.items])
|
|
96
|
+
if (!answers.environments.includes(String(isScalar(pair.key) ? pair.key.value : pair.key)))
|
|
97
|
+
environments.delete(pair.key);
|
|
98
|
+
for (const name of answers.environments)
|
|
99
|
+
if (!environments.has(name))
|
|
100
|
+
environments.set(name, new YAMLMap());
|
|
101
|
+
document.set("environments", environments);
|
|
102
|
+
for (const [key, value] of Object.entries(answers.values))
|
|
103
|
+
document.setIn(["values", key], value);
|
|
104
|
+
return document.toString();
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=scaffold.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,uDAAuD;AACvD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACzF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAY/D,uFAAuF;AACvF,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC;IACtB,eAAe;IACf,WAAW;IACX,OAAO;IACP,iBAAiB;IACjB,MAAM;IACN,YAAY;CACb,CAAC,CAAC;AAKH,iFAAiF;AACjF,MAAM,UAAU,aAAa,CAC3B,QAAkB,EAClB,OAAgB,EAChB,QAAkC;IAElC,MAAM,KAAK,GAA4B,EAAE,GAAG,QAAQ,EAAE,CAAC;IACvD,IAAI,CAAC,QAAQ;QACX,KAAK,MAAM,IAAI,IAAI,aAAa,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC;YACzD,KAAK,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;IAC5D,KAAK,CAAC,cAAc,CAAC,GAAG,WAAW,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,OAAO,CAAC,CAAC;IACtF,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrB,MAAM,IAAI,GAAG,YAAY,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACzD,KAAK,CAAC,eAAe,CAAC,GAAG,UAAU,OAAO,CAAC,QAAQ,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;IACxE,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAC3B,MAAc,EACd,KAA8B;IAE9B,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;IACxC,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACrF,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,CAAC;IAC3C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5D,4DAA4D;QAC5D,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,KAAK,CAAC,IAAI,CAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAC5B,CAAC;AAED,yFAAyF;AACzF,SAAS,QAAQ,CAAC,MAAc,EAAE,IAAY;IAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC9B,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACtD,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC/C,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC,CAAC;QACxE,IAAI,CAAC,IAAI;YAAE,OAAO,EAAE,CAAC;QACrB,IAAI,KAAK,KAAK,KAAK,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;YAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,IAA+B;IACvE,IAAI,SAAS,CAAC,IAAI,CAAC,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IAC/C,OAAO,IAAI,IAAI,oBAAoB,IAAI,sFAAsF,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;AACnJ,CAAC;AAED,iGAAiG;AACjG,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,MAAM,EAAE,GAAG,IAAI;SACZ,WAAW,EAAE;SACb,OAAO,CAAC,cAAc,EAAE,GAAG,CAAC;SAC5B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC3B,OAAO,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;AAC5C,CAAC;AAED,SAAS,aAAa,CAAC,QAAkB,EAAE,MAAc;IACvD,OAAO,WAAW,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;QAC3C,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QACjC,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QAC7B,IAAI,IAAI,CAAC,cAAc,EAAE;YACvB,MAAM,IAAI,KAAK,CACb,aAAa,QAAQ,CAAC,IAAI,0BAA0B,QAAQ,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,0CAA0C,CAC9H,CAAC;QACJ,IAAI,IAAI,CAAC,WAAW,EAAE;YAAE,OAAO,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAC7D,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAChE,CAAC,CAAC,CAAC;AACL,CAAC;AAED,+EAA+E;AAC/E,SAAS,WAAW,CAAC,IAAY,EAAE,OAAgB;IACjD,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACrC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAC9C,MAAM,YAAY,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,OAAO,EAAoB,CAAC;IAClF,0EAA0E;IAC1E,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,YAAY,CAAC,KAAK,CAAC;QACxC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACxF,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAClC,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,YAAY;QACrC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,OAAO,EAAE,CAAC,CAAC;IACrE,QAAQ,CAAC,GAAG,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;IAC3C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;IAClG,OAAO,QAAQ,CAAC,QAAQ,EAAE,CAAC;AAC7B,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Options } from "./args.js";
|
|
2
|
+
import type { Io } from "./io.js";
|
|
3
|
+
/** Writes the schemas to `.ingestron/schemas` and prints the VS Code setting. */
|
|
4
|
+
export declare function writeSchemas(options: Options, io: Io): number;
|
|
5
|
+
//# sourceMappingURL=schemas.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAGlC,iFAAiF;AACjF,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,GAAG,MAAM,CAsC7D"}
|
package/dist/schemas.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Editor schemas for VS Code's YAML extension. One combined schema chooses
|
|
2
|
+
// each document's schema by its `kind`, so a single setting covers every file.
|
|
3
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { join, relative, resolve } from "node:path";
|
|
5
|
+
import { manifestSchema, toEditorSchema } from "@ingestron/config";
|
|
6
|
+
import { kinds } from "@ingestron/definitions";
|
|
7
|
+
import { templateSchema } from "./templates.js";
|
|
8
|
+
/** Writes the schemas to `.ingestron/schemas` and prints the VS Code setting. */
|
|
9
|
+
export function writeSchemas(options, io) {
|
|
10
|
+
const folder = join(io.cwd, ".ingestron", "schemas");
|
|
11
|
+
mkdirSync(folder, { recursive: true });
|
|
12
|
+
const write = (name, schema) => writeFileSync(join(folder, name), `${JSON.stringify(schema, null, 2)}\n`);
|
|
13
|
+
write("project.json", manifestSchema);
|
|
14
|
+
const branches = Object.values(kinds).map((kind) => {
|
|
15
|
+
const file = `${kind.kind.toLowerCase()}.json`;
|
|
16
|
+
write(file, toEditorSchema(kind.schema));
|
|
17
|
+
return {
|
|
18
|
+
if: { required: ["kind"], properties: { kind: { const: kind.kind } } },
|
|
19
|
+
then: { $ref: file },
|
|
20
|
+
};
|
|
21
|
+
});
|
|
22
|
+
write("template.json", templateSchema);
|
|
23
|
+
// Without a kind: project.yaml has an id, a template's template.yaml does not.
|
|
24
|
+
branches.push({
|
|
25
|
+
if: { not: { required: ["kind"] }, required: ["id"] },
|
|
26
|
+
then: { $ref: "project.json" },
|
|
27
|
+
}, {
|
|
28
|
+
if: { not: { anyOf: [{ required: ["kind"] }, { required: ["id"] }] } },
|
|
29
|
+
then: { $ref: "template.json" },
|
|
30
|
+
});
|
|
31
|
+
write("definitions.json", { title: "Ingestron definitions", allOf: branches });
|
|
32
|
+
const files = join(relative(io.cwd, resolve(io.cwd, options.definitions)) || ".", "**/*.yaml").replace(/^\.\//, "");
|
|
33
|
+
const setting = {
|
|
34
|
+
"yaml.schemas": { [relative(io.cwd, join(folder, "definitions.json"))]: files },
|
|
35
|
+
};
|
|
36
|
+
io.write(`Wrote editor schemas to ${relative(io.cwd, folder)}.\nAdd this to .vscode/settings.json:\n${JSON.stringify(setting, null, 2)}\n`);
|
|
37
|
+
return 0;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=schemas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemas.js","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type Template } from "./templates.js";
|
|
2
|
+
/** The URL without `user:password@`, for messages and the standard's "From" line. */
|
|
3
|
+
export declare function withoutCredentials(text: string): string;
|
|
4
|
+
/** A Git URL rather than a path or a name. */
|
|
5
|
+
export declare function isGitUrl(spec: string): boolean;
|
|
6
|
+
/** A template from a built-in name, a folder or a Git URL (`#` names a sub-folder). Call `done()` when finished. */
|
|
7
|
+
export declare function templateSource(spec: string, cwd: string): {
|
|
8
|
+
template: Template;
|
|
9
|
+
done(): void;
|
|
10
|
+
};
|
|
11
|
+
/** A standard file from a path or a Git URL with `#path/to/standard.yaml`. */
|
|
12
|
+
export declare function standardSource(spec: string, cwd: string): {
|
|
13
|
+
file: string;
|
|
14
|
+
source: string;
|
|
15
|
+
done(): void;
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=sources.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sources.d.ts","sourceRoot":"","sources":["../src/sources.ts"],"names":[],"mappings":"AAMA,OAAO,EAAkC,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/E,qFAAqF;AACrF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvD;AAQD,8CAA8C;AAC9C,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAM9C;AAED,oHAAoH;AACpH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,IAAI,IAAI,IAAI,CAAA;CAAE,CAuB9F;AAED,8EAA8E;AAC9E,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,GACV;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,IAAI,IAAI,CAAA;CAAE,CAQhD"}
|