neo.mjs 6.1.5 → 6.2.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/apps/ServiceWorker.mjs +2 -2
- package/buildScripts/createClass.mjs +50 -35
- package/buildScripts/createComponent.mjs +250 -0
- package/buildScripts/tools/createExample.mjs +159 -0
- package/buildScripts/tools/createScss.mjs +98 -0
- package/examples/ServiceWorker.mjs +2 -2
- package/package.json +2 -1
- package/src/DefaultConfig.mjs +2 -2
- package/src/menu/List.mjs +6 -3
- package/src/menu/Model.mjs +3 -0
package/apps/ServiceWorker.mjs
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env node
|
2
2
|
|
3
3
|
import chalk from 'chalk';
|
4
|
-
import {
|
4
|
+
import {Command} from 'commander/esm.mjs';
|
5
5
|
import envinfo from 'envinfo';
|
6
6
|
import fs from 'fs-extra';
|
7
7
|
import inquirer from 'inquirer';
|
@@ -10,36 +10,37 @@ import path from 'path';
|
|
10
10
|
import {fileURLToPath} from 'url';
|
11
11
|
|
12
12
|
const
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
13
|
+
__dirname = fileURLToPath(new URL('../', import.meta.url)),
|
14
|
+
cwd = process.cwd(),
|
15
|
+
requireJson = path => JSON.parse(fs.readFileSync((path))),
|
16
|
+
packageJson = requireJson(path.join(__dirname, 'package.json')),
|
17
|
+
insideNeo = process.env.npm_package_name === 'neo.mjs',
|
18
|
+
program = new Command(),
|
19
|
+
programName = `${packageJson.name} create-class`,
|
20
|
+
questions = [],
|
21
|
+
/**
|
22
|
+
* Maintain a list of dir-names recognized as source root directories.
|
23
|
+
* When not using dot notation with a class-name, the program assumes
|
24
|
+
* that we want to create the class inside the cwd. The proper namespace
|
25
|
+
* is then looked up by traversing the directory path up to the first
|
26
|
+
* folder that matches an entry in "sourceRootDirs". The owning
|
27
|
+
* folder (parent of cwd, child of sourceRootDirs[n]) will then be used as the
|
28
|
+
* namespace for this created class.
|
29
|
+
* Can be overwritten with the -s option.
|
30
|
+
* @type {String[]}
|
31
|
+
*/
|
32
|
+
sourceRootDirs = ['apps'];
|
33
33
|
|
34
34
|
program
|
35
35
|
.name(programName)
|
36
36
|
.version(packageJson.version)
|
37
|
-
.option('-i, --info',
|
38
|
-
.option('-d, --drop',
|
37
|
+
.option('-i, --info', 'print environment debug info')
|
38
|
+
.option('-d, --drop', 'drops class in the currently selected folder')
|
39
39
|
.option('-n, --singleton <value>', 'Create a singleton? Pick "yes" or "no"')
|
40
|
-
.option('-s, --source <value>',
|
40
|
+
.option('-s, --source <value>', `name of the folder containing the project. Defaults to any of ${sourceRootDirs.join(',')}`)
|
41
41
|
.option('-b, --baseClass <value>')
|
42
42
|
.option('-c, --className <value>')
|
43
|
+
.option('-r, --scss <value>')
|
43
44
|
.allowUnknownOption()
|
44
45
|
.on('--help', () => {
|
45
46
|
console.log('\nIn case you have any issues, please create a ticket here:');
|
@@ -144,9 +145,11 @@ if (programOpts.info) {
|
|
144
145
|
className = programOpts.className || answers.className,
|
145
146
|
singleton = programOpts.singleton || answers.singleton || 'no',
|
146
147
|
isDrop = programOpts.drop,
|
148
|
+
scssClass = programOpts.scss,
|
147
149
|
isSingleton = singleton === 'yes',
|
148
150
|
startDate = new Date(),
|
149
|
-
baseType, classFolder, configName, file, folderDelta, importName, importPath, index, ns, root, rootLowerCase,
|
151
|
+
baseType, classFolder, configName, file, folderDelta, importName, importPath, index, ns, root, rootLowerCase,
|
152
|
+
viewFile;
|
150
153
|
|
151
154
|
if (className.endsWith('.mjs')) {
|
152
155
|
className = className.slice(0, -4);
|
@@ -241,7 +244,8 @@ if (programOpts.info) {
|
|
241
244
|
file,
|
242
245
|
folderDelta,
|
243
246
|
ns,
|
244
|
-
root
|
247
|
+
root,
|
248
|
+
scssClass
|
245
249
|
});
|
246
250
|
|
247
251
|
if (baseClass === 'data.Model') {
|
@@ -259,7 +263,7 @@ if (programOpts.info) {
|
|
259
263
|
* @param {Number} index=contentArray.length - 1
|
260
264
|
* @returns {String[]}
|
261
265
|
*/
|
262
|
-
function addComma(contentArray, index=contentArray.length - 1) {
|
266
|
+
function addComma(contentArray, index = contentArray.length - 1) {
|
263
267
|
contentArray[index] += ',';
|
264
268
|
return contentArray;
|
265
269
|
}
|
@@ -329,7 +333,7 @@ if (programOpts.info) {
|
|
329
333
|
content.splice(i, 0, `import ${importName} from '${opts.importPath}';`);
|
330
334
|
|
331
335
|
// find the longest import module name
|
332
|
-
for (i=0; i < len; i++) {
|
336
|
+
for (i = 0; i < len; i++) {
|
333
337
|
codeLine = content[i];
|
334
338
|
|
335
339
|
if (codeLine === '') {
|
@@ -340,7 +344,7 @@ if (programOpts.info) {
|
|
340
344
|
}
|
341
345
|
|
342
346
|
// adjust the block-formatting for imports
|
343
|
-
for (i=0; i < len; i++) {
|
347
|
+
for (i = 0; i < len; i++) {
|
344
348
|
codeLine = content[i];
|
345
349
|
|
346
350
|
if (codeLine === '') {
|
@@ -353,7 +357,7 @@ if (programOpts.info) {
|
|
353
357
|
if (adjustSpaces > 0) {
|
354
358
|
spaces = '';
|
355
359
|
|
356
|
-
for (j=0; j < adjustSpaces; j++) {
|
360
|
+
for (j = 0; j < adjustSpaces; j++) {
|
357
361
|
spaces += ' ';
|
358
362
|
}
|
359
363
|
|
@@ -396,7 +400,7 @@ if (programOpts.info) {
|
|
396
400
|
}
|
397
401
|
|
398
402
|
if (className > configName) {
|
399
|
-
for (j=i; j > 0; j--) {
|
403
|
+
for (j = i; j > 0; j--) {
|
400
404
|
if (content[j].includes('/**')) {
|
401
405
|
addConfig({
|
402
406
|
baseType,
|
@@ -444,7 +448,8 @@ if (programOpts.info) {
|
|
444
448
|
file,
|
445
449
|
folderDelta,
|
446
450
|
ns,
|
447
|
-
root
|
451
|
+
root,
|
452
|
+
scssClass = undefined,
|
448
453
|
} = opts, baseFileName;
|
449
454
|
|
450
455
|
fs.mkdirpSync(classFolder, {recursive: true});
|
@@ -464,10 +469,11 @@ if (programOpts.info) {
|
|
464
469
|
file,
|
465
470
|
folderDelta,
|
466
471
|
ns,
|
467
|
-
root
|
472
|
+
root,
|
473
|
+
scssClass
|
468
474
|
}));
|
469
475
|
|
470
|
-
switch(baseClass) {
|
476
|
+
switch (baseClass) {
|
471
477
|
case 'controller.Component': {
|
472
478
|
baseType = 'Neo.controller.Component';
|
473
479
|
configName = 'controller';
|
@@ -555,7 +561,9 @@ if (programOpts.info) {
|
|
555
561
|
isSingleton = opts.isSingleton,
|
556
562
|
file = opts.file,
|
557
563
|
i = 0,
|
558
|
-
importDelta = ''
|
564
|
+
importDelta = '',
|
565
|
+
scssClass = opts.scssClass,
|
566
|
+
isScss = scssClass !== null && scssClass !== undefined;
|
559
567
|
|
560
568
|
if (root === 'Neo') {
|
561
569
|
if (className.startsWith('Neo.examples')) {
|
@@ -592,6 +600,13 @@ if (programOpts.info) {
|
|
592
600
|
` className: '${className}'`
|
593
601
|
);
|
594
602
|
|
603
|
+
isScss && addComma(classContent).push(
|
604
|
+
" /**",
|
605
|
+
` * @member {String[]} baseCls=['${scssClass}']`,
|
606
|
+
" * @protected",
|
607
|
+
" */",
|
608
|
+
` baseCls: ['${scssClass}']`);
|
609
|
+
|
595
610
|
baseClass === 'table.Container' && addComma(classContent).push(
|
596
611
|
" /**",
|
597
612
|
" * @member {Object[]} columns",
|
@@ -0,0 +1,250 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
|
3
|
+
import chalk from 'chalk';
|
4
|
+
import {spawnSync} from 'child_process';
|
5
|
+
import {Command} from 'commander/esm.mjs';
|
6
|
+
import envinfo from 'envinfo';
|
7
|
+
import fs from 'fs-extra';
|
8
|
+
import inquirer from 'inquirer';
|
9
|
+
import path from 'path';
|
10
|
+
import {fileURLToPath} from 'url';
|
11
|
+
|
12
|
+
const
|
13
|
+
__dirname = fileURLToPath(new URL('../', import.meta.url)),
|
14
|
+
cwd = process.cwd(),
|
15
|
+
requireJson = path => JSON.parse(fs.readFileSync((path))),
|
16
|
+
packageJson = requireJson(path.join(__dirname, 'package.json')),
|
17
|
+
program = new Command(),
|
18
|
+
programName = `${packageJson.name} create-class`,
|
19
|
+
questions = [],
|
20
|
+
/**
|
21
|
+
* Maintain a list of dir-names recognized as source root directories.
|
22
|
+
* When not using dot notation with a class-name, the program assumes
|
23
|
+
* that we want to create the class inside the cwd. The proper namespace
|
24
|
+
* is then looked up by traversing the directory path up to the first
|
25
|
+
* folder that matches an entry in "sourceRootDirs". The owning
|
26
|
+
* folder (parent of cwd, child of sourceRootDirs[n]) will then be used as the
|
27
|
+
* namespace for this created class.
|
28
|
+
* Can be overwritten with the -s option.
|
29
|
+
* @type {String[]}
|
30
|
+
*/
|
31
|
+
sourceRootDirs = ['apps'];
|
32
|
+
|
33
|
+
program
|
34
|
+
.name(programName)
|
35
|
+
.version(packageJson.version)
|
36
|
+
.option('-i, --info', 'print environment debug info')
|
37
|
+
.option('-n, --singleton <value>', 'Create a singleton? Pick "yes" or "no"')
|
38
|
+
.option('-s, --source <value>', `name of the folder containing the project. Defaults to any of ${sourceRootDirs.join(',')}`)
|
39
|
+
.option('-b, --baseClass <value>')
|
40
|
+
.option('-c, --className <value>')
|
41
|
+
.allowUnknownOption()
|
42
|
+
.on('--help', () => {
|
43
|
+
console.log('\nIn case you have any issues, please create a ticket here:');
|
44
|
+
console.log(chalk.cyan(process.env.npm_package_bugs_url));
|
45
|
+
})
|
46
|
+
.parse(process.argv);
|
47
|
+
|
48
|
+
const programOpts = program.opts();
|
49
|
+
|
50
|
+
if (programOpts.info) {
|
51
|
+
console.log(chalk.bold('\nEnvironment Info:'));
|
52
|
+
console.log(`\n current version of ${packageJson.name}: ${packageJson.version}`);
|
53
|
+
console.log(` running from ${cwd}`);
|
54
|
+
|
55
|
+
envinfo
|
56
|
+
.run({
|
57
|
+
System : ['OS', 'CPU'],
|
58
|
+
Binaries : ['Node', 'npm', 'Yarn'],
|
59
|
+
Browsers : ['Chrome', 'Edge', 'Firefox', 'Safari'],
|
60
|
+
npmPackages: ['neo.mjs']
|
61
|
+
}, {
|
62
|
+
duplicates : true,
|
63
|
+
showNotFound: true
|
64
|
+
})
|
65
|
+
.then(console.log);
|
66
|
+
} else {
|
67
|
+
console.log(chalk.green(programName));
|
68
|
+
|
69
|
+
let answers = {},
|
70
|
+
answer;
|
71
|
+
|
72
|
+
if (!programOpts.className) {
|
73
|
+
answer = await inquirer.prompt({
|
74
|
+
type : 'input',
|
75
|
+
name : 'className',
|
76
|
+
message: 'Please choose the namespace for your class:',
|
77
|
+
default: 'Covid.view.MyContainer'
|
78
|
+
});
|
79
|
+
|
80
|
+
Object.assign(answers, answer);
|
81
|
+
}
|
82
|
+
|
83
|
+
if (!programOpts.baseClass) {
|
84
|
+
questions.push({
|
85
|
+
type : 'list',
|
86
|
+
name : 'baseClass',
|
87
|
+
message: 'Please pick the base class, which you want to extend:',
|
88
|
+
default: guessBaseClass(programOpts.className || answers.className),
|
89
|
+
|
90
|
+
choices: [
|
91
|
+
'component.Base',
|
92
|
+
'container.Base',
|
93
|
+
'container.Viewport',
|
94
|
+
'controller.Component',
|
95
|
+
'core.Base',
|
96
|
+
'data.Model',
|
97
|
+
'data.Store',
|
98
|
+
'model.Component',
|
99
|
+
'tab.Container',
|
100
|
+
'table.Container'
|
101
|
+
]
|
102
|
+
});
|
103
|
+
}
|
104
|
+
|
105
|
+
|
106
|
+
if (!programOpts.singleton) {
|
107
|
+
questions.push({
|
108
|
+
type : 'list',
|
109
|
+
name : 'singleton',
|
110
|
+
message: 'Singleton?',
|
111
|
+
default: 'no',
|
112
|
+
choices: ['yes', 'no']
|
113
|
+
});
|
114
|
+
}
|
115
|
+
|
116
|
+
answer = await inquirer.prompt(questions);
|
117
|
+
|
118
|
+
Object.assign(answers, answer);
|
119
|
+
|
120
|
+
let baseClass = programOpts.baseClass || answers.baseClass,
|
121
|
+
className = programOpts.className || answers.className,
|
122
|
+
singleton = programOpts.singleton || answers.singleton || 'no';
|
123
|
+
|
124
|
+
let ns = className.split('.');
|
125
|
+
ns.pop();
|
126
|
+
let root = ns.shift();
|
127
|
+
let rootLowerCase = root.toLowerCase();
|
128
|
+
|
129
|
+
|
130
|
+
if (!baseClass && !className) {
|
131
|
+
console.error(chalk.red('className and baseClass must be defined'));
|
132
|
+
process.exit(1);
|
133
|
+
}
|
134
|
+
|
135
|
+
const scssClassName = getScssClassName(className, rootLowerCase);
|
136
|
+
|
137
|
+
let childProcess = spawnSync('node', [
|
138
|
+
'./buildScripts/createClass.mjs',
|
139
|
+
'-c',
|
140
|
+
className,
|
141
|
+
'-b',
|
142
|
+
baseClass,
|
143
|
+
'-n',
|
144
|
+
singleton,
|
145
|
+
'-r',
|
146
|
+
scssClassName
|
147
|
+
], {env: process.env, cwd: process.cwd(), stdio: 'inherit'});
|
148
|
+
childProcess.status && process.exit(childProcess.status);
|
149
|
+
|
150
|
+
|
151
|
+
//create scss stubs only if it is a NEO component or a view component
|
152
|
+
const resultView = ns.filter(f => f === 'view');
|
153
|
+
if (rootLowerCase === 'neo' || resultView.length > 0) {
|
154
|
+
let childProcess = spawnSync('node', [
|
155
|
+
'./buildScripts/tools/createScss.mjs',
|
156
|
+
'-c',
|
157
|
+
className,
|
158
|
+
'-b',
|
159
|
+
baseClass
|
160
|
+
], {env: process.env, cwd: process.cwd(), stdio: 'inherit'});
|
161
|
+
childProcess.status && process.exit(childProcess.status);
|
162
|
+
}
|
163
|
+
|
164
|
+
// create only example stub when it is a NEO component
|
165
|
+
if (rootLowerCase === 'neo') {
|
166
|
+
let childProcess = spawnSync('node', [
|
167
|
+
'./buildScripts/tools/createExample.mjs',
|
168
|
+
// '--',
|
169
|
+
'-c',
|
170
|
+
className
|
171
|
+
], {env: process.env, cwd: process.cwd(), stdio: 'inherit'});
|
172
|
+
childProcess.status && process.exit(childProcess.status);
|
173
|
+
}
|
174
|
+
|
175
|
+
//re-build the themes
|
176
|
+
let buildThemes = spawnSync('node', [
|
177
|
+
'./buildScripts/buildThemes.mjs',
|
178
|
+
// '--',
|
179
|
+
'-f',
|
180
|
+
'-e',
|
181
|
+
'all',
|
182
|
+
'-n'
|
183
|
+
], {env: process.env, cwd: process.cwd(), stdio: 'inherit'});
|
184
|
+
buildThemes.status && process.exit(buildThemes.status);
|
185
|
+
|
186
|
+
|
187
|
+
// start the dev server
|
188
|
+
if (rootLowerCase === 'neo') {
|
189
|
+
let temp = className.split('.');
|
190
|
+
temp.splice(0, 1); //remove Neo namespace
|
191
|
+
let componentPath = `/examples/${temp.join('/')}`;
|
192
|
+
componentPath = componentPath.toLowerCase();
|
193
|
+
|
194
|
+
let startServer = spawnSync('webpack', [
|
195
|
+
'serve',
|
196
|
+
'-c',
|
197
|
+
'./buildScripts/webpack/webpack.server.config.mjs',
|
198
|
+
'--open',
|
199
|
+
componentPath
|
200
|
+
], {env: process.env, cwd: process.cwd(), stdio: 'inherit'});
|
201
|
+
startServer.status && process.exit(startServer.status);
|
202
|
+
}
|
203
|
+
}
|
204
|
+
|
205
|
+
function guessBaseClass(className) {
|
206
|
+
className = className.toLowerCase();
|
207
|
+
|
208
|
+
if (className.includes('.model.')) {
|
209
|
+
return 'data.Model';
|
210
|
+
}
|
211
|
+
|
212
|
+
if (className.includes('.store.')) {
|
213
|
+
return 'data.Store';
|
214
|
+
}
|
215
|
+
|
216
|
+
if (className.endsWith('component')) {
|
217
|
+
return 'component.Base';
|
218
|
+
}
|
219
|
+
|
220
|
+
if (className.endsWith('controller')) {
|
221
|
+
return 'controller.Component';
|
222
|
+
}
|
223
|
+
|
224
|
+
if (className.endsWith('model')) {
|
225
|
+
return 'model.Component';
|
226
|
+
}
|
227
|
+
|
228
|
+
if (className.includes('table')) {
|
229
|
+
return 'table.Container';
|
230
|
+
}
|
231
|
+
|
232
|
+
if (className.includes('tab')) {
|
233
|
+
return 'tab.Container';
|
234
|
+
}
|
235
|
+
|
236
|
+
return 'container.Base';
|
237
|
+
}
|
238
|
+
|
239
|
+
function getScssClassName(className) {
|
240
|
+
//template
|
241
|
+
let classItems = className.split('.');
|
242
|
+
let result = [];
|
243
|
+
|
244
|
+
classItems.forEach(item => {
|
245
|
+
let temp = item.split(/(?=[A-Z])/);
|
246
|
+
result.push(temp.join('-').toLowerCase());
|
247
|
+
});
|
248
|
+
|
249
|
+
return result.join('-');
|
250
|
+
}
|
@@ -0,0 +1,159 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
|
3
|
+
import {Command} from 'commander/esm.mjs';
|
4
|
+
import fs from 'fs-extra';
|
5
|
+
import os from 'os';
|
6
|
+
import path from 'path';
|
7
|
+
import {fileURLToPath} from 'url';
|
8
|
+
|
9
|
+
const
|
10
|
+
__dirname = fileURLToPath(new URL('../../', import.meta.url)),
|
11
|
+
cwd = process.cwd(),
|
12
|
+
requireJson = path => JSON.parse(fs.readFileSync((path))),
|
13
|
+
packageJson = requireJson(path.join(__dirname, 'package.json')),
|
14
|
+
program = new Command();
|
15
|
+
|
16
|
+
program
|
17
|
+
.version(packageJson.version)
|
18
|
+
.option('-b, --baseClass <value>')
|
19
|
+
.option('-c, --className <value>')
|
20
|
+
.allowUnknownOption()
|
21
|
+
.parse(process.argv);
|
22
|
+
|
23
|
+
const programOpts = program.opts();
|
24
|
+
let className = programOpts.className;
|
25
|
+
|
26
|
+
let ns = className.split('.');
|
27
|
+
ns.splice(0, 1); //remove Neo namespace
|
28
|
+
let componentPath = ns.join('/');
|
29
|
+
componentPath = componentPath.toLowerCase();
|
30
|
+
const componentChunk = ns.join('.')
|
31
|
+
const name = ns.pop();
|
32
|
+
let classFolder = path.join(cwd, 'examples', `/${componentPath}`);
|
33
|
+
|
34
|
+
if (!fs.existsSync(classFolder)) {
|
35
|
+
fs.mkdirpSync(classFolder, {recursive: true});
|
36
|
+
}
|
37
|
+
|
38
|
+
createAppMjs(classFolder, componentChunk);
|
39
|
+
createIndexHtml(classFolder, name);
|
40
|
+
createNeoConfig(classFolder, componentPath);
|
41
|
+
createMainContainer(classFolder, componentPath, componentChunk, name);
|
42
|
+
|
43
|
+
|
44
|
+
function createAppMjs(classFolder, componentChunk) {
|
45
|
+
let template = [];
|
46
|
+
|
47
|
+
template.push(
|
48
|
+
"import MainContainer from './MainContainer.mjs';",
|
49
|
+
"",
|
50
|
+
"export const onStart = () => Neo.app({",
|
51
|
+
" mainView: MainContainer,",
|
52
|
+
` name : 'Neo.examples.${componentChunk}'`,
|
53
|
+
"});");
|
54
|
+
|
55
|
+
const file = `${classFolder}/app.mjs`;
|
56
|
+
fs.writeFileSync(file, `${template.join(os.EOL)}${os.EOL}`);
|
57
|
+
}
|
58
|
+
|
59
|
+
function createIndexHtml(classFolder, title) {
|
60
|
+
const template = [];
|
61
|
+
|
62
|
+
template.push(
|
63
|
+
'<!DOCTYPE HTML>',
|
64
|
+
'<html>',
|
65
|
+
'<head>',
|
66
|
+
' <meta name="viewport" content="width=device-width, initial-scale=1">',
|
67
|
+
' <meta charset="UTF-8">',
|
68
|
+
` <title>Neo ${title}</title>`,
|
69
|
+
'</head>',
|
70
|
+
'<body>',
|
71
|
+
' <script src="../../../src/MicroLoader.mjs" type="module"></script>',
|
72
|
+
'</body>',
|
73
|
+
'</html>`');
|
74
|
+
|
75
|
+
const file = `${classFolder}/index.html`;
|
76
|
+
fs.writeFileSync(file, `${template.join(os.EOL)}${os.EOL}`);
|
77
|
+
}
|
78
|
+
|
79
|
+
function createNeoConfig(classFolder, componentPath) {
|
80
|
+
const template = [];
|
81
|
+
|
82
|
+
template.push(
|
83
|
+
'{',
|
84
|
+
` "appPath" : "examples/${componentPath}/app.mjs",`,
|
85
|
+
' "basePath" : "../../../",',
|
86
|
+
' "environment": "development",',
|
87
|
+
' "mainPath" : "./Main.mjs"',
|
88
|
+
'}'
|
89
|
+
);
|
90
|
+
const file = `${classFolder}/neo-config.json`;
|
91
|
+
fs.writeFileSync(file, `${template.join(os.EOL)}${os.EOL}`);
|
92
|
+
|
93
|
+
}
|
94
|
+
|
95
|
+
|
96
|
+
function createMainContainer(classFolder, componentPath, componentChunk, name) {
|
97
|
+
const template = [];
|
98
|
+
|
99
|
+
template.push(
|
100
|
+
"import ConfigurationViewport from '../../ConfigurationViewport.mjs';",
|
101
|
+
"import NumberField from '../../../src/form/field/Number.mjs';",
|
102
|
+
`import ${name} from '../../../src/${componentPath}.mjs';`,
|
103
|
+
"",
|
104
|
+
"/**",
|
105
|
+
` * @class Neo.examples.${componentChunk.toLowerCase()}.MainContainer`,
|
106
|
+
" * @extends Neo.examples.ConfigurationViewport",
|
107
|
+
" */",
|
108
|
+
"class MainContainer extends ConfigurationViewport {",
|
109
|
+
" static config = {",
|
110
|
+
` className: 'Neo.examples.${componentChunk.toLowerCase()}.MainContainer',`,
|
111
|
+
" autoMount: true,",
|
112
|
+
" configItemLabelWidth: 110,",
|
113
|
+
" configItemWidth: 230,",
|
114
|
+
" layout: { ntype: 'hbox', align: 'stretch' }",
|
115
|
+
" }",
|
116
|
+
"",
|
117
|
+
" createConfigurationComponents() {",
|
118
|
+
" let me = this;",
|
119
|
+
"",
|
120
|
+
" return [{",
|
121
|
+
" module: NumberField,",
|
122
|
+
" clearable: true,",
|
123
|
+
" labelText: 'height',",
|
124
|
+
" listeners: { change: me.onConfigChange.bind(me, 'height') },",
|
125
|
+
" maxValue: 100,",
|
126
|
+
" minValue: 20,",
|
127
|
+
" stepSize: 2,",
|
128
|
+
" style: { marginTop: '10px' },",
|
129
|
+
" value: me.exampleComponent.height",
|
130
|
+
" }, {",
|
131
|
+
" module: NumberField,",
|
132
|
+
" clearable: true,",
|
133
|
+
" labelText: 'width',",
|
134
|
+
" listeners: { change: me.onConfigChange.bind(me, 'width') },",
|
135
|
+
" maxValue: 300,",
|
136
|
+
" minValue: 100,",
|
137
|
+
" stepSize: 5,",
|
138
|
+
" style: { marginTop: '10px' },",
|
139
|
+
" value: me.exampleComponent.width",
|
140
|
+
" }]",
|
141
|
+
" }",
|
142
|
+
"",
|
143
|
+
" createExampleComponent() {",
|
144
|
+
" return Neo.create({",
|
145
|
+
` module: ${name},`,
|
146
|
+
" height: 30,",
|
147
|
+
" width: 100",
|
148
|
+
" // property_xy: <value>",
|
149
|
+
" })",
|
150
|
+
" }",
|
151
|
+
"}",
|
152
|
+
"",
|
153
|
+
"Neo.applyClassConfig(MainContainer);",
|
154
|
+
"",
|
155
|
+
"export default MainContainer;"
|
156
|
+
);
|
157
|
+
const file = `${classFolder}/MainContainer.mjs`;
|
158
|
+
fs.writeFileSync(file, `${template.join(os.EOL)}${os.EOL}`);
|
159
|
+
}
|
@@ -0,0 +1,98 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
|
3
|
+
import {Command} from 'commander/esm.mjs';
|
4
|
+
import fs from 'fs-extra';
|
5
|
+
import os from 'os';
|
6
|
+
import path from 'path';
|
7
|
+
import {fileURLToPath} from 'url';
|
8
|
+
|
9
|
+
const
|
10
|
+
__dirname = fileURLToPath(new URL('../../', import.meta.url)),
|
11
|
+
cwd = process.cwd(),
|
12
|
+
requireJson = path => JSON.parse(fs.readFileSync((path))),
|
13
|
+
packageJson = requireJson(path.join(__dirname, 'package.json')),
|
14
|
+
program = new Command();
|
15
|
+
|
16
|
+
program
|
17
|
+
.version(packageJson.version)
|
18
|
+
.option('-b, --baseClass <value>')
|
19
|
+
.option('-c, --className <value>')
|
20
|
+
.allowUnknownOption()
|
21
|
+
.parse(process.argv);
|
22
|
+
|
23
|
+
const programOpts = program.opts();
|
24
|
+
|
25
|
+
let className = programOpts.className;
|
26
|
+
|
27
|
+
let ns = className.split('.');
|
28
|
+
let file = ns.pop();
|
29
|
+
let root = ns.shift();
|
30
|
+
let rootLowerCase = root.toLowerCase();
|
31
|
+
|
32
|
+
// let classFolder = path.join(cwd, '/src/', ns.join('/'));
|
33
|
+
const forNonNeoPathArray = ns.filter(f => f !== 'view');
|
34
|
+
let nonNeoPath = `apps/${rootLowerCase}`;
|
35
|
+
if (forNonNeoPathArray.length > 0) {
|
36
|
+
nonNeoPath = nonNeoPath.concat('/', forNonNeoPathArray.join('/'));
|
37
|
+
}
|
38
|
+
|
39
|
+
let classFolder = path.join(cwd, 'resources/scss/src/', rootLowerCase === 'neo' ? `/${ns.join('/')}` : nonNeoPath);
|
40
|
+
|
41
|
+
if (!fs.existsSync(classFolder)) {
|
42
|
+
fs.mkdirpSync(classFolder, {recursive: true});
|
43
|
+
}
|
44
|
+
|
45
|
+
const scssClassName = getScssClassName(className);
|
46
|
+
const template = `.${scssClassName} {
|
47
|
+
// add css information here
|
48
|
+
background-color: var(--${scssClassName.toLowerCase()}-background-color); // this is an example
|
49
|
+
}`;
|
50
|
+
createScssStub(classFolder, file, template);
|
51
|
+
|
52
|
+
// iterate over themes
|
53
|
+
let themeFoldersPath = path.join(cwd, 'resources/scss/');
|
54
|
+
|
55
|
+
const themeFolders = listDirectories(themeFoldersPath);
|
56
|
+
|
57
|
+
themeFolders.forEach(theme => {
|
58
|
+
const forNonNeoPathArray = ns.filter(f => f !== 'view');
|
59
|
+
let nonNeoPath = `apps/${rootLowerCase}`;
|
60
|
+
if (forNonNeoPathArray.length > 0) {
|
61
|
+
nonNeoPath = nonNeoPath.concat('/', forNonNeoPathArray.join('/'));
|
62
|
+
}
|
63
|
+
classFolder = path.join(cwd, 'resources/scss/', theme, rootLowerCase === 'neo' ? `/${ns.join('/')}` : nonNeoPath);
|
64
|
+
if (!fs.existsSync(classFolder)) {
|
65
|
+
fs.mkdirpSync(classFolder, {recursive: true});
|
66
|
+
}
|
67
|
+
const exampleColor = theme.includes('dark') ? 'darkgreen' : 'green';
|
68
|
+
const themeTemplate = `:root .${rootLowerCase}-${theme} { // .${scssClassName}
|
69
|
+
// add css theme information here
|
70
|
+
--${scssClassName.toLowerCase()}-background-color: ${exampleColor}; //example
|
71
|
+
}`;
|
72
|
+
createScssStub(classFolder, file, themeTemplate);
|
73
|
+
})
|
74
|
+
|
75
|
+
function listDirectories(path) {
|
76
|
+
return fs.readdirSync(path, {withFileTypes: true})
|
77
|
+
.filter(dirent => dirent.isDirectory() && dirent.name.startsWith('theme'))
|
78
|
+
.map(dirent => dirent.name);
|
79
|
+
}
|
80
|
+
|
81
|
+
function createScssStub(classFolder, file, template) {
|
82
|
+
const scssFile = `${classFolder}/${file}.scss`;
|
83
|
+
|
84
|
+
fs.writeFileSync(scssFile, `${template}${os.EOL}`);
|
85
|
+
}
|
86
|
+
|
87
|
+
function getScssClassName(className) {
|
88
|
+
let classItems = className.split('.');
|
89
|
+
let result = [];
|
90
|
+
|
91
|
+
classItems.forEach(item => {
|
92
|
+
let temp = item.split(/(?=[A-Z])/);
|
93
|
+
result.push(temp.join('-').toLowerCase());
|
94
|
+
});
|
95
|
+
|
96
|
+
return result.join('-');
|
97
|
+
}
|
98
|
+
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "neo.mjs",
|
3
|
-
"version": "6.1
|
3
|
+
"version": "6.2.1",
|
4
4
|
"description": "The webworkers driven UI framework",
|
5
5
|
"type": "module",
|
6
6
|
"repository": {
|
@@ -19,6 +19,7 @@
|
|
19
19
|
"build-threads": "node ./buildScripts/webpack/buildThreads.mjs -f",
|
20
20
|
"create-app": "node ./buildScripts/createApp.mjs",
|
21
21
|
"create-class": "node ./buildScripts/createClass.mjs",
|
22
|
+
"create-component": "node ./buildScripts/createComponent.mjs",
|
22
23
|
"generate-docs-json": "node ./buildScripts/docs/jsdocx.mjs",
|
23
24
|
"inject-package-version": "node ./buildScripts/injectPackageVersion.mjs",
|
24
25
|
"server-start": "webpack serve -c ./buildScripts/webpack/webpack.server.config.mjs --open",
|
package/src/DefaultConfig.mjs
CHANGED
@@ -236,12 +236,12 @@ const DefaultConfig = {
|
|
236
236
|
useVdomWorker: true,
|
237
237
|
/**
|
238
238
|
* buildScripts/injectPackageVersion.mjs will update this value
|
239
|
-
* @default '6.1
|
239
|
+
* @default '6.2.1'
|
240
240
|
* @memberOf! module:Neo
|
241
241
|
* @name config.version
|
242
242
|
* @type String
|
243
243
|
*/
|
244
|
-
version: '6.1
|
244
|
+
version: '6.2.1'
|
245
245
|
};
|
246
246
|
|
247
247
|
Object.assign(DefaultConfig, {
|
package/src/menu/List.mjs
CHANGED
@@ -357,9 +357,12 @@ class List extends BaseList {
|
|
357
357
|
|
358
358
|
record.handler?.call(me, record);
|
359
359
|
|
360
|
-
|
361
|
-
me.
|
362
|
-
|
360
|
+
record.route && Neo.Main.setRoute({
|
361
|
+
appName: me.appName,
|
362
|
+
value : record.route
|
363
|
+
});
|
364
|
+
|
365
|
+
me.hideOnLeafItemClick && !record.items && me.unmount();
|
363
366
|
|
364
367
|
if (record.items) {
|
365
368
|
submenu = me.subMenuMap?.[me.getMenuMapId(recordId)];
|