@jackens/nnn 2025.2.2 → 2025.3.5

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 +16 -23
  2. package/nnn.js +22 -38
  3. package/package.json +1 -1
  4. package/readme.md +26 -118
package/nnn.d.ts CHANGED
@@ -105,19 +105,21 @@ export declare const svgUse: (id: string, ...args: Partial<Array<HArgs1>>) => SV
105
105
  */
106
106
  export declare const hasOwn: (ref: unknown, key: unknown) => boolean;
107
107
  /**
108
- * A helper that checks if the given argument is of a certain type.
109
- */
110
- export declare const is: {
111
- (type: ArrayConstructor, arg: unknown): arg is Partial<Array<unknown>>;
112
- (type: BigIntConstructor, arg: unknown): arg is bigint;
113
- (type: BooleanConstructor, arg: unknown): arg is boolean;
114
- (type: NumberConstructor, arg: unknown): arg is number;
115
- (type: ObjectConstructor, arg: unknown): arg is Partial<Record<PropertyKey, unknown>>;
116
- (type: StringConstructor, arg: unknown): arg is string;
117
- (type: SymbolConstructor, arg: unknown): arg is symbol;
118
- (type: undefined, arg: unknown): arg is undefined | null;
119
- <T extends abstract new (...args: Partial<Array<any>>) => unknown>(type: T, arg: unknown): arg is InstanceType<T>;
120
- };
108
+ * A helper that checks if the given argument is of type `any[]`.
109
+ */
110
+ export declare const isArray: (arg: any) => arg is any[];
111
+ /**
112
+ * A helper that checks if the given argument is of type `number`.
113
+ */
114
+ export declare const isNumber: (arg: any) => arg is number;
115
+ /**
116
+ * A helper that checks if the given argument is of type `Partial<Record<PropertyKey, unknown>>`.
117
+ */
118
+ export declare const isRecord: (arg: any) => arg is Partial<Record<PropertyKey, unknown>>;
119
+ /**
120
+ * A helper that checks if the given argument is of type `string`.
121
+ */
122
+ export declare const isString: (arg: any) => arg is string;
121
123
  /**
122
124
  * `JSON.parse` with “JavaScript turned on”.
123
125
  *
@@ -163,18 +165,9 @@ export declare const plUral: (singular: string, plural2: string, plural5: string
163
165
  * object.
164
166
  */
165
167
  export declare const pro: (ref: unknown) => any;
166
- /**
167
- * A helper that provides information about the given `refs`.
168
- *
169
- * It returns an array of triples: `[«name», «prototype-name», «array-of-own-property-names»]`.
170
- */
171
- export declare const refsInfo: (...refs: Partial<Array<unknown>>) => Partial<Array<[string, string, Partial<Array<string>>]>>;
172
168
  /**
173
169
  * A helper that generates a UUID v1 identifier (with a creation timestamp).
174
170
  *
175
171
  * - The optional `node` parameter should have the format `/^[0123456789abcdef]+$/`. Its value will be trimmed to last 12 characters and left padded with zeros.
176
172
  */
177
- export declare const uuid1: ({ date, node }?: {
178
- date?: Date | undefined;
179
- node?: string | undefined;
180
- }) => string;
173
+ export declare const uuid1: (date?: Date, node?: string) => string;
package/nnn.js CHANGED
@@ -1,5 +1,8 @@
1
1
  // src/nnn/is.ts
2
- var is = (type, arg) => arg?.constructor === type;
2
+ var isArray = Array.isArray;
3
+ var isNumber = (arg) => typeof arg === "number";
4
+ var isRecord = (arg) => typeof arg === "object" && arg != null && !isArray(arg);
5
+ var isString = (arg) => typeof arg === "string";
3
6
 
4
7
  // src/nnn/c.ts
