@w5s/dev 2.3.0 → 2.5.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.
package/src/exec.ts ADDED
@@ -0,0 +1,73 @@
1
+ import { spawn, spawnSync } from 'node:child_process';
2
+
3
+ export interface ExecOptions {
4
+ /**
5
+ * Current working directory
6
+ */
7
+ cwd?: string;
8
+ /**
9
+ * Stdio options
10
+ */
11
+ stdio?: 'inherit' | 'pipe' | 'ignore';
12
+ }
13
+
14
+ /**
15
+ * Runs a command in a shell and returns a promise that resolves with an object
16
+ * containing the stdout and stderr strings.
17
+ *
18
+ * @param command - The command to run
19
+ * @param args - The arguments to pass to the command
20
+ * @returns A promise that resolves with an object like `{ stdout: string, stderr: string }`
21
+ */
22
+ export function execSync(
23
+ command: string,
24
+ args: ReadonlyArray<string>,
25
+ options?: ExecOptions,
26
+ ): { stdout: string; stderr: string } {
27
+ const result = spawnSync(command, args, { ...options });
28
+ const encoding = 'utf8';
29
+
30
+ return { stdout: result.stdout.toString(encoding), stderr: result.stderr.toString(encoding) };
31
+ }
32
+
33
+ /**
34
+ * Runs a command in a shell and returns a promise that resolves with an object
35
+ * containing the stdout and stderr strings.
36
+ *
37
+ * @param command - The command to run
38
+ * @param args - The arguments to pass to the command
39
+ * @returns A promise that resolves with an object containing the stdout and stderr strings
40
+ */
41
+ export async function exec(
42
+ command: string,
43
+ args: ReadonlyArray<string>,
44
+ options?: ExecOptions,
45
+ ): Promise<{ stdout: string; stderr: string }> {
46
+ return new Promise((resolve, reject) => {
47
+ const encoding = 'utf8';
48
+ const child = spawn(command, args, { ...options });
49
+ let stdout = '';
50
+ let stderr = '';
51
+
52
+ // Capture the stdout and stderr streams
53
+ if (child.stdout != null) {
54
+ child.stdout.on('data', (data) => {
55
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
56
+ stdout += data.toString(encoding);
57
+ });
58
+ }
59
+ if (child.stderr != null) {
60
+ child.stderr.on('data', (data) => {
61
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
62
+ stderr += data.toString(encoding);
63
+ });
64
+ }
65
+ // Handle process exit
66
+ child.on('close', (_code) => {
67
+ resolve({ stdout, stderr });
68
+ });
69
+
70
+ // Handle errors
71
+ child.on('error', reject);
72
+ });
73
+ }
package/src/index.ts CHANGED
@@ -1,7 +1,11 @@
1
1
  export * from './directory.js';
2
- export * from './eslint.js';
2
+ export * from './ESLintConfig.js';
3
3
  export * from './block.js';
4
4
  export * from './file.js';
5
+ export * from './interopDefault.js';
6
+ export * from './LanguageId.js';
5
7
  export * from './json.js';
