From 842327df933ce9e733f3e5e00291e2b6e2ee0165 Mon Sep 17 00:00:00 2001 From: kyungseopk1m Date: Thu, 16 Apr 2026 00:35:27 +0900 Subject: [PATCH 1/2] chore: enable TypeScript strict mode Replace individual strict compiler options with "strict": true in tsconfig.json. This also enables strictPropertyInitialization, which required adding definite assignment assertions (!:) to properties initialized via Object.defineProperty helpers or Promise executors. Additionally fixes useUnknownInCatchVariables errors introduced by the new flag. --- src/app-check/app-check.ts | 2 +- src/app/credential-internal.ts | 22 +++++------ src/app/firebase-app.ts | 4 +- src/auth/auth-api-request.ts | 8 ++-- src/auth/auth-config.ts | 2 +- src/auth/base-auth.ts | 2 +- src/auth/tenant-manager.ts | 2 +- src/auth/user-import-builder.ts | 4 +- src/auth/user-record.ts | 36 +++++++++--------- src/database/database.ts | 4 +- .../installations-request-handler.ts | 2 +- src/messaging/messaging.ts | 2 +- src/project-management/project-management.ts | 2 +- src/remote-config/remote-config.ts | 27 ++++++------- src/utils/api-request.ts | 38 +++++++++---------- src/utils/jwt.ts | 4 +- test/unit/remote-config/remote-config.spec.ts | 26 +++++++++++++ tsconfig.json | 9 +---- 18 files changed, 108 insertions(+), 88 deletions(-) diff --git a/src/app-check/app-check.ts b/src/app-check/app-check.ts index c7e6cadbd1..ae9318307c 100644 --- a/src/app-check/app-check.ts +++ b/src/app-check/app-check.ts @@ -51,7 +51,7 @@ export class AppCheck { try { this.tokenGenerator = new AppCheckTokenGenerator(cryptoSignerFromApp(app)); } catch (err) { - throw appCheckErrorFromCryptoSignerError(err); + throw appCheckErrorFromCryptoSignerError(err as Error); } this.appCheckTokenVerifier = new AppCheckTokenVerifier(app); } diff --git a/src/app/credential-internal.ts b/src/app/credential-internal.ts index 8ce61b4edd..38f21ecf06 100644 --- a/src/app/credential-internal.ts +++ b/src/app/credential-internal.ts @@ -37,7 +37,7 @@ const SCOPES = [ export class ApplicationDefaultCredential implements Credential { private readonly googleAuth: GoogleAuth; - private authClient: AnyAuthClient; + private authClient?: AnyAuthClient; private projectId?: string; private quotaProjectId?: string; private accountId?: string; @@ -121,7 +121,7 @@ export class ServiceAccountCredential implements Credential { public readonly privateKey: string; public readonly clientEmail: string; - private googleAuth: GoogleAuth; + private googleAuth!: GoogleAuth; private authClient: AnyAuthClient | undefined; /** @@ -173,9 +173,9 @@ export class ServiceAccountCredential implements Credential { */ class ServiceAccount { - public readonly projectId: string; - public readonly privateKey: string; - public readonly clientEmail: string; + public readonly projectId!: string; + public readonly privateKey!: string; + public readonly clientEmail!: string; public static fromPath(filePath: string): ServiceAccount { try { @@ -231,7 +231,7 @@ class ServiceAccount { */ export class RefreshTokenCredential implements Credential { - private googleAuth: GoogleAuth; + private googleAuth!: GoogleAuth; private authClient: AnyAuthClient | undefined; /** @@ -278,10 +278,10 @@ export class RefreshTokenCredential implements Credential { class RefreshToken { - public readonly clientId: string; - public readonly clientSecret: string; - public readonly refreshToken: string; - public readonly type: string; + public readonly clientId!: string; + public readonly clientSecret!: string; + public readonly refreshToken!: string; + public readonly type!: string; /* * Tries to load a RefreshToken from a path. Throws if the path doesn't exist or the @@ -330,7 +330,7 @@ class RefreshToken { */ export class ImpersonatedServiceAccountCredential implements Credential { - private googleAuth: GoogleAuth; + private googleAuth!: GoogleAuth; private authClient: AnyAuthClient | undefined; /** diff --git a/src/app/firebase-app.ts b/src/app/firebase-app.ts index dcd30d8a1d..adfbf734bd 100644 --- a/src/app/firebase-app.ts +++ b/src/app/firebase-app.ts @@ -38,8 +38,8 @@ export interface FirebaseAccessToken { * Internals of a FirebaseApp instance. */ export class FirebaseAppInternals { - private cachedToken_: FirebaseAccessToken; - private promiseToCachedToken_: Promise; + private cachedToken_!: FirebaseAccessToken; + private promiseToCachedToken_!: Promise; private tokenListeners_: Array<(token: string) => void>; private isRefreshing: boolean; diff --git a/src/auth/auth-api-request.ts b/src/auth/auth-api-request.ts index 8e979d1aed..6819c61c52 100644 --- a/src/auth/auth-api-request.ts +++ b/src/auth/auth-api-request.ts @@ -121,7 +121,7 @@ enum WriteOperationType { class AuthResourceUrlBuilder { protected urlFormat: string; - private projectId: string; + private projectId!: string; /** * The resource URL builder constructor. @@ -494,7 +494,7 @@ function validateCreateEditRequest(request: any, writeOperationType: WriteOperat // JSON parsing error. This should never happen as we stringify the claims internally. // However, we still need to check since setAccountInfo via edit requests could pass // this field. - throw new FirebaseAuthError(AuthClientErrorCode.INVALID_CLAIMS, error.message); + throw new FirebaseAuthError(AuthClientErrorCode.INVALID_CLAIMS, (error as Error).message); } const invalidClaims: string[] = []; // Check for any invalid claims. @@ -1013,8 +1013,8 @@ const LIST_INBOUND_SAML_CONFIGS = new ApiSettings('/inboundSamlConfigs', 'GET') export abstract class AbstractAuthRequestHandler { protected readonly httpClient: AuthorizedHttpClient; - private authUrlBuilder: AuthResourceUrlBuilder; - private projectConfigUrlBuilder: AuthResourceUrlBuilder; + private authUrlBuilder!: AuthResourceUrlBuilder; + private projectConfigUrlBuilder!: AuthResourceUrlBuilder; /** * @param response - The response to check for errors. diff --git a/src/auth/auth-config.ts b/src/auth/auth-config.ts index 1dd5565a88..ba24c76d1f 100644 --- a/src/auth/auth-config.ts +++ b/src/auth/auth-config.ts @@ -1337,7 +1337,7 @@ export class OIDCConfig implements OIDCAuthProviderConfig { public readonly issuer: string; public readonly clientId: string; public readonly clientSecret?: string; - public readonly responseType: OAuthResponseType; + public readonly responseType?: OAuthResponseType; /** * Converts a client side request to a OIDCConfigServerRequest which is the format diff --git a/src/auth/base-auth.ts b/src/auth/base-auth.ts index 25e1a3db2b..59f648422d 100644 --- a/src/auth/base-auth.ts +++ b/src/auth/base-auth.ts @@ -121,7 +121,7 @@ export function createFirebaseTokenGenerator(app: App, const signer = useEmulator() ? new EmulatedSigner() : cryptoSignerFromApp(app); return new FirebaseTokenGenerator(signer, tenantId); } catch (err) { - throw handleCryptoSignerError(err); + throw handleCryptoSignerError(err as Error); } } diff --git a/src/auth/tenant-manager.ts b/src/auth/tenant-manager.ts index 19da5b4c83..8653349675 100644 --- a/src/auth/tenant-manager.ts +++ b/src/auth/tenant-manager.ts @@ -69,7 +69,7 @@ export class TenantAwareAuth extends BaseAuth { * All calls to the user management APIs, OIDC/SAML provider management APIs, email link * generation APIs, etc will only be applied within the scope of this tenant. */ - public readonly tenantId: string; + public readonly tenantId!: string; /** * The TenantAwareAuth class constructor. diff --git a/src/auth/user-import-builder.ts b/src/auth/user-import-builder.ts index f396066b49..c9e2baa5c2 100644 --- a/src/auth/user-import-builder.ts +++ b/src/auth/user-import-builder.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { FirebaseArrayIndexError } from '../app/index'; +import { FirebaseArrayIndexError, FirebaseError } from '../app/index'; import { deepCopy, deepExtend } from '../utils/deep-copy'; import * as utils from '../utils'; import * as validator from '../utils/validator'; @@ -752,7 +752,7 @@ export class UserImportBuilder { // Save the client side error with respect to the developer provided array. this.userImportResultErrors.push({ index, - error, + error: error as FirebaseError, }); } }); diff --git a/src/auth/user-record.ts b/src/auth/user-record.ts index 2310968849..01da8e7ccd 100644 --- a/src/auth/user-record.ts +++ b/src/auth/user-record.ts @@ -100,7 +100,7 @@ export abstract class MultiFactorInfo { /** * The ID of the enrolled second factor. This ID is unique to the user. */ - public readonly uid: string; + public readonly uid!: string; /** * The optional display name of the enrolled second factor. @@ -112,7 +112,7 @@ export abstract class MultiFactorInfo { * For SMS second factors, this is `phone`. * For TOTP second factors, this is `totp`. */ - public readonly factorId: string; + public readonly factorId!: string; /** * The optional date the second factor was enrolled, formatted as a UTC string. @@ -215,7 +215,7 @@ export class PhoneMultiFactorInfo extends MultiFactorInfo { /** * The phone number associated with a phone second factor. */ - public readonly phoneNumber: string; + public readonly phoneNumber!: string; /** * Initializes the PhoneMultiFactorInfo object using the server side response. @@ -269,7 +269,7 @@ export class TotpMultiFactorInfo extends MultiFactorInfo { /** * `TotpInfo` struct associated with a second factor */ - public readonly totpInfo: TotpInfo; + public readonly totpInfo!: TotpInfo; /** * Initializes the `TotpMultiFactorInfo` object using the server side response. @@ -317,7 +317,7 @@ export class MultiFactorSettings { * List of second factors enrolled with the current user. * Currently only phone and TOTP second factors are supported. */ - public enrolledFactors: MultiFactorInfo[]; + public enrolledFactors!: MultiFactorInfo[]; /** * Initializes the `MultiFactor` object using the server side or JWT format response. @@ -365,12 +365,12 @@ export class UserMetadata { /** * The date the user was created, formatted as a UTC string. */ - public readonly creationTime: string; + public readonly creationTime!: string; /** * The date the user last signed in, formatted as a UTC string. */ - public readonly lastSignInTime: string; + public readonly lastSignInTime!: string; /** * The time at which the user was last active (ID token refreshed), @@ -419,32 +419,32 @@ export class UserInfo { /** * The user identifier for the linked provider. */ - public readonly uid: string; + public readonly uid!: string; /** * The display name for the linked provider. */ - public readonly displayName: string; + public readonly displayName!: string; /** * The email for the linked provider. */ - public readonly email: string; + public readonly email!: string; /** * The photo URL for the linked provider. */ - public readonly photoURL: string; + public readonly photoURL!: string; /** * The linked provider ID (for example, "google.com" for the Google provider). */ - public readonly providerId: string; + public readonly providerId!: string; /** * The phone number for the linked provider. */ - public readonly phoneNumber: string; + public readonly phoneNumber!: string; /** @@ -494,7 +494,7 @@ export class UserRecord { /** * The user's `uid`. */ - public readonly uid: string; + public readonly uid!: string; /** * The user's primary email, if set. @@ -504,7 +504,7 @@ export class UserRecord { /** * Whether or not the user's primary email is verified. */ - public readonly emailVerified: boolean; + public readonly emailVerified!: boolean; /** * The user's display name. @@ -525,17 +525,17 @@ export class UserRecord { * Whether or not the user is disabled: `true` for disabled; `false` for * enabled. */ - public readonly disabled: boolean; + public readonly disabled!: boolean; /** * Additional metadata about the user. */ - public readonly metadata: UserMetadata; + public readonly metadata!: UserMetadata; /** * An array of providers (for example, Google, Facebook) linked to the user. */ - public readonly providerData: UserInfo[]; + public readonly providerData!: UserInfo[]; /** * The user's hashed password (base64-encoded), only if Firebase Auth hashing diff --git a/src/database/database.ts b/src/database/database.ts index 355c43b33a..653e2f4560 100644 --- a/src/database/database.ts +++ b/src/database/database.ts @@ -64,8 +64,8 @@ const TOKEN_REFRESH_THRESHOLD_MILLIS = 5 * 60 * 1000; export class DatabaseService { private readonly appInternal: App; - private tokenListener: (token: string) => void; - private tokenRefreshTimeout: NodeJS.Timeout; + private tokenListener!: (token: string) => void; + private tokenRefreshTimeout!: NodeJS.Timeout; private databases: { [dbUrl: string]: Database; diff --git a/src/installations/installations-request-handler.ts b/src/installations/installations-request-handler.ts index 67c0f6f46f..f9bde317e6 100644 --- a/src/installations/installations-request-handler.ts +++ b/src/installations/installations-request-handler.ts @@ -52,7 +52,7 @@ export class FirebaseInstallationsRequestHandler { private readonly host: string = FIREBASE_IID_HOST; private readonly timeout: number = FIREBASE_IID_TIMEOUT; private readonly httpClient: AuthorizedHttpClient; - private path: string; + private path!: string; /** * @param app - The app used to fetch access tokens to sign API requests. diff --git a/src/messaging/messaging.ts b/src/messaging/messaging.ts index 05367128f4..d89e6d7529 100644 --- a/src/messaging/messaging.ts +++ b/src/messaging/messaging.ts @@ -87,7 +87,7 @@ function mapRawResponseToTopicManagementResponse(response: object): MessagingTop */ export class Messaging { - private urlPath: string; + private urlPath!: string; private readonly appInternal: App; private readonly messagingRequestHandler: FirebaseMessagingRequestHandler; private useLegacyTransport = false; diff --git a/src/project-management/project-management.ts b/src/project-management/project-management.ts index c29589be86..47bceba9c2 100644 --- a/src/project-management/project-management.ts +++ b/src/project-management/project-management.ts @@ -29,7 +29,7 @@ import { AppMetadata, AppPlatform } from './app-metadata'; export class ProjectManagement { private readonly requestHandler: ProjectManagementRequestHandler; - private projectId: string; + private projectId!: string; /** * @param app - The app for this ProjectManagement service. diff --git a/src/remote-config/remote-config.ts b/src/remote-config/remote-config.ts index 6ae44c4064..461b4bc1ee 100644 --- a/src/remote-config/remote-config.ts +++ b/src/remote-config/remote-config.ts @@ -299,7 +299,7 @@ class RemoteConfigTemplateImpl implements RemoteConfigTemplate { * Remote Config dataplane template data implementation. */ class ServerTemplateImpl implements ServerTemplate { - private cache: ServerTemplateData; + private cache?: ServerTemplateData; private stringifiedDefaultConfig: { [key: string]: string } = {}; constructor( @@ -350,18 +350,10 @@ class ServerTemplateImpl implements ServerTemplate { * Evaluates the current template in cache to produce a {@link ServerConfig}. */ public evaluate(context: EvaluationContext = {}): ServerConfig { - if (!this.cache) { - - // This is the only place we should throw during evaluation, since it's under the - // control of application logic. To preserve forward-compatibility, we should only - // return false in cases where the SDK is unsure how to evaluate the fetched template. - throw new FirebaseRemoteConfigError( - 'failed-precondition', - 'No Remote Config Server template in cache. Call load() before calling evaluate().'); - } + const cachedTemplate = this.getCachedTemplate('evaluate()'); const evaluatedConditions = this.conditionEvaluator.evaluateConditions( - this.cache.conditions, context); + cachedTemplate.conditions, context); const configValues: { [key: string]: Value } = {}; @@ -371,7 +363,7 @@ class ServerTemplateImpl implements ServerTemplate { } // Overlays config Value objects derived by evaluating the template. - for (const [key, parameter] of Object.entries(this.cache.parameters)) { + for (const [key, parameter] of Object.entries(cachedTemplate.parameters)) { const { conditionalValues, defaultValue } = parameter; // Supports parameters with no conditional values. @@ -423,6 +415,15 @@ class ServerTemplateImpl implements ServerTemplate { * @returns JSON representation of the server template */ public toJSON(): ServerTemplateData { + return this.getCachedTemplate('toJSON()'); + } + + private getCachedTemplate(methodName: string): ServerTemplateData { + if (!this.cache) { + throw new FirebaseRemoteConfigError( + 'failed-precondition', + `No Remote Config Server template in cache. Call load() or set() before calling ${methodName}.`); + } return this.cache; } } @@ -453,7 +454,7 @@ class ServerConfigImpl implements ServerConfig { */ class ServerTemplateDataImpl implements ServerTemplateData { public parameters: { [key: string]: RemoteConfigParameter }; - public parameterGroups: { [key: string]: RemoteConfigParameterGroup }; + public parameterGroups!: { [key: string]: RemoteConfigParameterGroup }; public conditions: NamedCondition[]; public readonly etag: string; public version?: Version; diff --git a/src/utils/api-request.ts b/src/utils/api-request.ts index 9616b7a39f..59990abfec 100644 --- a/src/utils/api-request.ts +++ b/src/utils/api-request.ts @@ -129,7 +129,7 @@ class DefaultRequestResponse implements RequestResponse { public readonly text?: string; private readonly parsedData: any; - private readonly parseError: Error; + private readonly parseError!: Error; private readonly request: string; /** @@ -146,7 +146,7 @@ class DefaultRequestResponse implements RequestResponse { this.parsedData = JSON.parse(resp.data); } catch (err) { this.parsedData = undefined; - this.parseError = err; + this.parseError = err as Error; } this.request = `${resp.config.method} ${resp.config.url}`; } @@ -284,7 +284,7 @@ function validateRetryConfig(retry: RetryConfig): void { } export class RequestClient { - protected readonly retry: RetryConfig; + protected readonly retry!: RetryConfig; constructor(retry: RetryConfig | null = defaultRetryConfig()) { if (retry) { @@ -564,11 +564,11 @@ export function parseHttpResponse( * It also wraps the callback API of the Node.js standard library in a more flexible Promise API. */ class AsyncRequestCall { - protected resolve: (_: any) => void; - protected reject: (_: any) => void; - protected options: https.RequestOptions; + protected resolve!: (_: any) => void; + protected reject!: (_: any) => void; + protected options!: https.RequestOptions; protected entity: Buffer | undefined; - protected promise: Promise; + protected promise!: Promise; constructor(private readonly configImpl: HttpRequestConfigImpl | Http2RequestConfigImpl) {} @@ -715,7 +715,7 @@ class AsyncRequestCall { * It also wraps the callback API of the Node.js standard library in a more flexible Promise API. */ class AsyncHttpCall extends AsyncRequestCall { - private readonly httpConfigImpl: HttpRequestConfigImpl; + private readonly httpConfigImpl!: HttpRequestConfigImpl; /** * Sends an HTTP request based on the provided configuration. @@ -816,7 +816,7 @@ class AsyncHttpCall extends AsyncRequestCall { } class AsyncHttp2Call extends AsyncRequestCall { - private readonly http2ConfigImpl: Http2RequestConfigImpl + private readonly http2ConfigImpl!: Http2RequestConfigImpl /** * Sends an HTTP2 request based on the provided configuration. @@ -1156,8 +1156,8 @@ export class AuthorizedHttp2Client extends Http2Client { * @constructor */ export class ApiSettings { - private requestValidator: ApiCallbackFunction; - private responseValidator: ApiCallbackFunction; + private requestValidator!: ApiCallbackFunction; + private responseValidator!: ApiCallbackFunction; constructor(private endpoint: string, private httpMethod: HttpMethod = 'POST') { this.setRequestValidator(null) @@ -1233,12 +1233,12 @@ export class ExponentialBackoffPoller extends EventEmitter { private numTries = 0; private completed = false; - private masterTimer: NodeJS.Timeout; - private repollTimer: NodeJS.Timeout; + private masterTimer!: NodeJS.Timeout; + private repollTimer!: NodeJS.Timeout; private pollCallback?: () => Promise; - private resolve: (result: T) => void; - private reject: (err: object) => void; + private resolve!: (result: T) => void; + private reject!: (err: object) => void; constructor( private readonly initialPollingDelayMillis: number = 1000, @@ -1325,10 +1325,10 @@ export class ExponentialBackoffPoller extends EventEmitter { export class Http2SessionHandler { - private http2Session: http2.ClientHttp2Session - protected promise: Promise - protected resolve: () => void; - protected reject: (_: any) => void; + private http2Session!: http2.ClientHttp2Session + protected promise!: Promise + protected resolve!: () => void; + protected reject!: (_: any) => void; constructor(url: string){ this.promise = new Promise((resolve, reject) => { diff --git a/src/utils/jwt.ts b/src/utils/jwt.ts index 41433c4f06..1ab713af38 100644 --- a/src/utils/jwt.ts +++ b/src/utils/jwt.ts @@ -50,7 +50,7 @@ interface KeyFetcher { } export class JwksFetcher implements KeyFetcher { - private publicKeys: { [key: string]: string }; + private publicKeys!: { [key: string]: string }; private publicKeysExpireAt = 0; private client: jwks.JwksClient; @@ -99,7 +99,7 @@ export class JwksFetcher implements KeyFetcher { * Class to fetch public keys from a client certificates URL. */ export class UrlKeyFetcher implements KeyFetcher { - private publicKeys: { [key: string]: string }; + private publicKeys!: { [key: string]: string }; private publicKeysExpireAt = 0; constructor(private clientCertUrl: string, private readonly httpAgent?: Agent) { diff --git a/test/unit/remote-config/remote-config.spec.ts b/test/unit/remote-config/remote-config.spec.ts index 74d277290e..870aad99ac 100644 --- a/test/unit/remote-config/remote-config.spec.ts +++ b/test/unit/remote-config/remote-config.spec.ts @@ -1154,7 +1154,33 @@ describe('RemoteConfig', () => { }); }); + describe('toJSON', () => { + it('should throw if template is not present in cache', () => { + const initializedTemplate = remoteConfig.initServerTemplate(); + const expected = new FirebaseRemoteConfigError( + 'failed-precondition', + 'No Remote Config Server template in cache. Call load() or set() before calling toJSON().', + ); + + expect(() => initializedTemplate.toJSON()).to.throw(FirebaseRemoteConfigError) + .with.property('code', expected.code); + expect(() => initializedTemplate.toJSON()).to.throw(expected.message); + }); + }); + describe('evaluate', () => { + it('should throw if template is not present in cache', () => { + const initializedTemplate = remoteConfig.initServerTemplate(); + const expected = new FirebaseRemoteConfigError( + 'failed-precondition', + 'No Remote Config Server template in cache. Call load() or set() before calling evaluate().', + ); + + expect(() => initializedTemplate.evaluate()).to.throw(FirebaseRemoteConfigError) + .with.property('code', expected.code); + expect(() => initializedTemplate.evaluate()).to.throw(expected.message); + }); + it('returns a config when template is present in cache', () => { const stub = sinon .stub(RemoteConfigApiClient.prototype, 'getServerTemplate') diff --git a/tsconfig.json b/tsconfig.json index 1b21a0e365..ef68e4343f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,15 +4,8 @@ "target": "es2020", "declaration": true, "sourceMap": true, - "noImplicitAny": true, + "strict": true, "noUnusedLocals": true, - // TODO(rsgowman): enable `"strict": true,` and remove explicit setting of: noImplicitAny, noImplicitThis, alwaysStrict, strictBindCallApply, strictNullChecks, strictFunctionTypes, strictPropertyInitialization. - "noImplicitThis": true, - "alwaysStrict": true, - "strictBindCallApply": true, - "strictNullChecks": true, - "strictFunctionTypes": true, - //"strictPropertyInitialization": true, "lib": ["es2020"], "outDir": "lib", "stripInternal": true, From a4951856df33a108c42a76638fe729900d612889 Mon Sep 17 00:00:00 2001 From: kyungseopk1m Date: Thu, 16 Apr 2026 00:45:17 +0900 Subject: [PATCH 2/2] chore: use dynamic method names in getCachedTemplate error messages --- src/remote-config/remote-config.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/remote-config/remote-config.ts b/src/remote-config/remote-config.ts index 461b4bc1ee..845f2119d0 100644 --- a/src/remote-config/remote-config.ts +++ b/src/remote-config/remote-config.ts @@ -350,7 +350,7 @@ class ServerTemplateImpl implements ServerTemplate { * Evaluates the current template in cache to produce a {@link ServerConfig}. */ public evaluate(context: EvaluationContext = {}): ServerConfig { - const cachedTemplate = this.getCachedTemplate('evaluate()'); + const cachedTemplate = this.getCachedTemplate(`${this.evaluate.name}()`); const evaluatedConditions = this.conditionEvaluator.evaluateConditions( cachedTemplate.conditions, context); @@ -415,7 +415,7 @@ class ServerTemplateImpl implements ServerTemplate { * @returns JSON representation of the server template */ public toJSON(): ServerTemplateData { - return this.getCachedTemplate('toJSON()'); + return this.getCachedTemplate(`${this.toJSON.name}()`); } private getCachedTemplate(methodName: string): ServerTemplateData {