vivth 1.1.1 → 1.2.0

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 (108) hide show
  1. package/.vivth-temp/README.src.md +35 -0
  2. package/README.md +1243 -441
  3. package/README.src.md +5 -2
  4. package/bun.lock +228 -0
  5. package/index.mjs +22 -9
  6. package/package.json +6 -3
  7. package/src/bundler/CompileJS.mjs +258 -0
  8. package/src/bundler/CreateESPlugin.mjs +24 -0
  9. package/src/bundler/EsBundler.mjs +27 -13
  10. package/src/bundler/FSInline.mjs +57 -0
  11. package/src/bundler/FSInlineAnalyzer.mjs +197 -0
  12. package/src/bundler/FSInlineBundled.mjs +34 -0
  13. package/src/bundler/adds/ToBundledJSPlugin.mjs +77 -0
  14. package/src/bundler/adds/externals.mjs +8 -0
  15. package/src/bundler/adds/pluginVivthBundle.mjs +5 -0
  16. package/src/class/Console.mjs +48 -27
  17. package/src/class/Derived.mjs +55 -7
  18. package/src/class/Effect.mjs +100 -39
  19. package/src/class/EnvSignal.mjs +5 -5
  20. package/src/class/EventSignal.mjs +55 -5
  21. package/src/class/FileSafe.mjs +124 -0
  22. package/src/class/ListDerived.mjs +6 -3
  23. package/src/class/ListSignal.mjs +11 -11
  24. package/src/class/LitExp.mjs +405 -0
  25. package/src/class/Paths.mjs +39 -4
  26. package/src/class/QChannel.mjs +79 -28
  27. package/src/class/SafeExit.mjs +31 -11
  28. package/src/class/Setup.mjs +12 -7
  29. package/src/class/Signal.mjs +26 -24
  30. package/src/class/WorkerMainThread.mjs +108 -135
  31. package/src/class/WorkerMainThreadBundled.mjs +216 -0
  32. package/src/class/WorkerThread.mjs +40 -31
  33. package/src/common/Base64URL.mjs +10 -5
  34. package/src/common/Base64URLFromFile.mjs +24 -0
  35. package/src/common/keys.mjs +3 -0
  36. package/src/doc/JSautoDOC.mjs +32 -56
  37. package/src/doc/parsedFile.mjs +37 -36
  38. package/src/function/CreateImmutable.mjs +9 -9
  39. package/src/function/EventCheck.mjs +2 -2
  40. package/src/function/EventObject.mjs +5 -5
  41. package/src/function/GetRuntime.mjs +38 -0
  42. package/src/function/IsAsync.mjs +2 -2
  43. package/src/function/LazyFactory.mjs +13 -13
  44. package/src/function/Timeout.mjs +2 -2
  45. package/src/function/Try.mjs +17 -12
  46. package/src/function/TryAsync.mjs +5 -5
  47. package/src/function/TrySync.mjs +5 -5
  48. package/src/function/TsToMjs.mjs +5 -4
  49. package/src/types/LitExpKeyType.mjs +5 -0
  50. package/src/types/QCBReturn.mjs +1 -1
  51. package/src/types/Runtime.mjs +7 -0
  52. package/types/dev/fsInline.d.mts +1 -0
  53. package/types/dev/test.d.mts +1 -0
  54. package/types/dev/testWorker.d.mts +7 -0
  55. package/types/dev/testbundle.d.mts +1 -0
  56. package/types/dev/workerThreadClass.d.mts +13 -0
  57. package/types/index.d.mts +18 -9
  58. package/types/src/bundler/CompileJS.d.mts +78 -0
  59. package/types/src/bundler/CreateESPlugin.d.mts +17 -0
  60. package/types/src/bundler/EsBundler.d.mts +33 -4
  61. package/types/src/bundler/FSInline.d.mts +43 -0
  62. package/types/src/bundler/FSInlineAnalyzer.d.mts +36 -0
  63. package/types/src/bundler/FSInlineBundled.d.mts +22 -0
  64. package/types/src/bundler/adds/ToBundledJSPlugin.d.mts +16 -0
  65. package/types/src/bundler/adds/externals.d.mts +1 -0
  66. package/types/src/bundler/adds/pluginVivthBundle.d.mts +1 -0
  67. package/types/src/class/Console.d.mts +36 -5
  68. package/types/src/class/Derived.d.mts +132 -5
  69. package/types/src/class/Effect.d.mts +106 -7
  70. package/types/src/class/EnvSignal.d.mts +8 -8
  71. package/types/src/class/EventSignal.d.mts +151 -7
  72. package/types/src/class/FileSafe.d.mts +90 -0
  73. package/types/src/class/ListDerived.d.mts +8 -5
  74. package/types/src/class/ListSignal.d.mts +123 -18
  75. package/types/src/class/LitExp.d.mts +361 -0
  76. package/types/src/class/Paths.d.mts +30 -4
  77. package/types/src/class/QChannel.d.mts +69 -22
  78. package/types/src/class/SafeExit.d.mts +24 -9
  79. package/types/src/class/Setup.d.mts +13 -10
  80. package/types/src/class/Signal.d.mts +73 -17
  81. package/types/src/class/WorkerMainThread.d.mts +47 -39
  82. package/types/src/class/WorkerMainThreadBundled.d.mts +85 -0
  83. package/types/src/class/WorkerThread.d.mts +34 -26
  84. package/types/src/common/Base64URL.d.mts +22 -1
  85. package/types/src/common/Base64URLFromFile.d.mts +16 -0
  86. package/types/src/common/keys.d.mts +1 -0
  87. package/types/src/doc/JSautoDOC.d.mts +3 -19
  88. package/types/src/doc/parsedFile.d.mts +72 -13
  89. package/types/src/function/CreateImmutable.d.mts +27 -2
  90. package/types/src/function/EventCheck.d.mts +15 -0
  91. package/types/src/function/EventObject.d.mts +17 -2
  92. package/types/src/function/GetRuntime.d.mts +2 -0
  93. package/types/src/function/IsAsync.d.mts +18 -0
  94. package/types/src/function/LazyFactory.d.mts +35 -2
  95. package/types/src/function/Timeout.d.mts +16 -0
  96. package/types/src/function/Try.d.mts +52 -1
  97. package/types/src/function/TryAsync.d.mts +22 -1
  98. package/types/src/function/TrySync.d.mts +16 -1
  99. package/types/src/function/TsToMjs.d.mts +19 -0
  100. package/types/src/types/LitExpKeyType.d.mts +1 -0
  101. package/types/src/types/QCBReturn.d.mts +1 -1
  102. package/types/src/types/Runtime.d.mts +1 -0
  103. package/dev/index.mjs +0 -28
  104. package/src/bundler/CompileMJS.mjs +0 -110
  105. package/src/function/WriteFileSafe.mjs +0 -37
  106. package/types/src/bundler/A.d.mts +0 -1
  107. package/types/src/bundler/CompileMJS.d.mts +0 -8
  108. package/types/src/function/WriteFileSafe.d.mts +0 -2
