@servicetitan/web-components 23.0.0 → 23.2.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 (94) hide show
  1. package/dist/__mocks__/index.d.ts +3 -0
  2. package/dist/__mocks__/index.d.ts.map +1 -0
  3. package/dist/__mocks__/index.js +3 -0
  4. package/dist/__mocks__/index.js.map +1 -0
  5. package/dist/__mocks__/register-component.d.ts +4 -0
  6. package/dist/__mocks__/register-component.d.ts.map +1 -0
  7. package/dist/__mocks__/register-component.js +14 -0
  8. package/dist/__mocks__/register-component.js.map +1 -0
  9. package/dist/__mocks__/test-component.d.ts +3 -0
  10. package/dist/__mocks__/test-component.d.ts.map +1 -0
  11. package/dist/__mocks__/test-component.js +14 -0
  12. package/dist/__mocks__/test-component.js.map +1 -0
  13. package/dist/contexts/tests/mfe-data-context.test.js +1 -1
  14. package/dist/contexts/tests/mfe-data-context.test.js.map +1 -1
  15. package/dist/contexts/tests/mfe-metadata-context.test.js +1 -1
  16. package/dist/contexts/tests/mfe-metadata-context.test.js.map +1 -1
  17. package/dist/loader.d.ts +7 -17
  18. package/dist/loader.d.ts.map +1 -1
  19. package/dist/loader.js +74 -224
  20. package/dist/loader.js.map +1 -1
  21. package/dist/register.d.ts +4 -1
  22. package/dist/register.d.ts.map +1 -1
  23. package/dist/register.js +26 -13
  24. package/dist/register.js.map +1 -1
  25. package/dist/render.d.ts +11 -0
  26. package/dist/render.d.ts.map +1 -0
  27. package/dist/render.js +39 -0
  28. package/dist/render.js.map +1 -0
  29. package/dist/utils/get-bundle-info.d.ts +24 -0
  30. package/dist/utils/get-bundle-info.d.ts.map +1 -0
  31. package/dist/utils/get-bundle-info.js +98 -0
  32. package/dist/utils/get-bundle-info.js.map +1 -0
  33. package/dist/utils/get-entry-points.d.ts +6 -0
  34. package/dist/utils/get-entry-points.d.ts.map +1 -0
  35. package/dist/utils/get-entry-points.js +24 -0
  36. package/dist/utils/get-entry-points.js.map +1 -0
  37. package/dist/{get-mfe-supports-rerendering.d.ts → utils/get-mfe-supports-rerendering.d.ts} +1 -1
  38. package/dist/utils/get-mfe-supports-rerendering.d.ts.map +1 -0
  39. package/dist/utils/get-mfe-supports-rerendering.js.map +1 -0
  40. package/dist/{utils.d.ts → utils/get-version-mismatches.d.ts} +2 -3
  41. package/dist/utils/get-version-mismatches.d.ts.map +1 -0
  42. package/dist/{utils.js → utils/get-version-mismatches.js} +2 -10
  43. package/dist/utils/get-version-mismatches.js.map +1 -0
  44. package/dist/utils/index.d.ts +9 -0
  45. package/dist/utils/index.d.ts.map +1 -0
  46. package/dist/utils/index.js +9 -0
  47. package/dist/utils/index.js.map +1 -0
  48. package/dist/utils/is-versioned-url.d.ts +2 -0
  49. package/dist/utils/is-versioned-url.d.ts.map +1 -0
  50. package/dist/utils/is-versioned-url.js +9 -0
  51. package/dist/utils/is-versioned-url.js.map +1 -0
  52. package/dist/utils/load-scripts.d.ts +3 -0
  53. package/dist/utils/load-scripts.d.ts.map +1 -0
  54. package/dist/utils/load-scripts.js +31 -0
  55. package/dist/utils/load-scripts.js.map +1 -0
  56. package/dist/utils/validate-bundle-info.d.ts +7 -0
  57. package/dist/utils/validate-bundle-info.d.ts.map +1 -0
  58. package/dist/utils/validate-bundle-info.js +10 -0
  59. package/dist/utils/validate-bundle-info.js.map +1 -0
  60. package/dist/utils/web-component.d.ts +17 -0
  61. package/dist/utils/web-component.d.ts.map +1 -0
  62. package/dist/utils/web-component.js +54 -0
  63. package/dist/utils/web-component.js.map +1 -0
  64. package/package.json +17 -18
  65. package/src/__mocks__/index.ts +2 -0
  66. package/src/__mocks__/register-component.tsx +20 -0
  67. package/src/__mocks__/test-component.tsx +30 -0
  68. package/src/__tests__/event-bus.test.ts +3 -2
  69. package/src/__tests__/loader.test.tsx +17 -11
  70. package/src/__tests__/register-legacy-root.test.tsx +36 -0
  71. package/src/__tests__/register.test.tsx +16 -81
  72. package/src/contexts/tests/mfe-data-context.test.tsx +4 -4
  73. package/src/contexts/tests/mfe-metadata-context.test.tsx +4 -4
  74. package/src/loader.tsx +129 -374
  75. package/src/register.tsx +25 -14
  76. package/src/render.ts +62 -0
  77. package/src/{__tests__ → utils/__tests__}/get-mfe-supports-rerendering.test.ts +1 -1
  78. package/src/utils/__tests__/get-version-mismatches.test.ts +76 -0
  79. package/src/utils/__tests__/is-versioned-url.test.ts +18 -0
  80. package/src/utils/get-bundle-info.ts +121 -0
  81. package/src/utils/get-entry-points.ts +23 -0
  82. package/src/{get-mfe-supports-rerendering.ts → utils/get-mfe-supports-rerendering.ts} +1 -1
  83. package/src/{utils.ts → utils/get-version-mismatches.ts} +1 -12
  84. package/src/utils/index.ts +8 -0
  85. package/src/utils/is-versioned-url.ts +11 -0
  86. package/src/utils/load-scripts.ts +38 -0
  87. package/src/utils/validate-bundle-info.ts +15 -0
  88. package/src/utils/web-component.tsx +96 -0
  89. package/dist/get-mfe-supports-rerendering.d.ts.map +0 -1
  90. package/dist/get-mfe-supports-rerendering.js.map +0 -1
  91. package/dist/utils.d.ts.map +0 -1
  92. package/dist/utils.js.map +0 -1
  93. package/src/__tests__/utils.test.ts +0 -95
  94. /package/dist/{get-mfe-supports-rerendering.js → utils/get-mfe-supports-rerendering.js} +0 -0
