@lumiflora/fsdk 0.1.4

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 (83) hide show
  1. package/README.md +150 -0
  2. package/dist/commands/add-component.d.ts +7 -0
  3. package/dist/commands/add-component.d.ts.map +1 -0
  4. package/dist/commands/add-component.js +93 -0
  5. package/dist/commands/add-page.d.ts +8 -0
  6. package/dist/commands/add-page.d.ts.map +1 -0
  7. package/dist/commands/add-page.js +98 -0
  8. package/dist/commands/add-store.d.ts +6 -0
  9. package/dist/commands/add-store.d.ts.map +1 -0
  10. package/dist/commands/add-store.js +204 -0
  11. package/dist/commands/completion.d.ts +8 -0
  12. package/dist/commands/completion.d.ts.map +1 -0
  13. package/dist/commands/completion.js +271 -0
  14. package/dist/commands/create-app.d.ts +10 -0
  15. package/dist/commands/create-app.d.ts.map +1 -0
  16. package/dist/commands/create-app.js +174 -0
  17. package/dist/commands/index.d.ts +9 -0
  18. package/dist/commands/index.d.ts.map +1 -0
  19. package/dist/commands/index.js +8 -0
  20. package/dist/commands/preview.d.ts +8 -0
  21. package/dist/commands/preview.d.ts.map +1 -0
  22. package/dist/commands/preview.js +162 -0
  23. package/dist/commands/sync-template.d.ts +6 -0
  24. package/dist/commands/sync-template.d.ts.map +1 -0
  25. package/dist/commands/sync-template.js +94 -0
  26. package/dist/commands/validate.d.ts +7 -0
  27. package/dist/commands/validate.d.ts.map +1 -0
  28. package/dist/commands/validate.js +136 -0
  29. package/dist/completion/completion-scripts.d.ts +4 -0
  30. package/dist/completion/completion-scripts.d.ts.map +1 -0
  31. package/dist/completion/completion-scripts.js +193 -0
  32. package/dist/completion/index.d.ts +2 -0
  33. package/dist/completion/index.d.ts.map +1 -0
  34. package/dist/completion/index.js +1 -0
  35. package/dist/core/config-loader.d.ts +91 -0
  36. package/dist/core/config-loader.d.ts.map +1 -0
  37. package/dist/core/config-loader.js +118 -0
  38. package/dist/core/hot-reload.d.ts +24 -0
  39. package/dist/core/hot-reload.d.ts.map +1 -0
  40. package/dist/core/hot-reload.js +97 -0
  41. package/dist/core/index.d.ts +5 -0
  42. package/dist/core/index.d.ts.map +1 -0
  43. package/dist/core/index.js +4 -0
  44. package/dist/core/plugin-system.d.ts +32 -0
  45. package/dist/core/plugin-system.d.ts.map +1 -0
  46. package/dist/core/plugin-system.js +69 -0
  47. package/dist/core/template-engine.d.ts +22 -0
  48. package/dist/core/template-engine.d.ts.map +1 -0
  49. package/dist/core/template-engine.js +89 -0
  50. package/dist/index.d.ts +3 -0
  51. package/dist/index.d.ts.map +1 -0
  52. package/dist/index.js +214 -0
  53. package/dist/plugins/add-component-plugin.d.ts +4 -0
  54. package/dist/plugins/add-component-plugin.d.ts.map +1 -0
  55. package/dist/plugins/add-component-plugin.js +23 -0
  56. package/dist/plugins/add-page-plugin.d.ts +4 -0
  57. package/dist/plugins/add-page-plugin.d.ts.map +1 -0
  58. package/dist/plugins/add-page-plugin.js +23 -0
  59. package/dist/plugins/add-store-plugin.d.ts +4 -0
  60. package/dist/plugins/add-store-plugin.d.ts.map +1 -0
  61. package/dist/plugins/add-store-plugin.js +23 -0
  62. package/dist/plugins/core-plugin.d.ts +4 -0
  63. package/dist/plugins/core-plugin.d.ts.map +1 -0
  64. package/dist/plugins/core-plugin.js +22 -0
  65. package/dist/plugins/index.d.ts +5 -0
  66. package/dist/plugins/index.d.ts.map +1 -0
  67. package/dist/plugins/index.js +4 -0
  68. package/dist/utils/command-helpers.d.ts +15 -0
  69. package/dist/utils/command-helpers.d.ts.map +1 -0
  70. package/dist/utils/command-helpers.js +40 -0
  71. package/dist/utils/index.d.ts +5 -0
  72. package/dist/utils/index.d.ts.map +1 -0
  73. package/dist/utils/index.js +4 -0
  74. package/dist/utils/logger.d.ts +19 -0
  75. package/dist/utils/logger.d.ts.map +1 -0
  76. package/dist/utils/logger.js +32 -0
  77. package/dist/utils/path.d.ts +9 -0
  78. package/dist/utils/path.d.ts.map +1 -0
  79. package/dist/utils/path.js +66 -0
  80. package/dist/utils/spinner.d.ts +23 -0
  81. package/dist/utils/spinner.d.ts.map +1 -0
  82. package/dist/utils/spinner.js +61 -0
  83. package/package.json +37 -0
