capnpc-ts
Version:
Cap'n Proto schema compiler for TypeScript.
517 lines • 29.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getImportNodes = exports.generateUnnamedUnionEnum = exports.generateStructNode = exports.generateStructFieldMethods = exports.generateNode = exports.generateInterfaceClasses = exports.generateFileId = exports.generateEnumNode = exports.generateDefaultValue = exports.generateConcreteListInitializer = exports.generateNestedImports = exports.generateCapnpImport = void 0;
const tslib_1 = require("tslib");
const capnp = tslib_1.__importStar(require("capnp-ts"));
const s = tslib_1.__importStar(require("capnp-ts/src/std/schema.capnp.js"));
const util_1 = require("capnp-ts/src/util");
const debug_1 = tslib_1.__importDefault(require("debug"));
const typescript_1 = tslib_1.__importDefault(require("typescript"));
const ast_creators_1 = require("./ast-creators");
const constants_1 = require("./constants");
const E = tslib_1.__importStar(require("./errors"));
const file_1 = require("./file");
const util = tslib_1.__importStar(require("./util"));
const trace = debug_1.default("capnpc:generators");
trace("load");
function generateCapnpImport(ctx) {
// Look for the special importPath annotation on the file to see if we need a different import path for capnp-ts.
const fileNode = file_1.lookupNode(ctx, ctx.file);
const tsFileId = capnp.Uint64.fromHexString(constants_1.TS_FILE_ID);
// This may be undefined if ts.capnp is not imported; fine, we'll just use the default.
const tsAnnotationFile = ctx.nodes.find((n) => n.getId().equals(tsFileId));
// We might not find the importPath annotation; that's definitely a bug but let's move on.
const tsImportPathAnnotation = tsAnnotationFile && tsAnnotationFile.getNestedNodes().find((n) => n.getName() === "importPath");
// There may not necessarily be an import path annotation on the file node. That's fine.
const importAnnotation = tsImportPathAnnotation && fileNode.getAnnotations().find((a) => a.getId().equals(tsImportPathAnnotation.getId()));
const importPath = importAnnotation === undefined ? "capnp-ts" : importAnnotation.getValue().getText();
let u;
// import * as capnp from '${importPath}';
ctx.statements.push(typescript_1.default.createImportDeclaration(constants_1.__, constants_1.__, typescript_1.default.createImportClause(u, typescript_1.default.createNamespaceImport(constants_1.CAPNP)), typescript_1.default.createLiteral(importPath)));
// import { ObjectSize as __O, Struct as __S } from '${importPath}';
ctx.statements.push(typescript_1.default.createStatement(typescript_1.default.createIdentifier(`import { ObjectSize as __O, Struct as __S } from '${importPath}'`)));
}
exports.generateCapnpImport = generateCapnpImport;
function generateNestedImports(ctx) {
ctx.imports.forEach((i) => {
const name = i.getName();
let importPath;
if (name.substr(0, 7) === "/capnp/") {
importPath = `capnp-ts/src/std/${name.substr(7)}.js`;
}
else {
importPath = name[0] === "." ? `${name}.js` : `./${name}.js`;
}
const imports = getImportNodes(ctx, file_1.lookupNode(ctx, i)).map(file_1.getFullClassName).join(", ");
if (imports.length < 1)
return;
const importStatement = `import { ${imports} } from "${importPath}"`;
trace("emitting import statement:", importStatement);
ctx.statements.push(typescript_1.default.createStatement(typescript_1.default.createIdentifier(importStatement)));
});
}
exports.generateNestedImports = generateNestedImports;
function generateConcreteListInitializer(ctx, fullClassName, field) {
const left = typescript_1.default.createPropertyAccess(typescript_1.default.createIdentifier(fullClassName), `_${util.c2t(field.getName())}`);
const right = typescript_1.default.createIdentifier(file_1.getConcreteListType(ctx, field.getSlot().getType()));
ctx.statements.push(typescript_1.default.createStatement(typescript_1.default.createAssignment(left, right)));
}
exports.generateConcreteListInitializer = generateConcreteListInitializer;
function generateDefaultValue(field) {
const name = field.getName();
const slot = field.getSlot();
const whichSlotType = slot.getType().which();
const p = constants_1.Primitive[whichSlotType];
let initializer;
switch (whichSlotType) {
case s.Type_Which.ANY_POINTER:
case s.Type_Which.DATA:
case s.Type_Which.LIST:
case s.Type_Which.STRUCT:
initializer = ast_creators_1.createValueExpression(slot.getDefaultValue());
break;
case s.Type_Which.TEXT:
initializer = typescript_1.default.createLiteral(slot.getDefaultValue().getText());
break;
case s.Type_Which.BOOL:
initializer = typescript_1.default.createCall(typescript_1.default.createPropertyAccess(constants_1.CAPNP, p.mask), constants_1.__, [
ast_creators_1.createValueExpression(slot.getDefaultValue()),
typescript_1.default.createNumericLiteral((slot.getOffset() % 8).toString()),
]);
break;
case s.Type_Which.ENUM:
case s.Type_Which.FLOAT32:
case s.Type_Which.FLOAT64:
case s.Type_Which.INT16:
case s.Type_Which.INT32:
case s.Type_Which.INT64:
case s.Type_Which.INT8:
case s.Type_Which.UINT16:
case s.Type_Which.UINT32:
case s.Type_Which.UINT64:
case s.Type_Which.UINT8:
initializer = typescript_1.default.createCall(typescript_1.default.createPropertyAccess(constants_1.CAPNP, p.mask), constants_1.__, [
ast_creators_1.createValueExpression(slot.getDefaultValue()),
]);
break;
default:
throw new Error(util_1.format(E.GEN_UNKNOWN_DEFAULT, s.Type_Which[whichSlotType]));
}
return typescript_1.default.createPropertyAssignment(`default${util.c2t(name)}`, initializer);
}
exports.generateDefaultValue = generateDefaultValue;
function generateEnumNode(ctx, node) {
trace("generateEnumNode(%s) [%s]", node, node.getDisplayName());
const members = node
.getEnum()
.getEnumerants()
.toArray()
.sort(file_1.compareCodeOrder)
.map((e) => typescript_1.default.createEnumMember(util.c2s(e.getName())));
const d = typescript_1.default.createEnumDeclaration(constants_1.__, [constants_1.EXPORT], file_1.getFullClassName(node), members);
ctx.statements.push(d);
}
exports.generateEnumNode = generateEnumNode;
function generateFileId(ctx) {
trace("generateFileId()");
// export const _capnpFileId = 'abcdef';
const fileId = typescript_1.default.createLiteral(ctx.file.getId().toHexString());
ctx.statements.push(typescript_1.default.createVariableStatement([constants_1.EXPORT], typescript_1.default.createVariableDeclarationList([typescript_1.default.createVariableDeclaration("_capnpFileId", constants_1.__, fileId)], typescript_1.default.NodeFlags.Const)));
}
exports.generateFileId = generateFileId;
function generateInterfaceClasses(_ctx, node) {
trace("Interface generation is not yet implemented.");
/* tslint:disable-next-line */
console.error(`CAPNP-TS: Warning! Interface generation (${node.getDisplayName()}) is not yet implemented.`);
}
exports.generateInterfaceClasses = generateInterfaceClasses;
function generateNode(ctx, node) {
trace("generateNode(%s, %s)", ctx, node.getId().toHexString());
const nodeId = node.getId();
const nodeIdHex = nodeId.toHexString();
if (ctx.generatedNodeIds.indexOf(nodeIdHex) > -1)
return;
ctx.generatedNodeIds.push(nodeIdHex);
/** An array of group structs formed as children of this struct. They appear before the struct node in the file. */
const groupNodes = ctx.nodes.filter((n) => n.getScopeId().equals(nodeId) && n.isStruct() && n.getStruct().getIsGroup());
/**
* An array of nodes that are nested within this node; these must appear first since those symbols will be
* refernced in the node's class definition.
*/
const nestedNodes = node.getNestedNodes().map((n) => file_1.lookupNode(ctx, n));
nestedNodes.forEach((n) => generateNode(ctx, n));
groupNodes.forEach((n) => generateNode(ctx, n));
const whichNode = node.which();
switch (whichNode) {
case s.Node.STRUCT:
generateStructNode(ctx, node, false);
break;
case s.Node.CONST:
// Const nodes are generated along with the containing class, ignore these.
break;
case s.Node.ENUM:
generateEnumNode(ctx, node);
break;
case s.Node.INTERFACE:
generateStructNode(ctx, node, true);
break;
case s.Node.ANNOTATION:
trace("ignoring unsupported annotation node: %s", node.getDisplayName());
break;
case s.Node.FILE:
default:
throw new Error(util_1.format(E.GEN_NODE_UNKNOWN_TYPE, s.Node_Which[whichNode]));
}
}
exports.generateNode = generateNode;
const listLengthParameterName = "length";
function generateStructFieldMethods(ctx, members, node, field) {
let jsType;
let whichType;
if (field.isSlot()) {
const slotType = field.getSlot().getType();
jsType = file_1.getJsType(ctx, slotType, false);
whichType = slotType.which();
}
else if (field.isGroup()) {
jsType = file_1.getFullClassName(file_1.lookupNode(ctx, field.getGroup().getTypeId()));
whichType = "group";
}
else {
throw new Error(util_1.format(E.GEN_UNKNOWN_STRUCT_FIELD, field.which()));
}
const jsTypeReference = typescript_1.default.createTypeReferenceNode(jsType, constants_1.__);
const discriminantOffset = node.getStruct().getDiscriminantOffset();
const name = field.getName();
const properName = util.c2t(name);
const hadExplicitDefault = field.isSlot() && field.getSlot().getHadExplicitDefault();
const discriminantValue = field.getDiscriminantValue();
const fullClassName = file_1.getFullClassName(node);
const union = discriminantValue !== s.Field.NO_DISCRIMINANT;
const offset = (field.isSlot() && field.getSlot().getOffset()) || 0;
const offsetLiteral = typescript_1.default.createNumericLiteral(offset.toString());
/** __S.getPointer(0, this) */
const getPointer = typescript_1.default.createCall(typescript_1.default.createPropertyAccess(constants_1.STRUCT, "getPointer"), constants_1.__, [offsetLiteral, constants_1.THIS]);
/** __S.copyFrom(value, __S.getPointer(0, this)) */
const copyFromValue = typescript_1.default.createCall(typescript_1.default.createPropertyAccess(constants_1.STRUCT, "copyFrom"), constants_1.__, [constants_1.VALUE, getPointer]);
/** capnp.Orphan<Foo> */
const orphanType = typescript_1.default.createTypeReferenceNode("capnp.Orphan", [jsTypeReference]);
const discriminantOffsetLiteral = typescript_1.default.createNumericLiteral((discriminantOffset * 2).toString());
const discriminantValueLiteral = typescript_1.default.createNumericLiteral(discriminantValue.toString());
/** __S.getUint16(0, this) */
const getDiscriminant = typescript_1.default.createCall(typescript_1.default.createPropertyAccess(constants_1.STRUCT, "getUint16"), constants_1.__, [
discriminantOffsetLiteral,
constants_1.THIS,
]);
/** __S.setUint16(0, this) */
const setDiscriminant = typescript_1.default.createCall(typescript_1.default.createPropertyAccess(constants_1.STRUCT, "setUint16"), constants_1.__, [
discriminantOffsetLiteral,
discriminantValueLiteral,
constants_1.THIS,
]);
const defaultValue = hadExplicitDefault
? typescript_1.default.createIdentifier(`${fullClassName}._capnp.default${properName}`)
: undefined;
let adopt = false;
let disown = false;
let init;
let has = false;
let get;
let set;
let getArgs;
switch (whichType) {
case s.Type.ANY_POINTER:
getArgs = [offsetLiteral, constants_1.THIS];
if (defaultValue)
getArgs.push(defaultValue);
adopt = true;
disown = true;
/** __S.getPointer(0, this) */
get = typescript_1.default.createCall(typescript_1.default.createPropertyAccess(constants_1.STRUCT, "getPointer"), constants_1.__, getArgs);
has = true;
/** __S.copyFrom(value, __S.getPointer(0, this)) */
set = typescript_1.default.createCall(typescript_1.default.createPropertyAccess(constants_1.STRUCT, "copyFrom"), constants_1.__, [constants_1.VALUE, get]);
break;
case s.Type.BOOL:
case s.Type.ENUM:
case s.Type.FLOAT32:
case s.Type.FLOAT64:
case s.Type.INT16:
case s.Type.INT32:
case s.Type.INT64:
case s.Type.INT8:
case s.Type.UINT16:
case s.Type.UINT32:
case s.Type.UINT64:
case s.Type.UINT8: {
const { byteLength, getter, setter } = constants_1.Primitive[whichType];
// NOTE: For a BOOL type this is actually a bit offset; `byteLength` will be `1` in that case.
const byteOffset = typescript_1.default.createNumericLiteral((offset * byteLength).toString());
getArgs = [byteOffset, constants_1.THIS];
if (defaultValue)
getArgs.push(defaultValue);
/** __S.getXYZ(0, this) */
get = typescript_1.default.createCall(typescript_1.default.createPropertyAccess(constants_1.STRUCT, getter), constants_1.__, getArgs);
/** __S.setXYZ(0, value, this) */
set = typescript_1.default.createCall(typescript_1.default.createPropertyAccess(constants_1.STRUCT, setter), constants_1.__, [byteOffset, constants_1.VALUE, constants_1.THIS]);
break;
}
case s.Type.DATA:
getArgs = [offsetLiteral, constants_1.THIS];
if (defaultValue)
getArgs.push(defaultValue);
adopt = true;
disown = true;
/** __S.getData(0, this) */
get = typescript_1.default.createCall(typescript_1.default.createPropertyAccess(constants_1.STRUCT, "getData"), constants_1.__, getArgs);
has = true;
/** __S.initData(0, length, this) */
init = typescript_1.default.createCall(typescript_1.default.createPropertyAccess(constants_1.STRUCT, "initData"), constants_1.__, [offsetLiteral, constants_1.LENGTH, constants_1.THIS]);
set = copyFromValue;
break;
case s.Type.INTERFACE:
if (hadExplicitDefault) {
throw new Error(util_1.format(E.GEN_EXPLICIT_DEFAULT_NON_PRIMITIVE, "INTERFACE"));
}
/** __S.getPointerAs(0, Foo, this) */
get = typescript_1.default.createCall(typescript_1.default.createPropertyAccess(constants_1.STRUCT, "getPointerAs"), constants_1.__, [
offsetLiteral,
typescript_1.default.createIdentifier(jsType),
constants_1.THIS,
]);
set = copyFromValue;
break;
case s.Type.LIST: {
const whichElementType = field.getSlot().getType().getList().getElementType().which();
let listClass = constants_1.ConcreteListType[whichElementType];
if (whichElementType === s.Type.LIST || whichElementType === s.Type.STRUCT) {
listClass = `${fullClassName}._${properName}`;
}
else if (listClass === void 0) {
/* istanbul ignore next */
throw new Error(util_1.format(E.GEN_UNSUPPORTED_LIST_ELEMENT_TYPE, whichElementType));
}
const listClassIdentifier = typescript_1.default.createIdentifier(listClass);
getArgs = [offsetLiteral, listClassIdentifier, constants_1.THIS];
if (defaultValue)
getArgs.push(defaultValue);
adopt = true;
disown = true;
/** __S.getList(0, MyStruct._Foo, this) */
get = typescript_1.default.createCall(typescript_1.default.createPropertyAccess(constants_1.STRUCT, "getList"), constants_1.__, getArgs);
has = true;
/** __S.initList(0, MyStruct._Foo, length, this) */
init = typescript_1.default.createCall(typescript_1.default.createPropertyAccess(constants_1.STRUCT, "initList"), constants_1.__, [
offsetLiteral,
listClassIdentifier,
typescript_1.default.createIdentifier(listLengthParameterName),
constants_1.THIS,
]);
set = copyFromValue;
break;
}
case s.Type.STRUCT: {
const structType = typescript_1.default.createIdentifier(file_1.getJsType(ctx, field.getSlot().getType(), false));
getArgs = [offsetLiteral, structType, constants_1.THIS];
if (defaultValue)
getArgs.push(defaultValue);
adopt = true;
disown = true;
/** __S.getStruct(0, Foo, this) */
get = typescript_1.default.createCall(typescript_1.default.createPropertyAccess(constants_1.STRUCT, "getStruct"), constants_1.__, getArgs);
has = true;
/** __S.initStruct(0, Foo, this) */
init = typescript_1.default.createCall(typescript_1.default.createPropertyAccess(constants_1.STRUCT, "initStructAt"), constants_1.__, [offsetLiteral, structType, constants_1.THIS]);
set = copyFromValue;
break;
}
case s.Type.TEXT:
getArgs = [offsetLiteral, constants_1.THIS];
if (defaultValue)
getArgs.push(defaultValue);
/** __S.getText(0, this) */
get = typescript_1.default.createCall(typescript_1.default.createPropertyAccess(constants_1.STRUCT, "getText"), constants_1.__, getArgs);
/** __S.setText(0, value, this) */
set = typescript_1.default.createCall(typescript_1.default.createPropertyAccess(constants_1.STRUCT, "setText"), constants_1.__, [offsetLiteral, constants_1.VALUE, constants_1.THIS]);
break;
case s.Type.VOID:
break;
case "group": {
if (hadExplicitDefault) {
throw new Error(util_1.format(E.GEN_EXPLICIT_DEFAULT_NON_PRIMITIVE, "group"));
}
const groupType = typescript_1.default.createIdentifier(jsType);
/** __S.getAs(Foo, this); */
get = typescript_1.default.createCall(typescript_1.default.createPropertyAccess(constants_1.STRUCT, "getAs"), constants_1.__, [groupType, constants_1.THIS]);
init = get;
break;
}
default:
// TODO Maybe this should be an error?
break;
}
// adoptFoo(value: capnp.Orphan<Foo>): void { __S.adopt(value, this._getPointer(3)); }}
if (adopt) {
const parameters = [typescript_1.default.createParameter(constants_1.__, constants_1.__, constants_1.__, constants_1.VALUE, constants_1.__, orphanType, constants_1.__)];
const expressions = [typescript_1.default.createCall(typescript_1.default.createPropertyAccess(constants_1.STRUCT, "adopt"), constants_1.__, [constants_1.VALUE, getPointer])];
if (union)
expressions.unshift(setDiscriminant);
members.push(ast_creators_1.createMethod(`adopt${properName}`, parameters, constants_1.VOID_TYPE, expressions));
}
// disownFoo(): capnp.Orphan<Foo> { return __S.disown(this.getFoo()); }
if (disown) {
const getter = typescript_1.default.createCall(typescript_1.default.createPropertyAccess(constants_1.THIS, `get${properName}`), constants_1.__, []);
const expressions = [typescript_1.default.createCall(typescript_1.default.createPropertyAccess(constants_1.STRUCT, "disown"), constants_1.__, [getter])];
members.push(ast_creators_1.createMethod(`disown${properName}`, [], orphanType, expressions));
}
// getFoo(): FooType { ... }
if (get) {
const expressions = [get];
if (union) {
expressions.unshift(typescript_1.default.createCall(typescript_1.default.createPropertyAccess(constants_1.STRUCT, "testWhich"), constants_1.__, [
typescript_1.default.createLiteral(name),
getDiscriminant,
discriminantValueLiteral,
constants_1.THIS,
]));
}
members.push(ast_creators_1.createMethod(`get${properName}`, [], jsTypeReference, expressions));
}
// hasFoo(): boolean { ... }
if (has) {
// !__S.isNull(this._getPointer(8));
const expressions = [
typescript_1.default.createLogicalNot(typescript_1.default.createCall(typescript_1.default.createPropertyAccess(constants_1.STRUCT, "isNull"), constants_1.__, [getPointer])),
];
members.push(ast_creators_1.createMethod(`has${properName}`, [], constants_1.BOOLEAN_TYPE, expressions));
}
// initFoo(): FooType { ... } / initFoo(length: number): capnp.List<FooElementType> { ... }
if (init) {
const parameters = whichType === s.Type.DATA || whichType === s.Type.LIST
? [typescript_1.default.createParameter(constants_1.__, constants_1.__, constants_1.__, listLengthParameterName, constants_1.__, constants_1.NUMBER_TYPE, constants_1.__)]
: [];
const expressions = [init];
if (union)
expressions.unshift(setDiscriminant);
members.push(ast_creators_1.createMethod(`init${properName}`, parameters, jsTypeReference, expressions));
}
// isFoo(): boolean { ... }
if (union) {
const left = typescript_1.default.createCall(typescript_1.default.createPropertyAccess(constants_1.STRUCT, "getUint16"), constants_1.__, [discriminantOffsetLiteral, constants_1.THIS]);
const right = discriminantValueLiteral;
const expressions = [typescript_1.default.createBinary(left, typescript_1.default.SyntaxKind.EqualsEqualsEqualsToken, right)];
members.push(ast_creators_1.createMethod(`is${properName}`, [], constants_1.BOOLEAN_TYPE, expressions));
}
// setFoo(value: FooType): void { ... }
if (set || union) {
const expressions = [];
const parameters = [];
if (set) {
expressions.unshift(set);
parameters.unshift(typescript_1.default.createParameter(constants_1.__, constants_1.__, constants_1.__, constants_1.VALUE, constants_1.__, jsTypeReference, constants_1.__));
}
if (union) {
expressions.unshift(setDiscriminant);
}
members.push(ast_creators_1.createMethod(`set${properName}`, parameters, constants_1.VOID_TYPE, expressions));
}
}
exports.generateStructFieldMethods = generateStructFieldMethods;
function generateStructNode(ctx, node, interfaceNode) {
trace("generateStructNode(%s) [%s]", node, node.getDisplayName());
const displayNamePrefix = file_1.getDisplayNamePrefix(node);
const fullClassName = file_1.getFullClassName(node);
const nestedNodes = node
.getNestedNodes()
.map((n) => file_1.lookupNode(ctx, n))
.filter((n) => !n.isConst() && !n.isAnnotation());
const nodeId = node.getId();
const nodeIdHex = nodeId.toHexString();
const struct = node.which() === s.Node.STRUCT ? node.getStruct() : undefined;
const unionFields = file_1.getUnnamedUnionFields(node).sort(file_1.compareCodeOrder);
const dataWordCount = struct ? struct.getDataWordCount() : 0;
const dataByteLength = struct ? dataWordCount * 8 : 0;
const discriminantCount = struct ? struct.getDiscriminantCount() : 0;
const discriminantOffset = struct ? struct.getDiscriminantOffset() : 0;
const fields = struct ? struct.getFields().toArray().sort(file_1.compareCodeOrder) : [];
const pointerCount = struct ? struct.getPointerCount() : 0;
const concreteLists = fields.filter(file_1.needsConcreteListClass).sort(file_1.compareCodeOrder);
const consts = ctx.nodes.filter((n) => n.getScopeId().equals(nodeId) && n.isConst());
// const groups = ctx.nodes.filter(
// (n) => n.getScopeId().equals(nodeId) && n.isStruct() && n.getStruct().getIsGroup());
const hasUnnamedUnion = discriminantCount !== 0;
if (hasUnnamedUnion) {
generateUnnamedUnionEnum(ctx, fullClassName, unionFields);
}
const members = [];
// static readonly CONSTANT = 'foo';
members.push(...consts.map(ast_creators_1.createConstProperty));
// static readonly WHICH = MyStruct_Which.WHICH;
members.push(...unionFields.map((f) => ast_creators_1.createUnionConstProperty(fullClassName, f)));
// static readonly NestedStruct = MyStruct_NestedStruct;
members.push(...nestedNodes.map(ast_creators_1.createNestedNodeProperty));
// static readonly Client = MyInterface_Client;
// static readonly Server = MyInterface_Server;
// if (interfaceNode) {
// members.push(
// ts.createProperty(__, [STATIC, READONLY], 'Client', __, __, ts.createLiteral(`${fullClassName}_Client`)));
// members.push(
// ts.createProperty(__, [STATIC, READONLY], 'Server', __, __, ts.createLiteral(`${fullClassName}_Server`)));
// }
const defaultValues = fields.reduce((acc, f) => f.isSlot() && f.getSlot().getHadExplicitDefault() && f.getSlot().getType().which() !== s.Type.VOID
? acc.concat(generateDefaultValue(f))
: acc, []);
// static reaodnly _capnp = { displayName: 'MyStruct', id: '4732bab4310f81', size = new __O(8, 8) };
members.push(typescript_1.default.createProperty(constants_1.__, [constants_1.STATIC, constants_1.READONLY], "_capnp", constants_1.__, constants_1.__, typescript_1.default.createObjectLiteral([
typescript_1.default.createPropertyAssignment("displayName", typescript_1.default.createLiteral(displayNamePrefix)),
typescript_1.default.createPropertyAssignment("id", typescript_1.default.createLiteral(nodeIdHex)),
typescript_1.default.createPropertyAssignment("size", typescript_1.default.createNew(constants_1.OBJECT_SIZE, constants_1.__, [
typescript_1.default.createNumericLiteral(dataByteLength.toString()),
typescript_1.default.createNumericLiteral(pointerCount.toString()),
])),
].concat(defaultValues))));
// private static _ConcreteListClass: MyStruct_ConcreteListClass;
members.push(...concreteLists.map((f) => ast_creators_1.createConcreteListProperty(ctx, f)));
// getFoo() { ... } initFoo() { ... } setFoo() { ... }
fields.forEach((f) => generateStructFieldMethods(ctx, members, node, f));
// toString(): string { return 'MyStruct_' + super.toString(); }
const toStringExpression = typescript_1.default.createBinary(typescript_1.default.createLiteral(`${fullClassName}_`), typescript_1.default.SyntaxKind.PlusToken, typescript_1.default.createCall(typescript_1.default.createIdentifier("super.toString"), constants_1.__, []));
members.push(ast_creators_1.createMethod("toString", [], constants_1.STRING_TYPE, [toStringExpression], true));
if (hasUnnamedUnion) {
// which(): MyStruct_Which { return __S.getUint16(12, this); }
const whichExpression = typescript_1.default.createCall(typescript_1.default.createPropertyAccess(constants_1.STRUCT, "getUint16"), constants_1.__, [
typescript_1.default.createNumericLiteral((discriminantOffset * 2).toString()),
constants_1.THIS,
]);
members.push(ast_creators_1.createMethod("which", [], typescript_1.default.createTypeReferenceNode(`${fullClassName}_Which`, constants_1.__), [whichExpression], true));
}
const c = typescript_1.default.createClassDeclaration(constants_1.__, [constants_1.EXPORT], fullClassName, constants_1.__, [ast_creators_1.createClassExtends("__S")], members);
// Make sure the interface classes are generated first.
if (interfaceNode) {
generateInterfaceClasses(ctx, node);
}
ctx.statements.push(c);
// Write out the concrete list type initializer after all the class definitions. It can't be initialized within the
// class's static initializer because the nested type might not be defined yet.
// FIXME: This might be solvable with topological sorting?
ctx.concreteLists.push(...concreteLists.map((f) => [fullClassName, f]));
}
exports.generateStructNode = generateStructNode;
function generateUnnamedUnionEnum(ctx, fullClassName, unionFields) {
const members = unionFields
.sort(file_1.compareCodeOrder)
.map((f) => typescript_1.default.createEnumMember(util.c2s(f.getName()), typescript_1.default.createNumericLiteral(f.getDiscriminantValue().toString())));
const d = typescript_1.default.createEnumDeclaration(constants_1.__, [constants_1.EXPORT], `${fullClassName}_Which`, members);
ctx.statements.push(d);
}
exports.generateUnnamedUnionEnum = generateUnnamedUnionEnum;
function getImportNodes(ctx, node) {
return file_1.lookupNode(ctx, node)
.getNestedNodes()
.filter((n) => file_1.hasNode(ctx, n))
.map((n) => file_1.lookupNode(ctx, n))
.reduce((a, n) => a.concat([n], getImportNodes(ctx, n)), new Array())
.filter((n) => file_1.lookupNode(ctx, n).isStruct() || file_1.lookupNode(ctx, n).isEnum());
}
exports.getImportNodes = getImportNodes;
//# sourceMappingURL=generators.js.map