@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
package/README.md ADDED
@@ -0,0 +1,150 @@
1
+ # @lumiflora/fsdk
2
+
3
+ Vue 3 前端项目脚手架 CLI 工具,快速创建包含最佳技术栈的项目骨架。
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ npm install -g @lumiflora/fsdk
9
+ ```
10
+
11
+ ## 快速开始
12
+
13
+ ```bash
14
+ # 交互式创建项目
15
+ fsdk create
16
+
17
+ # 指定参数创建
18
+ fsdk create my-project --template full --package-manager pnpm
19
+ ```
20
+
21
+ ## 命令
22
+
23
+ ### create - 创建新项目
24
+
25
+ ```bash
26
+ fsdk create [project-name] [options]
27
+
28
+ Options:
29
+ --template <name> 模板名称 (base|full) [default: base]
30
+ --package-manager <pm> 包管理器 (npm|pnpm|yarn|bun) [default: pnpm]
31
+ --eslint 启用 ESLint [default: true]
32
+ --no-git 跳过 git 初始化
33
+ --no-install 跳过依赖安装
34
+ ```
35
+
36
+ ### add-page - 添加页面
37
+
38
+ ```bash
39
+ fsdk add-page [options]
40
+
41
+ Options:
42
+ --page-name <name> 页面名称
43
+ --router-path <path> 路由路径
44
+ ```
45
+
46
+ ### add-component - 添加组件
47
+
48
+ ```bash
49
+ fsdk add-component [options]
50
+
51
+ Options:
52
+ --name <name> 组件名称
53
+ --type <type> 组件类型 (page|common|business) [default: common]
54
+ --dir <dir> 子目录
55
+ ```
56
+
57
+ ### add-store - 添加状态管理
58
+
59
+ ```bash
60
+ fsdk add-store [options]
61
+
62
+ Options:
63
+ --name <name> Store 名称
64
+ --type <type> Store 类型 (pinia|redux) [default: pinia]
65
+ ```
66
+
67
+ ### validate - 校验配置和模板
68
+
69
+ ```bash
70
+ fsdk validate [options]
71
+
72
+ Options:
73
+ --config 仅校验配置
74
+ --templates 仅校验模板
75
+ --strict 严格校验
76
+ ```
77
+
78
+ ### preview - 预览模板
79
+
80
+ ```bash
81
+ fsdk preview [options]
82
+
83
+ Options:
84
+ --port <port> 端口号 [default: 3000]
85
+ --host <host> 主机地址 [default: localhost]
86
+ --open 打开浏览器
87
+ --template <name> 模板名称
88
+ ```
89
+
90
+ ### sync-template - 同步模板文件
91
+
92
+ ```bash
93
+ fsdk sync-template [options]
94
+
95
+ Options:
96
+ --template <name> 模板名称
97
+ --force 强制同步
98
+ ```
99
+
100
+ ### completion - 生成 Shell 补全
101
+
102
+ ```bash
103
+ fsdk completion [shell] [options]
104
+
105
+ Options:
106
+ --install 自动安装到 shell 配置
107
+
108
+ # 示例
109
+ fsdk completion --install # 自动配置当前 shell
110
+ fsdk completion zsh --install
111
+ fsdk completion bash --install
112
+ ```
113
+
114
+ ## 模板
115
+
116
+ | 模板 | 说明 |
117
+ |------|------|
118
+ | `base` | Vue 3.5 + Vite 6 基础版 |
119
+ | `full` | Vue 3.5 + Vite 6 + Element Plus + Pinia + Vue Router + SCSS + ESLint |
120
+
121
+ ## 技术栈
122
+
123
+ | 技术 | 版本 | 用途 |
124
+ |------|------|------|
125
+ | Vue | ^3.5.0 | 前端框架 |
126
+ | Vue Router | ^4.4.0 | 路由(文件路由系统) |
127
+ | Pinia | ^2.2.0 | 状态管理 |
128
+ | Element Plus | ^2.8.0 | UI 组件库 |
129
+ | Vite | ^6.0.0 | 构建工具 |
130
+ | TypeScript | ~5.6.0 | 类型系统 |
131
+ | ESLint | ^9.0.0 | 代码检查 |
132
+
133
+ ## 开发
134
+
135
+ ```bash
136
+ # 本地开发
137
+ cd packages/cli
138
+ pnpm install
139
+ pnpm dev
140
+
141
+ # 构建
142
+ pnpm build
143
+
144
+ # 类型检查
145
+ pnpm typecheck
146
+ ```
147
+
148
+ ## License
149
+
150
+ MIT
@@ -0,0 +1,7 @@
1
+ export interface AddComponentOptions {
2
+ type?: 'page' | 'common' | 'business';
3
+ name?: string;
4
+ dir?: string;
5
+ }
6
+ export declare function addComponent(cwd: string, options?: AddComponentOptions): Promise<void>;
7
+ //# sourceMappingURL=add-component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add-component.d.ts","sourceRoot":"","sources":["../../src/commands/add-component.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAC;IACtC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBhG"}
@@ -0,0 +1,93 @@
1
+ import prompts from 'prompts';
2
+ import fs from 'fs-extra';
3
+ import path from 'path';
4
+ import { logger, toKebabCase } from '../utils/index.js';
5
+ export async function addComponent(cwd, options = {}) {
6
+ try {
7
+ const resolvedOptions = await resolveOptions(options);
8
+ const { type, name, dir } = resolvedOptions;
9
+ const componentDir = path.resolve(cwd, 'src', 'components', type, dir || '');
10
+ await fs.ensureDir(componentDir);
11
+ const componentTemplate = generateComponentTemplate(name, type);
12
+ await Promise.all([
13
+ fs.writeFile(path.resolve(componentDir, `${name}.vue`), componentTemplate.component),
14
+ fs.writeFile(path.resolve(componentDir, `${name}.less`), componentTemplate.styles),
15
+ fs.writeFile(path.resolve(componentDir, `index.ts`), componentTemplate.index),
16
+ ]);
17
+ logger.success(`Component ${name} created at src/components/${type}/${dir || name}/`);
18
+ }
19
+ catch (error) {
20
+ logger.error('Failed to add component:', error);
21
+ throw error;
22
+ }
23
+ }
24
+ async function resolveOptions(options) {
25
+ if (options.type && options.name) {
26
+ return {
27
+ type: options.type,
28
+ name: options.name,
29
+ dir: options.dir || '',
30
+ };
31
+ }
32
+ const responses = await prompts([
33
+ {
34
+ type: 'select',
35
+ name: 'type',
36
+ message: 'Select component type',
37
+ choices: [
38
+ { title: 'Common', value: 'common', description: 'Shared components' },
39
+ { title: 'Business', value: 'business', description: 'Business-specific components' },
40
+ { title: 'Page', value: 'page', description: 'Page-specific components' },
41
+ ],
42
+ initial: 0,
43
+ },
44
+ {
45
+ type: 'text',
46
+ name: 'name',
47
+ message: 'What is the component name?',
48
+ initial: 'my-component',
49
+ validate: (value) => /^[A-Z][a-zA-Z0-9]*$/.test(value) || 'Start with uppercase letter',
50
+ },
51
+ {
52
+ type: 'text',
53
+ name: 'dir',
54
+ message: 'Subdirectory (optional):',
55
+ initial: '',
56
+ },
57
+ ]);
58
+ return {
59
+ type: options.type || responses.type,
60
+ name: options.name || responses.name,
61
+ dir: options.dir || responses.dir || '',
62
+ };
63
+ }
64
+ function generateComponentTemplate(name, type) {
65
+ const component = `<template>
66
+ <div class="${toKebabCase(name)}">
67
+ <slot></slot>
68
+ </div>
69
+ </template>
70
+
71
+ <script setup lang="ts">
72
+ defineOptions({
73
+ name: '${name}',
74
+ inheritAttrs: true,
75
+ });
76
+ </script>
77
+
78
+ <style scoped lang="less">
79
+ .${toKebabCase(name)} {
80
+ display: block;
81
+ }
82
+ </style>
83
+ `;
84
+ const styles = `// ${name} component styles
85
+ .${toKebabCase(name)} {
86
+ // component styles
87
+ }
88
+ `;
89
+ const index = `export { default as ${name} } from './${name}.vue';
90
+ export type { } from './${name}.vue';
91
+ `;
92
+ return { component, styles, index };
93
+ }
@@ -0,0 +1,8 @@
1
+ export interface AddPageOptions {
2
+ routerPath?: string;
3
+ pageName?: string;
4
+ type?: 'page' | 'component';
5
+ }
6
+ export declare function addPage(cwd: string, options?: AddPageOptions): Promise<void>;
7
+ export declare function syncPageRoutes(cwd: string): Promise<void>;
8
+ //# sourceMappingURL=add-page.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add-page.d.ts","sourceRoot":"","sources":["../../src/commands/add-page.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,cAAc;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC;CAC7B;AAED,wBAAsB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkCtF;AA8DD,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAS/D"}
@@ -0,0 +1,98 @@
1
+ import prompts from 'prompts';
2
+ import fs from 'fs-extra';
3
+ import path from 'path';
4
+ import { logger, toPascalCase, toKebabCase } from '../utils/index.js';
5
+ import fg from 'fast-glob';
6
+ export async function addPage(cwd, options = {}) {
7
+ // Early check: if pageName is provided, verify directory doesn't exist
8
+ if (options.pageName) {
9
+ const pageDir = path.resolve(cwd, 'src', 'views', options.pageName);
10
+ if (fs.existsSync(pageDir)) {
11
+ logger.error(`Page directory ${options.pageName} already exists`);
12
+ throw new Error(`Page directory ${options.pageName} already exists`);
13
+ }
14
+ }
15
+ try {
16
+ const resolvedOptions = await resolveOptions(options);
17
+ const { pageName, routerPath } = resolvedOptions;
18
+ const pageDir = path.resolve(cwd, 'src', 'views', pageName);
19
+ if (fs.existsSync(pageDir)) {
20
+ logger.error(`Page directory ${pageName} already exists`);
21
+ throw new Error(`Page directory ${pageName} already exists`);
22
+ }
23
+ await fs.ensureDir(pageDir);
24
+ const pageTemplate = generatePageTemplate(pageName, routerPath);
25
+ await Promise.all([
26
+ fs.writeFile(path.resolve(pageDir, 'index.vue'), pageTemplate.page),
27
+ fs.writeFile(path.resolve(pageDir, 'index.less'), pageTemplate.styles),
28
+ ]);
29
+ logger.success(`Page ${pageName} created at src/views/${pageName}/`);
30
+ logger.info(`Router path: ${routerPath}`);
31
+ }
32
+ catch (error) {
33
+ logger.error('Failed to add page:', error);
34
+ throw error;
35
+ }
36
+ }
37
+ async function resolveOptions(options) {
38
+ if (options.pageName && options.routerPath) {
39
+ return {
40
+ pageName: options.pageName,
41
+ routerPath: options.routerPath,
42
+ };
43
+ }
44
+ const responses = await prompts([
45
+ {
46
+ type: 'text',
47
+ name: 'pageName',
48
+ message: 'What is the page name?',
49
+ initial: 'about',
50
+ validate: (value) => /^[a-z][a-z0-9-]*$/.test(value) || 'Start with lowercase letter, only lowercase letters, numbers, and hyphens',
51
+ },
52
+ {
53
+ type: 'text',
54
+ name: 'routerPath',
55
+ message: 'Enter the router path:',
56
+ initial: (prev) => `/${toKebabCase(prev)}`,
57
+ },
58
+ ]);
59
+ return {
60
+ pageName: options.pageName || responses.pageName,
61
+ routerPath: options.routerPath || responses.routerPath,
62
+ };
63
+ }
64
+ function generatePageTemplate(pageName, routerPath) {
65
+ const componentName = toPascalCase(pageName);
66
+ const page = `<template>
67
+ <div class="${pageName}-page">
68
+ <h1>${componentName}</h1>
69
+ <p>Router path: ${routerPath}</p>
70
+ </div>
71
+ </template>
72
+
73
+ <script setup lang="ts">
74
+ // ${componentName} page component
75
+ </script>
76
+
77
+ <style scoped lang="less">
78
+ .${pageName}-page {
79
+ padding: 20px;
80
+ }
81
+ </style>
82
+ `;
83
+ const styles = `// ${componentName} page styles
84
+ .${pageName}-page {
85
+ min-height: 100vh;
86
+ }
87
+ `;
88
+ return { page, styles };
89
+ }
90
+ export async function syncPageRoutes(cwd) {
91
+ const viewsDir = path.resolve(cwd, 'src', 'views');
92
+ if (!fs.existsSync(viewsDir)) {
93
+ logger.warning('Views directory does not exist');
94
+ return;
95
+ }
96
+ const pageDirs = await fg.glob('*', { cwd: viewsDir, onlyDirectories: true });
97
+ logger.success(`Found ${pageDirs.length} pages to sync routes`);
98
+ }
@@ -0,0 +1,6 @@
1
+ export interface AddStoreOptions {
2
+ name?: string;
3
+ type?: 'pinia' | 'redux';
4
+ }
5
+ export declare function addStore(cwd: string, options?: AddStoreOptions): Promise<void>;
6
+ //# sourceMappingURL=add-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add-store.d.ts","sourceRoot":"","sources":["../../src/commands/add-store.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;CAC1B;AAED,wBAAsB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBxF"}
@@ -0,0 +1,204 @@
1
+ import prompts from 'prompts';
2
+ import fs from 'fs-extra';
3
+ import path from 'path';
4
+ import { logger, toPascalCase } from '../utils/index.js';
5
+ export async function addStore(cwd, options = {}) {
6
+ try {
7
+ const resolvedOptions = await resolveOptions(options);
8
+ const { name, type } = resolvedOptions;
9
+ const storeDir = path.resolve(cwd, 'src', 'stores');
10
+ await fs.ensureDir(storeDir);
11
+ const storeTemplate = generateStoreTemplate(name, type);
12
+ await Promise.all([
13
+ fs.writeFile(path.resolve(storeDir, `${name}.ts`), storeTemplate.store),
14
+ fs.writeFile(path.resolve(storeDir, `${name}.test.ts`), storeTemplate.test),
15
+ ]);
16
+ logger.success(`Store ${name} created at src/stores/`);
17
+ }
18
+ catch (error) {
19
+ logger.error('Failed to add store:', error);
20
+ throw error;
21
+ }
22
+ }
23
+ async function resolveOptions(options) {
24
+ if (options.name && options.type) {
25
+ return {
26
+ name: options.name,
27
+ type: options.type,
28
+ };
29
+ }
30
+ const responses = await prompts([
31
+ {
32
+ type: 'text',
33
+ name: 'name',
34
+ message: 'What is the store name?',
35
+ initial: 'user',
36
+ validate: (value) => /^[a-z][a-z0-9]*$/.test(value) || 'Start with lowercase letter',
37
+ },
38
+ {
39
+ type: 'select',
40
+ name: 'type',
41
+ message: 'Select store type',
42
+ choices: [
43
+ { title: 'Pinia', value: 'pinia', description: 'Vue 3 state management' },
44
+ { title: 'Redux', value: 'redux', description: 'Predictable state container' },
45
+ ],
46
+ initial: 0,
47
+ },
48
+ ]);
49
+ return {
50
+ name: options.name || responses.name,
51
+ type: options.type || responses.type,
52
+ };
53
+ }
54
+ function generateStoreTemplate(name, type) {
55
+ if (type === 'pinia') {
56
+ return generatePiniaTemplate(name);
57
+ }
58
+ return generateReduxTemplate(name);
59
+ }
60
+ function generatePiniaTemplate(name) {
61
+ const store = `import { defineStore } from 'pinia';
62
+ import { ref, computed } from 'vue';
63
+
64
+ export const use${toPascalCase(name)}Store = defineStore('${name}', () => {
65
+ // State
66
+ const data = ref<unknown>(null);
67
+ const loading = ref(false);
68
+ const error = ref<string | null>(null);
69
+
70
+ // Getters
71
+ const hasData = computed(() => data.value !== null);
72
+
73
+ // Actions
74
+ async function fetchData() {
75
+ loading.value = true;
76
+ error.value = null;
77
+ try {
78
+ // Replace with actual API call when implementing real data fetching
79
+ // Example: data.value = await api.get('/endpoint');
80
+ data.value = null;
81
+ } catch (e) {
82
+ error.value = e instanceof Error ? e.message : 'Unknown error';
83
+ throw e;
84
+ } finally {
85
+ loading.value = false;
86
+ }
87
+ }
88
+
89
+ function setData(newData: unknown) {
90
+ data.value = newData;
91
+ }
92
+
93
+ function reset() {
94
+ data.value = null;
95
+ error.value = null;
96
+ }
97
+
98
+ return {
99
+ data,
100
+ loading,
101
+ error,
102
+ hasData,
103
+ fetchData,
104
+ setData,
105
+ reset,
106
+ };
107
+ });
108
+ `;
109
+ const test = `import { setActivePinia, createPinia } from 'pinia';
110
+ import { describe, it, expect, beforeEach } from 'vitest';
111
+ import { use${toPascalCase(name)}Store } from './${name}';
112
+
113
+ describe('${name} store', () => {
114
+ beforeEach(() => {
115
+ setActivePinia(createPinia());
116
+ });
117
+
118
+ it('should initialize with default values', () => {
119
+ const store = use${toPascalCase(name)}Store();
120
+ expect(store.data).toBeNull();
121
+ expect(store.loading).toBe(false);
122
+ expect(store.error).toBeNull();
123
+ });
124
+
125
+ it('should set data', () => {
126
+ const store = use${toPascalCase(name)}Store();
127
+ store.setData({ test: 'value' });
128
+ expect(store.data).toEqual({ test: 'value' });
129
+ });
130
+
131
+ it('should reset state', () => {
132
+ const store = use${toPascalCase(name)}Store();
133
+ store.setData({ test: 'value' });
134
+ store.reset();
135
+ expect(store.data).toBeNull();
136
+ });
137
+ });
138
+ `;
139
+ return { store, test };
140
+ }
141
+ function generateReduxTemplate(name) {
142
+ const store = `import { configureStore, createSlice, PayloadAction } from '@reduxjs/toolkit';
143
+
144
+ interface ${toPascalCase(name)}State {
145
+ data: unknown;
146
+ loading: boolean;
147
+ error: string | null;
148
+ }
149
+
150
+ const initialState: ${toPascalCase(name)}State = {
151
+ data: null,
152
+ loading: false,
153
+ error: null,
154
+ };
155
+
156
+ const ${name}Slice = createSlice({
157
+ name: '${name}',
158
+ initialState,
159
+ reducers: {
160
+ setData: (state, action: PayloadAction<unknown>) => {
161
+ state.data = action.payload;
162
+ },
163
+ setLoading: (state, action: PayloadAction<boolean>) => {
164
+ state.loading = action.payload;
165
+ },
166
+ setError: (state, action: PayloadAction<string | null>) => {
167
+ state.error = action.payload;
168
+ },
169
+ reset: () => initialState,
170
+ },
171
+ });
172
+
173
+ export const { setData, setLoading, setError, reset } = ${name}Slice.actions;
174
+ export default ${name}Slice.reducer;
175
+
176
+ export const ${name}Store = configureStore({
177
+ reducer: {
178
+ ${name}: ${name}Slice.reducer,
179
+ },
180
+ });
181
+
182
+ export type RootState = ReturnType<typeof ${name}Store.getState>;
183
+ export type AppDispatch = typeof ${name}Store.dispatch;
184
+ `;
185
+ const test = `import { describe, it, expect } from 'vitest';
186
+ import { ${name}Slice } from './${name}';
187
+
188
+ describe('${name} slice', () => {
189
+ it('should return the initial state', () => {
190
+ expect(${name}Slice.reducer(undefined, { type: 'unknown' })).toEqual({
191
+ data: null,
192
+ loading: false,
193
+ error: null,
194
+ });
195
+ });
196
+
197
+ it('should handle setData', () => {
198
+ const actual = ${name}Slice.reducer(undefined, ${name}Slice.actions.setData({ test: 'value' }));
199
+ expect(actual.data).toEqual({ test: 'value' });
200
+ });
201
+ });
202
+ `;
203
+ return { store, test };
204
+ }
@@ -0,0 +1,8 @@
1
+ export type ShellType = 'bash' | 'zsh' | 'fish';
2
+ export interface CompletionOptions {
3
+ shell?: ShellType;
4
+ output?: string;
5
+ install?: boolean;
6
+ }
7
+ export declare function generateCompletion(options?: CompletionOptions): Promise<void>;
8
+ //# sourceMappingURL=completion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completion.d.ts","sourceRoot":"","sources":["../../src/commands/completion.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;AAEhD,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAoLD,wBAAsB,kBAAkB,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CA+BvF"}