@@ -0,0 +1,94 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import fg from 'fast-glob';
4
+ import { logger } from '../utils/index.js';
5
+ import { templateEngine } from '../core/index.js';
6
+ export async function syncTemplate(cwd, options = {}) {
7
+ try {
8
+ const template = options.template || 'base';
9
+ logger.info(`Syncing template ${template}...`);
10
+ const templatePath = path.resolve(cwd, '.fsdk', 'template');
11
+ const currentTemplatePath = path.resolve(templatePath, template);
12
+ if (!fs.existsSync(currentTemplatePath)) {
13
+ logger.warning(`Template ${template} not found in .fsdk/template`);
14
+ logger.info('Run "fsdk create" first to initialize a template');
15
+ return;
16
+ }
17
+ const srcDir = path.resolve(cwd, 'src');
18
+ if (!fs.existsSync(srcDir)) {
19
+ logger.error('src directory does not exist. Run "fsdk create" first.');
20
+ return;
21
+ }
22
+ const { modifiedFiles, addedFiles, removedFiles } = await compareTemplates(currentTemplatePath, srcDir);
23
+ if (modifiedFiles.length === 0 && addedFiles.length === 0 && removedFiles.length === 0) {
24
+ logger.success('Template is already up to date');
25
+ return;
26
+ }
27
+ if (options.force) {
28
+ await applyTemplateSync(currentTemplatePath, srcDir, { modifiedFiles, addedFiles, removedFiles });
29
+ }
30
+ else {
31
+ await interactiveSync(currentTemplatePath, srcDir, { modifiedFiles, addedFiles, removedFiles });
32
+ }
33
+ templateEngine.clearCache();
34
+ logger.success('Template sync completed');
35
+ }
36
+ catch (error) {
37
+ logger.error('Failed to sync template:', error);
38
+ throw error;
39
+ }
40
+ }
41
+ async function compareTemplates(templateDir, srcDir) {
42
+ const templateFiles = await fg.glob('**/*', { cwd: templateDir, dot: true, onlyFiles: true });
43
+ const srcFiles = await fg.glob('**/*', { cwd: srcDir, dot: true, onlyFiles: true });
44
+ const templateSet = new Set(templateFiles);
45
+ const srcSet = new Set(srcFiles);
46
+ const modifiedFiles = [];
47
+ const addedFiles = [];
48
+ const removedFiles = [];
49
+ for (const file of srcFiles) {
50
+ if (templateSet.has(file)) {
51
+ const templateContent = await fs.readFile(path.resolve(templateDir, file), 'utf-8');
52
+ const srcContent = await fs.readFile(path.resolve(srcDir, file), 'utf-8');
53
+ if (templateContent !== srcContent) {
54
+ modifiedFiles.push(file);
55
+ }
56
+ }
57
+ else {
58
+ addedFiles.push(file);
59
+ }
60
+ }
61
+ for (const file of templateFiles) {
62
+ if (!srcSet.has(file)) {
63
+ removedFiles.push(file);
64
+ }
65
+ }
66
+ return { modifiedFiles, addedFiles, removedFiles };
67
+ }
68
+ async function applyTemplateSync(templateDir, srcDir, changes) {
69
+ const { modifiedFiles, addedFiles, removedFiles } = changes;
70
+ for (const file of removedFiles) {
71
+ const filePath = path.resolve(srcDir, file);
72
+ await fs.remove(filePath);
73
+ logger.debug(`Removed: ${file}`);
74
+ }
75
+ for (const file of [...modifiedFiles, ...addedFiles]) {
76
+ await fs.copy(path.resolve(templateDir, file), path.resolve(srcDir, file));
77
+ logger.debug(`Copied: ${file}`);
78
+ }
79
+ logger.info(`Synced: ${modifiedFiles.length} modified, ${addedFiles.length} added, ${removedFiles.length} removed`);
80
+ }
81
+ async function interactiveSync(templateDir, srcDir, changes) {
82
+ const { modifiedFiles, addedFiles, removedFiles } = changes;
83
+ logger.info('Changes detected:');
84
+ if (modifiedFiles.length > 0) {
85
+ logger.info(` Modified: ${modifiedFiles.length} files`);
86
+ }
87
+ if (addedFiles.length > 0) {
88
+ logger.info(` Added: ${addedFiles.length} files`);
89
+ }
90
+ if (removedFiles.length > 0) {
91
+ logger.info(` Removed: ${removedFiles.length} files`);
92
+ }
93
+ logger.warning('Use --force to apply all changes without confirmation');
94
+ }
@@ -0,0 +1,7 @@
1
+ export interface ValidateOptions {
2
+ config?: boolean;
3
+ templates?: boolean;
4
+ strict?: boolean;
5
+ }
6
+ export declare function validate(cwd: string, options?: ValidateOptions): Promise<void>;
7
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,wBAAsB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CA6BxF"}
@@ -0,0 +1,136 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import { z } from 'zod';
4
+ import fg from 'fast-glob';
5
+ import { logger } from '../utils/index.js';
6
+ import { FsdkConfigSchema } from '../core/index.js';
7
+ export async function validate(cwd, options = {}) {
8
+ const errors = [];
9
+ const warnings = [];
10
+ try {
11
+ if (options.config || (!options.config && !options.templates)) {
12
+ await validateConfig(cwd, errors, warnings);
13
+ }
14
+ if (options.templates || (!options.config && !options.templates)) {
15
+ await validateTemplates(cwd, errors, warnings);
16
+ }
17
+ if (errors.length > 0) {
18
+ logger.error('Validation failed with errors:');
19
+ errors.forEach((e) => logger.error(` - ${e}`));
20
+ process.exit(1);
21
+ }
22
+ if (warnings.length > 0) {
23
+ logger.warning('Validation passed with warnings:');
24
+ warnings.forEach((w) => logger.warning(` - ${w}`));
25
+ }
26
+ else {
27
+ logger.success('All validations passed!');
28
+ }
29
+ }
30
+ catch (error) {
31
+ logger.error('Validation error:', error);
32
+ throw error;
33
+ }
34
+ }
35
+ async function validateConfig(cwd, errors, warnings) {
36
+ logger.info('Validating configuration...');
37
+ const configFiles = [
38
+ '.fsdkrc.ts',
39
+ '.fsdkrc.js',
40
+ '.fsdkrc.json',
41
+ '.fsdkrc',
42
+ 'fsdk.config.ts',
43
+ 'fsdk.config.js',
44
+ 'fsdk.config.json',
45
+ ];
46
+ const foundConfig = configFiles.find((f) => fs.existsSync(path.resolve(cwd, f)));
47
+ if (!foundConfig) {
48
+ warnings.push('No .fsdkrc configuration file found, using defaults');
49
+ return;
50
+ }
51
+ try {
52
+ const configPath = path.resolve(cwd, foundConfig);
53
+ const ext = path.extname(foundConfig).toLowerCase();
54
+ let config;
55
+ if (ext === '.ts' || ext === '.js') {
56
+ const module = await import(configPath);
57
+ config = module.default || module;
58
+ }
59
+ else {
60
+ const content = await fs.readFile(configPath, 'utf-8');
61
+ config = JSON.parse(content);
62
+ }
63
+ const result = FsdkConfigSchema.safeParse(config);
64
+ if (!result.success) {
65
+ result.error.errors.forEach((e) => {
66
+ errors.push(`Config validation failed: ${e.path.join('.')} - ${e.message}`);
67
+ });
68
+ }
69
+ else {
70
+ logger.success(`Config file ${foundConfig} is valid`);
71
+ }
72
+ }
73
+ catch (error) {
74
+ if (error instanceof z.ZodError) {
75
+ error.errors.forEach((e) => {
76
+ errors.push(`Config validation failed: ${e.path.join('.')} - ${e.message}`);
77
+ });
78
+ }
79
+ else {
80
+ errors.push(`Failed to parse config file: ${error}`);
81
+ }
82
+ }
83
+ }
84
+ async function validateTemplates(cwd, errors, warnings) {
85
+ logger.info('Validating templates...');
86
+ const templateDir = path.resolve(cwd, '.fsdk', 'template');
87
+ if (!fs.existsSync(templateDir)) {
88
+ warnings.push('No template directory found');
89
+ return;
90
+ }
91
+ const templateFiles = await fg.glob('**/*', { cwd: templateDir, dot: true, onlyFiles: true });
92
+ if (templateFiles.length === 0) {
93
+ warnings.push('Template directory is empty');
94
+ return;
95
+ }
96
+ const vueFiles = templateFiles.filter((f) => String(f).endsWith('.vue'));
97
+ const tsFiles = templateFiles.filter((f) => String(f).endsWith('.ts'));
98
+ const lessFiles = templateFiles.filter((f) => String(f).endsWith('.less'));
99
+ logger.debug(`Found ${vueFiles.length} Vue files, ${tsFiles.length} TS files, ${lessFiles.length} Less files`);
100
+ let valid = true;
101
+ for (const vueFile of vueFiles) {
102
+ const content = await fs.readFile(path.resolve(templateDir, vueFile), 'utf-8');
103
+ if (!validateVueFile(content)) {
104
+ errors.push(`Invalid Vue file: ${vueFile}`);
105
+ valid = false;
106
+ }
107
+ }
108
+ for (const tsFile of tsFiles) {
109
+ const content = await fs.readFile(path.resolve(templateDir, tsFile), 'utf-8');
110
+ if (!validateTsFile(content)) {
111
+ errors.push(`Invalid TypeScript file: ${tsFile}`);
112
+ valid = false;
113
+ }
114
+ }
115
+ if (valid) {
116
+ logger.success(`Template validation passed (${templateFiles.length} files)`);
117
+ }
118
+ }
119
+ function validateVueFile(content) {
120
+ const hasTemplate = content.includes('<template>');
121
+ const hasScript = content.includes('<script');
122
+ return hasTemplate || hasScript;
123
+ }
124
+ function validateTsFile(content) {
125
+ const lines = content.split('\n');
126
+ for (const line of lines) {
127
+ const trimmed = line.trim();
128
+ if (trimmed.startsWith('//') || trimmed.startsWith('/*') || trimmed.startsWith('*')) {
129
+ continue;
130
+ }
131
+ if (trimmed.includes(':') && !trimmed.match(/^\s*\/\//)) {
132
+ return true;
133
+ }
134
+ }
135
+ return content.includes('export') || content.includes('import');
136
+ }
@@ -0,0 +1,4 @@
1
+ export declare const BASH_COMPLETION = "#!/bin/bash\n# fsdk bash completion\n\n_fsdk_completion() {\n local cur prev opts\n COMPREPLY=()\n cur=\"${COMP_WORDS[COMP_CWORD]}\"\n prev=\"${COMP_WORDS[COMP_CWORD-1]}\"\n\n opts=\"create add-page add-component add-store sync-template validate preview completion\"\n\n case \"${prev}\" in\n create)\n opts=\"--template --package-manager --eslint --no-git --no-install\"\n ;;\n add-page)\n opts=\"--router-path --page-name\"\n ;;\n add-component)\n opts=\"--type --name --dir\"\n ;;\n add-store)\n opts=\"--type --name\"\n ;;\n sync-template)\n opts=\"--template --force\"\n ;;\n validate)\n opts=\"--config --templates --strict\"\n ;;\n preview)\n opts=\"--port --host --open --template\"\n ;;\n completion)\n opts=\"bash zsh fish\"\n ;;\n esac\n\n COMPREPLY=($(compgen -W \"${opts}\" -- \"${cur}\"))\n return 0\n}\n\ncomplete -F _fsdk_completion fsdk\n";
2
+ export declare const FISH_COMPLETION = "# fsdk fish completion\n\nfunction __fsdk_commands\n echo \"create\tCreate a new application\"\n echo \"add-page\t\tAdd a new page\"\n echo \"add-component\tAdd a new component\"\n echo \"add-store\tAdd a new store\"\n echo \"sync-template\tSync template files\"\n echo \"validate\t\tValidate configuration and templates\"\n echo \"preview\t\tPreview template\"\n echo \"completion\tGenerate shell completion script\"\nend\n\nfunction __fsdk_create_app_opts\n echo \"--template\tTemplate name (base|full)\"\n echo \"--package-manager\tPackage manager (npm|pnpm|yarn|bun)\"\n echo \"--eslint\tEnable ESLint\"\n echo \"--no-git\tSkip git initialization\"\n echo \"--no-install\tSkip dependency installation\"\nend\n\nfunction __fsdk_add_page_opts\n echo \"--router-path\tRouter path\"\n echo \"--page-name\tPage name\"\nend\n\nfunction __fsdk_add_component_opts\n echo \"--type\tComponent type (page|common|business)\"\n echo \"--name\tComponent name\"\n echo \"--dir\tSubdirectory\"\nend\n\nfunction __fsdk_add_store_opts\n echo \"--type\tStore type (pinia|redux)\"\n echo \"--name\tStore name\"\nend\n\nfunction __fsdk_sync_template_opts\n echo \"--template\tTemplate name\"\n echo \"--force\tForce sync\"\nend\n\nfunction __fsdk_validate_opts\n echo \"--config\tValidate config only\"\n echo \"--templates\tValidate templates only\"\n echo \"--strict\tStrict validation\"\nend\n\nfunction __fsdk_preview_opts\n echo \"--port\tPort number\"\n echo \"--host\tHost address\"\n echo \"--open\tOpen browser\"\n echo \"--template\tTemplate name\"\nend\n\nfunction __fsdk_completion_opts\n echo \"bash\tGenerate bash completion\"\n echo \"zsh\tGenerate zsh completion\"\n echo \"fish\tGenerate fish completion\"\nend\n\ncomplete -c fsdk -f -a \"(__fsdk_commands)\"\n\ncomplete -c fsdk -n \"not __fish_seen_subcommand_from create\" -a \"(__fsdk_create_app_opts)\" --option\ncomplete -c fsdk -n \"not __fish_seen_subcommand_from add-page\" -a \"(__fsdk_add_page_opts)\" --option\ncomplete -c fsdk -n \"not __fish_seen_subcommand_from add-component\" -a \"(__fsdk_add_component_opts)\" --option\ncomplete -c fsdk -n \"not __fish_seen_subcommand_from add-store\" -a \"(__fsdk_add_store_opts)\" --option\ncomplete -c fsdk -n \"not __fish_seen_subcommand_from sync-template\" -a \"(__fsdk_sync_template_opts)\" --option\ncomplete -c fsdk -n \"not __fish_seen_subcommand_from validate\" -a \"(__fsdk_validate_opts)\" --option\ncomplete -c fsdk -n \"not __fish_seen_subcommand_from preview\" -a \"(__fsdk_preview_opts)\" --option\ncomplete -c fsdk -n \"not __fish_seen_subcommand_from completion\" -a \"(__fsdk_completion_opts)\" --option\n";
3
+ export declare const ZSH_COMPLETION = "#compdef fsdk\n\nlocal -a commands\ncommands=(\n 'create:Create a new application'\n 'add-page:Add a new page'\n 'add-component:Add a new component'\n 'add-store:Add a new store'\n 'sync-template:Sync template files'\n 'validate:Validate configuration and templates'\n 'preview:Preview template'\n 'completion:Generate shell completion script'\n)\n\n_arguments -C \\\n '1: :->command' \\\n '2: :->args' \\\n '*: :->rest'\n\ncase \"$state\" in\n command)\n _describe 'command' commands\n ;;\n args)\n case $words[1] in\n create)\n _arguments -s \\\n '--template[Template name]' \\\n '--package-manager[Package manager: npm|pnpm|yarn|bun]' \\\n '--eslint[Enable ESLint]' \\\n '--no-git[Skip git initialization]' \\\n '--no-install[Skip dependency installation]'\n ;;\n add-page)\n _arguments -s \\\n '--router-path[Router path]' \\\n '--page-name[Page name]'\n ;;\n add-component)\n _arguments -s \\\n '--type[Component type: page|common|business]' \\\n '--name[Component name]' \\\n '--dir[Subdirectory]'\n ;;\n add-store)\n _arguments -s \\\n '--type[Store type: pinia|redux]' \\\n '--name[Store name]'\n ;;\n sync-template)\n _arguments -s \\\n '--template[Template name]' \\\n '--force[Force sync]'\n ;;\n validate)\n _arguments -s \\\n '--config[Validate config only]' \\\n '--templates[Validate templates only]' \\\n '--strict[Strict validation]'\n ;;\n preview)\n _arguments -s \\\n '--port[Port number]' \\\n '--host[Host address]' \\\n '--open[Open browser]' \\\n '--template[Template name]'\n ;;\n completion)\n _arguments -s \\\n 'bash:Generate bash completion' \\\n 'zsh:Generate zsh completion' \\\n 'fish:Generate fish completion'\n ;;\n esac\n ;;\nesac\n";
4
+ //# sourceMappingURL=completion-scripts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completion-scripts.d.ts","sourceRoot":"","sources":["../../src/completion/completion-scripts.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe,68BA2C3B,CAAC;AAEF,eAAO,MAAM,eAAe,umFAuE3B,CAAC;AAEF,eAAO,MAAM,cAAc,ohEA4E1B,CAAC"}
@@ -0,0 +1,193 @@
1
+ export const BASH_COMPLETION = `#!/bin/bash
2
+ # fsdk bash completion
3
+
4
+ _fsdk_completion() {
5
+ local cur prev opts
6
+ COMPREPLY=()
7
+ cur="\${COMP_WORDS[COMP_CWORD]}"
8
+ prev="\${COMP_WORDS[COMP_CWORD-1]}"
9
+
10
+ opts="create add-page add-component add-store sync-template validate preview completion"
11
+
12
+ case "\${prev}" in
13
+ create)
14
+ opts="--template --package-manager --eslint --no-git --no-install"
15
+ ;;
16
+ add-page)
17
+ opts="--router-path --page-name"
18
+ ;;
19
+ add-component)
20
+ opts="--type --name --dir"
21
+ ;;
22
+ add-store)
23
+ opts="--type --name"
24
+ ;;
25
+ sync-template)
26
+ opts="--template --force"
27
+ ;;
28
+ validate)
29
+ opts="--config --templates --strict"
30
+ ;;
31
+ preview)
32
+ opts="--port --host --open --template"
33
+ ;;
34
+ completion)
35
+ opts="bash zsh fish"
36
+ ;;
37
+ esac
38
+
39
+ COMPREPLY=($(compgen -W "\${opts}" -- "\${cur}"))
40
+ return 0
41
+ }
42
+
43
+ complete -F _fsdk_completion fsdk
44
+ `;
45
+ export const FISH_COMPLETION = `# fsdk fish completion
46
+
47
+ function __fsdk_commands
48
+ echo "create\tCreate a new application"
49
+ echo "add-page\t\tAdd a new page"
50
+ echo "add-component\tAdd a new component"
51
+ echo "add-store\tAdd a new store"
52
+ echo "sync-template\tSync template files"
53
+ echo "validate\t\tValidate configuration and templates"
54
+ echo "preview\t\tPreview template"
55
+ echo "completion\tGenerate shell completion script"
56
+ end
57
+
58
+ function __fsdk_create_app_opts
59
+ echo "--template\tTemplate name (base|full)"
60
+ echo "--package-manager\tPackage manager (npm|pnpm|yarn|bun)"
61
+ echo "--eslint\tEnable ESLint"
62
+ echo "--no-git\tSkip git initialization"
63
+ echo "--no-install\tSkip dependency installation"
64
+ end
65
+
66
+ function __fsdk_add_page_opts
67
+ echo "--router-path\tRouter path"
68
+ echo "--page-name\tPage name"
69
+ end
70
+
71
+ function __fsdk_add_component_opts
72
+ echo "--type\tComponent type (page|common|business)"
73
+ echo "--name\tComponent name"
74
+ echo "--dir\tSubdirectory"
75
+ end
76
+
77
+ function __fsdk_add_store_opts
78
+ echo "--type\tStore type (pinia|redux)"
79
+ echo "--name\tStore name"
80
+ end
81
+
82
+ function __fsdk_sync_template_opts
83
+ echo "--template\tTemplate name"
84
+ echo "--force\tForce sync"
85
+ end
86
+
87
+ function __fsdk_validate_opts
88
+ echo "--config\tValidate config only"
89
+ echo "--templates\tValidate templates only"
90
+ echo "--strict\tStrict validation"
91
+ end
92
+
93
+ function __fsdk_preview_opts
94
+ echo "--port\tPort number"
95
+ echo "--host\tHost address"
96
+ echo "--open\tOpen browser"
97
+ echo "--template\tTemplate name"
98
+ end
99
+
100
+ function __fsdk_completion_opts
101
+ echo "bash\tGenerate bash completion"
102
+ echo "zsh\tGenerate zsh completion"
103
+ echo "fish\tGenerate fish completion"
104
+ end
105
+
106
+ complete -c fsdk -f -a "(__fsdk_commands)"
107
+
108
+ complete -c fsdk -n "not __fish_seen_subcommand_from create" -a "(__fsdk_create_app_opts)" --option
109
+ complete -c fsdk -n "not __fish_seen_subcommand_from add-page" -a "(__fsdk_add_page_opts)" --option
110
+ complete -c fsdk -n "not __fish_seen_subcommand_from add-component" -a "(__fsdk_add_component_opts)" --option
111
+ complete -c fsdk -n "not __fish_seen_subcommand_from add-store" -a "(__fsdk_add_store_opts)" --option
112
+ complete -c fsdk -n "not __fish_seen_subcommand_from sync-template" -a "(__fsdk_sync_template_opts)" --option
113
+ complete -c fsdk -n "not __fish_seen_subcommand_from validate" -a "(__fsdk_validate_opts)" --option
114
+ complete -c fsdk -n "not __fish_seen_subcommand_from preview" -a "(__fsdk_preview_opts)" --option
115
+ complete -c fsdk -n "not __fish_seen_subcommand_from completion" -a "(__fsdk_completion_opts)" --option
116
+ `;
117
+ export const ZSH_COMPLETION = `#compdef fsdk
118
+
119
+ local -a commands
120
+ commands=(
121
+ 'create:Create a new application'
122
+ 'add-page:Add a new page'
123
+ 'add-component:Add a new component'
124
+ 'add-store:Add a new store'
125
+ 'sync-template:Sync template files'
126
+ 'validate:Validate configuration and templates'
127
+ 'preview:Preview template'
128
+ 'completion:Generate shell completion script'
129
+ )
130
+
131
+ _arguments -C \\
132
+ '1: :->command' \\
133
+ '2: :->args' \\
134
+ '*: :->rest'
135
+
136
+ case "$state" in
137
+ command)
138
+ _describe 'command' commands
139
+ ;;
140
+ args)
141
+ case $words[1] in
142
+ create)
143
+ _arguments -s \\
144
+ '--template[Template name]' \\
145
+ '--package-manager[Package manager: npm|pnpm|yarn|bun]' \\
146
+ '--eslint[Enable ESLint]' \\
147
+ '--no-git[Skip git initialization]' \\
148
+ '--no-install[Skip dependency installation]'
149
+ ;;
150
+ add-page)
151
+ _arguments -s \\
152
+ '--router-path[Router path]' \\
153
+ '--page-name[Page name]'
154
+ ;;
155
+ add-component)
156
+ _arguments -s \\
157
+ '--type[Component type: page|common|business]' \\
158
+ '--name[Component name]' \\
159
+ '--dir[Subdirectory]'
160
+ ;;
161
+ add-store)
162
+ _arguments -s \\
163
+ '--type[Store type: pinia|redux]' \\
164
+ '--name[Store name]'
165
+ ;;
166
+ sync-template)
167
+ _arguments -s \\
168
+ '--template[Template name]' \\
169
+ '--force[Force sync]'
170
+ ;;
171
+ validate)
172
+ _arguments -s \\
173
+ '--config[Validate config only]' \\
174
+ '--templates[Validate templates only]' \\
175
+ '--strict[Strict validation]'
176
+ ;;
177
+ preview)
178
+ _arguments -s \\
179
+ '--port[Port number]' \\
180
+ '--host[Host address]' \\
181
+ '--open[Open browser]' \\
182
+ '--template[Template name]'
183
+ ;;
184
+ completion)
185
+ _arguments -s \\
186
+ 'bash:Generate bash completion' \\
187
+ 'zsh:Generate zsh completion' \\
188
+ 'fish:Generate fish completion'
189
+ ;;
190
+ esac
191
+ ;;
192
+ esac
193
+ `;
@@ -0,0 +1,2 @@
1
+ export { BASH_COMPLETION, ZSH_COMPLETION, FISH_COMPLETION } from './completion-scripts.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/completion/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC"}
@@ -0,0 +1 @@
1
+ export { BASH_COMPLETION, ZSH_COMPLETION, FISH_COMPLETION } from './completion-scripts.js';
@@ -0,0 +1,91 @@
1
+ import { z } from 'zod';
2
+ export declare const FsdkConfigSchema: z.ZodObject<{
3
+ template: z.ZodOptional<z.ZodString>;
4
+ packageManager: z.ZodOptional<z.ZodEnum<["npm", "pnpm", "yarn", "bun"]>>;
5
+ eslint: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
6
+ git: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
7
+ install: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
8
+ router: z.ZodOptional<z.ZodObject<{
9
+ type: z.ZodDefault<z.ZodOptional<z.ZodEnum<["hash", "history"]>>>;
10
+ base: z.ZodOptional<z.ZodString>;
11
+ }, "strip", z.ZodTypeAny, {
12
+ type: "hash" | "history";
13
+ base?: string | undefined;
14
+ }, {
15
+ type?: "hash" | "history" | undefined;
16
+ base?: string | undefined;
17
+ }>>;
18
+ store: z.ZodOptional<z.ZodObject<{
19
+ type: z.ZodDefault<z.ZodOptional<z.ZodEnum<["pinia", "redux"]>>>;
20
+ }, "strip", z.ZodTypeAny, {
21
+ type: "pinia" | "redux";
22
+ }, {
23
+ type?: "pinia" | "redux" | undefined;
24
+ }>>;
25
+ aliases: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
26
+ transforms: z.ZodOptional<z.ZodArray<z.ZodObject<{
27
+ name: z.ZodString;
28
+ options: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
29
+ }, "strip", z.ZodTypeAny, {
30
+ name: string;
31
+ options?: Record<string, unknown> | undefined;
32
+ }, {
33
+ name: string;
34
+ options?: Record<string, unknown> | undefined;
35
+ }>, "many">>;
36
+ }, "strip", z.ZodTypeAny, {
37
+ eslint: boolean;
38
+ git: boolean;
39
+ install: boolean;
40
+ template?: string | undefined;
41
+ packageManager?: "npm" | "pnpm" | "yarn" | "bun" | undefined;
42
+ router?: {
43
+ type: "hash" | "history";
44
+ base?: string | undefined;
45
+ } | undefined;
46
+ store?: {
47
+ type: "pinia" | "redux";
48
+ } | undefined;
49
+ aliases?: Record<string, string> | undefined;
50
+ transforms?: {
51
+ name: string;
52
+ options?: Record<string, unknown> | undefined;
53
+ }[] | undefined;
54
+ }, {
55
+ template?: string | undefined;
56
+ packageManager?: "npm" | "pnpm" | "yarn" | "bun" | undefined;
57
+ eslint?: boolean | undefined;
58
+ git?: boolean | undefined;
59
+ install?: boolean | undefined;
60
+ router?: {
61
+ type?: "hash" | "history" | undefined;
62
+ base?: string | undefined;
63
+ } | undefined;
64
+ store?: {
65
+ type?: "pinia" | "redux" | undefined;
66
+ } | undefined;
67
+ aliases?: Record<string, string> | undefined;
68
+ transforms?: {
69
+ name: string;
70
+ options?: Record<string, unknown> | undefined;
71
+ }[] | undefined;
72
+ }>;
73
+ export type FsdkConfig = z.infer<typeof FsdkConfigSchema>;
74
+ export interface PluginContext {
75
+ cwd: string;
76
+ config: FsdkConfig;
77
+ templatesDir: string;
78
+ pluginsDir: string;
79
+ }
80
+ export declare class ConfigLoader {
81
+ private configCache;
82
+ loadConfig(cwd?: string): Promise<FsdkConfig>;
83
+ private findConfigFile;
84
+ private parseConfigFile;
85
+ private getDefaultConfig;
86
+ clearCache(cwd?: string): void;
87
+ getDefault(): FsdkConfig;
88
+ createPluginContext(cwd: string, templatesDir: string, pluginsDir: string): PluginContext;
89
+ }
90
+ export declare const configLoader: ConfigLoader;
91
+ //# sourceMappingURL=config-loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["../../src/core/config-loader.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkB3B,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE1D,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,UAAU,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,WAAW,CAAsC;IAEnD,UAAU,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,UAAU,CAAC;IA2BlE,OAAO,CAAC,cAAc;YAqBR,eAAe;IAiB7B,OAAO,CAAC,gBAAgB;IAYxB,UAAU,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI;IAS9B,UAAU,IAAI,UAAU;IAIxB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,aAAa;CAQ1F;AAED,eAAO,MAAM,YAAY,cAAqB,CAAC"}
@@ -0,0 +1,118 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import { z } from 'zod';
4
+ import json5 from 'json5';
5
+ import { logger } from '../utils/index.js';
6
+ import { normalizePath } from '../utils/path.js';
7
+ export const FsdkConfigSchema = z.object({
8
+ template: z.string().optional(),
9
+ packageManager: z.enum(['npm', 'pnpm', 'yarn', 'bun']).optional(),
10
+ eslint: z.boolean().optional().default(true),
11
+ git: z.boolean().optional().default(true),
12
+ install: z.boolean().optional().default(true),
13
+ router: z.object({
14
+ type: z.enum(['hash', 'history']).optional().default('hash'),
15
+ base: z.string().optional(),
16
+ }).optional(),
17
+ store: z.object({
18
+ type: z.enum(['pinia', 'redux']).optional().default('pinia'),
19
+ }).optional(),
20
+ aliases: z.record(z.string()).optional(),
21
+ transforms: z.array(z.object({
22
+ name: z.string(),
23
+ options: z.record(z.unknown()).optional(),
24
+ })).optional(),
25
+ });
26
+ export class ConfigLoader {
27
+ configCache = new Map();
28
+ async loadConfig(cwd = process.cwd()) {
29
+ const cacheKey = normalizePath(cwd);
30
+ if (this.configCache.has(cacheKey)) {
31
+ return this.configCache.get(cacheKey);
32
+ }
33
+ const configPath = this.findConfigFile(cwd);
34
+ if (!configPath) {
35
+ logger.debug('No .fsdkrc.ts found, using defaults');
36
+ return this.getDefaultConfig();
37
+ }
38
+ try {
39
+ const config = await this.parseConfigFile(configPath);
40
+ const validated = FsdkConfigSchema.parse(config);
41
+ this.configCache.set(cacheKey, validated);
42
+ logger.success(`Loaded config from ${path.basename(configPath)}`);
43
+ return validated;
44
+ }
45
+ catch (error) {
46
+ if (error instanceof z.ZodError) {
47
+ logger.error('Config validation failed:', error.errors);
48
+ throw new Error(`Config validation failed: ${error.errors.map((e) => e.message).join(', ')}`);
49
+ }
50
+ throw error;
51
+ }
52
+ }
53
+ findConfigFile(cwd) {
54
+ const candidates = [
55
+ '.fsdkrc.ts',
56
+ '.fsdkrc.js',
57
+ '.fsdkrc.json',
58
+ '.fsdkrc',
59
+ 'fsdk.config.ts',
60
+ 'fsdk.config.js',
61
+ 'fsdk.config.json',
62
+ ];
63
+ for (const candidate of candidates) {
64
+ const configPath = path.resolve(cwd, candidate);
65
+ if (fs.existsSync(configPath)) {
66
+ return configPath;
67
+ }
68
+ }
69
+ return null;
70
+ }
71
+ async parseConfigFile(configPath) {
72
+ const ext = path.extname(configPath).toLowerCase();
73
+ switch (ext) {
74
+ case '.ts':
75
+ case '.js': {
76
+ const module = await import(configPath);
77
+ return module.default || module;
78
+ }
79
+ case '.json':
80
+ case '':
81
+ return json5.parse(fs.readFileSync(configPath, 'utf-8'));
82
+ default:
83
+ throw new Error(`Unsupported config file format: ${ext}`);
84
+ }
85
+ }
86
+ getDefaultConfig() {
87
+ return {
88
+ template: 'base',
89
+ packageManager: 'pnpm',
90
+ eslint: true,
91
+ git: true,
92
+ install: true,
93
+ router: { type: 'hash' },
94
+ store: { type: 'pinia' },
95
+ };
96
+ }
97
+ clearCache(cwd) {
98
+ if (cwd) {
99
+ this.configCache.delete(normalizePath(cwd));
100
+ }
101
+ else {
102
+ this.configCache.clear();
103
+ }
104
+ logger.debug('Config cache cleared');
105
+ }
106
+ getDefault() {
107
+ return this.getDefaultConfig();
108
+ }
109
+ createPluginContext(cwd, templatesDir, pluginsDir) {
110
+ return {
111
+ cwd,
112
+ config: this.getDefaultConfig(),
113
+ templatesDir,
114
+ pluginsDir,
115
+ };
116
+ }
117
+ }
118
+ export const configLoader = new ConfigLoader();