@hahnpro/flow-cli 2.9.0 → 2.12.1

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.9.0",
3
+ "version": "2.12.1",
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,55 @@
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.25.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": "^9.0.0",
40
36
  "copyfiles": "^2.4.1",
41
- "dotenv": "^10.0.0",
42
- "execa": "^5.1.1",
37
+ "dotenv": "^16.0.0",
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.5.0"
45
+ },
46
+ "devDependencies": {
47
+ "@types/jest": "^27.4.0",
48
+ "@types/node": "^16.11.22",
49
+ "eslint": "^8.8.0",
50
+ "eslint-plugin-unicorn": "^40.1.0",
51
+ "jest": "^27.5.0",
52
+ "prettier": "^2.5.1",
53
+ "typescript": "^4.5.5"
61
54
  },
62
55
  "engines": {
63
- "node": ">=14"
64
- }
65
- }
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"
77
+ },
78
+ "readme": "# `@hahnpro/flow-cli`\n\nhttps://github.com/hahnprojects/flow\n\n# Commands\n\n## `build [projectName]`\n\nBuilds specified Project.\n\n## `install [projectName]`\n\nInstalls the dependencies of the specified Project.\n\n## `format`\n\nFormats all typescript files according to prettier configuration.\n\n## `name [projectName]`\n\nInstalls Dependencies and Builds the specified Project.\n\n## `package [projectName]`\n\nBuilds specified Module and packages it as .zip File for manual upload to the platform.\n\n## `publish-module [projectName]`\n\nPublishes specified Module to Cloud Platform.\n\n- `-f`, `--functions` Publish flow functions.\n- `-u`, `--update` Update existing flow functions.\n\n## `publish-functions [projectName]`\n\nPublishes all Flow Functions inside specified Module to Cloud Platform.\n\n- `-u`, `--update` Update existing flow functions.\n\n## `serve [projectName]`\n\nBuilds and serves your Project. Rebuilding on file changes.\n\n## `start [projectName]`\n\nRuns your project.\n\n## `test [projectName]`\n\nRuns tests for your Project.\n\n## `generate-schemas [projectName]`\n\nGenerates Input, Output and Properties-Schemas for the specified project.\n\n- `--verbose` Output more information about what is being done.\n- `-h`, `--hide` Hide warnings if Input/OutputProperties classes can´t be found.\n This command generates the schemas and puts them in the `inputStreams` and `outputStreams`\n fields in the json-files of each Flow-Function. It always assumes the properties defined\n in the `Input/OutPutProperties` classes are meant for the default input/output streams.\n If your Function uses different streams you may have to change stream name manually.\n"
79
+ }