fix: cli installation error

This commit is contained in:
zernonia 2023-09-06 12:55:50 +08:00
parent bc545c95e4
commit ec0c3cc659
12 changed files with 167 additions and 162 deletions

1
.gitignore vendored
View File

@ -7,6 +7,7 @@ yarn-error.log*
pnpm-debug.log* pnpm-debug.log*
lerna-debug.log* lerna-debug.log*
.env
node_modules node_modules
.DS_Store .DS_Store
dist dist

View File

@ -292,74 +292,41 @@ Add the following to your `src/app.postcss` file. You can learn more about using
You'll want to create a `cn` helper to make it easier to conditionally add Tailwind CSS classes. Additionally, you'll want to add the custom transition that is used by various components. You'll want to create a `cn` helper to make it easier to conditionally add Tailwind CSS classes. Additionally, you'll want to add the custom transition that is used by various components.
```ts title="src/lib/utils.ts" ```ts title="src/lib/utils.ts"
import type { Updater } from '@tanstack/vue-table'
import { type ClassValue, clsx } from 'clsx' import { type ClassValue, clsx } from 'clsx'
import { twMerge } from 'tailwind-merge' import { twMerge } from 'tailwind-merge'
import { cubicOut } from 'svelte/easing' import { type Ref, camelize, getCurrentInstance, toHandlerKey } from 'vue'
import type { TransitionConfig } from 'svelte/transition'
export function cn(...inputs: ClassValue[]) { export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs)) return twMerge(clsx(inputs))
} }
interface FlyAndScaleParams { // Vue doesn't have emits forwarding, in order to bind the emits we have to convert events into `onXXX` handlers
y?: number // issue: https://github.com/vuejs/core/issues/5917
x?: number export function useEmitAsProps<Name extends string>(
start?: number emit: (name: Name, ...args: any[]) => void,
duration?: number ) {
const vm = getCurrentInstance()
const events = vm?.type.emits as Name[]
const result: Record<string, any> = {}
if (!events?.length) {
console.warn(
`No emitted event found. Please check component: ${vm?.type.__name}`,
)
}
events?.forEach((ev) => {
result[toHandlerKey(camelize(ev))] = (...arg: any) => emit(ev, ...arg)
})
return result
} }
export function flyAndScale(node: Element, export function valueUpdater<T extends Updater<any>>(updaterOrValue: T, ref: Ref) {
params: FlyAndScaleParams = { y: -8, x: 0, start: 0.95, duration: 150 }): TransitionConfig { ref.value
const style = getComputedStyle(node) = typeof updaterOrValue === 'function'
const transform = style.transform === 'none' ? '' : style.transform ? updaterOrValue(ref.value)
: updaterOrValue
const scaleConversion = (
valueA: number,
scaleA: [number, number],
scaleB: [number, number]
) => {
const [minA, maxA] = scaleA
const [minB, maxB] = scaleB
const percentage = (valueA - minA) / (maxA - minA)
const valueB = percentage * (maxB - minB) + minB
return valueB
}
const styleToString = (
style: Record<string, number | string | undefined>
): string => {
return Object.keys(style).reduce((str, key) => {
if (style[key] === undefined)
return str
return `${str + key}:${style[key]};`
}, '')
}
return {
duration: params.duration ?? 200,
delay: 0,
css: (t) => {
const y = scaleConversion(t, [0, 1], [params.y ?? 5, 0])
const x = scaleConversion(t, [0, 1], [params.x ?? 0, 0])
const scale = scaleConversion(t, [0, 1], [params.start ?? 0.95, 1])
return styleToString({
transform:
`${transform
}translate3d(${
x
}px, ${
y
}px, 0) scale(${
scale
})`,
opacity: t
})
},
easing: cubicOut
}
} }
``` ```

View File

