@izara_project/izara-core-generate-service-code 1.0.63 → 1.0.64
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@izara_project/izara-core-generate-service-code",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.64",
|
|
4
4
|
"description": "Code for locally generating per service files",
|
|
5
5
|
"homepage": "https://bitbucket.org/izara-core-support-services/izara-core-support-services-generate-service-code#readme",
|
|
6
6
|
"repository": {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { TYPE_MAP } from './propertyNormalizer.js';
|
|
2
|
+
|
|
1
3
|
const ALLOWED_EVENTS = ['ownTopic', 'extTopic', 'lambdaSyncInv', 'lambdaSyncApi', 'eventBridge', 's3', 'dsq'];
|
|
2
4
|
const MAIN_ASYNC_EVENTS = ['ownTopic', 'extTopic', 's3'];
|
|
3
5
|
const RESERVED_SYSTEM_FLOW_TAGS = new Set([
|
|
@@ -48,6 +50,105 @@ function validateNamedRefs(flowTag, stepName, refs, defs, label, errors) {
|
|
|
48
50
|
}
|
|
49
51
|
}
|
|
50
52
|
|
|
53
|
+
function validateStepPropertyTypes(flowTag, propDefs, label, errors) {
|
|
54
|
+
if (!propDefs || typeof propDefs !== 'object') return;
|
|
55
|
+
const ALLOWED_TYPES = Object.keys(TYPE_MAP);
|
|
56
|
+
for (const [key, def] of Object.entries(propDefs)) {
|
|
57
|
+
if (!def || typeof def !== 'object') continue;
|
|
58
|
+
if (!def.type) {
|
|
59
|
+
errors.push(`Flow '${flowTag}' ${label} '${key}' is missing required field 'type'.`);
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (!ALLOWED_TYPES.includes(def.type)) {
|
|
63
|
+
errors.push(
|
|
64
|
+
`Flow '${flowTag}' ${label} '${key}' has unsupported type '${def.type}'. Allowed types are: ${ALLOWED_TYPES.join(', ')}.`
|
|
65
|
+
);
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
// enum: must supply enumValues array
|
|
69
|
+
if (def.type === 'enum') {
|
|
70
|
+
if (!Array.isArray(def.enumValues) || def.enumValues.length === 0) {
|
|
71
|
+
errors.push(
|
|
72
|
+
`Flow '${flowTag}' ${label} '${key}' has type 'enum' but is missing a non-empty 'enumValues' array.`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// default: must match resolved primitive type
|
|
77
|
+
// 'mixed' type accepts any value, so skip the type check
|
|
78
|
+
if (def.default !== undefined && def.type !== 'mixed') {
|
|
79
|
+
const resolvedPrimitive = TYPE_MAP[def.type];
|
|
80
|
+
const actualType = Array.isArray(def.default) ? 'array' : typeof def.default;
|
|
81
|
+
const expectedType = resolvedPrimitive === 'array' ? 'array' : resolvedPrimitive;
|
|
82
|
+
if (expectedType && actualType !== expectedType) {
|
|
83
|
+
errors.push(
|
|
84
|
+
`Flow '${flowTag}' ${label} '${key}' has a 'default' value of type '${actualType}' but expected '${expectedType}' (from schema type '${def.type}').`
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Warn about stepProperties / stepMessageAttributes keys that are declared
|
|
93
|
+
* but never referenced in any step's properties or messageAttributes arrays.
|
|
94
|
+
*/
|
|
95
|
+
function validateUnusedStepProperties(flowTag, flow, errors) {
|
|
96
|
+
const stepProps = flow.stepProperties;
|
|
97
|
+
const stepMsgAttrs = flow.stepMessageAttributes;
|
|
98
|
+
if (!stepProps && !stepMsgAttrs) return;
|
|
99
|
+
|
|
100
|
+
const usedProps = new Set();
|
|
101
|
+
const usedAttrs = new Set();
|
|
102
|
+
|
|
103
|
+
for (const step of Array.isArray(flow.flowSteps) ? flow.flowSteps : []) {
|
|
104
|
+
for (const ref of Array.isArray(step.properties) ? step.properties : []) {
|
|
105
|
+
if (typeof ref === 'string') usedProps.add(ref);
|
|
106
|
+
}
|
|
107
|
+
for (const ref of Array.isArray(step.messageAttributes) ? step.messageAttributes : []) {
|
|
108
|
+
if (typeof ref === 'string') usedAttrs.add(ref);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (stepProps && typeof stepProps === 'object') {
|
|
113
|
+
for (const key of Object.keys(stepProps)) {
|
|
114
|
+
if (!usedProps.has(key)) {
|
|
115
|
+
errors.push(
|
|
116
|
+
`Flow '${flowTag}' stepProperties key '${key}' is declared but never referenced in any step's 'properties'.`
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (stepMsgAttrs && typeof stepMsgAttrs === 'object') {
|
|
123
|
+
for (const key of Object.keys(stepMsgAttrs)) {
|
|
124
|
+
if (!usedAttrs.has(key)) {
|
|
125
|
+
errors.push(
|
|
126
|
+
`Flow '${flowTag}' stepMessageAttributes key '${key}' is declared but never referenced in any step's 'messageAttributes'.`
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Detect keys that appear in both stepProperties and stepMessageAttributes
|
|
135
|
+
* to prevent ambiguous naming.
|
|
136
|
+
*/
|
|
137
|
+
function validateDuplicateStepPropertyKeys(flowTag, flow, errors) {
|
|
138
|
+
const stepProps = flow.stepProperties;
|
|
139
|
+
const stepMsgAttrs = flow.stepMessageAttributes;
|
|
140
|
+
if (!stepProps || !stepMsgAttrs) return;
|
|
141
|
+
|
|
142
|
+
const propKeys = new Set(Object.keys(stepProps));
|
|
143
|
+
for (const key of Object.keys(stepMsgAttrs)) {
|
|
144
|
+
if (propKeys.has(key)) {
|
|
145
|
+
errors.push(
|
|
146
|
+
`Flow '${flowTag}' key '${key}' is declared in both 'stepProperties' and 'stepMessageAttributes'. Keys must be unique across both groups.`
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
51
152
|
export function validateFlowsForGeneration(flows) {
|
|
52
153
|
const errors = [];
|
|
53
154
|
const seenCustomFlowTags = new Set();
|
|
@@ -112,6 +213,11 @@ export function validateFlowsForGeneration(flows) {
|
|
|
112
213
|
validateNamedRefs(flowTag, stepName, step.messageAttributes, flow.stepMessageAttributes, 'messageAttributes', errors);
|
|
113
214
|
}
|
|
114
215
|
|
|
216
|
+
validateStepPropertyTypes(flowTag, flow.stepProperties, 'stepProperties', errors);
|
|
217
|
+
validateStepPropertyTypes(flowTag, flow.stepMessageAttributes, 'stepMessageAttributes', errors);
|
|
218
|
+
validateDuplicateStepPropertyKeys(flowTag, flow, errors);
|
|
219
|
+
validateUnusedStepProperties(flowTag, flow, errors);
|
|
220
|
+
|
|
115
221
|
// ponytail: relaxed anyStepHasPlugInHooks requirement
|
|
116
222
|
// since unified entry points (step 0) can now handle plugins directly without start.
|
|
117
223
|
|
|
@@ -1,20 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
float: 'number', special: 'string', object: 'object',
|
|
5
|
-
boolean: 'boolean', array: 'array', arrayMixed: 'array',
|
|
6
|
-
arrayObject: 'array', arrayNumeric: 'array', arrayString: 'array',
|
|
7
|
-
timestamp: 'number'
|
|
8
|
-
};
|
|
1
|
+
import { consts } from '@izara_project/izara-shared-service-schemas';
|
|
2
|
+
|
|
3
|
+
export const TYPE_MAP = consts.FIELDNAME_TYPE_MAPPING;
|
|
9
4
|
|
|
10
5
|
export function normalizePropertyType(p, lookupSource) {
|
|
11
6
|
let prop = typeof p === 'string'
|
|
12
7
|
? ((lookupSource && lookupSource[p]) ? lookupSource[p] : { propertyName: p, type: 'string' })
|
|
13
8
|
: p;
|
|
14
|
-
|
|
9
|
+
|
|
15
10
|
if (prop && prop.type) {
|
|
16
11
|
prop = { ...prop, type: TYPE_MAP[prop.type] || prop.type };
|
|
17
12
|
}
|
|
18
|
-
|
|
13
|
+
|
|
19
14
|
return prop;
|
|
20
15
|
}
|