@openedx/frontend-base 1.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (356) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +112 -0
  3. package/config/babel/babel.config.js +28 -0
  4. package/config/config-helpers/createConfig.js +13 -0
  5. package/config/config-helpers/createLintConfig.js +16 -0
  6. package/config/config-helpers/getBaseConfig.js +12 -0
  7. package/config/defaultConfigPaths.js +35 -0
  8. package/config/eslint/base.eslint.config.js +113 -0
  9. package/config/index.js +12 -0
  10. package/config/jest/jest.config.js +30 -0
  11. package/config/tsconfig.json +32 -0
  12. package/config/types.js +25 -0
  13. package/config/webpack/common-config/all/getCodeRules.js +52 -0
  14. package/config/webpack/common-config/all/getFileLoaderRules.js +26 -0
  15. package/config/webpack/common-config/all/getIgnoreWarnings.js +14 -0
  16. package/config/webpack/common-config/all/getImageMinimizer.js +25 -0
  17. package/config/webpack/common-config/all/getStylesheetRule.js +112 -0
  18. package/config/webpack/common-config/dev/getDevServer.js +38 -0
  19. package/config/webpack/common-config/index.js +18 -0
  20. package/config/webpack/common-config/site/getHtmlWebpackPlugin.js +16 -0
  21. package/config/webpack/plugins/html-webpack-new-relic-plugin/HtmlWebpackNewRelicPlugin.js +91 -0
  22. package/config/webpack/plugins/html-webpack-new-relic-plugin/index.js +7 -0
  23. package/config/webpack/plugins/html-webpack-new-relic-plugin/test/fixtures/entry.js +3 -0
  24. package/config/webpack/plugins/paragon-webpack-plugin/ParagonWebpackPlugin.js +108 -0
  25. package/config/webpack/plugins/paragon-webpack-plugin/index.js +7 -0
  26. package/config/webpack/plugins/paragon-webpack-plugin/utils/assetUtils.js +64 -0
  27. package/config/webpack/plugins/paragon-webpack-plugin/utils/htmlUtils.js +53 -0
  28. package/config/webpack/plugins/paragon-webpack-plugin/utils/index.js +9 -0
  29. package/config/webpack/plugins/paragon-webpack-plugin/utils/paragonStylesheetUtils.js +114 -0
  30. package/config/webpack/plugins/paragon-webpack-plugin/utils/scriptUtils.js +146 -0
  31. package/config/webpack/plugins/paragon-webpack-plugin/utils/stylesheetUtils.js +126 -0
  32. package/config/webpack/plugins/paragon-webpack-plugin/utils/tagUtils.js +57 -0
  33. package/config/webpack/types.js +2 -0
  34. package/config/webpack/utils/getLocalAliases.js +65 -0
  35. package/config/webpack/utils/getPublicPath.js +6 -0
  36. package/config/webpack/utils/getResolvedSiteConfigPath.js +32 -0
  37. package/config/webpack/utils/paragonUtils.js +138 -0
  38. package/config/webpack/webpack.config.build.js +80 -0
  39. package/config/webpack/webpack.config.dev.js +76 -0
  40. package/config/webpack/webpack.config.dev.shell.js +110 -0
  41. package/eslint.config.js +18 -0
  42. package/frontend-base.d.ts +8 -0
  43. package/index.ts +7 -0
  44. package/jest.config.js +7 -0
  45. package/openedx-frontend-base.tgz +0 -0
  46. package/package.json +149 -0
  47. package/runtime/analytics/MockAnalyticsService.js +71 -0
  48. package/runtime/analytics/SegmentAnalyticsService.js +243 -0
  49. package/runtime/analytics/index.ts +12 -0
  50. package/runtime/analytics/interface.js +145 -0
  51. package/runtime/auth/AxiosCsrfTokenService.js +60 -0
  52. package/runtime/auth/AxiosJwtAuthService.js +363 -0
  53. package/runtime/auth/AxiosJwtTokenService.js +134 -0
  54. package/runtime/auth/LocalForageCache.js +76 -0
  55. package/runtime/auth/MockAuthService.js +278 -0
  56. package/runtime/auth/index.ts +19 -0
  57. package/runtime/auth/interceptors/createCsrfTokenProviderInterceptor.js +36 -0
  58. package/runtime/auth/interceptors/createJwtTokenProviderInterceptor.js +37 -0
  59. package/runtime/auth/interceptors/createProcessAxiosRequestErrorInterceptor.js +20 -0
  60. package/runtime/auth/interceptors/createRetryInterceptor.js +74 -0
  61. package/runtime/auth/interface.js +309 -0
  62. package/runtime/auth/utils.js +105 -0
  63. package/runtime/babel.config.js +3 -0
  64. package/runtime/config/index.ts +295 -0
  65. package/runtime/constants.ts +68 -0
  66. package/runtime/i18n/index.js +118 -0
  67. package/runtime/i18n/injectIntlWithShim.jsx +48 -0
  68. package/runtime/i18n/lib.ts +272 -0
  69. package/runtime/index.ts +134 -0
  70. package/runtime/initialize.js +352 -0
  71. package/runtime/jest.config.js +32 -0
  72. package/runtime/logging/MockLoggingService.js +31 -0
  73. package/runtime/logging/NewRelicLoggingService.js +184 -0
  74. package/runtime/logging/index.ts +9 -0
  75. package/runtime/logging/interface.js +109 -0
  76. package/runtime/logging/types.ts +4 -0
  77. package/runtime/react/AuthenticatedPageRoute.jsx +43 -0
  78. package/runtime/react/CombinedAppProvider.tsx +46 -0
  79. package/runtime/react/CurrentAppContext.tsx +25 -0
  80. package/runtime/react/CurrentAppProvider.tsx +46 -0
  81. package/runtime/react/Divider.tsx +5 -0
  82. package/runtime/react/ErrorBoundary.jsx +47 -0
  83. package/runtime/react/ErrorPage.jsx +72 -0
  84. package/runtime/react/LoginRedirect.jsx +16 -0
  85. package/runtime/react/PageWrap.jsx +24 -0
  86. package/runtime/react/SiteContext.tsx +32 -0
  87. package/runtime/react/SiteProvider.tsx +78 -0
  88. package/runtime/react/hooks.ts +106 -0
  89. package/runtime/react/index.ts +19 -0
  90. package/runtime/routing/index.ts +1 -0
  91. package/runtime/routing/utils.ts +34 -0
  92. package/runtime/scripts/GoogleAnalyticsLoader.ts +59 -0
  93. package/runtime/scripts/index.ts +1 -0
  94. package/runtime/setupTest.js +49 -0
  95. package/runtime/slots/Slot.tsx +32 -0
  96. package/runtime/slots/SlotContext.tsx +8 -0
  97. package/runtime/slots/hooks.ts +35 -0
  98. package/runtime/slots/index.ts +7 -0
  99. package/runtime/slots/layout/DefaultSlotLayout.tsx +9 -0
  100. package/runtime/slots/layout/hooks.ts +65 -0
  101. package/runtime/slots/layout/index.ts +5 -0
  102. package/runtime/slots/layout/types.ts +45 -0
  103. package/runtime/slots/layout/utils.ts +14 -0
  104. package/runtime/slots/types.ts +23 -0
  105. package/runtime/slots/utils.ts +59 -0
  106. package/runtime/slots/widget/WidgetContext.tsx +9 -0
  107. package/runtime/slots/widget/WidgetProvider.tsx +30 -0
  108. package/runtime/slots/widget/hooks.ts +105 -0
  109. package/runtime/slots/widget/iframe/IFrameContentWrapper.messages.tsx +16 -0
  110. package/runtime/slots/widget/iframe/IFrameContentWrapper.tsx +84 -0
  111. package/runtime/slots/widget/iframe/IFrameWidget.tsx +59 -0
  112. package/runtime/slots/widget/iframe/constants.ts +19 -0
  113. package/runtime/slots/widget/iframe/hooks.ts +179 -0
  114. package/runtime/slots/widget/iframe/index.ts +6 -0
  115. package/runtime/slots/widget/iframe/types.ts +7 -0
  116. package/runtime/slots/widget/index.ts +6 -0
  117. package/runtime/slots/widget/types.ts +134 -0
  118. package/runtime/slots/widget/utils.tsx +201 -0
  119. package/runtime/subscriptions.ts +60 -0
  120. package/runtime/testing/index.ts +9 -0
  121. package/runtime/testing/initializeMockApp.ts +81 -0
  122. package/runtime/testing/mockMessages.ts +23 -0
  123. package/runtime/utils.js +178 -0
  124. package/shell/DefaultLayout.tsx +18 -0
  125. package/shell/DefaultMain.tsx +7 -0
  126. package/shell/Logo.tsx +28 -0
  127. package/shell/Shell.messages.ts +61 -0
  128. package/shell/Shell.tsx +18 -0
  129. package/shell/app.scss +149 -0
  130. package/shell/app.ts +24 -0
  131. package/shell/babel.config.js +3 -0
  132. package/shell/dev/devFooter/app.tsx +43 -0
  133. package/shell/dev/devFooter/index.ts +1 -0
  134. package/shell/dev/devHeader/BarContext.tsx +13 -0
  135. package/shell/dev/devHeader/BarLink.tsx +16 -0
  136. package/shell/dev/devHeader/BarProvider.tsx +25 -0
  137. package/shell/dev/devHeader/CoursesLink.tsx +16 -0
  138. package/shell/dev/devHeader/FooContext.tsx +13 -0
  139. package/shell/dev/devHeader/FooLink.tsx +16 -0
  140. package/shell/dev/devHeader/FooProvider.tsx +25 -0
  141. package/shell/dev/devHeader/app.tsx +53 -0
  142. package/shell/dev/devHeader/index.ts +1 -0
  143. package/shell/dev/devHeader/providers.tsx +11 -0
  144. package/shell/dev/devHome/HomePage.tsx +28 -0
  145. package/shell/dev/devHome/app.ts +18 -0
  146. package/shell/dev/devHome/i18n/index.ts +27 -0
  147. package/shell/dev/devHome/index.ts +1 -0
  148. package/shell/dev/devHome/messages.ts +11 -0
  149. package/shell/dev/devUser/app.tsx +24 -0
  150. package/shell/dev/devUser/index.ts +1 -0
  151. package/shell/dev/index.ts +5 -0
  152. package/shell/dev/slotShowcase/HorizontalSlotLayout.tsx +11 -0
  153. package/shell/dev/slotShowcase/LayoutWithOptions.tsx +17 -0
  154. package/shell/dev/slotShowcase/SlotShowcasePage.tsx +66 -0
  155. package/shell/dev/slotShowcase/WidgetWithOptions.tsx +11 -0
  156. package/shell/dev/slotShowcase/app.tsx +373 -0
  157. package/shell/dev/slotShowcase/index.ts +1 -0
  158. package/shell/footer/CenterLinks.tsx +11 -0
  159. package/shell/footer/CopyrightNotice.tsx +36 -0
  160. package/shell/footer/Footer.tsx +34 -0
  161. package/shell/footer/LabeledLinkColumn.tsx +19 -0
  162. package/shell/footer/LanguageMenu.tsx +35 -0
  163. package/shell/footer/LanguageMenuItem.tsx +23 -0
  164. package/shell/footer/LeftLinks.tsx +11 -0
  165. package/shell/footer/LegalNotices.tsx +17 -0
  166. package/shell/footer/PoweredBy.tsx +17 -0
  167. package/shell/footer/RevealLinks.tsx +43 -0
  168. package/shell/footer/RightLinks.tsx +11 -0
  169. package/shell/footer/app.tsx +73 -0
  170. package/shell/footer/data/api.ts +48 -0
  171. package/shell/footer/index.ts +2 -0
  172. package/shell/header/AuthenticatedMenu.tsx +32 -0
  173. package/shell/header/Header.tsx +17 -0
  174. package/shell/header/anonymous-menu/AnonymousMenu.tsx +14 -0
  175. package/shell/header/anonymous-menu/LoginButton.tsx +14 -0
  176. package/shell/header/anonymous-menu/RegisterButton.tsx +15 -0
  177. package/shell/header/app.tsx +142 -0
  178. package/shell/header/desktop/DesktopLayout.tsx +22 -0
  179. package/shell/header/desktop/PrimaryNavLinks.tsx +10 -0
  180. package/shell/header/desktop/SecondaryNavLinks.tsx +10 -0
  181. package/shell/header/index.ts +2 -0
  182. package/shell/header/mobile/MobileLayout.tsx +47 -0
  183. package/shell/header/mobile/MobileNavLinks.tsx +10 -0
  184. package/shell/i18n/index.ts +25 -0
  185. package/shell/index.ts +7 -0
  186. package/shell/jest.config.js +30 -0
  187. package/shell/menus/LinkMenuItem.tsx +64 -0
  188. package/shell/menus/NavDropdownMenuSlot.tsx +29 -0
  189. package/shell/menus/ProfileLinkMenuItem.tsx +33 -0
  190. package/shell/menus/data/utils.ts +19 -0
  191. package/shell/public/index.html +10 -0
  192. package/shell/router/createRouter.ts +17 -0
  193. package/shell/router/getAppRoutes.ts +21 -0
  194. package/shell/setupTest.js +48 -0
  195. package/shell/site.config.dev.tsx +49 -0
  196. package/shell/site.tsx +41 -0
  197. package/test-site/app.d.ts +15 -0
  198. package/test-site/dist/176.436443549ebb858db483.js +2 -0
  199. package/test-site/dist/176.436443549ebb858db483.js.map +1 -0
  200. package/test-site/dist/362.536eff787d2380fe246c.js +2 -0
  201. package/test-site/dist/362.536eff787d2380fe246c.js.map +1 -0
  202. package/test-site/dist/653.486966b108d224551296.js +2 -0
  203. package/test-site/dist/653.486966b108d224551296.js.map +1 -0
  204. package/test-site/dist/74e025d3fe9a7b7f8503054e2563b353.jpg +0 -0
  205. package/test-site/dist/806.323cf6496ad0a7fe73a7.js +3 -0
  206. package/test-site/dist/806.323cf6496ad0a7fe73a7.js.LICENSE.txt +106 -0
  207. package/test-site/dist/806.323cf6496ad0a7fe73a7.js.map +1 -0
  208. package/test-site/dist/95ec738c0b7faac5b5c9126794446bbd.svg +4 -0
  209. package/test-site/dist/app.612058b36c74787759ac.css +61 -0
  210. package/test-site/dist/app.612058b36c74787759ac.css.map +1 -0
  211. package/test-site/dist/app.612058b36c74787759ac.js +2 -0
  212. package/test-site/dist/app.612058b36c74787759ac.js.map +1 -0
  213. package/test-site/dist/cb28cdb1468c915e27e5cec9af64f22f.svg +1 -0
  214. package/test-site/dist/index.html +1 -0
  215. package/test-site/dist/report.html +39 -0
  216. package/test-site/dist/runtime.c7aeaf7b967496cb076f.js +2 -0
  217. package/test-site/dist/runtime.c7aeaf7b967496cb076f.js.map +1 -0
  218. package/test-site/eslint.config.js +12 -0
  219. package/test-site/package-lock.json +19226 -0
  220. package/test-site/package.json +29 -0
  221. package/test-site/public/index.html +10 -0
  222. package/test-site/site.config.build.tsx +27 -0
  223. package/test-site/site.config.dev.tsx +27 -0
  224. package/test-site/src/authenticated-page/AuthenticatedPage.tsx +18 -0
  225. package/test-site/src/authenticated-page/i18n/index.ts +27 -0
  226. package/test-site/src/authenticated-page/index.tsx +28 -0
  227. package/test-site/src/example-page/ExamplePage.tsx +79 -0
  228. package/test-site/src/example-page/Image.tsx +11 -0
  229. package/test-site/src/example-page/ParagonPreview.jsx +66 -0
  230. package/test-site/src/example-page/apple.jpg +0 -0
  231. package/test-site/src/example-page/apple.svg +1 -0
  232. package/test-site/src/example-page/index.ts +16 -0
  233. package/test-site/src/i18n/README.md +3 -0
  234. package/test-site/src/i18n/messages/frontend-app-sample/ar.json +4 -0
  235. package/test-site/src/i18n/messages/frontend-app-sample/eo.json +1 -0
  236. package/test-site/src/i18n/messages/frontend-app-sample/es_419.json +4 -0
  237. package/test-site/src/i18n/messages/frontend-component-emptylangs/ar.json +1 -0
  238. package/test-site/src/i18n/messages/frontend-component-singlelang/ar.json +3 -0
  239. package/test-site/src/iframe-widget/IframeWidget.tsx +14 -0
  240. package/test-site/src/iframe-widget/index.ts +16 -0
  241. package/test-site/src/index.tsx +3 -0
  242. package/test-site/src/messages.js +11 -0
  243. package/test-site/src/site.scss +11 -0
  244. package/test-site/tsconfig.json +14 -0
  245. package/tools/babel/babel.config.js +27 -0
  246. package/tools/babel.config.js +3 -0
  247. package/tools/cli/README.md +29 -0
  248. package/tools/cli/commands/pack.ts +9 -0
  249. package/tools/cli/commands/release.ts +27 -0
  250. package/tools/cli/commands/serve.ts +43 -0
  251. package/tools/cli/intl-imports.ts +274 -0
  252. package/tools/cli/openedx.ts +101 -0
  253. package/tools/cli/transifex-utils.ts +75 -0
  254. package/tools/cli/utils/ensureConfigFilenameOption.ts +40 -0
  255. package/tools/cli/utils/formatter.ts +10 -0
  256. package/tools/cli/utils/getResolvedConfigPath.ts +23 -0
  257. package/tools/cli/utils/prettyPrintTitle.ts +15 -0
  258. package/tools/cli/utils/printUsage.ts +53 -0
  259. package/tools/config-helpers/createConfig.ts +8 -0
  260. package/tools/config-helpers/createLintConfig.ts +14 -0
  261. package/tools/config-helpers/getBaseConfig.ts +11 -0
  262. package/tools/defaultConfigPaths.ts +30 -0
  263. package/tools/dist/babel/babel.config.js +28 -0
  264. package/tools/dist/cli/commands/pack.js +14 -0
  265. package/tools/dist/cli/commands/release.js +28 -0
  266. package/tools/dist/cli/commands/serve.js +44 -0
  267. package/tools/dist/cli/intl-imports.js +233 -0
  268. package/tools/dist/cli/openedx.js +100 -0
  269. package/tools/dist/cli/transifex-utils.js +68 -0
  270. package/tools/dist/cli/utils/ensureConfigFilenameOption.js +42 -0
  271. package/tools/dist/cli/utils/formatter.js +10 -0
  272. package/tools/dist/cli/utils/getResolvedConfigPath.js +28 -0
  273. package/tools/dist/cli/utils/prettyPrintTitle.js +17 -0
  274. package/tools/dist/cli/utils/printUsage.js +48 -0
  275. package/tools/dist/config-helpers/createConfig.js +13 -0
  276. package/tools/dist/config-helpers/createLintConfig.js +16 -0
  277. package/tools/dist/config-helpers/getBaseConfig.js +12 -0
  278. package/tools/dist/defaultConfigPaths.js +35 -0
  279. package/tools/dist/eslint/base.eslint.config.js +113 -0
  280. package/tools/dist/eslint.config.js +11 -0
  281. package/tools/dist/index.js +12 -0
  282. package/tools/dist/jest/jest.config.js +30 -0
  283. package/tools/dist/jest.config.js +20 -0
  284. package/tools/dist/types.js +25 -0
  285. package/tools/dist/typescript/tsconfig.json +32 -0
  286. package/tools/dist/webpack/common-config/all/getCodeRules.js +52 -0
  287. package/tools/dist/webpack/common-config/all/getFileLoaderRules.js +26 -0
  288. package/tools/dist/webpack/common-config/all/getIgnoreWarnings.js +14 -0
  289. package/tools/dist/webpack/common-config/all/getImageMinimizer.js +25 -0
  290. package/tools/dist/webpack/common-config/all/getStylesheetRule.js +112 -0
  291. package/tools/dist/webpack/common-config/dev/getDevServer.js +38 -0
  292. package/tools/dist/webpack/common-config/index.js +18 -0
  293. package/tools/dist/webpack/common-config/site/getHtmlWebpackPlugin.js +16 -0
  294. package/tools/dist/webpack/plugins/html-webpack-new-relic-plugin/HtmlWebpackNewRelicPlugin.js +91 -0
  295. package/tools/dist/webpack/plugins/html-webpack-new-relic-plugin/index.js +7 -0
  296. package/tools/dist/webpack/plugins/html-webpack-new-relic-plugin/test/fixtures/entry.js +3 -0
  297. package/tools/dist/webpack/plugins/paragon-webpack-plugin/ParagonWebpackPlugin.js +108 -0
  298. package/tools/dist/webpack/plugins/paragon-webpack-plugin/index.js +7 -0
  299. package/tools/dist/webpack/plugins/paragon-webpack-plugin/utils/assetUtils.js +64 -0
  300. package/tools/dist/webpack/plugins/paragon-webpack-plugin/utils/htmlUtils.js +53 -0
  301. package/tools/dist/webpack/plugins/paragon-webpack-plugin/utils/index.js +9 -0
  302. package/tools/dist/webpack/plugins/paragon-webpack-plugin/utils/paragonStylesheetUtils.js +114 -0
  303. package/tools/dist/webpack/plugins/paragon-webpack-plugin/utils/scriptUtils.js +146 -0
  304. package/tools/dist/webpack/plugins/paragon-webpack-plugin/utils/stylesheetUtils.js +126 -0
  305. package/tools/dist/webpack/plugins/paragon-webpack-plugin/utils/tagUtils.js +57 -0
  306. package/tools/dist/webpack/types.js +2 -0
  307. package/tools/dist/webpack/utils/getLocalAliases.js +65 -0
  308. package/tools/dist/webpack/utils/getPublicPath.js +6 -0
  309. package/tools/dist/webpack/utils/getResolvedSiteConfigPath.js +32 -0
  310. package/tools/dist/webpack/utils/paragonUtils.js +138 -0
  311. package/tools/dist/webpack/webpack.config.build.js +80 -0
  312. package/tools/dist/webpack/webpack.config.dev.js +76 -0
  313. package/tools/dist/webpack/webpack.config.dev.shell.js +110 -0
  314. package/tools/eslint/base.eslint.config.js +124 -0
  315. package/tools/eslint/modules.d.ts +5 -0
  316. package/tools/eslint.config.js +15 -0
  317. package/tools/index.ts +3 -0
  318. package/tools/jest/jest.config.js +30 -0
  319. package/tools/jest.config.js +19 -0
  320. package/tools/tsconfig.json +24 -0
  321. package/tools/types.ts +21 -0
  322. package/tools/typescript/tsconfig.json +32 -0
  323. package/tools/webpack/common-config/README.md +15 -0
  324. package/tools/webpack/common-config/all/getCodeRules.ts +51 -0
  325. package/tools/webpack/common-config/all/getFileLoaderRules.ts +23 -0
  326. package/tools/webpack/common-config/all/getIgnoreWarnings.ts +13 -0
  327. package/tools/webpack/common-config/all/getImageMinimizer.ts +26 -0
  328. package/tools/webpack/common-config/all/getStylesheetRule.ts +111 -0
  329. package/tools/webpack/common-config/dev/getDevServer.ts +35 -0
  330. package/tools/webpack/common-config/index.ts +6 -0
  331. package/tools/webpack/common-config/site/getHtmlWebpackPlugin.ts +11 -0
  332. package/tools/webpack/modules.d.ts +6 -0
  333. package/tools/webpack/plugins/html-webpack-new-relic-plugin/HtmlWebpackNewRelicPlugin.ts +102 -0
  334. package/tools/webpack/plugins/html-webpack-new-relic-plugin/LICENSE +21 -0
  335. package/tools/webpack/plugins/html-webpack-new-relic-plugin/README.md +7 -0
  336. package/tools/webpack/plugins/html-webpack-new-relic-plugin/index.js +3 -0
  337. package/tools/webpack/plugins/html-webpack-new-relic-plugin/test/fixtures/entry.js +1 -0
  338. package/tools/webpack/plugins/paragon-webpack-plugin/ParagonWebpackPlugin.ts +134 -0
  339. package/tools/webpack/plugins/paragon-webpack-plugin/index.ts +3 -0
  340. package/tools/webpack/plugins/paragon-webpack-plugin/utils/assetUtils.ts +71 -0
  341. package/tools/webpack/plugins/paragon-webpack-plugin/utils/htmlUtils.ts +72 -0
  342. package/tools/webpack/plugins/paragon-webpack-plugin/utils/index.ts +6 -0
  343. package/tools/webpack/plugins/paragon-webpack-plugin/utils/paragonStylesheetUtils.ts +131 -0
  344. package/tools/webpack/plugins/paragon-webpack-plugin/utils/scriptUtils.ts +144 -0
  345. package/tools/webpack/plugins/paragon-webpack-plugin/utils/stylesheetUtils.ts +106 -0
  346. package/tools/webpack/plugins/paragon-webpack-plugin/utils/tagUtils.ts +54 -0
  347. package/tools/webpack/types.ts +69 -0
  348. package/tools/webpack/utils/getLocalAliases.ts +65 -0
  349. package/tools/webpack/utils/getPublicPath.ts +3 -0
  350. package/tools/webpack/utils/getResolvedSiteConfigPath.ts +28 -0
  351. package/tools/webpack/utils/paragonUtils.ts +152 -0
  352. package/tools/webpack/webpack.config.build.ts +93 -0
  353. package/tools/webpack/webpack.config.dev.shell.ts +122 -0
  354. package/tools/webpack/webpack.config.dev.ts +90 -0
  355. package/tsconfig.json +23 -0
  356. package/types.ts +99 -0
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getParagonVersion = getParagonVersion;
7
+ exports.getParagonThemeCss = getParagonThemeCss;
8
+ exports.getParagonCacheGroups = getParagonCacheGroups;
9
+ exports.getParagonEntryPoints = getParagonEntryPoints;
10
+ const fs_1 = __importDefault(require("fs"));
11
+ const path_1 = __importDefault(require("path"));
12
+ /**
13
+ * Retrieves the name of the brand package from the given directory.
14
+ *
15
+ * @param {string} dir - The directory path containing the package.json file.
16
+ * @return {string} The name of the brand package, or an empty string if not found.
17
+ */
18
+ function getBrandPackageName(dir) {
19
+ const appDependencies = JSON.parse(fs_1.default.readFileSync(path_1.default.resolve(dir, 'package.json'), 'utf-8')).dependencies;
20
+ return Object.keys(appDependencies).find((key) => /@(open)?edx\/brand/.exec(key)) ?? '';
21
+ }
22
+ /**
23
+ * Attempts to extract the Paragon version from the `node_modules` of
24
+ * the consuming application.
25
+ *
26
+ * @param {string} dir Path to directory containing `node_modules`.
27
+ * @returns {string} Paragon dependency version of the consuming application
28
+ */
29
+ function getParagonVersion(dir, { isBrandOverride = false } = {}) {
30
+ const npmPackageName = isBrandOverride ? getBrandPackageName(dir) : '@openedx/paragon';
31
+ const pathToPackageJson = `${dir}/node_modules/${npmPackageName}/package.json`;
32
+ if (!fs_1.default.existsSync(pathToPackageJson)) {
33
+ return undefined;
34
+ }
35
+ return JSON.parse(fs_1.default.readFileSync(pathToPackageJson, 'utf-8')).version;
36
+ }
37
+ /**
38
+ * Attempts to extract the Paragon theme CSS from the locally installed `@openedx/paragon` package.
39
+ * @param {string} dir Path to directory containing `node_modules`.
40
+ * @param {boolean} isBrandOverride
41
+ * @returns {ParagonThemeCss}
42
+ */
43
+ function getParagonThemeCss(dir, { isBrandOverride = false } = {}) {
44
+ const npmPackageName = isBrandOverride ? getBrandPackageName(dir) : '@openedx/paragon';
45
+ const pathToParagonThemeOutput = path_1.default.resolve(dir, 'node_modules', npmPackageName, 'dist', 'theme-urls.json');
46
+ if (!fs_1.default.existsSync(pathToParagonThemeOutput)) {
47
+ return undefined;
48
+ }
49
+ const paragonConfig = JSON.parse(fs_1.default.readFileSync(pathToParagonThemeOutput, 'utf-8'));
50
+ const { core: themeCore, variants: themeVariants, defaults, } = paragonConfig?.themeUrls || {};
51
+ const pathToCoreCss = path_1.default.resolve(dir, 'node_modules', npmPackageName, 'dist', themeCore.paths.minified);
52
+ const coreCssExists = fs_1.default.existsSync(pathToCoreCss);
53
+ const themeVariantResults = Object.entries(themeVariants || {}).reduce((themeVariantAcc, [themeVariant, value]) => {
54
+ const themeVariantCssDefault = path_1.default.resolve(dir, 'node_modules', npmPackageName, 'dist', value.paths.default);
55
+ const themeVariantCssMinified = path_1.default.resolve(dir, 'node_modules', npmPackageName, 'dist', value.paths.minified);
56
+ if (!fs_1.default.existsSync(themeVariantCssDefault) && !fs_1.default.existsSync(themeVariantCssMinified)) {
57
+ return themeVariantAcc;
58
+ }
59
+ return ({
60
+ ...themeVariantAcc,
61
+ [themeVariant]: {
62
+ filePath: themeVariantCssMinified,
63
+ entryName: isBrandOverride ? `brand.theme.variants.${themeVariant}` : `paragon.theme.variants.${themeVariant}`,
64
+ outputChunkName: isBrandOverride ? `brand-theme-variants-${themeVariant}` : `paragon-theme-variants-${themeVariant}`,
65
+ },
66
+ });
67
+ }, {});
68
+ if (!coreCssExists || Object.keys(themeVariantResults).length === 0) {
69
+ return undefined;
70
+ }
71
+ const coreResult = {
72
+ filePath: path_1.default.resolve(dir, pathToCoreCss),
73
+ entryName: isBrandOverride ? 'brand.theme.core' : 'paragon.theme.core',
74
+ outputChunkName: isBrandOverride ? 'brand-theme-core' : 'paragon-theme-core',
75
+ };
76
+ return {
77
+ core: fs_1.default.existsSync(pathToCoreCss) ? coreResult : undefined,
78
+ variants: themeVariantResults,
79
+ defaults,
80
+ };
81
+ }
82
+ /**
83
+ * @typedef CacheGroup
84
+ * @property {string} type The type of cache group.
85
+ * @property {string|function} name The name of the cache group.
86
+ * @property {function} chunks A function that returns true if the chunk should be included in the cache group.
87
+ * @property {boolean} enforce If true, this cache group will be created even if it conflicts with default cache groups.
88
+ */
89
+ /**
90
+ * @param {ParagonThemeCss} paragonThemeCss The Paragon theme CSS metadata.
91
+ * @returns {Object.<string, CacheGroup>} The cache groups for the Paragon theme CSS.
92
+ */
93
+ function getParagonCacheGroups(paragonThemeCss) {
94
+ if (!paragonThemeCss) {
95
+ return {};
96
+ }
97
+ const cacheGroups = {};
98
+ if (paragonThemeCss.core !== undefined) {
99
+ const { core } = paragonThemeCss;
100
+ cacheGroups[paragonThemeCss.core.outputChunkName] = {
101
+ type: 'css/mini-extract',
102
+ name: paragonThemeCss.core.outputChunkName,
103
+ chunks: (chunk) => chunk.name === core.entryName,
104
+ enforce: true,
105
+ };
106
+ }
107
+ Object.values(paragonThemeCss.variants).forEach(({ entryName, outputChunkName }) => {
108
+ cacheGroups[outputChunkName] = {
109
+ type: 'css/mini-extract',
110
+ name: outputChunkName,
111
+ chunks: (chunk) => chunk.name === entryName,
112
+ enforce: true,
113
+ };
114
+ });
115
+ return cacheGroups;
116
+ }
117
+ /**
118
+ * @param {ParagonThemeCss} paragonThemeCss The Paragon theme CSS metadata.
119
+ * @returns {Object.<string, string>} The entry points for the Paragon theme CSS. Example: ```
120
+ * {
121
+ * "paragon.theme.core": "/path/to/node_modules/@openedx/paragon/dist/core.min.css",
122
+ * "paragon.theme.variants.light": "/path/to/node_modules/@openedx/paragon/dist/light.min.css"
123
+ * }
124
+ * ```
125
+ */
126
+ function getParagonEntryPoints(paragonThemeCss) {
127
+ if (!paragonThemeCss) {
128
+ return {};
129
+ }
130
+ const entryPoints = {};
131
+ if (paragonThemeCss.core !== undefined) {
132
+ entryPoints[paragonThemeCss.core.entryName] = path_1.default.resolve(process.cwd(), paragonThemeCss.core.filePath);
133
+ }
134
+ Object.values(paragonThemeCss.variants).forEach(({ filePath, entryName }) => {
135
+ entryPoints[entryName] = path_1.default.resolve(process.cwd(), filePath);
136
+ });
137
+ return entryPoints;
138
+ }
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const fork_ts_checker_webpack_plugin_1 = __importDefault(require("fork-ts-checker-webpack-plugin"));
7
+ const mini_css_extract_plugin_1 = __importDefault(require("mini-css-extract-plugin"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const webpack_bundle_analyzer_1 = require("webpack-bundle-analyzer");
10
+ const webpack_remove_empty_scripts_1 = __importDefault(require("webpack-remove-empty-scripts"));
11
+ const common_config_1 = require("./common-config");
12
+ const ParagonWebpackPlugin_1 = __importDefault(require("./plugins/paragon-webpack-plugin/ParagonWebpackPlugin"));
13
+ const getLocalAliases_1 = __importDefault(require("./utils/getLocalAliases"));
14
+ const getPublicPath_1 = __importDefault(require("./utils/getPublicPath"));
15
+ const getResolvedSiteConfigPath_1 = __importDefault(require("./utils/getResolvedSiteConfigPath"));
16
+ const paragonUtils_1 = require("./utils/paragonUtils");
17
+ const paragonThemeCss = (0, paragonUtils_1.getParagonThemeCss)(process.cwd());
18
+ const brandThemeCss = (0, paragonUtils_1.getParagonThemeCss)(process.cwd(), { isBrandOverride: true });
19
+ const aliases = (0, getLocalAliases_1.default)();
20
+ const resolvedSiteConfigPath = (0, getResolvedSiteConfigPath_1.default)('site.config.build.tsx');
21
+ const config = {
22
+ mode: 'production',
23
+ devtool: 'source-map',
24
+ entry: {
25
+ app: path_1.default.resolve(process.cwd(), 'node_modules/@openedx/frontend-base/shell/site'),
26
+ ...(0, paragonUtils_1.getParagonEntryPoints)(paragonThemeCss),
27
+ ...(0, paragonUtils_1.getParagonEntryPoints)(brandThemeCss),
28
+ },
29
+ output: {
30
+ filename: '[name].[chunkhash].js',
31
+ path: path_1.default.resolve(process.cwd(), 'dist'),
32
+ publicPath: (0, getPublicPath_1.default)(),
33
+ clean: true, // Clean the output directory before emit.
34
+ },
35
+ resolve: {
36
+ alias: {
37
+ ...aliases,
38
+ 'site.config': resolvedSiteConfigPath,
39
+ },
40
+ extensions: ['.js', '.jsx', '.ts', '.tsx'],
41
+ },
42
+ module: {
43
+ rules: [
44
+ ...(0, common_config_1.getCodeRules)('production', resolvedSiteConfigPath),
45
+ (0, common_config_1.getStylesheetRule)('production'),
46
+ ...(0, common_config_1.getFileLoaderRules)(),
47
+ ],
48
+ },
49
+ // Extract common modules among all chunks to one common chunk and extract the Webpack runtime to a single runtime chunk.
50
+ optimization: {
51
+ runtimeChunk: 'single',
52
+ splitChunks: {
53
+ chunks: 'all',
54
+ cacheGroups: {
55
+ ...(0, paragonUtils_1.getParagonCacheGroups)(paragonThemeCss),
56
+ ...(0, paragonUtils_1.getParagonCacheGroups)(brandThemeCss),
57
+ },
58
+ },
59
+ minimizer: (0, common_config_1.getImageMinimizer)(),
60
+ },
61
+ // Specify additional processing or side-effects done on the Webpack output bundles as a whole.
62
+ plugins: [
63
+ // RemoveEmptyScriptsPlugin get rid of empty scripts generated by webpack when using mini-css-extract-plugin
64
+ // This helps to clean up the final bundle application
65
+ // See: https://www.npmjs.com/package/webpack-remove-empty-scripts#usage-with-mini-css-extract-plugin
66
+ new webpack_remove_empty_scripts_1.default(),
67
+ // Writes the extracted CSS from each entry to a file in the output directory.
68
+ new ParagonWebpackPlugin_1.default(),
69
+ new mini_css_extract_plugin_1.default({
70
+ filename: '[name].[chunkhash].css',
71
+ }),
72
+ (0, common_config_1.getHtmlWebpackPlugin)(),
73
+ new fork_ts_checker_webpack_plugin_1.default(),
74
+ new webpack_bundle_analyzer_1.BundleAnalyzerPlugin({
75
+ analyzerMode: 'static',
76
+ openAnalyzer: false,
77
+ }),
78
+ ],
79
+ };
80
+ exports.default = config;
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const react_refresh_webpack_plugin_1 = __importDefault(require("@pmmmwh/react-refresh-webpack-plugin"));
7
+ const fork_ts_checker_webpack_plugin_1 = __importDefault(require("fork-ts-checker-webpack-plugin"));
8
+ const mini_css_extract_plugin_1 = __importDefault(require("mini-css-extract-plugin"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const webpack_remove_empty_scripts_1 = __importDefault(require("webpack-remove-empty-scripts"));
11
+ const common_config_1 = require("./common-config");
12
+ const ParagonWebpackPlugin_1 = __importDefault(require("./plugins/paragon-webpack-plugin/ParagonWebpackPlugin"));
13
+ const getLocalAliases_1 = __importDefault(require("./utils/getLocalAliases"));
14
+ const getPublicPath_1 = __importDefault(require("./utils/getPublicPath"));
15
+ const getResolvedSiteConfigPath_1 = __importDefault(require("./utils/getResolvedSiteConfigPath"));
16
+ const paragonUtils_1 = require("./utils/paragonUtils");
17
+ const paragonThemeCss = (0, paragonUtils_1.getParagonThemeCss)(process.cwd());
18
+ const brandThemeCss = (0, paragonUtils_1.getParagonThemeCss)(process.cwd(), { isBrandOverride: true });
19
+ const aliases = (0, getLocalAliases_1.default)();
20
+ const resolvedSiteConfigPath = (0, getResolvedSiteConfigPath_1.default)('site.config.dev.tsx');
21
+ const config = {
22
+ entry: {
23
+ app: path_1.default.resolve(process.cwd(), 'node_modules/@openedx/frontend-base/shell/site'),
24
+ ...(0, paragonUtils_1.getParagonEntryPoints)(paragonThemeCss),
25
+ ...(0, paragonUtils_1.getParagonEntryPoints)(brandThemeCss),
26
+ },
27
+ output: {
28
+ path: path_1.default.resolve(process.cwd(), './dist'),
29
+ publicPath: (0, getPublicPath_1.default)(),
30
+ },
31
+ resolve: {
32
+ alias: {
33
+ ...aliases,
34
+ 'site.config': resolvedSiteConfigPath,
35
+ },
36
+ extensions: ['.js', '.jsx', '.ts', '.tsx'],
37
+ },
38
+ mode: 'development',
39
+ devtool: 'eval-source-map',
40
+ module: {
41
+ rules: [
42
+ ...(0, common_config_1.getCodeRules)('dev', resolvedSiteConfigPath),
43
+ (0, common_config_1.getStylesheetRule)('dev'),
44
+ ...(0, common_config_1.getFileLoaderRules)(),
45
+ ],
46
+ },
47
+ optimization: {
48
+ splitChunks: {
49
+ chunks: 'all',
50
+ cacheGroups: {
51
+ ...(0, paragonUtils_1.getParagonCacheGroups)(paragonThemeCss),
52
+ ...(0, paragonUtils_1.getParagonCacheGroups)(brandThemeCss),
53
+ },
54
+ },
55
+ minimizer: (0, common_config_1.getImageMinimizer)(),
56
+ },
57
+ // Specify additional processing or side-effects done on the Webpack output bundles as a whole.
58
+ plugins: [
59
+ // RemoveEmptyScriptsPlugin get rid of empty scripts generated by webpack when using mini-css-extract-plugin
60
+ // This helps to clean up the final bundle application
61
+ // See: https://www.npmjs.com/package/webpack-remove-empty-scripts#usage-with-mini-css-extract-plugin
62
+ new webpack_remove_empty_scripts_1.default(),
63
+ new ParagonWebpackPlugin_1.default(),
64
+ // Writes the extracted CSS from each entry to a file in the output directory.
65
+ new mini_css_extract_plugin_1.default({
66
+ filename: '[name].css',
67
+ }),
68
+ (0, common_config_1.getHtmlWebpackPlugin)(),
69
+ new react_refresh_webpack_plugin_1.default(),
70
+ new fork_ts_checker_webpack_plugin_1.default(),
71
+ ],
72
+ // This configures webpack-dev-server which serves bundles from memory and provides live
73
+ // reloading.
74
+ devServer: (0, common_config_1.getDevServer)(),
75
+ };
76
+ exports.default = config;
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const ts_transformer_1 = require("@formatjs/ts-transformer");
7
+ const react_refresh_webpack_plugin_1 = __importDefault(require("@pmmmwh/react-refresh-webpack-plugin"));
8
+ const fork_ts_checker_webpack_plugin_1 = __importDefault(require("fork-ts-checker-webpack-plugin"));
9
+ const mini_css_extract_plugin_1 = __importDefault(require("mini-css-extract-plugin"));
10
+ const path_1 = __importDefault(require("path"));
11
+ const react_refresh_typescript_1 = __importDefault(require("react-refresh-typescript"));
12
+ const webpack_remove_empty_scripts_1 = __importDefault(require("webpack-remove-empty-scripts"));
13
+ const common_config_1 = require("./common-config");
14
+ const ParagonWebpackPlugin_1 = __importDefault(require("./plugins/paragon-webpack-plugin/ParagonWebpackPlugin"));
15
+ const html_webpack_plugin_1 = __importDefault(require("html-webpack-plugin"));
16
+ const getLocalAliases_1 = __importDefault(require("./utils/getLocalAliases"));
17
+ const getPublicPath_1 = __importDefault(require("./utils/getPublicPath"));
18
+ const getResolvedSiteConfigPath_1 = __importDefault(require("./utils/getResolvedSiteConfigPath"));
19
+ const paragonUtils_1 = require("./utils/paragonUtils");
20
+ const paragonThemeCss = (0, paragonUtils_1.getParagonThemeCss)(process.cwd());
21
+ const brandThemeCss = (0, paragonUtils_1.getParagonThemeCss)(process.cwd(), { isBrandOverride: true });
22
+ const aliases = (0, getLocalAliases_1.default)();
23
+ const resolvedSiteConfigPath = (0, getResolvedSiteConfigPath_1.default)('shell/site.config.dev.tsx');
24
+ const config = {
25
+ entry: {
26
+ app: path_1.default.resolve(process.cwd(), 'shell/site'),
27
+ ...(0, paragonUtils_1.getParagonEntryPoints)(paragonThemeCss),
28
+ ...(0, paragonUtils_1.getParagonEntryPoints)(brandThemeCss),
29
+ },
30
+ output: {
31
+ path: path_1.default.resolve(process.cwd(), './dist'),
32
+ publicPath: (0, getPublicPath_1.default)(),
33
+ },
34
+ resolve: {
35
+ alias: {
36
+ ...aliases,
37
+ 'site.config': resolvedSiteConfigPath,
38
+ },
39
+ extensions: ['.js', '.jsx', '.ts', '.tsx'],
40
+ },
41
+ mode: 'development',
42
+ devtool: 'eval-source-map',
43
+ module: {
44
+ rules: [
45
+ {
46
+ test: /\.(js|jsx|ts|tsx)$/,
47
+ include: [
48
+ /shell/,
49
+ /runtime/,
50
+ path_1.default.resolve(process.cwd(), 'types'),
51
+ resolvedSiteConfigPath,
52
+ ],
53
+ use: {
54
+ loader: require.resolve('ts-loader'),
55
+ options: {
56
+ transpileOnly: true,
57
+ compilerOptions: {
58
+ noEmit: false,
59
+ },
60
+ getCustomTransformers() {
61
+ return {
62
+ before: [
63
+ (0, ts_transformer_1.transform)({
64
+ overrideIdFn: '[sha512:contenthash:base64:6]',
65
+ }),
66
+ (0, react_refresh_typescript_1.default)()
67
+ ],
68
+ };
69
+ },
70
+ },
71
+ },
72
+ },
73
+ (0, common_config_1.getStylesheetRule)('dev'),
74
+ ...(0, common_config_1.getFileLoaderRules)(),
75
+ ],
76
+ },
77
+ optimization: {
78
+ splitChunks: {
79
+ chunks: 'all',
80
+ cacheGroups: {
81
+ ...(0, paragonUtils_1.getParagonCacheGroups)(paragonThemeCss),
82
+ ...(0, paragonUtils_1.getParagonCacheGroups)(brandThemeCss),
83
+ },
84
+ },
85
+ minimizer: (0, common_config_1.getImageMinimizer)(),
86
+ },
87
+ // Specify additional processing or side-effects done on the Webpack output bundles as a whole.
88
+ plugins: [
89
+ // RemoveEmptyScriptsPlugin get rid of empty scripts generated by webpack when using mini-css-extract-plugin
90
+ // This helps to clean up the final bundle application
91
+ // See: https://www.npmjs.com/package/webpack-remove-empty-scripts#usage-with-mini-css-extract-plugin
92
+ new webpack_remove_empty_scripts_1.default(),
93
+ new ParagonWebpackPlugin_1.default(),
94
+ // Writes the extracted CSS from each entry to a file in the output directory.
95
+ new mini_css_extract_plugin_1.default({
96
+ filename: '[name].css',
97
+ }),
98
+ new html_webpack_plugin_1.default({
99
+ inject: true, // Appends script tags linking to the webpack bundles at the end of the body
100
+ template: path_1.default.resolve(process.cwd(), 'shell/public/index.html'),
101
+ chunks: ['app'],
102
+ }),
103
+ new react_refresh_webpack_plugin_1.default(),
104
+ new fork_ts_checker_webpack_plugin_1.default(),
105
+ ],
106
+ // This configures webpack-dev-server which serves bundles from memory and provides live
107
+ // reloading.
108
+ devServer: (0, common_config_1.getDevServer)(),
109
+ };
110
+ exports.default = config;
@@ -0,0 +1,18 @@
1
+ // @ts-check
2
+
3
+ const tseslint = require('typescript-eslint');
4
+ const eslintConfig = require('./tools/eslint/base.eslint.config.js');
5
+
6
+ module.exports = tseslint.config(
7
+ {
8
+ extends: eslintConfig,
9
+ },
10
+ {
11
+ ignores: [
12
+ 'tools/*',
13
+ 'test-site/*',
14
+ 'config/*',
15
+ 'docs/*',
16
+ ],
17
+ },
18
+ );
@@ -0,0 +1,8 @@
1
+ declare module 'site.config' {
2
+ export default SiteConfig;
3
+ }
4
+
5
+ declare module '*.svg' {
6
+ const content: string;
7
+ export default content;
8
+ }
package/index.ts ADDED
@@ -0,0 +1,7 @@
1
+ export * from './runtime';
2
+
3
+ export type * from './types';
4
+
5
+ export * from './types';
6
+
7
+ export * from './shell';
package/jest.config.js ADDED
@@ -0,0 +1,7 @@
1
+ module.exports = {
2
+ projects: [
3
+ 'tools',
4
+ 'runtime',
5
+ 'shell',
6
+ ],
7
+ };
Binary file
package/package.json ADDED
@@ -0,0 +1,149 @@
1
+ {
2
+ "name": "@openedx/frontend-base",
3
+ "version": "1.0.0-alpha.0",
4
+ "description": "Build tools, setup and config for frontend apps",
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "main": "index.ts",
9
+ "bin": {
10
+ "intl-imports.js": "tools/dist/cli/scripts/intl-imports.js",
11
+ "openedx": "tools/dist/cli/openedx.js",
12
+ "transifex-utils.js": "tools/dist/cli/scripts/transifex-utils.js"
13
+ },
14
+ "scripts": {
15
+ "build": "make build",
16
+ "clean": "rm -rf dist",
17
+ "dev": "npm run build && node ./tools/dist/cli/openedx.js dev:shell",
18
+ "docs": "jsdoc -c jsdoc.json",
19
+ "docs:watch": "nodemon -w runtime -w docs/template -w README.md -e js,jsx,ts,tsx --exec npm run docs",
20
+ "lint": "eslint .; npm run lint:tools; npm --prefix ./test-site run lint",
21
+ "lint:tools": "cd ./tools && eslint . && cd ..",
22
+ "test": "jest"
23
+ },
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "git+https://github.com/openedx/frontend-base.git"
27
+ },
28
+ "keywords": [],
29
+ "author": "Open edX Community",
30
+ "license": "AGPL-3.0",
31
+ "bugs": {
32
+ "url": "https://github.com/openedx/frontend-base/issues"
33
+ },
34
+ "sideEffects": [
35
+ "*.css",
36
+ "*.scss"
37
+ ],
38
+ "homepage": "https://github.com/openedx/frontend-base#readme",
39
+ "dependencies": {
40
+ "@babel/core": "^7.24.9",
41
+ "@babel/preset-env": "^7.24.8",
42
+ "@babel/preset-react": "^7.26.3",
43
+ "@babel/preset-typescript": "^7.24.7",
44
+ "@edx/new-relic-source-map-webpack-plugin": "2.1.0",
45
+ "@eslint/compat": "^1.2.1",
46
+ "@eslint/js": "^9.13.0",
47
+ "@formatjs/cli": "^6.0.3",
48
+ "@formatjs/ts-transformer": "^3.13.14",
49
+ "@pmmmwh/react-refresh-webpack-plugin": "^0.5.15",
50
+ "@stylistic/eslint-plugin": "^2.9.0",
51
+ "@types/eslint__js": "^8.42.3",
52
+ "@types/gradient-string": "^1.1.6",
53
+ "autoprefixer": "^10.4.20",
54
+ "axios": "^1.7.9",
55
+ "axios-cache-interceptor": "^1.6.0",
56
+ "babel-jest": "^29.7.0",
57
+ "babel-plugin-formatjs": "^10.5.16",
58
+ "chalk": "^4.1.2",
59
+ "classnames": "^2.5.1",
60
+ "clean-webpack-plugin": "^4.0.0",
61
+ "compression": "^1.7.4",
62
+ "css-loader": "^7.1.2",
63
+ "cssnano": "^6.1.2",
64
+ "eslint": "^9.13.0",
65
+ "eslint-plugin-formatjs": "^5.1.3",
66
+ "eslint-plugin-jest": "^28.8.3",
67
+ "eslint-plugin-jsx-a11y": "^6.10.1",
68
+ "eslint-plugin-react": "^7.37.2",
69
+ "eslint-plugin-react-hooks": "^5.0.0",
70
+ "express": "^4.18.2",
71
+ "file-loader": "6.2.0",
72
+ "fork-ts-checker-webpack-plugin": "^9.0.2",
73
+ "form-urlencoded": "^6.1.5",
74
+ "glob": "^7.2.3",
75
+ "globals": "^15.11.0",
76
+ "gradient-string": "^2.0.2",
77
+ "html-webpack-plugin": "5.6.0",
78
+ "identity-obj-proxy": "3.0.0",
79
+ "image-minimizer-webpack-plugin": "3.8.3",
80
+ "jest": "^29.7.0",
81
+ "jest-environment-jsdom": "^29.7.0",
82
+ "jwt-decode": "^3.1.2",
83
+ "localforage": "^1.10.0",
84
+ "localforage-memoryStorageDriver": "^0.9.2",
85
+ "lodash.camelcase": "^4.3.0",
86
+ "lodash.memoize": "^4.1.2",
87
+ "lodash.merge": "^4.6.2",
88
+ "lodash.snakecase": "^4.1.1",
89
+ "mini-css-extract-plugin": "1.6.2",
90
+ "parse5": "7.1.2",
91
+ "postcss": "^8.4.47",
92
+ "postcss-custom-media": "10.0.8",
93
+ "postcss-loader": "7.3.4",
94
+ "postcss-rtlcss": "^5.5.0",
95
+ "prop-types": "^15.8.1",
96
+ "react-dev-utils": "12.0.1",
97
+ "react-focus-on": "^3.9.4",
98
+ "react-intl": "^6.6.6",
99
+ "react-refresh": "0.16.0",
100
+ "react-refresh-typescript": "^2.0.9",
101
+ "react-responsive": "^10.0.0",
102
+ "react-transition-group": "^4.4.5",
103
+ "resolve-url-loader": "^5.0.0",
104
+ "sass-embedded": "^1.87.0",
105
+ "sass-loader": "^16.0.2",
106
+ "sharp": "^0.33.5",
107
+ "source-map-loader": "4.0.2",
108
+ "style-loader": "^4.0.0",
109
+ "ts-loader": "^9.5.1",
110
+ "typescript": "^5.6.3",
111
+ "typescript-eslint": "^8.11.0",
112
+ "universal-cookie": "^8.0.1",
113
+ "url-loader": "^4.1.1",
114
+ "uuid": "^11.0.2",
115
+ "webpack": "^5.97.1",
116
+ "webpack-bundle-analyzer": "^4.10.1",
117
+ "webpack-cli": "^5.1.4",
118
+ "webpack-dev-server": "^5.1.0",
119
+ "webpack-merge": "^5.10.0",
120
+ "webpack-remove-empty-scripts": "1.0.4"
121
+ },
122
+ "devDependencies": {
123
+ "@edx/browserslist-config": "^1.5.0",
124
+ "@testing-library/dom": "^10.4.0",
125
+ "@testing-library/jest-dom": "^6.6.3",
126
+ "@testing-library/react": "^16.3.0",
127
+ "@testing-library/user-event": "^14.6.1",
128
+ "@tsconfig/node20": "^20.1.5",
129
+ "@types/compression": "^1.7.5",
130
+ "@types/jest": "^29.5.14",
131
+ "@types/lodash.camelcase": "^4.3.9",
132
+ "@types/lodash.merge": "^4.6.9",
133
+ "@types/node": "^18.19.43",
134
+ "@types/react": "^18.3.20",
135
+ "@types/react-dom": "^18.3.6",
136
+ "axios-mock-adapter": "^1.22.0",
137
+ "jest-chain": "^1.1.6",
138
+ "jsdoc": "^4.0.3",
139
+ "nodemon": "^3.1.4"
140
+ },
141
+ "peerDependencies": {
142
+ "@openedx/paragon": "^22.20.2",
143
+ "@tanstack/react-query": "^5.81.2",
144
+ "react": "^18.3.1",
145
+ "react-dom": "^18.3.1",
146
+ "react-router": "^6.26.1",
147
+ "react-router-dom": "^6.26.1"
148
+ }
149
+ }
@@ -0,0 +1,71 @@
1
+ /**
2
+ * The MockAnalyticsService implements all functions of AnalyticsService as Jest mocks (jest.fn())).
3
+ * It emulates the behavior of a real analytics service but witohut making any requests. It has no
4
+ * other functionality.
5
+ *
6
+ * @implements {AnalyticsService}
7
+ * @memberof module:Analytics
8
+ */
9
+ class MockAnalyticsService {
10
+ static hasIdentifyBeenCalled = false;
11
+
12
+ constructor({ httpClient, loggingService }) {
13
+ this.loggingService = loggingService;
14
+ this.httpClient = httpClient;
15
+ }
16
+
17
+ checkIdentifyCalled = jest.fn(() => {
18
+ if (!this.hasIdentifyBeenCalled) {
19
+ this.loggingService.logError('Identify must be called before other tracking events.');
20
+ }
21
+ });
22
+
23
+ /**
24
+ * Returns a resolved promise.
25
+ *
26
+ * @returns {Promise} The promise returned by HttpClient.post.
27
+ */
28
+ sendTrackingLogEvent = jest.fn(() => Promise.resolve());
29
+
30
+ /**
31
+ * No-op, but records that identify has been called.
32
+ *
33
+ * @param {string} userId
34
+ * @throws {Error} If userId argument is not supplied.
35
+ */
36
+ identifyAuthenticatedUser = jest.fn((userId) => {
37
+ if (!userId) {
38
+ throw new Error('UserId is required for identifyAuthenticatedUser.');
39
+ }
40
+ this.hasIdentifyBeenCalled = true;
41
+ });
42
+
43
+ /**
44
+ * No-op, but records that it has been called to prevent double-identification.
45
+ * @returns {Promise} A resolved promise.
46
+ */
47
+ identifyAnonymousUser = jest.fn(() => {
48
+ this.hasIdentifyBeenCalled = true;
49
+ return Promise.resolve();
50
+ });
51
+
52
+ /**
53
+ * Logs the event to the console.
54
+ *
55
+ * Checks whether identify has been called, logging an error to the logging service if not.
56
+ */
57
+ sendTrackEvent = jest.fn(() => {
58
+ this.checkIdentifyCalled();
59
+ });
60
+
61
+ /**
62
+ * Logs the event to the console.
63
+ *
64
+ * Checks whether identify has been called, logging an error to the logging service if not.
65
+ */
66
+ sendPageEvent = jest.fn(() => {
67
+ this.checkIdentifyCalled();
68
+ });
69
+ }
70
+
71
+ export default MockAnalyticsService;