@jackens/nnn 2024.2.27 → 2024.3.2

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 (4) hide show
  1. package/nnn.d.ts +25 -25
  2. package/nnn.js +61 -61
  3. package/package.json +1 -1
  4. package/readme.md +240 -219
package/nnn.d.ts CHANGED
@@ -1,3 +1,28 @@
1
+ /**
2
+ * The type of arguments of the `c` helper.
3
+ */
4
+ export type CNode = {
5
+ [attributeOrSelector: string]: string | number | CNode | undefined;
6
+ };
7
+
8
+ /**
9
+ * The type of arguments of the `c` helper.
10
+ */
11
+ export type CRoot = Partial<Record<PropertyKey, CNode>>;
12
+
13
+ /**
14
+ * A simple CSS-in-JS helper.
15
+ *
16
+ * The `root` parameter provides a hierarchical description of CSS rules.
17
+ *
18
+ * - Keys of sub-objects whose values are NOT objects are treated as CSS attribute, and values are treated as values of those CSS attributes; the concatenation of keys of all parent objects is a CSS rule.
19
+ * - All keys ignore the part starting with a splitter (default: `$$`) sign until the end of the key (e.g. `src$$1` → `src`, `@font-face$$1` → `@font-face`).
20
+ * - In keys specifying CSS attribute, all uppercase letters are replaced by lowercase letters with an additional `-` character preceding them (e.g. `fontFamily` → `font-family`).
21
+ * - Commas in keys that makes a CSS rule cause it to “split” and create separate rules for each part (e.g. `{div:{margin:1,'.a,.b,.c':{margin:2}}}` → `div{margin:1}div.a,div.b,div.c{margin:2}`).
22
+ * - Top-level keys that begin with `@` are not concatenated with sub-object keys.
23
+ */
24
+ export declare const c: (root: CRoot, splitter?: string) => string;
25
+
1
26
  /**
2
27
  * A helper for creating a chart based on a table (conf. <https://jackens.github.io/nnn/chartable/>).
3
28
  *
@@ -126,31 +151,6 @@ export declare const is: {
126
151
  <T extends abstract new (...args: any[]) => any>(type: T, arg: any): arg is InstanceType<T>;
127
152
  };
128
153
 
129
- /**
130
- * The type of arguments of the `jcss` helper.
131
- */
132
- export type JcssNode = {
133
- [attributeOrSelector: string]: string | number | JcssNode | undefined;
134
- };
135
-
136
- /**
137
- * The type of arguments of the `jcss` helper.
138
- */
139
- export type JcssRoot = Partial<Record<PropertyKey, JcssNode>>;
140
-
141
- /**
142
- * A simple CSS-in-JS helper.
143
- *
144
- * The `root` parameter provides a hierarchical description of CSS rules.
145
- *
146
- * - Keys of sub-objects whose values are NOT objects are treated as CSS attribute, and values are treated as values of those CSS attributes; the concatenation of keys of all parent objects is a CSS rule.
147
- * - All keys ignore the part starting with a splitter (default: `$$`) sign until the end of the key (e.g. `src$$1` → `src`, `@font-face$$1` → `@font-face`).
148
- * - In keys specifying CSS attribute, all uppercase letters are replaced by lowercase letters with an additional `-` character preceding them (e.g. `fontFamily` → `font-family`).
149
- * - Commas in keys that makes a CSS rule cause it to “split” and create separate rules for each part (e.g. `{div:{margin:1,'.a,.b,.c':{margin:2}}}` → `div{margin:1}div.a,div.b,div.c{margin:2}`).
150
- * - Top-level keys that begin with `@` are not concatenated with sub-object keys.
151
- */
152
- export declare const jcss: (root: JcssRoot, splitter?: string) => string;
153
-
154
154
  /**
155
155
  * `JSON.parse` with “JavaScript turned on”.
156
156
  *
package/nnn.js CHANGED
@@ -1,6 +1,59 @@
1
1
  // src/nnn/is.ts
2
2
  var is = (type, arg) => arg?.constructor === type;
3
3
 
4
+ // src/nnn/c.ts
5
+ var _c = (node, prefix, result, split) => {
6
+ const queue = [[node, prefix]];
7
+ while (queue.length > 0) {
8
+ const [style0, prefix0] = queue.shift() ?? [];
9
+ if (style0 == null || prefix0 == null) {
10
+ continue;
11
+ }
12
+ if (is(Array, style0)) {
13
+ result.push(prefix0, prefix0 !== "" ? "{" : "", style0.join(";"), prefix0 !== "" ? "}" : "");
14
+ } else {
15
+ const todo = [];
16
+ let attributes = [];
17
+ let attributesPushed = false;
18
+ for (const key in style0) {
19
+ const value = style0[key];
20
+ if (is(String, value) || is(Number, value)) {
21
+ if (!attributesPushed) {
22
+ attributesPushed = true;
23
+ attributes = [];
24
+ todo.push([attributes, prefix0]);
25
+ }
26
+ attributes.push(`${split(key).replace(/([A-Z])/g, (_, letter) => "-" + letter.toLowerCase())}:${value}`);
27
+ } else if (value != null) {
28
+ attributesPushed = false;
29
+ const prefixN = [];
30
+ const keyChunks = key.split(",");
31
+ prefix0.split(",").forEach((prefixChunk) => keyChunks.forEach((keyChunk) => prefixN.push(prefixChunk + keyChunk)));
32
+ todo.push([value, prefixN.join(",")]);
33
+ }
34
+ }
35
+ queue.unshift(...todo);
36
+ }
37
+ }
38
+ };
39
+ var c = (root, splitter = "$$") => {
40
+ const split = (text) => text.split(splitter)[0];
41
+ const chunks = [];
42
+ for (const key in root) {
43
+ const value = root[key];
44
+ if (value != null) {
45
+ if (key[0] === "@") {
46
+ chunks.push(split(key) + "{");
47
+ _c(value, "", chunks, split);
48
+ chunks.push("}");
49
+ } else {
50
+ _c(value, split(key), chunks, split);
51
+ }
52
+ }
53
+ }
54
+ return chunks.join("");
55
+ };
56
+
4
57
  // src/nnn/h.ts
5
58
  var NS = {
6
59
  xlink: "http://www.w3.org/1999/xlink"
@@ -88,9 +141,9 @@ var chartable = ({
88
141
  const zxValues = [];
89
142
  const xLabels = [];
90
143
  const zLabels = [];
91
- table.querySelectorAll("tr").forEach((row, r) => row.querySelectorAll("td,th").forEach((col, c) => {
144
+ table.querySelectorAll("tr").forEach((row, r) => row.querySelectorAll("td,th").forEach((col, c2) => {
92
145
  const x = r - 1;
93
- const z = c - +headerColumn;
146
+ const z = c2 - +headerColumn;
94
147
  const value = col.innerText;
95
148
  if (x >= 0 && z >= 0) {
96
149
  zxValues[z] = zxValues[z] ?? [];
@@ -215,11 +268,8 @@ var eq = (x, y) => {
215
268
  var escapeValues = (escapeMap, values) => values.map((value) => (escapeMap.get(value?.constructor) ?? escapeMap.get(undefined))?.(value) ?? "");
216
269
  var escape = (escapeMap, template, ...values) => String.raw(template, ...escapeValues(escapeMap, values));
217
270
 
218
- // src/nnn/has.ts
219
- var has = (key, ref) => (is(String, key) || is(Number, key) || is(Symbol, key)) && Object.hasOwnProperty.call(ref ?? Object, key);
220
-
221
271
  // src/nnn/fixTypography.ts
222
- var TAGS_TO_SKIP = { IFRAME: 1, NOSCRIPT: 1, PRE: 1, SCRIPT: 1, STYLE: 1, TEXTAREA: 1 };
272
+ var TAGS_TO_SKIP = ["IFRAME", "NOSCRIPT", "PRE", "SCRIPT", "STYLE", "TEXTAREA"];
223
273
  var fixTypography = (node) => {
224
274
  const queue = [node];
225
275
  while (queue.length > 0) {
@@ -228,7 +278,7 @@ var fixTypography = (node) => {
228
278
  node0.childNodes.forEach((childNode) => {
229
279
  if (childNode instanceof Text) {
230
280
  queue.push(childNode);
231
- } else if (childNode instanceof Element && !has(childNode.tagName, TAGS_TO_SKIP)) {
281
+ } else if (childNode instanceof Element && !TAGS_TO_SKIP.includes(childNode.tagName)) {
232
282
  queue.push(childNode);
233
283
  }
234
284
  });
@@ -250,58 +300,8 @@ var fixTypography = (node) => {
250
300
  }
251
301
  };
252
302
 
253
- // src/nnn/jcss.ts
254
- var _jcss = (node, prefix, result, split) => {
255
- const queue = [[node, prefix]];
256
- while (queue.length > 0) {
257
- const [style0, prefix0] = queue.shift() ?? [];
258
- if (style0 == null || prefix0 == null) {
259
- continue;
260
- }
261
- if (is(Array, style0)) {
262
- result.push(prefix0, prefix0 !== "" ? "{" : "", style0.join(";"), prefix0 !== "" ? "}" : "");
263
- } else {
264
- const todo = [];
265
- let attributes = [];
266
- let attributesPushed = false;
267
- for (const key in style0) {
268
- const value = style0[key];
269
- if (is(String, value) || is(Number, value)) {
270
- if (!attributesPushed) {
271
- attributesPushed = true;
272
- attributes = [];
273
- todo.push([attributes, prefix0]);
274
- }
275
- attributes.push(`${split(key).replace(/([A-Z])/g, (_, letter) => "-" + letter.toLowerCase())}:${value}`);
276
- } else if (value != null) {
277
- attributesPushed = false;
278
- const prefixN = [];
279
- const keyChunks = key.split(",");
280
- prefix0.split(",").forEach((prefixChunk) => keyChunks.forEach((keyChunk) => prefixN.push(prefixChunk + keyChunk)));
281
- todo.push([value, prefixN.join(",")]);
282
- }
283
- }
284
- queue.unshift(...todo);
285
- }
286
- }
287
- };
288
- var jcss = (root, splitter = "$$") => {
289
- const split = (text) => text.split(splitter)[0];
290
- const chunks = [];
291
- for (const key in root) {
292
- const value = root[key];
293
- if (value != null) {
294
- if (key[0] === "@") {
295
- chunks.push(split(key) + "{");
296
- _jcss(value, "", chunks, split);
297
- chunks.push("}");
298
- } else {
299
- _jcss(value, split(key), chunks, split);
300
- }
301
- }
302
- }
303
- return chunks.join("");
304
- };
303
+ // src/nnn/has.ts
304
+ var has = (key, ref) => (is(String, key) || is(Number, key) || is(Symbol, key)) && Object.hasOwnProperty.call(ref ?? Object, key);
305
305
 
306
306
  // src/nnn/jsOnParse.ts
307
307
  var jsOnParse = (handlers, text) => JSON.parse(text, (key, value) => {
@@ -408,7 +408,6 @@ export {
408
408
  nanolight,
409
409
  locale,
410
410
  jsOnParse,
411
- jcss,
412
411
  is,
413
412
  has,
414
413
  h,
@@ -416,5 +415,6 @@ export {
416
415
  escapeValues,
417
416
  escape,
418
417
  eq,
419
- chartable
418
+ chartable,
419
+ c
420
420
  };
package/package.json CHANGED
@@ -42,5 +42,5 @@
42
42
  "types": "nnn.d.ts",
43
43
  "name": "@jackens/nnn",
44
44
  "type": "module",
45
- "version": "2024.2.27"
45
+ "version": "2024.3.2"
46
46
  }
package/readme.md CHANGED
@@ -2,7 +2,15 @@
2
2
 
3
3
  Jackens’ JavaScript helpers.
4
4
 
5
- <sub>Version: <code class="version">2024.2.27</code></sub>
5
+ <sub>Version: <code class="version">2024.3.2</code></sub>
6
+
7
+ ## Examples
8
+
9
+ - [Chartable Demo](/nnn/chartable/)
10
+ - [Chessboard Demo](/nnn/chessboard/)
11
+ - [Documentation](/nnn/doc/)
12
+ - [Gant Chart Demo](/nnn/gantt/)
13
+ - [Responsive Web Design Demo](/nnn/rwd/)
6
14
 
7
15
  ## Installation
8
16
 
@@ -32,11 +40,12 @@ import { «something» } from './node_modules/@jackens/nnn/nnn.js'
32
40
 
33
41
  ## Exports
34
42
 
43
+ - `CNode`: The type of arguments of the `c` helper.
44
+ - `CRoot`: The type of arguments of the `c` helper.
35
45
  - `EscapeMap`: The type of arguments of the `escapeValues` and `escape` helpers.
36
46
  - `HArgs`: The type of arguments of the `h` and `s` helpers.
37
47
  - `HArgs1`: The type of arguments of the `h` and `s` helpers.
38
- - `JcssNode`: The type of arguments of the `jcss` helper.
39
- - `JcssRoot`: The type of arguments of the `jcss` helper.
48
+ - `c`: A simple CSS-in-JS helper.
40
49
  - `chartable`: A helper for creating a chart based on a table (conf. <https://jackens.github.io/nnn/chartable/>).
41
50
  - `eq`: A helper that checks equality of the given arguments.
42
51
  - `escape`: A generic helper for escaping `values` by given `escapeMap` (in *TemplateStrings* flavor).
@@ -45,7 +54,6 @@ import { «something» } from './node_modules/@jackens/nnn/nnn.js'
45
54
  - `h`: A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `HTMLElement`s (see also `s`).
46
55
  - `has`: A replacement for the `in` operator (not to be confused with the `for-in` loop) that works properly.
47
56
  - `is`: A helper that checks if the given argument is of a certain type.
48
- - `jcss`: A simple CSS-in-JS helper.
49
57
  - `jsOnParse`: `JSON.parse` with “JavaScript turned on”.
50
58
  - `locale`: Language translations helper.
51
59
  - `nanolight`: A generic helper for syntax highlighting (see also `nanolightJs`).
@@ -58,6 +66,24 @@ import { «something» } from './node_modules/@jackens/nnn/nnn.js'
58
66
  - `s`: A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `SVGElement`s (see also `h`).
59
67
  - `uuid1`: A helper that generates a UUID v1 identifier (with a creation timestamp).
60
68
 
69
+ ### CNode
70
+
71
+ ```ts
72
+ type CNode = {
73
+ [attributeOrSelector: string]: string | number | CNode | undefined;
74
+ };
75
+ ```
76
+
77
+ The type of arguments of the `c` helper.
78
+
79
+ ### CRoot
80
+
81
+ ```ts
82
+ type CRoot = Partial<Record<PropertyKey, CNode>>;
83
+ ```
84
+
85
+ The type of arguments of the `c` helper.
86
+
61
87
  ### EscapeMap
62
88
 
63
89
  ```ts
@@ -82,23 +108,217 @@ type HArgs1 = Partial<Record<PropertyKey, any>> | null | undefined | Node | stri
82
108
 
83
109
  The type of arguments of the `h` and `s` helpers.
84
110
 
85
- ### JcssNode
111
+ ### c
86
112
 
87
113
  ```ts
88
- type JcssNode = {
89
- [attributeOrSelector: string]: string | number | JcssNode | undefined;
90
- };
114
+ const c: (root: CRoot, splitter?: string) => string;
91
115
  ```
92
116
 
93
- The type of arguments of the `jcss` helper.
117
+ A simple CSS-in-JS helper.
94
118
 
95
- ### JcssRoot
119
+ The `root` parameter provides a hierarchical description of CSS rules.
96
120
 
97
- ```ts
98
- type JcssRoot = Partial<Record<PropertyKey, JcssNode>>;
121
+ - Keys of sub-objects whose values are NOT objects are treated as CSS attribute, and values are treated as values of those CSS attributes; the concatenation of keys of all parent objects is a CSS rule.
122
+ - All keys ignore the part starting with a splitter (default: `$$`) sign until the end of the key (e.g. `src$$1` → `src`, `@font-face$$1` → `@font-face`).
123
+ - In keys specifying CSS attribute, all uppercase letters are replaced by lowercase letters with an additional `-` character preceding them (e.g. `fontFamily` → `font-family`).
124
+ - Commas in keys that makes a CSS rule cause it to “split” and create separate rules for each part (e.g. `{div:{margin:1,'.a,.b,.c':{margin:2}}}` → `div{margin:1}div.a,div.b,div.c{margin:2}`).
125
+ - Top-level keys that begin with `@` are not concatenated with sub-object keys.
126
+
127
+ #### Usage Examples
128
+
129
+ ```js
130
+ const actual = c({
131
+ a: {
132
+ color: 'red',
133
+ margin: 1,
134
+ '.c': { margin: 2, padding: 2 },
135
+ padding: 1
136
+ }
137
+ })
138
+
139
+ const expected = `
140
+ a{
141
+ color:red;
142
+ margin:1
143
+ }
144
+ a.c{
145
+ margin:2;
146
+ padding:2
147
+ }
148
+ a{
149
+ padding:1
150
+ }`.replace(/\n\s*/g, '')
151
+
152
+ expect(actual).toStrictEqual(expected)
99
153
  ```
100
154
 
101
- The type of arguments of the `jcss` helper.
155
+ ```js
156
+ const actual = c({
157
+ a: {
158
+ '.b': {
159
+ color: 'red',
160
+ margin: 1,
161
+ '.c': { margin: 2, padding: 2 },
162
+ padding: 1
163
+ }
164
+ }
165
+ })
166
+
167
+ const expected = `
168
+ a.b{
169
+ color:red;
170
+ margin:1
171
+ }
172
+ a.b.c{
173
+ margin:2;
174
+ padding:2
175
+ }
176
+ a.b{
177
+ padding:1
178
+ }`.replace(/\n\s*/g, '')
179
+
180
+ expect(actual).toStrictEqual(expected)
181
+ ```
182
+
183
+ ```js
184
+ const actual = c({
185
+ '@font-face$$1': {
186
+ fontFamily: 'Jackens',
187
+ src$$1: 'url(otf/jackens.otf)',
188
+ src$$2: "url(otf/jackens.otf) format('opentype')," +
189
+ "url(svg/jackens.svg) format('svg')",
190
+ fontWeight: 'normal',
191
+ fontStyle: 'normal'
192
+ },
193
+ '@font-face$$2': {
194
+ fontFamily: 'C64',
195
+ src: 'url(fonts/C64_Pro_Mono-STYLE.woff)'
196
+ },
197
+ '@keyframes spin': {
198
+ '0%': { transform: 'rotate(0deg)' },
199
+ '100%': { transform: 'rotate(360deg)' }
200
+ },
201
+ div: {
202
+ border: 'solid red 1px',
203
+ '.c1': { 'background-color': '#000' },
204
+ ' .c1': { backgroundColor: 'black' },
205
+ '.c2': { backgroundColor: 'rgb(0,0,0)' }
206
+ },
207
+ '@media(min-width:200px)': {
208
+ div: { margin: 0, padding: 0 },
209
+ span: { color: '#000' }
210
+ }
211
+ })
212
+
213
+ const expected = `
214
+ @font-face{
215
+ font-family:Jackens;
216
+ src:url(otf/jackens.otf);
217
+ src:url(otf/jackens.otf) format('opentype'),url(svg/jackens.svg) format('svg');
218
+ font-weight:normal;
219
+ font-style:normal
220
+ }
221
+ @font-face{
222
+ font-family:C64;
223
+ src:url(fonts/C64_Pro_Mono-STYLE.woff)
224
+ }
225
+ @keyframes spin{
226
+ 0%{
227
+ transform:rotate(0deg)
228
+ }
229
+ 100%{
230
+ transform:rotate(360deg)
231
+ }
232
+ }
233
+ div{
234
+ border:solid red 1px
235
+ }
236
+ div.c1{
237
+ background-color:#000
238
+ }
239
+ div .c1{
240
+ background-color:black
241
+ }
242
+ div.c2{
243
+ background-color:rgb(0,0,0)
244
+ }
245
+ @media(min-width:200px){
246
+ div{
247
+ margin:0;
248
+ padding:0
249
+ }
250
+ span{
251
+ color:#000
252
+ }
253
+ }`.replace(/\n\s*/g, '')
254
+
255
+ expect(actual).toStrictEqual(expected)
256
+ ```
257
+
258
+ ```js
259
+ const actual = c({
260
+ a: {
261
+ '.b,.c': {
262
+ margin: 1,
263
+ '.d': {
264
+ margin: 2
265
+ }
266
+ }
267
+ }
268
+ })
269
+
270
+ const expected = `
271
+ a.b,a.c{
272
+ margin:1
273
+ }
274
+ a.b.d,a.c.d{
275
+ margin:2
276
+ }`.replace(/\n\s*/g, '')
277
+
278
+ expect(actual).toStrictEqual(expected)
279
+ ```
280
+
281
+ ```js
282
+ const actual = c({
283
+ '.b,.c': {
284
+ margin: 1,
285
+ '.d': {
286
+ margin: 2
287
+ }
288
+ }
289
+ })
290
+
291
+ const expected = `
292
+ .b,.c{
293
+ margin:1
294
+ }
295
+ .b.d,.c.d{
296
+ margin:2
297
+ }`.replace(/\n\s*/g, '')
298
+
299
+ expect(actual).toStrictEqual(expected)
300
+ ```
301
+
302
+ ```js
303
+ const actual = c({
304
+ '.a,.b': {
305
+ margin: 1,
306
+ '.c,.d': {
307
+ margin: 2
308
+ }
309
+ }
310
+ })
311
+
312
+ const expected = `
313
+ .a,.b{
314
+ margin:1
315
+ }
316
+ .a.c,.a.d,.b.c,.b.d{
317
+ margin:2
318
+ }`.replace(/\n\s*/g, '')
319
+
320
+ expect(actual).toStrictEqual(expected)
321
+ ```
102
322
 
103
323
  ### chartable
104
324
 
@@ -432,216 +652,17 @@ expect(is(Object, fakeFooBar)).toBeTrue()
432
652
  expect(iz(Object, fakeFooBar)).toBeFalse()
433
653
  ```
