···16791679 </div>
16801680 <div class="error-hint"><p>Python deps must live in a venv. Never use pip install --break-system-packages. The generate.sh wrapper should create/reuse a venv automatically.</p></div>
16811681</div>
16821682+<div class="error-card" id="E900">
16831683+ <div>
16841684+ <span class="error-code">E900</span>
16851685+ <span class="error-title">Wire.Codec without c/ directory</span>
16861686+ </div>
16871687+ <div class="error-hint"><p>Add a c/ directory with gen.ml that calls Wire_3d.main to generate .3d files and C validators from the Wire codec definitions. See ocaml-clcw/c/ for the pattern.</p></div>
16881688+</div>
16891689+<div class="error-card" id="E905">
16901690+ <div>
16911691+ <span class="error-code">E905</span>
16921692+ <span class="error-title">Wire struct_/module_ in public API</span>
16931693+ </div>
16941694+ <div class="error-hint"><p>Move struct_, module_, c_stubs, ml_stubs out of the .mli. These belong in c/gen.ml where they are used to generate EverParse 3D files and C stubs. The codec is the public API; the 3D projection is a build artifact.</p></div>
16951695+</div>
1682169616831697 <a href="#top" class="back-to-top">↑ Top</a>
16841698</body>
···1010 | Project_structure
1111 | Testing
1212 | Interop_testing
1313+ | Code_generation
13141415type example = {
1516 is_good : bool; (** true for good examples, false for bad examples. *)
+55
lib/rules/e900.ml
···11+(** E900: Wire.Codec without c/ directory *)
22+33+type payload = { package : string }
44+55+let check (ctx : Context.project) =
66+ let desc = Context.dune_describe ctx in
77+ let libs = Dune.libraries desc in
88+ let issues = ref [] in
99+ List.iter
1010+ (fun (lib : Dune.library_info) ->
1111+ let has_wire =
1212+ List.exists
1313+ (fun f ->
1414+ Fpath.has_ext ".ml" f
1515+ &&
1616+ try
1717+ let content =
1818+ In_channel.with_open_text (Fpath.to_string f)
1919+ In_channel.input_all
2020+ in
2121+ Astring.String.is_infix ~affix:"Wire.Codec" content
2222+ || Astring.String.is_infix ~affix:"Wire.Field" content
2323+ with _ -> false)
2424+ lib.files
2525+ in
2626+ if has_wire then
2727+ let lib_dir =
2828+ match lib.files with f :: _ -> Fpath.parent f | [] -> Fpath.v "."
2929+ in
3030+ let pkg_dir =
3131+ if Fpath.basename lib_dir = "lib" then Fpath.parent lib_dir
3232+ else lib_dir
3333+ in
3434+ let c_dir = Fpath.(pkg_dir / "c") in
3535+ if
3636+ not
3737+ (Sys.file_exists (Fpath.to_string c_dir)
3838+ && Sys.is_directory (Fpath.to_string c_dir))
3939+ then issues := Issue.v { package = Fpath.to_string pkg_dir } :: !issues)
4040+ libs;
4141+ !issues
4242+4343+let pp ppf { package } =
4444+ Fmt.pf ppf
4545+ "%s uses Wire.Codec but has no c/ directory for EverParse 3D generation"
4646+ package
4747+4848+let rule =
4949+ Rule.v ~code:"E900" ~title:"Wire.Codec without c/ directory"
5050+ ~category:Code_generation
5151+ ~hint:
5252+ "Add a c/ directory with gen.ml that calls Wire_3d.main to generate .3d \
5353+ files and C validators from the Wire codec definitions. See \
5454+ ocaml-clcw/c/ for the pattern."
5555+ ~examples:[] ~pp (Project check)
+45
lib/rules/e905.ml
···11+(** E905: Wire struct_/module_ exposed in public API *)
22+33+type payload = { file : string; symbol : string }
44+55+let wire_symbols = [ "struct_"; "module_"; "c_stubs"; "ml_stubs" ]
66+77+let check (ctx : Context.project) =
88+ let desc = Context.dune_describe ctx in
99+ let libs = Dune.libraries desc in
1010+ let issues = ref [] in
1111+ List.iter
1212+ (fun (lib : Dune.library_info) ->
1313+ List.iter
1414+ (fun f ->
1515+ if Fpath.has_ext ".mli" f then
1616+ try
1717+ let content =
1818+ In_channel.with_open_text (Fpath.to_string f)
1919+ In_channel.input_all
2020+ in
2121+ List.iter
2222+ (fun sym ->
2323+ let pattern = "val " ^ sym in
2424+ if Astring.String.is_infix ~affix:pattern content then
2525+ issues :=
2626+ Issue.v { file = Fpath.to_string f; symbol = sym }
2727+ :: !issues)
2828+ wire_symbols
2929+ with _ -> ())
3030+ lib.files)
3131+ libs;
3232+ !issues
3333+3434+let pp ppf { file; symbol } =
3535+ Fmt.pf ppf "%s exposes Wire EverParse symbol `%s` in public API" file symbol
3636+3737+let rule =
3838+ Rule.v ~code:"E905" ~title:"Wire struct_/module_ in public API"
3939+ ~category:Code_generation
4040+ ~hint:
4141+ "Move struct_, module_, c_stubs, ml_stubs out of the .mli. These belong \
4242+ in c/gen.ml where they are used to generate EverParse 3D files and C \
4343+ stubs. The codec is the public API; the 3D projection is a build \
4444+ artifact."
4545+ ~examples:[] ~pp (Project check)