@ixon-cdk/core 1.21.0-next.2 → 1.22.0-next.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/api/api.utils.js +1 -5
- package/api/auth.service.js +6 -6
- package/api/base.service.js +7 -6
- package/api/config.service.js +119 -0
- package/api/deploy.service.js +10 -11
- package/config/config.service.js +9 -9
- package/http-request.js +11 -7
- package/index.js +8 -10
- package/meta-files.js +79 -79
- package/package.json +12 -8
- package/prompts.js +33 -34
- package/server/index.js +27 -20
- package/template/template.service.js +29 -19
- package/utils.js +117 -101
package/api/api.utils.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
function whileMoreAfter(reqFn) {
|
|
1
|
+
export function whileMoreAfter(reqFn) {
|
|
2
2
|
const fetcher = async (seed, moreAfter) => {
|
|
3
3
|
const response = await reqFn(moreAfter);
|
|
4
4
|
const data = [...seed, ...response.data.data];
|
|
@@ -12,7 +12,3 @@ function whileMoreAfter(reqFn) {
|
|
|
12
12
|
status: 'success',
|
|
13
13
|
}));
|
|
14
14
|
}
|
|
15
|
-
|
|
16
|
-
module.exports = {
|
|
17
|
-
whileMoreAfter,
|
|
18
|
-
};
|
package/api/auth.service.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { ApiBaseService } from './base.service.js';
|
|
3
|
+
import httpRequest from '../http-request.js';
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
export class AuthService extends ApiBaseService {
|
|
6
6
|
logIn(credentials) {
|
|
7
7
|
const c = credentials;
|
|
8
8
|
const expiresIn = 2592000; // 30 days
|
|
@@ -42,7 +42,7 @@ module.exports = class AuthService extends ApiBaseService {
|
|
|
42
42
|
|
|
43
43
|
remember(secretId) {
|
|
44
44
|
fs.writeFileSync(this._getAccessTokenFilePath(), secretId, {
|
|
45
|
-
encoding: '
|
|
45
|
+
encoding: 'utf-8',
|
|
46
46
|
flag: 'w',
|
|
47
47
|
});
|
|
48
48
|
}
|
|
@@ -52,4 +52,4 @@ module.exports = class AuthService extends ApiBaseService {
|
|
|
52
52
|
fs.rmSync(this._getAccessTokenFilePath());
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
|
-
}
|
|
55
|
+
}
|
package/api/base.service.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { ConfigService } from '../config/config.service.js';
|
|
4
|
+
import { getRootDir } from '../utils.js';
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
export class ApiBaseService {
|
|
6
7
|
_configSrv = new ConfigService();
|
|
7
8
|
|
|
8
9
|
/**
|
|
@@ -19,7 +20,7 @@ module.exports = class ApiBaseService {
|
|
|
19
20
|
|
|
20
21
|
/** Returns an absolute path to the `.accesstoken` file. */
|
|
21
22
|
_getAccessTokenFilePath() {
|
|
22
|
-
return path.join(
|
|
23
|
+
return path.join(getRootDir(), '.accesstoken');
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
_getApiAuthHeaderValue() {
|
|
@@ -53,4 +54,4 @@ module.exports = class ApiBaseService {
|
|
|
53
54
|
}
|
|
54
55
|
return secretId;
|
|
55
56
|
}
|
|
56
|
-
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { merge } from 'lodash-es';
|
|
4
|
+
import {
|
|
5
|
+
getArgv,
|
|
6
|
+
getRootDir,
|
|
7
|
+
logFileCrudMessage,
|
|
8
|
+
logErrorMessage,
|
|
9
|
+
} from '../utils.js';
|
|
10
|
+
|
|
11
|
+
export class ConfigService {
|
|
12
|
+
_config = { components: {} };
|
|
13
|
+
|
|
14
|
+
constructor(configFile) {
|
|
15
|
+
// When the CDK is part of a larger project workspace it may be desirable to have a more explicit config-file name. Therefore, unless
|
|
16
|
+
// a specific config file path was defined in the constructor, we'll first try to find `cdk.config.json`, before falling back to the
|
|
17
|
+
// default file name `config.json`.
|
|
18
|
+
if (configFile !== undefined) {
|
|
19
|
+
this._path = path.join(getRootDir(), configFile);
|
|
20
|
+
} else {
|
|
21
|
+
const argv = getArgv();
|
|
22
|
+
const argConfigPath = argv['config'] || argv['c'];
|
|
23
|
+
if (argConfigPath) {
|
|
24
|
+
if (fs.existsSync(path.join(getRootDir(), argConfigPath))) {
|
|
25
|
+
this._path = path.join(getRootDir(), argConfigPath);
|
|
26
|
+
} else {
|
|
27
|
+
logErrorMessage(
|
|
28
|
+
`Config file not found: ${path.join(getRootDir(), argConfigPath)}`,
|
|
29
|
+
);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
this._path = path.join(getRootDir(), argConfigPath);
|
|
33
|
+
} else if (fs.existsSync(path.join(getRootDir(), 'cdk.config.json'))) {
|
|
34
|
+
this._path = path.join(getRootDir(), 'cdk.config.json');
|
|
35
|
+
} else {
|
|
36
|
+
this._path = path.join(getRootDir(), 'config.json');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (!fs.existsSync(this._path)) {
|
|
41
|
+
this._path = path.join(getRootDir(), 'cdk.config.json');
|
|
42
|
+
fs.writeFileSync(
|
|
43
|
+
this._path,
|
|
44
|
+
`${JSON.stringify(
|
|
45
|
+
{
|
|
46
|
+
$schema: './node_modules/@ixon-cdk/core/config/schema.json',
|
|
47
|
+
prefix: 'pct',
|
|
48
|
+
components: {},
|
|
49
|
+
},
|
|
50
|
+
null,
|
|
51
|
+
2,
|
|
52
|
+
)}\n`,
|
|
53
|
+
{ encoding: 'utf-8' },
|
|
54
|
+
);
|
|
55
|
+
logFileCrudMessage('CREATE', 'cdk.config.json');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
this._config = JSON.parse(fs.readFileSync(this._path, 'utf-8'));
|
|
60
|
+
} catch {
|
|
61
|
+
logErrorMessage("Couldn't parse config file.");
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
hasComponent(name) {
|
|
67
|
+
return name in this._config.components;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
getComponent(name) {
|
|
71
|
+
return this._config.components[name];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
getNewComponentRoot() {
|
|
75
|
+
return this._config.newComponentRoot || 'components';
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
getOutputPath() {
|
|
79
|
+
return this._config.outputPath || 'dist';
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
getPrefix() {
|
|
83
|
+
return this._config.prefix || null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
getApiApplication() {
|
|
87
|
+
return this._config.apiApplication || 'LtDdZKEPa5lK';
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
getApiBaseUrl() {
|
|
91
|
+
return this._config.apiBaseUrl || 'https://api.ayayot.com';
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
getApiVersion() {
|
|
95
|
+
return this._config.apiVersion || '2';
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
addComponent(name, config) {
|
|
99
|
+
this._config.components[name] = config;
|
|
100
|
+
this._sync();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
extendComponent(name, config) {
|
|
104
|
+
this._config.components[name] = merge(
|
|
105
|
+
{},
|
|
106
|
+
this._config.components[name],
|
|
107
|
+
config,
|
|
108
|
+
);
|
|
109
|
+
this._sync();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
_sync() {
|
|
113
|
+
fs.writeFileSync(this._path, `${JSON.stringify(this._config, null, 2)}\n`, {
|
|
114
|
+
encoding: 'utf-8',
|
|
115
|
+
flag: 'w',
|
|
116
|
+
});
|
|
117
|
+
logFileCrudMessage('UPDATE', path.basename(this._path));
|
|
118
|
+
}
|
|
119
|
+
}
|
package/api/deploy.service.js
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { ApiBaseService } from './base.service.js';
|
|
4
|
+
import httpRequest from '../http-request.js';
|
|
5
|
+
import { whileMoreAfter } from './api.utils.js';
|
|
6
|
+
import { generatePreviewHash, getRootDir } from '../utils.js';
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
export class DeployService extends ApiBaseService {
|
|
8
9
|
deploy(companyId, templateId, file) {
|
|
9
10
|
const url = `${this._getApiBaseUrl()}/page-component-templates/${templateId}/version-upload`;
|
|
10
|
-
const body = fs.readFileSync(
|
|
11
|
-
path.join(require('../utils').getRootDir(), file),
|
|
12
|
-
);
|
|
11
|
+
const body = fs.readFileSync(path.join(getRootDir(), file));
|
|
13
12
|
const headers = {
|
|
14
13
|
...this._getApiDefaultHeaders(),
|
|
15
14
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
@@ -49,7 +48,7 @@ module.exports = class DeployService extends ApiBaseService {
|
|
|
49
48
|
),
|
|
50
49
|
)
|
|
51
50
|
.then(([fqdn, version, template]) => {
|
|
52
|
-
const hash =
|
|
51
|
+
const hash = generatePreviewHash(
|
|
53
52
|
template.publicId,
|
|
54
53
|
template.name,
|
|
55
54
|
version.publicId,
|
|
@@ -180,4 +179,4 @@ module.exports = class DeployService extends ApiBaseService {
|
|
|
180
179
|
};
|
|
181
180
|
return httpRequest({ method: 'PATCH', url, data: body, headers });
|
|
182
181
|
}
|
|
183
|
-
}
|
|
182
|
+
}
|
package/config/config.service.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { merge } from 'lodash-es';
|
|
4
|
+
import {
|
|
5
5
|
getArgv,
|
|
6
6
|
getRootDir,
|
|
7
7
|
logFileCrudMessage,
|
|
8
8
|
logErrorMessage,
|
|
9
|
-
}
|
|
9
|
+
} from '../utils.js';
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
export class ConfigService {
|
|
12
12
|
_config = { components: {} };
|
|
13
13
|
|
|
14
14
|
constructor(configFile) {
|
|
@@ -58,7 +58,7 @@ module.exports = class ConfigService {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
try {
|
|
61
|
-
config =
|
|
61
|
+
config = JSON.parse(fs.readFileSync(this._path, 'utf-8'));
|
|
62
62
|
} catch {
|
|
63
63
|
logErrorMessage("Couldn't parse config file.");
|
|
64
64
|
process.exit(1);
|
|
@@ -115,9 +115,9 @@ module.exports = class ConfigService {
|
|
|
115
115
|
|
|
116
116
|
_sync() {
|
|
117
117
|
fs.writeFileSync(this._path, `${JSON.stringify(this._config, null, 2)}\n`, {
|
|
118
|
-
encoding: '
|
|
118
|
+
encoding: 'utf-8',
|
|
119
119
|
flag: 'w',
|
|
120
120
|
});
|
|
121
121
|
logFileCrudMessage('UPDATE', path.basename(this._path));
|
|
122
122
|
}
|
|
123
|
-
}
|
|
123
|
+
}
|
package/http-request.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import axios from 'axios';
|
|
4
|
+
import { getRootDir, logErrorMessage } from './utils.js';
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
export default async function request(options) {
|
|
7
7
|
const customPath = path.join(getRootDir(), 'http-request.js');
|
|
8
8
|
|
|
9
9
|
if (fs.existsSync(customPath)) {
|
|
10
|
-
|
|
10
|
+
let customRequest = await import(customPath);
|
|
11
|
+
|
|
12
|
+
if (typeof customRequest === 'object' && 'default' in customRequest) {
|
|
13
|
+
customRequest = customRequest.default;
|
|
14
|
+
}
|
|
11
15
|
|
|
12
16
|
if (typeof customRequest !== 'function') {
|
|
13
17
|
logErrorMessage(
|
|
@@ -29,4 +33,4 @@ module.exports = function request(options) {
|
|
|
29
33
|
}
|
|
30
34
|
|
|
31
35
|
return axios.request(options);
|
|
32
|
-
}
|
|
36
|
+
}
|
package/index.js
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
...require('./utils'),
|
|
10
|
-
};
|
|
1
|
+
export { AuthService } from './api/auth.service.js';
|
|
2
|
+
export { DeployService } from './api/deploy.service.js';
|
|
3
|
+
export { ConfigService } from './config/config.service.js';
|
|
4
|
+
export { Server } from './server/index.js';
|
|
5
|
+
export { TemplateService } from './template/template.service.js';
|
|
6
|
+
export * from './meta-files.js';
|
|
7
|
+
export * from './prompts.js';
|
|
8
|
+
export * from './utils.js';
|
package/meta-files.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import fse from 'fs-extra';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { watch } from 'chokidar';
|
|
5
|
+
import { globSync } from 'glob';
|
|
6
|
+
import { debounce, isEqual, uniqWith } from 'lodash-es';
|
|
7
|
+
import { getRootDir } from './utils.js';
|
|
8
8
|
|
|
9
9
|
const ICON_FILE_NAME = 'icon.svg';
|
|
10
10
|
const MANIFEST_FILE_NAME = 'manifest.json';
|
|
@@ -20,78 +20,78 @@ const WATCH_OPTIONS = {
|
|
|
20
20
|
* @property {String} [output] - A path relative to outputPath (default is dist/component-name).
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
}
|
|
23
|
+
export function cleanDir(dir) {
|
|
24
|
+
fse.emptyDirSync(dir);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @param {Array<String | Asset>} assets
|
|
29
|
+
* @param {String} inputDir
|
|
30
|
+
* @param {String} outputDir
|
|
31
|
+
*/
|
|
32
|
+
export function copyAssets(assets, inputDir, outputDir) {
|
|
33
|
+
_getAssetSpecs(assets, inputDir, outputDir).forEach(
|
|
34
|
+
({ glob, input, output }) => {
|
|
35
|
+
const globFilePath = path.join(input, glob).replaceAll('\\', '/');
|
|
36
|
+
globSync(globFilePath).forEach(file => {
|
|
37
|
+
const filePath = file.slice(input.length + 1);
|
|
38
|
+
_copyFromToSync(filePath, input, output);
|
|
39
|
+
});
|
|
40
|
+
},
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function watchAssets(assets, inputDir, outputDir) {
|
|
45
|
+
const root = getRootDir();
|
|
46
|
+
return Promise.all(
|
|
47
|
+
_getAssetSpecs(assets, inputDir, outputDir).map(asset => {
|
|
48
|
+
return watch(path.join(asset.input, asset.glob), WATCH_OPTIONS).on(
|
|
49
|
+
'all',
|
|
50
|
+
(type, file) => {
|
|
51
|
+
const filePath = path.join(root, file).slice(asset.input.length + 1);
|
|
52
|
+
switch (type) {
|
|
53
|
+
case 'add':
|
|
54
|
+
case 'addDir':
|
|
55
|
+
case 'change':
|
|
56
|
+
case 'changeDir':
|
|
57
|
+
_copyFromToSync(filePath, asset.input, asset.output);
|
|
58
|
+
break;
|
|
59
|
+
case 'unlink':
|
|
60
|
+
case 'unlinkDir':
|
|
61
|
+
fse.removeSync(path.join(asset.output, filePath));
|
|
62
|
+
break;
|
|
63
|
+
default:
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
);
|
|
68
|
+
}),
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function watchInputDir(dir, watchCallback) {
|
|
73
|
+
const _debouncedCallback = debounce(() => watchCallback(), 300);
|
|
74
|
+
watch([`${dir}/**`], WATCH_OPTIONS).on('all', (_, _path) => {
|
|
75
|
+
if (
|
|
76
|
+
_path.endsWith(path.join(dir, MANIFEST_FILE_NAME)) ||
|
|
77
|
+
_path.endsWith(path.join(dir, ICON_FILE_NAME))
|
|
78
|
+
) {
|
|
79
|
+
watchCallback(true);
|
|
80
|
+
} else {
|
|
81
|
+
_debouncedCallback();
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function writeDemoFile(tag, outputDir, outputFile) {
|
|
87
|
+
const demoFileContent = `<meta charset="utf-8">\n<title>${tag} demo</title>\n<script src="./${path.basename(
|
|
88
|
+
outputFile,
|
|
89
|
+
)}"></script>\n\n\n<${tag}></${tag}>\n\n`;
|
|
90
|
+
fs.writeFileSync(`${outputDir}/demo.html`, demoFileContent, {
|
|
91
|
+
encoding: 'utf8',
|
|
92
|
+
flag: 'w',
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
95
|
|
|
96
96
|
/**
|
|
97
97
|
* Copies an asset file or directory from the source directory to a destination directory.
|
package/package.json
CHANGED
|
@@ -1,23 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ixon-cdk/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.22.0-next.0",
|
|
4
4
|
"description": "",
|
|
5
|
+
"type": "module",
|
|
5
6
|
"main": "index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./index.js"
|
|
9
|
+
},
|
|
6
10
|
"author": "",
|
|
7
11
|
"license": "ISC",
|
|
8
12
|
"dependencies": {
|
|
9
13
|
"app-root-dir": "^1.0.2",
|
|
10
14
|
"archiver": "^7.0.1",
|
|
11
|
-
"axios": "^1.
|
|
12
|
-
"chalk": "^
|
|
15
|
+
"axios": "^1.13.2",
|
|
16
|
+
"chalk": "^5.6.2",
|
|
13
17
|
"chokidar": "^3.6.0",
|
|
14
18
|
"cors": "^2.8.5",
|
|
15
19
|
"crypto-js": "^4.2.0",
|
|
16
|
-
"express": "^
|
|
17
|
-
"fs-extra": "^11.2
|
|
18
|
-
"glob": "^
|
|
19
|
-
"livereload": "^0.
|
|
20
|
-
"lodash": "^4.17.21",
|
|
20
|
+
"express": "^5.2.1",
|
|
21
|
+
"fs-extra": "^11.3.2",
|
|
22
|
+
"glob": "^13.0.0",
|
|
23
|
+
"livereload": "^0.10.3",
|
|
24
|
+
"lodash-es": "^4.17.21",
|
|
21
25
|
"opener": "^1.5.2",
|
|
22
26
|
"prompts": "^2.4.2",
|
|
23
27
|
"yargs": "^17.7.2"
|
package/prompts.js
CHANGED
|
@@ -1,34 +1,33 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
};
|
|
1
|
+
export function promptCompanyId(name) {
|
|
2
|
+
return {
|
|
3
|
+
type: 'text',
|
|
4
|
+
name,
|
|
5
|
+
message: 'What is the ID of your Company?',
|
|
6
|
+
validate: value => {
|
|
7
|
+
if (!value) {
|
|
8
|
+
return 'Company ID is required.';
|
|
9
|
+
}
|
|
10
|
+
if (!/^[0-9]{4}-[0-9]{4}-[0-9]{4}-[0-9]{4}-[0-9]{4}$/.test(value)) {
|
|
11
|
+
return 'Invalid company ID.';
|
|
12
|
+
}
|
|
13
|
+
return true;
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function promptPageComponentTemplateId(name) {
|
|
19
|
+
return {
|
|
20
|
+
type: 'text',
|
|
21
|
+
name,
|
|
22
|
+
message: 'What is the ID of the UI Component?',
|
|
23
|
+
validate: value => {
|
|
24
|
+
if (!value) {
|
|
25
|
+
return 'UI Component ID is required.';
|
|
26
|
+
}
|
|
27
|
+
if (!/^[a-zA-Z0-9]{12}$/.test(value)) {
|
|
28
|
+
return 'Invalid UI Component ID.';
|
|
29
|
+
}
|
|
30
|
+
return true;
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
package/server/index.js
CHANGED
|
@@ -1,17 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import express from 'express';
|
|
5
|
+
import cors from 'cors';
|
|
6
|
+
import liveReload from 'livereload';
|
|
7
|
+
import opener from 'opener';
|
|
8
|
+
import { debounce } from 'lodash-es';
|
|
9
|
+
import { ApiBaseService } from '../api/base.service.js';
|
|
10
|
+
import { ConfigService } from '../config/config.service.js';
|
|
11
|
+
import { getRootDir } from '../utils.js';
|
|
7
12
|
|
|
8
13
|
const LR_PORT_DEFAULT = 35729;
|
|
9
14
|
|
|
10
|
-
|
|
15
|
+
export class Server {
|
|
11
16
|
constructor(opts) {
|
|
12
17
|
this._apiSrv = new ApiBaseService();
|
|
13
18
|
this._configSrv = new ConfigService();
|
|
14
|
-
this._rootDir =
|
|
19
|
+
this._rootDir = getRootDir();
|
|
15
20
|
this._opts = {
|
|
16
21
|
port: 8000,
|
|
17
22
|
componentBasePath: 'components',
|
|
@@ -57,30 +62,33 @@ module.exports = class Server {
|
|
|
57
62
|
port: this._opts.liveReloadPort,
|
|
58
63
|
});
|
|
59
64
|
const _refresh = () => lrServer.refresh('/');
|
|
60
|
-
const _debouncedRefresh =
|
|
65
|
+
const _debouncedRefresh = debounce(_refresh, 250);
|
|
61
66
|
names
|
|
62
67
|
.flatMap(name => [
|
|
63
68
|
[path.join(this._rootDir, this._getOutput(name)), 100],
|
|
64
69
|
[path.join(this._rootDir, `dist/${name}/manifest.json`), 500],
|
|
65
70
|
])
|
|
66
71
|
.forEach(([filename, interval]) =>
|
|
67
|
-
|
|
72
|
+
fs.watchFile(filename, { interval }, _debouncedRefresh),
|
|
68
73
|
);
|
|
69
74
|
|
|
70
75
|
// Simulator app
|
|
71
76
|
let appDir;
|
|
72
77
|
try {
|
|
73
|
-
appDir = path.dirname(
|
|
78
|
+
appDir = path.dirname(
|
|
79
|
+
fileURLToPath(import.meta.resolve('@ixon-cdk/simulator')),
|
|
80
|
+
);
|
|
74
81
|
} catch {
|
|
75
|
-
// If
|
|
76
|
-
// a "MODULE_NOT_FOUND" error. In that case (as a fallback) we'll find the simulator
|
|
77
|
-
// relative to the core module (which should have already been installed).
|
|
82
|
+
// If import.meta.resolve is invoked immediately after the simulator is installed, it will
|
|
83
|
+
// return a "MODULE_NOT_FOUND" error. In that case (as a fallback) we'll find the simulator
|
|
84
|
+
// app dir relative to the core module (which should have already been installed).
|
|
78
85
|
appDir = path.join(
|
|
79
|
-
|
|
86
|
+
fileURLToPath(import.meta.resolve('@ixon-cdk/core')),
|
|
80
87
|
'../../simulator/dist',
|
|
81
88
|
);
|
|
82
89
|
}
|
|
83
|
-
app.
|
|
90
|
+
app.use(express.static(appDir));
|
|
91
|
+
app.get(`/${this._opts.componentBasePath}/*splat`, (req, res) => {
|
|
84
92
|
res.sendStatus(404);
|
|
85
93
|
});
|
|
86
94
|
app.get(
|
|
@@ -100,8 +108,7 @@ module.exports = class Server {
|
|
|
100
108
|
},
|
|
101
109
|
});
|
|
102
110
|
});
|
|
103
|
-
app.
|
|
104
|
-
app.all('*', (req, res) => {
|
|
111
|
+
app.all('*splat', (req, res) => {
|
|
105
112
|
res.status(200).sendFile('/index.html', { root: appDir });
|
|
106
113
|
});
|
|
107
114
|
|
|
@@ -120,7 +127,7 @@ module.exports = class Server {
|
|
|
120
127
|
}
|
|
121
128
|
const queryString = params.toString();
|
|
122
129
|
const openUrl = `${this._getBaseUrl()}/?${queryString}`;
|
|
123
|
-
|
|
130
|
+
opener(openUrl);
|
|
124
131
|
return openUrl;
|
|
125
132
|
}
|
|
126
133
|
|
|
@@ -155,4 +162,4 @@ module.exports = class Server {
|
|
|
155
162
|
_getOutputDir(name) {
|
|
156
163
|
return name ? `${this._configSrv.getOutputPath()}/${name}` : null;
|
|
157
164
|
}
|
|
158
|
-
}
|
|
165
|
+
}
|
|
@@ -1,18 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import prompts from 'prompts';
|
|
6
|
+
import { ConfigService } from '../config/config.service.js';
|
|
7
|
+
import {
|
|
6
8
|
getFiles,
|
|
7
9
|
getRootDir,
|
|
8
10
|
ensureModule,
|
|
9
11
|
logErrorMessage,
|
|
10
12
|
logFileCrudMessage,
|
|
11
13
|
pascalCase,
|
|
12
|
-
}
|
|
13
|
-
const ConfigService = require('../config/config.service');
|
|
14
|
+
} from '../utils.js';
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
export class TemplateService {
|
|
16
17
|
_configSrv = new ConfigService();
|
|
17
18
|
|
|
18
19
|
_rootDir = getRootDir();
|
|
@@ -136,8 +137,8 @@ module.exports = class TemplateService {
|
|
|
136
137
|
files.forEach(file => {
|
|
137
138
|
if (/\.(jsx?|tsx?|svelte|vue)$/i.test(file)) {
|
|
138
139
|
const fileContents = fs.readFileSync(file);
|
|
139
|
-
const { dependencies } =
|
|
140
|
-
path.join(examplesRoot, 'package.json'),
|
|
140
|
+
const { dependencies } = JSON.parse(
|
|
141
|
+
fs.readFileSync(path.join(examplesRoot, 'package.json'), 'utf-8'),
|
|
141
142
|
);
|
|
142
143
|
this._checkDependencies(fileContents, dependencies || {});
|
|
143
144
|
}
|
|
@@ -317,7 +318,9 @@ module.exports = class TemplateService {
|
|
|
317
318
|
if (file.interpolateContent) {
|
|
318
319
|
const text = fs.readFileSync(
|
|
319
320
|
path.join(
|
|
320
|
-
path.dirname(
|
|
321
|
+
path.dirname(
|
|
322
|
+
fileURLToPath(import.meta.resolve('@ixon-cdk/templates')),
|
|
323
|
+
),
|
|
321
324
|
file.source,
|
|
322
325
|
),
|
|
323
326
|
{ encoding: 'utf-8' },
|
|
@@ -329,7 +332,9 @@ module.exports = class TemplateService {
|
|
|
329
332
|
} else {
|
|
330
333
|
fs.copyFileSync(
|
|
331
334
|
path.join(
|
|
332
|
-
path.dirname(
|
|
335
|
+
path.dirname(
|
|
336
|
+
fileURLToPath(import.meta.resolve('@ixon-cdk/templates')),
|
|
337
|
+
),
|
|
333
338
|
file.source,
|
|
334
339
|
),
|
|
335
340
|
path.join(this._rootDir, file.dest),
|
|
@@ -341,17 +346,20 @@ module.exports = class TemplateService {
|
|
|
341
346
|
/**
|
|
342
347
|
* This script loops over a dependencies object and will check if the provided file contents is
|
|
343
348
|
* importing any. When that is the case, it will first check for that package whether it could
|
|
344
|
-
* already be a
|
|
349
|
+
* already be a dependency in your workspace. If not, the package will get installed and saved.
|
|
345
350
|
*/
|
|
346
351
|
_checkDependencies(fileContents, dependencies) {
|
|
347
|
-
const
|
|
348
|
-
|
|
352
|
+
const rootPkgJsonRaw = fs.readFileSync(
|
|
353
|
+
path.join(this._rootDir, 'package.json'),
|
|
354
|
+
'utf-8',
|
|
355
|
+
);
|
|
356
|
+
const rootDeps = JSON.parse(rootPkgJsonRaw).dependencies || {};
|
|
349
357
|
Object.keys(dependencies).forEach(pkg => {
|
|
350
358
|
const matcher = new RegExp(`^\\s*import.*\\s['"]${pkg}\\S*['"]`, 'gm');
|
|
351
359
|
if (matcher.test(fileContents) && !(pkg in rootDeps)) {
|
|
352
360
|
const version = dependencies[pkg];
|
|
353
361
|
console.log(`Installing package '${pkg}'...`);
|
|
354
|
-
|
|
362
|
+
execSync(`npm i ${pkg}@${version} --save`);
|
|
355
363
|
}
|
|
356
364
|
});
|
|
357
365
|
}
|
|
@@ -370,7 +378,7 @@ module.exports = class TemplateService {
|
|
|
370
378
|
* This script will find and replace the component class definition and the arguments for the
|
|
371
379
|
* custom element define method in a static input file.
|
|
372
380
|
*
|
|
373
|
-
* Given the example input file has the
|
|
381
|
+
* Given the example input file has the following contents:
|
|
374
382
|
*
|
|
375
383
|
* ```js
|
|
376
384
|
* class PctExample extends HTMLElement {
|
|
@@ -420,7 +428,9 @@ module.exports = class TemplateService {
|
|
|
420
428
|
}
|
|
421
429
|
|
|
422
430
|
_discover() {
|
|
423
|
-
const dir = path.dirname(
|
|
431
|
+
const dir = path.dirname(
|
|
432
|
+
fileURLToPath(import.meta.resolve('@ixon-cdk/templates')),
|
|
433
|
+
);
|
|
424
434
|
const files = fs.readdirSync(dir);
|
|
425
435
|
const tail = ['iframe-wrapper'];
|
|
426
436
|
files
|
|
@@ -485,4 +495,4 @@ module.exports = class TemplateService {
|
|
|
485
495
|
.replace(/<%=\s*tag\s*%>/g, params.tag)
|
|
486
496
|
.replace(/<%=\s*classify\(\s*tag\s*\)\s*%>/g, pascalCase(params.tag));
|
|
487
497
|
}
|
|
488
|
-
}
|
|
498
|
+
}
|
package/utils.js
CHANGED
|
@@ -1,87 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import net from 'node:net';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { execSync } from 'node:child_process';
|
|
5
|
+
import { get as getAppRootDir } from 'app-root-dir';
|
|
6
|
+
import archiver from 'archiver';
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import CryptoJS from 'crypto-js';
|
|
9
|
+
import fse from 'fs-extra';
|
|
10
|
+
import { globSync } from 'glob';
|
|
11
|
+
import { camelCase, flow, upperFirst } from 'lodash-es';
|
|
12
|
+
import yargs from 'yargs/yargs';
|
|
9
13
|
|
|
10
|
-
function
|
|
11
|
-
const files = globSync(path.join(dir, globPattern));
|
|
12
|
-
return !!files.length;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function getArgv() {
|
|
16
|
-
const remain = process.argv.slice(2);
|
|
17
|
-
const { argv } = require('yargs/yargs')(remain).version(false);
|
|
18
|
-
|
|
19
|
-
return argv;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function getRootDir() {
|
|
23
|
-
return require('app-root-dir').get();
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function logErrorMessage(message) {
|
|
27
|
-
console.log(chalk.redBright.bold(message));
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function logFileCrudMessage(crud, file) {
|
|
31
|
-
switch (crud) {
|
|
32
|
-
case 'CREATE':
|
|
33
|
-
case 'UPDATE':
|
|
34
|
-
console.log(`${chalk.green(crud)} ${file}`);
|
|
35
|
-
break;
|
|
36
|
-
default:
|
|
37
|
-
break;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function logSuccessMessage(message) {
|
|
42
|
-
console.log(chalk.green(message));
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function moduleExists(moduleName) {
|
|
46
|
-
let exists = true;
|
|
47
|
-
try {
|
|
48
|
-
require.resolve(moduleName);
|
|
49
|
-
} catch {
|
|
50
|
-
exists = false;
|
|
51
|
-
}
|
|
52
|
-
return exists;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function ensureModule(moduleName, moduleVersion = null, dev = true) {
|
|
56
|
-
if (!moduleExists(moduleName)) {
|
|
57
|
-
if (moduleName.startsWith('@ixon-cdk/')) {
|
|
58
|
-
moduleVersion = require('./package.json').version;
|
|
59
|
-
}
|
|
60
|
-
const v = moduleVersion ? '@' + moduleVersion : '';
|
|
61
|
-
console.log(`Installing package '${moduleName}${v}...`);
|
|
62
|
-
require('child_process').execSync(
|
|
63
|
-
`npm install --save${dev ? '-dev' : ''} ${moduleName}${v}`,
|
|
64
|
-
);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function zip(output, callback) {
|
|
69
|
-
const outputDir = path.dirname(output);
|
|
70
|
-
const zipFile = path.join(`${outputDir}.zip`);
|
|
71
|
-
const stream = fs.createWriteStream(zipFile);
|
|
72
|
-
stream.on('close', () => {
|
|
73
|
-
fse.removeSync(outputDir);
|
|
74
|
-
callback(zipFile);
|
|
75
|
-
});
|
|
76
|
-
const archive = require('archiver')('zip', { zlib: { level: 9 } });
|
|
77
|
-
archive.pipe(stream);
|
|
78
|
-
archive.directory(outputDir, path.basename(outputDir));
|
|
79
|
-
archive.finalize();
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const pascalCase = flow(camelCase, upperFirst);
|
|
83
|
-
|
|
84
|
-
function apiHttpErrorToMessage(error, exit = true) {
|
|
14
|
+
export function apiHttpErrorToMessage(error, exit = true) {
|
|
85
15
|
if (typeof error === 'string') {
|
|
86
16
|
logErrorMessage(error);
|
|
87
17
|
exit && process.exit(1);
|
|
@@ -108,7 +38,42 @@ function apiHttpErrorToMessage(error, exit = true) {
|
|
|
108
38
|
exit && process.exit(1);
|
|
109
39
|
}
|
|
110
40
|
|
|
111
|
-
function
|
|
41
|
+
export function checkPortAvailable(port) {
|
|
42
|
+
return new Promise((resolve, reject) => {
|
|
43
|
+
const server = net.createServer();
|
|
44
|
+
server
|
|
45
|
+
.once('error', err => {
|
|
46
|
+
server.close();
|
|
47
|
+
return reject(err);
|
|
48
|
+
})
|
|
49
|
+
.once('listening', () => {
|
|
50
|
+
server.close();
|
|
51
|
+
return resolve(port);
|
|
52
|
+
})
|
|
53
|
+
.listen(port);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function dirContains(dir, globPattern) {
|
|
58
|
+
const files = globSync(path.join(dir, globPattern));
|
|
59
|
+
return !!files.length;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function ensureModule(moduleName, moduleVersion = null, dev = true) {
|
|
63
|
+
if (!moduleExists(moduleName)) {
|
|
64
|
+
if (moduleName.startsWith('@ixon-cdk/')) {
|
|
65
|
+
const modulePkgJson = JSON.parse(
|
|
66
|
+
fs.readFileSync('./package.json', 'utf-8'),
|
|
67
|
+
);
|
|
68
|
+
moduleVersion = modulePkgJson.version;
|
|
69
|
+
}
|
|
70
|
+
const v = moduleVersion ? '@' + moduleVersion : '';
|
|
71
|
+
console.log(`Installing package '${moduleName}${v}...`);
|
|
72
|
+
execSync(`npm install --save${dev ? '-dev' : ''} ${moduleName}${v}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function generatePreviewHash(
|
|
112
77
|
templateId,
|
|
113
78
|
templateName,
|
|
114
79
|
versionId,
|
|
@@ -123,10 +88,33 @@ function generatePreviewHash(
|
|
|
123
88
|
vmp: versionMainPath,
|
|
124
89
|
};
|
|
125
90
|
const salt = 'A9qJ03jh';
|
|
126
|
-
return
|
|
91
|
+
return CryptoJS.AES.encrypt(JSON.stringify(ref), salt).toString();
|
|
127
92
|
}
|
|
128
93
|
|
|
129
|
-
|
|
94
|
+
export function getArgv() {
|
|
95
|
+
const remain = process.argv.slice(2);
|
|
96
|
+
const { argv } = yargs(remain).version(false);
|
|
97
|
+
return argv;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function getAvailablePort() {
|
|
101
|
+
return new Promise((resolve, reject) => {
|
|
102
|
+
const server = net.createServer();
|
|
103
|
+
server
|
|
104
|
+
.once('error', err => {
|
|
105
|
+
server.close();
|
|
106
|
+
return reject(err);
|
|
107
|
+
})
|
|
108
|
+
.once('listening', () => {
|
|
109
|
+
const { port } = server.address();
|
|
110
|
+
server.close();
|
|
111
|
+
return resolve(port);
|
|
112
|
+
})
|
|
113
|
+
.listen();
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export async function getFiles(dir) {
|
|
130
118
|
const dirents = await fs.promises.readdir(dir, { withFileTypes: true });
|
|
131
119
|
const files = await Promise.all(
|
|
132
120
|
dirents.map(dirent => {
|
|
@@ -137,18 +125,46 @@ async function getFiles(dir) {
|
|
|
137
125
|
return Array.prototype.concat(...files);
|
|
138
126
|
}
|
|
139
127
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
128
|
+
export function getRootDir() {
|
|
129
|
+
return getAppRootDir();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function logErrorMessage(message) {
|
|
133
|
+
console.log(chalk.redBright.bold(message));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function logFileCrudMessage(crud, file) {
|
|
137
|
+
if (['CREATE', 'UPDATE'].includes(crud)) {
|
|
138
|
+
console.log(`${chalk.green(crud)} ${file}`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function logSuccessMessage(message) {
|
|
143
|
+
console.log(chalk.green(message));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export function moduleExists(moduleName) {
|
|
147
|
+
let exists = true;
|
|
148
|
+
try {
|
|
149
|
+
import.meta.resolve(moduleName);
|
|
150
|
+
} catch {
|
|
151
|
+
exists = false;
|
|
152
|
+
}
|
|
153
|
+
return exists;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export const pascalCase = flow(camelCase, upperFirst);
|
|
157
|
+
|
|
158
|
+
export function zip(output, callback) {
|
|
159
|
+
const outputDir = path.dirname(output);
|
|
160
|
+
const zipFile = path.join(`${outputDir}.zip`);
|
|
161
|
+
const stream = fs.createWriteStream(zipFile);
|
|
162
|
+
stream.on('close', () => {
|
|
163
|
+
fse.removeSync(outputDir);
|
|
164
|
+
callback(zipFile);
|
|
165
|
+
});
|
|
166
|
+
const archive = archiver('zip', { zlib: { level: 9 } });
|
|
167
|
+
archive.pipe(stream);
|
|
168
|
+
archive.directory(outputDir, path.basename(outputDir));
|
|
169
|
+
archive.finalize();
|
|
170
|
+
}
|