package/src/render.ts ADDED
@@ -0,0 +1,62 @@
1
+ /* eslint-disable react/no-deprecated */
2
+ import { ReactElement } from 'react';
3
+ import ReactDOM from 'react-dom';
4
+ import type ReactDOMClient from 'react-dom/client';
5
+
6
+ let createRoot: typeof ReactDOMClient.createRoot;
7
+ try {
8
+ /**
9
+ * Note, the webpack.IgnorePlugin must be configured to ignore this dependency.
10
+ * @see {@link file://./../../startup/src/webpack/configs/plugins/ignore-plugin/ignore-plugin.ts}
11
+ */
12
+ createRoot = require('react-dom/client').createRoot;
13
+ } catch (e) {
14
+ // ignore
15
+ }
16
+
17
+ interface RenderOptions {
18
+ legacyRoot?: boolean;
19
+ }
20
+
21
+ interface RenderResult {
22
+ rerender(element: ReactElement): void;
23
+ unmount(): void;
24
+ }
25
+
26
+ export function render(
27
+ element: ReactElement,
28
+ container: Element | DocumentFragment,
29
+ options?: RenderOptions
30
+ ): RenderResult {
31
+ if (typeof createRoot !== 'function' || options?.legacyRoot) {
32
+ return renderLegacyRoot(element, container);
33
+ }
34
+
35
+ const root = createRoot(container);
36
+ root.render(element);
37
+
38
+ return {
39
+ rerender(element: ReactElement) {
40
+ root.render(element);
41
+ },
42
+ unmount() {
43
+ root.unmount();
44
+ },
45
+ };
46
+ }
47
+
48
+ function renderLegacyRoot(
49
+ element: ReactElement,
50
+ container: Element | DocumentFragment
51
+ ): RenderResult {
52
+ ReactDOM.render(element, container);
53
+
54
+ return {
55
+ rerender(element: ReactElement) {
56
+ ReactDOM.render(element, container);
57
+ },
58
+ unmount() {
59
+ ReactDOM.unmountComponentAtNode(container);
60
+ },
61
+ };
62
+ }
@@ -1,5 +1,5 @@
1
1
  import { getMFESupportsRerendering } from '../get-mfe-supports-rerendering';
