@okalit/cli 0.1.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.
Files changed (34) hide show
  1. package/README.md +32 -0
  2. package/bin/okalit-cli.js +8 -0
  3. package/lib/cli.js +515 -0
  4. package/package.json +30 -0
  5. package/templates/app/@okalit/AppMixin.js +29 -0
  6. package/templates/app/@okalit/EventBus.js +152 -0
  7. package/templates/app/@okalit/ModuleMixin.js +7 -0
  8. package/templates/app/@okalit/Okalit.js +129 -0
  9. package/templates/app/@okalit/OkalitService.js +145 -0
  10. package/templates/app/@okalit/defineElement.js +65 -0
  11. package/templates/app/@okalit/i18n.js +89 -0
  12. package/templates/app/@okalit/idle.js +40 -0
  13. package/templates/app/@okalit/index.js +10 -0
  14. package/templates/app/@okalit/lazy.js +32 -0
  15. package/templates/app/@okalit/okalit-router.js +309 -0
  16. package/templates/app/@okalit/service.js +33 -0
  17. package/templates/app/@okalit/trigger.js +14 -0
  18. package/templates/app/@okalit/viewport.js +69 -0
  19. package/templates/app/@okalit/when.js +40 -0
  20. package/templates/app/babel.config.json +5 -0
  21. package/templates/app/index.html +15 -0
  22. package/templates/app/package.json +23 -0
  23. package/templates/app/public/i18n/en.json +3 -0
  24. package/templates/app/public/i18n/es.json +3 -0
  25. package/templates/app/public/lit.svg +1 -0
  26. package/templates/app/src/app.routes.ts +10 -0
  27. package/templates/app/src/main-app.js +13 -0
  28. package/templates/app/src/modules/example/example.module.js +4 -0
  29. package/templates/app/src/modules/example/example.routes.js +7 -0
  30. package/templates/app/src/modules/example/pages/example.page.js +43 -0
  31. package/templates/app/src/modules/example/pages/example.page.scss +76 -0
  32. package/templates/app/src/styles/global.scss +0 -0
  33. package/templates/app/src/styles/index.css +4 -0
  34. package/templates/app/vite.config.js +19 -0
