/
index.js
129 lines (93 loc) · 2.77 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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
118
119
120
121
122
123
124
125
126
127
128
129
const path = require('path');
const { sync: resolveSync } = require('resolve');
const dotProp = require('dot-prop');
const sass = require('node-sass');
const toJS = sassValue => {
if (sassValue instanceof sass.types.Number) {
return sassValue.getValue();
}
if (sassValue instanceof sass.types.String) {
return sassValue.getValue();
}
// TODO?: color
if (sassValue instanceof sass.types.Boolean) {
return sassValue.getValue();
}
if (sassValue instanceof sass.types.Null) {
return null;
}
if (sassValue instanceof sass.types.List) {
const length = sassValue.getLength();
const result = [];
for (let i = 0; i < length; i++) {
result.push(toJS(sassValue.getValue(i)));
}
// TODO?: separator
return result;
}
throw new TypeError(`Could not convert an expected SASS value \`${sassValue}\` to a JS value.`);
};
const toSass = jsValue => {
if (typeof jsValue === 'number') {
return new sass.types.Number(jsValue);
}
if (typeof jsValue === 'string') {
return new sass.types.String(jsValue);
}
// TODO?: color
if (typeof jsValue === 'boolean') {
return jsValue ? sass.types.Boolean.TRUE : sass.types.Boolean.FALSE;
}
if (Array.isArray(jsValue)) {
const result = new sass.types.List(jsValue.length);
for (const [ i, value ] of jsValue.entries()) {
result.setValue(i, toSass(value));
}
// TODO?: separator
return result;
}
if (jsValue === null || jsValue === undefined) {
return sass.types.Null.NULL;
}
if (typeof jsValue === 'object') {
const keys = Object.keys(jsValue);
const result = new sass.types.Map(keys.length);
let i = 0;
for (const key of keys) {
const value = jsValue[key];
result.setKey(i, toSass(key));
result.setValue(i, toSass(value));
i += 1;
}
return result;
}
// TODO?: Map
throw new TypeError(`Could not convert an expected JS value \`${jsValue}\` to a SASS value.`);
};
const functions = {
'ffi-require($module-path, $property-path: null)'(modulePath, propertyPath) {
modulePath = toJS(modulePath);
propertyPath = toJS(propertyPath);
const dirname = this.options.file && path.dirname(this.options.file);
const includePaths = Array.isArray(this.options.includePaths) ?
this.options.includePaths :
this.options.includePaths.split(':');
const paths = includePaths.concat(dirname).filter(Boolean);
const basedir = paths[paths.length - 1];
const resolvedModulePath = resolveSync(modulePath, {
basedir,
});
const module = require(resolvedModulePath);
const value = propertyPath ? dotProp.get(module, propertyPath) : module;
return toSass(value);
},
};
const withSassFfiOptions = options => {
options = options || {};
return Object.assign({}, options, {
functions: Object.assign({}, options.functions || {}, functions),
});
};
module.exports = {
withSassFfiOptions,
};