Chapter 5 - Interfaces and Output Artifacts
AZM has three public entry surfaces: the command-line binary, the compile API and the tooling API. They all use the same compiler pipeline. Output writers then serialize assembled facts for users, Debug80 and package consumers.
This chapter covers the boundary between the compiler and its callers: package exports, CLI flow, public TypeScript APIs and artifact shapes.
Package Exports
package.json exposes:
@jhlagado/azm
@jhlagado/azm/compile
@jhlagado/azm/tooling
@jhlagado/azm/cli
src/index.ts re-exports the stable public surface. src/api-compile.ts backs
@jhlagado/azm/compile. src/api-tooling.ts backs
@jhlagado/azm/tooling. src/cli.ts is the executable entry.
The root export gives consumers a broad import. The /compile path is the
build-system path. The /tooling path is the editor and analysis path. The
/cli path backs the executable entry.
CLI Flow
The executable path in package.json points to dist/src/cli.js, compiled from
src/cli.ts. That file calls runCli(process.argv.slice(2)) and sets the
process exit code.
src/cli/run.ts owns the CLI control flow:
runCli(argv)
parseCliArgs(argv)
artifactBase(entryFile, outputType, outputPath)
compile(entryFile, buildCompileOptions(parsed, base))
sort and print diagnostics
writeArtifacts(base, artifacts, outputType)
return exit code
The CLI returns 0 for a successful assembly, 1 when diagnostics include an
error and 2 for argument or unexpected runtime failures. Diagnostics are
printed to standard error. The primary output path is printed to standard output
when artifact writing succeeds.
src/cli/parse-args.ts parses switches and validates the command shape. It
recognises output selection, artifact suppression, include paths, source-root,
case-style linting, directive aliases and register-care options.
src/cli/write-artifacts.ts maps parsed options into
CompileNextFunctionOptions and writes in-memory artifacts to disk. The base
path calculation is central to CLI behaviour. If the user supplies
--output build/program.bin, the primary artifact is written to that path and
side artifacts use the same base. If the user supplies only program.asm, AZM
writes outputs next to the entry source using the source stem.
Compile API
src/api-compile.ts exports:
export async function compile(
entryFile: string,
options: CompileNextFunctionOptions = {},
deps: CompileNextDependencies = { formats: defaultFormatWriters },
): Promise<CompileNextResult>
The compile API is file-backed. It reads source from disk, expands includes, analyses the program, assembles it and returns artifacts in memory.
Important options include:
| Option | Meaning |
|---|---|
includeDirs |
Include search paths. |
directiveAliasFiles |
Project alias profile files. |
caseStyle |
Case-style lint mode. |
outputType |
Primary output type, hex or bin. |
sourceRoot |
Root used for portable D8 map paths. |
d8mInputs |
Artifact paths recorded in D8 metadata. |
emitBin, emitHex, emitD8m, emitAsm80 |
Artifact selection. |
registerCare |
Register-care mode. |
emitRegisterReport |
Emit .regcare.txt artifact. |
emitRegisterInterface |
Emit .asmi artifact. |
emitRegisterAnnotations |
Emit source annotation artifact. |
fixRegisterContracts |
Apply conservative source fixes. |
acceptRegisterOutputCandidates |
Promote selected output candidates. |
registerCareProfile |
Built-in external contract profile. |
registerCareInterfaces |
External .asmi contract files. |
skipAssembly |
Run loading and analysis only. |
compile() returns:
export interface CompileNextResult {
readonly diagnostics: readonly Diagnostic[];
readonly artifacts: readonly Artifact[];
}
Diagnostics describe every warning or error observed during loading, analysis, register care, assembly or artifact creation. Artifacts contain the in-memory outputs requested by options.
Tooling API
src/tooling/api.ts exports loadProgramNext() and analyzeProgramNext().
src/api-tooling.ts re-exports those functions with register-care tooling
helpers.
loadProgramNext() returns a loaded program with source items, source texts and
source line comments. analyzeProgramNext() runs semantic checks and returns
symbols. analyzeRegisterCareForTools() returns register-care diagnostics and
code actions in a form suitable for editors.
An editor integration usually starts with:
const loaded = await loadProgramNext({
entryFile: '/project/src/main.asm',
includeDirs: ['/project/include'],
preloadedText: editorText,
});
When loaded.loadedProgram is present, the editor can call
analyzeProgramNext() for symbols and case-style diagnostics. It can also call
analyzeRegisterCareForTools() for register-care candidate diagnostics and code
actions.
Artifact Types
The output layer uses structured artifact objects from src/outputs/types.ts:
BinArtifactHexArtifactD8mArtifactAsm80ArtifactRegisterCareReportArtifactRegisterCareInterfaceArtifactRegisterCareAnnotationsArtifact
Each artifact has a kind field. Callers can switch on kind to find the
artifact they need:
const d8m = result.artifacts.find((artifact) => artifact.kind === 'd8m');
const bin = result.artifacts.find((artifact) => artifact.kind === 'bin');
This shape keeps the compile API independent from output paths. A caller can write artifacts to disk, keep them in memory, send them to another process or compare them in a test.
Byte Maps, BIN and HEX
Assembly produces an EmittedByteMap. It represents sparse output: addresses
map to byte values and source segments describe where those bytes came from.
src/outputs/range.ts provides range helpers. getWrittenSegments() identifies
contiguous written address ranges. getWrittenRange() returns the overall
written span.
src/outputs/write-bin.ts writes flat binary. It chooses the written range,
fills gaps as needed and returns a Uint8Array artifact. src/outputs/write-
hex.ts wraps src/outputs/hex.ts, which writes Intel HEX records and
checksums.
D8 Debug Maps
src/outputs/write-d8.ts writes Debug80 metadata. It records generator details,
input artifact paths, source files, source segments, addressable symbols and
value-only constants.
The writer normalizes source paths through sourceRoot when provided. It also
coalesces source segments and clips them to written ranges so Debug80 receives a
clean map of source lines to emitted bytes.
The D8 map distinguishes addressable symbols from constants. Labels and addressable data carry addresses. Constants carry values. Debug80 can then use addressable symbols for breakpoints and display constants as metadata.
Lowered ASM80 and Register-Care Artifacts
src/outputs/write-asm80.ts serializes accepted AZM source items as
ASM80-compatible .z80 text. It lowers supported AZM constructs into forms that
can be compared against ASM80 output. The writer is larger than the other
writers because it turns structured items back into source text.
Register-care report and interface artifacts are created by
analyzeRegisterCare() and flow through the same compile result and CLI write
path. The report is human-readable. The .asmi interface is metadata that can
be loaded by later compile runs through --interface.
Public API Compatibility
The public API is defined by package exports and exported TypeScript types. Major-version planning is the point where these shapes can change:
- exported function names
- option object property names
- result object shapes
- artifact kinds
- diagnostic object shape
- D8 map type exports
- register-care tooling result shapes
The type tests are the safety net for this boundary. When a public type changes, the change should be intentional and reflected in package documentation.