From 811400dd506b50bd958d736120e870d931ae5deb Mon Sep 17 00:00:00 2001 From: Diana Olarte Date: Thu, 12 Mar 2026 17:40:04 +1100 Subject: [PATCH 1/4] chore: add ts configuration --- Makefile | 3 ++- babel.config.js | 4 +++- package.json | 2 +- src/analytics/SegmentAnalyticsService.js | 3 ++- src/auth/AxiosJwtTokenService.js | 2 +- src/react/PageWrap.jsx | 2 +- tsconfig.json | 9 +++++++++ 7 files changed, 19 insertions(+), 6 deletions(-) create mode 100644 tsconfig.json diff --git a/Makefile b/Makefile index 6f69d3f1c..b00995454 100644 --- a/Makefile +++ b/Makefile @@ -12,9 +12,10 @@ cat_docs_command = cat ./docs/_API-header.md ./docs/_API-body.md > ./docs/API.md build: rm -rf ./dist - ./node_modules/.bin/fedx-scripts babel src --out-dir dist --source-maps --ignore **/*.test.jsx,**/*.test.js,**/setupTest.js --copy-files + ./node_modules/.bin/fedx-scripts babel src --out-dir dist --source-maps --extensions '.js,.jsx,.ts,.tsx' --ignore **/*.test.jsx,**/*.test.js,**/*.test.tsx,**/*.test.ts,**/setupTest.js --copy-files @# --copy-files will bring in everything else that wasn't processed by babel. Remove what we don't want. @find dist -name '*.test.js*' -delete + @find dist -name '*.test.ts*' -delete rm ./dist/setupTest.js cp ./package.json ./dist/package.json cp ./LICENSE ./dist/LICENSE diff --git a/babel.config.js b/babel.config.js index 28efaeeeb..0fe2bc493 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,3 +1,5 @@ const { createConfig } = require('@openedx/frontend-build'); -module.exports = createConfig('babel-preserve-modules'); +const config = createConfig('babel-preserve-modules'); +config.presets.push('@babel/preset-typescript'); +module.exports = config; diff --git a/package.json b/package.json index 18a8fc2ac..299667ec8 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "build": "make build", "docs": "jsdoc -c jsdoc.json", "docs-watch": "nodemon -w src -w docs/template -w README.md -e js,jsx --exec npm run docs", - "lint": "fedx-scripts eslint --ext .js --ext .jsx .", + "lint": "fedx-scripts eslint --ext .js --ext .jsx --ext .ts --ext .tsx .", "i18n_extract": "fedx-scripts formatjs extract", "snapshot": "fedx-scripts jest --updateSnapshot", "start": "fedx-scripts webpack-dev-server --progress", diff --git a/src/analytics/SegmentAnalyticsService.js b/src/analytics/SegmentAnalyticsService.js index 3a22b406c..0d77cd52e 100644 --- a/src/analytics/SegmentAnalyticsService.js +++ b/src/analytics/SegmentAnalyticsService.js @@ -174,6 +174,7 @@ class SegmentAnalyticsService { * @param {*} [traits] * @returns {Promise} Promise that will resolve once the document readyState is complete */ + // eslint-disable-next-line @typescript-eslint/no-unused-vars identifyAnonymousUser(traits) { // eslint-disable-line no-unused-vars if (!this.segmentInitialized) { return Promise.resolve(); @@ -182,7 +183,7 @@ class SegmentAnalyticsService { // but we still have a user id associated in segment, reset the local segment state // This has to be wrapped in the analytics.ready() callback because the analytics.user() // function isn't available until the analytics.js package has finished initializing. - return new Promise((resolve, reject) => { // eslint-disable-line no-unused-vars + return new Promise((resolve, reject) => { // eslint-disable-line no-unused-vars, @typescript-eslint/no-unused-vars global.analytics.ready(() => { if (global.analytics.user().id()) { global.analytics.reset(); diff --git a/src/auth/AxiosJwtTokenService.js b/src/auth/AxiosJwtTokenService.js index 83021ed7c..a28e8613c 100644 --- a/src/auth/AxiosJwtTokenService.js +++ b/src/auth/AxiosJwtTokenService.js @@ -124,7 +124,7 @@ export default class AxiosJwtTokenService { } try { - return await this.refresh(); + return await this.refresh(); // eslint-disable-line @typescript-eslint/return-await } catch (e) { // TODO: Fix these. They're still using loggingService as a singleton. logFrontendAuthError(this.loggingService, e); diff --git a/src/react/PageWrap.jsx b/src/react/PageWrap.jsx index d7130cd73..692f59900 100644 --- a/src/react/PageWrap.jsx +++ b/src/react/PageWrap.jsx @@ -1,5 +1,5 @@ /* eslint-disable react/prop-types */ -// eslint-disable-next-line no-unused-vars +// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars import React, { useEffect } from 'react'; import { useLocation } from 'react-router-dom'; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 000000000..9e07a2415 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "@edx/typescript-config", + "compilerOptions": { + "rootDir": ".", + "outDir": "dist" + }, + "include": ["src/**/*", "example/**/*", "__mocks__/**/*", ".*.js", "*.js", "*.jsx"], + "exclude": ["dist", "node_modules"] +} From a14d05f7c3e272449aa353b8d7dabec6481e8e33 Mon Sep 17 00:00:00 2001 From: Diana Olarte Date: Fri, 20 Mar 2026 20:15:32 +1100 Subject: [PATCH 2/4] fix: add missing extensions in tsconfig file --- tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index 9e07a2415..5b44fa523 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,6 +4,6 @@ "rootDir": ".", "outDir": "dist" }, - "include": ["src/**/*", "example/**/*", "__mocks__/**/*", ".*.js", "*.js", "*.jsx"], + "include": ["src/**/*", "example/**/*", "__mocks__/**/*", ".*.js", "*.js", "*.jsx", "*.ts", "*.tsx"], "exclude": ["dist", "node_modules"] } From 76a4319a848e25c3fdc61b8451291336c81ec89b Mon Sep 17 00:00:00 2001 From: Diana Olarte Date: Fri, 20 Mar 2026 21:48:03 +1100 Subject: [PATCH 3/4] refactor: change pubSub to typescript --- Makefile | 4 +++- package.json | 1 + src/global.d.ts | 8 ++++++++ src/{pubSub.js => pubSub.ts} | 24 ++++++++++++++---------- tsconfig.build.json | 11 +++++++++++ 5 files changed, 37 insertions(+), 11 deletions(-) create mode 100644 src/global.d.ts rename src/{pubSub.js => pubSub.ts} (59%) create mode 100644 tsconfig.build.json diff --git a/Makefile b/Makefile index b00995454..332531934 100644 --- a/Makefile +++ b/Makefile @@ -12,11 +12,13 @@ cat_docs_command = cat ./docs/_API-header.md ./docs/_API-body.md > ./docs/API.md build: rm -rf ./dist - ./node_modules/.bin/fedx-scripts babel src --out-dir dist --source-maps --extensions '.js,.jsx,.ts,.tsx' --ignore **/*.test.jsx,**/*.test.js,**/*.test.tsx,**/*.test.ts,**/setupTest.js --copy-files + ./node_modules/.bin/fedx-scripts babel src --out-dir dist --source-maps --extensions '.js,.jsx,.ts,.tsx' --ignore **/*.test.jsx,**/*.test.js,**/*.test.tsx,**/*.test.ts,**/setupTest.js,**/*.d.ts --copy-files @# --copy-files will bring in everything else that wasn't processed by babel. Remove what we don't want. @find dist -name '*.test.js*' -delete @find dist -name '*.test.ts*' -delete rm ./dist/setupTest.js + @# Generate .d.ts type declaration files from TypeScript sources + ./node_modules/.bin/tsc --project tsconfig.build.json cp ./package.json ./dist/package.json cp ./LICENSE ./dist/LICENSE cp ./README.md ./dist/README.md diff --git a/package.json b/package.json index 299667ec8..fe1c939b6 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "1.0.0-semantically-released", "description": "Foundational application framework for Open edX micro-frontend applications.", "main": "index.js", + "types": "index.d.ts", "publishConfig": { "access": "public" }, diff --git a/src/global.d.ts b/src/global.d.ts new file mode 100644 index 000000000..6bf235f1b --- /dev/null +++ b/src/global.d.ts @@ -0,0 +1,8 @@ +declare module 'pubsub-js' { + const PubSub: { + subscribe(type: string, callback: (message: string, data?: unknown) => void): string; + unsubscribe(token: string): void; + publish(type: string, data?: unknown): boolean; + }; + export default PubSub; +} diff --git a/src/pubSub.js b/src/pubSub.ts similarity index 59% rename from src/pubSub.js rename to src/pubSub.ts index 1104f2442..1c3db5bb8 100644 --- a/src/pubSub.js +++ b/src/pubSub.ts @@ -20,28 +20,32 @@ import PubSub from 'pubsub-js'; /** + * Subscribes to a PubSub event. * - * @param {string} type - * @param {function} callback - * @returns {string} A subscription token that can be passed to `unsubscribe` + * @param type - The event type to subscribe to + * @param callback - The callback function invoked when the event is published + * @returns A subscription token that can be passed to {@link unsubscribe} */ -export function subscribe(type, callback) { +export function subscribe(type: string, callback: (message: string, data: unknown) => void): string { return PubSub.subscribe(type, callback); } /** + * Unsubscribes from a PubSub event. * - * @param {string} token A subscription token provided by `subscribe` + * @param token - A subscription token provided by {@link subscribe} */ -export function unsubscribe(token) { - return PubSub.unsubscribe(token); +export function unsubscribe(token: string): void { + PubSub.unsubscribe(token); } /** + * Publishes a PubSub event. * - * @param {string} type - * @param {Object} data + * @param type - The event type to publish + * @param data - The data to pass to subscribers + * @returns Whether the event was published successfully */ -export function publish(type, data) { +export function publish(type: string, data?: unknown): boolean { return PubSub.publish(type, data); } diff --git a/tsconfig.build.json b/tsconfig.build.json new file mode 100644 index 000000000..38f0e1818 --- /dev/null +++ b/tsconfig.build.json @@ -0,0 +1,11 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "dist", + "declaration": true, + "emitDeclarationOnly": true + }, + "include": ["src/**/*"], + "exclude": ["dist", "node_modules", "src/**/*.test.*", "src/setupTest.*"] +} From 9d8d072f57c3c72e0a807028bdffd8aecba2576b Mon Sep 17 00:00:00 2001 From: Diana Olarte Date: Sat, 21 Mar 2026 07:55:08 +1100 Subject: [PATCH 4/4] fix: add a delete line for removing .d.ts at babel step --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 332531934..732b43eda 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,7 @@ build: @# --copy-files will bring in everything else that wasn't processed by babel. Remove what we don't want. @find dist -name '*.test.js*' -delete @find dist -name '*.test.ts*' -delete + @find dist -name '*.d.ts' -delete rm ./dist/setupTest.js @# Generate .d.ts type declaration files from TypeScript sources ./node_modules/.bin/tsc --project tsconfig.build.json