rapydscript-ns 0.8.4 → 0.9.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.
Files changed (132) hide show
  1. package/.agignore +1 -1
  2. package/.github/workflows/ci.yml +38 -38
  3. package/=template.pyj +5 -5
  4. package/CHANGELOG.md +18 -0
  5. package/HACKING.md +103 -103
  6. package/LICENSE +24 -24
  7. package/README.md +715 -169
  8. package/TODO.md +9 -2
  9. package/add-toc-to-readme +2 -2
  10. package/bin/export +75 -75
  11. package/bin/rapydscript +70 -70
  12. package/bin/web-repl-export +102 -102
  13. package/build +2 -2
  14. package/language-service/index.js +36 -27
  15. package/package.json +1 -1
  16. package/publish.py +37 -37
  17. package/release/baselib-plain-pretty.js +2358 -168
  18. package/release/baselib-plain-ugly.js +73 -3
  19. package/release/compiler.js +6282 -3092
  20. package/release/signatures.json +31 -30
  21. package/session.vim +4 -4
  22. package/setup.cfg +2 -2
  23. package/src/ast.pyj +1 -0
  24. package/src/baselib-builtins.pyj +340 -2
  25. package/src/baselib-bytes.pyj +664 -0
  26. package/src/baselib-errors.pyj +1 -1
  27. package/src/baselib-internal.pyj +267 -60
  28. package/src/baselib-itertools.pyj +110 -97
  29. package/src/baselib-str.pyj +22 -4
  30. package/src/compiler.pyj +36 -36
  31. package/src/errors.pyj +30 -30
  32. package/src/lib/abc.pyj +317 -0
  33. package/src/lib/aes.pyj +646 -646
  34. package/src/lib/copy.pyj +120 -120
  35. package/src/lib/dataclasses.pyj +532 -0
  36. package/src/lib/elementmaker.pyj +83 -83
  37. package/src/lib/encodings.pyj +126 -126
  38. package/src/lib/enum.pyj +125 -0
  39. package/src/lib/gettext.pyj +569 -569
  40. package/src/lib/itertools.pyj +580 -580
  41. package/src/lib/math.pyj +193 -193
  42. package/src/lib/operator.pyj +11 -11
  43. package/src/lib/pythonize.pyj +20 -20
  44. package/src/lib/random.pyj +118 -118
  45. package/src/lib/re.pyj +504 -470
  46. package/src/lib/react.pyj +74 -74
  47. package/src/lib/traceback.pyj +63 -63
  48. package/src/lib/typing.pyj +577 -0
  49. package/src/lib/uuid.pyj +77 -77
  50. package/src/monaco-language-service/builtins.js +14 -4
  51. package/src/monaco-language-service/diagnostics.js +19 -20
  52. package/src/monaco-language-service/dts.js +550 -550
  53. package/src/output/classes.pyj +62 -26
  54. package/src/output/comments.pyj +45 -45
  55. package/src/output/exceptions.pyj +201 -201
  56. package/src/output/functions.pyj +78 -5
  57. package/src/output/jsx.pyj +164 -164
  58. package/src/output/loops.pyj +5 -2
  59. package/src/output/operators.pyj +100 -34
  60. package/src/output/treeshake.pyj +182 -182
  61. package/src/output/utils.pyj +72 -72
  62. package/src/parse.pyj +80 -16
  63. package/src/string_interpolation.pyj +72 -72
  64. package/src/tokenizer.pyj +9 -4
  65. package/src/unicode_aliases.pyj +576 -576
  66. package/src/utils.pyj +192 -192
  67. package/test/_import_one.pyj +37 -37
  68. package/test/_import_two/__init__.pyj +11 -11
  69. package/test/_import_two/level2/deep.pyj +4 -4
  70. package/test/_import_two/other.pyj +6 -6
  71. package/test/_import_two/sub.pyj +13 -13
  72. package/test/abc.pyj +291 -0
  73. package/test/aes_vectors.pyj +421 -421
  74. package/test/annotations.pyj +80 -80
  75. package/test/arithmetic_nostrict.pyj +88 -0
  76. package/test/arithmetic_types.pyj +169 -0
  77. package/test/baselib.pyj +91 -0
  78. package/test/bytes.pyj +467 -0
  79. package/test/classes.pyj +1 -0
  80. package/test/comparison_ops.pyj +173 -0
  81. package/test/dataclasses.pyj +253 -0
  82. package/test/decorators.pyj +77 -77
  83. package/test/docstrings.pyj +39 -39
  84. package/test/elementmaker_test.pyj +45 -45
  85. package/test/enum.pyj +134 -0
  86. package/test/eval_exec.pyj +56 -0
  87. package/test/format.pyj +148 -0
  88. package/test/functions.pyj +151 -151
  89. package/test/generators.pyj +41 -41
  90. package/test/generic.pyj +370 -370
  91. package/test/imports.pyj +72 -72
  92. package/test/internationalization.pyj +73 -73
  93. package/test/lint.pyj +164 -164
  94. package/test/loops.pyj +85 -85
  95. package/test/numpy.pyj +734 -734
  96. package/test/object.pyj +64 -0
  97. package/test/omit_function_metadata.pyj +20 -20
  98. package/test/python_compat.pyj +17 -15
  99. package/test/python_features.pyj +70 -15
  100. package/test/regexp.pyj +83 -55
  101. package/test/repl.pyj +121 -121
  102. package/test/scoped_flags.pyj +76 -76
  103. package/test/tuples.pyj +96 -0
  104. package/test/typing.pyj +469 -0
  105. package/test/unit/index.js +116 -7
  106. package/test/unit/language-service-dts.js +543 -543
  107. package/test/unit/language-service-hover.js +455 -455
  108. package/test/unit/language-service.js +84 -0
  109. package/test/unit/web-repl.js +804 -1
  110. package/test/vars_locals_globals.pyj +94 -0
  111. package/tools/cli.js +558 -547
  112. package/tools/compile.js +224 -219
  113. package/tools/completer.js +131 -131
  114. package/tools/embedded_compiler.js +262 -251
  115. package/tools/gettext.js +185 -185
  116. package/tools/ini.js +65 -65
  117. package/tools/lint.js +16 -19
  118. package/tools/msgfmt.js +187 -187
  119. package/tools/repl.js +223 -223
  120. package/tools/test.js +118 -118
  121. package/tools/utils.js +128 -128
  122. package/tools/web_repl.js +95 -95
  123. package/try +41 -41
  124. package/web-repl/env.js +196 -196
  125. package/web-repl/index.html +163 -163
  126. package/web-repl/main.js +252 -252
  127. package/web-repl/prism.css +139 -139
  128. package/web-repl/prism.js +113 -113
  129. package/web-repl/rapydscript.js +224 -224
  130. package/web-repl/sha1.js +25 -25
  131. package/PYTHON_DIFFERENCES_REPORT.md +0 -291
  132. package/PYTHON_FEATURE_COVERAGE.md +0 -200
