@lytjs/cli 6.4.0 → 6.6.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 +96 -11
- package/dist/create.cjs.map +1 -1
- package/dist/create.mjs +96 -11
- package/dist/create.mjs.map +1 -1
- package/dist/index.cjs +968 -76
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +951 -79
- package/dist/index.mjs.map +1 -1
- package/dist/lyt.cjs +968 -76
- package/dist/lyt.cjs.map +1 -1
- package/dist/lyt.mjs +951 -79
- package/dist/lyt.mjs.map +1 -1
- package/lyt-cli.js +1 -0
- package/package.json +55 -55
- package/dist/create.d.mts +0 -2
- package/dist/create.d.ts +0 -2
- package/dist/index.d.mts +0 -188
- package/dist/index.d.ts +0 -188
- package/dist/lyt.d.mts +0 -1
- package/dist/lyt.d.ts +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { existsSync, readFileSync, mkdirSync, writeFileSync, readdirSync } from 'fs';
|
|
2
|
+
import { existsSync, readFileSync, mkdirSync, writeFileSync, readdirSync as readdirSync$1 } from 'fs';
|
|
3
|
+
import * as path from 'path';
|
|
3
4
|
import { join, resolve, dirname } from 'path';
|
|
4
5
|
import { execSync, spawn } from 'child_process';
|
|
5
6
|
|
|
@@ -60,12 +61,12 @@ function writeFile(filePath, content) {
|
|
|
60
61
|
function readFile(filePath) {
|
|
61
62
|
return readFileSync(filePath, "utf-8");
|
|
62
63
|
}
|
|
63
|
-
function exists(
|
|
64
|
-
return existsSync(
|
|
64
|
+
function exists(path2) {
|
|
65
|
+
return existsSync(path2);
|
|
65
66
|
}
|
|
66
67
|
function isEmptyDir(dir) {
|
|
67
68
|
if (!existsSync(dir)) return true;
|
|
68
|
-
const files = readdirSync(dir);
|
|
69
|
+
const files = readdirSync$1(dir);
|
|
69
70
|
return files.length === 0;
|
|
70
71
|
}
|
|
71
72
|
function detectPackageManager(cwd = process.cwd()) {
|
|
@@ -168,7 +169,7 @@ function generateProjectFiles(targetDir, projectName, template) {
|
|
|
168
169
|
},
|
|
169
170
|
devDependencies: {
|
|
170
171
|
"@lytjs/plugin-vite": "^6.0.0",
|
|
171
|
-
|
|
172
|
+
vite: "^5.0.0"
|
|
172
173
|
}
|
|
173
174
|
};
|
|
174
175
|
if (!isMinimal) {
|
|
@@ -441,12 +442,19 @@ export const useCounterStore = defineStore('counter', () => {
|
|
|
441
442
|
writeFile(join(targetDir, "src", "stores", "counter.ts"), counterStore);
|
|
442
443
|
}
|
|
443
444
|
if (isSsr) {
|
|
444
|
-
const entryServer = `import { createSSRApp } from '@lytjs/core';
|
|
445
|
+
const entryServer = `import { createSSRApp, h } from '@lytjs/core';
|
|
446
|
+
import { renderToString } from '@lytjs/ssr';
|
|
445
447
|
import App from './App.lyt';
|
|
446
448
|
|
|
447
449
|
export async function render(url: string) {
|
|
448
|
-
const app = createSSRApp(
|
|
449
|
-
|
|
450
|
+
const app = createSSRApp({
|
|
451
|
+
render() {
|
|
452
|
+
return h(App);
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
const html = await renderToString(app);
|
|
457
|
+
return html;
|
|
450
458
|
}
|
|
451
459
|
`;
|
|
452
460
|
writeFile(join(targetDir, "src/entry-server.ts"), entryServer);
|
|
@@ -460,36 +468,114 @@ app.mount('#app');
|
|
|
460
468
|
const serverTs = `/**
|
|
461
469
|
* LytJS SSR Server
|
|
462
470
|
*
|
|
463
|
-
*
|
|
471
|
+
* Complete SSR server with Vite dev server and production build support.
|
|
472
|
+
* Supports streaming SSR, route prefetching, and static file serving.
|
|
464
473
|
*/
|
|
465
474
|
|
|
466
475
|
import fs from 'fs';
|
|
467
476
|
import path from 'path';
|
|
468
477
|
import { fileURLToPath } from 'url';
|
|
478
|
+
import http from 'http';
|
|
469
479
|
|
|
470
480
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
471
481
|
const isProduction = process.env.NODE_ENV === 'production';
|
|
482
|
+
const DIST_DIR = path.join(__dirname, 'dist');
|
|
483
|
+
const PORT = parseInt(process.env.PORT || '3000', 10);
|
|
484
|
+
|
|
485
|
+
interface RenderOptions {
|
|
486
|
+
url: string;
|
|
487
|
+
template: string;
|
|
488
|
+
manifest?: Record<string, string[]>;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
async function renderPage({ url, template, manifest }: RenderOptions): Promise<string> {
|
|
492
|
+
let app: any;
|
|
493
|
+
let vite: any;
|
|
494
|
+
|
|
495
|
+
if (!isProduction) {
|
|
496
|
+
const { createServer: createViteServer } = await import('vite');
|
|
497
|
+
vite = await createViteServer({
|
|
498
|
+
server: { middlewareMode: true },
|
|
499
|
+
appType: 'custom',
|
|
500
|
+
});
|
|
501
|
+
app = (await vite.ssrLoadModule(path.join(__dirname, 'src/entry-server.ts'))).default;
|
|
502
|
+
} else {
|
|
503
|
+
app = (await import(path.join(DIST_DIR, 'server/entry-server.js'))).default;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
const html = await app.render(url);
|
|
507
|
+
return template.replace('<!--app-html-->', html);
|
|
508
|
+
}
|
|
472
509
|
|
|
473
510
|
async function createServer() {
|
|
474
|
-
let resolve: any;
|
|
475
511
|
let vite: any;
|
|
476
512
|
|
|
513
|
+
// Load index.html template
|
|
514
|
+
let template: string;
|
|
515
|
+
|
|
477
516
|
if (!isProduction) {
|
|
478
517
|
const { createServer: createViteServer } = await import('vite');
|
|
479
518
|
vite = await createViteServer({
|
|
480
519
|
server: { middlewareMode: true },
|
|
481
520
|
appType: 'custom',
|
|
482
521
|
});
|
|
483
|
-
|
|
522
|
+
template = fs.readFileSync(path.join(__dirname, 'index.html'), 'utf-8');
|
|
484
523
|
} else {
|
|
485
|
-
|
|
524
|
+
template = fs.readFileSync(path.join(DIST_DIR, 'client/index.html'), 'utf-8');
|
|
486
525
|
}
|
|
487
526
|
|
|
488
|
-
|
|
489
|
-
|
|
527
|
+
const server = http.createServer(async (req, res) => {
|
|
528
|
+
const url = req.url || '/';
|
|
529
|
+
|
|
530
|
+
try {
|
|
531
|
+
if (!isProduction && url.startsWith('/@')) {
|
|
532
|
+
// Vite dev server requests
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// Static assets
|
|
537
|
+
if (url.startsWith('/assets/') || url.endsWith('.js') || url.endsWith('.css')) {
|
|
538
|
+
const filePath = isProduction
|
|
539
|
+
? path.join(DIST_DIR, 'client', url)
|
|
540
|
+
: path.join(__dirname, url);
|
|
541
|
+
|
|
542
|
+
if (fs.existsSync(filePath)) {
|
|
543
|
+
const ext = path.extname(filePath);
|
|
544
|
+
const contentType = ext === '.css' ? 'text/css' : 'application/javascript';
|
|
545
|
+
res.writeHead(200, { 'Content-Type': contentType });
|
|
546
|
+
res.end(fs.readFileSync(filePath));
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
// SSR rendering
|
|
552
|
+
const html = await renderPage({
|
|
553
|
+
url,
|
|
554
|
+
template,
|
|
555
|
+
manifest: isProduction
|
|
556
|
+
? JSON.parse(fs.readFileSync(path.join(DIST_DIR, 'client/ssr-manifest.json'), 'utf-8'))
|
|
557
|
+
: undefined
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
561
|
+
res.end(html);
|
|
562
|
+
} catch (err: any) {
|
|
563
|
+
if (!isProduction && vite) {
|
|
564
|
+
vite.ssrFixStacktrace(err);
|
|
565
|
+
}
|
|
566
|
+
console.error('SSR Error:', err);
|
|
567
|
+
res.writeHead(500, { 'Content-Type': 'text/plain' });
|
|
568
|
+
res.end('Internal Server Error');
|
|
569
|
+
}
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
server.listen(PORT, () => {
|
|
573
|
+
console.log(\`LytJS SSR server running at http://localhost:\${PORT}\`);
|
|
574
|
+
console.log(\`Mode: \${isProduction ? 'Production' : 'Development'}\`);
|
|
575
|
+
});
|
|
490
576
|
}
|
|
491
577
|
|
|
492
|
-
createServer();
|
|
578
|
+
createServer().catch(console.error);
|
|
493
579
|
`;
|
|
494
580
|
writeFile(join(targetDir, "server.ts"), serverTs);
|
|
495
581
|
}
|
|
@@ -639,9 +725,10 @@ async function test(options = {}) {
|
|
|
639
725
|
var TEMPLATES2 = {
|
|
640
726
|
component(name, basePath) {
|
|
641
727
|
const filePath = join(basePath, `${name}.lyt`);
|
|
642
|
-
return [
|
|
643
|
-
|
|
644
|
-
|
|
728
|
+
return [
|
|
729
|
+
{
|
|
730
|
+
filePath,
|
|
731
|
+
content: `<template>
|
|
645
732
|
<div class="${name}">
|
|
646
733
|
<slot />
|
|
647
734
|
</div>
|
|
@@ -663,15 +750,18 @@ defineEmits<{
|
|
|
663
750
|
}
|
|
664
751
|
</style>
|
|
665
752
|
`
|
|
666
|
-
|
|
753
|
+
}
|
|
754
|
+
];
|
|
667
755
|
},
|
|
668
756
|
page(name, basePath) {
|
|
757
|
+
const pascalName = toPascalCase(name);
|
|
669
758
|
const filePath = join(basePath, `${name}.lyt`);
|
|
670
|
-
return [
|
|
671
|
-
|
|
672
|
-
|
|
759
|
+
return [
|
|
760
|
+
{
|
|
761
|
+
filePath,
|
|
762
|
+
content: `<template>
|
|
673
763
|
<div class="page-${name}">
|
|
674
|
-
<h1>${
|
|
764
|
+
<h1>${pascalName}</h1>
|
|
675
765
|
</div>
|
|
676
766
|
</template>
|
|
677
767
|
|
|
@@ -685,13 +775,15 @@ defineEmits<{
|
|
|
685
775
|
}
|
|
686
776
|
</style>
|
|
687
777
|
`
|
|
688
|
-
|
|
778
|
+
}
|
|
779
|
+
];
|
|
689
780
|
},
|
|
690
781
|
store(name, basePath) {
|
|
691
782
|
const filePath = join(basePath, `${name}.ts`);
|
|
692
|
-
return [
|
|
693
|
-
|
|
694
|
-
|
|
783
|
+
return [
|
|
784
|
+
{
|
|
785
|
+
filePath,
|
|
786
|
+
content: `import { defineStore } from '@lytjs/store';
|
|
695
787
|
import { signal, computed } from '@lytjs/reactivity';
|
|
696
788
|
|
|
697
789
|
export const use${toPascalCase(name)}Store = defineStore('${name}', () => {
|
|
@@ -723,12 +815,178 @@ export const use${toPascalCase(name)}Store = defineStore('${name}', () => {
|
|
|
723
815
|
};
|
|
724
816
|
});
|
|
725
817
|
`
|
|
726
|
-
|
|
818
|
+
}
|
|
819
|
+
];
|
|
820
|
+
},
|
|
821
|
+
directive(name, basePath) {
|
|
822
|
+
const filePath = join(basePath, `${name}.ts`);
|
|
823
|
+
const camelCaseName = toCamelCase(name);
|
|
824
|
+
return [
|
|
825
|
+
{
|
|
826
|
+
filePath,
|
|
827
|
+
content: `import type { Directive } from '@lytjs/core';
|
|
828
|
+
|
|
829
|
+
/**
|
|
830
|
+
* ${toPascalCase(name)} Directive
|
|
831
|
+
*
|
|
832
|
+
* @example
|
|
833
|
+
* \`\`\`vue
|
|
834
|
+
* <div v-${camelCaseName} />
|
|
835
|
+
* \`\`\`
|
|
836
|
+
*/
|
|
837
|
+
export const v${toPascalCase(name)}: Directive = {
|
|
838
|
+
mounted(el, binding) {
|
|
839
|
+
// Directive mounted
|
|
840
|
+
},
|
|
841
|
+
|
|
842
|
+
updated(el, binding) {
|
|
843
|
+
// Directive updated
|
|
844
|
+
},
|
|
845
|
+
|
|
846
|
+
unmounted(el) {
|
|
847
|
+
// Directive unmounted
|
|
848
|
+
},
|
|
849
|
+
};
|
|
850
|
+
`
|
|
851
|
+
}
|
|
852
|
+
];
|
|
853
|
+
},
|
|
854
|
+
composable(name, basePath) {
|
|
855
|
+
const filePath = join(basePath, `use${toPascalCase(name)}.ts`);
|
|
856
|
+
return [
|
|
857
|
+
{
|
|
858
|
+
filePath,
|
|
859
|
+
content: `import { signal, computed } from '@lytjs/reactivity';
|
|
860
|
+
|
|
861
|
+
/**
|
|
862
|
+
* ${toPascalCase(name)} Composable
|
|
863
|
+
*
|
|
864
|
+
* @example
|
|
865
|
+
* \`\`\`typescript
|
|
866
|
+
* const { state, actions } = use${toPascalCase(name)}();
|
|
867
|
+
* \`\`\`
|
|
868
|
+
*/
|
|
869
|
+
export function use${toPascalCase(name)}() {
|
|
870
|
+
// State
|
|
871
|
+
const isLoading = signal(false);
|
|
872
|
+
const error = signal<Error | null>(null);
|
|
873
|
+
const data = signal<any>(null);
|
|
874
|
+
|
|
875
|
+
// Computed
|
|
876
|
+
const hasData = computed(() => data.value !== null);
|
|
877
|
+
|
|
878
|
+
// Actions
|
|
879
|
+
async function fetch() {
|
|
880
|
+
isLoading.value = true;
|
|
881
|
+
error.value = null;
|
|
882
|
+
try {
|
|
883
|
+
// TODO: Fetch logic here
|
|
884
|
+
// data.value = await someApi();
|
|
885
|
+
} catch (e) {
|
|
886
|
+
error.value = e as Error;
|
|
887
|
+
} finally {
|
|
888
|
+
isLoading.value = false;
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
function reset() {
|
|
893
|
+
isLoading.value = false;
|
|
894
|
+
error.value = null;
|
|
895
|
+
data.value = null;
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
return {
|
|
899
|
+
isLoading,
|
|
900
|
+
error,
|
|
901
|
+
data,
|
|
902
|
+
hasData,
|
|
903
|
+
fetch,
|
|
904
|
+
reset,
|
|
905
|
+
};
|
|
906
|
+
}
|
|
907
|
+
`
|
|
908
|
+
}
|
|
909
|
+
];
|
|
910
|
+
},
|
|
911
|
+
hook(name, basePath) {
|
|
912
|
+
const filePath = join(basePath, `use${toPascalCase(name)}.ts`);
|
|
913
|
+
return [
|
|
914
|
+
{
|
|
915
|
+
filePath,
|
|
916
|
+
content: `import { signal, onMounted, onUnmounted } from '@lytjs/core';
|
|
917
|
+
|
|
918
|
+
/**
|
|
919
|
+
* ${toPascalCase(name)} Hook
|
|
920
|
+
*/
|
|
921
|
+
export function use${toPascalCase(name)}() {
|
|
922
|
+
const state = signal(null);
|
|
923
|
+
|
|
924
|
+
onMounted(() => {
|
|
925
|
+
// Setup code on mount
|
|
926
|
+
});
|
|
927
|
+
|
|
928
|
+
onUnmounted(() => {
|
|
929
|
+
// Cleanup on unmount
|
|
930
|
+
});
|
|
931
|
+
|
|
932
|
+
return {
|
|
933
|
+
state,
|
|
934
|
+
};
|
|
935
|
+
}
|
|
936
|
+
`
|
|
937
|
+
}
|
|
938
|
+
];
|
|
939
|
+
},
|
|
940
|
+
util(name, basePath) {
|
|
941
|
+
const filePath = join(basePath, `${name}.ts`);
|
|
942
|
+
return [
|
|
943
|
+
{
|
|
944
|
+
filePath,
|
|
945
|
+
content: `/**
|
|
946
|
+
* ${toPascalCase(name)} Utility Functions
|
|
947
|
+
*/
|
|
948
|
+
|
|
949
|
+
/**
|
|
950
|
+
* ${toPascalCase(name)} function
|
|
951
|
+
*
|
|
952
|
+
* @param input - The input value
|
|
953
|
+
* @returns The processed result
|
|
954
|
+
*/
|
|
955
|
+
export function ${toCamelCase(name)}(input: any) {
|
|
956
|
+
// TODO: Implement function
|
|
957
|
+
return input;
|
|
958
|
+
}
|
|
959
|
+
`
|
|
960
|
+
}
|
|
961
|
+
];
|
|
962
|
+
},
|
|
963
|
+
middleware(name, basePath) {
|
|
964
|
+
const filePath = join(basePath, `${name}.ts`);
|
|
965
|
+
return [
|
|
966
|
+
{
|
|
967
|
+
filePath,
|
|
968
|
+
content: `import type { NavigationGuard } from '@lytjs/router';
|
|
969
|
+
|
|
970
|
+
/**
|
|
971
|
+
* ${toPascalCase(name)} Middleware
|
|
972
|
+
*/
|
|
973
|
+
export const ${toCamelCase(name)}Middleware: NavigationGuard = (to, from, next) => {
|
|
974
|
+
// Middleware logic
|
|
975
|
+
console.log('Middleware:', to.path);
|
|
976
|
+
next();
|
|
977
|
+
};
|
|
978
|
+
`
|
|
979
|
+
}
|
|
980
|
+
];
|
|
727
981
|
}
|
|
728
982
|
};
|
|
729
983
|
function toPascalCase(str) {
|
|
730
984
|
return str.split(/[-_]/).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
731
985
|
}
|
|
986
|
+
function toCamelCase(str) {
|
|
987
|
+
const pascalCase = toPascalCase(str);
|
|
988
|
+
return pascalCase.charAt(0).toLowerCase() + pascalCase.slice(1);
|
|
989
|
+
}
|
|
732
990
|
function resolveTargetDir(type) {
|
|
733
991
|
const cwd = process.cwd();
|
|
734
992
|
switch (type) {
|
|
@@ -738,6 +996,16 @@ function resolveTargetDir(type) {
|
|
|
738
996
|
return join(cwd, "src", "pages");
|
|
739
997
|
case "store":
|
|
740
998
|
return join(cwd, "src", "stores");
|
|
999
|
+
case "directive":
|
|
1000
|
+
return join(cwd, "src", "directives");
|
|
1001
|
+
case "composable":
|
|
1002
|
+
return join(cwd, "src", "composables");
|
|
1003
|
+
case "util":
|
|
1004
|
+
return join(cwd, "src", "utils");
|
|
1005
|
+
case "middleware":
|
|
1006
|
+
return join(cwd, "src", "middleware");
|
|
1007
|
+
case "hook":
|
|
1008
|
+
return join(cwd, "src", "hooks");
|
|
741
1009
|
}
|
|
742
1010
|
}
|
|
743
1011
|
async function add(type, name, options = {}) {
|
|
@@ -764,6 +1032,546 @@ async function add(type, name, options = {}) {
|
|
|
764
1032
|
logger.success(`Created ${type}: ${file.filePath}`);
|
|
765
1033
|
}
|
|
766
1034
|
}
|
|
1035
|
+
var TEMPLATES3 = {
|
|
1036
|
+
component: (data, withStyles, withTest, template, lang) => {
|
|
1037
|
+
const styleImport = withStyles ? `
|
|
1038
|
+
import './${data.kebabName}.styles.css';` : "";
|
|
1039
|
+
const tsOnly = lang === "ts";
|
|
1040
|
+
if (template === "sfc") {
|
|
1041
|
+
return `<template>
|
|
1042
|
+
<div class="${data.kebabName}">
|
|
1043
|
+
<slot>
|
|
1044
|
+
${data.pascalName} Component
|
|
1045
|
+
</slot>
|
|
1046
|
+
</div>
|
|
1047
|
+
</template>
|
|
1048
|
+
|
|
1049
|
+
<script setup${tsOnly ? ' lang="ts"' : ""}>
|
|
1050
|
+
${tsOnly ? `import { ref } from '@lytjs/reactivity';
|
|
1051
|
+
` : ""}
|
|
1052
|
+
${tsOnly ? `
|
|
1053
|
+
export interface ${data.pascalName}Props {
|
|
1054
|
+
className?: string;
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
const props = defineProps<${data.pascalName}Props>();
|
|
1058
|
+
` : ""}
|
|
1059
|
+
|
|
1060
|
+
const title = ref('${data.pascalName}');
|
|
1061
|
+
</script>
|
|
1062
|
+
|
|
1063
|
+
<style scoped>
|
|
1064
|
+
.${data.kebabName} {
|
|
1065
|
+
/* Component styles */
|
|
1066
|
+
}
|
|
1067
|
+
</style>
|
|
1068
|
+
`;
|
|
1069
|
+
}
|
|
1070
|
+
const testImport = withTest ? `
|
|
1071
|
+
import { describe, it, expect } from 'vitest';
|
|
1072
|
+
import { ${data.pascalName} } from './${data.kebabName}';
|
|
1073
|
+
|
|
1074
|
+
describe('${data.pascalName}', () => {
|
|
1075
|
+
it('should render', () => {
|
|
1076
|
+
// Add test here
|
|
1077
|
+
expect(true).toBe(true);
|
|
1078
|
+
});
|
|
1079
|
+
});` : "";
|
|
1080
|
+
const propsDecl = tsOnly ? `['className', 'children']` : `[]`;
|
|
1081
|
+
return `/**
|
|
1082
|
+
* ${data.pascalName} \u7EC4\u4EF6
|
|
1083
|
+
*
|
|
1084
|
+
* @description ${data.description}
|
|
1085
|
+
* @created ${data.date}
|
|
1086
|
+
*/
|
|
1087
|
+
|
|
1088
|
+
import { h, defineComponent } from '@lytjs/core';${styleImport}
|
|
1089
|
+
|
|
1090
|
+
${tsOnly ? `export interface ${data.pascalName}Props {
|
|
1091
|
+
className?: string;
|
|
1092
|
+
children?: any;
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
` : ""}${template === "functional" ? `export function ${data.pascalName}(${tsOnly ? `props: ${data.pascalName}Props` : "props"}) {
|
|
1096
|
+
const { className = '', children } = props;
|
|
1097
|
+
|
|
1098
|
+
return (
|
|
1099
|
+
<div className={\`${data.kebabName} \${className}\`}>
|
|
1100
|
+
{children || '${data.pascalName} Component'}
|
|
1101
|
+
</div>
|
|
1102
|
+
);
|
|
1103
|
+
}` : `export const ${data.pascalName} = defineComponent({
|
|
1104
|
+
name: '${data.pascalName}',
|
|
1105
|
+
props: ${propsDecl},
|
|
1106
|
+
setup(props) {
|
|
1107
|
+
const { className = '', children } = props;
|
|
1108
|
+
|
|
1109
|
+
return () => (
|
|
1110
|
+
<div className={\`${data.kebabName} \${className}\`}>
|
|
1111
|
+
{children || '${data.pascalName} Component'}
|
|
1112
|
+
</div>
|
|
1113
|
+
);
|
|
1114
|
+
},
|
|
1115
|
+
});`}
|
|
1116
|
+
|
|
1117
|
+
export default ${data.pascalName};${testImport}
|
|
1118
|
+
`;
|
|
1119
|
+
},
|
|
1120
|
+
page: (data, withStyles, withTest, template, lang) => {
|
|
1121
|
+
const styleImport = withStyles ? `
|
|
1122
|
+
import './${data.kebabName}.styles.css';` : "";
|
|
1123
|
+
const tsOnly = lang === "ts";
|
|
1124
|
+
if (template === "sfc") {
|
|
1125
|
+
return `<template>
|
|
1126
|
+
<div class="${data.kebabName}-page">
|
|
1127
|
+
<h1>{title}</h1>
|
|
1128
|
+
<p>Page content for ${data.pascalName}</p>
|
|
1129
|
+
<slot />
|
|
1130
|
+
</div>
|
|
1131
|
+
</template>
|
|
1132
|
+
|
|
1133
|
+
<script setup${tsOnly ? ' lang="ts"' : ""}>
|
|
1134
|
+
${tsOnly ? `import { ref } from '@lytjs/reactivity';
|
|
1135
|
+
` : ""}
|
|
1136
|
+
${tsOnly ? `
|
|
1137
|
+
export interface ${data.pascalName}PageProps {
|
|
1138
|
+
title?: string;
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
const props = defineProps<${data.pascalName}PageProps>();
|
|
1142
|
+
` : ""}
|
|
1143
|
+
|
|
1144
|
+
const title = ref(props.title || '${data.pascalName}');
|
|
1145
|
+
</script>
|
|
1146
|
+
|
|
1147
|
+
<style scoped>
|
|
1148
|
+
.${data.kebabName}-page {
|
|
1149
|
+
padding: 2rem;
|
|
1150
|
+
}
|
|
1151
|
+
</style>
|
|
1152
|
+
`;
|
|
1153
|
+
}
|
|
1154
|
+
const testImport = withTest ? `
|
|
1155
|
+
import { describe, it, expect } from 'vitest';
|
|
1156
|
+
import { ${data.pascalName}Page } from './${data.kebabName}';
|
|
1157
|
+
|
|
1158
|
+
describe('${data.pascalName}Page', () => {
|
|
1159
|
+
it('should render', () => {
|
|
1160
|
+
// Add test here
|
|
1161
|
+
expect(true).toBe(true);
|
|
1162
|
+
});
|
|
1163
|
+
});` : "";
|
|
1164
|
+
return `/**
|
|
1165
|
+
* ${data.pascalName} \u9875\u9762
|
|
1166
|
+
*
|
|
1167
|
+
* @description ${data.description}
|
|
1168
|
+
* @created ${data.date}
|
|
1169
|
+
*/
|
|
1170
|
+
|
|
1171
|
+
import { h, ${tsOnly ? "signal" : "signal"} } from '@lytjs/core';
|
|
1172
|
+
${styleImport}
|
|
1173
|
+
|
|
1174
|
+
${tsOnly ? `export interface ${data.pascalName}PageProps {
|
|
1175
|
+
title?: string;
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
` : ""}export function ${data.pascalName}Page(${tsOnly ? `props: ${data.pascalName}PageProps` : "props"}) {
|
|
1179
|
+
const { title = '${data.pascalName}' } = props;
|
|
1180
|
+
|
|
1181
|
+
return (
|
|
1182
|
+
<div className="${data.kebabName}-page">
|
|
1183
|
+
<h1>{title}</h1>
|
|
1184
|
+
<p>Page content for ${data.pascalName}</p>
|
|
1185
|
+
</div>
|
|
1186
|
+
);
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
export default ${data.pascalName}Page;${testImport}
|
|
1190
|
+
`;
|
|
1191
|
+
},
|
|
1192
|
+
service: (data, _withStyles, _withTest, _template, lang) => {
|
|
1193
|
+
const tsOnly = lang === "ts";
|
|
1194
|
+
return `/**
|
|
1195
|
+
* ${data.pascalName} \u670D\u52A1
|
|
1196
|
+
*
|
|
1197
|
+
* @description ${data.description}
|
|
1198
|
+
* @created ${data.date}
|
|
1199
|
+
*/
|
|
1200
|
+
|
|
1201
|
+
${tsOnly ? `export interface ${data.pascalName}ServiceOptions {
|
|
1202
|
+
baseUrl?: string;
|
|
1203
|
+
timeout?: number;
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
` : ""}${tsOnly ? `export class ${data.pascalName}Service {
|
|
1207
|
+
private baseUrl: string;
|
|
1208
|
+
private timeout: number;
|
|
1209
|
+
` : `export class ${data.pascalName}Service {
|
|
1210
|
+
`}
|
|
1211
|
+
constructor(${tsOnly ? `options: ${data.pascalName}ServiceOptions = {}` : "options = {}"}) {
|
|
1212
|
+
this.baseUrl = options.baseUrl || '/api';
|
|
1213
|
+
this.timeout = options.timeout || 30000;
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
async getAll()${tsOnly ? ": Promise<any[]>" : ""} {
|
|
1217
|
+
const response = await fetch(\`\${this.baseUrl}/${data.kebabName}s\`, {
|
|
1218
|
+
method: 'GET',
|
|
1219
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1220
|
+
signal: AbortSignal.timeout(this.timeout),
|
|
1221
|
+
});
|
|
1222
|
+
return response.json();
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
async getById(id)${tsOnly ? ": Promise<any>" : ""} {
|
|
1226
|
+
const response = await fetch(\`\${this.baseUrl}/${data.kebabName}s/\${id}\`, {
|
|
1227
|
+
method: 'GET',
|
|
1228
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1229
|
+
signal: AbortSignal.timeout(this.timeout),
|
|
1230
|
+
});
|
|
1231
|
+
return response.json();
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
async create(${tsOnly ? "data: any" : "data"})${tsOnly ? ": Promise<any>" : ""} {
|
|
1235
|
+
const response = await fetch(\`\${this.baseUrl}/${data.kebabName}s\`, {
|
|
1236
|
+
method: 'POST',
|
|
1237
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1238
|
+
body: JSON.stringify(data),
|
|
1239
|
+
signal: AbortSignal.timeout(this.timeout),
|
|
1240
|
+
});
|
|
1241
|
+
return response.json();
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
async update(id)${tsOnly ? ": Promise<any>" : ""} {
|
|
1245
|
+
const response = await fetch(\`\${this.baseUrl}/${data.kebabName}s/\${id}\`, {
|
|
1246
|
+
method: 'PUT',
|
|
1247
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1248
|
+
body: JSON.stringify(data),
|
|
1249
|
+
signal: AbortSignal.timeout(this.timeout),
|
|
1250
|
+
});
|
|
1251
|
+
return response.json();
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
async delete(id)${tsOnly ? ": Promise<void>" : ""} {
|
|
1255
|
+
await fetch(\`\${this.baseUrl}/${data.kebabName}s/\${id}\`, {
|
|
1256
|
+
method: 'DELETE',
|
|
1257
|
+
signal: AbortSignal.timeout(this.timeout),
|
|
1258
|
+
});
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
export default ${data.pascalName}Service;
|
|
1263
|
+
`;
|
|
1264
|
+
},
|
|
1265
|
+
hook: (data, _withStyles, _withTest, _template, lang) => {
|
|
1266
|
+
const tsOnly = lang === "ts";
|
|
1267
|
+
return `/**
|
|
1268
|
+
* ${data.pascalName} Hook
|
|
1269
|
+
*
|
|
1270
|
+
* @description ${data.description}
|
|
1271
|
+
* @created ${data.date}
|
|
1272
|
+
*/
|
|
1273
|
+
|
|
1274
|
+
import { signal, effect } from '@lytjs/reactivity';
|
|
1275
|
+
|
|
1276
|
+
${tsOnly ? `export interface ${data.pascalName}Options {
|
|
1277
|
+
immediate?: boolean;
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
export interface ${data.pascalName}Return {
|
|
1281
|
+
data: ReturnType<typeof signal>;
|
|
1282
|
+
loading: ReturnType<typeof signal>;
|
|
1283
|
+
error: ReturnType<typeof signal>;
|
|
1284
|
+
execute: () => Promise<void>;
|
|
1285
|
+
reset: () => void;
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
` : ""}export function use${data.pascalName}(${tsOnly ? `options: ${data.pascalName}Options = {}` : "options = {}"})${tsOnly ? `: ${data.pascalName}Return` : ""} {
|
|
1289
|
+
const { immediate = false } = options;
|
|
1290
|
+
|
|
1291
|
+
const data = signal<any>(null);
|
|
1292
|
+
const loading = signal(false);
|
|
1293
|
+
const error = signal<Error | null>(null);
|
|
1294
|
+
|
|
1295
|
+
async function execute() {
|
|
1296
|
+
loading.value = true;
|
|
1297
|
+
error.value = null;
|
|
1298
|
+
|
|
1299
|
+
try {
|
|
1300
|
+
const result = await new Promise(resolve => setTimeout(() => resolve(null), 100));
|
|
1301
|
+
data.value = result;
|
|
1302
|
+
} catch (e) {
|
|
1303
|
+
error.value = e as Error;
|
|
1304
|
+
} finally {
|
|
1305
|
+
loading.value = false;
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
function reset() {
|
|
1310
|
+
data.value = null;
|
|
1311
|
+
loading.value = false;
|
|
1312
|
+
error.value = null;
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
if (immediate) {
|
|
1316
|
+
execute();
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
return {
|
|
1320
|
+
data,
|
|
1321
|
+
loading,
|
|
1322
|
+
error,
|
|
1323
|
+
execute,
|
|
1324
|
+
reset,
|
|
1325
|
+
};
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
export default use${data.pascalName};
|
|
1329
|
+
`;
|
|
1330
|
+
},
|
|
1331
|
+
store: (data, _withStyles, _withTest, _template, lang) => {
|
|
1332
|
+
const tsOnly = lang === "ts";
|
|
1333
|
+
return `/**
|
|
1334
|
+
* ${data.pascalName} Store
|
|
1335
|
+
*
|
|
1336
|
+
* @description ${data.description}
|
|
1337
|
+
* @created ${data.date}
|
|
1338
|
+
*/
|
|
1339
|
+
|
|
1340
|
+
import { signal, computed } from '@lytjs/reactivity';
|
|
1341
|
+
|
|
1342
|
+
${tsOnly ? `export interface ${data.pascalName}State {
|
|
1343
|
+
items: any[];
|
|
1344
|
+
selectedId: string | null;
|
|
1345
|
+
loading: boolean;
|
|
1346
|
+
error: Error | null;
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
` : ""}export function create${data.pascalName}Store() {
|
|
1350
|
+
const state = signal${tsOnly ? `<${data.pascalName}State>` : ""}({
|
|
1351
|
+
items: [],
|
|
1352
|
+
selectedId: null,
|
|
1353
|
+
loading: false,
|
|
1354
|
+
error: null,
|
|
1355
|
+
});
|
|
1356
|
+
|
|
1357
|
+
const selectedItem = computed(() => {
|
|
1358
|
+
const currentState = state.value;
|
|
1359
|
+
return currentState.items.find(item => item.id === currentState.selectedId);
|
|
1360
|
+
});
|
|
1361
|
+
|
|
1362
|
+
const itemCount = computed(() => state.value.items.length);
|
|
1363
|
+
|
|
1364
|
+
function setItems(items) {
|
|
1365
|
+
state.value = { ...state.value, items };
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
function selectItem(id) {
|
|
1369
|
+
state.value = { ...state.value, selectedId: id };
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
function addItem(item) {
|
|
1373
|
+
state.value = {
|
|
1374
|
+
...state.value,
|
|
1375
|
+
items: [...state.value.items, item],
|
|
1376
|
+
};
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
function updateItem(id, updates) {
|
|
1380
|
+
state.value = {
|
|
1381
|
+
...state.value,
|
|
1382
|
+
items: state.value.items.map(item =>
|
|
1383
|
+
item.id === id ? { ...item, ...updates } : item
|
|
1384
|
+
),
|
|
1385
|
+
};
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
function removeItem(id) {
|
|
1389
|
+
state.value = {
|
|
1390
|
+
...state.value,
|
|
1391
|
+
items: state.value.items.filter(item => item.id !== id),
|
|
1392
|
+
selectedId: state.value.selectedId === id ? null : state.value.selectedId,
|
|
1393
|
+
};
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
function setLoading(loading) {
|
|
1397
|
+
state.value = { ...state.value, loading };
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
function setError(error) {
|
|
1401
|
+
state.value = { ...state.value, error };
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
function reset() {
|
|
1405
|
+
state.value = {
|
|
1406
|
+
items: [],
|
|
1407
|
+
selectedId: null,
|
|
1408
|
+
loading: false,
|
|
1409
|
+
error: null,
|
|
1410
|
+
};
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
return {
|
|
1414
|
+
state,
|
|
1415
|
+
selectedItem,
|
|
1416
|
+
itemCount,
|
|
1417
|
+
setItems,
|
|
1418
|
+
selectItem,
|
|
1419
|
+
addItem,
|
|
1420
|
+
updateItem,
|
|
1421
|
+
removeItem,
|
|
1422
|
+
setLoading,
|
|
1423
|
+
setError,
|
|
1424
|
+
reset,
|
|
1425
|
+
};
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
${tsOnly ? `export type ${data.pascalName}Store = ReturnType<typeof create${data.pascalName}Store>;
|
|
1429
|
+
` : ""}export default create${data.pascalName}Store;
|
|
1430
|
+
`;
|
|
1431
|
+
},
|
|
1432
|
+
layout: (data, withStyles, _withTest, _template, lang) => {
|
|
1433
|
+
const tsOnly = lang === "ts";
|
|
1434
|
+
const styleImport = withStyles ? `
|
|
1435
|
+
import './${data.kebabName}.styles.css';` : "";
|
|
1436
|
+
return `/**
|
|
1437
|
+
* ${data.pascalName} \u5E03\u5C40
|
|
1438
|
+
*
|
|
1439
|
+
* @description ${data.description}
|
|
1440
|
+
* @created ${data.date}
|
|
1441
|
+
*/
|
|
1442
|
+
|
|
1443
|
+
import { h, defineComponent } from '@lytjs/core';${styleImport}
|
|
1444
|
+
|
|
1445
|
+
${tsOnly ? `export interface ${data.pascalName}LayoutProps {
|
|
1446
|
+
children?: any;
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1449
|
+
` : ""}export const ${data.pascalName}Layout = defineComponent({
|
|
1450
|
+
name: '${data.pascalName}Layout',
|
|
1451
|
+
setup(props) {
|
|
1452
|
+
return () => (
|
|
1453
|
+
<div className="${data.kebabName}-layout">
|
|
1454
|
+
<header className="${data.kebabName}-header">
|
|
1455
|
+
<slot name="header">
|
|
1456
|
+
<h1>${data.pascalName}</h1>
|
|
1457
|
+
</slot>
|
|
1458
|
+
</header>
|
|
1459
|
+
<main className="${data.kebabName}-main">
|
|
1460
|
+
<slot />
|
|
1461
|
+
</main>
|
|
1462
|
+
<footer className="${data.kebabName}-footer">
|
|
1463
|
+
<slot name="footer" />
|
|
1464
|
+
</footer>
|
|
1465
|
+
</div>
|
|
1466
|
+
);
|
|
1467
|
+
},
|
|
1468
|
+
});
|
|
1469
|
+
|
|
1470
|
+
export default ${data.pascalName}Layout;
|
|
1471
|
+
`;
|
|
1472
|
+
},
|
|
1473
|
+
middleware: (data, _withStyles, _withTest, _template, lang) => {
|
|
1474
|
+
const tsOnly = lang === "ts";
|
|
1475
|
+
return `/**
|
|
1476
|
+
* ${data.pascalName} \u4E2D\u95F4\u4EF6
|
|
1477
|
+
*
|
|
1478
|
+
* @description ${data.description}
|
|
1479
|
+
* @created ${data.date}
|
|
1480
|
+
*/
|
|
1481
|
+
|
|
1482
|
+
${tsOnly ? `import type { Request, Response, NextFunction } from 'express';
|
|
1483
|
+
` : ""}
|
|
1484
|
+
export function ${data.camelName}Middleware(${tsOnly ? `req: Request, res: Response, next: NextFunction` : "req, res, next"}) {
|
|
1485
|
+
try {
|
|
1486
|
+
console.log('[${data.pascalName}] Middleware executed');
|
|
1487
|
+
next();
|
|
1488
|
+
} catch (error) {
|
|
1489
|
+
next(error);
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
export default ${data.camelName}Middleware;
|
|
1494
|
+
`;
|
|
1495
|
+
}
|
|
1496
|
+
};
|
|
1497
|
+
function toPascalCase2(name) {
|
|
1498
|
+
return name.split(/[-_]/).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
1499
|
+
}
|
|
1500
|
+
function toCamelCase2(name) {
|
|
1501
|
+
const pascal = toPascalCase2(name);
|
|
1502
|
+
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
1503
|
+
}
|
|
1504
|
+
function toKebabCase(name) {
|
|
1505
|
+
return name.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[\s_]+/g, "-").toLowerCase();
|
|
1506
|
+
}
|
|
1507
|
+
async function generate(options) {
|
|
1508
|
+
const {
|
|
1509
|
+
type,
|
|
1510
|
+
name,
|
|
1511
|
+
path: basePath = "./src",
|
|
1512
|
+
withStyles = false,
|
|
1513
|
+
withTest = false,
|
|
1514
|
+
description = "",
|
|
1515
|
+
template = "default",
|
|
1516
|
+
language = "ts"
|
|
1517
|
+
} = options;
|
|
1518
|
+
const templateData = {
|
|
1519
|
+
name,
|
|
1520
|
+
pascalName: toPascalCase2(name),
|
|
1521
|
+
kebabName: toKebabCase(name),
|
|
1522
|
+
camelName: toCamelCase2(name),
|
|
1523
|
+
date: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
|
|
1524
|
+
description: description || `${toPascalCase2(name)} ${type}`
|
|
1525
|
+
};
|
|
1526
|
+
const typeDirs = {
|
|
1527
|
+
component: "components",
|
|
1528
|
+
page: "pages",
|
|
1529
|
+
service: "services",
|
|
1530
|
+
hook: "hooks",
|
|
1531
|
+
store: "stores",
|
|
1532
|
+
layout: "layouts",
|
|
1533
|
+
middleware: "middleware"
|
|
1534
|
+
};
|
|
1535
|
+
const targetDir = path.join(process.cwd(), basePath, typeDirs[type] || "components");
|
|
1536
|
+
await ensureDir(targetDir);
|
|
1537
|
+
const templateFn = TEMPLATES3[type];
|
|
1538
|
+
if (!templateFn) {
|
|
1539
|
+
logger.error(`Unknown type: ${type}`);
|
|
1540
|
+
logger.info("Available types: component, page, service, hook, store, layout, middleware");
|
|
1541
|
+
process.exit(1);
|
|
1542
|
+
}
|
|
1543
|
+
const extension = template === "sfc" ? "lyt" : language;
|
|
1544
|
+
const filename = `${templateData.kebabName}${type === "page" ? ".page" : ""}.${extension}`;
|
|
1545
|
+
const filePath = path.join(targetDir, filename);
|
|
1546
|
+
const content = templateFn(templateData, withStyles, withTest, template, language);
|
|
1547
|
+
await writeFile(filePath, content);
|
|
1548
|
+
logger.success(`Generated ${type}: ${filePath}`);
|
|
1549
|
+
if (withStyles && template !== "sfc") {
|
|
1550
|
+
const styleContent = `/**
|
|
1551
|
+
* ${templateData.pascalName} Styles
|
|
1552
|
+
*/
|
|
1553
|
+
|
|
1554
|
+
.${templateData.kebabName} {
|
|
1555
|
+
/* Component styles */
|
|
1556
|
+
}
|
|
1557
|
+
`;
|
|
1558
|
+
const stylePath = path.join(targetDir, `${templateData.kebabName}.styles.css`);
|
|
1559
|
+
await writeFile(stylePath, styleContent);
|
|
1560
|
+
logger.success(`Generated styles: ${stylePath}`);
|
|
1561
|
+
}
|
|
1562
|
+
if (withTest && template !== "sfc") {
|
|
1563
|
+
logger.info("Test file included in generated component");
|
|
1564
|
+
}
|
|
1565
|
+
logger.info("\nNext steps:");
|
|
1566
|
+
logger.info(` cd ${targetDir}`);
|
|
1567
|
+
logger.info(
|
|
1568
|
+
` Import your ${type}: import { ${template === "sfc" ? "default" : templateData.pascalName} } from './${templateData.kebabName}'`
|
|
1569
|
+
);
|
|
1570
|
+
logger.info("\nAvailable options:");
|
|
1571
|
+
logger.info(" --template=sfc : Single File Component (.lyt)");
|
|
1572
|
+
logger.info(" --template=functional : Functional component");
|
|
1573
|
+
logger.info(" --language=js : JavaScript output");
|
|
1574
|
+
}
|
|
767
1575
|
var PLUGIN_TEMPLATES = {
|
|
768
1576
|
default: "Default plugin template with TypeScript",
|
|
769
1577
|
minimal: "Minimal plugin without extra dependencies",
|
|
@@ -772,45 +1580,53 @@ var PLUGIN_TEMPLATES = {
|
|
|
772
1580
|
function getTemplateContent(template, pluginName) {
|
|
773
1581
|
const packageName = `@lytjs/plugin-${pluginName}`;
|
|
774
1582
|
const files = {};
|
|
775
|
-
files["package.json"] = JSON.stringify(
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
1583
|
+
files["package.json"] = JSON.stringify(
|
|
1584
|
+
{
|
|
1585
|
+
name: packageName,
|
|
1586
|
+
version: "0.1.0",
|
|
1587
|
+
description: `LytJS plugin: ${pluginName}`,
|
|
1588
|
+
main: "dist/index.cjs",
|
|
1589
|
+
module: "dist/index.mjs",
|
|
1590
|
+
types: "dist/index.d.ts",
|
|
1591
|
+
exports: {
|
|
1592
|
+
".": {
|
|
1593
|
+
import: "./dist/index.mjs",
|
|
1594
|
+
require: "./dist/index.cjs",
|
|
1595
|
+
types: "./dist/index.d.ts"
|
|
1596
|
+
}
|
|
1597
|
+
},
|
|
1598
|
+
files: ["dist"],
|
|
1599
|
+
scripts: {
|
|
1600
|
+
build: "tsup",
|
|
1601
|
+
dev: "tsup --watch",
|
|
1602
|
+
test: "vitest",
|
|
1603
|
+
lint: "eslint src",
|
|
1604
|
+
prepublishOnly: "npm run build"
|
|
1605
|
+
},
|
|
1606
|
+
keywords: ["lytjs", "plugin"],
|
|
1607
|
+
license: "MIT",
|
|
1608
|
+
peerDependencies: {
|
|
1609
|
+
"@lytjs/core": ">=6.0.0"
|
|
787
1610
|
}
|
|
788
1611
|
},
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
1612
|
+
null,
|
|
1613
|
+
2
|
|
1614
|
+
);
|
|
1615
|
+
files["tsconfig.json"] = JSON.stringify(
|
|
1616
|
+
{
|
|
1617
|
+
extends: "@lytjs/core/tsconfig.json",
|
|
1618
|
+
compilerOptions: {
|
|
1619
|
+
outDir: "./dist",
|
|
1620
|
+
rootDir: "./src",
|
|
1621
|
+
declaration: true,
|
|
1622
|
+
declarationMap: true
|
|
1623
|
+
},
|
|
1624
|
+
include: ["src"],
|
|
1625
|
+
exclude: ["node_modules", "dist", "tests"]
|
|
796
1626
|
},
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
"@lytjs/core": ">=6.0.0"
|
|
801
|
-
}
|
|
802
|
-
}, null, 2);
|
|
803
|
-
files["tsconfig.json"] = JSON.stringify({
|
|
804
|
-
extends: "@lytjs/core/tsconfig.json",
|
|
805
|
-
compilerOptions: {
|
|
806
|
-
outDir: "./dist",
|
|
807
|
-
rootDir: "./src",
|
|
808
|
-
declaration: true,
|
|
809
|
-
declarationMap: true
|
|
810
|
-
},
|
|
811
|
-
include: ["src"],
|
|
812
|
-
exclude: ["node_modules", "dist", "tests"]
|
|
813
|
-
}, null, 2);
|
|
1627
|
+
null,
|
|
1628
|
+
2
|
|
1629
|
+
);
|
|
814
1630
|
files["tsup.config.ts"] = `import { defineConfig } from 'tsup';
|
|
815
1631
|
|
|
816
1632
|
export default defineConfig({
|
|
@@ -855,8 +1671,6 @@ const optionsSchema: ConfigSchema<${pluginName.replace(/-/g, "")}Options> = {
|
|
|
855
1671
|
additionalProperties: false,
|
|
856
1672
|
};
|
|
857
1673
|
|
|
858
|
-
${pluginName.replace(/-/g, "")}Options\`;
|
|
859
|
-
|
|
860
1674
|
export interface ${pluginName.replace(/-/g, "")}Options {
|
|
861
1675
|
debug?: boolean;
|
|
862
1676
|
option1?: string;
|
|
@@ -1024,7 +1838,16 @@ async function buildPlugin(options = {}) {
|
|
|
1024
1838
|
logger.info("Building plugin...");
|
|
1025
1839
|
try {
|
|
1026
1840
|
const buildCmd = "tsup";
|
|
1027
|
-
const args = [
|
|
1841
|
+
const args = [
|
|
1842
|
+
"--entry",
|
|
1843
|
+
"src/index.ts",
|
|
1844
|
+
"--outDir",
|
|
1845
|
+
outDir,
|
|
1846
|
+
"--format",
|
|
1847
|
+
"esm,cjs",
|
|
1848
|
+
"--dts",
|
|
1849
|
+
"--sourcemap"
|
|
1850
|
+
];
|
|
1028
1851
|
if (options.minify) {
|
|
1029
1852
|
args.push("--minify");
|
|
1030
1853
|
}
|
|
@@ -1090,8 +1913,8 @@ async function validatePlugin(options = {}) {
|
|
|
1090
1913
|
if (!existsSync(tsupConfigPath)) {
|
|
1091
1914
|
warnings.push("tsup.config.ts not found (recommended for builds)");
|
|
1092
1915
|
}
|
|
1093
|
-
|
|
1094
|
-
|
|
1916
|
+
const hasErrors = errors.length > 0;
|
|
1917
|
+
const hasWarnings = warnings.length > 0;
|
|
1095
1918
|
if (hasErrors) {
|
|
1096
1919
|
logger.error("Validation failed with errors:");
|
|
1097
1920
|
for (const err of errors) {
|
|
@@ -1120,7 +1943,7 @@ async function validatePlugin(options = {}) {
|
|
|
1120
1943
|
}
|
|
1121
1944
|
function isEmptyDir2(dir) {
|
|
1122
1945
|
if (!existsSync(dir)) return true;
|
|
1123
|
-
const files =
|
|
1946
|
+
const files = readdirSync(dir);
|
|
1124
1947
|
return files.length === 0;
|
|
1125
1948
|
}
|
|
1126
1949
|
function listPluginTemplates() {
|
|
@@ -1139,7 +1962,7 @@ async function runCli(rawArgs = process.argv.slice(2)) {
|
|
|
1139
1962
|
return;
|
|
1140
1963
|
}
|
|
1141
1964
|
if (options.version || command === "version" || command === "-v" || command === "--version") {
|
|
1142
|
-
console.
|
|
1965
|
+
console.warn(`LytJS CLI v${VERSION}`);
|
|
1143
1966
|
return;
|
|
1144
1967
|
}
|
|
1145
1968
|
switch (command) {
|
|
@@ -1173,9 +1996,20 @@ async function runCli(rawArgs = process.argv.slice(2)) {
|
|
|
1173
1996
|
grep: options.grep
|
|
1174
1997
|
});
|
|
1175
1998
|
break;
|
|
1176
|
-
case "add":
|
|
1177
|
-
|
|
1178
|
-
|
|
1999
|
+
case "add": {
|
|
2000
|
+
const addTypes = [
|
|
2001
|
+
"component",
|
|
2002
|
+
"page",
|
|
2003
|
+
"store",
|
|
2004
|
+
"directive",
|
|
2005
|
+
"composable",
|
|
2006
|
+
"util",
|
|
2007
|
+
"middleware",
|
|
2008
|
+
"hook"
|
|
2009
|
+
];
|
|
2010
|
+
if (!args[0] || !addTypes.includes(args[0])) {
|
|
2011
|
+
logger.error("Usage: lyt add <type> <name>");
|
|
2012
|
+
logger.info("Types: component, page, store, directive, composable, util, middleware, hook");
|
|
1179
2013
|
logger.info("Example: lyt add component Button");
|
|
1180
2014
|
process.exit(1);
|
|
1181
2015
|
}
|
|
@@ -1183,7 +2017,27 @@ async function runCli(rawArgs = process.argv.slice(2)) {
|
|
|
1183
2017
|
force: options.force
|
|
1184
2018
|
});
|
|
1185
2019
|
break;
|
|
1186
|
-
|
|
2020
|
+
}
|
|
2021
|
+
case "generate":
|
|
2022
|
+
case "g": {
|
|
2023
|
+
const genTypes = ["component", "page", "service", "hook", "store"];
|
|
2024
|
+
if (!args[0] || !genTypes.includes(args[0])) {
|
|
2025
|
+
logger.error("Usage: lyt generate <type> <name>");
|
|
2026
|
+
logger.info("Types: component, page, service, hook, store");
|
|
2027
|
+
logger.info("Example: lyt generate component Button");
|
|
2028
|
+
process.exit(1);
|
|
2029
|
+
}
|
|
2030
|
+
await generate({
|
|
2031
|
+
type: args[0],
|
|
2032
|
+
name: args[1] || "Unnamed",
|
|
2033
|
+
path: options.path,
|
|
2034
|
+
withStyles: options.styles,
|
|
2035
|
+
withTest: options.test,
|
|
2036
|
+
withStorybook: options.storybook
|
|
2037
|
+
});
|
|
2038
|
+
break;
|
|
2039
|
+
}
|
|
2040
|
+
case "plugin": {
|
|
1187
2041
|
if (!args[0]) {
|
|
1188
2042
|
logger.error("Usage: lyt plugin <create|build|validate|templates>");
|
|
1189
2043
|
logger.info("Example: lyt plugin create my-plugin");
|
|
@@ -1220,6 +2074,7 @@ async function runCli(rawArgs = process.argv.slice(2)) {
|
|
|
1220
2074
|
process.exit(1);
|
|
1221
2075
|
}
|
|
1222
2076
|
break;
|
|
2077
|
+
}
|
|
1223
2078
|
default:
|
|
1224
2079
|
if (command) {
|
|
1225
2080
|
logger.error(`Unknown command: ${command}`);
|
|
@@ -1266,7 +2121,7 @@ function parseArgs(args) {
|
|
|
1266
2121
|
return { command, args: positional, options };
|
|
1267
2122
|
}
|
|
1268
2123
|
function showHelp() {
|
|
1269
|
-
console.
|
|
2124
|
+
console.warn(`
|
|
1270
2125
|
${logger.bold("LytJS CLI")} v${VERSION}
|
|
1271
2126
|
|
|
1272
2127
|
${logger.bold("Usage:")}
|
|
@@ -1278,10 +2133,11 @@ ${logger.bold("Commands:")}
|
|
|
1278
2133
|
dev Start development server
|
|
1279
2134
|
build Build for production
|
|
1280
2135
|
test Run tests
|
|
1281
|
-
add <type> <name> Generate a component, page,
|
|
2136
|
+
add <type> <name> Generate a component, page, store, directive, composable, etc.
|
|
2137
|
+
generate, g Advanced code generation (component, page, service, hook, store)
|
|
1282
2138
|
plugin <subcmd> Plugin development commands
|
|
1283
2139
|
help Show this help message
|
|
1284
|
-
|
|
2140
|
+
|
|
1285
2141
|
${logger.bold("Options:")}
|
|
1286
2142
|
--version, -v Show version number
|
|
1287
2143
|
--help Show help
|
|
@@ -1305,6 +2161,12 @@ ${logger.bold("Test Options:")}
|
|
|
1305
2161
|
--coverage Generate coverage report
|
|
1306
2162
|
--grep <pattern> Filter tests by pattern
|
|
1307
2163
|
|
|
2164
|
+
${logger.bold("Generate Options:")}
|
|
2165
|
+
--path <dir> Output directory (default: ./src)
|
|
2166
|
+
--styles Generate CSS styles file
|
|
2167
|
+
--test Generate test file
|
|
2168
|
+
--storybook Generate Storybook story file
|
|
2169
|
+
|
|
1308
2170
|
${logger.bold("Plugin Options:")}
|
|
1309
2171
|
--template <name> Use a specific plugin template (default, minimal, withConfig)
|
|
1310
2172
|
--force Overwrite existing directory
|
|
@@ -1325,6 +2187,16 @@ ${logger.bold("Examples:")}
|
|
|
1325
2187
|
lyt add component Button
|
|
1326
2188
|
lyt add page About
|
|
1327
2189
|
lyt add store user
|
|
2190
|
+
lyt directive click-outside
|
|
2191
|
+
lyt add composable fetch-data
|
|
2192
|
+
lyt add util format
|
|
2193
|
+
lyt add hook window-size
|
|
2194
|
+
lyt generate component Button --styles --test
|
|
2195
|
+
lyt generate page Dashboard --path ./src/pages
|
|
2196
|
+
lyt generate service User --path ./src/services
|
|
2197
|
+
lyt generate hook useCounter
|
|
2198
|
+
lyt generate store Auth --path ./src/stores
|
|
2199
|
+
lyt g page Login
|
|
1328
2200
|
lyt plugin create my-plugin
|
|
1329
2201
|
lyt plugin create my-plugin --template withConfig
|
|
1330
2202
|
lyt plugin build
|
|
@@ -1337,6 +2209,6 @@ if (__require.main === module) {
|
|
|
1337
2209
|
runCli().catch(console.error);
|
|
1338
2210
|
}
|
|
1339
2211
|
|
|
1340
|
-
export { add, build, buildPlugin, create, createPlugin, detectPackageManager, dev, ensureDir, exists, getAddCommand, getInstallCommand, getRunCommand, listPluginTemplates, listTemplates, logger, readFile, runCli, test, validatePlugin, writeFile };
|
|
2212
|
+
export { add, build, buildPlugin, create, createPlugin, detectPackageManager, dev, ensureDir, exists, generate, getAddCommand, getInstallCommand, getRunCommand, listPluginTemplates, listTemplates, logger, readFile, runCli, test, validatePlugin, writeFile };
|
|
1341
2213
|
//# sourceMappingURL=index.mjs.map
|
|
1342
2214
|
//# sourceMappingURL=index.mjs.map
|