@jackens/nnn 2026.2.26 → 2026.2.27

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 +3 -25
  2. package/nnn.js +1 -3
  3. package/package.json +1 -1
  4. package/readme.md +34 -52
package/nnn.d.ts CHANGED
@@ -253,40 +253,18 @@ export declare const monokai: CRoot;
253
253
  * An array of {@link HArgs1} elements suitable for rendering with {@link h}.
254
254
  */
255
255
  export declare const nanolightTs: (code: string) => HArgs1[];
256
- /**
257
- * A map from value constructors (or `null`/`undefined`) to escape functions.
258
- *
259
- * Used by {@link escapeValues} and {@link newEscape}.
260
- */
261
- export type EscapeMap = Map<unknown, (value?: unknown) => string>;
262
- /**
263
- * Escapes an array of values using the provided escape map.
264
- *
265
- * @param escapeMap
266
- *
267
- * A map where keys are constructors (e.g., `String`, `Number`) and values are escape functions.
268
- *
269
- * @param values
270
- *
271
- * The array of values to escape.
272
- *
273
- * @returns
274
- *
275
- * An array of escaped strings.
276
- */
277
- export declare const escapeValues: (escapeMap: EscapeMap, values: unknown[]) => string[];
278
256
  /**
279
257
  * Creates a tag function for escaping interpolated values in template literals.
280
258
  *
281
- * @param escapeMap
259
+ * @param escapeFn
282
260
  *
283
- * A map where keys are constructors and values are escape functions.
261
+ * A function that takes a value and returns its escaped string representation.
284
262
  *
285
263
  * @returns
286
264
  *
287
265
  * A tag function that escapes interpolated values using the provided escape map.
288
266
  */
