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 | const assert_1 = __importDefault(require("assert"));
|
7 | const utils_1 = require("./utils");
|
8 | function 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 |
|
34 | return {
|
35 | imports: sortedAndNormalizedImports,
|
36 | scopes: sortedAndNormalizedScopes,
|
37 | };
|
38 | }
|
39 | exports.parseFromString = parseFromString;
|
40 | function 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 | }
|
75 | function 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 | }
|
96 | function normalizeSpecifierKey(specifierKey, baseURL) {
|
97 |
|
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 | }
|
108 | function isJSONObject(value) {
|
109 | return typeof value === "object" && value !== null && !Array.isArray(value);
|
110 | }
|
111 | function codeUnitCompare(a, b) {
|
112 | if (a > b) {
|
113 | return 1;
|
114 | }
|
115 |
|
116 | if (b > a) {
|
117 | return -1;
|
118 | }
|
119 |
|
120 | throw new Error("This should never be reached because this is only used on JSON object keys");
|
121 | }
|