a simpler package manager for no-build websites
0

Configure Feed

Select the types of activity you want to include in your feed.

Expand checks

+88 -1
+88 -1
pkg/unpm/unpm.go
··· 183 183 } 184 184 185 185 func Check(cfg *Config, outDir string) error { 186 - checkBareImports(outDir, cfg.Imports) 186 + var errors []string 187 + 188 + // 1. Error: bare module specifiers in vendored files not in the import map. 189 + missing := map[string][]string{} 190 + filepath.Walk(outDir, func(p string, info os.FileInfo, err error) error { 191 + if err != nil || info.IsDir() { 192 + return nil 193 + } 194 + ext := strings.ToLower(filepath.Ext(p)) 195 + if ext != ".js" && ext != ".mjs" { 196 + return nil 197 + } 198 + data, err := os.ReadFile(p) 199 + if err != nil { 200 + return nil 201 + } 202 + relPath, _ := filepath.Rel(outDir, p) 203 + relPath = filepath.ToSlash(relPath) 204 + for _, m := range allImportRe.FindAllStringSubmatch(string(data), -1) { 205 + spec := m[1] 206 + if strings.HasPrefix(spec, ".") || strings.HasPrefix(spec, "/") || strings.Contains(spec, "://") { 207 + continue 208 + } 209 + if _, ok := cfg.Imports[spec]; !ok { 210 + missing[spec] = append(missing[spec], relPath) 211 + } 212 + } 213 + return nil 214 + }) 215 + for spec, files := range missing { 216 + errors = append(errors, fmt.Sprintf("%q is imported by %s but missing from import map", spec, strings.Join(files, ", "))) 217 + } 218 + 219 + // 2. Error: import map entries with no corresponding file on disk. 220 + for key, rawURL := range cfg.Imports { 221 + relPath, err := resolveVendorPath(rawURL, outDir) 222 + if err != nil { 223 + errors = append(errors, fmt.Sprintf("%q (%s): %v", key, rawURL, err)) 224 + continue 225 + } 226 + absPath := filepath.Join(outDir, filepath.FromSlash(relPath)) 227 + if _, err := os.Stat(absPath); os.IsNotExist(err) { 228 + errors = append(errors, fmt.Sprintf("%q: expected file %s not found on disk", key, relPath)) 229 + } 230 + } 231 + 232 + // 3. Warning: files on disk not reachable from any import map entry. 233 + reachable := map[string]bool{ 234 + filepath.Clean(filepath.Join(outDir, "importmap.js")): true, 235 + filepath.Clean(filepath.Join(outDir, "importmap.json")): true, 236 + filepath.Clean(filepath.Join(outDir, "jsconfig.json")): true, 237 + } 238 + for key, rawURL := range cfg.Imports { 239 + relPath, err := resolveVendorPath(rawURL, outDir) 240 + if err != nil { 241 + continue // already reported above 242 + } 243 + if err := walkImports(outDir, relPath, reachable); err != nil { 244 + fmt.Fprintf(os.Stderr, " \033[33mwarning:\033[0m could not walk imports for %q: %v\n", key, err) 245 + } 246 + } 247 + var unreachable []string 248 + filepath.Walk(outDir, func(p string, info os.FileInfo, err error) error { 249 + if err != nil || info.IsDir() { 250 + return nil 251 + } 252 + if !reachable[filepath.Clean(p)] { 253 + rel, _ := filepath.Rel(outDir, p) 254 + unreachable = append(unreachable, filepath.ToSlash(rel)) 255 + } 256 + return nil 257 + }) 258 + for _, f := range unreachable { 259 + fmt.Fprintf(os.Stderr, " \033[33mwarning:\033[0m %s is not reachable from any import map entry\n", f) 260 + } 261 + 262 + if len(errors) > 0 { 263 + sort.Strings(errors) 264 + for _, e := range errors { 265 + fmt.Fprintf(os.Stderr, " \033[31merror:\033[0m %s\n", e) 266 + } 267 + return fmt.Errorf("check failed with %d error(s)", len(errors)) 268 + } 269 + 270 + if len(unreachable) == 0 { 271 + fmt.Println(" all checks passed") 272 + } 273 + 187 274 return nil 188 275 } 189 276