Skip to content

Commit a4e314c

Browse files
bradenmacdonaldarbrandes
authored andcommitted
feat: improve type accuracy for getConfig() and others
1 parent 4c556c2 commit a4e314c

File tree

6 files changed

+144
-112
lines changed

6 files changed

+144
-112
lines changed

package-lock.json

Lines changed: 25 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
"@testing-library/jest-dom": "6.6.3",
4343
"@testing-library/react": "16.2.0",
4444
"@testing-library/user-event": "14.6.1",
45+
"@types/node": "^25.6.0",
4546
"axios-mock-adapter": "^1.22.0",
4647
"jest-environment-jsdom": "29.7.0",
4748
"jest-localstorage-mock": "^2.4.26",

src/auth/interface.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ export async function hydrateAuthenticatedUser() {
302302
* @name UserData
303303
* @interface
304304
* @memberof module:Auth
305-
* @property {string} userId
305+
* @property {number} userId
306306
* @property {string} username
307307
* @property {Array} roles
308308
* @property {boolean} administrator

src/config.js renamed to src/config.ts

Lines changed: 99 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ import { APP_CONFIG_INITIALIZED, CONFIG_CHANGED } from './constants';
128128
import { publish, subscribe } from './pubSub';
129129
import { ensureDefinedConfig } from './utils';
130130

131-
function extractRegex(envVar) {
131+
function extractRegex(envVar: unknown) {
132132
// Convert the environment variable string to a regex, while guarding
133133
// against a non-string and an empty/whitespace-only string.
134134
if (typeof envVar === 'string' && envVar.trim() !== '') {
@@ -141,9 +141,10 @@ function extractRegex(envVar) {
141141
* Safely parses a JSON string coming from the environment variables.
142142
* If the JSON is invalid, the function returns an empty object and logs an error to the console.
143143
*
144-
* @param {string} paragonUrlsJson - The JSON string representing Paragon theme URLs.
145-
* @returns {Object|undefined} - Returns a parsed object if the JSON is valid; otherwise, returns
146-
* an empty object if invalid or undefined if no input is provided.
144+
* @param paragonUrlsJson - The JSON string representing Paragon theme URLs.
145+
* @returns Returns a parsed object if the JSON is valid; otherwise, returns
146+
* an empty object if invalid or undefined if no input is provided. In case of a
147+
* different type of error, return the error object itself.
147148
*
148149
* @example
149150
* const jsonString = '{
@@ -154,7 +155,7 @@ function extractRegex(envVar) {
154155
* const parsedUrls = parseParagonThemeUrls(jsonString);
155156
* console.log(parsedUrls); // Outputs the parsed JSON object
156157
*/
157-
function parseParagonThemeUrls(paragonUrlsJson) {
158+
function parseParagonThemeUrls(paragonUrlsJson: string): Record<string, any> | undefined | Error {
158159
if (!paragonUrlsJson) {
159160
return undefined;
160161
}
@@ -167,45 +168,105 @@ function parseParagonThemeUrls(paragonUrlsJson) {
167168
return {};
168169
}
169170
// In case of a different type of error, return the error object itself
170-
return err;
171+
return err as Error;
171172
}
172173
}
173174

174-
const ENVIRONMENT = process.env.NODE_ENV;
175-
let config = {
176-
ACCESS_TOKEN_COOKIE_NAME: process.env.ACCESS_TOKEN_COOKIE_NAME,
177-
ACCOUNT_PROFILE_URL: process.env.ACCOUNT_PROFILE_URL,
178-
ACCOUNT_SETTINGS_URL: process.env.ACCOUNT_SETTINGS_URL,
179-
BASE_URL: process.env.BASE_URL,
175+
/**
176+
* An object describing the current application configuration.
177+
*
178+
* In its most basic form, the initialization process loads this document via `process.env`
179+
* variables. There are other ways to add configuration variables to the ConfigDocument as
180+
* documented above (JavaScript File Configuration, Runtime Configuration, and the Initialization
181+
* Config Handler).
182+
*
183+
* ```
184+
* {
185+
* BASE_URL: process.env.BASE_URL,
186+
* // ... other vars
187+
* }
188+
* ```
189+
*
190+
* When using Webpack (i.e., normal usage), the build process is responsible for supplying these
191+
* variables via command-line environment variables. That means they must be supplied at build
192+
* time.
193+
*
194+
* @memberof module:Config
195+
*/
196+
export interface ConfigDocument {
197+
ACCESS_TOKEN_COOKIE_NAME: string;
198+
ACCOUNT_PROFILE_URL: string;
199+
ACCOUNT_SETTINGS_URL: string;
200+
/** The URL of the current application. */
201+
BASE_URL: string;
202+
PUBLIC_PATH: string;
203+
CREDENTIALS_BASE_URL?: string;
204+
CSRF_TOKEN_API_PATH: string;
205+
DISCOVERY_API_BASE_URL?: string;
206+
PUBLISHER_BASE_URL?: string;
207+
ECOMMERCE_BASE_URL?: string;
208+
ENVIRONMENT: 'development' | 'production' | 'test';
209+
IGNORED_ERROR_REGEX?: RegExp;
210+
LANGUAGE_PREFERENCE_COOKIE_NAME: string;
211+
LEARNING_BASE_URL: string;
212+
LMS_BASE_URL: string;
213+
LOGIN_URL: string;
214+
LOGOUT_URL: string;
215+
STUDIO_BASE_URL: string;
216+
MARKETING_SITE_BASE_URL: string;
217+
ORDER_HISTORY_URL?: string;
218+
REFRESH_ACCESS_TOKEN_ENDPOINT: string;
219+
SECURE_COOKIES: boolean; // <-- the only non-string value
220+
SEGMENT_KEY?: string;
221+
SITE_NAME: string;
222+
USER_INFO_COOKIE_NAME: string;
223+
LOGO_URL: string;
224+
LOGO_TRADEMARK_URL: string;
225+
LOGO_WHITE_URL: string;
226+
FAVICON_URL: string;
227+
MFE_CONFIG_API_URL: string;
228+
APP_ID: string;
229+
SUPPORT_URL: string;
230+
PARAGON_THEME_URLS: Record<string, any> | Error | undefined;
231+
externalLinkUrlOverrides?: null | Record<string, string>;
232+
[otherKey: string]: any;
233+
}
234+
235+
const ENVIRONMENT = process.env.NODE_ENV as 'development' | 'production' | 'test';
236+
let config: ConfigDocument = {
237+
ACCESS_TOKEN_COOKIE_NAME: process.env.ACCESS_TOKEN_COOKIE_NAME!,
238+
ACCOUNT_PROFILE_URL: process.env.ACCOUNT_PROFILE_URL!,
239+
ACCOUNT_SETTINGS_URL: process.env.ACCOUNT_SETTINGS_URL!,
240+
BASE_URL: process.env.BASE_URL!,
180241
PUBLIC_PATH: process.env.PUBLIC_PATH || '/',
181242
CREDENTIALS_BASE_URL: process.env.CREDENTIALS_BASE_URL,
182-
CSRF_TOKEN_API_PATH: process.env.CSRF_TOKEN_API_PATH,
243+
CSRF_TOKEN_API_PATH: process.env.CSRF_TOKEN_API_PATH!,
183244
DISCOVERY_API_BASE_URL: process.env.DISCOVERY_API_BASE_URL,
184245
PUBLISHER_BASE_URL: process.env.PUBLISHER_BASE_URL,
185246
ECOMMERCE_BASE_URL: process.env.ECOMMERCE_BASE_URL,
186247
ENVIRONMENT,
187248
IGNORED_ERROR_REGEX: extractRegex(process.env.IGNORED_ERROR_REGEX),
188-
LANGUAGE_PREFERENCE_COOKIE_NAME: process.env.LANGUAGE_PREFERENCE_COOKIE_NAME,
189-
LEARNING_BASE_URL: process.env.LEARNING_BASE_URL,
190-
LMS_BASE_URL: process.env.LMS_BASE_URL,
191-
LOGIN_URL: process.env.LOGIN_URL,
192-
LOGOUT_URL: process.env.LOGOUT_URL,
193-
STUDIO_BASE_URL: process.env.STUDIO_BASE_URL,
194-
MARKETING_SITE_BASE_URL: process.env.MARKETING_SITE_BASE_URL,
249+
LANGUAGE_PREFERENCE_COOKIE_NAME: process.env.LANGUAGE_PREFERENCE_COOKIE_NAME!,
250+
LEARNING_BASE_URL: process.env.LEARNING_BASE_URL!,
251+
LMS_BASE_URL: process.env.LMS_BASE_URL!,
252+
LOGIN_URL: process.env.LOGIN_URL!,
253+
LOGOUT_URL: process.env.LOGOUT_URL!,
254+
STUDIO_BASE_URL: process.env.STUDIO_BASE_URL!,
255+
MARKETING_SITE_BASE_URL: process.env.MARKETING_SITE_BASE_URL!,
195256
ORDER_HISTORY_URL: process.env.ORDER_HISTORY_URL,
196-
REFRESH_ACCESS_TOKEN_ENDPOINT: process.env.REFRESH_ACCESS_TOKEN_ENDPOINT,
257+
REFRESH_ACCESS_TOKEN_ENDPOINT: process.env.REFRESH_ACCESS_TOKEN_ENDPOINT!,
197258
SECURE_COOKIES: ENVIRONMENT !== 'development',
198259
SEGMENT_KEY: process.env.SEGMENT_KEY,
199-
SITE_NAME: process.env.SITE_NAME,
200-
USER_INFO_COOKIE_NAME: process.env.USER_INFO_COOKIE_NAME,
201-
LOGO_URL: process.env.LOGO_URL,
202-
LOGO_TRADEMARK_URL: process.env.LOGO_TRADEMARK_URL,
203-
LOGO_WHITE_URL: process.env.LOGO_WHITE_URL,
204-
FAVICON_URL: process.env.FAVICON_URL,
205-
MFE_CONFIG_API_URL: process.env.MFE_CONFIG_API_URL,
206-
APP_ID: process.env.APP_ID,
207-
SUPPORT_URL: process.env.SUPPORT_URL,
208-
PARAGON_THEME_URLS: parseParagonThemeUrls(process.env.PARAGON_THEME_URLS),
260+
SITE_NAME: process.env.SITE_NAME!,
261+
USER_INFO_COOKIE_NAME: process.env.USER_INFO_COOKIE_NAME!,
262+
LOGO_URL: process.env.LOGO_URL!,
263+
LOGO_TRADEMARK_URL: process.env.LOGO_TRADEMARK_URL!,
264+
LOGO_WHITE_URL: process.env.LOGO_WHITE_URL!,
265+
FAVICON_URL: process.env.FAVICON_URL!,
266+
MFE_CONFIG_API_URL: process.env.MFE_CONFIG_API_URL!,
267+
APP_ID: process.env.APP_ID!,
268+
SUPPORT_URL: process.env.SUPPORT_URL!,
269+
PARAGON_THEME_URLS: parseParagonThemeUrls(process.env.PARAGON_THEME_URLS!),
209270
};
210271

211272
/**
@@ -221,10 +282,8 @@ let config = {
221282
* LMS_BASE_URL,
222283
* } = getConfig();
223284
* ```
224-
*
225-
* @returns {ConfigDocument}
226285
*/
227-
export function getConfig() {
286+
export function getConfig(): ConfigDocument {
228287
return config;
229288
}
230289

@@ -243,10 +302,8 @@ export function getConfig() {
243302
* LMS_BASE_URL, // This is overriding the ENTIRE document - this is not merged in!
244303
* });
245304
* ```
246-
*
247-
* @param {ConfigDocument} newConfig
248305
*/
249-
export function setConfig(newConfig) {
306+
export function setConfig(newConfig: ConfigDocument) {
250307
ensureDefinedConfig(config, 'config');
251308
config = newConfig;
252309
publish(CONFIG_CHANGED);
@@ -264,9 +321,8 @@ export function setConfig(newConfig) {
264321
*
265322
* If any of the key values are `undefined`, an error will be logged to 'warn'.
266323
*
267-
* @param {Object} newConfig
268324
*/
269-
export function mergeConfig(newConfig) {
325+
export function mergeConfig(newConfig: Partial<ConfigDocument>) {
270326
ensureDefinedConfig(newConfig, 'ProcessEnvConfigService');
271327
config = Object.assign(config, newConfig);
272328
publish(CONFIG_CHANGED);
@@ -292,11 +348,8 @@ export function mergeConfig(newConfig) {
292348
* of the specified properties. This means that this function is compatible with custom `config`
293349
* phase handlers responsible for loading additional configuration data in the initialization
294350
* sequence.
295-
*
296-
* @param {Array} keys
297-
* @param {string} [requester='unspecified application code']
298351
*/
299-
export function ensureConfig(keys, requester = 'unspecified application code') {
352+
export function ensureConfig(keys: string[], requester = 'unspecified application code') {
300353
subscribe(APP_CONFIG_INITIALIZED, () => {
301354
keys.forEach((key) => {
302355
if (config[key] === undefined) {
@@ -313,8 +366,8 @@ export function ensureConfig(keys, requester = 'unspecified application code') {
313366
* the provided URL.
314367
*
315368
*
316-
* @param {string} url - The default URL.
317-
* @returns {string} - The external link URL. Defaults to the input URL if not found in the
369+
* @param url - The default URL.
370+
* @returns - The external link URL. Defaults to the input URL if not found in the
318371
* `externalLinkUrlOverrides` object. If the input URL is invalid, '#' is returned.
319372
*
320373
* @example
@@ -325,7 +378,7 @@ export function ensureConfig(keys, requester = 'unspecified application code') {
325378
* target="_blank"
326379
* >
327380
*/
328-
export function getExternalLinkUrl(url) {
381+
export function getExternalLinkUrl(url: string): string {
329382
// Guard against non-strings or whitespace-only strings
330383
if (typeof url !== 'string' || !url.trim()) {
331384
return '#';
@@ -334,58 +387,3 @@ export function getExternalLinkUrl(url) {
334387
const overriddenLinkUrls = getConfig().externalLinkUrlOverrides || {};
335388
return overriddenLinkUrls[url] || url;
336389
}
337-
338-
/**
339-
* An object describing the current application configuration.
340-
*
341-
* In its most basic form, the initialization process loads this document via `process.env`
342-
* variables. There are other ways to add configuration variables to the ConfigDocument as
343-
* documented above (JavaScript File Configuration, Runtime Configuration, and the Initialization
344-
* Config Handler).
345-
*
346-
* ```
347-
* {
348-
* BASE_URL: process.env.BASE_URL,
349-
* // ... other vars
350-
* }
351-
* ```
352-
*
353-
* When using Webpack (i.e., normal usage), the build process is responsible for supplying these
354-
* variables via command-line environment variables. That means they must be supplied at build
355-
* time.
356-
*
357-
* @name ConfigDocument
358-
* @memberof module:Config
359-
* @property {string} ACCESS_TOKEN_COOKIE_NAME
360-
* @property {string} ACCOUNT_PROFILE_URL
361-
* @property {string} ACCOUNT_SETTINGS_URL
362-
* @property {string} BASE_URL The URL of the current application.
363-
* @property {string} CREDENTIALS_BASE_URL
364-
* @property {string} CSRF_TOKEN_API_PATH
365-
* @property {string} DISCOVERY_API_BASE_URL
366-
* @property {string} PUBLISHER_BASE_URL
367-
* @property {string} ECOMMERCE_BASE_URL
368-
* @property {string} ENVIRONMENT This is one of: development, production, or test.
369-
* @property {string} IGNORED_ERROR_REGEX
370-
* @property {string} LANGUAGE_PREFERENCE_COOKIE_NAME
371-
* @property {string} LEARNING_BASE_URL
372-
* @property {string} LMS_BASE_URL
373-
* @property {string} LOGIN_URL
374-
* @property {string} LOGOUT_URL
375-
* @property {string} STUDIO_BASE_URL
376-
* @property {string} MARKETING_SITE_BASE_URL
377-
* @property {string} ORDER_HISTORY_URL
378-
* @property {string} REFRESH_ACCESS_TOKEN_ENDPOINT
379-
* @property {boolean} SECURE_COOKIES
380-
* @property {string} SEGMENT_KEY
381-
* @property {string} SITE_NAME
382-
* @property {string} USER_INFO_COOKIE_NAME
383-
* @property {string} LOGO_URL
384-
* @property {string} LOGO_TRADEMARK_URL
385-
* @property {string} LOGO_WHITE_URL
386-
* @property {string} FAVICON_URL
387-
* @property {string} MFE_CONFIG_API_URL
388-
* @property {string} APP_ID
389-
* @property {string} SUPPORT_URL
390-
* @property {string} PARAGON_THEME_URLS
391-
*/

src/i18n/lib.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ export function findSupportedLocale(locale) {
147147
* Gracefully fall back to a more general primary language subtag or to English (en)
148148
* if we don't support that language.
149149
*
150-
* @param {string} locale If a locale is provided, returns the closest supported locale. Optional.
150+
* @param {string} [locale] If a locale is provided, returns the closest supported locale. Optional.
151151
* @throws An error if i18n has not yet been configured.
152152
* @returns {string}
153153
* @memberof module:Internationalization

0 commit comments

Comments
 (0)