@ -1,13 +1,7 @@
import type { Updater } from '@tanstack/vue-table' import type { Updater } from '@tanstack/vue-table'
import type { ClassValue } from 'clsx' import { type ClassValue, clsx } from 'clsx'
import { clsx } from 'clsx'
import { twMerge } from 'tailwind-merge' import { twMerge } from 'tailwind-merge'
import type { FunctionalComponent, Ref } from 'vue' import { type Ref, camelize, getCurrentInstance, toHandlerKey } from 'vue'
import { camelize, defineComponent, getCurrentInstance, h, toHandlerKey } from 'vue'
export type ParseEmits<T extends Record<string, any>> = {
[K in keyof T]: (...args: T[K]) => void;
}
export function cn(...inputs: ClassValue[]) { export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs)) return twMerge(clsx(inputs))
@ -34,15 +28,19 @@ export function useEmitAsProps<Name extends string>(
return result return result
} }
export function convertToComponent(component: FunctionalComponent) {
return defineComponent({
setup() { return () => h(component) },
})
}
export function valueUpdater<T extends Updater<any>>(updaterOrValue: T, ref: Ref) { export function valueUpdater<T extends Updater<any>>(updaterOrValue: T, ref: Ref) {
ref.value ref.value
= typeof updaterOrValue === 'function' = typeof updaterOrValue === 'function'
? updaterOrValue(ref.value) ? updaterOrValue(ref.value)
: updaterOrValue : updaterOrValue
} }
// export type ParseEmits<T extends Record<string, any>> = {
// [K in keyof T]: (...args: T[K]) => void;
// }
// export function convertToComponent(component: FunctionalComponent) {
// return defineComponent({
// setup() { return () => h(component) },
// })
// }

View File

@ -72,6 +72,7 @@
"@types/lodash.template": "^4.5.1", "@types/lodash.template": "^4.5.1",
"@types/prompts": "^2.4.4", "@types/prompts": "^2.4.4",
"@vitest/ui": "^0.34.3", "@vitest/ui": "^0.34.3",
"magic-string": "^0.30.3",
"rimraf": "^5.0.1", "rimraf": "^5.0.1",
"tsup": "^7.2.0", "tsup": "^7.2.0",
"type-fest": "^4.3.0", "type-fest": "^4.3.0",

View File

