vue-feat-cli 26.9.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.
@@ -0,0 +1,18 @@
1
+ <script setup lang="ts">
2
+ interface Props {
3
+ // TODO: define component props
4
+ }
5
+
6
+ defineProps<Props>()
7
+ </script>
8
+
9
+ <template>
10
+ <div class="{{name}}">
11
+ <!-- {{Name}} -->
12
+ </div>
13
+ </template>
14
+
15
+ <style scoped>
16
+ .{{name}} {
17
+ }
18
+ </style>
@@ -0,0 +1,22 @@
1
+ import { ref, computed } from 'vue'
2
+
3
+ export function use{{Name}}() {
4
+ const state = ref<unknown>(null)
5
+
6
+ const isReady = computed(() => state.value !== null)
7
+
8
+ function set{{Name}}(value: unknown) {
9
+ state.value = value
10
+ }
11
+
12
+ function reset() {
13
+ state.value = null
14
+ }
15
+
16
+ return {
17
+ state,
18
+ isReady,
19
+ set{{Name}},
20
+ reset,
21
+ }
22
+ }
@@ -0,0 +1,29 @@
1
+ <script setup lang="ts">
2
+ import { onMounted } from 'vue'
3
+ import { use{{Name}}Page } from '../composables/use{{Name}}Page'
4
+
5
+ const { items, loading, error, load } = use{{Name}}Page()
6
+
7
+ onMounted(load)
8
+ </script>
9
+
10
+ <template>
11
+ <section class="{{name}}-view">
12
+ <h1>{{Name}}</h1>
13
+
14
+ <p v-if="loading">Loading...</p>
15
+ <p v-else-if="error">\{{ error }}</p>
16
+
17
+ <ul v-else>
18
+ <li v-for="item in items" :key="item.id">
19
+ \{{ item.id }}
20
+ </li>
21
+ </ul>
22
+ </section>
23
+ </template>
24
+
25
+ <style scoped>
26
+ .{{name}}-view {
27
+ padding: 1rem;
28
+ }
29
+ </style>
@@ -0,0 +1,28 @@
1
+ import { ref } from 'vue'
2
+ import { {{nameCamel}}Service } from '../services/{{name}}.service'
3
+ import type { {{Name}} } from '../types/{{name}}.types'
4
+
5
+ export function use{{Name}}() {
6
+ const items = ref<{{Name}}[]>([])
7
+ const loading = ref(false)
8
+ const error = ref<string | null>(null)
9
+
10
+ async function fetchAll() {
11
+ loading.value = true
12
+ error.value = null
13
+ try {
14
+ items.value = await {{nameCamel}}Service.getAll()
15
+ } catch (e) {
16
+ error.value = (e as Error).message
17
+ } finally {
18
+ loading.value = false
19
+ }
20
+ }
21
+
22
+ return {
23
+ items,
24
+ loading,
25
+ error,
26
+ fetchAll,
27
+ }
28
+ }
@@ -0,0 +1,8 @@
1
+ export * from './services/{{name}}.service'
2
+ export * from './composables/use{{Name}}Service'
3
+ export * from './composables/use{{Name}}Page'
4
+ export * from './stores/{{name}}.store'
5
+ export * from './types/{{name}}.types'
6
+ {{#if usesVueRouter}}
7
+ export * from './routes'
8
+ {{/if}}
@@ -0,0 +1,45 @@
1
+ import { ref } from 'vue'
2
+ import { use{{Name}}Service } from './use{{Name}}Service'
3
+
4
+ export function use{{Name}}Page() {
5
+ const loading = ref(false)
6
+ const error = ref<string | null>(null)
7
+
8
+ const { items, selected, fetchAll, fetchById, create, update, remove } = use{{Name}}Service()
9
+
10
+ async function load() {
11
+ loading.value = true
12
+ error.value = null
13
+ try {
14
+ await fetchAll()
15
+ } catch (e) {
16
+ error.value = (e as Error).message
17
+ } finally {
18
+ loading.value = false
19
+ }
20
+ }
21
+
22
+ async function loadById(id: string) {
23
+ loading.value = true
24
+ error.value = null
25
+ try {
26
+ await fetchById(id)
27
+ } catch (e) {
28
+ error.value = (e as Error).message
29
+ } finally {
30
+ loading.value = false
31
+ }
32
+ }
33
+
34
+ return {
35
+ items,
36
+ selected,
37
+ loading,
38
+ error,
39
+ load,
40
+ loadById,
41
+ create,
42
+ update,
43
+ remove,
44
+ }
45
+ }
@@ -0,0 +1,28 @@
1
+ import { ref } from 'vue'
2
+ import { use{{Name}}Service } from './use{{Name}}Service'
3
+
4
+ export function use{{Name}}Page() {
5
+ const loading = ref(false)
6
+ const error = ref<string | null>(null)
7
+
8
+ const { items, fetchAll } = use{{Name}}Service()
9
+
10
+ async function load() {
11
+ loading.value = true
12
+ error.value = null
13
+ try {
14
+ await fetchAll()
15
+ } catch (e) {
16
+ error.value = (e as Error).message
17
+ } finally {
18
+ loading.value = false
19
+ }
20
+ }
21
+
22
+ return {
23
+ items,
24
+ loading,
25
+ error,
26
+ load,
27
+ }
28
+ }
@@ -0,0 +1,9 @@
1
+ import type { RouteRecordRaw } from 'vue-router'
2
+
3
+ export const {{nameCamel}}Routes: RouteRecordRaw[] = [
4
+ {
5
+ path: '/{{name}}',
6
+ name: '{{name}}',
7
+ component: () => import('./views/{{Name}}View.vue'),
8
+ },
9
+ ]
@@ -0,0 +1,44 @@
1
+ import { ref } from 'vue'
2
+ import { {{nameCamel}}Service } from '../services/{{name}}.service'
3
+ import type { {{Name}}, Create{{Name}}Dto, Update{{Name}}Dto } from '../types/{{name}}.types'
4
+
5
+ export function use{{Name}}Service() {
6
+ const items = ref<{{Name}}[]>([])
7
+ const selected = ref<{{Name}} | null>(null)
8
+
9
+ async function fetchAll() {
10
+ items.value = await {{nameCamel}}Service.getAll()
11
+ }
12
+
13
+ async function fetchById(id: string) {
14
+ selected.value = await {{nameCamel}}Service.getById(id)
15
+ }
16
+
17
+ async function create(payload: Create{{Name}}Dto) {
18
+ const created = await {{nameCamel}}Service.create(payload)
19
+ items.value.push(created)
20
+ return created
21
+ }
22
+
23
+ async function update(id: string, payload: Update{{Name}}Dto) {
24
+ const updated = await {{nameCamel}}Service.update(id, payload)
25
+ const index = items.value.findIndex((i) => i.id === id)
26
+ if (index !== -1) items.value[index] = updated
27
+ return updated
28
+ }
29
+
30
+ async function remove(id: string) {
31
+ await {{nameCamel}}Service.remove(id)
32
+ items.value = items.value.filter((i) => i.id !== id)
33
+ }
34
+
35
+ return {
36
+ items,
37
+ selected,
38
+ fetchAll,
39
+ fetchById,
40
+ create,
41
+ update,
42
+ remove,
43
+ }
44
+ }
@@ -0,0 +1,16 @@
1
+ import { ref } from 'vue'
2
+ import { {{nameCamel}}Service } from '../services/{{name}}.service'
3
+ import type { {{Name}} } from '../types/{{name}}.types'
4
+
5
+ export function use{{Name}}Service() {
6
+ const items = ref<{{Name}}[]>([])
7
+
8
+ async function fetchAll() {
9
+ items.value = await {{nameCamel}}Service.getAll()
10
+ }
11
+
12
+ return {
13
+ items,
14
+ fetchAll,
15
+ }
16
+ }
@@ -0,0 +1,26 @@
1
+ import { httpClient } from '{{alias}}/shared/http/client'
2
+ import type { {{Name}}, Create{{Name}}Dto, Update{{Name}}Dto } from '../types/{{name}}.types'
3
+
4
+ const RESOURCE = '/{{name}}'
5
+
6
+ export const {{nameCamel}}Service = {
7
+ async getAll(): Promise<{{Name}}[]> {
8
+ return httpClient.get<{{Name}}[]>(RESOURCE)
9
+ },
10
+
11
+ async getById(id: string): Promise<{{Name}}> {
12
+ return httpClient.get<{{Name}}>(`${RESOURCE}/${id}`)
13
+ },
14
+
15
+ async create(payload: Create{{Name}}Dto): Promise<{{Name}}> {
16
+ return httpClient.post<{{Name}}>(RESOURCE, payload)
17
+ },
18
+
19
+ async update(id: string, payload: Update{{Name}}Dto): Promise<{{Name}}> {
20
+ return httpClient.put<{{Name}}>(`${RESOURCE}/${id}`, payload)
21
+ },
22
+
23
+ async remove(id: string): Promise<void> {
24
+ return httpClient.delete<void>(`${RESOURCE}/${id}`)
25
+ },
26
+ }
@@ -0,0 +1,15 @@
1
+ import { httpClient } from '{{alias}}/shared/http/client'
2
+ import type { {{Name}} } from '../types/{{name}}.types'
3
+
4
+ const RESOURCE = '/{{name}}'
5
+
6
+ export const {{nameCamel}}Service = {
7
+ async getAll(): Promise<{{Name}}[]> {
8
+ return httpClient.get<{{Name}}[]>(RESOURCE)
9
+ },
10
+
11
+ // Example with query params:
12
+ // async search(query: string): Promise<{{Name}}[]> {
13
+ // return httpClient.get<{{Name}}[]>(RESOURCE, { params: { q: query } })
14
+ // },
15
+ }
@@ -0,0 +1,28 @@
1
+ import { reactive, readonly } from 'vue'
2
+ import type { {{Name}} } from '../types/{{name}}.types'
3
+
4
+ interface {{Name}}State {
5
+ items: {{Name}}[]
6
+ selected: {{Name}} | null
7
+ }
8
+
9
+ const state = reactive<{{Name}}State>({
10
+ items: [],
11
+ selected: null,
12
+ })
13
+
14
+ export function use{{Name}}Store() {
15
+ function setItems(items: {{Name}}[]) {
16
+ state.items = items
17
+ }
18
+
19
+ function select(item: {{Name}}) {
20
+ state.selected = item
21
+ }
22
+
23
+ return {
24
+ state: readonly(state),
25
+ setItems,
26
+ select,
27
+ }
28
+ }
@@ -0,0 +1,26 @@
1
+ import { computed, ref } from 'vue'
2
+ import { defineStore } from 'pinia'
3
+ import type { {{Name}} } from '../types/{{name}}.types'
4
+
5
+ export const use{{Name}}Store = defineStore('{{nameCamel}}', () => {
6
+ const items = ref<{{Name}}[]>([])
7
+ const selected = ref<{{Name}} | null>(null)
8
+
9
+ const count = computed(() => items.value.length)
10
+
11
+ function setItems(newItems: {{Name}}[]) {
12
+ items.value = newItems
13
+ }
14
+
15
+ function select(item: {{Name}}) {
16
+ selected.value = item
17
+ }
18
+
19
+ return {
20
+ items,
21
+ selected,
22
+ count,
23
+ setItems,
24
+ select,
25
+ }
26
+ })
@@ -0,0 +1,7 @@
1
+ export interface {{Name}} {
2
+ id: string
3
+ // TODO: add domain fields
4
+ }
5
+
6
+ export type Create{{Name}}Dto = Omit<{{Name}}, 'id'>
7
+ export type Update{{Name}}Dto = Partial<Create{{Name}}Dto>
@@ -0,0 +1,4 @@
1
+ export interface {{Name}} {
2
+ id: string
3
+ // TODO: add domain fields
4
+ }
@@ -0,0 +1,25 @@
1
+ import axios from 'axios'
2
+
3
+ const instance = axios.create({
4
+ baseURL: import.meta.env.VITE_API_BASE_URL ?? '',
5
+ headers: {
6
+ 'Content-Type': 'application/json',
7
+ },
8
+ })
9
+
10
+ export const httpClient = {
11
+ get: async <T>(url: string, config?: Parameters<typeof instance.get>[1]) =>
12
+ (await instance.get<T>(url, config)).data,
13
+
14
+ post: async <T>(url: string, body?: unknown, config?: Parameters<typeof instance.post>[2]) =>
15
+ (await instance.post<T>(url, body, config)).data,
16
+
17
+ put: async <T>(url: string, body?: unknown, config?: Parameters<typeof instance.put>[2]) =>
18
+ (await instance.put<T>(url, body, config)).data,
19
+
20
+ patch: async <T>(url: string, body?: unknown, config?: Parameters<typeof instance.patch>[2]) =>
21
+ (await instance.patch<T>(url, body, config)).data,
22
+
23
+ delete: async <T>(url: string, config?: Parameters<typeof instance.delete>[1]) =>
24
+ (await instance.delete<T>(url, config)).data,
25
+ }
@@ -0,0 +1,58 @@
1
+ const BASE_URL = import.meta.env.VITE_API_BASE_URL ?? ''
2
+
3
+ interface RequestOptions extends RequestInit {
4
+ params?: Record<string, string | number | boolean>
5
+ }
6
+
7
+ function buildUrl(path: string, params?: RequestOptions['params']) {
8
+ const full = path.startsWith('http') ? path : `${BASE_URL}${path}`
9
+ if (!params) return full
10
+
11
+ // Avoid `new URL()` here: it throws on a relative `full` (e.g. "/job") when
12
+ // BASE_URL is unset, which is the default right after scaffolding.
13
+ const query = new URLSearchParams(
14
+ Object.entries(params).map(([key, value]) => [key, String(value)]),
15
+ ).toString()
16
+
17
+ if (!query) return full
18
+ return `${full}${full.includes('?') ? '&' : '?'}${query}`
19
+ }
20
+
21
+ async function request<T>(path: string, options: RequestOptions = {}): Promise<T> {
22
+ const { params, ...init } = options
23
+
24
+ const response = await fetch(buildUrl(path, params), {
25
+ headers: {
26
+ 'Content-Type': 'application/json',
27
+ ...init.headers,
28
+ },
29
+ ...init,
30
+ })
31
+
32
+ if (!response.ok) {
33
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`)
34
+ }
35
+
36
+ if (response.status === 204) {
37
+ return undefined as T
38
+ }
39
+
40
+ return response.json() as Promise<T>
41
+ }
42
+
43
+ export const httpClient = {
44
+ get: <T>(path: string, options?: RequestOptions) =>
45
+ request<T>(path, { ...options, method: 'GET' }),
46
+
47
+ post: <T>(path: string, body?: unknown, options?: RequestOptions) =>
48
+ request<T>(path, { ...options, method: 'POST', body: JSON.stringify(body) }),
49
+
50
+ put: <T>(path: string, body?: unknown, options?: RequestOptions) =>
51
+ request<T>(path, { ...options, method: 'PUT', body: JSON.stringify(body) }),
52
+
53
+ patch: <T>(path: string, body?: unknown, options?: RequestOptions) =>
54
+ request<T>(path, { ...options, method: 'PATCH', body: JSON.stringify(body) }),
55
+
56
+ delete: <T>(path: string, options?: RequestOptions) =>
57
+ request<T>(path, { ...options, method: 'DELETE' }),
58
+ }
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "vue-feat-cli",
3
+ "version": "26.9.0",
4
+ "description": "",
5
+ "main": "./dist/cli.js",
6
+ "files": [
7
+ "dist",
8
+ "bin"
9
+ ],
10
+ "scripts": {
11
+ "test": "vitest run",
12
+ "test:watch": "vitest",
13
+ "test:coverage": "vitest run --coverage",
14
+ "dev": "tsx src/cli.ts",
15
+ "build": "tsup src/cli.ts --format esm --dts",
16
+ "prepublishOnly": "npm run build"
17
+ },
18
+ "keywords": [],
19
+ "author": "",
20
+ "license": "ISC",
21
+ "type": "module",
22
+ "bin": {
23
+ "vf": "bin/vf.js"
24
+ },
25
+ "dependencies": {
26
+ "@clack/prompts": "^1.5.1",
27
+ "cac": "^7.0.0",
28
+ "fs-extra": "^11.3.5",
29
+ "handlebars": "^4.7.9",
30
+ "prettier": "^3.8.4"
31
+ },
32
+ "devDependencies": {
33
+ "@types/fs-extra": "^11.0.4",
34
+ "@types/node": "^25.9.3",
35
+ "@vitest/coverage-v8": "^5.0.0",
36
+ "tsup": "^8.5.1",
37
+ "tsx": "^4.22.4",
38
+ "typescript": "^6.0.3",
39
+ "vitest": "^5.0.0"
40
+ }
41
+ }