@eik/postcss-plugin 4.0.0 → 4.0.2
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.
- package/CHANGELOG.md +14 -0
- package/package.json +22 -18
- package/src/plugin.js +157 -112
- package/types/plugin.d.ts +26 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [4.0.2](https://github.com/eik-lib/postcss-import-map/compare/v4.0.1...v4.0.2) (2024-08-12)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **deps:** update dependency @eik/common to v4.0.8 ([169bffa](https://github.com/eik-lib/postcss-import-map/commit/169bffa9abe95c6d79e5987c679f4e1e619e94ee))
|
|
7
|
+
|
|
8
|
+
## [4.0.1](https://github.com/eik-lib/postcss-import-map/compare/v4.0.0...v4.0.1) (2024-08-09)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* include type definitions ([7ad7a16](https://github.com/eik-lib/postcss-import-map/commit/7ad7a16ea7f4ca246383cf1b8797f45b0dd2995d))
|
|
14
|
+
|
|
1
15
|
# [4.0.0](https://github.com/eik-lib/postcss-import-map/compare/v3.0.14...v4.0.0) (2024-07-29)
|
|
2
16
|
|
|
3
17
|
|
package/package.json
CHANGED
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eik/postcss-plugin",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.2",
|
|
4
4
|
"description": "PostCSS plugin that uses Eik defined import map files to transform bare import specifiers to absolute URLs in @import rules",
|
|
5
5
|
"main": "src/plugin.js",
|
|
6
|
+
"types": "./types/plugin.d.ts",
|
|
6
7
|
"type": "module",
|
|
7
8
|
"files": [
|
|
8
9
|
"CHANGELOG.md",
|
|
9
10
|
"package.json",
|
|
10
|
-
"src/"
|
|
11
|
+
"src/",
|
|
12
|
+
"types/"
|
|
11
13
|
],
|
|
12
14
|
"scripts": {
|
|
15
|
+
"clean": "rimraf .tap node_modules types",
|
|
13
16
|
"test": "tap test/*.js --disable-coverage --allow-empty-coverage",
|
|
14
17
|
"test:snapshot": "TAP_SNAPSHOT=1 tap test/*.js --disable-coverage --allow-empty-coverage",
|
|
15
18
|
"lint": "eslint .",
|
|
16
|
-
"lint:fix": "eslint . --fix"
|
|
19
|
+
"lint:fix": "eslint . --fix",
|
|
20
|
+
"types": "run-s types:module types:test",
|
|
21
|
+
"types:module": "tsc",
|
|
22
|
+
"types:test": "tsc --project tsconfig.test.json"
|
|
17
23
|
},
|
|
18
24
|
"repository": {
|
|
19
25
|
"type": "git",
|
|
@@ -33,25 +39,23 @@
|
|
|
33
39
|
},
|
|
34
40
|
"homepage": "https://github.com/eik-lib/postcss-import-map#readme",
|
|
35
41
|
"devDependencies": {
|
|
36
|
-
"@
|
|
37
|
-
"@
|
|
38
|
-
"@semantic-release
|
|
39
|
-
"@
|
|
40
|
-
"
|
|
41
|
-
"@semantic-release/release-notes-generator": "14.0.1",
|
|
42
|
-
"eslint": "9.8.0",
|
|
43
|
-
"eslint-config-prettier": "9.1.0",
|
|
44
|
-
"eslint-plugin-prettier": "5.2.1",
|
|
42
|
+
"@eik/eslint-config": "1.0.2",
|
|
43
|
+
"@eik/prettier-config": "1.0.1",
|
|
44
|
+
"@eik/semantic-release-config": "1.0.0",
|
|
45
|
+
"@eik/typescript-config": "1.0.0",
|
|
46
|
+
"eslint": "9.9.0",
|
|
45
47
|
"fastify": "4.28.1",
|
|
46
|
-
"
|
|
47
|
-
"postcss": "8.4.
|
|
48
|
-
"rollup": "4.19.1",
|
|
49
|
-
"semantic-release": "24.0.0",
|
|
48
|
+
"npm-run-all2": "5.0.0",
|
|
49
|
+
"postcss": "8.4.41",
|
|
50
50
|
"prettier": "3.3.3",
|
|
51
|
-
"
|
|
51
|
+
"rimraf": "6.0.1",
|
|
52
|
+
"rollup": "4.20.0",
|
|
53
|
+
"semantic-release": "24.0.0",
|
|
54
|
+
"tap": "20.0.3",
|
|
55
|
+
"typescript": "5.5.4"
|
|
52
56
|
},
|
|
53
57
|
"dependencies": {
|
|
54
|
-
"@eik/common
|
|
58
|
+
"@eik/common": "4.0.8",
|
|
55
59
|
"css-url-parser": "1.1.3"
|
|
56
60
|
},
|
|
57
61
|
"peerDependencies": {
|
package/src/plugin.js
CHANGED
|
@@ -1,118 +1,163 @@
|
|
|
1
|
-
import parseCssUrls from
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import parseCssUrls from "css-url-parser";
|
|
2
|
+
import { helpers } from "@eik/common";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @param {string} url
|
|
6
|
+
* @returns {boolean}
|
|
7
|
+
*/
|
|
8
|
+
const notUrl = (url) => url.substr(0, 4) !== "http";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @typedef {object} ImportMap
|
|
12
|
+
* @property {Record<string, string>} imports
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param {string[]} urls
|
|
17
|
+
* @returns {Promise<ImportMap[]>}
|
|
18
|
+
*/
|
|
6
19
|
async function fetchImportMaps(urls = []) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
try {
|
|
21
|
+
const maps = urls.map((map) =>
|
|
22
|
+
fetch(map).then((result) => {
|
|
23
|
+
if (result.status === 404) {
|
|
24
|
+
throw new Error("Import map could not be found on server");
|
|
25
|
+
} else if (result.status >= 400 && result.status < 500) {
|
|
26
|
+
throw new Error("Server rejected client request");
|
|
27
|
+
} else if (result.status >= 500) {
|
|
28
|
+
throw new Error("Server error");
|
|
29
|
+
}
|
|
30
|
+
return /** @type {Promise<ImportMap>} */ (result.json());
|
|
31
|
+
}),
|
|
32
|
+
);
|
|
33
|
+
return await Promise.all(maps);
|
|
34
|
+
} catch (err) {
|
|
35
|
+
throw new Error(
|
|
36
|
+
`Unable to load import map file from server: ${err.message}`,
|
|
37
|
+
);
|
|
38
|
+
}
|
|
26
39
|
}
|
|
27
40
|
|
|
41
|
+
/**
|
|
42
|
+
* @param {ImportMap} map
|
|
43
|
+
* @returns {Array<{ key: string; value: string; }>}
|
|
44
|
+
*/
|
|
28
45
|
const validate = (map) =>
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
46
|
+
Object.keys(map.imports).map((key) => {
|
|
47
|
+
const value = map.imports[key];
|
|
48
|
+
|
|
49
|
+
if (notUrl(value)) {
|
|
50
|
+
throw Error(
|
|
51
|
+
`Import specifier can NOT be mapped to a bare import statement. Import specifier "${key}" is being wrongly mapped to "${value}"`,
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return { key, value };
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @typedef {object} PluginOptions
|
|
60
|
+
* @property {string} [path=process.cwd()]
|
|
61
|
+
* @property {string[]} [urls=[]] URLs to import maps hosted on an Eik server. Takes precedence over `eik.json`.
|
|
62
|
+
* @property {ImportMap[]} [maps=[]] Inline import maps that should be used. Takes precedence over `urls` and `eik.json`.
|
|
63
|
+
*/
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @typedef {object} PrepareResult
|
|
67
|
+
* @property {(root: import('postcss').Root) => Promise<void>} Once
|
|
68
|
+
* @property {{ import: (decl: import('postcss').AtRule) => Promise<void> }} AtRule
|
|
69
|
+
*/
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* @typedef {object} Plugin
|
|
73
|
+
* @property {string} postcssPlugin
|
|
74
|
+
* @property {() => PrepareResult} prepare
|
|
75
|
+
*/
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Returns the plugin which will apply the given import maps during the build.
|
|
79
|
+
* @param {PluginOptions} options
|
|
80
|
+
* @returns {Plugin}
|
|
81
|
+
*/
|
|
41
82
|
export default ({ path = process.cwd(), maps = [], urls = [] } = {}) => {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
83
|
+
const pMaps = Array.isArray(maps) ? maps : [maps];
|
|
84
|
+
const pUrls = Array.isArray(urls) ? urls : [urls];
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
postcssPlugin: "@eik/postcss-import-map",
|
|
88
|
+
prepare() {
|
|
89
|
+
// Avoid parsing things more than necessary
|
|
90
|
+
const processed = new WeakMap();
|
|
91
|
+
// Only replace once per url
|
|
92
|
+
const replaced = new Set();
|
|
93
|
+
// Eagerly start resolving
|
|
94
|
+
|
|
95
|
+
// Reused replace logic
|
|
96
|
+
/**
|
|
97
|
+
*
|
|
98
|
+
* @param {Map<string, string>} mapping
|
|
99
|
+
* @param {import('postcss').AtRule} decl
|
|
100
|
+
* @returns {void}
|
|
101
|
+
*/
|
|
102
|
+
const applyImportMap = (mapping, decl) => {
|
|
103
|
+
if (processed.has(decl)) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
let key;
|
|
108
|
+
// First check if it's possibly using syntax like url()
|
|
109
|
+
const parsedUrls = parseCssUrls(decl.params);
|
|
110
|
+
if (parsedUrls.length > 0) {
|
|
111
|
+
key = parsedUrls[0];
|
|
112
|
+
} else {
|
|
113
|
+
// Handle the common cases where it's not wrapped in url() but may have quotes
|
|
114
|
+
key = decl.params.replace(/["']/g, "");
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Webpack interop
|
|
118
|
+
key = key.replace(/^~/, "");
|
|
119
|
+
|
|
120
|
+
if (replaced.has(key)) {
|
|
121
|
+
decl.remove();
|
|
122
|
+
} else if (mapping.has(key)) {
|
|
123
|
+
decl.params = `'${mapping.get(key)}'`;
|
|
124
|
+
replaced.add(key);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Cache we've processed this
|
|
128
|
+
processed.set(decl, true);
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
/** @type {Map<string, string>} */
|
|
132
|
+
const mapping = new Map();
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
// Run initially once, this is to ensure it runs before postcss-import
|
|
136
|
+
async Once(root) {
|
|
137
|
+
// Load eik config from eik.json or package.json
|
|
138
|
+
const config = await helpers.getDefaults(path);
|
|
139
|
+
|
|
140
|
+
// Fetch import maps from the server
|
|
141
|
+
const fetched = await fetchImportMaps([...config.map, ...pUrls]);
|
|
142
|
+
|
|
143
|
+
const allImportMaps = [...fetched, ...pMaps];
|
|
144
|
+
allImportMaps.forEach((item) => {
|
|
145
|
+
const i = validate(item);
|
|
146
|
+
i.forEach((obj) => {
|
|
147
|
+
mapping.set(obj.key, obj.value);
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
root.walkAtRules("import", (decl) => {
|
|
152
|
+
applyImportMap(mapping, decl);
|
|
153
|
+
});
|
|
154
|
+
},
|
|
155
|
+
AtRule: {
|
|
156
|
+
import: async (decl) => {
|
|
157
|
+
applyImportMap(mapping, decl);
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
},
|
|
162
|
+
};
|
|
118
163
|
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
declare function _default({ path, maps, urls }?: PluginOptions): Plugin;
|
|
2
|
+
export default _default;
|
|
3
|
+
export type ImportMap = {
|
|
4
|
+
imports: Record<string, string>;
|
|
5
|
+
};
|
|
6
|
+
export type PluginOptions = {
|
|
7
|
+
path?: string;
|
|
8
|
+
/**
|
|
9
|
+
* URLs to import maps hosted on an Eik server. Takes precedence over `eik.json`.
|
|
10
|
+
*/
|
|
11
|
+
urls?: string[];
|
|
12
|
+
/**
|
|
13
|
+
* Inline import maps that should be used. Takes precedence over `urls` and `eik.json`.
|
|
14
|
+
*/
|
|
15
|
+
maps?: ImportMap[];
|
|
16
|
+
};
|
|
17
|
+
export type PrepareResult = {
|
|
18
|
+
Once: (root: import("postcss").Root) => Promise<void>;
|
|
19
|
+
AtRule: {
|
|
20
|
+
import: (decl: import("postcss").AtRule) => Promise<void>;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
export type Plugin = {
|
|
24
|
+
postcssPlugin: string;
|
|
25
|
+
prepare: () => PrepareResult;
|
|
26
|
+
};
|