in src/assembler.ts [1967:2084]
private _visitProperty(
symbol: ts.Symbol,
type: spec.ClassType | spec.InterfaceType,
ctx: EmitContext,
declaringTypeDecl: ts.ClassLikeDeclaration | ts.InterfaceDeclaration | undefined,
) {
if (type.properties?.find((p) => p.name === symbol.name)) {
/*
* Second declaration of the same property. For example, if code specifies a getter & setter signature,
* there will be one pass for each of the signatures, but we can process only the first encountered. The
* typescript compiler will take care of making sure we don't have conflicting declarations, anyway.
*/
return;
}
if (LOG.isTraceEnabled()) {
LOG.trace(`Processing property: ${chalk.green(type.fqn)}#${chalk.cyan(symbol.name)}`);
}
const declaration = symbol.valueDeclaration ?? symbol.declarations?.[0];
const signature = declaration as
| ts.PropertySignature
| ts.PropertyDeclaration
| ts.AccessorDeclaration
| ts.ParameterPropertyDeclaration;
if (type.name === Case.pascal(symbol.name)) {
this._diagnostics.push(
JsiiDiagnostic.JSII_5019_MEMBER_TYPE_NAME_CONFLICT.create(
signature.name,
'property',
symbol,
type,
).addRelatedInformationIf(
declaringTypeDecl?.name ?? declaringTypeDecl,
`The declaring ${type.kind} is introduced here`,
),
);
}
if (isProhibitedMemberName(symbol.name)) {
this._diagnostics.push(
JsiiDiagnostic.JSII_5016_PROHIBITED_MEMBER_NAME.create(
symbol.valueDeclaration ?? symbol.declarations?.[0],
symbol.name,
),
);
return;
}
this._warnAboutReservedWords(symbol);
const property: spec.Property = bindings.setPropertyRelatedNode(
{
...this._optionalValue(
this._typeChecker.getTypeOfSymbolAtLocation(symbol, signature),
signature.type ?? signature.name,
'property type',
),
abstract: _isAbstract(symbol, type) || undefined,
name: symbol.name,
protected: _isProtected(symbol) || undefined,
static: _isStatic(symbol) || undefined,
locationInModule: this.declarationLocation(signature),
},
signature,
);
if (ts.isGetAccessor(signature)) {
property.immutable = true;
for (const decl of symbol.getDeclarations() ?? []) {
if (!ts.isSetAccessor(decl)) {
continue;
}
delete property.immutable;
// Verify the setter doesn't have a Separate Write Type (SWT)
const valueParam = decl.parameters[0];
if (valueParam?.type == null) {
// If there is no type node, there can't be a SWT
continue;
}
const paramType = this._typeChecker.getTypeFromTypeNode(valueParam.type);
const paramOptionalValue = this._optionalValue(paramType, valueParam.type, 'parameter type');
if (
property.optional !== paramOptionalValue.optional ||
describeTypeReference(property.type) !== describeTypeReference(paramOptionalValue.type)
) {
this._diagnostics.push(
JsiiDiagnostic.JSII_1005_SEPARATE_WRITE_TYPE.create(valueParam.type).addRelatedInformation(
signature.type ?? signature.name,
'The getter signature is declared here',
),
);
}
}
} else {
property.immutable = (ts.getCombinedModifierFlags(signature) & ts.ModifierFlags.Readonly) !== 0 || undefined;
}
if (signature.questionToken) {
property.optional = true;
}
if (property.static && property.immutable && ts.isPropertyDeclaration(signature) && signature.initializer) {
property.const = true;
}
property.docs = this._visitDocumentation(symbol, ctx).docs;
type.properties = type.properties ?? [];
if (type.properties.find((prop) => prop.name === property.name && prop.static === property.static) != null) {
LOG.trace(`Dropping re-declaration of ${chalk.green(type.fqn)}#${chalk.cyan(property.name)}`);
return;
}
type.properties.push(property);
}