// Command locks refuses a TypeScript module that names packages beyond the SDK in its package.json and commits no // package-lock.json (novox/hq ADR 0469 §5, issue 1868): the Node build module installs a module's own packages only // from its committed lock, so such a module is refused by the builder and could not be delivered. // // go run . // // Exits 1 on a finding. The packages that count are those the build module counts (mesh-build-node fetch.go // ownDependencies): the `dependencies` beyond the SDK, typescript and the @types packages. package main import ( "encoding/json" "fmt" "os" "path/filepath" "sort" "strings" ) // Finding is one module refused: it names Packages beyond the SDK and has no lock file. type Finding struct { Module string Packages []string } // Check reads every module under root/modules that builds a TypeScript artifact. func Check(root string) ([]Finding, error) { manifests, err := filepath.Glob(filepath.Join(root, "modules", "*", "module.json")) if err != nil { return nil, err } sort.Strings(manifests) var out []Finding for _, path := range manifests { raw, err := os.ReadFile(path) if err != nil { return nil, err } var m struct { Module string `json:"module"` Build struct { Artifacts []struct { Language string `json:"language"` } `json:"artifacts"` } `json:"build"` } if err := json.Unmarshal(raw, &m); err != nil { return nil, fmt.Errorf("%s: %w", path, err) } typescript := false for _, a := range m.Build.Artifacts { typescript = typescript || a.Language == "typescript" } if !typescript { continue } dir := filepath.Dir(path) pkgRaw, err := os.ReadFile(filepath.Join(dir, "package.json")) if os.IsNotExist(err) { continue } if err != nil { return nil, err } var pkg struct { Dependencies map[string]json.RawMessage `json:"dependencies"` } if err := json.Unmarshal(pkgRaw, &pkg); err != nil { return nil, fmt.Errorf("%s: package.json: %w", m.Module, err) } var names []string for n := range pkg.Dependencies { if n != "@novox/mesh-sdk" && n != "typescript" && !strings.HasPrefix(n, "@types/") { names = append(names, n) } } if len(names) == 0 { continue } if _, err := os.Stat(filepath.Join(dir, "package-lock.json")); err != nil { sort.Strings(names) out = append(out, Finding{Module: m.Module, Packages: names}) } } return out, nil } func main() { root := "." if len(os.Args) > 1 { root = os.Args[1] } found, err := Check(root) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } for _, f := range found { fmt.Printf("%s names packages beyond the SDK (%s) and has no package-lock.json: commit one made by the build module's toolchain (novox/hq ADR 0469 §5)\n", f.Module, strings.Join(f.Packages, ", ")) } if len(found) > 0 { os.Exit(1) } fmt.Println("locks: every TypeScript module that names packages beyond the SDK commits its lock") }