@@ -0,0 +1,124 @@
1
+ // @ts-check
2
+ import { writeFile, mkdir, copyFile, rename, rm } from 'node:fs/promises';
3
+ import { dirname } from 'node:path';
4
+
5
+ import { TryAsync } from '../function/TryAsync.mjs';
6
+
7
+ /**
8
+ * @description
9
+ * - collection of static methods of file access with added safety to mkdir before proceeding;
10
+ */
11
+ export class FileSafe {
12
+ /**
13
+ * @description
14
+ * - method to create file safely by recursively mkdir the dirname of the outFile;
15
+ * - also returning promise of result & error as value;
16
+ * @param {Parameters<writeFile>[0]} outFile
17
+ * @param {Parameters<writeFile>[1]} content
18
+ * @param {Parameters<writeFile>[2]} [options]
19
+ * @returns {ReturnType<typeof TryAsync<void>>}
20
+ * @example
21
+ * import { join } from 'node:path';
22
+ * import { FileSafe, Paths } from 'vivth';
23
+ *
24
+ * const [, errorWrite] = await FileSafe.write(
25
+ * join(Paths.root, '/some/path.mjs'),
26
+ * `console.log("hello-world!!");`,
27
+ * { encoding: 'utf-8' }
28
+ * );
29
+ */
30
+ static write = async (outFile, content, options) => {
31
+ return await TryAsync(async () => {
32
+ const [, errorMkDir] = await FileSafe.mkdir(dirname(outFile.toString()));
33
+ if (errorMkDir) {
34
+ throw new Error(`error mkdir, "${dirname(outFile.toString())}"`);
35
+ }
36
+ return writeFile(outFile, content, options);
37
+ });
38
+ };
39
+ /**
40
+ * @description
41
+ * - method to copy file/dir safely by recursively mkdir the dirname of the dest;
42
+ * - also returning promise of result & error as value;
43
+ * @param {Parameters<typeof copyFile>[0]} sourceFile
44
+ * @param {Parameters<typeof copyFile>[1]} destinationFile
45
+ * @param {Parameters<typeof copyFile>[2]} mode
46
+ * @returns {ReturnType<typeof TryAsync<void>>}
47
+ * @example
48
+ * import { join } from 'node:path';
49
+ * import { FileSafe, Paths } from 'vivth';
50
+ *
51
+ * const [, errorWrite] = await FileSafe.copy(
52
+ * join(Paths.root, '/some/path.mjs'),
53
+ * join(Paths.root, '/other/path.copy.mjs'),
54
+ * { encoding: 'utf-8' }
55
+ * );
56
+ */
57
+ static copy = async (sourceFile, destinationFile, mode) => {
58
+ return await TryAsync(async () => {
59
+ const dest_ = destinationFile.toString();
60
+ const [, errorMkDir] = await FileSafe.mkdir(dirname(dest_));
61
+ if (errorMkDir) {
62
+ throw new Error(`error mkdir, "${dirname(dest_)}"`);
63
+ }
64
+ return await copyFile(sourceFile, destinationFile, mode);
65
+ });
66
+ };
67
+ /**
68
+ * @description
69
+ * - method to rename file/dir safely by recursively mkdir the dirname of the dest;
70
+ * - also returning promise of result & error as value;
71
+ * @param {Parameters<typeof rename>[0]} oldPath
72
+ * @param {Parameters<typeof rename>[0]} newPath
73
+ * @returns {ReturnType<typeof TryAsync<void>>}
74
+ * @example
75
+ * import { join } from 'node:path';
76
+ * import { FileSafe, Paths } from 'vivth';
77
+ *
78
+ * const [, errorRename] = await FileSafe.rename(
79
+ * join(Paths.root, 'some/path'),
80
+ * join(Paths.root, 'other/path'),
81
+ * );
82
+ */
83
+ static rename = async (oldPath, newPath) => {
84
+ return await TryAsync(async () => {
85
+ const dest_ = newPath.toString();
86
+ const [, errorMkDir] = await FileSafe.mkdir(dirname(dest_));
87
+ if (errorMkDir) {
88
+ throw new Error(`error mkdir, "${dirname(dest_)}"`);
89
+ }
90
+ return await rename(oldPath, newPath);
91
+ });
92
+ };
93
+ /**
94
+ * @description
95
+ * - function to remove dir and file;
96
+ * - also returning promise of result & error as value;
97
+ * @param {Parameters<rm>[0]} path
98
+ * @param {Parameters<rm>[1]} [rmOptions]
99
+ * @returns {ReturnType<typeof TryAsync<void>>}
100
+ */
101
+ static rm = async (path, rmOptions) => {
102
+ return await TryAsync(async () => {
103
+ return await rm(path, rmOptions);
104
+ });
105
+ };
106
+ /**
107
+ * @description
108
+ * - create directory recursively;
109
+ * - also returning promise of result & error as value;
110
+ * @param {Parameters<mkdir>[0]} outDir
111
+ * - absolute path
112
+ * @returns {ReturnType<typeof TryAsync<string>>}
113
+ * @example
114
+ * import { join } from 'node:path';
115
+ * import { FileSafe, Paths } from 'vivth';
116
+ *
117
+ * const [str, errorMkDir] = await FileSafe.mkdir(join(Paths.root, '/some/path/example'));
118
+ */
119
+ static mkdir = async (outDir) => {
120
+ return await TryAsync(async () => {
121
+ return await mkdir(outDir, { recursive: true });
122
+ });
123
+ };
124
+ }
@@ -7,16 +7,19 @@ import { Effect } from './Effect.mjs';
7
7
  * - class to create `dervivedList` that satisfy `Array<Record<string, string>>`;
