@autometa/vitest-plugins 1.0.0-rc.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 @@
1
+ {"version":3,"sources":["../src/index.ts"],"names":["next"],"mappings":"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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA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","sourcesContent":["import { resolve, isAbsolute, relative, dirname, extname } from \"path\";\nimport { existsSync } from \"fs\";\nimport type { Plugin } from \"vite\";\nimport type { Config } from \"@autometa/config\";\nimport jiti from \"jiti\";\n\nconst STEP_FALLBACK_GLOB = \"**/*.{ts,tsx,js,jsx,mjs,cjs,mts,cts}\";\n\ntype ModuleDeclaration =\n | string\n | { readonly name: string; readonly submodules?: readonly ModuleDeclaration[] | undefined };\n\nfunction flattenModuleDeclarations(\n declarations: readonly ModuleDeclaration[] | undefined,\n prefix: readonly string[] = []\n): readonly (readonly string[])[] {\n if (!declarations || declarations.length === 0) {\n return [];\n }\n\n const results: string[][] = [];\n\n for (const entry of declarations) {\n if (typeof entry === \"string\") {\n const next = [...prefix, entry];\n results.push(next);\n continue;\n }\n\n const next = [...prefix, entry.name];\n results.push(next);\n\n const nested = flattenModuleDeclarations(entry.submodules ?? undefined, next);\n for (const path of nested) {\n results.push([...path]);\n }\n }\n\n const unique = new Map<string, readonly string[]>();\n for (const path of results) {\n unique.set(path.join(\"/\"), path);\n }\n\n return Array.from(unique.values()).sort((a, b) => b.length - a.length);\n}\n\nfunction buildStepScopingData(resolvedConfig: unknown, projectRoot: string): unknown {\n const groups = (resolvedConfig as { modules?: { groups?: unknown } } | null)?.modules?.groups;\n if (!groups || typeof groups !== \"object\") {\n return null;\n }\n\n const entries = Object.entries(groups as Record<string, unknown>).map(([group, groupConfig]) => {\n const configRecord =\n groupConfig && typeof groupConfig === \"object\" ? (groupConfig as Record<string, unknown>) : {};\n const rootAbs = resolve(projectRoot, String(configRecord.root ?? \"\"));\n const modules = configRecord.modules;\n const modulePaths = Array.isArray(modules)\n ? flattenModuleDeclarations(modules as ModuleDeclaration[])\n : [];\n return { group, rootAbs, modulePaths };\n });\n\n return { groups: entries };\n}\n\nexport function autometa(): Plugin {\n let autometaConfig: Config | undefined;\n let configPath: string | undefined;\n let projectRoot: string | undefined;\n\n return {\n name: \"autometa-vitest-plugin\",\n enforce: \"pre\",\n async configResolved(viteConfig) {\n projectRoot = viteConfig.root || process.cwd();\n const loaded = await loadAutometaConfig(projectRoot);\n autometaConfig = loaded.config;\n configPath = loaded.path;\n },\n transform(code, id) {\n const cleanId = id.split(\"?\", 1)[0] ?? id;\n\n if (!cleanId.endsWith(\".feature\")) {\n return;\n }\n\n if (!autometaConfig) {\n throw new Error(\"Autometa config not found\");\n }\n\n const resolved = autometaConfig.resolve();\n const stepRoots = resolved.config.roots.steps;\n const configDir = configPath ? dirname(configPath) : projectRoot ?? process.cwd();\n const rootDir = projectRoot ?? process.cwd();\n const stepGlobs = buildStepGlobs(stepRoots, {\n configDir,\n projectRoot: rootDir,\n });\n if (stepGlobs.length === 0) {\n throw new Error(\n \"Autometa config did not resolve any step files within the current project root.\"\n );\n }\n\n const eventGlobs = buildStepGlobs(resolved.config.events, {\n configDir,\n projectRoot: rootDir,\n });\n\n const runtimeConfig = JSON.stringify(resolved.config);\n const stepScopingMode = resolved.config.modules?.stepScoping ?? \"global\";\n\n // Group/module index data is useful even when step scoping is disabled,\n // since we may need it to select the correct steps environment.\n const groupIndexData = buildStepScopingData(resolved.config, rootDir);\n const stepScopingData = stepScopingMode === \"scoped\" ? groupIndexData : null;\n\n const featureFile = cleanId;\n\n return {\n code: String.raw`\n import { describe } from 'vitest';\n import { execute } from '@autometa/vitest-executor';\n import { coordinateRunnerFeature, CucumberRunner, STEPS_ENVIRONMENT_META } from '@autometa/runner';\n import { parseGherkin } from '@autometa/gherkin';\n import { relative as __pathRelative, resolve as __pathResolve, isAbsolute as __pathIsAbsolute } from 'node:path';\n\n const __AUTOMETA_STEP_SCOPING_MODE = ${JSON.stringify(stepScopingMode)};\n const __AUTOMETA_GROUP_INDEX = ${JSON.stringify(groupIndexData)};\n const __AUTOMETA_STEP_SCOPING = ${JSON.stringify(stepScopingData)};\n const __AUTOMETA_FEATURE_FILE = ${JSON.stringify(featureFile)};\n\n const __AUTOMETA_EVENT_MODULES = ${eventGlobs.length > 0\n ? `import.meta.glob(${JSON.stringify(eventGlobs)}, { eager: true })`\n : \"{}\"};\n const stepModules = import.meta.glob(${JSON.stringify(stepGlobs)}, { eager: true });\n\n function collectCandidateModules(imported) {\n if (!imported || typeof imported !== 'object') {\n return [];\n }\n\n const modules = new Set();\n modules.add(imported);\n\n const exportedModules = imported.modules;\n if (Array.isArray(exportedModules)) {\n for (const entry of exportedModules) {\n if (entry && typeof entry === 'object') {\n modules.add(entry);\n }\n }\n }\n\n const defaultExport = imported.default;\n if (Array.isArray(defaultExport)) {\n for (const entry of defaultExport) {\n if (entry && typeof entry === 'object') {\n modules.add(entry);\n }\n }\n } else if (defaultExport && typeof defaultExport === 'object') {\n modules.add(defaultExport);\n }\n\n return Array.from(modules);\n }\n\n function isStepsEnvironment(candidate) {\n return Boolean(\n candidate &&\n typeof candidate === 'object' &&\n typeof candidate.coordinateFeature === 'function' &&\n typeof candidate.getPlan === 'function' &&\n typeof candidate.Given === 'function' &&\n typeof candidate.When === 'function' &&\n typeof candidate.Then === 'function'\n );\n }\n\n function extractStepsEnvironments(candidate) {\n const environments = [];\n\n if (!candidate || typeof candidate !== 'object') {\n return environments;\n }\n\n if (isStepsEnvironment(candidate)) {\n environments.push(candidate);\n }\n\n const stepsEnv = candidate.stepsEnvironment;\n if (isStepsEnvironment(stepsEnv)) {\n environments.push(stepsEnv);\n }\n\n const defaultExport = candidate.default;\n if (isStepsEnvironment(defaultExport)) {\n environments.push(defaultExport);\n }\n\n return environments;\n }\n\n function collectStepsEnvironments(modules) {\n const environments = new Set();\n for (const moduleExports of Object.values(modules)) {\n for (const candidate of collectCandidateModules(moduleExports)) {\n for (const env of extractStepsEnvironments(candidate)) {\n environments.add(env);\n }\n }\n }\n return Array.from(environments);\n }\n\n function __normalizePathSegments(input) {\n return String(input).replace(/\\\\/g, '/').split('/').filter(Boolean);\n }\n\n function __startsWithSegments(haystack, needle) {\n if (needle.length > haystack.length) return false;\n for (let i = 0; i < needle.length; i += 1) {\n if (haystack[i] !== needle[i]) return false;\n }\n return true;\n }\n\n function __resolveFileScope(fileAbs) {\n if (!__AUTOMETA_GROUP_INDEX || !__AUTOMETA_GROUP_INDEX.groups) {\n return { kind: 'root' };\n }\n if (String(fileAbs).startsWith('node:')) {\n return { kind: 'root' };\n }\n\n const absoluteFile = __pathIsAbsolute(String(fileAbs))\n ? String(fileAbs)\n : __pathResolve(process.cwd(), String(fileAbs));\n\n for (const entry of __AUTOMETA_GROUP_INDEX.groups) {\n const rootAbs = entry.rootAbs;\n const rel = rootAbs ? __pathRelative(rootAbs, absoluteFile) : '';\n if (rel === '' || (!rel.startsWith('..') && !rel.startsWith('../') && !rel.startsWith('..\\\\'))) {\n const segments = __normalizePathSegments(rel);\n const modulePaths = entry.modulePaths || [];\n for (const modulePath of modulePaths) {\n if (__startsWithSegments(segments, modulePath)) {\n return { kind: 'module', group: entry.group, modulePath };\n }\n }\n return { kind: 'group', group: entry.group };\n }\n }\n return { kind: 'root' };\n }\n\n function __parseScopeOverrideTag(tags) {\n if (!Array.isArray(tags)) return undefined;\n for (const tag of tags) {\n const match = String(tag).match(/^@scope(?::|=|\\()(.+?)(?:\\))?$/u);\n if (!match) continue;\n const raw = String(match[1] ?? '').trim();\n if (!raw) continue;\n const normalized = raw.replace(/\\//g, ':');\n const parts = normalized.split(':').filter(Boolean);\n const group = parts[0];\n const rest = parts.slice(1);\n if (!group) continue;\n return rest.length > 0 ? { group, modulePath: rest } : { group };\n }\n return undefined;\n }\n\n function __resolveFeatureScope(feature) {\n const override = __parseScopeOverrideTag(feature.tags);\n if (override) {\n if (override.modulePath && override.modulePath.length > 0) {\n return { kind: 'module', group: override.group, modulePath: override.modulePath };\n }\n return { kind: 'group', group: override.group };\n }\n return __resolveFileScope(__AUTOMETA_FEATURE_FILE);\n }\n\n function __inferEnvironmentGroup(environment) {\n const meta = environment && typeof environment === 'object'\n ? environment[STEPS_ENVIRONMENT_META]\n : undefined;\n if (meta && typeof meta === 'object') {\n if (meta.kind === 'group' && typeof meta.group === 'string' && meta.group.trim().length > 0) {\n return { kind: 'group', group: meta.group };\n }\n if (meta.kind === 'root') {\n return { kind: 'root' };\n }\n }\n\n const plan = environment.getPlan();\n const groups = new Set();\n for (const def of plan.stepsById.values()) {\n const file = def && def.source ? def.source.file : undefined;\n if (!file) continue;\n const scope = __resolveFileScope(file);\n if (scope.kind === 'group' || scope.kind === 'module') {\n groups.add(scope.group);\n if (groups.size > 1) return { kind: 'ambiguous' };\n }\n }\n const only = Array.from(groups.values())[0];\n return only ? { kind: 'group', group: only } : { kind: 'root' };\n }\n\n function selectStepsEnvironment(environments, feature) {\n if (!Array.isArray(environments) || environments.length === 0) {\n return undefined;\n }\n if (environments.length === 1) {\n return environments[0];\n }\n\n const featureScope = __resolveFeatureScope(feature);\n const indexed = environments\n .map((env) => ({ env, inferred: __inferEnvironmentGroup(env) }))\n .filter((entry) => entry.inferred.kind !== 'ambiguous');\n\n if (featureScope.kind === 'root') {\n const root = indexed.find((entry) => entry.inferred.kind === 'root');\n return (root ? root.env : indexed[0]?.env) ?? environments[0];\n }\n\n const match = indexed.find((entry) => entry.inferred.kind === 'group' && entry.inferred.group === featureScope.group);\n return match ? match.env : undefined;\n }\n\n function isScenario(element) {\n return Boolean(\n element &&\n typeof element === 'object' &&\n 'steps' in element &&\n !('exampleGroups' in element) &&\n !('elements' in element)\n );\n }\n\n function isScenarioOutline(element) {\n return Boolean(\n element &&\n typeof element === 'object' &&\n 'steps' in element &&\n 'exampleGroups' in element\n );\n }\n\n function isRule(element) {\n return Boolean(\n element &&\n typeof element === 'object' &&\n 'elements' in element &&\n Array.isArray(element.elements)\n );\n }\n\n function createFeatureScopePlan(feature, basePlan) {\n const allSteps = Array.from(basePlan.stepsById.values());\n\n function normalizePathSegments(input) {\n return String(input).replace(/\\\\/g, '/').split('/').filter(Boolean);\n }\n\n function startsWithSegments(haystack, needle) {\n if (needle.length > haystack.length) return false;\n for (let i = 0; i < needle.length; i += 1) {\n if (haystack[i] !== needle[i]) return false;\n }\n return true;\n }\n\n function resolveFileScope(fileAbs) {\n if (!__AUTOMETA_STEP_SCOPING || !__AUTOMETA_STEP_SCOPING.groups) {\n return { kind: 'root' };\n }\n if (String(fileAbs).startsWith('node:')) {\n return { kind: 'root' };\n }\n\n const absoluteFile = __pathIsAbsolute(String(fileAbs))\n ? String(fileAbs)\n : __pathResolve(process.cwd(), String(fileAbs));\n\n for (const entry of __AUTOMETA_STEP_SCOPING.groups) {\n const rootAbs = entry.rootAbs;\n const rel = rootAbs ? __pathRelative(rootAbs, absoluteFile) : '';\n if (rel === '' || (!rel.startsWith('..') && !rel.startsWith('../') && !rel.startsWith('..\\\\'))) {\n const segments = normalizePathSegments(rel);\n const modulePaths = entry.modulePaths || [];\n for (const modulePath of modulePaths) {\n if (startsWithSegments(segments, modulePath)) {\n return { kind: 'module', group: entry.group, modulePath };\n }\n }\n return { kind: 'group', group: entry.group };\n }\n }\n return { kind: 'root' };\n }\n\n function parseScopeOverrideTag(tags) {\n if (!Array.isArray(tags)) return undefined;\n for (const tag of tags) {\n const match = String(tag).match(/^@scope(?::|=|\\()(.+?)(?:\\))?$/u);\n if (!match) continue;\n const raw = String(match[1] ?? '').trim();\n if (!raw) continue;\n const normalized = raw.replace(/\\//g, ':');\n const parts = normalized.split(':').filter(Boolean);\n const group = parts[0];\n const rest = parts.slice(1);\n if (!group) continue;\n return rest.length > 0 ? { group, modulePath: rest } : { group };\n }\n return undefined;\n }\n\n function resolveFeatureScope() {\n const override = parseScopeOverrideTag(feature.tags);\n if (override) {\n if (override.modulePath && override.modulePath.length > 0) {\n return { kind: 'module', group: override.group, modulePath: override.modulePath };\n }\n return { kind: 'group', group: override.group };\n }\n return resolveFileScope(__AUTOMETA_FEATURE_FILE);\n }\n\n function isVisibleStepScope(stepScope, featureScope) {\n if (featureScope.kind === 'root') {\n return stepScope.kind === 'root';\n }\n if (featureScope.kind === 'group') {\n if (stepScope.kind === 'root') return true;\n return stepScope.kind === 'group' && stepScope.group === featureScope.group;\n }\n // module\n if (stepScope.kind === 'root') return true;\n if (stepScope.kind === 'group') return stepScope.group === featureScope.group;\n if (stepScope.kind === 'module') {\n return stepScope.group === featureScope.group && startsWithSegments(featureScope.modulePath, stepScope.modulePath);\n }\n return false;\n }\n\n function stepScopeRank(scope) {\n if (scope.kind === 'module') return 200 + (scope.modulePath ? scope.modulePath.length : 0);\n if (scope.kind === 'group') return 100;\n return 0;\n }\n\n const useScopedSteps = __AUTOMETA_STEP_SCOPING_MODE === 'scoped' && __AUTOMETA_STEP_SCOPING && __AUTOMETA_STEP_SCOPING.groups;\n const featureVisibilityScope = useScopedSteps ? resolveFeatureScope() : { kind: 'root' };\n const visibleSteps = useScopedSteps\n ? allSteps\n .filter((definition) => {\n const file = definition && definition.source ? definition.source.file : undefined;\n const scope = file ? resolveFileScope(file) : { kind: 'root' };\n return isVisibleStepScope(scope, featureVisibilityScope);\n })\n .sort((a, b) => {\n const aFile = a && a.source ? a.source.file : undefined;\n const bFile = b && b.source ? b.source.file : undefined;\n const aScope = aFile ? resolveFileScope(aFile) : { kind: 'root' };\n const bScope = bFile ? resolveFileScope(bFile) : { kind: 'root' };\n const delta = stepScopeRank(bScope) - stepScopeRank(aScope);\n return delta !== 0 ? delta : String(a.id).localeCompare(String(b.id));\n })\n : allSteps;\n\n const scopedStepsById = useScopedSteps\n ? (() => {\n const allowed = new Set(visibleSteps.map((s) => s.id));\n const next = new Map();\n for (const [id, def] of basePlan.stepsById.entries()) {\n if (allowed.has(id)) next.set(id, def);\n }\n return next;\n })()\n : basePlan.stepsById;\n const featureChildren = [];\n const scopesById = new Map(basePlan.scopesById);\n\n for (const element of feature.elements ?? []) {\n if (isScenario(element) || isScenarioOutline(element)) {\n const scenarioScope = {\n id: element.id ?? element.name,\n kind: isScenarioOutline(element) ? 'scenarioOutline' : 'scenario',\n name: element.name,\n mode: 'default',\n tags: element.tags ?? [],\n steps: visibleSteps,\n hooks: [],\n children: [],\n pending: false,\n };\n featureChildren.push(scenarioScope);\n scopesById.set(scenarioScope.id, scenarioScope);\n continue;\n }\n\n if (isRule(element)) {\n const ruleChildren = [];\n for (const ruleElement of element.elements ?? []) {\n if (isScenario(ruleElement) || isScenarioOutline(ruleElement)) {\n const scenarioScope = {\n id: ruleElement.id ?? ruleElement.name,\n kind: isScenarioOutline(ruleElement) ? 'scenarioOutline' : 'scenario',\n name: ruleElement.name,\n mode: 'default',\n tags: ruleElement.tags ?? [],\n steps: visibleSteps,\n hooks: [],\n children: [],\n pending: false,\n };\n ruleChildren.push(scenarioScope);\n scopesById.set(scenarioScope.id, scenarioScope);\n }\n }\n\n const ruleScope = {\n id: element.id ?? element.name,\n kind: 'rule',\n name: element.name,\n mode: 'default',\n tags: element.tags ?? [],\n steps: visibleSteps,\n hooks: [],\n children: ruleChildren,\n pending: false,\n };\n featureChildren.push(ruleScope);\n scopesById.set(ruleScope.id, ruleScope);\n }\n }\n\n const featureScope = {\n id: feature.uri ?? feature.name,\n kind: 'feature',\n name: feature.name,\n mode: 'default',\n tags: feature.tags ?? [],\n steps: visibleSteps,\n hooks: [],\n children: featureChildren,\n pending: false,\n };\n\n const existingRoot = basePlan.root;\n const updatedRoot = {\n ...existingRoot,\n children: [...existingRoot.children, featureScope],\n };\n\n scopesById.set(featureScope.id, featureScope);\n scopesById.set(updatedRoot.id, updatedRoot);\n\n const scopePlan = {\n root: updatedRoot,\n stepsById: scopedStepsById,\n hooksById: basePlan.hooksById,\n scopesById,\n };\n\n if (basePlan.worldFactory) {\n scopePlan.worldFactory = basePlan.worldFactory;\n }\n\n if (basePlan.parameterRegistry) {\n scopePlan.parameterRegistry = basePlan.parameterRegistry;\n }\n\n return scopePlan;\n }\n\n const gherkin = ${JSON.stringify(code)};\n const feature = parseGherkin(gherkin);\n const environments = collectStepsEnvironments(stepModules);\n const steps = selectStepsEnvironment(environments, feature);\n\n if (!steps) {\n throw new Error('Autometa could not find a steps environment for this feature. If you are using per-group environments, ensure each group exports a steps environment (\"stepsEnvironment\" or default export) under the configured step roots.');\n }\n\n CucumberRunner.setSteps(steps);\n\n describe(feature.name, () => {\n const basePlan = steps.getPlan();\n const scopedPlan = createFeatureScopePlan(feature, basePlan);\n const { plan, adapter } = coordinateRunnerFeature({\n feature,\n environment: steps,\n config: ${runtimeConfig},\n plan: scopedPlan\n });\n\n execute({ plan, adapter, config: ${runtimeConfig} });\n });\n `,\n map: null,\n };\n },\n };\n}\n\ninterface StepGlobOptions {\n readonly configDir: string;\n readonly projectRoot: string;\n}\n\nfunction buildStepGlobs(\n entries: readonly string[] | undefined,\n options: StepGlobOptions\n): string[] {\n if (!entries || entries.length === 0) {\n return [];\n }\n\n const patterns = new Set<string>();\n for (const entry of entries) {\n const normalized = entry.trim();\n if (!normalized) {\n continue;\n }\n\n for (const candidate of toPatterns(normalized, STEP_FALLBACK_GLOB)) {\n const absolute = isAbsolute(candidate)\n ? normalizeSlashes(candidate)\n : normalizeSlashes(resolve(options.configDir, candidate));\n const rootRelative = toRootRelativeGlob(absolute, options.projectRoot);\n patterns.add(rootRelative);\n }\n }\n\n return Array.from(patterns);\n}\n\nfunction toPatterns(entry: string, fallbackGlob: string): string[] {\n if (hasGlobMagic(entry) || hasFileExtension(entry)) {\n return [entry];\n }\n return [appendGlob(entry, fallbackGlob)];\n}\n\nfunction hasGlobMagic(input: string): boolean {\n return /[*?{}()[\\]!,@+]/u.test(input);\n}\n\nfunction hasFileExtension(input: string): boolean {\n const normalized = normalizeSlashes(input);\n const trimmed = normalized === \"/\" ? normalized : normalized.replace(/\\/+$/u, \"\");\n if (!trimmed || trimmed === \".\" || trimmed === \"..\") {\n return false;\n }\n return Boolean(extname(trimmed));\n}\n\nfunction appendGlob(entry: string, glob: string): string {\n const normalized = normalizeSlashes(entry);\n const trimmed = normalized === \"/\" ? normalized : normalized.replace(/\\/+$/u, \"\");\n if (!trimmed || trimmed === \".\") {\n return glob;\n }\n if (trimmed === \"/\") {\n return `/${glob}`;\n }\n return `${trimmed}/${glob}`;\n}\n\nfunction toRootRelativeGlob(pattern: string, rootDir: string): string {\n const normalizedRoot = normalizeSlashes(rootDir);\n const normalizedPattern = normalizeSlashes(pattern);\n let relativePattern = normalizeSlashes(relative(normalizedRoot, normalizedPattern));\n\n if (!relativePattern || relativePattern === \".\") {\n relativePattern = \"\";\n }\n\n if (!relativePattern || relativePattern.startsWith(\"..\")) {\n return ensureGlobPrefix(normalizedPattern);\n }\n\n return ensureGlobPrefix(relativePattern);\n}\n\nfunction ensureGlobPrefix(pattern: string): string {\n if (/^[A-Za-z]:\\//u.test(pattern)) {\n return pattern;\n }\n if (pattern.startsWith(\"/\")) {\n return pattern;\n }\n return `/${pattern.replace(/^\\/+/, \"\")}`;\n}\n\nfunction normalizeSlashes(pathname: string): string {\n return pathname.replace(/\\\\/gu, \"/\");\n}\n\nasync function loadAutometaConfig(root: string): Promise<{ config: Config; path: string }> {\n const _jiti = jiti(root, { interopDefault: true });\n\n const candidates = [\n \"autometa.config.ts\",\n \"autometa.config.js\",\n \"autometa.config.mts\",\n \"autometa.config.mjs\",\n \"autometa.config.cts\",\n \"autometa.config.cjs\",\n ];\n\n for (const candidate of candidates) {\n const path = resolve(root, candidate);\n if (!existsSync(path)) {\n continue;\n }\n\n try {\n const mod = _jiti(path);\n const config = mod.default || mod;\n\n if (isConfig(config)) {\n return { config, path };\n } else {\n console.warn(`Found config at ${path} but it does not export a Config instance.`);\n }\n } catch (error: unknown) {\n console.error(`Error loading config at ${path}:`, error);\n throw error;\n }\n }\n throw new Error(\"Could not find autometa.config.{ts,js,mjs,cjs} in \" + root);\n}\n\nfunction isConfig(config: unknown): config is Config {\n return (\n typeof config === \"object\" &&\n config !== null &&\n \"resolve\" in config &&\n typeof (config as Config).resolve === \"function\" &&\n \"current\" in config &&\n typeof (config as Config).current === \"function\"\n );\n}\n"]}
@@ -0,0 +1,2 @@
1
+ import type { Plugin } from "vite";
2
+ export declare function autometa(): Plugin;