@zaininnari/postcss-cachebuster 0.4.0 → 0.4.1

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.
@@ -0,0 +1,28 @@
1
+ name: Lint
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ jobs:
8
+ test:
9
+ runs-on: ubuntu-latest
10
+
11
+ strategy:
12
+ matrix:
13
+ node-version: [20, 22, 24]
14
+
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+
18
+ - name: Use Node.js
19
+ uses: actions/setup-node@v4
20
+ with:
21
+ node-version: ${{ matrix.node-version }}
22
+ cache: 'npm'
23
+
24
+ - name: Install dependencies
25
+ run: npm ci
26
+
27
+ - name: Run tests
28
+ run: npm run lint
package/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.1 (2026-01-02)
4
+ - Add ESLint
5
+ - @eslint/js recommended
6
+ - eslint-plugin-n recommended
7
+
3
8
  ## 0.4.0 (2025-12-30)
4
9
  - update dependencies
5
10
  - update support node version 20+
@@ -0,0 +1,22 @@
1
+ import js from "@eslint/js";
2
+ import globals from "globals";
3
+ import n from "eslint-plugin-n";
4
+ import {defineConfig} from "eslint/config";
5
+
6
+ export default defineConfig([
7
+ {
8
+ files: ["**/*.{js,mjs,cjs}"],
9
+ languageOptions: {
10
+ ecmaVersion: "latest",
11
+ sourceType: "module",
12
+ globals: {
13
+ ...globals.node,
14
+ ...globals.mocha,
15
+ myCustomGlobal: "readonly",
16
+ },
17
+ },
18
+ plugins: {js, n},
19
+ extends: ["js/recommended", "n/recommended"],
20
+ ignores: ['eslint.config.js'],
21
+ },
22
+ ]);
package/index.mjs CHANGED
@@ -1,4 +1,3 @@
1
- import url from 'url';
2
1
  import fs from 'fs';
3
2
  import crypto from 'crypto';
4
3
  import chalk from 'chalk';
@@ -7,6 +6,15 @@ import path from 'canonical-path';
7
6
 
8
7
  const checksums = {};
9
8
 
