@hahnpro/flow-cli 2.8.0 → 2.12.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/lib/utils.mjs ADDED
@@ -0,0 +1,197 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+
4
+ const defaultLogger = {
5
+ /* eslint-disable no-console */
6
+ log: console.log,
7
+ error: console.error,
8
+ ok: console.info,
9
+ /* eslint-enable no-console */
10
+ };
11
+
12
+ export function checkTypes(definedTypes, propertiesSchema, jsonPath, logger = defaultLogger) {
13
+ const knownTypes = new Set([
14
+ ...definedTypes,
15
+ 'string',
16
+ 'undefined',
17
+ 'number',
18
+ 'boolean',
19
+ 'any',
20
+ 'object',
21
+ 'array',
22
+ 'integer',
23
+ 'Asset',
24
+ 'AssetType',
25
+ 'Flow',
26
+ 'Secret',
27
+ 'TimeSeries',
28
+ ]);
29
+
30
+ // check if all types are known
31
+ const properties = propertiesSchema.properties || {};
32
+ for (const property of Object.keys(properties)) {
33
+ if (properties[property].type && !knownTypes.has(properties[property].type)) {
34
+ logger.error(
35
+ `ERROR: unknown type ${properties[property].type}.
36
+ Please add a schema for this type in ${jsonPath}
37
+ for more info check the documentation`,
38
+ );
39
+ return false;
40
+ }
41
+ }
42
+ return true;
43
+ }
44
+
45
+ export async function getTypes(filePath) {
46
+ try {
47
+ const json = JSON.parse(await fs.readFile(path.join(process.cwd(), filePath)));
48
+ return json.definitions ? Object.keys(json.definitions) : [];
49
+ } catch {
50
+ return [];
51
+ }
52
+ }
53
+
54
+ export async function handleConvertedOutput(result, jsonPath, json, logger = defaultLogger) {
55
+ let schema;
56
+ try {
57
+ schema = JSON.parse(result);
58
+ } catch {
59
+ logger.error(result);
60
+ return json;
61
+ }
62
+
63
+ const values = [
64
+ ['propertiesSchema', 'Properties'],
65
+ ['inputStreams', 'InputProperties'],
66
+ ['outputStreams', 'OutputProperties'],
67
+ ];
68
+
69
+ for (const value of values) {
70
+ const propertiesSchema = schema[value[1]] || {};
71
+ for (const requestProperty of propertiesSchema.required || []) {
72
+ propertiesSchema.properties[requestProperty] = { ...propertiesSchema.properties[requestProperty], required: true };
73
+ }
74
+ // remove required field
75
+ delete propertiesSchema.required;
76
+
77
+ const types = await getTypes(jsonPath);
78
+ checkTypes(types, propertiesSchema, jsonPath);
79
+
80
+ const completeSchema = {
81
+ schema: {
82
+ type: 'object',
83
+ properties: {
84
+ ...propertiesSchema.properties,
85
+ },
86
+ },
87
+ };
88
+
89
+ if (value[0] === 'propertiesSchema') {
90
+ if (!json['propertiesSchema']) {
91
+ json['propertiesSchema'] = completeSchema;
92
+ }
93
+ } else {
94
+ // check if config for default input/output stream exists
95
+ if (!json[value[0]].some((v) => v.name === 'default') && propertiesSchema) {
96
+ json[value[0]].push({
97
+ name: 'default',
98
+ ...completeSchema,
99
+ });
100
+ }
101
+ }
102
+ }
103
+
104
+ // add definitions
105
+ if (Object.keys(schema).some((key) => !['Properties', 'InputProperties', 'OutputProperties'].includes(key))) {
106
+ const typeDefinitions = Object.keys(schema).filter((key) => !['Properties', 'InputProperties', 'OutputProperties'].includes(key));
107
+ json.definitions = typeDefinitions.reduce((previousValue, currentValue) => {
108
+ const additionalSchema = schema[currentValue];
109
+ for (const requestProperty of additionalSchema.required || []) {
110
+ additionalSchema.properties[requestProperty] = { ...additionalSchema.properties[requestProperty], required: true };
111
+ }
112
+ delete additionalSchema.required;
113
+ previousValue[currentValue] = additionalSchema;
114
+ return previousValue;
115
+ }, {});
116
+ }
117
+ return json;
118
+ }
119
+
120
+ export function prepareTsFile(file) {
121
+ // if a class extends another and does not have its own fields no metadata is generated and so no schema can be generated
122
+ // in this case replace empty block with the block it inherits from
123
+ let codeBlocks = getCodeBlocks(file);
124
+ const emptyExtendsBlock = codeBlocks.find((block) => blockDefinitionIncludes(block, 'extends') && isBlockEmpty(block));
125
+ if (emptyExtendsBlock) {
126
+ // replace block and remove extends
127
+ let replBlock = `${emptyExtendsBlock}`;
128
+ if (replBlock.replace(/\s\s+/g, ' ').trim().startsWith('class OutputProperties')) {
129
+ // remove extends
130
+ replBlock = replBlock.replace('extends InputProperties', '');
131
+ // replace block with InputProperties block
132
+ const inputPropertiesBlock = codeBlocks.find(
133
+ (v) => blockDefinitionIncludes(v, 'InputProperties') && !blockDefinitionIncludes(v, 'OutputProperties'),
134
+ );
135
+ replBlock = replBlock.replace(getBlockContent(replBlock), getBlockContent(inputPropertiesBlock));
136
+
137
+ file = file.replace(emptyExtendsBlock, replBlock);
138
+ }
139
+ }
140
+ return (
141
+ `import { validationMetadatasToSchemas as v } from 'class-validator-jsonschema';\n` +
142
+ `import { defaultMetadataStorage as classTransformerDefaultMetadataStorage } from 'class-transformer/cjs/storage';\n` +
143
+ `${file}\n` +
144
+ `const s = v({\n
145
+ additionalConverters: {\n
146
+ UnitArgsValidator: (meta) => {\n
147
+ return {\n
148
+ measure: meta.constraints[0],\n
149
+ unit: meta.constraints[1],\n
150
+ type: 'number',\n
151
+ };\n
152
+ },\n
153
+ },\n
154
+ classTransformerMetadataStorage\n
155
+ });\n` +
156
+ `console.log(JSON.stringify(s));`
157
+ );
158
+ }
159
+
160
+ export function getCodeBlocks(string_) {
161
+ const blocks = [];
162
+ let counter = 0;
163
+ let start = 0;
164
+ let lastNewline = 0;
165
+ for (const [index, char] of [...string_].entries()) {
166
+ if (char === '\n') {
167
+ lastNewline = index;
168
+ }
169
+ if (char === '{') {
170
+ if (counter === 0) {
171
+ // first bracket of block
172
+ start = lastNewline;
173
+ }
174
+ counter++;
175
+ } else if (char === '}') {
176
+ counter--;
177
+ if (counter === 0) {
178
+ // last bracket of block
179
+ blocks.push(string_.slice(start, index + 1));
180
+ }
181
+ }
182
+ }
183
+ return blocks;
184
+ }
185
+
186
+ function blockDefinitionIncludes(block, value) {
187
+ return block.trim().split('\n', 1)[0].includes(value);
188
+ }
189
+
190
+ function getBlockContent(block) {
191
+ return block.slice(block.indexOf('{'), block.lastIndexOf('}') + 1);
192
+ }
193
+
194
+ function isBlockEmpty(block) {
195
+ const blockContent = block.slice(block.indexOf('{') + 1, block.lastIndexOf('}'));
196
+ return !blockContent.trim();
197
+ }
package/package.json CHANGED
@@ -1,18 +1,19 @@
1
1
  {
2
2
  "name": "@hahnpro/flow-cli",
3
- "version": "2.8.0",
3
+ "version": "2.12.0",
4
4
  "description": "CLI for managing Flow Modules",
5
5
  "license": "MIT",
6
+ "type": "module",
6
7
  "author": {
7
8
  "name": "Hahn Projects GmbH",
8
9
  "url": "https://hahnpro.com"
9
10
  },
10
11
  "repository": {
11
12
  "type": "git",
12
- "url": "git@gitlab.com:hahnpro/flow.git"
13
+ "url": "git@github.com:hahnprojects/flow.git"
13
14
  },
14
15
  "bin": {
15
- "flow": "lib/cli.js"
16
+ "flow": "lib/cli.mjs"
16
17
  },
17
18
  "directories": {
18
19
  "lib": "lib",
@@ -24,42 +25,54 @@
24
25
  "publishConfig": {
25
26
  "access": "public"
26
27
  },
27
- "scripts": {},
28
28
  "dependencies": {
29
- "@ihof/https-proxy-agent-timeout": "^5.0.1",
30
- "@types/jest": "^26.0.19",
31
- "@types/node": "^14.17.3",
32
- "@types/supertest": "^2.0.10",
33
- "archiver": "^5.1.0",
34
- "axios": "^0.21.1",
35
- "chalk": "^4.1.0",
36
- "class-transformer": "0.3.1",
37
- "class-validator": "~0.12.2",
38
- "class-validator-jsonschema": "^2.2.0",
39
- "commander": "^7.1.0",
29
+ "archiver": "^5.3.0",
30
+ "axios": "^0.24.0",
31
+ "chalk": "^5.0.0",
32
+ "class-transformer": "0.5.1",
33
+ "class-validator": "~0.13.2",
34
+ "class-validator-jsonschema": "^3.1.0",
35
+ "commander": "^8.3.0",
40
36
  "copyfiles": "^2.4.1",
41
37
  "dotenv": "^10.0.0",
42
- "execa": "^5.1.1",
38
+ "execa": "^6.0.0",
43
39
  "form-data": "^4.0.0",
44
- "glob": "^7.1.7",
40
+ "glob": "^7.2.0",
45
41
  "https-proxy-agent": "^5.0.0",
46
- "jest": "^26.6.2",
47
- "latest-semver": "^3.0.0",
48
- "nodemon": "^2.0.7",
49
- "ora": "^5.4.1",
50
- "prettier": "^2.3.1",
51
- "querystring": "^0.2.1",
52
- "read-pkg": "^5.2.0",
42
+ "ora": "^6.0.1",
53
43
  "reflect-metadata": "^0.1.13",
54
- "supertest": "^6.1.3",
55
- "ts-jest": "^26.5.6",
56
- "ts-node": "^10.0.0",
57
- "tslint": "^6.1.3",
58
- "tslint-config-prettier": "^1.18.0",
59
- "typescript": "^4.3.2",
60
- "write-pkg": "^4.0.0"
44
+ "ts-node": "^10.4.0"
45
+ },
46
+ "devDependencies": {
47
+ "@types/jest": "^27.0.3",
48
+ "@types/node": "^16.11.12",
49
+ "eslint": "^8.4.1",
50
+ "eslint-plugin-unicorn": "^39.0.0",
51
+ "jest": "^27.4.4",
52
+ "prettier": "^2.5.1",
53
+ "typescript": "^4.5.3"
61
54
  },
62
55
  "engines": {
63
- "node": ">=14"
56
+ "node": "^14.13.1 || >=16.0.0"
57
+ },
58
+ "eslintConfig": {
59
+ "extends": [
60
+ "eslint:recommended",
61
+ "prettier",
62
+ "plugin:prettier/recommended",
63
+ "plugin:unicorn/all"
64
+ ],
65
+ "rules": {
66
+ "unicorn/no-array-reduce": "off",
67
+ "unicorn/no-null": "off",
68
+ "unicorn/prefer-object-from-entries": "off",
69
+ "no-async-promise-executor": "off",
70
+ "no-console": "error"
71
+ }
72
+ },
73
+ "scripts": {
74
+ "format": "prettier --write .",
75
+ "lint": "eslint '*/**/*.{js,mjs}'",
76
+ "test": "jest"
64
77
  }
65
- }
78
+ }