vivth 1.3.2 → 1.3.4

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 (61) hide show
  1. package/README.md +2156 -1782
  2. package/README.src.md +10 -0
  3. package/bun.lock +6 -0
  4. package/index.mjs +12 -3
  5. package/package.json +4 -2
  6. package/src/bundler/CompileJS.mjs +62 -28
  7. package/src/bundler/EsBundler.mjs +2 -1
  8. package/src/bundler/FSInline.mjs +8 -1
  9. package/src/bundler/FSInlineAnalyzer.mjs +47 -38
  10. package/src/bundler/adds/ToBundledJSPlugin.mjs +42 -28
  11. package/src/bundler/adds/pluginVivthBundle.mjs +3 -1
  12. package/src/class/EventSignal.mjs +15 -9
  13. package/src/class/FileSafe.mjs +30 -1
  14. package/src/class/ListSignal.mjs +1 -1
  15. package/src/class/LitExp.mjs +3 -2
  16. package/src/class/Paths.mjs +2 -11
  17. package/src/class/QChannel.mjs +4 -5
  18. package/src/class/SafeExit.mjs +7 -24
  19. package/src/class/Setup.mjs +5 -8
  20. package/src/class/Signal.mjs +4 -1
  21. package/src/common/Base64URL.mjs +6 -4
  22. package/src/common/Dev.mjs +134 -0
  23. package/src/common/DevBundled.mjs +5 -0
  24. package/src/common/Trace.mjs +24 -0
  25. package/src/doc/JSautoDOC.mjs +16 -11
  26. package/src/doc/correctBeforeParse.mjs +1 -1
  27. package/src/doc/parsedFile.mjs +1 -1
  28. package/src/function/GetNamedImportAlias.mjs +37 -0
  29. package/src/function/LazyFactory.mjs +1 -1
  30. package/src/function/TsToMjs.mjs +3 -3
  31. package/src/types/DevTestCB.mjs +11 -0
  32. package/src/types/Runtime.mjs +0 -1
  33. package/src/types/VivthDevCodeBlockStringType.mjs +6 -0
  34. package/tsconfig.json +6 -1
  35. package/types/index.d.mts +8 -3
  36. package/types/src/bundler/CompileJS.d.mts +58 -28
  37. package/types/src/bundler/EsBundler.d.mts +2 -2
  38. package/types/src/bundler/FSInline.d.mts +8 -1
  39. package/types/src/bundler/FSInlineAnalyzer.d.mts +1 -0
  40. package/types/src/bundler/adds/ToBundledJSPlugin.d.mts +6 -3
  41. package/types/src/class/EventSignal.d.mts +8 -8
  42. package/types/src/class/FileSafe.d.mts +21 -0
  43. package/types/src/class/ListSignal.d.mts +2 -2
  44. package/types/src/class/LitExp.d.mts +1 -0
  45. package/types/src/class/Paths.d.mts +2 -9
  46. package/types/src/class/QChannel.d.mts +4 -4
  47. package/types/src/class/SafeExit.d.mts +7 -24
  48. package/types/src/class/Setup.d.mts +5 -8
  49. package/types/src/common/Base64URL.d.mts +5 -3
  50. package/types/src/common/Dev.d.mts +68 -0
  51. package/types/src/common/DevBundled.d.mts +3 -0
  52. package/types/src/common/Trace.d.mts +14 -0
  53. package/types/src/doc/JSautoDOC.d.mts +8 -7
  54. package/types/src/function/GetNamedImportAlias.d.mts +22 -0
  55. package/types/src/function/LazyFactory.d.mts +1 -1
  56. package/types/src/function/TsToMjs.d.mts +3 -3
  57. package/types/src/function/WithDefer.d.mts +10 -0
  58. package/types/src/types/DevTestCB.d.mts +3 -0
  59. package/types/src/types/IsDevCBStringType.d.mts +4 -0
  60. package/types/src/types/Runtime.d.mts +3 -0
  61. package/types/src/types/VivthDevCodeBlockStringType.d.mts +4 -0
@@ -1,6 +1,8 @@
1
1
  // @ts-check
2
- import { writeFile, mkdir, copyFile, rename, rm } from 'node:fs/promises';
2
+
3
+ import { writeFile, mkdir, copyFile, rename, rm, access } from 'node:fs/promises';
3
4
  import { dirname } from 'node:path';
