@lwrjs/shared-utils 0.12.0-alpha.2 → 0.12.0-alpha.21

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.
@@ -28,6 +28,9 @@ function isGroupie(rawSpecifier, groupsConfig) {
28
28
  return false;
29
29
  }
30
30
  function createAmdAlias(aliasSpecifier, originalSpecifier) {
31
+ if (aliasSpecifier === originalSpecifier) {
32
+ return "";
33
+ }
31
34
  const builder = [];
32
35
  builder.push(`LWR.define('${aliasSpecifier}',['exports','${originalSpecifier}'],function(e,m){`);
33
36
  builder.push(`e.default=m&&'object'==typeof m&&'default'in m?m.default:m;`);
package/build/cjs/env.cjs CHANGED
@@ -8,8 +8,11 @@ var __export = (target, all) => {
8
8
  // packages/@lwrjs/shared-utils/src/env.ts
9
9
  __markAsModule(exports);
10
10
  __export(exports, {
11
+ REQUEST_DEPTH_HEADER: () => REQUEST_DEPTH_HEADER,
12
+ REQUEST_DEPTH_KEY: () => REQUEST_DEPTH_KEY,
11
13
  buildEnvironmentContext: () => buildEnvironmentContext,
12
- getFeatureFlags: () => getFeatureFlags
14
+ getFeatureFlags: () => getFeatureFlags,
15
+ parseRequestDepthHeader: () => parseRequestDepthHeader
13
16
  });
14
17
  function getFeatureFlags() {
15
18
  return {
@@ -19,7 +22,7 @@ function getFeatureFlags() {
19
22
  SSR_STATIC_BUNDLES: process.env.SSR_STATIC_BUNDLES !== void 0 && process.env.SSR_STATIC_BUNDLES.toLowerCase() === "true" ? true : false,
20
23
  SSR_WITH_CSR_FALLBACK: process.env.SSR_WITH_CSR_FALLBACK !== void 0 && process.env.SSR_WITH_CSR_FALLBACK.toLowerCase() === "true" ? true : false,
21
24
  EXPERIMENTAL_UNVERSIONED_ALIASES: process.env.EXPERIMENTAL_UNVERSIONED_ALIASES !== void 0 && process.env.EXPERIMENTAL_UNVERSIONED_ALIASES.toLowerCase() === "true" ? true : false,
22
- LWR_TRACING: process.env.LWR_TRACING !== void 0 && process.env.LWR_TRACING.toLowerCase() !== "off" ? true : false
25
+ LWR_TRACING: process.env.LWR_TRACING !== void 0 && process.env.LWR_TRACING.toLowerCase() !== "off" ? process.env.LWR_TRACING : false
23
26
  };
24
27
  }
25
28
  function buildEnvironmentContext(runtimeParams) {
@@ -34,3 +37,27 @@ function buildEnvironmentContext(runtimeParams) {
34
37
  uiBasePath
35
38
  };
36
39
  }
40
+ var REQUEST_DEPTH_HEADER = "X-SFDC-Request-Depth";
41
+ var REQUEST_DEPTH_KEY = REQUEST_DEPTH_HEADER.toLowerCase();
42
+ function parseRequestDepthHeader(headers = {}) {
43
+ let maxDepth = 0;
44
+ const value = headers && headers[REQUEST_DEPTH_KEY];
45
+ if (value) {
46
+ if (Array.isArray(value)) {
47
+ for (const depth of value) {
48
+ if (typeof depth === "string") {
49
+ const depthValue = parseInt(depth, 10);
50
+ if (!isNaN(depthValue) && depthValue > maxDepth) {
51
+ maxDepth = depthValue;
52
+ }
53
+ }
54
+ }
55
+ } else if (typeof value === "string") {
56
+ const depth = parseInt(value, 10);
57
+ if (!isNaN(depth) && depth > maxDepth) {
58
+ maxDepth = depth;
59
+ }
60
+ }
61
+ }
62
+ return maxDepth;
63
+ }
package/build/cjs/fs.cjs CHANGED
@@ -24,20 +24,29 @@ var __toModule = (module2) => {
24
24
  // packages/@lwrjs/shared-utils/src/fs.ts
25
25
  __markAsModule(exports);
26
26
  __export(exports, {
27
+ PROTOCOL_FILE: () => PROTOCOL_FILE,
28
+ PROTOCOL_HTTP: () => PROTOCOL_HTTP,
29
+ PROTOCOL_HTTPS: () => PROTOCOL_HTTPS,
30
+ PROTOCOL_LWR: () => PROTOCOL_LWR,
27
31
  canResolveView: () => canResolveView,
32
+ filterProtocolEntries: () => filterProtocolEntries,
28
33
  getViewSourceFromFile: () => getViewSourceFromFile,
29
34
  hashContent: () => hashContent,
35
+ isLocalPath: () => isLocalPath,
30
36
  mimeLookup: () => import_mime_types.lookup,
31
37
  normalizeAssetSpecifier: () => normalizeAssetSpecifier,
32
38
  normalizeDirectory: () => normalizeDirectory,
39
+ normalizeFromFileURL: () => normalizeFromFileURL,
33
40
  normalizeResourcePath: () => normalizeResourcePath,
41
+ normalizeToFileUrl: () => normalizeToFileUrl,
34
42
  readFile: () => readFile,
35
43
  resolveFileExtension: () => resolveFileExtension,
36
44
  streamToString: () => streamToString,
37
45
  stringToStream: () => stringToStream
38
46
  });
39
- var import_fs = __toModule(require("fs"));
47
+ var import_fs_extra = __toModule(require("fs-extra"));
40
48
  var import_path = __toModule(require("path"));
49
+ var import_url = __toModule(require("url"));
41
50
  var import_crypto = __toModule(require("crypto"));
42
51
  var import_identity = __toModule(require("./identity.cjs"));
43
52
  var import_diagnostics = __toModule(require("@lwrjs/diagnostics"));
@@ -46,12 +55,16 @@ var import_stream = __toModule(require("stream"));
46
55
  var import_diagnostics2 = __toModule(require("@lwrjs/diagnostics"));
47
56
  var fileCount = 0;
48
57
  var files = new Map();
58
+ var PROTOCOL_LWR = "lwr://";
59
+ var PROTOCOL_HTTP = "http://";
60
+ var PROTOCOL_HTTPS = "https://";
61
+ var PROTOCOL_FILE = "file://";
49
62
  function hashContent(source) {
50
63
  return import_crypto.default.createHash("md5").update(source).digest("hex");
51
64
  }
52
65
  function readFile(filePath) {
53
66
  logMetrics(filePath);
54
- return import_fs.default.readFileSync(filePath, "utf8");
67
+ return import_fs_extra.default.readFileSync(filePath, "utf8");
55
68
  }
56
69
  function resolveFileExtension(filePath) {
57
70
  const fileName = import_path.default.basename(filePath);
@@ -59,16 +72,16 @@ function resolveFileExtension(filePath) {
59
72
  if (hasExt) {
60
73
  return filePath;
61
74
  }
62
- if (import_fs.default.existsSync(filePath)) {
63
- if (import_fs.default.statSync(filePath).isFile()) {
75
+ if (import_fs_extra.default.existsSync(filePath)) {
76
+ if (import_fs_extra.default.statSync(filePath).isFile()) {
64
77
  return filePath;
65
78
  } else {
66
79
  filePath = import_path.default.join(filePath, "index");
67
80
  }
68
81
  }
69
- if (import_fs.default.existsSync(filePath + ".js")) {
82
+ if (import_fs_extra.default.existsSync(filePath + ".js")) {
70
83
  return filePath + ".js";
71
- } else if (import_fs.default.existsSync(filePath + ".ts")) {
84
+ } else if (import_fs_extra.default.existsSync(filePath + ".ts")) {
72
85
  return filePath + ".ts";
73
86
  } else {
74
87
  throw new Error(`Unable to find file "${filePath}"`);
@@ -81,7 +94,7 @@ function canResolveView(source, type) {
81
94
  if (!source.endsWith(`.${type}`)) {
82
95
  return false;
83
96
  }
84
- if (!import_fs.default.existsSync(import_path.default.resolve(source))) {
97
+ if (!import_fs_extra.default.existsSync(import_path.default.resolve(source))) {
85
98
  throw new Error(`View template cannot be found: "${source}"`);
86
99
  }
87
100
  return true;
@@ -103,6 +116,44 @@ var ROOT_DIR_REGEX = /\$rootDir/g;
103
116
  function normalizeDirectory(dir, rootDir) {
104
117
  return dir.replace(ROOT_DIR_REGEX, rootDir);
105
118
  }
119
+ function normalizeToFileUrl(filePath, rootDir) {
120
+ if (filePath.startsWith(PROTOCOL_FILE)) {
121
+ return filePath;
122
+ }
123
+ const replacedPath = filePath.replace(ROOT_DIR_REGEX, rootDir);
124
+ const fullPath = import_path.default.resolve(rootDir, replacedPath);
125
+ return import_url.default.pathToFileURL(fullPath).href;
126
+ }
127
+ function normalizeFromFileURL(fileURL, basePath) {
128
+ if (typeof fileURL !== "string" || !fileURL.startsWith("file://")) {
129
+ return null;
130
+ }
131
+ const filePath = import_url.default.fileURLToPath(fileURL);
132
+ const normalizedBasePath = import_path.default.resolve(import_path.default.normalize(basePath));
133
+ const compatibleFilePath = filePath.split(import_path.default.sep).join("/");
134
+ const compatibleBasePath = normalizedBasePath.split(import_path.default.sep).join("/");
135
+ if (compatibleFilePath.startsWith(compatibleBasePath)) {
136
+ const relativePath = "/" + import_path.default.relative(normalizedBasePath, filePath).split(import_path.default.sep).join("/");
137
+ return relativePath;
138
+ } else {
139
+ return compatibleFilePath.startsWith("/") ? compatibleFilePath : "/" + compatibleFilePath;
140
+ }
141
+ }
142
+ function isLocalPath(filePath) {
143
+ if (!filePath) {
144
+ return false;
145
+ }
146
+ if (filePath.startsWith("//")) {
147
+ return false;
148
+ }
149
+ if (filePath.startsWith("$rootDir") || filePath.startsWith(PROTOCOL_FILE) || filePath.startsWith("/")) {
150
+ return true;
151
+ }
152
+ if (/^[a-zA-Z]:\\/.test(filePath)) {
153
+ return true;
154
+ }
155
+ return false;
156
+ }
106
157
  var RESOURCE_DIR_REGEX = /\$(\w+)|^\$(\w+)/g;
107
158
  function normalizeResourcePath(rawPath, {rootDir, assets, contentDir, layoutsDir}, allowUnresolvedAlias) {
108
159
  const assetsMap = assets.reduce((map, asset) => {
@@ -188,3 +239,7 @@ function stringToStream(str) {
188
239
  });
189
240
  return readable;
190
241
  }
242
+ function filterProtocolEntries(record, protocol) {
243
+ const filteredEntries = Object.entries(record).filter(([_key, value]) => !value || !value.startsWith(protocol));
244
+ return Object.fromEntries(filteredEntries);
245
+ }
@@ -80,6 +80,7 @@ var DEFAULT_LWR_BOOTSTRAP_CONFIG = {
80
80
  services: [],
81
81
  configAsSrc: false,
82
82
  ssr: false,
83
+ preloadData: false,
83
84
  mixedMode: false,
84
85
  module: void 0,
85
86
  preloadModules: []
@@ -121,10 +122,10 @@ function getSpecifier({specifier, namespace, name = "", version}) {
121
122
  if (specifier) {
122
123
  const versionMatch = specifier.match(/(.+)\/v\/[a-zA-Z0-9-_.]+$/);
123
124
  specifier = versionMatch ? versionMatch[1] : specifier;
124
- return version ? `${specifier}${VERSION_SIGIL}${normalizeVersionToUri(version)}` : specifier;
125
+ return version && version !== VERSION_NOT_PROVIDED ? `${specifier}${VERSION_SIGIL}${normalizeVersionToUri(version)}` : specifier;
125
126
  }
126
127
  const bareSpecifier = namespace ? `${namespace}/${name}` : name;
127
- return version ? `${bareSpecifier}${VERSION_SIGIL}${normalizeVersionToUri(version)}` : bareSpecifier;
128
+ return version && version !== VERSION_NOT_PROVIDED ? `${bareSpecifier}${VERSION_SIGIL}${normalizeVersionToUri(version)}` : bareSpecifier;
128
129
  }
129
130
  async function getVersionedModuleId(rawSpecifier, moduleRegistry, runtimeParams) {
130
131
  const moduleId = explodeSpecifier(rawSpecifier);
@@ -25,6 +25,7 @@ var __toModule = (module2) => {
25
25
  __markAsModule(exports);
26
26
  __export(exports, {
27
27
  getImportMetadataMappings: () => getImportMetadataMappings,
28
+ isExternalSpecifier: () => isExternalSpecifier,
28
29
  toImportMetadata: () => toImportMetadata
29
30
  });
30
31
  var import_graph = __toModule(require("./graph.cjs"));
@@ -61,6 +62,9 @@ async function toImportMetadata(moduleGraph, existingImportMetadata = {imports:
61
62
  const specifier = moduleGraph.graphs[0].specifier;
62
63
  const uri = moduleGraph.uriMap[specifier];
63
64
  const definition = moduleGraph.linkedDefinitions[specifier];
65
+ if (isExternalSpecifier(specifier, moduleRegistry.getConfig().bundleConfig)) {
66
+ return {imports: {}, index: {}};
67
+ }
64
68
  if (!uri) {
65
69
  throw new Error("URI was not included in the graph: " + specifier);
66
70
  }
@@ -74,6 +78,9 @@ async function toImportMetadata(moduleGraph, existingImportMetadata = {imports:
74
78
  const depUri = moduleGraph.uriMap[depSpecifier];
75
79
  const depDef = moduleGraph.linkedDefinitions[depSpecifier];
76
80
  const depMissing = !depUri || !depDef;
81
+ if (isExternalSpecifier(depSpecifier, moduleRegistry.getConfig().bundleConfig)) {
82
+ continue;
83
+ }
77
84
  if (depMissing && runtimeEnvironment.format !== "esm") {
78
85
  if (!depUri) {
79
86
  throw new Error("URI was not included in the graph for dependent: " + depSpecifier);
@@ -124,14 +131,13 @@ async function createIndex(specifiers, moduleRegistry, runtimeEnvironment, runti
124
131
  const moduleRuntimeEnvironment = {...runtimeEnvironment, bundle: false};
125
132
  async function getUri(specifier) {
126
133
  const moduleId = (0, import_identity.explodeSpecifier)(specifier);
127
- if (!moduleId.version) {
128
- throw new Error("Module specifier must include a version: " + specifier);
129
- }
130
- index[specifier] = await moduleRegistry.resolveModuleUri({...moduleId, version: moduleId.version}, moduleRuntimeEnvironment, runtimeParams);
134
+ index[specifier] = await moduleRegistry.resolveModuleUri({...moduleId, version: moduleId.version || import_identity.VERSION_NOT_PROVIDED}, moduleRuntimeEnvironment, runtimeParams);
131
135
  }
132
136
  const promises = [];
133
137
  for (const specifier of specifiers) {
134
- promises.push(getUri(specifier));
138
+ if (!isExternalSpecifier(specifier, moduleRegistry.getConfig().bundleConfig)) {
139
+ promises.push(getUri(specifier));
140
+ }
135
141
  }
136
142
  await Promise.all(promises);
137
143
  return index;
@@ -145,3 +151,7 @@ async function getVersionedSpecifier(moduleId, moduleRegistry, runtimeParams) {
145
151
  }, runtimeParams);
146
152
  return (0, import_identity.getSpecifier)(versionedModuleEntry);
147
153
  }
154
+ function isExternalSpecifier(id, bundleConfig) {
155
+ const {specifier} = (0, import_identity.explodeSpecifier)(id);
156
+ return !!(bundleConfig?.external && bundleConfig.external[specifier]);
157
+ }
@@ -113,19 +113,11 @@ function getViewUri(routePath, basePath, locale, i18n) {
113
113
  url = import_path.default.join(url, `/${locale}`);
114
114
  }
115
115
  url = import_path.default.join(url, routePath);
116
- if (i18n.uriPattern === "query-param" && locale !== i18n.defaultLocale) {
117
- url = addQueryParamToAbsoluteURI(url, "locale", locale);
118
- }
119
116
  return url;
120
117
  }
121
118
  function isURL(uri) {
122
119
  return /^https?:\/\//i.test(uri);
123
120
  }
124
- function addQueryParamToAbsoluteURI(absoluteURI, paramName, paramValue) {
125
- const url = new URL(absoluteURI, "http://example.com");
126
- url.searchParams.set(paramName, paramValue);
127
- return url.pathname + url.search;
128
- }
129
121
  function sortedQueryParamString(query) {
130
122
  if (!query) {
131
123
  return "";
@@ -25,6 +25,10 @@ export function isGroupie(rawSpecifier, groupsConfig) {
25
25
  *
26
26
  */
27
27
  export function createAmdAlias(aliasSpecifier, originalSpecifier) {
28
+ // If the aliasSpecifier === the originalSpecifier specifier do not bother creating an alias
29
+ if (aliasSpecifier === originalSpecifier) {
30
+ return '';
31
+ }
28
32
  const builder = [];
29
33
  // Define statement
30
34
  builder.push(`LWR.define('${aliasSpecifier}',['exports','${originalSpecifier}'],function(e,m){`);
package/build/es/env.d.ts CHANGED
@@ -1,7 +1,10 @@
1
- import type { EnvironmentContext, FeatureFlags, RuntimeParams } from '@lwrjs/types';
1
+ import type { EnvironmentContext, FeatureFlags, Headers, RuntimeParams } from '@lwrjs/types';
2
2
  export declare function getFeatureFlags(): FeatureFlags;
3
3
  /**
4
4
  * Create a serializable context for the lwr/environment variable
5
5
  */
6
6
  export declare function buildEnvironmentContext(runtimeParams: RuntimeParams): EnvironmentContext;
7
+ export declare const REQUEST_DEPTH_HEADER = "X-SFDC-Request-Depth";
8
+ export declare const REQUEST_DEPTH_KEY: string;
9
+ export declare function parseRequestDepthHeader(headers?: Headers): number;
7
10
  //# sourceMappingURL=env.d.ts.map
package/build/es/env.js CHANGED
@@ -10,7 +10,7 @@ export function getFeatureFlags() {
10
10
  LEGACY_LOADER: process.env.LEGACY_LOADER !== undefined && process.env.LEGACY_LOADER.toLowerCase() === 'true'
11
11
  ? true
12
12
  : false,
13
- // Should we use a js worker for SSR, sand-boxing = false (use locker for ssr sand-boxing)
13
+ // Set true to use worker_threads for SSR sandboxes
14
14
  SSR_SANDBOX_WORKER: process.env.SSR_SANDBOX_WORKER !== undefined &&
15
15
  process.env.SSR_SANDBOX_WORKER.toLowerCase() === 'true'
16
16
  ? true
@@ -31,7 +31,7 @@ export function getFeatureFlags() {
31
31
  ? true
32
32
  : false,
33
33
  LWR_TRACING: process.env.LWR_TRACING !== undefined && process.env.LWR_TRACING.toLowerCase() !== 'off'
34
- ? true
34
+ ? process.env.LWR_TRACING
35
35
  : false,
36
36
  };
37
37
  }
@@ -54,4 +54,29 @@ export function buildEnvironmentContext(runtimeParams) {
54
54
  uiBasePath,
55
55
  };
56
56
  }
57
+ export const REQUEST_DEPTH_HEADER = 'X-SFDC-Request-Depth';
58
+ export const REQUEST_DEPTH_KEY = REQUEST_DEPTH_HEADER.toLowerCase();
59
+ export function parseRequestDepthHeader(headers = {}) {
60
+ let maxDepth = 0;
61
+ const value = headers && headers[REQUEST_DEPTH_KEY];
62
+ if (value) {
63
+ if (Array.isArray(value)) {
64
+ for (const depth of value) {
65
+ if (typeof depth === 'string') {
66
+ const depthValue = parseInt(depth, 10);
67
+ if (!isNaN(depthValue) && depthValue > maxDepth) {
68
+ maxDepth = depthValue;
69
+ }
70
+ }
71
+ }
72
+ }
73
+ else if (typeof value === 'string') {
74
+ const depth = parseInt(value, 10);
75
+ if (!isNaN(depth) && depth > maxDepth) {
76
+ maxDepth = depth;
77
+ }
78
+ }
79
+ }
80
+ return maxDepth;
81
+ }
57
82
  //# sourceMappingURL=env.js.map
package/build/es/fs.d.ts CHANGED
@@ -3,6 +3,10 @@
3
3
  import type { AssetIdentifier, ResourcePaths, ViewSource } from '@lwrjs/types';
4
4
  import { lookup } from 'mime-types';
5
5
  import { Readable } from 'stream';
6
+ export declare const PROTOCOL_LWR = "lwr://";
7
+ export declare const PROTOCOL_HTTP = "http://";
8
+ export declare const PROTOCOL_HTTPS = "https://";
9
+ export declare const PROTOCOL_FILE = "file://";
6
10
  /**
7
11
  * Create a hash string for a source
8
12
  * @param source
@@ -32,6 +36,15 @@ export declare function canResolveView(source: unknown, type: string): boolean;
32
36
  */
33
37
  export declare function getViewSourceFromFile(source: string): ViewSource;
34
38
  export declare function normalizeDirectory(dir: string, rootDir: string): string;
39
+ /**
40
+ * Replace all instances of `$rootDir` with `rootDir`.
41
+ * Convert path to file:// url
42
+ * @param file
43
+ * @param rootDir
44
+ */
45
+ export declare function normalizeToFileUrl(filePath: string, rootDir: string): string;
46
+ export declare function normalizeFromFileURL(fileURL: string | undefined, basePath: string): string | null;
47
+ export declare function isLocalPath(filePath: string): boolean;
35
48
  export declare function normalizeResourcePath(rawPath: string, { rootDir, assets, contentDir, layoutsDir }: ResourcePaths, allowUnresolvedAlias?: boolean): string;
36
49
  export { lookup as mimeLookup };
37
50
  /**
@@ -40,4 +53,5 @@ export { lookup as mimeLookup };
40
53
  export declare function normalizeAssetSpecifier(assetId: AssetIdentifier, assetPathMap: Map<string, string>, resourcePaths: ResourcePaths, basePath: string): string;
41
54
  export declare function streamToString(stream: Readable, encoding?: BufferEncoding): Promise<string>;
42
55
  export declare function stringToStream(str: string | Buffer): Readable;
56
+ export declare function filterProtocolEntries(record: Record<string, string>, protocol: string): Record<string, string>;
43
57
  //# sourceMappingURL=fs.d.ts.map
package/build/es/fs.js CHANGED
@@ -1,5 +1,6 @@
1
- import fs from 'fs';
1
+ import fs from 'fs-extra';
2
2
  import pathLib from 'path';
3
+ import url from 'url';
3
4
  import crypto from 'crypto';
4
5
  import { slugify } from './identity.js';
5
6
  import { LwrUnresolvableError, createSingleDiagnosticError, descriptions } from '@lwrjs/diagnostics';
@@ -8,6 +9,11 @@ import { Readable } from 'stream';
8
9
  import { logger } from '@lwrjs/diagnostics';
9
10
  let fileCount = 0;
10
11
  const files = new Map();
12
+ // LWR Internal URL protocol
13
+ export const PROTOCOL_LWR = 'lwr://';
14
+ export const PROTOCOL_HTTP = 'http://';
15
+ export const PROTOCOL_HTTPS = 'https://';
16
+ export const PROTOCOL_FILE = 'file://';
11
17
  /**
12
18
  * Create a hash string for a source
13
19
  * @param source
@@ -99,6 +105,63 @@ const ROOT_DIR_REGEX = /\$rootDir/g;
99
105
  export function normalizeDirectory(dir, rootDir) {
100
106
  return dir.replace(ROOT_DIR_REGEX, rootDir);
101
107
  }
108
+ /**
109
+ * Replace all instances of `$rootDir` with `rootDir`.
110
+ * Convert path to file:// url
111
+ * @param file
112
+ * @param rootDir
113
+ */
114
+ export function normalizeToFileUrl(filePath, rootDir) {
115
+ // Check if filePath already starts with 'file://'
116
+ if (filePath.startsWith(PROTOCOL_FILE)) {
117
+ return filePath;
118
+ }
119
+ const replacedPath = filePath.replace(ROOT_DIR_REGEX, rootDir);
120
+ const fullPath = pathLib.resolve(rootDir, replacedPath);
121
+ return url.pathToFileURL(fullPath).href;
122
+ }
123
+ export function normalizeFromFileURL(fileURL, basePath) {
124
+ if (typeof fileURL !== 'string' || !fileURL.startsWith('file://')) {
125
+ return null;
126
+ }
127
+ // Convert fileURL to a system-specific path
128
+ const filePath = url.fileURLToPath(fileURL);
129
+ // Resolve and normalize base path to ensure it's in the correct format and system-specific
130
+ const normalizedBasePath = pathLib.resolve(pathLib.normalize(basePath));
131
+ // Ensure compatibility across different OS by replacing path separators accordingly
132
+ const compatibleFilePath = filePath.split(pathLib.sep).join('/');
133
+ const compatibleBasePath = normalizedBasePath.split(pathLib.sep).join('/');
134
+ // Check if filePath starts with the basePath
135
+ if (compatibleFilePath.startsWith(compatibleBasePath)) {
136
+ // Return the relative path from basePath, ensuring it starts with a '/'
137
+ const relativePath = '/' + pathLib.relative(normalizedBasePath, filePath).split(pathLib.sep).join('/');
138
+ return relativePath;
139
+ }
140
+ else {
141
+ // Return the full path if outside of basePath, ensuring it starts with a '/'
142
+ return compatibleFilePath.startsWith('/') ? compatibleFilePath : '/' + compatibleFilePath;
143
+ }
144
+ }
145
+ export function isLocalPath(filePath) {
146
+ // handle null or undefined
147
+ if (!filePath) {
148
+ return false;
149
+ }
150
+ // Check for protocol-relative URLs or network paths
151
+ if (filePath.startsWith('//')) {
152
+ return false;
153
+ }
154
+ // Check for file protocol or absolute file paths on Unix/Linux
155
+ if (filePath.startsWith('$rootDir') || filePath.startsWith(PROTOCOL_FILE) || filePath.startsWith('/')) {
156
+ return true;
157
+ }
158
+ // Check for Windows absolute paths (e.g., C:\path\to\file)
159
+ if (/^[a-zA-Z]:\\/.test(filePath)) {
160
+ return true;
161
+ }
162
+ // Consider anything not identified as a file protocol or an absolute path as non-local
163
+ return false;
164
+ }
102
165
  /**
103
166
  * Replace all instances of `$*Dir` with `resourcePaths.*Dir`
104
167
  * @param rawPath
@@ -203,4 +266,12 @@ export function stringToStream(str) {
203
266
  });
204
267
  return readable;
205
268
  }
269
+ // Function to filter out entries where the value starts with given protocol
270
+ export function filterProtocolEntries(record, protocol) {
271
+ // Use Object.entries to get an array of [key, value] pairs,
272
+ // then filter out the pairs where value starts with {protocol}
273
+ const filteredEntries = Object.entries(record).filter(([_key, value]) => !value || !value.startsWith(protocol));
274
+ // Use Object.fromEntries to convert the filtered entries back into an object
275
+ return Object.fromEntries(filteredEntries);
276
+ }
206
277
  //# sourceMappingURL=fs.js.map
@@ -56,6 +56,7 @@ export declare function explodeSpecifiers(rawSpecifiers: string): PartialModuleI
56
56
  * @example - { name: 'lwc', version: '1.7' } => 'lwc/v/1.7'
57
57
  * @example - { namespace: 'c', name: 'navMenu', version: '2.0' } => 'c/navMenu/v/2.0'
58
58
  * @example - { namespace: '@salesforce', name: 'label/my.label', version: '1' } => '@salesforce/label/my.label/v/1'
59
+ * @example - { namespace: '@salesforce', name: 'label/my.label', version: 'version-not-provided' } => '@salesforce/label/my.label'
59
60
  */
60
61
  export declare function getSpecifier({ specifier, namespace, name, version }: ModuleIdentifierPartial): string;
61
62
  interface VersionedAbstractModuleId extends AbstractModuleId {
@@ -22,6 +22,7 @@ export const DEFAULT_LWR_BOOTSTRAP_CONFIG = {
22
22
  services: [],
23
23
  configAsSrc: false,
24
24
  ssr: false,
25
+ preloadData: false,
25
26
  mixedMode: false,
26
27
  module: undefined,
27
28
  preloadModules: [],
@@ -89,16 +90,23 @@ export function explodeSpecifiers(rawSpecifiers) {
89
90
  * @example - { name: 'lwc', version: '1.7' } => 'lwc/v/1.7'
90
91
  * @example - { namespace: 'c', name: 'navMenu', version: '2.0' } => 'c/navMenu/v/2.0'
91
92
  * @example - { namespace: '@salesforce', name: 'label/my.label', version: '1' } => '@salesforce/label/my.label/v/1'
93
+ * @example - { namespace: '@salesforce', name: 'label/my.label', version: 'version-not-provided' } => '@salesforce/label/my.label'
92
94
  */
93
95
  export function getSpecifier({ specifier, namespace, name = '', version }) {
94
96
  if (specifier) {
95
97
  // Remove any versioning from the specifier
96
98
  const versionMatch = specifier.match(/(.+)\/v\/[a-zA-Z0-9-_.]+$/);
97
99
  specifier = versionMatch ? versionMatch[1] : specifier;
98
- return version ? `${specifier}${VERSION_SIGIL}${normalizeVersionToUri(version)}` : specifier;
100
+ // If a module has an explicit 'version-not-provided' version this will not be reflected in the specifier
101
+ return version && version !== VERSION_NOT_PROVIDED
102
+ ? `${specifier}${VERSION_SIGIL}${normalizeVersionToUri(version)}`
103
+ : specifier;
99
104
  }
100
105
  const bareSpecifier = namespace ? `${namespace}/${name}` : name;
101
- return version ? `${bareSpecifier}${VERSION_SIGIL}${normalizeVersionToUri(version)}` : bareSpecifier;
106
+ // If a module has an explicit 'version-not-provided' version this will not be reflected in the specifier
107
+ return version && version !== VERSION_NOT_PROVIDED
108
+ ? `${bareSpecifier}${VERSION_SIGIL}${normalizeVersionToUri(version)}`
109
+ : bareSpecifier;
102
110
  }
103
111
  /**
104
112
  * Create a AbstractModuleId using the module registry to resolve the version
@@ -1,4 +1,4 @@
1
- import type { AbstractModuleId, FlattenedModuleGraphs, ImportMetadata, ModuleBundler, ModuleRegistry, RuntimeEnvironment, RuntimeParams } from '@lwrjs/types';
1
+ import type { AbstractModuleId, BundleConfig, FlattenedModuleGraphs, ImportMetadata, ModuleBundler, ModuleRegistry, RuntimeEnvironment, RuntimeParams } from '@lwrjs/types';
2
2
  /**
3
3
  * Get the Import Metadata for the LWR Mapping Api (https://rfcs.lwc.dev/rfcs/lwr/0000-mapping-api)
4
4
  */
@@ -16,4 +16,5 @@ export declare function getImportMetadataMappings(moduleIds: AbstractModuleId[],
16
16
  * @returns Returns ImportMetadata from a module graph in the format here -> https://rfcs.lwc.dev/rfcs/lwr/0000-mapping-api#uri-mapping-resource-specification
17
17
  */
18
18
  export declare function toImportMetadata(moduleGraph: FlattenedModuleGraphs, existingImportMetadata: ImportMetadata | undefined, moduleRegistry: ModuleRegistry, runtimeEnvironment: RuntimeEnvironment, runtimeParams?: RuntimeParams): Promise<ImportMetadata>;
19
+ export declare function isExternalSpecifier(id: string, bundleConfig: BundleConfig): boolean;
19
20
  //# sourceMappingURL=mappings.d.ts.map
@@ -1,5 +1,5 @@
1
1
  import { getModuleGraphs, GraphDepth } from './graph.js';
2
- import { explodeSpecifier, getSpecifier, isBundleDefinition } from './identity.js';
2
+ import { explodeSpecifier, getSpecifier, isBundleDefinition, VERSION_NOT_PROVIDED } from './identity.js';
3
3
  /**
4
4
  * Get the Import Metadata for the LWR Mapping Api (https://rfcs.lwc.dev/rfcs/lwr/0000-mapping-api)
5
5
  */
@@ -58,6 +58,10 @@ export async function toImportMetadata(moduleGraph, existingImportMetadata = { i
58
58
  const specifier = moduleGraph.graphs[0].specifier;
59
59
  const uri = moduleGraph.uriMap[specifier];
60
60
  const definition = moduleGraph.linkedDefinitions[specifier];
61
+ if (isExternalSpecifier(specifier, moduleRegistry.getConfig().bundleConfig)) {
62
+ // Ignore Externals
63
+ return { imports: {}, index: {} };
64
+ }
61
65
  if (!uri) {
62
66
  throw new Error('URI was not included in the graph: ' + specifier);
63
67
  }
@@ -77,6 +81,10 @@ export async function toImportMetadata(moduleGraph, existingImportMetadata = { i
77
81
  const depUri = moduleGraph.uriMap[depSpecifier];
78
82
  const depDef = moduleGraph.linkedDefinitions[depSpecifier];
79
83
  const depMissing = !depUri || !depDef;
84
+ if (isExternalSpecifier(depSpecifier, moduleRegistry.getConfig().bundleConfig)) {
85
+ // Ignore Externals
86
+ continue;
87
+ }
80
88
  if (depMissing && runtimeEnvironment.format !== 'esm') {
81
89
  if (!depUri) {
82
90
  throw new Error('URI was not included in the graph for dependent: ' + depSpecifier);
@@ -138,17 +146,16 @@ async function createIndex(specifiers, moduleRegistry, runtimeEnvironment, runti
138
146
  const moduleRuntimeEnvironment = { ...runtimeEnvironment, bundle: false };
139
147
  async function getUri(specifier) {
140
148
  const moduleId = explodeSpecifier(specifier);
141
- if (!moduleId.version) {
142
- throw new Error('Module specifier must include a version: ' + specifier);
143
- }
144
- // Do not use replace with the moduleBundler. Otherwize we will create a bundle from every
149
+ // Do not use replace with the moduleBundler. Otherwise we will create a bundle from every
145
150
  // root just to get the URL.
146
- index[specifier] = await moduleRegistry.resolveModuleUri({ ...moduleId, version: moduleId.version }, moduleRuntimeEnvironment, runtimeParams);
151
+ index[specifier] = await moduleRegistry.resolveModuleUri({ ...moduleId, version: moduleId.version || VERSION_NOT_PROVIDED }, moduleRuntimeEnvironment, runtimeParams);
147
152
  }
148
153
  // Queue up uri requests
149
154
  const promises = [];
150
155
  for (const specifier of specifiers) {
151
- promises.push(getUri(specifier));
156
+ if (!isExternalSpecifier(specifier, moduleRegistry.getConfig().bundleConfig)) {
157
+ promises.push(getUri(specifier));
158
+ }
152
159
  }
153
160
  // Wait for them to finish
154
161
  await Promise.all(promises);
@@ -163,4 +170,8 @@ async function getVersionedSpecifier(moduleId, moduleRegistry, runtimeParams) {
163
170
  }, runtimeParams);
164
171
  return getSpecifier(versionedModuleEntry);
165
172
  }
173
+ export function isExternalSpecifier(id, bundleConfig) {
174
+ const { specifier } = explodeSpecifier(id);
175
+ return !!(bundleConfig?.external && bundleConfig.external[specifier]);
176
+ }
166
177
  //# sourceMappingURL=mappings.js.map
package/build/es/urls.js CHANGED
@@ -106,9 +106,6 @@ export function getViewUri(routePath, basePath, locale, i18n) {
106
106
  url = path.join(url, `/${locale}`);
107
107
  }
108
108
  url = path.join(url, routePath);
109
- if (i18n.uriPattern === 'query-param' && locale !== i18n.defaultLocale) {
110
- url = addQueryParamToAbsoluteURI(url, 'locale', locale);
111
- }
112
109
  return url;
113
110
  }
114
111
  /**
@@ -117,14 +114,6 @@ export function getViewUri(routePath, basePath, locale, i18n) {
117
114
  export function isURL(uri) {
118
115
  return /^https?:\/\//i.test(uri);
119
116
  }
120
- function addQueryParamToAbsoluteURI(absoluteURI, paramName, paramValue) {
121
- // Use a dummy domain for parsing
122
- const url = new URL(absoluteURI, 'http://example.com');
123
- // Add the query parameter
124
- url.searchParams.set(paramName, paramValue);
125
- // Get the modified URI with the query parameter
126
- return url.pathname + url.search;
127
- }
128
117
  function sortedQueryParamString(query) {
129
118
  if (!query) {
130
119
  return '';
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
- "version": "0.12.0-alpha.2",
7
+ "version": "0.12.0-alpha.21",
8
8
  "homepage": "https://developer.salesforce.com/docs/platform/lwr/overview",
9
9
  "repository": {
10
10
  "type": "git",
@@ -37,10 +37,10 @@
37
37
  "build/**/*.d.ts"
38
38
  ],
39
39
  "dependencies": {
40
- "@lwrjs/diagnostics": "0.12.0-alpha.2",
40
+ "@lwrjs/diagnostics": "0.12.0-alpha.21",
41
41
  "es-module-lexer": "^1.3.0",
42
42
  "fast-json-stable-stringify": "^2.1.0",
43
- "magic-string": "^0.30.0",
43
+ "magic-string": "^0.30.7",
44
44
  "mime-types": "^2.1.33",
45
45
  "ms": "^2.1.3",
46
46
  "parse5-sax-parser": "^6.0.1",
@@ -50,12 +50,12 @@
50
50
  "slugify": "^1.4.5"
51
51
  },
52
52
  "devDependencies": {
53
- "@lwrjs/types": "0.12.0-alpha.2",
53
+ "@lwrjs/types": "0.12.0-alpha.21",
54
54
  "@types/mime-types": "2.1.1",
55
55
  "@types/path-to-regexp": "^1.7.0"
56
56
  },
57
57
  "engines": {
58
58
  "node": ">=18.0.0"
59
59
  },
60
- "gitHead": "586a2aa659882483af9249dc3db7fe07bc842a25"
60
+ "gitHead": "3d77678ca2f568fcbe29efa2bf7e6f75778be50c"
61
61
  }