@ixon-cdk/core 1.0.0-alpha.9 → 1.1.0-next.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/api/auth.service.js +21 -20
- package/api/base.service.js +8 -8
- package/api/deploy.service.js +46 -54
- package/config/config.service.js +17 -21
- package/http-request.js +28 -0
- package/index.js +8 -8
- package/meta-files.js +30 -24
- package/package.json +8 -9
- package/prompts.js +10 -10
- package/server/index.js +51 -41
- package/template/template.service.js +235 -51
- package/utils.js +47 -39
package/api/auth.service.js
CHANGED
|
@@ -1,30 +1,31 @@
|
|
|
1
|
-
const fs = require(
|
|
2
|
-
const
|
|
3
|
-
const
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const ApiBaseService = require('./base.service');
|
|
3
|
+
const httpRequest = require('../http-request');
|
|
4
4
|
|
|
5
5
|
module.exports = class AuthService extends ApiBaseService {
|
|
6
6
|
logIn(credentials) {
|
|
7
7
|
const c = credentials;
|
|
8
|
-
return
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
{
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
);
|
|
8
|
+
return httpRequest({
|
|
9
|
+
method: 'POST',
|
|
10
|
+
url: `${this._getApiBaseUrl()}/access-tokens`,
|
|
11
|
+
data: { expiresIn: 86400 },
|
|
12
|
+
headers: {
|
|
13
|
+
...this._getApiDefaultHeaders(),
|
|
14
|
+
'User-Agent': 'ComponentDevKit',
|
|
15
|
+
Authorization: `Basic ${Buffer.from(
|
|
16
|
+
`${c.email}:${c.otp || ''}:${c.password}`,
|
|
17
|
+
'utf-8',
|
|
18
|
+
).toString('base64')}`,
|
|
19
|
+
},
|
|
20
|
+
});
|
|
22
21
|
}
|
|
23
22
|
|
|
24
23
|
logOut() {
|
|
25
24
|
const secretId = this._getSecretId();
|
|
26
25
|
if (secretId) {
|
|
27
|
-
return
|
|
26
|
+
return httpRequest({
|
|
27
|
+
method: 'DELETE',
|
|
28
|
+
url: `${this._getApiBaseUrl()}/access-tokens/me`,
|
|
28
29
|
headers: {
|
|
29
30
|
...this._getApiDefaultHeaders(),
|
|
30
31
|
Authorization: this._getApiAuthHeaderValue(),
|
|
@@ -40,8 +41,8 @@ module.exports = class AuthService extends ApiBaseService {
|
|
|
40
41
|
|
|
41
42
|
remember(secretId) {
|
|
42
43
|
fs.writeFileSync(this._getAccessTokenFilePath(), secretId, {
|
|
43
|
-
encoding:
|
|
44
|
-
flag:
|
|
44
|
+
encoding: 'utf8',
|
|
45
|
+
flag: 'w',
|
|
45
46
|
});
|
|
46
47
|
}
|
|
47
48
|
|
package/api/base.service.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
const fs = require(
|
|
2
|
-
const path = require(
|
|
3
|
-
const ConfigService = require(
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const ConfigService = require('../config/config.service');
|
|
4
4
|
|
|
5
5
|
module.exports = class ApiBaseService {
|
|
6
6
|
_configSrv = new ConfigService();
|
|
7
7
|
|
|
8
8
|
_getAccessTokenFilePath() {
|
|
9
|
-
return path.join(require(
|
|
9
|
+
return path.join(require('../utils').getRootDir(), '.accesstoken');
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
_getApiAuthHeaderValue() {
|
|
@@ -19,9 +19,9 @@ module.exports = class ApiBaseService {
|
|
|
19
19
|
|
|
20
20
|
_getApiDefaultHeaders() {
|
|
21
21
|
return {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
'Content-Type': 'application/json',
|
|
23
|
+
'Api-Application': this._configSrv.getApiApplication(),
|
|
24
|
+
'Api-Version': this._configSrv.getApiVersion(),
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
27
|
|
|
@@ -29,7 +29,7 @@ module.exports = class ApiBaseService {
|
|
|
29
29
|
let secretId;
|
|
30
30
|
try {
|
|
31
31
|
secretId = fs.readFileSync(this._getAccessTokenFilePath(), {
|
|
32
|
-
encoding:
|
|
32
|
+
encoding: 'utf-8',
|
|
33
33
|
});
|
|
34
34
|
} catch {
|
|
35
35
|
// do nothing
|
package/api/deploy.service.js
CHANGED
|
@@ -1,38 +1,32 @@
|
|
|
1
|
-
const fs = require(
|
|
2
|
-
const path = require(
|
|
3
|
-
const
|
|
4
|
-
const
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const ApiBaseService = require('./base.service');
|
|
4
|
+
const httpRequest = require('../http-request');
|
|
5
5
|
|
|
6
6
|
module.exports = class DeployService extends ApiBaseService {
|
|
7
7
|
deploy(companyId, templateId, file) {
|
|
8
8
|
const url = `${this._getApiBaseUrl()}/page-component-templates/${templateId}/version-upload`;
|
|
9
|
-
const body = fs.readFileSync(
|
|
10
|
-
path.join(require("../utils").getRootDir(), file)
|
|
11
|
-
);
|
|
9
|
+
const body = fs.readFileSync(path.join(require('../utils').getRootDir(), file));
|
|
12
10
|
const headers = {
|
|
13
11
|
...this._getApiDefaultHeaders(),
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
13
|
+
'Api-Company': companyId,
|
|
16
14
|
Authorization: this._getApiAuthHeaderValue(),
|
|
17
15
|
};
|
|
18
|
-
return
|
|
16
|
+
return httpRequest({ method: 'POST', url, data: body, headers }).then((res) => res.data.data);
|
|
19
17
|
}
|
|
20
18
|
|
|
21
19
|
deployAndPublish(companyId, templateId, file) {
|
|
22
20
|
return this.deploy(companyId, templateId, file).then((data) =>
|
|
23
|
-
this._publish(companyId, data.publicId)
|
|
21
|
+
this._publish(companyId, data.publicId),
|
|
24
22
|
);
|
|
25
23
|
}
|
|
26
24
|
|
|
27
25
|
fetchPublishable(companyId, templateId) {
|
|
28
|
-
return this._fetchDescTemplateVersions(companyId, templateId).then(
|
|
29
|
-
(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
);
|
|
33
|
-
return publishedIdx !== -1 ? versions.slice(0, publishedIdx) : versions;
|
|
34
|
-
}
|
|
35
|
-
);
|
|
26
|
+
return this._fetchDescTemplateVersions(companyId, templateId).then((versions) => {
|
|
27
|
+
const publishedIdx = versions.findIndex((v) => typeof v.publishedOn === 'string');
|
|
28
|
+
return publishedIdx !== -1 ? versions.slice(0, publishedIdx) : versions;
|
|
29
|
+
});
|
|
36
30
|
}
|
|
37
31
|
|
|
38
32
|
generatePreviewLink(companyId, versionId) {
|
|
@@ -40,32 +34,32 @@ module.exports = class DeployService extends ApiBaseService {
|
|
|
40
34
|
this._fetchBrandingFqdn(companyId),
|
|
41
35
|
this._fetchTemplateVersion(companyId, versionId),
|
|
42
36
|
])
|
|
43
|
-
.then(([fqdn, version]) =>
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
37
|
+
.then(([fqdn, version]) =>
|
|
38
|
+
this._fetchTemplate(companyId, version.template.publicId).then((template) => [
|
|
39
|
+
fqdn,
|
|
40
|
+
version,
|
|
41
|
+
template,
|
|
42
|
+
]),
|
|
43
|
+
)
|
|
48
44
|
.then(([fqdn, version, template]) => {
|
|
49
|
-
const hash = require(
|
|
45
|
+
const hash = require('../utils').generatePreviewHash(
|
|
50
46
|
template.publicId,
|
|
51
47
|
template.name,
|
|
52
48
|
version.publicId,
|
|
53
49
|
version.number,
|
|
54
|
-
version.mainPath
|
|
50
|
+
version.mainPath,
|
|
55
51
|
);
|
|
56
52
|
const search = `?pctpvw=${encodeURIComponent(hash)}`;
|
|
57
|
-
return `https://${fqdn ||
|
|
53
|
+
return `https://${fqdn || '[YOUR-PLATFORM-DOMAIN]'}/portal/${search}`;
|
|
58
54
|
});
|
|
59
55
|
}
|
|
60
56
|
|
|
61
57
|
publishLatestVersion(companyId, templateId) {
|
|
62
58
|
return this.fetchPublishable(companyId, templateId).then((data) => {
|
|
63
59
|
if (!data.length) {
|
|
64
|
-
return Promise.reject(
|
|
60
|
+
return Promise.reject('Template has no publishable versions');
|
|
65
61
|
}
|
|
66
|
-
const latest = data.sort(
|
|
67
|
-
(v1, v2) => Number(v2.number) - Number(v1.number)
|
|
68
|
-
)[0];
|
|
62
|
+
const latest = data.sort((v1, v2) => Number(v2.number) - Number(v1.number))[0];
|
|
69
63
|
return this._publish(companyId, latest.publicId);
|
|
70
64
|
});
|
|
71
65
|
}
|
|
@@ -73,26 +67,26 @@ module.exports = class DeployService extends ApiBaseService {
|
|
|
73
67
|
publishVersion(companyId, templateId, versionNumber) {
|
|
74
68
|
return this.fetchPublishable(companyId, templateId).then((data) => {
|
|
75
69
|
if (!data.length) {
|
|
76
|
-
return Promise.reject(
|
|
70
|
+
return Promise.reject('Template has no publishable versions');
|
|
77
71
|
}
|
|
78
72
|
const _version = data.find((v) => v.number === String(versionNumber));
|
|
79
|
-
if (
|
|
73
|
+
if (_version) {
|
|
80
74
|
return this._publish(companyId, _version.publicId);
|
|
81
75
|
}
|
|
82
|
-
return Promise.reject(
|
|
76
|
+
return Promise.reject('Could not match!');
|
|
83
77
|
});
|
|
84
78
|
}
|
|
85
79
|
|
|
86
80
|
_fetchBrandingFqdn(companyId) {
|
|
87
81
|
const url = `${this._getApiBaseUrl()}/companies/me`;
|
|
88
|
-
const params = { fields:
|
|
82
|
+
const params = { fields: 'branding(fqdn)' };
|
|
89
83
|
const headers = {
|
|
90
84
|
...this._getApiDefaultHeaders(),
|
|
91
|
-
|
|
85
|
+
'Api-Company': companyId,
|
|
92
86
|
Authorization: this._getApiAuthHeaderValue(),
|
|
93
87
|
};
|
|
94
88
|
// Lookup company FQDN (premium branding)
|
|
95
|
-
return
|
|
89
|
+
return httpRequest({ method: 'GET', url, params, headers }).then((res) => {
|
|
96
90
|
const myCompany = res.data.data;
|
|
97
91
|
if (myCompany.branding && myCompany.branding.fqdn) {
|
|
98
92
|
return myCompany.branding.fqdn;
|
|
@@ -100,7 +94,7 @@ module.exports = class DeployService extends ApiBaseService {
|
|
|
100
94
|
// Or fallback to sector FQDN
|
|
101
95
|
const _url = `${this._getApiBaseUrl()}/sectors/me`;
|
|
102
96
|
const _headers = { ...this._getApiDefaultHeaders() };
|
|
103
|
-
return
|
|
97
|
+
return httpRequest({ method: 'GET', url: _url, params, headers: _headers }).then((res) => {
|
|
104
98
|
const mySector = res.data.data;
|
|
105
99
|
if (mySector.branding && mySector.branding.fqdn) {
|
|
106
100
|
return mySector.branding.fqdn;
|
|
@@ -113,42 +107,40 @@ module.exports = class DeployService extends ApiBaseService {
|
|
|
113
107
|
_fetchDescTemplateVersions(companyId, templateId) {
|
|
114
108
|
const url = `${this._getApiBaseUrl()}/page-component-template-versions`;
|
|
115
109
|
const params = {
|
|
116
|
-
fields:
|
|
110
|
+
fields: '*,template(*)',
|
|
117
111
|
filters: `eq(template.publicId,"${templateId}")`,
|
|
118
|
-
|
|
112
|
+
'page-size': '100',
|
|
119
113
|
};
|
|
120
114
|
const headers = {
|
|
121
115
|
...this._getApiDefaultHeaders(),
|
|
122
|
-
|
|
116
|
+
'Api-Company': companyId,
|
|
123
117
|
Authorization: this._getApiAuthHeaderValue(),
|
|
124
118
|
};
|
|
125
|
-
return
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
);
|
|
129
|
-
});
|
|
119
|
+
return httpRequest({ method: 'GET', url, params, headers }).then((res) =>
|
|
120
|
+
res.data.data.sort((v1, v2) => Number(v2.number) - Number(v1.number)),
|
|
121
|
+
);
|
|
130
122
|
}
|
|
131
123
|
|
|
132
124
|
_fetchTemplate(companyId, templateId) {
|
|
133
125
|
const url = `${this._getApiBaseUrl()}/page-component-templates/${templateId}`;
|
|
134
|
-
const params = { fields:
|
|
126
|
+
const params = { fields: '*' };
|
|
135
127
|
const headers = {
|
|
136
128
|
...this._getApiDefaultHeaders(),
|
|
137
|
-
|
|
129
|
+
'Api-Company': companyId,
|
|
138
130
|
Authorization: this._getApiAuthHeaderValue(),
|
|
139
131
|
};
|
|
140
|
-
return
|
|
132
|
+
return httpRequest({ method: 'GET', url, params, headers }).then((res) => res.data.data);
|
|
141
133
|
}
|
|
142
134
|
|
|
143
135
|
_fetchTemplateVersion(companyId, versionId) {
|
|
144
136
|
const url = `${this._getApiBaseUrl()}/page-component-template-versions/${versionId}`;
|
|
145
|
-
const params = { fields:
|
|
137
|
+
const params = { fields: '*,template(*)' };
|
|
146
138
|
const headers = {
|
|
147
139
|
...this._getApiDefaultHeaders(),
|
|
148
|
-
|
|
140
|
+
'Api-Company': companyId,
|
|
149
141
|
Authorization: this._getApiAuthHeaderValue(),
|
|
150
142
|
};
|
|
151
|
-
return
|
|
143
|
+
return httpRequest({ method: 'GET', url, params, headers }).then((res) => res.data.data);
|
|
152
144
|
}
|
|
153
145
|
|
|
154
146
|
_publish(companyId, versionId) {
|
|
@@ -156,9 +148,9 @@ module.exports = class DeployService extends ApiBaseService {
|
|
|
156
148
|
const body = { published: true };
|
|
157
149
|
const headers = {
|
|
158
150
|
...this._getApiDefaultHeaders(),
|
|
159
|
-
|
|
151
|
+
'Api-Company': companyId,
|
|
160
152
|
Authorization: this._getApiAuthHeaderValue(),
|
|
161
153
|
};
|
|
162
|
-
return
|
|
154
|
+
return httpRequest({ method: 'PATCH', url, data: body, headers });
|
|
163
155
|
}
|
|
164
156
|
};
|
package/config/config.service.js
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
const fs = require(
|
|
2
|
-
const { merge } = require(
|
|
3
|
-
const path = require(
|
|
4
|
-
const { getRootDir, logFileCrudMessage, logErrorMessage } = require(
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const { merge } = require('lodash');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const { getRootDir, logFileCrudMessage, logErrorMessage } = require('../utils');
|
|
5
5
|
|
|
6
6
|
module.exports = class ConfigService {
|
|
7
7
|
_config = { components: {} };
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
constructor(configFile = 'config.json') {
|
|
10
|
+
this._path = path.join(getRootDir(), configFile);
|
|
10
11
|
|
|
11
|
-
constructor() {
|
|
12
12
|
let config;
|
|
13
13
|
|
|
14
14
|
if (!fs.existsSync(this._path)) {
|
|
15
|
-
logErrorMessage(
|
|
15
|
+
logErrorMessage('No config file.');
|
|
16
16
|
process.exit();
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
try {
|
|
20
20
|
config = require(this._path);
|
|
21
21
|
} catch {
|
|
22
|
-
logErrorMessage(
|
|
22
|
+
logErrorMessage("Couldn't parse config file.");
|
|
23
23
|
process.exit();
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -35,7 +35,7 @@ module.exports = class ConfigService {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
getNewComponentRoot() {
|
|
38
|
-
return this._config.newComponentRoot ||
|
|
38
|
+
return this._config.newComponentRoot || 'components';
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
getPrefix() {
|
|
@@ -43,15 +43,15 @@ module.exports = class ConfigService {
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
getApiApplication() {
|
|
46
|
-
return this._config.apiApplication ||
|
|
46
|
+
return this._config.apiApplication || 'LtDdZKEPa5lK';
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
getApiBaseUrl() {
|
|
50
|
-
return this._config.apiBaseUrl ||
|
|
50
|
+
return this._config.apiBaseUrl || 'https://api.ayayot.com';
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
getApiVersion() {
|
|
54
|
-
return this._config.apiVersion ||
|
|
54
|
+
return this._config.apiVersion || '2';
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
addComponent(name, config) {
|
|
@@ -60,19 +60,15 @@ module.exports = class ConfigService {
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
extendComponent(name, config) {
|
|
63
|
-
this._config.components[name] = merge(
|
|
64
|
-
{},
|
|
65
|
-
this._config.components[name],
|
|
66
|
-
config
|
|
67
|
-
);
|
|
63
|
+
this._config.components[name] = merge({}, this._config.components[name], config);
|
|
68
64
|
this._sync();
|
|
69
65
|
}
|
|
70
66
|
|
|
71
67
|
_sync() {
|
|
72
|
-
fs.writeFileSync(this._path, JSON.stringify(this._config, null, 2)
|
|
73
|
-
encoding:
|
|
74
|
-
flag:
|
|
68
|
+
fs.writeFileSync(this._path, `${JSON.stringify(this._config, null, 2)}\n`, {
|
|
69
|
+
encoding: 'utf8',
|
|
70
|
+
flag: 'w',
|
|
75
71
|
});
|
|
76
|
-
logFileCrudMessage(
|
|
72
|
+
logFileCrudMessage('UPDATE', 'config.json');
|
|
77
73
|
}
|
|
78
74
|
};
|
package/http-request.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const axios = require('axios');
|
|
4
|
+
const { getRootDir, logErrorMessage } = require('./utils');
|
|
5
|
+
|
|
6
|
+
module.exports = function request(options) {
|
|
7
|
+
const customPath = path.join(getRootDir(), 'http-request.js');
|
|
8
|
+
|
|
9
|
+
if (fs.existsSync(customPath)) {
|
|
10
|
+
const customRequest = require(customPath);
|
|
11
|
+
|
|
12
|
+
if (typeof customRequest !== 'function') {
|
|
13
|
+
logErrorMessage('The custom "http-request.js" file must export a function.');
|
|
14
|
+
process.exit();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const promise = customRequest(options);
|
|
18
|
+
|
|
19
|
+
if (typeof promise !== 'object' || typeof promise.then !== 'function') {
|
|
20
|
+
logErrorMessage('The exported function in the custom "http-request.js" file must return a Promise.');
|
|
21
|
+
process.exit();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return promise;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return axios.request(options);
|
|
28
|
+
};
|
package/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
module.exports = {
|
|
2
|
-
AuthService: require(
|
|
3
|
-
DeployService: require(
|
|
4
|
-
ConfigService: require(
|
|
5
|
-
Server: require(
|
|
6
|
-
TemplateService: require(
|
|
7
|
-
...require(
|
|
8
|
-
...require(
|
|
9
|
-
...require(
|
|
2
|
+
AuthService: require('./api/auth.service'),
|
|
3
|
+
DeployService: require('./api/deploy.service'),
|
|
4
|
+
ConfigService: require('./config/config.service'),
|
|
5
|
+
Server: require('./server'),
|
|
6
|
+
TemplateService: require('./template/template.service'),
|
|
7
|
+
...require('./meta-files'),
|
|
8
|
+
...require('./prompts'),
|
|
9
|
+
...require('./utils'),
|
|
10
10
|
};
|
package/meta-files.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
const fs = require(
|
|
2
|
-
const path = require(
|
|
3
|
-
const { debounce, uniq } = require(
|
|
4
|
-
const rimraf = require(
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { debounce, uniq } = require('lodash');
|
|
4
|
+
const rimraf = require('rimraf');
|
|
5
5
|
|
|
6
|
-
const ICON_FILE_NAME =
|
|
7
|
-
const MANIFEST_FILE_NAME =
|
|
6
|
+
const ICON_FILE_NAME = 'icon.svg';
|
|
7
|
+
const MANIFEST_FILE_NAME = 'manifest.json';
|
|
8
|
+
const WATCH_OPTIONS = {
|
|
9
|
+
cwd: require('./utils').getRootDir(),
|
|
10
|
+
usePolling: process.platform !== 'darwin',
|
|
11
|
+
};
|
|
8
12
|
|
|
9
13
|
module.exports = {
|
|
10
14
|
cleanDir(dir) {
|
|
@@ -14,11 +18,11 @@ module.exports = {
|
|
|
14
18
|
fs.mkdirSync(dir, { recursive: true });
|
|
15
19
|
},
|
|
16
20
|
copyAssets(assets, inputDir, outputDir) {
|
|
17
|
-
const paths = uniq([MANIFEST_FILE_NAME, ICON_FILE_NAME, ...assets]).map(
|
|
18
|
-
|
|
21
|
+
const paths = uniq([MANIFEST_FILE_NAME, ICON_FILE_NAME, ...assets]).map((asset) =>
|
|
22
|
+
path.join(inputDir, asset),
|
|
19
23
|
);
|
|
20
24
|
paths.forEach((_path) => {
|
|
21
|
-
require(
|
|
25
|
+
require('glob')
|
|
22
26
|
.sync(_path)
|
|
23
27
|
.forEach((file) => {
|
|
24
28
|
const fileName = file.slice(inputDir.length + 1);
|
|
@@ -27,34 +31,36 @@ module.exports = {
|
|
|
27
31
|
});
|
|
28
32
|
},
|
|
29
33
|
watchAssets(assets, inputDir, outputDir) {
|
|
30
|
-
const root = require(
|
|
31
|
-
return require(
|
|
34
|
+
const root = require('./utils').getRootDir();
|
|
35
|
+
return require('chokidar')
|
|
32
36
|
.watch(
|
|
33
37
|
uniq([MANIFEST_FILE_NAME, ICON_FILE_NAME, ...assets]).map((asset) =>
|
|
34
|
-
path.join(inputDir, asset)
|
|
38
|
+
path.join(inputDir, asset),
|
|
35
39
|
),
|
|
36
|
-
|
|
40
|
+
WATCH_OPTIONS,
|
|
37
41
|
)
|
|
38
|
-
.on(
|
|
42
|
+
.on('all', (type, file) => {
|
|
39
43
|
const fileName = path.join(root, file).slice(inputDir.length + 1);
|
|
40
44
|
switch (type) {
|
|
41
|
-
case
|
|
42
|
-
case
|
|
45
|
+
case 'add':
|
|
46
|
+
case 'change':
|
|
43
47
|
_copyFileNameFromToSync(fileName, inputDir, outputDir);
|
|
44
48
|
break;
|
|
45
|
-
case
|
|
49
|
+
case 'unlink':
|
|
46
50
|
if (fs.existsSync(path.join(outputDir, fileName))) {
|
|
47
51
|
rimraf.sync(path.join(outputDir, fileName));
|
|
48
52
|
}
|
|
49
53
|
break;
|
|
54
|
+
default:
|
|
55
|
+
break;
|
|
50
56
|
}
|
|
51
57
|
});
|
|
52
58
|
},
|
|
53
|
-
watchInputDir
|
|
59
|
+
watchInputDir(dir, watchCallback) {
|
|
54
60
|
const _debouncedCallback = debounce(() => watchCallback(), 300);
|
|
55
|
-
require(
|
|
56
|
-
.watch([`${dir}/**`],
|
|
57
|
-
.on(
|
|
61
|
+
require('chokidar')
|
|
62
|
+
.watch([`${dir}/**`], WATCH_OPTIONS)
|
|
63
|
+
.on('all', (_, _path) => {
|
|
58
64
|
if (
|
|
59
65
|
_path.endsWith(path.join(dir, MANIFEST_FILE_NAME)) ||
|
|
60
66
|
_path.endsWith(path.join(dir, ICON_FILE_NAME))
|
|
@@ -67,11 +73,11 @@ module.exports = {
|
|
|
67
73
|
},
|
|
68
74
|
writeDemoFile: function writeDemoFile(tag, outputDir, outputFile) {
|
|
69
75
|
const demoFileContent = `<meta charset="utf-8">\n<title>${tag} demo</title>\n<script src="./${path.basename(
|
|
70
|
-
outputFile
|
|
76
|
+
outputFile,
|
|
71
77
|
)}"></script>\n\n\n<${tag}></${tag}>\n\n`;
|
|
72
78
|
fs.writeFileSync(`${outputDir}/demo.html`, demoFileContent, {
|
|
73
|
-
encoding:
|
|
74
|
-
flag:
|
|
79
|
+
encoding: 'utf8',
|
|
80
|
+
flag: 'w',
|
|
75
81
|
});
|
|
76
82
|
},
|
|
77
83
|
};
|
package/package.json
CHANGED
|
@@ -1,25 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ixon-cdk/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0-next.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"author": "",
|
|
7
7
|
"license": "ISC",
|
|
8
8
|
"dependencies": {
|
|
9
9
|
"app-root-dir": "^1.0.2",
|
|
10
|
-
"archiver": "^5.3.
|
|
11
|
-
"axios": "^0.
|
|
10
|
+
"archiver": "^5.3.1",
|
|
11
|
+
"axios": "^0.26.1",
|
|
12
12
|
"chalk": "^4.1.2",
|
|
13
|
-
"chokidar": "^3.5.
|
|
13
|
+
"chokidar": "^3.5.3",
|
|
14
14
|
"crypto-js": "^4.1.1",
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"glob": "^7.2.0",
|
|
15
|
+
"express": "^4.17.3",
|
|
16
|
+
"glob": "^8.0.1",
|
|
18
17
|
"livereload": "^0.9.3",
|
|
19
18
|
"lodash": "^4.17.21",
|
|
20
19
|
"opener": "^1.5.2",
|
|
21
|
-
"prompts": "^2.4.
|
|
20
|
+
"prompts": "^2.4.2",
|
|
22
21
|
"rimraf": "^3.0.2",
|
|
23
|
-
"yargs": "^17.
|
|
22
|
+
"yargs": "^17.4.1"
|
|
24
23
|
}
|
|
25
24
|
}
|
package/prompts.js
CHANGED
|
@@ -1,31 +1,31 @@
|
|
|
1
1
|
module.exports = {
|
|
2
|
-
promptCompanyId
|
|
2
|
+
promptCompanyId(name) {
|
|
3
3
|
return {
|
|
4
|
-
type:
|
|
4
|
+
type: 'text',
|
|
5
5
|
name,
|
|
6
|
-
message:
|
|
6
|
+
message: 'What is the ID of your Company?',
|
|
7
7
|
validate: (value) => {
|
|
8
8
|
if (!value) {
|
|
9
|
-
return
|
|
9
|
+
return 'Company ID is required.';
|
|
10
10
|
}
|
|
11
11
|
if (!/^[0-9]{4}-[0-9]{4}-[0-9]{4}-[0-9]{4}-[0-9]{4}$/.test(value)) {
|
|
12
|
-
return
|
|
12
|
+
return 'Invalid company ID.';
|
|
13
13
|
}
|
|
14
14
|
return true;
|
|
15
15
|
},
|
|
16
16
|
};
|
|
17
17
|
},
|
|
18
|
-
promptPageComponentTemplateId
|
|
18
|
+
promptPageComponentTemplateId(name) {
|
|
19
19
|
return {
|
|
20
|
-
type:
|
|
20
|
+
type: 'text',
|
|
21
21
|
name,
|
|
22
|
-
message:
|
|
22
|
+
message: 'What is the ID of the PageComponentTemplate?',
|
|
23
23
|
validate: (value) => {
|
|
24
24
|
if (!value) {
|
|
25
|
-
return
|
|
25
|
+
return 'Template ID is required.';
|
|
26
26
|
}
|
|
27
27
|
if (!/^[a-zA-Z0-9]{12}$/.test(value)) {
|
|
28
|
-
return
|
|
28
|
+
return 'Invalid template ID.';
|
|
29
29
|
}
|
|
30
30
|
return true;
|
|
31
31
|
},
|
package/server/index.js
CHANGED
|
@@ -1,32 +1,34 @@
|
|
|
1
|
-
const path = require(
|
|
2
|
-
const express = require(
|
|
3
|
-
const
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const express = require('express');
|
|
3
|
+
const liveReload = require('livereload');
|
|
4
|
+
const ConfigService = require('../config/config.service');
|
|
5
|
+
|
|
6
|
+
const LR_PORT_DEFAULT = 35729;
|
|
4
7
|
|
|
5
8
|
module.exports = class Server {
|
|
6
9
|
constructor(opts) {
|
|
7
10
|
this._configSrv = new ConfigService();
|
|
8
|
-
this.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
this._rootDir = require('../utils').getRootDir();
|
|
12
|
+
this._opts = {
|
|
13
|
+
port: 8000,
|
|
14
|
+
componentBasePath: 'components',
|
|
15
|
+
...opts,
|
|
16
|
+
};
|
|
12
17
|
}
|
|
13
18
|
|
|
14
19
|
serve(names) {
|
|
15
20
|
const app = express();
|
|
16
21
|
|
|
17
22
|
// Cache
|
|
18
|
-
app.use(
|
|
19
|
-
res.header(
|
|
23
|
+
app.use((_, res, next) => {
|
|
24
|
+
res.header('Cache-Control', 'no-store');
|
|
20
25
|
next();
|
|
21
26
|
});
|
|
22
27
|
|
|
23
28
|
// CORS
|
|
24
|
-
app.use(
|
|
25
|
-
res.header(
|
|
26
|
-
res.header(
|
|
27
|
-
"Access-Control-Allow-Headers",
|
|
28
|
-
"Origin, X-Requested-With, Content-Type, Accept"
|
|
29
|
-
);
|
|
29
|
+
app.use((_, res, next) => {
|
|
30
|
+
res.header('Access-Control-Allow-Origin', '*');
|
|
31
|
+
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
|
|
30
32
|
next();
|
|
31
33
|
});
|
|
32
34
|
|
|
@@ -35,35 +37,33 @@ module.exports = class Server {
|
|
|
35
37
|
names.forEach((name) => {
|
|
36
38
|
const outputDir = this._getOutputDir(name);
|
|
37
39
|
if (outputDir) {
|
|
38
|
-
const dir = path.resolve(
|
|
39
|
-
app.use(
|
|
40
|
-
`/${this._opts.componentBasePath}/${name}`,
|
|
41
|
-
express.static(dir)
|
|
42
|
-
);
|
|
40
|
+
const dir = path.resolve(this._rootDir, outputDir);
|
|
41
|
+
app.use(`/${this._opts.componentBasePath}/${name}`, express.static(dir));
|
|
43
42
|
}
|
|
44
43
|
});
|
|
45
44
|
}
|
|
46
45
|
|
|
47
46
|
// Adds live reload watchers
|
|
48
|
-
const lrServer =
|
|
49
|
-
|
|
50
|
-
this._getOutput(name),
|
|
51
|
-
`dist/${name}/manifest.json`,
|
|
52
|
-
]);
|
|
53
|
-
|
|
54
|
-
const watcher = require("chokidar").watch(outputs, { ignoreInitial: true, usePolling: true });
|
|
55
|
-
watcher.on("change", require("debounce")(() => lrServer,refresh("/"), 500));
|
|
56
|
-
process.on("exit", () => {
|
|
57
|
-
lrServer.close();
|
|
58
|
-
watcher.close();
|
|
47
|
+
const lrServer = liveReload.createServer({
|
|
48
|
+
port: this._opts.liveReloadPort,
|
|
59
49
|
});
|
|
50
|
+
const _refresh = () => lrServer.refresh('/');
|
|
51
|
+
const _debouncedRefresh = require('lodash/debounce')(_refresh, 250);
|
|
52
|
+
names
|
|
53
|
+
.flatMap((name) => [
|
|
54
|
+
[path.join(this._rootDir, this._getOutput(name)), 100],
|
|
55
|
+
[path.join(this._rootDir, `dist/${name}/manifest.json`), 500],
|
|
56
|
+
])
|
|
57
|
+
.forEach(([filename, interval]) =>
|
|
58
|
+
require('fs').watchFile(filename, { interval }, _debouncedRefresh),
|
|
59
|
+
);
|
|
60
60
|
|
|
61
61
|
// Simulator app
|
|
62
|
-
const appDir = path.dirname(require.resolve(
|
|
63
|
-
app.get(`/${this._opts.componentBasePath}/*`,
|
|
62
|
+
const appDir = path.dirname(require.resolve('@ixon-cdk/simulator'));
|
|
63
|
+
app.get(`/${this._opts.componentBasePath}/*`, (req, res) => {
|
|
64
64
|
res.sendStatus(404);
|
|
65
65
|
});
|
|
66
|
-
app.get(
|
|
66
|
+
app.get('/config.json', (req, res) => {
|
|
67
67
|
res.send({
|
|
68
68
|
api: {
|
|
69
69
|
appId: this._configSrv.getApiApplication(),
|
|
@@ -72,22 +72,32 @@ module.exports = class Server {
|
|
|
72
72
|
},
|
|
73
73
|
});
|
|
74
74
|
});
|
|
75
|
-
app.get(
|
|
76
|
-
app.all(
|
|
77
|
-
res.status(200).sendFile(
|
|
75
|
+
app.get('*.*', express.static(appDir));
|
|
76
|
+
app.all('*', (req, res) => {
|
|
77
|
+
res.status(200).sendFile('/index.html', { root: appDir });
|
|
78
78
|
});
|
|
79
79
|
|
|
80
|
-
app.listen(this._opts.port);
|
|
80
|
+
this.server = app.listen(this._opts.port);
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
openSimulator(name = null) {
|
|
84
84
|
const url = this._getComponentUrl(name);
|
|
85
|
-
const
|
|
86
|
-
|
|
85
|
+
const lrPort = this._opts.liveReloadPort;
|
|
86
|
+
const params = new URLSearchParams();
|
|
87
|
+
if (url) {
|
|
88
|
+
params.set('pct-url', url);
|
|
89
|
+
}
|
|
90
|
+
if (lrPort !== LR_PORT_DEFAULT) {
|
|
91
|
+
params.set('lr-port', lrPort);
|
|
92
|
+
}
|
|
93
|
+
const queryString = params.toString();
|
|
94
|
+
const openUrl = `${this._getBaseUrl()}/?${queryString}`;
|
|
95
|
+
require('opener')(openUrl);
|
|
87
96
|
}
|
|
88
97
|
|
|
89
98
|
_getBaseUrl() {
|
|
90
|
-
|
|
99
|
+
const address = this.server.address();
|
|
100
|
+
return `http://localhost:${address.port}`;
|
|
91
101
|
}
|
|
92
102
|
|
|
93
103
|
_getComponentUrl(name) {
|
|
@@ -1,31 +1,152 @@
|
|
|
1
|
-
const fs = require(
|
|
2
|
-
const path = require(
|
|
3
|
-
const prompts = require(
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const prompts = require('prompts');
|
|
4
4
|
|
|
5
5
|
const {
|
|
6
|
+
getFiles,
|
|
6
7
|
getRootDir,
|
|
7
8
|
ensureModule,
|
|
9
|
+
logErrorMessage,
|
|
8
10
|
logFileCrudMessage,
|
|
9
11
|
pascalCase,
|
|
10
|
-
} = require(
|
|
11
|
-
const ConfigService = require(
|
|
12
|
+
} = require('../utils');
|
|
13
|
+
const ConfigService = require('../config/config.service');
|
|
12
14
|
|
|
13
15
|
module.exports = class TemplateService {
|
|
14
16
|
_configSrv = new ConfigService();
|
|
15
17
|
|
|
18
|
+
_rootDir = getRootDir();
|
|
19
|
+
|
|
16
20
|
_schemas = {};
|
|
17
21
|
|
|
18
22
|
constructor() {
|
|
19
23
|
this._discover();
|
|
20
24
|
}
|
|
21
25
|
|
|
26
|
+
async addFromExample(componentName, componentPrefix) {
|
|
27
|
+
const examplesRoot = path.join(this._rootDir, 'node_modules/component-examples');
|
|
28
|
+
|
|
29
|
+
if (!fs.existsSync(examplesRoot)) {
|
|
30
|
+
logErrorMessage("Package 'ixoncloud/component-examples' is not installed.");
|
|
31
|
+
process.exit();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const examplesConfigSrv = new ConfigService('node_modules/component-examples/config.json');
|
|
35
|
+
const { components } = examplesConfigSrv._config;
|
|
36
|
+
|
|
37
|
+
if (!Object.keys(components).length) {
|
|
38
|
+
logErrorMessage('No examples found.');
|
|
39
|
+
process.exit();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const exampleComponentRoot = examplesConfigSrv.getNewComponentRoot();
|
|
43
|
+
const examplePrefix = examplesConfigSrv.getPrefix();
|
|
44
|
+
|
|
45
|
+
const result = await prompts({
|
|
46
|
+
type: 'select',
|
|
47
|
+
name: 'name',
|
|
48
|
+
message: 'Pick a template',
|
|
49
|
+
choices: Object.keys(components).map((name) => ({ title: name, value: name })),
|
|
50
|
+
initial: 0,
|
|
51
|
+
});
|
|
52
|
+
const exampleName = result.name;
|
|
53
|
+
|
|
54
|
+
if (!exampleName) {
|
|
55
|
+
process.exit();
|
|
56
|
+
} else if (!components[exampleName]) {
|
|
57
|
+
logErrorMessage(`Example '${exampleName}' is not configured.`);
|
|
58
|
+
process.exit();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const { build } = components[exampleName].runner;
|
|
62
|
+
const { builder } = build;
|
|
63
|
+
const isVue = builder.startsWith('@ixon-cdk/vue-builder');
|
|
64
|
+
const isStatic = builder.startsWith('@ixon-cdk/static-builder');
|
|
65
|
+
const isSvelte = builder.startsWith('@ixon-cdk/svelte-builder');
|
|
66
|
+
|
|
67
|
+
// find source files, read and replace.
|
|
68
|
+
const exampleDir = path.join(examplesRoot, exampleComponentRoot, exampleName);
|
|
69
|
+
const inputFilePath = path.join(exampleDir, build.input);
|
|
70
|
+
let inputFileContents = fs.readFileSync(inputFilePath, { encoding: 'utf-8' });
|
|
71
|
+
|
|
72
|
+
if (isVue) {
|
|
73
|
+
inputFileContents = this._findAndReplaceVueInputFile(inputFileContents, componentName);
|
|
74
|
+
} else if (isStatic) {
|
|
75
|
+
inputFileContents = this._findAndReplaceStaticInputFile(
|
|
76
|
+
inputFileContents,
|
|
77
|
+
examplePrefix,
|
|
78
|
+
exampleName,
|
|
79
|
+
componentPrefix,
|
|
80
|
+
componentName,
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// find manifest file, read and replace.
|
|
85
|
+
const manifestFilePath = path.join(path.dirname(inputFilePath), 'manifest.json');
|
|
86
|
+
const manifestFileContents = JSON.parse(fs.readFileSync(manifestFilePath));
|
|
87
|
+
manifestFileContents.main = `${this._getTag(componentPrefix, componentName)}.min.js`;
|
|
88
|
+
manifestFileContents.version = '1';
|
|
89
|
+
|
|
90
|
+
let input;
|
|
91
|
+
if (isVue) {
|
|
92
|
+
input = `${componentName}.vue`;
|
|
93
|
+
} else if (isStatic) {
|
|
94
|
+
input = `${componentName}.js`;
|
|
95
|
+
} else if (isSvelte) {
|
|
96
|
+
input = `${componentName}.svelte`;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const files = await getFiles(exampleDir).catch(logErrorMessage);
|
|
100
|
+
|
|
101
|
+
// find and install any missing dependencies.
|
|
102
|
+
files.forEach((file) => {
|
|
103
|
+
if (/\.(jsx?|tsx?|svelte|vue)$/i.test(file)) {
|
|
104
|
+
const fileContents = fs.readFileSync(file);
|
|
105
|
+
const { dependencies } = require(path.join(examplesRoot, 'package.json'));
|
|
106
|
+
this._checkDependencies(fileContents, dependencies || {});
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// else start copying input, and menifest files
|
|
111
|
+
const componentRoot = this._configSrv.getNewComponentRoot();
|
|
112
|
+
const dir = path.join(this._rootDir, componentRoot, componentName);
|
|
113
|
+
const _logCreatedInDir = (fileName) => {
|
|
114
|
+
logFileCrudMessage('CREATE', path.join(componentRoot, componentName, fileName));
|
|
115
|
+
};
|
|
116
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
117
|
+
|
|
118
|
+
files
|
|
119
|
+
.map((file) => file.slice(exampleDir.length + 1))
|
|
120
|
+
.forEach((file) => {
|
|
121
|
+
// create directory if it doesn't exist.
|
|
122
|
+
const _dir = path.dirname(path.join(dir, file));
|
|
123
|
+
if (!fs.existsSync(_dir)) {
|
|
124
|
+
fs.mkdirSync(_dir, { recursive: true });
|
|
125
|
+
}
|
|
126
|
+
// for the input-file and manifest use the replaced file contents.
|
|
127
|
+
if (file === build.input) {
|
|
128
|
+
fs.writeFileSync(path.join(dir, input), inputFileContents, { encoding: 'utf-8' });
|
|
129
|
+
_logCreatedInDir(input);
|
|
130
|
+
} else if (file === 'manifest.json') {
|
|
131
|
+
const json = `${JSON.stringify(manifestFileContents, null, 2)}\n`;
|
|
132
|
+
fs.writeFileSync(path.join(dir, file), json, { encoding: 'utf-8' });
|
|
133
|
+
_logCreatedInDir(file);
|
|
134
|
+
} else {
|
|
135
|
+
fs.copyFileSync(path.join(exampleDir, file), path.join(dir, file));
|
|
136
|
+
_logCreatedInDir(file);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
return Promise.resolve({ config: { runner: { build: { builder, input } } } });
|
|
141
|
+
}
|
|
142
|
+
|
|
22
143
|
async add(componentName, componentPrefix) {
|
|
23
144
|
let schema;
|
|
24
145
|
|
|
25
146
|
const result = await prompts({
|
|
26
|
-
type:
|
|
27
|
-
name:
|
|
28
|
-
message:
|
|
147
|
+
type: 'select',
|
|
148
|
+
name: 'templateName',
|
|
149
|
+
message: 'Pick a template',
|
|
29
150
|
choices: Object.keys(this._schemas).map((key) => ({
|
|
30
151
|
title: this._schemas[key].name,
|
|
31
152
|
value: key,
|
|
@@ -33,23 +154,19 @@ module.exports = class TemplateService {
|
|
|
33
154
|
initial: 0,
|
|
34
155
|
});
|
|
35
156
|
|
|
36
|
-
const tag = componentPrefix
|
|
37
|
-
? `${componentPrefix}-${componentName}`
|
|
38
|
-
: componentName;
|
|
39
|
-
|
|
40
157
|
if (result) {
|
|
41
158
|
schema = this._schemas[result.templateName];
|
|
42
159
|
}
|
|
43
160
|
|
|
44
161
|
if (schema) {
|
|
45
|
-
const context = { name: componentName, tag };
|
|
162
|
+
const context = { name: componentName, tag: this._getTag(componentPrefix, componentName) };
|
|
46
163
|
let variantIdx = null;
|
|
47
164
|
|
|
48
165
|
if (schema.variants) {
|
|
49
166
|
const _result = await prompts({
|
|
50
|
-
type:
|
|
51
|
-
name:
|
|
52
|
-
message:
|
|
167
|
+
type: 'select',
|
|
168
|
+
name: 'variantIdx',
|
|
169
|
+
message: 'Pick a variant',
|
|
53
170
|
choices: schema.variants.map((variant, index) => ({
|
|
54
171
|
title: variant.name,
|
|
55
172
|
value: index,
|
|
@@ -65,31 +182,28 @@ module.exports = class TemplateService {
|
|
|
65
182
|
schema = this._interpolateSchema(schema, context);
|
|
66
183
|
|
|
67
184
|
if (schema.config.runner) {
|
|
68
|
-
const modulesNames = Object.keys(schema.config.runner).reduce(
|
|
69
|
-
(
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
return [...names, name];
|
|
74
|
-
}
|
|
185
|
+
const modulesNames = Object.keys(schema.config.runner).reduce((names, cmd) => {
|
|
186
|
+
if (schema.config.runner[cmd].builder) {
|
|
187
|
+
const name = schema.config.runner[cmd].builder.split(':')[0];
|
|
188
|
+
if (!names.includes(name)) {
|
|
189
|
+
return [...names, name];
|
|
75
190
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
);
|
|
191
|
+
}
|
|
192
|
+
return names;
|
|
193
|
+
}, []);
|
|
80
194
|
modulesNames.forEach((name) => ensureModule(name));
|
|
81
195
|
}
|
|
82
196
|
|
|
83
|
-
const
|
|
197
|
+
const componentRoot = this._configSrv.getNewComponentRoot();
|
|
84
198
|
|
|
85
199
|
schema.files.forEach((file) => {
|
|
86
|
-
file.dest = `${
|
|
200
|
+
file.dest = `${componentRoot}/${componentName}/${file.dest}`;
|
|
87
201
|
this.createFile(file, context);
|
|
88
202
|
});
|
|
89
203
|
|
|
90
204
|
if (variantIdx !== null) {
|
|
91
205
|
schema.variants[variantIdx].files.forEach((file) => {
|
|
92
|
-
file.dest = `${
|
|
206
|
+
file.dest = `${componentRoot}/${componentName}/${file.dest}`;
|
|
93
207
|
this.createFile(file, context);
|
|
94
208
|
});
|
|
95
209
|
}
|
|
@@ -99,56 +213,126 @@ module.exports = class TemplateService {
|
|
|
99
213
|
}
|
|
100
214
|
|
|
101
215
|
createFile(file, ctx) {
|
|
102
|
-
|
|
103
|
-
fs.mkdirSync(path.dirname(path.join(rootDir, file.dest)), {
|
|
216
|
+
fs.mkdirSync(path.dirname(path.join(this._rootDir, file.dest)), {
|
|
104
217
|
recursive: true,
|
|
105
218
|
});
|
|
106
219
|
if (file.interpolateContent) {
|
|
107
220
|
const text = fs.readFileSync(
|
|
108
|
-
path.join(
|
|
109
|
-
|
|
110
|
-
file.source
|
|
111
|
-
),
|
|
112
|
-
{ encoding: "utf-8" }
|
|
221
|
+
path.join(path.dirname(require.resolve('@ixon-cdk/templates')), file.source),
|
|
222
|
+
{ encoding: 'utf-8' },
|
|
113
223
|
);
|
|
114
224
|
const data = this._interpolateText(text, ctx);
|
|
115
|
-
fs.writeFileSync(path.join(
|
|
116
|
-
encoding:
|
|
225
|
+
fs.writeFileSync(path.join(this._rootDir, file.dest), data, {
|
|
226
|
+
encoding: 'utf-8',
|
|
117
227
|
});
|
|
118
228
|
} else {
|
|
119
229
|
fs.copyFileSync(
|
|
120
|
-
path.join(
|
|
121
|
-
|
|
122
|
-
file.source
|
|
123
|
-
),
|
|
124
|
-
path.join(rootDir, file.dest)
|
|
230
|
+
path.join(path.dirname(require.resolve('@ixon-cdk/templates')), file.source),
|
|
231
|
+
path.join(this._rootDir, file.dest),
|
|
125
232
|
);
|
|
126
233
|
}
|
|
127
|
-
logFileCrudMessage(
|
|
234
|
+
logFileCrudMessage('CREATE', file.dest);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* This script loops over a dependencies object and will check if the provided file contents is
|
|
239
|
+
* importing any. When that is the case, it will first check for that package whether it could
|
|
240
|
+
* already be a depencency in your workspace. If not, the package will get installed and saved.
|
|
241
|
+
*/
|
|
242
|
+
_checkDependencies(fileContents, dependencies) {
|
|
243
|
+
const rootDeps = require(path.join(this._rootDir, 'package.json')).dependencies || {};
|
|
244
|
+
Object.keys(dependencies).forEach((pkg) => {
|
|
245
|
+
const matcher = new RegExp(`^\\s*import.*\\s['"]${pkg}\\S*['"]`, 'gm');
|
|
246
|
+
if (matcher.test(fileContents) && !(pkg in rootDeps)) {
|
|
247
|
+
const version = dependencies[pkg];
|
|
248
|
+
console.log(`Installing package '${pkg}'...`);
|
|
249
|
+
require('child_process').execSync(`npm i ${pkg}@${version} --save`);
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* This script will find and replace the component name definition in a vue (SFC) input file.
|
|
256
|
+
*/
|
|
257
|
+
_findAndReplaceVueInputFile(fileContents, componentName) {
|
|
258
|
+
const matcher = /export\s+default\s+{\s+name:\s+['"](\S+)['"]/gm;
|
|
259
|
+
return fileContents.replaceAll(matcher, (match, p1) => match.replace(p1, componentName));
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* This script will find and replace the component class definition and the arguments for the
|
|
264
|
+
* custom element define method in a static input file.
|
|
265
|
+
*
|
|
266
|
+
* Given the example input file has the follwing contents:
|
|
267
|
+
*
|
|
268
|
+
* ```js
|
|
269
|
+
* class PctExample extends HTMLElement {
|
|
270
|
+
* ...
|
|
271
|
+
* }
|
|
272
|
+
*
|
|
273
|
+
* customElements.define('pct-example', PctExample);
|
|
274
|
+
* ```
|
|
275
|
+
*
|
|
276
|
+
* ...if your workspace prefix is "abc" and your component name is "from-example", the content
|
|
277
|
+
* will be transformed into:
|
|
278
|
+
*
|
|
279
|
+
* ```js
|
|
280
|
+
* class AbcFromExample extends HTMLElement {
|
|
281
|
+
* ...
|
|
282
|
+
* }
|
|
283
|
+
*
|
|
284
|
+
* customElements.define('abc-from-example', AbcFromExample);
|
|
285
|
+
* ```
|
|
286
|
+
*/
|
|
287
|
+
_findAndReplaceStaticInputFile(
|
|
288
|
+
fileContents,
|
|
289
|
+
searchPrefix,
|
|
290
|
+
searchName,
|
|
291
|
+
replacementPrefix,
|
|
292
|
+
replacementName,
|
|
293
|
+
) {
|
|
294
|
+
const searchTag = this._getTag(searchPrefix, searchName);
|
|
295
|
+
const replacementTag = this._getTag(replacementPrefix, replacementName);
|
|
296
|
+
return fileContents
|
|
297
|
+
.replaceAll(new RegExp(`class\\s+(${pascalCase(searchTag)})`, 'gm'), (match, p1) =>
|
|
298
|
+
match.replace(p1, pascalCase(replacementTag)),
|
|
299
|
+
)
|
|
300
|
+
.replaceAll(
|
|
301
|
+
new RegExp(
|
|
302
|
+
`define\\s*\\(\\s*['"](${searchTag})['"]\\s*,\\s+(${pascalCase(searchTag)})\\)`,
|
|
303
|
+
'gm',
|
|
304
|
+
),
|
|
305
|
+
(match, p1, p2) =>
|
|
306
|
+
match.replace(p1, replacementTag).replace(p2, pascalCase(replacementTag)),
|
|
307
|
+
);
|
|
128
308
|
}
|
|
129
309
|
|
|
130
310
|
_discover() {
|
|
131
|
-
const dir = path.dirname(require.resolve(
|
|
311
|
+
const dir = path.dirname(require.resolve('@ixon-cdk/templates'));
|
|
132
312
|
const files = fs.readdirSync(dir);
|
|
133
313
|
files.forEach((file) => {
|
|
134
314
|
if (fs.lstatSync(path.join(dir, file)).isDirectory()) {
|
|
135
|
-
const schemaFile = path.join(dir, file,
|
|
315
|
+
const schemaFile = path.join(dir, file, 'schema.json');
|
|
136
316
|
if (fs.existsSync(schemaFile)) {
|
|
137
317
|
const schema = JSON.parse(fs.readFileSync(schemaFile));
|
|
138
|
-
this._schemas =
|
|
318
|
+
this._schemas = { ...this._schemas, [file]: schema };
|
|
139
319
|
}
|
|
140
320
|
}
|
|
141
321
|
});
|
|
142
322
|
}
|
|
143
323
|
|
|
324
|
+
_getTag(prefix, name) {
|
|
325
|
+
return prefix ? `${prefix}-${name}` : name;
|
|
326
|
+
}
|
|
327
|
+
|
|
144
328
|
_interpolateSchema(schema, params) {
|
|
145
329
|
return JSON.parse(this._interpolateText(JSON.stringify(schema), params));
|
|
146
330
|
}
|
|
147
331
|
|
|
148
332
|
_interpolateText(text, params) {
|
|
149
333
|
return text
|
|
150
|
-
.replace(
|
|
151
|
-
.replace(
|
|
152
|
-
.replace(
|
|
334
|
+
.replace(/<%=\s*name\s*%>/g, params.name)
|
|
335
|
+
.replace(/<%=\s*tag\s*%>/g, params.tag)
|
|
336
|
+
.replace(/<%=\s*classify\(\s*tag\s*\)\s*%>/g, pascalCase(params.tag));
|
|
153
337
|
}
|
|
154
338
|
};
|
package/utils.js
CHANGED
|
@@ -1,20 +1,18 @@
|
|
|
1
|
-
const fs = require(
|
|
2
|
-
const path = require(
|
|
3
|
-
const chalk = require(
|
|
4
|
-
const flow = require(
|
|
5
|
-
const camelCase = require(
|
|
6
|
-
const upperFirst = require(
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const chalk = require('chalk');
|
|
4
|
+
const flow = require('lodash/flow');
|
|
5
|
+
const camelCase = require('lodash/camelCase');
|
|
6
|
+
const upperFirst = require('lodash/upperFirst');
|
|
7
7
|
|
|
8
8
|
function getArgv() {
|
|
9
9
|
const remain = process.argv.slice(2);
|
|
10
|
-
const argv = require(
|
|
10
|
+
const { argv } = require('yargs/yargs')(remain);
|
|
11
11
|
|
|
12
12
|
// version argument fix
|
|
13
|
-
if (
|
|
14
|
-
const versionArg = remain.find((arg) =>
|
|
15
|
-
|
|
16
|
-
);
|
|
17
|
-
if (!!versionArg) {
|
|
13
|
+
if ('version' in argv) {
|
|
14
|
+
const versionArg = remain.find((arg) => /^--version=("[0-9]+"|'[0-9]+'|[0-9]+)$/.test(arg));
|
|
15
|
+
if (versionArg) {
|
|
18
16
|
const matches = versionArg.match(/^--version=['"]?([0-9]+)['"]?$/);
|
|
19
17
|
argv.version = Number(matches[1]);
|
|
20
18
|
}
|
|
@@ -24,7 +22,7 @@ function getArgv() {
|
|
|
24
22
|
}
|
|
25
23
|
|
|
26
24
|
function getRootDir() {
|
|
27
|
-
return require(
|
|
25
|
+
return require('app-root-dir').get();
|
|
28
26
|
}
|
|
29
27
|
|
|
30
28
|
function logErrorMessage(message) {
|
|
@@ -33,10 +31,12 @@ function logErrorMessage(message) {
|
|
|
33
31
|
|
|
34
32
|
function logFileCrudMessage(crud, file) {
|
|
35
33
|
switch (crud) {
|
|
36
|
-
case
|
|
37
|
-
case
|
|
34
|
+
case 'CREATE':
|
|
35
|
+
case 'UPDATE':
|
|
38
36
|
console.log(`${chalk.green(crud)} ${file}`);
|
|
39
37
|
break;
|
|
38
|
+
default:
|
|
39
|
+
break;
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
|
|
@@ -55,24 +55,30 @@ function moduleExists(moduleName) {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
function ensureModule(moduleName) {
|
|
58
|
-
if (!moduleName.startsWith(
|
|
59
|
-
|
|
58
|
+
if (!moduleName.startsWith('@ixon-cdk/')) {
|
|
59
|
+
logErrorMessage('Cannot install this module.');
|
|
60
|
+
return;
|
|
60
61
|
}
|
|
61
62
|
if (!moduleExists(moduleName)) {
|
|
62
63
|
console.log(`Installing package '${moduleName}'...`);
|
|
63
|
-
|
|
64
|
+
if (moduleName.startsWith('@ixon-cdk/')) {
|
|
65
|
+
const cdkVersion = require('./package.json').version;
|
|
66
|
+
require('child_process').execSync(`npm install --save-dev ${moduleName}@${cdkVersion}`);
|
|
67
|
+
} else {
|
|
68
|
+
require('child_process').execSync(`npm install --save-dev ${moduleName}`);
|
|
69
|
+
}
|
|
64
70
|
}
|
|
65
71
|
}
|
|
66
72
|
|
|
67
73
|
function zip(output, callback) {
|
|
68
74
|
const outputDir = path.dirname(output);
|
|
69
|
-
const zipFile = path.join(outputDir
|
|
75
|
+
const zipFile = path.join(`${outputDir}.zip`);
|
|
70
76
|
const stream = fs.createWriteStream(zipFile);
|
|
71
|
-
stream.on(
|
|
72
|
-
require(
|
|
77
|
+
stream.on('close', () => {
|
|
78
|
+
require('rimraf').sync(outputDir);
|
|
73
79
|
callback(zipFile);
|
|
74
80
|
});
|
|
75
|
-
const archive = require(
|
|
81
|
+
const archive = require('archiver')('zip', { zlib: { level: 9 } });
|
|
76
82
|
archive.pipe(stream);
|
|
77
83
|
archive.directory(outputDir, path.basename(outputDir));
|
|
78
84
|
archive.finalize();
|
|
@@ -81,7 +87,7 @@ function zip(output, callback) {
|
|
|
81
87
|
const pascalCase = flow(camelCase, upperFirst);
|
|
82
88
|
|
|
83
89
|
function apiHttpErrorToMessage(error) {
|
|
84
|
-
if (typeof error ===
|
|
90
|
+
if (typeof error === 'string') {
|
|
85
91
|
logErrorMessage(error);
|
|
86
92
|
process.exit();
|
|
87
93
|
}
|
|
@@ -90,28 +96,18 @@ function apiHttpErrorToMessage(error) {
|
|
|
90
96
|
if (errors) {
|
|
91
97
|
logErrorMessage(
|
|
92
98
|
errors
|
|
93
|
-
.map((err) =>
|
|
94
|
-
|
|
95
|
-
? `${err.propertyName}: ${err.message}`
|
|
96
|
-
: err.message
|
|
97
|
-
)
|
|
98
|
-
.join("\n")
|
|
99
|
+
.map((err) => (err.propertyName ? `${err.propertyName}: ${err.message}` : err.message))
|
|
100
|
+
.join('\n'),
|
|
99
101
|
);
|
|
100
102
|
process.exit();
|
|
101
103
|
}
|
|
102
104
|
}
|
|
103
|
-
logErrorMessage(
|
|
105
|
+
logErrorMessage('Unexpected error.');
|
|
104
106
|
console.log(error);
|
|
105
107
|
process.exit();
|
|
106
108
|
}
|
|
107
109
|
|
|
108
|
-
function generatePreviewHash(
|
|
109
|
-
templateId,
|
|
110
|
-
templateName,
|
|
111
|
-
versionId,
|
|
112
|
-
versionNumber,
|
|
113
|
-
versionMainPath
|
|
114
|
-
) {
|
|
110
|
+
function generatePreviewHash(templateId, templateName, versionId, versionNumber, versionMainPath) {
|
|
115
111
|
const ref = {
|
|
116
112
|
tid: templateId,
|
|
117
113
|
tnm: templateName,
|
|
@@ -119,14 +115,26 @@ function generatePreviewHash(
|
|
|
119
115
|
vnr: versionNumber,
|
|
120
116
|
vmp: versionMainPath,
|
|
121
117
|
};
|
|
122
|
-
const salt =
|
|
123
|
-
return require(
|
|
118
|
+
const salt = 'A9qJ03jh';
|
|
119
|
+
return require('crypto-js').AES.encrypt(JSON.stringify(ref), salt).toString();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async function getFiles(dir) {
|
|
123
|
+
const dirents = await fs.promises.readdir(dir, { withFileTypes: true });
|
|
124
|
+
const files = await Promise.all(
|
|
125
|
+
dirents.map((dirent) => {
|
|
126
|
+
const res = path.resolve(dir, dirent.name);
|
|
127
|
+
return dirent.isDirectory() ? getFiles(res) : res;
|
|
128
|
+
}),
|
|
129
|
+
);
|
|
130
|
+
return Array.prototype.concat(...files);
|
|
124
131
|
}
|
|
125
132
|
|
|
126
133
|
module.exports = {
|
|
127
134
|
getArgv,
|
|
128
135
|
getRootDir,
|
|
129
136
|
logErrorMessage,
|
|
137
|
+
getFiles,
|
|
130
138
|
logFileCrudMessage,
|
|
131
139
|
logSuccessMessage,
|
|
132
140
|
moduleExists,
|