package engine import ( "errors" "io/fs" "path" "path/filepath" "sort" ) type importSelectionOutcome uint8 const ( importSelectionNone importSelectionOutcome = iota importSelectionHasCandidates ) type selectedImportCandidate struct { path string accessPath string site importFieldSite } // importSelection contains lexical candidates only; admission assigns source identity later. type importSelection struct { candidates []selectedImportCandidate outcome importSelectionOutcome } func selectNamedImportCandidates(access *filesystemAccess, basePath string, spec importDeclarationSpec, policy resolvedImportPolicy) (importSelection, []Diagnostic) { normalized := make([]selectedImportCandidate, 0, len(spec.paths)) seen := make(map[string]struct{}, len(spec.paths)) for index, relative := range spec.paths { accessPath := access.join(basePath, relative) candidatePath := accessPath if access.native == nil { candidatePath = filepath.ToSlash(filepath.Clean(accessPath)) } if _, exists := seen[candidatePath]; exists { continue } seen[candidatePath] = struct{}{} var site importFieldSite if index < len(spec.pathSites) { site = spec.pathSites[index] } else { site = spec.fieldSites["path"] } normalized = append(normalized, selectedImportCandidate{path: candidatePath, accessPath: accessPath, site: site}) } sort.Slice(normalized, func(left, right int) bool { return normalized[left].path < normalized[right].path }) candidates := make([]selectedImportCandidate, 0, len(normalized)) for _, candidate := range normalized { missing, diagnostic := validateNamedImportTarget(access, candidate, policy.required) if diagnostic != nil { return importSelection{}, []Diagnostic{*diagnostic} } if missing { continue } if excludedBasename(path.Base(candidate.path), policy.exclude) { continue } candidates = append(candidates, candidate) } selection := importSelection{candidates: candidates} if len(candidates) != 0 { selection.outcome = importSelectionHasCandidates } return selection, nil } func validateNamedImportTarget(access *filesystemAccess, candidate selectedImportCandidate, required bool) (bool, *Diagnostic) { if !access.contains(candidate.accessPath) { return false, importSelectionDiagnostic(candidate.site, CodeImportOutsideRoot, "import target is outside the configuration root") } canonical, err := access.canonical(candidate.accessPath) if err != nil { if errors.Is(err, fs.ErrNotExist) { if required { return false, importSelectionDiagnostic(candidate.site, CodeImportMissing, "required import target does not exist") } return true, nil } if errors.Is(err, fs.ErrPermission) { return false, importSelectionDiagnostic(candidate.site, CodeImportInvalid, "import target cannot be accessed") } return false, importSelectionDiagnostic(candidate.site, CodeImportInvalid, "import target could not be canonicalized") } if !access.contains(canonical) { return false, importSelectionDiagnostic(candidate.site, CodeImportOutsideRoot, "import target resolves outside the configuration root") } info, err := access.stat(canonical) if err != nil { if errors.Is(err, fs.ErrNotExist) { if required { return false, importSelectionDiagnostic(candidate.site, CodeImportMissing, "required import target does not exist") } return true, nil } if errors.Is(err, fs.ErrPermission) { return false, importSelectionDiagnostic(candidate.site, CodeImportInvalid, "import target cannot be accessed") } return false, importSelectionDiagnostic(candidate.site, CodeImportInvalid, "import target could not be inspected") } if !info.Mode().IsRegular() { return false, importSelectionDiagnostic(candidate.site, CodeSourceNotRegular, "source is not a regular file") } return false, nil } func excludedBasename(name string, patterns []string) bool { for _, pattern := range patterns { matched, err := path.Match(pattern, name) if err == nil && matched { return true } } return false } func importSelectionDiagnostic(site importFieldSite, code Code, message string) *Diagnostic { location := site.location return &Diagnostic{ Code: code, Severity: SeverityError, Path: site.path.clone(), Message: message, Primary: &location, } }