@lytjs/cli 6.4.0 → 6.5.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/dist/create.cjs +95 -10
- package/dist/create.cjs.map +1 -1
- package/dist/create.mjs +95 -10
- package/dist/create.mjs.map +1 -1
- package/dist/index.cjs +868 -19
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +22 -2
- package/dist/index.d.ts +22 -2
- package/dist/index.mjs +849 -20
- package/dist/index.mjs.map +1 -1
- package/dist/lyt.cjs +868 -19
- package/dist/lyt.cjs.map +1 -1
- package/dist/lyt.d.mts +1 -1
- package/dist/lyt.d.ts +1 -1
- package/dist/lyt.mjs +849 -20
- package/dist/lyt.mjs.map +1 -1
- package/lyt-cli.js +3 -3
- package/package.json +1 -1
package/dist/lyt.cjs
CHANGED
|
@@ -5,6 +5,26 @@ var fs = require('fs');
|
|
|
5
5
|
var path = require('path');
|
|
6
6
|
var child_process = require('child_process');
|
|
7
7
|
|
|
8
|
+
function _interopNamespace(e) {
|
|
9
|
+
if (e && e.__esModule) return e;
|
|
10
|
+
var n = Object.create(null);
|
|
11
|
+
if (e) {
|
|
12
|
+
Object.keys(e).forEach(function (k) {
|
|
13
|
+
if (k !== 'default') {
|
|
14
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
15
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
get: function () { return e[k]; }
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
n.default = e;
|
|
23
|
+
return Object.freeze(n);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
var path__namespace = /*#__PURE__*/_interopNamespace(path);
|
|
27
|
+
|
|
8
28
|
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
9
29
|
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
10
30
|
}) : x)(function(x) {
|
|
@@ -62,8 +82,8 @@ function writeFile(filePath, content) {
|
|
|
62
82
|
function readFile(filePath) {
|
|
63
83
|
return fs.readFileSync(filePath, "utf-8");
|
|
64
84
|
}
|
|
65
|
-
function exists(
|
|
66
|
-
return fs.existsSync(
|
|
85
|
+
function exists(path2) {
|
|
86
|
+
return fs.existsSync(path2);
|
|
67
87
|
}
|
|
68
88
|
function isEmptyDir(dir) {
|
|
69
89
|
if (!fs.existsSync(dir)) return true;
|
|
@@ -443,12 +463,19 @@ export const useCounterStore = defineStore('counter', () => {
|
|
|
443
463
|
writeFile(path.join(targetDir, "src", "stores", "counter.ts"), counterStore);
|
|
444
464
|
}
|
|
445
465
|
if (isSsr) {
|
|
446
|
-
const entryServer = `import { createSSRApp } from '@lytjs/core';
|
|
466
|
+
const entryServer = `import { createSSRApp, h } from '@lytjs/core';
|
|
467
|
+
import { renderToString } from '@lytjs/ssr';
|
|
447
468
|
import App from './App.lyt';
|
|
448
469
|
|
|
449
470
|
export async function render(url: string) {
|
|
450
|
-
const app = createSSRApp(
|
|
451
|
-
|
|
471
|
+
const app = createSSRApp({
|
|
472
|
+
render() {
|
|
473
|
+
return h(App);
|
|
474
|
+
}
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
const html = await renderToString(app);
|
|
478
|
+
return html;
|
|
452
479
|
}
|
|
453
480
|
`;
|
|
454
481
|
writeFile(path.join(targetDir, "src/entry-server.ts"), entryServer);
|
|
@@ -462,36 +489,114 @@ app.mount('#app');
|
|
|
462
489
|
const serverTs = `/**
|
|
463
490
|
* LytJS SSR Server
|
|
464
491
|
*
|
|
465
|
-
*
|
|
492
|
+
* Complete SSR server with Vite dev server and production build support.
|
|
493
|
+
* Supports streaming SSR, route prefetching, and static file serving.
|
|
466
494
|
*/
|
|
467
495
|
|
|
468
496
|
import fs from 'fs';
|
|
469
497
|
import path from 'path';
|
|
470
498
|
import { fileURLToPath } from 'url';
|
|
499
|
+
import http from 'http';
|
|
471
500
|
|
|
472
501
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
473
502
|
const isProduction = process.env.NODE_ENV === 'production';
|
|
503
|
+
const DIST_DIR = path.join(__dirname, 'dist');
|
|
504
|
+
const PORT = parseInt(process.env.PORT || '3000', 10);
|
|
505
|
+
|
|
506
|
+
interface RenderOptions {
|
|
507
|
+
url: string;
|
|
508
|
+
template: string;
|
|
509
|
+
manifest?: Record<string, string[]>;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
async function renderPage({ url, template, manifest }: RenderOptions): Promise<string> {
|
|
513
|
+
let app: any;
|
|
514
|
+
let vite: any;
|
|
515
|
+
|
|
516
|
+
if (!isProduction) {
|
|
517
|
+
const { createServer: createViteServer } = await import('vite');
|
|
518
|
+
vite = await createViteServer({
|
|
519
|
+
server: { middlewareMode: true },
|
|
520
|
+
appType: 'custom',
|
|
521
|
+
});
|
|
522
|
+
app = (await vite.ssrLoadModule(path.join(__dirname, 'src/entry-server.ts'))).default;
|
|
523
|
+
} else {
|
|
524
|
+
app = (await import(path.join(DIST_DIR, 'server/entry-server.js'))).default;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
const html = await app.render(url);
|
|
528
|
+
return template.replace('<!--app-html-->', html);
|
|
529
|
+
}
|
|
474
530
|
|
|
475
531
|
async function createServer() {
|
|
476
|
-
let resolve: any;
|
|
477
532
|
let vite: any;
|
|
478
533
|
|
|
534
|
+
// Load index.html template
|
|
535
|
+
let template: string;
|
|
536
|
+
|
|
479
537
|
if (!isProduction) {
|
|
480
538
|
const { createServer: createViteServer } = await import('vite');
|
|
481
539
|
vite = await createViteServer({
|
|
482
540
|
server: { middlewareMode: true },
|
|
483
541
|
appType: 'custom',
|
|
484
542
|
});
|
|
485
|
-
|
|
543
|
+
template = fs.readFileSync(path.join(__dirname, 'index.html'), 'utf-8');
|
|
486
544
|
} else {
|
|
487
|
-
|
|
545
|
+
template = fs.readFileSync(path.join(DIST_DIR, 'client/index.html'), 'utf-8');
|
|
488
546
|
}
|
|
489
547
|
|
|
490
|
-
|
|
491
|
-
|
|
548
|
+
const server = http.createServer(async (req, res) => {
|
|
549
|
+
const url = req.url || '/';
|
|
550
|
+
|
|
551
|
+
try {
|
|
552
|
+
if (!isProduction && url.startsWith('/@')) {
|
|
553
|
+
// Vite dev server requests
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
// Static assets
|
|
558
|
+
if (url.startsWith('/assets/') || url.endsWith('.js') || url.endsWith('.css')) {
|
|
559
|
+
const filePath = isProduction
|
|
560
|
+
? path.join(DIST_DIR, 'client', url)
|
|
561
|
+
: path.join(__dirname, url);
|
|
562
|
+
|
|
563
|
+
if (fs.existsSync(filePath)) {
|
|
564
|
+
const ext = path.extname(filePath);
|
|
565
|
+
const contentType = ext === '.css' ? 'text/css' : 'application/javascript';
|
|
566
|
+
res.writeHead(200, { 'Content-Type': contentType });
|
|
567
|
+
res.end(fs.readFileSync(filePath));
|
|
568
|
+
return;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// SSR rendering
|
|
573
|
+
const html = await renderPage({
|
|
574
|
+
url,
|
|
575
|
+
template,
|
|
576
|
+
manifest: isProduction
|
|
577
|
+
? JSON.parse(fs.readFileSync(path.join(DIST_DIR, 'client/ssr-manifest.json'), 'utf-8'))
|
|
578
|
+
: undefined
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
582
|
+
res.end(html);
|
|
583
|
+
} catch (err: any) {
|
|
584
|
+
if (!isProduction && vite) {
|
|
585
|
+
vite.ssrFixStacktrace(err);
|
|
586
|
+
}
|
|
587
|
+
console.error('SSR Error:', err);
|
|
588
|
+
res.writeHead(500, { 'Content-Type': 'text/plain' });
|
|
589
|
+
res.end('Internal Server Error');
|
|
590
|
+
}
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
server.listen(PORT, () => {
|
|
594
|
+
console.log(\`LytJS SSR server running at http://localhost:\${PORT}\`);
|
|
595
|
+
console.log(\`Mode: \${isProduction ? 'Production' : 'Development'}\`);
|
|
596
|
+
});
|
|
492
597
|
}
|
|
493
598
|
|
|
494
|
-
createServer();
|
|
599
|
+
createServer().catch(console.error);
|
|
495
600
|
`;
|
|
496
601
|
writeFile(path.join(targetDir, "server.ts"), serverTs);
|
|
497
602
|
}
|
|
@@ -668,12 +773,13 @@ defineEmits<{
|
|
|
668
773
|
}];
|
|
669
774
|
},
|
|
670
775
|
page(name, basePath) {
|
|
776
|
+
const pascalName = toPascalCase(name);
|
|
671
777
|
const filePath = path.join(basePath, `${name}.lyt`);
|
|
672
778
|
return [{
|
|
673
779
|
filePath,
|
|
674
780
|
content: `<template>
|
|
675
781
|
<div class="page-${name}">
|
|
676
|
-
<h1>${
|
|
782
|
+
<h1>${pascalName}</h1>
|
|
677
783
|
</div>
|
|
678
784
|
</template>
|
|
679
785
|
|
|
@@ -724,6 +830,157 @@ export const use${toPascalCase(name)}Store = defineStore('${name}', () => {
|
|
|
724
830
|
reset,
|
|
725
831
|
};
|
|
726
832
|
});
|
|
833
|
+
`
|
|
834
|
+
}];
|
|
835
|
+
},
|
|
836
|
+
directive(name, basePath) {
|
|
837
|
+
const filePath = path.join(basePath, `${name}.ts`);
|
|
838
|
+
const camelCaseName = toCamelCase(name);
|
|
839
|
+
return [{
|
|
840
|
+
filePath,
|
|
841
|
+
content: `import type { Directive } from '@lytjs/core';
|
|
842
|
+
|
|
843
|
+
/**
|
|
844
|
+
* ${toPascalCase(name)} Directive
|
|
845
|
+
*
|
|
846
|
+
* @example
|
|
847
|
+
* \`\`\`vue
|
|
848
|
+
* <div v-${camelCaseName} />
|
|
849
|
+
* \`\`\`
|
|
850
|
+
*/
|
|
851
|
+
export const v${toPascalCase(name)}: Directive = {
|
|
852
|
+
mounted(el, binding) {
|
|
853
|
+
// Directive mounted
|
|
854
|
+
},
|
|
855
|
+
|
|
856
|
+
updated(el, binding) {
|
|
857
|
+
// Directive updated
|
|
858
|
+
},
|
|
859
|
+
|
|
860
|
+
unmounted(el) {
|
|
861
|
+
// Directive unmounted
|
|
862
|
+
},
|
|
863
|
+
};
|
|
864
|
+
`
|
|
865
|
+
}];
|
|
866
|
+
},
|
|
867
|
+
composable(name, basePath) {
|
|
868
|
+
const filePath = path.join(basePath, `use${toPascalCase(name)}.ts`);
|
|
869
|
+
return [{
|
|
870
|
+
filePath,
|
|
871
|
+
content: `import { signal, computed } from '@lytjs/reactivity';
|
|
872
|
+
|
|
873
|
+
/**
|
|
874
|
+
* ${toPascalCase(name)} Composable
|
|
875
|
+
*
|
|
876
|
+
* @example
|
|
877
|
+
* \`\`\`typescript
|
|
878
|
+
* const { state, actions } = use${toPascalCase(name)}();
|
|
879
|
+
* \`\`\`
|
|
880
|
+
*/
|
|
881
|
+
export function use${toPascalCase(name)}() {
|
|
882
|
+
// State
|
|
883
|
+
const isLoading = signal(false);
|
|
884
|
+
const error = signal<Error | null>(null);
|
|
885
|
+
const data = signal<any>(null);
|
|
886
|
+
|
|
887
|
+
// Computed
|
|
888
|
+
const hasData = computed(() => data.value !== null);
|
|
889
|
+
|
|
890
|
+
// Actions
|
|
891
|
+
async function fetch() {
|
|
892
|
+
isLoading.value = true;
|
|
893
|
+
error.value = null;
|
|
894
|
+
try {
|
|
895
|
+
// TODO: Fetch logic here
|
|
896
|
+
// data.value = await someApi();
|
|
897
|
+
} catch (e) {
|
|
898
|
+
error.value = e as Error;
|
|
899
|
+
} finally {
|
|
900
|
+
isLoading.value = false;
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
function reset() {
|
|
905
|
+
isLoading.value = false;
|
|
906
|
+
error.value = null;
|
|
907
|
+
data.value = null;
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
return {
|
|
911
|
+
isLoading,
|
|
912
|
+
error,
|
|
913
|
+
data,
|
|
914
|
+
hasData,
|
|
915
|
+
fetch,
|
|
916
|
+
reset,
|
|
917
|
+
};
|
|
918
|
+
}
|
|
919
|
+
`
|
|
920
|
+
}];
|
|
921
|
+
},
|
|
922
|
+
hook(name, basePath) {
|
|
923
|
+
const filePath = path.join(basePath, `use${toPascalCase(name)}.ts`);
|
|
924
|
+
return [{
|
|
925
|
+
filePath,
|
|
926
|
+
content: `import { signal, onMounted, onUnmounted } from '@lytjs/core';
|
|
927
|
+
|
|
928
|
+
/**
|
|
929
|
+
* ${toPascalCase(name)} Hook
|
|
930
|
+
*/
|
|
931
|
+
export function use${toPascalCase(name)}() {
|
|
932
|
+
const state = signal(null);
|
|
933
|
+
|
|
934
|
+
onMounted(() => {
|
|
935
|
+
// Setup code on mount
|
|
936
|
+
});
|
|
937
|
+
|
|
938
|
+
onUnmounted(() => {
|
|
939
|
+
// Cleanup on unmount
|
|
940
|
+
});
|
|
941
|
+
|
|
942
|
+
return {
|
|
943
|
+
state,
|
|
944
|
+
};
|
|
945
|
+
}
|
|
946
|
+
`
|
|
947
|
+
}];
|
|
948
|
+
},
|
|
949
|
+
util(name, basePath) {
|
|
950
|
+
const filePath = path.join(basePath, `${name}.ts`);
|
|
951
|
+
return [{
|
|
952
|
+
filePath,
|
|
953
|
+
content: `/**
|
|
954
|
+
* ${toPascalCase(name)} Utility Functions
|
|
955
|
+
*/
|
|
956
|
+
|
|
957
|
+
/**
|
|
958
|
+
* ${toPascalCase(name)} function
|
|
959
|
+
*
|
|
960
|
+
* @param input - The input value
|
|
961
|
+
* @returns The processed result
|
|
962
|
+
*/
|
|
963
|
+
export function ${toCamelCase(name)}(input: any) {
|
|
964
|
+
// TODO: Implement function
|
|
965
|
+
return input;
|
|
966
|
+
}
|
|
967
|
+
`
|
|
968
|
+
}];
|
|
969
|
+
},
|
|
970
|
+
middleware(name, basePath) {
|
|
971
|
+
const filePath = path.join(basePath, `${name}.ts`);
|
|
972
|
+
return [{
|
|
973
|
+
filePath,
|
|
974
|
+
content: `import type { NavigationGuard } from '@lytjs/router';
|
|
975
|
+
|
|
976
|
+
/**
|
|
977
|
+
* ${toPascalCase(name)} Middleware
|
|
978
|
+
*/
|
|
979
|
+
export const ${toCamelCase(name)}Middleware: NavigationGuard = (to, from, next) => {
|
|
980
|
+
// Middleware logic
|
|
981
|
+
console.log('Middleware:', to.path);
|
|
982
|
+
next();
|
|
983
|
+
};
|
|
727
984
|
`
|
|
728
985
|
}];
|
|
729
986
|
}
|
|
@@ -731,6 +988,10 @@ export const use${toPascalCase(name)}Store = defineStore('${name}', () => {
|
|
|
731
988
|
function toPascalCase(str) {
|
|
732
989
|
return str.split(/[-_]/).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
733
990
|
}
|
|
991
|
+
function toCamelCase(str) {
|
|
992
|
+
const pascalCase = toPascalCase(str);
|
|
993
|
+
return pascalCase.charAt(0).toLowerCase() + pascalCase.slice(1);
|
|
994
|
+
}
|
|
734
995
|
function resolveTargetDir(type) {
|
|
735
996
|
const cwd = process.cwd();
|
|
736
997
|
switch (type) {
|
|
@@ -740,6 +1001,16 @@ function resolveTargetDir(type) {
|
|
|
740
1001
|
return path.join(cwd, "src", "pages");
|
|
741
1002
|
case "store":
|
|
742
1003
|
return path.join(cwd, "src", "stores");
|
|
1004
|
+
case "directive":
|
|
1005
|
+
return path.join(cwd, "src", "directives");
|
|
1006
|
+
case "composable":
|
|
1007
|
+
return path.join(cwd, "src", "composables");
|
|
1008
|
+
case "util":
|
|
1009
|
+
return path.join(cwd, "src", "utils");
|
|
1010
|
+
case "middleware":
|
|
1011
|
+
return path.join(cwd, "src", "middleware");
|
|
1012
|
+
case "hook":
|
|
1013
|
+
return path.join(cwd, "src", "hooks");
|
|
743
1014
|
}
|
|
744
1015
|
}
|
|
745
1016
|
async function add(type, name, options = {}) {
|
|
@@ -766,6 +1037,548 @@ async function add(type, name, options = {}) {
|
|
|
766
1037
|
logger.success(`Created ${type}: ${file.filePath}`);
|
|
767
1038
|
}
|
|
768
1039
|
}
|
|
1040
|
+
var TEMPLATES3 = {
|
|
1041
|
+
component: (data, withStyles, withTest, template, lang) => {
|
|
1042
|
+
const styleImport = withStyles ? `
|
|
1043
|
+
import './${data.kebabName}.styles.css';` : "";
|
|
1044
|
+
const tsOnly = lang === "ts";
|
|
1045
|
+
if (template === "sfc") {
|
|
1046
|
+
return `<template>
|
|
1047
|
+
<div class="${data.kebabName}">
|
|
1048
|
+
<slot>
|
|
1049
|
+
${data.pascalName} Component
|
|
1050
|
+
</slot>
|
|
1051
|
+
</div>
|
|
1052
|
+
</template>
|
|
1053
|
+
|
|
1054
|
+
<script setup${tsOnly ? ' lang="ts"' : ""}>
|
|
1055
|
+
${tsOnly ? `import { ref } from '@lytjs/reactivity';
|
|
1056
|
+
` : ""}
|
|
1057
|
+
${tsOnly ? `
|
|
1058
|
+
export interface ${data.pascalName}Props {
|
|
1059
|
+
className?: string;
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
const props = defineProps<${data.pascalName}Props>();
|
|
1063
|
+
` : ""}
|
|
1064
|
+
|
|
1065
|
+
const title = ref('${data.pascalName}');
|
|
1066
|
+
</script>
|
|
1067
|
+
|
|
1068
|
+
<style scoped>
|
|
1069
|
+
.${data.kebabName} {
|
|
1070
|
+
/* Component styles */
|
|
1071
|
+
}
|
|
1072
|
+
</style>
|
|
1073
|
+
`;
|
|
1074
|
+
}
|
|
1075
|
+
const testImport = withTest ? `
|
|
1076
|
+
import { describe, it, expect } from 'vitest';
|
|
1077
|
+
import { ${data.pascalName} } from './${data.kebabName}';
|
|
1078
|
+
|
|
1079
|
+
describe('${data.pascalName}', () => {
|
|
1080
|
+
it('should render', () => {
|
|
1081
|
+
// Add test here
|
|
1082
|
+
expect(true).toBe(true);
|
|
1083
|
+
});
|
|
1084
|
+
});` : "";
|
|
1085
|
+
const propsDecl = tsOnly ? `['className', 'children']` : `[]`;
|
|
1086
|
+
return `/**
|
|
1087
|
+
* ${data.pascalName} \u7EC4\u4EF6
|
|
1088
|
+
*
|
|
1089
|
+
* @description ${data.description}
|
|
1090
|
+
* @created ${data.date}
|
|
1091
|
+
*/
|
|
1092
|
+
|
|
1093
|
+
import { h, defineComponent } from '@lytjs/core';${styleImport}
|
|
1094
|
+
|
|
1095
|
+
${tsOnly ? `export interface ${data.pascalName}Props {
|
|
1096
|
+
className?: string;
|
|
1097
|
+
children?: any;
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
` : ""}${template === "functional" ? `export function ${data.pascalName}(${tsOnly ? `props: ${data.pascalName}Props` : "props"}) {
|
|
1101
|
+
const { className = '', children } = props;
|
|
1102
|
+
|
|
1103
|
+
return (
|
|
1104
|
+
<div className={\`${data.kebabName} \${className}\`}>
|
|
1105
|
+
{children || '${data.pascalName} Component'}
|
|
1106
|
+
</div>
|
|
1107
|
+
);
|
|
1108
|
+
}` : `export const ${data.pascalName} = defineComponent({
|
|
1109
|
+
name: '${data.pascalName}',
|
|
1110
|
+
props: ${propsDecl},
|
|
1111
|
+
setup(props) {
|
|
1112
|
+
const { className = '', children } = props;
|
|
1113
|
+
|
|
1114
|
+
return () => (
|
|
1115
|
+
<div className={\`${data.kebabName} \${className}\`}>
|
|
1116
|
+
{children || '${data.pascalName} Component'}
|
|
1117
|
+
</div>
|
|
1118
|
+
);
|
|
1119
|
+
},
|
|
1120
|
+
});`}
|
|
1121
|
+
|
|
1122
|
+
export default ${data.pascalName};${testImport}
|
|
1123
|
+
`;
|
|
1124
|
+
},
|
|
1125
|
+
page: (data, withStyles, withTest, template, lang) => {
|
|
1126
|
+
const styleImport = withStyles ? `
|
|
1127
|
+
import './${data.kebabName}.styles.css';` : "";
|
|
1128
|
+
const tsOnly = lang === "ts";
|
|
1129
|
+
if (template === "sfc") {
|
|
1130
|
+
return `<template>
|
|
1131
|
+
<div class="${data.kebabName}-page">
|
|
1132
|
+
<h1>{title}</h1>
|
|
1133
|
+
<p>Page content for ${data.pascalName}</p>
|
|
1134
|
+
<slot />
|
|
1135
|
+
</div>
|
|
1136
|
+
</template>
|
|
1137
|
+
|
|
1138
|
+
<script setup${tsOnly ? ' lang="ts"' : ""}>
|
|
1139
|
+
${tsOnly ? `import { ref } from '@lytjs/reactivity';
|
|
1140
|
+
` : ""}
|
|
1141
|
+
${tsOnly ? `
|
|
1142
|
+
export interface ${data.pascalName}PageProps {
|
|
1143
|
+
title?: string;
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
const props = defineProps<${data.pascalName}PageProps>();
|
|
1147
|
+
` : ""}
|
|
1148
|
+
|
|
1149
|
+
const title = ref(props.title || '${data.pascalName}');
|
|
1150
|
+
</script>
|
|
1151
|
+
|
|
1152
|
+
<style scoped>
|
|
1153
|
+
.${data.kebabName}-page {
|
|
1154
|
+
padding: 2rem;
|
|
1155
|
+
}
|
|
1156
|
+
</style>
|
|
1157
|
+
`;
|
|
1158
|
+
}
|
|
1159
|
+
const testImport = withTest ? `
|
|
1160
|
+
import { describe, it, expect } from 'vitest';
|
|
1161
|
+
import { ${data.pascalName}Page } from './${data.kebabName}';
|
|
1162
|
+
|
|
1163
|
+
describe('${data.pascalName}Page', () => {
|
|
1164
|
+
it('should render', () => {
|
|
1165
|
+
// Add test here
|
|
1166
|
+
expect(true).toBe(true);
|
|
1167
|
+
});
|
|
1168
|
+
});` : "";
|
|
1169
|
+
return `/**
|
|
1170
|
+
* ${data.pascalName} \u9875\u9762
|
|
1171
|
+
*
|
|
1172
|
+
* @description ${data.description}
|
|
1173
|
+
* @created ${data.date}
|
|
1174
|
+
*/
|
|
1175
|
+
|
|
1176
|
+
import { h, ${tsOnly ? "signal" : "signal"} } from '@lytjs/core';
|
|
1177
|
+
${styleImport}
|
|
1178
|
+
|
|
1179
|
+
${tsOnly ? `export interface ${data.pascalName}PageProps {
|
|
1180
|
+
title?: string;
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
` : ""}export function ${data.pascalName}Page(${tsOnly ? `props: ${data.pascalName}PageProps` : "props"}) {
|
|
1184
|
+
const { title = '${data.pascalName}' } = props;
|
|
1185
|
+
|
|
1186
|
+
return (
|
|
1187
|
+
<div className="${data.kebabName}-page">
|
|
1188
|
+
<h1>{title}</h1>
|
|
1189
|
+
<p>Page content for ${data.pascalName}</p>
|
|
1190
|
+
</div>
|
|
1191
|
+
);
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
export default ${data.pascalName}Page;${testImport}
|
|
1195
|
+
`;
|
|
1196
|
+
},
|
|
1197
|
+
service: (data, _withStyles, _withTest, _template, lang) => {
|
|
1198
|
+
const tsOnly = lang === "ts";
|
|
1199
|
+
return `/**
|
|
1200
|
+
* ${data.pascalName} \u670D\u52A1
|
|
1201
|
+
*
|
|
1202
|
+
* @description ${data.description}
|
|
1203
|
+
* @created ${data.date}
|
|
1204
|
+
*/
|
|
1205
|
+
|
|
1206
|
+
${tsOnly ? `export interface ${data.pascalName}ServiceOptions {
|
|
1207
|
+
baseUrl?: string;
|
|
1208
|
+
timeout?: number;
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
` : ""}${tsOnly ? `export class ${data.pascalName}Service {
|
|
1212
|
+
private baseUrl: string;
|
|
1213
|
+
private timeout: number;
|
|
1214
|
+
` : `export class ${data.pascalName}Service {
|
|
1215
|
+
`}
|
|
1216
|
+
constructor(${tsOnly ? `options: ${data.pascalName}ServiceOptions = {}` : "options = {}"}) {
|
|
1217
|
+
this.baseUrl = options.baseUrl || '/api';
|
|
1218
|
+
this.timeout = options.timeout || 30000;
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
async getAll()${tsOnly ? ": Promise<any[]>" : ""} {
|
|
1222
|
+
const response = await fetch(\`\${this.baseUrl}/${data.kebabName}s\`, {
|
|
1223
|
+
method: 'GET',
|
|
1224
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1225
|
+
signal: AbortSignal.timeout(this.timeout),
|
|
1226
|
+
});
|
|
1227
|
+
return response.json();
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
async getById(id)${tsOnly ? ": Promise<any>" : ""} {
|
|
1231
|
+
const response = await fetch(\`\${this.baseUrl}/${data.kebabName}s/\${id}\`, {
|
|
1232
|
+
method: 'GET',
|
|
1233
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1234
|
+
signal: AbortSignal.timeout(this.timeout),
|
|
1235
|
+
});
|
|
1236
|
+
return response.json();
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
async create(${tsOnly ? "data: any" : "data"})${tsOnly ? ": Promise<any>" : ""} {
|
|
1240
|
+
const response = await fetch(\`\${this.baseUrl}/${data.kebabName}s\`, {
|
|
1241
|
+
method: 'POST',
|
|
1242
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1243
|
+
body: JSON.stringify(data),
|
|
1244
|
+
signal: AbortSignal.timeout(this.timeout),
|
|
1245
|
+
});
|
|
1246
|
+
return response.json();
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
async update(id)${tsOnly ? ": Promise<any>" : ""} {
|
|
1250
|
+
const response = await fetch(\`\${this.baseUrl}/${data.kebabName}s/\${id}\`, {
|
|
1251
|
+
method: 'PUT',
|
|
1252
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1253
|
+
body: JSON.stringify(data),
|
|
1254
|
+
signal: AbortSignal.timeout(this.timeout),
|
|
1255
|
+
});
|
|
1256
|
+
return response.json();
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
async delete(id)${tsOnly ? ": Promise<void>" : ""} {
|
|
1260
|
+
await fetch(\`\${this.baseUrl}/${data.kebabName}s/\${id}\`, {
|
|
1261
|
+
method: 'DELETE',
|
|
1262
|
+
signal: AbortSignal.timeout(this.timeout),
|
|
1263
|
+
});
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
export default ${data.pascalName}Service;
|
|
1268
|
+
`;
|
|
1269
|
+
},
|
|
1270
|
+
hook: (data, _withStyles, _withTest, _template, lang) => {
|
|
1271
|
+
const tsOnly = lang === "ts";
|
|
1272
|
+
return `/**
|
|
1273
|
+
* ${data.pascalName} Hook
|
|
1274
|
+
*
|
|
1275
|
+
* @description ${data.description}
|
|
1276
|
+
* @created ${data.date}
|
|
1277
|
+
*/
|
|
1278
|
+
|
|
1279
|
+
import { signal, effect } from '@lytjs/reactivity';
|
|
1280
|
+
|
|
1281
|
+
${tsOnly ? `export interface ${data.pascalName}Options {
|
|
1282
|
+
immediate?: boolean;
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
export interface ${data.pascalName}Return {
|
|
1286
|
+
data: ReturnType<typeof signal>;
|
|
1287
|
+
loading: ReturnType<typeof signal>;
|
|
1288
|
+
error: ReturnType<typeof signal>;
|
|
1289
|
+
execute: () => Promise<void>;
|
|
1290
|
+
reset: () => void;
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
` : ""}export function use${data.pascalName}(${tsOnly ? `options: ${data.pascalName}Options = {}` : "options = {}"})${tsOnly ? `: ${data.pascalName}Return` : ""} {
|
|
1294
|
+
const { immediate = false } = options;
|
|
1295
|
+
|
|
1296
|
+
const data = signal<any>(null);
|
|
1297
|
+
const loading = signal(false);
|
|
1298
|
+
const error = signal<Error | null>(null);
|
|
1299
|
+
|
|
1300
|
+
async function execute() {
|
|
1301
|
+
loading.value = true;
|
|
1302
|
+
error.value = null;
|
|
1303
|
+
|
|
1304
|
+
try {
|
|
1305
|
+
const result = await new Promise(resolve => setTimeout(() => resolve(null), 100));
|
|
1306
|
+
data.value = result;
|
|
1307
|
+
} catch (e) {
|
|
1308
|
+
error.value = e as Error;
|
|
1309
|
+
} finally {
|
|
1310
|
+
loading.value = false;
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
function reset() {
|
|
1315
|
+
data.value = null;
|
|
1316
|
+
loading.value = false;
|
|
1317
|
+
error.value = null;
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
if (immediate) {
|
|
1321
|
+
execute();
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
return {
|
|
1325
|
+
data,
|
|
1326
|
+
loading,
|
|
1327
|
+
error,
|
|
1328
|
+
execute,
|
|
1329
|
+
reset,
|
|
1330
|
+
};
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
export default use${data.pascalName};
|
|
1334
|
+
`;
|
|
1335
|
+
},
|
|
1336
|
+
store: (data, _withStyles, _withTest, _template, lang) => {
|
|
1337
|
+
const tsOnly = lang === "ts";
|
|
1338
|
+
return `/**
|
|
1339
|
+
* ${data.pascalName} Store
|
|
1340
|
+
*
|
|
1341
|
+
* @description ${data.description}
|
|
1342
|
+
* @created ${data.date}
|
|
1343
|
+
*/
|
|
1344
|
+
|
|
1345
|
+
import { signal, computed } from '@lytjs/reactivity';
|
|
1346
|
+
|
|
1347
|
+
${tsOnly ? `export interface ${data.pascalName}State {
|
|
1348
|
+
items: any[];
|
|
1349
|
+
selectedId: string | null;
|
|
1350
|
+
loading: boolean;
|
|
1351
|
+
error: Error | null;
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
` : ""}export function create${data.pascalName}Store() {
|
|
1355
|
+
const state = signal${tsOnly ? `<${data.pascalName}State>` : ""}({
|
|
1356
|
+
items: [],
|
|
1357
|
+
selectedId: null,
|
|
1358
|
+
loading: false,
|
|
1359
|
+
error: null,
|
|
1360
|
+
});
|
|
1361
|
+
|
|
1362
|
+
const selectedItem = computed(() => {
|
|
1363
|
+
const currentState = state.value;
|
|
1364
|
+
return currentState.items.find(item => item.id === currentState.selectedId);
|
|
1365
|
+
});
|
|
1366
|
+
|
|
1367
|
+
const itemCount = computed(() => state.value.items.length);
|
|
1368
|
+
|
|
1369
|
+
function setItems(items) {
|
|
1370
|
+
state.value = { ...state.value, items };
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
function selectItem(id) {
|
|
1374
|
+
state.value = { ...state.value, selectedId: id };
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
function addItem(item) {
|
|
1378
|
+
state.value = {
|
|
1379
|
+
...state.value,
|
|
1380
|
+
items: [...state.value.items, item],
|
|
1381
|
+
};
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1384
|
+
function updateItem(id, updates) {
|
|
1385
|
+
state.value = {
|
|
1386
|
+
...state.value,
|
|
1387
|
+
items: state.value.items.map(item =>
|
|
1388
|
+
item.id === id ? { ...item, ...updates } : item
|
|
1389
|
+
),
|
|
1390
|
+
};
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
function removeItem(id) {
|
|
1394
|
+
state.value = {
|
|
1395
|
+
...state.value,
|
|
1396
|
+
items: state.value.items.filter(item => item.id !== id),
|
|
1397
|
+
selectedId: state.value.selectedId === id ? null : state.value.selectedId,
|
|
1398
|
+
};
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
function setLoading(loading) {
|
|
1402
|
+
state.value = { ...state.value, loading };
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
function setError(error) {
|
|
1406
|
+
state.value = { ...state.value, error };
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
function reset() {
|
|
1410
|
+
state.value = {
|
|
1411
|
+
items: [],
|
|
1412
|
+
selectedId: null,
|
|
1413
|
+
loading: false,
|
|
1414
|
+
error: null,
|
|
1415
|
+
};
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
return {
|
|
1419
|
+
state,
|
|
1420
|
+
selectedItem,
|
|
1421
|
+
itemCount,
|
|
1422
|
+
setItems,
|
|
1423
|
+
selectItem,
|
|
1424
|
+
addItem,
|
|
1425
|
+
updateItem,
|
|
1426
|
+
removeItem,
|
|
1427
|
+
setLoading,
|
|
1428
|
+
setError,
|
|
1429
|
+
reset,
|
|
1430
|
+
};
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
${tsOnly ? `export type ${data.pascalName}Store = ReturnType<typeof create${data.pascalName}Store>;
|
|
1434
|
+
` : ""}export default create${data.pascalName}Store;
|
|
1435
|
+
`;
|
|
1436
|
+
},
|
|
1437
|
+
layout: (data, withStyles, _withTest, _template, lang) => {
|
|
1438
|
+
const tsOnly = lang === "ts";
|
|
1439
|
+
const styleImport = withStyles ? `
|
|
1440
|
+
import './${data.kebabName}.styles.css';` : "";
|
|
1441
|
+
return `/**
|
|
1442
|
+
* ${data.pascalName} \u5E03\u5C40
|
|
1443
|
+
*
|
|
1444
|
+
* @description ${data.description}
|
|
1445
|
+
* @created ${data.date}
|
|
1446
|
+
*/
|
|
1447
|
+
|
|
1448
|
+
import { h, defineComponent } from '@lytjs/core';${styleImport}
|
|
1449
|
+
|
|
1450
|
+
${tsOnly ? `export interface ${data.pascalName}LayoutProps {
|
|
1451
|
+
children?: any;
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
` : ""}export const ${data.pascalName}Layout = defineComponent({
|
|
1455
|
+
name: '${data.pascalName}Layout',
|
|
1456
|
+
setup(props) {
|
|
1457
|
+
return () => (
|
|
1458
|
+
<div className="${data.kebabName}-layout">
|
|
1459
|
+
<header className="${data.kebabName}-header">
|
|
1460
|
+
<slot name="header">
|
|
1461
|
+
<h1>${data.pascalName}</h1>
|
|
1462
|
+
</slot>
|
|
1463
|
+
</header>
|
|
1464
|
+
<main className="${data.kebabName}-main">
|
|
1465
|
+
<slot />
|
|
1466
|
+
</main>
|
|
1467
|
+
<footer className="${data.kebabName}-footer">
|
|
1468
|
+
<slot name="footer" />
|
|
1469
|
+
</footer>
|
|
1470
|
+
</div>
|
|
1471
|
+
);
|
|
1472
|
+
},
|
|
1473
|
+
});
|
|
1474
|
+
|
|
1475
|
+
export default ${data.pascalName}Layout;
|
|
1476
|
+
`;
|
|
1477
|
+
},
|
|
1478
|
+
middleware: (data, _withStyles, _withTest, _template, lang) => {
|
|
1479
|
+
const tsOnly = lang === "ts";
|
|
1480
|
+
return `/**
|
|
1481
|
+
* ${data.pascalName} \u4E2D\u95F4\u4EF6
|
|
1482
|
+
*
|
|
1483
|
+
* @description ${data.description}
|
|
1484
|
+
* @created ${data.date}
|
|
1485
|
+
*/
|
|
1486
|
+
|
|
1487
|
+
${tsOnly ? `import type { Request, Response, NextFunction } from 'express';
|
|
1488
|
+
` : ""}
|
|
1489
|
+
export function ${data.camelName}Middleware(${tsOnly ? `req: Request, res: Response, next: NextFunction` : "req, res, next"}) {
|
|
1490
|
+
try {
|
|
1491
|
+
console.log('[${data.pascalName}] Middleware executed');
|
|
1492
|
+
next();
|
|
1493
|
+
} catch (error) {
|
|
1494
|
+
next(error);
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1498
|
+
export default ${data.camelName}Middleware;
|
|
1499
|
+
`;
|
|
1500
|
+
}
|
|
1501
|
+
};
|
|
1502
|
+
function toPascalCase2(name) {
|
|
1503
|
+
return name.split(/[-_]/).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
1504
|
+
}
|
|
1505
|
+
function toCamelCase2(name) {
|
|
1506
|
+
const pascal = toPascalCase2(name);
|
|
1507
|
+
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
1508
|
+
}
|
|
1509
|
+
function toKebabCase(name) {
|
|
1510
|
+
return name.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[\s_]+/g, "-").toLowerCase();
|
|
1511
|
+
}
|
|
1512
|
+
async function generate(options) {
|
|
1513
|
+
const {
|
|
1514
|
+
type,
|
|
1515
|
+
name,
|
|
1516
|
+
path: basePath = "./src",
|
|
1517
|
+
withStyles = false,
|
|
1518
|
+
withTest = false,
|
|
1519
|
+
description = "",
|
|
1520
|
+
template = "default",
|
|
1521
|
+
language = "ts"
|
|
1522
|
+
} = options;
|
|
1523
|
+
const templateData = {
|
|
1524
|
+
name,
|
|
1525
|
+
pascalName: toPascalCase2(name),
|
|
1526
|
+
kebabName: toKebabCase(name),
|
|
1527
|
+
camelName: toCamelCase2(name),
|
|
1528
|
+
date: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
|
|
1529
|
+
description: description || `${toPascalCase2(name)} ${type}`
|
|
1530
|
+
};
|
|
1531
|
+
const typeDirs = {
|
|
1532
|
+
component: "components",
|
|
1533
|
+
page: "pages",
|
|
1534
|
+
service: "services",
|
|
1535
|
+
hook: "hooks",
|
|
1536
|
+
store: "stores",
|
|
1537
|
+
layout: "layouts",
|
|
1538
|
+
middleware: "middleware"
|
|
1539
|
+
};
|
|
1540
|
+
const targetDir = path__namespace.join(
|
|
1541
|
+
process.cwd(),
|
|
1542
|
+
basePath,
|
|
1543
|
+
typeDirs[type] || "components"
|
|
1544
|
+
);
|
|
1545
|
+
await ensureDir(targetDir);
|
|
1546
|
+
const templateFn = TEMPLATES3[type];
|
|
1547
|
+
if (!templateFn) {
|
|
1548
|
+
logger.error(`Unknown type: ${type}`);
|
|
1549
|
+
logger.info("Available types: component, page, service, hook, store, layout, middleware");
|
|
1550
|
+
process.exit(1);
|
|
1551
|
+
}
|
|
1552
|
+
const extension = template === "sfc" ? "lyt" : language;
|
|
1553
|
+
const filename = `${templateData.kebabName}${type === "page" ? ".page" : ""}.${extension}`;
|
|
1554
|
+
const filePath = path__namespace.join(targetDir, filename);
|
|
1555
|
+
const content = templateFn(templateData, withStyles, withTest, template, language);
|
|
1556
|
+
await writeFile(filePath, content);
|
|
1557
|
+
logger.success(`Generated ${type}: ${filePath}`);
|
|
1558
|
+
if (withStyles && template !== "sfc") {
|
|
1559
|
+
const styleContent = `/**
|
|
1560
|
+
* ${templateData.pascalName} Styles
|
|
1561
|
+
*/
|
|
1562
|
+
|
|
1563
|
+
.${templateData.kebabName} {
|
|
1564
|
+
/* Component styles */
|
|
1565
|
+
}
|
|
1566
|
+
`;
|
|
1567
|
+
const stylePath = path__namespace.join(targetDir, `${templateData.kebabName}.styles.css`);
|
|
1568
|
+
await writeFile(stylePath, styleContent);
|
|
1569
|
+
logger.success(`Generated styles: ${stylePath}`);
|
|
1570
|
+
}
|
|
1571
|
+
if (withTest && template !== "sfc") {
|
|
1572
|
+
logger.info("Test file included in generated component");
|
|
1573
|
+
}
|
|
1574
|
+
logger.info("\nNext steps:");
|
|
1575
|
+
logger.info(` cd ${targetDir}`);
|
|
1576
|
+
logger.info(` Import your ${type}: import { ${template === "sfc" ? "default" : templateData.pascalName} } from './${templateData.kebabName}'`);
|
|
1577
|
+
logger.info("\nAvailable options:");
|
|
1578
|
+
logger.info(" --template=sfc : Single File Component (.lyt)");
|
|
1579
|
+
logger.info(" --template=functional : Functional component");
|
|
1580
|
+
logger.info(" --language=js : JavaScript output");
|
|
1581
|
+
}
|
|
769
1582
|
var PLUGIN_TEMPLATES = {
|
|
770
1583
|
default: "Default plugin template with TypeScript",
|
|
771
1584
|
minimal: "Minimal plugin without extra dependencies",
|
|
@@ -857,8 +1670,6 @@ const optionsSchema: ConfigSchema<${pluginName.replace(/-/g, "")}Options> = {
|
|
|
857
1670
|
additionalProperties: false,
|
|
858
1671
|
};
|
|
859
1672
|
|
|
860
|
-
${pluginName.replace(/-/g, "")}Options\`;
|
|
861
|
-
|
|
862
1673
|
export interface ${pluginName.replace(/-/g, "")}Options {
|
|
863
1674
|
debug?: boolean;
|
|
864
1675
|
option1?: string;
|
|
@@ -1176,8 +1987,10 @@ async function runCli(rawArgs = process.argv.slice(2)) {
|
|
|
1176
1987
|
});
|
|
1177
1988
|
break;
|
|
1178
1989
|
case "add":
|
|
1179
|
-
|
|
1180
|
-
|
|
1990
|
+
const addTypes = ["component", "page", "store", "directive", "composable", "util", "middleware", "hook"];
|
|
1991
|
+
if (!args[0] || !addTypes.includes(args[0])) {
|
|
1992
|
+
logger.error("Usage: lyt add <type> <name>");
|
|
1993
|
+
logger.info("Types: component, page, store, directive, composable, util, middleware, hook");
|
|
1181
1994
|
logger.info("Example: lyt add component Button");
|
|
1182
1995
|
process.exit(1);
|
|
1183
1996
|
}
|
|
@@ -1185,6 +1998,24 @@ async function runCli(rawArgs = process.argv.slice(2)) {
|
|
|
1185
1998
|
force: options.force
|
|
1186
1999
|
});
|
|
1187
2000
|
break;
|
|
2001
|
+
case "generate":
|
|
2002
|
+
case "g":
|
|
2003
|
+
const genTypes = ["component", "page", "service", "hook", "store"];
|
|
2004
|
+
if (!args[0] || !genTypes.includes(args[0])) {
|
|
2005
|
+
logger.error("Usage: lyt generate <type> <name>");
|
|
2006
|
+
logger.info("Types: component, page, service, hook, store");
|
|
2007
|
+
logger.info("Example: lyt generate component Button");
|
|
2008
|
+
process.exit(1);
|
|
2009
|
+
}
|
|
2010
|
+
await generate({
|
|
2011
|
+
type: args[0],
|
|
2012
|
+
name: args[1] || "Unnamed",
|
|
2013
|
+
path: options.path,
|
|
2014
|
+
withStyles: options.styles,
|
|
2015
|
+
withTest: options.test,
|
|
2016
|
+
withStorybook: options.storybook
|
|
2017
|
+
});
|
|
2018
|
+
break;
|
|
1188
2019
|
case "plugin":
|
|
1189
2020
|
if (!args[0]) {
|
|
1190
2021
|
logger.error("Usage: lyt plugin <create|build|validate|templates>");
|
|
@@ -1280,10 +2111,11 @@ ${logger.bold("Commands:")}
|
|
|
1280
2111
|
dev Start development server
|
|
1281
2112
|
build Build for production
|
|
1282
2113
|
test Run tests
|
|
1283
|
-
add <type> <name> Generate a component, page,
|
|
2114
|
+
add <type> <name> Generate a component, page, store, directive, composable, etc.
|
|
2115
|
+
generate, g Advanced code generation (component, page, service, hook, store)
|
|
1284
2116
|
plugin <subcmd> Plugin development commands
|
|
1285
2117
|
help Show this help message
|
|
1286
|
-
|
|
2118
|
+
|
|
1287
2119
|
${logger.bold("Options:")}
|
|
1288
2120
|
--version, -v Show version number
|
|
1289
2121
|
--help Show help
|
|
@@ -1307,6 +2139,12 @@ ${logger.bold("Test Options:")}
|
|
|
1307
2139
|
--coverage Generate coverage report
|
|
1308
2140
|
--grep <pattern> Filter tests by pattern
|
|
1309
2141
|
|
|
2142
|
+
${logger.bold("Generate Options:")}
|
|
2143
|
+
--path <dir> Output directory (default: ./src)
|
|
2144
|
+
--styles Generate CSS styles file
|
|
2145
|
+
--test Generate test file
|
|
2146
|
+
--storybook Generate Storybook story file
|
|
2147
|
+
|
|
1310
2148
|
${logger.bold("Plugin Options:")}
|
|
1311
2149
|
--template <name> Use a specific plugin template (default, minimal, withConfig)
|
|
1312
2150
|
--force Overwrite existing directory
|
|
@@ -1327,6 +2165,16 @@ ${logger.bold("Examples:")}
|
|
|
1327
2165
|
lyt add component Button
|
|
1328
2166
|
lyt add page About
|
|
1329
2167
|
lyt add store user
|
|
2168
|
+
lyt directive click-outside
|
|
2169
|
+
lyt add composable fetch-data
|
|
2170
|
+
lyt add util format
|
|
2171
|
+
lyt add hook window-size
|
|
2172
|
+
lyt generate component Button --styles --test
|
|
2173
|
+
lyt generate page Dashboard --path ./src/pages
|
|
2174
|
+
lyt generate service User --path ./src/services
|
|
2175
|
+
lyt generate hook useCounter
|
|
2176
|
+
lyt generate store Auth --path ./src/stores
|
|
2177
|
+
lyt g page Login
|
|
1330
2178
|
lyt plugin create my-plugin
|
|
1331
2179
|
lyt plugin create my-plugin --template withConfig
|
|
1332
2180
|
lyt plugin build
|
|
@@ -1348,6 +2196,7 @@ exports.detectPackageManager = detectPackageManager;
|
|
|
1348
2196
|
exports.dev = dev;
|
|
1349
2197
|
exports.ensureDir = ensureDir;
|
|
1350
2198
|
exports.exists = exists;
|
|
2199
|
+
exports.generate = generate;
|
|
1351
2200
|
exports.getAddCommand = getAddCommand;
|
|
1352
2201
|
exports.getInstallCommand = getInstallCommand;
|
|
1353
2202
|
exports.getRunCommand = getRunCommand;
|