@caleuche/cli 0.2.4 → 0.4.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 CHANGED
@@ -1,5 +1,18 @@
1
1
  # @caleuche/cli
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 566dad9: Updated command help strings.
8
+ - 6215af4: Adding option directory to batch command.
9
+
10
+ ## 0.3.0
11
+
12
+ ### Minor Changes
13
+
14
+ - ff834ac: Changing batch file schema.
15
+
3
16
  ## 0.2.4
4
17
 
5
18
  ### Patch Changes
package/dist/batch.js CHANGED
@@ -4,73 +4,86 @@ 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 loadVariantDefinition(variant, workingDirectory) {
12
- if ((0, utils_1.isVariantDefinition)(variant)) {
13
- return variant;
10
+ function loadVariantInputDefinition(variantInput, workingDirectory) {
11
+ if ((0, utils_1.isVariantInputDefinition)(variantInput)) {
12
+ return variantInput;
14
13
  }
15
- else if (fs_1.default.existsSync(path_1.default.join(workingDirectory, variant))) {
16
- const v = (0, utils_1.parse)(path_1.default.join(workingDirectory, variant));
17
- if (!v) {
18
- console.error(`Failed to parse variant at path: ${variant}`);
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
30
  function loadVariantDefinitions(variants, workingDirectory) {
26
31
  if (!variants)
27
32
  return {};
28
33
  const definitions = {};
29
- for (const [key, variant] of Object.entries(variants)) {
30
- const v = loadVariantDefinition(variant, workingDirectory);
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 "${key}": ${variant}`);
37
+ console.error(`Failed to load variant definition for key "${name}"`);
33
38
  return null;
34
39
  }
35
- definitions[key] = v;
40
+ definitions[name] = v;
36
41
  }
37
42
  return definitions;
38
43
  }
39
44
  function resolveVariantDefinition(variant, variantRegistry, workingDirectory) {
40
- if ((0, utils_1.isVariantDefinition)(variant.data)) {
41
- return variant.data;
42
- }
43
- if ((0, utils_1.isFile)(path_1.default.join(workingDirectory, variant.data))) {
44
- const v = (0, utils_1.parse)(path_1.default.join(workingDirectory, variant.data));
45
+ if ((0, utils_1.isVariantInputReference)(variant.input)) {
46
+ const ref = (0, utils_1.getVariantInputReferenceValue)(variant.input);
47
+ const v = variantRegistry[ref];
45
48
  if (v) {
46
49
  return v;
47
50
  }
51
+ console.error(`Variant "${ref}" could not be resolved.`);
52
+ return null;
53
+ }
54
+ else if ((0, utils_1.isVariantInputDefinition)(variant.input)) {
55
+ return variant.input;
48
56
  }
49
- const v = variantRegistry[variant.data];
50
- if (v) {
51
- return v;
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
+ }
64
+ }
65
+ console.error(`Variant input path "${variant.input.value}" does not exist or is not a file.`);
66
+ return null;
52
67
  }
53
- console.error(`Variant "${variant.data}" could not be resolved.`);
54
- return null;
55
68
  }
56
- function batchCompile(batchFile) {
69
+ function batchCompile(batchFile, options) {
57
70
  if (!(0, utils_1.isFile)(batchFile)) {
58
71
  console.error(`Batch file "${batchFile}" does not exist or is not a file.`);
59
72
  process.exit(1);
60
73
  }
61
74
  const workingDirectory = (0, utils_1.getAbsoluteDirectoryPath)(batchFile);
62
75
  console.log(`Working directory: ${workingDirectory}`);
63
- const bachDefinition = (0, utils_1.parse)(batchFile);
64
- if (!bachDefinition) {
76
+ const batchDefinition = (0, utils_1.parse)(batchFile);
77
+ if (!batchDefinition) {
65
78
  console.error(`Failed to parse batch file: ${batchFile}`);
66
79
  process.exit(1);
67
80
  }
68
- const variants = loadVariantDefinitions(bachDefinition.variants, workingDirectory);
81
+ const variants = loadVariantDefinitions(batchDefinition.variants, workingDirectory);
69
82
  console.log(`Loaded ${Object.keys(variants || {}).length} variant definitions from batch file.`);
70
83
  if (!variants) {
71
84
  process.exit(1);
72
85
  }
73
- const samples = bachDefinition.samples;
86
+ const samples = batchDefinition.samples;
74
87
  for (const sampleDefinition of samples) {
75
88
  console.log(`Processing sample: ${sampleDefinition.templatePath}`);
76
89
  const templatePath = path_1.default.join(workingDirectory, sampleDefinition.templatePath);
@@ -84,8 +97,8 @@ function batchCompile(batchFile) {
84
97
  if (!resolvedVariant) {
85
98
  process.exit(1);
86
99
  }
87
- const effectiveOutputPath = path_1.default.join(workingDirectory, variant.output);
88
- if (!(0, common_1.compileAndWriteOutput)(sample, resolvedVariant, effectiveOutputPath, {
100
+ const effectiveOutputPath = path_1.default.join(options?.outputDir || workingDirectory, variant.output);
101
+ if (!(0, common_1.compileAndWriteOutput)(sample, resolvedVariant.properties, effectiveOutputPath, {
89
102
  project: true,
90
103
  })) {
91
104
  console.error(`Sample: ${sampleDefinition.templatePath}, Variant: ${JSON.stringify(variant)}`);
package/dist/index.js CHANGED
@@ -10,8 +10,15 @@ commander_1.program
10
10
  .description("Caleuche CLI for compiling samples")
11
11
  .version(package_json_1.version);
12
12
  commander_1.program
13
- .command("compile <sample-directory> <data-file> <output-directory>")
14
- .option("-p, --project", "Generate project file")
13
+ .command("compile")
14
+ .argument("<sample-path>", "Path to the sample file or the directory that containes it.")
15
+ .argument("<data-file>", "Path to the input to be used to compile the template.")
16
+ .argument("<output-directory>", "Directory where the compiled output will be written.")
17
+ .option("-p, --project", "Flag to indicate whether to generate the appropriate project file along with the compiled template.")
15
18
  .action(compile_1.compile);
16
- commander_1.program.command("batch <batch-file>").action(batch_1.batchCompile);
19
+ commander_1.program
20
+ .command("batch")
21
+ .argument("<batch-file>", "Path to the batch file")
22
+ .option("-d, --output-dir <outputDir>", "Output directory for compiled samples")
23
+ .action(batch_1.batchCompile);
17
24
  commander_1.program.parse();
package/dist/utils.js CHANGED
@@ -9,7 +9,10 @@ exports.isDirectory = isDirectory;
9
9
  exports.createOutputDirectory = createOutputDirectory;
10
10
  exports.resolveTemplate = resolveTemplate;
11
11
  exports.isObject = isObject;
12
- exports.isVariantDefinition = isVariantDefinition;
12
+ exports.isVariantInputDefinition = isVariantInputDefinition;
13
+ exports.isVariantInputPath = isVariantInputPath;
14
+ exports.isVariantInputReference = isVariantInputReference;
15
+ exports.getVariantInputReferenceValue = getVariantInputReferenceValue;
13
16
  exports.getAbsoluteDirectoryPath = getAbsoluteDirectoryPath;
14
17
  exports.isFile = isFile;
15
18
  const yaml_1 = require("yaml");
@@ -57,8 +60,21 @@ function resolveTemplate(samplePath, sample) {
57
60
  function isObject(value) {
58
61
  return value !== null && typeof value === "object" && !Array.isArray(value);
59
62
  }
60
- function isVariantDefinition(variant) {
61
- return isObject(variant) && !Array.isArray(variant);
63
+ function isVariantInputDefinition(variant) {
64
+ return isObject(variant) && variant.type === "object";
65
+ }
66
+ function isVariantInputPath(variant) {
67
+ return isObject(variant) && variant.type === "path";
68
+ }
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;
62
78
  }
63
79
  function getAbsoluteDirectoryPath(filePath) {
64
80
  return path_1.default.dirname(path_1.default.resolve(filePath));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@caleuche/cli",
3
- "version": "0.2.4",
3
+ "version": "0.4.0",
4
4
  "main": "dist/index.js",
5
5
  "bin": {
6
6
  "che": "dist/index.js"
package/src/batch.ts CHANGED
@@ -1,94 +1,108 @@
1
- import fs from "fs";
2
1
  import {
3
2
  getAbsoluteDirectoryPath,
3
+ getVariantInputReferenceValue,
4
4
  isFile,
5
- isVariantDefinition,
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 loadVariantDefinition(
12
- variant: SampleVariantDefinition | SampleVariantPath,
13
- workingDirectory: string
14
- ): SampleVariantDefinition | null {
15
- if (isVariantDefinition(variant)) {
16
- return variant;
17
- } else if (fs.existsSync(path.join(workingDirectory, variant))) {
18
- const v = parse<SampleVariantDefinition>(path.join(workingDirectory, variant));
19
- if (!v) {
20
- console.error(`Failed to parse variant at path: ${variant}`);
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
+ );
21
31
  return null;
22
32
  }
23
- return v;
24
33
  }
25
- return null;
26
34
  }
27
35
 
28
36
  function loadVariantDefinitions(
29
- variants: Record<string, SampleVariantDefinition | SampleVariantPath> | undefined,
30
- workingDirectory: string
31
- ): Record<string, SampleVariantDefinition> | null {
37
+ variants: SampleVariantInputEntry[] | undefined,
38
+ workingDirectory: string,
39
+ ): Record<string, SampleVariantInputDefinition> | null {
32
40
  if (!variants) return {};
33
- const definitions: Record<string, SampleVariantDefinition> = {};
34
- for (const [key, variant] of Object.entries(variants)) {
35
- const v = loadVariantDefinition(variant, workingDirectory);
41
+ const definitions: Record<string, SampleVariantInputDefinition> = {};
42
+ for (const { name, input } of variants) {
43
+ const v = loadVariantInputDefinition(input, workingDirectory);
36
44
  if (!v) {
37
- console.error(
38
- `Failed to load variant definition for key "${key}": ${variant}`,
39
- );
45
+ console.error(`Failed to load variant definition for key "${name}"`);
40
46
  return null;
41
47
  }
42
- definitions[key] = v;
48
+ definitions[name] = v;
43
49
  }
44
50
  return definitions;
45
51
  }
46
52
 
47
53
  function resolveVariantDefinition(
48
54
  variant: SampleVariantConfig,
49
- variantRegistry: Record<string, SampleVariantDefinition>,
50
- workingDirectory: string
51
- ): SampleVariantDefinition | null {
52
- if (isVariantDefinition(variant.data)) {
53
- return variant.data;
54
- }
55
-
56
- if (isFile(path.join(workingDirectory, variant.data))) {
57
- const v = parse<SampleVariantDefinition>(path.join(workingDirectory, variant.data));
55
+ variantRegistry: Record<string, SampleVariantInputDefinition>,
56
+ workingDirectory: string,
57
+ ): SampleVariantInputDefinition | null {
58
+ if (isVariantInputReference(variant.input)) {
59
+ const ref = getVariantInputReferenceValue(variant.input);
60
+ const v = variantRegistry[ref];
58
61
  if (v) {
59
62
  return v;
60
63
  }
61
- }
62
-
63
-
64
- const v = variantRegistry[variant.data];
65
- if (v) {
66
- return v;
64
+ console.error(`Variant "${ref}" could not be resolved.`);
65
+ return null;
66
+ } else if (isVariantInputDefinition(variant.input)) {
67
+ return variant.input;
68
+ } else {
69
+ const absolutePath = path.join(workingDirectory, variant.input.value);
70
+ if (isFile(absolutePath)) {
71
+ const v = parse<SampleVariantInputDefinition>(absolutePath);
72
+ if (v) {
73
+ return v;
74
+ }
67
75
  }
68
- console.error(`Variant "${variant.data}" could not be resolved.`);
69
- return null
76
+ console.error(
77
+ `Variant input path "${variant.input.value}" does not exist or is not a file.`,
78
+ );
79
+ return null;
80
+ }
70
81
  }
71
82
 
72
- export function batchCompile(batchFile: string) {
83
+ export function batchCompile(batchFile: string, options: { outputDir?: string }) {
73
84
  if (!isFile(batchFile)) {
74
85
  console.error(`Batch file "${batchFile}" does not exist or is not a file.`);
75
86
  process.exit(1);
76
87
  }
77
88
  const workingDirectory = getAbsoluteDirectoryPath(batchFile);
78
89
  console.log(`Working directory: ${workingDirectory}`);
79
- const bachDefinition = parse<BatchCompileOptions>(batchFile);
80
- if (!bachDefinition) {
90
+ const batchDefinition = parse<BatchCompileDescription>(batchFile);
91
+ if (!batchDefinition) {
81
92
  console.error(`Failed to parse batch file: ${batchFile}`);
82
93
  process.exit(1);
83
94
  }
84
- const variants = loadVariantDefinitions(bachDefinition.variants, workingDirectory);
95
+ const variants = loadVariantDefinitions(
96
+ batchDefinition.variants,
97
+ workingDirectory,
98
+ );
85
99
  console.log(
86
100
  `Loaded ${Object.keys(variants || {}).length} variant definitions from batch file.`,
87
101
  );
88
102
  if (!variants) {
89
103
  process.exit(1);
90
104
  }
91
- const samples = bachDefinition.samples;
105
+ const samples = batchDefinition.samples;
92
106
  for (const sampleDefinition of samples) {
93
107
  console.log(`Processing sample: ${sampleDefinition.templatePath}`);
94
108
  const templatePath = path.join(
@@ -102,18 +116,21 @@ export function batchCompile(batchFile: string) {
102
116
 
103
117
  for (const variant of sampleDefinition.variants) {
104
118
  console.log("Processing variant...");
105
- const resolvedVariant = resolveVariantDefinition(variant, variants, workingDirectory);
119
+ const resolvedVariant = resolveVariantDefinition(
120
+ variant,
121
+ variants,
122
+ workingDirectory,
123
+ );
106
124
  if (!resolvedVariant) {
107
125
  process.exit(1);
108
126
  }
109
127
 
110
128
  const effectiveOutputPath = path.join(
111
- workingDirectory,
112
- variant.output,
113
- );
129
+ options?.outputDir || workingDirectory,
130
+ variant.output);
114
131
 
115
132
  if (
116
- !compileAndWriteOutput(sample, resolvedVariant, effectiveOutputPath, {
133
+ !compileAndWriteOutput(sample, resolvedVariant.properties, effectiveOutputPath, {
117
134
  project: true,
118
135
  })
119
136
  ) {
package/src/index.ts CHANGED
@@ -11,10 +11,17 @@ program
11
11
  .version(version);
12
12
 
13
13
  program
14
- .command("compile <sample-directory> <data-file> <output-directory>")
15
- .option("-p, --project", "Generate project file")
14
+ .command("compile")
15
+ .argument("<sample-path>", "Path to the sample file or the directory that containes it.")
16
+ .argument("<data-file>", "Path to the input to be used to compile the template.")
17
+ .argument("<output-directory>", "Directory where the compiled output will be written.")
18
+ .option("-p, --project", "Flag to indicate whether to generate the appropriate project file along with the compiled template.")
16
19
  .action(compile);
17
20
 
18
- program.command("batch <batch-file>").action(batchCompile);
21
+ program
22
+ .command("batch")
23
+ .argument("<batch-file>", "Path to the batch file")
24
+ .option("-d, --output-dir <outputDir>", "Output directory for compiled samples")
25
+ .action(batchCompile);
19
26
 
20
27
  program.parse();
package/src/interfaces.ts CHANGED
@@ -1,14 +1,26 @@
1
- type SampleVariantDefinition = Record<string, any>;
2
- type SampleVariantReference = string;
3
- type SampleVariantPath = string;
4
- type SampleVariant =
5
- | SampleVariantDefinition
6
- | SampleVariantReference
7
- | SampleVariantPath;
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
- data: SampleVariant;
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 BatchCompileOptions {
20
- variants?: Record<string, SampleVariantDefinition | SampleVariantPath>;
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
@@ -3,6 +3,8 @@ import fs from "fs";
3
3
  import path from "path";
4
4
  import { Sample } from "@caleuche/core";
5
5
 
6
+ export type Optional<T> = T | undefined;
7
+
6
8
  export function parse<T>(filePath: string): T | null {
7
9
  try {
8
10
  const fileContent = fs.readFileSync(filePath, "utf-8");
@@ -52,15 +54,37 @@ export function isObject(value: any): value is Record<string, any> {
52
54
  return value !== null && typeof value === "object" && !Array.isArray(value);
53
55
  }
54
56
 
55
- export function isVariantDefinition(
56
- variant: SampleVariant,
57
- ): variant is SampleVariantDefinition {
58
- return isObject(variant) && !Array.isArray(variant);
57
+ export function isVariantInputDefinition(
58
+ variant: SampleVariantInput,
59
+ ): variant is SampleVariantInputDefinition {
60
+ return isObject(variant) && variant.type === "object";
61
+ }
62
+
63
+ export function isVariantInputPath(
64
+ variant: SampleVariantInput,
65
+ ): variant is SampleVariantInputPath {
66
+ return isObject(variant) && variant.type === "path";
67
+ }
68
+
69
+ export function isVariantInputReference(
70
+ variant: SampleVariantInput | string,
71
+ ): variant is SampleVariantInputReference | string {
72
+ return (
73
+ (isObject(variant) && variant.type === "reference") ||
74
+ typeof variant === "string"
75
+ );
59
76
  }
60
77
 
61
- export function getAbsoluteDirectoryPath(
62
- filePath: string,
78
+ export function getVariantInputReferenceValue(
79
+ variant: SampleVariantInputReference | string,
63
80
  ): string {
81
+ if (typeof variant === "string") {
82
+ return variant;
83
+ }
84
+ return variant.value;
85
+ }
86
+
87
+ export function getAbsoluteDirectoryPath(filePath: string): string {
64
88
  return path.dirname(path.resolve(filePath));
65
89
  }
66
90
 
package/test/bach.test.ts CHANGED
@@ -1,40 +1,23 @@
1
1
  import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
2
- import path from "path";
3
-
4
- vi.mock("fs");
5
2
  import fs from "fs";
6
- const mockFs = vi.mocked(fs);
3
+ import path from "path";
4
+ import os from "os";
7
5
 
8
6
  vi.mock("@caleuche/core");
9
- import { compileSample, Sample } from "@caleuche/core";
7
+ import { compileSample } from "@caleuche/core";
10
8
  const mockCompileSample = vi.mocked(compileSample);
11
9
 
12
- vi.mock("../src/utils");
13
- import {
14
- parse,
15
- resolveSampleFile,
16
- createOutputDirectory,
17
- resolveTemplate,
18
- isVariantDefinition,
19
- getAbsoluteDirectoryPath,
20
- isFile,
21
- } from "../src/utils";
22
- const mockParse = vi.mocked(parse);
23
- const mockResolveSampleFile = vi.mocked(resolveSampleFile);
24
- const mockCreateOutputDirectory = vi.mocked(createOutputDirectory);
25
- const mockResolveTemplate = vi.mocked(resolveTemplate);
26
- const mockIsVariantDefinition = vi.mocked(isVariantDefinition);
27
- const mockGetAbsoluteDirectoryPath = vi.mocked(getAbsoluteDirectoryPath);
28
- const mockIsFile = vi.mocked(isFile);
29
-
30
10
  import { batchCompile } from "../src/batch";
11
+ import { Optional } from "../src/utils";
12
+ import { multiline } from "./utils.test";
31
13
 
32
14
  describe("batchCompile", () => {
15
+ let tempDir: Optional<string>;
33
16
  let mockExit: any;
34
17
  let mockConsoleError: any;
35
18
 
36
19
  beforeEach(() => {
37
- vi.clearAllMocks();
20
+ tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "caleuche-cli-test-"));
38
21
  mockExit = vi.spyOn(process, "exit").mockImplementation(() => {
39
22
  throw new Error("process.exit");
40
23
  });
@@ -42,154 +25,193 @@ describe("batchCompile", () => {
42
25
  });
43
26
 
44
27
  afterEach(() => {
28
+ if (tempDir) {
29
+ fs.rmSync(tempDir, { recursive: true });
30
+ }
45
31
  vi.restoreAllMocks();
46
32
  });
47
33
 
34
+ function getPath(relative: string): string {
35
+ return path.join(tempDir!, relative);
36
+ }
37
+
48
38
  it("should exit if batch file does not exist", () => {
49
- mockFs.existsSync.mockReturnValue(false);
50
39
  expect(() => {
51
- batchCompile("batch.yaml");
40
+ batchCompile(getPath("batch.yaml"), {});
52
41
  }).toThrow("process.exit");
53
42
  expect(mockConsoleError).toHaveBeenCalledWith(
54
- "Batch file \"batch.yaml\" does not exist or is not a file.",
43
+ `Batch file "${getPath("batch.yaml")}" does not exist or is not a file.`,
55
44
  );
56
45
  expect(mockExit).toHaveBeenCalledWith(1);
57
46
  });
58
47
 
59
48
  it("should exit if batch file is not a file", () => {
60
- mockFs.existsSync.mockReturnValue(true);
61
- mockFs.lstatSync.mockReturnValue({ isFile: () => false } as any);
49
+ fs.mkdirSync(getPath("batch.yaml"));
62
50
  expect(() => {
63
- batchCompile("batch.yaml");
51
+ batchCompile("batch.yaml", {});
64
52
  }).toThrow("process.exit");
65
53
  expect(mockConsoleError).toHaveBeenCalledWith(
66
- "Batch file \"batch.yaml\" does not exist or is not a file.",
54
+ 'Batch file "batch.yaml" does not exist or is not a file.',
67
55
  );
68
56
  expect(mockExit).toHaveBeenCalledWith(1);
69
57
  });
70
58
 
71
59
  it("should exit if batch file cannot be parsed", () => {
72
- mockFs.existsSync.mockReturnValue(true);
73
- mockFs.lstatSync.mockReturnValue({ isFile: () => true } as any);
74
- mockParse.mockReturnValueOnce(null);
60
+ const batchFilePath = getPath("batch.yaml");
61
+ const invalidYaml = multiline`
62
+ invalid: yaml: structure:
63
+ broken
64
+ `;
65
+ fs.writeFileSync(batchFilePath, invalidYaml);
66
+
75
67
  expect(() => {
76
- batchCompile("batch.yaml");
68
+ batchCompile(batchFilePath, {});
77
69
  }).toThrow("process.exit");
78
70
  expect(mockConsoleError).toHaveBeenCalledWith(
79
- "Batch file \"batch.yaml\" does not exist or is not a file.",
71
+ `Failed to parse batch file: ${batchFilePath}`,
80
72
  );
81
73
  expect(mockExit).toHaveBeenCalledWith(1);
82
74
  });
83
75
 
84
76
  it("should exit if variant definitions cannot be loaded", () => {
85
- mockFs.existsSync.mockReturnValue(true);
86
- mockFs.lstatSync.mockReturnValue({ isFile: () => true } as any);
87
- mockParse
88
- .mockImplementationOnce(() => ({
89
- variants: { foo: "badvariant.yaml" },
90
- samples: [],
91
- }))
92
- .mockImplementationOnce(() => null);
77
+ const batchFilePath = getPath("batch.yaml");
78
+ const content = multiline`
79
+ variants:
80
+ - name: foo
81
+ input:
82
+ type: path
83
+ value: badvariant.yaml
84
+ `;
85
+ fs.writeFileSync(batchFilePath, content);
86
+
93
87
  expect(() => {
94
- batchCompile("batch.yaml");
88
+ batchCompile(batchFilePath, {});
95
89
  }).toThrow("process.exit");
96
90
  expect(mockConsoleError).toHaveBeenCalledWith(
97
- `Batch file \"batch.yaml\" does not exist or is not a file.`,
91
+ `Failed to load variant definition for key "foo"`,
98
92
  );
99
93
  expect(mockExit).toHaveBeenCalledWith(1);
100
94
  });
101
95
 
102
96
  it("should exit if sample file not found", () => {
103
- mockIsFile.mockReturnValue(true);
104
- mockGetAbsoluteDirectoryPath.mockReturnValue("/working/directory");
105
- mockParse.mockReturnValueOnce({
106
- variants: {},
107
- samples: [{ templatePath: "sample.yaml", variants: [], output: "out" }],
108
- });
109
- mockResolveSampleFile.mockReturnValue("sample.yaml");
110
- mockFs.existsSync.mockReturnValueOnce(false);
97
+ const batchFilePath = getPath("batch.yaml");
98
+ const content = multiline`
99
+ samples:
100
+ - templatePath: sample.yaml
101
+ variants: []
102
+ output: out
103
+ `;
104
+ fs.writeFileSync(batchFilePath, content);
105
+
111
106
  expect(() => {
112
- batchCompile("batch.yaml");
107
+ batchCompile(batchFilePath, {});
113
108
  }).toThrow("process.exit");
114
109
  expect(mockConsoleError).toHaveBeenCalledWith(
115
- "Failed to parse sample file: sample.yaml",
110
+ `Sample file not found: ${getPath("sample.yaml")}`,
116
111
  );
112
+
117
113
  expect(mockExit).toHaveBeenCalledWith(1);
118
114
  });
119
115
 
120
116
  it("should exit if sample file cannot be parsed", () => {
121
- mockFs.existsSync.mockReturnValue(true);
122
- mockFs.lstatSync.mockReturnValue({ isFile: () => true } as any);
123
- mockParse.mockReturnValueOnce({
124
- variants: {},
125
- samples: [
126
- { templatePath: "sample.yaml", variants: ["v1"], output: "out" },
127
- ]
128
- });
129
- mockResolveSampleFile.mockReturnValue("/path/to/sample.yaml");
130
- mockParse.mockReturnValueOnce(null);
117
+ const batchFilePath = getPath("batch.yaml");
118
+ const batchFileContent = multiline`
119
+ variants:
120
+ - name: foo
121
+ input:
122
+ type: object
123
+ properties:
124
+ var: value
125
+ samples:
126
+ - templatePath: sample.yaml
127
+ variants:
128
+ - output: out
129
+ input: foo
130
+ `;
131
+ fs.writeFileSync(batchFilePath, batchFileContent);
132
+ const sampleFilePath = getPath("sample.yaml");
133
+ const invalidSampleContent = multiline`
134
+ some: invalid: yaml
135
+ `;
136
+ fs.writeFileSync(sampleFilePath, invalidSampleContent);
137
+
131
138
  expect(() => {
132
- batchCompile("batch.yaml");
139
+ batchCompile(batchFilePath, {});
133
140
  }).toThrow("process.exit");
134
141
  expect(mockConsoleError).toHaveBeenCalledWith(
135
- "Batch file \"batch.yaml\" does not exist or is not a file.",
142
+ `Failed to parse sample file: ${sampleFilePath}`,
136
143
  );
137
144
  expect(mockExit).toHaveBeenCalledWith(1);
138
145
  });
139
146
 
140
147
  it("should exit if variant cannot be resolved", () => {
141
- mockIsFile.mockReturnValue(true);
142
- mockGetAbsoluteDirectoryPath.mockReturnValue("/working/directory");
143
- mockParse.mockReturnValueOnce({
144
- variants: {},
145
- samples: [
146
- { templatePath: "sample.yaml", variants: [{ output: "out", data: "v1" }] },
147
- ],
148
- });
149
- mockResolveSampleFile.mockReturnValue("/path/to/sample.yaml");
150
- mockParse.mockReturnValueOnce({
151
- template: "t",
152
- type: "js",
153
- dependencies: [],
154
- input: [],
155
- });
156
- mockResolveTemplate.mockReturnValue("resolved template");
157
- mockIsVariantDefinition.mockReturnValue(false);
148
+ const batchFilePath = getPath("batch.yaml");
149
+ const batchFileContent = multiline`
150
+ variants:
151
+ - name: foo
152
+ input:
153
+ type: object
154
+ properties:
155
+ var: value
156
+ samples:
157
+ - templatePath: sample.yaml
158
+ variants:
159
+ - output: out
160
+ input: bar
161
+ `;
162
+ fs.writeFileSync(batchFilePath, batchFileContent);
163
+ const sampleFilePath = getPath("sample.yaml");
164
+ const sampleContent = multiline`
165
+ template: sample.js.template
166
+ type: javascript
167
+ dependencies:
168
+ input:
169
+ - name: var
170
+ type: string
171
+ required: true
172
+ `;
173
+ fs.writeFileSync(sampleFilePath, sampleContent);
158
174
  expect(() => {
159
- batchCompile("batch.yaml");
175
+ batchCompile(batchFilePath, {});
160
176
  }).toThrow("process.exit");
161
177
  expect(mockConsoleError).toHaveBeenCalledWith(
162
- `Variant "v1" could not be resolved.`,
178
+ `Variant "bar" could not be resolved.`,
163
179
  );
164
180
  expect(mockExit).toHaveBeenCalledWith(1);
165
181
  });
166
182
 
167
183
  it("should exit if compilation throws error", () => {
168
- mockIsFile.mockReturnValue(true);
169
- mockGetAbsoluteDirectoryPath.mockReturnValue("/working/directory");
170
- mockParse.mockReturnValueOnce({
171
- variants: {},
172
- samples: [
173
- {
174
- templatePath: "sample.yaml",
175
- variants: [{ output: "out", data: "v1" }],
176
- },
177
- ],
178
- });
179
- mockResolveSampleFile.mockReturnValue("/path/to/sample.yaml");
180
- mockParse.mockReturnValueOnce({
181
- template: "t",
182
- type: "js",
183
- dependencies: [],
184
- input: [],
185
- });
186
- mockResolveTemplate.mockReturnValue("resolved template");
187
- mockIsVariantDefinition.mockReturnValue(true);
188
184
  mockCompileSample.mockImplementation(() => {
189
185
  throw new Error("Compilation error");
190
186
  });
187
+ const batchFilePath = getPath("batch.yaml");
188
+ const batchFileContent = multiline`
189
+ variants:
190
+ - name: foo
191
+ input:
192
+ type: object
193
+ properties:
194
+ var2: value
195
+ samples:
196
+ - templatePath: sample.yaml
197
+ variants:
198
+ - output: out
199
+ input: foo
200
+ `;
201
+ fs.writeFileSync(batchFilePath, batchFileContent);
202
+ const sampleFilePath = getPath("sample.yaml");
203
+ const sampleContent = multiline`
204
+ template: sample.js.template
205
+ type: javascript
206
+ dependencies:
207
+ input:
208
+ - name: var
209
+ type: string
210
+ required: true
211
+ `;
212
+ fs.writeFileSync(sampleFilePath, sampleContent);
191
213
  expect(() => {
192
- batchCompile("batch.yaml");
214
+ batchCompile(batchFilePath, {});
193
215
  }).toThrow("process.exit");
194
216
  expect(mockConsoleError).toHaveBeenNthCalledWith(
195
217
  1,
@@ -197,37 +219,43 @@ describe("batchCompile", () => {
197
219
  );
198
220
  expect(mockConsoleError).toHaveBeenNthCalledWith(
199
221
  2,
200
- 'Sample: sample.yaml, Variant: {"output":"out","data":"v1"}',
222
+ 'Sample: sample.yaml, Variant: {"output":"out","input":"foo"}',
201
223
  );
202
224
  expect(mockExit).toHaveBeenCalledWith(1);
203
225
  });
204
226
 
205
227
  it("should exit if compilation throws unknown error", () => {
206
- mockIsFile.mockReturnValue(true);
207
- mockGetAbsoluteDirectoryPath.mockReturnValue("/working/directory");
208
- mockParse.mockReturnValueOnce({
209
- variants: {},
210
- samples: [
211
- {
212
- templatePath: "sample.yaml",
213
- variants: [{ output: "out", data: "v1" }],
214
- },
215
- ],
216
- });
217
- mockResolveSampleFile.mockReturnValue("/path/to/sample.yaml");
218
- mockParse.mockReturnValueOnce({
219
- template: "t",
220
- type: "js",
221
- dependencies: [],
222
- input: [],
223
- });
224
- mockResolveTemplate.mockReturnValue("resolved template");
225
- mockIsVariantDefinition.mockReturnValue(true);
226
228
  mockCompileSample.mockImplementation(() => {
227
229
  throw "Unknown error";
228
230
  });
231
+ const batchFilePath = getPath("batch.yaml");
232
+ const batchFileContent = multiline`
233
+ variants:
234
+ - name: foo
235
+ input:
236
+ type: object
237
+ properties:
238
+ var2: value
239
+ samples:
240
+ - templatePath: sample.yaml
241
+ variants:
242
+ - output: out
243
+ input: foo
244
+ `;
245
+ fs.writeFileSync(batchFilePath, batchFileContent);
246
+ const sampleFilePath = getPath("sample.yaml");
247
+ const sampleContent = multiline`
248
+ template: sample.js.template
249
+ type: javascript
250
+ dependencies:
251
+ input:
252
+ - name: var
253
+ type: string
254
+ required: true
255
+ `;
256
+ fs.writeFileSync(sampleFilePath, sampleContent);
229
257
  expect(() => {
230
- batchCompile("batch.yaml");
258
+ batchCompile(getPath("batch.yaml"), {});
231
259
  }).toThrow("process.exit");
232
260
  expect(mockConsoleError).toHaveBeenCalledWith(
233
261
  "An unknown error occurred during compilation.",
@@ -236,47 +264,91 @@ describe("batchCompile", () => {
236
264
  });
237
265
 
238
266
  it("should compile and write output files for each variant", () => {
239
- mockIsFile.mockReturnValue(true);
240
- mockGetAbsoluteDirectoryPath.mockReturnValue("/working/directory");
241
- mockParse.mockReturnValueOnce({
242
- variants: {},
243
- samples: [
244
- {
245
- templatePath: "sample.yaml",
246
- variants: [
247
- { output: "v1.output", data: {} },
248
- { output: "v2.output", data: {} },
249
- ],
250
- output: "out",
251
- },
267
+ mockCompileSample.mockReturnValue({
268
+ items: [
269
+ { fileName: "file1.js", content: "console.log('1');" },
270
+ { fileName: "file2.js", content: "console.log('2');" },
252
271
  ],
253
272
  });
254
- mockResolveSampleFile.mockReturnValue("/path/to/sample.yaml");
255
- mockParse.mockReturnValueOnce({
256
- template: "t",
257
- type: "js",
258
- dependencies: [],
259
- input: [],
260
- });
261
- mockResolveTemplate.mockReturnValue("resolved template");
262
- mockIsVariantDefinition.mockReturnValue(true);
273
+ const batchFilePath = getPath("batch.yaml");
274
+ const batchFileContent = multiline`
275
+ variants:
276
+ - name: foo
277
+ input:
278
+ type: object
279
+ properties:
280
+ var2: value
281
+ samples:
282
+ - templatePath: sample.yaml
283
+ variants:
284
+ - output: out
285
+ input: foo
286
+ `;
287
+ fs.writeFileSync(batchFilePath, batchFileContent);
288
+ const sampleFilePath = getPath("sample.yaml");
289
+ const sampleContent = multiline`
290
+ template: sample.js.template
291
+ type: javascript
292
+ dependencies:
293
+ input:
294
+ - name: var
295
+ type: string
296
+ required: true
297
+ `;
298
+ fs.writeFileSync(sampleFilePath, sampleContent);
299
+ batchCompile(batchFilePath, {});
300
+
301
+ expect(fs.existsSync(getPath("out/file1.js"))).toBe(true);
302
+ expect(fs.readFileSync(getPath("out/file1.js"), "utf-8")).toBe(
303
+ "console.log('1');",
304
+ );
305
+ expect(fs.existsSync(getPath("out/file2.js"))).toBe(true);
306
+ expect(fs.readFileSync(getPath("out/file2.js"), "utf-8")).toBe(
307
+ "console.log('2');",
308
+ );
309
+ });
310
+
311
+ it("should compile and write output files for each variant", () => {
263
312
  mockCompileSample.mockReturnValue({
264
313
  items: [
265
314
  { fileName: "file1.js", content: "console.log('1');" },
266
315
  { fileName: "file2.js", content: "console.log('2');" },
267
316
  ],
268
317
  });
269
- mockCreateOutputDirectory.mockImplementation(() => {});
270
- mockFs.writeFileSync.mockImplementation(() => {});
271
- batchCompile("batch.yaml");
272
- expect(mockCreateOutputDirectory).toHaveBeenCalledWith("/working/directory/v1.output");
273
- expect(mockCreateOutputDirectory).toHaveBeenCalledWith("/working/directory/v2.output");
274
- expect(mockFs.writeFileSync).toHaveBeenCalledWith(
275
- path.join("/working/directory", "v1.output", "file1.js"),
318
+ const batchFilePath = getPath("batch.yaml");
319
+ const batchFileContent = multiline`
320
+ variants:
321
+ - name: foo
322
+ input:
323
+ type: object
324
+ properties:
325
+ var2: value
326
+ samples:
327
+ - templatePath: sample.yaml
328
+ variants:
329
+ - output: out
330
+ input: foo
331
+ `;
332
+ fs.writeFileSync(batchFilePath, batchFileContent);
333
+ const sampleFilePath = getPath("sample.yaml");
334
+ const sampleContent = multiline`
335
+ template: sample.js.template
336
+ type: javascript
337
+ dependencies:
338
+ input:
339
+ - name: var
340
+ type: string
341
+ required: true
342
+ `;
343
+ fs.writeFileSync(sampleFilePath, sampleContent);
344
+ batchCompile(batchFilePath, { outputDir: getPath("other") });
345
+
346
+ expect(fs.existsSync(getPath("other/out/file1.js"))).toBe(true);
347
+ expect(fs.readFileSync(getPath("other/out/file1.js"), "utf-8")).toBe(
276
348
  "console.log('1');",
277
349
  );
278
- expect(mockFs.writeFileSync).toHaveBeenCalledWith(
279
- path.join("/working/directory", "v1.output", "file2.js"),
350
+ expect(fs.existsSync(getPath("other/out/file2.js"))).toBe(true);
351
+ expect(fs.readFileSync(getPath("other/out/file2.js"), "utf-8")).toBe(
280
352
  "console.log('2');",
281
353
  );
282
354
  });
@@ -6,11 +6,7 @@ import fs from "fs";
6
6
  const mockFs = vi.mocked(fs);
7
7
 
8
8
  vi.mock("../src/utils");
9
- import {
10
- parse,
11
- resolveSampleFile,
12
- isFile,
13
- } from "../src/utils";
9
+ import { parse, resolveSampleFile, isFile } from "../src/utils";
14
10
  import { resolveAndParseSample } from "../src/common";
15
11
  const mockParse = vi.mocked(parse);
16
12
  const mockResolveSampleFile = vi.mocked(resolveSampleFile);
@@ -12,7 +12,7 @@ import {
12
12
  } from "../src/utils";
13
13
  import { Sample } from "@caleuche/core";
14
14
 
15
- function multiline(strings: TemplateStringsArray, ...values: any[]) {
15
+ export function multiline(strings: TemplateStringsArray, ...values: any[]) {
16
16
  let result = strings[0];
17
17
  for (let i = 0; i < values.length; i++) {
18
18
  result += values[i] + strings[i + 1];