style: lint
This commit is contained in:
@@ -37,13 +37,13 @@ const isCleartext = serverURL?.startsWith('http://') ?? false
|
||||
const config: CapacitorConfig = {
|
||||
appId: 'com.example.app',
|
||||
appName: 'Example App',
|
||||
webDir: 'dist',
|
||||
server: serverURL
|
||||
? {
|
||||
url: serverURL,
|
||||
cleartext: isCleartext,
|
||||
url: serverURL,
|
||||
}
|
||||
: undefined,
|
||||
webDir: 'dist',
|
||||
}
|
||||
|
||||
export default config
|
||||
|
||||
@@ -34,7 +34,7 @@ export function getCapViteCliUsage(): string {
|
||||
// library (cac is already a dependency—consider subcommands or a small wrapper) so flags like
|
||||
// `--target` / `--target=`, env-based defaults, and validation stay in one maintainable layer.
|
||||
|
||||
export function parseCapViteCliArgs(argv: string[]): ParsedCapViteCliArgs | null {
|
||||
export function parseCapViteCliArgs(argv: string[]): null | ParsedCapViteCliArgs {
|
||||
if (argv.length === 1 && (argv[0] === '--help' || argv[0] === '-h')) {
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -15,14 +15,6 @@ export interface RunCapViteOptions {
|
||||
cwd?: string
|
||||
}
|
||||
|
||||
interface PreparedViteLaunch {
|
||||
baseConfigFile?: string
|
||||
configLoader?: 'bundle' | 'native' | 'runner'
|
||||
projectRoot: string
|
||||
viteArgs: string[]
|
||||
wrapperConfigFile: string
|
||||
}
|
||||
|
||||
interface ParsedViteArg {
|
||||
baseConfigFile?: string
|
||||
configLoader?: 'bundle' | 'native' | 'runner'
|
||||
@@ -30,96 +22,12 @@ interface ParsedViteArg {
|
||||
forwardedArgs: string[]
|
||||
}
|
||||
|
||||
function resolveWrapperConfigFile(): string {
|
||||
const currentModulePath = fileURLToPath(import.meta.url)
|
||||
const wrapperExtension = extname(currentModulePath) === '.ts' ? '.ts' : '.mjs'
|
||||
return fileURLToPath(new URL(`./vite-wrapper-config${wrapperExtension}`, import.meta.url))
|
||||
}
|
||||
|
||||
function parseViteConfigLoader(value: string | undefined): 'bundle' | 'native' | 'runner' | undefined {
|
||||
if (value === 'bundle' || value === 'native' || value === 'runner') {
|
||||
return value
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
function resolveConfigPath(cwd: string, value: string): string {
|
||||
return resolve(cwd, value)
|
||||
}
|
||||
|
||||
function readRequiredOptionValue(viteArgs: string[], index: number, optionName: string): string {
|
||||
const value = viteArgs[index + 1]
|
||||
if (!value) {
|
||||
throw new Error(`Missing value for \`${optionName}\`.`)
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
function parseConfigArg(viteArgs: string[], index: number, cwd: string): ParsedViteArg | null {
|
||||
const arg = viteArgs[index]
|
||||
|
||||
// NOTICE: Vite only accepts one `--config` entrypoint. cap-vite consumes that slot
|
||||
// for its wrapper config, then loads the user config from inside the wrapper.
|
||||
if (arg === '--config' || arg === '-c') {
|
||||
return {
|
||||
baseConfigFile: resolveConfigPath(cwd, readRequiredOptionValue(viteArgs, index, '--config')),
|
||||
consumedArgs: 2,
|
||||
forwardedArgs: [],
|
||||
}
|
||||
}
|
||||
|
||||
if (arg.startsWith('--config=')) {
|
||||
return {
|
||||
baseConfigFile: resolveConfigPath(cwd, arg.slice('--config='.length)),
|
||||
consumedArgs: 1,
|
||||
forwardedArgs: [],
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
function parseConfigLoaderArg(viteArgs: string[], index: number): ParsedViteArg | null {
|
||||
const arg = viteArgs[index]
|
||||
|
||||
if (arg === '--configLoader') {
|
||||
const value = readRequiredOptionValue(viteArgs, index, '--configLoader')
|
||||
|
||||
return {
|
||||
configLoader: parseViteConfigLoader(value),
|
||||
consumedArgs: 2,
|
||||
forwardedArgs: [arg, value],
|
||||
}
|
||||
}
|
||||
|
||||
if (arg.startsWith('--configLoader=')) {
|
||||
return {
|
||||
configLoader: parseViteConfigLoader(arg.slice('--configLoader='.length)),
|
||||
consumedArgs: 1,
|
||||
forwardedArgs: [arg],
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
function parseViteArg(viteArgs: string[], index: number, cwd: string): ParsedViteArg {
|
||||
return parseConfigArg(viteArgs, index, cwd)
|
||||
?? parseConfigLoaderArg(viteArgs, index)
|
||||
?? {
|
||||
consumedArgs: 1,
|
||||
forwardedArgs: [viteArgs[index]],
|
||||
}
|
||||
}
|
||||
|
||||
function resolveProjectRoot(viteArgs: string[], cwd: string): string {
|
||||
const firstArg = viteArgs[0]
|
||||
|
||||
return firstArg && !firstArg.startsWith('-')
|
||||
? resolve(cwd, firstArg)
|
||||
: cwd
|
||||
interface PreparedViteLaunch {
|
||||
baseConfigFile?: string
|
||||
configLoader?: 'bundle' | 'native' | 'runner'
|
||||
projectRoot: string
|
||||
viteArgs: string[]
|
||||
wrapperConfigFile: string
|
||||
}
|
||||
|
||||
export function prepareCapViteLaunch(viteArgs: string[], cwd: string = process.cwd()): PreparedViteLaunch {
|
||||
@@ -161,7 +69,6 @@ export async function runCapVite(
|
||||
const prepared = prepareCapViteLaunch(viteArgs, cwd)
|
||||
|
||||
return await x('vite', ['--config', prepared.wrapperConfigFile, ...prepared.viteArgs], {
|
||||
throwOnError: false,
|
||||
nodeOptions: {
|
||||
cwd,
|
||||
env: {
|
||||
@@ -172,5 +79,98 @@ export async function runCapVite(
|
||||
},
|
||||
stdio: 'inherit',
|
||||
},
|
||||
throwOnError: false,
|
||||
})
|
||||
}
|
||||
|
||||
function parseConfigArg(viteArgs: string[], index: number, cwd: string): null | ParsedViteArg {
|
||||
const arg = viteArgs[index]
|
||||
|
||||
// NOTICE: Vite only accepts one `--config` entrypoint. cap-vite consumes that slot
|
||||
// for its wrapper config, then loads the user config from inside the wrapper.
|
||||
if (arg === '--config' || arg === '-c') {
|
||||
return {
|
||||
baseConfigFile: resolveConfigPath(cwd, readRequiredOptionValue(viteArgs, index, '--config')),
|
||||
consumedArgs: 2,
|
||||
forwardedArgs: [],
|
||||
}
|
||||
}
|
||||
|
||||
if (arg.startsWith('--config=')) {
|
||||
return {
|
||||
baseConfigFile: resolveConfigPath(cwd, arg.slice('--config='.length)),
|
||||
consumedArgs: 1,
|
||||
forwardedArgs: [],
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
function parseConfigLoaderArg(viteArgs: string[], index: number): null | ParsedViteArg {
|
||||
const arg = viteArgs[index]
|
||||
|
||||
if (arg === '--configLoader') {
|
||||
const value = readRequiredOptionValue(viteArgs, index, '--configLoader')
|
||||
|
||||
return {
|
||||
configLoader: parseViteConfigLoader(value),
|
||||
consumedArgs: 2,
|
||||
forwardedArgs: [arg, value],
|
||||
}
|
||||
}
|
||||
|
||||
if (arg.startsWith('--configLoader=')) {
|
||||
return {
|
||||
configLoader: parseViteConfigLoader(arg.slice('--configLoader='.length)),
|
||||
consumedArgs: 1,
|
||||
forwardedArgs: [arg],
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
function parseViteArg(viteArgs: string[], index: number, cwd: string): ParsedViteArg {
|
||||
return parseConfigArg(viteArgs, index, cwd)
|
||||
?? parseConfigLoaderArg(viteArgs, index)
|
||||
?? {
|
||||
consumedArgs: 1,
|
||||
forwardedArgs: [viteArgs[index]],
|
||||
}
|
||||
}
|
||||
|
||||
function parseViteConfigLoader(value: string | undefined): 'bundle' | 'native' | 'runner' | undefined {
|
||||
if (value === 'bundle' || value === 'native' || value === 'runner') {
|
||||
return value
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
function readRequiredOptionValue(viteArgs: string[], index: number, optionName: string): string {
|
||||
const value = viteArgs[index + 1]
|
||||
if (!value) {
|
||||
throw new Error(`Missing value for \`${optionName}\`.`)
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
function resolveConfigPath(cwd: string, value: string): string {
|
||||
return resolve(cwd, value)
|
||||
}
|
||||
|
||||
function resolveProjectRoot(viteArgs: string[], cwd: string): string {
|
||||
const firstArg = viteArgs[0]
|
||||
|
||||
return firstArg && !firstArg.startsWith('-')
|
||||
? resolve(cwd, firstArg)
|
||||
: cwd
|
||||
}
|
||||
|
||||
function resolveWrapperConfigFile(): string {
|
||||
const currentModulePath = fileURLToPath(import.meta.url)
|
||||
const wrapperExtension = extname(currentModulePath) === '.ts' ? '.ts' : '.mjs'
|
||||
return fileURLToPath(new URL(`./vite-wrapper-config${wrapperExtension}`, import.meta.url))
|
||||
}
|
||||
|
||||
@@ -15,6 +15,15 @@ interface CapacitorTarget {
|
||||
type ListCapacitorTargets = (platform: CapacitorPlatform) => Promise<readonly CapacitorTarget[]>
|
||||
|
||||
const nativeExtensionsByPlatform: Record<CapacitorPlatform, Set<string>> = {
|
||||
android: new Set([
|
||||
'.gradle',
|
||||
'.java',
|
||||
'.json',
|
||||
'.kt',
|
||||
'.kts',
|
||||
'.properties',
|
||||
'.xml',
|
||||
]),
|
||||
ios: new Set([
|
||||
'.entitlements',
|
||||
'.h',
|
||||
@@ -26,28 +35,14 @@ const nativeExtensionsByPlatform: Record<CapacitorPlatform, Set<string>> = {
|
||||
'.storyboard',
|
||||
'.strings',
|
||||
'.swift',
|
||||
'.xcodeproj',
|
||||
'.xcconfig',
|
||||
'.xcodeproj',
|
||||
'.xcscheme',
|
||||
'.xib',
|
||||
]),
|
||||
android: new Set([
|
||||
'.gradle',
|
||||
'.java',
|
||||
'.json',
|
||||
'.kts',
|
||||
'.kt',
|
||||
'.properties',
|
||||
'.xml',
|
||||
]),
|
||||
}
|
||||
|
||||
const nativeNamesByPlatform: Record<CapacitorPlatform, Set<string>> = {
|
||||
ios: new Set([
|
||||
'Podfile',
|
||||
'Podfile.lock',
|
||||
'project.pbxproj',
|
||||
]),
|
||||
android: new Set([
|
||||
'AndroidManifest.xml',
|
||||
'build.gradle',
|
||||
@@ -56,6 +51,11 @@ const nativeNamesByPlatform: Record<CapacitorPlatform, Set<string>> = {
|
||||
'settings.gradle',
|
||||
'settings.gradle.kts',
|
||||
]),
|
||||
ios: new Set([
|
||||
'Podfile',
|
||||
'Podfile.lock',
|
||||
'project.pbxproj',
|
||||
]),
|
||||
}
|
||||
|
||||
const ignoredNames = new Set([
|
||||
@@ -64,16 +64,13 @@ const ignoredNames = new Set([
|
||||
|
||||
const ignoredPathSegments = new Set([
|
||||
'.gradle',
|
||||
'build',
|
||||
'DerivedData',
|
||||
'Pods',
|
||||
'build',
|
||||
'xcuserdata',
|
||||
])
|
||||
|
||||
const ignoredPathPrefixesByPlatform: Record<CapacitorPlatform, string[][]> = {
|
||||
ios: [
|
||||
['App', 'CapApp-SPM'],
|
||||
],
|
||||
android: [
|
||||
['app', 'src', 'main', 'assets', 'public'],
|
||||
['app', 'src', 'main', 'assets', 'capacitor.plugins.json'],
|
||||
@@ -82,30 +79,27 @@ const ignoredPathPrefixesByPlatform: Record<CapacitorPlatform, string[][]> = {
|
||||
['capacitor-cordova-android-plugins'],
|
||||
['capacitor.settings.gradle'],
|
||||
],
|
||||
}
|
||||
|
||||
export function parseCapacitorPlatform(value: string | undefined): CapacitorPlatform | null {
|
||||
return value === 'android' || value === 'ios' ? value : null
|
||||
ios: [
|
||||
['App', 'CapApp-SPM'],
|
||||
],
|
||||
}
|
||||
|
||||
export function hasCapacitorTargetArg(capArgs: string[]): boolean {
|
||||
return capArgs.some((arg, index) => arg === '--target' || (index > 0 && arg.startsWith('--target=')))
|
||||
}
|
||||
|
||||
function parseCapacitorTargetList(value: string): CapacitorTarget[] {
|
||||
const parsed = JSON.parse(value)
|
||||
if (!Array.isArray(parsed)) {
|
||||
throw new TypeError('Expected `cap run --list --json` to return a JSON array.')
|
||||
}
|
||||
|
||||
return parsed
|
||||
.filter((target): target is CapacitorTarget => typeof target === 'object' && target !== null && typeof (target as CapacitorTarget).id === 'string')
|
||||
export function parseCapacitorPlatform(value: string | undefined): CapacitorPlatform | null {
|
||||
return value === 'android' || value === 'ios' ? value : null
|
||||
}
|
||||
|
||||
async function listCapacitorTargets(platform: CapacitorPlatform): Promise<CapacitorTarget[]> {
|
||||
const output = await x('cap', ['run', platform, '--list', '--json'])
|
||||
export function pickServerUrl(server: Pick<ViteDevServer, 'resolvedUrls'>): URL {
|
||||
const url = server.resolvedUrls?.network?.[0] ?? server.resolvedUrls?.local?.[0]
|
||||
|
||||
return parseCapacitorTargetList(output.stdout)
|
||||
if (!url) {
|
||||
throw new Error('Vite did not expose a reachable dev server URL.')
|
||||
}
|
||||
|
||||
return new URL(url)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -158,16 +152,6 @@ export async function resolveCapRunArgs(
|
||||
return [platformArg, '--target', target, ...rest]
|
||||
}
|
||||
|
||||
export function pickServerUrl(server: Pick<ViteDevServer, 'resolvedUrls'>): URL {
|
||||
const url = server.resolvedUrls?.network?.[0] ?? server.resolvedUrls?.local?.[0]
|
||||
|
||||
if (!url) {
|
||||
throw new Error('Vite did not expose a reachable dev server URL.')
|
||||
}
|
||||
|
||||
return new URL(url)
|
||||
}
|
||||
|
||||
export function shouldRestartForNativeChange(file: string, platform: CapacitorPlatform, cwd: string): boolean {
|
||||
const absoluteFile = resolve(cwd, file)
|
||||
const platformRoot = resolve(cwd, platform)
|
||||
@@ -205,3 +189,19 @@ export function shouldRestartForNativeChange(file: string, platform: CapacitorPl
|
||||
|
||||
return nativeExtensionsByPlatform[platform].has(extname(fileName).toLowerCase())
|
||||
}
|
||||
|
||||
async function listCapacitorTargets(platform: CapacitorPlatform): Promise<CapacitorTarget[]> {
|
||||
const output = await x('cap', ['run', platform, '--list', '--json'])
|
||||
|
||||
return parseCapacitorTargetList(output.stdout)
|
||||
}
|
||||
|
||||
function parseCapacitorTargetList(value: string): CapacitorTarget[] {
|
||||
const parsed = JSON.parse(value)
|
||||
if (!Array.isArray(parsed)) {
|
||||
throw new TypeError('Expected `cap run --list --json` to return a JSON array.')
|
||||
}
|
||||
|
||||
return parsed
|
||||
.filter((target): target is CapacitorTarget => typeof target === 'object' && target !== null && typeof (target as CapacitorTarget).id === 'string')
|
||||
}
|
||||
|
||||
@@ -23,12 +23,25 @@ type MockResult = Promise<{ exitCode: number, stderr: string, stdout: string }>
|
||||
kill: ReturnType<typeof vi.fn>
|
||||
}
|
||||
|
||||
class MockHttpServer extends EventEmitter {}
|
||||
|
||||
class MockWatcher extends EventEmitter {
|
||||
add = vi.fn()
|
||||
unwatch = vi.fn(async () => {})
|
||||
}
|
||||
|
||||
class MockHttpServer extends EventEmitter {}
|
||||
async function configurePluginServer(plugin: Plugin, server: ReturnType<typeof createMockServer>) {
|
||||
const configureServer = plugin.configureServer
|
||||
if (!configureServer) {
|
||||
throw new Error('cap-vite plugin is missing configureServer().')
|
||||
}
|
||||
|
||||
const handler = typeof configureServer === 'function'
|
||||
? configureServer
|
||||
: configureServer.handler
|
||||
|
||||
await handler.call({} as any, server as any)
|
||||
}
|
||||
|
||||
function createMockResult(): MockResult {
|
||||
const output = {
|
||||
@@ -82,19 +95,6 @@ function createMockStdin() {
|
||||
return stdin
|
||||
}
|
||||
|
||||
async function configurePluginServer(plugin: Plugin, server: ReturnType<typeof createMockServer>) {
|
||||
const configureServer = plugin.configureServer
|
||||
if (!configureServer) {
|
||||
throw new Error('cap-vite plugin is missing configureServer().')
|
||||
}
|
||||
|
||||
const handler = typeof configureServer === 'function'
|
||||
? configureServer
|
||||
: configureServer.handler
|
||||
|
||||
await handler.call({} as any, server as any)
|
||||
}
|
||||
|
||||
const originalStdin = Object.getOwnPropertyDescriptor(process, 'stdin')
|
||||
|
||||
describe('capVitePlugin', () => {
|
||||
|
||||
@@ -46,8 +46,8 @@ describe('vite-wrapper-config', () => {
|
||||
const module = await import('./vite-wrapper-config')
|
||||
const config = await module.default({
|
||||
command: 'serve',
|
||||
mode: 'development',
|
||||
isPreview: false,
|
||||
mode: 'development',
|
||||
})
|
||||
|
||||
expect(defineConfig).toHaveBeenCalledTimes(1)
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { defineConfig } from 'tsdown'
|
||||
|
||||
export default defineConfig({
|
||||
dts: true,
|
||||
entry: {
|
||||
'index': 'src/index.ts',
|
||||
'bin/run': 'src/bin/run.ts',
|
||||
'index': 'src/index.ts',
|
||||
'vite-plugin': 'src/vite-plugin.ts',
|
||||
'vite-wrapper-config': 'src/vite-wrapper-config.ts',
|
||||
},
|
||||
target: 'node18',
|
||||
outDir: 'dist',
|
||||
dts: true,
|
||||
sourcemap: true,
|
||||
target: 'node18',
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user