firefly-compiler 0.4.81 → 0.4.82

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.
@@ -1025,11 +1025,10 @@ extend self: Parser {
1025
1025
  if(self.current().is(LKeyword) && (self.current().rawIs("let") || self.current().rawIs("mutable"))) {self.parseLet()} else:
1026
1026
  if(self.current().is(LKeyword) && self.current().rawIs("function")) {self.parseFunctions()} else:
1027
1027
  let term = self.parseTerm()
1028
- if(!self.current().is(LAssign) && !self.current().is3(LAssignPlus, LAssignMinus, LAssignLink)) {term} else:
1028
+ if(!self.current().is(LAssign) && !self.current().is2(LAssignPlus, LAssignMinus)) {term} else:
1029
1029
  let token = do {
1030
1030
  if(self.current().is(LAssignPlus)) {self.skip(LAssignPlus)} else:
1031
1031
  if(self.current().is(LAssignMinus)) {self.skip(LAssignMinus)} else:
1032
- if(self.current().is(LAssignLink)) {self.skip(LAssignLink)} else:
1033
1032
  self.skip(LAssign)
1034
1033
  }
1035
1034
  let operator = token.raw().dropLast(1)
@@ -1153,7 +1152,7 @@ extend self: Parser {
1153
1152
  True
1154
1153
  } else {False}
1155
1154
  mutable result = self.parseAtom()
1156
- while {self.current().is(LBracketLeft) || self.current().is(LColon) || self.current().is(LDot)} {
1155
+ while {self.current().is4(LBracketLeft, LColon, LDot, LArrowThin)} {
1157
1156
  if(self.current().is(LDot)) {
1158
1157
  self.skip(LDot)
1159
1158
  if(self.current().rawIs("{")) {
@@ -1166,6 +1165,8 @@ extend self: Parser {
1166
1165
  let token = self.skip(LLower)
1167
1166
  result = EField(token.at(), False, result, token.raw())
1168
1167
  }
1168
+ } elseIf {self.current().is(LArrowThin)} {
1169
+ result = self.parseDynamicMember(result)
1169
1170
  } else {
1170
1171
  let at = self.current().at()
1171
1172
  let typeArguments = if(!self.current().rawIs("[")) {[]} else {self.parseTypeArguments()}
@@ -1181,6 +1182,46 @@ extend self: Parser {
1181
1182
  }
1182
1183
  result
1183
1184
  }
1185
+
1186
+ parseDynamicMember(record: Term): Term {
1187
+ self.skip(LArrowThin)
1188
+ let token = self.skip(LLower)
1189
+ let member = EString(token.at(), "\"" + token.raw() + "\"")
1190
+ if(self.current().rawIs("(")) {
1191
+ let arguments = self.parseFunctionArguments(record.at, False)
1192
+ let effect = self.freshUnificationVariable(record.at)
1193
+ let target = DynamicCall(EField(token.at(), False, record, "call" + arguments.first.size()), False)
1194
+ ECall(record.at, target, effect, [], [
1195
+ Argument(member.at, None, member)
1196
+ ...arguments.first
1197
+ ], [])
1198
+ } elseIf {self.current().is3(LAssign, LAssignPlus, LAssignMinus)} {
1199
+ let method =
1200
+ if(self.current().is(LAssign)) {
1201
+ self.skip(LAssign)
1202
+ "set"
1203
+ } elseIf {self.current().is(LAssignPlus)} {
1204
+ self.skip(LAssignPlus)
1205
+ "increment"
1206
+ } else {
1207
+ self.skip(LAssignMinus)
1208
+ "decrement"
1209
+ }
1210
+ let value = self.parseTerm()
1211
+ let effect = self.freshUnificationVariable(record.at)
1212
+ let target = DynamicCall(EField(token.at(), False, record, "set"), False)
1213
+ ECall(record.at, target, effect, [], [
1214
+ Argument(member.at, None, member)
1215
+ Argument(value.at, None, value)
1216
+ ], [])
1217
+ } else {
1218
+ let effect = self.freshUnificationVariable(record.at)
1219
+ let target = DynamicCall(EField(token.at(), False, record, "get"), False)
1220
+ ECall(record.at, target, effect, [], [
1221
+ Argument(member.at, None, member)
1222
+ ], [])
1223
+ }
1224
+ }
1184
1225
 
1185
1226
  parseAtom(): Term {
1186
1227
  if(self.current().is(LString)) {
package/compiler/Token.ff CHANGED
@@ -38,6 +38,10 @@ extend token: Token {
38
38
  token.kind == kind1 || token.kind == kind2 || token.kind == kind3
39
39
  }
40
40
 
41
+ is4(kind1: TokenKind, kind2: TokenKind, kind3: TokenKind, kind4: TokenKind): Bool {
42
+ token.kind == kind1 || token.kind == kind2 || token.kind == kind3 || token.kind == kind4
43
+ }
44
+
41
45
  rawIs(value: String): Bool {
42
46
  token.stopOffset - token.startOffset == value.size() &&
43
47
  token.code.startsWith(value, token.startOffset)
@@ -78,11 +82,11 @@ data TokenKind {
78
82
  LPipe
79
83
  LColon
80
84
  LDotDotDot
85
+ LArrowThin
81
86
  LArrowThick
82
87
  LAssign
83
88
  LAssignPlus
84
89
  LAssignMinus
85
- LAssignLink
86
90
  }
87
91
 
88
92
  extend self: TokenKind {
@@ -109,11 +113,11 @@ extend self: TokenKind {
109
113
  | LPipe => False
110
114
  | LColon => False
111
115
  | LDotDotDot => False
116
+ | LArrowThin => False
112
117
  | LArrowThick => False
113
118
  | LAssign => False
114
119
  | LAssignPlus => False
115
120
  | LAssignMinus => False
116
- | LAssignLink => False
117
121
  }
118
122
  }
119
123
 
@@ -139,11 +143,11 @@ extend self: TokenKind {
139
143
  | LPipe => False
140
144
  | LColon => False
141
145
  | LDotDotDot => True
146
+ | LArrowThin => False
142
147
  | LArrowThick => False
143
148
  | LAssign => False
144
149
  | LAssignPlus => False
145
150
  | LAssignMinus => False
146
- | LAssignLink => False
147
151
  }
148
152
  }
149
153
 
@@ -169,11 +173,11 @@ extend self: TokenKind {
169
173
  | LPipe => False
170
174
  | LColon => False
171
175
  | LDotDotDot => False
176
+ | LArrowThin => False
172
177
  | LArrowThick => False
173
178
  | LAssign => False
174
179
  | LAssignPlus => False
175
180
  | LAssignMinus => False
176
- | LAssignLink => False
177
181
  }
178
182
  }
179
183
 
@@ -226,6 +226,8 @@ tokenize(file: String, code: String, completionAt: Option[Location], attemptFixe
226
226
  LColon
227
227
  } elseIf {i - start == 3 && code.grab(i - 3) == '.' && code.grab(i - 2) == '.' && code.grab(i - 1) == '.'} {
228
228
  LDotDotDot
229
+ } elseIf {i - start == 2 && code.grab(i - 2) == '-' && code.grab(i - 1) == '>'} {
230
+ LArrowThin
229
231
  } elseIf {i - start == 2 && code.grab(i - 2) == '=' && code.grab(i - 1) == '>'} {
230
232
  LArrowThick
231
233
  } elseIf {i - start == 1 && code.grab(i - 1) == '='} {
@@ -234,8 +236,6 @@ tokenize(file: String, code: String, completionAt: Option[Location], attemptFixe
234
236
  LAssignPlus
235
237
  } elseIf {i - start == 2 && code.grab(i - 2) == '-' && code.grab(i - 1) == '='} {
236
238
  LAssignMinus
237
- } elseIf {i - start == 3 && code.grab(i - 3) == ':' && code.grab(i - 2) == ':' && code.grab(i - 1) == '='} {
238
- LAssignLink
239
239
  } else {
240
240
  LOperator
241
241
  }
package/core/JsSystem.ff CHANGED
@@ -5,6 +5,18 @@ extend self: JsSystem {
5
5
  global(): JsValue
6
6
  target js sync "return self_"
7
7
 
8
+ get(key: String): JsValue
9
+ target js sync "return self_[key_]"
10
+
11
+ set[V: IsJsValue](key: String, value: V): Unit
12
+ target js sync "self_[key_] = value_"
13
+
14
+ increment[V: IsJsValue](key: String, value: V): Unit
15
+ target js sync "self_[key_] += value_"
16
+
17
+ decrement[V: IsJsValue](key: String, value: V): Unit
18
+ target js sync "self_[key_] -= value_"
19
+
8
20
  parseJson(json: String): JsValue
9
21
  target js sync "return JSON.parse(json_)"
10
22
 
package/core/JsValue.ff CHANGED
@@ -88,6 +88,12 @@ extend self: JsValue {
88
88
  set[K: IsJsValue, V: IsJsValue](key: K, value: V): Unit
89
89
  target js sync "self_[key_] = value_"
90
90
 
91
+ increment[K: IsJsValue, V: IsJsValue](key: K, value: V): Unit
92
+ target js sync "self_[key_] += value_"
93
+
94
+ decrement[K: IsJsValue, V: IsJsValue](key: K, value: V): Unit
95
+ target js sync "self_[key_] -= value_"
96
+
91
97
  delete[K: IsJsValue](key: K): Unit
92
98
  target js sync "delete self_[key_]"
93
99
 
package/lux/Lux.ff CHANGED
@@ -15,6 +15,7 @@ capability Lux(
15
15
  mutable keys: Option[StringMap[JsValue]]
16
16
  mutable key: String
17
17
  mutable attributes: Option[StringMap[String]]
18
+ mutable texts: Array[String]
18
19
  )
19
20
 
20
21
  capability RenderQueueItem(
@@ -71,16 +72,16 @@ extend self: DryNode {
71
72
 
72
73
  extend self: LuxElement {
73
74
  childAt(index: Int): JsValue {
74
- self.element.get("childNodes").get(index)
75
+ self.element->childNodes.get(index)
75
76
  }
76
77
  insertBefore(newNode: JsValue, referenceNode: JsValue): JsValue {
77
- self.element.call2("insertBefore", newNode, referenceNode)
78
+ self.element->insertBefore(newNode, referenceNode)
78
79
  }
79
80
  removeAt(index: Int): Bool {
80
81
  let node = self.childAt(index)
81
82
  let remove = !node.isNullOrUndefined()
82
83
  if(remove) {
83
- self.element.call1("removeChild", node)
84
+ self.element->removeChild(node)
84
85
  }
85
86
  remove
86
87
  }
@@ -88,15 +89,15 @@ extend self: LuxElement {
88
89
 
89
90
  extend self: LuxDocument {
90
91
  createTextNode(value: String): JsValue {
91
- self.document.call1("createTextNode", value)
92
+ self.document->createTextNode(value)
92
93
  }
93
94
 
94
95
  createElement(tagName: String): JsValue {
95
- self.document.call1("createElement", tagName)
96
+ self.document->createElement(tagName)
96
97
  }
97
98
 
98
99
  createFragment(): JsValue {
99
- self.document.call0("createDocumentFragment")
100
+ self.document->createDocumentFragment()
100
101
  }
101
102
  }
102
103
 
@@ -113,27 +114,28 @@ extend self: Lux {
113
114
  }
114
115
 
115
116
  text(value: String) {
116
- self.dry.map {_.push(DryText(value))}.else:
117
- let oldNode = self.element.childAt(self.element.child)
118
- let oldValue = if(!oldNode.isNullOrUndefined()) {oldNode.get("data")} else {oldNode}
119
- if(oldValue.isNullOrUndefined() || oldValue.grabString() != value) {
120
- let node = self.document.createTextNode(value)
121
- self.element.insertBefore(node, oldNode)
117
+ if(value.size() != 0) {
118
+ self.texts.push(value)
122
119
  }
123
- self.element.child += 1
124
120
  }
125
121
 
126
122
  add(tagName: String, body: () => Unit = {}) {
123
+ patchText(self)
127
124
  self.dry.map {dry =>
128
125
  self.dry = Some([].toArray())
129
126
  let savedAttributes = self.attributes
130
127
  let savedKeys = self.keys
131
- self.attributes = None
128
+ self.attributes = if(self.key != "") {
129
+ let attributes = StringMap.new()
130
+ attributes.set("data-lux-key", tagName.upper() + ">" + self.key)
131
+ attributes
132
+ }
132
133
  self.key = ""
133
134
  self.depth += 1
134
135
  try {
135
136
  body()
136
137
  } finally {
138
+ patchText(self)
137
139
  dry.push(DryElement(tagName, self.attributes.else {StringMap.new()}, self.dry.grab()))
138
140
  self.depth -= 1
139
141
  self.attributes = savedAttributes
@@ -143,23 +145,24 @@ extend self: Lux {
143
145
  }
144
146
  }.else:
145
147
  let node = patchElement(self, tagName)
146
- if(!node.get("luxHandlers").isNullOrUndefined()) {
147
- node.get("luxHandlers").grabArray().each {pair =>
148
- node.call2("removeEventListener", pair.get("event"), pair.get("handler"))
148
+ if(!node->luxHandlers.isNullOrUndefined()) {
149
+ node->luxHandlers.grabArray().each {pair =>
150
+ node->removeEventListener(pair->event, pair->handler)
149
151
  }
150
- node.set("luxHandlers", self.jsSystem.array([]))
152
+ node->luxHandlers = self.jsSystem.array([])
151
153
  }
152
154
  let savedAttributes = self.attributes
153
155
  let savedKeys = self.keys
154
156
  let savedElement = self.element
155
157
  self.attributes = None
156
158
  self.element = LuxElement(node, 0, keepChildren = False)
157
- self.element.element.get("classList").set("value", "")
159
+ self.element.element->classList->value = ""
158
160
  self.key = ""
159
161
  self.depth += 1
160
162
  try {
161
163
  body()
162
164
  } finally {
165
+ patchText(self)
163
166
  if(!self.element.keepChildren) {
164
167
  doWhile {removeCurrentChild(self)}
165
168
  }
@@ -212,7 +215,7 @@ extend self: Lux {
212
215
 
213
216
  setValue(value: String) { // TODO: Not an attribute
214
217
  self.dry.map {_ => self.set("value", value)}.else:
215
- self.element.element.set("value", value)
218
+ self.element.element->value = value
216
219
  }
217
220
 
218
221
  css(style: Css) {
@@ -233,15 +236,15 @@ extend self: Lux {
233
236
  self.cssClasses.set(class.name(), class)
234
237
  if(self.dry.isEmpty()):
235
238
  let styleSheet = self.document.createElement("style")
236
- styleSheet.set("textContent", class.show())
237
- self.document.document.get("head").call1("appendChild", styleSheet)
239
+ styleSheet->textContent = class.show()
240
+ self.document.document->head->appendChild(styleSheet)
238
241
  }
239
242
  if(!self.dry.isEmpty()) {
240
243
  let classNames = self.attributes.flatMap {_.get("class")}.else {""}
241
244
  self.set("class", (classNames + " " + class.name()).trim())
242
245
  } else {
243
- self.element.element.get("classList").call1("add", class.name())
244
- self.set("class", self.element.element.get("className").grabString())
246
+ self.element.element->classList->add(class.name())
247
+ self.set("class", self.element.element->className.grabString())
245
248
  }
246
249
  }
247
250
 
@@ -253,11 +256,11 @@ extend self: Lux {
253
256
  processRenderQueue(self)
254
257
  }
255
258
  }
256
- self.element.element.call2("addEventListener", event, jsHandler)
257
- if(self.element.element.get("luxHandlers").isNullOrUndefined()) {
258
- self.element.element.set("luxHandlers", self.jsSystem.array([]))
259
+ self.element.element->addEventListener(event, jsHandler)
260
+ if(self.element.element->luxHandlers.isNullOrUndefined()) {
261
+ self.element.element->luxHandlers = self.jsSystem.array([])
259
262
  }
260
- self.element.element.get("luxHandlers").call1("push"
263
+ self.element.element->luxHandlers->push(
261
264
  self.jsSystem.object().with("event", event).with("handler", jsHandler)
262
265
  )
263
266
  }
@@ -410,7 +413,7 @@ processRenderQueue(self: Lux) {
410
413
 
411
414
  removeCurrentChild(self: Lux): Bool {
412
415
  let child = self.element.childAt(self.element.child)
413
- if(!child.isNullOrUndefined() && !child.get("children").isNullOrUndefined()) {
416
+ if(!child.isNullOrUndefined() && !child->children.isNullOrUndefined()) {
414
417
  abortTasksOnElement(self, child, False)
415
418
  }
416
419
  self.element.removeAt(self.element.child)
@@ -429,21 +432,21 @@ setStateOnElement[T /*: HasAnyTag*/](element: JsValue, depth: Int, value: T): Un
429
432
 
430
433
 
431
434
  getTaskOnElement(element: JsValue): Option[Task] {
432
- let value = element.get("luxTask")
435
+ let value = element->luxTask
433
436
  if(value.isNullOrUndefined()) {None} else {
434
437
  unsafeJsToValue(value)
435
438
  }
436
439
  }
437
440
 
438
441
  setTaskOnElement(element: JsValue, task: Option[Task]): Unit {
439
- element.set("luxTask", unsafeJsFromValue(task))
442
+ element->luxTask = unsafeJsFromValue(task)
440
443
  }
441
444
 
442
445
  abortTasksOnElement(lux: Lux, element: JsValue, onlyChildren: Bool): Unit {
443
446
  if(!onlyChildren) {
444
447
  getTaskOnElement(element).each {task => forceAsyncAbort(lux, task)}
445
448
  }
446
- element.get("children").each {child =>
449
+ element->children.each {child =>
447
450
  abortTasksOnElement(lux, child, False)
448
451
  }
449
452
  }
@@ -460,19 +463,34 @@ unsafeAsyncFunction1ToJs[R](self: Lux, body: JsValue => R): JsValue
460
463
  forceAsyncAbort(self: Lux, task: Task): Unit {
461
464
  task.abort()
462
465
  }
463
-
466
+
467
+ patchText(self: Lux) {
468
+ if(!self.texts.isEmpty()):
469
+ let value = self.texts.drain().join()
470
+ self.dry.map {_.push(DryText(value))}.else:
471
+ let oldNode = self.element.childAt(self.element.child)
472
+ let oldValue = if(!oldNode.isNullOrUndefined()) {oldNode->data} else {oldNode}
473
+ if(oldValue.isNullOrUndefined() || oldValue.grabString() != value) {
474
+ let node = self.document.createTextNode(value)
475
+ self.element.insertBefore(node, oldNode)
476
+ }
477
+ self.element.child += 1
478
+ }
479
+
464
480
  patchElement(self: Lux, tagName: String): JsValue {
465
481
  let newKey = if(self.key != "") {tagName.upper() + ">" + self.key} else {""}
466
482
  let oldNode = self.element.childAt(self.element.child)
467
- let oldKey = if(!oldNode.isNullOrUndefined()) {oldNode.get("luxKey")} else {oldNode}
483
+ let oldKey = if(!oldNode.isNullOrUndefined() && !oldNode->getAttribute.isNullOrUndefined()) {
484
+ oldNode->getAttribute("data-lux-key")
485
+ } else {oldNode}
468
486
  let match = if(newKey != "") {
469
487
  !oldKey.isNullOrUndefined() &&
470
488
  oldKey.grabString() == newKey
471
489
  } else {
472
490
  oldKey.isNullOrUndefined() &&
473
491
  !oldNode.isNullOrUndefined() &&
474
- !oldNode.get("tagName").isNullOrUndefined() &&
475
- oldNode.get("tagName").grabString() == tagName.upper()
492
+ !oldNode->tagName.isNullOrUndefined() &&
493
+ oldNode->tagName.grabString() == tagName.upper()
476
494
  }
477
495
  if(match) {
478
496
  oldNode
@@ -483,8 +501,10 @@ patchElement(self: Lux, tagName: String): JsValue {
483
501
  mutable i = self.element.child
484
502
  mutable c = self.element.childAt(i)
485
503
  while {!c.isNullOrUndefined()} {
486
- let k = c.get("luxKey")
487
- if(!k.isNullOrUndefined()) {map.set(k.grabString(), c)}
504
+ if(!c->getAttribute.isNullOrUndefined()) {
505
+ let k = c->getAttribute("data-lux-key")
506
+ if(!k.isNullOrUndefined()) {map.set(k.grabString(), c)}
507
+ }
488
508
  c = self.element.childAt(i)
489
509
  i += 1
490
510
  }
@@ -497,7 +517,7 @@ patchElement(self: Lux, tagName: String): JsValue {
497
517
  foundNode
498
518
  } else {
499
519
  let createdNode = self.document.createElement(tagName)
500
- createdNode.set("luxKey", newKey)
520
+ createdNode->setAttribute("data-lux-key", newKey)
501
521
  createdNode
502
522
  }
503
523
  }
@@ -507,28 +527,28 @@ patchElement(self: Lux, tagName: String): JsValue {
507
527
  }
508
528
 
509
529
  patchAttributes(self: Lux) {
510
- let attributes = self.element.element.get("attributes")
530
+ let attributes = self.element.element->attributes
511
531
  self.attributes.{
512
532
  | None =>
513
- mutable i = attributes.get("length").grabInt() - 1
533
+ mutable i = attributes->length.grabInt() - 1
514
534
  while {i >= 0} {
515
535
  let attribute = attributes.get(i)
516
- self.element.element.call1("removeAttribute", attribute.get("name"))
536
+ self.element.element->removeAttribute(attribute->name)
517
537
  i -= 1
518
538
  }
519
539
  | Some(map) =>
520
- mutable i = attributes.get("length").grabInt() - 1
540
+ mutable i = attributes->length.grabInt() - 1
521
541
  while {i >= 0} {
522
542
  let attribute = attributes.get(i)
523
- if(!map.has(attribute.get("name").grabString())) {
524
- self.element.element.call1("removeAttribute", attribute.get("name"))
543
+ if(!map.has(attribute->name.grabString())) {
544
+ self.element.element->removeAttribute(attribute->name)
525
545
  }
526
546
  i -= 1
527
547
  }
528
548
  map.each {name, value =>
529
- let oldValue = self.element.element.call1("getAttribute", name)
549
+ let oldValue = self.element.element->getAttribute(name)
530
550
  if(oldValue.isNullOrUndefined() || !oldValue.equals(value)) {
531
- self.element.element.call2("setAttribute", name, value)
551
+ self.element.element->setAttribute(name, value)
532
552
  }
533
553
  }
534
554
  }
@@ -536,14 +556,14 @@ patchAttributes(self: Lux) {
536
556
 
537
557
  render(browserSystem: BrowserSystem, element: JsValue, body: Lux => Unit) {
538
558
  mutable document = element
539
- while {!document.get("parentNode").isNullOrUndefined()} {
540
- document = document.get("parentNode")
559
+ while {!document->parentNode.isNullOrUndefined()} {
560
+ document = document->parentNode
541
561
  }
542
562
  // [...document.querySelectorAll("[lux-class]")].map(x => x.getAttribute("lux-class"))
543
563
  let staticCssClasses = StringMap.new()
544
564
  let dummyCssClass = CssClass([], [], [])
545
- document.call1("querySelectorAll", "[lux-class]").each {e =>
546
- staticCssClasses.set(e.call1("getAttribute", "lux-class").grabString(), dummyCssClass)
565
+ document->querySelectorAll("[lux-class]").each {e =>
566
+ staticCssClasses.set(e->getAttribute("lux-class").grabString(), dummyCssClass)
547
567
  }
548
568
  let lux = Lux(
549
569
  jsSystem = browserSystem.js()
@@ -557,15 +577,17 @@ render(browserSystem: BrowserSystem, element: JsValue, body: Lux => Unit) {
557
577
  keys = None
558
578
  key = ""
559
579
  attributes = None
580
+ texts = Array.new()
560
581
  renderQueue = Array.new()
561
582
  )
562
583
  lux.renderLock.do(reentrant = False) {
563
584
  body(lux)
585
+ patchText(lux)
564
586
  }
565
587
  }
566
588
 
567
589
  renderById(browserSystem: BrowserSystem, id: String, body: Lux => Unit) {
568
- let element = browserSystem.js().global().get("document").call1("getElementById", id)
590
+ let element = browserSystem.js()->document->getElementById(id)
569
591
  render(browserSystem, element, body)
570
592
  }
571
593
 
@@ -583,9 +605,11 @@ renderToString(nodeSystem: NodeSystem, body: Lux => Unit): Pair[String, String]
583
605
  keys = None
584
606
  key = ""
585
607
  attributes = None
608
+ texts = Array.new()
586
609
  renderQueue = Array.new()
587
610
  )
588
611
  body(lux)
612
+ patchText(lux)
589
613
  let styleTags = lux.cssClasses.values().map {c =>
590
614
  "<style lux-class=\"" + c.name() + "\">" + c.show() + "</style>"
591
615
  }.join()
package/lux/TestDry.ff CHANGED
@@ -5,7 +5,7 @@ nodeMain(system: NodeSystem) {
5
5
 
6
6
 
7
7
  let html = Lux.renderToString(system, render)
8
- Log.trace(html)
8
+ Log.trace(html.first)
9
9
 
10
10
  }
11
11
 
@@ -14,6 +14,7 @@ render(lux: Lux): Unit {
14
14
  lux.set("id", "its-me")
15
15
  lux.span {
16
16
  lux.text("Hello")
17
+ lux.keyed("noegle"):
17
18
  lux.div {
18
19
  lux.set("id", "it's \"a-me\"")
19
20
  lux.span {