1 | "use strict";
|
2 | var __importDefault = (this && this.__importDefault) || function (mod) {
|
3 | return (mod && mod.__esModule) ? mod : { "default": mod };
|
4 | };
|
5 | Object.defineProperty(exports, "__esModule", { value: true });
|
6 | exports.parseFromString = void 0;
|
7 | const assert_1 = __importDefault(require("assert"));
|
8 | const utils_1 = require("./utils");
|
9 | function 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 |
|
35 | return {
|
36 | imports: sortedAndNormalizedImports,
|
37 | scopes: sortedAndNormalizedScopes,
|
38 | };
|
39 | }
|
40 | exports.parseFromString = parseFromString;
|
41 | function 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 | }
|
76 | function 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 | }
|
97 | function normalizeSpecifierKey(specifierKey, baseURL) {
|
98 |
|
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 | }
|
109 | function isJSONObject(value) {
|
110 | return typeof value === "object" && value !== null && !Array.isArray(value);
|
111 | }
|
112 | function codeUnitCompare(a, b) {
|
113 | if (a > b) {
|
114 | return 1;
|
115 | }
|
116 |
|
117 | if (b > a) {
|
118 | return -1;
|
119 | }
|
120 |
|
121 | throw new Error("This should never be reached because this is only used on JSON object keys");
|
122 | }
|