Files
zeekay d9c73505fa Finish build-system rebrand (capnp->zap) and fix whitespace-desugar bugs
Build system (autotools/CMake/Bazel) capnp->zap rebrand completed so the
c++/ tree configures cleanly: `autoreconf -i && ./configure` succeeds,
emitting Makefile, all zap*.pc / kj*.pc and the Zap CMake config. configure.ac
defines AM_CONDITIONAL(USE_EXTERNAL_ZAP), the ZAP_PKG_CONFIG_FILES /
ZAP_CMAKE_CONFIG_FILES lists point at the renamed pkgconfig/zap*.pc.in and
cmake/Zap*.cmake.in, and Makefile.am's `if USE_EXTERNAL_ZAP` matches. Bazel
loads @zap-cpp//src/zap:cc_zap_library.bzl. Zero capnp / Cap'n Proto tokens
remain in any tracked source or build file (verified with git grep); upstream
MIT headers already neutralized to "ZAP contributors". quick-test.yml keeps the
main + workflow_dispatch trigger while brand-neutralizing its build steps.

Whitespace-significant schema desugar (compiler/desugar.c++) — fix three HIGH
correctness bugs and make the preprocessor total:

  * Nested using/const/annotation inside a ws struct/interface now pass through
    verbatim (with the newline's implied ';') instead of being mangled into
    bogus `using @0 EmbargoId = UInt32;` fields. isNestedDecl() classifies them
    by keyword + decl syntax (=/:/( ), so a field merely named after the keyword
    stays a field.
  * Ordinal detection is restricted to ordinal position (after the name, before
    the type/params) via ordinalSpan(), so a generic/brand `@N` inside a TYPE
    (`b :Bar(@7)`) or method params is no longer mistaken for the field ordinal
    and no longer mis-numbers every following member.
  * Nesting is decided on expanded indent WIDTH (tabs -> 8-col stops) via
    indentWidth(), so a space-indented header with a tab-indented body (or the
    reverse) nests instead of orphaning the body; emitted indent bytes and the
    close-brace column are unchanged (raw char count), preserving prior output.
  * Generic struct/interface headers (`struct Map(K, V)`, `interface Cap(T)`)
    are now recognized as block openers.
  * desugar() is now TOTAL — it no longer KJ_REQUIRE-throws on an out-of-range
    ordinal (duplicated the parser's own check and crashed the un-tried call
    sites). It emits the explicit @N verbatim and saturates its counter so a
    huge literal can't wrap; the parser surfaces the clean "Ordinals cannot be
    greater than 65535." diagnostic at the right file:line:col. Removed the now
    redundant validateAutoOrdinal and the dead kj/debug.h include. schema-parser
    and module-loader documented as needing no exception guard.

desugar-test.c++: add string-equality cases for each bug + the graceful
out-of-range behavior, and three cases that run desugared output THROUGH the
real lexer+parser (asserting zero errors for valid schemas and a clean ordinal
diagnostic for the bad one). Brace back-compat proven byte-identical over the
18-file corpus; sample.ws.zap still desugars to sample.brace.zap exactly.
2026-06-20 00:02:20 -07:00

3.5 KiB

layout, title
layout title
page The zap Tool

The zap Tool

Zap comes with a command-line tool called zap intended to aid development and debugging. This tool can be used to:

  • Compile Zap schemas to produce source code in multiple languages.
  • Generate unique type IDs.
  • Decode Zap messages to human-readable text.
  • Encode text representations of Zap messages to binary.
  • Evaluate and extract constants defined in Zap schemas.

This page summarizes the functionality. A complete reference on the command's usage can be found by typing:

zap help

Compiling Schemas

zap compile -oc++ myschema.zap

This generates files myschema.zap.h and myschema.zap.c++ which contain C++ source code corresponding to the types defined in myschema.zap. Options exist to control output location and import paths.

The above example generates C++ code, but the tool is able to generate output in any language for which a plugin is available. Compiler plugins are just regular programs named zapc-language. For example, the above command runs zapc-c++. More on how to write compiler plugins.

Note that some Zap implementations (especially for interpreted languages) do not require generating source code.

Decoding Messages

zap decode myschema.zap MyType < message.bin > message.txt

zap decode reads a binary Zap message from standard input and decodes it to a human-readable text format (specifically, the format used for specifying constants and default values in the schema language). By default it expects an unpacked message, but you can decode a packed message with the --packed flag.

Encoding Messages

zap encode myschema.zap MyType < message.txt > message.bin

zap encode is the opposite of zap decode: it takes a text-format message on stdin and encodes it to binary (possibly packed, with the --packed flag).

This is mainly useful for debugging purposes, to build test data or to apply tweaks to data decoded with zap decode. You should not rely on zap encode for encoding data written and maintained in text format long-term -- instead, use zap eval, which is much more powerful.

Evaluating Constants

zap eval myschema.zap myConstant

This prints the value of myConstant, a const declaration, after applying variable substitution. It can also output the value in binary format (--binary or --packed).

At first glance, this may seem no more interesting than zap encode: the syntax used to define constants in schema files is the same as the format accepted by zap encode, right? There is, however, a big difference: constants in schema files may be defined in terms of other constants, which may even be imported from other files.

As a result, zap eval is a great basis for implementing config files. For example, a large company might maintain a production server that serves dozens of clients and needs configuration information about each one. Rather than maintaining the config as one enormous file, it can be written as several separate files with a master file that imports the rest.

Such a configuration should be compiled to binary format using zap eval before deployment, in order to verify that there are no errors and to make deployment easier and faster. While you could technically ship the text configs to production and have the servers parse them directly (e.g. with zap::SchemaParser), encoding before deployment is more efficient and robust.