289
- export declare const newEscape: (escapeMap: EscapeMap) => (template: TemplateStringsArray, ...values: unknown[]) => string;
267
+ export declare const newEscape: (escapeFn: (value: any) => string) => (template: TemplateStringsArray, ...values: unknown[]) => string;
290
268
  /**
291
269
  * Creates a function that returns the appropriate noun form based on a numeric value using `Intl.PluralRules`.
292
270
  *
package/nnn.js CHANGED
@@ -298,8 +298,7 @@ var PUNCTUATION = "punctuation";
298
298
  var STRING = "string";
299
299
  var nanolightTs = /* @__PURE__ */ newTokenizer((chunk, name) => name != null ? ["span", { class: name }, chunk] : chunk, [COMMENT, /\/\*.*?\*\//s], [COMMENT, /(?<!\\)\/\/.*?(?=\n)/], [STRING, /".*?"/], [STRING, /'.*?'/], [STRING, /`.*?`/s], [STRING, /\/[^\s]*[^\\]\/[dgimsuvy]*/], [NUMBER, /0b[01_]+/], [NUMBER, /0o[01234567_]+/], [NUMBER, /0x[\dabcdef_]+/], [NUMBER, /\d[\d_]*(\.[\d_]+)?(e[+-]?[\d_]+)?/], [OPERATOR, "!"], [OPERATOR, "!="], [OPERATOR, "!=="], [OPERATOR, "%"], [OPERATOR, "%="], [OPERATOR, "&&"], [OPERATOR, "&&="], [OPERATOR, "&"], [OPERATOR, "&="], [OPERATOR, "*"], [OPERATOR, "**"], [OPERATOR, "**="], [OPERATOR, "*="], [OPERATOR, "+"], [OPERATOR, "++"], [OPERATOR, "+="], [OPERATOR, "-"], [OPERATOR, "--"], [OPERATOR, "-="], [OPERATOR, "..."], [OPERATOR, "/"], [OPERATOR, "/="], [OPERATOR, ":"], [OPERATOR, "<"], [OPERATOR, "<<"], [OPERATOR, "<<="], [OPERATOR, "<="], [OPERATOR, "="], [OPERATOR, "=="], [OPERATOR, "==="], [OPERATOR, "=>"], [OPERATOR, ">"], [OPERATOR, ">="], [OPERATOR, ">>"], [OPERATOR, ">>="], [OPERATOR, ">>>"], [OPERATOR, ">>>="], [OPERATOR, "?"], [OPERATOR, "?"], [OPERATOR, "??"], [OPERATOR, "??="], [OPERATOR, "^"], [OPERATOR, "^="], [OPERATOR, "|"], [OPERATOR, "|="], [OPERATOR, "||"], [OPERATOR, "||="], [OPERATOR, "~"], [OPERATOR, "~="], [OPERATOR, /(?<=\s):/], [PUNCTUATION, "("], [PUNCTUATION, ")"], [PUNCTUATION, ","], [PUNCTUATION, "."], [PUNCTUATION, ":"], [PUNCTUATION, ";"], [PUNCTUATION, "?."], [PUNCTUATION, "["], [PUNCTUATION, "]"], [PUNCTUATION, "{"], [PUNCTUATION, "}"], [KEYWORD_1, "as"], [KEYWORD_1, "async"], [KEYWORD_1, "await"], [KEYWORD_1, "break"], [KEYWORD_1, "case"], [KEYWORD_1, "catch"], [KEYWORD_1, "class"], [KEYWORD_1, "const"], [KEYWORD_1, "continue"], [KEYWORD_1, "debugger"], [KEYWORD_1, "default"], [KEYWORD_1, "delete"], [KEYWORD_1, "do"], [KEYWORD_1, "else"], [KEYWORD_1, "export"], [KEYWORD_1, "extends"], [KEYWORD_1, "finally"], [KEYWORD_1, "for"], [KEYWORD_1, "from"], [KEYWORD_1, "function"], [KEYWORD_1, "function*"], [KEYWORD_1, "goto"], [KEYWORD_1, "if"], [KEYWORD_1, "import"], [KEYWORD_1, "in"], [KEYWORD_1, "instanceof"], [KEYWORD_1, "is"], [KEYWORD_1, "keyof"], [KEYWORD_1, "let"], [KEYWORD_1, "new"], [KEYWORD_1, "of"], [KEYWORD_1, "package"], [KEYWORD_1, "return"], [KEYWORD_1, "super"], [KEYWORD_1, "switch"], [KEYWORD_1, "this"], [KEYWORD_1, "throw"], [KEYWORD_1, "try"], [KEYWORD_1, "type"], [KEYWORD_1, "typeof"], [KEYWORD_1, "var"], [KEYWORD_1, "void"], [KEYWORD_1, "while"], [KEYWORD_1, "with"], [KEYWORD_1, "yield"], [KEYWORD_1, "yield*"], [KEYWORD_2, "false"], [KEYWORD_2, "Infinity"], [KEYWORD_2, "NaN"], [KEYWORD_2, "null"], [KEYWORD_2, "true"], [KEYWORD_2, "undefined"], [KEYWORD_3, "any"], [KEYWORD_3, "bigint"], [KEYWORD_3, "boolean"], [KEYWORD_3, "eval"], [KEYWORD_3, "number"], [KEYWORD_3, "string"], [KEYWORD_3, "symbol"], [KEYWORD_3, "unknown"], [IDENTIFIER_1, /[\p{Lu}_$][\p{Lu}\d_$]*/u], [IDENTIFIER_2, /[\p{L}_$][\p{L}\d_$]*(?=[(`])/u], [IDENTIFIER_3, /\p{Lu}[\p{L}\d_$]*/u], [IDENTIFIER_4, /[\p{L}_$][\p{L}\d_$]*/u]);
300
300
  // src/nnn/newEscape.ts
301
- var escapeValues = (escapeMap, values) => values.map((value) => (value == null ? escapeMap.get(value) : escapeMap.get(value?.constructor))?.(value) ?? "");
302
- var newEscape = (escapeMap) => (template, ...values) => String.raw(template, ...escapeValues(escapeMap, values));
301
+ var newEscape = (escapeFn) => (template, ...values) => String.raw(template, ...values.map(escapeFn));
303
302
  // src/nnn/newNounForm.ts
304
303
  var PLURAL_RULES = {};
305
304
  var newNounForm = (locale, forms) => (value) => forms[(PLURAL_RULES[locale] ??= new Intl.PluralRules(locale)).select(value)] ?? forms.other ?? "";
@@ -384,7 +383,6 @@ export {
384
383
  hasOwn,
385
384
  h,
386
385
  fixPlTypography,
387
- escapeValues,
388
386
  csvParse,
389
387
  c
390
388
  };
package/package.json CHANGED
@@ -44,5 +44,5 @@
44
44
  "name": "@jackens/nnn",
45
45
  "type": "module",
46
46
  "types": "nnn.d.ts",
47
- "version": "2026.2.26"
47
+ "version": "2026.2.27"
48
48
  }
package/readme.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # nnn
2
2
 
3
- A collection of Jackens’ JavaScript helper utilities (version: `2026.2.26`).
3
+ A collection of Jackens’ JavaScript helper utilities (version: `2026.2.27`).
4
4
 
5
5
  ## Installation
6
6
 
@@ -20,7 +20,6 @@ npm i @jackens/nnn
20
20
  import {
21
21
  c,
22
22
  csvParse,
23
- escapeValues,
24
23
  fixPlTypography,
25
24
  h,
26
25
  hasOwn,
@@ -50,12 +49,10 @@ import {
50
49
 
51
50
  - [`CNode`](#CNode): Represents a CSS rule node for the [`c`](#c) helper. Keys are CSS properties or nested selectors.
52
51
  - [`CRoot`](#CRoot): Represents the root CSS object for the [`c`](#c) helper. Keys are top-level selectors or at-rules.
53
- - [`EscapeMap`](#EscapeMap): A map from value constructors (or `null`/`undefined`) to escape functions.
54
52
  - [`HArgs`](#HArgs): Tuple argument type for the [`h`](#h) and [`s`](#s) helpers.
55
53
  - [`HArgs1`](#HArgs1): Single argument type for the [`h`](#h) and [`s`](#s) helpers.
56
54
  - [`c`](#c): A minimal CSS-in-JS helper that converts a JavaScript object hierarchy into a CSS string.
57
55
  - [`csvParse`](#csvParse): Parses a CSV string into a two-dimensional array of strings.
58
- - [`escapeValues`](#escapeValues): Escapes an array of values using the provided escape map.
59
56
  - [`fixPlTypography`](#fixPlTypography): Applies Polish-specific typographic corrections to a DOM subtree.
60
57
  - [`h`](#h): A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `HTMLElement`s (see also [`s`](#s)).
61
58
  - [`hasOwn`](#hasOwn): Checks whether an object has the specified key as its own property.
@@ -97,16 +94,6 @@ type CRoot = Record<PropertyKey, CNode>;
97
94
 
98
95
  Represents the root CSS object for the [`c`](#c) helper. Keys are top-level selectors or at-rules.
99
96
 
100
- ### EscapeMap
101
-
102
- ```ts
103
- type EscapeMap = Map<unknown, (value?: unknown) => string>;
104
- ```
105
-
106
- A map from value constructors (or `null`/`undefined`) to escape functions.
107
-
108
- Used by [`escapeValues`](#escapeValues) and [`newEscape`](#newEscape).
109
-
110
97
  ### HArgs
111
98
 
112
99
  ```ts
@@ -381,26 +368,6 @@ expect(csvParse(text)).to.deep.equal([
381
368
  ])
382
369
  ```
383
370
 
384
- ### escapeValues
385
-
386
- ```ts
387
- const escapeValues: (escapeMap: EscapeMap, values: unknown[]) => string[];
388
- ```
389
-
390
- Escapes an array of values using the provided escape map.
391
-
392
- #### escapeMap
393
-
394
- A map where keys are constructors (e.g., `String`, `Number`) and values are escape functions.
395
-
396
- #### values
397
-
398
- The array of values to escape.
399
-
400
- #### Returns
401
-
402
- An array of escaped strings.
403
-
404
371
  ### fixPlTypography
405
372
 
406
373
  ```ts
@@ -421,13 +388,18 @@ except those inside `IFRAME`, `NOSCRIPT`, `PRE`, `SCRIPT`, `STYLE`, or `TEXTAREA
421
388
  #### Usage Examples
422
389
 
423
390
  ```ts
424
- const p = h('p', 'Pchnąć w tę łódź jeża lub ośm skrzyń fig (zob. https://pl.wikipedia.org/wiki/Pangram).')
391
+ const p = h('p',
392
+ 'Pchnąć w tę łódź jeża lub ośm skrzyń fig (zob. https://pl.wikipedia.org/wiki/Pangram).',
393
+ ['br'],
394
+ ['b', 'Zażółć gęślą jaźń.']
395
+ )
425
396
 
426
397
  fixPlTypography(p)
427
398
 
428
399
  expect(p.innerHTML).to.deep.equal(
429
400
  'Pchnąć <span style="white-space:nowrap">w </span>tę łódź jeża lub ośm skrzyń fig ' +
430
- '(zob. https://\u200Bpl.\u200Bwikipedia.\u200Borg/\u200Bwiki/\u200BPangram).')
401
+ '(zob. https://\u200Bpl.\u200Bwikipedia.\u200Borg/\u200Bwiki/\u200BPangram).' +
402
+ '<br><b>Zażółć gęślą jaźń.</b>')
431
403
  ```
432
404
 
433
405
  ### h
@@ -869,14 +841,14 @@ expect(nanolightTs(codeJs)).to.deep.equal([
869
841
  ### newEscape
870
842
 
871
843
  ```ts
872
- const newEscape: (escapeMap: EscapeMap) => (template: TemplateStringsArray, ...values: unknown[]) => string;
844
+ const newEscape: (escapeFn: (value: any) => string) => (template: TemplateStringsArray, ...values: unknown[]) => string;
873
845
  ```
874
846
 
875
847
  Creates a tag function for escaping interpolated values in template literals.
876
848
 
877
- #### escapeMap
849
+ #### escapeFn
878
850
 
879
- A map where keys are constructors and values are escape functions.
851
+ A function that takes a value and returns its escaped string representation.
880
852
 
881
853
  #### Returns
882
854
 
@@ -885,27 +857,30 @@ A tag function that escapes interpolated values using the provided escape map.
885
857
  #### Usage Examples
886
858
 
887
859
  ```ts
888
- const escapeMap: EscapeMap = new Map([
889
- [null, () => 'NULL'],
890
- [undefined, () => 'NULL'],
891
- [Array, (values: unknown[]) => escapeValues(escapeMap, values).join(', ')],
892
- [Boolean, (value: boolean) => `b'${+value}'`],
893
- [Date, (value: Date) => `'${value.toISOString().replace(/^(.+)T(.+)\..*$/, '$1 $2')}'`],
894
- [Number, (value: number) => `${value}`],
895
- [String, (value: string) => `'${value.replace(/'/g, "''")}'`]
896
- ])
897
-
898
- const sql = newEscape(escapeMap)
860
+ const escapeFn = (value: any): string =>
861
+ isArray(value)
862
+ ? value.map(escapeFn).join(', ')
863
+ : value === true || value === false
864
+ ? `b'${+value}'`
865
+ : value instanceof Date
866
+ ? `'${value.toISOString().replace(/^(.+)T(.+)\..*$/, '$1 $2')}'`
867
+ : isFiniteNumber(value)
868
+ ? `${value}`
869
+ : isString(value)
870
+ ? `'${value.replace(/'/g, "''")}'`
871
+ : 'NULL'
872
+
873
+ const sql = newEscape(escapeFn)
899
874
 
900
875
  const actual = sql`
901
876
  SELECT *
902
877
  FROM table_name
903
- WHERE column_name IN (${[true, null, undefined, 42, '42', "4'2", new Date(323325000000)]})`
878
+ WHERE column_name IN (${[true, null, undefined, NaN, Infinity, 42, '42', "4'2", /42/, new Date(323325000000)]})`
904
879
 
905
880
  const expected = `
906
881
  SELECT *
907
882
  FROM table_name
908
- WHERE column_name IN (b'1', NULL, NULL, 42, '42', '4''2', '1980-03-31 04:30:00')`
883
+ WHERE column_name IN (b'1', NULL, NULL, NULL, NULL, 42, '42', '4''2', NULL, '1980-03-31 04:30:00')`
909
884
 
910
885
  expect(actual).to.equal(expected)
911
886
  ```
@@ -957,6 +932,13 @@ expect(car(0)).to.equal('cars')
957
932
  expect(car(1)).to.equal('car')
958
933
  expect(car(17)).to.equal('cars')
959
934
  expect(car(42)).to.equal('cars')
935
+
936
+ const empty = newNounForm('en', {})
937
+
938
+ expect(empty(0)).to.equal('')
939
+ expect(empty(1)).to.equal('')
940
+ expect(empty(17)).to.equal('')
941
+ expect(empty(42)).to.equal('')
960
942
  ```
961
943
 
962
944
  ### newTokenizer