8
8
  * - usefull for `derivedLoops`, e.g. temporary search values;
9
9
  * - is a `Derived` instance;
10
- * @template {ListArg} LA
11
- * @extends {Derived<LA[]>}
10
+ * @template {ListArg} LISTARG
11
+ * @extends {Derived<LISTARG[]>}
12
12
  */
13
13
  export class ListDerived extends Derived {
14
14
  /**
15
15
  * @typedef {import('../types/ListArg.mjs').ListArg} ListArg
16
+ * @typedef {import('../common/lazie.mjs').unwrapLazy} unwrapLazy
16
17
  */
17
18
  /**
18
19
  * @description
19
- * @param {(effectInstanceOptions:Effect["options"])=>Promise<LA[]>} derivedFunction
20
+ * @param {(effectInstanceOptions:Omit<Effect["options"],
21
+ * unwrapLazy>)=>
22
+ * Promise<LISTARG[]>} derivedFunction
20
23
  * @example
21
24
  * import { ListSignal, ListDerived } from 'vivth';
22
25
  *
@@ -11,8 +11,8 @@ import { Signal } from './Signal.mjs';
11
11
  /**
12
12
  * @description
13
13
  * - class to create list that satisfy `Array<Record<string, string>>`.
14
- * @template {import('../types/ListArg.mjs').ListArg} LA
15
- * @extends {Signal<LA[]>}
14
+ * @template {import('../types/ListArg.mjs').ListArg} LISTARG
15
+ * @extends {Signal<LISTARG[]>}
16
16
  */
17
17
  export class ListSignal extends Signal {
18
18
  /**
@@ -41,7 +41,7 @@ export class ListSignal extends Signal {
41
41
  /**
42
42
  * @description
43
43
  * - usefull for `loops`;
44
- * @param {LA[]} [value]
44
+ * @param {LISTARG[]} [value]
45
45
  * @example
46
46
  * import { ListSignal } from 'vivth';
47
47
  *
@@ -56,7 +56,7 @@ export class ListSignal extends Signal {
56
56
  /**
57
57
  * @description
58
58
  * - reference to original inputed `value`;
59
- * @type {LA[]}
59
+ * @returns {LISTARG[]}
60
60
  */
61
61
  get value() {
62
62
  return super.value;
@@ -65,7 +65,7 @@ export class ListSignal extends Signal {
65
65
  * @description
66
66
  * - you cannot mannually set`value` `ListSignal_instance`;
67
67
  * @private
68
- * @type {LA[]}
68
+ * @type {LISTARG[]}
69
69
  */
70
70
  set value(_) {
71
71
  Console.error('`List.value` `setter` are not available outside the class or instance');
@@ -82,7 +82,7 @@ export class ListSignal extends Signal {
82
82
  * @description
83
83
  * - reference to structuredClone elements of `value`;
84
84
  * - calling doesn't notify
85
- * @type {Array<LA>}
85
+ * @returns {Array<LISTARG>}
86
86
  */
87
87
  get structuredClone() {
88
88
  return structuredClone(super.value);
@@ -91,7 +91,7 @@ export class ListSignal extends Signal {
91
91
  * @instance arrayMethods
92
92
  * @description
93
93
  * - appends new elements to the end;
94
- * @param {...LA} listArg
94
+ * @param {...LISTARG} listArg
95
95
  * @returns {void}
96
96
  */
97
97
  push: (...listArg) => {
@@ -112,7 +112,7 @@ export class ListSignal extends Signal {
112
112
  * @instance arrayMethods
113
113
  * @description
114
114
  * - inserts new element at the start;
115
- * @param {...LA} listArg
115
+ * @param {...LISTARG} listArg
116
116
  * @returns {void}
117
117
  */
118
118
  unshift: (...listArg) => {
@@ -137,7 +137,7 @@ export class ListSignal extends Signal {
137
137
  * @instance arrayMethods
138
138
  * @description
139
139
  * - replace whole `List` data with new array.
140
- * @param {LA[]} listArgs
140
+ * @param {LISTARG[]} listArgs
141
141
  * - new array in place of the deleted array.
142
142
  * @returns {void}
143
143
  */
@@ -152,7 +152,7 @@ export class ListSignal extends Signal {
152
152
  * - The zero-based location in the data from which to start removing elements.
153
153
  * @param {number} deleteCount
154
154
  * -The number of elements to remove.
155
- * @param {...LA} listArg
155
+ * @param {...LISTARG} listArg
156
156
  * - new data in place of the deleted data.
157
157
  * @returns {void}
158
158
  */
@@ -184,7 +184,7 @@ export class ListSignal extends Signal {
184
184
  * @description
185
185
  * - modify `List` element at specific index;
186
186
  * @param {number} index
187
- * @param {Partial<LA>} listArg
187
+ * @param {Partial<LISTARG>} listArg
188
188
  * @returns {void}
189
189
  */
190
190
  modify: (index, listArg) => {
@@ -0,0 +1,405 @@
1
+ // @ts-check
2
+
3
+ import { LazyFactory } from '../function/LazyFactory.mjs';
4
+ import { TrySync } from '../function/TrySync.mjs';
5
+
6
+ /**
7
+ * @description
8
+ * - class helper to created opionated regex helper;
9
+ * - named capture uses `es6+` feature, you might need to add polyfill to target extremely old browser;
10
+ * - class name refer to `Literal Expression`;
11
+ * - please be patient when using this class;
12
+ * >- destructuring is meant for extensive typehelper;
13
+ * >- and destructuring can lead to unhandled error here and there;
14
+ * >- therefore error as value is introduced to help to prevent error on runtime;
15
+ * @template {LitExpKeyType} KEYS
16
+ */
17
+ export class LitExp {
18
+ /**
19
+ * @typedef {import("../types/LitExpKeyType.mjs").LitExpKeyType} LitExpKeyType
20
+ */
21
+ /**
22
+ * @description
23
+ * - constructor helper;
24
+ * - under the hood it is an abstraction of `RegExp`, with more template literal touch;
25
+ * >- you can apply inline `RegExp` features on the string template literal(as constructor RegExp arg0);
26
+ * >>- by doing so you are opting in to make:
27
+ * >>>- your regex detection more robust; but
28
+ * >>>- `litExp_instance.make.string` to be `unusable`;
29
+ * >>- also mind the needs of escape for special characters;
30
+ * @template {LitExpKeyType} KEYS
31
+ * @param {KEYS} keysAndDefaultValuePair
32
+ * - keys and whether to override regex detection;
33
+ * >- example:
34
+ * ```js
35
+ * myKey: /myCustomCapture/ // all flags will be stripped;
36
+ * ```
37
+ * - default value === `false` is "[\\s\\S]*?", as in whiteSpace and nonWhiteSpace 0 to more occurence;
38
+ * @returns {ReturnType<typeof TrySync<(templateStringArray:TemplateStringsArray,
39
+ * ...values:(keyof KEYS)[]
40
+ * )=>LitExp<KEYS>>>}
41
+ * - placement of `key` will determine the named capture group will be placed in the template literal;
42
+ * - it is recomended to not end template literal with any of the `key`s as the regex detection might failed to detects the boundary of the end of matched string of that capture group;
43
+ * @example
44
+ * import { LitExp } from 'vivth';
45
+ *
46
+ * (()=>{
47
+ * const [liteal, errorPrep] = LitExp.prepare({
48
+ * myKey: /myCustomCapture/, // is placed on (?<myKey>myCustomCapture)
49
+ * // use false to place "[\\s\\S]\*?" instead;
50
+ * ...keyCaptureLogicPair
51
+ * })
52
+ * if (errorPrep) {
53
+ * console.error(error);
54
+ * return;
55
+ * }
56
+ * const litExp_instance = liteal`templateLiteral:${'myKey'};`
57
+ * // recommended to end the template literal with any string but `key`;
58
+ * })()
59
+ */
60
+ static prepare = (keysAndDefaultValuePair) => {
61
+ return TrySync(() => {
62
+ for (const key in keysAndDefaultValuePair) {
63
+ const regex = keysAndDefaultValuePair[key];
64
+ const capture = !regex ? `[\\s\\S]*?` : regex.source;
65
+ if (capture.match(/\(\<\w+\>[\s\S]*?\)/g)) {
66
+ throw Error('trying to add named capture');
67
+ }
68
+ }
69
+ return (templateStringArray, ...values) =>
70
+ new LitExp(keysAndDefaultValuePair, templateStringArray, ...values);
71
+ });
72
+ };
73
+ /**
74
+ * @private
75
+ * @param {KEYS} keys
76
+ * @param {TemplateStringsArray} templateStringArray
77
+ * @param {...(keyof KEYS)} values
78
+ */
79
+ constructor(keys, templateStringArray, ...values) {
80
+ this.#templateStringArray = templateStringArray;
81
+ this.#keyRules = keys;
82
+ this.#values = values;
83
+ }
84
+ /**
85
+ * @type {KEYS}
86
+ */
87
+ #keyRules;
88
+ /**
89
+ * @type {TemplateStringsArray}
90
+ */
91
+ #templateStringArray;
92
+ /**
93
+ * @type {(keyof KEYS)[]}
94
+ */
95
+ #values;
96
+ /**
97
+ * @template {LitExpKeyType} KEYS
98
+ * @param {KEYS} instance_rules
99
+ * @param {(keyof KEYS)[]} intance_values
100
+ * @param {(value:keyof KEYS, regex:RegExp|false)=>ReturnType<typeof TrySync<string>>} valueHandler
101
+ * @param {TemplateStringsArray} strings
102
+ * @returns {ReturnType<typeof TrySync<string[]>>}
103
+ */
104
+ static #processTemplate = (instance_rules, intance_values, valueHandler, strings) => {
105
+ return TrySync(() => {
106
+ const result = [];
107
+ const values = intance_values;
108
+ const stringsLength = strings.length;
109
+ for (let i = 0; i < stringsLength; i++) {
110
+ const string = strings[i];
111
+ if (i + 1 == stringsLength && string === '') {
112
+ result.push('(?:\\s*?|$)');
113
+ } else {
114
+ result.push(string);
115
+ }
116
+ if (i < values.length) {
117
+ const value = values[i];
118
+ const [valueHandled, errorValue] = valueHandler(value, instance_rules[value]);
119
+ if (errorValue || !valueHandled) {
120
+ throw errorValue;
121
+ }
122
+ result.push(valueHandled);
123
+ }
124
+ }
125
+ return result;
126
+ });
127
+ };
128
+ /**
129
+ * @param {Parameters<LitExp<KEYS>["evaluate"]["execGroups"]>[1] &
130
+ * { absoluteLeadAndFollowing: boolean }} options
131
+ * @returns {ReturnType<typeof TrySync<RegExp>>}
132
+ */
133
+ #regExp = ({ flags, whiteSpaceSensitive, absoluteLeadAndFollowing }) => {
134
+ return TrySync(() => {
135
+ let regExpStringCache;
136
+ if (!this.#regExpStringCache) {
137
+ const [regExpStringCache, error] = LitExp.#processTemplate(
138
+ this.#keyRules,
139
+ this.#values,
140
+ LitExp.#namedChapture,
141
+ this.#templateStringArray
142
+ );
143
+ if (error) {
144
+ throw error;
145
+ }
146
+ this.#regExpStringCache = regExpStringCache.join('');
147
+ }
148
+ if (!whiteSpaceSensitive) {
149
+ regExpStringCache = this.#regExpStringCache.replace(/\s+/g, `\\s+`);
150
+ } else {
151
+ regExpStringCache = this.#regExpStringCache;
152
+ }
153
+ return new RegExp(
154
+ absoluteLeadAndFollowing ? `\^${regExpStringCache}\$` : regExpStringCache,
155
+ flags
156
+ );
157
+ });
158
+ };
159
+ /**
160
+ * @param {Parameters<LitExp<KEYS>["evaluate"]["matchedAllAndGrouped"]>[1]} options
161
+ * @returns {ReturnType<typeof TrySync<RegExp>>}
162
+ */
163
+ #regexToMatchAll = ({ flags, whiteSpaceSensitive }) => {
164
+ return TrySync(() => {
165
+ let regExpToMatchStringCache;
166
+ if (!this.#regExpToMatchStringCache) {
167
+ const [regExpToMatchStringCache, error] = LitExp.#processTemplate(
168
+ this.#keyRules,
169
+ this.#values,
170
+ LitExp.#namedChapture,
171
+ this.#templateStringArray
172
+ );
173
+ if (error) {
174
+ throw error;
175
+ }
176
+ this.#regExpToMatchStringCache = regExpToMatchStringCache.join('');
177
+ }
178
+ if (!whiteSpaceSensitive) {
179
+ regExpToMatchStringCache = this.#regExpToMatchStringCache.replace(/\s+/g, `\\s+`);
180
+ } else {
181
+ regExpToMatchStringCache = this.#regExpToMatchStringCache;
182
+ }
183
+ return new RegExp(`\(${regExpToMatchStringCache}\)`, flags);
184
+ });
185
+ };
186
+
187
+ /**
188
+ * @description
189
+ * - instance methods for generating things;
190
+ */
191
+ make = LazyFactory(() => ({
192
+ /**
193
+ * @instance make
194
+ * @description
195
+ * - to make string based on the template literal;
196
+ * @param {Partial<ReturnType<LitExp<KEYS>["evaluate"]["execGroups"]>>[0]["result"]} overrides
197
+ * @returns {string}
198
+ * @example
199
+ * import { LitExp } from 'vivth';
200
+ *
201
+ * const [literal, errorPreparing] = LitExp.prepare({
202
+ * myKey: false,
203
+ * ...keyCaptureLogicPair
204
+ * })
205
+ *
206
+ * // asuming no error
207
+ * litExp_instance = `templateLiteral:${'myKey'};`;
208
+ * const [result, error] = litExp_instance.make.string({
209
+ * myKey: 'actualvalue',
210
+ * });
211
+ *
212
+ * console.log(result); // "templateLiteral:actualvalue;"
213
+ */
214
+ string: (overrides) => {
215
+ return TrySync(() => {
216
+ const [res, error] = LitExp.#processTemplate(
217
+ this.#keyRules,
218
+ this.#values,
219
+ (key) => {
220
+ return TrySync(() => {
221
+ return overrides[key.toString()] ?? '';
222
+ });
223
+ },
224
+ this.#templateStringArray
225
+ );
226
+ if (error || !res) {
227
+ throw error;
228
+ }
229
+ return res.join('');
230
+ })[0];
231
+ },
232
+ }));
233
+ /**
234
+ * @type {string}
235
+ */
236
+ #regExpStringCache;
237
+ /**
238
+ * @template {LitExpKeyType} KEYS
239
+ * @param {RegExp|false} regex
240
+ * @param {keyof KEYS} value
241
+ * @returns {ReturnType<typeof TrySync<string>>}
242
+ */
243
+ static #namedChapture = (value, regex) => {
244
+ return TrySync(() => {
245
+ const capture = !regex ? `[\\s\\S]*?` : regex.source;
246
+ return `(?<${value.toString()}>${capture})`;
247
+ });
248
+ };
249
+ /**
250
+ * @type {string}
251
+ */
252
+ #regExpToMatchStringCache;
253
+ /**
254
+ * @description
255
+ * - methods collections to evaluate string with `Literal Expression`;
256
+ */
257
+ evaluate = LazyFactory(() => ({
258
+ /**
259
+ * @instance evaluate
260
+ * @description
261
+ * - to exec and grouped based on `key`;
262
+ * @param {string} string
263
+ * @param {Object} options
264
+ * @param {ConstructorParameters<typeof RegExp>[1]} options.flags
265
+ * @param {boolean} options.whiteSpaceSensitive
266
+ * - true: leave any whitespace as is to be used as regex detection;
267
+ * - false: convert all whitespace to `\s+`;
268
+ * @param {boolean} options.absoluteLeadAndFollowing
269
+ * - false: standard capture;
270
+ * - true: add `^` and `$` to capture definition:
271
+ * >- meaning string will have to match starting and end of line from capture definition;
272
+ * @returns {ReturnType<typeof TrySync<{
273
+ * result:{ whole:string, named: Record<keyof KEYS, string>},
274
+ * regexp:RegExp}>>
275
+ * }
276
+ * @example
277
+ * import { LitExp } from 'vivth';
278
+ *
279
+ * const [literal, errorPreparing] = LitExp.prepare({
280
+ * myKey: false,
281
+ * ...keyCaptureLogicPair
282
+ * })
283
+ *
284
+ * // asuming no eror
285
+ * const litExp_instance = literal`templateLiteral:${'myKey'};`
286
+ *
287
+ * const [{
288
+ * result:{ // asuming there's no error
289
+ * named: { myKey },
290
+ * whole,
291
+ * },
292
+ * regex, // for reference
293
+ * }, error] = litExp_instance.evaluate.execGroups(
294
+ * `templateLiteral:Something;`,
295
+ * { ...options }
296
+ * )
297
+ *
298
+ * console.log(whole); // "templateLiteral:Something;"
299
+ * console.log(myKey); // "Something"
300
+ */
301
+ execGroups: (string, options) => {
302
+ // @ts-expect-error
303
+ return TrySync(() => {
304
+ const [regexp, error] = this.#regExp(options);
305
+ if (error || !regexp) {
306
+ throw error;
307
+ }
308
+ const execResult = regexp.exec(string);
309
+ const whole = execResult[1];
310
+ const named = execResult?.groups;
311
+ const result = { named, whole };
312
+ if (!named) {
313
+ throw new Error(
314
+ JSON.stringify({
315
+ regexpSource: regexp.source,
316
+ message: 'no match is found',
317
+ sugestion: 'make sure all `keys` values will capture any scenario',
318
+ })
319
+ );
320
+ }
321
+ return { result, regexp };
322
+ });
323
+ },
324
+ /**
325
+ * @instance evaluate
326
+ * @description
327
+ * - to match all and grouped based on `key`;
328
+ * @param {Parameters<LitExp<KEYS>["evaluate"]["execGroups"]>[0]} string
329
+ * @param {Omit<Parameters<LitExp<KEYS>["evaluate"]["execGroups"]>[1], 'absoluteLeadAndFollowing'>} options
330
+ * @returns {ReturnType<typeof TrySync<{result:{whole:string[], named:Array<Record<keyof KEYS, string>>},
331
+ * regexp: RegExp}>>
332
+ * }
333
+ * @example
334
+ * import { LitExp, Console } from 'vivth';
335
+ *
336
+ * const [literal, errorPreparing] = LitExp.prepare({
337
+ * myKey: false,
338
+ * ...keyCaptureLogicPair
339
+ * })
340
+ *
341
+ * // asuming no error;
342
+ * litExp_instance = literal`templateLiteral:${'myKey'};`
343
+ *
344
+ * const [resultOfMatchedAllAndGrouped, error] = litExp_instance.evaluate.matchedAllAndGrouped(
345
+ * `templateLiteral:Something;
346
+ * templateLiteral:SomethingElse;`,
347
+ * { ...options }
348
+ * )
349
+ * (()=>{
350
+ * if (error) {
351
+ * Console.error(error);
352
+ * return;
353
+ * }
354
+ * const {
355
+ * result: {
356
+ * whole: [whole0, whole1],
357
+ * named: [
358
+ * { myKey: myKeyExec0, },
359
+ * { myKey: myKeyExec1, },
360
+ * ],
361
+ * },
362
+ * regexp
363
+ * } = resultOfMatchedAllAndGrouped;
364
+ *
365
+ * console.log(whole0); // "templateLiteral:Something;"
366
+ * console.log(whole1); // "templateLiteral:SomethingElse;"
367
+ * console.log(myKeyExec0); // "Something"
368
+ * console.log(myKeyExec1); // "SomethingElse"
369
+ * })()
370
+ */
371
+ matchedAllAndGrouped: (string, options) => {
372
+ return TrySync(() => {
373
+ const [regexp, error] = this.#regexToMatchAll(options);
374
+ if (error || !regexp) {
375
+ throw error;
376
+ }
377
+ /**
378
+ * @type {Array<Record<keyof KEYS, string>>}
379
+ */
380
+ const named = [];
381
+ const whole = [];
382
+ /**
383
+ * @type {{whole:string[], named:Array<Record<keyof KEYS, string>>}}
384
+ */
385
+ const result = { named, whole };
386
+ const matchedAll = string.matchAll(regexp);
387
+ for (const match of matchedAll) {
388
+ if (!match.groups) {
389
+ throw new Error(
390
+ JSON.stringify({
391
+ regexpSource: regexp.source,
392
+ message: 'no match is found',
393
+ sugestion: 'make sure all `keys` values will capture any scenario',
394
+ })
395
+ );
396
+ }
397
+ whole.push(match[1]);
398
+ // @ts-expect-error
399
+ named.push(match.groups);
400
+ }
401
+ return { result, regexp };
402
+ });
403
+ },
404
+ }));
405
+ }