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/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 || new URL("main.js", document.baseURI).href;
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 import_path2 = __toESM(require("path"));
271
- var import_fs5 = __toESM(require("fs"));
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(path6) {
4195
- if (!path6) {
4193
+ resolve(path8) {
4194
+ if (!path8) {
4196
4195
  return this;
4197
4196
  }
4198
- const rootPath = this.getRootString(path6);
4199
- const dir = path6.substring(rootPath.length);
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(path6) {
4952
- return import_node_path.win32.parse(path6).root;
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(path6) {
4999
- return path6.startsWith("/") ? "/" : "";
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: fs7 = defaultFS } = {}) {
5049
- this.#fs = fsFromOption(fs7);
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(path6 = this.cwd) {
5089
- if (typeof path6 === "string") {
5090
- path6 = this.cwd.resolve(path6);
5087
+ depth(path8 = this.cwd) {
5088
+ if (typeof path8 === "string") {
5089
+ path8 = this.cwd.resolve(path8);
5091
5090
  }
5092
- return path6.depth();
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(path6 = this.cwd) {
5578
+ chdir(path8 = this.cwd) {
5580
5579
  const oldCwd = this.cwd;
5581
- this.cwd = typeof path6 === "string" ? this.cwd.resolve(path6) : path6;
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(fs7) {
5608
- return new PathWin32(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs: fs7 });
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(fs7) {
5637
- return new PathPosix(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs: fs7 });
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(([path6, n]) => [
5944
- path6,
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, path6, opts) {
6148
+ constructor(patterns, path8, opts) {
6150
6149
  this.patterns = patterns;
6151
- this.path = path6;
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(path6) {
6171
- return this.seen.has(path6) || !!this.#ignore?.ignored?.(path6);
6169
+ #ignored(path8) {
6170
+ return this.seen.has(path8) || !!this.#ignore?.ignored?.(path8);
6172
6171
  }
6173
- #childrenIgnored(path6) {
6174
- return !!this.#ignore?.childrenIgnored?.(path6);
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, path6, opts) {
6390
- super(patterns, path6, opts);
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, path6, opts) {
6428
- super(patterns, path6, opts);
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 path6 = err.instancePath || "root";
6799
- console.error(`${index + 1}. Path: ${path6}`);
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 path6 = err.instancePath || "root";
6810
- console.error(`${index + 1}. Field: ${path6}`);
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 chalk3 = (await import("chalk")).default;
6828
- console.log(chalk3.blue("Starting resuml validate..."));
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(chalk3.blue("Validating resume data..."));
6831
+ console.log(chalk6.blue("Validating resume data..."));
6833
6832
  try {
6834
6833
  await processResumeData(yamlContents);
6835
- console.log(chalk3.green("\u2713 Resume data is valid against the schema!"));
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 chalk3 = (await import("chalk")).default;
6850
- console.log(chalk3.blue("Starting resuml tojson..."));
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(chalk3.blue("Processing and validating data..."));
6853
+ console.log(chalk6.blue("Processing and validating data..."));
6855
6854
  const resumeData = await processResumeData(yamlContents);
6856
- console.log(chalk3.green("Processing and validation successful!"));
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(chalk3.green(`Successfully wrote output to ${options.output}`));
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 = import_path2.default.dirname((0, import_url.fileURLToPath)(importMetaUrl));
7472
+ var currentDir = import_path3.default.dirname((0, import_url.fileURLToPath)(importMetaUrl));
7117
7473
  function getCliVersion() {
7118
- const packageJsonPath = import_path2.default.resolve(currentDir, "../package.json");
7119
- if (import_fs5.default.existsSync(packageJsonPath)) {
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(import_fs5.default.readFileSync(packageJsonPath, "utf8"));
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 {