@tangelo/tangelo-configuration-toolkit 1.19.0 → 1.20.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/index.js +7 -4
- package/package.json +3 -2
- package/src/lib/get-repoconfig.js +5 -2
- package/src/lib/gulp-sftp.js +1 -1
- package/src/lib/gulp-tcl-config.js +40 -0
- package/src/lib/set-global-functions.js +3 -0
- package/src/lib/tcl-config.js +101 -0
- package/src/modules/deploy/execute.js +4 -2
- package/src/modules/deploy/index.js +2 -2
- package/src/modules/deploy/srcset.js +4 -4
- package/src/modules/fonto/commands.js +34 -15
- package/src/modules/git/index.js +4 -4
package/index.js
CHANGED
|
@@ -92,13 +92,13 @@ global._isPre51 = () => !fs.existsSync(path.join(_paths.repo, _paths.tdi, 'src')
|
|
|
92
92
|
|
|
93
93
|
global._modulesTdi = {
|
|
94
94
|
absolutePathTdi: path.join(_paths.repo, _paths.tdi),
|
|
95
|
-
ensureDepsUpToDate() {
|
|
95
|
+
ensureDepsUpToDate(message) {
|
|
96
96
|
if (this.depsUpToDate) return;
|
|
97
97
|
try {
|
|
98
|
-
_info('Checking installed dependencies in submodule');
|
|
98
|
+
if (message) _info('Checking installed dependencies in submodule');
|
|
99
99
|
execSync('npm list', {cwd: this.absolutePathTdi, stdio: 'ignore'});
|
|
100
100
|
} catch (e) {
|
|
101
|
-
_info('Updating dependencies in submodule');
|
|
101
|
+
if (message) _info('Updating dependencies in submodule');
|
|
102
102
|
execSync('npm update', {cwd: this.absolutePathTdi, stdio: 'ignore'});
|
|
103
103
|
}
|
|
104
104
|
this.depsUpToDate = true;
|
|
@@ -110,7 +110,10 @@ global._modulesTdi = {
|
|
|
110
110
|
return require(path.join(this.absolutePathTdi, 'tct', module));
|
|
111
111
|
}
|
|
112
112
|
catch (e) {
|
|
113
|
-
if (throws)
|
|
113
|
+
if (throws) {
|
|
114
|
+
_debug(`${e}`);
|
|
115
|
+
_error('Module could not be loaded: ' + module);
|
|
116
|
+
}
|
|
114
117
|
else return undefined;
|
|
115
118
|
}
|
|
116
119
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangelo/tangelo-configuration-toolkit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.20.1",
|
|
4
4
|
"engines": {
|
|
5
5
|
"node": ">=14.0.0"
|
|
6
6
|
},
|
|
@@ -46,10 +46,11 @@
|
|
|
46
46
|
"p-limit": "^3.1.0",
|
|
47
47
|
"replace-in-file": "^6.3.2",
|
|
48
48
|
"sass": "^1.43.5",
|
|
49
|
-
"saxon-js": "^2.
|
|
49
|
+
"saxon-js": "^2.5.0",
|
|
50
50
|
"ssh2-sftp-client": "^9.1.0",
|
|
51
51
|
"through2": "^4.0.2",
|
|
52
52
|
"tiny-lr": "^2.0.0",
|
|
53
|
+
"xml2js": "^0.6.2",
|
|
53
54
|
"yargs": "^17.7.2"
|
|
54
55
|
},
|
|
55
56
|
"repository": {
|
|
@@ -17,12 +17,15 @@ module.exports = function getRepoconfig(repoPath) {
|
|
|
17
17
|
const path_cmscustom = xpiDir.replace(/\/[^/]+$/, '').split(/\//);
|
|
18
18
|
const path_dbconfig = p.replace(/.*\/database\/config\/(.*)\/[^/]+/, '$1').split(/[/\\]/);
|
|
19
19
|
const dnRegex = [path_cmscustom[0].replace(/[_'"]/g, '.'), path_dbconfig[0].replace(/[_'"]/g, '.')].sort((a, b) => b.length - a.length).join('|');
|
|
20
|
-
|
|
20
|
+
/* Get customer name based on txd_document_types.display_name; if that match fails fallback to customername defined in path */
|
|
21
|
+
const customer_name = (dtDisplayName.match(RegExp(dnRegex, 'i')) || [path_cmscustom[0].split(/[\s_]/g).map(s => s[0].toUpperCase() + s.substring(1)).join(' ')])[0];
|
|
22
|
+
const customer_name_regex = RegExp(customer_name.replace(/(\W)/g, '\\$1?'), 'gi'); // match customer name; allow differences in special characters / match case insensitive
|
|
21
23
|
|
|
22
24
|
return {
|
|
23
25
|
customer_name,
|
|
24
26
|
customer_abbr: ntName.split('_')[0],
|
|
25
|
-
|
|
27
|
+
/* if display name matches the customer name; strip customer name from display name to get the project name; otherwise use the complete display name as projectname */
|
|
28
|
+
project_name: dtDisplayName.match(customer_name_regex) ? dtDisplayName.replace(customer_name_regex, '').trim() : dtDisplayName,
|
|
26
29
|
project_abbr: ntName.split('_')[1],
|
|
27
30
|
path_cmscustom,
|
|
28
31
|
path_dbconfig,
|
package/src/lib/gulp-sftp.js
CHANGED
|
@@ -14,7 +14,7 @@ module.exports = function(ftpConfig, remotedir) {
|
|
|
14
14
|
|
|
15
15
|
function transform (file, _, cb) {
|
|
16
16
|
if (file.isStream()) return cb(new Error('Streaming not supported.'));
|
|
17
|
-
if (file.stat
|
|
17
|
+
if (file.stat?.isDirectory()) return cb();
|
|
18
18
|
|
|
19
19
|
file.destination = path.join(remotedir, file.relative).toFws;
|
|
20
20
|
files.push(file); // collect all files in array
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const fs = require('fs-extra');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const TclConfig = require('./tcl-config');
|
|
4
|
+
const through2 = require('through2');
|
|
5
|
+
const Vinyl = require('vinyl');
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
function createAddToStreamFn(stream) {
|
|
9
|
+
return (path, content) => stream.push(new Vinyl({
|
|
10
|
+
path: path,
|
|
11
|
+
contents: Buffer.from(content)
|
|
12
|
+
}));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
module.exports = function() {
|
|
16
|
+
const tclFileDirs = [];
|
|
17
|
+
|
|
18
|
+
return through2.obj(
|
|
19
|
+
|
|
20
|
+
function transform (file, _, cb) {
|
|
21
|
+
if (file.isStream()) return cb(new Error('Streaming not supported.'));
|
|
22
|
+
|
|
23
|
+
if (file.extname == '.tcl') tclFileDirs.push(path.dirname(file.relative));
|
|
24
|
+
return cb(null, file);
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
function flush(cb) {
|
|
28
|
+
for (const tclFileDir of tclFileDirs) {
|
|
29
|
+
const tclConfig = new TclConfig(tclFileDir, createAddToStreamFn(this));
|
|
30
|
+
tclConfig.outputJson(path.resolve(tclFileDir, 'fonto/assets'));
|
|
31
|
+
tclConfig.outputCss(path.resolve(tclFileDir, 'fonto'));
|
|
32
|
+
const esefCssDir = path.resolve(tclFileDir, 'export/esef/esef_out/css');
|
|
33
|
+
if (fs.existsSync(esefCssDir)) tclConfig.outputCss(esefCssDir);
|
|
34
|
+
}
|
|
35
|
+
cb();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
)
|
|
39
|
+
.resume(); // required for triggering 'end' event
|
|
40
|
+
};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
const fs = require('fs-extra');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const sass = require('sass');
|
|
4
|
+
const SaxonJS = require('saxon-js');
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
module.exports = class TclConfig {
|
|
8
|
+
|
|
9
|
+
static #SEF_FILE_PATH = 'tcl/configToJson.sef.json';
|
|
10
|
+
static #JSON_TO_SCSS_FILE_PATH = 'tcl/configJsonToScss';
|
|
11
|
+
static #TCL_FILE_NAME = 'project.tcl';
|
|
12
|
+
static #TCL_JSON_FILE_NAME = 'tcl-config.json';
|
|
13
|
+
static #TCL_CSS_FILE_NAME = 'tcl-styles.css';
|
|
14
|
+
static #FONTO_HTML_FILE_NAME = 'index.html';
|
|
15
|
+
|
|
16
|
+
static #sefFile;
|
|
17
|
+
static #jsonToScssFile;
|
|
18
|
+
|
|
19
|
+
static #transformTclConfigToJson(tclFilePathRel) {
|
|
20
|
+
this.#sefFile ??= _modulesTdi.require(this.#SEF_FILE_PATH, {message: false});
|
|
21
|
+
|
|
22
|
+
const messages = [` Warnings from transformation of ${tclFilePathRel}`];
|
|
23
|
+
const transformation = SaxonJS.transform({
|
|
24
|
+
stylesheetText: JSON.stringify(this.#sefFile),
|
|
25
|
+
sourceFileName: tclFilePathRel,
|
|
26
|
+
destination: 'raw',
|
|
27
|
+
deliverMessage(messageNode) {
|
|
28
|
+
messages.push(messageNode.textContent);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
if (messages[1]) _warn(messages.join('\n '));
|
|
33
|
+
return transformation.principalResult ?? _error(`No result from transformation of ${tclFilePathRel}`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
static #transformJsonToCss(tclFilePathRel, json, moduleName) {
|
|
37
|
+
this.#jsonToScssFile ??= _modulesTdi.require(this.#JSON_TO_SCSS_FILE_PATH, {message: false});
|
|
38
|
+
const scss = this.#jsonToScssFile(json.project, moduleName);
|
|
39
|
+
const url = new URL(path.join('file://', path.resolve(tclFilePathRel)));
|
|
40
|
+
return sass.compileString(scss, {url, style: 'compressed'}).css;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
static #addCssImportToHtml(dir) {
|
|
44
|
+
const filepath = path.join(dir, this.#FONTO_HTML_FILE_NAME);
|
|
45
|
+
|
|
46
|
+
if (fs.existsSync(filepath)) {
|
|
47
|
+
const html = fs.readFileSync(filepath).toString();
|
|
48
|
+
|
|
49
|
+
if (!RegExp(`<link[^>]*${this.#TCL_CSS_FILE_NAME}[^>]*>`).test(html)) {
|
|
50
|
+
const newHtml = html.replace(/((\s+<link.*")[^"]+\.css(.*))/, `$1$2${this.#TCL_CSS_FILE_NAME}$3`);
|
|
51
|
+
fs.outputFileSync(filepath, newHtml);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
#outputFn;
|
|
57
|
+
#doModifyFontoHtml;
|
|
58
|
+
#tclFilePathRel;
|
|
59
|
+
#tclFileExists;
|
|
60
|
+
#resultJson;
|
|
61
|
+
#resultCss = {};
|
|
62
|
+
|
|
63
|
+
constructor(tclFileRelDir, addToStreamFn) {
|
|
64
|
+
this.#tclFilePathRel = path.join(tclFileRelDir, TclConfig.#TCL_FILE_NAME);
|
|
65
|
+
this.#tclFileExists = fs.existsSync(this.#tclFilePathRel);
|
|
66
|
+
this.#outputFn = addToStreamFn ?? fs.outputFileSync;
|
|
67
|
+
this.#doModifyFontoHtml = !addToStreamFn;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
#getJson() {
|
|
71
|
+
return this.#resultJson ??= TclConfig.#transformTclConfigToJson(this.#tclFilePathRel);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
#getCss(moduleName) {
|
|
75
|
+
return this.#resultCss[moduleName] ??= TclConfig.#transformJsonToCss(this.#tclFilePathRel, this.#getJson(), moduleName);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
outputJson(dir) {
|
|
79
|
+
if (this.#tclFileExists) {
|
|
80
|
+
const filepath = path.join(dir, TclConfig.#TCL_JSON_FILE_NAME);
|
|
81
|
+
this.#outputFn(filepath, JSON.stringify(this.#getJson()));
|
|
82
|
+
}
|
|
83
|
+
return this;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
outputCss(dir) {
|
|
87
|
+
if (this.#tclFileExists) {
|
|
88
|
+
const filepath = path.join(dir, TclConfig.#TCL_CSS_FILE_NAME);
|
|
89
|
+
const moduleName = dir.includes('esef') ? 'ESEF' : 'FONTO';
|
|
90
|
+
this.#outputFn(filepath, this.#getCss(moduleName));
|
|
91
|
+
this.modifyFontoHtml(dir);
|
|
92
|
+
}
|
|
93
|
+
return this;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
modifyFontoHtml(dir) {
|
|
97
|
+
if (this.#tclFileExists && this.#doModifyFontoHtml) TclConfig.#addCssImportToHtml(dir);
|
|
98
|
+
return this;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
};
|
|
@@ -4,6 +4,7 @@ const fs = require('fs-extra');
|
|
|
4
4
|
const globby = require('globby');
|
|
5
5
|
const gulp = require('gulp');
|
|
6
6
|
const {NodeSSH} = require('node-ssh');
|
|
7
|
+
const g_tcl = require('../../lib/gulp-tcl-config');
|
|
7
8
|
const through2 = require('through2');
|
|
8
9
|
const {spawnSync} = require('child_process');
|
|
9
10
|
|
|
@@ -119,13 +120,13 @@ const createDeliveryPack = () => { // create install scripts if necessary, zip o
|
|
|
119
120
|
};
|
|
120
121
|
|
|
121
122
|
|
|
122
|
-
const transfer = (paths, lrServer) => {
|
|
123
|
+
const transfer = (paths, {watch, lrServer}) => {
|
|
123
124
|
const jsFGlob = _settingsTdi().transpileToES5 ? ['**/*.js', '!**/hce/**/template_*', '!**/fonto/**', '!**/vendor/**', '!**/*.min.js'] : [];
|
|
124
125
|
const jsF = g_filter(jsFGlob, {restore: true});
|
|
125
126
|
const xpsF = g_filter(['**/xopus/**/*.x*'], {restore: true});
|
|
126
127
|
const sassF = g_filter(['**/*.scss'], {restore: true});
|
|
127
128
|
const shF = g_filter(['**/*.sh'], {restore: true});
|
|
128
|
-
const srcset = s.create(paths);
|
|
129
|
+
const srcset = s.create(paths, {watch});
|
|
129
130
|
const files = [];
|
|
130
131
|
|
|
131
132
|
// local git repo must be on latest commit containing fonto changes, and fonto build files must be newer than that commit, unless that commit belongs to the current user
|
|
@@ -160,6 +161,7 @@ const transfer = (paths, lrServer) => {
|
|
|
160
161
|
.pipe(xpsF)
|
|
161
162
|
.pipe(g_resolveIncl())
|
|
162
163
|
.pipe(xpsF.restore)
|
|
164
|
+
.pipe(g_tcl())
|
|
163
165
|
.pipe(jsF)
|
|
164
166
|
.pipe(g_sourcemaps.init())
|
|
165
167
|
.pipe(g_babel({presets: [[babel_pe, {modules: false}]], comments: false, minified: true})) // function must be executed here, otherwise second execution during watch fails
|
|
@@ -33,7 +33,7 @@ module.exports = function deploy (argv) {
|
|
|
33
33
|
// execute chosen option
|
|
34
34
|
|
|
35
35
|
if (argv.test) {
|
|
36
|
-
s.create([...c.transferPatterns, '!**/fonto/{*.*,!(dist)/**}'], true);
|
|
36
|
+
s.create([...c.transferPatterns, '!**/fonto/{*.*,!(dist)/**}'], {test: true});
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
if (argv.copy) {
|
|
@@ -52,7 +52,7 @@ module.exports = function deploy (argv) {
|
|
|
52
52
|
this.queue = this.queue.map(p => p.replace(/fonto(.)(?:dist|dev).assets.schemas(.sx-shell-.*?).json/, 'fonto$1packages$2$1src$1assets$1schemas$2.json')); // fonto schema changes can be detected in different paths at the same time, rewrite paths to original package-path because files in build folders can be removed before transfer starts
|
|
53
53
|
this.queue = [...new Set(this.queue)]; // remove duplicates
|
|
54
54
|
this.queue.forEach(v => s.addToCache(v));
|
|
55
|
-
transfer(this.queue, lrServer);
|
|
55
|
+
transfer(this.queue, {watch: true, lrServer});
|
|
56
56
|
this.queue = [];
|
|
57
57
|
},
|
|
58
58
|
add (fp) {
|
|
@@ -9,12 +9,12 @@ const resolveBind = (d, p) => p.replace('#{cmscustompath}', 'cmscustom/').replac
|
|
|
9
9
|
|
|
10
10
|
module.exports = {
|
|
11
11
|
|
|
12
|
-
create (
|
|
12
|
+
create (paths, {test, watch}) {
|
|
13
13
|
const startTime = new Date();
|
|
14
14
|
|
|
15
|
-
this.filesToTransfer
|
|
16
|
-
this.potentialBaseFilesCache
|
|
17
|
-
this.potentialBaseFiles
|
|
15
|
+
this.filesToTransfer = watch ? paths : globby.sync(paths, {nodir: true}); // get list of files to transfer
|
|
16
|
+
this.potentialBaseFilesCache ??= globby.sync('**/*.{xml,xsd,xsl,scss}'); // get list of potential base files, if not previously done
|
|
17
|
+
this.potentialBaseFiles = this.potentialBaseFilesCache
|
|
18
18
|
.filter(p => !this.filesToTransfer.includes(p)) // subtract files to transfer from list of potential base files
|
|
19
19
|
.map(path => [path]); // make array so file contents can be added later
|
|
20
20
|
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
const del
|
|
2
|
-
const {exec}
|
|
3
|
-
const fs
|
|
4
|
-
const globby
|
|
5
|
-
const gulp
|
|
6
|
-
const g_print
|
|
7
|
-
const path
|
|
8
|
-
const sass
|
|
9
|
-
const
|
|
1
|
+
const del = require('del');
|
|
2
|
+
const {exec} = require('child_process');
|
|
3
|
+
const fs = require('fs-extra');
|
|
4
|
+
const globby = require('globby');
|
|
5
|
+
const gulp = require('gulp');
|
|
6
|
+
const g_print = require('gulp-print');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const sass = require('gulp-sass')(require('sass'));
|
|
9
|
+
const TclConfig = require('../../lib/tcl-config');
|
|
10
|
+
const wws = require('../../lib/worker-with-spinner');
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
g_print.setLogFunction((filepath) => _write(filepath.nostyle));
|
|
@@ -261,6 +262,11 @@ module.exports = {
|
|
|
261
262
|
_write('Done.\n');
|
|
262
263
|
})
|
|
263
264
|
.then(() => cmdExec(`${fdt} editor build`))
|
|
265
|
+
.then(() => {
|
|
266
|
+
_info('Read project configuration and create json and css for Fonto:');
|
|
267
|
+
new TclConfig('..').outputJson('dist/assets').outputCss('dist');
|
|
268
|
+
_write('Done.\n');
|
|
269
|
+
})
|
|
264
270
|
.then(() => [fdt])
|
|
265
271
|
;
|
|
266
272
|
},
|
|
@@ -268,14 +274,27 @@ module.exports = {
|
|
|
268
274
|
run ([fdt]) {
|
|
269
275
|
return compileSass()
|
|
270
276
|
.then(() => {
|
|
271
|
-
_info('
|
|
272
|
-
|
|
277
|
+
_info('Read project configuration and create json and css for Fonto:');
|
|
278
|
+
new TclConfig('..').outputJson('dev/assets').outputCss('dev');
|
|
279
|
+
_write('Done.\n');
|
|
280
|
+
})
|
|
281
|
+
.then(() => {
|
|
282
|
+
_info('Starting watch for tcl and sass files:');
|
|
283
|
+
gulp.watch(['**/*.scss', '../*.tcl', 'dev/index.html'])
|
|
273
284
|
.on('all', (event, filepath) => {
|
|
274
285
|
_write(event + ':', filepath);
|
|
275
|
-
|
|
276
|
-
.
|
|
277
|
-
|
|
278
|
-
|
|
286
|
+
if (filepath.endsWith('.scss')) {
|
|
287
|
+
gulp.src('**/*.scss')
|
|
288
|
+
.pipe(sass().on('error', sass.logError))
|
|
289
|
+
.pipe(gulp.dest('.'))
|
|
290
|
+
;
|
|
291
|
+
}
|
|
292
|
+
else if (filepath.endsWith('.html')) {
|
|
293
|
+
new TclConfig('..').modifyFontoHtml('dev');
|
|
294
|
+
}
|
|
295
|
+
else if (filepath.endsWith('.tcl')) {
|
|
296
|
+
new TclConfig('..').outputJson('dev/assets').outputCss('dev');
|
|
297
|
+
}
|
|
279
298
|
});
|
|
280
299
|
_write('Done.\n');
|
|
281
300
|
})
|
package/src/modules/git/index.js
CHANGED
|
@@ -71,9 +71,9 @@ function init () {
|
|
|
71
71
|
])
|
|
72
72
|
.then(() => {
|
|
73
73
|
_info(`Next steps:
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
74
|
+
1. Go to https://bitbucket.org/repo/create?workspace=tangelosoftware and create a repository named "${path.basename(process.cwd()).replace(/\W/, '-')}", with options for including README/.gitignore disabled.
|
|
75
|
+
2. Open this folder in Sourcetree (ctrl+O), and push master branch to origin.
|
|
76
|
+
`.replace(/^\s{8}/gm, ''));
|
|
77
77
|
});
|
|
78
78
|
});
|
|
79
79
|
}
|
|
@@ -101,7 +101,7 @@ function clone ({clone: repoName}) {
|
|
|
101
101
|
// Change directory for the next commands, it should have the same name as the clone argument from commandline at this point
|
|
102
102
|
process.chdir('./' + repoName);
|
|
103
103
|
cmdExec([
|
|
104
|
-
|
|
104
|
+
// Retrieve TDI submodule for this client
|
|
105
105
|
['git submodule update --init', 'Fetch submodules such as TDI'],
|
|
106
106
|
// Create symlinks for TDI
|
|
107
107
|
['tct b -s', 'Create TDI symlinks'],
|