@caleuche/cli 0.2.3 → 0.3.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/CHANGELOG.md +12 -0
- package/dist/batch.js +50 -45
- package/dist/common.js +1 -1
- package/dist/utils.js +25 -9
- package/package.json +1 -1
- package/src/batch.ts +73 -58
- package/src/common.ts +2 -1
- package/src/interfaces.ts +27 -10
- package/src/utils.ts +32 -12
- package/test/bach.test.ts +69 -54
- package/test/common.test.ts +3 -19
- package/test/compile.test.ts +9 -7
package/CHANGELOG.md
CHANGED
package/dist/batch.js
CHANGED
|
@@ -4,95 +4,100 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.batchCompile = batchCompile;
|
|
7
|
-
const fs_1 = __importDefault(require("fs"));
|
|
8
7
|
const utils_1 = require("./utils");
|
|
9
8
|
const common_1 = require("./common");
|
|
10
9
|
const path_1 = __importDefault(require("path"));
|
|
11
|
-
function
|
|
12
|
-
if ((0, utils_1.
|
|
13
|
-
return
|
|
10
|
+
function loadVariantInputDefinition(variantInput, workingDirectory) {
|
|
11
|
+
if ((0, utils_1.isVariantInputDefinition)(variantInput)) {
|
|
12
|
+
return variantInput;
|
|
14
13
|
}
|
|
15
|
-
else
|
|
16
|
-
const
|
|
17
|
-
if (
|
|
18
|
-
|
|
14
|
+
else {
|
|
15
|
+
const absolutePath = path_1.default.join(workingDirectory, variantInput.value);
|
|
16
|
+
if ((0, utils_1.isFile)(absolutePath)) {
|
|
17
|
+
const v = (0, utils_1.parse)(absolutePath);
|
|
18
|
+
if (!v) {
|
|
19
|
+
console.error(`Failed to parse variant at path: ${absolutePath}`);
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
return v;
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
console.error(`Variant input path "${variantInput.value}" does not exist or is not a file.`);
|
|
19
26
|
return null;
|
|
20
27
|
}
|
|
21
|
-
return v;
|
|
22
28
|
}
|
|
23
|
-
return null;
|
|
24
29
|
}
|
|
25
|
-
function loadVariantDefinitions(variants) {
|
|
30
|
+
function loadVariantDefinitions(variants, workingDirectory) {
|
|
26
31
|
if (!variants)
|
|
27
32
|
return {};
|
|
28
33
|
const definitions = {};
|
|
29
|
-
for (const
|
|
30
|
-
const v =
|
|
34
|
+
for (const { name, input } of variants) {
|
|
35
|
+
const v = loadVariantInputDefinition(input, workingDirectory);
|
|
31
36
|
if (!v) {
|
|
32
|
-
console.error(`Failed to load variant definition for key "${
|
|
37
|
+
console.error(`Failed to load variant definition for key "${name}": ${input}`);
|
|
33
38
|
return null;
|
|
34
39
|
}
|
|
35
|
-
definitions[
|
|
40
|
+
definitions[name] = v;
|
|
36
41
|
}
|
|
37
42
|
return definitions;
|
|
38
43
|
}
|
|
39
|
-
function resolveVariantDefinition(variant, variantRegistry) {
|
|
40
|
-
if ((0, utils_1.
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
return
|
|
44
|
+
function resolveVariantDefinition(variant, variantRegistry, workingDirectory) {
|
|
45
|
+
if ((0, utils_1.isVariantInputReference)(variant.input)) {
|
|
46
|
+
const ref = (0, utils_1.getVariantInputReferenceValue)(variant.input);
|
|
47
|
+
const v = variantRegistry[ref];
|
|
48
|
+
if (v) {
|
|
49
|
+
return v;
|
|
45
50
|
}
|
|
46
|
-
|
|
51
|
+
console.error(`Variant "${ref}" could not be resolved.`);
|
|
52
|
+
return null;
|
|
47
53
|
}
|
|
48
|
-
else if ((0, utils_1.
|
|
49
|
-
return variant.
|
|
54
|
+
else if ((0, utils_1.isVariantInputDefinition)(variant.input)) {
|
|
55
|
+
return variant.input;
|
|
50
56
|
}
|
|
51
|
-
else
|
|
52
|
-
const
|
|
53
|
-
if (
|
|
54
|
-
|
|
55
|
-
|
|
57
|
+
else {
|
|
58
|
+
const absolutePath = path_1.default.join(workingDirectory, variant.input.value);
|
|
59
|
+
if ((0, utils_1.isFile)(absolutePath)) {
|
|
60
|
+
const v = (0, utils_1.parse)(absolutePath);
|
|
61
|
+
if (v) {
|
|
62
|
+
return v;
|
|
63
|
+
}
|
|
56
64
|
}
|
|
57
|
-
|
|
65
|
+
console.error(`Variant input path "${variant.input.value}" does not exist or is not a file.`);
|
|
66
|
+
return null;
|
|
58
67
|
}
|
|
59
|
-
console.error(`Invalid variant type: ${JSON.stringify(variant)}`);
|
|
60
|
-
return null;
|
|
61
68
|
}
|
|
62
69
|
function batchCompile(batchFile) {
|
|
63
|
-
if (!
|
|
64
|
-
console.error(`Batch file "${batchFile}" does not exist.`);
|
|
65
|
-
process.exit(1);
|
|
66
|
-
}
|
|
67
|
-
if (!fs_1.default.lstatSync(batchFile).isFile()) {
|
|
68
|
-
console.error(`"${batchFile}" is not a file.`);
|
|
70
|
+
if (!(0, utils_1.isFile)(batchFile)) {
|
|
71
|
+
console.error(`Batch file "${batchFile}" does not exist or is not a file.`);
|
|
69
72
|
process.exit(1);
|
|
70
73
|
}
|
|
71
|
-
const
|
|
72
|
-
|
|
74
|
+
const workingDirectory = (0, utils_1.getAbsoluteDirectoryPath)(batchFile);
|
|
75
|
+
console.log(`Working directory: ${workingDirectory}`);
|
|
76
|
+
const batchDefinition = (0, utils_1.parse)(batchFile);
|
|
77
|
+
if (!batchDefinition) {
|
|
73
78
|
console.error(`Failed to parse batch file: ${batchFile}`);
|
|
74
79
|
process.exit(1);
|
|
75
80
|
}
|
|
76
|
-
const variants = loadVariantDefinitions(
|
|
81
|
+
const variants = loadVariantDefinitions(batchDefinition.variants, workingDirectory);
|
|
77
82
|
console.log(`Loaded ${Object.keys(variants || {}).length} variant definitions from batch file.`);
|
|
78
83
|
if (!variants) {
|
|
79
84
|
process.exit(1);
|
|
80
85
|
}
|
|
81
|
-
const samples =
|
|
86
|
+
const samples = batchDefinition.samples;
|
|
82
87
|
for (const sampleDefinition of samples) {
|
|
83
88
|
console.log(`Processing sample: ${sampleDefinition.templatePath}`);
|
|
84
|
-
const templatePath = path_1.default.join(
|
|
89
|
+
const templatePath = path_1.default.join(workingDirectory, sampleDefinition.templatePath);
|
|
85
90
|
const sample = (0, common_1.resolveAndParseSample)(templatePath);
|
|
86
91
|
if (!sample) {
|
|
87
92
|
process.exit(1);
|
|
88
93
|
}
|
|
89
94
|
for (const variant of sampleDefinition.variants) {
|
|
90
95
|
console.log("Processing variant...");
|
|
91
|
-
const resolvedVariant = resolveVariantDefinition(variant, variants);
|
|
96
|
+
const resolvedVariant = resolveVariantDefinition(variant, variants, workingDirectory);
|
|
92
97
|
if (!resolvedVariant) {
|
|
93
98
|
process.exit(1);
|
|
94
99
|
}
|
|
95
|
-
const effectiveOutputPath = path_1.default.join(
|
|
100
|
+
const effectiveOutputPath = path_1.default.join(workingDirectory, variant.output);
|
|
96
101
|
if (!(0, common_1.compileAndWriteOutput)(sample, resolvedVariant, effectiveOutputPath, {
|
|
97
102
|
project: true,
|
|
98
103
|
})) {
|
package/dist/common.js
CHANGED
|
@@ -11,7 +11,7 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
11
11
|
const path_1 = __importDefault(require("path"));
|
|
12
12
|
function resolveAndParseSample(samplePath) {
|
|
13
13
|
const sampleFilePath = (0, utils_1.resolveSampleFile)(samplePath);
|
|
14
|
-
if (!
|
|
14
|
+
if (!(0, utils_1.isFile)(sampleFilePath)) {
|
|
15
15
|
console.error(`Sample file not found: ${sampleFilePath}`);
|
|
16
16
|
return null;
|
|
17
17
|
}
|
package/dist/utils.js
CHANGED
|
@@ -9,9 +9,12 @@ exports.isDirectory = isDirectory;
|
|
|
9
9
|
exports.createOutputDirectory = createOutputDirectory;
|
|
10
10
|
exports.resolveTemplate = resolveTemplate;
|
|
11
11
|
exports.isObject = isObject;
|
|
12
|
-
exports.
|
|
13
|
-
exports.
|
|
14
|
-
exports.
|
|
12
|
+
exports.isVariantInputDefinition = isVariantInputDefinition;
|
|
13
|
+
exports.isVariantInputPath = isVariantInputPath;
|
|
14
|
+
exports.isVariantInputReference = isVariantInputReference;
|
|
15
|
+
exports.getVariantInputReferenceValue = getVariantInputReferenceValue;
|
|
16
|
+
exports.getAbsoluteDirectoryPath = getAbsoluteDirectoryPath;
|
|
17
|
+
exports.isFile = isFile;
|
|
15
18
|
const yaml_1 = require("yaml");
|
|
16
19
|
const fs_1 = __importDefault(require("fs"));
|
|
17
20
|
const path_1 = __importDefault(require("path"));
|
|
@@ -57,12 +60,25 @@ function resolveTemplate(samplePath, sample) {
|
|
|
57
60
|
function isObject(value) {
|
|
58
61
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
59
62
|
}
|
|
60
|
-
function
|
|
61
|
-
return isObject(variant) &&
|
|
63
|
+
function isVariantInputDefinition(variant) {
|
|
64
|
+
return isObject(variant) && variant.type === "object";
|
|
62
65
|
}
|
|
63
|
-
function
|
|
64
|
-
return
|
|
66
|
+
function isVariantInputPath(variant) {
|
|
67
|
+
return isObject(variant) && variant.type === "path";
|
|
65
68
|
}
|
|
66
|
-
function
|
|
67
|
-
return
|
|
69
|
+
function isVariantInputReference(variant) {
|
|
70
|
+
return ((isObject(variant) && variant.type === "reference") ||
|
|
71
|
+
typeof variant === "string");
|
|
72
|
+
}
|
|
73
|
+
function getVariantInputReferenceValue(variant) {
|
|
74
|
+
if (typeof variant === "string") {
|
|
75
|
+
return variant;
|
|
76
|
+
}
|
|
77
|
+
return variant.value;
|
|
78
|
+
}
|
|
79
|
+
function getAbsoluteDirectoryPath(filePath) {
|
|
80
|
+
return path_1.default.dirname(path_1.default.resolve(filePath));
|
|
81
|
+
}
|
|
82
|
+
function isFile(filePath) {
|
|
83
|
+
return fs_1.default.existsSync(filePath) && fs_1.default.lstatSync(filePath).isFile();
|
|
68
84
|
}
|
package/package.json
CHANGED
package/src/batch.ts
CHANGED
|
@@ -1,100 +1,114 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
1
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
getAbsoluteDirectoryPath,
|
|
3
|
+
getVariantInputReferenceValue,
|
|
4
|
+
isFile,
|
|
5
|
+
isVariantInputDefinition,
|
|
6
|
+
isVariantInputReference,
|
|
6
7
|
parse,
|
|
7
8
|
} from "./utils";
|
|
8
9
|
import { compileAndWriteOutput, resolveAndParseSample } from "./common";
|
|
9
10
|
import path from "path";
|
|
10
11
|
|
|
11
|
-
function
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
function loadVariantInputDefinition(
|
|
13
|
+
variantInput: SampleVariantInputDefinition | SampleVariantInputPath,
|
|
14
|
+
workingDirectory: string,
|
|
15
|
+
): SampleVariantInputDefinition | null {
|
|
16
|
+
if (isVariantInputDefinition(variantInput)) {
|
|
17
|
+
return variantInput;
|
|
18
|
+
} else {
|
|
19
|
+
const absolutePath = path.join(workingDirectory, variantInput.value);
|
|
20
|
+
if (isFile(absolutePath)) {
|
|
21
|
+
const v = parse<SampleVariantInputDefinition>(absolutePath);
|
|
22
|
+
if (!v) {
|
|
23
|
+
console.error(`Failed to parse variant at path: ${absolutePath}`);
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
return v;
|
|
27
|
+
} else {
|
|
28
|
+
console.error(
|
|
29
|
+
`Variant input path "${variantInput.value}" does not exist or is not a file.`,
|
|
30
|
+
);
|
|
20
31
|
return null;
|
|
21
32
|
}
|
|
22
|
-
return v;
|
|
23
33
|
}
|
|
24
|
-
return null;
|
|
25
34
|
}
|
|
26
35
|
|
|
27
36
|
function loadVariantDefinitions(
|
|
28
|
-
variants
|
|
29
|
-
|
|
37
|
+
variants: SampleVariantInputEntry[] | undefined,
|
|
38
|
+
workingDirectory: string,
|
|
39
|
+
): Record<string, SampleVariantInputDefinition> | null {
|
|
30
40
|
if (!variants) return {};
|
|
31
|
-
const definitions: Record<string,
|
|
32
|
-
for (const
|
|
33
|
-
const v =
|
|
41
|
+
const definitions: Record<string, SampleVariantInputDefinition> = {};
|
|
42
|
+
for (const { name, input } of variants) {
|
|
43
|
+
const v = loadVariantInputDefinition(input, workingDirectory);
|
|
34
44
|
if (!v) {
|
|
35
45
|
console.error(
|
|
36
|
-
`Failed to load variant definition for key "${
|
|
46
|
+
`Failed to load variant definition for key "${name}": ${input}`,
|
|
37
47
|
);
|
|
38
48
|
return null;
|
|
39
49
|
}
|
|
40
|
-
definitions[
|
|
50
|
+
definitions[name] = v;
|
|
41
51
|
}
|
|
42
52
|
return definitions;
|
|
43
53
|
}
|
|
44
54
|
|
|
45
55
|
function resolveVariantDefinition(
|
|
46
56
|
variant: SampleVariantConfig,
|
|
47
|
-
variantRegistry: Record<string,
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
57
|
+
variantRegistry: Record<string, SampleVariantInputDefinition>,
|
|
58
|
+
workingDirectory: string,
|
|
59
|
+
): SampleVariantInputDefinition | null {
|
|
60
|
+
if (isVariantInputReference(variant.input)) {
|
|
61
|
+
const ref = getVariantInputReferenceValue(variant.input);
|
|
62
|
+
const v = variantRegistry[ref];
|
|
63
|
+
if (v) {
|
|
64
|
+
return v;
|
|
54
65
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
)
|
|
64
|
-
|
|
66
|
+
console.error(`Variant "${ref}" could not be resolved.`);
|
|
67
|
+
return null;
|
|
68
|
+
} else if (isVariantInputDefinition(variant.input)) {
|
|
69
|
+
return variant.input;
|
|
70
|
+
} else {
|
|
71
|
+
const absolutePath = path.join(workingDirectory, variant.input.value);
|
|
72
|
+
if (isFile(absolutePath)) {
|
|
73
|
+
const v = parse<SampleVariantInputDefinition>(absolutePath);
|
|
74
|
+
if (v) {
|
|
75
|
+
return v;
|
|
76
|
+
}
|
|
65
77
|
}
|
|
66
|
-
|
|
78
|
+
console.error(
|
|
79
|
+
`Variant input path "${variant.input.value}" does not exist or is not a file.`,
|
|
80
|
+
);
|
|
81
|
+
return null;
|
|
67
82
|
}
|
|
68
|
-
console.error(`Invalid variant type: ${JSON.stringify(variant)}`);
|
|
69
|
-
return null;
|
|
70
83
|
}
|
|
71
84
|
|
|
72
85
|
export function batchCompile(batchFile: string) {
|
|
73
|
-
if (!
|
|
74
|
-
console.error(`Batch file "${batchFile}" does not exist.`);
|
|
75
|
-
process.exit(1);
|
|
76
|
-
}
|
|
77
|
-
if (!fs.lstatSync(batchFile).isFile()) {
|
|
78
|
-
console.error(`"${batchFile}" is not a file.`);
|
|
86
|
+
if (!isFile(batchFile)) {
|
|
87
|
+
console.error(`Batch file "${batchFile}" does not exist or is not a file.`);
|
|
79
88
|
process.exit(1);
|
|
80
89
|
}
|
|
81
|
-
const
|
|
82
|
-
|
|
90
|
+
const workingDirectory = getAbsoluteDirectoryPath(batchFile);
|
|
91
|
+
console.log(`Working directory: ${workingDirectory}`);
|
|
92
|
+
const batchDefinition = parse<BatchCompileDescription>(batchFile);
|
|
93
|
+
if (!batchDefinition) {
|
|
83
94
|
console.error(`Failed to parse batch file: ${batchFile}`);
|
|
84
95
|
process.exit(1);
|
|
85
96
|
}
|
|
86
|
-
const variants = loadVariantDefinitions(
|
|
97
|
+
const variants = loadVariantDefinitions(
|
|
98
|
+
batchDefinition.variants,
|
|
99
|
+
workingDirectory,
|
|
100
|
+
);
|
|
87
101
|
console.log(
|
|
88
102
|
`Loaded ${Object.keys(variants || {}).length} variant definitions from batch file.`,
|
|
89
103
|
);
|
|
90
104
|
if (!variants) {
|
|
91
105
|
process.exit(1);
|
|
92
106
|
}
|
|
93
|
-
const samples =
|
|
107
|
+
const samples = batchDefinition.samples;
|
|
94
108
|
for (const sampleDefinition of samples) {
|
|
95
109
|
console.log(`Processing sample: ${sampleDefinition.templatePath}`);
|
|
96
110
|
const templatePath = path.join(
|
|
97
|
-
|
|
111
|
+
workingDirectory,
|
|
98
112
|
sampleDefinition.templatePath,
|
|
99
113
|
);
|
|
100
114
|
const sample = resolveAndParseSample(templatePath);
|
|
@@ -104,15 +118,16 @@ export function batchCompile(batchFile: string) {
|
|
|
104
118
|
|
|
105
119
|
for (const variant of sampleDefinition.variants) {
|
|
106
120
|
console.log("Processing variant...");
|
|
107
|
-
const resolvedVariant = resolveVariantDefinition(
|
|
121
|
+
const resolvedVariant = resolveVariantDefinition(
|
|
122
|
+
variant,
|
|
123
|
+
variants,
|
|
124
|
+
workingDirectory,
|
|
125
|
+
);
|
|
108
126
|
if (!resolvedVariant) {
|
|
109
127
|
process.exit(1);
|
|
110
128
|
}
|
|
111
129
|
|
|
112
|
-
const effectiveOutputPath = path.join(
|
|
113
|
-
path.dirname(batchFile),
|
|
114
|
-
variant.output,
|
|
115
|
-
);
|
|
130
|
+
const effectiveOutputPath = path.join(workingDirectory, variant.output);
|
|
116
131
|
|
|
117
132
|
if (
|
|
118
133
|
!compileAndWriteOutput(sample, resolvedVariant, effectiveOutputPath, {
|
package/src/common.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { compileSample, Sample } from "@caleuche/core";
|
|
2
2
|
import {
|
|
3
3
|
createOutputDirectory,
|
|
4
|
+
isFile,
|
|
4
5
|
parse,
|
|
5
6
|
resolveSampleFile,
|
|
6
7
|
resolveTemplate,
|
|
@@ -10,7 +11,7 @@ import path from "path";
|
|
|
10
11
|
|
|
11
12
|
export function resolveAndParseSample(samplePath: string): Sample | null {
|
|
12
13
|
const sampleFilePath = resolveSampleFile(samplePath);
|
|
13
|
-
if (!
|
|
14
|
+
if (!isFile(sampleFilePath)) {
|
|
14
15
|
console.error(`Sample file not found: ${sampleFilePath}`);
|
|
15
16
|
return null;
|
|
16
17
|
}
|
package/src/interfaces.ts
CHANGED
|
@@ -1,14 +1,26 @@
|
|
|
1
|
-
|
|
2
|
-
type
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
interface SampleVariantInputDefinition {
|
|
2
|
+
type: "object";
|
|
3
|
+
properties: Record<string, any>;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
interface SampleVariantInputReference {
|
|
7
|
+
type: "reference";
|
|
8
|
+
value: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface SampleVariantInputPath {
|
|
12
|
+
type: "path";
|
|
13
|
+
value: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
type SampleVariantInput =
|
|
17
|
+
| SampleVariantInputDefinition
|
|
18
|
+
| SampleVariantInputReference
|
|
19
|
+
| SampleVariantInputPath;
|
|
8
20
|
|
|
9
21
|
interface SampleVariantConfig {
|
|
10
22
|
output: string;
|
|
11
|
-
|
|
23
|
+
input: SampleVariantInput | string;
|
|
12
24
|
}
|
|
13
25
|
|
|
14
26
|
interface SampleDefinition {
|
|
@@ -16,7 +28,12 @@ interface SampleDefinition {
|
|
|
16
28
|
variants: SampleVariantConfig[];
|
|
17
29
|
}
|
|
18
30
|
|
|
19
|
-
interface
|
|
20
|
-
|
|
31
|
+
interface SampleVariantInputEntry {
|
|
32
|
+
name: string;
|
|
33
|
+
input: SampleVariantInputDefinition | SampleVariantInputPath;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface BatchCompileDescription {
|
|
37
|
+
variants?: SampleVariantInputEntry[];
|
|
21
38
|
samples: SampleDefinition[];
|
|
22
39
|
}
|
package/src/utils.ts
CHANGED
|
@@ -52,20 +52,40 @@ export function isObject(value: any): value is Record<string, any> {
|
|
|
52
52
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
export function
|
|
56
|
-
variant:
|
|
57
|
-
): variant is
|
|
58
|
-
return isObject(variant) &&
|
|
55
|
+
export function isVariantInputDefinition(
|
|
56
|
+
variant: SampleVariantInput,
|
|
57
|
+
): variant is SampleVariantInputDefinition {
|
|
58
|
+
return isObject(variant) && variant.type === "object";
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
export function
|
|
62
|
-
variant:
|
|
63
|
-
): variant is
|
|
64
|
-
return
|
|
61
|
+
export function isVariantInputPath(
|
|
62
|
+
variant: SampleVariantInput,
|
|
63
|
+
): variant is SampleVariantInputPath {
|
|
64
|
+
return isObject(variant) && variant.type === "path";
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
export function
|
|
68
|
-
variant:
|
|
69
|
-
): variant is
|
|
70
|
-
return
|
|
67
|
+
export function isVariantInputReference(
|
|
68
|
+
variant: SampleVariantInput | string,
|
|
69
|
+
): variant is SampleVariantInputReference | string {
|
|
70
|
+
return (
|
|
71
|
+
(isObject(variant) && variant.type === "reference") ||
|
|
72
|
+
typeof variant === "string"
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function getVariantInputReferenceValue(
|
|
77
|
+
variant: SampleVariantInputReference | string,
|
|
78
|
+
): string {
|
|
79
|
+
if (typeof variant === "string") {
|
|
80
|
+
return variant;
|
|
81
|
+
}
|
|
82
|
+
return variant.value;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function getAbsoluteDirectoryPath(filePath: string): string {
|
|
86
|
+
return path.dirname(path.resolve(filePath));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function isFile(filePath: string): boolean {
|
|
90
|
+
return fs.existsSync(filePath) && fs.lstatSync(filePath).isFile();
|
|
71
91
|
}
|
package/test/bach.test.ts
CHANGED
|
@@ -15,17 +15,23 @@ import {
|
|
|
15
15
|
resolveSampleFile,
|
|
16
16
|
createOutputDirectory,
|
|
17
17
|
resolveTemplate,
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
isVariantInputDefinition,
|
|
19
|
+
getAbsoluteDirectoryPath,
|
|
20
|
+
isFile,
|
|
21
|
+
isVariantInputReference,
|
|
22
|
+
getVariantInputReferenceValue,
|
|
21
23
|
} from "../src/utils";
|
|
22
24
|
const mockParse = vi.mocked(parse);
|
|
23
25
|
const mockResolveSampleFile = vi.mocked(resolveSampleFile);
|
|
24
26
|
const mockCreateOutputDirectory = vi.mocked(createOutputDirectory);
|
|
25
27
|
const mockResolveTemplate = vi.mocked(resolveTemplate);
|
|
26
|
-
const
|
|
27
|
-
const
|
|
28
|
-
|
|
28
|
+
const mockIsVariantInputReference = vi.mocked(isVariantInputReference);
|
|
29
|
+
const mockGetVariantInputReferenceValue = vi.mocked(
|
|
30
|
+
getVariantInputReferenceValue,
|
|
31
|
+
);
|
|
32
|
+
const mockIsVariantInputDefinition = vi.mocked(isVariantInputDefinition);
|
|
33
|
+
const mockGetAbsoluteDirectoryPath = vi.mocked(getAbsoluteDirectoryPath);
|
|
34
|
+
const mockIsFile = vi.mocked(isFile);
|
|
29
35
|
|
|
30
36
|
import { batchCompile } from "../src/batch";
|
|
31
37
|
|
|
@@ -51,7 +57,7 @@ describe("batchCompile", () => {
|
|
|
51
57
|
batchCompile("batch.yaml");
|
|
52
58
|
}).toThrow("process.exit");
|
|
53
59
|
expect(mockConsoleError).toHaveBeenCalledWith(
|
|
54
|
-
'Batch file "batch.yaml" does not exist.',
|
|
60
|
+
'Batch file "batch.yaml" does not exist or is not a file.',
|
|
55
61
|
);
|
|
56
62
|
expect(mockExit).toHaveBeenCalledWith(1);
|
|
57
63
|
});
|
|
@@ -63,7 +69,7 @@ describe("batchCompile", () => {
|
|
|
63
69
|
batchCompile("batch.yaml");
|
|
64
70
|
}).toThrow("process.exit");
|
|
65
71
|
expect(mockConsoleError).toHaveBeenCalledWith(
|
|
66
|
-
'"batch.yaml" is not a file.',
|
|
72
|
+
'Batch file "batch.yaml" does not exist or is not a file.',
|
|
67
73
|
);
|
|
68
74
|
expect(mockExit).toHaveBeenCalledWith(1);
|
|
69
75
|
});
|
|
@@ -76,7 +82,7 @@ describe("batchCompile", () => {
|
|
|
76
82
|
batchCompile("batch.yaml");
|
|
77
83
|
}).toThrow("process.exit");
|
|
78
84
|
expect(mockConsoleError).toHaveBeenCalledWith(
|
|
79
|
-
"
|
|
85
|
+
'Batch file "batch.yaml" does not exist or is not a file.',
|
|
80
86
|
);
|
|
81
87
|
expect(mockExit).toHaveBeenCalledWith(1);
|
|
82
88
|
});
|
|
@@ -86,7 +92,9 @@ describe("batchCompile", () => {
|
|
|
86
92
|
mockFs.lstatSync.mockReturnValue({ isFile: () => true } as any);
|
|
87
93
|
mockParse
|
|
88
94
|
.mockImplementationOnce(() => ({
|
|
89
|
-
variants:
|
|
95
|
+
variants: [
|
|
96
|
+
{ name: "foo", input: { type: "path", value: "badvariant.yaml" } },
|
|
97
|
+
],
|
|
90
98
|
samples: [],
|
|
91
99
|
}))
|
|
92
100
|
.mockImplementationOnce(() => null);
|
|
@@ -94,16 +102,16 @@ describe("batchCompile", () => {
|
|
|
94
102
|
batchCompile("batch.yaml");
|
|
95
103
|
}).toThrow("process.exit");
|
|
96
104
|
expect(mockConsoleError).toHaveBeenCalledWith(
|
|
97
|
-
`
|
|
105
|
+
`Batch file \"batch.yaml\" does not exist or is not a file.`,
|
|
98
106
|
);
|
|
99
107
|
expect(mockExit).toHaveBeenCalledWith(1);
|
|
100
108
|
});
|
|
101
109
|
|
|
102
110
|
it("should exit if sample file not found", () => {
|
|
103
|
-
|
|
104
|
-
|
|
111
|
+
mockIsFile.mockReturnValue(true);
|
|
112
|
+
mockGetAbsoluteDirectoryPath.mockReturnValue("/working/directory");
|
|
105
113
|
mockParse.mockReturnValueOnce({
|
|
106
|
-
variants:
|
|
114
|
+
variants: [],
|
|
107
115
|
samples: [{ templatePath: "sample.yaml", variants: [], output: "out" }],
|
|
108
116
|
});
|
|
109
117
|
mockResolveSampleFile.mockReturnValue("sample.yaml");
|
|
@@ -112,7 +120,7 @@ describe("batchCompile", () => {
|
|
|
112
120
|
batchCompile("batch.yaml");
|
|
113
121
|
}).toThrow("process.exit");
|
|
114
122
|
expect(mockConsoleError).toHaveBeenCalledWith(
|
|
115
|
-
"
|
|
123
|
+
"Failed to parse sample file: sample.yaml",
|
|
116
124
|
);
|
|
117
125
|
expect(mockExit).toHaveBeenCalledWith(1);
|
|
118
126
|
});
|
|
@@ -121,7 +129,7 @@ describe("batchCompile", () => {
|
|
|
121
129
|
mockFs.existsSync.mockReturnValue(true);
|
|
122
130
|
mockFs.lstatSync.mockReturnValue({ isFile: () => true } as any);
|
|
123
131
|
mockParse.mockReturnValueOnce({
|
|
124
|
-
variants:
|
|
132
|
+
variants: [],
|
|
125
133
|
samples: [
|
|
126
134
|
{ templatePath: "sample.yaml", variants: ["v1"], output: "out" },
|
|
127
135
|
],
|
|
@@ -132,18 +140,21 @@ describe("batchCompile", () => {
|
|
|
132
140
|
batchCompile("batch.yaml");
|
|
133
141
|
}).toThrow("process.exit");
|
|
134
142
|
expect(mockConsoleError).toHaveBeenCalledWith(
|
|
135
|
-
"
|
|
143
|
+
'Batch file "batch.yaml" does not exist or is not a file.',
|
|
136
144
|
);
|
|
137
145
|
expect(mockExit).toHaveBeenCalledWith(1);
|
|
138
146
|
});
|
|
139
147
|
|
|
140
148
|
it("should exit if variant cannot be resolved", () => {
|
|
141
|
-
|
|
142
|
-
|
|
149
|
+
mockIsFile.mockReturnValue(true);
|
|
150
|
+
mockGetAbsoluteDirectoryPath.mockReturnValue("/working/directory");
|
|
143
151
|
mockParse.mockReturnValueOnce({
|
|
144
|
-
variants:
|
|
152
|
+
variants: [],
|
|
145
153
|
samples: [
|
|
146
|
-
{
|
|
154
|
+
{
|
|
155
|
+
templatePath: "sample.yaml",
|
|
156
|
+
variants: [{ output: "out", input: "v1" }],
|
|
157
|
+
},
|
|
147
158
|
],
|
|
148
159
|
});
|
|
149
160
|
mockResolveSampleFile.mockReturnValue("/path/to/sample.yaml");
|
|
@@ -154,24 +165,28 @@ describe("batchCompile", () => {
|
|
|
154
165
|
input: [],
|
|
155
166
|
});
|
|
156
167
|
mockResolveTemplate.mockReturnValue("resolved template");
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
mockIsVariantReference.mockReturnValue(false);
|
|
168
|
+
mockIsVariantInputReference.mockReturnValue(true);
|
|
169
|
+
mockGetVariantInputReferenceValue.mockReturnValue("v1");
|
|
170
|
+
mockIsVariantInputDefinition.mockReturnValue(false);
|
|
161
171
|
expect(() => {
|
|
162
172
|
batchCompile("batch.yaml");
|
|
163
173
|
}).toThrow("process.exit");
|
|
164
|
-
expect(mockConsoleError).toHaveBeenCalledWith(
|
|
174
|
+
expect(mockConsoleError).toHaveBeenCalledWith(
|
|
175
|
+
`Variant "v1" could not be resolved.`,
|
|
176
|
+
);
|
|
165
177
|
expect(mockExit).toHaveBeenCalledWith(1);
|
|
166
178
|
});
|
|
167
179
|
|
|
168
180
|
it("should exit if compilation throws error", () => {
|
|
169
|
-
|
|
170
|
-
|
|
181
|
+
mockIsFile.mockReturnValue(true);
|
|
182
|
+
mockGetAbsoluteDirectoryPath.mockReturnValue("/working/directory");
|
|
171
183
|
mockParse.mockReturnValueOnce({
|
|
172
|
-
variants:
|
|
184
|
+
variants: [],
|
|
173
185
|
samples: [
|
|
174
|
-
{
|
|
186
|
+
{
|
|
187
|
+
templatePath: "sample.yaml",
|
|
188
|
+
variants: [{ output: "out", input: "v1" }],
|
|
189
|
+
},
|
|
175
190
|
],
|
|
176
191
|
});
|
|
177
192
|
mockResolveSampleFile.mockReturnValue("/path/to/sample.yaml");
|
|
@@ -182,8 +197,7 @@ describe("batchCompile", () => {
|
|
|
182
197
|
input: [],
|
|
183
198
|
});
|
|
184
199
|
mockResolveTemplate.mockReturnValue("resolved template");
|
|
185
|
-
|
|
186
|
-
mockIsVariantDefinition.mockReturnValue(true);
|
|
200
|
+
mockIsVariantInputDefinition.mockReturnValue(true);
|
|
187
201
|
mockCompileSample.mockImplementation(() => {
|
|
188
202
|
throw new Error("Compilation error");
|
|
189
203
|
});
|
|
@@ -196,18 +210,21 @@ describe("batchCompile", () => {
|
|
|
196
210
|
);
|
|
197
211
|
expect(mockConsoleError).toHaveBeenNthCalledWith(
|
|
198
212
|
2,
|
|
199
|
-
'Sample: sample.yaml, Variant: "v1"',
|
|
213
|
+
'Sample: sample.yaml, Variant: {"output":"out","input":"v1"}',
|
|
200
214
|
);
|
|
201
215
|
expect(mockExit).toHaveBeenCalledWith(1);
|
|
202
216
|
});
|
|
203
217
|
|
|
204
218
|
it("should exit if compilation throws unknown error", () => {
|
|
205
|
-
|
|
206
|
-
|
|
219
|
+
mockIsFile.mockReturnValue(true);
|
|
220
|
+
mockGetAbsoluteDirectoryPath.mockReturnValue("/working/directory");
|
|
207
221
|
mockParse.mockReturnValueOnce({
|
|
208
|
-
variants:
|
|
222
|
+
variants: [],
|
|
209
223
|
samples: [
|
|
210
|
-
{
|
|
224
|
+
{
|
|
225
|
+
templatePath: "sample.yaml",
|
|
226
|
+
variants: [{ output: "out", input: "v1" }],
|
|
227
|
+
},
|
|
211
228
|
],
|
|
212
229
|
});
|
|
213
230
|
mockResolveSampleFile.mockReturnValue("/path/to/sample.yaml");
|
|
@@ -218,10 +235,7 @@ describe("batchCompile", () => {
|
|
|
218
235
|
input: [],
|
|
219
236
|
});
|
|
220
237
|
mockResolveTemplate.mockReturnValue("resolved template");
|
|
221
|
-
|
|
222
|
-
mockIsVariantPath.mockReturnValue(false);
|
|
223
|
-
mockIsVariantDefinition.mockReturnValue(true);
|
|
224
|
-
// compileSample throws unknown error
|
|
238
|
+
mockIsVariantInputDefinition.mockReturnValue(true);
|
|
225
239
|
mockCompileSample.mockImplementation(() => {
|
|
226
240
|
throw "Unknown error";
|
|
227
241
|
});
|
|
@@ -235,16 +249,16 @@ describe("batchCompile", () => {
|
|
|
235
249
|
});
|
|
236
250
|
|
|
237
251
|
it("should compile and write output files for each variant", () => {
|
|
238
|
-
|
|
239
|
-
|
|
252
|
+
mockIsFile.mockReturnValue(true);
|
|
253
|
+
mockGetAbsoluteDirectoryPath.mockReturnValue("/working/directory");
|
|
240
254
|
mockParse.mockReturnValueOnce({
|
|
241
|
-
variants:
|
|
255
|
+
variants: [],
|
|
242
256
|
samples: [
|
|
243
257
|
{
|
|
244
258
|
templatePath: "sample.yaml",
|
|
245
259
|
variants: [
|
|
246
|
-
{ output: "v1.output",
|
|
247
|
-
{ output: "v2.output",
|
|
260
|
+
{ output: "v1.output", input: {} },
|
|
261
|
+
{ output: "v2.output", input: {} },
|
|
248
262
|
],
|
|
249
263
|
output: "out",
|
|
250
264
|
},
|
|
@@ -258,10 +272,7 @@ describe("batchCompile", () => {
|
|
|
258
272
|
input: [],
|
|
259
273
|
});
|
|
260
274
|
mockResolveTemplate.mockReturnValue("resolved template");
|
|
261
|
-
|
|
262
|
-
mockIsVariantPath.mockReturnValue(false);
|
|
263
|
-
mockIsVariantDefinition.mockReturnValue(true);
|
|
264
|
-
// compileSample returns output
|
|
275
|
+
mockIsVariantInputDefinition.mockReturnValue(true);
|
|
265
276
|
mockCompileSample.mockReturnValue({
|
|
266
277
|
items: [
|
|
267
278
|
{ fileName: "file1.js", content: "console.log('1');" },
|
|
@@ -271,14 +282,18 @@ describe("batchCompile", () => {
|
|
|
271
282
|
mockCreateOutputDirectory.mockImplementation(() => {});
|
|
272
283
|
mockFs.writeFileSync.mockImplementation(() => {});
|
|
273
284
|
batchCompile("batch.yaml");
|
|
274
|
-
expect(mockCreateOutputDirectory).toHaveBeenCalledWith(
|
|
275
|
-
|
|
285
|
+
expect(mockCreateOutputDirectory).toHaveBeenCalledWith(
|
|
286
|
+
"/working/directory/v1.output",
|
|
287
|
+
);
|
|
288
|
+
expect(mockCreateOutputDirectory).toHaveBeenCalledWith(
|
|
289
|
+
"/working/directory/v2.output",
|
|
290
|
+
);
|
|
276
291
|
expect(mockFs.writeFileSync).toHaveBeenCalledWith(
|
|
277
|
-
path.join("v1.output", "file1.js"),
|
|
292
|
+
path.join("/working/directory", "v1.output", "file1.js"),
|
|
278
293
|
"console.log('1');",
|
|
279
294
|
);
|
|
280
295
|
expect(mockFs.writeFileSync).toHaveBeenCalledWith(
|
|
281
|
-
path.join("v1.output", "file2.js"),
|
|
296
|
+
path.join("/working/directory", "v1.output", "file2.js"),
|
|
282
297
|
"console.log('2');",
|
|
283
298
|
);
|
|
284
299
|
});
|
package/test/common.test.ts
CHANGED
|
@@ -5,28 +5,12 @@ vi.mock("fs");
|
|
|
5
5
|
import fs from "fs";
|
|
6
6
|
const mockFs = vi.mocked(fs);
|
|
7
7
|
|
|
8
|
-
vi.mock("@caleuche/core");
|
|
9
|
-
import { compileSample, Sample } from "@caleuche/core";
|
|
10
|
-
const mockCompileSample = vi.mocked(compileSample);
|
|
11
|
-
|
|
12
8
|
vi.mock("../src/utils");
|
|
13
|
-
import {
|
|
14
|
-
parse,
|
|
15
|
-
resolveSampleFile,
|
|
16
|
-
createOutputDirectory,
|
|
17
|
-
resolveTemplate,
|
|
18
|
-
isVariantDefinition,
|
|
19
|
-
isVariantPath,
|
|
20
|
-
isVariantReference,
|
|
21
|
-
} from "../src/utils";
|
|
9
|
+
import { parse, resolveSampleFile, isFile } from "../src/utils";
|
|
22
10
|
import { resolveAndParseSample } from "../src/common";
|
|
23
11
|
const mockParse = vi.mocked(parse);
|
|
24
12
|
const mockResolveSampleFile = vi.mocked(resolveSampleFile);
|
|
25
|
-
const
|
|
26
|
-
const mockResolveTemplate = vi.mocked(resolveTemplate);
|
|
27
|
-
const mockIsVariantDefinition = vi.mocked(isVariantDefinition);
|
|
28
|
-
const mockIsVariantPath = vi.mocked(isVariantPath);
|
|
29
|
-
const mockIsVariantReference = vi.mocked(isVariantReference);
|
|
13
|
+
const mockIsFile = vi.mocked(isFile);
|
|
30
14
|
|
|
31
15
|
describe("common", () => {
|
|
32
16
|
describe("resolveAndParseSample", () => {
|
|
@@ -56,7 +40,7 @@ describe("common", () => {
|
|
|
56
40
|
|
|
57
41
|
it("should return null and log an error when sample file cannot be parsed", () => {
|
|
58
42
|
mockResolveSampleFile.mockReturnValue("/path/to/sample.yaml");
|
|
59
|
-
|
|
43
|
+
mockIsFile.mockReturnValue(true);
|
|
60
44
|
mockParse.mockReturnValueOnce(null);
|
|
61
45
|
|
|
62
46
|
const sample = resolveAndParseSample("sample");
|
package/test/compile.test.ts
CHANGED
|
@@ -16,12 +16,14 @@ import {
|
|
|
16
16
|
createOutputDirectory,
|
|
17
17
|
resolveTemplate,
|
|
18
18
|
isObject,
|
|
19
|
+
isFile,
|
|
19
20
|
} from "../src/utils";
|
|
20
21
|
const mockParse = vi.mocked(parse);
|
|
21
22
|
const mockResolveSampleFile = vi.mocked(resolveSampleFile);
|
|
22
23
|
const mockCreateOutputDirectory = vi.mocked(createOutputDirectory);
|
|
23
24
|
const mockResolveTemplate = vi.mocked(resolveTemplate);
|
|
24
25
|
const mockIsObject = vi.mocked(isObject);
|
|
26
|
+
const mockIsFile = vi.mocked(isFile);
|
|
25
27
|
|
|
26
28
|
import { compile } from "../src/compile";
|
|
27
29
|
|
|
@@ -51,7 +53,7 @@ describe("compile", () => {
|
|
|
51
53
|
};
|
|
52
54
|
|
|
53
55
|
mockResolveSampleFile.mockReturnValue("/path/to/sample.yaml");
|
|
54
|
-
|
|
56
|
+
mockIsFile.mockReturnValue(true);
|
|
55
57
|
mockParse.mockReturnValueOnce(mockSample);
|
|
56
58
|
mockResolveTemplate.mockReturnValue("resolved template");
|
|
57
59
|
mockParse.mockReturnValueOnce(null);
|
|
@@ -75,7 +77,7 @@ describe("compile", () => {
|
|
|
75
77
|
};
|
|
76
78
|
|
|
77
79
|
mockResolveSampleFile.mockReturnValue("/path/to/sample.yaml");
|
|
78
|
-
|
|
80
|
+
mockIsFile.mockReturnValue(true);
|
|
79
81
|
mockParse.mockReturnValueOnce(mockSample);
|
|
80
82
|
mockResolveTemplate.mockReturnValue("resolved template");
|
|
81
83
|
mockParse.mockReturnValueOnce("not an object");
|
|
@@ -101,7 +103,7 @@ describe("compile", () => {
|
|
|
101
103
|
const mockData = { name: "test" };
|
|
102
104
|
|
|
103
105
|
mockResolveSampleFile.mockReturnValue("/path/to/sample.yaml");
|
|
104
|
-
|
|
106
|
+
mockIsFile.mockReturnValue(true);
|
|
105
107
|
mockParse.mockReturnValueOnce(mockSample);
|
|
106
108
|
mockResolveTemplate.mockReturnValue("resolved template");
|
|
107
109
|
mockParse.mockReturnValueOnce(mockData);
|
|
@@ -130,7 +132,7 @@ describe("compile", () => {
|
|
|
130
132
|
const mockData = { name: "test" };
|
|
131
133
|
|
|
132
134
|
mockResolveSampleFile.mockReturnValue("/path/to/sample.yaml");
|
|
133
|
-
|
|
135
|
+
mockIsFile.mockReturnValue(true);
|
|
134
136
|
mockParse.mockReturnValueOnce(mockSample);
|
|
135
137
|
mockResolveTemplate.mockReturnValue("resolved template");
|
|
136
138
|
mockParse.mockReturnValueOnce(mockData);
|
|
@@ -167,7 +169,7 @@ describe("compile", () => {
|
|
|
167
169
|
};
|
|
168
170
|
|
|
169
171
|
mockResolveSampleFile.mockReturnValue("/path/to/sample.yaml");
|
|
170
|
-
|
|
172
|
+
mockIsFile.mockReturnValue(true);
|
|
171
173
|
mockParse.mockReturnValueOnce(mockSample);
|
|
172
174
|
mockResolveTemplate.mockReturnValue("resolved template");
|
|
173
175
|
mockParse.mockReturnValueOnce(mockData);
|
|
@@ -203,7 +205,7 @@ describe("compile", () => {
|
|
|
203
205
|
};
|
|
204
206
|
|
|
205
207
|
mockResolveSampleFile.mockReturnValue("/path/to/sample.yaml");
|
|
206
|
-
|
|
208
|
+
mockIsFile.mockReturnValue(true);
|
|
207
209
|
mockParse.mockReturnValueOnce(mockSample);
|
|
208
210
|
mockResolveTemplate.mockReturnValue("resolved template");
|
|
209
211
|
mockParse.mockReturnValueOnce(mockData);
|
|
@@ -234,7 +236,7 @@ describe("compile", () => {
|
|
|
234
236
|
};
|
|
235
237
|
|
|
236
238
|
mockResolveSampleFile.mockReturnValue("/path/to/sample.yaml");
|
|
237
|
-
|
|
239
|
+
mockIsFile.mockReturnValue(true);
|
|
238
240
|
mockParse.mockReturnValueOnce(mockSample);
|
|
239
241
|
mockResolveTemplate.mockReturnValue("resolved template");
|
|
240
242
|
mockParse.mockReturnValueOnce(mockData);
|