@olenbetong/appframe-vite 6.1.2 → 6.3.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/README.md +115 -5
- package/lib/cli-resources-add.d.ts +1 -0
- package/lib/cli-resources-add.js +192 -0
- package/lib/cli-resources-edit.d.ts +1 -0
- package/lib/cli-resources-edit.js +185 -0
- package/lib/cli-resources-generate.d.ts +1 -0
- package/lib/cli-resources-generate.js +43 -0
- package/lib/cli.js +45 -15
- package/lib/devtoolsServer.d.ts +7 -0
- package/lib/devtoolsServer.js +240 -0
- package/lib/index.d.ts +11 -1
- package/lib/index.js +50 -2
- package/lib/resourceGenerate.d.ts +63 -0
- package/lib/resourceGenerate.js +569 -0
- package/lib/resourcesConfig.d.ts +83 -0
- package/lib/resourcesConfig.js +180 -0
- package/package.json +14 -4
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
5
|
+
/**
|
|
6
|
+
* Build an inline TypeScript type string from a structured returnType definition.
|
|
7
|
+
*
|
|
8
|
+
* The server always returns a DataSet serialized as `{ Table: T[], Table1: U[], ... }`.
|
|
9
|
+
* The first table is always `"Table"`, subsequent ones are `"Table1"`, `"Table2"`, etc.
|
|
10
|
+
* An explicit `table` name on the entry overrides the auto-generated key (for procedures
|
|
11
|
+
* that assign custom DataTable.TableName values).
|
|
12
|
+
*/
|
|
13
|
+
export function returnTypeToString(returnType) {
|
|
14
|
+
if (returnType.length === 0) {
|
|
15
|
+
return "unknown";
|
|
16
|
+
}
|
|
17
|
+
function tableRowType(table) {
|
|
18
|
+
if (table.fields.length === 0) {
|
|
19
|
+
return "Record<string, unknown>";
|
|
20
|
+
}
|
|
21
|
+
let props = table.fields.map((f) => `${f.name}: ${f.type}`).join("; ");
|
|
22
|
+
return `{ ${props} }`;
|
|
23
|
+
}
|
|
24
|
+
function tableKey(table, index) {
|
|
25
|
+
if (table.table) {
|
|
26
|
+
return table.table;
|
|
27
|
+
}
|
|
28
|
+
return index === 0 ? "Table" : `Table${index}`;
|
|
29
|
+
}
|
|
30
|
+
let props = returnType.map((t, i) => `${tableKey(t, i)}: ${tableRowType(t)}[]`).join("; ");
|
|
31
|
+
return `{ ${props} }`;
|
|
32
|
+
}
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
// Config file path
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
export const RESOURCES_CONFIG_FILE = "resources.yaml";
|
|
37
|
+
export function getResourcesConfigPath(filePath) {
|
|
38
|
+
return resolve(process.cwd(), filePath ?? RESOURCES_CONFIG_FILE);
|
|
39
|
+
}
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
// Read / write
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
export async function readResourcesConfig(filePath) {
|
|
44
|
+
let configPath = getResourcesConfigPath(filePath);
|
|
45
|
+
if (!existsSync(configPath)) {
|
|
46
|
+
return {};
|
|
47
|
+
}
|
|
48
|
+
let raw = await readFile(configPath, "utf-8");
|
|
49
|
+
return parseYaml(raw) ?? {};
|
|
50
|
+
}
|
|
51
|
+
export async function writeResourcesConfig(config, filePath) {
|
|
52
|
+
let configPath = getResourcesConfigPath(filePath);
|
|
53
|
+
let content = stringifyYaml(config, { lineWidth: 120 });
|
|
54
|
+
await writeFile(configPath, content, "utf-8");
|
|
55
|
+
}
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
// Convert ResourceEntry ↔ CLIOptions
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
function arrayOrStringToString(value) {
|
|
60
|
+
if (value === undefined)
|
|
61
|
+
return undefined;
|
|
62
|
+
if (Array.isArray(value))
|
|
63
|
+
return value.join(",");
|
|
64
|
+
return value;
|
|
65
|
+
}
|
|
66
|
+
/** Convert sortOrder (new object format, old string/array) to comma-separated CLIOptions string. */
|
|
67
|
+
function sortOrderToString(sortOrder) {
|
|
68
|
+
if (!sortOrder)
|
|
69
|
+
return undefined;
|
|
70
|
+
if (typeof sortOrder === "string")
|
|
71
|
+
return sortOrder;
|
|
72
|
+
if (Array.isArray(sortOrder) && sortOrder.length === 0)
|
|
73
|
+
return undefined;
|
|
74
|
+
if (typeof sortOrder[0] === "string")
|
|
75
|
+
return sortOrder.join(",");
|
|
76
|
+
return sortOrder
|
|
77
|
+
.map((s) => (s.direction ? `${s.field}:${s.direction}` : s.field))
|
|
78
|
+
.join(",");
|
|
79
|
+
}
|
|
80
|
+
/** Convert aggregates (new object format, old string/array) to comma-separated CLIOptions string. */
|
|
81
|
+
function aggregatesToString(aggregates) {
|
|
82
|
+
if (!aggregates)
|
|
83
|
+
return undefined;
|
|
84
|
+
if (typeof aggregates === "string")
|
|
85
|
+
return aggregates;
|
|
86
|
+
if (Array.isArray(aggregates) && aggregates.length === 0)
|
|
87
|
+
return undefined;
|
|
88
|
+
if (typeof aggregates[0] === "string")
|
|
89
|
+
return aggregates.join(",");
|
|
90
|
+
return aggregates.map((a) => `${a.field}:${a.aggregate}`).join(",");
|
|
91
|
+
}
|
|
92
|
+
/** Convert a `ResourceEntry` into a `CLIOptions`-compatible object for code generation. */
|
|
93
|
+
export function entryToCLIOptions(entry, hostname) {
|
|
94
|
+
return {
|
|
95
|
+
server: hostname,
|
|
96
|
+
id: entry.id,
|
|
97
|
+
global: entry.global ?? false,
|
|
98
|
+
dynamic: entry.dynamic ?? false,
|
|
99
|
+
types: entry.types,
|
|
100
|
+
maxRecords: entry.maxRecords !== undefined ? String(entry.maxRecords) : "50",
|
|
101
|
+
sortOrder: sortOrderToString(entry.sortOrder),
|
|
102
|
+
permissions: entry.permissions,
|
|
103
|
+
master: entry.master,
|
|
104
|
+
linkFields: arrayOrStringToString(entry.linkFields),
|
|
105
|
+
expose: entry.expose,
|
|
106
|
+
unique: entry.unique,
|
|
107
|
+
overrides: arrayOrStringToString(entry.overrides),
|
|
108
|
+
distinct: entry.distinct,
|
|
109
|
+
aggregates: aggregatesToString(entry.aggregates),
|
|
110
|
+
groupBy: entry.groupBy?.join(","),
|
|
111
|
+
where: entry.where,
|
|
112
|
+
fields: arrayOrStringToString(entry.fields) ?? false,
|
|
113
|
+
output: resolve(process.cwd(), entry.output ?? `src/data/${entry.id}.ts`),
|
|
114
|
+
typesJsonReturnType: entry.returnType ? returnTypeToString(entry.returnType) : undefined,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
/** Convert a `CLIOptions` back to a `ResourceEntry` for saving to YAML. */
|
|
118
|
+
export function cliOptionsToEntry(resource, options) {
|
|
119
|
+
function maybeArray(value) {
|
|
120
|
+
if (!value)
|
|
121
|
+
return undefined;
|
|
122
|
+
let arr = value.split(",").filter(Boolean);
|
|
123
|
+
return arr.length > 1 ? arr : undefined;
|
|
124
|
+
}
|
|
125
|
+
let entry = {
|
|
126
|
+
id: options.id,
|
|
127
|
+
resource,
|
|
128
|
+
output: options.output ?? `src/data/${options.id}.ts`,
|
|
129
|
+
};
|
|
130
|
+
if (options.global)
|
|
131
|
+
entry.global = true;
|
|
132
|
+
if (options.types)
|
|
133
|
+
entry.types = true;
|
|
134
|
+
if (options.permissions)
|
|
135
|
+
entry.permissions = options.permissions;
|
|
136
|
+
if (options.maxRecords && options.maxRecords !== "50") {
|
|
137
|
+
entry.maxRecords = Number(options.maxRecords);
|
|
138
|
+
}
|
|
139
|
+
if (options.sortOrder) {
|
|
140
|
+
entry.sortOrder = options.sortOrder
|
|
141
|
+
.split(",")
|
|
142
|
+
.filter(Boolean)
|
|
143
|
+
.map((s) => {
|
|
144
|
+
const [field, direction] = s.split(":");
|
|
145
|
+
return direction ? { field, direction } : { field };
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
if (options.master)
|
|
149
|
+
entry.master = options.master;
|
|
150
|
+
if (options.linkFields)
|
|
151
|
+
entry.linkFields = maybeArray(options.linkFields) ?? options.linkFields;
|
|
152
|
+
if (options.expose !== undefined)
|
|
153
|
+
entry.expose = options.expose;
|
|
154
|
+
if (options.dynamic)
|
|
155
|
+
entry.dynamic = true;
|
|
156
|
+
if (options.unique)
|
|
157
|
+
entry.unique = options.unique;
|
|
158
|
+
if (options.overrides)
|
|
159
|
+
entry.overrides = maybeArray(options.overrides) ?? options.overrides;
|
|
160
|
+
if (options.distinct)
|
|
161
|
+
entry.distinct = true;
|
|
162
|
+
if (options.aggregates) {
|
|
163
|
+
entry.aggregates = options.aggregates
|
|
164
|
+
.split(",")
|
|
165
|
+
.filter(Boolean)
|
|
166
|
+
.map((a) => {
|
|
167
|
+
const [field, aggregate] = a.split(":");
|
|
168
|
+
return { field, aggregate: aggregate ?? "" };
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
if (options.groupBy)
|
|
172
|
+
entry.groupBy = options.groupBy.split(",").filter(Boolean);
|
|
173
|
+
if (options.where)
|
|
174
|
+
entry.where = options.where;
|
|
175
|
+
if (options.fields && typeof options.fields === "string") {
|
|
176
|
+
let fields = options.fields.split(",").filter(Boolean);
|
|
177
|
+
entry.fields = fields.length > 1 ? fields : options.fields;
|
|
178
|
+
}
|
|
179
|
+
return entry;
|
|
180
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@olenbetong/appframe-vite",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.3.0",
|
|
4
4
|
"description": "Tools to use and deploy Vite applications to Appframe",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -13,6 +13,10 @@
|
|
|
13
13
|
"./proxy": {
|
|
14
14
|
"import": "./lib/proxy.js",
|
|
15
15
|
"types": "./lib/proxy.d.ts"
|
|
16
|
+
},
|
|
17
|
+
"./resources": {
|
|
18
|
+
"import": "./lib/resourceGenerate.js",
|
|
19
|
+
"types": "./lib/resourceGenerate.d.ts"
|
|
16
20
|
}
|
|
17
21
|
},
|
|
18
22
|
"files": [
|
|
@@ -25,19 +29,25 @@
|
|
|
25
29
|
"author": "Bjørnar Vister Hansen <bvh@olenbetong.no>",
|
|
26
30
|
"license": "MIT",
|
|
27
31
|
"dependencies": {
|
|
32
|
+
"@olenbetong/appframe-data": "1.5.0",
|
|
28
33
|
"body-parser": "^2.2.2",
|
|
29
34
|
"chalk": "^5.4.1",
|
|
30
35
|
"chokidar": "^5.0.0",
|
|
36
|
+
"commander": "^14.0.1",
|
|
31
37
|
"dotenv": "^17.2.3",
|
|
32
|
-
"
|
|
38
|
+
"fuzzy": "^0.1.3",
|
|
39
|
+
"inquirer": "^12.9.6",
|
|
40
|
+
"inquirer-autocomplete-standalone": "^0.8.1",
|
|
41
|
+
"jsdom": "29.1.1",
|
|
33
42
|
"rollup-plugin-visualizer": "^6.0.5",
|
|
34
|
-
"
|
|
43
|
+
"yaml": "^2.8.4",
|
|
44
|
+
"@olenbetong/appframe-devtools": "0.1.0"
|
|
35
45
|
},
|
|
36
46
|
"devDependencies": {
|
|
37
47
|
"@types/jsdom": "^27.0.0",
|
|
38
48
|
"@types/node": "25.6.0",
|
|
39
49
|
"typescript": "6.0.3",
|
|
40
|
-
"vite": "8.0.
|
|
50
|
+
"vite": "8.0.10"
|
|
41
51
|
},
|
|
42
52
|
"peerDependencies": {
|
|
43
53
|
"vite": ">=5.0.0"
|