@lwrjs/shared-utils 0.11.0-alpha.4 → 0.11.0-alpha.6

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.
package/build/cjs/env.cjs CHANGED
@@ -16,6 +16,7 @@ function getFeatureFlags() {
16
16
  LEGACY_LOADER: process.env.LEGACY_LOADER !== void 0 && process.env.LEGACY_LOADER.toLowerCase() === "true" ? true : false,
17
17
  SSR_SANDBOX_WORKER: process.env.SSR_SANDBOX_WORKER !== void 0 && process.env.SSR_SANDBOX_WORKER.toLowerCase() === "true" ? true : false,
18
18
  SSR_STATIC_BUNDLES: process.env.SSR_STATIC_BUNDLES !== void 0 && process.env.SSR_STATIC_BUNDLES.toLowerCase() === "true" ? true : false,
19
+ SSR_WITH_CSR_FALLBACK: process.env.SSR_WITH_CSR_FALLBACK !== void 0 && process.env.SSR_WITH_CSR_FALLBACK.toLowerCase() === "true" ? true : false,
19
20
  EXPERIMENTAL_UNVERSIONED_ALIASES: process.env.EXPERIMENTAL_UNVERSIONED_ALIASES !== void 0 && process.env.EXPERIMENTAL_UNVERSIONED_ALIASES.toLowerCase() === "true" ? true : false,
20
21
  LWR_TRACING: process.env.LWR_TRACING !== void 0 && process.env.LWR_TRACING.toLowerCase() !== "off" ? true : false
21
22
  };
package/build/cjs/fs.cjs CHANGED
@@ -75,6 +75,9 @@ function resolveFileExtension(filePath) {
75
75
  }
76
76
  }
