@newlogic-digital/cli 0.2.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.mjs +7 -4
- package/package.json +2 -2
- package/src/commands/cms/index.mjs +23 -1
- package/src/commands/cms/prepare.mjs +247 -4
- package/src/commands/init/cms.mjs +4 -3
package/index.mjs
CHANGED
|
@@ -23,10 +23,13 @@ if (!command) {
|
|
|
23
23
|
${pc.green('newlogic init cms')} ${pc.yellow('<directory>')} - Creates a new ${pc.blue('@newlogic-digital/cms')} project in new directory with the name ${pc.yellow('<directory>')}
|
|
24
24
|
|
|
25
25
|
-- cms --
|
|
26
|
-
${pc.green('newlogic cms prepare')} - Copies templates and
|
|
27
|
-
${pc.green('newlogic cms prepare
|
|
28
|
-
${pc.green('newlogic cms prepare
|
|
29
|
-
${pc.green('newlogic cms new-
|
|
26
|
+
${pc.green('newlogic cms prepare')} - Copies templates and components from ${pc.blue('@newlogic-digital/ui')} project to ${pc.blue('@newlogic-digital/cms')}
|
|
27
|
+
${pc.green('newlogic cms prepare views')} - Copies views from ${pc.blue('@newlogic-digital/ui')} project to ${pc.blue('@newlogic-digital/cms')} even if they already exists
|
|
28
|
+
${pc.green('newlogic cms prepare components')} - Copies components from ${pc.blue('@newlogic-digital/ui')} project to ${pc.blue('@newlogic-digital/cms')} even if they already exists
|
|
29
|
+
${pc.green('newlogic cms new-component')} ${pc.yellow('<name>')} - Creates a new ${pc.blue('@newlogic-digital/cms')} section with name ${pc.yellow('<name>')}
|
|
30
|
+
${pc.red('newlogic cms prepare templates')} - (deprecated) Copies templates from ${pc.blue('@newlogic-digital/ui')} project to ${pc.blue('@newlogic-digital/cms')} even if they already exists
|
|
31
|
+
${pc.red('newlogic cms prepare sections')} - (deprecated) Copies sections from ${pc.blue('@newlogic-digital/ui')} project to ${pc.blue('@newlogic-digital/cms')} even if they already exists
|
|
32
|
+
${pc.red('newlogic cms new-section')} ${pc.yellow('<name>')} - (deprecated) Creates a new ${pc.blue('@newlogic-digital/cms')} section with name ${pc.yellow('<name>')}
|
|
30
33
|
`)
|
|
31
34
|
}
|
|
32
35
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@newlogic-digital/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"main": "index.mjs",
|
|
5
5
|
"bin": {
|
|
6
6
|
"newlogic-cli": "index.mjs",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"lodash": "^4.17.21",
|
|
14
14
|
"prompts": "^2.4.2",
|
|
15
15
|
"fs-extra": "^11.2.0",
|
|
16
|
-
"picocolors": "^1.
|
|
16
|
+
"picocolors": "^1.1.1",
|
|
17
17
|
"fast-glob": "^3.3.2",
|
|
18
18
|
"dedent": "^1.5.3"
|
|
19
19
|
},
|
|
@@ -8,11 +8,15 @@ export const options = {
|
|
|
8
8
|
path: {
|
|
9
9
|
src: {
|
|
10
10
|
templates: resolve(process.cwd(), 'src/templates'),
|
|
11
|
+
components: resolve(process.cwd(), 'src/templates/components'),
|
|
11
12
|
sections: resolve(process.cwd(), 'src/templates/Sections'),
|
|
12
|
-
views: resolve(process.cwd(), 'src/views')
|
|
13
|
+
views: resolve(process.cwd(), 'src/views'),
|
|
14
|
+
pages: resolve(process.cwd(), 'src/pages')
|
|
13
15
|
},
|
|
14
16
|
app: {
|
|
15
17
|
templates: resolve(process.cwd(), 'app/Templates'),
|
|
18
|
+
components: resolve(process.cwd(), 'app/Components'),
|
|
19
|
+
componentsFactory: resolve(process.cwd(), 'app/Components/Factory'),
|
|
16
20
|
sections: resolve(process.cwd(), 'app/Sections'),
|
|
17
21
|
sectionsFactory: resolve(process.cwd(), 'app/Sections/Factory'),
|
|
18
22
|
tempCache: resolve(process.cwd(), 'temp/cache')
|
|
@@ -25,6 +29,24 @@ export default async function cms(action, name) {
|
|
|
25
29
|
await prepare(options).copy(name)
|
|
26
30
|
}
|
|
27
31
|
|
|
32
|
+
if (action === 'new-component') {
|
|
33
|
+
const nameFormatted = name.replaceAll('/', '')
|
|
34
|
+
|
|
35
|
+
if (fs.existsSync(join(options.path.app.components, `${nameFormatted}.php`))) {
|
|
36
|
+
console.log(`${pc.red('✖')} section ${nameFormatted} already exists`)
|
|
37
|
+
process.exit(1)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
prepare(options).writeComponent(name)
|
|
41
|
+
prepare(options).writeComponentFactory(nameFormatted)
|
|
42
|
+
|
|
43
|
+
if (fs.existsSync(options.path.app.tempCache)) {
|
|
44
|
+
fse.removeSync(options.path.app.tempCache)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
console.log(`${pc.green('✔')} component ${nameFormatted} created`)
|
|
48
|
+
}
|
|
49
|
+
|
|
28
50
|
if (action === 'new-section') {
|
|
29
51
|
const nameFormatted = name.replaceAll('/', '')
|
|
30
52
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import FastGlob from 'fast-glob'
|
|
2
|
-
import { join, relative, extname } from 'path'
|
|
2
|
+
import { join, relative, extname, basename } from 'path'
|
|
3
3
|
import fs from 'fs'
|
|
4
4
|
import fse from 'fs-extra'
|
|
5
5
|
import pc from 'picocolors'
|
|
@@ -13,7 +13,25 @@ let templatesCount = 0
|
|
|
13
13
|
export default function prepare(options) {
|
|
14
14
|
return {
|
|
15
15
|
async copy(name) {
|
|
16
|
-
if (!name || name === '
|
|
16
|
+
if (!name || name === 'components') {
|
|
17
|
+
if (!fs.existsSync(options.path.src.components)) {
|
|
18
|
+
console.log(`${pc.red('✖')} path ${options.path.src.components} doesn't exists`)
|
|
19
|
+
process.exit(1)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (!fs.existsSync(options.path.app.components)) {
|
|
23
|
+
console.log(`${pc.red('✖')} path ${options.path.app.components} doesn't exists`)
|
|
24
|
+
process.exit(1)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (!fs.existsSync(options.path.app.componentsFactory)) {
|
|
28
|
+
fs.mkdirSync(options.path.app.componentsFactory)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
await this.copyComponents(name === 'components')
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (name === 'sections') {
|
|
17
35
|
if (!fs.existsSync(options.path.src.sections)) {
|
|
18
36
|
console.log(`${pc.red('✖')} path ${options.path.src.sections} doesn't exists`)
|
|
19
37
|
process.exit(1)
|
|
@@ -31,7 +49,20 @@ export default function prepare(options) {
|
|
|
31
49
|
await this.copySections(name === 'sections')
|
|
32
50
|
}
|
|
33
51
|
|
|
34
|
-
if (!name || name === '
|
|
52
|
+
if (!name || name === 'views') {
|
|
53
|
+
if (!fs.existsSync(options.path.src.templates)) {
|
|
54
|
+
console.log(`${pc.red('✖')} path ${options.path.src.templates} doesn't exists`)
|
|
55
|
+
process.exit(1)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (!fs.existsSync(options.path.app.components)) {
|
|
59
|
+
fs.mkdirSync(options.path.app.components)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
await this.copyViews(name === 'views')
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (name === 'templates') {
|
|
35
66
|
if (!fs.existsSync(options.path.src.templates)) {
|
|
36
67
|
console.log(`${pc.red('✖')} path ${options.path.src.templates} doesn't exists`)
|
|
37
68
|
process.exit(1)
|
|
@@ -123,7 +154,7 @@ export default function prepare(options) {
|
|
|
123
154
|
annotations.push(`
|
|
124
155
|
#[FieldType(FieldType::${getField(control, type)})]
|
|
125
156
|
#[FieldName('${getTitle(control)}')]
|
|
126
|
-
public
|
|
157
|
+
public ?${phpType} $${control}${type === 'string' ? " = '" + value + "'" : ' = null'};
|
|
127
158
|
`)
|
|
128
159
|
|
|
129
160
|
if (type === 'object') {
|
|
@@ -199,6 +230,173 @@ export default function prepare(options) {
|
|
|
199
230
|
}
|
|
200
231
|
}
|
|
201
232
|
},
|
|
233
|
+
writeComponent(name, path, force) {
|
|
234
|
+
if (!path) {
|
|
235
|
+
path = name + '.latte'
|
|
236
|
+
name = name.replaceAll('/', '')
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (!name.match(/(Ui)/)) {
|
|
240
|
+
if (!fs.existsSync(join(options.path.app.components, `${name}.php`)) || force) {
|
|
241
|
+
const schema = this.getComponentsSchema()
|
|
242
|
+
const controls = schema[path] ?? {}
|
|
243
|
+
let annotations = []
|
|
244
|
+
let objects = []
|
|
245
|
+
|
|
246
|
+
const getField = (control, type) => {
|
|
247
|
+
if (type === 'number') {
|
|
248
|
+
return 'INT'
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (control.startsWith('table')) {
|
|
252
|
+
return 'TABLE'
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (control === 'heading' || control === 'title') {
|
|
256
|
+
return 'TEXT'
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
if (control === 'content') {
|
|
260
|
+
return 'WSW'
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (type === 'string') {
|
|
264
|
+
return 'TEXTAREA'
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (type === 'boolean') {
|
|
268
|
+
return 'BOOLEAN'
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return 'OTHER'
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const getTitle = (control) => {
|
|
275
|
+
if (control === 'heading') {
|
|
276
|
+
return 'Nadpis'
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (control === 'title') {
|
|
280
|
+
return 'Titulek'
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (control === 'content') {
|
|
284
|
+
return 'Obsah'
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (control === 'text') {
|
|
288
|
+
return 'Text'
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return control[0].toUpperCase() + control.slice(1)
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
Object.keys(controls).forEach(control => {
|
|
295
|
+
if (control !== 'src') {
|
|
296
|
+
const type = typeof controls[control]
|
|
297
|
+
const value = typeof controls[control] === 'object' ? JSON.stringify(controls[control]) : controls[control]
|
|
298
|
+
|
|
299
|
+
let phpType = type
|
|
300
|
+
|
|
301
|
+
if (type === 'object' && Array.isArray(controls[control])) {
|
|
302
|
+
phpType = 'array'
|
|
303
|
+
} else if (type === 'boolean') {
|
|
304
|
+
phpType = 'bool'
|
|
305
|
+
} else if (type === 'number') {
|
|
306
|
+
phpType = 'int'
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
annotations.push(`
|
|
310
|
+
#[FieldType(FieldType::${getField(control, type)})]
|
|
311
|
+
#[FieldName('${getTitle(control)}')]
|
|
312
|
+
public ?${phpType} $${control}${type === 'string' ? " = '" + value + "'" : ' = null'};
|
|
313
|
+
`)
|
|
314
|
+
|
|
315
|
+
if (type === 'object') {
|
|
316
|
+
objects.push(`
|
|
317
|
+
$this->${control} = json_decode('${value}', false);
|
|
318
|
+
`)
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
})
|
|
322
|
+
|
|
323
|
+
if (annotations.length > 0) {
|
|
324
|
+
annotations = annotations.map(item => item).join('')
|
|
325
|
+
} else {
|
|
326
|
+
annotations = ''
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (objects.length > 0) {
|
|
330
|
+
objects = objects.map(item => item).join('')
|
|
331
|
+
} else {
|
|
332
|
+
objects = ''
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
fs.writeFileSync(join(options.path.app.components, `${name}.php`),
|
|
336
|
+
dedent`
|
|
337
|
+
<?php
|
|
338
|
+
|
|
339
|
+
declare(strict_types=1);
|
|
340
|
+
|
|
341
|
+
namespace App\Components;
|
|
342
|
+
|
|
343
|
+
use App\Components\Attributes\FieldName;
|
|
344
|
+
use App\Components\Attributes\FieldType;
|
|
345
|
+
use App\Components\Attributes\SectionName;
|
|
346
|
+
|
|
347
|
+
#[ComponentName('${name}')]
|
|
348
|
+
class ${name} extends BaseComponent
|
|
349
|
+
{
|
|
350
|
+
${annotations}
|
|
351
|
+
public function render() : void
|
|
352
|
+
{
|
|
353
|
+
${objects}
|
|
354
|
+
$this->template->render(TEMPLATES_DIR . '/${path}');
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
`
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
sectionsCount += 1
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
},
|
|
364
|
+
writeComponentFactory(name, force) {
|
|
365
|
+
if (!name.match(/(Ui)/)) {
|
|
366
|
+
if (!fs.existsSync(join(options.path.app.componentsFactory, `${name}Factory.php`)) || force) {
|
|
367
|
+
fs.writeFileSync(join(options.path.app.componentsFactory, `${name}Factory.php`),
|
|
368
|
+
dedent`
|
|
369
|
+
<?php
|
|
370
|
+
|
|
371
|
+
declare(strict_types=1);
|
|
372
|
+
|
|
373
|
+
namespace App\SComponents\Factory;
|
|
374
|
+
|
|
375
|
+
use ${'App\\Components\\'}${name};
|
|
376
|
+
|
|
377
|
+
interface ${name}Factory
|
|
378
|
+
{
|
|
379
|
+
public function create(): ${name};
|
|
380
|
+
}
|
|
381
|
+
`
|
|
382
|
+
)
|
|
383
|
+
|
|
384
|
+
sectionsFactoryCount += 1
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
},
|
|
388
|
+
async copyComponents(force = false) {
|
|
389
|
+
const components = FastGlob.sync(join(options.path.src.components, '/**'))
|
|
390
|
+
|
|
391
|
+
components.forEach(path => {
|
|
392
|
+
const name = basename(relative(options.path.src.components, path), extname(relative(options.path.src.components, path)))
|
|
393
|
+
|
|
394
|
+
this.writeComponent(name, relative(options.path.src.templates, path), force)
|
|
395
|
+
this.writeComponentFactory(name, force)
|
|
396
|
+
})
|
|
397
|
+
|
|
398
|
+
console.log(`${pc.green('✔')} ${sectionsCount} components and ${sectionsFactoryCount} factory files copied to app`)
|
|
399
|
+
},
|
|
202
400
|
async copySections(force = false) {
|
|
203
401
|
const sections = FastGlob.sync(join(options.path.src.sections, '/**'))
|
|
204
402
|
|
|
@@ -211,6 +409,18 @@ export default function prepare(options) {
|
|
|
211
409
|
|
|
212
410
|
console.log(`${pc.green('✔')} ${sectionsCount} sections and ${sectionsFactoryCount} factory files copied to app`)
|
|
213
411
|
},
|
|
412
|
+
async copyViews(force = false) {
|
|
413
|
+
const templates = FastGlob.sync(join(options.path.src.templates, '/**')).filter(entry => {
|
|
414
|
+
return !fs.existsSync(join(options.path.src.views, relative(options.path.src.templates, entry))) || force
|
|
415
|
+
})
|
|
416
|
+
|
|
417
|
+
for (const path of templates) {
|
|
418
|
+
await fse.copy(path, join(options.path.src.views, relative(options.path.src.templates, path)))
|
|
419
|
+
templatesCount += 1
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
console.log(`${pc.green('✔')} ${templatesCount} views files copied from templates`)
|
|
423
|
+
},
|
|
214
424
|
async copyTemplates(force = false) {
|
|
215
425
|
const templates = FastGlob.sync(join(options.path.src.templates, '/**')).filter(entry => {
|
|
216
426
|
return !fs.existsSync(join(options.path.app.templates, relative(options.path.src.templates, entry))) || force
|
|
@@ -254,6 +464,39 @@ export default function prepare(options) {
|
|
|
254
464
|
sectionsSchema[sortedSection.src] = sortedSection
|
|
255
465
|
})
|
|
256
466
|
|
|
467
|
+
return sectionsSchema
|
|
468
|
+
},
|
|
469
|
+
getComponentsSchema() {
|
|
470
|
+
const views = FastGlob.sync(join(options.path.src.pages, '/**/*.json'))
|
|
471
|
+
const sectionsUnsorted = {}
|
|
472
|
+
const sectionsSchema = {}
|
|
473
|
+
|
|
474
|
+
views.forEach(path => {
|
|
475
|
+
const json = JSON.parse(fs.readFileSync(path).toString())
|
|
476
|
+
const sections = [...(json.body ?? []), ...(json.head ?? []), ...(json.foot ?? [])]
|
|
477
|
+
|
|
478
|
+
sections.forEach((section) => {
|
|
479
|
+
if (section.src) {
|
|
480
|
+
if (typeof sectionsUnsorted[section.src] === 'undefined') {
|
|
481
|
+
sectionsUnsorted[section.src] = []
|
|
482
|
+
sectionsUnsorted[section.src].push(section)
|
|
483
|
+
} else {
|
|
484
|
+
sectionsUnsorted[section.src].push(section)
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
})
|
|
488
|
+
})
|
|
489
|
+
|
|
490
|
+
Object.keys(sectionsUnsorted).forEach(key => {
|
|
491
|
+
const sortedSection = {}
|
|
492
|
+
|
|
493
|
+
sectionsUnsorted[key].forEach(section => {
|
|
494
|
+
lodash.merge(sortedSection, section)
|
|
495
|
+
})
|
|
496
|
+
|
|
497
|
+
sectionsSchema[sortedSection.src] = sortedSection
|
|
498
|
+
})
|
|
499
|
+
|
|
257
500
|
return sectionsSchema
|
|
258
501
|
}
|
|
259
502
|
}
|
|
@@ -76,16 +76,17 @@ export default async function cms(name, { variant, branch }) {
|
|
|
76
76
|
await move('app')
|
|
77
77
|
await move('config')
|
|
78
78
|
await move('log')
|
|
79
|
-
await move('public/.htaccess')
|
|
80
79
|
await move('public/index.php')
|
|
80
|
+
await move('src/views')
|
|
81
81
|
await move('temp')
|
|
82
|
+
await move('tests')
|
|
82
83
|
await move('.gitignore', { overwrite: true })
|
|
83
|
-
await move('.htaccess')
|
|
84
|
-
await move('Makefile')
|
|
85
84
|
await move('composer.json')
|
|
86
85
|
await move('composer.lock')
|
|
87
86
|
await move('docker-compose.yml')
|
|
87
|
+
await move('Makefile')
|
|
88
88
|
await move('phpstan.neon')
|
|
89
|
+
await move('phpunit.xml')
|
|
89
90
|
await move('pint.json')
|
|
90
91
|
await move('rector.php')
|
|
91
92
|
await fse.move(join(tempDir, '.gitlab-ci.prod.yml'), resolve(process.cwd(), '.gitlab-ci.yml'), { overwrite: true }).catch(err => console.log(`${pc.red(err)} - .gitlab-ci.yml`))
|