@jackens/nnn 2024.4.5 → 2024.4.14

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 +14 -2
  2. package/nnn.js +16 -1
  3. package/package.json +3 -5
  4. package/readme.md +125 -5
package/nnn.d.ts CHANGED
@@ -1,3 +1,15 @@
1
+ /**
2
+ * A tiny helper for CSV parsing.
3
+ *
4
+ * Options:
5
+ * - `header`: flag indicating that the parsed CSV has a header row (default: `true`)
6
+ * - `separator`: field separator (default: `','`)
7
+ */
8
+ export declare const csvParse: (text: string, { header, separator }?: {
9
+ header?: boolean | undefined;
10
+ separator?: string | undefined;
11
+ }) => Partial<Array<Partial<Record<PropertyKey, string>>>> | Partial<Array<Partial<Array<string>>>>;
12
+
1
13
  /**
2
14
  * The type of arguments of the `escapeValues` and `escape` helpers.
3
15
  */
@@ -145,7 +157,7 @@ export declare const locale: (map: Partial<Record<PropertyKey, Partial<Record<Pr
145
157
  /**
146
158
  * A generic helper for syntax highlighting (see also `nanolightJs`).
147
159
  */
148
- export declare const nanolight: (pattern: RegExp, highlighters: ((chunk: string, index: number) => HArgs1)[], code: string) => HArgs1[];
160
+ export declare const nanolight: (pattern: RegExp, highlighters: Partial<Array<(chunk: string, index: number) => HArgs1>>, code: string) => HArgs1[];
149
161
 
150
162
  /**
151
163
  * A helper for highlighting JavaScript.
@@ -177,7 +189,7 @@ export declare const pro: (ref: unknown) => any;
177
189
  *
178
190
  * It returns an array of triples: `[«name», «prototype-name», «array-of-own-property-names»]`.
179
191
  */
180
- export declare const refsInfo: (...refs: Partial<Array<unknown>>) => [string, string, (string | undefined)[]][];
192
+ export declare const refsInfo: (...refs: Partial<Array<unknown>>) => Partial<Array<[string, string, Partial<Array<string>>]>>;
181
193
 
182
194
  /**
183
195
  * A helper that generates a UUID v1 identifier (with a creation timestamp).
package/nnn.js CHANGED
@@ -1,3 +1,17 @@
1
+ // src/nnn/csvParse.ts
2
+ var csvParse = (text, { header = true, separator = "," } = {}) => {
3
+ const regExp = new RegExp(`${separator}|(?<!")\\s*"((?:[^"]|"")*)"\\s*(?!")`, "g");
4
+ const rows = text.replace(/\r/g, "").replace(/\n+$/, "").replace(/\n|(?<!")("(?:[^"]|"")*")(?!")/g, (_, chunk) => chunk ?? "\r").split("\r").map((line) => line.replace(regExp, (_, chunk) => chunk == null ? "\r" : chunk.replace(/""/g, '"')).split("\r"));
5
+ if (header) {
6
+ const keys = rows.shift();
7
+ return rows.map((row) => keys.reduce((record, key, index) => {
8
+ record[key] = row[index];
9
+ return record;
10
+ }, {}));
11
+ }
12
+ return rows;
13
+ };
14
+
1
15
  // src/nnn/escape.ts
2
16
  var escapeValues = (escapeMap, values) => values.map((value) => (escapeMap.get(value?.constructor) ?? escapeMap.get(undefined))?.(value) ?? "");
3
17
  var escape = (escapeMap, template, ...values) => String.raw(template, ...escapeValues(escapeMap, values));
@@ -272,5 +286,6 @@ export {
272
286
  h,
273
287
  fixTypography,
274
288
  escapeValues,
275
- escape
289
+ escape,
290
+ csvParse
276
291
  };
package/package.json CHANGED
@@ -4,13 +4,11 @@
4
4
  "homepage": "https://jackens.github.io/nnn/doc/",
5
5
  "keywords": [
6
6
  "CSS-in-JS",
7
- "deepEqual",
7
+ "CSV",
8
+ "csvParse",
8
9
  "DOM",
9
- "eq",
10
- "equal",
11
10
  "escape",
12
11
  "Gantt",
13
- "graph",
14
12
  "h",
15
13
  "has",
16
14
  "highlight",
@@ -40,5 +38,5 @@
40
38
  "types": "nnn.d.ts",
41
39
  "name": "@jackens/nnn",
42
40
  "type": "module",
43
- "version": "2024.4.5"
41
+ "version": "2024.4.14"
44
42
  }
package/readme.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Jackens’ JavaScript helpers.
4
4
 
5
- <sub>Version: <code class="version">2024.4.5</code></sub>
5
+ <sub>Version: <code class="version">2024.4.14</code></sub>
6
6
 
7
7
  ## Examples
8
8
 
@@ -44,6 +44,7 @@ import { «something» } from './node_modules/@jackens/nnn/nnn.js'
44
44
  - `HArgs1`: The type of arguments of the `h` and `s` helpers.
45
45
  - `JcNode`: The type of arguments of the `jc` helper.
46
46
  - `JcRoot`: The type of arguments of the `jc` helper.
47
+ - `csvParse`: A tiny helper for CSV parsing.
47
48
  - `escape`: A generic helper for escaping `values` by given `escapeMap` (in *TemplateStrings* flavor).
48
49
  - `escapeValues`: A generic helper for escaping `values` by given `escapeMap`.
49
50
  - `fixTypography`: A helper that implements typographic corrections specific to Polish typography.
@@ -86,6 +87,8 @@ The type of arguments of the `h` and `s` helpers.
86
87
  type HArgs1 = Partial<Record<PropertyKey, unknown>> | null | undefined | Node | string | number | HArgs;
87
88
  ```
88
89
 
90
+ > See [here](https://jackens.github.io/nnn/doc/#Why-Partial-Array-and-Partial-Record) for an explanation of why `Partial<Record>` instead of `Record`.
91
+
89
92
  The type of arguments of the `h` and `s` helpers.
90
93
 
91
94
  ### JcNode
@@ -104,14 +107,63 @@ The type of arguments of the `jc` helper.
104
107
  type JcRoot = Partial<Record<PropertyKey, JcNode>>;
105
108
  ```
106
109
 
110
+ > See [here](https://jackens.github.io/nnn/doc/#Why-Partial-Array-and-Partial-Record) for an explanation of why `Partial<Record>` instead of `Record`.
111
+
107
112
  The type of arguments of the `jc` helper.
108
113
 
114
+ ### csvParse
115
+
116
+ ```ts
117
+ const csvParse: (text: string, { header, separator }?: {
118
+ header?: boolean | undefined;
119
+ separator?: string | undefined;
120
+ }) => Partial<Array<Partial<Record<PropertyKey, string>>>> | Partial<Array<Partial<Array<string>>>>;
121
+ ```
122
+
123
+ > See [here](https://jackens.github.io/nnn/doc/#Why-Partial-Array-and-Partial-Record) for an explanation of why `Partial<Array>`/`Partial<Record>` instead of `Array`/`Record`.
124
+
125
+ A tiny helper for CSV parsing.
126
+
127
+ Options:
128
+ - `header`: flag indicating that the parsed CSV has a header row (default: `true`)
129
+ - `separator`: field separator (default: `','`)
130
+
131
+ #### Usage Examples
132
+
133
+ ```js
134
+ const text = `"aaa
135
+ ""aaa""
136
+ aaa",bbb, "ccc,ccc"
137
+ "xxx,xxx", "yyy
138
+ yyy",zzz
139
+ 42 , "42" , 17
140
+
141
+ `
142
+ expect(csvParse(text, { header: false })).toStrictEqual([
143
+ ['aaa\n"aaa"\naaa', 'bbb', 'ccc,ccc'],
144
+ ['xxx,xxx', 'yyy\nyyy', 'zzz'],
145
+ [' 42 ', '42', ' 17']
146
+ ])
147
+
148
+ expect(csvParse(text)).toStrictEqual([{
149
+ 'aaa\n"aaa"\naaa': 'xxx,xxx',
150
+ bbb: 'yyy\nyyy',
151
+ 'ccc,ccc': 'zzz'
152
+ }, {
153
+ 'aaa\n"aaa"\naaa': ' 42 ',
154
+ bbb: '42',
155
+ 'ccc,ccc': ' 17'
156
+ }])
157
+ ```
158
+
109
159
  ### escape
110
160
 
111
161
  ```ts
112
162
  const escape: (escapeMap: EscapeMap, template: TemplateStringsArray, ...values: Partial<Array<unknown>>) => string;
113
163
  ```
114
164
 
165
+ > See [here](https://jackens.github.io/nnn/doc/#Why-Partial-Array-and-Partial-Record) for an explanation of why `Partial<Array>` instead of `Array`.
166
+
115
167
  A generic helper for escaping `values` by given `escapeMap` (in *TemplateStrings* flavor).
116
168
 
117
169
  #### Usage Examples
@@ -147,6 +199,8 @@ expect(actual).toStrictEqual(expected)
147
199
  const escapeValues: (escapeMap: EscapeMap, values: Partial<Array<unknown>>) => Partial<Array<string>>;
148
200
  ```
149
201
 
202
+ > See [here](https://jackens.github.io/nnn/doc/#Why-Partial-Array-and-Partial-Record) for an explanation of why `Partial<Array>` instead of `Array`.
203
+
150
204
  A generic helper for escaping `values` by given `escapeMap`.
151
205
 
152
206
  ### fixTypography
@@ -179,6 +233,8 @@ const h: {
179
233
  };
180
234
  ```
181
235
 
236
+ > See [here](https://jackens.github.io/nnn/doc/#Why-Partial-Array-and-Partial-Record) for an explanation of why `Partial<Array>` instead of `Array`.
237
+
182
238
  A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `HTMLElement`s (see also `s`).
183
239
 
184
240
  - The first argument of type `string` specifies the tag of the element to be created.
@@ -316,6 +372,8 @@ const is: {
316
372
  };
317
373
  ```
318
374
 
375
+ > See [here](https://jackens.github.io/nnn/doc/#Why-Partial-Array-and-Partial-Record) for an explanation of why `Partial<Array>`/`Partial<Record>` instead of `Array`/`Record`.
376
+
319
377
  A helper that checks if the given argument is of a certain type.
320
378
 
321
379
  #### Usage Examples
@@ -593,6 +651,8 @@ expect(actual).toStrictEqual(expected)
593
651
  const jsOnParse: (handlers: Partial<Record<PropertyKey, Function>>, text: string) => any;
594
652
  ```
595
653
 
654
+ > See [here](https://jackens.github.io/nnn/doc/#Why-Partial-Array-and-Partial-Record) for an explanation of why `Partial<Record>` instead of `Record`.
655
+
596
656
  `JSON.parse` with “JavaScript turned on”.
597
657
 
598
658
  Objects having *exactly* one property which is present in the `handlers` map, i.e. objects of the form:
@@ -660,6 +720,8 @@ expect(actual).toStrictEqual(expected)
660
720
  const locale: (map: Partial<Record<PropertyKey, Partial<Record<PropertyKey, string>>>>, defaultVersion: string) => (text: string, version?: string) => string;
661
721
  ```
662
722
 
723
+ > See [here](https://jackens.github.io/nnn/doc/#Why-Partial-Array-and-Partial-Record) for an explanation of why `Partial<Record>` instead of `Record`.
724
+
663
725
  Language translations helper.
664
726
 
665
727
  #### Usage Examples
@@ -687,9 +749,11 @@ expect(_('toString', 'undefined_version')).toStrictEqual('toString')
687
749
  ### nanolight
688
750
 
689
751
  ```ts
690
- const nanolight: (pattern: RegExp, highlighters: ((chunk: string, index: number) => HArgs1)[], code: string) => HArgs1[];
752
+ const nanolight: (pattern: RegExp, highlighters: Partial<Array<(chunk: string, index: number) => HArgs1>>, code: string) => HArgs1[];
691
753
  ```
692
754
 
755
+ > See [here](https://jackens.github.io/nnn/doc/#Why-Partial-Array-and-Partial-Record) for an explanation of why `Partial<Array>` instead of `Array`.
756
+
693
757
  A generic helper for syntax highlighting (see also `nanolightJs`).
694
758
 
695
759
  ### nanolightJs
@@ -722,6 +786,8 @@ expect(nanolightJs(codeJs)).toStrictEqual([
722
786
  const omit: <T extends Partial<Record<PropertyKey, unknown>>, K extends (keyof T)[]>(obj: Partial<Record<PropertyKey, unknown>>, keys: Partial<Array<unknown>>) => Omit<T, K[number]>;
723
787
  ```
724
788
 
789
+ > See [here](https://jackens.github.io/nnn/doc/#Why-Partial-Array-and-Partial-Record) for an explanation of why `Partial<Array>`/`Partial<Record>` instead of `Array`/`Record`.
790
+
725
791
  A helper that implements TypeScript’s `Omit` utility type.
726
792
 
727
793
  #### Usage Examples
@@ -738,6 +804,8 @@ expect(omit(obj, ['c'])).toStrictEqual({ a: 42, b: '42' })
738
804
  const pick: <T extends Partial<Record<PropertyKey, unknown>>, K extends (keyof T)[]>(obj: Partial<Record<PropertyKey, unknown>>, keys: Partial<Array<unknown>>) => Pick<T, K[number]>;
739
805
  ```
740
806
 
807
+ > See [here](https://jackens.github.io/nnn/doc/#Why-Partial-Array-and-Partial-Record) for an explanation of why `Partial<Array>`/`Partial<Record>` instead of `Array`/`Record`.
808
+
741
809
  A helper that implements TypeScript’s `Pick` utility type.
742
810
 
743
811
  #### Usage Examples
@@ -815,9 +883,11 @@ expect(ref).toStrictEqual({ one: { two: { three: { four: 1234 } } } })
815
883
  ### refsInfo
816
884
 
817
885
  ```ts
818
- const refsInfo: (...refs: Partial<Array<unknown>>) => [string, string, (string | undefined)[]][];
886
+ const refsInfo: (...refs: Partial<Array<unknown>>) => Partial<Array<[string, string, Partial<Array<string>>]>>;
819
887
  ```
820
888
 
889
+ > See [here](https://jackens.github.io/nnn/doc/#Why-Partial-Array-and-Partial-Record) for an explanation of why `Partial<Array>` instead of `Array`.
890
+
821
891
  A helper that provides information about the given `refs`.
822
892
 
823
893
  It returns an array of triples: `[«name», «prototype-name», «array-of-own-property-names»]`.
@@ -827,8 +897,8 @@ It returns an array of triples: `[«name», «prototype-name», «array-of-own-p
827
897
  ```js
828
898
  const info = refsInfo(Array, Function)
829
899
 
830
- expect(info.find(([name]) => name === 'Array')?.[2]?.includes('length')).toBeTrue()
831
- expect(info.find(([name]) => name === 'Function')?.[2]?.includes('length')).toBeTrue()
900
+ expect(info.find(item => item?.[0] === 'Array')?.[2]?.includes('length')).toBeTrue()
901
+ expect(info.find(item => item?.[0] === 'Function')?.[2]?.includes('length')).toBeTrue()
832
902
  ```
833
903
 
834
904
  ```js
@@ -865,6 +935,8 @@ const s: {
865
935
  };
866
936
  ```
867
937
 
938
+ > See [here](https://jackens.github.io/nnn/doc/#Why-Partial-Array-and-Partial-Record) for an explanation of why `Partial<Array>` instead of `Array`.
939
+
868
940
  A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `SVGElement`s (see also `h`).
869
941
 
870
942
  - The first argument of type `string` specifies the tag of the element to be created.
@@ -885,6 +957,8 @@ A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style help
885
957
  const svgUse: (id: string, ...args: Partial<Array<HArgs1>>) => SVGSVGElement;
886
958
  ```
887
959
 
960
+ > See [here](https://jackens.github.io/nnn/doc/#Why-Partial-Array-and-Partial-Record) for an explanation of why `Partial<Array>` instead of `Array`.
961
+
888
962
  A convenient shortcut for `s('svg', ['use', { 'xlink:href': '#' + id }], ...args)`.
889
963
 
890
964
  ### uuid1
@@ -926,6 +1000,52 @@ expect(uuid1({ node: '123456789' }).split('-')[4]).toStrictEqual('000123456789')
926
1000
  expect(uuid1({ date: new Date(323325000000) }).startsWith('c1399400-9a71-11bd')).toBeTrue()
927
1001
  ```
928
1002
 
1003
+ ## Why Partial\<Array\> and Partial\<Record\>
1004
+
1005
+ Consider the following code snippet:
1006
+
1007
+ ```ts
1008
+ const arr = ['one', 'two', 'three'] // type: string[]
1009
+ const arrAt42 = arr[42] // type: string
1010
+
1011
+ arrAt42.toUpperCase() // 👎 allowed by TypeScript
1012
+ ```
1013
+
1014
+ TypeScript allows `arrAt42.toUpperCase()`,
1015
+ which causes a <code class="log">TypeError: undefined is not an object</code>.
1016
+ The variable `arr` should be of type `Partial<Array<string>>`:
1017
+
1018
+ ```ts
1019
+ const arr: Partial<Array<string>> = ['one', 'two', 'three']
1020
+ const arrAt42 = arr[42] // type: string | undefined
1021
+
1022
+ arrAt42.toUpperCase() // 👍 forbidden by TypeScript
1023
+ ```
1024
+
1025
+ Now `arrAt42.toUpperCase()` is forbidden by TypeScript (<code class="log">'arrAt42' is possibly undefined</code>).
1026
+
1027
+ Similarly for the type `Record`:
1028
+
1029
+ ```ts
1030
+ const rec = Object.fromEntries(['one', 'two', 'three'].map((k, i) => [k, i])) // type: Record<string, number>
1031
+ const { tree } = rec // type: number
1032
+
1033
+ tree.toFixed() // 👎 allowed by TypeScript
1034
+ ```
1035
+
1036
+ TypeScript allows `tree.toFixed()`, which causes a <code class="log">TypeError: undefined is not an object</code>.
1037
+ The variable `rec` should be of type `Partial<Record<PropertyKey, number>>`:
1038
+
1039
+ ```ts
1040
+ const rec: Partial<Record<PropertyKey, number>> =
1041
+ Object.fromEntries(['one', 'two', 'three'].map((k, i) => [k, i]))
1042
+ const { tree } = rec // type: number | undefined
1043
+
1044
+ tree.toFixed() // 👍 forbidden by TypeScript
1045
+ ```
1046
+
1047
+ Now `tree.toFixed()` is forbidden by TypeScript (<code class="log">'tree' is possibly undefined</code>).
1048
+
929
1049
  ## License
930
1050
 
931
1051
  The MIT License (MIT)