UNPKG

5 kBJavaScriptView Raw
1"use strict";
2var __importDefault = (this && this.__importDefault) || function (mod) {
3 return (mod && mod.__esModule) ? mod : { "default": mod };
4};
5Object.defineProperty(exports, "__esModule", { value: true });
6exports.parseFromString = void 0;
7const assert_1 = __importDefault(require("assert"));
8const utils_1 = require("./utils");
9function parseFromString(input, baseURL) {
10 const parsed = JSON.parse(input);
11 if (!isJSONObject(parsed)) {
12 throw new TypeError("Import map JSON must be an object.");
13 }
14 let sortedAndNormalizedImports = {};
15 if ("imports" in parsed) {
16 if (!isJSONObject(parsed.imports)) {
17 throw new TypeError("Import map's imports value must be an object.");
18 }
19 sortedAndNormalizedImports = sortAndNormalizeSpecifierMap(parsed.imports, baseURL);
20 }
21 let sortedAndNormalizedScopes = {};
22 if ("scopes" in parsed) {
23 if (!isJSONObject(parsed.scopes)) {
24 throw new TypeError("Import map's scopes value must be an object.");
25 }
26 sortedAndNormalizedScopes = sortAndNormalizeScopes(parsed.scopes, baseURL);
27 }
28 const badTopLevelKeys = new Set(Object.keys(parsed));
29 badTopLevelKeys.delete("imports");
30 badTopLevelKeys.delete("scopes");
31 for (const badKey of badTopLevelKeys) {
32 console.warn(`Invalid top-level key "${badKey}". Only "imports" and "scopes" can be present.`);
33 }
34 // Always have these two keys, and exactly these two keys, in the result.
35 return {
36 imports: sortedAndNormalizedImports,
37 scopes: sortedAndNormalizedScopes,
38 };
39}
40exports.parseFromString = parseFromString;
41function sortAndNormalizeSpecifierMap(obj, baseURL) {
42 assert_1.default(isJSONObject(obj));
43 const normalized = {};
44 for (const [specifierKey, value] of Object.entries(obj)) {
45 const normalizedSpecifierKey = normalizeSpecifierKey(specifierKey, baseURL);
46 if (normalizedSpecifierKey === null) {
47 continue;
48 }
49 if (typeof value !== "string") {
50 console.warn(`Invalid address ${JSON.stringify(value)} for the specifier key "${specifierKey}". ` +
51 `Addresses must be strings.`);
52 normalized[normalizedSpecifierKey] = null;
53 continue;
54 }
55 const addressURL = utils_1.tryURLLikeSpecifierParse(value, baseURL);
56 if (addressURL === null) {
57 console.warn(`Invalid address "${value}" for the specifier key "${specifierKey}".`);
58 normalized[normalizedSpecifierKey] = null;
59 continue;
60 }
61 if (specifierKey.endsWith("/") && !addressURL.href.endsWith("/")) {
62 console.warn(`Invalid address "${addressURL.href}" for package specifier key "${specifierKey}". ` +
63 `Package addresses must end with "/".`);
64 normalized[normalizedSpecifierKey] = null;
65 continue;
66 }
67 normalized[normalizedSpecifierKey] = addressURL;
68 }
69 const sortedAndNormalized = {};
70 const sortedKeys = Object.keys(normalized).sort((a, b) => codeUnitCompare(b, a));
71 for (const key of sortedKeys) {
72 sortedAndNormalized[key] = normalized[key];
73 }
74 return sortedAndNormalized;
75}
76function sortAndNormalizeScopes(obj, baseURL) {
77 const normalized = {};
78 for (const [scopePrefix, potentialSpecifierMap] of Object.entries(obj)) {
79 if (!isJSONObject(potentialSpecifierMap)) {
80 throw new TypeError(`The value for the "${scopePrefix}" scope prefix must be an object.`);
81 }
82 const scopePrefixURL = utils_1.tryURLParse(scopePrefix, baseURL);
83 if (scopePrefixURL === null) {
84 console.warn(`Invalid scope "${scopePrefix}" (parsed against base URL "${baseURL}").`);
85 continue;
86 }
87 const normalizedScopePrefix = scopePrefixURL.href;
88 normalized[normalizedScopePrefix] = sortAndNormalizeSpecifierMap(potentialSpecifierMap, baseURL);
89 }
90 const sortedAndNormalized = {};
91 const sortedKeys = Object.keys(normalized).sort((a, b) => codeUnitCompare(b, a));
92 for (const key of sortedKeys) {
93 sortedAndNormalized[key] = normalized[key];
94 }
95 return sortedAndNormalized;
96}
97function normalizeSpecifierKey(specifierKey, baseURL) {
98 // Ignore attempts to use the empty string as a specifier key
99 if (specifierKey === "") {
100 console.warn(`Invalid empty string specifier key.`);
101 return null;
102 }
103 const url = utils_1.tryURLLikeSpecifierParse(specifierKey, baseURL);
104 if (url !== null) {
105 return url.href;
106 }
107 return specifierKey;
108}
109function isJSONObject(value) {
110 return typeof value === "object" && value !== null && !Array.isArray(value);
111}
112function codeUnitCompare(a, b) {
113 if (a > b) {
114 return 1;
115 }
116 /* istanbul ignore else */
117 if (b > a) {
118 return -1;
119 }
120 /* istanbul ignore next */
121 throw new Error("This should never be reached because this is only used on JSON object keys");
122}