hugo-extended 0.154.3 → 0.154.5
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 +220 -65
- package/dist/cli.d.mts +1 -0
- package/dist/cli.mjs +28 -0
- package/dist/generated/flags.json +1143 -0
- package/dist/generated/types.d.mts +383 -0
- package/dist/generated/types.mjs +1 -0
- package/dist/generated/types.ts +490 -0
- package/dist/hugo.d.mts +240 -0
- package/dist/hugo.mjs +246 -0
- package/dist/lib/args.d.mts +30 -0
- package/dist/lib/args.mjs +126 -0
- package/dist/lib/env.d.mts +62 -0
- package/dist/lib/env.mjs +138 -0
- package/dist/lib/install.d.mts +66 -0
- package/dist/lib/install.mjs +190 -0
- package/dist/lib/utils.d.mts +123 -0
- package/dist/lib/utils.mjs +191 -0
- package/package.json +52 -26
- package/postinstall.js +57 -3
- package/index.d.ts +0 -7
- package/index.js +0 -22
- package/lib/cli.js +0 -15
- package/lib/install.js +0 -144
- package/lib/utils.js +0 -109
- /package/{LICENSE.md → LICENSE} +0 -0
package/dist/hugo.d.mts
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { HugoCommand, HugoOptionsFor } from "./generated/types.mjs";
|
|
2
|
+
import { ENV_VAR_DOCS, HugoEnvConfig, getEnvConfig } from "./lib/env.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/hugo.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Gets the path to the Hugo binary, automatically installing it if it's missing.
|
|
8
|
+
*
|
|
9
|
+
* This is the main entry point for the hugo-extended package. It checks if Hugo
|
|
10
|
+
* is already installed and available, and if not, triggers an automatic installation
|
|
11
|
+
* before returning the binary path.
|
|
12
|
+
*
|
|
13
|
+
* This handles the case where Hugo may mysteriously disappear (see issue #81),
|
|
14
|
+
* ensuring the binary is always available when this function is called.
|
|
15
|
+
*
|
|
16
|
+
* Environment variables that affect behavior:
|
|
17
|
+
* - HUGO_BIN_PATH: Use a custom binary path (skips auto-install if missing)
|
|
18
|
+
*
|
|
19
|
+
* @returns A promise that resolves with the absolute path to the Hugo binary
|
|
20
|
+
* @throws {Error} If installation fails, the platform is unsupported, or custom binary is missing
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* import hugo from 'hugo-extended';
|
|
25
|
+
*
|
|
26
|
+
* const hugoPath = await hugo();
|
|
27
|
+
* console.log(hugoPath); // "/usr/local/bin/hugo" or "./bin/hugo"
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
declare const getHugoBinary: () => Promise<string>;
|
|
31
|
+
/**
|
|
32
|
+
* Execute a Hugo command with type-safe options.
|
|
33
|
+
*
|
|
34
|
+
* This function runs Hugo with the specified command and options, inheriting stdio
|
|
35
|
+
* so output goes directly to the console. It's perfect for interactive commands
|
|
36
|
+
* like `hugo server` or build commands where you want to see live output.
|
|
37
|
+
*
|
|
38
|
+
* @param command - Hugo command to execute (e.g., "server", "build", "mod clean")
|
|
39
|
+
* @param positionalArgsOrOptions - Either positional arguments array or options object
|
|
40
|
+
* @param options - Type-safe options object (if first param is positional args)
|
|
41
|
+
* @returns A promise that resolves when the command completes successfully
|
|
42
|
+
* @throws {Error} If the command fails or Hugo is not available
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```typescript
|
|
46
|
+
* import { exec } from 'hugo-extended';
|
|
47
|
+
*
|
|
48
|
+
* // Start development server
|
|
49
|
+
* await exec("server", {
|
|
50
|
+
* port: 1313,
|
|
51
|
+
* buildDrafts: true,
|
|
52
|
+
* baseURL: "http://localhost:1313"
|
|
53
|
+
* });
|
|
54
|
+
*
|
|
55
|
+
* // Create a new site
|
|
56
|
+
* await exec("new site", ["my-site"], { format: "yaml" });
|
|
57
|
+
*
|
|
58
|
+
* // Build site for production
|
|
59
|
+
* await exec("build", {
|
|
60
|
+
* minify: true,
|
|
61
|
+
* cleanDestinationDir: true
|
|
62
|
+
* });
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
declare function exec<C extends HugoCommand>(command: C, positionalArgsOrOptions?: string[] | HugoOptionsFor<C>, options?: HugoOptionsFor<C>): Promise<void>;
|
|
66
|
+
/**
|
|
67
|
+
* Execute a Hugo command and capture its output.
|
|
68
|
+
*
|
|
69
|
+
* This function runs Hugo with the specified command and options, capturing
|
|
70
|
+
* stdout and stderr. It's useful for commands where you need to process the
|
|
71
|
+
* output programmatically, like `hugo version` or `hugo list all`.
|
|
72
|
+
*
|
|
73
|
+
* @param command - Hugo command to execute (e.g., "version", "list all")
|
|
74
|
+
* @param positionalArgsOrOptions - Either positional arguments array or options object
|
|
75
|
+
* @param options - Type-safe options object (if first param is positional args)
|
|
76
|
+
* @returns A promise that resolves with stdout and stderr strings
|
|
77
|
+
* @throws {Error} If the command fails or Hugo is not available
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```typescript
|
|
81
|
+
* import { execWithOutput } from 'hugo-extended';
|
|
82
|
+
*
|
|
83
|
+
* // Get Hugo version
|
|
84
|
+
* const { stdout } = await execWithOutput("version");
|
|
85
|
+
* console.log(stdout); // "hugo v0.154.3+extended ..."
|
|
86
|
+
*
|
|
87
|
+
* // List all content
|
|
88
|
+
* const { stdout: content } = await execWithOutput("list all");
|
|
89
|
+
* const pages = content.split('\n');
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
declare function execWithOutput<C extends HugoCommand>(command: C, positionalArgsOrOptions?: string[] | HugoOptionsFor<C>, options?: HugoOptionsFor<C>): Promise<{
|
|
93
|
+
stdout: string;
|
|
94
|
+
stderr: string;
|
|
95
|
+
}>;
|
|
96
|
+
/**
|
|
97
|
+
* Builder-style API for executing Hugo commands.
|
|
98
|
+
*
|
|
99
|
+
* Provides a fluent interface where each Hugo command is a method on the
|
|
100
|
+
* builder object. All methods are type-safe with autocomplete for options.
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* ```typescript
|
|
104
|
+
* import { hugo } from 'hugo-extended';
|
|
105
|
+
*
|
|
106
|
+
* // Start server
|
|
107
|
+
* await hugo.server({ port: 1313, buildDrafts: true });
|
|
108
|
+
*
|
|
109
|
+
* // Build site
|
|
110
|
+
* await hugo.build({ minify: true });
|
|
111
|
+
*
|
|
112
|
+
* // Module operations
|
|
113
|
+
* await hugo.mod.clean({ all: true });
|
|
114
|
+
* await hugo.mod.get();
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
declare const hugo: {
|
|
118
|
+
/** Build your site */
|
|
119
|
+
build: (options?: HugoOptionsFor<"build">) => Promise<void>;
|
|
120
|
+
/** Generate shell completion scripts */
|
|
121
|
+
completion: {
|
|
122
|
+
bash: (options?: HugoOptionsFor<"completion bash">) => Promise<void>;
|
|
123
|
+
fish: (options?: HugoOptionsFor<"completion fish">) => Promise<void>;
|
|
124
|
+
powershell: (options?: HugoOptionsFor<"completion powershell">) => Promise<void>;
|
|
125
|
+
zsh: (options?: HugoOptionsFor<"completion zsh">) => Promise<void>;
|
|
126
|
+
};
|
|
127
|
+
/** Print Hugo configuration */
|
|
128
|
+
config: (options?: HugoOptionsFor<"config">) => Promise<void>;
|
|
129
|
+
/** Convert content to different formats */
|
|
130
|
+
convert: {
|
|
131
|
+
toJSON: (options?: HugoOptionsFor<"convert toJSON">) => Promise<void>;
|
|
132
|
+
toTOML: (options?: HugoOptionsFor<"convert toTOML">) => Promise<void>;
|
|
133
|
+
toYAML: (options?: HugoOptionsFor<"convert toYAML">) => Promise<void>;
|
|
134
|
+
};
|
|
135
|
+
/** Print Hugo environment info */
|
|
136
|
+
env: (options?: HugoOptionsFor<"env">) => Promise<void>;
|
|
137
|
+
/** Generate documentation */
|
|
138
|
+
gen: {
|
|
139
|
+
doc: (options?: HugoOptionsFor<"gen doc">) => Promise<void>;
|
|
140
|
+
man: (options?: HugoOptionsFor<"gen man">) => Promise<void>;
|
|
141
|
+
};
|
|
142
|
+
/** Import your site from others */
|
|
143
|
+
import: {
|
|
144
|
+
jekyll: (options?: HugoOptionsFor<"import jekyll">) => Promise<void>;
|
|
145
|
+
};
|
|
146
|
+
/** List various types of content */
|
|
147
|
+
list: {
|
|
148
|
+
all: (options?: HugoOptionsFor<"list all">) => Promise<void>;
|
|
149
|
+
drafts: (options?: HugoOptionsFor<"list drafts">) => Promise<void>;
|
|
150
|
+
expired: (options?: HugoOptionsFor<"list expired">) => Promise<void>;
|
|
151
|
+
future: (options?: HugoOptionsFor<"list future">) => Promise<void>;
|
|
152
|
+
published: (options?: HugoOptionsFor<"list published">) => Promise<void>;
|
|
153
|
+
};
|
|
154
|
+
/** Module operations */
|
|
155
|
+
mod: {
|
|
156
|
+
clean: (options?: HugoOptionsFor<"mod clean">) => Promise<void>;
|
|
157
|
+
get: (options?: HugoOptionsFor<"mod get">) => Promise<void>;
|
|
158
|
+
graph: (options?: HugoOptionsFor<"mod graph">) => Promise<void>;
|
|
159
|
+
init: (options?: HugoOptionsFor<"mod init">) => Promise<void>;
|
|
160
|
+
npm: {
|
|
161
|
+
pack: (options?: HugoOptionsFor<"mod npm pack">) => Promise<void>;
|
|
162
|
+
};
|
|
163
|
+
tidy: (options?: HugoOptionsFor<"mod tidy">) => Promise<void>;
|
|
164
|
+
vendor: (options?: HugoOptionsFor<"mod vendor">) => Promise<void>;
|
|
165
|
+
verify: (options?: HugoOptionsFor<"mod verify">) => Promise<void>;
|
|
166
|
+
};
|
|
167
|
+
/** Create new content */
|
|
168
|
+
new: ((pathOrOptions?: string | HugoOptionsFor<"new">, options?: HugoOptionsFor<"new">) => Promise<void>) & {
|
|
169
|
+
content: (pathOrOptions?: string | HugoOptionsFor<"new content">, options?: HugoOptionsFor<"new content">) => Promise<void>;
|
|
170
|
+
site: (pathOrOptions?: string | HugoOptionsFor<"new site">, options?: HugoOptionsFor<"new site">) => Promise<void>;
|
|
171
|
+
theme: (nameOrOptions?: string | HugoOptionsFor<"new theme">, options?: HugoOptionsFor<"new theme">) => Promise<void>;
|
|
172
|
+
};
|
|
173
|
+
/** Start the Hugo development server */
|
|
174
|
+
server: (options?: HugoOptionsFor<"server">) => Promise<void>;
|
|
175
|
+
/** Print the Hugo version */
|
|
176
|
+
version: (options?: HugoOptionsFor<"version">) => Promise<void>;
|
|
177
|
+
};
|
|
178
|
+
declare const _default: (() => Promise<string>) & {
|
|
179
|
+
/** Build your site */
|
|
180
|
+
build: (options?: HugoOptionsFor<"build">) => Promise<void>;
|
|
181
|
+
/** Generate shell completion scripts */
|
|
182
|
+
completion: {
|
|
183
|
+
bash: (options?: HugoOptionsFor<"completion bash">) => Promise<void>;
|
|
184
|
+
fish: (options?: HugoOptionsFor<"completion fish">) => Promise<void>;
|
|
185
|
+
powershell: (options?: HugoOptionsFor<"completion powershell">) => Promise<void>;
|
|
186
|
+
zsh: (options?: HugoOptionsFor<"completion zsh">) => Promise<void>;
|
|
187
|
+
};
|
|
188
|
+
/** Print Hugo configuration */
|
|
189
|
+
config: (options?: HugoOptionsFor<"config">) => Promise<void>;
|
|
190
|
+
/** Convert content to different formats */
|
|
191
|
+
convert: {
|
|
192
|
+
toJSON: (options?: HugoOptionsFor<"convert toJSON">) => Promise<void>;
|
|
193
|
+
toTOML: (options?: HugoOptionsFor<"convert toTOML">) => Promise<void>;
|
|
194
|
+
toYAML: (options?: HugoOptionsFor<"convert toYAML">) => Promise<void>;
|
|
195
|
+
};
|
|
196
|
+
/** Print Hugo environment info */
|
|
197
|
+
env: (options?: HugoOptionsFor<"env">) => Promise<void>;
|
|
198
|
+
/** Generate documentation */
|
|
199
|
+
gen: {
|
|
200
|
+
doc: (options?: HugoOptionsFor<"gen doc">) => Promise<void>;
|
|
201
|
+
man: (options?: HugoOptionsFor<"gen man">) => Promise<void>;
|
|
202
|
+
};
|
|
203
|
+
/** Import your site from others */
|
|
204
|
+
import: {
|
|
205
|
+
jekyll: (options?: HugoOptionsFor<"import jekyll">) => Promise<void>;
|
|
206
|
+
};
|
|
207
|
+
/** List various types of content */
|
|
208
|
+
list: {
|
|
209
|
+
all: (options?: HugoOptionsFor<"list all">) => Promise<void>;
|
|
210
|
+
drafts: (options?: HugoOptionsFor<"list drafts">) => Promise<void>;
|
|
211
|
+
expired: (options?: HugoOptionsFor<"list expired">) => Promise<void>;
|
|
212
|
+
future: (options?: HugoOptionsFor<"list future">) => Promise<void>;
|
|
213
|
+
published: (options?: HugoOptionsFor<"list published">) => Promise<void>;
|
|
214
|
+
};
|
|
215
|
+
/** Module operations */
|
|
216
|
+
mod: {
|
|
217
|
+
clean: (options?: HugoOptionsFor<"mod clean">) => Promise<void>;
|
|
218
|
+
get: (options?: HugoOptionsFor<"mod get">) => Promise<void>;
|
|
219
|
+
graph: (options?: HugoOptionsFor<"mod graph">) => Promise<void>;
|
|
220
|
+
init: (options?: HugoOptionsFor<"mod init">) => Promise<void>;
|
|
221
|
+
npm: {
|
|
222
|
+
pack: (options?: HugoOptionsFor<"mod npm pack">) => Promise<void>;
|
|
223
|
+
};
|
|
224
|
+
tidy: (options?: HugoOptionsFor<"mod tidy">) => Promise<void>;
|
|
225
|
+
vendor: (options?: HugoOptionsFor<"mod vendor">) => Promise<void>;
|
|
226
|
+
verify: (options?: HugoOptionsFor<"mod verify">) => Promise<void>;
|
|
227
|
+
};
|
|
228
|
+
/** Create new content */
|
|
229
|
+
new: ((pathOrOptions?: string | HugoOptionsFor<"new">, options?: HugoOptionsFor<"new">) => Promise<void>) & {
|
|
230
|
+
content: (pathOrOptions?: string | HugoOptionsFor<"new content">, options?: HugoOptionsFor<"new content">) => Promise<void>;
|
|
231
|
+
site: (pathOrOptions?: string | HugoOptionsFor<"new site">, options?: HugoOptionsFor<"new site">) => Promise<void>;
|
|
232
|
+
theme: (nameOrOptions?: string | HugoOptionsFor<"new theme">, options?: HugoOptionsFor<"new theme">) => Promise<void>;
|
|
233
|
+
};
|
|
234
|
+
/** Start the Hugo development server */
|
|
235
|
+
server: (options?: HugoOptionsFor<"server">) => Promise<void>;
|
|
236
|
+
/** Print the Hugo version */
|
|
237
|
+
version: (options?: HugoOptionsFor<"version">) => Promise<void>;
|
|
238
|
+
};
|
|
239
|
+
//#endregion
|
|
240
|
+
export { ENV_VAR_DOCS, type HugoCommand, type HugoEnvConfig, type HugoOptionsFor, _default as default, exec, execWithOutput, getEnvConfig, getHugoBinary, hugo };
|
package/dist/hugo.mjs
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { buildArgs } from "./lib/args.mjs";
|
|
2
|
+
import { ENV_VAR_DOCS, getEnvConfig } from "./lib/env.mjs";
|
|
3
|
+
import { doesBinExist, getBinPath, logger } from "./lib/utils.mjs";
|
|
4
|
+
import install_default from "./lib/install.mjs";
|
|
5
|
+
import { spawn } from "node:child_process";
|
|
6
|
+
|
|
7
|
+
//#region src/hugo.ts
|
|
8
|
+
/**
|
|
9
|
+
* Gets the path to the Hugo binary, automatically installing it if it's missing.
|
|
10
|
+
*
|
|
11
|
+
* This is the main entry point for the hugo-extended package. It checks if Hugo
|
|
12
|
+
* is already installed and available, and if not, triggers an automatic installation
|
|
13
|
+
* before returning the binary path.
|
|
14
|
+
*
|
|
15
|
+
* This handles the case where Hugo may mysteriously disappear (see issue #81),
|
|
16
|
+
* ensuring the binary is always available when this function is called.
|
|
17
|
+
*
|
|
18
|
+
* Environment variables that affect behavior:
|
|
19
|
+
* - HUGO_BIN_PATH: Use a custom binary path (skips auto-install if missing)
|
|
20
|
+
*
|
|
21
|
+
* @returns A promise that resolves with the absolute path to the Hugo binary
|
|
22
|
+
* @throws {Error} If installation fails, the platform is unsupported, or custom binary is missing
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* import hugo from 'hugo-extended';
|
|
27
|
+
*
|
|
28
|
+
* const hugoPath = await hugo();
|
|
29
|
+
* console.log(hugoPath); // "/usr/local/bin/hugo" or "./bin/hugo"
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
const getHugoBinary = async () => {
|
|
33
|
+
const envConfig = getEnvConfig();
|
|
34
|
+
const bin = getBinPath();
|
|
35
|
+
if (envConfig.binPath) {
|
|
36
|
+
if (!doesBinExist(bin)) throw new Error(`Custom Hugo binary not found at HUGO_BIN_PATH: ${bin}`);
|
|
37
|
+
return bin;
|
|
38
|
+
}
|
|
39
|
+
if (!doesBinExist(bin)) {
|
|
40
|
+
logger.warn("Hugo is missing, reinstalling now...");
|
|
41
|
+
await install_default();
|
|
42
|
+
}
|
|
43
|
+
return bin;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Execute a Hugo command with type-safe options.
|
|
47
|
+
*
|
|
48
|
+
* This function runs Hugo with the specified command and options, inheriting stdio
|
|
49
|
+
* so output goes directly to the console. It's perfect for interactive commands
|
|
50
|
+
* like `hugo server` or build commands where you want to see live output.
|
|
51
|
+
*
|
|
52
|
+
* @param command - Hugo command to execute (e.g., "server", "build", "mod clean")
|
|
53
|
+
* @param positionalArgsOrOptions - Either positional arguments array or options object
|
|
54
|
+
* @param options - Type-safe options object (if first param is positional args)
|
|
55
|
+
* @returns A promise that resolves when the command completes successfully
|
|
56
|
+
* @throws {Error} If the command fails or Hugo is not available
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```typescript
|
|
60
|
+
* import { exec } from 'hugo-extended';
|
|
61
|
+
*
|
|
62
|
+
* // Start development server
|
|
63
|
+
* await exec("server", {
|
|
64
|
+
* port: 1313,
|
|
65
|
+
* buildDrafts: true,
|
|
66
|
+
* baseURL: "http://localhost:1313"
|
|
67
|
+
* });
|
|
68
|
+
*
|
|
69
|
+
* // Create a new site
|
|
70
|
+
* await exec("new site", ["my-site"], { format: "yaml" });
|
|
71
|
+
*
|
|
72
|
+
* // Build site for production
|
|
73
|
+
* await exec("build", {
|
|
74
|
+
* minify: true,
|
|
75
|
+
* cleanDestinationDir: true
|
|
76
|
+
* });
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
async function exec(command, positionalArgsOrOptions, options) {
|
|
80
|
+
const bin = await getHugoBinary();
|
|
81
|
+
let positionalArgs;
|
|
82
|
+
let opts;
|
|
83
|
+
if (Array.isArray(positionalArgsOrOptions)) {
|
|
84
|
+
positionalArgs = positionalArgsOrOptions;
|
|
85
|
+
opts = options;
|
|
86
|
+
} else {
|
|
87
|
+
positionalArgs = void 0;
|
|
88
|
+
opts = positionalArgsOrOptions;
|
|
89
|
+
}
|
|
90
|
+
const args = buildArgs(command, positionalArgs, opts);
|
|
91
|
+
return new Promise((resolve, reject) => {
|
|
92
|
+
const child = spawn(bin, args, { stdio: "inherit" });
|
|
93
|
+
child.on("exit", (code) => {
|
|
94
|
+
if (code === 0 || code === null) resolve();
|
|
95
|
+
else reject(/* @__PURE__ */ new Error(`Hugo command failed with exit code ${code}`));
|
|
96
|
+
});
|
|
97
|
+
child.on("error", (err) => {
|
|
98
|
+
reject(err);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Execute a Hugo command and capture its output.
|
|
104
|
+
*
|
|
105
|
+
* This function runs Hugo with the specified command and options, capturing
|
|
106
|
+
* stdout and stderr. It's useful for commands where you need to process the
|
|
107
|
+
* output programmatically, like `hugo version` or `hugo list all`.
|
|
108
|
+
*
|
|
109
|
+
* @param command - Hugo command to execute (e.g., "version", "list all")
|
|
110
|
+
* @param positionalArgsOrOptions - Either positional arguments array or options object
|
|
111
|
+
* @param options - Type-safe options object (if first param is positional args)
|
|
112
|
+
* @returns A promise that resolves with stdout and stderr strings
|
|
113
|
+
* @throws {Error} If the command fails or Hugo is not available
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```typescript
|
|
117
|
+
* import { execWithOutput } from 'hugo-extended';
|
|
118
|
+
*
|
|
119
|
+
* // Get Hugo version
|
|
120
|
+
* const { stdout } = await execWithOutput("version");
|
|
121
|
+
* console.log(stdout); // "hugo v0.154.3+extended ..."
|
|
122
|
+
*
|
|
123
|
+
* // List all content
|
|
124
|
+
* const { stdout: content } = await execWithOutput("list all");
|
|
125
|
+
* const pages = content.split('\n');
|
|
126
|
+
* ```
|
|
127
|
+
*/
|
|
128
|
+
async function execWithOutput(command, positionalArgsOrOptions, options) {
|
|
129
|
+
const bin = await getHugoBinary();
|
|
130
|
+
let positionalArgs;
|
|
131
|
+
let opts;
|
|
132
|
+
if (Array.isArray(positionalArgsOrOptions)) {
|
|
133
|
+
positionalArgs = positionalArgsOrOptions;
|
|
134
|
+
opts = options;
|
|
135
|
+
} else {
|
|
136
|
+
positionalArgs = void 0;
|
|
137
|
+
opts = positionalArgsOrOptions;
|
|
138
|
+
}
|
|
139
|
+
const args = buildArgs(command, positionalArgs, opts);
|
|
140
|
+
return new Promise((resolve, reject) => {
|
|
141
|
+
const stdoutChunks = [];
|
|
142
|
+
const stderrChunks = [];
|
|
143
|
+
const child = spawn(bin, args);
|
|
144
|
+
if (child.stdout) child.stdout.on("data", (chunk) => {
|
|
145
|
+
stdoutChunks.push(chunk);
|
|
146
|
+
});
|
|
147
|
+
if (child.stderr) child.stderr.on("data", (chunk) => {
|
|
148
|
+
stderrChunks.push(chunk);
|
|
149
|
+
});
|
|
150
|
+
child.on("exit", (code) => {
|
|
151
|
+
const stdout = Buffer.concat(stdoutChunks).toString("utf8");
|
|
152
|
+
const stderr = Buffer.concat(stderrChunks).toString("utf8");
|
|
153
|
+
if (code === 0 || code === null) resolve({
|
|
154
|
+
stdout,
|
|
155
|
+
stderr
|
|
156
|
+
});
|
|
157
|
+
else reject(/* @__PURE__ */ new Error(`Hugo command failed with exit code ${code}${stderr ? `\n${stderr}` : ""}`));
|
|
158
|
+
});
|
|
159
|
+
child.on("error", (err) => {
|
|
160
|
+
reject(err);
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Builder-style API for executing Hugo commands.
|
|
166
|
+
*
|
|
167
|
+
* Provides a fluent interface where each Hugo command is a method on the
|
|
168
|
+
* builder object. All methods are type-safe with autocomplete for options.
|
|
169
|
+
*
|
|
170
|
+
* @example
|
|
171
|
+
* ```typescript
|
|
172
|
+
* import { hugo } from 'hugo-extended';
|
|
173
|
+
*
|
|
174
|
+
* // Start server
|
|
175
|
+
* await hugo.server({ port: 1313, buildDrafts: true });
|
|
176
|
+
*
|
|
177
|
+
* // Build site
|
|
178
|
+
* await hugo.build({ minify: true });
|
|
179
|
+
*
|
|
180
|
+
* // Module operations
|
|
181
|
+
* await hugo.mod.clean({ all: true });
|
|
182
|
+
* await hugo.mod.get();
|
|
183
|
+
* ```
|
|
184
|
+
*/
|
|
185
|
+
const hugo = {
|
|
186
|
+
build: (options) => exec("build", options),
|
|
187
|
+
completion: {
|
|
188
|
+
bash: (options) => exec("completion bash", options),
|
|
189
|
+
fish: (options) => exec("completion fish", options),
|
|
190
|
+
powershell: (options) => exec("completion powershell", options),
|
|
191
|
+
zsh: (options) => exec("completion zsh", options)
|
|
192
|
+
},
|
|
193
|
+
config: (options) => exec("config", options),
|
|
194
|
+
convert: {
|
|
195
|
+
toJSON: (options) => exec("convert toJSON", options),
|
|
196
|
+
toTOML: (options) => exec("convert toTOML", options),
|
|
197
|
+
toYAML: (options) => exec("convert toYAML", options)
|
|
198
|
+
},
|
|
199
|
+
env: (options) => exec("env", options),
|
|
200
|
+
gen: {
|
|
201
|
+
doc: (options) => exec("gen doc", options),
|
|
202
|
+
man: (options) => exec("gen man", options)
|
|
203
|
+
},
|
|
204
|
+
import: { jekyll: (options) => exec("import jekyll", options) },
|
|
205
|
+
list: {
|
|
206
|
+
all: (options) => exec("list all", options),
|
|
207
|
+
drafts: (options) => exec("list drafts", options),
|
|
208
|
+
expired: (options) => exec("list expired", options),
|
|
209
|
+
future: (options) => exec("list future", options),
|
|
210
|
+
published: (options) => exec("list published", options)
|
|
211
|
+
},
|
|
212
|
+
mod: {
|
|
213
|
+
clean: (options) => exec("mod clean", options),
|
|
214
|
+
get: (options) => exec("mod get", options),
|
|
215
|
+
graph: (options) => exec("mod graph", options),
|
|
216
|
+
init: (options) => exec("mod init", options),
|
|
217
|
+
npm: { pack: (options) => exec("mod npm pack", options) },
|
|
218
|
+
tidy: (options) => exec("mod tidy", options),
|
|
219
|
+
vendor: (options) => exec("mod vendor", options),
|
|
220
|
+
verify: (options) => exec("mod verify", options)
|
|
221
|
+
},
|
|
222
|
+
new: Object.assign((pathOrOptions, options) => {
|
|
223
|
+
if (typeof pathOrOptions === "string") return exec("new", [pathOrOptions], options);
|
|
224
|
+
return exec("new", pathOrOptions);
|
|
225
|
+
}, {
|
|
226
|
+
content: (pathOrOptions, options) => {
|
|
227
|
+
if (typeof pathOrOptions === "string") return exec("new content", [pathOrOptions], options);
|
|
228
|
+
return exec("new content", pathOrOptions);
|
|
229
|
+
},
|
|
230
|
+
site: (pathOrOptions, options) => {
|
|
231
|
+
if (typeof pathOrOptions === "string") return exec("new site", [pathOrOptions], options);
|
|
232
|
+
return exec("new site", pathOrOptions);
|
|
233
|
+
},
|
|
234
|
+
theme: (nameOrOptions, options) => {
|
|
235
|
+
if (typeof nameOrOptions === "string") return exec("new theme", [nameOrOptions], options);
|
|
236
|
+
return exec("new theme", nameOrOptions);
|
|
237
|
+
}
|
|
238
|
+
}),
|
|
239
|
+
server: (options) => exec("server", options),
|
|
240
|
+
version: (options) => exec("version", options)
|
|
241
|
+
};
|
|
242
|
+
const hugoCompat = getHugoBinary;
|
|
243
|
+
var hugo_default = Object.assign(hugoCompat, hugo);
|
|
244
|
+
|
|
245
|
+
//#endregion
|
|
246
|
+
export { ENV_VAR_DOCS, hugo_default as default, exec, execWithOutput, getEnvConfig, getHugoBinary, hugo };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
//#region src/lib/args.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Build command-line arguments from a command and options object.
|
|
4
|
+
*
|
|
5
|
+
* This function:
|
|
6
|
+
* 1. Loads the Hugo spec to understand flag types
|
|
7
|
+
* 2. Converts camelCase property names to kebab-case flags
|
|
8
|
+
* 3. Formats values according to their types (boolean, string, number, arrays)
|
|
9
|
+
* 4. Returns an argv array ready to pass to child_process
|
|
10
|
+
*
|
|
11
|
+
* @param command - Hugo command string (e.g., "server", "build", "mod clean").
|
|
12
|
+
* @param positionalArgs - Optional array of positional arguments (e.g., paths, names).
|
|
13
|
+
* @param options - Options object with camelCase property names.
|
|
14
|
+
* @returns Array of command-line arguments.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* buildArgs("server", undefined, { port: 1313, buildDrafts: true })
|
|
18
|
+
* // Returns: ["server", "--port", "1313", "--build-drafts"]
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* buildArgs("new site", ["my-site"], { format: "yaml" })
|
|
22
|
+
* // Returns: ["new", "site", "my-site", "--format", "yaml"]
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* buildArgs("build", undefined, { theme: ["a", "b"], minify: true })
|
|
26
|
+
* // Returns: ["build", "--theme", "a", "--theme", "b", "--minify"]
|
|
27
|
+
*/
|
|
28
|
+
declare function buildArgs(command: string, positionalArgs?: string[], options?: Record<string, unknown>): string[];
|
|
29
|
+
//#endregion
|
|
30
|
+
export { buildArgs };
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
|
|
5
|
+
//#region src/lib/args.ts
|
|
6
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
let cachedSpec = null;
|
|
8
|
+
/**
|
|
9
|
+
* Load the Hugo spec from the generated json file (cached after first load).
|
|
10
|
+
*
|
|
11
|
+
* @returns The parsed Hugo spec containing global flags and command-specific flags.
|
|
12
|
+
*/
|
|
13
|
+
function loadSpec() {
|
|
14
|
+
if (cachedSpec) return cachedSpec;
|
|
15
|
+
const specPath = path.join(__dirname, "..", "generated", "flags.json");
|
|
16
|
+
try {
|
|
17
|
+
const specText = fs.readFileSync(specPath, "utf8");
|
|
18
|
+
cachedSpec = JSON.parse(specText);
|
|
19
|
+
} catch (error) {
|
|
20
|
+
throw new Error(`Failed to load Hugo spec from ${specPath}. Ensure the project is built (npm run build) before use.`, { cause: error });
|
|
21
|
+
}
|
|
22
|
+
return cachedSpec;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Convert a camelCase property name to kebab-case flag name.
|
|
26
|
+
*
|
|
27
|
+
* @param name - Property name in camelCase (e.g., "buildDrafts").
|
|
28
|
+
* @returns Kebab-case flag name (e.g., "build-drafts").
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* camelToKebab("baseURL") // "base-u-r-l"
|
|
32
|
+
* camelToKebab("buildDrafts") // "build-drafts"
|
|
33
|
+
*/
|
|
34
|
+
function camelToKebab(name) {
|
|
35
|
+
return name.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Find a flag spec by its camelCase property name.
|
|
39
|
+
*
|
|
40
|
+
* @param flags - Array of flag specs to search.
|
|
41
|
+
* @param propName - Property name in camelCase.
|
|
42
|
+
* @returns The matching flag spec, or undefined if not found.
|
|
43
|
+
*/
|
|
44
|
+
function findFlag(flags, propName) {
|
|
45
|
+
const kebab = camelToKebab(propName);
|
|
46
|
+
return flags.find((f) => {
|
|
47
|
+
const flagName = f.long.startsWith("--") ? f.long.slice(2) : f.long;
|
|
48
|
+
return flagName === kebab || flagName === propName;
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Build command-line arguments from a command and options object.
|
|
53
|
+
*
|
|
54
|
+
* This function:
|
|
55
|
+
* 1. Loads the Hugo spec to understand flag types
|
|
56
|
+
* 2. Converts camelCase property names to kebab-case flags
|
|
57
|
+
* 3. Formats values according to their types (boolean, string, number, arrays)
|
|
58
|
+
* 4. Returns an argv array ready to pass to child_process
|
|
59
|
+
*
|
|
60
|
+
* @param command - Hugo command string (e.g., "server", "build", "mod clean").
|
|
61
|
+
* @param positionalArgs - Optional array of positional arguments (e.g., paths, names).
|
|
62
|
+
* @param options - Options object with camelCase property names.
|
|
63
|
+
* @returns Array of command-line arguments.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* buildArgs("server", undefined, { port: 1313, buildDrafts: true })
|
|
67
|
+
* // Returns: ["server", "--port", "1313", "--build-drafts"]
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* buildArgs("new site", ["my-site"], { format: "yaml" })
|
|
71
|
+
* // Returns: ["new", "site", "my-site", "--format", "yaml"]
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* buildArgs("build", undefined, { theme: ["a", "b"], minify: true })
|
|
75
|
+
* // Returns: ["build", "--theme", "a", "--theme", "b", "--minify"]
|
|
76
|
+
*/
|
|
77
|
+
function buildArgs(command, positionalArgs, options) {
|
|
78
|
+
const spec = loadSpec();
|
|
79
|
+
const args = [];
|
|
80
|
+
args.push(...command.split(" "));
|
|
81
|
+
if (positionalArgs && positionalArgs.length > 0) args.push(...positionalArgs);
|
|
82
|
+
if (!options || Object.keys(options).length === 0) return args;
|
|
83
|
+
const cmdSpec = spec.commands.find((c) => c.command === command);
|
|
84
|
+
const allFlags = [...spec.globalFlags, ...cmdSpec?.flags ?? []];
|
|
85
|
+
for (const [key, value] of Object.entries(options)) {
|
|
86
|
+
if (value === void 0 || value === null) continue;
|
|
87
|
+
const flagSpec = findFlag(allFlags, key);
|
|
88
|
+
const flagName = flagSpec ? flagSpec.long.startsWith("--") ? flagSpec.long : `--${flagSpec.long}` : `--${camelToKebab(key)}`;
|
|
89
|
+
switch (flagSpec?.kind ?? inferKind(value)) {
|
|
90
|
+
case "boolean":
|
|
91
|
+
if (value === true) args.push(flagName);
|
|
92
|
+
break;
|
|
93
|
+
case "string":
|
|
94
|
+
args.push(flagName, String(value));
|
|
95
|
+
break;
|
|
96
|
+
case "number":
|
|
97
|
+
args.push(flagName, String(value));
|
|
98
|
+
break;
|
|
99
|
+
case "string[]":
|
|
100
|
+
if (Array.isArray(value)) for (const item of value) args.push(flagName, String(item));
|
|
101
|
+
break;
|
|
102
|
+
case "number[]":
|
|
103
|
+
if (Array.isArray(value)) for (const item of value) args.push(flagName, String(item));
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return args;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Infer the kind of a value when we don't have spec information.
|
|
111
|
+
*
|
|
112
|
+
* @param value - The value to inspect.
|
|
113
|
+
* @returns The inferred flag kind.
|
|
114
|
+
*/
|
|
115
|
+
function inferKind(value) {
|
|
116
|
+
if (typeof value === "boolean") return "boolean";
|
|
117
|
+
if (typeof value === "number") return "number";
|
|
118
|
+
if (Array.isArray(value)) {
|
|
119
|
+
if (value.length > 0 && typeof value[0] === "number") return "number[]";
|
|
120
|
+
return "string[]";
|
|
121
|
+
}
|
|
122
|
+
return "string";
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
//#endregion
|
|
126
|
+
export { buildArgs };
|