{"record":{"id":"a801f46c263827e0","repo":"babalae/better-genshin-impact","slug":"specifier","errorCode":null,"errorMessage":"无法解析模块导入路径: '{specifier}'","messagePattern":"无法解析模块导入路径: '(.+?)'","errorType":"exception","errorClass":"FileNotFoundException","httpStatus":null,"severity":"error","filePath":"BetterGenshinImpact/Core/Script/PackageDocumentLoader.cs","lineNumber":42,"sourceCode":"\n            // ResolvePhysicalPath 可能因 sourceInfo 为空而失败，直接从脚本根目录兜底\n            if (targetPath == null || !File.Exists(targetPath))\n            {\n                var stripped = Regex.Replace(specifier, @\"^(?:\\.\\.?/)+\", \"\");\n                if (!Path.IsPathRooted(stripped))\n                {\n                    var fullPath = Path.GetFullPath(Path.Combine(_scriptRootPath, stripped));\n                    if (fullPath.StartsWith(_scriptRootPath, StringComparison.OrdinalIgnoreCase)\n                        && File.Exists(fullPath))\n                    {\n                        targetPath = fullPath;\n                    }\n                }\n            }\n\n            if (targetPath == null || !File.Exists(targetPath))\n            {\n                throw new FileNotFoundException($\"无法解析模块导入路径: '{specifier}'\", specifier);\n            }\n\n            // 处理 JS 文件的重写\n            if (Path.GetExtension(targetPath).ToLower() == \".js\")\n            {\n                var uri = new Uri(targetPath);\n\n                // 检查缓存\n                var cached = GetCachedDocument(uri);\n                if (cached != null) return cached;\n\n                string content = await File.ReadAllTextAsync(targetPath);\n                string processedCode = RewriteScriptCode(content, targetPath);\n                var documentInfo = new DocumentInfo(uri) { Category = ModuleCategory.Standard };\n                return CacheDocument(new StringDocument(documentInfo, processedCode), false);\n            }\n\n            throw new FileNotFoundException($\"不支持的模块导入类型: '{specifier}' (仅支持 .js 文件)\", specifier);","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/babalae/better-genshin-impact/blob/a7cb36712dcb409be610257d877fcea3597e9d6b/BetterGenshinImpact/Core/Script/PackageDocumentLoader.cs#L24-L60","documentation":"Thrown by PackageDocumentLoader.LoadDocumentAsync when a JS module import specifier cannot be resolved to an existing file on disk. The loader first tries ResolvePhysicalPath (ClearScript's default resolution), then falls back to stripping relative prefixes and combining with the script root path. If both fail, this FileNotFoundException is thrown with the original specifier.","triggerScenarios":"A JS script uses import ... from './module' or import ... from 'packages/foo' where the target file doesn't exist relative to either the importing file or the script root. Common with typos, missing file extensions (the loader expects explicit paths), or case-sensitivity issues on case-sensitive filesystems.","commonSituations":"Script package author references a module file that wasn't included in the distribution. Relative import path depth is wrong (e.g. '../../utils' vs '../../../utils'). File renamed or moved but import not updated. Case mismatch on Linux (e.g. 'Utils.js' vs 'utils.js').","solutions":["Verify the imported file exists at the resolved path — check spelling and case.","Use correct relative path depth from the importing file, or use the packages/ root convention.","Ensure the file has a .js extension (the loader only resolves .js files for module imports).","Check the error's FileName property (the specifier) to identify which import failed."],"exampleFix":"// before\nimport { helper } from './util/helpers';\n// after\nimport { helper } from './util/helpers.js';","handlingStrategy":"validation","validationCode":"string resolvedPath = Path.IsPathRooted(specifier)\n    ? specifier\n    : Path.GetFullPath(Path.Combine(scriptRoot, specifier));\nif (!File.Exists(resolvedPath))\n    throw new FileNotFoundException($\"Module not found: {specifier}\");","typeGuard":"static bool IsModuleResolvable(string specifier, string scriptRoot)\n{\n    var stripped = System.Text.RegularExpressions.Regex.Replace(specifier, @\"^(?:\\.\\.?/)+\", \"\");\n    var fullPath = Path.GetFullPath(Path.Combine(scriptRoot, stripped));\n    return fullPath.StartsWith(scriptRoot, StringComparison.OrdinalIgnoreCase) && File.Exists(fullPath);\n}","tryCatchPattern":null,"preventionTips":["Always include the .js extension in import specifiers.","Verify file existence and case (especially on Linux) before importing.","Use consistent relative path conventions within a script package."],"tags":["module-resolution","javascript","clearscript","file-not-found","import"],"backgroundTag":null,"analyzedSha":"a7cb36712dcb409be610257d877fcea3597e9d6b","analyzedAt":"2026-08-13T16:44:57.548Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}