2
- import { Metadata } from '../loader';
2
+ import { Metadata } from '../get-bundle-info';
3
3
 
4
4
  describe(`[web-components] ${getMFESupportsRerendering.name}`, () => {
5
5
  let metadata: Required<Pick<Metadata, 'bundledWith' | 'dependencies'>>;
@@ -0,0 +1,76 @@
1
+ import { ExposedDependencies } from '../../common';
2
+ import { getVersionMismatches } from '../get-version-mismatches';
3
+
4
+ describe(`[web-components] ${getVersionMismatches.name}`, () => {
5
+ let sharedDependencies: Record<string, string> = {};
6
+ let dependencies: Record<string, string> = {};
7
+ let exposedDependencies: ExposedDependencies = {};
8
+
9
+ beforeEach(() => {
10
+ sharedDependencies = {
11
+ '@servicetitan/design-system': 'SharedDependencies.ServiceTitan.DesignSystem',
12
+ };
13
+
14
+ dependencies = {
15
+ '@servicetitan/design-system': '~11.8.0',
16
+ };
17
+
18
+ exposedDependencies = {
19
+ '@servicetitan/design-system': {
20
+ version: '~11.8.0',
21
+ variable: 'SharedDependencies.ServiceTitan.DesignSystem',
22
+ },
23
+ };
24
+ });
25
+
26
+ test('returns no mismatches', () => {
27
+ expect(getVersionMismatches(exposedDependencies, dependencies, sharedDependencies)).toEqual(
28
+ {}
29
+ );
30
+ });
31
+
32
+ describe('when there is a versions mismatch', () => {
33
+ beforeEach(() => (dependencies['@servicetitan/design-system'] = '~12.0.0'));
34
+
35
+ test('returns one mismatch', () => {
36
+ expect(
37
+ getVersionMismatches(exposedDependencies, dependencies, sharedDependencies)
38
+ ).toEqual({
39
+ '@servicetitan/design-system': {
40
+ host: '~11.8.0',
41
+ package: '~12.0.0',
42
+ },
43
+ });
44
+ });
45
+ });
46
+
47
+ describe('when a dependency is missing from exposed dependencies', () => {
48
+ beforeEach(() => delete exposedDependencies['@servicetitan/design-system']);
49
+
50
+ test('returns an object citing the dependency is missing from the host', () => {
51
+ expect(
52
+ getVersionMismatches(exposedDependencies, dependencies, sharedDependencies)
53
+ ).toEqual({
54
+ '@servicetitan/design-system': {
55
+ host: 'missing',
56
+ package: '~11.8.0',
57
+ },
58
+ });
59
+ });
60
+ });
61
+
62
+ describe('when a variable does not match', () => {
63
+ beforeEach(() => (exposedDependencies['@servicetitan/design-system'].variable = 'foo'));
64
+
65
+ test('returns an object citing the variable is wrong', () => {
66
+ expect(
67
+ getVersionMismatches(exposedDependencies, dependencies, sharedDependencies)
68
+ ).toEqual({
69
+ '@servicetitan/design-system': {
70
+ host: 'wrong global variable',
71
+ package: '~11.8.0',
72
+ },
73
+ });
74
+ });
75
+ });
76
+ });
@@ -0,0 +1,18 @@
1
+ import { isVersionedUrl } from '../is-versioned-url';
2
+
3
+ describe(`${isVersionedUrl.name}`, () => {
4
+ const results: [string, boolean][] = [
5
+ ['localhost:9090', false],
6
+ ['localhost:9090@1.1.1', false],
7
+ ['localhost:9090@dev', false],
8
+ ['//unpkg.servicetitan.com/@servicetitan/test', false],
9
+ ['//unpkg.servicetitan.com/@servicetitan/test@dev', false],
10
+ ['//unpkg.servicetitan.com/@servicetitan/test@0.0.0', true],
11
+ ['//unpkg.servicetitan.com/@servicetitan/test@0.0.0-hash', true],
12
+ ['//unpkg.servicetitan.com/@servicetitan/test@^16', false],
13
+ ];
14
+
15
+ test.each(results)(`providing %s returns %s`, (url, result) => {
16
+ expect(isVersionedUrl(url)).toEqual(result);
17
+ });
18
+ });
@@ -0,0 +1,121 @@
1
+ import semver from 'semver';
2
+ import get from 'lodash.get';
3
+
4
+ import { ExposedDependencies, getJson, GetJsonError } from '../common';
5
+ import { EntryPoints, getEntrypoints } from './get-entry-points';
6
+ import { getMFESupportsRerendering } from './get-mfe-supports-rerendering';
7
+ import { getVersionMismatches } from './get-version-mismatches';
8
+ import { isVersionedUrl } from './is-versioned-url';
9
+
10
+ export interface Metadata {
11
+ name: string;
12
+ bundledWith?: Record<string, string | undefined>;
13
+ sharedDependencies: Record<string, string>;
14
+ dependencies?: Record<string, string>;
15
+ entrypoints?: Record<string, { css: string[]; js: string[] }>;
16
+ }
17
+
18
+ export type BundleInfo = Awaited<ReturnType<typeof getBundleInfo>>;
19
+
20
+ export async function getBundleInfo(
21
+ mainPackageUrl: string,
22
+ fallbackPackageUrl: string | undefined,
23
+ exposedDependencies: ExposedDependencies = {},
24
+ signal?: AbortSignal,
25
+ retries?: number,
26
+ onRequestError?: (error: GetJsonError) => void
27
+ ) {
28
+ const { data: metadata, url: packageUrl } = await getMetadata({
29
+ fallbackPackageUrl,
30
+ mainPackageUrl,
31
+ onRequestError,
32
+ retries,
33
+ signal,
34
+ });
35
+
36
+ const { bundledWith, name, sharedDependencies } = metadata;
37
+ const exactPackageUrl = packageUrl.replace('/dist/metadata.json', '');
38
+ const cache = getCacheSetting(exactPackageUrl);
39
+
40
+ let dependencies: NonNullable<Metadata['dependencies']>;
41
+ if (metadata.dependencies) {
42
+ dependencies = metadata.dependencies;
43
+ } else {
44
+ const { data: packageJson } = await getJson(`${exactPackageUrl}/package.json`, {
45
+ cache,
46
+ retries,
47
+ signal,
48
+ });
49
+
50
+ dependencies = packageJson.dependencies;
51
+ }
52
+
53
+ const mismatch = getVersionMismatches(exposedDependencies, dependencies, sharedDependencies);
54
+ const hasMismatch = !!Object.keys(mismatch).length;
55
+ const startupVersion = bundledWith?.['@servicetitan/startup'];
56
+ const supportLightBundles = startupVersion && semver.gte(startupVersion, '17.0.0');
57
+ const embed = !hasMismatch && supportLightBundles;
58
+ const bundleType = embed ? 'light' : 'full';
59
+ const withBaseUrl = (path: string) => `${exactPackageUrl}/dist/bundle/${bundleType}/${path}`;
60
+
61
+ let entrypoints: EntryPoints;
62
+ if (metadata.entrypoints?.[bundleType]) {
63
+ entrypoints = metadata.entrypoints[bundleType];
64
+ } else {
65
+ entrypoints = await getEntrypoints(withBaseUrl('entrypoints.json'), cache);
66
+ }
67
+
68
+ const disposer = () => {
69
+ if (embed) {
70
+ const path = Object.values<string>(sharedDependencies).shift();
71
+ if (path) {
72
+ get(window, path).getStorage().clear(name);
73
+ }
74
+ }
75
+ };
76
+
77
+ const urls = Object.entries(entrypoints).reduce(
78
+ (result, [key, value]) => ({ ...result, [key]: value.map(withBaseUrl) }),
79
+ {} as EntryPoints
80
+ );
81
+
82
+ return {
83
+ disposer,
84
+ mfeSupportsRerendering: getMFESupportsRerendering(bundledWith, dependencies),
85
+ mismatch: hasMismatch ? mismatch : undefined,
86
+ urls,
87
+ WebComponent: name,
88
+ };
89
+ }
90
+
91
+ async function getMetadata(props: {
92
+ fallbackPackageUrl?: string;
93
+ mainPackageUrl: string;
94
+ onRequestError?: (error: GetJsonError) => void;
95
+ signal?: AbortSignal;
96
+ retries?: number;
97
+ }) {
98
+ const { fallbackPackageUrl, mainPackageUrl, onRequestError, retries, signal } = props;
99
+
100
+ return getJson<Metadata>(`${mainPackageUrl}/dist/metadata.json`, {
101
+ cache: getCacheSetting(mainPackageUrl),
102
+ retries: fallbackPackageUrl ? 0 : retries,
103
+ onRequestError,
104
+ signal,
105
+ }).catch(e => {
106
+ if (!fallbackPackageUrl) {
107
+ throw e;
108
+ }
109
+
110
+ return getJson(`${fallbackPackageUrl}/dist/metadata.json`, {
111
+ retries,
112
+ onRequestError,
113
+ cache: getCacheSetting(fallbackPackageUrl),
114
+ signal,
115
+ });
116
+ });
117
+ }
118
+
119
+ function getCacheSetting(url: string) {
120
+ return isVersionedUrl(url) ? undefined : 'no-store';
121
+ }
@@ -0,0 +1,23 @@
1
+ import { getJson } from '../common';
2
+
3
+ export interface EntryPoints {
4
+ css: string[];
5
+ js: string[];
6
+ }
7
+
8
+ export async function getEntrypoints(
9
+ url: string,
10
+ cache: 'no-store' | undefined,
11
+ signal?: AbortSignal
12
+ ): Promise<EntryPoints> {
13
+ try {
14
+ return (
15
+ await getJson(url, {
16
+ cache,
17
+ signal,
18
+ })
19
+ ).data;
20
+ } catch {
21
+ return { css: ['index.css'], js: ['index.js'] };
22
+ }
23
+ }
@@ -1,5 +1,5 @@
1
1
  import semver from 'semver';
2
- import { Metadata } from './loader';
2
+ import { Metadata } from './get-bundle-info';
3
3
 
4
4
  /*
5
5
  * Check if the MFE supports re-rendering itself when data changes
@@ -1,5 +1,4 @@
1
- import semver from 'semver';
2
- import { ExposedDependencies, isCompatible } from './common';
1
+ import { ExposedDependencies, isCompatible } from '../common';
3
2
 
4
3
  export const getVersionMismatches = (
5
4
  exposedDependencies: ExposedDependencies,
@@ -31,13 +30,3 @@ export const getVersionMismatches = (
31
30
 
32
31
  return mismatch;
33
32
  };
34
-
35
- export const isVersionedUrl = (url: string): boolean => {
36
- if (!url.includes('unpkg.')) {
37
- return false;
38
- }
39
-
40
- const parts = url.split('@');
41
-
42
- return !!semver.clean(parts[parts.length - 1]);
43
- };
@@ -0,0 +1,8 @@
1
+ export * from './get-bundle-info';
2
+ export * from './get-entry-points';
3
+ export * from './get-mfe-supports-rerendering';
4
+ export * from './get-version-mismatches';
5
+ export * from './is-versioned-url';
6
+ export * from './load-scripts';
7
+ export * from './validate-bundle-info';
8
+ export * from './web-component';
@@ -0,0 +1,11 @@
1
+ import semver from 'semver';
2
+
3
+ export const isVersionedUrl = (url: string): boolean => {
4
+ if (!url.includes('unpkg.')) {
5
+ return false;
6
+ }
7
+
8
+ const parts = url.split('@');
9
+
10
+ return !!semver.clean(parts[parts.length - 1]);
11
+ };
@@ -0,0 +1,38 @@
1
+ import { BundleInfo } from './get-bundle-info';
2
+
3
+ export function loadScripts({ urls, WebComponent }: BundleInfo) {
4
+ return Promise.all(
5
+ urls.js.map(url => {
6
+ const script = Array.from(document.scripts).find(({ src }) => src === url);
7
+ if (!script) {
8
+ return new Promise<void>(resolve => {
9
+ const script = document.createElement('script');
10
+
11
+ script.crossOrigin = 'anonymous';
12
+ script.onload = () => {
13
+ script.dataset.webComponent = WebComponent;
14
+ script.onload = null;
15
+ resolve();
16
+ };
17
+ script.async = true;
18
+ script.src = url;
19
+
20
+ document.body.append(script);
21
+ });
22
+ }
23
+
24
+ if (!script.dataset.webComponent) {
25
+ return new Promise<void>(resolve => {
26
+ const originalOnload = script.onload;
27
+ script.onload = (...args) => {
28
+ originalOnload?.call(script, ...args);
29
+ script.onload = null;
30
+ resolve();
31
+ };
32
+ });
33
+ }
34
+
35
+ return Promise.resolve();
36
+ })
37
+ );
38
+ }
@@ -0,0 +1,15 @@
1
+ import { Log } from '@servicetitan/log-service';
2
+ import { BundleInfo } from './get-bundle-info';
3
+
4
+ export function validateBundleInfo(
5
+ { mismatch }: BundleInfo,
6
+ { logService, packageName }: { logService?: Log; packageName: string }
7
+ ) {
8
+ if (mismatch) {
9
+ logService?.warning({
10
+ category: 'MicroFrontends.DependenciesMismatch',
11
+ message: 'Some of the package dependencies have incompatible versions.',
12
+ data: { package: packageName, dependencies: JSON.stringify(mismatch) },
13
+ });
14
+ }
15
+ }
@@ -0,0 +1,96 @@
1
+ import { Fragment, useMemo, useState } from 'react';
2
+ import { Log } from '@servicetitan/log-service';
3
+ import { useOptionalDependencies } from '@servicetitan/react-ioc';
4
+
5
+ import { ExposedDependencies, IWebComponent } from '../common';
6
+ import { MFEContextData } from '../contexts/mfe-data-context';
7
+ import { EventBus } from '../event-bus';
8
+ import { BundleInfo } from './get-bundle-info';
9
+ import { HistoryManager } from '../history-manager';
10
+ import { LoaderDataProps } from '../loader';
11
+
12
+ interface WebComponentProps {
13
+ basename?: string;
14
+ bundleInfo: BundleInfo;
15
+ eventBus: EventBus;
16
+ exposedDependencies?: ExposedDependencies;
17
+ logService?: Log;
18
+ LoadingFallback: () => JSX.Element;
19
+ }
20
+
21
+ export function webComponent(props: WebComponentProps) {
22
+ const { basename, bundleInfo, eventBus, exposedDependencies, logService, LoadingFallback } =
23
+ props;
24
+ const { WebComponent, disposer, mfeSupportsRerendering } = bundleInfo;
25
+
26
+ return (props: LoaderDataProps) => {
27
+ const [isLoading, setIsLoading] = useState(true);
28
+ const [historyManager] = useOptionalDependencies(HistoryManager);
29
+
30
+ const handleRef = (webComponent: IWebComponent | null) => {
31
+ webComponent?.provide({
32
+ logService,
33
+ historyManager,
34
+ exposedDependencies,
35
+ eventBus,
36
+ basename,
37
+ onReady: () => {
38
+ setIsLoading(false);
39
+ },
40
+ onDispose: () => {
41
+ disposer();
42
+ },
43
+ });
44
+ };
45
+
46
+ const stringifiedData = useMemo(() => JSON.stringify(props.data), [props.data]);
47
+
48
+ /*
49
+ * Set key for rendering the web component so that if the data from the Host change,
50
+ * and the MFE's version of startup doesn't support watching for data changes, then
51
+ * the web component will be re-mounted whenever the data changes.
52
+ * This is only used as a fallback when the MFE's version is older.
53
+ */
54
+ const key = mfeSupportsRerendering ? undefined : stringifiedData;
55
+ const dataAttrs = useMemo(() => composeDataAttributes(props.data), [props.data]);
56
+ const styleUrls = getStyleUrls(bundleInfo);
57
+
58
+ return (
59
+ <Fragment>
60
+ {isLoading && <LoadingFallback />}
61
+ <WebComponent
62
+ key={key}
63
+ ref={handleRef}
64
+ class={props.className}
65
+ {...(styleUrls && { 'style-urls': styleUrls })}
66
+ /*
67
+ * Continue to spread data as separate data attributes for backwards compatibility,
68
+ * in case the Host has updated web-components, but the MFE has not
69
+ */
70
+ {...dataAttrs}
71
+ // Stringify data object so that it can be passed as a data-attribute
72
+ data-mfe-data={stringifiedData}
73
+ />
74
+ </Fragment>
75
+ );
76
+ };
77
+ }
78
+
79
+ /*
80
+ * Convert camelCase data props to kebab-case data attributes, prepended with data-
81
+ * Ex: fooBar -> data-foo-bar
82
+ */
83
+ function composeDataAttributes(data: MFEContextData<{}> | undefined = {}) {
84
+ return Object.fromEntries(
85
+ Object.entries(data).map(([key, value]) => [
86
+ 'data-' + key.replace(/[A-Z]/g, letter => '-' + letter.toLowerCase()),
87
+ value,
88
+ ])
89
+ );
90
+ }
91
+
92
+ function getStyleUrls({ urls }: Pick<BundleInfo, 'urls'>) {
93
+ if (urls.css.length) {
94
+ return encodeURIComponent(JSON.stringify(urls.css));
95
+ }
96
+ }
@@ -1 +0,0 @@
1
- {"version":3,"file":"get-mfe-supports-rerendering.d.ts","sourceRoot":"","sources":["../src/get-mfe-supports-rerendering.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAYpC,wBAAgB,yBAAyB,CACrC,WAAW,EAAE,QAAQ,CAAC,aAAa,CAAC,EACpC,YAAY,EAAE,QAAQ,CAAC,cAAc,CAAC,WAOzC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"get-mfe-supports-rerendering.js","sourceRoot":"","sources":["../src/get-mfe-supports-rerendering.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAG5B;;;;;;;;;GASG;AACH,MAAM,UAAU,yBAAyB,CACrC,WAAoC,EACpC,YAAsC;;IAEtC,OAAO,CAAC,CAAC,CACL,MAAA,MAAA,kBAAkB,CAAC,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAG,8BAA8B,CAAC,CAAC,mCACjE,kBAAkB,CAAC,YAAY,aAAZ,YAAY,uBAAZ,YAAY,CAAG,8BAA8B,CAAC,CAAC,mCAClE,kBAAkB,CAAC,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAG,uBAAuB,CAAC,CAAC,CAC7D,CAAC;AACN,CAAC;AAED,SAAS,kBAAkB,CAAC,OAAgB;IACxC,MAAM,UAAU,GAAG,OAAO,IAAI,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IACzD,IAAI,UAAU,EAAE;QACZ,OAAO,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;KAC5C;AACL,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAgB,MAAM,UAAU,CAAC;AAE7D,eAAO,MAAM,oBAAoB,wBACR,mBAAmB,gBAC1B,OAAO,MAAM,EAAE,MAAM,CAAC,sBAChB,OAAO,MAAM,EAAE,MAAM,CAAC;UAYT,MAAM;aAAW,MAAM;EAc3D,CAAC;AAEF,eAAO,MAAM,cAAc,QAAS,MAAM,KAAG,OAQ5C,CAAC"}
package/dist/utils.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAuB,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7D,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAChC,mBAAwC,EACxC,YAAoC,EACpC,kBAA0C,EAC5C,EAAE;IACA,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC,MAAM,CACvD,CAAC,MAAM,EAAE,CAAC,UAAU,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,EAAE,EAAE;QAC/C,MAAM,cAAc,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;QAEhD,IAAI,cAAc,IAAI,CAAC,YAAY,CAAC,WAAW,EAAE,cAAc,CAAC,EAAE;YAC9D,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC;SACvE;QAED,OAAO,MAAM,CAAC;IAClB,CAAC,EACD,EAAuD,CAC1D,CAAC;IAEF,KAAK,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,kBAAkB,CAAC,EAAE;QACrE,MAAM,cAAc,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;QAEhD,IAAI,CAAC,mBAAmB,CAAC,UAAU,CAAC,EAAE;YAClC,QAAQ,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC;SACvE;aAAM,IAAI,mBAAmB,CAAC,UAAU,CAAC,CAAC,QAAQ,KAAK,QAAQ,EAAE;YAC9D,QAAQ,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,EAAE,uBAAuB,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC;SACrF;KACJ;IAED,OAAO,QAAQ,CAAC;AACpB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,GAAW,EAAW,EAAE;IACnD,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE;QACzB,OAAO,KAAK,CAAC;KAChB;IAED,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAE7B,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;AACnD,CAAC,CAAC"}
@@ -1,95 +0,0 @@
1
- import { ExposedDependencies } from '../common';
2
- import { getVersionMismatches, isVersionedUrl } from '../utils';
3
-
4
- describe('[web-components] utils', () => {
5
- describe(`${getVersionMismatches.name}`, () => {
6
- let sharedDependencies: Record<string, string> = {};
7
- let dependencies: Record<string, string> = {};
8
- let exposedDependencies: ExposedDependencies = {};
9
-
10
- beforeEach(() => {
11
- sharedDependencies = {
12
- '@servicetitan/design-system': 'SharedDependencies.ServiceTitan.DesignSystem',
13
- };
14
-
15
- dependencies = {
16
- '@servicetitan/design-system': '~11.8.0',
17
- };
18
-
19
- exposedDependencies = {
20
- '@servicetitan/design-system': {
21
- version: '~11.8.0',
22
- variable: 'SharedDependencies.ServiceTitan.DesignSystem',
23
- },
24
- };
25
- });
26
-
27
- test('returns no mismatches', () => {
28
- expect(
29
- getVersionMismatches(exposedDependencies, dependencies, sharedDependencies)
30
- ).toEqual({});
31
- });
32
-
33
- describe('when there is a versions mismatch', () => {
34
- beforeEach(() => (dependencies['@servicetitan/design-system'] = '~12.0.0'));
35
-
36
- test('returns one mismatch', () => {
37
- expect(
38
- getVersionMismatches(exposedDependencies, dependencies, sharedDependencies)
39
- ).toEqual({
40
- '@servicetitan/design-system': {
41
- host: '~11.8.0',
42
- package: '~12.0.0',
43
- },
44
- });
45
- });
46
- });
47
-
48
- describe('when a dependency is missing from exposed dependencies', () => {
49
- beforeEach(() => delete exposedDependencies['@servicetitan/design-system']);
50
-
51
- test('returns an object citing the dependency is missing from the host', () => {
52
- expect(
53
- getVersionMismatches(exposedDependencies, dependencies, sharedDependencies)
54
- ).toEqual({
55
- '@servicetitan/design-system': {
56
- host: 'missing',
57
- package: '~11.8.0',
58
- },
59
- });
60
- });
61
- });
62
-
63
- describe('when a variable does not match', () => {
64
- beforeEach(() => (exposedDependencies['@servicetitan/design-system'].variable = 'foo'));
65
-
66
- test('returns an object citing the variable is wrong', () => {
67
- expect(
68
- getVersionMismatches(exposedDependencies, dependencies, sharedDependencies)
69
- ).toEqual({
70
- '@servicetitan/design-system': {
71
- host: 'wrong global variable',
72
- package: '~11.8.0',
73
- },
74
- });
75
- });
76
- });
77
- });
78
-
79
- describe(`${isVersionedUrl.name}`, () => {
80
- const results: [string, boolean][] = [
81
- ['localhost:9090', false],
82
- ['localhost:9090@1.1.1', false],
83
- ['localhost:9090@dev', false],
84
- ['//unpkg.servicetitan.com/@servicetitan/test', false],
85
- ['//unpkg.servicetitan.com/@servicetitan/test@dev', false],
86
- ['//unpkg.servicetitan.com/@servicetitan/test@0.0.0', true],
87
- ['//unpkg.servicetitan.com/@servicetitan/test@0.0.0-hash', true],
88
- ['//unpkg.servicetitan.com/@servicetitan/test@^16', false],
89
- ];
90
-
91
- test.each(results)(`providing %s returns %s`, (url, result) => {
92
- expect(isVersionedUrl(url)).toEqual(result);
93
- });
94
- });
95
- });