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