@localnerve/sass-asset-functions 2.2.0 → 3.0.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/.eslintrc.json +2 -4
- package/CHANGELOG.md +20 -0
- package/{LICENSE → LICENSE.md} +1 -1
- package/README.md +45 -47
- package/babel.config.json +11 -0
- package/cjs/index.cjs +69 -0
- package/cjs/lib/processor.cjs +175 -0
- package/index.js +22 -16
- package/jest.config.js +1 -1
- package/lib/processor.js +9 -8
- package/package.json +18 -5
- package/posttranspile.cjs +9 -0
- package/.github/workflows/verify.yml +0 -32
- package/__tests__/css/asset_cache_buster/path/font-files.css +0 -3
- package/__tests__/css/asset_cache_buster/path/font-url.css +0 -6
- package/__tests__/css/asset_cache_buster/path/image-size.css +0 -3
- package/__tests__/css/asset_cache_buster/path/image-url.css +0 -5
- package/__tests__/css/asset_cache_buster/path/inline-image.css +0 -2
- package/__tests__/css/asset_cache_buster/query/font-files.css +0 -3
- package/__tests__/css/asset_cache_buster/query/font-url.css +0 -6
- package/__tests__/css/asset_cache_buster/query/image-size.css +0 -3
- package/__tests__/css/asset_cache_buster/query/image-url.css +0 -5
- package/__tests__/css/asset_cache_buster/query/inline-image.css +0 -2
- package/__tests__/css/asset_host/font-files.css +0 -3
- package/__tests__/css/asset_host/font-url.css +0 -6
- package/__tests__/css/asset_host/image-size.css +0 -3
- package/__tests__/css/asset_host/image-url.css +0 -5
- package/__tests__/css/asset_host/inline-image.css +0 -2
- package/__tests__/css/basic/font-files.css +0 -3
- package/__tests__/css/basic/font-url.css +0 -6
- package/__tests__/css/basic/image-size.css +0 -3
- package/__tests__/css/basic/image-url.css +0 -5
- package/__tests__/css/basic/inline-image.css +0 -2
- package/__tests__/images/barney.gif +0 -0
- package/__tests__/images/npm.svg +0 -1
- package/__tests__/scss/font-files.scss +0 -4
- package/__tests__/scss/font-url.scss +0 -8
- package/__tests__/scss/image-size.scss +0 -4
- package/__tests__/scss/image-url.scss +0 -7
- package/__tests__/scss/inline-image.scss +0 -3
- package/__tests__/test.js +0 -145
package/.eslintrc.json
CHANGED
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Sass Asset Functions Change Log
|
|
2
|
+
|
|
3
|
+
## 3.0.0
|
|
4
|
+
* **Breaking Change**
|
|
5
|
+
> ESM require support now requires destructuring `default` export.
|
|
6
|
+
```js
|
|
7
|
+
const { default: assetFunctions } = require('@localnerve/sass-asset-functions');
|
|
8
|
+
// or
|
|
9
|
+
const assetFunctions = require('@localnerve/sass-asset-functions').default;
|
|
10
|
+
```
|
|
11
|
+
* Dependency Update
|
|
12
|
+
* Full ESM module with cjs support
|
|
13
|
+
|
|
14
|
+
## 2.0.0
|
|
15
|
+
* Support Node 14+, update dependencies.
|
|
16
|
+
* Dropped support for Node 12.
|
|
17
|
+
|
|
18
|
+
## 1.0.0
|
|
19
|
+
* Dependency Update
|
|
20
|
+
* Dropped support for Node 10.
|
package/{LICENSE → LICENSE.md}
RENAMED
package/README.md
CHANGED
|
@@ -35,16 +35,25 @@ This module provides some of the asset functions that came with [Compass](http:/
|
|
|
35
35
|
Basic usage is as easy as setting the `functions` property:
|
|
36
36
|
|
|
37
37
|
```js
|
|
38
|
+
// non-module, require usage
|
|
38
39
|
const sass = require('sass');
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
40
|
+
const { default: assetFunctions } = require('@localnerve/sass-asset-functions');
|
|
41
|
+
|
|
42
|
+
const result = sass.compile(scss_filename, {
|
|
43
|
+
functions: assetFunctions(/* options */)
|
|
44
|
+
[, options...]
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
```js
|
|
49
|
+
// module usage
|
|
50
|
+
import sass from 'sass';
|
|
51
|
+
import assetFunctions from '@localnerve/sass-asset-functions';
|
|
52
|
+
|
|
53
|
+
const result = sass.compile(scss_filename, {
|
|
54
|
+
functions: assetFunctions(/* options */)
|
|
55
|
+
[, options...]
|
|
56
|
+
});
|
|
48
57
|
```
|
|
49
58
|
|
|
50
59
|
## Options
|
|
@@ -78,18 +87,15 @@ So if your project images reside in `public/img` at build-time instead of `publi
|
|
|
78
87
|
|
|
79
88
|
```js
|
|
80
89
|
const sass = require('sass');
|
|
81
|
-
const
|
|
82
|
-
const assetFunctions = require('@localnerve/sass-asset-functions');
|
|
90
|
+
const { default: assetFunctions } = require('@localnerve/sass-asset-functions');
|
|
83
91
|
|
|
84
|
-
sass.
|
|
92
|
+
const result = sass.compile(scss_filename, {
|
|
85
93
|
functions: assetFunctions({
|
|
86
94
|
images_path: 'public/img',
|
|
87
95
|
http_images_path: '/images'
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
[, options..]
|
|
92
|
-
}, function(err, result) { /*...*/ });
|
|
96
|
+
})
|
|
97
|
+
[, options...]
|
|
98
|
+
});
|
|
93
99
|
```
|
|
94
100
|
|
|
95
101
|
#### `sass`: Overriding the default compiler with Node-Sass
|
|
@@ -98,30 +104,27 @@ Example using the node-sass compiler using the new option `sass`.
|
|
|
98
104
|
|
|
99
105
|
```js
|
|
100
106
|
const sass = require('node-sass');
|
|
101
|
-
const assetFunctions = require('@localnerve/sass-asset-functions');
|
|
107
|
+
const { default: assetFunctions } = require('@localnerve/sass-asset-functions');
|
|
102
108
|
|
|
103
|
-
sass.
|
|
104
|
-
functions: assetFunctions({ sass })
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}, function(err, result) { /*...*/ });
|
|
109
|
+
const result = sass.compile(scss_filename, {
|
|
110
|
+
functions: assetFunctions({ sass })
|
|
111
|
+
[, options...]
|
|
112
|
+
});
|
|
108
113
|
```
|
|
109
114
|
|
|
110
115
|
#### `asset_host`: a function which completes with a string used as asset host.
|
|
111
116
|
|
|
112
117
|
```js
|
|
113
|
-
sass.
|
|
118
|
+
const result = sass.compile(scss_filename, {
|
|
114
119
|
functions: assetFunctions({
|
|
115
|
-
asset_host:
|
|
120
|
+
asset_host: (http_path, done) => {
|
|
116
121
|
done('http://assets.example.com');
|
|
117
122
|
// or use the supplied path to calculate a host
|
|
118
123
|
done(`http://assets${http_path.length % 4}.example.com`);
|
|
119
124
|
}
|
|
120
|
-
})
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
[, options..]
|
|
124
|
-
}, function(err, result) { /*...*/ });
|
|
125
|
+
})
|
|
126
|
+
[, options...]
|
|
127
|
+
});
|
|
125
128
|
```
|
|
126
129
|
|
|
127
130
|
#### `asset_cache_buster`: a function to rewrite the asset path
|
|
@@ -129,16 +132,14 @@ sass.render({
|
|
|
129
132
|
When this function returns a string, it's set as the query of the path. When returned an object, `path` and `query` will be used.
|
|
130
133
|
|
|
131
134
|
```js
|
|
132
|
-
sass.
|
|
135
|
+
const result = sass.compile(scss_filename, {
|
|
133
136
|
functions: assetFunctions({
|
|
134
|
-
asset_cache_buster:
|
|
137
|
+
asset_cache_buster: (http_path, real_path, done) => {
|
|
135
138
|
done('v=123');
|
|
136
139
|
}
|
|
137
|
-
})
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
[, options..]
|
|
141
|
-
}, function(err, result) { /*...*/ });
|
|
140
|
+
})
|
|
141
|
+
[, options...]
|
|
142
|
+
});
|
|
142
143
|
```
|
|
143
144
|
|
|
144
145
|
##### A more advanced example:
|
|
@@ -149,16 +150,15 @@ For example, `/images/myimage.png` would become `/images/myimage-8557f1c9b01dd6f
|
|
|
149
150
|
|
|
150
151
|
```js
|
|
151
152
|
const sass = require('sass');
|
|
152
|
-
const fiber = require('fibers');
|
|
153
153
|
const path = require('path');
|
|
154
154
|
const fs = require('fs');
|
|
155
155
|
const hexdigest = require('hexdigest');
|
|
156
|
-
const assetFunctions = require('@localnerve/sass-asset-functions');
|
|
156
|
+
const { default: assetFunctions } = require('@localnerve/sass-asset-functions');
|
|
157
157
|
|
|
158
|
-
sass.
|
|
158
|
+
const result = sass.compile(scss_filename, {
|
|
159
159
|
functions: assetFunctions({
|
|
160
|
-
asset_cache_buster:
|
|
161
|
-
hexdigest(real_path, 'sha1',
|
|
160
|
+
asset_cache_buster: (http_path, real_path, done) => {
|
|
161
|
+
hexdigest(real_path, 'sha1', (err, digest) => {
|
|
162
162
|
if (err) {
|
|
163
163
|
// an error occurred, maybe the file doesn't exist.
|
|
164
164
|
// Calling `done` without arguments will result in an unmodified path.
|
|
@@ -171,11 +171,9 @@ sass.render({
|
|
|
171
171
|
}
|
|
172
172
|
});
|
|
173
173
|
}
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
[, options..]
|
|
178
|
-
}, function(err, result) { /*...*/ });
|
|
174
|
+
})
|
|
175
|
+
[, options...]
|
|
176
|
+
});
|
|
179
177
|
```
|
|
180
178
|
|
|
181
179
|
## Contributing
|
package/cjs/index.cjs
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = sassFunctions;
|
|
7
|
+
var _sass = _interopRequireDefault(require("sass"));
|
|
8
|
+
var _processor = _interopRequireDefault(require("./lib/processor.cjs"));
|
|
9
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
10
|
+
/**
|
|
11
|
+
* Sass asset function suite.
|
|
12
|
+
*
|
|
13
|
+
* Copyright (c) 2023 Alex Grant (@localnerve), LocalNerve LLC
|
|
14
|
+
* Licensed under the MIT license.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
function sassFunctions(options = {}) {
|
|
18
|
+
const {
|
|
19
|
+
sass = _sass.default
|
|
20
|
+
} = options;
|
|
21
|
+
const processor = new _processor.default(options);
|
|
22
|
+
return {
|
|
23
|
+
'image-url($filename, $only_path: false)': (filename, only_path, done) => {
|
|
24
|
+
processor.image_url(filename.getValue(), url => {
|
|
25
|
+
if (!only_path.getValue()) url = `url('${url}')`;
|
|
26
|
+
done(new sass.types.String(url));
|
|
27
|
+
});
|
|
28
|
+
},
|
|
29
|
+
'inline-image($filename, $mime_type: null)': (filename, mime_type, done) => {
|
|
30
|
+
mime_type = mime_type instanceof sass.types.Null ? null : mime_type.getValue();
|
|
31
|
+
processor.inline_image(filename.getValue(), mime_type, dataUrl => {
|
|
32
|
+
done(new sass.types.String(`url('${dataUrl}')`));
|
|
33
|
+
});
|
|
34
|
+
},
|
|
35
|
+
'image-width($filename)': (filename, done) => {
|
|
36
|
+
processor.image_width(filename.getValue(), image_width => {
|
|
37
|
+
done(new sass.types.Number(image_width, 'px'));
|
|
38
|
+
});
|
|
39
|
+
},
|
|
40
|
+
'image-height($filename)': (filename, done) => {
|
|
41
|
+
processor.image_height(filename.getValue(), image_height => {
|
|
42
|
+
done(new sass.types.Number(image_height, 'px'));
|
|
43
|
+
});
|
|
44
|
+
},
|
|
45
|
+
'font-url($filename, $only-path: false)': (filename, only_path, done) => {
|
|
46
|
+
processor.font_url(filename.getValue(), url => {
|
|
47
|
+
if (!only_path.getValue()) url = `url('${url}')`;
|
|
48
|
+
done(new sass.types.String(url));
|
|
49
|
+
});
|
|
50
|
+
},
|
|
51
|
+
'font-files($filenames...)': (list, done) => {
|
|
52
|
+
let len = list.getLength(),
|
|
53
|
+
i = 0;
|
|
54
|
+
const filenames = [];
|
|
55
|
+
for (; i < len; ++i) {
|
|
56
|
+
filenames[i] = list.getValue(i).getValue();
|
|
57
|
+
}
|
|
58
|
+
processor.font_files(filenames, files => {
|
|
59
|
+
len = files.length;
|
|
60
|
+
i = 0;
|
|
61
|
+
list = new sass.types.List(len);
|
|
62
|
+
for (; i < len; ++i) {
|
|
63
|
+
list.setValue(i, new sass.types.String(`url('${files[i].url}') format('${files[i].type}')`));
|
|
64
|
+
}
|
|
65
|
+
done(list);
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _fs = _interopRequireDefault(require("fs"));
|
|
8
|
+
var _path = _interopRequireDefault(require("path"));
|
|
9
|
+
var _url = _interopRequireDefault(require("url"));
|
|
10
|
+
var _mime = _interopRequireDefault(require("mime"));
|
|
11
|
+
var _imageSize = _interopRequireDefault(require("image-size"));
|
|
12
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
13
|
+
/**
|
|
14
|
+
* Internal processor for the asset function suite.
|
|
15
|
+
*
|
|
16
|
+
* Copyright (c) 2023 Alex Grant (@localnerve), LocalNerve LLC
|
|
17
|
+
* Licensed under the MIT license.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const defaultPaths = {
|
|
21
|
+
images_path: 'public/images',
|
|
22
|
+
fonts_path: 'public/fonts',
|
|
23
|
+
http_images_path: '/images',
|
|
24
|
+
http_fonts_path: '/fonts'
|
|
25
|
+
};
|
|
26
|
+
const FONT_TYPES = {
|
|
27
|
+
woff: 'woff',
|
|
28
|
+
woff2: 'woff2',
|
|
29
|
+
otf: 'opentype',
|
|
30
|
+
opentype: 'opentype',
|
|
31
|
+
ttf: 'truetype',
|
|
32
|
+
truetype: 'truetype',
|
|
33
|
+
svg: 'svg',
|
|
34
|
+
eot: 'embedded-opentype'
|
|
35
|
+
};
|
|
36
|
+
class Processor {
|
|
37
|
+
constructor(options = {}) {
|
|
38
|
+
this.options = options;
|
|
39
|
+
const {
|
|
40
|
+
images_path = defaultPaths.images_path,
|
|
41
|
+
fonts_path = defaultPaths.fonts_path,
|
|
42
|
+
http_images_path = defaultPaths.http_images_path,
|
|
43
|
+
http_fonts_path = defaultPaths.http_fonts_path
|
|
44
|
+
} = options;
|
|
45
|
+
this.paths = {
|
|
46
|
+
images_path,
|
|
47
|
+
fonts_path,
|
|
48
|
+
http_images_path,
|
|
49
|
+
http_fonts_path
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
asset_cache_buster(http_path, real_path, done) {
|
|
53
|
+
const {
|
|
54
|
+
asset_cache_buster: buster
|
|
55
|
+
} = this.options;
|
|
56
|
+
if (typeof buster !== 'function') {
|
|
57
|
+
throw new Error('asset_cache_buster should be a function');
|
|
58
|
+
}
|
|
59
|
+
const http_path_url = _url.default.parse(http_path);
|
|
60
|
+
buster(http_path, real_path, value => {
|
|
61
|
+
let new_url;
|
|
62
|
+
if (typeof value == 'object') {
|
|
63
|
+
const parsed_path = _url.default.parse(value.path);
|
|
64
|
+
new_url = {
|
|
65
|
+
pathname: parsed_path.pathname,
|
|
66
|
+
search: value.query || http_path_url.search
|
|
67
|
+
};
|
|
68
|
+
} else {
|
|
69
|
+
new_url = {
|
|
70
|
+
pathname: http_path_url.pathname,
|
|
71
|
+
search: value
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
done(_url.default.format(new_url));
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
asset_host(filepath, done) {
|
|
78
|
+
const {
|
|
79
|
+
asset_host: ahost
|
|
80
|
+
} = this.options;
|
|
81
|
+
if (typeof ahost !== 'function') {
|
|
82
|
+
throw new Error('asset_host should be a function');
|
|
83
|
+
}
|
|
84
|
+
ahost(filepath, host => {
|
|
85
|
+
done(_url.default.resolve(host, filepath));
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
real_path(filepath, segment) {
|
|
89
|
+
const sanitized_filepath = filepath.replace(/(#|\?).+$/, '');
|
|
90
|
+
return _path.default.resolve(this.paths[`${segment}_path`], sanitized_filepath);
|
|
91
|
+
}
|
|
92
|
+
http_path(filepath, segment) {
|
|
93
|
+
return _path.default.join(this.paths[`http_${segment}_path`], filepath).replace(/\\/g, '/');
|
|
94
|
+
}
|
|
95
|
+
image_width(filepath, done) {
|
|
96
|
+
done((0, _imageSize.default)(this.real_path(filepath, 'images')).width);
|
|
97
|
+
}
|
|
98
|
+
image_height(filepath, done) {
|
|
99
|
+
done((0, _imageSize.default)(this.real_path(filepath, 'images')).height);
|
|
100
|
+
}
|
|
101
|
+
inline_image(filepath, mime_type, done) {
|
|
102
|
+
const src = this.real_path(filepath, 'images');
|
|
103
|
+
mime_type = mime_type || _mime.default.getType(src);
|
|
104
|
+
_fs.default.readFile(src, (err, data) => {
|
|
105
|
+
if (err) {
|
|
106
|
+
throw new Error(`inline_image failed to read ${src}: ${err}`);
|
|
107
|
+
}
|
|
108
|
+
done(`data:${mime_type};base64,${data.toString('base64')}`);
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
asset_url(filepath, segment, done) {
|
|
112
|
+
let fragment = '';
|
|
113
|
+
let sanitized_http_path = this.http_path(filepath, segment);
|
|
114
|
+
const real_path = this.real_path(filepath, segment);
|
|
115
|
+
const fragmentIndex = sanitized_http_path.indexOf('#');
|
|
116
|
+
const restoreFragment = url => done(url + fragment);
|
|
117
|
+
const next = http_path => {
|
|
118
|
+
if (this.options.asset_host) {
|
|
119
|
+
this.asset_host(http_path, restoreFragment);
|
|
120
|
+
} else {
|
|
121
|
+
restoreFragment(http_path);
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
if (~fragmentIndex) {
|
|
125
|
+
fragment = sanitized_http_path.substring(fragmentIndex);
|
|
126
|
+
sanitized_http_path = sanitized_http_path.substring(0, fragmentIndex);
|
|
127
|
+
}
|
|
128
|
+
if (this.options.asset_cache_buster) {
|
|
129
|
+
this.asset_cache_buster(sanitized_http_path, real_path, next);
|
|
130
|
+
} else {
|
|
131
|
+
next(sanitized_http_path);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
image_url(filepath, done) {
|
|
135
|
+
this.asset_url(filepath, 'images', done);
|
|
136
|
+
}
|
|
137
|
+
font_url(filepath, done) {
|
|
138
|
+
this.asset_url(filepath, 'fonts', done);
|
|
139
|
+
}
|
|
140
|
+
font_files(files, done) {
|
|
141
|
+
const processed_files = [];
|
|
142
|
+
let count = 0;
|
|
143
|
+
const complete = (index, type) => {
|
|
144
|
+
return url => {
|
|
145
|
+
processed_files[index] = {
|
|
146
|
+
url: url,
|
|
147
|
+
type: type
|
|
148
|
+
};
|
|
149
|
+
if (++count == files.length) {
|
|
150
|
+
done(processed_files);
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
};
|
|
154
|
+
let i = 0,
|
|
155
|
+
parts,
|
|
156
|
+
ext,
|
|
157
|
+
file,
|
|
158
|
+
next,
|
|
159
|
+
type;
|
|
160
|
+
for (; i < files.length; ++i) {
|
|
161
|
+
file = files[i];
|
|
162
|
+
next = files[i + 1];
|
|
163
|
+
parts = _url.default.parse(file);
|
|
164
|
+
if (FONT_TYPES[next]) {
|
|
165
|
+
type = files.splice(i + 1, 1);
|
|
166
|
+
} else {
|
|
167
|
+
ext = _path.default.extname(parts.path);
|
|
168
|
+
type = ext.substring(1);
|
|
169
|
+
}
|
|
170
|
+
type = FONT_TYPES[type];
|
|
171
|
+
this.font_url(file, complete(i, type));
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
exports.default = Processor;
|
package/index.js
CHANGED
|
@@ -1,47 +1,53 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Sass asset function suite.
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2023 Alex Grant (@localnerve), LocalNerve LLC
|
|
5
|
+
* Licensed under the MIT license.
|
|
6
|
+
*/
|
|
7
|
+
import defaultSass from 'sass';
|
|
8
|
+
import Processor from './lib/processor.js';
|
|
3
9
|
|
|
4
|
-
|
|
10
|
+
export default function sassFunctions (options = {}) {
|
|
5
11
|
const { sass = defaultSass } = options;
|
|
6
12
|
const processor = new Processor(options);
|
|
7
13
|
|
|
8
14
|
return {
|
|
9
|
-
'image-url($filename, $only_path: false)':
|
|
10
|
-
processor.image_url(filename.getValue(),
|
|
15
|
+
'image-url($filename, $only_path: false)': (filename, only_path, done) => {
|
|
16
|
+
processor.image_url(filename.getValue(), (url) => {
|
|
11
17
|
if (!only_path.getValue()) url = `url('${url}')`;
|
|
12
18
|
done(new sass.types.String(url));
|
|
13
19
|
});
|
|
14
20
|
},
|
|
15
|
-
'inline-image($filename, $mime_type: null)':
|
|
21
|
+
'inline-image($filename, $mime_type: null)': (filename, mime_type, done) => {
|
|
16
22
|
mime_type = mime_type instanceof sass.types.Null ? null : mime_type.getValue();
|
|
17
|
-
processor.inline_image(filename.getValue(), mime_type,
|
|
23
|
+
processor.inline_image(filename.getValue(), mime_type, (dataUrl) => {
|
|
18
24
|
done(new sass.types.String(`url('${dataUrl}')`));
|
|
19
25
|
});
|
|
20
26
|
},
|
|
21
|
-
'image-width($filename)':
|
|
22
|
-
processor.image_width(filename.getValue(),
|
|
27
|
+
'image-width($filename)': (filename, done) => {
|
|
28
|
+
processor.image_width(filename.getValue(), (image_width) => {
|
|
23
29
|
done(new sass.types.Number(image_width, 'px'));
|
|
24
30
|
});
|
|
25
31
|
},
|
|
26
|
-
'image-height($filename)':
|
|
27
|
-
processor.image_height(filename.getValue(),
|
|
32
|
+
'image-height($filename)': (filename, done) => {
|
|
33
|
+
processor.image_height(filename.getValue(), (image_height) => {
|
|
28
34
|
done(new sass.types.Number(image_height, 'px'));
|
|
29
35
|
});
|
|
30
36
|
},
|
|
31
|
-
'font-url($filename, $only-path: false)':
|
|
32
|
-
processor.font_url(filename.getValue(),
|
|
37
|
+
'font-url($filename, $only-path: false)': (filename, only_path, done) => {
|
|
38
|
+
processor.font_url(filename.getValue(), (url) => {
|
|
33
39
|
if (!only_path.getValue()) url = `url('${url}')`;
|
|
34
40
|
done(new sass.types.String(url));
|
|
35
41
|
});
|
|
36
42
|
},
|
|
37
|
-
'font-files($filenames...)':
|
|
43
|
+
'font-files($filenames...)': (list, done) => {
|
|
38
44
|
let len = list.getLength(), i = 0;
|
|
39
45
|
const filenames = [];
|
|
40
46
|
for(; i < len; ++i) {
|
|
41
47
|
filenames[i] = list.getValue(i).getValue();
|
|
42
48
|
}
|
|
43
49
|
|
|
44
|
-
processor.font_files(filenames,
|
|
50
|
+
processor.font_files(filenames, (files) => {
|
|
45
51
|
len = files.length;
|
|
46
52
|
i = 0;
|
|
47
53
|
list = new sass.types.List(len);
|
|
@@ -52,4 +58,4 @@ module.exports = function sassFunctions (options = {}) {
|
|
|
52
58
|
});
|
|
53
59
|
}
|
|
54
60
|
};
|
|
55
|
-
}
|
|
61
|
+
}
|
package/jest.config.js
CHANGED
package/lib/processor.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Internal processor for the asset function suite.
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2023 Alex Grant (@localnerve), LocalNerve LLC
|
|
5
|
+
* Licensed under the MIT license.
|
|
3
6
|
*/
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
import fs from 'fs';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import url from 'url';
|
|
10
|
+
import mime from 'mime';
|
|
11
|
+
import sizeOf from 'image-size';
|
|
9
12
|
|
|
10
13
|
const defaultPaths = {
|
|
11
14
|
images_path: 'public/images',
|
|
@@ -25,7 +28,7 @@ const FONT_TYPES = {
|
|
|
25
28
|
eot: 'embedded-opentype'
|
|
26
29
|
};
|
|
27
30
|
|
|
28
|
-
class Processor {
|
|
31
|
+
export default class Processor {
|
|
29
32
|
constructor (options = {}) {
|
|
30
33
|
this.options = options;
|
|
31
34
|
const {
|
|
@@ -175,5 +178,3 @@ class Processor {
|
|
|
175
178
|
}
|
|
176
179
|
}
|
|
177
180
|
}
|
|
178
|
-
|
|
179
|
-
module.exports = Processor;
|
package/package.json
CHANGED
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@localnerve/sass-asset-functions",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "compass-style asset functions for dart-sass or other sass compilers",
|
|
5
5
|
"main": "index.js",
|
|
6
|
+
"exports": {
|
|
7
|
+
"import": "./index.js",
|
|
8
|
+
"require": "./cjs/index.cjs",
|
|
9
|
+
"default": "./index.js"
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
6
12
|
"scripts": {
|
|
7
13
|
"test": "jest",
|
|
8
|
-
"lint": "eslint ."
|
|
14
|
+
"lint": "eslint .",
|
|
15
|
+
"pretranspile": "rimraf ./cjs",
|
|
16
|
+
"transpile": "babel index.js -o ./cjs/index.cjs && babel ./lib/processor.js -o ./cjs/lib/processor.cjs",
|
|
17
|
+
"posttranspile": "node posttranspile.cjs",
|
|
18
|
+
"prepublishOnly": "npm run transpile"
|
|
9
19
|
},
|
|
10
20
|
"repository": {
|
|
11
21
|
"type": "git",
|
|
@@ -39,11 +49,14 @@
|
|
|
39
49
|
"dependencies": {
|
|
40
50
|
"image-size": "^1.0.2",
|
|
41
51
|
"mime": "^3.0.0",
|
|
42
|
-
"sass": "^1.
|
|
52
|
+
"sass": "^1.58.0"
|
|
43
53
|
},
|
|
44
54
|
"devDependencies": {
|
|
45
|
-
"
|
|
46
|
-
"
|
|
55
|
+
"@babel/cli": "^7.20.7",
|
|
56
|
+
"@babel/preset-env": "^7.20.2",
|
|
57
|
+
"rimraf": "^4.1.2",
|
|
58
|
+
"jest": "^29.4.2",
|
|
59
|
+
"eslint": "^8.33.0",
|
|
47
60
|
"node-sass": "^8.0.0"
|
|
48
61
|
},
|
|
49
62
|
"engines": {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const fs = require('node:fs');
|
|
2
|
+
const fileToChange = './cjs/index.cjs';
|
|
3
|
+
fs.readFile(fileToChange, 'utf8', (err, data) => {
|
|
4
|
+
if (err) throw err;
|
|
5
|
+
const newData = data.replace('./lib/processor.js', './lib/processor.cjs');
|
|
6
|
+
fs.writeFile(fileToChange, newData, err => {
|
|
7
|
+
if (err) throw err;
|
|
8
|
+
});
|
|
9
|
+
});
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
name: Verify
|
|
2
|
-
on:
|
|
3
|
-
push:
|
|
4
|
-
branches: [ master ]
|
|
5
|
-
pull_request:
|
|
6
|
-
branches: [ master ]
|
|
7
|
-
|
|
8
|
-
jobs:
|
|
9
|
-
verify:
|
|
10
|
-
|
|
11
|
-
runs-on: ubuntu-latest
|
|
12
|
-
|
|
13
|
-
strategy:
|
|
14
|
-
matrix:
|
|
15
|
-
node-version: [14.x, 16.x, 18.x]
|
|
16
|
-
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
|
17
|
-
|
|
18
|
-
steps:
|
|
19
|
-
- uses: actions/checkout@v3
|
|
20
|
-
- name: Use Node.js ${{ matrix.node-version }}
|
|
21
|
-
uses: actions/setup-node@v3
|
|
22
|
-
with:
|
|
23
|
-
node-version: ${{ matrix.node-version }}
|
|
24
|
-
- run: npm ci
|
|
25
|
-
- name: Run Lint and Test
|
|
26
|
-
run: npm run lint && npm test
|
|
27
|
-
- name: Coverage Upload
|
|
28
|
-
if: ${{ success() }}
|
|
29
|
-
uses: coverallsapp/github-action@master
|
|
30
|
-
with:
|
|
31
|
-
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
32
|
-
path-to-lcov: ./coverage/lcov.info
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
#npm {
|
|
2
|
-
background: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTI5IiBoZWlnaHQ9IjUwIiB2aWV3Qm94PSIwIDAgMTI5IDUwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjx0aXRsZT5VbnRpdGxlZCA5PC90aXRsZT48ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz48cGF0aCBkPSJNMCAwaDEyOXY0My4wNzdINjQuNVY1MEgzNS44NjJ2LTYuOTIzSDBWMHptNy4zMDIgMzUuNzY3aDE0LjI1di0yMS41Mmg3LjE2NHYyMS41Mmg3LjFWNy4zMDdINy4zMDJ2MjguNDZ6TTQyLjkxNCA3LjE4TDQzIDQzLjA3NmgxNC4xOXYtNy4xNjJoMTQuMzY1VjcuMThoLTI4LjY0em0xNC4xMDQgNi45MjNINjQuNXYxNC42MTVoLTcuNDgyVjE0LjEwM3pNNzguNzc2IDcuMTh2MjguNDZIOTMuMDVWMTQuMjc0aDcuMTRWMzUuNjRoNy4xM1YxNC4zNmg3LjE0NXYyMS4yOGg3LjE0VjcuMThoLTQyLjgzeiIgZmlsbD0iIzAwMCIgZmlsbC1ydWxlPSJldmVub2RkIi8+PC9zdmc+'); }
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
#npm {
|
|
2
|
-
background: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTI5IiBoZWlnaHQ9IjUwIiB2aWV3Qm94PSIwIDAgMTI5IDUwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjx0aXRsZT5VbnRpdGxlZCA5PC90aXRsZT48ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz48cGF0aCBkPSJNMCAwaDEyOXY0My4wNzdINjQuNVY1MEgzNS44NjJ2LTYuOTIzSDBWMHptNy4zMDIgMzUuNzY3aDE0LjI1di0yMS41Mmg3LjE2NHYyMS41Mmg3LjFWNy4zMDdINy4zMDJ2MjguNDZ6TTQyLjkxNCA3LjE4TDQzIDQzLjA3NmgxNC4xOXYtNy4xNjJoMTQuMzY1VjcuMThoLTI4LjY0em0xNC4xMDQgNi45MjNINjQuNXYxNC42MTVoLTcuNDgyVjE0LjEwM3pNNzguNzc2IDcuMTh2MjguNDZIOTMuMDVWMTQuMjc0aDcuMTRWMzUuNjRoNy4xM1YxNC4zNmg3LjE0NXYyMS4yOGg3LjE0VjcuMThoLTQyLjgzeiIgZmlsbD0iIzAwMCIgZmlsbC1ydWxlPSJldmVub2RkIi8+PC9zdmc+'); }
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
@font-face {
|
|
2
|
-
font-family: 'SomeFont';
|
|
3
|
-
src: url('http://example.com/fonts/SomeFont.woff2') format('woff2'), url('http://example.com/fonts/SomeFont.woff') format('woff'), url('http://example.com/fonts/SomeFont.ttf') format('truetype'), url('http://example.com/fonts/SomeFont.svg#SomeFont') format('svg'); }
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
#npm {
|
|
2
|
-
background: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTI5IiBoZWlnaHQ9IjUwIiB2aWV3Qm94PSIwIDAgMTI5IDUwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjx0aXRsZT5VbnRpdGxlZCA5PC90aXRsZT48ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz48cGF0aCBkPSJNMCAwaDEyOXY0My4wNzdINjQuNVY1MEgzNS44NjJ2LTYuOTIzSDBWMHptNy4zMDIgMzUuNzY3aDE0LjI1di0yMS41Mmg3LjE2NHYyMS41Mmg3LjFWNy4zMDdINy4zMDJ2MjguNDZ6TTQyLjkxNCA3LjE4TDQzIDQzLjA3NmgxNC4xOXYtNy4xNjJoMTQuMzY1VjcuMThoLTI4LjY0em0xNC4xMDQgNi45MjNINjQuNXYxNC42MTVoLTcuNDgyVjE0LjEwM3pNNzguNzc2IDcuMTh2MjguNDZIOTMuMDVWMTQuMjc0aDcuMTRWMzUuNjRoNy4xM1YxNC4zNmg3LjE0NXYyMS4yOGg3LjE0VjcuMThoLTQyLjgzeiIgZmlsbD0iIzAwMCIgZmlsbC1ydWxlPSJldmVub2RkIi8+PC9zdmc+'); }
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
#npm {
|
|
2
|
-
background: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTI5IiBoZWlnaHQ9IjUwIiB2aWV3Qm94PSIwIDAgMTI5IDUwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjx0aXRsZT5VbnRpdGxlZCA5PC90aXRsZT48ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz48cGF0aCBkPSJNMCAwaDEyOXY0My4wNzdINjQuNVY1MEgzNS44NjJ2LTYuOTIzSDBWMHptNy4zMDIgMzUuNzY3aDE0LjI1di0yMS41Mmg3LjE2NHYyMS41Mmg3LjFWNy4zMDdINy4zMDJ2MjguNDZ6TTQyLjkxNCA3LjE4TDQzIDQzLjA3NmgxNC4xOXYtNy4xNjJoMTQuMzY1VjcuMThoLTI4LjY0em0xNC4xMDQgNi45MjNINjQuNXYxNC42MTVoLTcuNDgyVjE0LjEwM3pNNzguNzc2IDcuMTh2MjguNDZIOTMuMDVWMTQuMjc0aDcuMTRWMzUuNjRoNy4xM1YxNC4zNmg3LjE0NXYyMS4yOGg3LjE0VjcuMThoLTQyLjgzeiIgZmlsbD0iIzAwMCIgZmlsbC1ydWxlPSJldmVub2RkIi8+PC9zdmc+'); }
|
|
Binary file
|
package/__tests__/images/npm.svg
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg width="129" height="50" viewBox="0 0 129 50" xmlns="http://www.w3.org/2000/svg"><title>Untitled 9</title><desc>Created with Sketch.</desc><path d="M0 0h129v43.077H64.5V50H35.862v-6.923H0V0zm7.302 35.767h14.25v-21.52h7.164v21.52h7.1V7.307H7.302v28.46zM42.914 7.18L43 43.076h14.19v-7.162h14.365V7.18h-28.64zm14.104 6.923H64.5v14.615h-7.482V14.103zM78.776 7.18v28.46H93.05V14.274h7.14V35.64h7.13V14.36h7.145v21.28h7.14V7.18h-42.83z" fill="#000" fill-rule="evenodd"/></svg>
|
package/__tests__/test.js
DELETED
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Test driver.
|
|
3
|
-
*/
|
|
4
|
-
/* eslint-env jest */
|
|
5
|
-
|
|
6
|
-
const fs = require('fs');
|
|
7
|
-
const path = require('path');
|
|
8
|
-
const otherSass = require('node-sass');
|
|
9
|
-
const defaultSass = require('sass');
|
|
10
|
-
const assetFunctions = require('../');
|
|
11
|
-
|
|
12
|
-
const sassDir = path.join(__dirname, 'scss');
|
|
13
|
-
const cssDir = path.join(__dirname, 'css');
|
|
14
|
-
const otherSassOpts = { sass: otherSass };
|
|
15
|
-
const files = fs.readdirSync(sassDir);
|
|
16
|
-
|
|
17
|
-
function renderAsync (file, options = {}, done) {
|
|
18
|
-
const { sass = defaultSass } = options;
|
|
19
|
-
|
|
20
|
-
options.images_path = `${__dirname}/images`;
|
|
21
|
-
options.fonts_path = `${__dirname}/fonts`;
|
|
22
|
-
|
|
23
|
-
return sass.render({
|
|
24
|
-
functions: assetFunctions(options),
|
|
25
|
-
file: `${__dirname}/scss/${file}` // dart-sass will not find w/o jest testEnvironment 'node'
|
|
26
|
-
}, done);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function equalsFileAsync (file, suite, options, done) {
|
|
30
|
-
renderAsync(file, options, (err, result) => {
|
|
31
|
-
expect(err).toBeNull();
|
|
32
|
-
if (err) {
|
|
33
|
-
return done(err);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const cssPath = path.join(cssDir, suite, file.replace(/\.scss$/, '.css'));
|
|
37
|
-
fs.readFile(cssPath, (err, expected) => {
|
|
38
|
-
expect(err).toBeNull();
|
|
39
|
-
if (err) {
|
|
40
|
-
return done(err);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const rendered = result.css.toString();
|
|
44
|
-
const raw = expected.toString();
|
|
45
|
-
|
|
46
|
-
// Output style differences between node-sass and dart-sass, spacing and quotes '|".
|
|
47
|
-
// For output equality comparison, strip quotes and spaces.
|
|
48
|
-
const stripRendered = rendered.replace(/\s+|"|'/g, '');
|
|
49
|
-
const stripRaw = raw.replace(/\s+|"|'/g, '');
|
|
50
|
-
|
|
51
|
-
expect(stripRendered).toEqual(stripRaw);
|
|
52
|
-
done();
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function asset_host (http_path, done) {
|
|
58
|
-
done('http://example.com');
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function query_asset_cache_buster (http_path, real_path, done) {
|
|
62
|
-
setTimeout(done, 10, 'v=123');
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function path_asset_cache_buster (http_path, real_path, done) {
|
|
66
|
-
setTimeout(() => {
|
|
67
|
-
const extname = path.extname(http_path);
|
|
68
|
-
const basename = path.basename(http_path, extname);
|
|
69
|
-
const dirname = path.dirname(http_path);
|
|
70
|
-
|
|
71
|
-
done({
|
|
72
|
-
path: `${path.join(dirname, `${basename}-v123`)}${extname}`,
|
|
73
|
-
query: null
|
|
74
|
-
});
|
|
75
|
-
}, 10);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function chain (done, next, err) {
|
|
79
|
-
if (err) {
|
|
80
|
-
return done(err);
|
|
81
|
-
}
|
|
82
|
-
next();
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
describe('basic', function () {
|
|
86
|
-
files.forEach(file => {
|
|
87
|
-
test(file, done => {
|
|
88
|
-
const run = equalsFileAsync.bind(this, file, 'basic');
|
|
89
|
-
const next = chain.bind(this, done, () => {
|
|
90
|
-
run(otherSassOpts, done);
|
|
91
|
-
});
|
|
92
|
-
run({}, next);
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
describe('asset_host', function () {
|
|
98
|
-
files.forEach(file => {
|
|
99
|
-
test(file, done => {
|
|
100
|
-
const run = equalsFileAsync.bind(this, file, 'asset_host');
|
|
101
|
-
const opts = { asset_host: asset_host };
|
|
102
|
-
const next = chain.bind(this, done, () => {
|
|
103
|
-
run({
|
|
104
|
-
...otherSassOpts,
|
|
105
|
-
...opts
|
|
106
|
-
}, done);
|
|
107
|
-
});
|
|
108
|
-
run(opts, next);
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
describe('asset_cache_buster', function () {
|
|
114
|
-
describe('using query', function () {
|
|
115
|
-
files.forEach(file => {
|
|
116
|
-
test(file, done => {
|
|
117
|
-
const run = equalsFileAsync.bind(this, file, 'asset_cache_buster/query');
|
|
118
|
-
const opts = { asset_cache_buster: query_asset_cache_buster };
|
|
119
|
-
const next = chain.bind(this, done, () => {
|
|
120
|
-
run({
|
|
121
|
-
...otherSassOpts,
|
|
122
|
-
...opts
|
|
123
|
-
}, done);
|
|
124
|
-
});
|
|
125
|
-
run(opts, next);
|
|
126
|
-
});
|
|
127
|
-
});
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
describe('using path', function () {
|
|
131
|
-
files.forEach(file => {
|
|
132
|
-
test(file, done => {
|
|
133
|
-
const run = equalsFileAsync.bind(this, file, 'asset_cache_buster/path');
|
|
134
|
-
const opts = { asset_cache_buster: path_asset_cache_buster };
|
|
135
|
-
const next = chain.bind(this, done, () => {
|
|
136
|
-
run({
|
|
137
|
-
...otherSassOpts,
|
|
138
|
-
...opts
|
|
139
|
-
}, done);
|
|
140
|
-
});
|
|
141
|
-
run(opts, next);
|
|
142
|
-
});
|
|
143
|
-
});
|
|
144
|
-
});
|
|
145
|
-
});
|