5
+ import { constants } from 'node:fs';
4
6
 
5
7
  import { TryAsync } from '../function/TryAsync.mjs';
6
8
 
@@ -9,6 +11,33 @@ import { TryAsync } from '../function/TryAsync.mjs';
9
11
  * - collection of static methods of file access with added safety to mkdir before proceeding;
10
12
  */
11
13
  export class FileSafe {
14
+ /**
15
+ * @description
16
+ * - method to safely detects whether filePaths exist;
17
+ * - uses fs/promises access under the hood;
18
+ * - also returning promise of result & error as value;
19
+ * @param {string} filePath
20
+ * @returns {ReturnType<typeof TryAsync<true>>}
21
+ * @example
22
+ * import { join } from 'node:path';
23
+ * import { FileSafe, Paths } from 'vivth';
24
+ *
25
+ * const [, error] = await FileSafe.write(
26
+ * join(Paths.root, '/some/path.mjs'),
27
+ * );
28
+ * if (!error) {
29
+ * // file exists
30
+ * } else {
31
+ * // file not exists
32
+ * }
33
+ */
34
+ static exist = async (filePath) => {
35
+ // @ts-expect-error
36
+ return await TryAsync(async () => {
37
+ await access(filePath, constants.F_OK);
38
+ return true;
39
+ });
40
+ };
12
41
  /**
13
42
  * @description
14
43
  * - method to create file safely by recursively mkdir the dirname of the outFile;
@@ -85,7 +85,7 @@ export class ListSignal extends Signal {
85
85
  * @instance arrayMethods
86
86
  * @description
87
87
  * - reference to structuredClone elements of `value`;
88
- * - calling doesn't notify
88
+ * - calling doesn't notify for changes;
89
89
  * @returns {Array<LISTARG>}
90
90
  */
91
91
  get structuredClone() {
@@ -12,6 +12,7 @@ import { TrySync } from '../function/TrySync.mjs';
12
12
  * >- destructuring is meant for extensive typehelper;
13
13
  * >- and destructuring can lead to unhandled error here and there;
14
14
  * >- therefore error as value is introduced to help to prevent error on runtime;
15
+ * - made primarily for generating string file, that are purely managed programatically;
15
16
  * @template {LitExpKeyType} KEYS
16
17
  */
17
18
  export class LitExp {
@@ -32,7 +33,7 @@ export class LitExp {
32
33
  * new RegExp(escapedLiteral, 'g');
33
34
  */
34
35
  static escape = (string) => {
35
- return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
36
+ return string.replace(/[.*+?^${}()|[\]\\\]]/g, '\\$&');
36
37
  };
37
38
  /**
38
39
  * @description
@@ -131,7 +132,7 @@ export class LitExp {
131
132
  throw new Error('string undefined');
132
133
  }
133
134
  if (i + 1 == stringsLength && string === '') {
134
- result.push('(?:\\s+?|$)');
135
+ result.push('(?:\\s+?|;|,|$|)');
135
136
  } else {
136
137
  result.push(LitExp.escape(string));
137
138
  }
@@ -1,7 +1,5 @@
1
1
  // @ts-check
2
2
 
3
- import { relative } from 'node:path';
4
-
5
3
  import { Console } from './Console.mjs';
6
4
 
7
5
  /**
@@ -25,15 +23,8 @@ export class Paths {
25
23
  * ```
26
24
  * - node/bun compatible:
27
25
  * ```js
28
- * process?.env?.INIT_CWD ?? process?.cwd()
29
- * ```
30
- * - deno: need for `deno run --allow-env --allow-read your_script.ts`:
31
- * ```js
32
- * Deno.env.get("INIT_CWD") ?? Deno.cwd()
33
- * ```
34
- * - pkg:
35
- * ```js
36
- * __dirname
26
+ * import process from 'node:process';
27
+ * process.env.INIT_CWD ?? process.cwd()
37
28
  * ```
38
29
  * - other: you need to check your JSRuntime for the rootPath reference;
39
30
  * @example
@@ -2,7 +2,6 @@
2
2
 
3
3
  import { LazyFactory } from '../function/LazyFactory.mjs';
4
4
  import { TryAsync } from '../function/TryAsync.mjs';
5
- import { TrySync } from '../function/TrySync.mjs';
6
5
  import { Console } from './Console.mjs';
7
6
 
8
7
  /**
@@ -34,9 +33,9 @@ export class QChannel {
34
33
  * import { QChannel } from 'vivth';
35
34
  *
36
35
  * const myMappedQref = (window['myMappedQref'] = new Map());
37
- * export const MyQClass = QChannel.makeQClass(myMappedQref);
36
+ * export const MyQClass = QChannel.setup(myMappedQref);
38
37
  */
39
- static makeQClass = (uniqueMap) => {
38
+ static setup = (uniqueMap) => {
40
39
  QChannel.#uniquePromiser = uniqueMap;
41
40
  return QChannel;
42
41
  };
@@ -215,7 +214,7 @@ export class QChannel {
215
214
  * - `callbackBlock` with error as value:
216
215
  * - caveat:
217
216
  * >- no need to manually call resume();
218
- * >- slightly less performant than `callback`;
217
+ * >- slightly less performant than `key`;
219
218
  * @template RESULT
220
219
  * @param {DEFINEDANY} keyID
221
220
  * @param {(options:Omit<QCBReturn,
@@ -224,7 +223,7 @@ export class QChannel {
224
223
  * @returns {ReturnType<typeof TryAsync<RESULT>>}
225
224
  * @example
226
225
  * const q = new QChannel('channel name');
227
- * const [result, error] = await q.callback(keyID, async ({ isLastOnQ }) = > {
226
+ * const [result, error] = await q.callback(keyID, async ({ isLastOnQ }) => {
228
227
  * // if (!isLastOnQ()) { // imperative debounce if needed
229
228
  * // return;
230
229
  * // }
@@ -36,14 +36,10 @@ export class SafeExit {
36
36
  * ['SIGINT', 'SIGTERM']
37
37
  * ```
38
38
  * @param {()=>void} options.terminator
39
- * - standard node/bun:
39
+ * - standard, process must be imported statically from 'node:process':
40
40
  * ```js
41
41
  * () => process.exit(0),
42
42
  * ```
43
- * - Deno:
44
- * ```js
45
- * () => Deno.exit(0),
46
- * ```
47
43
  * @param {(eventName:string)=>void} [options.listener]
48
44
  * - default value
49
45
  * ```js
@@ -52,34 +48,21 @@ export class SafeExit {
52
48
  * SafeExit.instance.exiting.correction(true);
53
49
  * Console.log(`safe exit via "${eventName}"`);
54
50
  * });
55
- * };
56
- * ```
57
- * - example Deno:
58
- * ```js
59
- * (eventName) => {
60
- * const sig = Deno.signal(eventName);
61
- * for await (const _ of sig) {
62
- * exiting.correction(true);
63
- * sig.dispose();
64
- * Console.log(`safe exit via "${eventName}"`);
65
- * }
66
51
  * }
67
52
  * ```
68
53
  * - if your exit callback doesn't uses `process` global object you need to input on the SafeExit instantiation
69
54
  * @example
55
+ * import process from 'node:process';
70
56
  * import { SafeExit, Console } from 'vivth';
71
57
  *
72
58
  * new SafeExit({
73
59
  * eventNames: ['SIGINT', 'SIGTERM', ...eventNames],
74
- * terminator : () => process.exit(0), // OR on deno () => Deno.exit(0),
75
- * // optional deno example
60
+ * terminator : () => process.exit(0),
76
61
  * listener : (eventName) => {
77
- * const sig = Deno.signal(eventName);
78
- * for await (const _ of sig) {
79
- * exiting.correction(true);
80
- * sig.dispose();
62
+ * process.once(eventName, function () {
63
+ * SafeExit.instance?.exiting.correction(true);
81
64
  * Console.log(`safe exit via "${eventName}"`);
82
- * }
65
+ * });
83
66
  * }
84
67
  * });
85
68
  */
@@ -157,7 +140,7 @@ export class SafeExit {
157
140
  * // code
158
141
  * }
159
142
  * SafeExit.instance.addCallback(exitCallback);
160
- *
143
+ * // somewhere else
161
144
  * SafeExit.instance.removeCallback(exitCallback);
162
145
  */
163
146
  removeCallback = (cb) => {
@@ -20,15 +20,12 @@ export class Setup {
20
20
  * // eventNames are blank by default, you need to manually name them all;
21
21
  * // 'exit' will be omited, as it might cause async callbacks failed to execute;
22
22
  * eventNames: ['SIGINT', 'SIGTERM', ...eventNames],
23
- * terminator = () => process.exit(0), // OR on deno () => Deno.exit(0),
24
- * // optional deno example
25
- * listener = (eventName) => {
26
- * const sig = Deno.signal(eventName);
27
- * for await (const _ of sig) {
28
- * exiting.correction(true);
29
- * sig.dispose();
23
+ * terminator : () => process.exit(0),
24
+ * listener : (eventName) => {
25
+ * process.once(eventName, function () {
26
+ * SafeExit.instance?.exiting.correction(true);
30
27
  * Console.log(`safe exit via "${eventName}"`);
31
- * }
28
+ * });
32
29
  * }
33
30
  * });
34
31
  */
@@ -114,7 +114,10 @@ export class Signal {
114
114
  * @returns {void}
115
115
  */
116
116
  subscriber: (effectInstance) => {
117
- effectInstance.options.removeEffect();
117
+ /**
118
+ * this part is not needed, as the effect might need to react to other signals
119
+ // effectInstance.options.removeEffect();
120
+ */
118
121
  this.subscribers.setOf.delete(effectInstance);
119
122
  },
120
123
  /**
@@ -4,21 +4,23 @@
4
4
  * @description
5
5
  * - create inline base64 url;
6
6
  * - usage:
7
- * >- can be extremely usefull to display file on desktop app webview, without exposing http server;
7
+ * >- can be extremely usefull to display file on desktop app `webview` or any bundled browser, without exposing http server;
8
8
  * @param {string} fileString
9
9
  * @param {string} mimeType
10
10
  * @param {(string:string)=>string} btoaFunction
11
11
  * - check your js runtime `btoa`;
12
12
  * - node compatible:
13
13
  * ```js
14
- * (str, prevBufferEncoding) =>
15
- * Buffer.from(str, prevBufferEncoding).toString('base64')
14
+ * (str, prevBufferEncoding) => {
15
+ * return Buffer.from(str, prevBufferEncoding).toString('base64');
16
+ * }
16
17
  * ```
17
18
  * @returns {string}
18
19
  * @example
19
20
  * import { Base64URL } from 'vivth'
20
21
  * import fileString from './fileString.mjs';
21
22
  *
23
+ * // example for browser;
22
24
  * Base64URL(fileString, 'application/javascript', btoa);
23
25
  */
24
26
  export function Base64URL(fileString, mimeType, btoaFunction) {
@@ -28,4 +30,4 @@ export function Base64URL(fileString, mimeType, btoaFunction) {
28
30
  binary += String.fromCharCode(byte);
29
31
  }
30
32
  return `data:${mimeType.toString()};base64,${btoaFunction(binary)}`;
31
- };
33
+ }
@@ -0,0 +1,134 @@
1
+ // @ts-check
2
+
3
+ import { Console } from '../class/Console.mjs';
4
+ import { Effect } from '../class/Effect.mjs';
5
+ import { Signal } from '../class/Signal.mjs';
6
+ import { LazyFactory } from '../function/LazyFactory.mjs';
7
+ import { TryAsync } from '../function/TryAsync.mjs';
8
+ import { Trace } from './Trace.mjs';
9
+
10
+ /**
11
+ * @typedef {import("../types/VivthDevCodeBlockStringType.mjs").VivthDevCodeBlockStringType} VivthDevCodeBlockStringType
12
+ * @typedef {import('../types/DevTestCB.mjs').DevTestCB} DevTestCB
13
+ */
14
+
15
+ /**
16
+ * @description
17
+ * - class helper for `devTime` only code block;
18
+ */
19
+ export class Dev {
20
+ /**
21
+ * @description
22
+ * - persistent variable(during `devTime` and `bundled`);
23
+ * - can be used as `condition` for checking whether it is in `devTime` or `bundled`;
24
+ * @type {boolean}
25
+ * @example
26
+ * import { Dev } from 'vivth';
27
+ *
28
+ * if (Dev.isDev) {
29
+ * // this code block will presist even on `bundled`;
30
+ * }
31
+ */
32
+ static isDev = true;
33
+ /**
34
+ * @type {Signal<Map<string,Awaited<ReturnType<typeof TryAsync<boolean>>>>>}
35
+ */
36
+ static #notifications = LazyFactory(() => new Signal(new Map()));
37
+ /**
38
+ * @type {DevTestCB}
39
+ */
40
+ static #test = async (testName, testCallback) => {
41
+ testName = `${testName}:'${Trace(4)}'`;
42
+ Dev.#notifications.subscribers.notify(async ({ signalInstance }) => {
43
+ signalInstance.value.set(
44
+ testName,
45
+ await TryAsync(async () => {
46
+ return await testCallback();
47
+ })
48
+ );
49
+ });
50
+ Dev.#effectForCheck['vivth:unwrapLazy;']();
51
+ return {
52
+ removeId: () => {
53
+ Dev.#notifications.subscribers.notify(async ({ signalInstance }) => {
54
+ signalInstance.value.delete(testName);
55
+ });
56
+ },
57
+ };
58
+ };
59
+ static #effectForCheck = LazyFactory(
60
+ () =>
61
+ new Effect(async ({ isLastCalled, subscribe }) => {
62
+ const notifications = subscribe(Dev.#notifications).value;
63
+ if (!(await isLastCalled(100)) || !notifications.size) {
64
+ return;
65
+ }
66
+ /**
67
+ * @type {string[]}
68
+ */
69
+ const succeedTest = [];
70
+ /**
71
+ * @type {string[]}
72
+ */
73
+ const failedTest = [];
74
+ for (const [notificationID, [isCorrect, error]] of notifications) {
75
+ if (error || !isCorrect) {
76
+ failedTest.push(notificationID);
77
+ continue;
78
+ }
79
+ succeedTest.push(notificationID);
80
+ }
81
+ const size = notifications.size;
82
+ /**
83
+ * @type {{
84
+ * testCount:number,
85
+ * succeed?: {count:string, testID:string[]},
86
+ * failed?: {count:string, testID:string[]},
87
+ * }}
88
+ */
89
+ let warn = { testCount: size };
90
+ if (succeedTest.length) {
91
+ warn.succeed = {
92
+ count: `${succeedTest.length} of ${size}`,
93
+ testID: succeedTest,
94
+ };
95
+ }
96
+ if (failedTest.length) {
97
+ warn.failed = {
98
+ count: `${failedTest.length} of ${size}`,
99
+ testID: failedTest,
100
+ };
101
+ }
102
+ Console.warn(warn);
103
+ })
104
+ );
105
+ /**
106
+ * @description
107
+ * - to wrap `devTime` only code block;
108
+ * - when bundled uses `EsBundler` or esbuild with `ToBundledJSPlugin` plugin, the code block will be removed on the bundled version;
109
+ * @param {(options:{test:DevTestCB})=>Promise<void>} callback
110
+ * - also provide `test` method for inline testing:
111
+ * >- which is wrapped in `TryAsync`, throwed errors will automatically return `false`;
112
+ * @param {VivthDevCodeBlockStringType} _closing
113
+ * - it is needed to detect the code block closing;
114
+ * - should use single or double quote and not back tick;
115
+ * @returns {Promise<void>}
116
+ * @example
117
+ * import { Dev, Signal } from 'vivth';
118
+ *
119
+ * Dev.vivthDevCodeBlock(async function () {
120
+ * // this code block will be removed on `bundled` version;
121
+ * }, 'vivthDevCodeBlock');
122
+ *
123
+ * const numberSignal = new Signal(0);
124
+ * Dev.vivthDevCodeBlock(async ({ test }) => {
125
+ * // this code block will be removed on `bundled` version;
126
+ * const [{ removeId: removeTest }] = await Promise.all([
127
+ * test(async () => numberSignal.value === 0)
128
+ * ])
129
+ * }, 'vivthDevCodeBlock');
130
+ */
131
+ static vivthDevCodeBlock = async (callback, _closing) => {
132
+ await callback({ test: Dev.#test });
133
+ };
134
+ }
@@ -0,0 +1,5 @@
1
+ // @ts-check
2
+
3
+ export class Dev {
4
+ static isDev = false;
5
+ }
@@ -0,0 +1,24 @@
1
+ // @ts-check
2
+
3
+ import { Paths } from '../class/Paths.mjs';
4
+
5
+ /**
6
+ * @description
7
+ * - returns position of stack trace as string, formatted as `fileName:lineNumber:columnNumber`;
8
+ * - extremely usefull for:
9
+ * >- jumping positions to code line;
10
+ * >- creating dynamic string id;
11
+ * @param {number} traceIndex
12
+ * @returns {string}
13
+ * @example
14
+ * import { Trace, Console } from 'vivth';
15
+ *
16
+ * Console.log(Trace(3)); // "D://test.mjs:3:13"
17
+ */
18
+ export function Trace(traceIndex) {
19
+ const err = new Error();
20
+ const stack = err.stack?.split('\n');
21
+ const callerLine = stack?.[Math.round(traceIndex)] ?? 'unknown';
22
+ const match = callerLine.match(/([A-Z]:[^ ]*[0-9]|\/[^ )]+:\d+:\d+)/m);
23
+ return Paths.normalize(match?.[1] ?? callerLine.trim());
24
+ }
@@ -3,7 +3,9 @@
3
3
  import { extname, join } from 'node:path';
4
4
  import { readFile } from 'node:fs/promises';
5
5
 
6
+ import prettier from 'prettier';
6
7
  import chokidar from 'chokidar';
8
+
7
9
  import { EventSignal } from '../class/EventSignal.mjs';
8
10
  import { parsedFile } from './parsedFile.mjs';
9
11
  import { SafeExit } from '../class/SafeExit.mjs';
@@ -36,21 +38,22 @@ const acceptableExt = new Set(['.mjs', '.mts', '.ts']);
36
38
  * - this autodocumenter uses [chokidar](https://npmjs.com/package/chokidar) under the hood;
37
39
  * - this class also is used to generate this `README.md`;
38
40
  * - behaviours:
41
+ * >- auto export must follows the following rules;
39
42
  * >1) add `"at"noautodoc` on self closing jsdoc comment to opt out from generating documentation on said file;
40
- * >>- auto export must follows the following rules, and there's no way to override;
41
- * >2) export all named exported 'const'|'function'|'async function'|'class', alphanumeric name, started with Capital letter, same name with fileName on `options.pahts.file`;
42
- * >3) declare typedef of existing typedef with alphanumeric name, started with Capital letter, same name with fileName, and have no valid export like on point <sup>1</sup> on `options.pahts.file`;
43
- * >4) create `README.md` based on, `options.paths.dir` and `README.src.md`;
43
+ * >2) will (generate) export all named exported 'const'|'function'|'async function'|'class', alphanumeric name, started with Capital letter, same name with fileName on `options.paths.file`;
44
+ * >3) will (generate) declare typedef of existing typedef with alphanumeric name, started with Capital letter, same name with fileName, and have no valid export like on point <sup>1</sup> on `options.paths.file`;
45
+ * >4) will (generate) create `README.md` based on, `options.paths.dir` and `README.src.md`;
44
46
  * >5) extract `"at"description` jsdoc:
45
47
  * >>- on static/prop that have depths, all of children should have `"at"static`/`"at"instance` `nameOfImmediateParent`, same block but before `"at"description` comment line;
46
48
  * >>- `"at"description` are treated as plain `markdown`;
47
49
  * >>- first `"at"${string}` after `"at"description` until `"at"example` will be treated as `javascript` comment block on the `markdown`;
48
50
  * >>- `"at"example` are treated as `javascript` block on the `markdown` file, and should be placed last on the same comment block;
49
51
  * >>- you can always look at `vivth/src` files to check how the source, and the `README.md` and `index.mjs` documentation/generation results;
50
- * >6) this types of arrow functions will be converted to regullar function, for concise type emition:
52
+ * >6) this types of arrow functions will be converted to regullar function, for concise type emition, includes:
51
53
  * >>- validly exported function;
52
- * >>- static/instance method(s) with generic template;
53
- * >7) transpile `.ts` and `.mts` to `.mjs` same name and directory;
54
+ * >>- static/instance method with generic template;
55
+ * >7) transpile `.ts` and `.mts` to `.mjs` with same name and directory;
56
+ * >>- use `"at"preserve` to preserve tsdoc comment section;
54
57
  */
55
58
  export class JSautoDOC {
56
59
  /**
@@ -201,7 +204,9 @@ export class JSautoDOC {
201
204
  const readmePath = join(rootPath, this.#paths.readMe);
202
205
  const mjsFilePath = join(rootPath, this.#paths.file);
203
206
  const [[, errorWriteReadme], [, errorWriteMjsFile]] = await Promise.all([
204
- FileSafe.write(readmePath, readme, { encoding }),
207
+ FileSafe.write(readmePath, await prettier.format(readme, { parser: 'markdown' }), {
208
+ encoding,
209
+ }),
205
210
  FileSafe.write(mjsFilePath, mjsFile, { encoding }),
206
211
  ]);
207
212
  if (errorWriteReadme === undefined) {
@@ -244,7 +249,8 @@ export class JSautoDOC {
244
249
  const apiDocuments = [];
245
250
  const mjsMain = ['// @ts-check', this.#generateJSDOCFromstring(this.#copyright)];
246
251
  const mjsTypes = [];
247
- for await (const path_ of filepaths) {
252
+ const sortedFilepaths = [...filepaths].sort((a, b) => a.localeCompare(b));
253
+ for await (const path_ of sortedFilepaths) {
248
254
  const {
249
255
  documented,
250
256
  content,
@@ -256,7 +262,6 @@ export class JSautoDOC {
256
262
  if (trueContent === undefined) {
257
263
  return;
258
264
  }
259
-
260
265
  const hasNoAutoDoc = /\/\*\*[\s\*]*?@noautodoc[\s\*]*?\*\//.test(trueContent);
261
266
  if (hasValidExportObject) {
262
267
  mjsMain.push(
@@ -398,7 +403,7 @@ export class JSautoDOC {
398
403
  this.#filePaths.subscribers.notify(async ({ signalInstance }) => {
399
404
  Console.warn({ [eventName]: path__ });
400
405
  signalInstance.value.delete(path__);
401
- this.#parsedFilesRef.unRef(path__);
406
+ await this.#parsedFilesRef.unRef(path__);
402
407
  });
403
408
  });
404
409
  };
@@ -1,9 +1,9 @@
1
1
  // @ts-check
2
2
 
3
+ import { readFile, writeFile } from 'node:fs/promises';
3
4
  import { basename } from 'node:path';
4
5
 
5
6
  import { TryAsync } from '../function/TryAsync.mjs';
6
- import { readFile, writeFile } from 'node:fs/promises';
7
7
  import { Console } from '../class/Console.mjs';
8
8
  import { Timeout } from '../function/Timeout.mjs';
9
9
  import { LitExp } from '../class/LitExp.mjs';
@@ -322,7 +322,7 @@ export class parsedFile {
322
322
  const fullDescTrue_0 = fullDescTrue[0] ?? '';
323
323
  const description = fullDescTrue_0
324
324
  .replace('*', '')
325
- .replace(/(?<!\\)\*\s/g, '\n')
325
+ .replace(/\s*(?<!\\)\*\s/g, '\n')
326
326
  .trim();
327
327
  fullDescTrue.shift();
328
328
  let example;
@@ -0,0 +1,37 @@
1
+ // @ts-check
2
+
3
+ import { Console } from '../class/Console.mjs';
4
+
5
+ /**
6
+ * @description
7
+ * - regex helper for:
8
+ * >- get named import; OR
9
+ * >- alias of named import;
10
+ * @param {string} content
11
+ * @param {string} moduleName
12
+ * @param {string} packageName
13
+ * @returns {string|undefined}
14
+ * @example
15
+ * import { GetNamedImportAlias } from 'vivth';
16
+ *
17
+ * const checkNoAlias = `
18
+ * import { something } from 'packageName';
19
+ * `
20
+ * const checkAlias = `
21
+ * import { something as somethingElse } from 'packageName';
22
+ * `
23
+ * GetNamedImportAlias(checkNoAlias, 'something', 'packageName'); // 'something'
24
+ * GetNamedImportAlias(checkAlias, 'something', 'packageName'); // 'somethingElse'
25
+ */
26
+ export function GetNamedImportAlias(content, moduleName, packageName) {
27
+ const checkIfImportingFromVivthRegex = new RegExp(
28
+ `(import\\s+{\\s*[\\s\\S]*(?<imported>${moduleName})\\s+as\\s+(?<alias>[a-zA-Z0-9]+)[\\s\\S]*\\s*}\\s+from\\s+['"]${packageName}['"])|(import\\s+{\\s*[\\s\\S]*(?<imported>${moduleName})[\\s\\S]*\\s*}\\s+from\\s+['"]${packageName}['"])`,
29
+ 'g'
30
+ );
31
+ const matched = checkIfImportingFromVivthRegex.exec(content);
32
+ if (!matched || !matched.groups) {
33
+ return;
34
+ }
35
+ const { imported, alias } = matched.groups;
36
+ return alias ?? imported;
37
+ }
@@ -33,7 +33,7 @@ import { unwrapLazy } from '../common/lazie.mjs';
33
33
  * const a = myInstance; // not yet initiated;
34
34
  * const b = a.myProp // imediately initiated;
35
35
  * // OR
36
- * myInstance["vivth:unwrapLazy;"]() // forcefully call the callback;
36
+ * myInstance["vivth:unwrapLazy;"]() // forcefully call factory generator;
37
37
  */
38
38
  export function LazyFactory(factory) {
39
39
  /**
@@ -12,9 +12,9 @@ import { FileSafe } from '../class/FileSafe.mjs';
12
12
 
13
13
  /**
14
14
  * @description
15
- * - turn `.mts`||`.ts` file into `.mjs`, no bundling, just translation;
15
+ * - turn `.mts`||`.ts` file into `.mjs`, no bundling, just traspilation;
16
16
  * - on certain circumstance where `.mjs` result needed to be typed, you need to manually add `jsdoc`;
17
- * >- uses `"at"preserve` to register `jsdoc` inline;
17
+ * >- uses `"at"preserve` to register `jsdoc`;
18
18
  * @param {string} path_
19
19
  * - path from `Paths.root`;
20
20
  * @param {Object} [options]
@@ -27,7 +27,7 @@ import { FileSafe } from '../class/FileSafe.mjs';
27
27
  * @example
28
28
  * import { TsToMjs } from 'vivth';
29
29
  *
30
- * TsToMjs('./myFile.mts', { encoding: 'utf-8', overrideDir: './other/dir' });
30
+ * await TsToMjs('./myFile.mts', { encoding: 'utf-8', overrideDir: './other/dir' });
31
31
  */
32
32
  export async function TsToMjs(path_, { overrideDir = undefined, encoding = 'utf-8' } = {}) {
33
33
  if (Paths.root === undefined) {
@@ -0,0 +1,11 @@
1
+ // @ts-check
2
+
3
+ /**
4
+ * @callback DevTestCB
5
+ * @param {string} testName
6
+ * @param {()=>Promise<boolean>} testCallback
7
+ * - already wrapped with `TryAsync`:
8
+ * >- if throws error will automatically return false;
9
+ * @returns {Promise<{removeId:()=>void}>}
10
+ * - calling `removeId` will remove the this test from reports;
11
+ */
@@ -1,7 +1,6 @@
1
1
  // @ts-check
2
2
 
3
3
  /**
4
- * @description
5
4
  * - for popular runtimes check;
6
5
  * @typedef {'node' | 'bun' | 'deno' | 'browser' | 'unknown'} Runtime
7
6
  */
@@ -0,0 +1,6 @@
1
+ // @ts-check
2
+
3
+ /**
4
+ * - closing helper for `Dev.vivthDevCodeBlock`;
5
+ * @typedef {'vivthDevCodeBlock'} VivthDevCodeBlockStringType
6
+ */
package/tsconfig.json CHANGED
@@ -32,5 +32,10 @@
32
32
  "noUnusedParameters": false,
33
33
  "noPropertyAccessFromIndexSignature": false
34
34
  },
35
- "include": ["./index.mjs", "./src", "./dev"]
35
+ "include": [
36
+ //
37
+ "./index.mjs",
38
+ // "./dev",
39
+ "./src"
40
+ ]
36
41
  }