@lwrjs/shared-utils 0.12.0-alpha.9 → 0.12.1

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,14 +8,16 @@ 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 {
16
19
  ASSETS_ON_LAMBDA: process.env.ASSETS_ON_LAMBDA !== void 0 && process.env.ASSETS_ON_LAMBDA.toLowerCase() === "true" ? true : false,
17
20
  LEGACY_LOADER: process.env.LEGACY_LOADER !== void 0 && process.env.LEGACY_LOADER.toLowerCase() === "true" ? true : false,
18
- SSR_SANDBOX_VM: process.env.SSR_SANDBOX_VM !== void 0 && process.env.SSR_SANDBOX_VM.toLowerCase() === "true" ? true : false,
19
21
  SSR_STATIC_BUNDLES: process.env.SSR_STATIC_BUNDLES !== void 0 && process.env.SSR_STATIC_BUNDLES.toLowerCase() === "true" ? true : false,
20
22
  SSR_WITH_CSR_FALLBACK: process.env.SSR_WITH_CSR_FALLBACK !== void 0 && process.env.SSR_WITH_CSR_FALLBACK.toLowerCase() === "true" ? true : false,
21
23
  EXPERIMENTAL_UNVERSIONED_ALIASES: process.env.EXPERIMENTAL_UNVERSIONED_ALIASES !== void 0 && process.env.EXPERIMENTAL_UNVERSIONED_ALIASES.toLowerCase() === "true" ? true : false,
@@ -34,3 +36,27 @@ function buildEnvironmentContext(runtimeParams) {
34
36
  uiBasePath
35
37
  };
36
38
  }
39
+ var REQUEST_DEPTH_HEADER = "X-SFDC-Request-Depth";
40
+ var REQUEST_DEPTH_KEY = REQUEST_DEPTH_HEADER.toLowerCase();
41
+ function parseRequestDepthHeader(headers = {}) {
42
+ let maxDepth = 0;
43
+ const value = headers && headers[REQUEST_DEPTH_KEY];
44
+ if (value) {
45
+ if (Array.isArray(value)) {
46
+ for (const depth of value) {
47
+ if (typeof depth === "string") {
48
+ const depthValue = parseInt(depth, 10);
49
+ if (!isNaN(depthValue) && depthValue > maxDepth) {
50
+ maxDepth = depthValue;
51
+ }
52
+ }
53
+ }
54
+ } else if (typeof value === "string") {
55
+ const depth = parseInt(value, 10);
56
+ if (!isNaN(depth) && depth > maxDepth) {
57
+ maxDepth = depth;
58
+ }
59
+ }
60
+ }
61
+ return maxDepth;
62
+ }
package/build/cjs/fs.cjs CHANGED
@@ -24,20 +24,28 @@ 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,
27
30
  canResolveView: () => canResolveView,
31
+ filterProtocolEntries: () => filterProtocolEntries,
28
32
  getViewSourceFromFile: () => getViewSourceFromFile,
29
33
  hashContent: () => hashContent,
34
+ isLocalPath: () => isLocalPath,
30
35
  mimeLookup: () => import_mime_types.lookup,
31
36
  normalizeAssetSpecifier: () => normalizeAssetSpecifier,
32
37
  normalizeDirectory: () => normalizeDirectory,
38
+ normalizeFromFileURL: () => normalizeFromFileURL,
33
39
  normalizeResourcePath: () => normalizeResourcePath,
40
+ normalizeToFileUrl: () => normalizeToFileUrl,
34
41
  readFile: () => readFile,
35
42
  resolveFileExtension: () => resolveFileExtension,
36
43
  streamToString: () => streamToString,
37
44
  stringToStream: () => stringToStream
38
45
  });
39
- var import_fs = __toModule(require("fs"));
46
+ var import_fs_extra = __toModule(require("fs-extra"));
40
47
  var import_path = __toModule(require("path"));
48
+ var import_url = __toModule(require("url"));
41
49
  var import_crypto = __toModule(require("crypto"));
42
50
  var import_identity = __toModule(require("./identity.cjs"));
43
51
  var import_diagnostics = __toModule(require("@lwrjs/diagnostics"));
