UNPKG

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