@olenbetong/appframe-cli 4.4.10 → 4.5.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/CHANGELOG.md +20 -0
- package/README.md +3 -0
- package/cli/af-bundle-upload.js +15 -7
- package/cli/af-resources-generate.js +50 -292
- package/package.json +6 -3
- package/src/af-bundle-upload.ts +16 -7
- package/src/af-resources-generate.ts +55 -382
- package/src/editor/TransactionsEditor.tsx +1 -2
- package/tsconfig.build.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 4.5.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- e61d41b: af resources generate now reads types.json from cwd for type overrides keyed by database object name
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- 19ef84b: af resources generate: add --output flag to write to a file and compute the correct relative import path for custom.d.ts
|
|
12
|
+
- 1e0c584: Add resources.yaml config system for data objects and stored procedures
|
|
13
|
+
- `appframe-vite`: New `resources.yaml` config file support — declare all data objects and stored procedures in a single YAML file per app.
|
|
14
|
+
- `appframe-vite`: New CLI commands: `appframe-vite resources generate` (regenerate all files from config), `resources add` (interactive wizard), `resources edit [id]` (interactive editor).
|
|
15
|
+
- `appframe-vite`: Dev server now watches `resources.yaml` and auto-regenerates output files on change.
|
|
16
|
+
- `appframe-vite`: New `@olenbetong/appframe-vite/resources` package export with shared code generation utilities (`fetchAndGenerate`, `buildYamlConfig`, `parseYamlConfig`, etc.).
|
|
17
|
+
- `appframe-cli`: Remove `af resources regenerate` command (superseded by `appframe-vite resources generate`).
|
|
18
|
+
- `appframe-cli`: `af resources generate` now uses generation logic from `@olenbetong/appframe-vite/resources`.
|
|
19
|
+
|
|
20
|
+
- Updated dependencies [1e0c584]
|
|
21
|
+
- @olenbetong/appframe-vite@6.2.0
|
|
22
|
+
|
|
3
23
|
## 4.4.10
|
|
4
24
|
|
|
5
25
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -68,6 +68,9 @@ Use `af <command> --help` for full usage with options.
|
|
|
68
68
|
- `af resources add <id>`: Adds a data resource by DB object id. Options: `--server <host>`, `--name [name]`.
|
|
69
69
|
- `af resources delete <id>`: Deletes a data resource by id or name. Options: `--server <host>`.
|
|
70
70
|
|
|
71
|
+
> **Note:** To manage data objects and procedures declaratively, use the `resources.yaml` config system in `@olenbetong/appframe-vite`. See `appframe-vite resources add/edit/generate` commands.
|
|
72
|
+
|
|
73
|
+
|
|
71
74
|
### Bundles
|
|
72
75
|
|
|
73
76
|
- `af bundle create`: Scaffold a new bundle project.
|
package/cli/af-bundle-upload.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
import { mkdirSync, renameSync, rmSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import AdmZip from "adm-zip";
|
|
2
5
|
import chalk from "chalk";
|
|
3
6
|
import { Command } from "commander";
|
|
4
7
|
import { config } from "dotenv";
|
|
@@ -9,6 +12,11 @@ import { execShellCommand } from "./lib/execShellCommand.js";
|
|
|
9
12
|
import { importJson } from "./lib/importJson.js";
|
|
10
13
|
import { Server } from "./lib/Server.js";
|
|
11
14
|
config({ path: `${process.cwd()}/.env`, quiet: true });
|
|
15
|
+
function createZip(sourceDir, outputFile) {
|
|
16
|
+
let zip = new AdmZip();
|
|
17
|
+
zip.addLocalFolder(sourceDir, sourceDir);
|
|
18
|
+
zip.writeZip(outputFile);
|
|
19
|
+
}
|
|
12
20
|
async function prepareBundle(pkgName, options) {
|
|
13
21
|
try {
|
|
14
22
|
let name;
|
|
@@ -74,23 +82,23 @@ async function prepareBundle(pkgName, options) {
|
|
|
74
82
|
console.log(chalk.yellow("No bundle found..."));
|
|
75
83
|
}
|
|
76
84
|
console.log("Removing previous...");
|
|
77
|
-
|
|
85
|
+
rmSync(rootOutputFolder, { recursive: true, force: true });
|
|
78
86
|
console.log("Packing...");
|
|
79
87
|
await execShellCommand(pkgName ? `npm pack ${pkgName}` : "npm pack");
|
|
80
88
|
console.log("Making output directory...");
|
|
81
|
-
|
|
89
|
+
mkdirSync(name, { recursive: true });
|
|
82
90
|
console.log(`Extracting '${tarball}'...`);
|
|
83
91
|
await execShellCommand(`tar -xvzf ${tarball} -C ${name}`);
|
|
84
92
|
console.log(`Moving from 'package' to '${version}'...`);
|
|
85
|
-
|
|
93
|
+
renameSync(join(name, "package"), join(name, version));
|
|
86
94
|
console.log("Zipping...");
|
|
87
|
-
|
|
95
|
+
createZip(rootOutputFolder, zipFileName);
|
|
88
96
|
console.log("Cleaning...");
|
|
89
|
-
|
|
90
|
-
|
|
97
|
+
rmSync(rootOutputFolder, { recursive: true, force: true });
|
|
98
|
+
rmSync(tarball);
|
|
91
99
|
if (id) {
|
|
92
100
|
await server.uploadBundle(Project_ID, id, zipFileName);
|
|
93
|
-
|
|
101
|
+
rmSync(zipFileName);
|
|
94
102
|
console.log("Done!");
|
|
95
103
|
} else {
|
|
96
104
|
console.log("Launching explorer...");
|
|
@@ -1,280 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
import { writeFile } from "node:fs/promises";
|
|
3
|
+
import { Client } from "@olenbetong/appframe-data";
|
|
4
|
+
import {
|
|
5
|
+
buildYamlConfig,
|
|
6
|
+
fetchAndGenerate,
|
|
7
|
+
formatWithBiome
|
|
8
|
+
} from "@olenbetong/appframe-vite/resources";
|
|
9
|
+
import { config } from "dotenv";
|
|
2
10
|
import inquirer from "inquirer";
|
|
3
11
|
import { Command } from "./lib/Command.js";
|
|
4
12
|
import { importJson } from "./lib/importJson.js";
|
|
5
13
|
import { Server } from "./lib/Server.js";
|
|
14
|
+
config({ path: `${process.cwd()}/.env`, quiet: true });
|
|
6
15
|
const appPkg = await importJson("../package.json");
|
|
7
|
-
function afTypeToTsType(type, dateStyle = false) {
|
|
8
|
-
switch (type) {
|
|
9
|
-
case "bigint":
|
|
10
|
-
return "bigint";
|
|
11
|
-
case "int":
|
|
12
|
-
case "decimal":
|
|
13
|
-
case "smallint":
|
|
14
|
-
case "tinyint":
|
|
15
|
-
case "float":
|
|
16
|
-
case "numeric":
|
|
17
|
-
return "number";
|
|
18
|
-
case "bit":
|
|
19
|
-
return "boolean";
|
|
20
|
-
case "datetime2":
|
|
21
|
-
case "datetime":
|
|
22
|
-
case "smalldatetime":
|
|
23
|
-
case "date":
|
|
24
|
-
if (dateStyle === "ts") {
|
|
25
|
-
return "Date";
|
|
26
|
-
} else if (dateStyle === "ts-proc") {
|
|
27
|
-
return "string | Date";
|
|
28
|
-
} else {
|
|
29
|
-
return type === "date" ? "date" : "datetime";
|
|
30
|
-
}
|
|
31
|
-
default:
|
|
32
|
-
return "string";
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
function getProcedureDefinition(name, procDefinition, options) {
|
|
36
|
-
let parameters = [];
|
|
37
|
-
let typeOverrides = {};
|
|
38
|
-
if (options.overrides) {
|
|
39
|
-
let overrides = options.overrides.split(",");
|
|
40
|
-
for (let override of overrides) {
|
|
41
|
-
let [param, type] = override.split(":");
|
|
42
|
-
typeOverrides[param] = type;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
for (let parameter of procDefinition.Parameters) {
|
|
46
|
-
parameters.push({
|
|
47
|
-
name: parameter.ParamName,
|
|
48
|
-
type: afTypeToTsType(parameter.TypeName, "field"),
|
|
49
|
-
hasDefault: parameter.has_default_value,
|
|
50
|
-
required: !parameter.has_default_value && !parameter.is_nullable
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
let output = [];
|
|
54
|
-
if (!options.global) {
|
|
55
|
-
output.push(`import { ProcedureAPI } from "@olenbetong/appframe-data";`);
|
|
56
|
-
if (options.expose) {
|
|
57
|
-
output.push(`import { expose } from "@olenbetong/appframe-core";`);
|
|
58
|
-
}
|
|
59
|
-
output.push("");
|
|
60
|
-
}
|
|
61
|
-
let paramTypeName = "ProcParams";
|
|
62
|
-
let procName = "proc";
|
|
63
|
-
if (options.id) {
|
|
64
|
-
procName = options.id;
|
|
65
|
-
paramTypeName = `${options.id}Params`;
|
|
66
|
-
if (paramTypeName.startsWith("proc")) {
|
|
67
|
-
paramTypeName = paramTypeName.substring(4);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
if (options.types) {
|
|
71
|
-
if (procDefinition.Parameters.length > 0) {
|
|
72
|
-
let typeOutput = [`export type ${paramTypeName} = {`];
|
|
73
|
-
for (let parameter of procDefinition.Parameters) {
|
|
74
|
-
let type = typeOverrides[parameter.ParamName];
|
|
75
|
-
let name2 = parameter.ParamName;
|
|
76
|
-
if (!type) {
|
|
77
|
-
type = afTypeToTsType(parameter.TypeName, "ts-proc");
|
|
78
|
-
}
|
|
79
|
-
if (parameter.has_default_value || parameter.is_nullable) {
|
|
80
|
-
type += " | null";
|
|
81
|
-
name2 += "?";
|
|
82
|
-
}
|
|
83
|
-
typeOutput.push(` ${name2}: ${type}`);
|
|
84
|
-
}
|
|
85
|
-
typeOutput.push("};");
|
|
86
|
-
output.push(typeOutput.join("\n"));
|
|
87
|
-
output.push("");
|
|
88
|
-
} else {
|
|
89
|
-
output.push(`export type ${paramTypeName} = null | undefined | Record<string, unknown>;
|
|
90
|
-
`);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
output.push(`export const ${procName} = new ${options.global ? "af." : ""}ProcedureAPI${options.types ? `<${paramTypeName}, unknown>` : ""}({
|
|
94
|
-
procedureId: "${name}",
|
|
95
|
-
parameters: ${JSON.stringify(parameters, null, 2)},
|
|
96
|
-
timeout: 30000
|
|
97
|
-
});`);
|
|
98
|
-
if (options.expose) {
|
|
99
|
-
output.push("");
|
|
100
|
-
output.push(
|
|
101
|
-
`${options.global ? "af.common." : ""}expose("af.article.procedures.${procName}", ${procName}, { overwrite: true });`
|
|
102
|
-
);
|
|
103
|
-
}
|
|
104
|
-
return output.join("\n");
|
|
105
|
-
}
|
|
106
|
-
function getDataObjectDefinition(name, viewDefinition, options) {
|
|
107
|
-
let fields = [];
|
|
108
|
-
let includeFields = typeof options.fields === "string" ? options.fields?.split(",").filter((f) => !!f) ?? [] : [];
|
|
109
|
-
let aggregates = {};
|
|
110
|
-
if (options.aggregates) {
|
|
111
|
-
for (let aggregateDef of options.aggregates.split(",")) {
|
|
112
|
-
let [field, aggregate] = aggregateDef.split(":");
|
|
113
|
-
aggregates[field] = aggregate;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
for (let field of viewDefinition.Parameters) {
|
|
117
|
-
if (includeFields.length > 0 && !includeFields.includes(field.Name)) {
|
|
118
|
-
continue;
|
|
119
|
-
}
|
|
120
|
-
let fieldDefinition = {
|
|
121
|
-
name: field.Name,
|
|
122
|
-
type: field.DataType,
|
|
123
|
-
nullable: field.Nullable
|
|
124
|
-
};
|
|
125
|
-
if (field.HasDefault) {
|
|
126
|
-
fieldDefinition.hasDefault = true;
|
|
127
|
-
}
|
|
128
|
-
if (field.Computed) {
|
|
129
|
-
fieldDefinition.computed = true;
|
|
130
|
-
}
|
|
131
|
-
if (field.Identity) {
|
|
132
|
-
fieldDefinition.identity = true;
|
|
133
|
-
}
|
|
134
|
-
if (aggregates[field.Name]) {
|
|
135
|
-
fieldDefinition.aggregate = aggregates[field.Name];
|
|
136
|
-
}
|
|
137
|
-
fields.push(fieldDefinition);
|
|
138
|
-
}
|
|
139
|
-
let api = "generateApiDataObject";
|
|
140
|
-
let types = "";
|
|
141
|
-
let typeName = `${options.id}Record`;
|
|
142
|
-
let typeOverrides = {};
|
|
143
|
-
if (options.overrides) {
|
|
144
|
-
let overrides = options.overrides.split(",");
|
|
145
|
-
for (let override of overrides) {
|
|
146
|
-
let [param, type] = override.split(":");
|
|
147
|
-
typeOverrides[param] = type;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
if (typeName.startsWith("ds")) {
|
|
151
|
-
typeName = typeName.substring(2);
|
|
152
|
-
}
|
|
153
|
-
if (options.types) {
|
|
154
|
-
api = `generateApiDataObject<${typeName}>`;
|
|
155
|
-
let fieldTypes = "";
|
|
156
|
-
for (let field of fields) {
|
|
157
|
-
let type = typeOverrides[field.name];
|
|
158
|
-
if (!type) {
|
|
159
|
-
type = afTypeToTsType(field.type, "ts");
|
|
160
|
-
if (field.nullable) {
|
|
161
|
-
type += " | null";
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
fieldTypes += ` ${field.name}: ${type};
|
|
165
|
-
`;
|
|
166
|
-
}
|
|
167
|
-
types = `export type ${typeName} = {
|
|
168
|
-
${fieldTypes}}`;
|
|
169
|
-
}
|
|
170
|
-
if (options.global) {
|
|
171
|
-
api = `af.data.${api}`;
|
|
172
|
-
}
|
|
173
|
-
let output = "";
|
|
174
|
-
if (!options.global) {
|
|
175
|
-
output += `import { generateApiDataObject${options.sortOrder ? ", SortOrder" : ""} } from "@olenbetong/appframe-data";`;
|
|
176
|
-
if (options.expose) {
|
|
177
|
-
output += `
|
|
178
|
-
import { expose } from "@olenbetong/appframe-core";`;
|
|
179
|
-
}
|
|
180
|
-
output += "\n\n";
|
|
181
|
-
}
|
|
182
|
-
if (options.master && options.master.indexOf(":") > 0) {
|
|
183
|
-
let [name2, path] = options.master.split(":");
|
|
184
|
-
output += `import { ${name2} } from "${path}";
|
|
185
|
-
|
|
186
|
-
`;
|
|
187
|
-
}
|
|
188
|
-
if (options.types) {
|
|
189
|
-
output += `${types}
|
|
190
|
-
|
|
191
|
-
`;
|
|
192
|
-
}
|
|
193
|
-
let linkFields = "";
|
|
194
|
-
let dsOptions = [];
|
|
195
|
-
dsOptions.push(`resource: "${name}"`);
|
|
196
|
-
if (options.unique) {
|
|
197
|
-
dsOptions.push(`uniqueName: "${options.unique}"`);
|
|
198
|
-
}
|
|
199
|
-
dsOptions.push(`id: "${options.id}"`);
|
|
200
|
-
if (options.master && options.linkFields) {
|
|
201
|
-
dsOptions.push(`masterDataObject: ${options.master.split(":")[0]}`);
|
|
202
|
-
let fields2 = options.linkFields.split(",");
|
|
203
|
-
linkFields = `linkFields: {
|
|
204
|
-
${fields2.map((field) => {
|
|
205
|
-
let [thisField, masterField] = field.split(":");
|
|
206
|
-
return `${thisField}: "${masterField ?? thisField}",`;
|
|
207
|
-
}).join("\n ")}
|
|
208
|
-
}`;
|
|
209
|
-
dsOptions.push(linkFields);
|
|
210
|
-
}
|
|
211
|
-
dsOptions.push(`allowUpdate: ${options.permissions?.includes("U") ?? false}`);
|
|
212
|
-
dsOptions.push(`allowInsert: ${options.permissions?.includes("I") ?? false}`);
|
|
213
|
-
dsOptions.push(`allowDelete: ${options.permissions?.includes("D") ?? false}`);
|
|
214
|
-
dsOptions.push(`dynamicLoading: ${options.dynamic || false}`);
|
|
215
|
-
let fieldsOption = fields.map((field) => ({
|
|
216
|
-
...field,
|
|
217
|
-
type: afTypeToTsType(field.type, "field")
|
|
218
|
-
}));
|
|
219
|
-
dsOptions.push(`fields: ${JSON.stringify(fieldsOption, null, 2).split("\n").join("\n ")}`);
|
|
220
|
-
let parametersOption = [`maxRecords: ${options.maxRecords}`];
|
|
221
|
-
if (options.sortOrder) {
|
|
222
|
-
let sorts = options.sortOrder.split(",");
|
|
223
|
-
let sortPrefix = options.global ? "af.data.SortOrder." : "SortOrder.";
|
|
224
|
-
let sortOrder = sorts.map((sort) => {
|
|
225
|
-
let [field, order = "asc"] = sort.split(":");
|
|
226
|
-
switch (order.toLocaleLowerCase()) {
|
|
227
|
-
case "asc":
|
|
228
|
-
order = "Asc";
|
|
229
|
-
break;
|
|
230
|
-
case "desc":
|
|
231
|
-
order = "Desc";
|
|
232
|
-
break;
|
|
233
|
-
case "ascnullslast":
|
|
234
|
-
order = "AscNullsLast";
|
|
235
|
-
break;
|
|
236
|
-
case "descnullsfirst":
|
|
237
|
-
order = "DescNullsFirst";
|
|
238
|
-
break;
|
|
239
|
-
}
|
|
240
|
-
return `{ ${field}: ${sortPrefix}${order} }`;
|
|
241
|
-
}).join(", ");
|
|
242
|
-
parametersOption.push(`sortOrder: [${sortOrder}]`);
|
|
243
|
-
}
|
|
244
|
-
if (options.groupBy) {
|
|
245
|
-
parametersOption.push(`groupBy: ${JSON.stringify(options.groupBy.split(","))}`);
|
|
246
|
-
}
|
|
247
|
-
if (options.where) {
|
|
248
|
-
parametersOption.push(`whereClause: "${options.where}"`);
|
|
249
|
-
}
|
|
250
|
-
if (options.distinct) {
|
|
251
|
-
parametersOption.push(`distinctRows: true`);
|
|
252
|
-
}
|
|
253
|
-
dsOptions.push(`parameters: {
|
|
254
|
-
${parametersOption.join(",\n ")}
|
|
255
|
-
}`);
|
|
256
|
-
output += `export const ${options.id} = ${api}({
|
|
257
|
-
${dsOptions.join(",\n ")}
|
|
258
|
-
});
|
|
259
|
-
`;
|
|
260
|
-
if (options.expose) {
|
|
261
|
-
let id = typeof options.expose === "string" ? options.expose : options.id;
|
|
262
|
-
if (options.global) {
|
|
263
|
-
output += `
|
|
264
|
-
af.common.expose("af.article.dataObjects.${id}", ${options.id}, { overwrite: true });`;
|
|
265
|
-
} else {
|
|
266
|
-
output += `
|
|
267
|
-
expose("af.article.dataObjects.${id}", ${options.id}, { overwrite: true });`;
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
return output;
|
|
271
|
-
}
|
|
272
16
|
async function getResourceDefinition(resourceName, options) {
|
|
273
|
-
let server = new Server("dev.obet.no");
|
|
274
|
-
let resource = await server.getResourceArgument(resourceName);
|
|
275
|
-
let definition = await server.getResourceDefinition(resource);
|
|
276
|
-
definition.Parameters = definition.Parameters.filter((p) => !["CUT", "CDL"].includes(p.Name));
|
|
277
17
|
if (options.fields === true) {
|
|
18
|
+
let server2 = new Server(options.server);
|
|
19
|
+
let resource2 = await server2.getResourceArgument(resourceName);
|
|
20
|
+
let definition = await server2.getResourceDefinition(resource2);
|
|
278
21
|
let response = await inquirer.prompt([
|
|
279
22
|
{
|
|
280
23
|
type: "checkbox",
|
|
@@ -287,31 +30,43 @@ async function getResourceDefinition(resourceName, options) {
|
|
|
287
30
|
]);
|
|
288
31
|
options.fields = response.fields.join(",");
|
|
289
32
|
}
|
|
290
|
-
let
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
if (options.
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
33
|
+
let server = new Server(options.server);
|
|
34
|
+
let resource = await server.getResourceArgument(resourceName);
|
|
35
|
+
let { APPFRAME_LOGIN: username = "", APPFRAME_PWD: password = "" } = process.env;
|
|
36
|
+
let client = new Client(options.server);
|
|
37
|
+
await client.login(username, password);
|
|
38
|
+
let content = await fetchAndGenerate(resource, options, client);
|
|
39
|
+
if (options.output) {
|
|
40
|
+
let header = buildYamlConfig(resource, options);
|
|
41
|
+
await writeFile(options.output, `${header}
|
|
42
|
+
${content}`, "utf-8");
|
|
43
|
+
await formatWithBiome(options.output);
|
|
44
|
+
console.log(`Written to ${options.output}`);
|
|
45
|
+
} else {
|
|
46
|
+
let command = [`af resources generate ${resource}`];
|
|
47
|
+
if (options.id) command.push(`--id ${options.id}`);
|
|
48
|
+
if (options.unique) command.push(`--unique ${options.unique}`);
|
|
49
|
+
if (options.global) command.push("--global");
|
|
50
|
+
if (options.types) command.push("--types");
|
|
51
|
+
if (options.maxRecords) command.push(`--max-records ${options.maxRecords}`);
|
|
52
|
+
if (options.sortOrder) command.push(`--sort-order ${options.sortOrder}`);
|
|
53
|
+
if (options.permissions) command.push(`--permissions ${options.permissions}`);
|
|
54
|
+
if (options.master) command.push(`--master ${options.master}`);
|
|
55
|
+
if (options.linkFields) command.push(`--link-fields ${options.linkFields}`);
|
|
56
|
+
if (options.expose) command.push(`--expose${typeof options.expose === "string" ? ` ${options.expose}` : ""}`);
|
|
57
|
+
if (options.dynamic) command.push("--dynamic");
|
|
58
|
+
if (options.overrides) command.push(`--overrides "${options.overrides}"`);
|
|
59
|
+
if (options.distinct) command.push("--distinct");
|
|
60
|
+
if (options.aggregates) command.push(`--aggregates ${options.aggregates}`);
|
|
61
|
+
if (options.groupBy) command.push(`--group-by ${options.groupBy}`);
|
|
62
|
+
if (options.where) command.push(`--where "${options.where}"`);
|
|
63
|
+
if (options.fields) command.push(`--fields ${options.fields}`);
|
|
64
|
+
console.log(`/*
|
|
309
65
|
auto-generated by CLI:
|
|
310
66
|
${command.join(" \\\n ")}
|
|
311
67
|
*/`);
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
);
|
|
68
|
+
console.log(content);
|
|
69
|
+
}
|
|
315
70
|
}
|
|
316
71
|
const program = new Command();
|
|
317
72
|
program.version(appPkg.version).addResourceArgument().option("-i, --id <id>", "ID to use as name for the data object", "dsDataObject").option("-g, --global", "Use af.data globals to generate the data object").option("-t, --types", "Include data object types").option("-f, --fields [fields]", "Comma-separated list of fields to include").option(
|
|
@@ -332,5 +87,8 @@ program.version(appPkg.version).addResourceArgument().option("-i, --id <id>", "I
|
|
|
332
87
|
).option("--group-by <fields>", "Comma separated list of fields to group by").option(
|
|
333
88
|
"--aggregates <fields>",
|
|
334
89
|
"Comma separated list of aggregate binding for non-grouped fields, e.g. Quantity:SUM,Created:MAX"
|
|
335
|
-
).option("--distinct", "Data object should fetch distinct data").option("--where <whereClause>", "Initial where clause to set on the data object").
|
|
90
|
+
).option("--distinct", "Data object should fetch distinct data").option("--where <whereClause>", "Initial where clause to set on the data object").option(
|
|
91
|
+
"-O, --output <path>",
|
|
92
|
+
"Write output to this file instead of stdout; also sets the correct relative import path for custom.d.ts"
|
|
93
|
+
).action(getResourceDefinition);
|
|
336
94
|
await program.parseAsync(process.argv);
|
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"af": "./cli/af.js"
|
|
6
6
|
},
|
|
7
7
|
"type": "module",
|
|
8
|
-
"version": "4.
|
|
8
|
+
"version": "4.5.0",
|
|
9
9
|
"license": "MIT",
|
|
10
10
|
"keywords": [
|
|
11
11
|
"appframe",
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"appframe web"
|
|
14
14
|
],
|
|
15
15
|
"devDependencies": {
|
|
16
|
+
"@types/adm-zip": "^0.5.8",
|
|
16
17
|
"@types/d3": "^7.4.3",
|
|
17
18
|
"@types/degit": "^2.8.6",
|
|
18
19
|
"@types/inquirer": "^9.0.9",
|
|
@@ -22,7 +23,8 @@
|
|
|
22
23
|
"tough-cookie": "^6.0.0"
|
|
23
24
|
},
|
|
24
25
|
"dependencies": {
|
|
25
|
-
"@biomejs/biome": "2.4.
|
|
26
|
+
"@biomejs/biome": "2.4.14",
|
|
27
|
+
"adm-zip": "^0.5.17",
|
|
26
28
|
"chalk": "^5.6.2",
|
|
27
29
|
"commander": "^14.0.1",
|
|
28
30
|
"compare-versions": "^6.1.1",
|
|
@@ -41,7 +43,8 @@
|
|
|
41
43
|
"signal-exit": "^4.1.0",
|
|
42
44
|
"typescript": "6.0.3",
|
|
43
45
|
"@olenbetong/appframe-data": "1.5.0",
|
|
44
|
-
"@olenbetong/appframe-updater": "0.4.10"
|
|
46
|
+
"@olenbetong/appframe-updater": "0.4.10",
|
|
47
|
+
"@olenbetong/appframe-vite": "6.2.0"
|
|
45
48
|
},
|
|
46
49
|
"optionalDependencies": {
|
|
47
50
|
"keytar": "^8.3.1"
|
package/src/af-bundle-upload.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { mkdirSync, renameSync, rmSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import AdmZip from "adm-zip";
|
|
1
4
|
import chalk from "chalk";
|
|
2
5
|
import { Command } from "commander";
|
|
3
6
|
import { config } from "dotenv";
|
|
@@ -10,6 +13,12 @@ import { Server } from "./lib/Server.js";
|
|
|
10
13
|
|
|
11
14
|
config({ path: `${process.cwd()}/.env`, quiet: true });
|
|
12
15
|
|
|
16
|
+
function createZip(sourceDir: string, outputFile: string) {
|
|
17
|
+
let zip = new AdmZip();
|
|
18
|
+
zip.addLocalFolder(sourceDir, sourceDir);
|
|
19
|
+
zip.writeZip(outputFile);
|
|
20
|
+
}
|
|
21
|
+
|
|
13
22
|
/**
|
|
14
23
|
* @param {string} pkgName
|
|
15
24
|
* @param {{ bundle?: string | null }} options
|
|
@@ -90,24 +99,24 @@ async function prepareBundle(pkgName: string, options: { bundle: string }) {
|
|
|
90
99
|
}
|
|
91
100
|
|
|
92
101
|
console.log("Removing previous...");
|
|
93
|
-
|
|
102
|
+
rmSync(rootOutputFolder, { recursive: true, force: true });
|
|
94
103
|
console.log("Packing...");
|
|
95
104
|
await execShellCommand(pkgName ? `npm pack ${pkgName}` : "npm pack");
|
|
96
105
|
console.log("Making output directory...");
|
|
97
|
-
|
|
106
|
+
mkdirSync(name, { recursive: true });
|
|
98
107
|
console.log(`Extracting '${tarball}'...`);
|
|
99
108
|
await execShellCommand(`tar -xvzf ${tarball} -C ${name}`);
|
|
100
109
|
console.log(`Moving from 'package' to '${version}'...`);
|
|
101
|
-
|
|
110
|
+
renameSync(join(name, "package"), join(name, version));
|
|
102
111
|
console.log("Zipping...");
|
|
103
|
-
|
|
112
|
+
createZip(rootOutputFolder, zipFileName);
|
|
104
113
|
console.log("Cleaning...");
|
|
105
|
-
|
|
106
|
-
|
|
114
|
+
rmSync(rootOutputFolder, { recursive: true, force: true });
|
|
115
|
+
rmSync(tarball);
|
|
107
116
|
|
|
108
117
|
if (id) {
|
|
109
118
|
await server.uploadBundle(Project_ID, id, zipFileName);
|
|
110
|
-
|
|
119
|
+
rmSync(zipFileName);
|
|
111
120
|
console.log("Done!");
|
|
112
121
|
} else {
|
|
113
122
|
console.log("Launching explorer...");
|