@w5s/configurator-core 1.0.0-alpha.7 → 1.0.0-alpha.9
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/dist/index.cjs +199 -146
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +114 -91
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +114 -91
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +175 -147
- package/dist/index.js.map +1 -1
- package/package.json +5 -3
- package/src/FileMode.ts +14 -14
- package/src/__exists.ts +1 -1
- package/src/__toMode.ts +8 -8
- package/src/block.ts +51 -51
- package/src/directory.ts +14 -12
- package/src/exec.ts +23 -23
- package/src/file.ts +17 -15
- package/src/ignoreFile.ts +18 -18
- package/src/index.ts +2 -1
- package/src/json.ts +18 -18
- package/src/meta.ts +2 -2
- package/src/testing/getTempPath.ts +1 -0
- package/src/testing/getTestPath.ts +2 -1
- package/src/yaml.ts +45 -0
- package/src/yarnConfig.ts +13 -13
- package/src/yarnVersion.ts +10 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@w5s/configurator-core",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.9",
|
|
4
4
|
"description": "Core library for @w5s/configurator-core",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"config",
|
|
@@ -36,7 +36,9 @@
|
|
|
36
36
|
"scripts": {
|
|
37
37
|
"postpack": "clean-package restore"
|
|
38
38
|
},
|
|
39
|
-
"dependencies": {
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"yaml": "^2.9.0"
|
|
41
|
+
},
|
|
40
42
|
"engines": {
|
|
41
43
|
"node": ">=22.0.0"
|
|
42
44
|
},
|
|
@@ -44,5 +46,5 @@
|
|
|
44
46
|
"access": "public"
|
|
45
47
|
},
|
|
46
48
|
"sideEffect": false,
|
|
47
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "e6c63e0164ce2199e59bdca360f4766b6a78584d"
|
|
48
50
|
}
|
package/src/FileMode.ts
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
export interface
|
|
1
|
+
export interface FileMode {
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Group permissions
|
|
4
4
|
*/
|
|
5
|
-
readonly
|
|
5
|
+
readonly group?: FilePermissionSet;
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* Other permissions
|
|
9
9
|
*/
|
|
10
|
-
readonly
|
|
10
|
+
readonly other?: FilePermissionSet;
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
13
|
+
* Owner permissions
|
|
14
14
|
*/
|
|
15
|
-
readonly
|
|
15
|
+
readonly owner?: FilePermissionSet;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
export interface
|
|
18
|
+
export interface FilePermissionSet {
|
|
19
19
|
/**
|
|
20
|
-
*
|
|
20
|
+
* Execute permission
|
|
21
21
|
*/
|
|
22
|
-
readonly
|
|
22
|
+
readonly execute?: boolean;
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
|
-
*
|
|
25
|
+
* Read permission
|
|
26
26
|
*/
|
|
27
|
-
readonly
|
|
27
|
+
readonly read?: boolean;
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
|
-
*
|
|
30
|
+
* Write permission
|
|
31
31
|
*/
|
|
32
|
-
readonly
|
|
32
|
+
readonly write?: boolean;
|
|
33
33
|
}
|
package/src/__exists.ts
CHANGED
package/src/__toMode.ts
CHANGED
|
@@ -1,13 +1,5 @@
|
|
|
1
1
|
import type { FileMode, FilePermissionSet } from './FileMode.js';
|
|
2
2
|
|
|
3
|
-
function toModeFlag(permissionSet: FilePermissionSet | undefined, read: number, write: number, execute: number): number {
|
|
4
|
-
return (
|
|
5
|
-
(permissionSet?.read === true ? read : 0)
|
|
6
|
-
| (permissionSet?.write === true ? write : 0)
|
|
7
|
-
| (permissionSet?.execute === true ? execute : 0)
|
|
8
|
-
);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
3
|
export function __toMode(mode: FileMode | undefined): number | undefined {
|
|
12
4
|
return mode == null
|
|
13
5
|
? mode
|
|
@@ -17,3 +9,11 @@ export function __toMode(mode: FileMode | undefined): number | undefined {
|
|
|
17
9
|
| toModeFlag(mode.other, 0o004, 0o002, 0o001)
|
|
18
10
|
);
|
|
19
11
|
}
|
|
12
|
+
|
|
13
|
+
function toModeFlag(permissionSet: FilePermissionSet | undefined, read: number, write: number, execute: number): number {
|
|
14
|
+
return (
|
|
15
|
+
(permissionSet?.read === true ? read : 0)
|
|
16
|
+
| (permissionSet?.write === true ? write : 0)
|
|
17
|
+
| (permissionSet?.execute === true ? execute : 0)
|
|
18
|
+
);
|
|
19
|
+
}
|
package/src/block.ts
CHANGED
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
import { type FileOptions,
|
|
1
|
+
import { file, type FileOptions, fileSync } from './file.js';
|
|
2
2
|
|
|
3
3
|
export interface BlockOptions {
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* @default '# ${mark} MANAGED BLOCK'
|
|
5
|
+
* Block content to insert
|
|
8
6
|
*/
|
|
9
|
-
|
|
7
|
+
block: string;
|
|
10
8
|
|
|
11
9
|
/**
|
|
12
|
-
*
|
|
10
|
+
* Insert position
|
|
13
11
|
*/
|
|
14
|
-
|
|
12
|
+
insertPosition?: ['after', 'EndOfFile' | RegExp] | ['before', 'BeginningOfFile' | RegExp];
|
|
15
13
|
|
|
16
14
|
/**
|
|
17
|
-
*
|
|
15
|
+
* The marker builder function that will take either `markerBegin` or `markerEnd`
|
|
16
|
+
*
|
|
17
|
+
* @default '# ${mark} MANAGED BLOCK'
|
|
18
18
|
*/
|
|
19
|
-
|
|
19
|
+
marker?: (mark: 'Begin' | 'End') => string;
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
-
*
|
|
22
|
+
* File path
|
|
23
23
|
*/
|
|
24
|
-
|
|
24
|
+
path: string;
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* Block target state
|
|
28
28
|
*/
|
|
29
|
-
state?: '
|
|
29
|
+
state?: 'absent' | 'present';
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
const EOF = 'EndOfFile';
|
|
@@ -49,12 +49,38 @@ const matchLast = (string: string, regexp: RegExp) => {
|
|
|
49
49
|
return { firstIndex, lastIndex };
|
|
50
50
|
};
|
|
51
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Replace asynchronously a block in file that follows pattern :
|
|
54
|
+
*
|
|
55
|
+
* marker(markerBegin)
|
|
56
|
+
* ...
|
|
57
|
+
* marker(markerEnd)
|
|
58
|
+
*
|
|
59
|
+
* @param options
|
|
60
|
+
*/
|
|
61
|
+
export function block(options: BlockOptions) {
|
|
62
|
+
return file(toFileOptions(options));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Replace synchronously a block in file that follows pattern :
|
|
67
|
+
*
|
|
68
|
+
* marker(markerBegin)
|
|
69
|
+
* ...
|
|
70
|
+
* marker(markerEnd)
|
|
71
|
+
*
|
|
72
|
+
* @param options
|
|
73
|
+
*/
|
|
74
|
+
export function blockSync(options: BlockOptions) {
|
|
75
|
+
return fileSync(toFileOptions(options));
|
|
76
|
+
}
|
|
77
|
+
|
|
52
78
|
function toFileOptions(options: BlockOptions): FileOptions {
|
|
53
79
|
const {
|
|
54
|
-
marker = (mark) => `# ${mark.toUpperCase()} MANAGED BLOCK`,
|
|
55
|
-
path,
|
|
56
80
|
block: blockName,
|
|
57
81
|
insertPosition = ['after', EOF],
|
|
82
|
+
marker = (mark) => `# ${mark.toUpperCase()} MANAGED BLOCK`,
|
|
83
|
+
path,
|
|
58
84
|
state = 'present',
|
|
59
85
|
} = options;
|
|
60
86
|
|
|
@@ -89,17 +115,6 @@ function toFileOptions(options: BlockOptions): FileOptions {
|
|
|
89
115
|
return fullContent;
|
|
90
116
|
}
|
|
91
117
|
switch (positionDirection) {
|
|
92
|
-
case 'before': {
|
|
93
|
-
if (positionAnchor !== BOF) {
|
|
94
|
-
const { firstIndex } = matchLast(fullContent, positionAnchor);
|
|
95
|
-
if (firstIndex >= 0) {
|
|
96
|
-
return insertAt(fullContent, firstIndex, replaceBlock + EOL);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Beginning of file
|
|
101
|
-
return replaceBlock + EOL + fullContent;
|
|
102
|
-
}
|
|
103
118
|
case 'after': {
|
|
104
119
|
// insert
|
|
105
120
|
if (positionAnchor !== EOF) {
|
|
@@ -112,6 +127,17 @@ function toFileOptions(options: BlockOptions): FileOptions {
|
|
|
112
127
|
// end of file
|
|
113
128
|
return fullContent + EOL + replaceBlock;
|
|
114
129
|
}
|
|
130
|
+
case 'before': {
|
|
131
|
+
if (positionAnchor !== BOF) {
|
|
132
|
+
const { firstIndex } = matchLast(fullContent, positionAnchor);
|
|
133
|
+
if (firstIndex >= 0) {
|
|
134
|
+
return insertAt(fullContent, firstIndex, replaceBlock + EOL);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Beginning of file
|
|
139
|
+
return replaceBlock + EOL + fullContent;
|
|
140
|
+
}
|
|
115
141
|
|
|
116
142
|
default: {
|
|
117
143
|
throw new Error(`Unsupported position ${String(positionDirection)}`);
|
|
@@ -125,29 +151,3 @@ function toFileOptions(options: BlockOptions): FileOptions {
|
|
|
125
151
|
update: (sourceContent) => apply(sourceContent, blockName),
|
|
126
152
|
};
|
|
127
153
|
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Replace asynchronously a block in file that follows pattern :
|
|
131
|
-
*
|
|
132
|
-
* marker(markerBegin)
|
|
133
|
-
* ...
|
|
134
|
-
* marker(markerEnd)
|
|
135
|
-
*
|
|
136
|
-
* @param options
|
|
137
|
-
*/
|
|
138
|
-
export function block(options: BlockOptions) {
|
|
139
|
-
return file(toFileOptions(options));
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Replace synchronously a block in file that follows pattern :
|
|
144
|
-
*
|
|
145
|
-
* marker(markerBegin)
|
|
146
|
-
* ...
|
|
147
|
-
* marker(markerEnd)
|
|
148
|
-
*
|
|
149
|
-
* @param options
|
|
150
|
-
*/
|
|
151
|
-
export function blockSync(options: BlockOptions) {
|
|
152
|
-
return fileSync(toFileOptions(options));
|
|
153
|
-
}
|
package/src/directory.ts
CHANGED
|
@@ -1,25 +1,27 @@
|
|
|
1
1
|
import { chmodSync, mkdirSync, rmSync } from 'node:fs';
|
|
2
2
|
import { chmod, mkdir, rm } from 'node:fs/promises';
|
|
3
|
-
|
|
3
|
+
|
|
4
4
|
import type { FileMode } from './FileMode.js';
|
|
5
|
-
|
|
5
|
+
|
|
6
|
+
import { __exists } from './__exists.js';
|
|
6
7
|
import { __existsSync } from './__existsSync.js';
|
|
8
|
+
import { __toMode } from './__toMode.js';
|
|
7
9
|
|
|
8
10
|
export interface DirectoryOptions {
|
|
9
11
|
/**
|
|
10
|
-
*
|
|
12
|
+
* File permissions
|
|
11
13
|
*/
|
|
12
|
-
readonly
|
|
14
|
+
readonly mode?: FileMode;
|
|
13
15
|
|
|
14
16
|
/**
|
|
15
|
-
* Directory
|
|
17
|
+
* Directory path
|
|
16
18
|
*/
|
|
17
|
-
readonly
|
|
19
|
+
readonly path: string;
|
|
18
20
|
|
|
19
21
|
/**
|
|
20
|
-
*
|
|
22
|
+
* Directory target state
|
|
21
23
|
*/
|
|
22
|
-
readonly
|
|
24
|
+
readonly state: 'absent' | 'present';
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
/**
|
|
@@ -41,12 +43,12 @@ export interface DirectoryOptions {
|
|
|
41
43
|
* @param options
|
|
42
44
|
*/
|
|
43
45
|
export async function directory(options: DirectoryOptions): Promise<void> {
|
|
44
|
-
const { path, state
|
|
46
|
+
const { mode, path, state } = options;
|
|
45
47
|
const isPresent = await __exists(path);
|
|
46
48
|
if (state === 'present') {
|
|
47
49
|
const newMode = __toMode(mode);
|
|
48
50
|
if (!isPresent) {
|
|
49
|
-
await mkdir(path, {
|
|
51
|
+
await mkdir(path, { mode: newMode, recursive: true });
|
|
50
52
|
}
|
|
51
53
|
if (newMode != null && isPresent) {
|
|
52
54
|
await chmod(path, newMode);
|
|
@@ -75,12 +77,12 @@ export async function directory(options: DirectoryOptions): Promise<void> {
|
|
|
75
77
|
* @param options
|
|
76
78
|
*/
|
|
77
79
|
export function directorySync(options: DirectoryOptions): void {
|
|
78
|
-
const { path, state
|
|
80
|
+
const { mode, path, state } = options;
|
|
79
81
|
const isPresent = __existsSync(path);
|
|
80
82
|
if (state === 'present') {
|
|
81
83
|
const newMode = __toMode(mode);
|
|
82
84
|
if (!isPresent) {
|
|
83
|
-
mkdirSync(path, {
|
|
85
|
+
mkdirSync(path, { mode: newMode, recursive: true });
|
|
84
86
|
}
|
|
85
87
|
if (newMode != null && isPresent) {
|
|
86
88
|
chmodSync(path, newMode);
|
package/src/exec.ts
CHANGED
|
@@ -9,27 +9,7 @@ export interface ExecOptions {
|
|
|
9
9
|
/**
|
|
10
10
|
* Stdio options
|
|
11
11
|
*/
|
|
12
|
-
stdio?: '
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Runs a command in a shell and returns a promise that resolves with an object
|
|
17
|
-
* containing the stdout and stderr strings.
|
|
18
|
-
*
|
|
19
|
-
* @param command The command to run
|
|
20
|
-
* @param args The arguments to pass to the command
|
|
21
|
-
* @param options
|
|
22
|
-
* @returns A promise that resolves with an object like `{ stdout: string, stderr: string }`
|
|
23
|
-
*/
|
|
24
|
-
export function execSync(
|
|
25
|
-
command: string,
|
|
26
|
-
args: ReadonlyArray<string>,
|
|
27
|
-
options?: ExecOptions,
|
|
28
|
-
): { stdout: string; stderr: string } {
|
|
29
|
-
const result = spawnSync(command, args, { ...options });
|
|
30
|
-
const encoding = 'utf8';
|
|
31
|
-
|
|
32
|
-
return { stdout: result.stdout.toString(encoding), stderr: result.stderr.toString(encoding) };
|
|
12
|
+
stdio?: 'ignore' | 'inherit' | 'pipe';
|
|
33
13
|
}
|
|
34
14
|
|
|
35
15
|
/**
|
|
@@ -44,7 +24,7 @@ export async function exec(
|
|
|
44
24
|
command: string,
|
|
45
25
|
args: ReadonlyArray<string>,
|
|
46
26
|
options?: ExecOptions,
|
|
47
|
-
): Promise<{
|
|
27
|
+
): Promise<{ stderr: string; stdout: string }> {
|
|
48
28
|
return new Promise((resolve, reject) => {
|
|
49
29
|
const encoding = 'utf8';
|
|
50
30
|
const child = spawn(command, args, { ...options });
|
|
@@ -64,10 +44,30 @@ export async function exec(
|
|
|
64
44
|
}
|
|
65
45
|
// Handle process exit
|
|
66
46
|
child.on('close', (_code) => {
|
|
67
|
-
resolve({
|
|
47
|
+
resolve({ stderr, stdout });
|
|
68
48
|
});
|
|
69
49
|
|
|
70
50
|
// Handle errors
|
|
71
51
|
child.on('error', reject);
|
|
72
52
|
});
|
|
73
53
|
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Runs a command in a shell and returns a promise that resolves with an object
|
|
57
|
+
* containing the stdout and stderr strings.
|
|
58
|
+
*
|
|
59
|
+
* @param command The command to run
|
|
60
|
+
* @param args The arguments to pass to the command
|
|
61
|
+
* @param options
|
|
62
|
+
* @returns A promise that resolves with an object like `{ stdout: string, stderr: string }`
|
|
63
|
+
*/
|
|
64
|
+
export function execSync(
|
|
65
|
+
command: string,
|
|
66
|
+
args: ReadonlyArray<string>,
|
|
67
|
+
options?: ExecOptions,
|
|
68
|
+
): { stderr: string; stdout: string } {
|
|
69
|
+
const result = spawnSync(command, args, { ...options });
|
|
70
|
+
const encoding = 'utf8';
|
|
71
|
+
|
|
72
|
+
return { stderr: result.stderr.toString(encoding), stdout: result.stdout.toString(encoding) };
|
|
73
|
+
}
|
package/src/file.ts
CHANGED
|
@@ -1,36 +1,38 @@
|
|
|
1
|
-
import { chmod, readFile, rm, writeFile } from 'node:fs/promises';
|
|
2
1
|
import { chmodSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { chmod, readFile, rm, writeFile } from 'node:fs/promises';
|
|
3
|
+
|
|
4
|
+
import type { FileMode } from './FileMode.js';
|
|
5
|
+
|
|
3
6
|
import { __exists } from './__exists.js';
|
|
4
7
|
import { __existsSync } from './__existsSync.js';
|
|
5
|
-
import type { FileMode } from './FileMode.js';
|
|
6
8
|
import { __toMode } from './__toMode.js';
|
|
7
9
|
|
|
8
10
|
export interface FileOptions {
|
|
9
11
|
/**
|
|
10
|
-
* File
|
|
12
|
+
* File encoding
|
|
11
13
|
*/
|
|
12
|
-
readonly
|
|
14
|
+
readonly encoding?: BufferEncoding;
|
|
13
15
|
|
|
14
16
|
/**
|
|
15
|
-
* File
|
|
17
|
+
* File permissions
|
|
16
18
|
*/
|
|
17
|
-
readonly
|
|
19
|
+
readonly mode?: FileMode;
|
|
18
20
|
|
|
19
21
|
/**
|
|
20
|
-
* File
|
|
21
|
-
*
|
|
22
|
+
* File path
|
|
22
23
|
*/
|
|
23
|
-
readonly
|
|
24
|
+
readonly path: string;
|
|
24
25
|
|
|
25
26
|
/**
|
|
26
|
-
* File
|
|
27
|
+
* File target state
|
|
27
28
|
*/
|
|
28
|
-
readonly
|
|
29
|
+
readonly state: 'absent' | 'present';
|
|
29
30
|
|
|
30
31
|
/**
|
|
31
|
-
* File
|
|
32
|
+
* File content mapping function
|
|
33
|
+
*
|
|
32
34
|
*/
|
|
33
|
-
readonly
|
|
35
|
+
readonly update?: ((content: string) => string | undefined) | undefined;
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
/**
|
|
@@ -53,7 +55,7 @@ export interface FileOptions {
|
|
|
53
55
|
* @param options
|
|
54
56
|
*/
|
|
55
57
|
export async function file(options: FileOptions): Promise<void> {
|
|
56
|
-
const {
|
|
58
|
+
const { encoding = 'utf8', mode, path, state, update } = options;
|
|
57
59
|
if (state === 'present') {
|
|
58
60
|
const isPresent = await __exists(path);
|
|
59
61
|
const previousContent = isPresent ? await readFile(path, encoding) : '';
|
|
@@ -90,7 +92,7 @@ export async function file(options: FileOptions): Promise<void> {
|
|
|
90
92
|
* @param options
|
|
91
93
|
*/
|
|
92
94
|
export function fileSync(options: FileOptions): void {
|
|
93
|
-
const {
|
|
95
|
+
const { encoding = 'utf8', mode, path, state, update } = options;
|
|
94
96
|
if (state === 'present') {
|
|
95
97
|
const isPresent = __existsSync(path);
|
|
96
98
|
const previousContent = isPresent ? readFileSync(path, encoding) : '';
|
package/src/ignoreFile.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type FileOptions,
|
|
1
|
+
import { file, type FileOptions, fileSync } from './file.js';
|
|
2
2
|
|
|
3
3
|
export interface IgnoreFileOptions extends Omit<FileOptions, 'update'> {
|
|
4
4
|
/**
|
|
@@ -8,23 +8,6 @@ export interface IgnoreFileOptions extends Omit<FileOptions, 'update'> {
|
|
|
8
8
|
readonly update?: ((content: string[] | undefined) => string[] | undefined) | undefined;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
function toFileOption({ update, ...otherOptions }: IgnoreFileOptions): FileOptions {
|
|
12
|
-
return {
|
|
13
|
-
...otherOptions,
|
|
14
|
-
|
|
15
|
-
update:
|
|
16
|
-
update == null
|
|
17
|
-
? update
|
|
18
|
-
: (content) => {
|
|
19
|
-
const eol = content.includes('\r\n') ? '\r\n' : '\n';
|
|
20
|
-
const lines = content === '' ? undefined : content.split(eol);
|
|
21
|
-
const updatedLines = update(lines);
|
|
22
|
-
|
|
23
|
-
return updatedLines == null ? undefined : updatedLines.join(eol);
|
|
24
|
-
},
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
|
|
28
11
|
/**
|
|
29
12
|
* Ensure file is present/absent asynchronously with content initialized or modified by line.
|
|
30
13
|
*
|
|
@@ -56,3 +39,20 @@ export async function ignoreFile(options: IgnoreFileOptions): Promise<void> {
|
|
|
56
39
|
export function ignoreFileSync(options: IgnoreFileOptions): void {
|
|
57
40
|
return fileSync(toFileOption(options));
|
|
58
41
|
}
|
|
42
|
+
|
|
43
|
+
function toFileOption({ update, ...otherOptions }: IgnoreFileOptions): FileOptions {
|
|
44
|
+
return {
|
|
45
|
+
...otherOptions,
|
|
46
|
+
|
|
47
|
+
update:
|
|
48
|
+
update == null
|
|
49
|
+
? update
|
|
50
|
+
: (content) => {
|
|
51
|
+
const eol = content.includes('\r\n') ? '\r\n' : '\n';
|
|
52
|
+
const lines = content === '' ? undefined : content.split(eol);
|
|
53
|
+
const updatedLines = update(lines);
|
|
54
|
+
|
|
55
|
+
return updatedLines == null ? undefined : updatedLines.join(eol);
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
export * from './directory.js';
|
|
2
1
|
export * from './block.js';
|
|
2
|
+
export * from './directory.js';
|
|
3
3
|
export * from './file.js';
|
|
4
4
|
export * from './ignoreFile.js';
|
|
5
5
|
export * from './json.js';
|
|
6
6
|
export * from './meta.js';
|
|
7
|
+
export * from './yaml.js';
|
|
7
8
|
export * from './yarnConfig.js';
|
|
8
9
|
export * from './yarnVersion.js';
|
package/src/json.ts
CHANGED
|
@@ -1,28 +1,13 @@
|
|
|
1
|
-
import { type FileOptions,
|
|
2
|
-
|
|
3
|
-
export type JSONValue = null | number | string | boolean | JSONValue[] | { [key: string]: JSONValue };
|
|
1
|
+
import { file, type FileOptions, fileSync } from './file.js';
|
|
4
2
|
|
|
5
3
|
export interface JSONOption<V = JSONValue> extends Omit<FileOptions, 'update'> {
|
|
6
4
|
/**
|
|
7
5
|
* File content mapping function
|
|
8
6
|
*/
|
|
9
|
-
readonly update?: ((content:
|
|
7
|
+
readonly update?: ((content: undefined | V) => undefined | V) | undefined;
|
|
10
8
|
}
|
|
11
9
|
|
|
12
|
-
|
|
13
|
-
return {
|
|
14
|
-
...otherOptions,
|
|
15
|
-
|
|
16
|
-
update:
|
|
17
|
-
update == null
|
|
18
|
-
? update
|
|
19
|
-
: (content) => {
|
|
20
|
-
const jsonValue = content === '' ? undefined : (JSON.parse(content) as Value);
|
|
21
|
-
|
|
22
|
-
return JSON.stringify(update(jsonValue));
|
|
23
|
-
},
|
|
24
|
-
};
|
|
25
|
-
}
|
|
10
|
+
export type JSONValue = boolean | JSONValue[] | null | number | string | { [key: string]: JSONValue };
|
|
26
11
|
|
|
27
12
|
/**
|
|
28
13
|
* Ensure file is present/absent asynchronously with content value initialized or modified with `update`
|
|
@@ -41,3 +26,18 @@ export async function json<Value>(options: JSONOption<Value>): Promise<void> {
|
|
|
41
26
|
export function jsonSync<Value>(options: JSONOption<Value>): void {
|
|
42
27
|
return fileSync(toFileOption(options));
|
|
43
28
|
}
|
|
29
|
+
|
|
30
|
+
function toFileOption<Value>({ update, ...otherOptions }: JSONOption<Value>): FileOptions {
|
|
31
|
+
return {
|
|
32
|
+
...otherOptions,
|
|
33
|
+
|
|
34
|
+
update:
|
|
35
|
+
update == null
|
|
36
|
+
? update
|
|
37
|
+
: (content) => {
|
|
38
|
+
const jsonValue = content === '' ? undefined : (JSON.parse(content) as Value);
|
|
39
|
+
|
|
40
|
+
return JSON.stringify(update(jsonValue));
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
}
|
package/src/meta.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export const meta = Object.freeze({
|
|
2
|
+
// @ts-ignore - these variables are injected at build time
|
|
3
|
+
buildNumber: 1 as number, // (typeof __PACKAGE_BUILD_NUMBER__ === 'undefined' ? 0 : __PACKAGE_BUILD_NUMBER__) as number,
|
|
2
4
|
// @ts-ignore - these variables are injected at build time
|
|
3
5
|
name: (typeof __PACKAGE_NAME__ === 'undefined' ? '' : __PACKAGE_NAME__) as string,
|
|
4
6
|
// @ts-ignore - these variables are injected at build time
|
|
5
7
|
version: (typeof __PACKAGE_VERSION__ === 'undefined' ? '' : __PACKAGE_VERSION__) as string,
|
|
6
|
-
// @ts-ignore - these variables are injected at build time
|
|
7
|
-
buildNumber: 1 as number, // (typeof __PACKAGE_BUILD_NUMBER__ === 'undefined' ? 0 : __PACKAGE_BUILD_NUMBER__) as number,
|
|
8
8
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { mkdir, rm } from 'node:fs/promises';
|
|
1
2
|
import path from 'node:path';
|
|
2
3
|
import { afterAll, beforeAll } from 'vitest';
|
|
3
|
-
|
|
4
|
+
|
|
4
5
|
import { getTempPath } from './getTempPath.js';
|
|
5
6
|
|
|
6
7
|
export function getTestPath(prefix: string, remove = true) {
|
package/src/yaml.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import YAML from 'yaml';
|
|
2
|
+
|
|
3
|
+
import { file, type FileOptions, fileSync } from './file.js';
|
|
4
|
+
|
|
5
|
+
export interface YAMLOption<V = YAMLValue> extends Omit<FileOptions, 'update'> {
|
|
6
|
+
/**
|
|
7
|
+
* File content mapping function
|
|
8
|
+
*/
|
|
9
|
+
readonly update?: ((content: undefined | V) => undefined | V) | undefined;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type YAMLValue = boolean | null | number | string | YAMLValue[] | { [key: string]: YAMLValue };
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Ensure file is present/absent asynchronously with content value initialized or modified with `update`
|
|
16
|
+
*
|
|
17
|
+
* @param options
|
|
18
|
+
*/
|
|
19
|
+
export async function yaml<Value>(options: YAMLOption<Value>): Promise<void> {
|
|
20
|
+
return file(toFileOption(options));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Ensure file is present/absent synchronously with content value initialized or modified with `update`
|
|
25
|
+
*
|
|
26
|
+
* @param options
|
|
27
|
+
*/
|
|
28
|
+
export function yamlSync<Value>(options: YAMLOption<Value>): void {
|
|
29
|
+
return fileSync(toFileOption(options));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function toFileOption<Value>({ update, ...otherOptions }: YAMLOption<Value>): FileOptions {
|
|
33
|
+
return {
|
|
34
|
+
...otherOptions,
|
|
35
|
+
|
|
36
|
+
update:
|
|
37
|
+
update == null
|
|
38
|
+
? update
|
|
39
|
+
: (content) => {
|
|
40
|
+
const yamlValue = content === '' ? undefined : (YAML.parse(content) as Value);
|
|
41
|
+
|
|
42
|
+
return YAML.stringify(update(yamlValue));
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|