434
654
 
435
- ### jcss
436
-
437
- ```ts
438
- const jcss: (root: JcssRoot, splitter?: string) => string;
439
- ```
440
-
441
- A simple CSS-in-JS helper.
442
-
443
- The `root` parameter provides a hierarchical description of CSS rules.
444
-
445
- - Keys of sub-objects whose values are NOT objects are treated as CSS attribute, and values are treated as values of those CSS attributes; the concatenation of keys of all parent objects is a CSS rule.
446
- - All keys ignore the part starting with a splitter (default: `$$`) sign until the end of the key (e.g. `src$$1` → `src`, `@font-face$$1` → `@font-face`).
447
- - In keys specifying CSS attribute, all uppercase letters are replaced by lowercase letters with an additional `-` character preceding them (e.g. `fontFamily` → `font-family`).
448
- - Commas in keys that makes a CSS rule cause it to “split” and create separate rules for each part (e.g. `{div:{margin:1,'.a,.b,.c':{margin:2}}}` → `div{margin:1}div.a,div.b,div.c{margin:2}`).
449
- - Top-level keys that begin with `@` are not concatenated with sub-object keys.
450
-
451
- #### Usage Examples
452
-
453
- ```js
454
- const actual = jcss({
455
- a: {
456
- color: 'red',
457
- margin: 1,
458
- '.c': { margin: 2, padding: 2 },
459
- padding: 1
460
- }
461
- })
462
-
463
- const expected = `
464
- a{
465
- color:red;
466
- margin:1
467
- }
468
- a.c{
469
- margin:2;
470
- padding:2
471
- }
472
- a{
473
- padding:1
474
- }`.replace(/\n\s*/g, '')
475
-
476
- expect(actual).toStrictEqual(expected)
477
- ```
478
-
479
- ```js
480
- const actual = jcss({
481
- a: {
482
- '.b': {
483
- color: 'red',
484
- margin: 1,
485
- '.c': { margin: 2, padding: 2 },
486
- padding: 1
487
- }
488
- }
489
- })
490
-
491
- const expected = `
492
- a.b{
493
- color:red;
494
- margin:1
495
- }
496
- a.b.c{
497
- margin:2;
498
- padding:2
499
- }
500
- a.b{
501
- padding:1
502
- }`.replace(/\n\s*/g, '')
503
-
504
- expect(actual).toStrictEqual(expected)
505
- ```
506
-
507
- ```js
508
- const actual = jcss({
509
- '@font-face$$1': {
510
- fontFamily: 'Jackens',
511
- src$$1: 'url(otf/jackens.otf)',
512
- src$$2: "url(otf/jackens.otf) format('opentype')," +
513
- "url(svg/jackens.svg) format('svg')",
514
- fontWeight: 'normal',
515
- fontStyle: 'normal'
516
- },
517
- '@font-face$$2': {
518
- fontFamily: 'C64',
519
- src: 'url(fonts/C64_Pro_Mono-STYLE.woff)'
520
- },
521
- '@keyframes spin': {
522
- '0%': { transform: 'rotate(0deg)' },
523
- '100%': { transform: 'rotate(360deg)' }
524
- },
525
- div: {
526
- border: 'solid red 1px',
527
- '.c1': { 'background-color': '#000' },
528
- ' .c1': { backgroundColor: 'black' },
529
- '.c2': { backgroundColor: 'rgb(0,0,0)' }
530
- },
531
- '@media(min-width:200px)': {
532
- div: { margin: 0, padding: 0 },
533
- span: { color: '#000' }
534
- }
535
- })
536
-
537
- const expected = `
538
- @font-face{
539
- font-family:Jackens;
540
- src:url(otf/jackens.otf);
541
- src:url(otf/jackens.otf) format('opentype'),url(svg/jackens.svg) format('svg');
542
- font-weight:normal;
543
- font-style:normal
544
- }
545
- @font-face{
546
- font-family:C64;
547
- src:url(fonts/C64_Pro_Mono-STYLE.woff)
548
- }
549
- @keyframes spin{
550
- 0%{
551
- transform:rotate(0deg)
552
- }
553
- 100%{
554
- transform:rotate(360deg)
555
- }
556
- }
557
- div{
558
- border:solid red 1px
559
- }
560
- div.c1{
561
- background-color:#000
562
- }
563
- div .c1{
564
- background-color:black
565
- }
566
- div.c2{
567
- background-color:rgb(0,0,0)
568
- }
569
- @media(min-width:200px){
570
- div{
571
- margin:0;
572
- padding:0
573
- }
574
- span{
575
- color:#000
576
- }
577
- }`.replace(/\n\s*/g, '')
578
-
579
- expect(actual).toStrictEqual(expected)
580
- ```
581
-
582
- ```js
583
- const actual = jcss({
584
- a: {
585
- '.b,.c': {
586
- margin: 1,
587
- '.d': {
588
- margin: 2
589
- }
590
- }
591
- }
592
- })
593
-
594
- const expected = `
595
- a.b,a.c{
596
- margin:1
597
- }
598
- a.b.d,a.c.d{
599
- margin:2
600
- }`.replace(/\n\s*/g, '')
601
-
602
- expect(actual).toStrictEqual(expected)
603
- ```
604
-
605
655
  ```js
606
- const actual = jcss({
607
- '.b,.c': {
608
- margin: 1,
609
- '.d': {
610
- margin: 2
611
- }
612
- }
613
- })
656
+ const num = 42
657
+ const str = '42'
614
658
 
615
- const expected = `
616
- .b,.c{
617
- margin:1
618
- }
619
- .b.d,.c.d{
620
- margin:2
621
- }`.replace(/\n\s*/g, '')
622
-
623
- expect(actual).toStrictEqual(expected)
624
- ```
659
+ expect(is(Number, num)).toBeTrue()
625
660
 
626
- ```js
627
- const actual = jcss({
628
- '.a,.b': {
629
- margin: 1,
630
- '.c,.d': {
631
- margin: 2
632
- }
633
- }
634
- })
635
-
636
- const expected = `
637
- .a,.b{
638
- margin:1
639
- }
640
- .a.c,.a.d,.b.c,.b.d{
641
- margin:2
642
- }`.replace(/\n\s*/g, '')
661
+ try {
662
+ num.constructor = str.constructor
663
+ } catch { /* empty */ }
643
664
 
644
- expect(actual).toStrictEqual(expected)
665
+ expect(is(Number, num)).toBeTrue()
645
666
  ```
646
667
 
647
668
  ### jsOnParse