@localnerve/sass-asset-functions 7.10.0 → 7.11.0

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 CHANGED
@@ -1,5 +1,9 @@
1
1
  # Sass Asset Functions Change Log
2
2
 
3
+ # 7.11.0
4
+ * standard URL processing, deprecate messages for old api if needed
5
+ * devdeps - remove jest, rimraf, new lint rules, bump gha
6
+
3
7
  # 7.10.0
4
8
  * sass 1.99.0
5
9
  * devdeps
@@ -62,14 +62,21 @@ class Processor {
62
62
  if (typeof buster !== 'function') {
63
63
  throw new Error('asset_cache_buster should be a function');
64
64
  }
65
- const http_path_url = url.parse(http_path);
65
+ function preserveEmptyQS(originalUrl, query) {
66
+ let result = query;
67
+ if (!query && originalUrl.includes('?')) {
68
+ result = '?';
69
+ }
70
+ return result;
71
+ }
72
+ const http_path_url = this.parse_url(http_path);
66
73
  buster(http_path, real_path, value => {
67
74
  let new_url;
68
75
  if (typeof value == 'object') {
69
- const parsed_path = url.parse(value.path);
76
+ const parsed_path = this.parse_url(value.path);
70
77
  new_url = {
71
78
  pathname: parsed_path.pathname,
72
- search: value.query || http_path_url.search
79
+ search: value.query || preserveEmptyQS(http_path, http_path_url.search)
73
80
  };
74
81
  } else {
75
82
  new_url = {
@@ -88,9 +95,41 @@ class Processor {
88
95
  throw new Error('asset_host should be a function');
89
96
  }
90
97
  ahost(filepath, host => {
91
- done(url.resolve(host, filepath));
98
+ done(this.resolve_url(host, filepath));
92
99
  });
93
100
  }
101
+ resolve_url(from, to) {
102
+ let result;
103
+ try {
104
+ const resolvedUrl = new URL(to, new URL(from, 'resolve://bogus.local'));
105
+ if (resolvedUrl.protocol === 'resolve:') {
106
+ // `from` is a relative URL.
107
+ const {
108
+ pathname,
109
+ search,
110
+ hash
111
+ } = resolvedUrl;
112
+ result = `${pathname}${search}${hash}`;
113
+ } else {
114
+ result = resolvedUrl.toString();
115
+ }
116
+ } catch {
117
+ result = url.resolve(from, to); // eslint-disable-line n/no-deprecated-api
118
+ console.warn(`DEPRECATION WARNING [sass-asset-functions]: Resolving '${from}' to '${to}' will not work in an upcoming version`);
119
+ }
120
+ return result;
121
+ }
122
+ parse_url(input) {
123
+ let result;
124
+ try {
125
+ const parsedUrl = new URL(input, 'parse://bogus.local'); // base used if relative was supplied
126
+ result = parsedUrl;
127
+ } catch {
128
+ result = url.parse(input); // eslint-disable-line n/no-deprecated-api
129
+ console.warn(`DEPRECATION WARNING [sass-asset-functions]: Parsing url '${input}' will not work in an upcoming version`);
130
+ }
131
+ return result;
132
+ }
94
133
  real_path(filepath, segment) {
95
134
  const sanitized_filepath = filepath.replace(/(#|\?).+$/, '');
96
135
  return path.resolve(this.paths[`${segment}_path`], sanitized_filepath);
@@ -190,11 +229,11 @@ class Processor {
190
229
  for (; i < files.length; ++i) {
191
230
  file = files[i];
192
231
  next = files[i + 1];
193
- parts = url.parse(file);
194
232
  if (FONT_TYPES[next]) {
195
233
  type = files.splice(i + 1, 1);
196
234
  } else {
197
- ext = path.extname(parts.path);
235
+ parts = this.parse_url(file);
236
+ ext = path.extname(parts.pathname);
198
237
  type = ext.substring(1);
199
238
  }
200
239
  type = FONT_TYPES[type];
package/lib/processor.js CHANGED
@@ -49,16 +49,24 @@ export default class Processor {
49
49
  throw new Error('asset_cache_buster should be a function');
50
50
  }
51
51
 
52
- const http_path_url = url.parse(http_path);
52
+ function preserveEmptyQS (originalUrl, query) {
53
+ let result = query;
54
+ if (!query && originalUrl.includes('?')) {
55
+ result = '?';
56
+ }
57
+ return result;
58
+ }
59
+
60
+ const http_path_url = this.parse_url(http_path);
53
61
 
54
62
  buster(http_path, real_path, value => {
55
63
  let new_url;
56
64
 
57
65
  if (typeof value == 'object') {
58
- const parsed_path = url.parse(value.path);
66
+ const parsed_path = this.parse_url(value.path);
59
67
  new_url = {
60
68
  pathname: parsed_path.pathname,
61
- search: value.query || http_path_url.search
69
+ search: value.query || preserveEmptyQS(http_path, http_path_url.search)
62
70
  };
63
71
  } else {
64
72
  new_url = {
@@ -79,10 +87,44 @@ export default class Processor {
79
87
  }
80
88
 
81
89
  ahost(filepath, host => {
82
- done(url.resolve(host, filepath));
90
+ done(this.resolve_url(host, filepath));
83
91
  });
84
92
  }
85
93
 
94
+ resolve_url (from, to) {
95
+ let result;
96
+
97
+ try {
98
+ const resolvedUrl = new URL(to, new URL(from, 'resolve://bogus.local'));
99
+ if (resolvedUrl.protocol === 'resolve:') {
100
+ // `from` is a relative URL.
101
+ const { pathname, search, hash } = resolvedUrl;
102
+ result = `${pathname}${search}${hash}`;
103
+ } else {
104
+ result = resolvedUrl.toString();
105
+ }
106
+ } catch {
107
+ result = url.resolve(from, to); // eslint-disable-line n/no-deprecated-api
108
+ console.warn(`DEPRECATION WARNING [sass-asset-functions]: Resolving '${from}' to '${to}' will not work in an upcoming version`);
109
+ }
110
+
111
+ return result;
112
+ }
113
+
114
+ parse_url (input) {
115
+ let result;
116
+
117
+ try {
118
+ const parsedUrl = new URL(input, 'parse://bogus.local'); // base used if relative was supplied
119
+ result = parsedUrl;
120
+ } catch {
121
+ result = url.parse(input); // eslint-disable-line n/no-deprecated-api
122
+ console.warn(`DEPRECATION WARNING [sass-asset-functions]: Parsing url '${input}' will not work in an upcoming version`);
123
+ }
124
+
125
+ return result;
126
+ }
127
+
86
128
  real_path (filepath, segment) {
87
129
  const sanitized_filepath = filepath.replace(/(#|\?).+$/, '');
88
130
  return path.resolve(this.paths[`${segment}_path`], sanitized_filepath);
@@ -197,11 +239,11 @@ export default class Processor {
197
239
  file = files[i];
198
240
  next = files[i + 1];
199
241
 
200
- parts = url.parse(file);
201
242
  if (FONT_TYPES[next]) {
202
243
  type = files.splice(i + 1, 1);
203
244
  } else {
204
- ext = path.extname(parts.path);
245
+ parts = this.parse_url(file);
246
+ ext = path.extname(parts.pathname);
205
247
  type = ext.substring(1);
206
248
  }
207
249
  type = FONT_TYPES[type];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@localnerve/sass-asset-functions",
3
- "version": "7.10.0",
3
+ "version": "7.11.0",
4
4
  "description": "compass-style asset functions for dart-sass or other sass compilers",
5
5
  "main": "index.js",
6
6
  "exports": {
@@ -11,14 +11,14 @@
11
11
  "type": "module",
12
12
  "scripts": {
13
13
  "lint": "eslint .",
14
- "posttranspile": "node posttranspile.js",
15
14
  "prepublishOnly": "npm run transpile",
16
- "pretranspile": "rimraf ./cjs",
15
+ "pretranspile": "node -e 'require(\"fs\").rmSync(\"./cjs\",{recursive:true,force:true})'",
16
+ "transpile": "babel index.js -o ./cjs/index.cjs && babel ./lib --out-dir ./cjs/lib",
17
+ "posttranspile": "node posttranspile.js",
17
18
  "test": "npm run test:unit && npm run test:package",
18
19
  "test:package": "node ./__test-package__/index.js",
19
- "test:unit": "node --experimental-vm-modules node_modules/.bin/jest",
20
- "test:unit:debug": "node --inspect-brk --experimental-vm-modules node_modules/./bin/test",
21
- "transpile": "babel index.js -o ./cjs/index.cjs && babel ./lib --out-dir ./cjs/lib"
20
+ "pretest:unit": "node -e 'require(\"fs\").rmSync(\"./coverage\",{recursive:true,force:true})' && node -e 'require(\"fs\").mkdirSync(\"./coverage\",{recursive:true})'",
21
+ "test:unit": "node --test --experimental-test-coverage --test-reporter=spec --test-reporter-destination=stdout --test-reporter=lcov --test-reporter-destination=./coverage/lcov.info \"__tests__/test.js\""
22
22
  },
23
23
  "repository": {
24
24
  "type": "git",
@@ -60,12 +60,10 @@
60
60
  "@babel/cli": "^7.28.6",
61
61
  "@babel/preset-env": "^7.29.2",
62
62
  "@eslint/js": "^10.0.1",
63
- "eslint": "^10.1.0",
64
- "eslint-plugin-jest": "^29.15.1",
63
+ "eslint": "^10.2.1",
64
+ "eslint-plugin-n": "^17.24.0",
65
65
  "glob": "^13.0.6",
66
- "globals": "^17.4.0",
67
- "jest": "^30.3.0",
68
- "rimraf": "^6.1.3",
66
+ "globals": "^17.5.0",
69
67
  "tar": "^7.5.13"
70
68
  },
71
69
  "engines": {
package/babel.config.json DELETED
@@ -1,11 +0,0 @@
1
- {
2
- "presets": [
3
- [
4
- "@babel/preset-env", {
5
- "targets": {
6
- "node": "20"
7
- }
8
- }
9
- ]
10
- ]
11
- }
package/eslint.config.js DELETED
@@ -1,38 +0,0 @@
1
- import js from '@eslint/js';
2
- import globals from 'globals';
3
- import jest from 'eslint-plugin-jest';
4
-
5
- export default [{
6
- name: 'global',
7
- ignores: [
8
- 'cjs/**',
9
- 'coverage/**',
10
- 'tmp/**',
11
- 'node_modules/**'
12
- ]
13
- }, {
14
- name: 'lib-test-package',
15
- files: [
16
- '*.js',
17
- 'lib/**',
18
- '__test-package__/**'
19
- ],
20
- rules: js.configs.recommended.rules,
21
- languageOptions: {
22
- globals: {
23
- ...globals.node
24
- }
25
- }
26
- }, {
27
- name: 'tests',
28
- files: [
29
- '__tests__/**'
30
- ],
31
- ...jest.configs['flat/recommended'],
32
- rules: {
33
- ...jest.configs['flat/recommended'].rules,
34
- 'jest/no-done-callback': 'off',
35
- 'jest/expect-expect': 'off',
36
- 'jest/valid-title': 'off'
37
- }
38
- }];
package/jest.config.js DELETED
@@ -1,10 +0,0 @@
1
- export default {
2
- collectCoverage: true,
3
- coverageDirectory: 'coverage',
4
- verbose: true,
5
- testEnvironment: 'node',
6
- testPathIgnorePatterns: [
7
- '/node_modules/',
8
- '/tmp/'
9
- ]
10
- };
package/posttranspile.js DELETED
@@ -1,29 +0,0 @@
1
- import fs from 'node:fs/promises';
2
- import path from 'node:path';
3
-
4
- async function processFile (filename) {
5
- const newname = filename.replace(/\.js$/, '.cjs');
6
- await fs.rename(filename, newname);
7
- const data = await fs.readFile(newname, 'utf8');
8
- const newData = data.replaceAll('.js")', '.cjs")');
9
- await fs.writeFile(newname, newData);
10
- }
11
-
12
- async function processDirectory (dir) {
13
- try {
14
- const files = await fs.readdir(dir);
15
- for (const file of files) {
16
- const name = `${dir}${path.sep}${file}`;
17
- const stats = await fs.stat(name);
18
- if (stats.isDirectory()) {
19
- await processDirectory(name);
20
- } else {
21
- await processFile(name);
22
- }
23
- }
24
- } catch (err) {
25
- console.error('posttranspile error:\n\n', err);
26
- }
27
- }
28
-
29
- await processDirectory('./cjs');