@caleuche/cli 0.1.2

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/README.md ADDED
@@ -0,0 +1,103 @@
1
+ # Caleuche CLI
2
+
3
+ Caleuche CLI is a command-line tool for compiling code samples and generating project files from templates. It supports multiple languages and flexible sample definitions, including inline templates and external template files.
4
+
5
+ ## Installation
6
+
7
+ ```sh
8
+ npm install @caleuche/cli
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```
14
+ che compile <sample-directory|sample-file> <data-file> <output-directory> [options]
15
+ ```
16
+
17
+ - `<sample-directory|sample-file>`: Path to a directory containing a `sample.yaml` or a direct path to a sample YAML file.
18
+ - `<data-file>`: Path to the data file (JSON or YAML).
19
+ - `<output-directory>`: Directory where the generated project will be placed.
20
+
21
+ ### Options
22
+
23
+ - `-p, --project` Generate project file (e.g., csproj, go.mod, etc.)
24
+
25
+ ## Examples
26
+
27
+ ### 1. Sample with Inline Template
28
+
29
+ **sample.yaml**
30
+
31
+ ```yaml
32
+ template: |
33
+ Hello, <%= name %>!
34
+ type: python
35
+ dependencies: []
36
+ input:
37
+ - name: name
38
+ type: string
39
+ required: true
40
+ ```
41
+
42
+ **data.yaml**
43
+
44
+ ```yaml
45
+ name: World
46
+ ```
47
+
48
+ **Command:**
49
+
50
+ ```sh
51
+ che compile ./my-sample ./data.yaml ./output
52
+ ```
53
+
54
+ ### 2. Sample with Template File Reference
55
+
56
+ **Directory structure:**
57
+
58
+ ```
59
+ my-sample/
60
+ sample.yaml
61
+ main.py.tmpl
62
+ ```
63
+
64
+ **sample.yaml**
65
+
66
+ ```yaml
67
+ template: main.py.tmpl
68
+ type: python
69
+ dependencies: []
70
+ input:
71
+ - name: name
72
+ type: string
73
+ required: true
74
+ ```
75
+
76
+ **main.py.tmpl**
77
+
78
+ ```python
79
+ print("Hello, <%= name %>!")
80
+ ```
81
+
82
+ **data.yaml**
83
+
84
+ ```yaml
85
+ name: Alice
86
+ ```
87
+
88
+ **Command:**
89
+
90
+ ```sh
91
+ che compile ./my-sample ./data.yaml ./output
92
+ ```
93
+
94
+ ## Sample and Data File Structure
95
+
96
+ - **Sample file**: YAML describing the sample, including the template (inline or file reference), language, dependencies, and input fields.
97
+
98
+ - **Data file**: JSON or YAML with the data to inject into the sample.
99
+
100
+
101
+ ## License
102
+
103
+ MIT
package/dist/index.js ADDED
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const commander_1 = require("commander");
8
+ const core_1 = require("@caleuche/core");
9
+ const fs_1 = __importDefault(require("fs"));
10
+ const path_1 = __importDefault(require("path"));
11
+ const utils_1 = require("./utils");
12
+ commander_1.program
13
+ .name("@caleuche/cli")
14
+ .description("Caleuche CLI for compiling samples")
15
+ .version("1.0.0");
16
+ function compile(samplePath, dataPath, outputPath, options) {
17
+ const sampleFilePath = (0, utils_1.resolveSampleFile)(samplePath);
18
+ if (!fs_1.default.existsSync(sampleFilePath)) {
19
+ console.error(`Sample file not found: ${sampleFilePath}`);
20
+ process.exit(1);
21
+ }
22
+ const sample = (0, utils_1.parse)(sampleFilePath);
23
+ if (!sample) {
24
+ console.error(`Failed to parse sample file: ${sampleFilePath}`);
25
+ process.exit(1);
26
+ }
27
+ sample.template = (0, utils_1.resolveTemplate)(samplePath, sample);
28
+ const inputData = (0, utils_1.parse)(dataPath);
29
+ if (!inputData || !(0, utils_1.isObject)(inputData)) {
30
+ console.error(`Failed to parse input data file: ${dataPath}`);
31
+ process.exit(1);
32
+ }
33
+ const output = (0, core_1.compileSample)(sample, inputData, {
34
+ project: options.project || false,
35
+ });
36
+ if (!(0, utils_1.isObject)(inputData)) {
37
+ console.error("Input data must be an object.");
38
+ process.exit(1);
39
+ }
40
+ (0, utils_1.createOutputDirectory)(outputPath);
41
+ for (const { fileName, content } of output.items) {
42
+ const itemOutputPath = path_1.default.join(outputPath, fileName);
43
+ fs_1.default.writeFileSync(itemOutputPath, content);
44
+ }
45
+ }
46
+ commander_1.program
47
+ .command("compile <sample-directory> <data-file> <output-directory>")
48
+ .option("-p, --project", "Generate project file")
49
+ .action(compile);
50
+ commander_1.program.parse();
package/dist/utils.js ADDED
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.parse = parse;
7
+ exports.resolveSampleFile = resolveSampleFile;
8
+ exports.isDirectory = isDirectory;
9
+ exports.createOutputDirectory = createOutputDirectory;
10
+ exports.resolveTemplate = resolveTemplate;
11
+ exports.isObject = isObject;
12
+ const yaml_1 = require("yaml");
13
+ const fs_1 = __importDefault(require("fs"));
14
+ const path_1 = __importDefault(require("path"));
15
+ function parse(filePath) {
16
+ try {
17
+ const fileContent = fs_1.default.readFileSync(filePath, "utf-8");
18
+ if (filePath.endsWith(".yaml") || filePath.endsWith(".yml")) {
19
+ return (0, yaml_1.parse)(fileContent);
20
+ }
21
+ return JSON.parse(fileContent);
22
+ }
23
+ catch (error) {
24
+ return null;
25
+ }
26
+ }
27
+ function resolveSampleFile(samplePath) {
28
+ if (isDirectory(samplePath)) {
29
+ return path_1.default.join(samplePath, "sample.yaml");
30
+ }
31
+ return samplePath;
32
+ }
33
+ function isDirectory(path) {
34
+ return fs_1.default.existsSync(path) && fs_1.default.lstatSync(path).isDirectory();
35
+ }
36
+ function createOutputDirectory(outputPath) {
37
+ if (!fs_1.default.existsSync(outputPath)) {
38
+ fs_1.default.mkdirSync(outputPath, { recursive: true });
39
+ }
40
+ }
41
+ function resolveTemplate(samplePath, sample) {
42
+ try {
43
+ const templatePath = path_1.default.join(samplePath, sample.template);
44
+ if (!fs_1.default.existsSync(templatePath)) {
45
+ return sample.template;
46
+ }
47
+ return fs_1.default.readFileSync(templatePath, "utf-8");
48
+ }
49
+ catch (error) {
50
+ console.error("Error reading template file.");
51
+ process.exit(1);
52
+ }
53
+ }
54
+ function isObject(value) {
55
+ return value !== null && typeof value === "object" && !Array.isArray(value);
56
+ }
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@caleuche/cli",
3
+ "version": "0.1.2",
4
+ "main": "dist/index.js",
5
+ "bin": {
6
+ "che": "dist/index.js"
7
+ },
8
+ "scripts": {
9
+ "build": "tsc",
10
+ "build:watch": "tsc --watch",
11
+ "build:clean": "rimraf dist && tsc",
12
+ "build:clean:watch": "rimraf dist && tsc --watch",
13
+ "clean": "rimraf dist",
14
+ "format": "prettier --write .",
15
+ "prepare": "npm run build"
16
+ },
17
+ "author": "",
18
+ "license": "MIT",
19
+ "description": "Caleuche CLI",
20
+ "dependencies": {
21
+ "@caleuche/core": "file:../caleuche",
22
+ "commander": "^14.0.0",
23
+ "yaml": "^2.8.0"
24
+ },
25
+ "devDependencies": {
26
+ "@types/node": "^22.15.30",
27
+ "prettier": "^3.5.3",
28
+ "rimraf": "^6.0.1",
29
+ "typescript": "^5.8.3"
30
+ },
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "https://github.com/brandor64/caleuche"
34
+ },
35
+ "homepage": "https://github.com/brandor64/caleuche#readme"
36
+ }
package/src/index.ts ADDED
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { program } from "commander";
4
+ import { compileSample, Sample } from "@caleuche/core";
5
+ import fs from "fs";
6
+ import path from "path";
7
+ import {
8
+ createOutputDirectory,
9
+ isObject,
10
+ parse,
11
+ resolveSampleFile,
12
+ resolveTemplate,
13
+ } from "./utils";
14
+
15
+ program
16
+ .name("@caleuche/cli")
17
+ .description("Caleuche CLI for compiling samples")
18
+ .version("1.0.0");
19
+
20
+ function compile(
21
+ samplePath: string,
22
+ dataPath: string,
23
+ outputPath: string,
24
+ options: { project?: boolean },
25
+ ) {
26
+ const sampleFilePath = resolveSampleFile(samplePath);
27
+ if (!fs.existsSync(sampleFilePath)) {
28
+ console.error(`Sample file not found: ${sampleFilePath}`);
29
+ process.exit(1);
30
+ }
31
+
32
+ const sample = parse<Sample>(sampleFilePath);
33
+ if (!sample) {
34
+ console.error(`Failed to parse sample file: ${sampleFilePath}`);
35
+ process.exit(1);
36
+ }
37
+ sample.template = resolveTemplate(samplePath, sample);
38
+
39
+ const inputData = parse<Record<string, any>>(dataPath);
40
+ if (!inputData || !isObject(inputData)) {
41
+ console.error(`Failed to parse input data file: ${dataPath}`);
42
+ process.exit(1);
43
+ }
44
+
45
+ const output = compileSample(sample, inputData, {
46
+ project: options.project || false,
47
+ });
48
+
49
+ if (!isObject(inputData)) {
50
+ console.error("Input data must be an object.");
51
+ process.exit(1);
52
+ }
53
+
54
+ createOutputDirectory(outputPath);
55
+
56
+ for (const { fileName, content } of output.items) {
57
+ const itemOutputPath = path.join(outputPath, fileName);
58
+ fs.writeFileSync(itemOutputPath, content);
59
+ }
60
+ }
61
+
62
+ program
63
+ .command("compile <sample-directory> <data-file> <output-directory>")
64
+ .option("-p, --project", "Generate project file")
65
+ .action(compile);
66
+
67
+ program.parse();
package/src/utils.ts ADDED
@@ -0,0 +1,50 @@
1
+ import { parse as parseYaml } from "yaml";
2
+ import fs from "fs";
3
+ import path from "path";
4
+ import { Sample } from "@caleuche/core";
5
+
6
+ export function parse<T>(filePath: string): T | null {
7
+ try {
8
+ const fileContent = fs.readFileSync(filePath, "utf-8");
9
+ if (filePath.endsWith(".yaml") || filePath.endsWith(".yml")) {
10
+ return parseYaml(fileContent) as T;
11
+ }
12
+ return JSON.parse(fileContent) as T;
13
+ } catch (error) {
14
+ return null;
15
+ }
16
+ }
17
+
18
+ export function resolveSampleFile(samplePath: string): string {
19
+ if (isDirectory(samplePath)) {
20
+ return path.join(samplePath, "sample.yaml");
21
+ }
22
+ return samplePath;
23
+ }
24
+
25
+ export function isDirectory(path: string): boolean {
26
+ return fs.existsSync(path) && fs.lstatSync(path).isDirectory();
27
+ }
28
+
29
+ export function createOutputDirectory(outputPath: string) {
30
+ if (!fs.existsSync(outputPath)) {
31
+ fs.mkdirSync(outputPath, { recursive: true });
32
+ }
33
+ }
34
+
35
+ export function resolveTemplate(samplePath: string, sample: Sample): string {
36
+ try {
37
+ const templatePath = path.join(samplePath, sample.template);
38
+ if (!fs.existsSync(templatePath)) {
39
+ return sample.template;
40
+ }
41
+ return fs.readFileSync(templatePath, "utf-8");
42
+ } catch (error) {
43
+ console.error("Error reading template file.");
44
+ process.exit(1);
45
+ }
46
+ }
47
+
48
+ export function isObject(value: any): value is Record<string, any> {
49
+ return value !== null && typeof value === "object" && !Array.isArray(value);
50
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,11 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "es2020",
4
+ "module": "commonjs",
5
+ "outDir": "dist",
6
+ "rootDir": "src",
7
+ "strict": true,
8
+ "esModuleInterop": true
9
+ },
10
+ "include": ["src/**/*"]
11
+ }