@ui5/ts-interface-generator
Version:
Generator for TypeScript type definitions for custom UI5 controls implemented in TypeScript
656 lines • 42.6 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateMethods = generateMethods;
exports.generateEventWithGenericsCompatibilityModule = generateEventWithGenericsCompatibilityModule;
exports.generateSettingsInterface = generateSettingsInterface;
exports.generateEventParameterInterfaces = generateEventParameterInterfaces;
exports.generateEventTypeAliases = generateEventTypeAliases;
exports.addLineBreakBefore = addLineBreakBefore;
exports.createConstructorBlock = createConstructorBlock;
const ts = require("typescript");
const astToString_1 = __importDefault(require("./astToString"));
const loglevel_1 = __importDefault(require("loglevel"));
const jsdocGenerator_1 = require("./jsdocGenerator");
const preferences_1 = __importDefault(require("./preferences"));
// CAUTION: incompatible changes in TypeScript!
// factory.createParameterDeclaration -> use fixedCreateParameterDeclaration
// factory.createModuleDeclaration -> check TS version or als obuild a fixed one
// factory.createTypeAliasDeclaration -> same
const factory = ts.factory;
const fixedCreateParameterDeclaration = parseFloat(ts.version) >= 4.8
? factory.createParameterDeclaration.bind(this) // not used, but required by linting
: function (...args) {
// @ts-ignore old signature before 4.8 is used here
return factory.createParameterDeclaration(undefined, ...args);
};
function generateSettingsInterface(classInfo, classFileName, constructorSignaturesAvailable, settingsTypeFullName, requiredImports, knownGlobals, eventTypeAliases) {
const interfaceProperties = [];
const currentClassName = classInfo.name;
// properties
for (const n in classInfo.properties) {
const property = classInfo.properties[n];
if (property.visibility !== "hidden") {
const propertyTypes = [
// allowed types: 1. the actual type, ...
createTSTypeNode(property.type, requiredImports, knownGlobals, currentClassName),
createTSTypeNode(
// 2. a binding info object...
"sap.ui.base.ManagedObject.PropertyBindingInfo", requiredImports, knownGlobals, currentClassName),
];
if (property.type !== "string") {
// ...and if "string" is not allowed, anyway, then:
propertyTypes.push(createBindingStringTypeNode()); // 3. a binding string
}
const propertySignature = factory.createPropertySignature(undefined, property.name, factory.createToken(ts.SyntaxKind.QuestionToken), factory.createUnionTypeNode(propertyTypes));
addJSDocCommentToNode(propertySignature, (0, jsdocGenerator_1.buildJSDocStringFromLines)((0, jsdocGenerator_1.createJSDocCenterPart)(property)));
interfaceProperties.push(propertySignature);
}
}
// aggregations
for (const n in classInfo.aggregations) {
const aggregation = classInfo.aggregations[n];
if (aggregation.visibility !== "hidden") {
let aggregationInitializationTypeNode;
const aggregationSingleTypeNode = createTSTypeNode(aggregation.type, requiredImports, knownGlobals, currentClassName);
if (aggregation.cardinality === "0..1") {
if (Array.isArray(aggregation.altTypes) &&
aggregation.altTypes.length > 0) {
const typesToUse = [
aggregationSingleTypeNode,
createTSTypeNode(
// add first altType as alternative - only ONE is supported by UI5
aggregation.altTypes[0], requiredImports, knownGlobals, currentClassName),
];
typesToUse.push(createTSTypeNode(
// altType can be bound via property binding
"sap.ui.base.ManagedObject.PropertyBindingInfo", requiredImports, knownGlobals, currentClassName));
if (aggregation.altTypes[0] !== "string") {
// if "string" is not anyway allowed, also allow binding strings
typesToUse.push(createBindingStringTypeNode());
}
aggregationInitializationTypeNode =
factory.createUnionTypeNode(typesToUse);
}
else {
// no altTypes
aggregationInitializationTypeNode = aggregationSingleTypeNode;
}
}
else {
// 0..n
aggregationInitializationTypeNode = factory.createUnionTypeNode([
factory.createArrayTypeNode(aggregationSingleTypeNode), // 1. the type in an array
aggregationSingleTypeNode, // 2. the type as single object
createTSTypeNode(
// 3. an aggregation binding info object
"sap.ui.base.ManagedObject.AggregationBindingInfo", requiredImports, knownGlobals, currentClassName),
createBindingStringTypeNode(), // 4. a binding string
]);
}
const propertySignature = factory.createPropertySignature(undefined, aggregation.name, factory.createToken(ts.SyntaxKind.QuestionToken), aggregationInitializationTypeNode);
addJSDocCommentToNode(propertySignature, (0, jsdocGenerator_1.buildJSDocStringFromLines)((0, jsdocGenerator_1.createJSDocCenterPart)(aggregation)));
interfaceProperties.push(propertySignature);
}
}
// associations
for (const n in classInfo.associations) {
const association = classInfo.associations[n];
if (association.visibility !== "hidden") {
let associationInitializationTypeNode;
const associationSingleTypeNode = createTSTypeNode(association.type, requiredImports, knownGlobals, currentClassName);
// allow object and string (=ID) and in case of multiple associations also arrays
if (association.cardinality === "0..1") {
associationInitializationTypeNode = factory.createUnionTypeNode([
associationSingleTypeNode,
factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
]);
}
else {
// 0..n
associationInitializationTypeNode = factory.createUnionTypeNode([
associationSingleTypeNode,
factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
factory.createArrayTypeNode(factory.createUnionTypeNode([
associationSingleTypeNode,
factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
])),
]);
}
const propertySignature = factory.createPropertySignature(undefined, association.name, factory.createToken(ts.SyntaxKind.QuestionToken), associationInitializationTypeNode);
addJSDocCommentToNode(propertySignature, (0, jsdocGenerator_1.buildJSDocStringFromLines)((0, jsdocGenerator_1.createJSDocCenterPart)(association)));
(factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
interfaceProperties.push(propertySignature));
}
}
// events
for (const n in classInfo.events) {
const event = classInfo.events[n];
if (event.visibility !== "hidden") {
const propertySignature = factory.createPropertySignature(undefined, event.name, factory.createToken(ts.SyntaxKind.QuestionToken), factory.createFunctionTypeNode([], [
fixedCreateParameterDeclaration(undefined, undefined, "event", undefined, factory.createTypeReferenceNode(eventTypeAliases[event.name].name)),
], factory.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword)));
addJSDocCommentToNode(propertySignature, (0, jsdocGenerator_1.buildJSDocStringFromLines)((0, jsdocGenerator_1.createJSDocCenterPart)(event)));
interfaceProperties.push(propertySignature);
}
}
let ownSettingsTypeName = "$" + classInfo.name + "Settings";
if (settingsTypeFullName.endsWith(ownSettingsTypeName)) {
// name clash
ownSettingsTypeName += "_1"; // append suffix to make the name unique
}
const localName = uniqueImport(settingsTypeFullName, requiredImports, knownGlobals, currentClassName);
if (!constructorSignaturesAvailable) {
printConstructorBlockWarning(ownSettingsTypeName, classInfo.name, classFileName); // TODO: only print when the original class is missing the constructors!
}
else {
loglevel_1.default.debug(`Constructor signatures are present in implementation file of ${classInfo.name}.`);
}
const settingsSuperclass = factory.createIdentifier(localName);
const settingsSuperclassAsExpression = factory.createExpressionWithTypeArguments(settingsSuperclass, undefined);
const heritageClauses = [
factory.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [
settingsSuperclassAsExpression,
]),
];
let myInterface;
if (parseFloat(ts.version) >= 4.8) {
myInterface = factory.createInterfaceDeclaration(undefined, ownSettingsTypeName, undefined, heritageClauses, interfaceProperties);
}
else {
myInterface = factory.createInterfaceDeclaration(undefined, undefined, ownSettingsTypeName, undefined, heritageClauses,
// @ts-ignore: below TS 4.8 there were more params
interfaceProperties);
}
addLineBreakBefore(myInterface, 2);
ts.addSyntheticLeadingComment(myInterface, ts.SyntaxKind.MultiLineCommentTrivia, "*\n * Interface defining the settings object used in constructor calls\n ");
addLineBreakBefore(myInterface);
return myInterface;
}
// creates a template string that matches all binding strings
function createBindingStringTypeNode() {
return factory.createTemplateLiteralType(factory.createTemplateHead("{", "{"), [
factory.createTemplateLiteralTypeSpan(factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), factory.createTemplateTail("}", "}")),
]);
}
function printConstructorBlockWarning(settingsTypeName, className, fileName) {
const constructorBlock = createConstructorBlock(settingsTypeName);
const message = `
NOTE:
Class ${className} in file ${fileName} needs to contain the following constructors, in order to make TypeScript aware of the possible constructor settings. Please copy&paste the block manually, as the ts-interface-generator will not touch your source files:
===== BEGIN =====
// The following three lines were generated and should remain as-is to make TypeScript aware of the constructor signatures
${(0, astToString_1.default)(constructorBlock)}===== END =====
`;
loglevel_1.default.warn(message);
}
// adds the content into a multiline comment before the given node; the asterisk preceding each line must be present in the content
function addJSDocCommentToNode(node, content) {
if (content && preferences_1.default.get().jsdoc !== "none") {
addLineBreakBefore(node, 2); // some space before the JSDoc
// cannot explicitly create JSDoc: https://github.com/microsoft/TypeScript/issues/17146, so prepend a "*" at the very beginning to make it one
ts.addSyntheticLeadingComment(node, ts.SyntaxKind.MultiLineCommentTrivia, "*" + content, true);
}
}
function generateMethods(classInfo, requiredImports, knownGlobals, eventParameterInterfaces, eventTypeAliases) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y;
const allMethods = [];
const currentClassName = classInfo.name;
// properties
for (const n in classInfo.properties) {
const property = classInfo.properties[n];
if (property.visibility === "hidden") {
continue;
}
// property getter
const getter = factory.createMethodSignature(undefined, property.methods.get, undefined, [], [], createTSTypeNode(property.type, requiredImports, knownGlobals, currentClassName));
addLineBreakBefore(getter, 2);
ts.addSyntheticLeadingComment(getter, ts.SyntaxKind.SingleLineCommentTrivia, " property: " + n);
addJSDocCommentToNode(getter, (_a = classInfo.generatedJSDoc) === null || _a === void 0 ? void 0 : _a.PropertyGet[n]);
allMethods.push(getter);
// property setter
const setter = factory.createMethodSignature(undefined, property.methods.set, undefined, [], [
fixedCreateParameterDeclaration(undefined, undefined, n, undefined, createTSTypeNode(property.type, requiredImports, knownGlobals, currentClassName)),
], factory.createThisTypeNode());
addJSDocCommentToNode(setter, (_b = classInfo.generatedJSDoc) === null || _b === void 0 ? void 0 : _b.PropertySet[n]);
allMethods.push(setter);
if (property.bindable) {
// bind property
const bind = factory.createMethodSignature(undefined, property.methods.bind, undefined, [], [
fixedCreateParameterDeclaration(undefined, undefined, "bindingInfo", undefined, createTSTypeNode("sap.ui.base.ManagedObject.PropertyBindingInfo", requiredImports, knownGlobals, currentClassName)),
], factory.createThisTypeNode());
addJSDocCommentToNode(bind, (_c = classInfo.generatedJSDoc) === null || _c === void 0 ? void 0 : _c.PropertyBind[n]);
allMethods.push(bind);
// unbind property
const unbind = factory.createMethodSignature(undefined, property.methods.unbind, undefined, [], [], factory.createThisTypeNode());
addJSDocCommentToNode(unbind, (_d = classInfo.generatedJSDoc) === null || _d === void 0 ? void 0 : _d.PropertyUnbind[n]);
allMethods.push(unbind);
}
}
// aggregations
for (const n in classInfo.aggregations) {
const aggregation = classInfo.aggregations[n];
if (aggregation.visibility === "hidden") {
continue;
}
// aggregation getter
const getter = factory.createMethodSignature(undefined, aggregation.methods.get, undefined, [], [], aggregation.cardinality === "0..n"
? factory.createArrayTypeNode(createTSTypeNode(aggregation.type, requiredImports, knownGlobals, currentClassName))
: createTSTypeNode(aggregation.type, requiredImports, knownGlobals, currentClassName));
addLineBreakBefore(getter, 2);
ts.addSyntheticLeadingComment(getter, ts.SyntaxKind.SingleLineCommentTrivia, " aggregation: " + n);
addJSDocCommentToNode(getter, (_e = classInfo.generatedJSDoc) === null || _e === void 0 ? void 0 : _e.AggregationGet[n]);
allMethods.push(getter);
if (aggregation.cardinality === "0..n") {
// add aggregation
const add = factory.createMethodSignature(undefined, aggregation.methods.add, undefined, [], [
fixedCreateParameterDeclaration(undefined, undefined, n, undefined, createTSTypeNode(aggregation.type, requiredImports, knownGlobals, currentClassName)),
], factory.createThisTypeNode());
addJSDocCommentToNode(add, (_f = classInfo.generatedJSDoc) === null || _f === void 0 ? void 0 : _f.AggregationAdd[n]);
allMethods.push(add);
// insert aggregation
const insert = factory.createMethodSignature(undefined, aggregation.methods.insert, undefined, [], [
fixedCreateParameterDeclaration(undefined, undefined, n, undefined, createTSTypeNode(aggregation.type, requiredImports, knownGlobals, currentClassName)),
fixedCreateParameterDeclaration(undefined, undefined, "index", undefined, factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword)),
], factory.createThisTypeNode());
addJSDocCommentToNode(insert, (_g = classInfo.generatedJSDoc) === null || _g === void 0 ? void 0 : _g.AggregationInsert[n]);
allMethods.push(insert);
// remove aggregation
const remove = factory.createMethodSignature(undefined, aggregation.methods.remove, undefined, [], [
fixedCreateParameterDeclaration(undefined, undefined, n, undefined, factory.createUnionTypeNode([
factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword),
factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
createTSTypeNode(aggregation.type, requiredImports, knownGlobals, currentClassName),
])),
], factory.createUnionTypeNode([
// the removed child or null if not found
createTSTypeNode(aggregation.type, requiredImports, knownGlobals, currentClassName),
factory.createLiteralTypeNode(ts.factory.createNull()),
]));
addJSDocCommentToNode(remove, (_h = classInfo.generatedJSDoc) === null || _h === void 0 ? void 0 : _h.AggregationRemove[n]);
allMethods.push(remove);
// remove all aggregation
const removeAll = factory.createMethodSignature(undefined, aggregation.methods.removeAll, undefined, [], [], factory.createArrayTypeNode(createTSTypeNode(aggregation.type, requiredImports, knownGlobals, currentClassName)));
addJSDocCommentToNode(removeAll, (_j = classInfo.generatedJSDoc) === null || _j === void 0 ? void 0 : _j.AggregationRemoveAll[n]);
allMethods.push(removeAll);
// index of aggregation
const indexOf = factory.createMethodSignature(undefined, aggregation.methods.indexOf, undefined, [], [
fixedCreateParameterDeclaration(undefined, undefined, n, undefined, createTSTypeNode(aggregation.type, requiredImports, knownGlobals, currentClassName)),
], factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword));
addJSDocCommentToNode(indexOf, (_k = classInfo.generatedJSDoc) === null || _k === void 0 ? void 0 : _k.AggregationIndexOf[n]);
allMethods.push(indexOf);
// this._sUpdater = 'update' + N;
// this._sRefresher = 'refresh' + N;
}
else {
// set aggregation
const set = factory.createMethodSignature(undefined, aggregation.methods.set, undefined, [], [
fixedCreateParameterDeclaration(undefined, undefined, n, undefined, createTSTypeNode(aggregation.type, requiredImports, knownGlobals, currentClassName)),
], factory.createThisTypeNode());
addJSDocCommentToNode(set, (_l = classInfo.generatedJSDoc) === null || _l === void 0 ? void 0 : _l.AggregationSet[n]);
allMethods.push(set);
}
// destroy aggregation
const destroy = factory.createMethodSignature(undefined, aggregation.methods.destroy, undefined, [], [], factory.createThisTypeNode());
addJSDocCommentToNode(destroy, (_m = classInfo.generatedJSDoc) === null || _m === void 0 ? void 0 : _m.AggregationDestroy[n]);
allMethods.push(destroy);
if (aggregation.bindable) {
// bind aggregation
const bind = factory.createMethodSignature(undefined, aggregation.methods.bind, undefined, [], [
fixedCreateParameterDeclaration(undefined, undefined, "bindingInfo", undefined, createTSTypeNode("sap.ui.base.ManagedObject.AggregationBindingInfo", requiredImports, knownGlobals, currentClassName)),
], factory.createThisTypeNode());
addJSDocCommentToNode(bind, (_o = classInfo.generatedJSDoc) === null || _o === void 0 ? void 0 : _o.AggregationBind[n]);
allMethods.push(bind);
// unbind aggregation
const unbind = factory.createMethodSignature(undefined, aggregation.methods.unbind, undefined, [], [], factory.createThisTypeNode());
addJSDocCommentToNode(unbind, (_p = classInfo.generatedJSDoc) === null || _p === void 0 ? void 0 : _p.AggregationUnbind[n]);
allMethods.push(unbind);
}
}
// associations
for (const n in classInfo.associations) {
const association = classInfo.associations[n];
if (association.visibility === "hidden") {
continue;
}
// association getter
const getter = factory.createMethodSignature(undefined, association.methods.get, undefined, [], [], association.cardinality === "0..n"
? factory.createArrayTypeNode(factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword))
: factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword));
addLineBreakBefore(getter, 2);
ts.addSyntheticLeadingComment(getter, ts.SyntaxKind.SingleLineCommentTrivia, " association: " + n);
addJSDocCommentToNode(getter, (_q = classInfo.generatedJSDoc) === null || _q === void 0 ? void 0 : _q.AssociationGet[n]);
allMethods.push(getter);
// association setter
if (association.cardinality === "0..1") {
// set association
const setter = factory.createMethodSignature(undefined, association.methods.set, undefined, [], [
fixedCreateParameterDeclaration(undefined, undefined, n, factory.createToken(ts.SyntaxKind.QuestionToken), factory.createUnionTypeNode([
factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
createTSTypeNode(association.type, requiredImports, knownGlobals, currentClassName),
])),
], factory.createThisTypeNode());
addJSDocCommentToNode(setter, (_r = classInfo.generatedJSDoc) === null || _r === void 0 ? void 0 : _r.AssociationSet[n]);
allMethods.push(setter);
}
else {
// 0..n
// add association
const add = factory.createMethodSignature(undefined, association.methods.add, undefined, [], [
fixedCreateParameterDeclaration(undefined, undefined, n, undefined, factory.createUnionTypeNode([
factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
createTSTypeNode(association.type, requiredImports, knownGlobals, currentClassName),
])),
], factory.createThisTypeNode());
addJSDocCommentToNode(add, (_s = classInfo.generatedJSDoc) === null || _s === void 0 ? void 0 : _s.AssociationAdd[n]);
allMethods.push(add);
// remove association
const remove = factory.createMethodSignature(undefined, association.methods.remove, undefined, [], [
fixedCreateParameterDeclaration(undefined, undefined, n, undefined, factory.createUnionTypeNode([
factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword),
factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
createTSTypeNode(association.type, requiredImports, knownGlobals, currentClassName),
])),
], factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword));
addJSDocCommentToNode(remove, (_t = classInfo.generatedJSDoc) === null || _t === void 0 ? void 0 : _t.AssociationRemove[n]);
allMethods.push(remove);
// remove all aggregation
const removeAll = factory.createMethodSignature(undefined, association.methods.removeAll, undefined, [], [], factory.createArrayTypeNode(factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)));
addJSDocCommentToNode(removeAll, (_u = classInfo.generatedJSDoc) === null || _u === void 0 ? void 0 : _u.AssociationRemoveAll[n]);
allMethods.push(removeAll);
}
}
// events
for (const n in classInfo.events) {
const event = classInfo.events[n];
if (event.visibility === "hidden") {
continue;
}
// attach event
const callback = factory.createFunctionTypeNode([], [
fixedCreateParameterDeclaration(undefined, undefined, "event", undefined, factory.createTypeReferenceNode(eventTypeAliases[event.name].name)),
], factory.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword));
const attach = factory.createMethodSignature(undefined, event.methods.attach, undefined, [], [
fixedCreateParameterDeclaration(undefined, undefined, "fn", undefined, callback),
fixedCreateParameterDeclaration(undefined, undefined, "listener", factory.createToken(ts.SyntaxKind.QuestionToken), factory.createKeywordTypeNode(ts.SyntaxKind.ObjectKeyword)),
], factory.createThisTypeNode());
addLineBreakBefore(attach, 2);
ts.addSyntheticLeadingComment(attach, ts.SyntaxKind.SingleLineCommentTrivia, " event: " + n);
addJSDocCommentToNode(attach, (_v = classInfo.generatedJSDoc) === null || _v === void 0 ? void 0 : _v.EventAttach[n]);
allMethods.push(attach);
// attach event (with data)
const callbackWithData = factory.createFunctionTypeNode([], [
fixedCreateParameterDeclaration(undefined, undefined, "event", undefined, factory.createTypeReferenceNode(eventTypeAliases[event.name].name)),
fixedCreateParameterDeclaration(undefined, undefined, "data", undefined, factory.createTypeReferenceNode("CustomDataType")),
], factory.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword));
const attach2 = factory.createMethodSignature(undefined, event.methods.attach, undefined, [
parseFloat(ts.version) >= 4.8
? factory.createTypeParameterDeclaration(undefined, "CustomDataType", factory.createKeywordTypeNode(ts.SyntaxKind.ObjectKeyword))
: factory.createTypeParameterDeclaration(
// @ts-ignore this is the old method signature before TS 4.8
"CustomDataType", factory.createKeywordTypeNode(ts.SyntaxKind.ObjectKeyword)),
], [
fixedCreateParameterDeclaration(undefined, undefined, "data", undefined, factory.createTypeReferenceNode("CustomDataType")),
fixedCreateParameterDeclaration(undefined, undefined, "fn", undefined, callbackWithData),
fixedCreateParameterDeclaration(undefined, undefined, "listener", factory.createToken(ts.SyntaxKind.QuestionToken), factory.createKeywordTypeNode(ts.SyntaxKind.ObjectKeyword)),
], factory.createThisTypeNode());
addJSDocCommentToNode(attach2, (_w = classInfo.generatedJSDoc) === null || _w === void 0 ? void 0 : _w.EventAttachWithData[n]);
allMethods.push(attach2);
// detach event
const detach = factory.createMethodSignature(undefined, event.methods.detach, undefined, [], [
fixedCreateParameterDeclaration(undefined, undefined, "fn", undefined, callback),
fixedCreateParameterDeclaration(undefined, undefined, "listener", factory.createToken(ts.SyntaxKind.QuestionToken), factory.createKeywordTypeNode(ts.SyntaxKind.ObjectKeyword)),
], factory.createThisTypeNode());
addJSDocCommentToNode(detach, (_x = classInfo.generatedJSDoc) === null || _x === void 0 ? void 0 : _x.EventDetach[n]);
allMethods.push(detach);
const returnValue = event.allowPreventDefault
? factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword)
: factory.createThisTypeNode();
// fire event
const fire = factory.createMethodSignature(undefined, event.methods.fire, undefined, [], [
// TODO: describe parameter object with all details
fixedCreateParameterDeclaration(undefined, undefined, "parameters", factory.createToken(ts.SyntaxKind.QuestionToken), factory.createTypeReferenceNode(eventParameterInterfaces[event.name].name)),
], returnValue);
addJSDocCommentToNode(fire, (_y = classInfo.generatedJSDoc) === null || _y === void 0 ? void 0 : _y.EventFire[n]);
allMethods.push(fire);
}
return allMethods;
}
function createTSTypeNode(typeName, requiredImports, knownGlobals, currentClassName, typeArguments = []) {
switch (typeName) {
case "string":
return factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword);
case "string[]":
return factory.createArrayTypeNode(factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword));
case "int":
case "float":
return factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword);
case "int[]":
case "float[]":
return factory.createArrayTypeNode(factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword));
case "boolean":
return factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword);
case "boolean[]":
return factory.createArrayTypeNode(factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword));
case "object":
return factory.createKeywordTypeNode(ts.SyntaxKind.ObjectKeyword);
case "object[]":
return factory.createArrayTypeNode(factory.createKeywordTypeNode(ts.SyntaxKind.ObjectKeyword));
case "function":
return factory.createTypeReferenceNode(factory.createIdentifier("Function"));
case "function[]":
return factory.createArrayTypeNode(factory.createTypeReferenceNode(factory.createIdentifier("Function")));
case "any":
return factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword);
case "any[]": // a kinda strange type, but to be complete, let's cover it
return factory.createArrayTypeNode(factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword));
default:
// UI5 type
if (typeName.endsWith("[]")) {
// rare case: an array thereof, something like "sap.ui.core.CSSSize[]"
return factory.createArrayTypeNode(factory.createTypeReferenceNode(uniqueImport(typeName.slice(0, -2).trim(), requiredImports, knownGlobals, currentClassName), typeArguments));
}
else {
// common case: something like "sap.ui.core.CSSSize"
return factory.createTypeReferenceNode(uniqueImport(typeName, requiredImports, knownGlobals, currentClassName), typeArguments);
}
}
}
function uniqueImport(typeName, requiredImports, knownGlobals, currentClassName) {
if (typeName === currentClassName) {
// this is the class we are currently dealing with; no import and no name uniqueness check required
requiredImports.selfIsUsed = true; // FIXME: improve this shortcut
return typeName;
}
if (requiredImports[typeName]) {
return requiredImports[typeName].localName;
}
const parts = typeName.split(".");
let localName = parts[parts.length - 1];
// ensure uniqueness
while (nameIsUsed(localName, requiredImports)) {
localName += "_";
}
let moduleInfo = knownGlobals[typeName];
if (!moduleInfo) {
// FIXME e.g. a local module within the app
const match = typeName.match(/"([^"]+)"\.(.*)/);
if (match) {
moduleInfo = {
localName: localName,
moduleName: match[1],
exportName: match[2] || undefined,
};
}
else {
const moduleName = typeName.replace(/\./g, "/"); // FIXME
moduleInfo = {
localName,
moduleName,
exportName: undefined, // FIXME
};
loglevel_1.default.warn(`For the type '${typeName}' an import is created with module name '${moduleName}', using its default export. Is this correct?
Usually this indicates some kind of issue. Maybe this import will also show up as error in your code editor.
The cause of this could be that the type '${typeName}' is referenced somewhere in Class '${currentClassName}', but is mis-spelled or does actually not exist.`);
}
}
requiredImports[typeName] = {
localName: localName,
moduleName: moduleInfo.moduleName,
exportName: moduleInfo.exportName,
};
return localName;
}
function nameIsUsed(localName, requiredImports) {
for (const importName in requiredImports) {
if (requiredImports[importName].localName === localName) {
// name already used
return true;
}
}
}
function addLineBreakBefore(node, count = 1) {
for (let i = 0; i < count; i++) {
ts.addSyntheticLeadingComment(node, ts.SyntaxKind.SingleLineCommentTrivia, "");
}
}
function createConstructorBlock(settingsTypeName) {
const nodes = [];
// This creates:
// constructor(id?: string | $SampleControlSettings);
nodes.push(factory.createConstructorDeclaration(undefined, [
fixedCreateParameterDeclaration(undefined, undefined, "idOrSettings", factory.createToken(ts.SyntaxKind.QuestionToken), factory.createUnionTypeNode([
factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
factory.createTypeReferenceNode(settingsTypeName),
])),
], undefined));
// This creates:
// constructor(id?: string, settings?: $SampleControlSettings);
nodes.push(factory.createConstructorDeclaration(undefined, [
fixedCreateParameterDeclaration(undefined, undefined, "id", factory.createToken(ts.SyntaxKind.QuestionToken), factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)),
fixedCreateParameterDeclaration(undefined, undefined, "settings", factory.createToken(ts.SyntaxKind.QuestionToken), factory.createTypeReferenceNode(settingsTypeName)),
], undefined));
// This creates:
// constructor(id?: string, settings?: $SampleControlSettings) {
// super(id, settings);
// }
nodes.push(factory.createConstructorDeclaration(undefined, [
fixedCreateParameterDeclaration(undefined, undefined, "id", factory.createToken(ts.SyntaxKind.QuestionToken), factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)),
fixedCreateParameterDeclaration(undefined, undefined, "settings", factory.createToken(ts.SyntaxKind.QuestionToken), factory.createTypeReferenceNode(settingsTypeName)),
], factory.createBlock([
factory.createExpressionStatement(factory.createCallExpression(factory.createSuper(), undefined, [
factory.createIdentifier("id"),
factory.createIdentifier("settings"),
])),
])));
return nodes;
}
const makeEventParametersName = (className, eventName) => {
const capitalizedEventName = eventName.charAt(0).toUpperCase() + eventName.slice(1);
return {
eventParametersName: `${className}$${capitalizedEventName}EventParameters`,
eventTypealiasName: `${className}$${capitalizedEventName}Event`,
};
};
function generateEventWithGenericsCompatibilityModule(className, requiredImports, knownGlobals) {
const typeParameters = [
factory.createTypeParameterDeclaration(undefined, factory.createIdentifier("ParamsType"), factory.createTypeReferenceNode(factory.createIdentifier("Record"), [
factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword),
]), factory.createKeywordTypeNode(ts.SyntaxKind.ObjectKeyword)),
];
const methods = [
factory.createMethodSignature(undefined, factory.createIdentifier("constructor"), undefined, undefined, [
fixedCreateParameterDeclaration(undefined, undefined, factory.createIdentifier("id"), undefined, factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), undefined),
fixedCreateParameterDeclaration(undefined, undefined, factory.createIdentifier("oSource"), undefined, createTSTypeNode("sap.ui.base.EventProvider", requiredImports, knownGlobals, className), undefined),
fixedCreateParameterDeclaration(undefined, undefined, factory.createIdentifier("parameters"), undefined, factory.createTypeReferenceNode(factory.createIdentifier("ParamsType"), undefined), undefined),
], undefined),
factory.createMethodSignature(undefined, factory.createIdentifier("getParameters"), undefined, undefined, [], factory.createTypeReferenceNode(factory.createIdentifier("ParamsType"), undefined)),
factory.createMethodSignature(undefined, factory.createIdentifier("getParameter"), undefined, [
factory.createTypeParameterDeclaration(undefined, factory.createIdentifier("ParamName"), factory.createTypeOperatorNode(ts.SyntaxKind.KeyOfKeyword, factory.createTypeReferenceNode(factory.createIdentifier("ParamsType"), undefined)), undefined),
], [
fixedCreateParameterDeclaration(undefined, undefined, factory.createIdentifier("name"), undefined, factory.createTypeReferenceNode(factory.createIdentifier("ParamName"), undefined), undefined),
], factory.createIndexedAccessTypeNode(factory.createTypeReferenceNode(factory.createIdentifier("ParamsType"), undefined), factory.createTypeReferenceNode(factory.createIdentifier("ParamName"), undefined))),
];
let interfaceDeclaration;
if (parseFloat(ts.version) >= 4.8) {
interfaceDeclaration = factory.createInterfaceDeclaration([
factory.createToken(ts.SyntaxKind.ExportKeyword),
factory.createToken(ts.SyntaxKind.DefaultKeyword),
], factory.createIdentifier("Event"), typeParameters, [], methods);
}
else {
interfaceDeclaration = factory.createInterfaceDeclaration(undefined, [
factory.createToken(ts.SyntaxKind.ExportKeyword),
factory.createToken(ts.SyntaxKind.DefaultKeyword),
], factory.createIdentifier("Event"), typeParameters, [],
// @ts-ignore: below TS 4.8 there were more params
methods);
}
const moduleDeclaration = parseFloat(ts.version) >= 4.8
? factory.createModuleDeclaration([factory.createToken(ts.SyntaxKind.DeclareKeyword)], factory.createStringLiteral("sap/ui/base/Event"), factory.createModuleBlock([interfaceDeclaration]))
: factory.createModuleDeclaration(undefined,
// @ts-ignore old signature
[factory.createToken(ts.SyntaxKind.DeclareKeyword)], factory.createStringLiteral("sap/ui/base/Event"), factory.createModuleBlock([interfaceDeclaration]));
ts.addSyntheticLeadingComment(moduleDeclaration, ts.SyntaxKind.SingleLineCommentTrivia, " This module enhances sap.ui.base.Event with Generics, which is needed in UI5 type definition versions below 1.115");
return moduleDeclaration;
}
function generateEventParameterInterfaces(events, className, requiredImports, knownGlobals) {
const eventParameterInterfaces = {};
for (const eventName in events) {
const event = events[eventName];
if (event.visibility !== "hidden") {
const properties = [];
for (const parameterName in event.parameters) {
const parameter = event.parameters[parameterName];
const property = factory.createPropertySignature(undefined, factory.createIdentifier(parameter.name), factory.createToken(ts.SyntaxKind.QuestionToken), createTSTypeNode(parameter.type, requiredImports, knownGlobals, className));
/*
TODO: comments for event parameters are not supported yet. From a certain nesting depth, Hjson.parse without comments is used, so they are lost.
Once they are available, this can be enabled:
addJSDocCommentToNode(
property,
buildJSDocStringFromLines(createJSDocCenterPart(parameter, []))
);
*/
properties.push(property);
}
const interfc = parseFloat(ts.version) >= 4.8
? factory.createInterfaceDeclaration([factory.createToken(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier(makeEventParametersName(className, eventName)
.eventParametersName), undefined, undefined, properties)
: factory.createInterfaceDeclaration(undefined, [factory.createToken(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier(makeEventParametersName(className, eventName)
.eventParametersName), undefined, undefined,
// @ts-ignore: below TS 4.8 there were more params
properties);
addJSDocCommentToNode(interfc, (0, jsdocGenerator_1.buildJSDocStringFromLines)((0, jsdocGenerator_1.createJSDocCenterPart)(event, [
`Interface describing the parameters of ${className}'${className.endsWith("s") ? "" : "s"} '${eventName}' event.`,
])));
// empty interfaces can cause issues with linting
if (properties.length === 0) {
ts.addSyntheticLeadingComment(interfc, ts.SyntaxKind.SingleLineCommentTrivia, " eslint-disable-next-line");
}
eventParameterInterfaces[eventName] = interfc;
}
}
return eventParameterInterfaces;
}
function generateEventTypeAliases(events, eventParameterInterfaces, className, requiredImports, knownGlobals) {
const eventTypeAliases = {};
for (const eventName in eventParameterInterfaces) {
const typeNode = createTSTypeNode("sap.ui.base.Event", requiredImports, knownGlobals, className, [
factory.createTypeReferenceNode(factory.createIdentifier(eventParameterInterfaces[eventName].name.text), undefined),
]);
const typeAlias = parseFloat(ts.version) >= 4.8
? factory.createTypeAliasDeclaration([factory.createToken(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier(makeEventParametersName(className, eventName).eventTypealiasName), undefined, typeNode)
: factory.createTypeAliasDeclaration(undefined, [factory.createToken(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier(makeEventParametersName(className, eventName).eventTypealiasName), undefined,
// @ts-ignore: below TS 4.8 there were more params
typeNode);
addJSDocCommentToNode(typeAlias, (0, jsdocGenerator_1.buildJSDocStringFromLines)((0, jsdocGenerator_1.createJSDocCenterPart)(events[eventName], [
`Type describing the ${className}'${className.endsWith("s") ? "" : "s"} '${eventName}' event.`,
])));
eventTypeAliases[eventName] = typeAlias;
}
return eventTypeAliases;
}
//# sourceMappingURL=astGenerationHelper.js.map