Skip to content

Commit eeeac1d

Browse files
authored
Give JavaScript value objects useful constructor.name values (#936)
Closes #810
1 parent 244a1d9 commit eeeac1d

File tree

15 files changed

+117
-13
lines changed

15 files changed

+117
-13
lines changed

CHANGELOG.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,16 @@
2727

2828
* Add the variables `$pi` and `$e` to the built-in "sass:math" module.
2929

30+
### JavaScript API
31+
32+
* `constructor.value` fields on value objects now match their Node Sass
33+
equivalents.
34+
3035
## 1.24.5
3136

3237
* Highlight contextually-relevant sections of the stylesheet in error messages,
3338
rather than only highlighting the section where the error was detected.
34-
39+
3540
## 1.24.4
3641

3742
### JavaScript API

lib/src/node/utils.dart

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,14 @@ void jsForEach(Object object, void callback(Object key, Object value)) {
5858
}
5959
}
6060

61-
/// Creates a JS class with the given [constructor] and [methods].
61+
/// Creates a JS class with the given [name], [constructor] and [methods].
6262
///
6363
/// Both [constructor] and [methods] should take an initial `thisArg` parameter,
6464
/// representing the object being constructed.
65-
Function createClass(Function constructor, Map<String, Function> methods) {
65+
Function createClass(
66+
String name, Function constructor, Map<String, Function> methods) {
6667
var klass = allowInteropCaptureThis(constructor);
68+
_defineProperty(klass, 'name', _PropertyDescriptor(value: name));
6769
var prototype = getProperty(klass, 'prototype');
6870
methods.forEach((name, body) {
6971
setProperty(prototype, name, allowInteropCaptureThis(body));
@@ -77,6 +79,18 @@ external Object _getPrototypeOf(Object object);
7779
@JS("Object.setPrototypeOf")
7880
external void _setPrototypeOf(Object object, Object prototype);
7981

82+
@JS("Object.defineProperty")
83+
external void _defineProperty(
84+
Object object, String name, _PropertyDescriptor prototype);
85+
86+
@JS()
87+
@anonymous
88+
class _PropertyDescriptor {
89+
external Object get value;
90+
91+
external factory _PropertyDescriptor({Object value});
92+
}
93+
8094
@JS("Object.create")
8195
external Object _create(Object prototype);
8296

lib/src/node/value/color.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Object newNodeSassColor(SassColor value) =>
2020
callConstructor(colorConstructor, [null, null, null, null, value]);
2121

2222
/// The JS constructor for the `sass.types.Color` class.
23-
final Function colorConstructor = createClass(
23+
final Function colorConstructor = createClass('SassColor',
2424
(_NodeSassColor thisArg, num redOrArgb,
2525
[num green, num blue, num alpha, SassColor dartValue]) {
2626
if (dartValue != null) {

lib/src/node/value/list.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@ Object newNodeSassList(SassList value) =>
2121
callConstructor(listConstructor, [null, null, value]);
2222

2323
/// The JS constructor for the `sass.types.List` class.
24-
final Function listConstructor = createClass((_NodeSassList thisArg, int length,
25-
[bool commaSeparator, SassList dartValue]) {
24+
final Function listConstructor = createClass('SassList',
25+
(_NodeSassList thisArg, int length,
26+
[bool commaSeparator, SassList dartValue]) {
2627
thisArg.dartValue = dartValue ??
2728
SassList(Iterable.generate(length, (_) => sassNull),
2829
(commaSeparator ?? true) ? ListSeparator.comma : ListSeparator.space);

lib/src/node/value/map.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ Object newNodeSassMap(SassMap value) =>
2121
callConstructor(mapConstructor, [null, value]);
2222

2323
/// The JS constructor for the `sass.types.Map` class.
24-
final Function mapConstructor =
25-
createClass((_NodeSassMap thisArg, int length, [SassMap dartValue]) {
24+
final Function mapConstructor = createClass('SassMap',
25+
(_NodeSassMap thisArg, int length, [SassMap dartValue]) {
2626
thisArg.dartValue = dartValue ??
2727
SassMap(Map.fromIterables(Iterable.generate(length, (i) => SassNumber(i)),
2828
Iterable.generate(length, (_) => sassNull)));

lib/src/node/value/number.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Object newNodeSassNumber(SassNumber value) =>
2020
callConstructor(numberConstructor, [null, null, value]);
2121

2222
/// The JS constructor for the `sass.types.Number` class.
23-
final Function numberConstructor = createClass(
23+
final Function numberConstructor = createClass('SassNumber',
2424
(_NodeSassNumber thisArg, num value, [String unit, SassNumber dartValue]) {
2525
thisArg.dartValue = dartValue ?? _parseNumber(value, unit);
2626
}, {

lib/src/node/value/string.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Object newNodeSassString(SassString value) =>
2020
callConstructor(stringConstructor, [null, value]);
2121

2222
/// The JS constructor for the `sass.types.String` class.
23-
final Function stringConstructor = createClass(
23+
final Function stringConstructor = createClass('SassString',
2424
(_NodeSassString thisArg, String value, [SassString dartValue]) {
2525
thisArg.dartValue = dartValue ?? SassString(value, quotes: false);
2626
}, {

test/node_api/api.dart

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,20 @@ class NodeSassBooleanClass implements Function {
8585
external NodeSassBoolean get FALSE;
8686
}
8787

88+
@JS()
89+
class Constructor {
90+
external String get name;
91+
}
92+
8893
@JS()
8994
class NodeSassBoolean {
95+
external Constructor get constructor;
9096
external bool getValue();
9197
}
9298

9399
@JS()
94100
class NodeSassColor {
101+
external Constructor get constructor;
95102
external int getR();
96103
external void setR(num value);
97104
external int getG();
@@ -104,6 +111,7 @@ class NodeSassColor {
104111

105112
@JS()
106113
class NodeSassList {
114+
external Constructor get constructor;
107115
external Object getValue(int index);
108116
external void setValue(int index, Object value);
109117
external bool getSeparator();
@@ -113,6 +121,7 @@ class NodeSassList {
113121

114122
@JS()
115123
class NodeSassMap {
124+
external Constructor get constructor;
116125
external Object getValue(int index);
117126
external void setValue(int index, Object value);
118127
external Object getKey(int index);
@@ -123,11 +132,17 @@ class NodeSassMap {
123132
@JS()
124133
class NodeSassNullClass implements Function {
125134
external Object call();
126-
external Object get NULL;
135+
external NodeSassNull get NULL;
136+
}
137+
138+
@JS()
139+
class NodeSassNull implements Function {
140+
external Constructor get constructor;
127141
}
128142

129143
@JS()
130144
class NodeSassNumber {
145+
external Constructor get constructor;
131146
external num getValue();
132147
external void setValue(int value);
133148
external String getUnit();
@@ -136,6 +151,7 @@ class NodeSassNumber {
136151

137152
@JS()
138153
class NodeSassString {
154+
external Constructor get constructor;
139155
external String getValue();
140156
external void setValue(String value);
141157
}

test/node_api/value/boolean_test.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ void main() {
2525
expect(value, isJSInstanceOf(sass.types.Boolean));
2626
expect(value.getValue(), isFalse);
2727
});
28+
29+
test("has a useful .constructor.name", () {
30+
expect(parseValue<NodeSassBoolean>("true").constructor.name,
31+
equals("SassBoolean"));
32+
});
2833
});
2934

3035
group("from a constant", () {
@@ -39,6 +44,10 @@ void main() {
3944
expect(value, isJSInstanceOf(sass.types.Boolean));
4045
expect(value.getValue(), isFalse);
4146
});
47+
48+
test("has a useful .constructor.name", () {
49+
expect(sass.types.Boolean.FALSE.constructor.name, equals("SassBoolean"));
50+
});
4251
});
4352

4453
test("the constructor throws", () {

test/node_api/value/color_test.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,10 @@ void main() {
9393
color.setB(0.5);
9494
expect(color.getB(), equals(1));
9595
});
96+
97+
test("has a useful .constructor.name", () {
98+
expect(color.constructor.name, equals("SassColor"));
99+
});
96100
});
97101

98102
group("from a constructor", () {
@@ -120,5 +124,10 @@ void main() {
120124
expect(color.getB(), equals(0x78));
121125
expect(color.getA(), equals(0x12 / 0xff));
122126
});
127+
128+
test("has a useful .constructor.name", () {
129+
expect(callConstructor(sass.types.Color, [11, 12, 13]).constructor.name,
130+
equals("SassColor"));
131+
});
123132
});
124133
}

0 commit comments

Comments
 (0)