package/README.md ADDED
@@ -0,0 +1,32 @@
1
+ # Okalit CLI
2
+
3
+ CLI para crear apps Okalit y generar recursos dentro de un proyecto existente.
4
+
5
+ ## Uso
6
+
7
+ ```bash
8
+ npx okalit-cli new app-name
9
+ npx okalit-cli -g -c ./src/components/component-name
10
+ npx okalit-cli -g -s ./src/modules/home/services/example
11
+ npx okalit-cli -g -m ./src/modules/profile
12
+ npx okalit-cli -g --guard ./src/guards/auth
13
+ npx okalit-cli -g --interceptor ./src/interceptors/auth
14
+ ```
15
+
16
+ ## Qué genera
17
+
18
+ - `new <app-name>`: crea una app Vite basada en el template de Okalit.
19
+ - `-g -c`: crea carpeta del componente con `js` y `scss` o `css` según el proyecto.
20
+ - `-g -s`: crea un archivo `*.service.js` en la ruta indicada.
21
+ - `-g -m`: crea carpeta del módulo con `*.module.js`, `*.routes.js` y página inicial.
22
+ - `-g --guard`: crea un archivo `*.guard.js`.
23
+ - `-g --interceptor`: crea un archivo `*.interceptor.js`.
24
+
25
+ ## Desarrollo local
26
+
27
+ ```bash
28
+ cd okalit-cli
29
+ npm install
30
+ npm link
31
+ okalit-cli --help
32
+ ```
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { main } from '../lib/cli.js';
4
+
5
+ main(process.argv.slice(2)).catch((error) => {
6
+ console.error(`\nError: ${error.message}`);
7
+ process.exitCode = 1;
8
+ });
package/lib/cli.js ADDED
@@ -0,0 +1,515 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+
5
+ const __filename = fileURLToPath(import.meta.url);
6
+ const __dirname = path.dirname(__filename);
7
+ const TEMPLATE_DIR = path.resolve(__dirname, '../templates/app');
8
+ const HELP_CONTENT = `
9
+
10
+ ▄▄▄▄ ▄▄ ▄▄▄▄ ██
11
+ ██▀▀██ ██ ▀▀██ ▀▀ ██
12
+ ██ ██ ██ ▄██▀ ▄█████▄ ██ ████ ███████
13
+ ██ ██ ██▄██ ▀ ▄▄▄██ ██ ██ ██
14
+ ██ ██ ██▀██▄ ▄██▀▀▀██ ██ ██ ██
15
+ ██▄▄██ ██ ▀█▄ ██▄▄▄███ ██▄▄▄ ▄▄▄██▄▄▄ ██▄▄▄
16
+ ▀▀▀▀ ▀▀ ▀▀▀ ▀▀▀▀ ▀▀ ▀▀▀▀ ▀▀▀▀▀▀▀▀ ▀▀▀▀
17
+ By LIAPF Okalit CLI - v0.0.1
18
+
19
+ Usage:
20
+ okalit new <app-name>
21
+ okalit generate <type> <path>
22
+
23
+ Commands:
24
+ new <name> Create a new app
25
+
26
+ generate, -g
27
+ -c, --component <path> Create a component
28
+ -s, --service <path> Create a service
29
+ -m, --module <path> Create a module
30
+ --guard <path> Create a guard
31
+ --interceptor <path> Create an interceptor
32
+
33
+ Examples:
34
+ okalit new my-app
35
+ okalit -g -c ./src/components/user-card
36
+ okalit -g -s ./src/modules/home/services/user
37
+ `;
38
+
39
+ function getHelpText() {
40
+ return `${HELP_CONTENT}`;
41
+ }
42
+
43
+ export async function main(argv) {
44
+ if (argv.length === 0 || argv.includes('--help') || argv.includes('-h')) {
45
+ console.log(getHelpText());
46
+ return;
47
+ }
48
+
49
+ const command = argv[0];
50
+
51
+ if (command === 'new') {
52
+ const appName = argv[1];
53
+ if (!appName) {
54
+ throw new Error('You must provide an app name: okalit new <app-name>.');
55
+ }
56
+
57
+ await createApp(appName, process.cwd());
58
+ return;
59
+ }
60
+
61
+ if (argv.includes('-g') || argv.includes('--generate')) {
62
+ await handleGenerate(argv, process.cwd());
63
+ return;
64
+ }
65
+
66
+ throw new Error('Unknown command. Use --help to see available options.');
67
+ }
68
+
69
+ async function createApp(rawName, cwd) {
70
+ const appName = toKebabCase(rawName);
71
+ const targetDir = path.resolve(cwd, appName);
72
+
73
+ if (fs.existsSync(targetDir)) {
74
+ throw new Error(`La carpeta ya existe: ${targetDir}`);
75
+ }
76
+
77
+ copyDirectory(TEMPLATE_DIR, targetDir);
78
+
79
+ const initialClassName = toPascalCase(appName);
80
+ const mainAppFile = path.join(targetDir, 'src', 'main-app.js');
81
+ const packageJsonFile = path.join(targetDir, 'package.json');
82
+ const indexHtmlFile = path.join(targetDir, 'index.html');
83
+ const routesFile = [
84
+ path.join(targetDir, 'src', 'app.routes.ts'),
85
+ path.join(targetDir, 'src', 'app.routes.js'),
86
+ ].find((filePath) => fs.existsSync(filePath));
87
+
88
+ if (!routesFile) {
89
+ throw new Error('Could not find the app routes file.');
90
+ }
91
+
92
+ const routesExtension = path.extname(routesFile);
93
+
94
+ replaceInFile(packageJsonFile, '"name": "okalit-app"', `"name": "${appName}"`);
95
+ replaceInFile(indexHtmlFile, '<title>Okalit App</title>', `<title>${initialClassName}</title>`);
96
+ replaceManyInFile(mainAppFile, [
97
+ ['./app.routes.js', `./app.routes${routesExtension}`],
98
+ ['./app.routes.ts', `./app.routes${routesExtension}`],
99
+ ]);
100
+
101
+ console.log(`Okalit app created at ${targetDir}`);
102
+ console.log(`\nNext steps:`);
103
+ console.log(` cd ${appName}`);
104
+ console.log(' npm install');
105
+ console.log(' npm run dev');
106
+ }
107
+
108
+ async function handleGenerate(argv, cwd) {
109
+ const projectRoot = findProjectRoot(cwd);
110
+ const styleExt = detectStyleExtension(projectRoot);
111
+ const coreAlias = detectCoreAlias(projectRoot);
112
+ const globalStyleSpecifier = detectGlobalStyleSpecifier(projectRoot);
113
+
114
+ const targets = [
115
+ { kind: 'component', flags: ['-c', '--component'] },
116
+ { kind: 'service', flags: ['-s', '--service'] },
117
+ { kind: 'module', flags: ['-m', '--module'] },
118
+ { kind: 'guard', flags: ['--guard'] },
119
+ { kind: 'interceptor', flags: ['--interceptor'] },
120
+ ];
121
+
122
+ for (const target of targets) {
123
+ const value = readFlagValue(argv, target.flags);
124
+ if (!value) {
125
+ continue;
126
+ }
127
+
128
+ switch (target.kind) {
129
+ case 'component':
130
+ generateComponent(projectRoot, value, styleExt, coreAlias, globalStyleSpecifier);
131
+ break;
132
+ case 'service':
133
+ generatePlainFile(projectRoot, value, 'service', buildServiceTemplate(value, coreAlias));
134
+ break;
135
+ case 'module':
136
+ generateModule(projectRoot, value, styleExt, coreAlias, globalStyleSpecifier);
137
+ break;
138
+ case 'guard':
139
+ generatePlainFile(projectRoot, value, 'guard', buildGuardTemplate(value));
140
+ break;
141
+ case 'interceptor':
142
+ generatePlainFile(projectRoot, value, 'interceptor', buildInterceptorTemplate(value));
143
+ break;
144
+ default:
145
+ break;
146
+ }
147
+
148
+ return;
149
+ }
150
+
151
+ throw new Error('You must specify what to generate. Use -c, -s, -m, --guard or --interceptor.');
152
+ }
153
+
154
+ function generateComponent(projectRoot, targetPath, styleExt, coreAlias, globalStyleSpecifier) {
155
+ const normalizedTarget = normalizeProjectPath(projectRoot, targetPath);
156
+ const baseName = toKebabCase(path.basename(normalizedTarget));
157
+ const componentDir = normalizedTarget;
158
+ const jsFile = path.join(componentDir, `${baseName}.js`);
159
+ const styleFile = path.join(componentDir, `${baseName}.${styleExt}`);
160
+ const className = toPascalCase(baseName);
161
+
162
+ ensureMissing(componentDir);
163
+ fs.mkdirSync(componentDir, { recursive: true });
164
+ fs.writeFileSync(jsFile, buildComponentTemplate(baseName, className, styleExt, coreAlias, globalStyleSpecifier));
165
+ fs.writeFileSync(styleFile, '', 'utf8');
166
+
167
+ console.log(`Component created: ${path.relative(projectRoot, componentDir)}`);
168
+ }
169
+
170
+ function generateModule(projectRoot, targetPath, styleExt, coreAlias, globalStyleSpecifier) {
171
+ const normalizedTarget = normalizeProjectPath(projectRoot, targetPath);
172
+ const moduleName = toKebabCase(path.basename(normalizedTarget));
173
+ const moduleDir = normalizedTarget;
174
+ const pagesDir = path.join(moduleDir, 'pages');
175
+ const className = toPascalCase(moduleName);
176
+
177
+ ensureMissing(moduleDir);
178
+ fs.mkdirSync(pagesDir, { recursive: true });
179
+
180
+ const moduleFile = path.join(moduleDir, `${moduleName}.module.js`);
181
+ const routesFile = path.join(moduleDir, `${moduleName}.routes.js`);
182
+ const pageFile = path.join(pagesDir, `${moduleName}.page.js`);
183
+ const styleFile = path.join(pagesDir, `${moduleName}.page.${styleExt}`);
184
+
185
+ fs.writeFileSync(moduleFile, buildModuleTemplate(moduleName, className, coreAlias));
186
+ fs.writeFileSync(routesFile, buildModuleRoutesTemplate(moduleName), 'utf8');
187
+ fs.writeFileSync(pageFile, buildPageTemplate(moduleName, className, styleExt, coreAlias, globalStyleSpecifier));
188
+ fs.writeFileSync(styleFile, '', 'utf8');
189
+
190
+ attachModuleToAppRoutes(projectRoot, moduleName, className);
191
+
192
+ console.log(`Module created: ${path.relative(projectRoot, moduleDir)}`);
193
+ }
194
+
195
+ function generatePlainFile(projectRoot, targetPath, suffix, template) {
196
+ const normalizedTarget = normalizeProjectPath(projectRoot, targetPath);
197
+ const dirname = path.dirname(normalizedTarget);
198
+ const baseName = toKebabCase(path.basename(normalizedTarget));
199
+ const filePath = path.join(dirname, `${baseName}.${suffix}.js`);
200
+
201
+ ensureMissing(filePath);
202
+ fs.mkdirSync(dirname, { recursive: true });
203
+ fs.writeFileSync(filePath, template(baseName), 'utf8');
204
+
205
+ console.log(`File created: ${path.relative(projectRoot, filePath)}`);
206
+ }
207
+
208
+ function buildComponentTemplate(tagName, className, styleExt, coreAlias, globalStyleSpecifier) {
209
+ const globalStyleImport = globalStyleSpecifier
210
+ ? `\nimport global from "${globalStyleSpecifier}";`
211
+ : '';
212
+ const stylesArray = globalStyleSpecifier ? '[styles, global]' : '[styles]';
213
+
214
+ return `import { html } from "lit";
215
+ import { Okalit, defineElement } from "${coreAlias}";
216
+
217
+ import styles from "./${tagName}.${styleExt}?inline";${globalStyleImport}
218
+
219
+ @defineElement({
220
+ tag: "${tagName}",
221
+ styles: ${stylesArray}
222
+ })
223
+ export class ${className} extends Okalit {
224
+ render() {
225
+ return html\`
226
+ <div class="${tagName}">
227
+ <slot></slot>
228
+ </div>
229
+ \`;
230
+ }
231
+ }
232
+ `;
233
+ }
234
+
235
+ function buildModuleTemplate(moduleName, className, coreAlias) {
236
+ return `import { ModuleMixin, Okalit, defineElement } from "${coreAlias}";
237
+
238
+ @defineElement({ tag: "${moduleName}-module" })
239
+ export class ${className}Module extends ModuleMixin(Okalit) {}
240
+ `;
241
+ }
242
+
243
+ function buildModuleRoutesTemplate(moduleName) {
244
+ return `export default [
245
+ {
246
+ path: "",
247
+ component: "${moduleName}-page",
248
+ import: () => import("./pages/${moduleName}.page.js")
249
+ }
250
+ ];
251
+ `;
252
+ }
253
+
254
+ function buildPageTemplate(pageName, className, styleExt, coreAlias, globalStyleSpecifier) {
255
+ const globalStyleImport = globalStyleSpecifier
256
+ ? `import global from "${globalStyleSpecifier}";`
257
+ : '';
258
+ const stylesArray = globalStyleSpecifier ? '[styles, global]' : '[styles]';
259
+
260
+ return `import { html } from "lit";
261
+ import { Okalit, defineElement } from "${coreAlias}";
262
+
263
+ import styles from "./${pageName}.page.${styleExt}?inline";
264
+ ${globalStyleImport}
265
+
266
+ @defineElement({
267
+ tag: "${pageName}-page",
268
+ styles: ${stylesArray}
269
+ })
270
+ export class ${className}Page extends Okalit {
271
+ render() {
272
+ return html\`
273
+ <main>
274
+ <h1>${'${this.t("WELCOME")}'}</h1>
275
+ </main>
276
+ \`;
277
+ }
278
+ }
279
+ `;
280
+ }
281
+
282
+ function buildServiceTemplate(rawTarget, coreAlias) {
283
+ return (baseName) => {
284
+ const className = `${toPascalCase(baseName)}Service`;
285
+ const serviceName = `${toCamelCase(baseName)}Service`;
286
+ const resourcePath = `/${baseName}`;
287
+
288
+ return `import { OkalitService, service } from "${coreAlias}";
289
+
290
+ @service("${serviceName}")
291
+ export class ${className} extends OkalitService {
292
+ constructor() {
293
+ super();
294
+ this.baseUrl = "";
295
+ this.version = "1";
296
+ this.path = "${resourcePath}";
297
+ this.headers = {};
298
+ }
299
+ }
300
+ `;
301
+ };
302
+ }
303
+
304
+ function buildGuardTemplate(rawTarget) {
305
+ return (baseName) => {
306
+ const functionName = `${toCamelCase(baseName)}Guard`;
307
+
308
+ return `export async function ${functionName}(path, args) {
309
+ void path;
310
+ void args;
311
+
312
+ return { allow: true };
313
+ }
314
+ `;
315
+ };
316
+ }
317
+
318
+ function buildInterceptorTemplate(rawTarget) {
319
+ return (baseName) => {
320
+ const functionName = `${toCamelCase(baseName)}Interceptor`;
321
+
322
+ return `export async function ${functionName}(context) {
323
+ return context;
324
+ }
325
+ `;
326
+ };
327
+ }
328
+
329
+ function attachModuleToAppRoutes(projectRoot, moduleName, className) {
330
+ const candidateFiles = [
331
+ path.join(projectRoot, 'src', 'app.routes.ts'),
332
+ path.join(projectRoot, 'src', 'app.routes.js'),
333
+ ];
334
+ const routesFile = candidateFiles.find((file) => fs.existsSync(file));
335
+
336
+ if (!routesFile) {
337
+ return;
338
+ }
339
+
340
+ const importLine = `import ${className}ModuleRoutes from "./modules/${moduleName}/${moduleName}.routes.js";`;
341
+ const routeEntry = ` {\n path: "/${moduleName}",\n component: "${moduleName}-module",\n import: () => import("./modules/${moduleName}/${moduleName}.module.js"),\n children: ${className}ModuleRoutes,\n }`;
342
+ const source = fs.readFileSync(routesFile, 'utf8');
343
+
344
+ if (source.includes(importLine) || source.includes(`"/${moduleName}"`)) {
345
+ return;
346
+ }
347
+
348
+ let next = source;
349
+ if (/^export default \[/m.test(next)) {
350
+ next = `${importLine}\n\n${next}`;
351
+ }
352
+
353
+ next = next.replace(/export default \[(.*?)\];/s, (match, body) => {
354
+ const trimmedBody = body.trim();
355
+ if (!trimmedBody) {
356
+ return `export default [\n${routeEntry}\n];`;
357
+ }
358
+
359
+ return `export default [\n${trimmedBody.endsWith(',') ? trimmedBody : `${trimmedBody},`}\n${routeEntry}\n];`;
360
+ });
361
+
362
+ fs.writeFileSync(routesFile, `${next.endsWith('\n') ? next : `${next}\n`}`, 'utf8');
363
+ }
364
+
365
+ function findProjectRoot(startDir) {
366
+ let currentDir = startDir;
367
+
368
+ while (true) {
369
+ const packageJsonFile = path.join(currentDir, 'package.json');
370
+ if (fs.existsSync(packageJsonFile)) {
371
+ return currentDir;
372
+ }
373
+
374
+ const parentDir = path.dirname(currentDir);
375
+ if (parentDir === currentDir) {
376
+ throw new Error('No package.json found. Run this command inside an Okalit project.');
377
+ }
378
+
379
+ currentDir = parentDir;
380
+ }
381
+ }
382
+
383
+ function detectStyleExtension(projectRoot) {
384
+ const packageJsonFile = path.join(projectRoot, 'package.json');
385
+ if (!fs.existsSync(packageJsonFile)) {
386
+ return 'scss';
387
+ }
388
+
389
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonFile, 'utf8'));
390
+ const hasSass = Boolean(packageJson.dependencies?.sass || packageJson.devDependencies?.sass);
391
+ return hasSass ? 'scss' : 'css';
392
+ }
393
+
394
+ function detectGlobalStyleSpecifier(projectRoot) {
395
+ const candidates = [
396
+ {
397
+ filePath: path.join(projectRoot, 'src', 'styles', 'global.scss'),
398
+ specifier: '@styles/global.scss?inline',
399
+ },
400
+ {
401
+ filePath: path.join(projectRoot, 'src', 'styles', 'global.css'),
402
+ specifier: '@styles/global.css?inline',
403
+ },
404
+ ];
405
+
406
+ return candidates.find((candidate) => fs.existsSync(candidate.filePath))?.specifier ?? null;
407
+ }
408
+
409
+ function detectCoreAlias(projectRoot) {
410
+ const viteConfigFile = path.join(projectRoot, 'vite.config.js');
411
+ if (!fs.existsSync(viteConfigFile)) {
412
+ return '@okalit';
413
+ }
414
+
415
+ const viteConfig = fs.readFileSync(viteConfigFile, 'utf8');
416
+ if (viteConfig.includes("'@core'") || viteConfig.includes('"@core"')) {
417
+ return '@core';
418
+ }
419
+
420
+ if (viteConfig.includes("'@okalit'") || viteConfig.includes('"@okalit"')) {
421
+ return '@okalit';
422
+ }
423
+
424
+ return '@okalit';
425
+ }
426
+
427
+ function normalizeProjectPath(projectRoot, inputPath) {
428
+ const resolved = path.resolve(projectRoot, inputPath);
429
+ return resolved;
430
+ }
431
+
432
+ function readFlagValue(argv, flags) {
433
+ for (const flag of flags) {
434
+ const index = argv.indexOf(flag);
435
+ if (index !== -1) {
436
+ return argv[index + 1];
437
+ }
438
+ }
439
+
440
+ return null;
441
+ }
442
+
443
+ function copyDirectory(sourceDir, targetDir) {
444
+ fs.mkdirSync(targetDir, { recursive: true });
445
+
446
+ for (const entry of fs.readdirSync(sourceDir, { withFileTypes: true })) {
447
+ if (entry.name === '.DS_Store') {
448
+ continue;
449
+ }
450
+
451
+ const sourcePath = path.join(sourceDir, entry.name);
452
+ const targetPath = path.join(targetDir, entry.name);
453
+
454
+ if (entry.isDirectory()) {
455
+ copyDirectory(sourcePath, targetPath);
456
+ continue;
457
+ }
458
+
459
+ fs.copyFileSync(sourcePath, targetPath);
460
+ }
461
+ }
462
+
463
+ function replaceInFile(filePath, searchValue, replaceValue) {
464
+ const source = fs.readFileSync(filePath, 'utf8');
465
+ fs.writeFileSync(filePath, source.replace(searchValue, replaceValue), 'utf8');
466
+ }
467
+
468
+ function replaceManyInFile(filePath, replacements) {
469
+ let source = fs.readFileSync(filePath, 'utf8');
470
+
471
+ for (const [searchValue, replaceValue] of replacements) {
472
+ source = source.replaceAll(searchValue, replaceValue);
473
+ }
474
+
475
+ fs.writeFileSync(filePath, source, 'utf8');
476
+ }
477
+
478
+ function renameIfExists(sourcePath, targetPath) {
479
+ if (fs.existsSync(sourcePath)) {
480
+ fs.renameSync(sourcePath, targetPath);
481
+ }
482
+ }
483
+
484
+ function ensureMissing(targetPath) {
485
+ if (fs.existsSync(targetPath)) {
486
+ throw new Error(`Ya existe: ${targetPath}`);
487
+ }
488
+ }
489
+
490
+ function toKebabCase(value) {
491
+ return value
492
+ .replace(/^[./\\]+/, '')
493
+ .replace(/([a-z0-9])([A-Z])/g, '$1-$2')
494
+ .replace(/[^a-zA-Z0-9/]+/g, '-')
495
+ .replace(/\/+/g, '/')
496
+ .split('/')
497
+ .filter(Boolean)
498
+ .map((segment) => segment.toLowerCase().replace(/^-+|-+$/g, ''))
499
+ .join('/');
500
+ }
501
+
502
+ function toPascalCase(value) {
503
+ return toKebabCase(value)
504
+ .split('/')
505
+ .at(-1)
506
+ .split('-')
507
+ .filter(Boolean)
508
+ .map((part) => part[0].toUpperCase() + part.slice(1))
509
+ .join('');
510
+ }
511
+
512
+ function toCamelCase(value) {
513
+ const pascal = toPascalCase(value);
514
+ return pascal ? pascal[0].toLowerCase() + pascal.slice(1) : '';
515
+ }
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "@okalit/cli",
3
+ "version": "0.1.0",
4
+ "description": "CLI to create and generate resources for Okalit projects",
5
+ "type": "module",
6
+ "bin": {
7
+ "okalit": "./bin/okalit-cli.js"
8
+ },
9
+ "files": [
10
+ "bin",
11
+ "lib",
12
+ "templates",
13
+ "README.md"
14
+ ],
15
+ "keywords": [
16
+ "okalit",
17
+ "cli",
18
+ "scaffold",
19
+ "vite",
20
+ "lit"
21
+ ],
22
+ "license": "MIT",
23
+ "engines": {
24
+ "node": ">=18.0.0"
25
+ },
26
+ "scripts": {
27
+ "start": "node ./bin/okalit-cli.js",
28
+ "test:smoke": "node ./bin/okalit-cli.js --help"
29
+ }
30
+ }
@@ -0,0 +1,29 @@
1
+ import { html } from "lit";
2
+ import './okalit-router.js';
3
+ import { OkalitI18n } from './i18n.js';
4
+
5
+ export const AppMixin = (Base) => class extends Base {
6
+ async connectedCallback() {
7
+ super.connectedCallback();
8
+ if (this._appConfig.i18n && this._appConfig.i18n !== false) {
9
+ await OkalitI18n.init(this._appConfig.i18n);
10
+ }
11
+ }
12
+
13
+ get _getOkalitRouter() {
14
+ return html`
15
+ <okalit-router
16
+ .routes=${this._appConfig.routes}
17
+ .guards=${this._appConfig.guards}
18
+ .interceptors=${this._appConfig.interceptors}
19
+ ></okalit-router>
20
+ `;
21
+ }
22
+ render() {
23
+ return html`
24
+ ${ this._appConfig.layout
25
+ ? html`${this._appConfig.layout(this._getOkalitRouter) }`
26
+ : this._getOkalitRouter }
27
+ `;
28
+ }
29
+ }