@@ -46,12 +54,15 @@ var import_stream = __toModule(require("stream"));
46
54
  var import_diagnostics2 = __toModule(require("@lwrjs/diagnostics"));
47
55
  var fileCount = 0;
48
56
  var files = new Map();
57
+ var PROTOCOL_HTTP = "http://";
58
+ var PROTOCOL_HTTPS = "https://";
59
+ var PROTOCOL_FILE = "file://";
49
60
  function hashContent(source) {
50
61
  return import_crypto.default.createHash("md5").update(source).digest("hex");
51
62
  }
52
63
  function readFile(filePath) {
53
64
  logMetrics(filePath);
54
- return import_fs.default.readFileSync(filePath, "utf8");
65
+ return import_fs_extra.default.readFileSync(filePath, "utf8");
55
66
  }
56
67
  function resolveFileExtension(filePath) {
57
68
  const fileName = import_path.default.basename(filePath);
@@ -59,16 +70,16 @@ function resolveFileExtension(filePath) {
59
70
  if (hasExt) {
60
71
  return filePath;
61
72
  }
62
- if (import_fs.default.existsSync(filePath)) {
63
- if (import_fs.default.statSync(filePath).isFile()) {
73
+ if (import_fs_extra.default.existsSync(filePath)) {
74
+ if (import_fs_extra.default.statSync(filePath).isFile()) {
64
75
  return filePath;
65
76
  } else {
66
77
  filePath = import_path.default.join(filePath, "index");
67
78
  }
68
79
  }
69
- if (import_fs.default.existsSync(filePath + ".js")) {
80
+ if (import_fs_extra.default.existsSync(filePath + ".js")) {
70
81
  return filePath + ".js";
71
- } else if (import_fs.default.existsSync(filePath + ".ts")) {
82
+ } else if (import_fs_extra.default.existsSync(filePath + ".ts")) {
72
83
  return filePath + ".ts";
73
84
  } else {
74
85
  throw new Error(`Unable to find file "${filePath}"`);
@@ -81,7 +92,7 @@ function canResolveView(source, type) {
81
92
  if (!source.endsWith(`.${type}`)) {
82
93
  return false;
83
94
  }
84
- if (!import_fs.default.existsSync(import_path.default.resolve(source))) {
95
+ if (!import_fs_extra.default.existsSync(import_path.default.resolve(source))) {
85
96
  throw new Error(`View template cannot be found: "${source}"`);
86
97
  }
87
98
  return true;
@@ -103,6 +114,44 @@ var ROOT_DIR_REGEX = /\$rootDir/g;
103
114
  function normalizeDirectory(dir, rootDir) {
104
115
  return dir.replace(ROOT_DIR_REGEX, rootDir);
105
116
  }
117
+ function normalizeToFileUrl(filePath, rootDir) {
118
+ if (filePath.startsWith(PROTOCOL_FILE)) {
119
+ return filePath;
120
+ }
121
+ const replacedPath = filePath.replace(ROOT_DIR_REGEX, rootDir);
122
+ const fullPath = import_path.default.resolve(rootDir, replacedPath);
123
+ return import_url.default.pathToFileURL(fullPath).href;
124
+ }
125
+ function normalizeFromFileURL(fileURL, basePath) {
126
+ if (typeof fileURL !== "string" || !fileURL.startsWith("file://")) {
127
+ return null;
128
+ }
129
+ const filePath = import_url.default.fileURLToPath(fileURL);
130
+ const normalizedBasePath = import_path.default.resolve(import_path.default.normalize(basePath));
131
+ const compatibleFilePath = filePath.split(import_path.default.sep).join("/");
132
+ const compatibleBasePath = normalizedBasePath.split(import_path.default.sep).join("/");
133
+ if (compatibleFilePath.startsWith(compatibleBasePath)) {
134
+ const relativePath = "/" + import_path.default.relative(normalizedBasePath, filePath).split(import_path.default.sep).join("/");
135
+ return relativePath;
136
+ } else {
137
+ return compatibleFilePath.startsWith("/") ? compatibleFilePath : "/" + compatibleFilePath;
138
+ }
139
+ }
140
+ function isLocalPath(filePath) {
141
+ if (!filePath) {
142
+ return false;
143
+ }
144
+ if (filePath.startsWith("//")) {
145
+ return false;
146
+ }
147
+ if (filePath.startsWith("$rootDir") || filePath.startsWith(PROTOCOL_FILE) || filePath.startsWith("/")) {
148
+ return true;
149
+ }
150
+ if (/^[a-zA-Z]:\\/.test(filePath)) {
151
+ return true;
152
+ }
153
+ return false;
154
+ }
106
155
  var RESOURCE_DIR_REGEX = /\$(\w+)|^\$(\w+)/g;
107
156
  function normalizeResourcePath(rawPath, {rootDir, assets, contentDir, layoutsDir}, allowUnresolvedAlias) {
108
157
  const assetsMap = assets.reduce((map, asset) => {
@@ -188,3 +237,7 @@ function stringToStream(str) {
188
237
  });
189
238
  return readable;
190
239
  }
240
+ function filterProtocolEntries(record, protocol) {
241
+ const filteredEntries = Object.entries(record).filter(([_key, value]) => !value || !value.startsWith(protocol));
242
+ return Object.fromEntries(filteredEntries);
243
+ }
@@ -122,10 +122,10 @@ function getSpecifier({specifier, namespace, name = "", version}) {
122
122
  if (specifier) {
123
123
  const versionMatch = specifier.match(/(.+)\/v\/[a-zA-Z0-9-_.]+$/);
124
124
  specifier = versionMatch ? versionMatch[1] : specifier;
125
- return version ? `${specifier}${VERSION_SIGIL}${normalizeVersionToUri(version)}` : specifier;
125
+ return version && version !== VERSION_NOT_PROVIDED ? `${specifier}${VERSION_SIGIL}${normalizeVersionToUri(version)}` : specifier;
126
126
  }
127
127
  const bareSpecifier = namespace ? `${namespace}/${name}` : name;
128
- return version ? `${bareSpecifier}${VERSION_SIGIL}${normalizeVersionToUri(version)}` : bareSpecifier;
128
+ return version && version !== VERSION_NOT_PROVIDED ? `${bareSpecifier}${VERSION_SIGIL}${normalizeVersionToUri(version)}` : bareSpecifier;
129
129
  }
130
130
  async function getVersionedModuleId(rawSpecifier, moduleRegistry, runtimeParams) {
131
131
  const moduleId = explodeSpecifier(rawSpecifier);
@@ -25,10 +25,13 @@ var __toModule = (module2) => {
25
25
  __markAsModule(exports);
26
26
  __export(exports, {
27
27
  getImportMetadataMappings: () => getImportMetadataMappings,
28
+ isExternalFileSpecifier: () => isExternalFileSpecifier,
29
+ isExternalSpecifier: () => isExternalSpecifier,
28
30
  toImportMetadata: () => toImportMetadata
29
31
  });
30
32
  var import_graph = __toModule(require("./graph.cjs"));
31
33
  var import_identity = __toModule(require("./identity.cjs"));
34
+ var import_fs = __toModule(require("./fs.cjs"));
32
35
  async function getImportMetadataMappings(moduleIds, runtimeEnvironment, runtimeParams, moduleRegistry, moduleBundler) {
33
36
  const visitedCache = new Map();
34
37
  let importMetadata = {
@@ -46,7 +49,7 @@ async function getImportMetadataMappings(moduleIds, runtimeEnvironment, runtimeP
46
49
  const moduleGraph = await (0, import_graph.getModuleGraphs)(specifier, {includeUris: true, includeLinkedDefinitions: true, depth}, moduleRegistry, runtimeEnvironment.bundle ? moduleBundler : moduleRegistry, runtimeEnvironment, runtimeParams, visitedCache);
47
50
  importMetadata = await toImportMetadata(moduleGraph, importMetadata, moduleRegistry, runtimeEnvironment, runtimeParams);
48
51
  }
49
- if (requestedSpecifier !== specifier) {
52
+ if (moduleId.importer && requestedSpecifier !== specifier) {
50
53
  const requestedSpecifierPlusImporter = `${requestedSpecifier}?importer=${moduleId.importer}`;
51
54
  const specifiersArray = Object.values(importMetadata.imports).find((a) => a.includes(specifier));
52
55
  if (!specifiersArray) {
@@ -67,10 +70,19 @@ async function toImportMetadata(moduleGraph, existingImportMetadata = {imports:
67
70
  if (!definition) {
68
71
  throw new Error("Linked module definition was not included in the graph: " + specifier);
69
72
  }
73
+ if (isExternalSpecifier(specifier, moduleRegistry.getConfig().bundleConfig)) {
74
+ const externalMapping = {imports: {}, index: {}};
75
+ externalMapping.imports[uri] = [specifier];
76
+ externalMapping.index[specifier] = uri;
77
+ return externalMapping;
78
+ }
70
79
  const rootMetadata = await normalizeImportMetadata(specifier, uri, definition, moduleRegistry, runtimeEnvironment, runtimeParams);
71
80
  let importMetadata = mergeImportMetadata(existingImportMetadata, rootMetadata);
72
81
  const depSpecifiers = runtimeEnvironment.format === "esm" ? moduleGraph.graphs[0].dynamicRefs : moduleGraph.graphs[0].static;
73
82
  for (const depSpecifier of depSpecifiers) {
83
+ if (isExternalSpecifier(depSpecifier, moduleRegistry.getConfig().bundleConfig)) {
84
+ continue;
85
+ }
74
86
  const depUri = moduleGraph.uriMap[depSpecifier];
75
87
  const depDef = moduleGraph.linkedDefinitions[depSpecifier];
76
88
  const depMissing = !depUri || !depDef;
@@ -85,8 +97,11 @@ async function toImportMetadata(moduleGraph, existingImportMetadata = {imports:
85
97
  continue;
86
98
  }
87
99
  if (!importMetadata.imports[depUri]) {
88
- const depMetadata = await normalizeImportMetadata((0, import_identity.getSpecifier)(depDef), depUri, depDef, moduleRegistry, runtimeEnvironment, runtimeParams);
89
- importMetadata = mergeImportMetadata(importMetadata, depMetadata);
100
+ const depDefSpecifier = (0, import_identity.getSpecifier)(depDef);
101
+ if (!isExternalSpecifier(depDefSpecifier, moduleRegistry.getConfig().bundleConfig)) {
102
+ const depMetadata = await normalizeImportMetadata(depDefSpecifier, depUri, depDef, moduleRegistry, runtimeEnvironment, runtimeParams);
103
+ importMetadata = mergeImportMetadata(importMetadata, depMetadata);
104
+ }
90
105
  }
91
106
  }
92
107
  return importMetadata;
@@ -124,20 +139,19 @@ async function createIndex(specifiers, moduleRegistry, runtimeEnvironment, runti
124
139
  const moduleRuntimeEnvironment = {...runtimeEnvironment, bundle: false};
125
140
  async function getUri(specifier) {
126
141
  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);
142
+ index[specifier] = await moduleRegistry.resolveModuleUri({...moduleId, version: moduleId.version || import_identity.VERSION_NOT_PROVIDED}, moduleRuntimeEnvironment, runtimeParams);
131
143
  }
132
144
  const promises = [];
133
145
  for (const specifier of specifiers) {
134
- promises.push(getUri(specifier));
146
+ if (!isExternalSpecifier(specifier, moduleRegistry.getConfig().bundleConfig)) {
147
+ promises.push(getUri(specifier));
148
+ }
135
149
  }
136
150
  await Promise.all(promises);
137
151
  return index;
138
152
  }
139
153
  async function getVersionedSpecifier(moduleId, moduleRegistry, runtimeParams) {
140
- if (!moduleId.importer || moduleId.version) {
154
+ if (moduleId.version) {
141
155
  return (0, import_identity.getSpecifier)(moduleId);
142
156
  }
143
157
  const versionedModuleEntry = await moduleRegistry.getModuleEntry({
@@ -145,3 +159,11 @@ async function getVersionedSpecifier(moduleId, moduleRegistry, runtimeParams) {
145
159
  }, runtimeParams);
146
160
  return (0, import_identity.getSpecifier)(versionedModuleEntry);
147
161
  }
162
+ function isExternalSpecifier(id, bundleConfig) {
163
+ const {specifier} = (0, import_identity.explodeSpecifier)(id);
164
+ return !!(bundleConfig?.external && Object.prototype.hasOwnProperty.call(bundleConfig.external, specifier));
165
+ }
166
+ function isExternalFileSpecifier(id, bundleConfig) {
167
+ const {specifier} = (0, import_identity.explodeSpecifier)(id);
168
+ return !!(bundleConfig?.external && bundleConfig.external[specifier] && bundleConfig.external[specifier].startsWith(import_fs.PROTOCOL_FILE));
169
+ }
@@ -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,10 +10,6 @@ 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
- // Set true to use NODE:VM for SSR sandboxes
14
- SSR_SANDBOX_VM: process.env.SSR_SANDBOX_VM !== undefined && process.env.SSR_SANDBOX_VM.toLowerCase() === 'true'
15
- ? true
16
- : false,
17
13
  // SSR should concatenate bundles, default = false
18
14
  SSR_STATIC_BUNDLES: process.env.SSR_STATIC_BUNDLES !== undefined &&
19
15
  process.env.SSR_STATIC_BUNDLES.toLowerCase() === 'true'
@@ -53,4 +49,29 @@ export function buildEnvironmentContext(runtimeParams) {
53
49
  uiBasePath,
54
50
  };
55
51
  }
52
+ export const REQUEST_DEPTH_HEADER = 'X-SFDC-Request-Depth';
53
+ export const REQUEST_DEPTH_KEY = REQUEST_DEPTH_HEADER.toLowerCase();
54
+ export function parseRequestDepthHeader(headers = {}) {
55
+ let maxDepth = 0;
56
+ const value = headers && headers[REQUEST_DEPTH_KEY];
57
+ if (value) {
58
+ if (Array.isArray(value)) {
59
+ for (const depth of value) {
60
+ if (typeof depth === 'string') {
61
+ const depthValue = parseInt(depth, 10);
62
+ if (!isNaN(depthValue) && depthValue > maxDepth) {
63
+ maxDepth = depthValue;
64
+ }
65
+ }
66
+ }
67
+ }
68
+ else if (typeof value === 'string') {
69
+ const depth = parseInt(value, 10);
70
+ if (!isNaN(depth) && depth > maxDepth) {
71
+ maxDepth = depth;
72
+ }
73
+ }
74
+ }
75
+ return maxDepth;
76
+ }
56
77
  //# sourceMappingURL=env.js.map
package/build/es/fs.d.ts CHANGED
@@ -3,6 +3,9 @@
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_HTTP = "http://";
7
+ export declare const PROTOCOL_HTTPS = "https://";
8
+ export declare const PROTOCOL_FILE = "file://";
6
9
  /**
7
10
  * Create a hash string for a source
8
11
  * @param source
@@ -32,6 +35,15 @@ export declare function canResolveView(source: unknown, type: string): boolean;
32
35
  */
33
36
  export declare function getViewSourceFromFile(source: string): ViewSource;
34
37
  export declare function normalizeDirectory(dir: string, rootDir: string): string;
38
+ /**
39
+ * Replace all instances of `$rootDir` with `rootDir`.
40
+ * Convert path to file:// url
41
+ * @param file
42
+ * @param rootDir
43
+ */
44
+ export declare function normalizeToFileUrl(filePath: string, rootDir: string): string;
45
+ export declare function normalizeFromFileURL(fileURL: string | undefined, basePath: string): string | null;
46
+ export declare function isLocalPath(filePath: string): boolean;
35
47
  export declare function normalizeResourcePath(rawPath: string, { rootDir, assets, contentDir, layoutsDir }: ResourcePaths, allowUnresolvedAlias?: boolean): string;
36
48
  export { lookup as mimeLookup };
37
49
  /**
@@ -40,4 +52,5 @@ export { lookup as mimeLookup };
40
52
  export declare function normalizeAssetSpecifier(assetId: AssetIdentifier, assetPathMap: Map<string, string>, resourcePaths: ResourcePaths, basePath: string): string;
41
53
  export declare function streamToString(stream: Readable, encoding?: BufferEncoding): Promise<string>;
42
54
  export declare function stringToStream(str: string | Buffer): Readable;
55
+ export declare function filterProtocolEntries(record: Record<string, string>, protocol: string): Record<string, string>;
43
56
  //# 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,10 @@ 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_HTTP = 'http://';
14
+ export const PROTOCOL_HTTPS = 'https://';
15
+ export const PROTOCOL_FILE = 'file://';
11
16
  /**
12
17
  * Create a hash string for a source
13
18
  * @param source
@@ -99,6 +104,63 @@ const ROOT_DIR_REGEX = /\$rootDir/g;
99
104
  export function normalizeDirectory(dir, rootDir) {
100
105
  return dir.replace(ROOT_DIR_REGEX, rootDir);
101
106
  }
107
+ /**
108
+ * Replace all instances of `$rootDir` with `rootDir`.
109
+ * Convert path to file:// url
110
+ * @param file
111
+ * @param rootDir
112
+ */
113
+ export function normalizeToFileUrl(filePath, rootDir) {
114
+ // Check if filePath already starts with 'file://'
115
+ if (filePath.startsWith(PROTOCOL_FILE)) {
116
+ return filePath;
117
+ }
118
+ const replacedPath = filePath.replace(ROOT_DIR_REGEX, rootDir);
119
+ const fullPath = pathLib.resolve(rootDir, replacedPath);
120
+ return url.pathToFileURL(fullPath).href;
121
+ }
122
+ export function normalizeFromFileURL(fileURL, basePath) {
123
+ if (typeof fileURL !== 'string' || !fileURL.startsWith('file://')) {
124
+ return null;
125
+ }
126
+ // Convert fileURL to a system-specific path
127
+ const filePath = url.fileURLToPath(fileURL);
128
+ // Resolve and normalize base path to ensure it's in the correct format and system-specific
129
+ const normalizedBasePath = pathLib.resolve(pathLib.normalize(basePath));
130
+ // Ensure compatibility across different OS by replacing path separators accordingly
131
+ const compatibleFilePath = filePath.split(pathLib.sep).join('/');
132
+ const compatibleBasePath = normalizedBasePath.split(pathLib.sep).join('/');
133
+ // Check if filePath starts with the basePath
134
+ if (compatibleFilePath.startsWith(compatibleBasePath)) {
135
+ // Return the relative path from basePath, ensuring it starts with a '/'
136
+ const relativePath = '/' + pathLib.relative(normalizedBasePath, filePath).split(pathLib.sep).join('/');
137
+ return relativePath;
138
+ }
139
+ else {
140
+ // Return the full path if outside of basePath, ensuring it starts with a '/'
141
+ return compatibleFilePath.startsWith('/') ? compatibleFilePath : '/' + compatibleFilePath;
142
+ }
143
+ }
144
+ export function isLocalPath(filePath) {
145
+ // handle null or undefined
146
+ if (!filePath) {
147
+ return false;
148
+ }
149
+ // Check for protocol-relative URLs or network paths
150
+ if (filePath.startsWith('//')) {
151
+ return false;
152
+ }
153
+ // Check for file protocol or absolute file paths on Unix/Linux
154
+ if (filePath.startsWith('$rootDir') || filePath.startsWith(PROTOCOL_FILE) || filePath.startsWith('/')) {
155
+ return true;
156
+ }
157
+ // Check for Windows absolute paths (e.g., C:\path\to\file)
158
+ if (/^[a-zA-Z]:\\/.test(filePath)) {
159
+ return true;
160
+ }
161
+ // Consider anything not identified as a file protocol or an absolute path as non-local
162
+ return false;
163
+ }
102
164
  /**
103
165
  * Replace all instances of `$*Dir` with `resourcePaths.*Dir`
104
166
  * @param rawPath
@@ -203,4 +265,12 @@ export function stringToStream(str) {
203
265
  });
204
266
  return readable;
205
267
  }
268
+ // Function to filter out entries where the value starts with given protocol
269
+ export function filterProtocolEntries(record, protocol) {
270
+ // Use Object.entries to get an array of [key, value] pairs,
271
+ // then filter out the pairs where value starts with {protocol}
272
+ const filteredEntries = Object.entries(record).filter(([_key, value]) => !value || !value.startsWith(protocol));
273
+ // Use Object.fromEntries to convert the filtered entries back into an object
274
+ return Object.fromEntries(filteredEntries);
275
+ }
206
276
  //# 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 {
@@ -90,16 +90,23 @@ export function explodeSpecifiers(rawSpecifiers) {
90
90
  * @example - { name: 'lwc', version: '1.7' } => 'lwc/v/1.7'
91
91
  * @example - { namespace: 'c', name: 'navMenu', version: '2.0' } => 'c/navMenu/v/2.0'
92
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'
93
94
  */
94
95
  export function getSpecifier({ specifier, namespace, name = '', version }) {
95
96
  if (specifier) {
96
97
  // Remove any versioning from the specifier
97
98
  const versionMatch = specifier.match(/(.+)\/v\/[a-zA-Z0-9-_.]+$/);
98
99
  specifier = versionMatch ? versionMatch[1] : specifier;
99
- 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;
100
104
  }
101
105
  const bareSpecifier = namespace ? `${namespace}/${name}` : name;
102
- 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;
103
110
  }
104
111
  /**
105
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,6 @@ 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;
20
+ export declare function isExternalFileSpecifier(id: string, bundleConfig: BundleConfig): boolean;
19
21
  //# sourceMappingURL=mappings.d.ts.map
@@ -1,5 +1,6 @@
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
+ import { PROTOCOL_FILE } from './fs.js';
3
4
  /**
4
5
  * Get the Import Metadata for the LWR Mapping Api (https://rfcs.lwc.dev/rfcs/lwr/0000-mapping-api)
5
6
  */
@@ -30,7 +31,7 @@ export async function getImportMetadataMappings(moduleIds, runtimeEnvironment, r
30
31
  importMetadata = await toImportMetadata(moduleGraph, importMetadata, moduleRegistry, runtimeEnvironment, runtimeParams);
31
32
  }
32
33
  // If the requested specifier is not the same as the versioned specifier, include the requested specifier's importer.
33
- if (requestedSpecifier !== specifier) {
34
+ if (moduleId.importer && requestedSpecifier !== specifier) {
34
35
  const requestedSpecifierPlusImporter = `${requestedSpecifier}?importer=${moduleId.importer}`;
35
36
  const specifiersArray = Object.values(importMetadata.imports).find((a) => a.includes(specifier));
36
37
  if (!specifiersArray) {
@@ -64,6 +65,13 @@ export async function toImportMetadata(moduleGraph, existingImportMetadata = { i
64
65
  if (!definition) {
65
66
  throw new Error('Linked module definition was not included in the graph: ' + specifier);
66
67
  }
68
+ // Add a single entry for an external
69
+ if (isExternalSpecifier(specifier, moduleRegistry.getConfig().bundleConfig)) {
70
+ const externalMapping = { imports: {}, index: {} };
71
+ externalMapping.imports[uri] = [specifier];
72
+ externalMapping.index[specifier] = uri;
73
+ return externalMapping;
74
+ }
67
75
  // Merge in the existing metadata with imports for the root specifier
68
76
  const rootMetadata = await normalizeImportMetadata(specifier, uri, definition, moduleRegistry, runtimeEnvironment, runtimeParams);
69
77
  let importMetadata = mergeImportMetadata(existingImportMetadata, rootMetadata);
@@ -74,6 +82,10 @@ export async function toImportMetadata(moduleGraph, existingImportMetadata = { i
74
82
  ? moduleGraph.graphs[0].dynamicRefs
75
83
  : moduleGraph.graphs[0].static;
76
84
  for (const depSpecifier of depSpecifiers) {
85
+ if (isExternalSpecifier(depSpecifier, moduleRegistry.getConfig().bundleConfig)) {
86
+ // Ignore Externals
87
+ continue;
88
+ }
77
89
  const depUri = moduleGraph.uriMap[depSpecifier];
78
90
  const depDef = moduleGraph.linkedDefinitions[depSpecifier];
79
91
  const depMissing = !depUri || !depDef;
@@ -90,9 +102,12 @@ export async function toImportMetadata(moduleGraph, existingImportMetadata = { i
90
102
  continue;
91
103
  }
92
104
  if (!importMetadata.imports[depUri]) {
93
- // eslint-disable-next-line no-await-in-loop
94
- const depMetadata = await normalizeImportMetadata(getSpecifier(depDef), depUri, depDef, moduleRegistry, runtimeEnvironment, runtimeParams);
95
- importMetadata = mergeImportMetadata(importMetadata, depMetadata);
105
+ const depDefSpecifier = getSpecifier(depDef);
106
+ if (!isExternalSpecifier(depDefSpecifier, moduleRegistry.getConfig().bundleConfig)) {
107
+ // eslint-disable-next-line no-await-in-loop
108
+ const depMetadata = await normalizeImportMetadata(depDefSpecifier, depUri, depDef, moduleRegistry, runtimeEnvironment, runtimeParams);
109
+ importMetadata = mergeImportMetadata(importMetadata, depMetadata);
110
+ }
96
111
  }
97
112
  }
98
113
  return importMetadata;
@@ -138,24 +153,23 @@ async function createIndex(specifiers, moduleRegistry, runtimeEnvironment, runti
138
153
  const moduleRuntimeEnvironment = { ...runtimeEnvironment, bundle: false };
139
154
  async function getUri(specifier) {
140
155
  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
156
+ // Do not use replace with the moduleBundler. Otherwise we will create a bundle from every
145
157
  // root just to get the URL.
146
- index[specifier] = await moduleRegistry.resolveModuleUri({ ...moduleId, version: moduleId.version }, moduleRuntimeEnvironment, runtimeParams);
158
+ index[specifier] = await moduleRegistry.resolveModuleUri({ ...moduleId, version: moduleId.version || VERSION_NOT_PROVIDED }, moduleRuntimeEnvironment, runtimeParams);
147
159
  }
148
160
  // Queue up uri requests
149
161
  const promises = [];
150
162
  for (const specifier of specifiers) {
151
- promises.push(getUri(specifier));
163
+ if (!isExternalSpecifier(specifier, moduleRegistry.getConfig().bundleConfig)) {
164
+ promises.push(getUri(specifier));
165
+ }
152
166
  }
153
167
  // Wait for them to finish
154
168
  await Promise.all(promises);
155
169
  return index;
156
170
  }
157
171
  async function getVersionedSpecifier(moduleId, moduleRegistry, runtimeParams) {
158
- if (!moduleId.importer || moduleId.version) {
172
+ if (moduleId.version) {
159
173
  return getSpecifier(moduleId);
160
174
  }
161
175
  const versionedModuleEntry = await moduleRegistry.getModuleEntry({
@@ -163,4 +177,14 @@ async function getVersionedSpecifier(moduleId, moduleRegistry, runtimeParams) {
163
177
  }, runtimeParams);
164
178
  return getSpecifier(versionedModuleEntry);
165
179
  }
180
+ export function isExternalSpecifier(id, bundleConfig) {
181
+ const { specifier } = explodeSpecifier(id);
182
+ return !!(bundleConfig?.external && Object.prototype.hasOwnProperty.call(bundleConfig.external, specifier));
183
+ }
184
+ export function isExternalFileSpecifier(id, bundleConfig) {
185
+ const { specifier } = explodeSpecifier(id);
186
+ return !!(bundleConfig?.external &&
187
+ bundleConfig.external[specifier] &&
188
+ bundleConfig.external[specifier].startsWith(PROTOCOL_FILE));
189
+ }
166
190
  //# sourceMappingURL=mappings.js.map
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
- "version": "0.12.0-alpha.9",
7
+ "version": "0.12.1",
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.9",
40
+ "@lwrjs/diagnostics": "0.12.1",
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.8",
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.9",
54
- "@types/mime-types": "2.1.1",
53
+ "@lwrjs/types": "0.12.1",
54
+ "@types/mime-types": "2.1.4",
55
55
  "@types/path-to-regexp": "^1.7.0"
56
56
  },
57
57
  "engines": {
58
58
  "node": ">=18.0.0"
59
59
  },
60
- "gitHead": "58b28fbc6300b704ac17f8878423120de0e376d7"
60
+ "gitHead": "4f8b2759b540af7443f07528980ddb0e7d4d5e3a"
61
61
  }