Skip to content

Commit c14f042

Browse files
committed
fix(ts-interface-generator): fix crash with parent w/o settings type
To generate constructor signatures, a settings type needs to be created which inherits from the parent class' settings type and adds the properties, aggregations etc. of the current class. This rightly leads to an error. But this should not lead to an error when the class does not add any API items at all. related to #346
1 parent 22ee953 commit c14f042

File tree

2 files changed

+56
-42
lines changed

2 files changed

+56
-42
lines changed

packages/ts-interface-generator/src/interfaceGenerationHelper.ts

+55-42
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ function getManagedObjects(
114114
throw new Error(
115115
"Type '" +
116116
typeNode.getText() +
117-
"' in " +
117+
"' referenced in " +
118118
sourceFile.fileName +
119119
" could not be resolved - are the UI5 (and other) type definitions available and known in the tsconfig? Or is there a different reason why this type would not be known?"
120120
);
@@ -130,7 +130,45 @@ function getManagedObjects(
130130
}
131131
managedObjectFound = true;
132132

133-
// ok, we have a ManagedObject/Control; now check whether there is a settings type in the superclass
133+
// ok, we have a ManagedObject/Control; now check whether it contains a metadata section, which means that accessor methods need to be generated
134+
const metadata: ts.PropertyDeclaration[] = <
135+
ts.PropertyDeclaration[]
136+
>statement.members.filter((member) => {
137+
if (
138+
ts.isPropertyDeclaration(member) &&
139+
ts.isIdentifier(member.name) &&
140+
member.name.escapedText === "metadata" &&
141+
member.modifiers &&
142+
member.modifiers.some((modifier) => {
143+
return modifier.kind === ts.SyntaxKind.StaticKeyword;
144+
})
145+
) {
146+
return true;
147+
}
148+
});
149+
if (!metadata || metadata.length === 0) {
150+
// no metadata? => nothing to do
151+
log.debug(
152+
`Class ${statement.name ? statement.name.text : ""} in ${
153+
sourceFile.fileName
154+
} inherits from ${interestingBaseClass} but has no metadata. This is not necessarily an issue, but if there is a metadata member in this class which *should* be recognized, make sure it has the 'static' keyword!`
155+
);
156+
return;
157+
} else if (metadata.length > 1) {
158+
// no metadata? => nothing to do
159+
log.warn(
160+
`ManagedObject with ${
161+
metadata.length
162+
} static metadata members in class ${
163+
statement.name ? statement.name.text : ""
164+
} inside ${
165+
sourceFile.fileName
166+
}. This is unexpected. Ignoring this class.`
167+
);
168+
return;
169+
}
170+
171+
// now check whether there is a settings type in the superclass
134172
// (which the generated settings type needs to inherit from)
135173
// There really should be, because all descendants of ManagedObject should have one!
136174
let settingsTypeFullName;
@@ -141,13 +179,22 @@ function getManagedObjects(
141179
const symbol = settingsType.getSymbol();
142180
settingsTypeFullName =
143181
typeChecker.getFullyQualifiedName(symbol);
144-
} else {
182+
} else if (metadata) {
145183
throw new Error(
146184
`${
147185
statement.name ? statement.name.text : ""
148-
} inherits from ${interestingBaseClass} but the parent class ${typeChecker.getFullyQualifiedName(
186+
} inherits from ${interestingBaseClass} and has metadata but the parent class ${typeChecker.getFullyQualifiedName(
149187
type.getSymbol()
150-
)} seems to have no settings type`
188+
)} seems to have no settings type. It might have no constructors, this is where the settings type is used.
189+
190+
In case this parent class is also in your project, make sure to add its constructors, then try again. A comment with instructions might be in the console output above.
191+
Otherwise, you can temporarily remove this file (${
192+
sourceFile.fileName
193+
}) from the project and try again to get the console output with the suggested constructors.
194+
In any case, you need to make the parent parent class ${typeChecker.getFullyQualifiedName(
195+
type.getSymbol()
196+
)} have constructors with typed settings object to overcome this issue.
197+
`
151198
);
152199
}
153200

@@ -163,6 +210,7 @@ function getManagedObjects(
163210
settingsTypeFullName,
164211
interestingBaseClass,
165212
constructorSignaturesAvailable,
213+
metadata,
166214
});
167215
return;
168216
});
@@ -374,14 +422,13 @@ function generateInterface(
374422
{
375423
sourceFile,
376424
className,
377-
classDeclaration,
378425
settingsTypeFullName,
379426
interestingBaseClass,
380427
constructorSignaturesAvailable,
428+
metadata,
381429
}: {
382430
sourceFile: ts.SourceFile;
383431
className: string;
384-
classDeclaration: ts.ClassDeclaration;
385432
settingsTypeFullName: string;
386433
interestingBaseClass:
387434
| "ManagedObject"
@@ -390,45 +437,11 @@ function generateInterface(
390437
| "Control"
391438
| undefined;
392439
constructorSignaturesAvailable: boolean;
440+
metadata: ts.PropertyDeclaration[];
393441
},
394442
allKnownGlobals: GlobalToModuleMapping
395443
) {
396444
const fileName = sourceFile.fileName;
397-
const metadata: ts.PropertyDeclaration[] = <ts.PropertyDeclaration[]>(
398-
classDeclaration.members.filter((member) => {
399-
if (
400-
ts.isPropertyDeclaration(member) &&
401-
ts.isIdentifier(member.name) &&
402-
member.name.escapedText === "metadata" &&
403-
member.modifiers &&
404-
member.modifiers.some((modifier) => {
405-
return modifier.kind === ts.SyntaxKind.StaticKeyword;
406-
})
407-
) {
408-
return true;
409-
}
410-
})
411-
);
412-
if (!metadata || metadata.length === 0) {
413-
// no metadata? => nothing to do
414-
log.debug(
415-
`ManagedObject with no metadata in class ${className} inside ${fileName}. This is not necessarily an issue, but if there is a metadata member in this class which *should* be recognized, make sure it has the 'static' keyword!`
416-
);
417-
return;
418-
} else if (metadata.length > 1) {
419-
// no metadata? => nothing to do
420-
log.warn(
421-
`ManagedObject with ${metadata.length} static metadata members in class ${className} inside ${fileName}. This is unexpected. Ignoring this class.`
422-
);
423-
return;
424-
}
425-
426-
if (!metadata[0].initializer) {
427-
log.warn(
428-
`Class ${className} inside ${fileName} has a static metadata member without initializer. Please assign the metadata object immediately to have an interface generated for the API. Write: 'static readonly metadata = { ... }'`
429-
);
430-
return;
431-
}
432445

433446
// by now we have something that looks pretty much like a ManagedObject metadata object
434447

packages/ts-interface-generator/src/types.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ interface ManagedObjectInfo {
1414
| "Control"
1515
| undefined;
1616
constructorSignaturesAvailable: boolean;
17+
metadata: ts.PropertyDeclaration[];
1718
}
1819

1920
interface RequiredImports {

0 commit comments

Comments
 (0)