@ -7,6 +7,7 @@ import { execa } from 'execa'
import ora from 'ora' import ora from 'ora'
import prompts from 'prompts' import prompts from 'prompts'
import * as z from 'zod' import * as z from 'zod'
import { transformImport } from '../utils/transformers/transform-import'
import { getConfig } from '@/src/utils/get-config' import { getConfig } from '@/src/utils/get-config'
import { getPackageManager } from '@/src/utils/get-package-manager' import { getPackageManager } from '@/src/utils/get-package-manager'
import { handleError } from '@/src/utils/handle-error' import { handleError } from '@/src/utils/handle-error'
@ -18,7 +19,6 @@ import {
getRegistryIndex, getRegistryIndex,
resolveTree, resolveTree,
} from '@/src/utils/registry' } from '@/src/utils/registry'
import { transform } from '@/src/utils/transformers'
const addOptionsSchema = z.object({ const addOptionsSchema = z.object({
components: z.array(z.string()).optional(), components: z.array(z.string()).optional(),
@ -107,6 +107,7 @@ export const add = new Command()
} }
const spinner = ora('Installing components...').start() const spinner = ora('Installing components...').start()
const skippedDeps = new Set<string>()
for (const item of payload) { for (const item of payload) {
spinner.text = `Installing ${item.name}...` spinner.text = `Installing ${item.name}...`
const targetDir = await getItemTargetPath( const targetDir = await getItemTargetPath(
@ -122,41 +123,49 @@ export const add = new Command()
await fs.mkdir(targetDir, { recursive: true }) await fs.mkdir(targetDir, { recursive: true })
const existingComponent = item.files.filter(file => const existingComponent = item.files.filter(file =>
existsSync(path.resolve(targetDir, file.name)), existsSync(path.resolve(targetDir, item.name, file.name)),
) )
if (existingComponent.length && !options.overwrite) { if (existingComponent.length && !options.overwrite) {
if (selectedComponents.includes(item.name)) { if (selectedComponents.includes(item.name)) {
logger.warn( logger.warn(
`Component ${item.name} already exists. Use ${chalk.green( `\nComponent ${
'--overwrite', item.name
)} to overwrite.`, } already exists. Use ${chalk.green(
'--overwrite',
)} to overwrite.`,
) )
process.exit(1) spinner.stop()
process.exitCode = 1
return
} }
continue continue
} }
for (const file of item.files) { for (const file of item.files) {
const filePath = path.resolve(targetDir, file.name) const componentDir = path.resolve(targetDir, item.name)
const filePath = path.resolve(
targetDir,
item.name,
file.name,
)
// Run transformers. // Run transformers.
const content = await transform({ const content = transformImport(file.content, config)
filename: file.name,
raw: file.content,
config,
baseColor,
})
// if (!config.tsx) if (!existsSync(componentDir))
// filePath = filePath.replace(/\.tsx$/, '.jsx') await fs.mkdir(componentDir, { recursive: true })
await fs.writeFile(filePath, content) await fs.writeFile(filePath, content)
} }
// Install dependencies. // Install dependencies.
if (item.dependencies?.length) { if (item.dependencies?.length) {
item.dependencies.forEach(dep =>
skippedDeps.add(dep),
)
const packageManager = await getPackageManager(cwd) const packageManager = await getPackageManager(cwd)
await execa( await execa(
packageManager, packageManager,

View File

@ -112,8 +112,8 @@ export async function promptForConfig(
name: 'framework', name: 'framework',
message: `Which ${highlight('framework')} are you using?`, message: `Which ${highlight('framework')} are you using?`,
choices: [ choices: [
{ title: 'Nuxt', value: 'nuxt' },
{ title: 'Vite + Vue', value: 'vue' }, { title: 'Vite + Vue', value: 'vue' },
{ title: 'Nuxt', value: 'nuxt' },
], ],
}, },
{ {
@ -140,7 +140,7 @@ export async function promptForConfig(
type: 'text', type: 'text',
name: 'tailwindCss', name: 'tailwindCss',
message: `Where is your ${highlight('Tailwind CSS')} file?`, message: `Where is your ${highlight('Tailwind CSS')} file?`,
initial: (prev, values) => defaultConfig?.tailwind.css ?? values.framework === 'nuxt' ? DEFAULT_TAILWIND_CSS_NUXT : DEFAULT_TAILWIND_CSS, initial: (prev, values) => defaultConfig?.tailwind.css ?? (values.framework === 'nuxt' ? DEFAULT_TAILWIND_CSS_NUXT : DEFAULT_TAILWIND_CSS),
}, },
{ {
type: 'toggle', type: 'toggle',

View File

@ -6,8 +6,8 @@ import { resolveImport } from '@/src/utils/resolve-import'
export const DEFAULT_STYLE = 'default' export const DEFAULT_STYLE = 'default'
export const DEFAULT_COMPONENTS = '@/components' export const DEFAULT_COMPONENTS = '@/components'
export const DEFAULT_UTILS = '@/utils' export const DEFAULT_UTILS = '@/lib/utils'
export const DEFAULT_TAILWIND_CSS = 'src/style.css' export const DEFAULT_TAILWIND_CSS = 'src/assets/index.css'
export const DEFAULT_TAILWIND_CSS_NUXT = 'assets/style/tailwind.css' export const DEFAULT_TAILWIND_CSS_NUXT = 'assets/style/tailwind.css'
export const DEFAULT_TAILWIND_CONFIG = 'tailwind.config.js' export const DEFAULT_TAILWIND_CONFIG = 'tailwind.config.js'
export const DEFAULT_TAILWIND_BASE_COLOR = 'slate' export const DEFAULT_TAILWIND_BASE_COLOR = 'slate'
@ -61,8 +61,17 @@ export async function getConfig(cwd: string) {
} }
export async function resolveConfigPaths(cwd: string, config: RawConfig) { export async function resolveConfigPaths(cwd: string, config: RawConfig) {
const TSCONFIG_PATH = config.framework === 'nuxt' ? '.nuxt/tsconfig.json' : './tsconfig.json'
// In new Vue project, tsconfig has references to tsconfig.app.json, which is causing the path not resolving correctly
const FALLBACK_TSCONFIG_PATH = './tsconfig.app.json'
// Read tsconfig.json. // Read tsconfig.json.
const tsConfig = await loadConfig(cwd) const tsconfigPath = path.resolve(cwd, TSCONFIG_PATH)
let tsConfig = loadConfig(tsconfigPath)
// If no paths were found, we load the fallback tsconfig
if ('paths' in tsConfig && Object.keys(tsConfig.paths).length === 0)
tsConfig = loadConfig(path.resolve(cwd, FALLBACK_TSCONFIG_PATH))
if (tsConfig.resultType === 'failed') { if (tsConfig.resultType === 'failed') {
throw new Error( throw new Error(

View File

@ -144,7 +144,6 @@ async function fetchRegistry(paths: string[]) {
return await response.json() return await response.json()
}), }),
) )
return results return results
} }
catch (error) { catch (error) {

View File

@ -1,10 +1,29 @@
export const UTILS = `import { type ClassValue, clsx } from "clsx" export const UTILS = `import { type ClassValue, clsx } from 'clsx'
import { twMerge } from "tailwind-merge" import { twMerge } from 'tailwind-merge'
import { camelize, getCurrentInstance, toHandlerKey } from 'vue'
export function cn(...inputs: ClassValue[]) { export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs)) return twMerge(clsx(inputs))
} }
`
export function useEmitAsProps<Name extends string>(
emit: (name: Name, ...args: any[]) => void,
) {
const vm = getCurrentInstance()
const events = vm?.type.emits as Name[]
const result: Record<string, any> = {}
if (!events?.length) {
console.warn(
'No emitted event found. Please check component: \${vm?.type.__name}',
)
}
events?.forEach((ev) => {
result[toHandlerKey(camelize(ev))] = (...arg: any) => emit(ev, ...arg)
})
return result
}`
export const UTILS_JS = `import { clsx } from "clsx" export const UTILS_JS = `import { clsx } from "clsx"
import { twMerge } from "tailwind-merge" import { twMerge } from "tailwind-merge"
@ -12,6 +31,23 @@ import { twMerge } from "tailwind-merge"
export function cn(...inputs) { export function cn(...inputs) {
return twMerge(clsx(inputs)) return twMerge(clsx(inputs))
} }
export function useEmitAsProps(emit) {
const vm = getCurrentInstance()
const events = vm?.type.emits
const result = {}
if (!events?.length) {
console.warn(
'No emitted event found. Please check component: \${vm?.type.__name}',
)
}
events?.forEach((ev) => {
result[toHandlerKey(camelize(ev))] = (...arg) => emit(ev, ...arg)
})
return result
}
` `
export const TAILWIND_CONFIG = `/** @type {import('tailwindcss').Config} */ export const TAILWIND_CONFIG = `/** @type {import('tailwindcss').Config} */

View File

@ -6,7 +6,6 @@ import type * as z from 'zod'
import type { Config } from '@/src/utils/get-config' import type { Config } from '@/src/utils/get-config'
import type { registryBaseColorSchema } from '@/src/utils/registry/schema' import type { registryBaseColorSchema } from '@/src/utils/registry/schema'
import { transformCssVars } from '@/src/utils/transformers/transform-css-vars' import { transformCssVars } from '@/src/utils/transformers/transform-css-vars'
import { transformImport } from '@/src/utils/transformers/transform-import'
export interface TransformOpts { export interface TransformOpts {
filename: string filename: string
@ -22,7 +21,6 @@ export type Transformer<Output = SourceFile> = (
) => Promise<Output> ) => Promise<Output>
const transformers: Transformer[] = [ const transformers: Transformer[] = [
transformImport,
transformCssVars, transformCssVars,
] ]

View File

@ -1,32 +1,49 @@
import type { Transformer } from '@/src/utils/transformers' import MagicString from 'magic-string'
import type { z } from 'zod'
import type { Config } from '../get-config'
import type { registryBaseColorSchema } from '../registry/schema'
export const transformImport: Transformer = async ({ sourceFile, config }) => { export interface TransformOpts {
const importDeclarations = sourceFile.getImportDeclarations() filename: string
raw: string
for (const importDeclaration of importDeclarations) { config: Config
const moduleSpecifier = importDeclaration.getModuleSpecifierValue() baseColor?: z.infer<typeof registryBaseColorSchema>
// Replace @/registry/[style] with the components alias.
if (moduleSpecifier.startsWith('@/registry/')) {
importDeclaration.setModuleSpecifier(
moduleSpecifier.replace(
/^@\/registry\/[^/]+/,
config.aliases.components,
),
)
}
// Replace `import { cn } from "@/lib/utils"`
if (moduleSpecifier === '@/lib/utils') {
const namedImports = importDeclaration.getNamedImports()
const cnImport = namedImports.find(i => i.getName() === 'cn')
if (cnImport) {
importDeclaration.setModuleSpecifier(
moduleSpecifier.replace(/^@\/lib\/utils/, config.aliases.utils),
)
}
}
}
return sourceFile
} }
export function transformImport(content: string, config: Config) {
const s = new MagicString(content)
s.replaceAll(/@\/registry\/[^/]+/g, config.aliases.components)
s.replaceAll(/\$lib\/utils/g, config.aliases.utils)
return s.toString()
}
// export const transformImport: Transformer = async ({ sourceFile, config }) => {
// const importDeclarations = sourceFile.getImportDeclarations()
// for (const importDeclaration of importDeclarations) {
// const moduleSpecifier = importDeclaration.getModuleSpecifierValue()
// // Replace @/registry/[style] with the components alias.
// if (moduleSpecifier.startsWith('@/registry/')) {
// importDeclaration.setModuleSpecifier(
// moduleSpecifier.replace(
// /^@\/registry\/[^/]+/,
// config.aliases.components,
// ),
// )
// }
// // Replace `import { cn } from "@/lib/utils"`
// if (moduleSpecifier === '@/lib/utils') {
// const namedImports = importDeclaration.getNamedImports()
// const cnImport = namedImports.find(i => i.getName() === 'cn')
// if (cnImport) {
// importDeclaration.setModuleSpecifier(
// moduleSpecifier.replace(/^@\/lib\/utils/, config.aliases.utils),
// )
// }
// }
// }
// return sourceFile
// }

View File

@ -144,9 +144,6 @@ importers:
vite: vite:
specifier: ^4.3.9 specifier: ^4.3.9
version: 4.3.9(@types/node@20.5.7) version: 4.3.9(@types/node@20.5.7)
vite-tsconfig-paths:
specifier: ^4.2.0
version: 4.2.0(typescript@5.0.2)(vite@4.3.9)
vue-tsc: vue-tsc:
specifier: ^1.4.2 specifier: ^1.4.2
version: 1.4.2(typescript@5.0.2) version: 1.4.2(typescript@5.0.2)
@ -229,6 +226,9 @@ importers:
'@vitest/ui': '@vitest/ui':
specifier: ^0.34.3 specifier: ^0.34.3
version: 0.34.3(vitest@0.34.3) version: 0.34.3(vitest@0.34.3)
magic-string:
specifier: ^0.30.3
version: 0.30.3
rimraf: rimraf:
specifier: ^5.0.1 specifier: ^5.0.1
version: 5.0.1 version: 5.0.1
@ -7224,19 +7224,6 @@ packages:
v8-compile-cache-lib: 3.0.1 v8-compile-cache-lib: 3.0.1
yn: 3.1.1 yn: 3.1.1
/tsconfck@2.1.2(typescript@5.0.2):
resolution: {integrity: sha512-ghqN1b0puy3MhhviwO2kGF8SeMDNhEbnKxjK7h6+fvY9JAxqvXi8y5NAHSQv687OVboS2uZIByzGd45/YxrRHg==}
engines: {node: ^14.13.1 || ^16 || >=18}
hasBin: true
peerDependencies:
typescript: ^4.3.5 || ^5.0.0
peerDependenciesMeta:
typescript:
optional: true
dependencies:
typescript: 5.0.2
dev: true
/tsconfck@2.1.2(typescript@5.2.2): /tsconfck@2.1.2(typescript@5.2.2):
resolution: {integrity: sha512-ghqN1b0puy3MhhviwO2kGF8SeMDNhEbnKxjK7h6+fvY9JAxqvXi8y5NAHSQv687OVboS2uZIByzGd45/YxrRHg==} resolution: {integrity: sha512-ghqN1b0puy3MhhviwO2kGF8SeMDNhEbnKxjK7h6+fvY9JAxqvXi8y5NAHSQv687OVboS2uZIByzGd45/YxrRHg==}
engines: {node: ^14.13.1 || ^16 || >=18} engines: {node: ^14.13.1 || ^16 || >=18}
@ -7586,23 +7573,6 @@ packages:
- terser - terser
dev: true dev: true
/vite-tsconfig-paths@4.2.0(typescript@5.0.2)(vite@4.3.9):
resolution: {integrity: sha512-jGpus0eUy5qbbMVGiTxCL1iB9ZGN6Bd37VGLJU39kTDD6ZfULTTb1bcc5IeTWqWJKiWV5YihCaibeASPiGi8kw==}
peerDependencies:
vite: '*'
peerDependenciesMeta:
vite:
optional: true
dependencies:
debug: 4.3.4
globrex: 0.1.2
tsconfck: 2.1.2(typescript@5.0.2)
vite: 4.3.9(@types/node@20.5.7)
transitivePeerDependencies:
- supports-color
- typescript
dev: true
/vite-tsconfig-paths@4.2.0(typescript@5.2.2): /vite-tsconfig-paths@4.2.0(typescript@5.2.2):
resolution: {integrity: sha512-jGpus0eUy5qbbMVGiTxCL1iB9ZGN6Bd37VGLJU39kTDD6ZfULTTb1bcc5IeTWqWJKiWV5YihCaibeASPiGi8kw==} resolution: {integrity: sha512-jGpus0eUy5qbbMVGiTxCL1iB9ZGN6Bd37VGLJU39kTDD6ZfULTTb1bcc5IeTWqWJKiWV5YihCaibeASPiGi8kw==}
peerDependencies: peerDependencies: