@mux-magic/tools 0.1.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/package.json +37 -0
- package/src/__fixtures__/badBooleanName.ts +2 -0
- package/src/aclSafeCopyFile.test.ts +136 -0
- package/src/aclSafeCopyFile.ts +136 -0
- package/src/addFolderNameBeforeFilename.ts +13 -0
- package/src/captureConsoleMessage.test.ts +127 -0
- package/src/captureConsoleMessage.ts +22 -0
- package/src/captureLogMessage.ts +11 -0
- package/src/cleanupFilename.test.ts +26 -0
- package/src/cleanupFilename.ts +14 -0
- package/src/createRenameFileOrFolder.test.ts +220 -0
- package/src/createRenameFileOrFolder.ts +79 -0
- package/src/eslintBooleanPrefixRule.test.ts +30 -0
- package/src/eslintWebtypesGuardRule.test.ts +26 -0
- package/src/getFiles.ts +72 -0
- package/src/getFilesAtDepth.test.ts +158 -0
- package/src/getFilesAtDepth.ts +32 -0
- package/src/getFolder.test.ts +90 -0
- package/src/getFolder.ts +74 -0
- package/src/index.ts +60 -0
- package/src/insertIntoArray.test.ts +35 -0
- package/src/insertIntoArray.ts +10 -0
- package/src/listDirectoryEntries.ts +56 -0
- package/src/logAndRethrowPipelineError.test.ts +53 -0
- package/src/logAndRethrowPipelineError.ts +26 -0
- package/src/logAndSwallowPipelineError.test.ts +60 -0
- package/src/logAndSwallowPipelineError.ts +26 -0
- package/src/logMessage.test.ts +207 -0
- package/src/logMessage.ts +143 -0
- package/src/makeDirectory.test.ts +71 -0
- package/src/makeDirectory.ts +7 -0
- package/src/naturalSort.ts +8 -0
- package/src/replaceFileExtension.ts +9 -0
- package/src/test-runners.ts +43 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type BackgroundColorName,
|
|
3
|
+
Chalk,
|
|
4
|
+
type ChalkInstance,
|
|
5
|
+
type ColorName,
|
|
6
|
+
type ForegroundColorName,
|
|
7
|
+
} from "chalk"
|
|
8
|
+
|
|
9
|
+
export const createAddColorToChalk =
|
|
10
|
+
(chalkColor?: ColorName) =>
|
|
11
|
+
(chalkInstance: ChalkInstance) =>
|
|
12
|
+
chalkColor && chalkColor in chalkInstance
|
|
13
|
+
? chalkInstance[chalkColor]
|
|
14
|
+
: chalkInstance
|
|
15
|
+
|
|
16
|
+
export const messageTemplate = {
|
|
17
|
+
comparison: (firstItem: string, secondItem: string) =>
|
|
18
|
+
[firstItem].concat("\n", secondItem),
|
|
19
|
+
descriptiveComparison: (
|
|
20
|
+
description: unknown,
|
|
21
|
+
firstItem: string,
|
|
22
|
+
secondItem: string,
|
|
23
|
+
) =>
|
|
24
|
+
[description].concat(
|
|
25
|
+
"\n",
|
|
26
|
+
"\n",
|
|
27
|
+
firstItem,
|
|
28
|
+
"\n",
|
|
29
|
+
secondItem,
|
|
30
|
+
),
|
|
31
|
+
// Description followed by N items, each separated by a newline. Useful for
|
|
32
|
+
// download-summary logs and batch-result reports where the caller has a
|
|
33
|
+
// header line plus a variable-length list of details.
|
|
34
|
+
multipleItems: (description: string, items: string[]) =>
|
|
35
|
+
[description].concat(
|
|
36
|
+
"\n",
|
|
37
|
+
items.flatMap((item) => [item].concat("\n")),
|
|
38
|
+
),
|
|
39
|
+
noItems: () => [],
|
|
40
|
+
singleItem: (item: unknown) => [item],
|
|
41
|
+
} as const
|
|
42
|
+
|
|
43
|
+
const numericalMessageTemplateFallback = {
|
|
44
|
+
0: messageTemplate.noItems,
|
|
45
|
+
1: messageTemplate.singleItem,
|
|
46
|
+
2: messageTemplate.comparison,
|
|
47
|
+
3: messageTemplate.descriptiveComparison,
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export const createLogMessage =
|
|
51
|
+
<TemplateName extends keyof typeof messageTemplate>({
|
|
52
|
+
logType,
|
|
53
|
+
templateName,
|
|
54
|
+
titleBackgroundColor,
|
|
55
|
+
titleTextColor,
|
|
56
|
+
}: {
|
|
57
|
+
logType: "error" | "info" | "log" | "warn"
|
|
58
|
+
templateName?: TemplateName
|
|
59
|
+
titleBackgroundColor?: BackgroundColorName
|
|
60
|
+
titleTextColor?: ForegroundColorName
|
|
61
|
+
}) =>
|
|
62
|
+
(
|
|
63
|
+
title: string,
|
|
64
|
+
...content: Parameters<
|
|
65
|
+
(typeof messageTemplate)[TemplateName]
|
|
66
|
+
>
|
|
67
|
+
) => {
|
|
68
|
+
const optionallyColoredChalk = createAddColorToChalk(
|
|
69
|
+
titleBackgroundColor,
|
|
70
|
+
)(createAddColorToChalk(titleTextColor)(new Chalk()))
|
|
71
|
+
|
|
72
|
+
// Fallback dispatch when no templateName is set: a description string +
|
|
73
|
+
// an array of items at positions 0 and 1 is the multipleItems shape.
|
|
74
|
+
// Otherwise pick a template by arity.
|
|
75
|
+
const message = templateName
|
|
76
|
+
? messageTemplate[templateName](
|
|
77
|
+
// @ts-expect-error A spread argument must either have a tuple type or be passed to a rest parameter.ts(2556)
|
|
78
|
+
...content,
|
|
79
|
+
)
|
|
80
|
+
: content.at(0) !== undefined &&
|
|
81
|
+
Array.isArray(content.at(1))
|
|
82
|
+
? messageTemplate.multipleItems(
|
|
83
|
+
// @ts-expect-error A spread argument must either have a tuple type or be passed to a rest parameter.ts(2556)
|
|
84
|
+
...content,
|
|
85
|
+
)
|
|
86
|
+
: content.length in numericalMessageTemplateFallback
|
|
87
|
+
? numericalMessageTemplateFallback[
|
|
88
|
+
content.length
|
|
89
|
+
](
|
|
90
|
+
// @ts-expect-error A spread argument must either have a tuple type or be passed to a rest parameter.ts(2556)
|
|
91
|
+
...content,
|
|
92
|
+
)
|
|
93
|
+
: null
|
|
94
|
+
|
|
95
|
+
console[logType](
|
|
96
|
+
optionallyColoredChalk(`[${title}]`),
|
|
97
|
+
"\n",
|
|
98
|
+
...(message || content),
|
|
99
|
+
// (
|
|
100
|
+
// (
|
|
101
|
+
// content
|
|
102
|
+
// .length
|
|
103
|
+
// )
|
|
104
|
+
// ? (
|
|
105
|
+
// content
|
|
106
|
+
// .slice(0, 2)
|
|
107
|
+
// .join("\n\n")
|
|
108
|
+
// )
|
|
109
|
+
// ),
|
|
110
|
+
// ...(
|
|
111
|
+
// (
|
|
112
|
+
// 2 in content
|
|
113
|
+
// )
|
|
114
|
+
// ? (
|
|
115
|
+
// ["\n"]
|
|
116
|
+
// .concat(
|
|
117
|
+
// content
|
|
118
|
+
// .slice(2)
|
|
119
|
+
// .join("\n")
|
|
120
|
+
// )
|
|
121
|
+
// )
|
|
122
|
+
// : ""
|
|
123
|
+
// ),
|
|
124
|
+
"\n",
|
|
125
|
+
"\n",
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export const logError = createLogMessage({
|
|
130
|
+
logType: "error",
|
|
131
|
+
titleTextColor: "red",
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
export const logInfo = createLogMessage({
|
|
135
|
+
logType: "info",
|
|
136
|
+
titleTextColor: "green",
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
export const logWarning = createLogMessage({
|
|
140
|
+
logType: "warn",
|
|
141
|
+
titleBackgroundColor: "bgYellowBright",
|
|
142
|
+
titleTextColor: "black",
|
|
143
|
+
})
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { dirname } from "node:path"
|
|
2
|
+
import { vol } from "memfs"
|
|
3
|
+
import { firstValueFrom } from "rxjs"
|
|
4
|
+
import { beforeEach, describe, expect, test } from "vitest"
|
|
5
|
+
|
|
6
|
+
import { makeDirectory } from "./makeDirectory.js"
|
|
7
|
+
|
|
8
|
+
describe(makeDirectory.name, () => {
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
vol.fromJSON({
|
|
11
|
+
"/movies/Star Wars (1977)/Star Wars (1977).mkv": "",
|
|
12
|
+
})
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
test("creates the parent directory when caller passes dirname of a file path", async () => {
|
|
16
|
+
const filePath =
|
|
17
|
+
"/movies/Super Mario Bros (1993)/Super Mario Bros (1993).mkv"
|
|
18
|
+
|
|
19
|
+
await firstValueFrom(makeDirectory(dirname(filePath)))
|
|
20
|
+
|
|
21
|
+
await expect(
|
|
22
|
+
new Promise((resolve, reject) => {
|
|
23
|
+
vol.readdir(
|
|
24
|
+
"/movies",
|
|
25
|
+
(error: unknown, data: unknown) => {
|
|
26
|
+
if (error) {
|
|
27
|
+
reject(error)
|
|
28
|
+
} else {
|
|
29
|
+
resolve(data)
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
)
|
|
33
|
+
}),
|
|
34
|
+
).resolves.toEqual([
|
|
35
|
+
"Star Wars (1977)",
|
|
36
|
+
"Super Mario Bros (1993)",
|
|
37
|
+
])
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
test("creates the directory itself given a path with no file extension", async () => {
|
|
41
|
+
const folderPath = "/movies/Super Mario Bros (1993)"
|
|
42
|
+
|
|
43
|
+
await firstValueFrom(makeDirectory(folderPath))
|
|
44
|
+
|
|
45
|
+
await expect(
|
|
46
|
+
new Promise((resolve, reject) => {
|
|
47
|
+
vol.readdir(
|
|
48
|
+
"/movies",
|
|
49
|
+
(error: unknown, data: unknown) => {
|
|
50
|
+
if (error) {
|
|
51
|
+
reject(error)
|
|
52
|
+
} else {
|
|
53
|
+
resolve(data)
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
)
|
|
57
|
+
}),
|
|
58
|
+
).resolves.toEqual([
|
|
59
|
+
"Star Wars (1977)",
|
|
60
|
+
"Super Mario Bros (1993)",
|
|
61
|
+
])
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
test("emits the directory path so callers can chain off of it", async () => {
|
|
65
|
+
const folderPath = "/movies/Tron (1982)"
|
|
66
|
+
|
|
67
|
+
await expect(
|
|
68
|
+
firstValueFrom(makeDirectory(folderPath)),
|
|
69
|
+
).resolves.toBe(folderPath)
|
|
70
|
+
})
|
|
71
|
+
})
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {
|
|
2
|
+
firstValueFrom,
|
|
3
|
+
type Observable,
|
|
4
|
+
type Observer,
|
|
5
|
+
type OperatorFunction,
|
|
6
|
+
of,
|
|
7
|
+
} from "rxjs"
|
|
8
|
+
import {
|
|
9
|
+
type RunHelpers,
|
|
10
|
+
TestScheduler,
|
|
11
|
+
} from "rxjs/testing"
|
|
12
|
+
import { expect } from "vitest"
|
|
13
|
+
|
|
14
|
+
export const getOperatorValue = <InputValue, OutputValue>(
|
|
15
|
+
operator: OperatorFunction<InputValue, OutputValue>,
|
|
16
|
+
...inputValues: InputValue[]
|
|
17
|
+
) => firstValueFrom(of(...inputValues).pipe(operator))
|
|
18
|
+
|
|
19
|
+
export const runPromiseScheduler = <ObservableValue>({
|
|
20
|
+
getSubscriber,
|
|
21
|
+
observable,
|
|
22
|
+
}: {
|
|
23
|
+
getSubscriber: (
|
|
24
|
+
resolve: () => void,
|
|
25
|
+
reject: () => void,
|
|
26
|
+
) => Observer<ObservableValue>
|
|
27
|
+
observable: Observable<ObservableValue>
|
|
28
|
+
}) =>
|
|
29
|
+
new Promise<void>((resolve, reject) => {
|
|
30
|
+
observable.subscribe(getSubscriber(resolve, reject))
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
export const runTestScheduler = <ReturnValue>(
|
|
34
|
+
testRunner: (helpers: RunHelpers) => ReturnValue,
|
|
35
|
+
) => {
|
|
36
|
+
const testScheduler = new TestScheduler(
|
|
37
|
+
(actual, expected) => {
|
|
38
|
+
expect(actual).toEqual(expected)
|
|
39
|
+
},
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
return testScheduler.run<ReturnValue>(testRunner)
|
|
43
|
+
}
|