resuml 1.2.6 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +136 -58
- package/dist/api.js +35 -36
- package/dist/api.js.map +1 -1
- package/dist/index.js +446 -87
- package/dist/index.js.map +1 -1
- package/package.json +45 -21
package/dist/index.js
CHANGED
|
@@ -39,7 +39,7 @@ var getImportMetaUrl, importMetaUrl;
|
|
|
39
39
|
var init_cjs_shims = __esm({
|
|
40
40
|
"node_modules/tsup/assets/cjs_shims.js"() {
|
|
41
41
|
"use strict";
|
|
42
|
-
getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.src
|
|
42
|
+
getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href;
|
|
43
43
|
importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
44
44
|
}
|
|
45
45
|
});
|
|
@@ -181,7 +181,7 @@ var require_brace_expansion = __commonJS({
|
|
|
181
181
|
var isSequence = isNumericSequence || isAlphaSequence;
|
|
182
182
|
var isOptions = m.body.indexOf(",") >= 0;
|
|
183
183
|
if (!isSequence && !isOptions) {
|
|
184
|
-
if (m.post.match(
|
|
184
|
+
if (m.post.match(/,(?!,).*\}/)) {
|
|
185
185
|
str = m.pre + "{" + m.body + escClose + m.post;
|
|
186
186
|
return expand2(str);
|
|
187
187
|
}
|
|
@@ -267,8 +267,8 @@ __export(index_exports, {
|
|
|
267
267
|
module.exports = __toCommonJS(index_exports);
|
|
268
268
|
init_cjs_shims();
|
|
269
269
|
var import_commander = require("commander");
|
|
270
|
-
var
|
|
271
|
-
var
|
|
270
|
+
var import_path3 = __toESM(require("path"));
|
|
271
|
+
var import_fs7 = __toESM(require("fs"));
|
|
272
272
|
var import_url = require("url");
|
|
273
273
|
|
|
274
274
|
// src/commands/validate.ts
|
|
@@ -1012,7 +1012,7 @@ var path = {
|
|
|
1012
1012
|
};
|
|
1013
1013
|
var sep = defaultPlatform === "win32" ? path.win32.sep : path.posix.sep;
|
|
1014
1014
|
minimatch.sep = sep;
|
|
1015
|
-
var GLOBSTAR = Symbol("globstar **");
|
|
1015
|
+
var GLOBSTAR = /* @__PURE__ */ Symbol("globstar **");
|
|
1016
1016
|
minimatch.GLOBSTAR = GLOBSTAR;
|
|
1017
1017
|
var qmark2 = "[^/]";
|
|
1018
1018
|
var star2 = qmark2 + "*?";
|
|
@@ -1717,7 +1717,6 @@ if (typeof AC === "undefined") {
|
|
|
1717
1717
|
};
|
|
1718
1718
|
}
|
|
1719
1719
|
var shouldWarn = (code) => !warned.has(code);
|
|
1720
|
-
var TYPE = Symbol("type");
|
|
1721
1720
|
var isPosInt = (n) => n && n === Math.floor(n) && n > 0 && isFinite(n);
|
|
1722
1721
|
var getUintArray = (max) => !isPosInt(max) ? null : max <= Math.pow(2, 8) ? Uint8Array : max <= Math.pow(2, 16) ? Uint16Array : max <= Math.pow(2, 32) ? Uint32Array : max <= Number.MAX_SAFE_INTEGER ? ZeroArray : null;
|
|
1723
1722
|
var ZeroArray = class extends Array {
|
|
@@ -3062,37 +3061,37 @@ var isStream = (s) => !!s && typeof s === "object" && (s instanceof Minipass ||
|
|
|
3062
3061
|
var isReadable = (s) => !!s && typeof s === "object" && s instanceof import_node_events.EventEmitter && typeof s.pipe === "function" && // node core Writable streams have a pipe() method, but it throws
|
|
3063
3062
|
s.pipe !== import_node_stream.default.Writable.prototype.pipe;
|
|
3064
3063
|
var isWritable = (s) => !!s && typeof s === "object" && s instanceof import_node_events.EventEmitter && typeof s.write === "function" && typeof s.end === "function";
|
|
3065
|
-
var EOF = Symbol("EOF");
|
|
3066
|
-
var MAYBE_EMIT_END = Symbol("maybeEmitEnd");
|
|
3067
|
-
var EMITTED_END = Symbol("emittedEnd");
|
|
3068
|
-
var EMITTING_END = Symbol("emittingEnd");
|
|
3069
|
-
var EMITTED_ERROR = Symbol("emittedError");
|
|
3070
|
-
var CLOSED = Symbol("closed");
|
|
3071
|
-
var READ = Symbol("read");
|
|
3072
|
-
var FLUSH = Symbol("flush");
|
|
3073
|
-
var FLUSHCHUNK = Symbol("flushChunk");
|
|
3074
|
-
var ENCODING = Symbol("encoding");
|
|
3075
|
-
var DECODER = Symbol("decoder");
|
|
3076
|
-
var FLOWING = Symbol("flowing");
|
|
3077
|
-
var PAUSED = Symbol("paused");
|
|
3078
|
-
var RESUME = Symbol("resume");
|
|
3079
|
-
var BUFFER = Symbol("buffer");
|
|
3080
|
-
var PIPES = Symbol("pipes");
|
|
3081
|
-
var BUFFERLENGTH = Symbol("bufferLength");
|
|
3082
|
-
var BUFFERPUSH = Symbol("bufferPush");
|
|
3083
|
-
var BUFFERSHIFT = Symbol("bufferShift");
|
|
3084
|
-
var OBJECTMODE = Symbol("objectMode");
|
|
3085
|
-
var DESTROYED = Symbol("destroyed");
|
|
3086
|
-
var ERROR = Symbol("error");
|
|
3087
|
-
var EMITDATA = Symbol("emitData");
|
|
3088
|
-
var EMITEND = Symbol("emitEnd");
|
|
3089
|
-
var EMITEND2 = Symbol("emitEnd2");
|
|
3090
|
-
var ASYNC = Symbol("async");
|
|
3091
|
-
var ABORT = Symbol("abort");
|
|
3092
|
-
var ABORTED = Symbol("aborted");
|
|
3093
|
-
var SIGNAL = Symbol("signal");
|
|
3094
|
-
var DATALISTENERS = Symbol("dataListeners");
|
|
3095
|
-
var DISCARDED = Symbol("discarded");
|
|
3064
|
+
var EOF = /* @__PURE__ */ Symbol("EOF");
|
|
3065
|
+
var MAYBE_EMIT_END = /* @__PURE__ */ Symbol("maybeEmitEnd");
|
|
3066
|
+
var EMITTED_END = /* @__PURE__ */ Symbol("emittedEnd");
|
|
3067
|
+
var EMITTING_END = /* @__PURE__ */ Symbol("emittingEnd");
|
|
3068
|
+
var EMITTED_ERROR = /* @__PURE__ */ Symbol("emittedError");
|
|
3069
|
+
var CLOSED = /* @__PURE__ */ Symbol("closed");
|
|
3070
|
+
var READ = /* @__PURE__ */ Symbol("read");
|
|
3071
|
+
var FLUSH = /* @__PURE__ */ Symbol("flush");
|
|
3072
|
+
var FLUSHCHUNK = /* @__PURE__ */ Symbol("flushChunk");
|
|
3073
|
+
var ENCODING = /* @__PURE__ */ Symbol("encoding");
|
|
3074
|
+
var DECODER = /* @__PURE__ */ Symbol("decoder");
|
|
3075
|
+
var FLOWING = /* @__PURE__ */ Symbol("flowing");
|
|
3076
|
+
var PAUSED = /* @__PURE__ */ Symbol("paused");
|
|
3077
|
+
var RESUME = /* @__PURE__ */ Symbol("resume");
|
|
3078
|
+
var BUFFER = /* @__PURE__ */ Symbol("buffer");
|
|
3079
|
+
var PIPES = /* @__PURE__ */ Symbol("pipes");
|
|
3080
|
+
var BUFFERLENGTH = /* @__PURE__ */ Symbol("bufferLength");
|
|
3081
|
+
var BUFFERPUSH = /* @__PURE__ */ Symbol("bufferPush");
|
|
3082
|
+
var BUFFERSHIFT = /* @__PURE__ */ Symbol("bufferShift");
|
|
3083
|
+
var OBJECTMODE = /* @__PURE__ */ Symbol("objectMode");
|
|
3084
|
+
var DESTROYED = /* @__PURE__ */ Symbol("destroyed");
|
|
3085
|
+
var ERROR = /* @__PURE__ */ Symbol("error");
|
|
3086
|
+
var EMITDATA = /* @__PURE__ */ Symbol("emitData");
|
|
3087
|
+
var EMITEND = /* @__PURE__ */ Symbol("emitEnd");
|
|
3088
|
+
var EMITEND2 = /* @__PURE__ */ Symbol("emitEnd2");
|
|
3089
|
+
var ASYNC = /* @__PURE__ */ Symbol("async");
|
|
3090
|
+
var ABORT = /* @__PURE__ */ Symbol("abort");
|
|
3091
|
+
var ABORTED = /* @__PURE__ */ Symbol("aborted");
|
|
3092
|
+
var SIGNAL = /* @__PURE__ */ Symbol("signal");
|
|
3093
|
+
var DATALISTENERS = /* @__PURE__ */ Symbol("dataListeners");
|
|
3094
|
+
var DISCARDED = /* @__PURE__ */ Symbol("discarded");
|
|
3096
3095
|
var defer = (fn) => Promise.resolve().then(fn);
|
|
3097
3096
|
var nodefer = (fn) => fn();
|
|
3098
3097
|
var isEndish = (ev) => ev === "end" || ev === "finish" || ev === "prefinish";
|
|
@@ -4005,7 +4004,7 @@ var ChildrenCache = class extends LRUCache {
|
|
|
4005
4004
|
});
|
|
4006
4005
|
}
|
|
4007
4006
|
};
|
|
4008
|
-
var setAsCwd = Symbol("PathScurry setAsCwd");
|
|
4007
|
+
var setAsCwd = /* @__PURE__ */ Symbol("PathScurry setAsCwd");
|
|
4009
4008
|
var PathBase = class {
|
|
4010
4009
|
/**
|
|
4011
4010
|
* the basename of this path
|
|
@@ -4191,12 +4190,12 @@ var PathBase = class {
|
|
|
4191
4190
|
/**
|
|
4192
4191
|
* Get the Path object referenced by the string path, resolved from this Path
|
|
4193
4192
|
*/
|
|
4194
|
-
resolve(
|
|
4195
|
-
if (!
|
|
4193
|
+
resolve(path8) {
|
|
4194
|
+
if (!path8) {
|
|
4196
4195
|
return this;
|
|
4197
4196
|
}
|
|
4198
|
-
const rootPath = this.getRootString(
|
|
4199
|
-
const dir =
|
|
4197
|
+
const rootPath = this.getRootString(path8);
|
|
4198
|
+
const dir = path8.substring(rootPath.length);
|
|
4200
4199
|
const dirParts = dir.split(this.splitSep);
|
|
4201
4200
|
const result = rootPath ? this.getRoot(rootPath).#resolveParts(dirParts) : this.#resolveParts(dirParts);
|
|
4202
4201
|
return result;
|
|
@@ -4948,8 +4947,8 @@ var PathWin32 = class _PathWin32 extends PathBase {
|
|
|
4948
4947
|
/**
|
|
4949
4948
|
* @internal
|
|
4950
4949
|
*/
|
|
4951
|
-
getRootString(
|
|
4952
|
-
return import_node_path.win32.parse(
|
|
4950
|
+
getRootString(path8) {
|
|
4951
|
+
return import_node_path.win32.parse(path8).root;
|
|
4953
4952
|
}
|
|
4954
4953
|
/**
|
|
4955
4954
|
* @internal
|
|
@@ -4995,8 +4994,8 @@ var PathPosix = class _PathPosix extends PathBase {
|
|
|
4995
4994
|
/**
|
|
4996
4995
|
* @internal
|
|
4997
4996
|
*/
|
|
4998
|
-
getRootString(
|
|
4999
|
-
return
|
|
4997
|
+
getRootString(path8) {
|
|
4998
|
+
return path8.startsWith("/") ? "/" : "";
|
|
5000
4999
|
}
|
|
5001
5000
|
/**
|
|
5002
5001
|
* @internal
|
|
@@ -5045,8 +5044,8 @@ var PathScurryBase = class {
|
|
|
5045
5044
|
*
|
|
5046
5045
|
* @internal
|
|
5047
5046
|
*/
|
|
5048
|
-
constructor(cwd = process.cwd(), pathImpl, sep2, { nocase, childrenCacheSize = 16 * 1024, fs:
|
|
5049
|
-
this.#fs = fsFromOption(
|
|
5047
|
+
constructor(cwd = process.cwd(), pathImpl, sep2, { nocase, childrenCacheSize = 16 * 1024, fs: fs9 = defaultFS } = {}) {
|
|
5048
|
+
this.#fs = fsFromOption(fs9);
|
|
5050
5049
|
if (cwd instanceof URL || cwd.startsWith("file://")) {
|
|
5051
5050
|
cwd = (0, import_node_url.fileURLToPath)(cwd);
|
|
5052
5051
|
}
|
|
@@ -5085,11 +5084,11 @@ var PathScurryBase = class {
|
|
|
5085
5084
|
/**
|
|
5086
5085
|
* Get the depth of a provided path, string, or the cwd
|
|
5087
5086
|
*/
|
|
5088
|
-
depth(
|
|
5089
|
-
if (typeof
|
|
5090
|
-
|
|
5087
|
+
depth(path8 = this.cwd) {
|
|
5088
|
+
if (typeof path8 === "string") {
|
|
5089
|
+
path8 = this.cwd.resolve(path8);
|
|
5091
5090
|
}
|
|
5092
|
-
return
|
|
5091
|
+
return path8.depth();
|
|
5093
5092
|
}
|
|
5094
5093
|
/**
|
|
5095
5094
|
* Return the cache of child entries. Exposed so subclasses can create
|
|
@@ -5576,9 +5575,9 @@ var PathScurryBase = class {
|
|
|
5576
5575
|
process2();
|
|
5577
5576
|
return results;
|
|
5578
5577
|
}
|
|
5579
|
-
chdir(
|
|
5578
|
+
chdir(path8 = this.cwd) {
|
|
5580
5579
|
const oldCwd = this.cwd;
|
|
5581
|
-
this.cwd = typeof
|
|
5580
|
+
this.cwd = typeof path8 === "string" ? this.cwd.resolve(path8) : path8;
|
|
5582
5581
|
this.cwd[setAsCwd](oldCwd);
|
|
5583
5582
|
}
|
|
5584
5583
|
};
|
|
@@ -5604,8 +5603,8 @@ var PathScurryWin32 = class extends PathScurryBase {
|
|
|
5604
5603
|
/**
|
|
5605
5604
|
* @internal
|
|
5606
5605
|
*/
|
|
5607
|
-
newRoot(
|
|
5608
|
-
return new PathWin32(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs:
|
|
5606
|
+
newRoot(fs9) {
|
|
5607
|
+
return new PathWin32(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs: fs9 });
|
|
5609
5608
|
}
|
|
5610
5609
|
/**
|
|
5611
5610
|
* Return true if the provided path string is an absolute path
|
|
@@ -5633,8 +5632,8 @@ var PathScurryPosix = class extends PathScurryBase {
|
|
|
5633
5632
|
/**
|
|
5634
5633
|
* @internal
|
|
5635
5634
|
*/
|
|
5636
|
-
newRoot(
|
|
5637
|
-
return new PathPosix(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs:
|
|
5635
|
+
newRoot(fs9) {
|
|
5636
|
+
return new PathPosix(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs: fs9 });
|
|
5638
5637
|
}
|
|
5639
5638
|
/**
|
|
5640
5639
|
* Return true if the provided path string is an absolute path
|
|
@@ -5940,8 +5939,8 @@ var MatchRecord = class {
|
|
|
5940
5939
|
}
|
|
5941
5940
|
// match, absolute, ifdir
|
|
5942
5941
|
entries() {
|
|
5943
|
-
return [...this.store.entries()].map(([
|
|
5944
|
-
|
|
5942
|
+
return [...this.store.entries()].map(([path8, n]) => [
|
|
5943
|
+
path8,
|
|
5945
5944
|
!!(n & 2),
|
|
5946
5945
|
!!(n & 1)
|
|
5947
5946
|
]);
|
|
@@ -6146,9 +6145,9 @@ var GlobUtil = class {
|
|
|
6146
6145
|
signal;
|
|
6147
6146
|
maxDepth;
|
|
6148
6147
|
includeChildMatches;
|
|
6149
|
-
constructor(patterns,
|
|
6148
|
+
constructor(patterns, path8, opts) {
|
|
6150
6149
|
this.patterns = patterns;
|
|
6151
|
-
this.path =
|
|
6150
|
+
this.path = path8;
|
|
6152
6151
|
this.opts = opts;
|
|
6153
6152
|
this.#sep = !opts.posix && opts.platform === "win32" ? "\\" : "/";
|
|
6154
6153
|
this.includeChildMatches = opts.includeChildMatches !== false;
|
|
@@ -6167,11 +6166,11 @@ var GlobUtil = class {
|
|
|
6167
6166
|
});
|
|
6168
6167
|
}
|
|
6169
6168
|
}
|
|
6170
|
-
#ignored(
|
|
6171
|
-
return this.seen.has(
|
|
6169
|
+
#ignored(path8) {
|
|
6170
|
+
return this.seen.has(path8) || !!this.#ignore?.ignored?.(path8);
|
|
6172
6171
|
}
|
|
6173
|
-
#childrenIgnored(
|
|
6174
|
-
return !!this.#ignore?.childrenIgnored?.(
|
|
6172
|
+
#childrenIgnored(path8) {
|
|
6173
|
+
return !!this.#ignore?.childrenIgnored?.(path8);
|
|
6175
6174
|
}
|
|
6176
6175
|
// backpressure mechanism
|
|
6177
6176
|
pause() {
|
|
@@ -6386,8 +6385,8 @@ var GlobUtil = class {
|
|
|
6386
6385
|
};
|
|
6387
6386
|
var GlobWalker = class extends GlobUtil {
|
|
6388
6387
|
matches = /* @__PURE__ */ new Set();
|
|
6389
|
-
constructor(patterns,
|
|
6390
|
-
super(patterns,
|
|
6388
|
+
constructor(patterns, path8, opts) {
|
|
6389
|
+
super(patterns, path8, opts);
|
|
6391
6390
|
}
|
|
6392
6391
|
matchEmit(e) {
|
|
6393
6392
|
this.matches.add(e);
|
|
@@ -6424,8 +6423,8 @@ var GlobWalker = class extends GlobUtil {
|
|
|
6424
6423
|
};
|
|
6425
6424
|
var GlobStream = class extends GlobUtil {
|
|
6426
6425
|
results;
|
|
6427
|
-
constructor(patterns,
|
|
6428
|
-
super(patterns,
|
|
6426
|
+
constructor(patterns, path8, opts) {
|
|
6427
|
+
super(patterns, path8, opts);
|
|
6429
6428
|
this.results = new Minipass({
|
|
6430
6429
|
signal: this.signal,
|
|
6431
6430
|
objectMode: true
|
|
@@ -6795,8 +6794,8 @@ function handleCommandError(error, command, debug = false) {
|
|
|
6795
6794
|
if (debug) {
|
|
6796
6795
|
console.error("\nValidation failed with the following errors:");
|
|
6797
6796
|
errors.forEach((err, index) => {
|
|
6798
|
-
const
|
|
6799
|
-
console.error(`${index + 1}. Path: ${
|
|
6797
|
+
const path8 = err.instancePath || "root";
|
|
6798
|
+
console.error(`${index + 1}. Path: ${path8}`);
|
|
6800
6799
|
console.error(` Error: ${err.message || "Unknown validation error"}`);
|
|
6801
6800
|
if (err.params) {
|
|
6802
6801
|
console.error(` Params: ${JSON.stringify(err.params)}`);
|
|
@@ -6806,8 +6805,8 @@ function handleCommandError(error, command, debug = false) {
|
|
|
6806
6805
|
console.error("\nSome validation errors were found:");
|
|
6807
6806
|
const maxErrors = 5;
|
|
6808
6807
|
errors.slice(0, maxErrors).forEach((err, index) => {
|
|
6809
|
-
const
|
|
6810
|
-
console.error(`${index + 1}. Field: ${
|
|
6808
|
+
const path8 = err.instancePath || "root";
|
|
6809
|
+
console.error(`${index + 1}. Field: ${path8}`);
|
|
6811
6810
|
console.error(` Error: ${err.message || "Unknown validation error"}`);
|
|
6812
6811
|
});
|
|
6813
6812
|
if (errors.length > maxErrors) {
|
|
@@ -6824,15 +6823,15 @@ function handleCommandError(error, command, debug = false) {
|
|
|
6824
6823
|
|
|
6825
6824
|
// src/commands/validate.ts
|
|
6826
6825
|
async function validateAction(options) {
|
|
6827
|
-
const
|
|
6828
|
-
console.log(
|
|
6826
|
+
const chalk6 = (await import("chalk")).default;
|
|
6827
|
+
console.log(chalk6.blue("Starting resuml validate..."));
|
|
6829
6828
|
try {
|
|
6830
6829
|
const inputPath = options.resume;
|
|
6831
6830
|
const { yamlContents } = await loadResumeFiles(inputPath);
|
|
6832
|
-
console.log(
|
|
6831
|
+
console.log(chalk6.blue("Validating resume data..."));
|
|
6833
6832
|
try {
|
|
6834
6833
|
await processResumeData(yamlContents);
|
|
6835
|
-
console.log(
|
|
6834
|
+
console.log(chalk6.green("\u2713 Resume data is valid against the schema!"));
|
|
6836
6835
|
} catch (error) {
|
|
6837
6836
|
handleCommandError(error, "validate", options.debug);
|
|
6838
6837
|
return;
|
|
@@ -6846,17 +6845,17 @@ async function validateAction(options) {
|
|
|
6846
6845
|
init_cjs_shims();
|
|
6847
6846
|
var import_fs2 = __toESM(require("fs"));
|
|
6848
6847
|
async function toJsonAction(options) {
|
|
6849
|
-
const
|
|
6850
|
-
console.log(
|
|
6848
|
+
const chalk6 = (await import("chalk")).default;
|
|
6849
|
+
console.log(chalk6.blue("Starting resuml tojson..."));
|
|
6851
6850
|
try {
|
|
6852
6851
|
const inputPath = options.resume;
|
|
6853
6852
|
const { yamlContents } = await loadResumeFiles(inputPath);
|
|
6854
|
-
console.log(
|
|
6853
|
+
console.log(chalk6.blue("Processing and validating data..."));
|
|
6855
6854
|
const resumeData = await processResumeData(yamlContents);
|
|
6856
|
-
console.log(
|
|
6855
|
+
console.log(chalk6.green("Processing and validation successful!"));
|
|
6857
6856
|
const jsonOutput = JSON.stringify(resumeData, null, 2);
|
|
6858
6857
|
import_fs2.default.writeFileSync(options.output, jsonOutput, "utf8");
|
|
6859
|
-
console.log(
|
|
6858
|
+
console.log(chalk6.green(`Successfully wrote output to ${options.output}`));
|
|
6860
6859
|
} catch (error) {
|
|
6861
6860
|
handleCommandError(error, "tojson", options.debug);
|
|
6862
6861
|
}
|
|
@@ -7059,6 +7058,363 @@ async function startDevServer(port) {
|
|
|
7059
7058
|
});
|
|
7060
7059
|
}
|
|
7061
7060
|
|
|
7061
|
+
// src/commands/init.ts
|
|
7062
|
+
init_cjs_shims();
|
|
7063
|
+
var import_fs5 = __toESM(require("fs"));
|
|
7064
|
+
var import_path2 = __toESM(require("path"));
|
|
7065
|
+
var import_readline = __toESM(require("readline"));
|
|
7066
|
+
var import_chalk3 = __toESM(require("chalk"));
|
|
7067
|
+
function createReadlineInterface() {
|
|
7068
|
+
return import_readline.default.createInterface({
|
|
7069
|
+
input: process.stdin,
|
|
7070
|
+
output: process.stdout
|
|
7071
|
+
});
|
|
7072
|
+
}
|
|
7073
|
+
function ask(rl, question, defaultValue) {
|
|
7074
|
+
const prompt = defaultValue ? `${question} (${defaultValue}): ` : `${question}: `;
|
|
7075
|
+
return new Promise((resolve) => {
|
|
7076
|
+
rl.question(prompt, (answer) => {
|
|
7077
|
+
resolve(answer.trim() || defaultValue || "");
|
|
7078
|
+
});
|
|
7079
|
+
});
|
|
7080
|
+
}
|
|
7081
|
+
function generateResumeYaml(name, email, label) {
|
|
7082
|
+
return `# =============================================================================
|
|
7083
|
+
# Resume - Generated by resuml
|
|
7084
|
+
# Documentation: https://github.com/phoinixi/resuml
|
|
7085
|
+
# Schema: https://jsonresume.org/schema/
|
|
7086
|
+
# =============================================================================
|
|
7087
|
+
|
|
7088
|
+
# --- Basic Information ---
|
|
7089
|
+
basics:
|
|
7090
|
+
name: '${name}'
|
|
7091
|
+
label: '${label}'
|
|
7092
|
+
# image: 'https://example.com/photo.jpg'
|
|
7093
|
+
email: '${email}'
|
|
7094
|
+
# phone: '+1-555-123-4567'
|
|
7095
|
+
# url: 'https://yourwebsite.com'
|
|
7096
|
+
summary: >-
|
|
7097
|
+
Write a short professional summary here.
|
|
7098
|
+
This supports multi-line strings in YAML.
|
|
7099
|
+
location:
|
|
7100
|
+
# address: '123 Main Street'
|
|
7101
|
+
# postalCode: '12345'
|
|
7102
|
+
city: 'Your City'
|
|
7103
|
+
countryCode: 'US'
|
|
7104
|
+
# region: 'Your State'
|
|
7105
|
+
profiles:
|
|
7106
|
+
- network: 'LinkedIn'
|
|
7107
|
+
username: 'your-username'
|
|
7108
|
+
url: 'https://linkedin.com/in/your-username'
|
|
7109
|
+
- network: 'GitHub'
|
|
7110
|
+
username: 'your-username'
|
|
7111
|
+
url: 'https://github.com/your-username'
|
|
7112
|
+
|
|
7113
|
+
# --- Work Experience ---
|
|
7114
|
+
work:
|
|
7115
|
+
- name: 'Company Name'
|
|
7116
|
+
position: 'Job Title'
|
|
7117
|
+
url: 'https://company.com'
|
|
7118
|
+
startDate: '2020-01-01'
|
|
7119
|
+
# endDate: '2023-12-31' # Omit for current position
|
|
7120
|
+
summary: 'Brief description of your role and responsibilities.'
|
|
7121
|
+
highlights:
|
|
7122
|
+
- 'Key achievement or responsibility'
|
|
7123
|
+
- 'Another notable accomplishment'
|
|
7124
|
+
|
|
7125
|
+
# --- Education ---
|
|
7126
|
+
education:
|
|
7127
|
+
- institution: 'University Name'
|
|
7128
|
+
url: 'https://university.edu'
|
|
7129
|
+
area: 'Field of Study'
|
|
7130
|
+
studyType: 'Bachelor of Science'
|
|
7131
|
+
startDate: '2014-09-01'
|
|
7132
|
+
endDate: '2018-06-01'
|
|
7133
|
+
# score: '3.8'
|
|
7134
|
+
courses:
|
|
7135
|
+
- 'Relevant Course 1'
|
|
7136
|
+
- 'Relevant Course 2'
|
|
7137
|
+
|
|
7138
|
+
# --- Skills ---
|
|
7139
|
+
skills:
|
|
7140
|
+
- name: 'Programming Languages'
|
|
7141
|
+
level: 'Expert'
|
|
7142
|
+
keywords:
|
|
7143
|
+
- 'JavaScript'
|
|
7144
|
+
- 'TypeScript'
|
|
7145
|
+
- 'Python'
|
|
7146
|
+
- name: 'Frameworks'
|
|
7147
|
+
level: 'Advanced'
|
|
7148
|
+
keywords:
|
|
7149
|
+
- 'React'
|
|
7150
|
+
- 'Node.js'
|
|
7151
|
+
|
|
7152
|
+
# --- Projects ---
|
|
7153
|
+
# projects:
|
|
7154
|
+
# - name: 'Project Name'
|
|
7155
|
+
# description: 'Brief project description'
|
|
7156
|
+
# highlights:
|
|
7157
|
+
# - 'Key feature or result'
|
|
7158
|
+
# keywords:
|
|
7159
|
+
# - 'Technology Used'
|
|
7160
|
+
# startDate: '2023-01-01'
|
|
7161
|
+
# endDate: '2023-06-30'
|
|
7162
|
+
# url: 'https://github.com/you/project'
|
|
7163
|
+
# roles:
|
|
7164
|
+
# - 'Developer'
|
|
7165
|
+
# type: 'application'
|
|
7166
|
+
|
|
7167
|
+
# --- Languages ---
|
|
7168
|
+
# languages:
|
|
7169
|
+
# - language: 'English'
|
|
7170
|
+
# fluency: 'Native speaker'
|
|
7171
|
+
# - language: 'Spanish'
|
|
7172
|
+
# fluency: 'Professional working proficiency'
|
|
7173
|
+
|
|
7174
|
+
# --- Interests ---
|
|
7175
|
+
# interests:
|
|
7176
|
+
# - name: 'Open Source'
|
|
7177
|
+
# keywords:
|
|
7178
|
+
# - 'Contributing'
|
|
7179
|
+
# - 'Community'
|
|
7180
|
+
|
|
7181
|
+
# --- References ---
|
|
7182
|
+
# references:
|
|
7183
|
+
# - name: 'Jane Smith'
|
|
7184
|
+
# reference: 'It was a pleasure working with...'
|
|
7185
|
+
|
|
7186
|
+
# --- Awards ---
|
|
7187
|
+
# awards:
|
|
7188
|
+
# - title: 'Award Name'
|
|
7189
|
+
# date: '2023-01-01'
|
|
7190
|
+
# awarder: 'Organization'
|
|
7191
|
+
# summary: 'Description of the award'
|
|
7192
|
+
|
|
7193
|
+
# --- Certificates ---
|
|
7194
|
+
# certificates:
|
|
7195
|
+
# - name: 'Certificate Name'
|
|
7196
|
+
# date: '2023-01-01'
|
|
7197
|
+
# issuer: 'Issuing Organization'
|
|
7198
|
+
# url: 'https://example.com/cert'
|
|
7199
|
+
|
|
7200
|
+
# --- Publications ---
|
|
7201
|
+
# publications:
|
|
7202
|
+
# - name: 'Publication Title'
|
|
7203
|
+
# publisher: 'Publisher'
|
|
7204
|
+
# releaseDate: '2023-01-01'
|
|
7205
|
+
# url: 'https://example.com/publication'
|
|
7206
|
+
# summary: 'Brief description'
|
|
7207
|
+
|
|
7208
|
+
# --- Volunteer ---
|
|
7209
|
+
# volunteers:
|
|
7210
|
+
# - organization: 'Organization Name'
|
|
7211
|
+
# position: 'Volunteer Role'
|
|
7212
|
+
# url: 'https://organization.com'
|
|
7213
|
+
# startDate: '2022-01-01'
|
|
7214
|
+
# summary: 'Description of volunteer work'
|
|
7215
|
+
# highlights:
|
|
7216
|
+
# - 'Notable contribution'
|
|
7217
|
+
`;
|
|
7218
|
+
}
|
|
7219
|
+
async function initAction(options) {
|
|
7220
|
+
const outputPath = options.output || "resume.yaml";
|
|
7221
|
+
const fullPath = import_path2.default.resolve(outputPath);
|
|
7222
|
+
const rl = createReadlineInterface();
|
|
7223
|
+
try {
|
|
7224
|
+
if (import_fs5.default.existsSync(fullPath)) {
|
|
7225
|
+
const overwrite = await ask(
|
|
7226
|
+
rl,
|
|
7227
|
+
`${import_chalk3.default.yellow("\u26A0")} ${outputPath} already exists. Overwrite? (y/N)`,
|
|
7228
|
+
"N"
|
|
7229
|
+
);
|
|
7230
|
+
if (overwrite.toLowerCase() !== "y") {
|
|
7231
|
+
console.log(import_chalk3.default.blue("Aborted. No files were changed."));
|
|
7232
|
+
return;
|
|
7233
|
+
}
|
|
7234
|
+
}
|
|
7235
|
+
console.log(import_chalk3.default.blue("\n\u{1F4DD} Let's set up your resume!\n"));
|
|
7236
|
+
const name = await ask(rl, "Your full name", "John Doe");
|
|
7237
|
+
const email = await ask(rl, "Email address", "john@example.com");
|
|
7238
|
+
const label = await ask(rl, "Professional title/label", "Software Engineer");
|
|
7239
|
+
const yaml = generateResumeYaml(name, email, label);
|
|
7240
|
+
import_fs5.default.mkdirSync(import_path2.default.dirname(fullPath), { recursive: true });
|
|
7241
|
+
import_fs5.default.writeFileSync(fullPath, yaml, "utf8");
|
|
7242
|
+
console.log(import_chalk3.default.green(`
|
|
7243
|
+
\u2705 Created ${outputPath}`));
|
|
7244
|
+
console.log(import_chalk3.default.blue("\nNext steps:"));
|
|
7245
|
+
console.log(` 1. Edit ${outputPath} to fill in your details`);
|
|
7246
|
+
console.log(" 2. Run " + import_chalk3.default.cyan("resuml validate --resume " + outputPath));
|
|
7247
|
+
console.log(" 3. Run " + import_chalk3.default.cyan("resuml render --resume " + outputPath + " --theme stackoverflow"));
|
|
7248
|
+
} finally {
|
|
7249
|
+
rl.close();
|
|
7250
|
+
}
|
|
7251
|
+
}
|
|
7252
|
+
|
|
7253
|
+
// src/commands/pdf.ts
|
|
7254
|
+
init_cjs_shims();
|
|
7255
|
+
var import_fs6 = __toESM(require("fs"));
|
|
7256
|
+
var import_node_path4 = __toESM(require("path"));
|
|
7257
|
+
var import_chalk4 = __toESM(require("chalk"));
|
|
7258
|
+
async function loadPuppeteer() {
|
|
7259
|
+
try {
|
|
7260
|
+
const puppeteer = await import("puppeteer");
|
|
7261
|
+
return puppeteer.default || puppeteer;
|
|
7262
|
+
} catch {
|
|
7263
|
+
throw new Error(
|
|
7264
|
+
`Puppeteer is required for PDF export but is not installed.
|
|
7265
|
+
Install it with: ${import_chalk4.default.cyan("npm install puppeteer")}
|
|
7266
|
+
Or for a smaller download: ${import_chalk4.default.cyan("npm install puppeteer-core")}`
|
|
7267
|
+
);
|
|
7268
|
+
}
|
|
7269
|
+
}
|
|
7270
|
+
function parseMargin(margin) {
|
|
7271
|
+
const defaultMargin = { top: "10mm", right: "10mm", bottom: "10mm", left: "10mm" };
|
|
7272
|
+
if (!margin) return defaultMargin;
|
|
7273
|
+
const parts = margin.split(",").map((s) => s.trim());
|
|
7274
|
+
if (parts.length === 1) {
|
|
7275
|
+
return { top: parts[0], right: parts[0], bottom: parts[0], left: parts[0] };
|
|
7276
|
+
}
|
|
7277
|
+
if (parts.length === 2) {
|
|
7278
|
+
return { top: parts[0], right: parts[1], bottom: parts[0], left: parts[1] };
|
|
7279
|
+
}
|
|
7280
|
+
if (parts.length === 4) {
|
|
7281
|
+
return { top: parts[0], right: parts[1], bottom: parts[2], left: parts[3] };
|
|
7282
|
+
}
|
|
7283
|
+
return defaultMargin;
|
|
7284
|
+
}
|
|
7285
|
+
async function pdfAction(options) {
|
|
7286
|
+
if (!options.theme) {
|
|
7287
|
+
throw new Error(
|
|
7288
|
+
"--theme option is required. Please specify a theme name (e.g., stackoverflow, react)."
|
|
7289
|
+
);
|
|
7290
|
+
}
|
|
7291
|
+
console.log(import_chalk4.default.blue("Starting resuml PDF export..."));
|
|
7292
|
+
try {
|
|
7293
|
+
const inputPath = options.resume;
|
|
7294
|
+
const { yamlContents } = await loadResumeFiles(inputPath);
|
|
7295
|
+
console.log(import_chalk4.default.blue("Processing and validating resume data..."));
|
|
7296
|
+
const resumeData = await processResumeData(yamlContents);
|
|
7297
|
+
console.log(import_chalk4.default.green("Resume data processing and validation successful!"));
|
|
7298
|
+
const theme = await loadTheme(options.theme);
|
|
7299
|
+
const htmlOutput = await theme.render(resumeData, {
|
|
7300
|
+
locale: options.language
|
|
7301
|
+
});
|
|
7302
|
+
console.log(import_chalk4.default.blue("Loading Puppeteer..."));
|
|
7303
|
+
const puppeteer = await loadPuppeteer();
|
|
7304
|
+
const outputPath = options.output || "resume.pdf";
|
|
7305
|
+
const format = options.format === "Letter" ? "Letter" : "A4";
|
|
7306
|
+
const margin = parseMargin(options.margin);
|
|
7307
|
+
console.log(import_chalk4.default.blue(`Generating PDF (${format} format)...`));
|
|
7308
|
+
const browser = await puppeteer.launch({ headless: true });
|
|
7309
|
+
try {
|
|
7310
|
+
const page = await browser.newPage();
|
|
7311
|
+
await page.setContent(htmlOutput, { waitUntil: "networkidle0" });
|
|
7312
|
+
const pdfBuffer = await page.pdf({
|
|
7313
|
+
format,
|
|
7314
|
+
margin,
|
|
7315
|
+
printBackground: true,
|
|
7316
|
+
preferCSSPageSize: true
|
|
7317
|
+
});
|
|
7318
|
+
import_fs6.default.mkdirSync(import_node_path4.default.dirname(import_node_path4.default.resolve(outputPath)), { recursive: true });
|
|
7319
|
+
import_fs6.default.writeFileSync(outputPath, pdfBuffer);
|
|
7320
|
+
console.log(import_chalk4.default.green(`\u2705 Successfully generated ${outputPath}`));
|
|
7321
|
+
} finally {
|
|
7322
|
+
await browser.close();
|
|
7323
|
+
}
|
|
7324
|
+
} catch (error) {
|
|
7325
|
+
handleCommandError(error, "pdf", options.debug);
|
|
7326
|
+
}
|
|
7327
|
+
}
|
|
7328
|
+
|
|
7329
|
+
// src/commands/themes.ts
|
|
7330
|
+
init_cjs_shims();
|
|
7331
|
+
var import_chalk5 = __toESM(require("chalk"));
|
|
7332
|
+
var import_child_process2 = require("child_process");
|
|
7333
|
+
var import_module2 = require("module");
|
|
7334
|
+
var KNOWN_THEMES = [
|
|
7335
|
+
{ name: "stackoverflow", pkg: "jsonresume-theme-stackoverflow", description: "Stack Overflow inspired theme" },
|
|
7336
|
+
{ name: "elegant", pkg: "jsonresume-theme-elegant", description: "Elegant and professional" },
|
|
7337
|
+
{ name: "react", pkg: "jsonresume-theme-react", description: "Built with React components" },
|
|
7338
|
+
{ name: "even", pkg: "jsonresume-theme-even", description: "Clean and minimal" },
|
|
7339
|
+
{ name: "kendall", pkg: "jsonresume-theme-kendall", description: "Simple and clean layout" },
|
|
7340
|
+
{ name: "macchiato", pkg: "jsonresume-theme-macchiato", description: "Beautiful and modern" },
|
|
7341
|
+
{ name: "flat", pkg: "jsonresume-theme-flat", description: "Flat design theme" },
|
|
7342
|
+
{ name: "class", pkg: "jsonresume-theme-class", description: "Classic professional look" },
|
|
7343
|
+
{ name: "short", pkg: "jsonresume-theme-short", description: "Compact single-page resume" },
|
|
7344
|
+
{ name: "spartan", pkg: "jsonresume-theme-spartan", description: "Minimalist Spartan design" },
|
|
7345
|
+
{ name: "paper", pkg: "jsonresume-theme-paper", description: "Paper-like clean design" },
|
|
7346
|
+
{ name: "onepage", pkg: "jsonresume-theme-onepage", description: "One page resume layout" }
|
|
7347
|
+
];
|
|
7348
|
+
function isThemeInstalled(pkg) {
|
|
7349
|
+
try {
|
|
7350
|
+
const require3 = (0, import_module2.createRequire)(process.cwd() + "/");
|
|
7351
|
+
require3.resolve(pkg);
|
|
7352
|
+
return true;
|
|
7353
|
+
} catch {
|
|
7354
|
+
return false;
|
|
7355
|
+
}
|
|
7356
|
+
}
|
|
7357
|
+
function getInstalledVersion(pkg) {
|
|
7358
|
+
try {
|
|
7359
|
+
const require3 = (0, import_module2.createRequire)(process.cwd() + "/");
|
|
7360
|
+
const pkgJson = require3(`${pkg}/package.json`);
|
|
7361
|
+
return pkgJson.version || null;
|
|
7362
|
+
} catch {
|
|
7363
|
+
return null;
|
|
7364
|
+
}
|
|
7365
|
+
}
|
|
7366
|
+
function listThemes() {
|
|
7367
|
+
console.log(import_chalk5.default.blue("\n\u{1F4E6} Compatible JSON Resume Themes\n"));
|
|
7368
|
+
const nameWidth = 16;
|
|
7369
|
+
const pkgWidth = 38;
|
|
7370
|
+
console.log(
|
|
7371
|
+
` ${"Status".padEnd(10)}${"Name".padEnd(nameWidth)}${"Package".padEnd(pkgWidth)}Description`
|
|
7372
|
+
);
|
|
7373
|
+
console.log(` ${"\u2500".repeat(10)}${"\u2500".repeat(nameWidth)}${"\u2500".repeat(pkgWidth)}${"\u2500".repeat(30)}`);
|
|
7374
|
+
for (const theme of KNOWN_THEMES) {
|
|
7375
|
+
const installed = isThemeInstalled(theme.pkg);
|
|
7376
|
+
const version = installed ? getInstalledVersion(theme.pkg) : null;
|
|
7377
|
+
const status = installed ? import_chalk5.default.green(`\u2713 ${version || "yes"}`.padEnd(10)) : import_chalk5.default.yellow("not installed".substring(0, 10).padEnd(10));
|
|
7378
|
+
console.log(
|
|
7379
|
+
` ${status}${theme.name.padEnd(nameWidth)}${import_chalk5.default.blue(theme.pkg.padEnd(pkgWidth))}${theme.description}`
|
|
7380
|
+
);
|
|
7381
|
+
}
|
|
7382
|
+
console.log(import_chalk5.default.blue("\nInstall a theme:"));
|
|
7383
|
+
console.log(` ${import_chalk5.default.cyan("resuml themes --install <name>")}`);
|
|
7384
|
+
console.log(` ${import_chalk5.default.cyan("resuml themes --install stackoverflow")}
|
|
7385
|
+
`);
|
|
7386
|
+
console.log(
|
|
7387
|
+
import_chalk5.default.blue("Browse all themes: ") + "https://www.npmjs.com/search?q=jsonresume-theme\n"
|
|
7388
|
+
);
|
|
7389
|
+
}
|
|
7390
|
+
function installTheme2(name) {
|
|
7391
|
+
const known = KNOWN_THEMES.find((t) => t.name === name);
|
|
7392
|
+
const pkg = known ? known.pkg : name.startsWith("jsonresume-theme-") ? name : `jsonresume-theme-${name}`;
|
|
7393
|
+
console.log(import_chalk5.default.blue(`
|
|
7394
|
+
\u{1F4E6} Installing ${pkg}...
|
|
7395
|
+
`));
|
|
7396
|
+
try {
|
|
7397
|
+
(0, import_child_process2.execSync)(`npm install ${pkg}`, { stdio: "inherit" });
|
|
7398
|
+
console.log(import_chalk5.default.green(`
|
|
7399
|
+
\u2705 Successfully installed ${pkg}`));
|
|
7400
|
+
console.log(import_chalk5.default.blue(`
|
|
7401
|
+
Use it with: ${import_chalk5.default.cyan(`resuml render --theme ${known?.name || name}`)}
|
|
7402
|
+
`));
|
|
7403
|
+
} catch {
|
|
7404
|
+
console.error(import_chalk5.default.red(`
|
|
7405
|
+
\u274C Failed to install ${pkg}`));
|
|
7406
|
+
console.error(import_chalk5.default.yellow(`Make sure the package exists: https://www.npmjs.com/package/${pkg}
|
|
7407
|
+
`));
|
|
7408
|
+
}
|
|
7409
|
+
}
|
|
7410
|
+
async function themesAction(options) {
|
|
7411
|
+
if (options.install) {
|
|
7412
|
+
installTheme2(options.install);
|
|
7413
|
+
} else {
|
|
7414
|
+
listThemes();
|
|
7415
|
+
}
|
|
7416
|
+
}
|
|
7417
|
+
|
|
7062
7418
|
// src/utils/themeRender.ts
|
|
7063
7419
|
var themeRender_exports = {};
|
|
7064
7420
|
__export(themeRender_exports, {
|
|
@@ -7113,12 +7469,12 @@ function injectCss(html, css) {
|
|
|
7113
7469
|
}
|
|
7114
7470
|
|
|
7115
7471
|
// src/index.ts
|
|
7116
|
-
var currentDir =
|
|
7472
|
+
var currentDir = import_path3.default.dirname((0, import_url.fileURLToPath)(importMetaUrl));
|
|
7117
7473
|
function getCliVersion() {
|
|
7118
|
-
const packageJsonPath =
|
|
7119
|
-
if (
|
|
7474
|
+
const packageJsonPath = import_path3.default.resolve(currentDir, "../package.json");
|
|
7475
|
+
if (import_fs7.default.existsSync(packageJsonPath)) {
|
|
7120
7476
|
try {
|
|
7121
|
-
const packageJson = JSON.parse(
|
|
7477
|
+
const packageJson = JSON.parse(import_fs7.default.readFileSync(packageJsonPath, "utf8"));
|
|
7122
7478
|
return packageJson.version || "0.0.0";
|
|
7123
7479
|
} catch {
|
|
7124
7480
|
return "0.0.0";
|
|
@@ -7132,6 +7488,9 @@ program.command("validate").description("Validates resume data against the schem
|
|
|
7132
7488
|
program.command("tojson").description("Converts YAML resume data to JSON format.").option("-r, --resume <path>", "Input YAML file, directory, or glob pattern.").option("-o, --output <file>", "Output JSON file path.", "resume.json").option("--debug", "Show detailed validation and processing information.").action(toJsonAction);
|
|
7133
7489
|
program.command("render").description("Renders the resume data using a specified theme.").option("-r, --resume <path>", "Input YAML file, directory, or glob pattern.").option("-t, --theme <name>", "Theme name (e.g., stackoverflow, react).").option("-o, --output <file>", "Output HTML file path (defaults to resume.html).").option("--language <code>", "Language code for localization.", "en").option("--debug", "Show detailed validation and processing information.").action(renderAction);
|
|
7134
7490
|
program.command("dev").description("Start development server with hot-reload.").option("-r, --resume <path>", "Input YAML file, directory, or glob pattern.").option("-t, --theme <name>", "Theme name (e.g., stackoverflow, react).").option("--port <number>", "Port for development server.", "3000").option("--language <code>", "Language code for localization.", "en").option("--debug", "Show detailed validation and processing information.").action(devAction);
|
|
7491
|
+
program.command("init").description("Scaffold a starter resume.yaml file with all sections.").option("-o, --output <file>", "Output YAML file path.", "resume.yaml").action(initAction);
|
|
7492
|
+
program.command("pdf").description("Export resume as PDF using Puppeteer.").option("-r, --resume <path>", "Input YAML file, directory, or glob pattern.").option("-t, --theme <name>", "Theme name (e.g., stackoverflow, react).").option("-o, --output <file>", "Output PDF file path.", "resume.pdf").option("--language <code>", "Language code for localization.", "en").option("--format <size>", "Page format: A4 or Letter.", "A4").option("--margin <values>", 'Page margins (e.g., "10mm" or "10mm,15mm,10mm,15mm").').option("--debug", "Show detailed validation and processing information.").action(pdfAction);
|
|
7493
|
+
program.command("themes").description("List available JSON Resume themes and install them.").option("--install <name>", "Install a theme by name (e.g., stackoverflow, elegant).").action(themesAction);
|
|
7135
7494
|
if (process.env.NODE_ENV !== "test") {
|
|
7136
7495
|
(async () => {
|
|
7137
7496
|
try {
|