9
+ /**
10
+ * parsed
11
+ * @typedef {Object} parsed
12
+ * @property {URL} u
13
+ * @property {boolean} isAbsolute
14
+ * @property {boolean} isRootRelativeButNotProtocolRelative
15
+ * @property {string} originalUrl
16
+ */
17
+
10
18
  const plugin = (opts = {}) => {
11
19
  const pattern = /url\((['"])?([^'")]+)(['"])?\)/g;
12
20
  const supportedPropsDefault = [
@@ -56,10 +64,17 @@ const plugin = (opts = {}) => {
56
64
  return cachebuster;
57
65
  }
58
66
 
59
- function resolveUrl(assetUrl, file, imagesPath) {
67
+ /**
68
+ * @param assetUrl {URL}
69
+ * @param file {string}
70
+ * @param imagesPath {string}
71
+ * @param isRootRelativeButNotProtocolRelative {boolean}
72
+ * @returns {string}
73
+ */
74
+ function resolveUrl(assetUrl, file, imagesPath, isRootRelativeButNotProtocolRelative) {
60
75
  let assetPath = decodeURI(assetUrl.pathname);
61
76
 
62
- if (/^\//.test(assetUrl.pathname)) {
77
+ if (isRootRelativeButNotProtocolRelative) {
63
78
  assetPath = path.join(imagesPath, assetPath);
64
79
  } else {
65
80
  assetPath = path.join(opts.cssPath || path.dirname(file), assetPath);
@@ -67,14 +82,22 @@ const plugin = (opts = {}) => {
67
82
  return assetPath;
68
83
  }
69
84
 
70
- function updateAssetUrl(assetUrl, inputFile) {
71
- const assetPath = resolveUrl(assetUrl, inputFile, opts.imagesPath);
85
+ /**
86
+ * @param assetUrl {URL}
87
+ * @param inputFile {string}
88
+ * @param isRootRelativeButNotProtocolRelative {boolean}
89
+ */
90
+ function updateAssetUrl(assetUrl, inputFile, isRootRelativeButNotProtocolRelative) {
91
+ const assetPath = resolveUrl(assetUrl, inputFile, opts.imagesPath, isRootRelativeButNotProtocolRelative);
72
92
 
73
93
  // complete url with cachebuster
74
- const cachebuster = createCachebuster(assetPath, assetUrl.pathname, opts.type);
94
+ const originPath = isRootRelativeButNotProtocolRelative ? assetUrl.pathname : assetUrl.pathname.substring(1);
95
+ const cachebuster = createCachebuster(assetPath, originPath, opts.type);
75
96
  if (!cachebuster) {
76
97
  return;
77
- } else if (typeof opts.type === 'function') {
98
+ }
99
+
100
+ if (typeof opts.type === 'function') {
78
101
  assetUrl.pathname = cachebuster;
79
102
  } else if (assetUrl.search && assetUrl.search.length > 1) {
80
103
  assetUrl.search = assetUrl.search + '&' + opts.paramName + cachebuster;
@@ -83,6 +106,39 @@ const plugin = (opts = {}) => {
83
106
  }
84
107
  }
85
108
 
109
+ const DUMMY_BASE = 'http://localhost';
110
+
111
+ /**
112
+ * @param input {string}
113
+ * @returns {parsed}
114
+ */
115
+ function parseUrlPreserveRelative(input) {
116
+ const isAbsolute = /^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(input);
117
+ const isRootRelativeButNotProtocolRelative = /^\/(?!\/)/.test(input);
118
+ const u = isAbsolute ? new URL(input) : new URL(input, DUMMY_BASE);
119
+ return {u, isAbsolute, isRootRelativeButNotProtocolRelative, originalUrl: input};
120
+ }
121
+
122
+ /**
123
+ * @param parsed {parsed}
124
+ * @returns {string|string}
125
+ */
126
+ function formatUrlPreserveRelative(parsed) {
127
+ const u = parsed.u;
128
+ const isAbsolute = parsed.isAbsolute;
129
+ const isRootRelativeButNotProtocolRelative = parsed.isRootRelativeButNotProtocolRelative;
130
+
131
+ if (isAbsolute) {
132
+ return u.toString();
133
+ }
134
+ const url = `${u.pathname}${u.search}${u.hash}`;
135
+ if (!isRootRelativeButNotProtocolRelative) {
136
+ // remove start slash
137
+ return url.substring(1);
138
+ }
139
+ return url;
140
+ }
141
+
86
142
  return {
87
143
  postcssPlugin: 'postcss-cachebuster',
88
144
  Once(root) {
@@ -96,10 +152,10 @@ const plugin = (opts = {}) => {
96
152
  const quote = results[1] || '"';
97
153
  const originalUrl = results[2];
98
154
 
99
- const assetUrl = url.parse(originalUrl);
100
- updateAssetUrl(assetUrl, inputFile);
155
+ const parsed = parseUrlPreserveRelative(originalUrl);
156
+ updateAssetUrl(parsed.u, inputFile, parsed.isRootRelativeButNotProtocolRelative, parsed.originalUrl);
101
157
 
102
- atrule.params = 'url(' + quote + url.format(assetUrl) + quote + ')';
158
+ atrule.params = 'url(' + quote + formatUrlPreserveRelative(parsed) + quote + ')';
103
159
  });
104
160
 
105
161
  root.walkDecls(function walkThroughtDeclarations(declaration) {
@@ -111,20 +167,22 @@ const plugin = (opts = {}) => {
111
167
  declaration.value = declaration.value.replace(pattern, function (match, quote, originalUrl) {
112
168
  quote = quote || '"';
113
169
 
114
- const assetUrl = url.parse(originalUrl);
170
+ const parsed = parseUrlPreserveRelative(originalUrl);
171
+ const assetUrl = parsed.u;
115
172
 
116
173
  // only locals
117
174
  if (
118
- assetUrl.host ||
175
+ assetUrl.toString().indexOf(DUMMY_BASE) !== 0 ||
176
+ parsed.isAbsolute ||
119
177
  assetUrl.pathname.indexOf('//') === 0 ||
120
178
  assetUrl.pathname.indexOf(';base64') !== -1
121
179
  ) {
122
180
  return match;
123
181
  }
124
182
 
125
- updateAssetUrl(assetUrl, inputFile);
183
+ updateAssetUrl(assetUrl, inputFile, parsed.isRootRelativeButNotProtocolRelative);
126
184
 
127
- return 'url(' + quote + url.format(assetUrl) + quote + ')';
185
+ return 'url(' + quote + formatUrlPreserveRelative(parsed) + quote + ')';
128
186
  });
129
187
  });
130
188
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zaininnari/postcss-cachebuster",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Fork of postcss-cachebuster. Cachebusting all local files in css",
5
5
  "keywords": [
6
6
  "postcss",
@@ -38,7 +38,11 @@
38
38
  "path": "^0.12.7"
39
39
  },
40
40
  "devDependencies": {
41
+ "@eslint/js": "^9.39.2",
41
42
  "chai": "^6.2.2",
43
+ "eslint": "^9.39.2",
44
+ "eslint-plugin-n": "^17.23.1",
45
+ "globals": "^16.5.0",
42
46
  "gulp": "^5.0.1",
43
47
  "gulp-mocha": "^10.0.1",
44
48
  "gulp-postcss": "^10.0.0",
@@ -50,6 +54,7 @@
50
54
  "glob": "9.3.5"
51
55
  },
52
56
  "scripts": {
57
+ "lint": "eslint .",
53
58
  "test": "gulp --gulpfile gulpfile.mjs"
54
59
  }
55
60
  }
package/.eslintrc.json DELETED
@@ -1,13 +0,0 @@
1
-
2
- {
3
- "rules": {
4
- "max-len": 0,
5
- "indent": ["error", 2, { "VariableDeclarator": 1 }],
6
- "global-require": 0,
7
- "func-names": 0,
8
- "prefer-rest-params": 1,
9
- "strict": 1,
10
- "no-param-reassign": 0
11
- }
12
- }
13
-