@jackens/nnn 2025.6.14 → 2025.9.3
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.
- package/nnn.d.ts +45 -39
- package/nnn.js +101 -107
- package/package.json +8 -8
- package/readme.md +110 -153
package/nnn.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The type of arguments of the `c` helper.
|
|
3
3
|
*/
|
|
4
|
-
export type
|
|
5
|
-
[
|
|
4
|
+
export type C_Node = {
|
|
5
|
+
[attribute_or_selector: string]: string | number | C_Node | undefined;
|
|
6
6
|
};
|
|
7
7
|
/**
|
|
8
8
|
* The type of arguments of the `c` helper.
|
|
9
9
|
*/
|
|
10
|
-
export type
|
|
10
|
+
export type C_Root = Record<PropertyKey, C_Node>;
|
|
11
11
|
/**
|
|
12
12
|
* A simple JS-to-CSS (aka CSS-in-JS) helper.
|
|
13
13
|
*
|
|
@@ -15,43 +15,39 @@ export type CRoot = Record<PropertyKey, CNode>;
|
|
|
15
15
|
*
|
|
16
16
|
* - 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.
|
|
17
17
|
* - 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`).
|
|
18
|
-
* - In keys specifying CSS attribute, all uppercase letters are replaced by lowercase letters with an additional `-` character preceding them (e.g. `fontFamily` → `font-family`).
|
|
18
|
+
* - In keys specifying CSS attribute, all uppercase letters are replaced by lowercase letters with an additional `-` character preceding them (e.g. `fontFamily` → `font-family`), while all `_` characters are replaced by `-` character (e.g. `font_family` → `font-family`).
|
|
19
19
|
* - 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}`).
|
|
20
20
|
* - Top-level keys that begin with `@` are not concatenated with sub-object keys.
|
|
21
21
|
*/
|
|
22
|
-
export declare const c: (root:
|
|
22
|
+
export declare const c: (root: C_Root, splitter?: string) => string;
|
|
23
23
|
/**
|
|
24
24
|
* A tiny helper for parsing CSV.
|
|
25
25
|
*/
|
|
26
|
-
export declare const
|
|
26
|
+
export declare const csv_parse: (csv: string, separator?: string) => string[][];
|
|
27
27
|
/**
|
|
28
|
-
*
|
|
29
|
-
*/
|
|
30
|
-
export declare const csvParse: (csv: string, separator?: string) => Record<PropertyKey, string>[];
|
|
31
|
-
/**
|
|
32
|
-
* The type of arguments of the `escapeValues` and `escape` helpers.
|
|
28
|
+
* The type of arguments of the `escape_values` and `escape` helpers.
|
|
33
29
|
*/
|
|
34
|
-
export type
|
|
30
|
+
export type Escape_Map = Map<unknown, (value?: unknown) => string>;
|
|
35
31
|
/**
|
|
36
|
-
* A generic helper for escaping `values` by given `
|
|
32
|
+
* A generic helper for escaping `values` by given `escape_map`.
|
|
37
33
|
*/
|
|
38
|
-
export declare const
|
|
34
|
+
export declare const escape_values: (escape_map: Escape_Map, values: unknown[]) => string[];
|
|
39
35
|
/**
|
|
40
|
-
* A generic helper for escaping `values` by given `
|
|
36
|
+
* A generic helper for escaping `values` by given `escape_map` (in *TemplateStrings* flavor).
|
|
41
37
|
*/
|
|
42
|
-
export declare const escape: (
|
|
38
|
+
export declare const escape: (escape_map: Escape_Map, template: TemplateStringsArray, ...values: unknown[]) => string;
|
|
43
39
|
/**
|
|
44
40
|
* A helper that implements typographic corrections specific to Polish typography.
|
|
45
41
|
*/
|
|
46
|
-
export declare const
|
|
42
|
+
export declare const fix_typography: (node: Node) => void;
|
|
47
43
|
/**
|
|
48
44
|
* The type of arguments of the `h` and `s` helpers.
|
|
49
45
|
*/
|
|
50
|
-
export type
|
|
46
|
+
export type H_Args_1 = Record<PropertyKey, unknown> | null | undefined | Node | string | number | H_Args;
|
|
51
47
|
/**
|
|
52
48
|
* The type of arguments of the `h` and `s` helpers.
|
|
53
49
|
*/
|
|
54
|
-
export type
|
|
50
|
+
export type H_Args = [string | Node, ...H_Args_1[]];
|
|
55
51
|
/**
|
|
56
52
|
* A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `HTMLElement`s (see also `s`).
|
|
57
53
|
*
|
|
@@ -64,9 +60,9 @@ export type HArgs = [string | Node, ...HArgs1[]];
|
|
|
64
60
|
* - All other arguments of type `HArgs` are passed to `h` and the results are appended to the element being created or modified.
|
|
65
61
|
*/
|
|
66
62
|
export declare const h: {
|
|
67
|
-
<T extends keyof HTMLElementTagNameMap>(tag: T, ...args1:
|
|
68
|
-
<N extends Node>(node: N, ...args1:
|
|
69
|
-
(
|
|
63
|
+
<T extends keyof HTMLElementTagNameMap>(tag: T, ...args1: H_Args_1[]): HTMLElementTagNameMap[T];
|
|
64
|
+
<N extends Node>(node: N, ...args1: H_Args_1[]): N;
|
|
65
|
+
(tag_or_node: string | Node, ...args1: H_Args_1[]): Node;
|
|
70
66
|
};
|
|
71
67
|
/**
|
|
72
68
|
* A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `SVGElement`s (see also `h`).
|
|
@@ -80,58 +76,68 @@ export declare const h: {
|
|
|
80
76
|
* - All other arguments of type `HArgs` are passed to `s` and the results are appended to the element being created or modified.
|
|
81
77
|
*/
|
|
82
78
|
export declare const s: {
|
|
83
|
-
<T extends keyof SVGElementTagNameMap>(tag: T, ...args1:
|
|
84
|
-
<N extends Node>(node: N, ...args1:
|
|
85
|
-
(
|
|
79
|
+
<T extends keyof SVGElementTagNameMap>(tag: T, ...args1: H_Args_1[]): SVGElementTagNameMap[T];
|
|
80
|
+
<N extends Node>(node: N, ...args1: H_Args_1[]): N;
|
|
81
|
+
(tag_or_node: string | Node, ...args1: H_Args_1[]): Node;
|
|
86
82
|
};
|
|
87
83
|
/**
|
|
88
84
|
* A convenient shortcut for `s('svg', ['use', { 'xlink:href': '#' + id }], ...args)`.
|
|
89
85
|
*/
|
|
90
|
-
export declare const
|
|
86
|
+
export declare const svg_use: (id: string, ...args: H_Args_1[]) => SVGSVGElement;
|
|
91
87
|
/**
|
|
92
88
|
* A replacement for the `in` operator (not to be confused with the `for-in` loop) that works properly.
|
|
93
89
|
*/
|
|
94
|
-
export declare const
|
|
90
|
+
export declare const has_own: (ref: unknown, key: unknown) => boolean;
|
|
95
91
|
/**
|
|
96
92
|
* A helper that checks if the given argument is of type `any[]`.
|
|
97
93
|
*/
|
|
98
|
-
export declare const
|
|
94
|
+
export declare const is_array: (arg: any) => arg is any[];
|
|
95
|
+
declare const FINITE_NUMBER: unique symbol;
|
|
96
|
+
type Finite_Number = number & {
|
|
97
|
+
readonly [FINITE_NUMBER]: true;
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* A helper that checks if the given argument is of type `number` but not `±Infinity` nor `NaN`.
|
|
101
|
+
*/
|
|
102
|
+
export declare const is_finite_number: ((arg: unknown) => arg is Finite_Number);
|
|
99
103
|
/**
|
|
100
104
|
* A helper that checks if the given argument is of type `number`.
|
|
101
105
|
*/
|
|
102
|
-
export declare const
|
|
106
|
+
export declare const is_number: (arg: unknown) => arg is number;
|
|
103
107
|
/**
|
|
104
108
|
* A helper that checks if the given argument is of type `Record<PropertyKey, unknown>`.
|
|
105
109
|
*/
|
|
106
|
-
export declare const
|
|
110
|
+
export declare const is_record: (arg: unknown) => arg is Record<PropertyKey, unknown>;
|
|
107
111
|
/**
|
|
108
112
|
* A helper that checks if the given argument is of type `string`.
|
|
109
113
|
*/
|
|
110
|
-
export declare const
|
|
114
|
+
export declare const is_string: (arg: unknown) => arg is string;
|
|
115
|
+
export {};
|
|
111
116
|
/**
|
|
112
117
|
* `JSON.parse` with “JavaScript turned on”.
|
|
113
118
|
*
|
|
114
119
|
* Objects having *exactly* one property which is present in the `handlers` map, i.e. objects of the form:
|
|
115
120
|
*
|
|
116
121
|
* ```js
|
|
117
|
-
* { "«
|
|
122
|
+
* { "«handler_name»": [«params»] }
|
|
118
123
|
* ```
|
|
119
124
|
*
|
|
120
125
|
* are replaced by the result of call
|
|
121
126
|
*
|
|
122
127
|
* ```js
|
|
123
|
-
* handlers['«
|
|
128
|
+
* handlers['«handler_name»'](...«params»)
|
|
124
129
|
* ```
|
|
125
130
|
*/
|
|
126
|
-
export declare const
|
|
131
|
+
export declare const js_on_parse: (handlers: Record<PropertyKey, Function>, text: string) => any;
|
|
132
|
+
import type { H_Args_1 } from './h.js';
|
|
127
133
|
/**
|
|
128
|
-
* A generic helper for syntax highlighting (see also `
|
|
134
|
+
* A generic helper for syntax highlighting (see also `nanolight_js`).
|
|
129
135
|
*/
|
|
130
|
-
export declare const nanolight: (pattern: RegExp, highlighters: ((chunk: string, index: number) =>
|
|
136
|
+
export declare const nanolight: (pattern: RegExp, highlighters: ((chunk: string, index: number) => H_Args_1)[], code: string) => H_Args_1[];
|
|
131
137
|
/**
|
|
132
138
|
* A helper for highlighting JavaScript (see also `nanolight`).
|
|
133
139
|
*/
|
|
134
|
-
export declare const
|
|
140
|
+
export declare const nanolight_js: (code: string) => H_Args_1[];
|
|
135
141
|
/**
|
|
136
142
|
* A helper that implements TypeScript’s `Pick` utility type (see also `omit`).
|
|
137
143
|
*/
|
|
@@ -143,7 +149,7 @@ export declare const omit: <T, K extends keyof T>(ref: T, keys: unknown[]) => Om
|
|
|
143
149
|
/**
|
|
144
150
|
* A helper for choosing the correct singular and plural.
|
|
145
151
|
*/
|
|
146
|
-
export declare const
|
|
152
|
+
export declare const pl_ural: (singular: string, plural_2: string, plural_5: string, value: number) => string;
|
|
147
153
|
/**
|
|
148
154
|
* A helper that protects calls to nested properties by a `Proxy` that initializes non-existent values with an empty object.
|
|
149
155
|
*/
|
|
@@ -153,4 +159,4 @@ export declare const pro: (ref: unknown) => any;
|
|
|
153
159
|
*
|
|
154
160
|
* - The optional `node` parameter should have the format `/^[0123456789abcdef]+$/`. Its value will be trimmed to last 12 characters and left padded with zeros.
|
|
155
161
|
*/
|
|
156
|
-
export declare const
|
|
162
|
+
export declare const uuid_v1: (date?: Date, node?: string) => string;
|
package/nnn.js
CHANGED
|
@@ -1,38 +1,40 @@
|
|
|
1
1
|
// src/nnn/is.ts
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
var
|
|
5
|
-
var
|
|
2
|
+
var is_array = Array.isArray;
|
|
3
|
+
var is_finite_number = Number.isFinite;
|
|
4
|
+
var is_number = (arg) => typeof arg === "number";
|
|
5
|
+
var is_record = (arg) => typeof arg === "object" && arg != null && !is_array(arg);
|
|
6
|
+
var is_string = (arg) => typeof arg === "string";
|
|
6
7
|
|
|
7
8
|
// src/nnn/c.ts
|
|
8
|
-
var _c = (node, prefix, result,
|
|
9
|
+
var _c = (node, prefix, result, splitter) => {
|
|
9
10
|
const queue = [[node, prefix]];
|
|
10
11
|
while (queue.length > 0) {
|
|
11
|
-
const [
|
|
12
|
-
if (
|
|
12
|
+
const [style_0, prefix_0] = queue.shift() ?? [];
|
|
13
|
+
if (style_0 == null || prefix_0 == null) {
|
|
13
14
|
continue;
|
|
14
15
|
}
|
|
15
|
-
if (
|
|
16
|
-
result.push(
|
|
16
|
+
if (is_array(style_0)) {
|
|
17
|
+
result.push(prefix_0, prefix_0 !== "" ? "{" : "", style_0.join(";"), prefix_0 !== "" ? "}" : "");
|
|
17
18
|
} else {
|
|
18
19
|
const todo = [];
|
|
19
20
|
let attributes = [];
|
|
20
|
-
let
|
|
21
|
-
for (const key in
|
|
22
|
-
const value =
|
|
23
|
-
if (
|
|
24
|
-
if (!
|
|
25
|
-
|
|
21
|
+
let attributes_pushed = false;
|
|
22
|
+
for (const key in style_0) {
|
|
23
|
+
const value = style_0[key];
|
|
24
|
+
if (is_string(value) || is_number(value)) {
|
|
25
|
+
if (!attributes_pushed) {
|
|
26
|
+
attributes_pushed = true;
|
|
26
27
|
attributes = [];
|
|
27
|
-
todo.push([attributes,
|
|
28
|
+
todo.push([attributes, prefix_0]);
|
|
28
29
|
}
|
|
29
|
-
|
|
30
|
+
const attribute = key.split(splitter)[0].replace(/_/g, "-").replace(/([A-Z])/g, (_, letter) => "-" + letter.toLowerCase());
|
|
31
|
+
attributes.push(`${attribute}:${value}`);
|
|
30
32
|
} else if (value != null) {
|
|
31
|
-
|
|
32
|
-
const
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
todo.push([value,
|
|
33
|
+
attributes_pushed = false;
|
|
34
|
+
const prefix_n = [];
|
|
35
|
+
const key_chunks = key.split(",");
|
|
36
|
+
prefix_0.split(",").forEach((prefix_chunk) => key_chunks.forEach((key_chunk) => prefix_n.push(prefix_chunk + key_chunk)));
|
|
37
|
+
todo.push([value, prefix_n.join()]);
|
|
36
38
|
}
|
|
37
39
|
}
|
|
38
40
|
queue.unshift(...todo);
|
|
@@ -40,67 +42,59 @@ var _c = (node, prefix, result, split) => {
|
|
|
40
42
|
}
|
|
41
43
|
};
|
|
42
44
|
var c = (root, splitter = "$$") => {
|
|
43
|
-
const split = (text) => text.split(splitter)[0];
|
|
44
45
|
const chunks = [];
|
|
45
46
|
for (const key in root) {
|
|
46
47
|
const value = root[key];
|
|
47
48
|
if (value != null) {
|
|
48
49
|
if (key[0] === "@") {
|
|
49
|
-
chunks.push(split(
|
|
50
|
-
_c(value, "", chunks,
|
|
50
|
+
chunks.push(key.split(splitter)[0] + "{");
|
|
51
|
+
_c(value, "", chunks, splitter);
|
|
51
52
|
chunks.push("}");
|
|
52
53
|
} else {
|
|
53
|
-
_c(value, split(
|
|
54
|
+
_c(value, key.split(splitter)[0], chunks, splitter);
|
|
54
55
|
}
|
|
55
56
|
}
|
|
56
57
|
}
|
|
57
58
|
return chunks.join("");
|
|
58
59
|
};
|
|
59
|
-
// src/nnn/
|
|
60
|
-
var
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
var csvParse = (csv, separator = ",") => {
|
|
65
|
-
const rows = csvParseRaw(csv, separator);
|
|
66
|
-
const keys = rows.shift();
|
|
67
|
-
return keys != null ? rows.map((row) => keys.reduce((record, key, index) => {
|
|
68
|
-
record[key] = row[index];
|
|
69
|
-
return record;
|
|
70
|
-
}, {})) : [];
|
|
60
|
+
// src/nnn/csv_parse.ts
|
|
61
|
+
var csv_parse = (csv, separator = ",") => {
|
|
62
|
+
const main_pattern = /\n|(?<!")("(?:[^"]|"")*")(?!")/g;
|
|
63
|
+
const line_pattern = new RegExp(`${separator}|(?<!")\\s*"((?:[^"]|"")*)"\\s*(?!")`, "g");
|
|
64
|
+
return csv.replace(/\r/g, "").replace(/\n+$/, "").replace(main_pattern, (_, chunk) => chunk ?? "\r").split("\r").map((line) => line.replace(line_pattern, (_, chunk) => chunk == null ? "\r" : chunk.replace(/""/g, '"')).split("\r"));
|
|
71
65
|
};
|
|
72
66
|
// src/nnn/escape.ts
|
|
73
|
-
var
|
|
74
|
-
var escape = (
|
|
67
|
+
var escape_values = (escape_map, values) => values.map((value) => (escape_map.get(value?.constructor) ?? escape_map.get(undefined))?.(value) ?? "");
|
|
68
|
+
var escape = (escape_map, template, ...values) => String.raw(template, ...escape_values(escape_map, values));
|
|
75
69
|
// src/nnn/h.ts
|
|
76
|
-
var _h = (
|
|
77
|
-
const
|
|
78
|
-
const h = (
|
|
79
|
-
const node =
|
|
70
|
+
var _h = (namespace_uri) => {
|
|
71
|
+
const create_element = namespace_uri == null ? (tag) => document.createElement(tag) : (tag) => document.createElementNS(namespace_uri, tag);
|
|
72
|
+
const h = (tag_or_node, ...args) => {
|
|
73
|
+
const node = is_string(tag_or_node) ? create_element(tag_or_node) : tag_or_node;
|
|
80
74
|
args.forEach((arg) => {
|
|
81
75
|
let child = null;
|
|
82
76
|
if (arg instanceof Node) {
|
|
83
77
|
child = arg;
|
|
84
|
-
} else if (
|
|
78
|
+
} else if (is_array(arg)) {
|
|
85
79
|
child = h(...arg);
|
|
86
|
-
} else if (
|
|
80
|
+
} else if (is_record(arg)) {
|
|
87
81
|
for (const name in arg) {
|
|
88
82
|
const value = arg[name];
|
|
89
83
|
if (name[0] === "$") {
|
|
90
84
|
const name1 = name.slice(1);
|
|
91
|
-
if (
|
|
92
|
-
node[name1]
|
|
85
|
+
if (is_record(value)) {
|
|
86
|
+
node[name1] ??= {};
|
|
93
87
|
Object.assign(node[name1], value);
|
|
94
88
|
} else {
|
|
95
89
|
node[name1] = value;
|
|
96
90
|
}
|
|
97
91
|
} else if (node instanceof Element) {
|
|
98
|
-
const
|
|
99
|
-
if (
|
|
100
|
-
const
|
|
101
|
-
if (
|
|
92
|
+
const index_of_colon = name.indexOf(":");
|
|
93
|
+
if (index_of_colon >= 0) {
|
|
94
|
+
const ns_key = name.slice(0, index_of_colon);
|
|
95
|
+
if (ns_key === "xlink") {
|
|
102
96
|
const ns = "http://www.w3.org/1999/xlink";
|
|
103
|
-
const basename = name.slice(
|
|
97
|
+
const basename = name.slice(index_of_colon + 1);
|
|
104
98
|
if (value === true) {
|
|
105
99
|
node.setAttributeNS(ns, basename, "");
|
|
106
100
|
} else if (value === false) {
|
|
@@ -120,7 +114,7 @@ var _h = (namespaceURI) => {
|
|
|
120
114
|
}
|
|
121
115
|
}
|
|
122
116
|
}
|
|
123
|
-
} else if (
|
|
117
|
+
} else if (is_string(arg)) {
|
|
124
118
|
child = document.createTextNode(arg);
|
|
125
119
|
}
|
|
126
120
|
if (child != null) {
|
|
@@ -133,54 +127,54 @@ var _h = (namespaceURI) => {
|
|
|
133
127
|
};
|
|
134
128
|
var h = _h();
|
|
135
129
|
var s = _h("http://www.w3.org/2000/svg");
|
|
136
|
-
var
|
|
130
|
+
var svg_use = (id, ...args) => s("svg", ["use", { "xlink:href": "#" + id }], ...args);
|
|
137
131
|
|
|
138
|
-
// src/nnn/
|
|
132
|
+
// src/nnn/fix_typography.ts
|
|
139
133
|
var TAGS_TO_SKIP = ["IFRAME", "NOSCRIPT", "PRE", "SCRIPT", "STYLE", "TEXTAREA"];
|
|
140
|
-
var
|
|
134
|
+
var fix_typography = (node) => {
|
|
141
135
|
const queue = [node];
|
|
142
136
|
while (queue.length > 0) {
|
|
143
|
-
const
|
|
144
|
-
if (
|
|
145
|
-
|
|
146
|
-
if (
|
|
147
|
-
queue.push(
|
|
148
|
-
} else if (
|
|
149
|
-
queue.push(
|
|
137
|
+
const node_0 = queue.shift();
|
|
138
|
+
if (node_0 instanceof Element) {
|
|
139
|
+
node_0.childNodes.forEach((child_node) => {
|
|
140
|
+
if (child_node instanceof Text) {
|
|
141
|
+
queue.push(child_node);
|
|
142
|
+
} else if (child_node instanceof Element && !TAGS_TO_SKIP.includes(child_node.tagName)) {
|
|
143
|
+
queue.push(child_node);
|
|
150
144
|
}
|
|
151
145
|
});
|
|
152
|
-
} else if (
|
|
153
|
-
const
|
|
154
|
-
if (
|
|
155
|
-
let
|
|
156
|
-
|
|
146
|
+
} else if (node_0 instanceof Text) {
|
|
147
|
+
const node_value = node_0.nodeValue?.trim?.();
|
|
148
|
+
if (node_value != null) {
|
|
149
|
+
let previous_node = node_0;
|
|
150
|
+
node_value.split(/(\s|\(|„)([aiouwz—]\s)/gi).forEach((chunk, i) => {
|
|
157
151
|
i %= 3;
|
|
158
|
-
const
|
|
159
|
-
if (
|
|
160
|
-
|
|
152
|
+
const current_node = i === 2 ? h("span", { style: "white-space:nowrap" }, chunk) : i === 1 ? document.createTextNode(chunk) : document.createTextNode(chunk.replace(/(\/(?=[^/\s])|\.(?=[^\s]))/g, "$1"));
|
|
153
|
+
if (node_0.parentNode != null) {
|
|
154
|
+
node_0.parentNode.insertBefore(current_node, previous_node.nextSibling);
|
|
161
155
|
}
|
|
162
|
-
|
|
156
|
+
previous_node = current_node;
|
|
163
157
|
});
|
|
164
|
-
|
|
158
|
+
node_0.parentNode?.removeChild(node_0);
|
|
165
159
|
}
|
|
166
160
|
}
|
|
167
161
|
}
|
|
168
162
|
};
|
|
169
|
-
// src/nnn/
|
|
170
|
-
var
|
|
171
|
-
// src/nnn/
|
|
172
|
-
var
|
|
173
|
-
if (
|
|
174
|
-
let
|
|
163
|
+
// src/nnn/has_own.ts
|
|
164
|
+
var has_own = (ref, key) => ref != null && Object.hasOwn(ref, key);
|
|
165
|
+
// src/nnn/js_on_parse.ts
|
|
166
|
+
var js_on_parse = (handlers, text) => JSON.parse(text, (key, value) => {
|
|
167
|
+
if (is_record(value)) {
|
|
168
|
+
let is_second_key = false;
|
|
175
169
|
for (key in value) {
|
|
176
|
-
if (
|
|
170
|
+
if (is_second_key) {
|
|
177
171
|
return value;
|
|
178
172
|
}
|
|
179
|
-
|
|
173
|
+
is_second_key = true;
|
|
180
174
|
}
|
|
181
175
|
const handler = handlers[key];
|
|
182
176
|
const params = value[key];
|
|
183
|
-
if (handler instanceof Function &&
|
|
177
|
+
if (handler instanceof Function && is_array(params)) {
|
|
184
178
|
return handler(...params);
|
|
185
179
|
}
|
|
186
180
|
}
|
|
@@ -197,8 +191,8 @@ var nanolight = (pattern, highlighters, code) => {
|
|
|
197
191
|
});
|
|
198
192
|
return result;
|
|
199
193
|
};
|
|
200
|
-
// src/nnn/
|
|
201
|
-
var
|
|
194
|
+
// src/nnn/nanolight_js.ts
|
|
195
|
+
var nanolight_js = nanolight.bind(0, /('.*?'|".*?"|`[\s\S]*?`)|(\/\/.*?\n|\/\*[\s\S]*?\*\/)|(any|bigint|break|boolean|case|catch|class|const|continue|debugger|default|delete|do|else|eval|export|extends|false|finally|for|from|function|goto|if|import|in|instanceof|is|keyof|let|NaN|new|number|null|package|return|string|super|switch|symbol|this|throw|true|try|type|typeof|undefined|unknown|var|void|while|with|yield)(?!\w)|([<>=.?:&|!^~*/%+-])|(0x[\dabcdef_]+|0o[01234567_]+|0b[01_]+|\d[\d_]*(?:\.[\d_]+)?(?:e[+-]?[\d_]+)?)|([$\w]+)(?=\()|([$\wąćęłńóśżźĄĆĘŁŃÓŚŻŹ]+)/, [
|
|
202
196
|
(chunk) => chunk,
|
|
203
197
|
(chunk) => ["span", { class: "string" }, chunk],
|
|
204
198
|
(chunk) => ["span", { class: "comment" }, chunk],
|
|
@@ -211,47 +205,47 @@ var nanolightJs = nanolight.bind(0, /('.*?'|".*?"|`[\s\S]*?`)|(\/\/.*?\n|\/\*[\s
|
|
|
211
205
|
// src/nnn/pick.ts
|
|
212
206
|
var pick = (ref, keys) => Object.fromEntries(Object.entries(ref).filter(([key]) => keys.includes(key)));
|
|
213
207
|
var omit = (ref, keys) => Object.fromEntries(Object.entries(ref).filter(([key]) => !keys.includes(key)));
|
|
214
|
-
// src/nnn/
|
|
215
|
-
var
|
|
216
|
-
const
|
|
217
|
-
const
|
|
218
|
-
return value === 1 ? singular : (
|
|
208
|
+
// src/nnn/pl_ural.ts
|
|
209
|
+
var pl_ural = (singular, plural_2, plural_5, value) => {
|
|
210
|
+
const abs_value = Math.abs(value);
|
|
211
|
+
const abs_value_mod_10 = abs_value % 10;
|
|
212
|
+
return value === 1 ? singular : (abs_value_mod_10 === 2 || abs_value_mod_10 === 3 || abs_value_mod_10 === 4) && abs_value !== 12 && abs_value !== 13 && abs_value !== 14 ? plural_2 : plural_5;
|
|
219
213
|
};
|
|
220
214
|
// src/nnn/pro.ts
|
|
221
215
|
var pro = (ref) => new Proxy(ref, {
|
|
222
216
|
get(target, key) {
|
|
223
|
-
return pro(target[key]
|
|
217
|
+
return pro(target[key] ??= {});
|
|
224
218
|
}
|
|
225
219
|
});
|
|
226
|
-
// src/nnn/
|
|
220
|
+
// src/nnn/uuid_v1.ts
|
|
227
221
|
var ZEROS = "0".repeat(16);
|
|
228
222
|
var counter = 0;
|
|
229
|
-
var
|
|
223
|
+
var uuid_v1 = (date = new Date, node = Math.random().toString(16).slice(2)) => {
|
|
230
224
|
const time = ZEROS + (1e4 * (+date + 12219292800000)).toString(16);
|
|
231
225
|
counter = counter + 1 & 16383;
|
|
232
226
|
return time.slice(-8).concat("-", time.slice(-12, -8), -1, time.slice(-15, -12), "-", (8 | counter >> 12).toString(16), (ZEROS + (counter & 4095).toString(16)).slice(-3), "-", (ZEROS + node).slice(-12));
|
|
233
227
|
};
|
|
234
228
|
export {
|
|
235
|
-
|
|
236
|
-
|
|
229
|
+
uuid_v1,
|
|
230
|
+
svg_use,
|
|
237
231
|
s,
|
|
238
232
|
pro,
|
|
239
|
-
|
|
233
|
+
pl_ural,
|
|
240
234
|
pick,
|
|
241
235
|
omit,
|
|
242
|
-
|
|
236
|
+
nanolight_js,
|
|
243
237
|
nanolight,
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
238
|
+
js_on_parse,
|
|
239
|
+
is_string,
|
|
240
|
+
is_record,
|
|
241
|
+
is_number,
|
|
242
|
+
is_finite_number,
|
|
243
|
+
is_array,
|
|
244
|
+
has_own,
|
|
250
245
|
h,
|
|
251
|
-
|
|
252
|
-
|
|
246
|
+
fix_typography,
|
|
247
|
+
escape_values,
|
|
253
248
|
escape,
|
|
254
|
-
|
|
255
|
-
csvParse,
|
|
249
|
+
csv_parse,
|
|
256
250
|
c
|
|
257
251
|
};
|
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"c",
|
|
6
6
|
"CSS-in-JS",
|
|
7
7
|
"CSV",
|
|
8
|
-
"
|
|
8
|
+
"csv_parse",
|
|
9
9
|
"DOM",
|
|
10
10
|
"escape",
|
|
11
11
|
"h",
|
|
@@ -14,13 +14,14 @@
|
|
|
14
14
|
"HyperScript",
|
|
15
15
|
"in",
|
|
16
16
|
"is",
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
17
|
+
"is_array",
|
|
18
|
+
"is_finite_number",
|
|
19
|
+
"is_number",
|
|
20
|
+
"is_record",
|
|
21
|
+
"is_string",
|
|
21
22
|
"JS-to-CSS",
|
|
22
23
|
"JSON",
|
|
23
|
-
"
|
|
24
|
+
"js_on_parse",
|
|
24
25
|
"nanolight",
|
|
25
26
|
"nnn",
|
|
26
27
|
"omit",
|
|
@@ -28,7 +29,6 @@
|
|
|
28
29
|
"SVG",
|
|
29
30
|
"typography",
|
|
30
31
|
"uuid",
|
|
31
|
-
"uuid1",
|
|
32
32
|
"uuidv1"
|
|
33
33
|
],
|
|
34
34
|
"license": "MIT",
|
|
@@ -36,5 +36,5 @@
|
|
|
36
36
|
"name": "@jackens/nnn",
|
|
37
37
|
"type": "module",
|
|
38
38
|
"types": "nnn.d.ts",
|
|
39
|
-
"version": "2025.
|
|
39
|
+
"version": "2025.9.3"
|
|
40
40
|
}
|
package/readme.md
CHANGED
|
@@ -28,72 +28,72 @@ import { «something» } from './node_modules/@jackens/nnn/nnn.js'
|
|
|
28
28
|
|
|
29
29
|
## Exports
|
|
30
30
|
|
|
31
|
-
- `
|
|
32
|
-
- `
|
|
33
|
-
- `
|
|
34
|
-
- `
|
|
35
|
-
- `
|
|
31
|
+
- `C_Node`: The type of arguments of the `c` helper.
|
|
32
|
+
- `C_Root`: The type of arguments of the `c` helper.
|
|
33
|
+
- `Escape_Map`: The type of arguments of the `escape_values` and `escape` helpers.
|
|
34
|
+
- `H_Args`: The type of arguments of the `h` and `s` helpers.
|
|
35
|
+
- `H_Args_1`: The type of arguments of the `h` and `s` helpers.
|
|
36
36
|
- `c`: A simple JS-to-CSS (aka CSS-in-JS) helper.
|
|
37
|
-
- `
|
|
38
|
-
- `
|
|
39
|
-
- `
|
|
40
|
-
- `
|
|
41
|
-
- `fixTypography`: A helper that implements typographic corrections specific to Polish typography.
|
|
37
|
+
- `csv_parse`: A tiny helper for parsing CSV.
|
|
38
|
+
- `escape`: A generic helper for escaping `values` by given `escape_map` (in *TemplateStrings* flavor).
|
|
39
|
+
- `escape_values`: A generic helper for escaping `values` by given `escape_map`.
|
|
40
|
+
- `fix_typography`: A helper that implements typographic corrections specific to Polish typography.
|
|
42
41
|
- `h`: A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `HTMLElement`s (see also `s`).
|
|
43
|
-
- `
|
|
44
|
-
- `
|
|
45
|
-
- `
|
|
46
|
-
- `
|
|
47
|
-
- `
|
|
48
|
-
- `
|
|
49
|
-
- `
|
|
50
|
-
- `
|
|
42
|
+
- `has_own`: A replacement for the `in` operator (not to be confused with the `for-in` loop) that works properly.
|
|
43
|
+
- `is_array`: A helper that checks if the given argument is of type `any[]`.
|
|
44
|
+
- `is_finite_number`: A helper that checks if the given argument is of type `number` but not `±Infinity` nor `NaN`.
|
|
45
|
+
- `is_number`: A helper that checks if the given argument is of type `number`.
|
|
46
|
+
- `is_record`: A helper that checks if the given argument is of type `Record<PropertyKey, unknown>`.
|
|
47
|
+
- `is_string`: A helper that checks if the given argument is of type `string`.
|
|
48
|
+
- `js_on_parse`: `JSON.parse` with “JavaScript turned on”.
|
|
49
|
+
- `nanolight`: A generic helper for syntax highlighting (see also `nanolight_js`).
|
|
50
|
+
- `nanolight_js`: A helper for highlighting JavaScript (see also `nanolight`).
|
|
51
51
|
- `omit`: A helper that implements TypeScript’s `Omit` utility type (see also `pick`).
|
|
52
52
|
- `pick`: A helper that implements TypeScript’s `Pick` utility type (see also `omit`).
|
|
53
|
-
- `
|
|
53
|
+
- `pl_ural`: A helper for choosing the correct singular and plural.
|
|
54
54
|
- `pro`: A helper that protects calls to nested properties by a `Proxy` that initializes non-existent values with an empty object.
|
|
55
55
|
- `s`: A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `SVGElement`s (see also `h`).
|
|
56
|
-
- `
|
|
57
|
-
- `
|
|
56
|
+
- `svg_use`: A convenient shortcut for `s('svg', ['use', { 'xlink:href': '#' + id }], ...args)`.
|
|
57
|
+
- `uuid_v1`: A helper that generates a UUID v1 identifier (with a creation timestamp).
|
|
58
58
|
|
|
59
|
-
###
|
|
59
|
+
### C_Node
|
|
60
60
|
|
|
61
61
|
```ts
|
|
62
|
-
type
|
|
63
|
-
[
|
|
62
|
+
type C_Node = {
|
|
63
|
+
[attribute_or_selector: string]: string | number | C_Node | undefined;
|
|
64
64
|
};
|
|
65
65
|
```
|
|
66
66
|
|
|
67
67
|
The type of arguments of the `c` helper.
|
|
68
68
|
|
|
69
|
-
###
|
|
69
|
+
### C_Root
|
|
70
70
|
|
|
71
71
|
```ts
|
|
72
|
-
type
|
|
72
|
+
type C_Root = Record<PropertyKey, C_Node>;
|
|
73
73
|
```
|
|
74
74
|
|
|
75
75
|
The type of arguments of the `c` helper.
|
|
76
76
|
|
|
77
|
-
###
|
|
77
|
+
### Escape_Map
|
|
78
78
|
|
|
79
79
|
```ts
|
|
80
|
-
type
|
|
80
|
+
type Escape_Map = Map<unknown, (value?: unknown) => string>;
|
|
81
81
|
```
|
|
82
82
|
|
|
83
|
-
The type of arguments of the `
|
|
83
|
+
The type of arguments of the `escape_values` and `escape` helpers.
|
|
84
84
|
|
|
85
|
-
###
|
|
85
|
+
### H_Args
|
|
86
86
|
|
|
87
87
|
```ts
|
|
88
|
-
type
|
|
88
|
+
type H_Args = [string | Node, ...H_Args_1[]];
|
|
89
89
|
```
|
|
90
90
|
|
|
91
91
|
The type of arguments of the `h` and `s` helpers.
|
|
92
92
|
|
|
93
|
-
###
|
|
93
|
+
### H_Args_1
|
|
94
94
|
|
|
95
95
|
```ts
|
|
96
|
-
type
|
|
96
|
+
type H_Args_1 = Record<PropertyKey, unknown> | null | undefined | Node | string | number | H_Args;
|
|
97
97
|
```
|
|
98
98
|
|
|
99
99
|
The type of arguments of the `h` and `s` helpers.
|
|
@@ -101,7 +101,7 @@ The type of arguments of the `h` and `s` helpers.
|
|
|
101
101
|
### c
|
|
102
102
|
|
|
103
103
|
```ts
|
|
104
|
-
const c: (root:
|
|
104
|
+
const c: (root: C_Root, splitter?: string) => string;
|
|
105
105
|
```
|
|
106
106
|
|
|
107
107
|
A simple JS-to-CSS (aka CSS-in-JS) helper.
|
|
@@ -110,7 +110,7 @@ The `root` parameter provides a hierarchical description of CSS rules.
|
|
|
110
110
|
|
|
111
111
|
- 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.
|
|
112
112
|
- 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`).
|
|
113
|
-
- In keys specifying CSS attribute, all uppercase letters are replaced by lowercase letters with an additional `-` character preceding them (e.g. `fontFamily` → `font-family`).
|
|
113
|
+
- In keys specifying CSS attribute, all uppercase letters are replaced by lowercase letters with an additional `-` character preceding them (e.g. `fontFamily` → `font-family`), while all `_` characters are replaced by `-` character (e.g. `font_family` → `font-family`).
|
|
114
114
|
- 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}`).
|
|
115
115
|
- Top-level keys that begin with `@` are not concatenated with sub-object keys.
|
|
116
116
|
|
|
@@ -177,11 +177,11 @@ const actual = c({
|
|
|
177
177
|
src$$1: 'url(otf/jackens.otf)',
|
|
178
178
|
src$$2: "url(otf/jackens.otf) format('opentype')," +
|
|
179
179
|
"url(svg/jackens.svg) format('svg')",
|
|
180
|
-
|
|
181
|
-
|
|
180
|
+
font_weight: 'normal',
|
|
181
|
+
'font-style': 'normal'
|
|
182
182
|
},
|
|
183
183
|
'@font-face$$2': {
|
|
184
|
-
|
|
184
|
+
font_family: 'C64',
|
|
185
185
|
src: 'url(fonts/C64_Pro_Mono-STYLE.woff)'
|
|
186
186
|
},
|
|
187
187
|
'@keyframes spin': {
|
|
@@ -191,7 +191,7 @@ const actual = c({
|
|
|
191
191
|
div: {
|
|
192
192
|
border: 'solid red 1px',
|
|
193
193
|
'.c1': { 'background-color': '#000' },
|
|
194
|
-
' .c1': {
|
|
194
|
+
' .c1': { background_color: 'black' },
|
|
195
195
|
'.c2': { backgroundColor: 'rgb(0,0,0)' }
|
|
196
196
|
},
|
|
197
197
|
'@media(min-width:200px)': {
|
|
@@ -310,10 +310,10 @@ const expected = `
|
|
|
310
310
|
expect(actual).to.deep.equal(expected)
|
|
311
311
|
```
|
|
312
312
|
|
|
313
|
-
###
|
|
313
|
+
### csv_parse
|
|
314
314
|
|
|
315
315
|
```ts
|
|
316
|
-
const
|
|
316
|
+
const csv_parse: (csv: string, separator?: string) => string[][];
|
|
317
317
|
```
|
|
318
318
|
|
|
319
319
|
A tiny helper for parsing CSV.
|
|
@@ -329,38 +329,7 @@ yyy",zzz
|
|
|
329
329
|
42 , "42" , 17
|
|
330
330
|
|
|
331
331
|
`
|
|
332
|
-
|
|
333
|
-
expect(csvParse(text)).to.deep.equal([{
|
|
334
|
-
'aaa\n"aaa"\naaa': 'xxx,xxx',
|
|
335
|
-
bbb: 'yyy\nyyy',
|
|
336
|
-
'ccc,ccc': 'zzz'
|
|
337
|
-
}, {
|
|
338
|
-
'aaa\n"aaa"\naaa': ' 42 ',
|
|
339
|
-
bbb: '42',
|
|
340
|
-
'ccc,ccc': ' 17'
|
|
341
|
-
}])
|
|
342
|
-
```
|
|
343
|
-
|
|
344
|
-
### csvParseRaw
|
|
345
|
-
|
|
346
|
-
```ts
|
|
347
|
-
const csvParseRaw: (csv: string, separator?: string) => string[][];
|
|
348
|
-
```
|
|
349
|
-
|
|
350
|
-
A tiny helper for parsing CSV.
|
|
351
|
-
|
|
352
|
-
#### Usage Examples
|
|
353
|
-
|
|
354
|
-
```ts
|
|
355
|
-
const text = `"aaa
|
|
356
|
-
""aaa""
|
|
357
|
-
aaa",bbb, "ccc,ccc"
|
|
358
|
-
"xxx,xxx", "yyy
|
|
359
|
-
yyy",zzz
|
|
360
|
-
42 , "42" , 17
|
|
361
|
-
|
|
362
|
-
`
|
|
363
|
-
expect(csvParseRaw(text)).to.deep.equal([
|
|
332
|
+
expect(csv_parse(text)).to.deep.equal([
|
|
364
333
|
['aaa\n"aaa"\naaa', 'bbb', 'ccc,ccc'],
|
|
365
334
|
['xxx,xxx', 'yyy\nyyy', 'zzz'],
|
|
366
335
|
[' 42 ', '42', ' 17']
|
|
@@ -370,24 +339,24 @@ expect(csvParseRaw(text)).to.deep.equal([
|
|
|
370
339
|
### escape
|
|
371
340
|
|
|
372
341
|
```ts
|
|
373
|
-
const escape: (
|
|
342
|
+
const escape: (escape_map: Escape_Map, template: TemplateStringsArray, ...values: unknown[]) => string;
|
|
374
343
|
```
|
|
375
344
|
|
|
376
|
-
A generic helper for escaping `values` by given `
|
|
345
|
+
A generic helper for escaping `values` by given `escape_map` (in *TemplateStrings* flavor).
|
|
377
346
|
|
|
378
347
|
#### Usage Examples
|
|
379
348
|
|
|
380
349
|
```ts
|
|
381
|
-
const
|
|
350
|
+
const escape_map: Escape_Map = new Map([
|
|
382
351
|
[undefined, () => 'NULL'],
|
|
383
|
-
[Array, (values: unknown[]) =>
|
|
352
|
+
[Array, (values: unknown[]) => escape_values(escape_map, values).join(', ')],
|
|
384
353
|
[Boolean, (value: boolean) => `b'${+value}'`],
|
|
385
354
|
[Date, (value: Date) => `'${value.toISOString().replace(/^(.+)T(.+)\..*$/, '$1 $2')}'`],
|
|
386
355
|
[Number, (value: number) => `${value}`],
|
|
387
356
|
[String, (value: string) => `'${value.replace(/'/g, "''")}'`]
|
|
388
357
|
])
|
|
389
358
|
|
|
390
|
-
const sql = escape.bind(null,
|
|
359
|
+
const sql = escape.bind(null, escape_map)
|
|
391
360
|
|
|
392
361
|
const actual = sql`
|
|
393
362
|
SELECT *
|
|
@@ -402,18 +371,18 @@ const expected = `
|
|
|
402
371
|
expect(actual).to.deep.equal(expected)
|
|
403
372
|
```
|
|
404
373
|
|
|
405
|
-
###
|
|
374
|
+
### escape_values
|
|
406
375
|
|
|
407
376
|
```ts
|
|
408
|
-
const
|
|
377
|
+
const escape_values: (escape_map: Escape_Map, values: unknown[]) => string[];
|
|
409
378
|
```
|
|
410
379
|
|
|
411
|
-
A generic helper for escaping `values` by given `
|
|
380
|
+
A generic helper for escaping `values` by given `escape_map`.
|
|
412
381
|
|
|
413
|
-
###
|
|
382
|
+
### fix_typography
|
|
414
383
|
|
|
415
384
|
```ts
|
|
416
|
-
const
|
|
385
|
+
const fix_typography: (node: Node) => void;
|
|
417
386
|
```
|
|
418
387
|
|
|
419
388
|
A helper that implements typographic corrections specific to Polish typography.
|
|
@@ -423,7 +392,7 @@ A helper that implements typographic corrections specific to Polish typography.
|
|
|
423
392
|
```ts
|
|
424
393
|
const p = h('p', 'Pchnąć w tę łódź jeża lub ośm skrzyń fig (zob. https://pl.wikipedia.org/wiki/Pangram).')
|
|
425
394
|
|
|
426
|
-
|
|
395
|
+
fix_typography(p)
|
|
427
396
|
|
|
428
397
|
expect(p.innerHTML).to.deep.equal(
|
|
429
398
|
'Pchnąć <span style="white-space:nowrap">w </span>tę łódź jeża lub ośm skrzyń fig ' +
|
|
@@ -434,9 +403,9 @@ expect(p.innerHTML).to.deep.equal(
|
|
|
434
403
|
|
|
435
404
|
```ts
|
|
436
405
|
const h: {
|
|
437
|
-
<T extends keyof HTMLElementTagNameMap>(tag: T, ...args1:
|
|
438
|
-
<N extends Node>(node: N, ...args1:
|
|
439
|
-
(
|
|
406
|
+
<T extends keyof HTMLElementTagNameMap>(tag: T, ...args1: H_Args_1[]): HTMLElementTagNameMap[T];
|
|
407
|
+
<N extends Node>(node: N, ...args1: H_Args_1[]): N;
|
|
408
|
+
(tag_or_node: string | Node, ...args1: H_Args_1[]): Node;
|
|
440
409
|
};
|
|
441
410
|
```
|
|
442
411
|
|
|
@@ -518,10 +487,10 @@ h(div, { $key: { two: 2 } })
|
|
|
518
487
|
expect(div.key).to.deep.equal({ one: 1, two: 2 })
|
|
519
488
|
```
|
|
520
489
|
|
|
521
|
-
###
|
|
490
|
+
### has_own
|
|
522
491
|
|
|
523
492
|
```ts
|
|
524
|
-
const
|
|
493
|
+
const has_own: (ref: unknown, key: unknown) => boolean;
|
|
525
494
|
```
|
|
526
495
|
|
|
527
496
|
A replacement for the `in` operator (not to be confused with the `for-in` loop) that works properly.
|
|
@@ -532,69 +501,82 @@ A replacement for the `in` operator (not to be confused with the `for-in` loop)
|
|
|
532
501
|
const obj = { 42: null, null: 'k,e,y', 'k,e,y': 42 }
|
|
533
502
|
|
|
534
503
|
expect(42 in obj).to.be.true
|
|
535
|
-
expect(
|
|
504
|
+
expect(has_own(obj, 42)).to.be.true
|
|
536
505
|
|
|
537
506
|
expect('42' in obj).to.be.true
|
|
538
|
-
expect(
|
|
507
|
+
expect(has_own(obj, '42')).to.be.true
|
|
539
508
|
|
|
540
509
|
expect('null' in obj).to.be.true
|
|
541
|
-
expect(
|
|
510
|
+
expect(has_own(obj, 'null')).to.be.true
|
|
542
511
|
|
|
543
512
|
expect(null in obj).to.be.true
|
|
544
|
-
expect(
|
|
513
|
+
expect(has_own(obj, null)).to.be.true
|
|
545
514
|
|
|
546
515
|
expect('k,e,y' in obj).to.be.true
|
|
547
|
-
expect(
|
|
516
|
+
expect(has_own(obj, 'k,e,y')).to.be.true
|
|
548
517
|
|
|
549
518
|
expect(['k', 'e', 'y'] in obj).to.be.true
|
|
550
|
-
expect(
|
|
519
|
+
expect(has_own(obj, ['k', 'e', 'y'])).to.be.true
|
|
551
520
|
|
|
552
521
|
expect('toString' in obj).to.be.true
|
|
553
|
-
expect(
|
|
522
|
+
expect(has_own(obj, 'toString')).to.be.false
|
|
554
523
|
|
|
555
524
|
expect(() => 'key' in null).to.throw
|
|
556
|
-
expect(
|
|
525
|
+
expect(has_own(null, 'key')).to.be.false
|
|
557
526
|
|
|
558
527
|
expect(() => 'key' in undefined).to.throw
|
|
559
|
-
expect(
|
|
528
|
+
expect(has_own(undefined, 'key')).to.be.false
|
|
560
529
|
```
|
|
561
530
|
|
|
562
|
-
###
|
|
531
|
+
### is_array
|
|
563
532
|
|
|
564
533
|
```ts
|
|
565
|
-
const
|
|
534
|
+
const is_array: (arg: any) => arg is any[];
|
|
535
|
+
declare const FINITE_NUMBER: unique symbol;
|
|
536
|
+
type Finite_Number = number & {
|
|
537
|
+
readonly [FINITE_NUMBER]: true;
|
|
538
|
+
};
|
|
566
539
|
```
|
|
567
540
|
|
|
568
541
|
A helper that checks if the given argument is of type `any[]`.
|
|
569
542
|
|
|
570
|
-
###
|
|
543
|
+
### is_finite_number
|
|
544
|
+
|
|
545
|
+
```ts
|
|
546
|
+
const is_finite_number: ((arg: unknown) => arg is Finite_Number);
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
A helper that checks if the given argument is of type `number` but not `±Infinity` nor `NaN`.
|
|
550
|
+
|
|
551
|
+
### is_number
|
|
571
552
|
|
|
572
553
|
```ts
|
|
573
|
-
const
|
|
554
|
+
const is_number: (arg: unknown) => arg is number;
|
|
574
555
|
```
|
|
575
556
|
|
|
576
557
|
A helper that checks if the given argument is of type `number`.
|
|
577
558
|
|
|
578
|
-
###
|
|
559
|
+
### is_record
|
|
579
560
|
|
|
580
561
|
```ts
|
|
581
|
-
const
|
|
562
|
+
const is_record: (arg: unknown) => arg is Record<PropertyKey, unknown>;
|
|
582
563
|
```
|
|
583
564
|
|
|
584
565
|
A helper that checks if the given argument is of type `Record<PropertyKey, unknown>`.
|
|
585
566
|
|
|
586
|
-
###
|
|
567
|
+
### is_string
|
|
587
568
|
|
|
588
569
|
```ts
|
|
589
|
-
const
|
|
570
|
+
const is_string: (arg: unknown) => arg is string;
|
|
571
|
+
export {};
|
|
590
572
|
```
|
|
591
573
|
|
|
592
574
|
A helper that checks if the given argument is of type `string`.
|
|
593
575
|
|
|
594
|
-
###
|
|
576
|
+
### js_on_parse
|
|
595
577
|
|
|
596
578
|
```ts
|
|
597
|
-
const
|
|
579
|
+
const js_on_parse: (handlers: Record<PropertyKey, Function>, text: string) => any;
|
|
598
580
|
```
|
|
599
581
|
|
|
600
582
|
`JSON.parse` with “JavaScript turned on”.
|
|
@@ -602,13 +584,13 @@ const jsOnParse: (handlers: Record<PropertyKey, Function>, text: string) => any;
|
|
|
602
584
|
Objects having *exactly* one property which is present in the `handlers` map, i.e. objects of the form:
|
|
603
585
|
|
|
604
586
|
```js
|
|
605
|
-
{ "«
|
|
587
|
+
{ "«handler_name»": [«params»] }
|
|
606
588
|
```
|
|
607
589
|
|
|
608
590
|
are replaced by the result of call
|
|
609
591
|
|
|
610
592
|
```js
|
|
611
|
-
handlers['«
|
|
593
|
+
handlers['«handler_name»'](...«params»)
|
|
612
594
|
```
|
|
613
595
|
|
|
614
596
|
#### Usage Examples
|
|
@@ -619,7 +601,7 @@ const handlers = {
|
|
|
619
601
|
$foo: () => 'bar'
|
|
620
602
|
}
|
|
621
603
|
|
|
622
|
-
const actual =
|
|
604
|
+
const actual = js_on_parse(handlers, `[
|
|
623
605
|
{
|
|
624
606
|
"$hello": ["World"]
|
|
625
607
|
},
|
|
@@ -661,15 +643,15 @@ expect(actual).to.deep.equal(expected)
|
|
|
661
643
|
### nanolight
|
|
662
644
|
|
|
663
645
|
```ts
|
|
664
|
-
const nanolight: (pattern: RegExp, highlighters: ((chunk: string, index: number) =>
|
|
646
|
+
const nanolight: (pattern: RegExp, highlighters: ((chunk: string, index: number) => H_Args_1)[], code: string) => H_Args_1[];
|
|
665
647
|
```
|
|
666
648
|
|
|
667
|
-
A generic helper for syntax highlighting (see also `
|
|
649
|
+
A generic helper for syntax highlighting (see also `nanolight_js`).
|
|
668
650
|
|
|
669
|
-
###
|
|
651
|
+
### nanolight_js
|
|
670
652
|
|
|
671
653
|
```ts
|
|
672
|
-
const
|
|
654
|
+
const nanolight_js: (code: string) => H_Args_1[];
|
|
673
655
|
```
|
|
674
656
|
|
|
675
657
|
A helper for highlighting JavaScript (see also `nanolight`).
|
|
@@ -677,9 +659,9 @@ A helper for highlighting JavaScript (see also `nanolight`).
|
|
|
677
659
|
#### Usage Examples
|
|
678
660
|
|
|
679
661
|
```ts
|
|
680
|
-
const
|
|
662
|
+
const code_js = 'const answerToLifeTheUniverseAndEverything = 42'
|
|
681
663
|
|
|
682
|
-
expect(
|
|
664
|
+
expect(nanolight_js(code_js)).to.deep.equal([
|
|
683
665
|
['span', { class: 'keyword' }, 'const'],
|
|
684
666
|
' ',
|
|
685
667
|
['span', { class: 'literal' }, 'answerToLifeTheUniverseAndEverything'],
|
|
@@ -722,10 +704,10 @@ const obj = { a: 42, b: '42', c: 17 }
|
|
|
722
704
|
expect(pick(obj, ['a', 'b'])).to.deep.equal({ a: 42, b: '42' })
|
|
723
705
|
```
|
|
724
706
|
|
|
725
|
-
###
|
|
707
|
+
### pl_ural
|
|
726
708
|
|
|
727
709
|
```ts
|
|
728
|
-
const
|
|
710
|
+
const pl_ural: (singular: string, plural_2: string, plural_5: string, value: number) => string;
|
|
729
711
|
```
|
|
730
712
|
|
|
731
713
|
A helper for choosing the correct singular and plural.
|
|
@@ -733,14 +715,14 @@ A helper for choosing the correct singular and plural.
|
|
|
733
715
|
#### Usage Examples
|
|
734
716
|
|
|
735
717
|
```ts
|
|
736
|
-
const auto =
|
|
718
|
+
const auto = pl_ural.bind(null, 'auto', 'auta', 'aut')
|
|
737
719
|
|
|
738
720
|
expect(auto(0)).to.deep.equal('aut')
|
|
739
721
|
expect(auto(1)).to.deep.equal('auto')
|
|
740
722
|
expect(auto(17)).to.deep.equal('aut')
|
|
741
723
|
expect(auto(42)).to.deep.equal('auta')
|
|
742
724
|
|
|
743
|
-
const car =
|
|
725
|
+
const car = pl_ural.bind(null, 'car', 'cars', 'cars')
|
|
744
726
|
|
|
745
727
|
expect(car(0)).to.deep.equal('cars')
|
|
746
728
|
expect(car(1)).to.deep.equal('car')
|
|
@@ -790,9 +772,9 @@ expect(ref).to.deep.equal({ one: { two: { three: { four: 1234 } } } })
|
|
|
790
772
|
|
|
791
773
|
```ts
|
|
792
774
|
const s: {
|
|
793
|
-
<T extends keyof SVGElementTagNameMap>(tag: T, ...args1:
|
|
794
|
-
<N extends Node>(node: N, ...args1:
|
|
795
|
-
(
|
|
775
|
+
<T extends keyof SVGElementTagNameMap>(tag: T, ...args1: H_Args_1[]): SVGElementTagNameMap[T];
|
|
776
|
+
<N extends Node>(node: N, ...args1: H_Args_1[]): N;
|
|
777
|
+
(tag_or_node: string | Node, ...args1: H_Args_1[]): Node;
|
|
796
778
|
};
|
|
797
779
|
```
|
|
798
780
|
|
|
@@ -806,49 +788,24 @@ A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style help
|
|
|
806
788
|
- All other arguments of type `string`/`number` are converted to `Text` nodes and appended to the element being created or modified.
|
|
807
789
|
- All other arguments of type `HArgs` are passed to `s` and the results are appended to the element being created or modified.
|
|
808
790
|
|
|
809
|
-
###
|
|
791
|
+
### svg_use
|
|
810
792
|
|
|
811
793
|
```ts
|
|
812
|
-
const
|
|
794
|
+
const svg_use: (id: string, ...args: H_Args_1[]) => SVGSVGElement;
|
|
813
795
|
```
|
|
814
796
|
|
|
815
797
|
A convenient shortcut for `s('svg', ['use', { 'xlink:href': '#' + id }], ...args)`.
|
|
816
798
|
|
|
817
|
-
###
|
|
799
|
+
### uuid_v1
|
|
818
800
|
|
|
819
801
|
```ts
|
|
820
|
-
const
|
|
802
|
+
const uuid_v1: (date?: Date, node?: string) => string;
|
|
821
803
|
```
|
|
822
804
|
|
|
823
805
|
A helper that generates a UUID v1 identifier (with a creation timestamp).
|
|
824
806
|
|
|
825
807
|
- The optional `node` parameter should have the format `/^[0123456789abcdef]+$/`. Its value will be trimmed to last 12 characters and left padded with zeros.
|
|
826
808
|
|
|
827
|
-
#### Usage Examples
|
|
828
|
-
|
|
829
|
-
```ts
|
|
830
|
-
for (let i = 1; i <= 22136; ++i) {
|
|
831
|
-
const uuid = uuid1()
|
|
832
|
-
|
|
833
|
-
i === 1 && expect(uuid.split('-')[3]).to.deep.equal('8001')
|
|
834
|
-
i === 4095 && expect(uuid.split('-')[3]).to.deep.equal('8fff')
|
|
835
|
-
i === 4096 && expect(uuid.split('-')[3]).to.deep.equal('9000')
|
|
836
|
-
i === 9029 && expect(uuid.split('-')[3]).to.deep.equal('a345')
|
|
837
|
-
i === 13398 && expect(uuid.split('-')[3]).to.deep.equal('b456')
|
|
838
|
-
i === 16384 && expect(uuid.split('-')[3]).to.deep.equal('8000')
|
|
839
|
-
i === 17767 && expect(uuid.split('-')[3]).to.deep.equal('8567')
|
|
840
|
-
}
|
|
841
|
-
```
|
|
842
|
-
|
|
843
|
-
```ts
|
|
844
|
-
expect(uuid1(new Date(), '000123456789abc').split('-')[4]).to.deep.equal('123456789abc')
|
|
845
|
-
expect(uuid1(new Date(), '123456789').split('-')[4]).to.deep.equal('000123456789')
|
|
846
|
-
```
|
|
847
|
-
|
|
848
|
-
```ts
|
|
849
|
-
expect(uuid1(new Date(323325000000)).startsWith('c1399400-9a71-11bd')).to.be.true
|
|
850
|
-
```
|
|
851
|
-
|
|
852
809
|
## License
|
|
853
810
|
|
|
854
811
|
The MIT License (MIT)
|