@atmyapp/cli 0.0.4 → 0.0.7
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.
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Logger } from "../logger";
|
|
2
|
+
interface JsonSchema {
|
|
3
|
+
[key: string]: any;
|
|
4
|
+
}
|
|
5
|
+
export declare function isAmaCollectionStructure(structure: unknown): boolean;
|
|
6
|
+
export declare function convertAmaCollectionStructure(path: string, structure: JsonSchema, logger: Logger): JsonSchema | null;
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isAmaCollectionStructure = isAmaCollectionStructure;
|
|
4
|
+
exports.convertAmaCollectionStructure = convertAmaCollectionStructure;
|
|
5
|
+
const RESERVED_FIELD_NAMES = new Set(["id", "created_at"]);
|
|
6
|
+
const PRIMITIVE_TYPES = new Set(["string", "number", "boolean", "null"]);
|
|
7
|
+
const SUPPORTED_TYPES = new Set([...PRIMITIVE_TYPES, "array", "object"]);
|
|
8
|
+
const AMA_ASSET_TYPE_MAP = {
|
|
9
|
+
AmaImage: { format: "image" },
|
|
10
|
+
AmaFile: { format: "file" },
|
|
11
|
+
AmaIcon: { format: "image", semanticType: "image" },
|
|
12
|
+
};
|
|
13
|
+
function detectAmaAssetField(schema) {
|
|
14
|
+
var _a, _b, _c, _d, _e, _f;
|
|
15
|
+
const structureProperties = (_b = (_a = schema === null || schema === void 0 ? void 0 : schema.properties) === null || _a === void 0 ? void 0 : _a.structure) === null || _b === void 0 ? void 0 : _b.properties;
|
|
16
|
+
const amaType = (_c = structureProperties === null || structureProperties === void 0 ? void 0 : structureProperties.__amatype) === null || _c === void 0 ? void 0 : _c.const;
|
|
17
|
+
if (typeof amaType !== "string") {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
const assetMapping = AMA_ASSET_TYPE_MAP[amaType];
|
|
21
|
+
if (!assetMapping) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
let imageOptions;
|
|
25
|
+
const configSchema = (_d = structureProperties === null || structureProperties === void 0 ? void 0 : structureProperties.__config) === null || _d === void 0 ? void 0 : _d.properties;
|
|
26
|
+
if (configSchema && configSchema.imageOptions) {
|
|
27
|
+
const optionsSchema = configSchema.imageOptions;
|
|
28
|
+
imageOptions = (_f = (_e = optionsSchema.const) !== null && _e !== void 0 ? _e : optionsSchema.default) !== null && _f !== void 0 ? _f : undefined;
|
|
29
|
+
}
|
|
30
|
+
return Object.assign({ format: assetMapping.format, semanticType: assetMapping.semanticType }, (imageOptions ? { imageOptions } : {}));
|
|
31
|
+
}
|
|
32
|
+
function ensureDescription(description, fallback) {
|
|
33
|
+
if (typeof description === "string" && description.trim().length > 0) {
|
|
34
|
+
return description.trim();
|
|
35
|
+
}
|
|
36
|
+
return fallback;
|
|
37
|
+
}
|
|
38
|
+
function normalizeType(type) {
|
|
39
|
+
if (typeof type === "string") {
|
|
40
|
+
return type;
|
|
41
|
+
}
|
|
42
|
+
if (Array.isArray(type)) {
|
|
43
|
+
const withoutNull = type.filter((value) => value !== "null");
|
|
44
|
+
if (withoutNull.length === 1) {
|
|
45
|
+
return withoutNull[0];
|
|
46
|
+
}
|
|
47
|
+
if (withoutNull.length === 0 && type.includes("null")) {
|
|
48
|
+
return "null";
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
function inferType(schema) {
|
|
54
|
+
let type = normalizeType(schema.type);
|
|
55
|
+
if (!type && Array.isArray(schema.enum) && schema.enum.length > 0) {
|
|
56
|
+
const enumTypes = new Set(schema.enum.map((value) => typeof value));
|
|
57
|
+
if (enumTypes.size === 1) {
|
|
58
|
+
type = enumTypes.has("string")
|
|
59
|
+
? "string"
|
|
60
|
+
: enumTypes.has("number")
|
|
61
|
+
? "number"
|
|
62
|
+
: enumTypes.has("boolean")
|
|
63
|
+
? "boolean"
|
|
64
|
+
: null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (!type) {
|
|
68
|
+
switch (typeof schema.const) {
|
|
69
|
+
case "string":
|
|
70
|
+
type = "string";
|
|
71
|
+
break;
|
|
72
|
+
case "number":
|
|
73
|
+
type = "number";
|
|
74
|
+
break;
|
|
75
|
+
case "boolean":
|
|
76
|
+
type = "boolean";
|
|
77
|
+
break;
|
|
78
|
+
default:
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return type;
|
|
83
|
+
}
|
|
84
|
+
function copyProperties(target, source, keys) {
|
|
85
|
+
keys.forEach((key) => {
|
|
86
|
+
if (key in source) {
|
|
87
|
+
target[key] = source[key];
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
function convertArrayItems(schema, fieldName, logger, breadcrumb) {
|
|
92
|
+
if (!schema.items) {
|
|
93
|
+
logger.error(`Collection conversion failed for field "${breadcrumb}": array items schema is missing.`);
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
return convertField(schema.items, fieldName, logger, `${breadcrumb}[]`);
|
|
97
|
+
}
|
|
98
|
+
function convertObjectProperties(schema, logger, breadcrumb) {
|
|
99
|
+
const rawProperties = schema.properties;
|
|
100
|
+
const converted = {};
|
|
101
|
+
if (!rawProperties || typeof rawProperties !== "object") {
|
|
102
|
+
return { properties: converted };
|
|
103
|
+
}
|
|
104
|
+
for (const [childName, childSchema] of Object.entries(rawProperties)) {
|
|
105
|
+
const childBreadcrumb = `${breadcrumb}.${childName}`;
|
|
106
|
+
const convertedChild = convertField(childSchema, childName, logger, childBreadcrumb);
|
|
107
|
+
if (!convertedChild) {
|
|
108
|
+
logger.error(`Collection conversion failed for field "${childBreadcrumb}": unsupported schema.`);
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
converted[childName] = convertedChild;
|
|
112
|
+
}
|
|
113
|
+
const required = Array.isArray(schema.required)
|
|
114
|
+
? schema.required.filter((value) => typeof value === "string")
|
|
115
|
+
: undefined;
|
|
116
|
+
return { properties: converted, required };
|
|
117
|
+
}
|
|
118
|
+
function convertField(schema, fieldName, logger, breadcrumb) {
|
|
119
|
+
if (!schema || typeof schema !== "object") {
|
|
120
|
+
logger.error(`Collection conversion failed for field "${breadcrumb}": schema is not an object.`);
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
const amaAsset = detectAmaAssetField(schema);
|
|
124
|
+
if (amaAsset) {
|
|
125
|
+
const description = ensureDescription(schema.description, `Generated description for ${breadcrumb}`);
|
|
126
|
+
const base = {
|
|
127
|
+
type: "string",
|
|
128
|
+
description,
|
|
129
|
+
format: amaAsset.format,
|
|
130
|
+
};
|
|
131
|
+
if (amaAsset.semanticType) {
|
|
132
|
+
base.semanticType = amaAsset.semanticType;
|
|
133
|
+
}
|
|
134
|
+
if (amaAsset.imageOptions) {
|
|
135
|
+
base.imageOptions = amaAsset.imageOptions;
|
|
136
|
+
}
|
|
137
|
+
return base;
|
|
138
|
+
}
|
|
139
|
+
let type = inferType(schema);
|
|
140
|
+
if (!type) {
|
|
141
|
+
logger.error(`Collection conversion failed for field "${breadcrumb}": could not determine field type.`);
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
if (type === "integer") {
|
|
145
|
+
type = "number";
|
|
146
|
+
}
|
|
147
|
+
if (!SUPPORTED_TYPES.has(type)) {
|
|
148
|
+
logger.error(`Collection conversion failed for field "${breadcrumb}": unsupported field type "${type}".`);
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
const description = ensureDescription(schema.description, `Generated description for ${breadcrumb}`);
|
|
152
|
+
const base = { type, description };
|
|
153
|
+
if (PRIMITIVE_TYPES.has(type)) {
|
|
154
|
+
copyProperties(base, schema, [
|
|
155
|
+
"enum",
|
|
156
|
+
"default",
|
|
157
|
+
"format",
|
|
158
|
+
"semanticType",
|
|
159
|
+
"storeInBlob",
|
|
160
|
+
"imageOptions",
|
|
161
|
+
"maxLength",
|
|
162
|
+
"minLength",
|
|
163
|
+
"pattern",
|
|
164
|
+
"minimum",
|
|
165
|
+
"maximum",
|
|
166
|
+
"multipleOf",
|
|
167
|
+
]);
|
|
168
|
+
return base;
|
|
169
|
+
}
|
|
170
|
+
if (type === "array") {
|
|
171
|
+
const items = convertArrayItems(schema, fieldName, logger, breadcrumb);
|
|
172
|
+
if (!items) {
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
base.items = items;
|
|
176
|
+
copyProperties(base, schema, ["minItems", "maxItems", "uniqueItems", "default"]);
|
|
177
|
+
return base;
|
|
178
|
+
}
|
|
179
|
+
// Object type
|
|
180
|
+
const converted = convertObjectProperties(schema, logger, breadcrumb);
|
|
181
|
+
if (!converted) {
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
if (Object.keys(converted.properties).length > 0) {
|
|
185
|
+
base.properties = converted.properties;
|
|
186
|
+
}
|
|
187
|
+
if (converted.required && converted.required.length > 0) {
|
|
188
|
+
base.required = converted.required;
|
|
189
|
+
}
|
|
190
|
+
copyProperties(base, schema, ["default"]);
|
|
191
|
+
return base;
|
|
192
|
+
}
|
|
193
|
+
function extractIndexes(configSchema) {
|
|
194
|
+
var _a, _b;
|
|
195
|
+
const indexedColumnsSchema = (_a = configSchema === null || configSchema === void 0 ? void 0 : configSchema.properties) === null || _a === void 0 ? void 0 : _a.indexedColumns;
|
|
196
|
+
if (!indexedColumnsSchema) {
|
|
197
|
+
return undefined;
|
|
198
|
+
}
|
|
199
|
+
const value = (_b = indexedColumnsSchema.const) !== null && _b !== void 0 ? _b : indexedColumnsSchema.default;
|
|
200
|
+
if (!Array.isArray(value)) {
|
|
201
|
+
return undefined;
|
|
202
|
+
}
|
|
203
|
+
const indexes = value.filter((entry) => typeof entry === "string");
|
|
204
|
+
if (indexes.length === 0) {
|
|
205
|
+
return undefined;
|
|
206
|
+
}
|
|
207
|
+
return indexes.slice(0, 10);
|
|
208
|
+
}
|
|
209
|
+
function isAmaCollectionStructure(structure) {
|
|
210
|
+
var _a;
|
|
211
|
+
return Boolean(structure &&
|
|
212
|
+
typeof structure === "object" &&
|
|
213
|
+
((_a = structure.properties) === null || _a === void 0 ? void 0 : _a.__rowType));
|
|
214
|
+
}
|
|
215
|
+
function convertAmaCollectionStructure(path, structure, logger) {
|
|
216
|
+
var _a, _b;
|
|
217
|
+
if (!isAmaCollectionStructure(structure)) {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
const rowTypeSchema = (_a = structure.properties) === null || _a === void 0 ? void 0 : _a.__rowType;
|
|
221
|
+
if (!rowTypeSchema || typeof rowTypeSchema !== "object") {
|
|
222
|
+
logger.error(`Collection conversion failed for "${path}": missing __rowType definition.`);
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
const rowTypeType = inferType(rowTypeSchema);
|
|
226
|
+
if (rowTypeType !== "object") {
|
|
227
|
+
logger.error(`Collection conversion failed for "${path}": __rowType is not an object.`);
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
const rawFields = rowTypeSchema.properties;
|
|
231
|
+
if (!rawFields || typeof rawFields !== "object") {
|
|
232
|
+
logger.error(`Collection conversion failed for "${path}": __rowType has no properties.`);
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
const properties = {};
|
|
236
|
+
for (const [fieldName, fieldSchema] of Object.entries(rawFields)) {
|
|
237
|
+
if (RESERVED_FIELD_NAMES.has(fieldName)) {
|
|
238
|
+
logger.error(`Collection conversion failed for "${path}": field "${fieldName}" is reserved.`);
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
const converted = convertField(fieldSchema, fieldName, logger, `${path}.${fieldName}`);
|
|
242
|
+
if (!converted) {
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
properties[fieldName] = converted;
|
|
246
|
+
}
|
|
247
|
+
const required = Array.isArray(rowTypeSchema.required)
|
|
248
|
+
? rowTypeSchema.required.filter((value) => typeof value === "string")
|
|
249
|
+
: [];
|
|
250
|
+
const description = ensureDescription(structure.description, `Generated collection for ${path}`);
|
|
251
|
+
const indexes = extractIndexes((_b = structure.properties) === null || _b === void 0 ? void 0 : _b.__config);
|
|
252
|
+
const collectionStructure = {
|
|
253
|
+
description,
|
|
254
|
+
properties,
|
|
255
|
+
};
|
|
256
|
+
if (required.length > 0) {
|
|
257
|
+
collectionStructure.required = required;
|
|
258
|
+
}
|
|
259
|
+
if (indexes && indexes.length > 0) {
|
|
260
|
+
collectionStructure.indexes = indexes;
|
|
261
|
+
}
|
|
262
|
+
return collectionStructure;
|
|
263
|
+
}
|
|
@@ -18,6 +18,9 @@ function determineContentType(content) {
|
|
|
18
18
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
|
|
19
19
|
// Extract file extension
|
|
20
20
|
const fileExt = (_a = content.path.split(".").pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
21
|
+
if (content.type === "collection") {
|
|
22
|
+
return "collection";
|
|
23
|
+
}
|
|
21
24
|
// Check for event types - support both custom events and basic events
|
|
22
25
|
if (((_b = content.structure) === null || _b === void 0 ? void 0 : _b.type) === "event" ||
|
|
23
26
|
((_c = content.structure) === null || _c === void 0 ? void 0 : _c.type) === "basic_event" ||
|
|
@@ -47,6 +47,7 @@ export declare const definitionPipeline: DefinitionProcessingPipeline;
|
|
|
47
47
|
export declare const builtInProcessors: {
|
|
48
48
|
typeDetector: DefinitionProcessor;
|
|
49
49
|
pathNormalizer: DefinitionProcessor;
|
|
50
|
+
collectionStructureConverter: DefinitionProcessor;
|
|
50
51
|
};
|
|
51
52
|
export declare const builtInValidators: {
|
|
52
53
|
pathValidator: ValidationRule;
|
|
@@ -4,6 +4,7 @@ exports.builtInOutputTransformers = exports.builtInValidators = exports.builtInP
|
|
|
4
4
|
exports.registerBuiltInProcessors = registerBuiltInProcessors;
|
|
5
5
|
exports.registerBuiltInValidators = registerBuiltInValidators;
|
|
6
6
|
exports.registerBuiltInOutputTransformers = registerBuiltInOutputTransformers;
|
|
7
|
+
const collection_transformer_1 = require("./collection-transformer");
|
|
7
8
|
// Registry for processors, transformers, and validators
|
|
8
9
|
class DefinitionProcessingPipeline {
|
|
9
10
|
constructor() {
|
|
@@ -135,6 +136,10 @@ exports.builtInProcessors = {
|
|
|
135
136
|
process: (content, context) => {
|
|
136
137
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
137
138
|
const { logger } = context;
|
|
139
|
+
if (content.type) {
|
|
140
|
+
logger.verbose_log(`Preserving pre-detected type "${content.type}" for ${content.path}`);
|
|
141
|
+
return content;
|
|
142
|
+
}
|
|
138
143
|
// Extract file extension
|
|
139
144
|
const fileExt = (_a = content.path.split(".").pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
140
145
|
// Check for event types first
|
|
@@ -181,6 +186,21 @@ exports.builtInProcessors = {
|
|
|
181
186
|
return content;
|
|
182
187
|
},
|
|
183
188
|
},
|
|
189
|
+
collectionStructureConverter: {
|
|
190
|
+
name: "collection-structure-converter",
|
|
191
|
+
process: (content, context) => {
|
|
192
|
+
const { logger } = context;
|
|
193
|
+
if (!(0, collection_transformer_1.isAmaCollectionStructure)(content.structure)) {
|
|
194
|
+
return content;
|
|
195
|
+
}
|
|
196
|
+
const converted = (0, collection_transformer_1.convertAmaCollectionStructure)(content.path, content.structure, logger);
|
|
197
|
+
if (!converted) {
|
|
198
|
+
logger.warn(`Skipping definition "${content.path}" due to collection conversion errors.`);
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
return Object.assign(Object.assign({}, content), { type: "collection", structure: converted });
|
|
202
|
+
},
|
|
203
|
+
},
|
|
184
204
|
};
|
|
185
205
|
// Built-in validators
|
|
186
206
|
exports.builtInValidators = {
|
|
@@ -240,6 +260,7 @@ exports.builtInOutputTransformers = {
|
|
|
240
260
|
// Helper functions to register built-in components
|
|
241
261
|
function registerBuiltInProcessors() {
|
|
242
262
|
exports.definitionPipeline.addProcessor(exports.builtInProcessors.pathNormalizer);
|
|
263
|
+
exports.definitionPipeline.addProcessor(exports.builtInProcessors.collectionStructureConverter);
|
|
243
264
|
exports.definitionPipeline.addProcessor(exports.builtInProcessors.typeDetector);
|
|
244
265
|
}
|
|
245
266
|
function registerBuiltInValidators() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atmyapp/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"scripts": {
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"license": "ISC",
|
|
29
29
|
"description": "",
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"@atmyapp/core": "^0.0.
|
|
31
|
+
"@atmyapp/core": "^0.0.6",
|
|
32
32
|
"@types/jest": "^29.5.14",
|
|
33
33
|
"@typescript-eslint/eslint-plugin": "^8.32.1",
|
|
34
34
|
"@typescript-eslint/parser": "^8.32.1",
|