@cichol/sass-bridge 4.3.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/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # `@cichol/sass-bridge`
2
+
3
+ A bridge interface to define Sass custom functions.
4
+
5
+ [![Build Status][github actions badge]][github actions][![License][license badge]](LICENSE)[![Package Version][npm package version badge]][npm package]
6
+
7
+ ## Table of Contents
8
+
9
+ - [`@cichol/sass-bridge`](#cicholsass-bridge)
10
+ - [Table of Contents](#table-of-contents)
11
+ - [Installation](#installation)
12
+ - [Usage](#usage)
13
+ - [License](#license)
14
+
15
+ ## Installation
16
+
17
+ ```sh
18
+ $ npm install --save @cichol/sass-bridge
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ ```typescript
24
+ // ...
25
+ ```
26
+
27
+ ## License
28
+
29
+ [MIT Licensed](../../LICENSE).
30
+
31
+ [github actions badge]: https://img.shields.io/github/actions/workflow/status/morrighan/packages/default.yml?branch=develop&style=flat-square
32
+ [github actions]: https://github.com/morrighan/packages/actions
33
+ [license badge]: https://img.shields.io/github/license/morrighan/packages.svg?style=flat-square
34
+ [npm package version badge]: https://img.shields.io/npm/v/@cichol/sass-bridge.svg?style=flat-square
35
+ [npm package]: https://www.npmjs.com/package/@cichol/sass-bridge
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@cichol/sass-bridge",
3
+ "version": "4.3.0",
4
+ "description": "A bridge interface to define Sass custom functions.",
5
+ "homepage": "https://github.com/morrighan/packages",
6
+ "bugs": {
7
+ "url": "https://github.com/morrighan/packages/issues"
8
+ },
9
+ "license": "MIT",
10
+ "author": {
11
+ "name": "Yongbin Min",
12
+ "email": "contact@cichol.com",
13
+ "url": "https://www.cichol.com/"
14
+ },
15
+ "type": "module",
16
+ "main": "releases/cjs.js",
17
+ "module": "releases/esm.js",
18
+ "types": "types/index.d.ts",
19
+ "directories": {
20
+ "lib": "releases"
21
+ },
22
+ "exports": {
23
+ "import": "./releases/esm.js",
24
+ "require": "./releases/cjs.js"
25
+ },
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/morrighan/packages.git",
29
+ "directory": "packages/sass-bridge"
30
+ },
31
+ "scripts": {
32
+ "build": "npm run build:tsc",
33
+ "build:tsc": "npx tsc --project sources --outDir types"
34
+ },
35
+ "dependencies": {
36
+ "chroma-js": "^3.0.0",
37
+ "reflect-metadata": "^0.2.2",
38
+ "sass": "npm:sass-embedded@^1.77.8"
39
+ },
40
+ "engines": {
41
+ "node": "^20.16.0",
42
+ "npm": "^10.8.0"
43
+ },
44
+ "publishConfig": {
45
+ "registry": "https://registry.npmjs.org/",
46
+ "access": "public"
47
+ }
48
+ }
@@ -0,0 +1,211 @@
1
+ 'use strict';
2
+
3
+ var _Symbol = require('core-js-pure/stable/symbol/index.js');
4
+ var _Promise = require('core-js-pure/stable/promise/index.js');
5
+ var _mapInstanceProperty = require('core-js-pure/stable/instance/map.js');
6
+ var _Reflect$construct = require('core-js-pure/stable/reflect/construct.js');
7
+ var _Object$fromEntries = require('core-js-pure/stable/object/from-entries.js');
8
+ require('reflect-metadata');
9
+ var _fillInstanceProperty = require('core-js-pure/stable/instance/fill.js');
10
+ var _Array$from = require('core-js-pure/stable/array/from.js');
11
+ var _entriesInstanceProperty = require('core-js-pure/stable/instance/entries.js');
12
+ var _Map = require('core-js-pure/stable/map/index.js');
13
+ var _everyInstanceProperty = require('core-js-pure/stable/instance/every.js');
14
+ var _Array$isArray = require('core-js-pure/stable/array/is-array.js');
15
+ var chroma = require('chroma-js');
16
+ var _filterInstanceProperty = require('core-js-pure/stable/instance/filter.js');
17
+ var _Object$keys = require('core-js-pure/stable/object/keys.js');
18
+ var _startsWithInstanceProperty = require('core-js-pure/stable/instance/starts-with.js');
19
+ var _Object$getPrototypeOf = require('core-js-pure/stable/object/get-prototype-of.js');
20
+ var sass = require('sass');
21
+
22
+ function _interopNamespaceDefault(e) {
23
+ var n = Object.create(null);
24
+ if (e) {
25
+ Object.keys(e).forEach(function (k) {
26
+ if (k !== 'default') {
27
+ var d = Object.getOwnPropertyDescriptor(e, k);
28
+ Object.defineProperty(n, k, d.get ? d : {
29
+ enumerable: true,
30
+ get: function () { return e[k]; }
31
+ });
32
+ }
33
+ });
34
+ }
35
+ n.default = e;
36
+ return Object.freeze(n);
37
+ }
38
+
39
+ var sass__namespace = /*#__PURE__*/_interopNamespaceDefault(sass);
40
+
41
+ var _context, _context2, _context3, _context4, _context5;
42
+
43
+ // Type definitions.
44
+
45
+ const SassTypes = _Object$fromEntries(_mapInstanceProperty(_context = _filterInstanceProperty(_context2 = _filterInstanceProperty(_context3 = _mapInstanceProperty(_context4 = _filterInstanceProperty(_context5 = _Object$keys(sass__namespace)).call(_context5, propertyKey => _startsWithInstanceProperty(propertyKey).call(propertyKey, 'Sass'))).call(_context4, propertyKey => sass__namespace[propertyKey])).call(_context3, constructor => typeof constructor === 'function')).call(_context2, constructor => Object.prototype.isPrototypeOf.call(sass.Value.prototype, constructor.prototype))).call(_context, constructor => [constructor.name, constructor]));
46
+ const SassTRUE = sass__namespace.sassTrue;
47
+ const SassFALSE = sass__namespace.sassFalse;
48
+ const SassNULL = sass__namespace.sassNull;
49
+ const {
50
+ SassNumber
51
+ } = SassTypes;
52
+ const {
53
+ SassString
54
+ } = SassTypes;
55
+ const {
56
+ SassColor
57
+ } = SassTypes;
58
+ const {
59
+ SassList
60
+ } = SassTypes;
61
+ const {
62
+ SassMap
63
+ } = SassTypes;
64
+ const SassBoolean = _Object$getPrototypeOf(SassTRUE).constructor;
65
+
66
+ // Helper functions.
67
+ function isObject(value) {
68
+ const type = typeof value;
69
+ return !!value && (type === 'object' || type === 'function');
70
+ }
71
+ function sassToJavaScriptType(sassValue) {
72
+ switch (true) {
73
+ case sassValue instanceof SassBoolean:
74
+ {
75
+ return sassValue.value;
76
+ }
77
+ case sassValue instanceof SassString:
78
+ {
79
+ return sassValue.text;
80
+ }
81
+ case sassValue instanceof SassNumber:
82
+ {
83
+ const {
84
+ value,
85
+ numeratorUnits,
86
+ denominatorUnits
87
+ } = sassValue;
88
+ const unit = sassValue.hasUnits ? numeratorUnits.join('*') + (denominatorUnits.size > 0 ? `/${denominatorUnits.join('*')}` : '') : '';
89
+ return unit ? {
90
+ value,
91
+ unit
92
+ } : value;
93
+ }
94
+ case sassValue instanceof SassColor:
95
+ {
96
+ const {
97
+ red,
98
+ green,
99
+ blue,
100
+ alpha
101
+ } = sassValue;
102
+ return chroma(red, green, blue, alpha);
103
+ }
104
+ case sassValue instanceof SassList:
105
+ {
106
+ var _context;
107
+ const listValue = sassValue.asList;
108
+ const length = listValue.size;
109
+ const array = _fillInstanceProperty(_context = Array(length)).call(_context, undefined);
110
+ for (let index = 0; index < length; index += 1) {
111
+ array[index] = listValue.get(index);
112
+ }
113
+ return _mapInstanceProperty(array).call(array, value => sassToJavaScriptType(value));
114
+ }
115
+ case sassValue instanceof SassMap:
116
+ {
117
+ var _context2;
118
+ const mapValue = sassValue.contents;
119
+ const entries = _mapInstanceProperty(_context2 = _Array$from(_entriesInstanceProperty(mapValue).call(mapValue))).call(_context2, ([key, value]) => [sassToJavaScriptType(key), sassToJavaScriptType(value)]);
120
+ return new _Map(entries);
121
+ }
122
+ default:
123
+ {
124
+ return null;
125
+ }
126
+ }
127
+ }
128
+ function javaScriptToSassType(rawValue) {
129
+ var _context3;
130
+ switch (true) {
131
+ case typeof rawValue === 'boolean':
132
+ {
133
+ const booleanValue = rawValue;
134
+ return booleanValue ? SassTRUE : SassFALSE;
135
+ }
136
+ case typeof rawValue === 'number':
137
+ {
138
+ const numberValue = rawValue;
139
+ return new SassNumber(numberValue);
140
+ }
141
+ case isObject(rawValue) && _everyInstanceProperty(_context3 = ['value', 'unit']).call(_context3, propertyKey => propertyKey in rawValue):
142
+ {
143
+ const {
144
+ value,
145
+ unit
146
+ } = rawValue;
147
+ return new SassNumber(value, unit);
148
+ }
149
+ case typeof rawValue === 'string':
150
+ {
151
+ const stringValue = rawValue;
152
+ return new SassString(stringValue);
153
+ }
154
+ case isObject(rawValue) && '_rgb' in rawValue:
155
+ {
156
+ const [red, green, blue, alpha] = rawValue.rgba();
157
+ return new SassColor({
158
+ red,
159
+ green,
160
+ blue,
161
+ alpha
162
+ });
163
+ }
164
+ case _Array$isArray(rawValue):
165
+ {
166
+ return new SassList(_mapInstanceProperty(rawValue).call(rawValue, value => javaScriptToSassType(value)));
167
+ }
168
+ case rawValue instanceof _Map:
169
+ {
170
+ var _context4;
171
+ const mapValue = rawValue;
172
+ const sassMap = new SassMap();
173
+ const converted = _mapInstanceProperty(_context4 = _Array$from(_entriesInstanceProperty(mapValue).call(mapValue))).call(_context4, entry => _mapInstanceProperty(entry).call(entry, javaScriptToSassType));
174
+ for (const [key, value] of converted) {
175
+ sassMap.contents.set(key, value);
176
+ }
177
+ return sassMap;
178
+ }
179
+ default:
180
+ {
181
+ return SassNULL;
182
+ }
183
+ }
184
+ }
185
+
186
+ // Type definitions.
187
+
188
+ // Constants.
189
+ const KeyOfSignature = _Symbol('@cichol/sass-bridge::KeyOfSignature');
190
+ function sassFunction(definition) {
191
+ return target => {
192
+ Reflect.defineMetadata(KeyOfSignature, definition, target);
193
+ return target;
194
+ };
195
+ }
196
+ async function getFunctions(...moduleImports) {
197
+ const modules = await _Promise.all(_mapInstanceProperty(moduleImports).call(moduleImports, module => _Promise.resolve(module).then(module => module.default)));
198
+ const entries = _mapInstanceProperty(modules).call(modules, module => {
199
+ const signature = Reflect.getMetadata(KeyOfSignature, module);
200
+ async function customFunction(rawArgs) {
201
+ const args = _mapInstanceProperty(rawArgs).call(rawArgs, sassToJavaScriptType);
202
+ const result = await _Reflect$construct(module, args).execute();
203
+ return javaScriptToSassType(result);
204
+ }
205
+ return [signature, customFunction];
206
+ });
207
+ return _Object$fromEntries(entries);
208
+ }
209
+
210
+ exports.getFunctions = getFunctions;
211
+ exports.sassFunction = sassFunction;
@@ -0,0 +1,190 @@
1
+ import _Symbol from 'core-js-pure/stable/symbol/index.js';
2
+ import _Promise from 'core-js-pure/stable/promise/index.js';
3
+ import _mapInstanceProperty from 'core-js-pure/stable/instance/map.js';
4
+ import _Reflect$construct from 'core-js-pure/stable/reflect/construct.js';
5
+ import _Object$fromEntries from 'core-js-pure/stable/object/from-entries.js';
6
+ import 'reflect-metadata';
7
+ import _fillInstanceProperty from 'core-js-pure/stable/instance/fill.js';
8
+ import _Array$from from 'core-js-pure/stable/array/from.js';
9
+ import _entriesInstanceProperty from 'core-js-pure/stable/instance/entries.js';
10
+ import _Map from 'core-js-pure/stable/map/index.js';
11
+ import _everyInstanceProperty from 'core-js-pure/stable/instance/every.js';
12
+ import _Array$isArray from 'core-js-pure/stable/array/is-array.js';
13
+ import chroma from 'chroma-js';
14
+ import _filterInstanceProperty from 'core-js-pure/stable/instance/filter.js';
15
+ import _Object$keys from 'core-js-pure/stable/object/keys.js';
16
+ import _startsWithInstanceProperty from 'core-js-pure/stable/instance/starts-with.js';
17
+ import _Object$getPrototypeOf from 'core-js-pure/stable/object/get-prototype-of.js';
18
+ import * as sass from 'sass';
19
+ import { Value } from 'sass';
20
+
21
+ var _context, _context2, _context3, _context4, _context5;
22
+
23
+ // Type definitions.
24
+
25
+ const SassTypes = _Object$fromEntries(_mapInstanceProperty(_context = _filterInstanceProperty(_context2 = _filterInstanceProperty(_context3 = _mapInstanceProperty(_context4 = _filterInstanceProperty(_context5 = _Object$keys(sass)).call(_context5, propertyKey => _startsWithInstanceProperty(propertyKey).call(propertyKey, 'Sass'))).call(_context4, propertyKey => sass[propertyKey])).call(_context3, constructor => typeof constructor === 'function')).call(_context2, constructor => Object.prototype.isPrototypeOf.call(Value.prototype, constructor.prototype))).call(_context, constructor => [constructor.name, constructor]));
26
+ const SassTRUE = sass.sassTrue;
27
+ const SassFALSE = sass.sassFalse;
28
+ const SassNULL = sass.sassNull;
29
+ const {
30
+ SassNumber
31
+ } = SassTypes;
32
+ const {
33
+ SassString
34
+ } = SassTypes;
35
+ const {
36
+ SassColor
37
+ } = SassTypes;
38
+ const {
39
+ SassList
40
+ } = SassTypes;
41
+ const {
42
+ SassMap
43
+ } = SassTypes;
44
+ const SassBoolean = _Object$getPrototypeOf(SassTRUE).constructor;
45
+
46
+ // Helper functions.
47
+ function isObject(value) {
48
+ const type = typeof value;
49
+ return !!value && (type === 'object' || type === 'function');
50
+ }
51
+ function sassToJavaScriptType(sassValue) {
52
+ switch (true) {
53
+ case sassValue instanceof SassBoolean:
54
+ {
55
+ return sassValue.value;
56
+ }
57
+ case sassValue instanceof SassString:
58
+ {
59
+ return sassValue.text;
60
+ }
61
+ case sassValue instanceof SassNumber:
62
+ {
63
+ const {
64
+ value,
65
+ numeratorUnits,
66
+ denominatorUnits
67
+ } = sassValue;
68
+ const unit = sassValue.hasUnits ? numeratorUnits.join('*') + (denominatorUnits.size > 0 ? `/${denominatorUnits.join('*')}` : '') : '';
69
+ return unit ? {
70
+ value,
71
+ unit
72
+ } : value;
73
+ }
74
+ case sassValue instanceof SassColor:
75
+ {
76
+ const {
77
+ red,
78
+ green,
79
+ blue,
80
+ alpha
81
+ } = sassValue;
82
+ return chroma(red, green, blue, alpha);
83
+ }
84
+ case sassValue instanceof SassList:
85
+ {
86
+ var _context;
87
+ const listValue = sassValue.asList;
88
+ const length = listValue.size;
89
+ const array = _fillInstanceProperty(_context = Array(length)).call(_context, undefined);
90
+ for (let index = 0; index < length; index += 1) {
91
+ array[index] = listValue.get(index);
92
+ }
93
+ return _mapInstanceProperty(array).call(array, value => sassToJavaScriptType(value));
94
+ }
95
+ case sassValue instanceof SassMap:
96
+ {
97
+ var _context2;
98
+ const mapValue = sassValue.contents;
99
+ const entries = _mapInstanceProperty(_context2 = _Array$from(_entriesInstanceProperty(mapValue).call(mapValue))).call(_context2, ([key, value]) => [sassToJavaScriptType(key), sassToJavaScriptType(value)]);
100
+ return new _Map(entries);
101
+ }
102
+ default:
103
+ {
104
+ return null;
105
+ }
106
+ }
107
+ }
108
+ function javaScriptToSassType(rawValue) {
109
+ var _context3;
110
+ switch (true) {
111
+ case typeof rawValue === 'boolean':
112
+ {
113
+ const booleanValue = rawValue;
114
+ return booleanValue ? SassTRUE : SassFALSE;
115
+ }
116
+ case typeof rawValue === 'number':
117
+ {
118
+ const numberValue = rawValue;
119
+ return new SassNumber(numberValue);
120
+ }
121
+ case isObject(rawValue) && _everyInstanceProperty(_context3 = ['value', 'unit']).call(_context3, propertyKey => propertyKey in rawValue):
122
+ {
123
+ const {
124
+ value,
125
+ unit
126
+ } = rawValue;
127
+ return new SassNumber(value, unit);
128
+ }
129
+ case typeof rawValue === 'string':
130
+ {
131
+ const stringValue = rawValue;
132
+ return new SassString(stringValue);
133
+ }
134
+ case isObject(rawValue) && '_rgb' in rawValue:
135
+ {
136
+ const [red, green, blue, alpha] = rawValue.rgba();
137
+ return new SassColor({
138
+ red,
139
+ green,
140
+ blue,
141
+ alpha
142
+ });
143
+ }
144
+ case _Array$isArray(rawValue):
145
+ {
146
+ return new SassList(_mapInstanceProperty(rawValue).call(rawValue, value => javaScriptToSassType(value)));
147
+ }
148
+ case rawValue instanceof _Map:
149
+ {
150
+ var _context4;
151
+ const mapValue = rawValue;
152
+ const sassMap = new SassMap();
153
+ const converted = _mapInstanceProperty(_context4 = _Array$from(_entriesInstanceProperty(mapValue).call(mapValue))).call(_context4, entry => _mapInstanceProperty(entry).call(entry, javaScriptToSassType));
154
+ for (const [key, value] of converted) {
155
+ sassMap.contents.set(key, value);
156
+ }
157
+ return sassMap;
158
+ }
159
+ default:
160
+ {
161
+ return SassNULL;
162
+ }
163
+ }
164
+ }
165
+
166
+ // Type definitions.
167
+
168
+ // Constants.
169
+ const KeyOfSignature = _Symbol('@cichol/sass-bridge::KeyOfSignature');
170
+ function sassFunction(definition) {
171
+ return target => {
172
+ Reflect.defineMetadata(KeyOfSignature, definition, target);
173
+ return target;
174
+ };
175
+ }
176
+ async function getFunctions(...moduleImports) {
177
+ const modules = await _Promise.all(_mapInstanceProperty(moduleImports).call(moduleImports, module => _Promise.resolve(module).then(module => module.default)));
178
+ const entries = _mapInstanceProperty(modules).call(modules, module => {
179
+ const signature = Reflect.getMetadata(KeyOfSignature, module);
180
+ async function customFunction(rawArgs) {
181
+ const args = _mapInstanceProperty(rawArgs).call(rawArgs, sassToJavaScriptType);
182
+ const result = await _Reflect$construct(module, args).execute();
183
+ return javaScriptToSassType(result);
184
+ }
185
+ return [signature, customFunction];
186
+ });
187
+ return _Object$fromEntries(entries);
188
+ }
189
+
190
+ export { getFunctions, sassFunction };
@@ -0,0 +1,18 @@
1
+ import type { BridgedFunction } from '../../types';
2
+ import { sassFunction } from '../../releases/esm.js'; // eslint-disable-line import/extensions
3
+
4
+ @sassFunction('custom-function($a, $b)')
5
+ export default class CustomFunction implements BridgedFunction {
6
+ #a: string;
7
+
8
+ #b: string;
9
+
10
+ public constructor(A: string, B: string) {
11
+ this.#a = A;
12
+ this.#b = B;
13
+ }
14
+
15
+ public async execute() {
16
+ return this.#a.toLowerCase() + this.#b.toUpperCase();
17
+ }
18
+ }
@@ -0,0 +1,15 @@
1
+ import type { BridgedFunction } from '../../types';
2
+ import { sassFunction } from '../../releases/esm.js'; // eslint-disable-line import/extensions
3
+
4
+ @sassFunction('sqrt-cos($x)')
5
+ export default class SquareRootCosine implements BridgedFunction {
6
+ #x: number;
7
+
8
+ public constructor(X: number) {
9
+ this.#x = X;
10
+ }
11
+
12
+ public async execute() {
13
+ return Math.sqrt(Math.cos(this.#x));
14
+ }
15
+ }
package/tests/index.ts ADDED
@@ -0,0 +1,31 @@
1
+ // eslint-disable-next-line eslint-comments/disable-enable-pair
2
+ /* eslint-disable import/extensions */
3
+
4
+ // Third-party modules.
5
+ import { describe, it } from 'mocha';
6
+ import { expect } from 'chai';
7
+ import * as sass from 'sass';
8
+
9
+ // Testing target.
10
+ import { getFunctions } from '../releases/esm.js';
11
+
12
+ describe('@cichol/sass-bridge', () => {
13
+ it('should be working properly', async () => {
14
+ const source = `
15
+ body > *:first-child:after {
16
+ content: custom-function('HELLO', 'world');
17
+ line-height: sqrt-cos(${2 * Math.PI});
18
+ }
19
+ `;
20
+
21
+ const functions = await getFunctions(
22
+ import('./artifacts/custom-function.ts'),
23
+ import('./artifacts/sqrt-cos.ts')
24
+ );
25
+
26
+ const { css: result } = await sass.compileStringAsync(source, { functions });
27
+
28
+ expect(result).to.includes('content: "helloWORLD";');
29
+ expect(result).to.includes('line-height: 1;');
30
+ });
31
+ });