Permalink
Fetching contributors…
Cannot retrieve contributors at this time
137 lines (108 sloc) 4.61 KB

ADL typescript backend

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
          --include-rt        Generate the runtime code
          --exclude-ast       Exclude the generated ASTs
  -R DIR  --runtime-dir=DIR   Set the directory where runtime code is written

Generated Code

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
});

Serialization

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.

Annotations

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.