@jackens/nnn 2024.7.13 → 2024.7.18

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 +30 -38
  2. package/nnn.js +58 -58
  3. package/package.json +2 -2
  4. package/readme.md +232 -240
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 JS-to-CSS (aka 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 tiny helper for CSV parsing.
3
28
  *
@@ -45,11 +70,7 @@ export type HArgs = [string | Node, ...HArgs1[]];
45
70
  *
46
71
  * - The first argument of type `string` specifies the tag of the element to be created.
47
72
  * - The first argument of type `Node` specifies the element to be modified.
48
- * - All other arguments of type `Partial<Record<PropertyKey, unknown>>` are mappings of attributes and properties.
49
- * Keys starting with `$` specify *properties* (without the leading `$`) to be set on the element being created or modified.
50
- * (Note that `$` is not a valid attribute name character.)
51
- * All other keys specify *attributes* to be set by `setAttribute`.
52
- * An attribute equal to `false` causes the attribute to be removed by `removeAttribute`.
73
+ * - All other arguments of type `Partial<Record<PropertyKey, unknown>>` are mappings of attributes and properties. Keys starting with `$` specify *properties* (without the leading `$`) to be set on the element being created or modified. (Note that `$` is not a valid attribute name character.) All other keys specify *attributes* to be set by `setAttribute`. An attribute equal to `false` causes the attribute to be removed by `removeAttribute`.
53
74
  * - All other arguments of type `null` or `undefined` are simply ignored.
54
75
  * - All other arguments of type `Node` are appended to the element being created or modified.
55
76
  * - All other arguments of type `string`/`number` are converted to `Text` nodes and appended to the element being created or modified.
@@ -66,11 +87,7 @@ export declare const h: {
66
87
  *
67
88
  * - The first argument of type `string` specifies the tag of the element to be created.
68
89
  * - The first argument of type `Node` specifies the element to be modified.
69
- * - All other arguments of type `Partial<Record<PropertyKey, unknown>>` are mappings of attributes and properties.
70
- * Keys starting with `$` specify *properties* (without the leading `$`) to be set on the element being created or modified.
71
- * (Note that `$` is not a valid attribute name character.)
72
- * All other keys specify *attributes* to be set by `setAttributeNS`.
73
- * An attribute equal to `false` causes the attribute to be removed by `removeAttributeNS`.
90
+ * - All other arguments of type `Partial<Record<PropertyKey, unknown>>` are mappings of attributes and properties. Keys starting with `$` specify *properties* (without the leading `$`) to be set on the element being created or modified. (Note that `$` is not a valid attribute name character.) All other keys specify *attributes* to be set by `setAttributeNS`. An attribute equal to `false` causes the attribute to be removed by `removeAttributeNS`.
74
91
  * - All other arguments of type `null` or `undefined` are simply ignored.
75
92
  * - All other arguments of type `Node` are appended to the element being created or modified.
76
93
  * - All other arguments of type `string`/`number` are converted to `Text` nodes and appended to the element being created or modified.
@@ -107,31 +124,6 @@ export declare const is: {
107
124
  <T extends abstract new (...args: Partial<Array<any>>) => unknown>(type: T, arg: unknown): arg is InstanceType<T>;
108
125
  };
109
126
 
110
- /**
111
- * The type of arguments of the `jc` helper.
112
- */
113
- export type JcNode = {
114
- [attributeOrSelector: string]: string | number | JcNode | undefined;
115
- };
116
-
117
- /**
118
- * The type of arguments of the `jc` helper.
119
- */
120
- export type JcRoot = Partial<Record<PropertyKey, JcNode>>;
121
-
122
- /**
123
- * A simple JS-to-CSS (aka CSS-in-JS) helper.
124
- *
125
- * The `root` parameter provides a hierarchical description of CSS rules.
126
- *
127
- * - 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.
128
- * - 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`).
129
- * - In keys specifying CSS attribute, all uppercase letters are replaced by lowercase letters with an additional `-` character preceding them (e.g. `fontFamily` → `font-family`).
130
- * - 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}`).
131
- * - Top-level keys that begin with `@` are not concatenated with sub-object keys.
132
- */
133
- export declare const jc: (root: JcRoot, splitter?: string) => string;
134
-
135
127
  /**
136
128
  * `JSON.parse` with “JavaScript turned on”.
137
129
  *
@@ -180,7 +172,8 @@ export declare const omit: <T extends Partial<Record<PropertyKey, unknown>>, K e
180
172
  export declare const plUral: (singular: string, plural2: string, plural5: string, value: number) => string;
181
173
 
182
174
  /**
183
- * A helper that protects calls to nested properties by a `Proxy` that initializes non-existent values with an empty object.
175
+ * A helper that protects calls to nested properties by a `Proxy` that initializes non-existent values with an empty
176
+ * object.
184
177
  */
185
178
  export declare const pro: (ref: unknown) => any;
186
179
 
@@ -194,8 +187,7 @@ export declare const refsInfo: (...refs: Partial<Array<unknown>>) => Partial<Arr
194
187
  /**
195
188
  * A helper that generates a UUID v1 identifier (with a creation timestamp).
196
189
  *
197
- * - The optional `node` parameter should have the format `/^[0123456789abcdef]+$/`.
198
- * Its value will be trimmed to last 12 characters and left padded with zeros.
190
+ * - The optional `node` parameter should have the format `/^[0123456789abcdef]+$/`. Its value will be trimmed to last 12 characters and left padded with zeros.
199
191
  */
200
192
  export declare const uuid1: ({ date, node }?: {
201
193
  date?: Date | undefined;
package/nnn.js CHANGED
@@ -1,3 +1,59 @@
1
+ // src/nnn/is.ts
2
+ var is = (type, arg) => arg?.constructor === type;
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
+
1
57
  // src/nnn/csvParse.ts
2
58
  var csvParse = (text, { header = true, separator = "," } = {}) => {
3
59
  const regExp = new RegExp(`${separator}|(?<!")\\s*"((?:[^"]|"")*)"\\s*(?!")`, "g");
@@ -16,9 +72,6 @@ var csvParse = (text, { header = true, separator = "," } = {}) => {
16
72
  var escapeValues = (escapeMap, values) => values.map((value) => (escapeMap.get(value?.constructor) ?? escapeMap.get(undefined))?.(value) ?? "");
17
73
  var escape = (escapeMap, template, ...values) => String.raw(template, ...escapeValues(escapeMap, values));
18
74
 
19
- // src/nnn/is.ts
20
- var is = (type, arg) => arg?.constructor === type;
21
-
22
75
  // src/nnn/h.ts
23
76
  var NS = {
24
77
  xlink: "http://www.w3.org/1999/xlink"
@@ -119,59 +172,6 @@ var fixTypography = (node) => {
119
172
  // src/nnn/has.ts
120
173
  var has = (key, ref) => (is(String, key) || is(Number, key) || is(Symbol, key)) && Object.hasOwnProperty.call(ref ?? Object, key);
121
174
 
122
- // src/nnn/jc.ts
123
- var _jc = (node, prefix, result, split) => {
124
- const queue = [[node, prefix]];
125
- while (queue.length > 0) {
126
- const [style0, prefix0] = queue.shift() ?? [];
127
- if (style0 == null || prefix0 == null) {
128
- continue;
129
- }
130
- if (is(Array, style0)) {
131
- result.push(prefix0, prefix0 !== "" ? "{" : "", style0.join(";"), prefix0 !== "" ? "}" : "");
132
- } else {
133
- const todo = [];
134
- let attributes = [];
135
- let attributesPushed = false;
136
- for (const key in style0) {
137
- const value = style0[key];
138
- if (is(String, value) || is(Number, value)) {
139
- if (!attributesPushed) {
140
- attributesPushed = true;
141
- attributes = [];
142
- todo.push([attributes, prefix0]);
143
- }
144
- attributes.push(`${split(key).replace(/([A-Z])/g, (_, letter) => "-" + letter.toLowerCase())}:${value}`);
145
- } else if (value != null) {
146
- attributesPushed = false;
147
- const prefixN = [];
148
- const keyChunks = key.split(",");
149
- prefix0.split(",").forEach((prefixChunk) => keyChunks.forEach((keyChunk) => prefixN.push(prefixChunk + keyChunk)));
150
- todo.push([value, prefixN.join(",")]);
151
- }
152
- }
153
- queue.unshift(...todo);
154
- }
155
- }
156
- };
157
- var jc = (root, splitter = "$$") => {
158
- const split = (text) => text.split(splitter)[0];
159
- const chunks = [];
160
- for (const key in root) {
161
- const value = root[key];
162
- if (value != null) {
163
- if (key[0] === "@") {
164
- chunks.push(split(key) + "{");
165
- _jc(value, "", chunks, split);
166
- chunks.push("}");
167
- } else {
168
- _jc(value, split(key), chunks, split);
169
- }
170
- }
171
- }
172
- return chunks.join("");
173
- };
174
-
175
175
  // src/nnn/jsOnParse.ts
176
176
  var jsOnParse = (handlers, text) => JSON.parse(text, (key, value) => {
177
177
  if (is(Object, value)) {
@@ -280,12 +280,12 @@ export {
280
280
  nanolight,
281
281
  locale,
282
282
  jsOnParse,
283
- jc,
284
283
  is,
285
284
  has,
286
285
  h,
287
286
  fixTypography,
288
287
  escapeValues,
289
288
  escape,
290
- csvParse
289
+ csvParse,
290
+ c
291
291
  };
package/package.json CHANGED
@@ -3,6 +3,7 @@
3
3
  "description": "Jackens’ JavaScript helpers.",
4
4
  "homepage": "https://jackens.github.io/nnn/doc/",
5
5
  "keywords": [
6
+ "c",
6
7
  "CSS-in-JS",
7
8
  "CSV",
8
9
  "csvParse",
@@ -14,7 +15,6 @@
14
15
  "HyperScript",
15
16
  "in",
16
17
  "is",
17
- "jc",
18
18
  "JS-to-CSS",
19
19
  "JSON",
20
20
  "jsOnParse",
@@ -36,5 +36,5 @@
36
36
  "name": "@jackens/nnn",
37
37
  "type": "module",
38
38
  "types": "nnn.d.ts",
39
- "version": "2024.7.13"
39
+ "version": "2024.7.18"
40
40
  }
package/readme.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Jackens’ JavaScript helpers.
4
4
 
5
- <sub>Version: <code class="version">2024.7.13</code></sub>
5
+ <sub>Version: <code class="version">2024.7.18</code></sub>
6
6
 
7
7
  ## Installation
8
8
 
@@ -31,16 +31,17 @@ import { «something» } from './node_modules/@jackens/nnn/nnn.js'
31
31
  or:
32
32
 
33
33
  ```js
34
- import { «something» } from 'https://unpkg.com/@jackens/nnn@2024.7.13/nnn.js'
34
+ import { «something» } from 'https://unpkg.com/@jackens/nnn@2024.7.18/nnn.js'
35
35
  ```
36
36
 
37
37
  ## Exports
38
38
 
39
+ - `CNode`: The type of arguments of the `c` helper.
40
+ - `CRoot`: The type of arguments of the `c` helper.
39
41
  - `EscapeMap`: The type of arguments of the `escapeValues` and `escape` helpers.
40
42
  - `HArgs`: The type of arguments of the `h` and `s` helpers.
41
43
  - `HArgs1`: The type of arguments of the `h` and `s` helpers.
42
- - `JcNode`: The type of arguments of the `jc` helper.
43
- - `JcRoot`: The type of arguments of the `jc` helper.
44
+ - `c`: A simple JS-to-CSS (aka CSS-in-JS) helper.
44
45
  - `csvParse`: A tiny helper for CSV parsing.
45
46
  - `escape`: A generic helper for escaping `values` by given `escapeMap` (in *TemplateStrings* flavor).
46
47
  - `escapeValues`: A generic helper for escaping `values` by given `escapeMap`.
@@ -48,7 +49,6 @@ import { «something» } from 'https://unpkg.com/@jackens/nnn@2024.7.13/nnn.js'
48
49
  - `h`: A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `HTMLElement`s (see also `s`).
49
50
  - `has`: A replacement for the `in` operator (not to be confused with the `for-in` loop) that works properly.
50
51
  - `is`: A helper that checks if the given argument is of a certain type.
51
- - `jc`: A simple JS-to-CSS (aka CSS-in-JS) helper.
52
52
  - `jsOnParse`: `JSON.parse` with “JavaScript turned on”.
53
53
  - `locale`: Language translations helper.
54
54
  - `nanolight`: A generic helper for syntax highlighting (see also `nanolightJs`).
@@ -56,12 +56,30 @@ import { «something» } from 'https://unpkg.com/@jackens/nnn@2024.7.13/nnn.js'
56
56
  - `omit`: A helper that implements TypeScript’s `Omit` utility type.
57
57
  - `pick`: A helper that implements TypeScript’s `Pick` utility type.
58
58
  - `plUral`: A helper for choosing the correct singular and plural.
59
- - `pro`: A helper that protects calls to nested properties by a `Proxy` that initializes non-existent values with an empty object.
59
+ - `pro`: A helper that protects calls to nested properties by a `Proxy` that initializes non-existent values with an empty
60
60
  - `refsInfo`: A helper that provides information about the given `refs`.
61
61
  - `s`: A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `SVGElement`s (see also `h`).
62
62
  - `svgUse`: A convenient shortcut for `s('svg', ['use', { 'xlink:href': '#' + id }], ...args)`.
63
63
  - `uuid1`: A helper that generates a UUID v1 identifier (with a creation timestamp).
64
64
 
65
+ ### CNode
66
+
67
+ ```ts
68
+ type CNode = {
69
+ [attributeOrSelector: string]: string | number | CNode | undefined;
70
+ };
71
+ ```
72
+
73
+ The type of arguments of the `c` helper.
74
+
75
+ ### CRoot
76
+
77
+ ```ts
78
+ type CRoot = Partial<Record<PropertyKey, CNode>>;
79
+ ```
80
+
81
+ The type of arguments of the `c` helper.
82
+
65
83
  ### EscapeMap
66
84
 
67
85
  ```ts
@@ -86,23 +104,217 @@ type HArgs1 = Partial<Record<PropertyKey, unknown>> | null | undefined | Node |
86
104
 
87
105
  The type of arguments of the `h` and `s` helpers.
88
106
 
89
- ### JcNode
107
+ ### c
90
108
 
91
109
  ```ts
92
- type JcNode = {
93
- [attributeOrSelector: string]: string | number | JcNode | undefined;
94
- };
110
+ const c: (root: CRoot, splitter?: string) => string;
95
111
  ```
96
112
 
97
- The type of arguments of the `jc` helper.
113
+ A simple JS-to-CSS (aka CSS-in-JS) helper.
114
+
115
+ The `root` parameter provides a hierarchical description of CSS rules.
98
116
 
99
- ### JcRoot
117
+ - 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.
118
+ - 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`).
119
+ - In keys specifying CSS attribute, all uppercase letters are replaced by lowercase letters with an additional `-` character preceding them (e.g. `fontFamily` → `font-family`).
120
+ - 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}`).
121
+ - Top-level keys that begin with `@` are not concatenated with sub-object keys.
100
122
 
101
- ```ts
102
- type JcRoot = Partial<Record<PropertyKey, JcNode>>;
123
+ #### Usage Examples
124
+
125
+ ```js
126
+ const actual = c({
127
+ a: {
128
+ color: 'red',
129
+ margin: 1,
130
+ '.c': { margin: 2, padding: 2 },
131
+ padding: 1
132
+ }
133
+ })
134
+
135
+ const expected = `
136
+ a{
137
+ color:red;
138
+ margin:1
139
+ }
140
+ a.c{
141
+ margin:2;
142
+ padding:2
143
+ }
144
+ a{
145
+ padding:1
146
+ }`.replace(/\n\s*/g, '')
147
+
148
+ expect(actual).to.deep.equal(expected)
149
+ ```
150
+
151
+ ```js
152
+ const actual = c({
153
+ a: {
154
+ '.b': {
155
+ color: 'red',
156
+ margin: 1,
157
+ '.c': { margin: 2, padding: 2 },
158
+ padding: 1
159
+ }
160
+ }
161
+ })
162
+
163
+ const expected = `
164
+ a.b{
165
+ color:red;
166
+ margin:1
167
+ }
168
+ a.b.c{
169
+ margin:2;
170
+ padding:2
171
+ }
172
+ a.b{
173
+ padding:1
174
+ }`.replace(/\n\s*/g, '')
175
+
176
+ expect(actual).to.deep.equal(expected)
177
+ ```
178
+
179
+ ```js
180
+ const actual = c({
181
+ '@font-face$$1': {
182
+ fontFamily: 'Jackens',
183
+ src$$1: 'url(otf/jackens.otf)',
184
+ src$$2: "url(otf/jackens.otf) format('opentype')," +
185
+ "url(svg/jackens.svg) format('svg')",
186
+ fontWeight: 'normal',
187
+ fontStyle: 'normal'
188
+ },
189
+ '@font-face$$2': {
190
+ fontFamily: 'C64',
191
+ src: 'url(fonts/C64_Pro_Mono-STYLE.woff)'
192
+ },
193
+ '@keyframes spin': {
194
+ '0%': { transform: 'rotate(0deg)' },
195
+ '100%': { transform: 'rotate(360deg)' }
196
+ },
197
+ div: {
198
+ border: 'solid red 1px',
199
+ '.c1': { 'background-color': '#000' },
200
+ ' .c1': { backgroundColor: 'black' },
201
+ '.c2': { backgroundColor: 'rgb(0,0,0)' }
202
+ },
203
+ '@media(min-width:200px)': {
204
+ div: { margin: 0, padding: 0 },
205
+ span: { color: '#000' }
206
+ }
207
+ })
208
+
209
+ const expected = `
210
+ @font-face{
211
+ font-family:Jackens;
212
+ src:url(otf/jackens.otf);
213
+ src:url(otf/jackens.otf) format('opentype'),url(svg/jackens.svg) format('svg');
214
+ font-weight:normal;
215
+ font-style:normal
216
+ }
217
+ @font-face{
218
+ font-family:C64;
219
+ src:url(fonts/C64_Pro_Mono-STYLE.woff)
220
+ }
221
+ @keyframes spin{
222
+ 0%{
223
+ transform:rotate(0deg)
224
+ }
225
+ 100%{
226
+ transform:rotate(360deg)
227
+ }
228
+ }
229
+ div{
230
+ border:solid red 1px
231
+ }
232
+ div.c1{
233
+ background-color:#000
234
+ }
235
+ div .c1{
236
+ background-color:black
237
+ }
238
+ div.c2{
239
+ background-color:rgb(0,0,0)
240
+ }
241
+ @media(min-width:200px){
242
+ div{
243
+ margin:0;
244
+ padding:0
245
+ }
246
+ span{
247
+ color:#000
248
+ }
249
+ }`.replace(/\n\s*/g, '')
250
+
251
+ expect(actual).to.deep.equal(expected)
103
252
  ```
104
253
 
105
- The type of arguments of the `jc` helper.
254
+ ```js
255
+ const actual = c({
256
+ a: {
257
+ '.b,.c': {
258
+ margin: 1,
259
+ '.d': {
260
+ margin: 2
261
+ }
262
+ }
263
+ }
264
+ })
265
+
266
+ const expected = `
267
+ a.b,a.c{
268
+ margin:1
269
+ }
270
+ a.b.d,a.c.d{
271
+ margin:2
272
+ }`.replace(/\n\s*/g, '')
273
+
274
+ expect(actual).to.deep.equal(expected)
275
+ ```
276
+
277
+ ```js
278
+ const actual = c({
279
+ '.b,.c': {
280
+ margin: 1,
281
+ '.d': {
282
+ margin: 2
283
+ }
284
+ }
285
+ })
286
+
287
+ const expected = `
288
+ .b,.c{
289
+ margin:1
290
+ }
291
+ .b.d,.c.d{
292
+ margin:2
293
+ }`.replace(/\n\s*/g, '')
294
+
295
+ expect(actual).to.deep.equal(expected)
296
+ ```
297
+
298
+ ```js
299
+ const actual = c({
300
+ '.a,.b': {
301
+ margin: 1,
302
+ '.c,.d': {
303
+ margin: 2
304
+ }
305
+ }
306
+ })
307
+
308
+ const expected = `
309
+ .a,.b{
310
+ margin:1
311
+ }
312
+ .a.c,.a.d,.b.c,.b.d{
313
+ margin:2
314
+ }`.replace(/\n\s*/g, '')
315
+
316
+ expect(actual).to.deep.equal(expected)
317
+ ```
106
318
 
107
319
  ### csvParse
108
320
 
@@ -224,11 +436,7 @@ A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style help
224
436
 
225
437
  - The first argument of type `string` specifies the tag of the element to be created.
226
438
  - The first argument of type `Node` specifies the element to be modified.
227
- - All other arguments of type `Partial<Record<PropertyKey, unknown>>` are mappings of attributes and properties.
228
- Keys starting with `$` specify *properties* (without the leading `$`) to be set on the element being created or modified.
229
- (Note that `$` is not a valid attribute name character.)
230
- All other keys specify *attributes* to be set by `setAttribute`.
231
- An attribute equal to `false` causes the attribute to be removed by `removeAttribute`.
439
+ - All other arguments of type `Partial<Record<PropertyKey, unknown>>` are mappings of attributes and properties. Keys starting with `$` specify *properties* (without the leading `$`) to be set on the element being created or modified. (Note that `$` is not a valid attribute name character.) All other keys specify *attributes* to be set by `setAttribute`. An attribute equal to `false` causes the attribute to be removed by `removeAttribute`.
232
440
  - All other arguments of type `null` or `undefined` are simply ignored.
233
441
  - All other arguments of type `Node` are appended to the element being created or modified.
234
442
  - All other arguments of type `string`/`number` are converted to `Text` nodes and appended to the element being created or modified.
@@ -419,218 +627,6 @@ try {
419
627
  expect(is(Number, num)).to.be.true
420
628
  ```
421
629
 
422
- ### jc
423
-
424
- ```ts
425
- const jc: (root: JcRoot, splitter?: string) => string;
426
- ```
427
-
428
- A simple JS-to-CSS (aka CSS-in-JS) helper.
429
-
430
- The `root` parameter provides a hierarchical description of CSS rules.
431
-
432
- - 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.
433
- - 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`).
434
- - In keys specifying CSS attribute, all uppercase letters are replaced by lowercase letters with an additional `-` character preceding them (e.g. `fontFamily` → `font-family`).
435
- - 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}`).
436
- - Top-level keys that begin with `@` are not concatenated with sub-object keys.
437
-
438
- #### Usage Examples
439
-
440
- ```js
441
- const actual = jc({
442
- a: {
443
- color: 'red',
444
- margin: 1,
445
- '.c': { margin: 2, padding: 2 },
446
- padding: 1
447
- }
448
- })
449
-
450
- const expected = `
451
- a{
452
- color:red;
453
- margin:1
454
- }
455
- a.c{
456
- margin:2;
457
- padding:2
458
- }
459
- a{
460
- padding:1
461
- }`.replace(/\n\s*/g, '')
462
-
463
- expect(actual).to.deep.equal(expected)
464
- ```
465
-
466
- ```js
467
- const actual = jc({
468
- a: {
469
- '.b': {
470
- color: 'red',
471
- margin: 1,
472
- '.c': { margin: 2, padding: 2 },
473
- padding: 1
474
- }
475
- }
476
- })
477
-
478
- const expected = `
479
- a.b{
480
- color:red;
481
- margin:1
482
- }
483
- a.b.c{
484
- margin:2;
485
- padding:2
486
- }
487
- a.b{
488
- padding:1
489
- }`.replace(/\n\s*/g, '')
490
-
491
- expect(actual).to.deep.equal(expected)
492
- ```
493
-
494
- ```js
495
- const actual = jc({
496
- '@font-face$$1': {
497
- fontFamily: 'Jackens',
498
- src$$1: 'url(otf/jackens.otf)',
499
- src$$2: "url(otf/jackens.otf) format('opentype')," +
500
- "url(svg/jackens.svg) format('svg')",
501
- fontWeight: 'normal',
502
- fontStyle: 'normal'
503
- },
504
- '@font-face$$2': {
505
- fontFamily: 'C64',
506
- src: 'url(fonts/C64_Pro_Mono-STYLE.woff)'
507
- },
508
- '@keyframes spin': {
509
- '0%': { transform: 'rotate(0deg)' },
510
- '100%': { transform: 'rotate(360deg)' }
511
- },
512
- div: {
513
- border: 'solid red 1px',
514
- '.c1': { 'background-color': '#000' },
515
- ' .c1': { backgroundColor: 'black' },
516
- '.c2': { backgroundColor: 'rgb(0,0,0)' }
517
- },
518
- '@media(min-width:200px)': {
519
- div: { margin: 0, padding: 0 },
520
- span: { color: '#000' }
521
- }
522
- })
523
-
524
- const expected = `
525
- @font-face{
526
- font-family:Jackens;
527
- src:url(otf/jackens.otf);
528
- src:url(otf/jackens.otf) format('opentype'),url(svg/jackens.svg) format('svg');
529
- font-weight:normal;
530
- font-style:normal
531
- }
532
- @font-face{
533
- font-family:C64;
534
- src:url(fonts/C64_Pro_Mono-STYLE.woff)
535
- }
536
- @keyframes spin{
537
- 0%{
538
- transform:rotate(0deg)
539
- }
540
- 100%{
541
- transform:rotate(360deg)
542
- }
543
- }
544
- div{
545
- border:solid red 1px
546
- }
547
- div.c1{
548
- background-color:#000
549
- }
550
- div .c1{
551
- background-color:black
552
- }
553
- div.c2{
554
- background-color:rgb(0,0,0)
555
- }
556
- @media(min-width:200px){
557
- div{
558
- margin:0;
559
- padding:0
560
- }
561
- span{
562
- color:#000
563
- }
564
- }`.replace(/\n\s*/g, '')
565
-
566
- expect(actual).to.deep.equal(expected)
567
- ```
568
-
569
- ```js
570
- const actual = jc({
571
- a: {
572
- '.b,.c': {
573
- margin: 1,
574
- '.d': {
575
- margin: 2
576
- }
577
- }
578
- }
579
- })
580
-
581
- const expected = `
582
- a.b,a.c{
583
- margin:1
584
- }
585
- a.b.d,a.c.d{
586
- margin:2
587
- }`.replace(/\n\s*/g, '')
588
-
589
- expect(actual).to.deep.equal(expected)
590
- ```
591
-
592
- ```js
593
- const actual = jc({
594
- '.b,.c': {
595
- margin: 1,
596
- '.d': {
597
- margin: 2
598
- }
599
- }
600
- })
601
-
602
- const expected = `
603
- .b,.c{
604
- margin:1
605
- }
606
- .b.d,.c.d{
607
- margin:2
608
- }`.replace(/\n\s*/g, '')
609
-
610
- expect(actual).to.deep.equal(expected)
611
- ```
612
-
613
- ```js
614
- const actual = jc({
615
- '.a,.b': {
616
- margin: 1,
617
- '.c,.d': {
618
- margin: 2
619
- }
620
- }
621
- })
622
-
623
- const expected = `
624
- .a,.b{
625
- margin:1
626
- }
627
- .a.c,.a.d,.b.c,.b.d{
628
- margin:2
629
- }`.replace(/\n\s*/g, '')
630
-
631
- expect(actual).to.deep.equal(expected)
632
- ```
633
-
634
630
  ### jsOnParse
635
631
 
636
632
  ```ts
@@ -824,7 +820,8 @@ expect(car(42)).to.deep.equal('cars')
824
820
  const pro: (ref: unknown) => any;
825
821
  ```
826
822
 
827
- A helper that protects calls to nested properties by a `Proxy` that initializes non-existent values with an empty object.
823
+ A helper that protects calls to nested properties by a `Proxy` that initializes non-existent values with an empty
824
+ object.
828
825
 
829
826
  #### Usage Examples
830
827
 
@@ -913,11 +910,7 @@ A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style help
913
910
 
914
911
  - The first argument of type `string` specifies the tag of the element to be created.
915
912
  - The first argument of type `Node` specifies the element to be modified.
916
- - All other arguments of type `Partial<Record<PropertyKey, unknown>>` are mappings of attributes and properties.
917
- Keys starting with `$` specify *properties* (without the leading `$`) to be set on the element being created or modified.
918
- (Note that `$` is not a valid attribute name character.)
919
- All other keys specify *attributes* to be set by `setAttributeNS`.
920
- An attribute equal to `false` causes the attribute to be removed by `removeAttributeNS`.
913
+ - All other arguments of type `Partial<Record<PropertyKey, unknown>>` are mappings of attributes and properties. Keys starting with `$` specify *properties* (without the leading `$`) to be set on the element being created or modified. (Note that `$` is not a valid attribute name character.) All other keys specify *attributes* to be set by `setAttributeNS`. An attribute equal to `false` causes the attribute to be removed by `removeAttributeNS`.
921
914
  - All other arguments of type `null` or `undefined` are simply ignored.
922
915
  - All other arguments of type `Node` are appended to the element being created or modified.
923
916
  - All other arguments of type `string`/`number` are converted to `Text` nodes and appended to the element being created or modified.
@@ -942,8 +935,7 @@ const uuid1: ({ date, node }?: {
942
935
 
943
936
  A helper that generates a UUID v1 identifier (with a creation timestamp).
944
937
 
945
- - The optional `node` parameter should have the format `/^[0123456789abcdef]+$/`.
946
- Its value will be trimmed to last 12 characters and left padded with zeros.
938
+ - The optional `node` parameter should have the format `/^[0123456789abcdef]+$/`. Its value will be trimmed to last 12 characters and left padded with zeros.
947
939
 
948
940
  #### Usage Examples
949
941