77
77
  function canResolveView(source, type) {
78
+ if (typeof source !== "string") {
79
+ return false;
80
+ }
78
81
  if (!source.endsWith(`.${type}`)) {
79
82
  return false;
80
83
  }
@@ -61,13 +61,16 @@ function isSelfUrl(url) {
61
61
  return !url || !!url.match(isSelfUrlRegex);
62
62
  }
63
63
  var isSelfUrlRegex = /^\s*(data:|#)/i;
64
- async function extractMetadataFromHtml(htmlSource) {
64
+ function hasHydrationDirective(attrs = {}) {
65
+ return Object.keys(attrs).some((attr) => attr === HYDRATE_DIRECTIVE);
66
+ }
67
+ async function extractMetadataFromHtml(htmlSource, viewMetadata) {
68
+ const {customElements, assetReferences, serverData} = viewMetadata;
65
69
  return new Promise((resolve, reject) => {
66
- const customElements = [];
67
70
  const openElements = new Set();
68
- const assetReferences = [];
69
71
  const parser = new import_parse5_sax_parser.default({sourceCodeLocationInfo: true});
70
72
  const ceRefStack = [];
73
+ let nestedIslands = false;
71
74
  parser.on("startTag", ({
72
75
  tagName,
73
76
  attrs,
@@ -75,23 +78,23 @@ async function extractMetadataFromHtml(htmlSource) {
75
78
  }) => {
76
79
  if (tagName.includes("-") && !openElements.has(tagName)) {
77
80
  const {startOffset, endOffset} = sourceCodeLocation;
78
- const ceRef = {
79
- tagName,
80
- location: {startOffset, endOffset},
81
- props: attrs.length ? attrs.reduce((obj, {name, value}) => {
82
- obj[(0, import_identity.getPropFromAttrName)(name)] = value === "" ? "true" : value;
83
- return obj;
84
- }, {}) : void 0
85
- };
81
+ const props = attrs.length ? attrs.reduce((obj, {name, value}) => {
82
+ obj[(0, import_identity.getPropFromAttrName)(name)] = value === "" ? "true" : value;
83
+ return obj;
84
+ }, {}) : void 0;
85
+ const ceRef = {tagName, location: {startOffset, endOffset}, props};
86
86
  openElements.add(tagName);
87
87
  if (ceRefStack.length) {
88
88
  const last = ceRefStack[ceRefStack.length - 1];
89
89
  last.children = last.children ? [...last.children, ceRef] : [ceRef];
90
- ceRefStack.push(ceRef);
90
+ if (hasHydrationDirective(props)) {
91
+ customElements.push(ceRef);
92
+ nestedIslands = true;
93
+ }
91
94
  } else {
92
95
  customElements.push(ceRef);
93
- ceRefStack.push(ceRef);
94
96
  }
97
+ ceRefStack.push(ceRef);
95
98
  }
96
99
  if ((tagName === "img" || tagName === "script") && sourceCodeLocation.attrs) {
97
100
  if (sourceCodeLocation.attrs.src) {
@@ -118,7 +121,11 @@ async function extractMetadataFromHtml(htmlSource) {
118
121
  }
119
122
  });
120
123
  const inputStream = import_stream.Readable.from(htmlSource);
121
- inputStream.on("end", () => resolve({customElements, assetReferences}));
124
+ inputStream.on("end", () => resolve({
125
+ customElements: customElements.filter((ce) => !nestedIslands || hasHydrationDirective(ce.props)),
126
+ assetReferences,
127
+ serverData
128
+ }));
122
129
  inputStream.on("error", (error) => reject(error));
123
130
  inputStream.pipe(parser);
124
131
  });
@@ -47,6 +47,7 @@ __export(exports, {
47
47
  isAssetSourceExternal: () => isAssetSourceExternal,
48
48
  isBundleDefinition: () => isBundleDefinition,
49
49
  isExternalUrl: () => isExternalUrl,
50
+ isSpecifier: () => isSpecifier,
50
51
  kebabCaseToModuleSpecifier: () => kebabCaseToModuleSpecifier,
51
52
  moduleSpecifierToKebabCase: () => moduleSpecifierToKebabCase,
52
53
  normalizeVersionFromUri: () => normalizeVersionFromUri,
@@ -132,6 +133,9 @@ async function getVersionedModuleId(rawSpecifier, moduleRegistry, runtimeParams)
132
133
  const moduleEntry = await moduleRegistry.getModuleEntry(moduleId, runtimeParams);
133
134
  return {...moduleId, version: moduleEntry.version};
134
135
  }
136
+ function isSpecifier(specifier) {
137
+ return !!specifier && /^@?[\w-]+(\/[\w-]+)*$/.test(specifier);
138
+ }
135
139
  var RE_SCOPED = /^(@[^/]+\/[^/@]+)(?:\/([^@]+))?(?:@([\s\S]+))?/;
136
140
  var RE_NORMAL = /^([^/@]+)(?:\/([^@]+))?(?:@([\s\S]+))?/;
137
141
  function parsePackageSpecifier(specifier) {
@@ -1,54 +1,16 @@
1
- var __create = Object.create;
2
1
  var __defProp = Object.defineProperty;
3
- var __getProtoOf = Object.getPrototypeOf;
4
- var __hasOwnProp = Object.prototype.hasOwnProperty;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
7
2
  var __markAsModule = (target) => __defProp(target, "__esModule", {value: true});
8
3
  var __export = (target, all) => {
9
4
  for (var name in all)
10
5
  __defProp(target, name, {get: all[name], enumerable: true});
11
6
  };
12
- var __exportStar = (target, module2, desc) => {
13
- if (module2 && typeof module2 === "object" || typeof module2 === "function") {
14
- for (let key of __getOwnPropNames(module2))
15
- if (!__hasOwnProp.call(target, key) && key !== "default")
16
- __defProp(target, key, {get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable});
17
- }
18
- return target;
19
- };
20
- var __toModule = (module2) => {
21
- return __exportStar(__markAsModule(__defProp(module2 != null ? __create(__getProtoOf(module2)) : {}, "default", module2 && module2.__esModule && "default" in module2 ? {get: () => module2.default, enumerable: true} : {value: module2, enumerable: true})), module2);
22
- };
23
7
 
24
8
  // packages/@lwrjs/shared-utils/src/localization.ts
25
9
  __markAsModule(exports);
26
10
  __export(exports, {
27
- hasCountryCode: () => hasCountryCode,
28
- stripCountryCode: () => stripCountryCode
11
+ getFallbackLocale: () => getFallbackLocale
29
12
  });
30
- var import_logger = __toModule(require("./logger.cjs"));
31
- function hasCountryCode(locale) {
32
- try {
33
- const parsedLocale = new Intl.Locale(resolveLocaleId(locale));
34
- return typeof parsedLocale.region === "string";
35
- } catch (error) {
36
- import_logger.logger.debug(`[static-util] Failed to parse country code from locale: ${locale}`, error);
37
- return false;
38
- }
39
- }
40
- function stripCountryCode(locale) {
41
- try {
42
- const parsedLocale = new Intl.Locale(resolveLocaleId(locale));
43
- return parsedLocale.language;
44
- } catch (error) {
45
- import_logger.logger.debug(`[static-util] Failed to strip country code from locale: ${locale}`, error);
46
- }
47
- }
48
- function resolveLocaleId(locale) {
49
- const asLocalObj = locale;
50
- if (asLocalObj.id !== void 0) {
51
- return asLocalObj.id;
52
- }
53
- return locale;
13
+ function getFallbackLocale(localeId, i18n) {
14
+ const locale = i18n.locales.find((l) => l.id === localeId);
15
+ return locale?.fallback;
54
16
  }
@@ -23,7 +23,10 @@ function _deepFreeze(obj, maxDepth, depth) {
23
23
  }
24
24
  }
25
25
  function deepFreeze(obj, maxDepth = 5) {
26
- const objClone = JSON.parse(JSON.stringify(obj));
26
+ let objClone = obj;
27
+ if (process.env.UNSAFE_IGNORE_CONFIG_VALIDATION !== "true") {
28
+ objClone = JSON.parse(JSON.stringify(obj));
29
+ }
27
30
  return _deepFreeze(objClone, maxDepth, 0);
28
31
  }
29
32
  var debounce = (func, waitFor) => {
package/build/es/env.js CHANGED
@@ -20,6 +20,11 @@ export function getFeatureFlags() {
20
20
  process.env.SSR_STATIC_BUNDLES.toLowerCase() === 'true'
21
21
  ? true
22
22
  : false,
23
+ // Islands fallback to CSR if SSR fails
24
+ SSR_WITH_CSR_FALLBACK: process.env.SSR_WITH_CSR_FALLBACK !== undefined &&
25
+ process.env.SSR_WITH_CSR_FALLBACK.toLowerCase() === 'true'
26
+ ? true
27
+ : false,
23
28
  // AMD Module Bundles include un-versioned aliases
24
29
  EXPERIMENTAL_UNVERSIONED_ALIASES: process.env.EXPERIMENTAL_UNVERSIONED_ALIASES !== undefined &&
25
30
  process.env.EXPERIMENTAL_UNVERSIONED_ALIASES.toLowerCase() === 'true'
package/build/es/fs.d.ts CHANGED
@@ -21,10 +21,10 @@ export declare function resolveFileExtension(filePath: string): string;
21
21
  /**
22
22
  * Returns if view of specific type can be resolved
23
23
  *
24
- * @param source - path to view
24
+ * @param source - possible path to view
25
25
  * @param type - extension of file that should be expected, i.e. 'html'
26
26
  */
27
- export declare function canResolveView(source: string, type: string): boolean;
27
+ export declare function canResolveView(source: unknown, type: string): boolean;
28
28
  /**
29
29
  * Construct a ViewSource from the associated file on the fs
30
30
  * @param source - Filepath with the source (source can be an absolute or relative path)
package/build/es/fs.js CHANGED
@@ -57,10 +57,13 @@ export function resolveFileExtension(filePath) {
57
57
  /**
58
58
  * Returns if view of specific type can be resolved
59
59
  *
60
- * @param source - path to view
60
+ * @param source - possible path to view
61
61
  * @param type - extension of file that should be expected, i.e. 'html'
62
62
  */
63
63
  export function canResolveView(source, type) {
64
+ if (typeof source !== 'string') {
65
+ return false;
66
+ }
64
67
  if (!source.endsWith(`.${type}`)) {
65
68
  return false;
66
69
  }
@@ -5,7 +5,7 @@ export declare function isSelfUrl(url: string): boolean;
5
5
  * Pull the custom elements and img tags out of an HTML string, to use as metadata
6
6
  * @param htmlSource - An HTML string to parse
7
7
  */
8
- export declare function extractMetadataFromHtml(htmlSource: string): Promise<RenderedViewMetadata>;
8
+ export declare function extractMetadataFromHtml(htmlSource: string, viewMetadata: RenderedViewMetadata): Promise<RenderedViewMetadata>;
9
9
  export declare const HYDRATE_DIRECTIVE = "lwr:hydrate";
10
10
  export declare const HYDRATE_LOAD_VALUE = "load";
11
11
  export declare const HYDRATE_CLIENT_VALUE = "client-only";
@@ -29,46 +29,51 @@ export function isSelfUrl(url) {
29
29
  return !url || !!url.match(isSelfUrlRegex);
30
30
  }
31
31
  const isSelfUrlRegex = /^\s*(data:|#)/i;
32
+ function hasHydrationDirective(attrs = {}) {
33
+ return Object.keys(attrs).some((attr) => attr === HYDRATE_DIRECTIVE);
34
+ }
32
35
  /**
33
36
  * Pull the custom elements and img tags out of an HTML string, to use as metadata
34
37
  * @param htmlSource - An HTML string to parse
35
38
  */
36
- export async function extractMetadataFromHtml(htmlSource) {
39
+ export async function extractMetadataFromHtml(htmlSource, viewMetadata) {
40
+ const { customElements, assetReferences, serverData } = viewMetadata;
37
41
  return new Promise((resolve, reject) => {
38
- const customElements = [];
39
42
  const openElements = new Set();
40
- const assetReferences = [];
41
43
  const parser = new SAXParser({ sourceCodeLocationInfo: true }); // TODO: Would we need this in the future?
42
44
  const ceRefStack = [];
45
+ let nestedIslands = false;
43
46
  parser.on('startTag', ({ tagName, attrs, // attributes are passed into SSR
44
47
  sourceCodeLocation, }) => {
45
48
  // custom elements
46
49
  if (tagName.includes('-') && !openElements.has(tagName)) {
47
50
  const { startOffset, endOffset } = sourceCodeLocation;
48
- const ceRef = {
49
- tagName,
50
- location: { startOffset, endOffset },
51
- // transform attributes [{ name: 'some-attr', value: 'the value' }] into properties { someAttr: 'the value' }
52
- // leave props as undefined if there are no attributes
53
- // set boolean attribute values to "true", or lwc will see them as falsy
54
- props: attrs.length
55
- ? attrs.reduce((obj, { name, value }) => {
56
- obj[getPropFromAttrName(name)] = value === '' ? 'true' : value;
57
- return obj;
58
- }, {})
59
- : undefined,
60
- };
51
+ // transform attributes [{ name: 'some-attr', value: 'the value' }] into properties { someAttr: 'the value' }
52
+ // leave props as undefined if there are no attributes
53
+ // set boolean attribute values to "true", or lwc will see them as falsy
54
+ const props = attrs.length
55
+ ? attrs.reduce((obj, { name, value }) => {
56
+ obj[getPropFromAttrName(name)] = value === '' ? 'true' : value;
57
+ return obj;
58
+ }, {})
59
+ : undefined;
60
+ const ceRef = { tagName, location: { startOffset, endOffset }, props };
61
61
  openElements.add(tagName);
62
62
  if (ceRefStack.length) {
63
63
  // nested CE
64
64
  const last = ceRefStack[ceRefStack.length - 1];
65
65
  last.children = last.children ? [...last.children, ceRef] : [ceRef];
66
- ceRefStack.push(ceRef);
66
+ // nested CEs are collected if they have a hydration directive
67
+ if (hasHydrationDirective(props)) {
68
+ customElements.push(ceRef);
69
+ nestedIslands = true;
70
+ }
67
71
  }
68
72
  else {
73
+ // collect all top-level CEs
69
74
  customElements.push(ceRef);
70
- ceRefStack.push(ceRef);
71
75
  }
76
+ ceRefStack.push(ceRef);
72
77
  }
73
78
  // <img src="asset-url"/>
74
79
  // <script type="text/javascript" src="asset-url"></script>
@@ -99,8 +104,13 @@ export async function extractMetadataFromHtml(htmlSource) {
99
104
  }
100
105
  });
101
106
  const inputStream = Readable.from(htmlSource);
102
- // dedupe custom element references
103
- inputStream.on('end', () => resolve({ customElements, assetReferences }));
107
+ // If nested islands are found, ONLY collect custom elements with the hydration directive
108
+ // Otherwise, just collect top-level custom elements (ie: root components) as usual
109
+ inputStream.on('end', () => resolve({
110
+ customElements: customElements.filter((ce) => !nestedIslands || hasHydrationDirective(ce.props)),
111
+ assetReferences,
112
+ serverData,
113
+ }));
104
114
  inputStream.on('error', (error) => reject(error));
105
115
  inputStream.pipe(parser);
106
116
  });
@@ -82,6 +82,7 @@ interface VersionedAbstractModuleId extends AbstractModuleId {
82
82
  * @example - 'c/form/v/0_0_2' => {specifier: "c/form", version: "0.0.2"}
83
83
  */
84
84
  export declare function getVersionedModuleId(rawSpecifier: string, moduleRegistry: PublicModuleRegistry, runtimeParams: RuntimeParams): Promise<VersionedAbstractModuleId>;
85
+ export declare function isSpecifier(specifier?: string): boolean;
85
86
  interface PackageIdentity {
86
87
  scope?: string;
87
88
  packageName: string;
@@ -129,6 +129,9 @@ export async function getVersionedModuleId(rawSpecifier, moduleRegistry, runtime
129
129
  const moduleEntry = await moduleRegistry.getModuleEntry(moduleId, runtimeParams);
130
130
  return { ...moduleId, version: moduleEntry.version };
131
131
  }
132
+ export function isSpecifier(specifier) {
133
+ return !!specifier && /^@?[\w-]+(\/[\w-]+)*$/.test(specifier);
134
+ }
132
135
  const RE_SCOPED = /^(@[^/]+\/[^/@]+)(?:\/([^@]+))?(?:@([\s\S]+))?/;
133
136
  const RE_NORMAL = /^([^/@]+)(?:\/([^@]+))?(?:@([\s\S]+))?/;
134
137
  /**
@@ -1,4 +1,3 @@
1
- import type { Locale } from '@lwrjs/types';
2
- export declare function hasCountryCode(locale: Locale | string): boolean;
3
- export declare function stripCountryCode(locale: Locale | string): string | undefined;
1
+ import type { I18NConfig } from '@lwrjs/types';
2
+ export declare function getFallbackLocale(localeId: string, i18n: I18NConfig): string | undefined;
4
3
  //# sourceMappingURL=localization.d.ts.map
@@ -1,29 +1,6 @@
1
- import { logger } from './logger.js';
2
1
  // Utilities for working with localized content
3
- export function hasCountryCode(locale) {
4
- try {
5
- const parsedLocale = new Intl.Locale(resolveLocaleId(locale));
6
- return typeof parsedLocale.region === 'string';
7
- }
8
- catch (error) {
9
- logger.debug(`[static-util] Failed to parse country code from locale: ${locale}`, error);
10
- return false; // Invalid locale format
11
- }
12
- }
13
- export function stripCountryCode(locale) {
14
- try {
15
- const parsedLocale = new Intl.Locale(resolveLocaleId(locale));
16
- return parsedLocale.language;
17
- }
18
- catch (error) {
19
- logger.debug(`[static-util] Failed to strip country code from locale: ${locale}`, error);
20
- }
21
- }
22
- function resolveLocaleId(locale) {
23
- const asLocalObj = locale;
24
- if (asLocalObj.id !== undefined) {
25
- return asLocalObj.id;
26
- }
27
- return locale;
2
+ export function getFallbackLocale(localeId, i18n) {
3
+ const locale = i18n.locales.find((l) => l.id === localeId);
4
+ return locale?.fallback;
28
5
  }
29
6
  //# sourceMappingURL=localization.js.map
@@ -18,7 +18,12 @@ function _deepFreeze(obj, maxDepth, depth) {
18
18
  */
19
19
  // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
20
20
  export function deepFreeze(obj, maxDepth = 5) {
21
- const objClone = JSON.parse(JSON.stringify(obj));
21
+ let objClone = obj;
22
+ // Temporary fix for W-13723739 to prevent out of memory exceptions
23
+ // Only clone the object if we don't have the env variable set
24
+ if (process.env.UNSAFE_IGNORE_CONFIG_VALIDATION !== 'true') {
25
+ objClone = JSON.parse(JSON.stringify(obj));
26
+ }
22
27
  return _deepFreeze(objClone, maxDepth, 0);
23
28
  }
24
29
  /**
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
- "version": "0.11.0-alpha.4",
7
+ "version": "0.11.0-alpha.6",
8
8
  "homepage": "https://developer.salesforce.com/docs/platform/lwr/overview",
9
9
  "repository": {
10
10
  "type": "git",
@@ -61,13 +61,13 @@
61
61
  "rollup": "^2.78.0"
62
62
  },
63
63
  "devDependencies": {
64
- "@lwrjs/diagnostics": "0.11.0-alpha.4",
65
- "@lwrjs/types": "0.11.0-alpha.4",
64
+ "@lwrjs/diagnostics": "0.11.0-alpha.6",
65
+ "@lwrjs/types": "0.11.0-alpha.6",
66
66
  "@types/mime-types": "2.1.1",
67
67
  "@types/path-to-regexp": "^1.7.0"
68
68
  },
69
69
  "engines": {
70
70
  "node": ">=16.0.0"
71
71
  },
72
- "gitHead": "89a7e9815e0e381d9fd67212f0471d9a11f73985"
72
+ "gitHead": "571d4bac5650765aa818bcb9d5ed752a8cf041af"
73
73
  }