vde-layout 0.0.1

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.
Files changed (80) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +194 -0
  3. package/bin/vde-layout +2 -0
  4. package/dist/cli.d.ts +27 -0
  5. package/dist/cli.d.ts.map +1 -0
  6. package/dist/cli.js +138 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/config/loader.d.ts +14 -0
  9. package/dist/config/loader.d.ts.map +1 -0
  10. package/dist/config/loader.js +117 -0
  11. package/dist/config/loader.js.map +1 -0
  12. package/dist/config/validator.d.ts +3 -0
  13. package/dist/config/validator.d.ts.map +1 -0
  14. package/dist/config/validator.js +168 -0
  15. package/dist/config/validator.js.map +1 -0
  16. package/dist/executor/dry-run-executor.d.ts +16 -0
  17. package/dist/executor/dry-run-executor.d.ts.map +1 -0
  18. package/dist/executor/dry-run-executor.js +45 -0
  19. package/dist/executor/dry-run-executor.js.map +1 -0
  20. package/dist/executor/index.d.ts +6 -0
  21. package/dist/executor/index.d.ts.map +1 -0
  22. package/dist/executor/index.js +10 -0
  23. package/dist/executor/index.js.map +1 -0
  24. package/dist/executor/mock-executor.d.ts +21 -0
  25. package/dist/executor/mock-executor.d.ts.map +1 -0
  26. package/dist/executor/mock-executor.js +73 -0
  27. package/dist/executor/mock-executor.js.map +1 -0
  28. package/dist/executor/real-executor.d.ts +16 -0
  29. package/dist/executor/real-executor.d.ts.map +1 -0
  30. package/dist/executor/real-executor.js +58 -0
  31. package/dist/executor/real-executor.js.map +1 -0
  32. package/dist/index.d.ts +3 -0
  33. package/dist/index.d.ts.map +1 -0
  34. package/dist/index.js +24 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/interfaces/command-executor.d.ts +7 -0
  37. package/dist/interfaces/command-executor.d.ts.map +1 -0
  38. package/dist/interfaces/command-executor.js +3 -0
  39. package/dist/interfaces/command-executor.js.map +1 -0
  40. package/dist/interfaces/index.d.ts +31 -0
  41. package/dist/interfaces/index.d.ts.map +1 -0
  42. package/dist/interfaces/index.js +3 -0
  43. package/dist/interfaces/index.js.map +1 -0
  44. package/dist/layout/engine.d.ts +18 -0
  45. package/dist/layout/engine.d.ts.map +1 -0
  46. package/dist/layout/engine.js +174 -0
  47. package/dist/layout/engine.js.map +1 -0
  48. package/dist/layout/preset.d.ts +13 -0
  49. package/dist/layout/preset.d.ts.map +1 -0
  50. package/dist/layout/preset.js +55 -0
  51. package/dist/layout/preset.js.map +1 -0
  52. package/dist/models/schema.d.ts +144 -0
  53. package/dist/models/schema.d.ts.map +1 -0
  54. package/dist/models/schema.js +95 -0
  55. package/dist/models/schema.js.map +1 -0
  56. package/dist/models/types.d.ts +34 -0
  57. package/dist/models/types.d.ts.map +1 -0
  58. package/dist/models/types.js +16 -0
  59. package/dist/models/types.js.map +1 -0
  60. package/dist/tmux/commands.d.ts +14 -0
  61. package/dist/tmux/commands.d.ts.map +1 -0
  62. package/dist/tmux/commands.js +59 -0
  63. package/dist/tmux/commands.js.map +1 -0
  64. package/dist/tmux/executor.d.ts +20 -0
  65. package/dist/tmux/executor.d.ts.map +1 -0
  66. package/dist/tmux/executor.js +64 -0
  67. package/dist/tmux/executor.js.map +1 -0
  68. package/dist/utils/errors.d.ts +36 -0
  69. package/dist/utils/errors.d.ts.map +1 -0
  70. package/dist/utils/errors.js +131 -0
  71. package/dist/utils/errors.js.map +1 -0
  72. package/dist/utils/logger.d.ts +25 -0
  73. package/dist/utils/logger.d.ts.map +1 -0
  74. package/dist/utils/logger.js +67 -0
  75. package/dist/utils/logger.js.map +1 -0
  76. package/dist/utils/ratio.d.ts +3 -0
  77. package/dist/utils/ratio.d.ts.map +1 -0
  78. package/dist/utils/ratio.js +44 -0
  79. package/dist/utils/ratio.js.map +1 -0
  80. package/package.json +72 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Yuki Yano
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,194 @@
1
+ # vde-layout
2
+
3
+ A CLI tool for easily reproducing tmux pane layouts
4
+
5
+ ## Overview
6
+
7
+ vde-layout is a tool that allows you to define tmux pane layouts in YAML configuration files and reproduce them with a single command. You can manage multiple layouts as presets for different purposes such as development environments, monitoring, and test execution.
8
+
9
+ ## Features
10
+
11
+ - Define layouts in YAML format
12
+ - Reproduce layouts with a single command
13
+ - Manage presets for different use cases
14
+ - Flexible pane settings (commands, working directories, environment variables, etc.)
15
+ - Freely combine horizontal and vertical splits
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install -g vde-layout
21
+ ```
22
+
23
+ or
24
+
25
+ ```bash
26
+ pnpm add -g vde-layout
27
+ ```
28
+
29
+ or
30
+
31
+ ```bash
32
+ bun add -g vde-layout
33
+ ```
34
+
35
+ ## Usage
36
+
37
+ ### Creating a Configuration File
38
+
39
+ Create a configuration file at `~/.config/vde/layout.yml`:
40
+
41
+ ```yaml
42
+ presets:
43
+ # Development environment layout
44
+ dev:
45
+ name: Development Environment
46
+ description: 3-pane configuration with editor, server, and log monitoring
47
+ layout:
48
+ type: horizontal
49
+ ratio: [3, 2] # 60:40 ratio (automatically normalized)
50
+ panes:
51
+ - name: editor
52
+ command: nvim
53
+ focus: true
54
+ - type: vertical
55
+ ratio: [7, 3] # 70:30 ratio
56
+ panes:
57
+ - name: server
58
+ command: npm run dev
59
+ - name: logs
60
+ command: tail -f logs/app.log
61
+
62
+ # Simple 2-pane layout
63
+ simple:
64
+ name: Simple Layout
65
+ description: 2-pane configuration with editor and terminal
66
+ layout:
67
+ type: vertical
68
+ ratio: [7, 3] # 70:30 ratio
69
+ panes:
70
+ - name: editor
71
+ command: vim
72
+ - name: terminal
73
+ # Omitting command launches the default shell
74
+
75
+ # Single pane preset (without layout)
76
+ monitor:
77
+ name: System Monitor
78
+ description: System monitoring tool
79
+ command: htop
80
+ ```
81
+
82
+ ### Commands
83
+
84
+ #### List Presets
85
+
86
+ ```bash
87
+ vde-layout list
88
+ ```
89
+
90
+ #### Execute a Preset
91
+
92
+ ```bash
93
+ # Execute a specific preset
94
+ vde-layout dev
95
+
96
+ # Execute the default preset
97
+ vde-layout
98
+ ```
99
+
100
+ #### Options
101
+
102
+ ```bash
103
+ # dry-run mode (doesn't actually execute)
104
+ vde-layout dev --dry-run
105
+
106
+ # Show verbose logs
107
+ vde-layout dev --verbose
108
+
109
+ # Show help
110
+ vde-layout --help
111
+ ```
112
+
113
+ ## Configuration File Structure
114
+
115
+ ### Presets
116
+
117
+ Each preset is defined as an object with the following fields:
118
+
119
+ ```yaml
120
+ presets:
121
+ preset-name:
122
+ name: "Preset Name" # Required
123
+ description: "Description" # Optional
124
+ layout: # Optional (single pane when omitted)
125
+ # Layout definition
126
+ command: "Command" # Optional (only when layout is absent)
127
+ ```
128
+
129
+ ### Layout Definition
130
+
131
+ Layouts define horizontal or vertical splits:
132
+
133
+ ```yaml
134
+ layout:
135
+ type: horizontal # horizontal or vertical
136
+ ratio: [3, 2] # Split ratio (automatically normalized)
137
+ panes: # Array of panes
138
+ - name: "Pane Name" # Required (for pane identification)
139
+ command: "Command" # Optional (default shell when omitted)
140
+ cwd: "~/project" # Working directory (optional)
141
+ env: # Environment variables (optional)
142
+ NODE_ENV: development
143
+ focus: true # Focus setting (optional)
144
+ # Or nested layout
145
+ - type: vertical
146
+ ratio: [1, 1]
147
+ panes:
148
+ - name: "Child Pane 1"
149
+ - name: "Child Pane 2"
150
+ ```
151
+
152
+ ### Automatic Ratio Normalization
153
+
154
+ You can specify any positive numbers for ratio, which are automatically normalized to 100%:
155
+
156
+ - `[1, 1]` → `[50, 50]` (50% each)
157
+ - `[2, 3]` → `[40, 60]` (40%, 60%)
158
+ - `[1, 2, 1]` → `[25, 50, 25]` (25%, 50%, 25%)
159
+
160
+ ### Single Pane Presets
161
+
162
+ When layout is omitted, it operates as a single pane:
163
+
164
+ ```yaml
165
+ presets:
166
+ simple-command:
167
+ name: "Single Command"
168
+ command: "htop" # Execute a single command
169
+
170
+ default-shell:
171
+ name: "Default Shell"
172
+ # Omitting command also launches the default shell
173
+ ```
174
+
175
+ ### Environment Variables
176
+
177
+ The configuration file location can be changed using environment variables:
178
+
179
+ - `XDG_CONFIG_HOME`: Follows the XDG Base Directory specification
180
+ - `VDE_CONFIG_PATH`: Directly specify the configuration file directory
181
+
182
+ ## Requirements
183
+
184
+ - Node.js 22 or higher
185
+ - tmux 2.0 or higher
186
+ - Must be executed within a tmux session
187
+
188
+ ## License
189
+
190
+ MIT
191
+
192
+ ## Contributing
193
+
194
+ Please submit bug reports and feature requests to [GitHub Issues](https://github.com/yuki-yano/vde-layout/issues).
package/bin/vde-layout ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ require('../dist/index.js');
package/dist/cli.d.ts ADDED
@@ -0,0 +1,27 @@
1
+ import type { IPresetManager, ILayoutEngine, ICommandExecutor } from "./interfaces";
2
+ export interface CLIOptions {
3
+ presetManager?: IPresetManager;
4
+ createLayoutEngine?: (options: {
5
+ verbose: boolean;
6
+ dryRun: boolean;
7
+ executor?: ICommandExecutor;
8
+ }) => ILayoutEngine;
9
+ createCommandExecutor?: (options: {
10
+ verbose: boolean;
11
+ dryRun: boolean;
12
+ }) => ICommandExecutor;
13
+ }
14
+ export declare class CLI {
15
+ private program;
16
+ private presetManager;
17
+ private createLayoutEngine;
18
+ private createCommandExecutor;
19
+ private logger;
20
+ constructor(options?: CLIOptions);
21
+ private setupCommands;
22
+ run(args?: string[]): Promise<void>;
23
+ private listPresets;
24
+ private executePreset;
25
+ private handleError;
26
+ }
27
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAInF,MAAM,WAAW,UAAU;IACzB,aAAa,CAAC,EAAE,cAAc,CAAA;IAC9B,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,gBAAgB,CAAA;KAAE,KAAK,aAAa,CAAA;IACnH,qBAAqB,CAAC,EAAE,CAAC,OAAO,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,KAAK,gBAAgB,CAAA;CAC7F;AAMD,qBAAa,GAAG;IACd,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,kBAAkB,CAIP;IACnB,OAAO,CAAC,qBAAqB,CAAsE;IACnG,OAAO,CAAC,MAAM,CAAQ;gBAEV,OAAO,GAAE,UAAe;IAmBpC,OAAO,CAAC,aAAa;IAoCf,GAAG,CAAC,IAAI,GAAE,MAAM,EAA0B,GAAG,OAAO,CAAC,IAAI,CAAC;YAsBlD,WAAW;YA+BX,aAAa;IAkD3B,OAAO,CAAC,WAAW;CASpB"}
package/dist/cli.js ADDED
@@ -0,0 +1,138 @@
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.CLI = void 0;
7
+ const commander_1 = require("commander");
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const preset_1 = require("./layout/preset");
10
+ const engine_1 = require("./layout/engine");
11
+ const package_json_1 = require("../package.json");
12
+ const executor_1 = require("./executor");
13
+ const logger_1 = require("./utils/logger");
14
+ class CLI {
15
+ program;
16
+ presetManager;
17
+ createLayoutEngine;
18
+ createCommandExecutor;
19
+ logger;
20
+ constructor(options = {}) {
21
+ this.program = new commander_1.Command();
22
+ this.presetManager = options.presetManager || new preset_1.PresetManager();
23
+ this.createLayoutEngine = options.createLayoutEngine || ((opts) => new engine_1.LayoutEngine(opts));
24
+ this.createCommandExecutor =
25
+ options.createCommandExecutor ||
26
+ ((opts) => {
27
+ if (opts.dryRun) {
28
+ return new executor_1.DryRunExecutor({ verbose: opts.verbose });
29
+ }
30
+ return new executor_1.RealExecutor({ verbose: opts.verbose });
31
+ });
32
+ this.logger = new logger_1.Logger();
33
+ this.setupCommands();
34
+ }
35
+ setupCommands() {
36
+ this.program
37
+ .name("vde-layout")
38
+ .description("VDE (Vibrant Development Environment) Layout Manager - tmux pane layout management tool")
39
+ .version(package_json_1.version, "-V, --version", "Show version")
40
+ .helpOption("-h, --help", "Show help");
41
+ this.program
42
+ .option("-v, --verbose", "Show detailed logs", false)
43
+ .option("--dry-run", "Display commands without executing", false);
44
+ this.program
45
+ .command("list")
46
+ .description("List available presets")
47
+ .action(async () => {
48
+ await this.listPresets();
49
+ });
50
+ this.program
51
+ .argument("[preset]", 'Preset name (defaults to "default" preset when omitted)')
52
+ .action(async (presetName) => {
53
+ const options = this.program.opts();
54
+ await this.executePreset(presetName, {
55
+ verbose: options.verbose,
56
+ dryRun: options.dryRun,
57
+ });
58
+ });
59
+ }
60
+ async run(args = process.argv.slice(2)) {
61
+ try {
62
+ await this.program.parseAsync(args, { from: "user" });
63
+ const opts = this.program.opts();
64
+ if (opts.verbose === true) {
65
+ this.logger = new logger_1.Logger({ level: logger_1.LogLevel.INFO });
66
+ }
67
+ }
68
+ catch (error) {
69
+ if (error instanceof Error && error.message.includes("Process exited")) {
70
+ throw error;
71
+ }
72
+ this.handleError(error);
73
+ }
74
+ }
75
+ async listPresets() {
76
+ try {
77
+ await this.presetManager.loadConfig();
78
+ const presets = this.presetManager.listPresets();
79
+ if (presets.length === 0) {
80
+ this.logger.warn("No presets defined");
81
+ process.exit(0);
82
+ }
83
+ console.log(chalk_1.default.bold("Available presets:\n"));
84
+ const maxKeyLength = Math.max(...presets.map((p) => p.key.length));
85
+ presets.forEach((preset) => {
86
+ const paddedKey = preset.key.padEnd(maxKeyLength + 2);
87
+ const description = preset.description ?? "";
88
+ console.log(` ${chalk_1.default.cyan(paddedKey)} ${description}`);
89
+ });
90
+ process.exit(0);
91
+ }
92
+ catch (error) {
93
+ this.handleError(error);
94
+ }
95
+ }
96
+ async executePreset(presetName, options) {
97
+ try {
98
+ await this.presetManager.loadConfig();
99
+ const preset = presetName !== undefined && presetName.length > 0
100
+ ? this.presetManager.getPreset(presetName)
101
+ : this.presetManager.getDefaultPreset();
102
+ const forceDryRun = process.env.TMUX === undefined;
103
+ const effectiveDryRun = options.dryRun || forceDryRun;
104
+ const executor = this.createCommandExecutor({
105
+ verbose: options.verbose,
106
+ dryRun: effectiveDryRun,
107
+ });
108
+ const engine = this.createLayoutEngine({
109
+ verbose: options.verbose,
110
+ dryRun: effectiveDryRun,
111
+ executor,
112
+ });
113
+ if (effectiveDryRun) {
114
+ this.logger.warn("[DRY RUN] No actual commands will be executed");
115
+ if (forceDryRun && !options.dryRun) {
116
+ this.logger.warn("(Automatically enabled because not in tmux session)");
117
+ }
118
+ }
119
+ await engine.createLayout(preset);
120
+ this.logger.success(`✓ Applied preset "${preset.name}"`);
121
+ process.exit(0);
122
+ }
123
+ catch (error) {
124
+ this.handleError(error);
125
+ }
126
+ }
127
+ handleError(error) {
128
+ if (error instanceof Error) {
129
+ this.logger.error(error.message, error);
130
+ }
131
+ else {
132
+ this.logger.error("An unexpected error occurred");
133
+ }
134
+ process.exit(1);
135
+ }
136
+ }
137
+ exports.CLI = CLI;
138
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { Config } from "../models/types";
2
+ export interface ConfigLoaderOptions {
3
+ configPaths?: string[];
4
+ }
5
+ export declare class ConfigLoader {
6
+ private searchPaths;
7
+ constructor(options?: ConfigLoaderOptions);
8
+ loadYAML(): Promise<string>;
9
+ loadConfig(): Promise<Config>;
10
+ findConfigFile(): Promise<string | null>;
11
+ getSearchPaths(): string[];
12
+ private buildDefaultSearchPaths;
13
+ }
14
+ //# sourceMappingURL=loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAG7C,MAAM,WAAW,mBAAmB;IAClC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;CACvB;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,WAAW,CAAU;gBAEjB,OAAO,GAAE,mBAAwB;IASvC,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;IAyB3B,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAkC7B,cAAc,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAY9C,cAAc,IAAI,MAAM,EAAE;IAQ1B,OAAO,CAAC,uBAAuB;CAiBhC"}
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.ConfigLoader = void 0;
40
+ const fs_extra_1 = __importDefault(require("fs-extra"));
41
+ const path_1 = __importDefault(require("path"));
42
+ const os_1 = __importDefault(require("os"));
43
+ const yaml = __importStar(require("yaml"));
44
+ const errors_1 = require("../utils/errors");
45
+ class ConfigLoader {
46
+ searchPaths;
47
+ constructor(options = {}) {
48
+ this.searchPaths = options.configPaths ?? this.buildDefaultSearchPaths();
49
+ }
50
+ async loadYAML() {
51
+ const filePath = await this.findConfigFile();
52
+ if (filePath === null) {
53
+ throw new errors_1.ConfigError("Configuration file not found", errors_1.ErrorCodes.CONFIG_NOT_FOUND, {
54
+ searchPaths: this.searchPaths,
55
+ });
56
+ }
57
+ try {
58
+ const content = await fs_extra_1.default.readFile(filePath, "utf8");
59
+ return content;
60
+ }
61
+ catch (error) {
62
+ const errorMessage = error instanceof Error ? error.message : String(error);
63
+ throw new errors_1.ConfigError(`Failed to read configuration file`, errors_1.ErrorCodes.CONFIG_PERMISSION_ERROR, {
64
+ filePath,
65
+ error: errorMessage,
66
+ });
67
+ }
68
+ }
69
+ async loadConfig() {
70
+ const yamlContent = await this.loadYAML();
71
+ try {
72
+ if (!yamlContent.trim()) {
73
+ return { presets: {} };
74
+ }
75
+ const parsed = yaml.parse(yamlContent);
76
+ if (parsed === null || typeof parsed !== "object") {
77
+ return { presets: {} };
78
+ }
79
+ if (!("presets" in parsed) || typeof parsed.presets !== "object") {
80
+ return { presets: {} };
81
+ }
82
+ return parsed;
83
+ }
84
+ catch (error) {
85
+ const errorMessage = error instanceof Error ? error.message : String(error);
86
+ const filePath = await this.findConfigFile();
87
+ throw new errors_1.ConfigError(`Failed to parse YAML configuration file`, errors_1.ErrorCodes.CONFIG_PARSE_ERROR, {
88
+ filePath,
89
+ parseError: errorMessage,
90
+ });
91
+ }
92
+ }
93
+ async findConfigFile() {
94
+ for (const searchPath of this.searchPaths) {
95
+ if (await fs_extra_1.default.pathExists(searchPath)) {
96
+ return searchPath;
97
+ }
98
+ }
99
+ return null;
100
+ }
101
+ getSearchPaths() {
102
+ return [...this.searchPaths];
103
+ }
104
+ buildDefaultSearchPaths() {
105
+ const paths = [];
106
+ const vdeConfigPath = process.env.VDE_CONFIG_PATH;
107
+ if (vdeConfigPath !== undefined) {
108
+ paths.push(path_1.default.join(vdeConfigPath, "layout.yml"));
109
+ }
110
+ const homeDir = process.env.HOME ?? os_1.default.homedir();
111
+ const xdgConfigHome = process.env.XDG_CONFIG_HOME ?? path_1.default.join(homeDir, ".config");
112
+ paths.push(path_1.default.join(xdgConfigHome, "vde", "layout.yml"));
113
+ return [...new Set(paths)];
114
+ }
115
+ }
116
+ exports.ConfigLoader = ConfigLoader;
117
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Config } from "../models/types";
2
+ export declare function validateYAML(yamlText: string): Config;
3
+ //# sourceMappingURL=validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/config/validator.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAwI7C,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAoCrD"}