@@ -0,0 +1,253 @@
1
+ # globals: assrt
2
+ # vim:fileencoding=utf-8
3
+ #
4
+ # dataclasses.pyj
5
+ # Tests for the dataclasses standard library.
6
+
7
+ ae = assrt.equal
8
+ ade = assrt.deepEqual
9
+ ok = assrt.ok
10
+
11
+ from dataclasses import dataclass, field, fields, asdict, astuple, replace, is_dataclass, MISSING
12
+
13
+ # ── 1. Basic @dataclass: __init__, __repr__, __eq__ ───────────────────────────
14
+
15
+ @dataclass
16
+ class _Point:
17
+ x: float
18
+ y: float
19
+
20
+ p1 = _Point(1, 2)
21
+ ae(p1.x, 1)
22
+ ae(p1.y, 2)
23
+ ae(repr(p1), '_Point(x=1, y=2)')
24
+ ok(p1 == _Point(1, 2))
25
+ ok(p1 is not _Point(1, 2)) # different instances
26
+ ok(not (p1 == _Point(1, 9)))
27
+
28
+ # ── 2. Default values ─────────────────────────────────────────────────────────
29
+
30
+ @dataclass
31
+ class _Config:
32
+ name: str
33
+ debug: bool = False
34
+ count: int = 0
35
+
36
+ c1 = _Config('myapp')
37
+ ae(c1.name, 'myapp')
38
+ ok(c1.debug is False)
39
+ ae(c1.count, 0)
40
+
41
+ c2 = _Config('other', True, 5)
42
+ ae(c2.name, 'other')
43
+ ok(c2.debug is True)
44
+ ae(c2.count, 5)
45
+
46
+ # ── 3. Keyword arguments ──────────────────────────────────────────────────────
47
+
48
+ c3 = _Config(name='test', debug=True)
49
+ ae(c3.name, 'test')
50
+ ok(c3.debug is True)
51
+ ae(c3.count, 0)
52
+
53
+ # ── 4. field() with default_factory ──────────────────────────────────────────
54
+
55
+ @dataclass
56
+ class _Container:
57
+ items: list = field(default_factory=list)
58
+ label: str = 'default'
59
+
60
+ a = _Container()
61
+ b = _Container()
62
+ # Each instance gets its own list
63
+ a.items.push(1)
64
+ ae(a.items.length, 1)
65
+ ae(b.items.length, 0)
66
+ ae(a.label, 'default')
67
+
68
+ d = _Container(label='custom')
69
+ ae(d.label, 'custom')
70
+
71
+ # ── 5. field() repr=False ─────────────────────────────────────────────────────
72
+
73
+ @dataclass
74
+ class _Hidden:
75
+ public: str
76
+ secret: str = field('s3cr3t', repr=False)
77
+
78
+ h = _Hidden("visible")
79
+ ae(repr(h), '_Hidden(public="visible")')
80
+ ae(h.secret, 's3cr3t')
81
+
82
+ # ── 6. field() init=False ─────────────────────────────────────────────────────
83
+
84
+ @dataclass
85
+ class _WithPostInit:
86
+ x: int
87
+ y: int
88
+ dist: int = field(init=False, repr=True)
89
+
90
+ def __post_init__(self):
91
+ this.dist = this.x + this.y
92
+
93
+ w = _WithPostInit(3, 4)
94
+ ae(w.x, 3)
95
+ ae(w.y, 4)
96
+ ae(w.dist, 7)
97
+
98
+ # ── 7. fields() returns Field objects ────────────────────────────────────────
99
+
100
+ fs = fields(_Point)
101
+ ae(fs.length, 2)
102
+ ae(fs[0].name, 'x')
103
+ ae(fs[1].name, 'y')
104
+
105
+ # Also works on an instance
106
+ fs2 = fields(p1)
107
+ ae(fs2.length, 2)
108
+ ae(fs2[0].name, 'x')
109
+
110
+ # ── 8. asdict() ───────────────────────────────────────────────────────────────
111
+
112
+ @dataclass
113
+ class _Inner:
114
+ value: int
115
+
116
+ @dataclass
117
+ class _Outer:
118
+ inner: object
119
+ tag: str
120
+
121
+ d_obj = _Outer(_Inner(42), 'hello')
122
+ d_dict = asdict(d_obj)
123
+ ae(d_dict['tag'], 'hello')
124
+ ae(d_dict['inner']['value'], 42)
125
+
126
+ # ── 9. astuple() ──────────────────────────────────────────────────────────────
127
+
128
+ pt = _Point(3, 4)
129
+ t = astuple(pt)
130
+ ae(t[0], 3)
131
+ ae(t[1], 4)
132
+
133
+ # ── 10. replace() ────────────────────────────────────────────────────────────
134
+
135
+ p2 = _Point(1, 2)
136
+ p3 = replace(p2, y=99)
137
+ ae(p3.x, 1)
138
+ ae(p3.y, 99)
139
+ ae(p2.y, 2) # original unchanged
140
+
141
+ # ── 11. is_dataclass() ───────────────────────────────────────────────────────
142
+
143
+ ok(is_dataclass(_Point))
144
+ ok(is_dataclass(p1))
145
+ ok(not is_dataclass(42))
146
+ ok(not is_dataclass('hello'))
147
+ ok(not is_dataclass({}))
148
+ ok(not is_dataclass(None))
149
+
150
+ # ── 12. @dataclass(order=True) ───────────────────────────────────────────────
151
+ # Note: RapydScript's < / > operators do not dispatch to __lt__/__gt__, so
152
+ # order=True is tested by calling the generated comparison methods directly.
153
+
154
+ @dataclass(order=True)
155
+ class _Version:
156
+ major: int
157
+ minor: int
158
+
159
+ v1 = _Version(1, 0)
160
+ v2 = _Version(1, 5)
161
+ v3 = _Version(2, 0)
162
+
163
+ ok(v1.__lt__(v2))
164
+ ok(v2.__lt__(v3))
165
+ ok(v3.__gt__(v1))
166
+ ok(v1.__le__(v1))
167
+ ok(v1.__ge__(v1))
168
+ ok(v2.__ge__(v1))
169
+ ok(not v1.__lt__(v1))
170
+
171
+ # ── 13. @dataclass(frozen=True) ──────────────────────────────────────────────
172
+
173
+ @dataclass(frozen=True)
174
+ class _ImmutablePoint:
175
+ x: int
176
+ y: int
177
+
178
+ ip = _ImmutablePoint(1, 2)
179
+ ae(ip.x, 1)
180
+
181
+ # Assigning to a frozen dataclass field raises an error (TypeError in JS,
182
+ # since writable:false is enforced via Object.defineProperty).
183
+ _frozen_error = None
184
+ try:
185
+ ip.x = 99
186
+ except Exception as e:
187
+ _frozen_error = str(e)
188
+ ok(_frozen_error is not None)
189
+
190
+ # ── 14. Inheritance ───────────────────────────────────────────────────────────
191
+
192
+ @dataclass
193
+ class _Base:
194
+ x: int
195
+ y: int = 0
196
+
197
+ @dataclass
198
+ class _Child(_Base):
199
+ z: str = 'default'
200
+
201
+ ch = _Child(x=1, y=2, z='hi')
202
+ ae(ch.x, 1)
203
+ ae(ch.y, 2)
204
+ ae(ch.z, 'hi')
205
+
206
+ ch2 = _Child(10)
207
+ ae(ch2.x, 10)
208
+ ae(ch2.y, 0)
209
+ ae(ch2.z, 'default')
210
+
211
+ # repr shows all fields including inherited
212
+ # (RapydScript repr() uses double quotes for strings, like JavaScript)
213
+ r = repr(ch2)
214
+ ok('x=10' in r)
215
+ ok('y=0' in r)
216
+ ok('z="default"' in r)
217
+
218
+ # ── 15. MISSING sentinel ──────────────────────────────────────────────────────
219
+
220
+ ae(repr(MISSING), 'MISSING')
221
+
222
+ # ── 16. Multiple independent dataclasses ─────────────────────────────────────
223
+
224
+ @dataclass
225
+ class _A:
226
+ val: int = 1
227
+
228
+ @dataclass
229
+ class _B:
230
+ val: int = 2
231
+
232
+ ok(_A().val is 1)
233
+ ok(_B().val is 2)
234
+
235
+ # ── 17. @dataclass as decorator factory (explicit parens, no args) ────────────
236
+
237
+ @dataclass()
238
+ class _Explicit:
239
+ name: str = 'x'
240
+
241
+ ex = _Explicit()
242
+ ae(ex.name, 'x')
243
+ ae(repr(ex), '_Explicit(name="x")')
244
+
245
+ # ── 18. Nested list field with asdict ────────────────────────────────────────
246
+
247
+ @dataclass
248
+ class _WithList:
249
+ numbers: list = field(default_factory=list)
250
+
251
+ wl = _WithList([1, 2, 3])
252
+ d2 = asdict(wl)
253
+ ade(d2['numbers'], [1, 2, 3])
@@ -1,77 +1,77 @@
1
- # vim:fileencoding=utf-8
2
- # License: BSD Copyright: 2015, Kovid Goyal <kovid at kovidgoyal.net>
3
-
4
- def double(f):
5
- return def (x):
6
- return 2 * f(x)
7
-
8
- def triple(f):
9
- return def(x):
10
- return 3 * f(x)
11
-
12
- @double
13
- def half(x):
14
- return x // 2
15
-
16
- @double
17
- def f1(x):
18
- return x
19
-
20
- @double
21
- @triple
22
- def f2(x):
23
- return x
24
-
25
- def append_one(f):
26
- return def(x):
27
- ans = f(x)
28
- ans.push(1)
29
- return ans
30
-
31
- def append_two(f):
32
- return def(x):
33
- ans = f(x)
34
- ans.push(2)
35
- return ans
36
-
37
- @append_two
38
- @append_one
39
- def f3():
40
- return []
41
-
42
- o = {'double':double}
43
-
44
- @o.double
45
- def f4():
46
- return 1
47
-
48
- assrt.equal(2, half(2))
49
- assrt.equal(4, f1(2))
50
- assrt.equal(12, f2(2))
51
- assrt.equal(2, f4())
52
- assrt.deepEqual([1, 2], f3())
53
-
54
- def multiply(amt):
55
-
56
- def wrapper(f):
57
- return def ():
58
- return amt * f()
59
-
60
- return wrapper
61
-
62
- @multiply(2)
63
- def two():
64
- return 1
65
-
66
- @multiply(3)
67
- def three():
68
- return 1
69
-
70
- @multiply(2)
71
- @multiply(2)
72
- def four():
73
- return 1
74
-
75
- assrt.equal(2, two())
76
- assrt.equal(3, three())
77
- assrt.equal(4, four())
1
+ # vim:fileencoding=utf-8
2
+ # License: BSD Copyright: 2015, Kovid Goyal <kovid at kovidgoyal.net>
3
+
4
+ def double(f):
5
+ return def (x):
6
+ return 2 * f(x)
7
+
8
+ def triple(f):
9
+ return def(x):
10
+ return 3 * f(x)
11
+
12
+ @double
13
+ def half(x):
14
+ return x // 2
15
+
16
+ @double
17
+ def f1(x):
18
+ return x
19
+
20
+ @double
21
+ @triple
22
+ def f2(x):
23
+ return x
24
+
25
+ def append_one(f):
26
+ return def(x):
27
+ ans = f(x)
28
+ ans.push(1)
29
+ return ans
30
+
31
+ def append_two(f):
32
+ return def(x):
33
+ ans = f(x)
34
+ ans.push(2)
35
+ return ans
36
+
37
+ @append_two
38
+ @append_one
39
+ def f3():
40
+ return []
41
+
42
+ o = {'double':double}
43
+
44
+ @o.double
45
+ def f4():
46
+ return 1
47
+
48
+ assrt.equal(2, half(2))
49
+ assrt.equal(4, f1(2))
50
+ assrt.equal(12, f2(2))
51
+ assrt.equal(2, f4())
52
+ assrt.deepEqual([1, 2], f3())
53
+
54
+ def multiply(amt):
55
+
56
+ def wrapper(f):
57
+ return def ():
58
+ return amt * f()
59
+
60
+ return wrapper
61
+
62
+ @multiply(2)
63
+ def two():
64
+ return 1
65
+
66
+ @multiply(3)
67
+ def three():
68
+ return 1
69
+
70
+ @multiply(2)
71
+ @multiply(2)
72
+ def four():
73
+ return 1
74
+
75
+ assrt.equal(2, two())
76
+ assrt.equal(3, three())
77
+ assrt.equal(4, four())
@@ -1,39 +1,39 @@
1
- # vim:fileencoding=utf-8
2
- # License: BSD Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
3
- # globals: ρσ_module_doc__
4
-
5
- import _import_one
6
-
7
- def f():
8
- " A basic docstring "
9
- pass
10
-
11
- assrt.equal(f.__doc__, 'A basic docstring')
12
- assrt.equal(_import_one.__doc__, 'Module level ds1\n\nModule level ds2\nline2\n\nModule level ds 3')
13
-
14
- def g():
15
- '''
16
- A more complex docstring:
17
- xxx
18
- yyyy
19
-
20
- the end
21
- '''
22
- pass
23
-
24
- assrt.equal(g.__doc__, 'A more complex docstring:\n xxx\n yyyy\n\nthe end')
25
-
26
- class D:
27
- ' Docstring for a class '
28
-
29
- def method(self):
30
- 'ds for a method'
31
- pass
32
-
33
- assrt.equal(D().__doc__, 'Docstring for a class')
34
- assrt.equal(D().method.__doc__, 'ds for a method')
35
-
36
- x = def():
37
- 'xxx'
38
-
39
- assrt.equal(x.__doc__, 'xxx')
1
+ # vim:fileencoding=utf-8
2
+ # License: BSD Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
3
+ # globals: ρσ_module_doc__
4
+
5
+ import _import_one
6
+
7
+ def f():
8
+ " A basic docstring "
9
+ pass
10
+
11
+ assrt.equal(f.__doc__, 'A basic docstring')
12
+ assrt.equal(_import_one.__doc__, 'Module level ds1\n\nModule level ds2\nline2\n\nModule level ds 3')
13
+
14
+ def g():
15
+ '''
16
+ A more complex docstring:
17
+ xxx
18
+ yyyy
19
+
20
+ the end
21
+ '''
22
+ pass
23
+
24
+ assrt.equal(g.__doc__, 'A more complex docstring:\n xxx\n yyyy\n\nthe end')
25
+
26
+ class D:
27
+ ' Docstring for a class '
28
+
29
+ def method(self):
30
+ 'ds for a method'
31
+ pass
32
+
33
+ assrt.equal(D().__doc__, 'Docstring for a class')
34
+ assrt.equal(D().method.__doc__, 'ds for a method')
35
+
36
+ x = def():
37
+ 'xxx'
38
+
39
+ assrt.equal(x.__doc__, 'xxx')
@@ -1,45 +1,45 @@
1
- # vim:fileencoding=utf-8
2
- # License: BSD Copyright: 2015, Kovid Goyal <kovid at kovidgoyal.net>
3
- # globals: assrt
4
-
5
- from elementmaker import E
6
-
7
- eq = assrt.equal
8
-
9
- def dummy_elem_eq(a, b):
10
- eq(jstype(a), jstype(b))
11
- if (jstype(a) == 'string'):
12
- eq(a, b)
13
- return
14
- eq(a.attributes.length, b.attributes.length)
15
- eq(a.children.length, b.children.length)
16
- eq(a.name, b.name)
17
- for attr in a.attributes:
18
- eq(a[attr], b[attr])
19
- for i, child in enumerate(a.children):
20
- dummy_elem_eq(child, b.children[i])
21
-
22
- q = E.div('text', id='1', class_='c', data_x='x')
23
- dummy_elem_eq(q, {'name':'div', 'children':['text'], 'attributes':{'id':'1', 'class':'c', 'data-x': 'x'}})
24
-
25
- q = E.div(
26
- E.span('a'),
27
- E.span('b'),
28
- E.a(),
29
- id='1',
30
- boolean_attr=True,
31
- )
32
- dummy_elem_eq(q, {'name':'div', 'children':[
33
- {
34
- 'name':'span',
35
- 'children':['a'], 'attributes': {}
36
- },
37
- {
38
- 'name':'span',
39
- 'children':['b'], 'attributes': {}
40
- },
41
- {
42
- 'name':'a',
43
- 'children':[], 'attributes': {}
44
- },
45
- ], 'attributes':{'id':'1', 'boolean-attr':'boolean-attr'}})
1
+ # vim:fileencoding=utf-8
2
+ # License: BSD Copyright: 2015, Kovid Goyal <kovid at kovidgoyal.net>
3
+ # globals: assrt
4
+
5
+ from elementmaker import E
6
+
7
+ eq = assrt.equal
8
+
9
+ def dummy_elem_eq(a, b):
10
+ eq(jstype(a), jstype(b))
11
+ if (jstype(a) == 'string'):
12
+ eq(a, b)
13
+ return
14
+ eq(a.attributes.length, b.attributes.length)
15
+ eq(a.children.length, b.children.length)
16
+ eq(a.name, b.name)
17
+ for attr in a.attributes:
18
+ eq(a[attr], b[attr])
19
+ for i, child in enumerate(a.children):
20
+ dummy_elem_eq(child, b.children[i])
21
+
22
+ q = E.div('text', id='1', class_='c', data_x='x')
23
+ dummy_elem_eq(q, {'name':'div', 'children':['text'], 'attributes':{'id':'1', 'class':'c', 'data-x': 'x'}})
24
+
25
+ q = E.div(
26
+ E.span('a'),
27
+ E.span('b'),
28
+ E.a(),
29
+ id='1',
30
+ boolean_attr=True,
31
+ )
32
+ dummy_elem_eq(q, {'name':'div', 'children':[
33
+ {
34
+ 'name':'span',
35
+ 'children':['a'], 'attributes': {}
36
+ },
37
+ {
38
+ 'name':'span',
39
+ 'children':['b'], 'attributes': {}
40
+ },
41
+ {
42
+ 'name':'a',
43
+ 'children':[], 'attributes': {}
44
+ },
45
+ ], 'attributes':{'id':'1', 'boolean-attr':'boolean-attr'}})