5
8
  var _c = (node, prefix, result, split) => {
@@ -9,7 +12,7 @@ var _c = (node, prefix, result, split) => {
9
12
  if (style0 == null || prefix0 == null) {
10
13
  continue;
11
14
  }
12
- if (is(Array, style0)) {
15
+ if (isArray(style0)) {
13
16
  result.push(prefix0, prefix0 !== "" ? "{" : "", style0.join(";"), prefix0 !== "" ? "}" : "");
14
17
  } else {
15
18
  const todo = [];
@@ -17,7 +20,7 @@ var _c = (node, prefix, result, split) => {
17
20
  let attributesPushed = false;
18
21
  for (const key in style0) {
19
22
  const value = style0[key];
20
- if (is(String, value) || is(Number, value)) {
23
+ if (isString(value) || isNumber(value)) {
21
24
  if (!attributesPushed) {
22
25
  attributesPushed = true;
23
26
  attributes = [];
@@ -77,21 +80,19 @@ var NS = {
77
80
  var _h = (namespaceURI) => {
78
81
  const createElement = namespaceURI == null ? (tag) => document.createElement(tag) : (tag) => document.createElementNS(namespaceURI, tag);
79
82
  const h = (tagOrNode, ...args) => {
80
- const node = is(String, tagOrNode) ? createElement(tagOrNode) : tagOrNode;
83
+ const node = isString(tagOrNode) ? createElement(tagOrNode) : tagOrNode;
81
84
  args.forEach((arg) => {
82
85
  let child = null;
83
86
  if (arg instanceof Node) {
84
87
  child = arg;
85
- } else if (is(String, arg) || is(Number, arg)) {
86
- child = document.createTextNode(arg);
87
- } else if (is(Array, arg)) {
88
+ } else if (isArray(arg)) {
88
89
  child = h(...arg);
89
- } else if (arg != null) {
90
+ } else if (isRecord(arg)) {
90
91
  for (const name in arg) {
91
92
  const value = arg[name];
92
93
  if (name[0] === "$") {
93
94
  const name1 = name.slice(1);
94
- if (is(Object, value)) {
95
+ if (isRecord(value)) {
95
96
  node[name1] = node[name1] ?? {};
96
97
  Object.assign(node[name1], value);
97
98
  } else {
@@ -108,7 +109,7 @@ var _h = (namespaceURI) => {
108
109
  } else if (value === false) {
109
110
  node.removeAttributeNS(ns, basename);
110
111
  } else {
111
- node.setAttributeNS(ns, basename, is(String, value) ? value : "" + value);
112
+ node.setAttributeNS(ns, basename, value);
112
113
  }
113
114
  }
114
115
  } else {
@@ -117,11 +118,13 @@ var _h = (namespaceURI) => {
117
118
  } else if (value === false) {
118
119
  node.removeAttribute(name);
119
120
  } else {
120
- node.setAttribute(name, is(String, value) ? value : "" + value);
121
+ node.setAttribute(name, "" + value);
121
122
  }
122
123
  }
123
124
  }
124
125
  }
126
+ } else if (arg != null) {
127
+ child = document.createTextNode(arg);
125
128
  }
126
129
  if (child != null) {
127
130
  node.appendChild(child);
@@ -170,7 +173,7 @@ var fixTypography = (node) => {
170
173
  var hasOwn = (ref, key) => ref != null && Object.hasOwn(ref, key);
171
174
  // src/nnn/jsOnParse.ts
172
175
  var jsOnParse = (handlers, text) => JSON.parse(text, (key, value) => {
173
- if (is(Object, value)) {
176
+ if (isRecord(value)) {
174
177
  let isSecondKey = false;
175
178
  for (key in value) {
176
179
  if (isSecondKey) {
@@ -180,7 +183,7 @@ var jsOnParse = (handlers, text) => JSON.parse(text, (key, value) => {
180
183
  }
181
184
  const handler = handlers[key];
182
185
  const params = value[key];
183
- if (handler instanceof Function && is(Array, params)) {
186
+ if (handler instanceof Function && isArray(params)) {
184
187
  return handler(...params);
185
188
  }
186
189
  }
@@ -190,7 +193,7 @@ var jsOnParse = (handlers, text) => JSON.parse(text, (key, value) => {
190
193
  var locale = (map, defaultVersion) => (text, version = defaultVersion) => {
191
194
  const textV = map?.[version]?.[text];
192
195
  const textD = map?.[defaultVersion]?.[text];
193
- return is(String, textV) ? textV : is(String, textD) ? textD : text;
196
+ return isString(textV) ? textV : isString(textD) ? textD : text;
194
197
  };
195
198
  // src/nnn/nanolight.ts
196
199
  var nanolight = (pattern, highlighters, code) => {
@@ -229,31 +232,10 @@ var pro = (ref) => new Proxy(ref, {
229
232
  return pro(target[key] = target[key] ?? {});
230
233
  }
231
234
  });
232
- // src/nnn/refsInfo.ts
233
- var refsInfo = (...refs) => {
234
- const fns = new Set;
235
- refs.forEach((ref) => {
236
- try {
237
- while (ref instanceof Function && !fns.has(ref) && `${ref}`.match(/function\s+\w+[\s\S]+\[native code\]/)) {
238
- fns.add(ref);
239
- ref = Object.getPrototypeOf(ref);
240
- }
241
- } catch {
242
- }
243
- });
244
- return Array.from(fns.values()).map((fn) => [
245
- fn.name,
246
- Object.getPrototypeOf(fn)?.name ?? "",
247
- Object.getOwnPropertyNames(fn.prototype ?? Object.create(null)).sort()
248
- ]).sort((a, b) => -(a[0] < b[0]));
249
- };
250
235
  // src/nnn/uuid1.ts
251
236
  var ZEROS = "0".repeat(16);
252
237
  var counter = 0;
253
- var uuid1 = ({
254
- date = new Date,
255
- node = Math.random().toString(16).slice(2)
256
- } = {}) => {
238
+ var uuid1 = (date = new Date, node = Math.random().toString(16).slice(2)) => {
257
239
  const time = ZEROS + (1e4 * (+date + 12219292800000)).toString(16);
258
240
  counter = counter + 1 & 16383;
259
241
  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));
@@ -262,7 +244,6 @@ export {
262
244
  uuid1,
263
245
  svgUse,
264
246
  s,
265
- refsInfo,
266
247
  pro,
267
248
  plUral,
268
249
  pick,
@@ -271,7 +252,10 @@ export {
271
252
  nanolight,
272
253
  locale,
273
254
  jsOnParse,
274
- is,
255
+ isString,
256
+ isRecord,
257
+ isNumber,
258
+ isArray,
275
259
  hasOwn,
276
260
  h,
277
261
  fixTypography,
package/package.json CHANGED
@@ -36,5 +36,5 @@
36
36
  "name": "@jackens/nnn",
37
37
  "type": "module",
38
38
  "types": "nnn.d.ts",
39
- "version": "2025.2.2"
39
+ "version": "2025.3.5"
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">2025.2.2</code></sub>
5
+ <sub>Version: <code class="version">2025.3.5</code></sub>
6
6
 
7
7
  * [Documentation](https://jackens.github.io/nnn/doc/)
8
8
  * [Tests](https://jackens.github.io/nnn/test/)
@@ -37,7 +37,7 @@ import { «something» } from './node_modules/@jackens/nnn/nnn.js'
37
37
  or
38
38
 
39
39
  ```js
40
- import { «something» } from 'https://unpkg.com/@jackens/nnn@2025.2.2/nnn.js'
40
+ import { «something» } from 'https://unpkg.com/@jackens/nnn@2025.3.5/nnn.js'
41
41
  ```
42
42
 
43
43
  ## Exports
@@ -54,7 +54,10 @@ import { «something» } from 'https://unpkg.com/@jackens/nnn@2025.2.2/nnn.js'
54
54
  - `fixTypography`: A helper that implements typographic corrections specific to Polish typography.
55
55
  - `h`: A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `HTMLElement`s (see also `s`).
56
56
  - `hasOwn`: A replacement for the `in` operator (not to be confused with the `for-in` loop) that works properly.
57
- - `is`: A helper that checks if the given argument is of a certain type.
57
+ - `isArray`: A helper that checks if the given argument is of type `any[]`.
58
+ - `isNumber`: A helper that checks if the given argument is of type `number`.
59
+ - `isRecord`: A helper that checks if the given argument is of type `Partial<Record<PropertyKey, unknown>>`.
60
+ - `isString`: A helper that checks if the given argument is of type `string`.
58
61
  - `jsOnParse`: `JSON.parse` with “JavaScript turned on”.
59
62
  - `locale`: Language translations helper.
60
63
  - `nanolight`: A generic helper for syntax highlighting (see also `nanolightJs`).
@@ -63,7 +66,6 @@ import { «something» } from 'https://unpkg.com/@jackens/nnn@2025.2.2/nnn.js'
63
66
  - `pick`: A helper that implements TypeScript’s `Pick` utility type (see also `omit`).
64
67
  - `plUral`: A helper for choosing the correct singular and plural.
65
68
  - `pro`: A helper that protects calls to nested properties by a `Proxy` that initializes non-existent values with an empty
66
- - `refsInfo`: A helper that provides information about the given `refs`.
67
69
  - `s`: A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `SVGElement`s (see also `h`).
68
70
  - `svgUse`: A convenient shortcut for `s('svg', ['use', { 'xlink:href': '#' + id }], ...args)`.
69
71
  - `uuid1`: A helper that generates a UUID v1 identifier (with a creation timestamp).
@@ -566,86 +568,38 @@ expect(() => 'key' in undefined).to.throw
566
568
  expect(hasOwn(undefined, 'key')).to.be.false
567
569
  ```
568
570
 
569
- ### is
571
+ ### isArray
570
572
 
571
573
  ```ts
572
- const is: {
573
- (type: ArrayConstructor, arg: unknown): arg is Partial<Array<unknown>>;
574
- (type: BigIntConstructor, arg: unknown): arg is bigint;
575
- (type: BooleanConstructor, arg: unknown): arg is boolean;
576
- (type: NumberConstructor, arg: unknown): arg is number;
577
- (type: ObjectConstructor, arg: unknown): arg is Partial<Record<PropertyKey, unknown>>;
578
- (type: StringConstructor, arg: unknown): arg is string;
579
- (type: SymbolConstructor, arg: unknown): arg is symbol;
580
- (type: undefined, arg: unknown): arg is undefined | null;
581
- <T extends abstract new (...args: Partial<Array<any>>) => unknown>(type: T, arg: unknown): arg is InstanceType<T>;
582
- };
574
+ const isArray: (arg: any) => arg is any[];
583
575
  ```
584
576
 
585
- A helper that checks if the given argument is of a certain type.
577
+ A helper that checks if the given argument is of type `any[]`.
586
578
 
587
- #### Usage Examples
579
+ ### isNumber
588
580
 
589
- ```js
590
- expect(is(Number, 42)).to.be.true
591
- expect(is(Number, Number(42))).to.be.true
592
- expect(is(Number, new Number(42))).to.be.true
593
- expect(is(Number, NaN)).to.be.true
594
-
595
- expect(is(String, '42')).to.be.true
596
- expect(is(String, String('42'))).to.be.true
597
- expect(is(String, new String('42'))).to.be.true
598
-
599
- expect(is(Symbol, Symbol('42'))).to.be.true
600
- expect(is(Symbol, Object(Symbol('42')))).to.be.true
601
-
602
- expect(is(undefined, undefined)).to.be.true
603
- expect(is(undefined, null)).to.be.true
604
-
605
- expect(is(Object, {})).to.be.true
606
- expect(is(Array, [])).to.be.true
607
- expect(is(RegExp, /42/)).to.be.true
608
- expect(is(Date, new Date(42))).to.be.true
609
- expect(is(Set, new Set(['42', 42]))).to.be.true
610
- expect(is(Map, new Map([[{ j: 42 }, { J: '42' }], [{ c: 42 }, { C: '42' }]]))).to.be.true
581
+ ```ts
582
+ const isNumber: (arg: any) => arg is number;
611
583
  ```
612
584
 
613
- ```js
614
- const iz = (/** @type {unknown} */ type, /** @type {unknown} */ arg) =>
615
- ({}).toString.call(arg).slice(8, -1) === type?.name
616
-
617
- class FooBar { }
618
-
619
- expect(is(FooBar, new FooBar())).to.be.true
620
- expect(iz(FooBar, new FooBar())).to.be.false
621
-
622
- expect(is(Object, new FooBar())).to.be.false
623
- expect(iz(Object, new FooBar())).to.be.true
624
-
625
- const fakeFooBar = {}
585
+ A helper that checks if the given argument is of type `number`.
626
586
 
627
- fakeFooBar[Symbol.toStringTag] = FooBar.name
587
+ ### isRecord
628
588
 
629
- expect(is(FooBar, fakeFooBar)).to.be.false
630
- expect(iz(FooBar, fakeFooBar)).to.be.true
631
-
632
- expect(is(Object, fakeFooBar)).to.be.true
633
- expect(iz(Object, fakeFooBar)).to.be.false
589
+ ```ts
590
+ const isRecord: (arg: any) => arg is Partial<Record<PropertyKey, unknown>>;
634
591
  ```
635
592
 
636
- ```js
637
- const num = 42
638
- const str = '42'
593
+ A helper that checks if the given argument is of type `Partial<Record<PropertyKey, unknown>>`.
639
594
 
640
- expect(is(Number, num)).to.be.true
595
+ ### isString
641
596
 
642
- try {
643
- num.constructor = str.constructor
644
- } catch { /* empty */ }
645
-
646
- expect(is(Number, num)).to.be.true
597
+ ```ts
598
+ const isString: (arg: any) => arg is string;
647
599
  ```
648
600
 
601
+ A helper that checks if the given argument is of type `string`.
602
+
649
603
  ### jsOnParse
650
604
 
651
605
  ```ts
@@ -872,49 +826,6 @@ pro(ref).one.two.three.four = 1234
872
826
  expect(ref).to.deep.equal({ one: { two: { three: { four: 1234 } } } })
873
827
  ```
874
828
 
875
- ### refsInfo
876
-
877
- ```ts
878
- const refsInfo: (...refs: Partial<Array<unknown>>) => Partial<Array<[string, string, Partial<Array<string>>]>>;
879
- ```
880
-
881
- A helper that provides information about the given `refs`.
882
-
883
- It returns an array of triples: `[«name», «prototype-name», «array-of-own-property-names»]`.
884
-
885
- #### Usage Examples
886
-
887
- ```js
888
- const info = refsInfo(Array, Function)
889
-
890
- expect(info.find(item => item?.[0] === 'Array')?.[2]?.includes('length')).to.be.true
891
- expect(info.find(item => item?.[0] === 'Function')?.[2]?.includes('length')).to.be.true
892
- ```
893
-
894
- ```js
895
- const browserFingerprint = () => {
896
- const refs = Object.getOwnPropertyNames(window).map(name => window[name])
897
- const info = refsInfo(...refs)
898
- const json = JSON.stringify(info)
899
- const hash = Array(32).fill(0)
900
- let j = 0
901
-
902
- for (let i = 0; i < json.length; i++) {
903
- let charCode = json.charCodeAt(i)
904
-
905
- while (charCode > 0) {
906
- hash[j] = hash[j] ^ (charCode & 15)
907
- charCode >>= 4
908
- j = (j + 1) & 31
909
- }
910
- }
911
-
912
- return hash.map(x => x.toString(16)).join('')
913
- }
914
-
915
- console.log(browserFingerprint())
916
- ```
917
-
918
829
  ### s
919
830
 
920
831
  ```ts
@@ -946,10 +857,7 @@ A convenient shortcut for `s('svg', ['use', { 'xlink:href': '#' + id }], ...args
946
857
  ### uuid1
947
858
 
948
859
  ```ts
949
- const uuid1: ({ date, node }?: {
950
- date?: Date | undefined;
951
- node?: string | undefined;
952
- }) => string;
860
+ const uuid1: (date?: Date, node?: string) => string;
953
861
  ```
954
862
 
955
863
  A helper that generates a UUID v1 identifier (with a creation timestamp).
@@ -973,12 +881,12 @@ for (let i = 1; i <= 22136; ++i) {
973
881
  ```
974
882
 
975
883
  ```js
976
- expect(uuid1({ node: '000123456789abc' }).split('-')[4]).to.deep.equal('123456789abc')
977
- expect(uuid1({ node: '123456789' }).split('-')[4]).to.deep.equal('000123456789')
884
+ expect(uuid1(new Date(), '000123456789abc').split('-')[4]).to.deep.equal('123456789abc')
885
+ expect(uuid1(new Date(), '123456789').split('-')[4]).to.deep.equal('000123456789')
978
886
  ```
979
887
 
980
888
  ```js
981
- expect(uuid1({ date: new Date(323325000000) }).startsWith('c1399400-9a71-11bd')).to.be.true
889
+ expect(uuid1(new Date(323325000000)).startsWith('c1399400-9a71-11bd')).to.be.true
982
890
  ```
983
891
 
984
892
  ## Why Partial\<Array\> and Partial\<Record\>