Usage: adlc typescript [OPTION...] files...
-I DIR --searchdir=DIR Add the specifed directory to the ADL searchpath
-O DIR --outputdir=DIR Set the directory where generated code is written
--merge-adlext=EXT Add the specifed adl file extension to merged on loading
--verbose Print extra diagnostic information, especially about files being read/written
--no-overwrite Don't update files that haven't changed
--manifest=FILE Write a manifest file recording generated files
--generate-transitive Also generate code for the transitive dependencies of the specified adl files
--include-rt Generate the runtime code
--ts-style=tsc|deno Select the style of typescript to be generated
--include-resolver Generate the resolver map for all generated adl files
--exclude-ast Exclude the generated ASTs
--excluded-ast-annotations=SCOPEDNAMES Set the annotations to be excluded from the ast (comma separated, default=sys.annotations.Doc)
-R DIR --runtime-dir=DIR Set the directory where runtime code is written
The typescript runtime and ADL generated code depend on ES6 (so use --target ES6
for the tsc compiler).
The typescript backend generates typescript code from the input ADL files. Each ADL module results in a typescript module.
ADL structs such as
struct Rectangle
{
Double width;
Double height;
};
produce typescript interfaces (see Rectangle). In
addition, a helper constructor function
makeRectangle
is also generated. Fields of the
ADL struct that have default values specified are optional parameters
to the constructor function.
ADL unions such as
union Picture
{
Circle circle;
Rectangle rectangle;
Vector<Picture> composed;
Translated<Picture> translated;
};
produce typescript discriminated unions (Picture). Refer to the typescript docs for more information on the discriminated union pattern in typescript.
ADL newtypes and type aliases are eliminated in the generated typescript code by substitution.
Unlike the the haskell and java language backends, the typescript backend doesn't generate code for serialization. Instead it generates a representation of each ADL type, available at runtime. This representation can be processed generically to implement serialization and potentially many other capabilities. For each ADL type T, the typescript backend will also generate:
- an ast representation (as a value of type ScopedDecl)
- a type expression function (returning a value of type ATypeExpr)
Together with a standard DeclResolver
interface,
these are sufficient to provide runtime access to ADL type
information. In order to build a DeclResolver
, each generated ADL
modules contains an _AST_MAP
value, which can be passed to
a runtime provided helper function. One
generally has a single global DeclResolver
instance for an
application, that can resolve all available ADL definitions. For
example:
import * as adl from "./adlgen/runtime/adl";
import * as common from './adlgen/common';
import * as ui from './adlgen/common/ui';
export const DECL_RESOLVER = adl.declResolver({
...common._AST_MAP,
...ui._AST_MAP
});
A small amount of runtime code is required to support the ADL generated typescript. This code is referenced as @adllang/adl-runtime
and published to both JSR and NPM.
Alternatively, the adl compiler can embed the runtime code in the generated typescript via the --include-rt
and
--runtime-dir
flags.
The json module makes use of the runtime ast to provide this API:
type Json = {}|null;
export interface JsonBinding<T> {
toJson (t : T): Json;
fromJson(json : Json) : T;
};
function createJsonBinding<T>(dresolver : DeclResolver, texpr : ATypeExpr<T>) : JsonBinding<T> {
...
}
Hence, a concrete example to serialize a value:
const pictureJB : JsonBinding<Picture> = createJsonBinding(dresolver, picturemodule.texprPicture());
const p : Picture = ...;
const seralized = JSON.stringify(pictureJB.toJson(p));
This approach works for arbitrary ADL Types, including generics.
The typescript backend merges annotations from files with an .adl-ts
suffix: eg when loading demo/model.adl
it will automatically merge
demo/model.adl-ts
if found.
Any Doc
annotations (which can also be specified using ///
comments), are included as comments in the generated typescript code.
The TypescriptGenerate
annotation can be applied to
modules or declarations to disable code generation. This is useful if
you have a large tree of ADL only some of which needs generated typescript
code.