6
- export * from './project.js';
7
- export * from './projectScript.js';
8
+ export * from './Project.js';
9
+ export * from './ProjectScript.js';
10
+ export * from './yarnConfig.js';
11
+ export * from './yarnVersion.js';
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Resolves a module or promise-like object, returning the default export if available.
3
+ *
4
+ * @example
5
+ * ```ts
6
+ * await interopDefault(import('./module'));// Can be a commonjs or esm module
7
+ * ```
8
+ *
9
+ * @template T - The type of the module or promise-like object.
10
+ * @param {T | PromiseLike<T>} m - The module or promise-like object to resolve.
11
+ * @returns {Promise<T extends { default: infer U } ? U : T>} A promise resolving to the default export if present, otherwise the module itself.
12
+ */
13
+
14
+ export async function interopDefault<T>(m: T | PromiseLike<T>): Promise<T extends { default: infer U } ? U : T> {
15
+ const resolved = await m;
16
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access
17
+ return (resolved as any).default ?? resolved;
18
+ }
@@ -0,0 +1,60 @@
1
+ import { exec, execSync } from './exec.js';
2
+
3
+ export interface YarnConfigOptions {
4
+ /**
5
+ * Configuration key
6
+ */
7
+ readonly key: string;
8
+
9
+ /**
10
+ * Option target state
11
+ */
12
+ readonly state: 'present' | 'absent';
13
+
14
+ /**
15
+ * File content mapping function
16
+ *
17
+ * @param content
18
+ */
19
+ readonly update?: ((content: string) => string | undefined) | undefined;
20
+ }
21
+
22
+ /**
23
+ * Synchronous version of {@link yarnConfig}
24
+ *
25
+ * @example
26
+ * yarnConfigSync({
27
+ * key: 'nodeLinker',
28
+ * state: 'present',
29
+ * update: (content) => content.replace('node-modules', 'hoisted'),
30
+ * })
31
+ */
32
+ export function yarnConfigSync(options: YarnConfigOptions) {
33
+ const { key, state, update } = options;
34
+ if (state === 'present') {
35
+ const { stdout } = execSync('yarn', ['config', 'get', String(key)]);
36
+ execSync('yarn', ['config', 'set', String(key), `${update == null ? '' : update(stdout)}`]);
37
+ } else {
38
+ execSync('yarn', ['config', 'unset']);
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Set/Unset yarn configuration value
44
+ *
45
+ * @example
46
+ * await yarnConfig({
47
+ * key: 'nodeLinker',
48
+ * state: 'present',
49
+ * update: (content) => content.replace('node-modules', 'hoisted'),
50
+ * })
51
+ */
52
+ export async function yarnConfig(options: YarnConfigOptions): Promise<void> {
53
+ const { key, state, update } = options;
54
+ if (state === 'present') {
55
+ const { stdout } = await exec('yarn', ['config', 'get', String(key)]);
56
+ await exec('yarn', ['config', 'set', String(key), `${update == null ? '' : update(stdout)}`]);
57
+ } else {
58
+ await exec('yarn', ['config', 'unset']);
59
+ }
60
+ }
@@ -0,0 +1,55 @@
1
+ import { exec, execSync } from './exec.js';
2
+
3
+ export type YarnVersionKind = 'berry' | 'classic';
4
+
5
+ export interface YarnVersionOptions {
6
+ /**
7
+ * Option target state
8
+ */
9
+ readonly state: 'present' | 'absent';
10
+
11
+ /**
12
+ * Version mapping function
13
+ *
14
+ * @param content
15
+ */
16
+ readonly update?: (() => YarnVersionKind | undefined) | undefined;
17
+ }
18
+
19
+ /**
20
+ * Synchronous version of {@link yarnVersion}
21
+ *
22
+ * @example
23
+ * yarnVersionSync({
24
+ * state: 'present',
25
+ * update: () => 'berry', // or 'classic'
26
+ * })
27
+ */
28
+ export function yarnVersionSync(options: YarnVersionOptions) {
29
+ const { state, update } = options;
30
+ if (state === 'present') {
31
+ execSync('yarn', ['set', 'version', `${update == null ? 'berry' : update()}`]);
32
+ } else {
33
+ // TODO: remove yarn.lock
34
+ throw new Error('Not implemented');
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Set/Unset yarn configuration value
40
+ *
41
+ * @example
42
+ * await yarnVersion({
43
+ * state: 'present',
44
+ * update: () => 'berry', // or 'classic'
45
+ * })
46
+ */
47
+ export async function yarnVersion(options: YarnVersionOptions): Promise<void> {
48
+ const { state, update } = options;
49
+ if (state === 'present') {
50
+ await exec('yarn', ['set', 'version', `${update == null ? 'berry' : update()}`]);
51
+ } else {
52
+ // TODO: remove yarn.lock
53
+ throw new Error('Not implemented');
54
+ }
55
+ }
File without changes