resuml 1.3.0 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +93 -1
- package/bin/resuml +21 -0
- package/dist/{api.js → api.cjs} +50 -45
- package/dist/api.cjs.map +1 -0
- package/dist/api.d.cts +9 -0
- package/dist/{index.js → index.cjs} +1180 -118
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +88 -0
- package/dist/{loadResume-BFCirLAW.d.ts → themeLoader-C7CBqNiC.d.cts} +14 -1
- package/package.json +53 -47
- package/scripts/build-builder.js +25 -0
- package/scripts/bundle-themes.js +233 -0
- package/scripts/dev-server.js +392 -0
- package/scripts/quick-bundle.cjs +129 -0
- package/dist/api.d.ts +0 -8
- package/dist/api.js.map +0 -1
- package/dist/index.d.ts +0 -55
- package/dist/index.js.map +0 -1
- /package/scripts/{generate-types.js → generate-types.cjs} +0 -0
|
@@ -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.
|
|
42
|
+
getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && 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
|
}
|
|
@@ -258,6 +258,7 @@ var require_brace_expansion = __commonJS({
|
|
|
258
258
|
// src/index.ts
|
|
259
259
|
var index_exports = {};
|
|
260
260
|
__export(index_exports, {
|
|
261
|
+
analyzeAts: () => analyzeAts,
|
|
261
262
|
loadResumeFiles: () => loadResumeFiles,
|
|
262
263
|
loadTheme: () => loadTheme,
|
|
263
264
|
processResumeData: () => processResumeData,
|
|
@@ -267,17 +268,18 @@ __export(index_exports, {
|
|
|
267
268
|
module.exports = __toCommonJS(index_exports);
|
|
268
269
|
init_cjs_shims();
|
|
269
270
|
var import_commander = require("commander");
|
|
270
|
-
var import_path3 = __toESM(require("path"));
|
|
271
|
-
var
|
|
271
|
+
var import_path3 = __toESM(require("path"), 1);
|
|
272
|
+
var import_fs8 = __toESM(require("fs"), 1);
|
|
272
273
|
var import_url = require("url");
|
|
273
274
|
|
|
274
275
|
// src/commands/validate.ts
|
|
275
276
|
init_cjs_shims();
|
|
277
|
+
var import_fs2 = __toESM(require("fs"), 1);
|
|
276
278
|
|
|
277
279
|
// src/core.ts
|
|
278
280
|
init_cjs_shims();
|
|
279
281
|
var import_yaml = require("yaml");
|
|
280
|
-
var import_lodash = __toESM(require("lodash.merge"));
|
|
282
|
+
var import_lodash = __toESM(require("lodash.merge"), 1);
|
|
281
283
|
var import_schema = require("@jsonresume/schema");
|
|
282
284
|
async function processResumeData(yamlContents) {
|
|
283
285
|
if (yamlContents.length === 0) {
|
|
@@ -316,13 +318,13 @@ async function processResumeData(yamlContents) {
|
|
|
316
318
|
|
|
317
319
|
// src/utils/loadResume.ts
|
|
318
320
|
init_cjs_shims();
|
|
319
|
-
var import_promises3 = __toESM(require("fs/promises"));
|
|
320
|
-
var import_yaml2 = __toESM(require("yaml"));
|
|
321
|
+
var import_promises3 = __toESM(require("fs/promises"), 1);
|
|
322
|
+
var import_yaml2 = __toESM(require("yaml"), 1);
|
|
321
323
|
|
|
322
324
|
// src/utils/fileUtils.ts
|
|
323
325
|
init_cjs_shims();
|
|
324
|
-
var import_promises2 = __toESM(require("fs/promises"));
|
|
325
|
-
var import_path = __toESM(require("path"));
|
|
326
|
+
var import_promises2 = __toESM(require("fs/promises"), 1);
|
|
327
|
+
var import_path = __toESM(require("path"), 1);
|
|
326
328
|
|
|
327
329
|
// node_modules/glob/dist/esm/index.js
|
|
328
330
|
init_cjs_shims();
|
|
@@ -1012,7 +1014,7 @@ var path = {
|
|
|
1012
1014
|
};
|
|
1013
1015
|
var sep = defaultPlatform === "win32" ? path.win32.sep : path.posix.sep;
|
|
1014
1016
|
minimatch.sep = sep;
|
|
1015
|
-
var GLOBSTAR =
|
|
1017
|
+
var GLOBSTAR = Symbol("globstar **");
|
|
1016
1018
|
minimatch.GLOBSTAR = GLOBSTAR;
|
|
1017
1019
|
var qmark2 = "[^/]";
|
|
1018
1020
|
var star2 = qmark2 + "*?";
|
|
@@ -1717,6 +1719,7 @@ if (typeof AC === "undefined") {
|
|
|
1717
1719
|
};
|
|
1718
1720
|
}
|
|
1719
1721
|
var shouldWarn = (code) => !warned.has(code);
|
|
1722
|
+
var TYPE = Symbol("type");
|
|
1720
1723
|
var isPosInt = (n) => n && n === Math.floor(n) && n > 0 && isFinite(n);
|
|
1721
1724
|
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;
|
|
1722
1725
|
var ZeroArray = class extends Array {
|
|
@@ -3061,37 +3064,37 @@ var isStream = (s) => !!s && typeof s === "object" && (s instanceof Minipass ||
|
|
|
3061
3064
|
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
|
|
3062
3065
|
s.pipe !== import_node_stream.default.Writable.prototype.pipe;
|
|
3063
3066
|
var isWritable = (s) => !!s && typeof s === "object" && s instanceof import_node_events.EventEmitter && typeof s.write === "function" && typeof s.end === "function";
|
|
3064
|
-
var EOF =
|
|
3065
|
-
var MAYBE_EMIT_END =
|
|
3066
|
-
var EMITTED_END =
|
|
3067
|
-
var EMITTING_END =
|
|
3068
|
-
var EMITTED_ERROR =
|
|
3069
|
-
var CLOSED =
|
|
3070
|
-
var READ =
|
|
3071
|
-
var FLUSH =
|
|
3072
|
-
var FLUSHCHUNK =
|
|
3073
|
-
var ENCODING =
|
|
3074
|
-
var DECODER =
|
|
3075
|
-
var FLOWING =
|
|
3076
|
-
var PAUSED =
|
|
3077
|
-
var RESUME =
|
|
3078
|
-
var BUFFER =
|
|
3079
|
-
var PIPES =
|
|
3080
|
-
var BUFFERLENGTH =
|
|
3081
|
-
var BUFFERPUSH =
|
|
3082
|
-
var BUFFERSHIFT =
|
|
3083
|
-
var OBJECTMODE =
|
|
3084
|
-
var DESTROYED =
|
|
3085
|
-
var ERROR =
|
|
3086
|
-
var EMITDATA =
|
|
3087
|
-
var EMITEND =
|
|
3088
|
-
var EMITEND2 =
|
|
3089
|
-
var ASYNC =
|
|
3090
|
-
var ABORT =
|
|
3091
|
-
var ABORTED =
|
|
3092
|
-
var SIGNAL =
|
|
3093
|
-
var DATALISTENERS =
|
|
3094
|
-
var DISCARDED =
|
|
3067
|
+
var EOF = Symbol("EOF");
|
|
3068
|
+
var MAYBE_EMIT_END = Symbol("maybeEmitEnd");
|
|
3069
|
+
var EMITTED_END = Symbol("emittedEnd");
|
|
3070
|
+
var EMITTING_END = Symbol("emittingEnd");
|
|
3071
|
+
var EMITTED_ERROR = Symbol("emittedError");
|
|
3072
|
+
var CLOSED = Symbol("closed");
|
|
3073
|
+
var READ = Symbol("read");
|
|
3074
|
+
var FLUSH = Symbol("flush");
|
|
3075
|
+
var FLUSHCHUNK = Symbol("flushChunk");
|
|
3076
|
+
var ENCODING = Symbol("encoding");
|
|
3077
|
+
var DECODER = Symbol("decoder");
|
|
3078
|
+
var FLOWING = Symbol("flowing");
|
|
3079
|
+
var PAUSED = Symbol("paused");
|
|
3080
|
+
var RESUME = Symbol("resume");
|
|
3081
|
+
var BUFFER = Symbol("buffer");
|
|
3082
|
+
var PIPES = Symbol("pipes");
|
|
3083
|
+
var BUFFERLENGTH = Symbol("bufferLength");
|
|
3084
|
+
var BUFFERPUSH = Symbol("bufferPush");
|
|
3085
|
+
var BUFFERSHIFT = Symbol("bufferShift");
|
|
3086
|
+
var OBJECTMODE = Symbol("objectMode");
|
|
3087
|
+
var DESTROYED = Symbol("destroyed");
|
|
3088
|
+
var ERROR = Symbol("error");
|
|
3089
|
+
var EMITDATA = Symbol("emitData");
|
|
3090
|
+
var EMITEND = Symbol("emitEnd");
|
|
3091
|
+
var EMITEND2 = Symbol("emitEnd2");
|
|
3092
|
+
var ASYNC = Symbol("async");
|
|
3093
|
+
var ABORT = Symbol("abort");
|
|
3094
|
+
var ABORTED = Symbol("aborted");
|
|
3095
|
+
var SIGNAL = Symbol("signal");
|
|
3096
|
+
var DATALISTENERS = Symbol("dataListeners");
|
|
3097
|
+
var DISCARDED = Symbol("discarded");
|
|
3095
3098
|
var defer = (fn) => Promise.resolve().then(fn);
|
|
3096
3099
|
var nodefer = (fn) => fn();
|
|
3097
3100
|
var isEndish = (ev) => ev === "end" || ev === "finish" || ev === "prefinish";
|
|
@@ -3130,7 +3133,7 @@ var PipeProxyErrors = class extends Pipe {
|
|
|
3130
3133
|
}
|
|
3131
3134
|
constructor(src, dest, opts) {
|
|
3132
3135
|
super(src, dest, opts);
|
|
3133
|
-
this.proxyErrors = (er) => dest.emit("error", er);
|
|
3136
|
+
this.proxyErrors = (er) => this.dest.emit("error", er);
|
|
3134
3137
|
src.on("error", this.proxyErrors);
|
|
3135
3138
|
}
|
|
3136
3139
|
};
|
|
@@ -3844,6 +3847,8 @@ var Minipass = class extends import_node_events.EventEmitter {
|
|
|
3844
3847
|
return: stop,
|
|
3845
3848
|
[Symbol.asyncIterator]() {
|
|
3846
3849
|
return this;
|
|
3850
|
+
},
|
|
3851
|
+
[Symbol.asyncDispose]: async () => {
|
|
3847
3852
|
}
|
|
3848
3853
|
};
|
|
3849
3854
|
}
|
|
@@ -3879,6 +3884,8 @@ var Minipass = class extends import_node_events.EventEmitter {
|
|
|
3879
3884
|
return: stop,
|
|
3880
3885
|
[Symbol.iterator]() {
|
|
3881
3886
|
return this;
|
|
3887
|
+
},
|
|
3888
|
+
[Symbol.dispose]: () => {
|
|
3882
3889
|
}
|
|
3883
3890
|
};
|
|
3884
3891
|
}
|
|
@@ -4004,7 +4011,7 @@ var ChildrenCache = class extends LRUCache {
|
|
|
4004
4011
|
});
|
|
4005
4012
|
}
|
|
4006
4013
|
};
|
|
4007
|
-
var setAsCwd =
|
|
4014
|
+
var setAsCwd = Symbol("PathScurry setAsCwd");
|
|
4008
4015
|
var PathBase = class {
|
|
4009
4016
|
/**
|
|
4010
4017
|
* the basename of this path
|
|
@@ -5044,8 +5051,8 @@ var PathScurryBase = class {
|
|
|
5044
5051
|
*
|
|
5045
5052
|
* @internal
|
|
5046
5053
|
*/
|
|
5047
|
-
constructor(cwd = process.cwd(), pathImpl, sep2, { nocase, childrenCacheSize = 16 * 1024, fs:
|
|
5048
|
-
this.#fs = fsFromOption(
|
|
5054
|
+
constructor(cwd = process.cwd(), pathImpl, sep2, { nocase, childrenCacheSize = 16 * 1024, fs: fs10 = defaultFS } = {}) {
|
|
5055
|
+
this.#fs = fsFromOption(fs10);
|
|
5049
5056
|
if (cwd instanceof URL || cwd.startsWith("file://")) {
|
|
5050
5057
|
cwd = (0, import_node_url.fileURLToPath)(cwd);
|
|
5051
5058
|
}
|
|
@@ -5603,8 +5610,8 @@ var PathScurryWin32 = class extends PathScurryBase {
|
|
|
5603
5610
|
/**
|
|
5604
5611
|
* @internal
|
|
5605
5612
|
*/
|
|
5606
|
-
newRoot(
|
|
5607
|
-
return new PathWin32(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs:
|
|
5613
|
+
newRoot(fs10) {
|
|
5614
|
+
return new PathWin32(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs: fs10 });
|
|
5608
5615
|
}
|
|
5609
5616
|
/**
|
|
5610
5617
|
* Return true if the provided path string is an absolute path
|
|
@@ -5632,8 +5639,8 @@ var PathScurryPosix = class extends PathScurryBase {
|
|
|
5632
5639
|
/**
|
|
5633
5640
|
* @internal
|
|
5634
5641
|
*/
|
|
5635
|
-
newRoot(
|
|
5636
|
-
return new PathPosix(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs:
|
|
5642
|
+
newRoot(fs10) {
|
|
5643
|
+
return new PathPosix(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs: fs10 });
|
|
5637
5644
|
}
|
|
5638
5645
|
/**
|
|
5639
5646
|
* Return true if the provided path string is an absolute path
|
|
@@ -6816,12 +6823,1011 @@ function handleCommandError(error, command, debug = false) {
|
|
|
6816
6823
|
}
|
|
6817
6824
|
}
|
|
6818
6825
|
}
|
|
6819
|
-
if (process.env
|
|
6826
|
+
if (process.env["NODE_ENV"] !== "test") {
|
|
6820
6827
|
process.exit(1);
|
|
6821
6828
|
}
|
|
6822
6829
|
}
|
|
6823
6830
|
|
|
6831
|
+
// src/ats/index.ts
|
|
6832
|
+
init_cjs_shims();
|
|
6833
|
+
|
|
6834
|
+
// src/ats/genericChecks.ts
|
|
6835
|
+
init_cjs_shims();
|
|
6836
|
+
|
|
6837
|
+
// src/ats/i18n/index.ts
|
|
6838
|
+
init_cjs_shims();
|
|
6839
|
+
|
|
6840
|
+
// src/ats/i18n/en.ts
|
|
6841
|
+
init_cjs_shims();
|
|
6842
|
+
var en = {
|
|
6843
|
+
actionVerbs: [
|
|
6844
|
+
// Leadership & Management
|
|
6845
|
+
"achieved",
|
|
6846
|
+
"administered",
|
|
6847
|
+
"advanced",
|
|
6848
|
+
"allocated",
|
|
6849
|
+
"approved",
|
|
6850
|
+
"assigned",
|
|
6851
|
+
"authorized",
|
|
6852
|
+
"chaired",
|
|
6853
|
+
"consolidated",
|
|
6854
|
+
"coordinated",
|
|
6855
|
+
"delegated",
|
|
6856
|
+
"directed",
|
|
6857
|
+
"established",
|
|
6858
|
+
"executed",
|
|
6859
|
+
"headed",
|
|
6860
|
+
"hired",
|
|
6861
|
+
"hosted",
|
|
6862
|
+
"led",
|
|
6863
|
+
"managed",
|
|
6864
|
+
"mentored",
|
|
6865
|
+
"motivated",
|
|
6866
|
+
"orchestrated",
|
|
6867
|
+
"organized",
|
|
6868
|
+
"oversaw",
|
|
6869
|
+
"planned",
|
|
6870
|
+
"presided",
|
|
6871
|
+
"prioritized",
|
|
6872
|
+
"produced",
|
|
6873
|
+
"recruited",
|
|
6874
|
+
"spearheaded",
|
|
6875
|
+
"supervised",
|
|
6876
|
+
// Technical & Engineering
|
|
6877
|
+
"architected",
|
|
6878
|
+
"automated",
|
|
6879
|
+
"built",
|
|
6880
|
+
"coded",
|
|
6881
|
+
"configured",
|
|
6882
|
+
"debugged",
|
|
6883
|
+
"deployed",
|
|
6884
|
+
"designed",
|
|
6885
|
+
"developed",
|
|
6886
|
+
"devised",
|
|
6887
|
+
"engineered",
|
|
6888
|
+
"implemented",
|
|
6889
|
+
"installed",
|
|
6890
|
+
"integrated",
|
|
6891
|
+
"launched",
|
|
6892
|
+
"maintained",
|
|
6893
|
+
"migrated",
|
|
6894
|
+
"modernized",
|
|
6895
|
+
"optimized",
|
|
6896
|
+
"overhauled",
|
|
6897
|
+
"programmed",
|
|
6898
|
+
"prototyped",
|
|
6899
|
+
"refactored",
|
|
6900
|
+
"reengineered",
|
|
6901
|
+
"resolved",
|
|
6902
|
+
"restructured",
|
|
6903
|
+
"revamped",
|
|
6904
|
+
"scaled",
|
|
6905
|
+
"standardized",
|
|
6906
|
+
"streamlined",
|
|
6907
|
+
"tested",
|
|
6908
|
+
"troubleshot",
|
|
6909
|
+
"upgraded",
|
|
6910
|
+
// Achievement & Impact
|
|
6911
|
+
"accelerated",
|
|
6912
|
+
"accomplished",
|
|
6913
|
+
"boosted",
|
|
6914
|
+
"completed",
|
|
6915
|
+
"contributed",
|
|
6916
|
+
"converted",
|
|
6917
|
+
"decreased",
|
|
6918
|
+
"delivered",
|
|
6919
|
+
"doubled",
|
|
6920
|
+
"earned",
|
|
6921
|
+
"eliminated",
|
|
6922
|
+
"exceeded",
|
|
6923
|
+
"expanded",
|
|
6924
|
+
"expedited",
|
|
6925
|
+
"generated",
|
|
6926
|
+
"grew",
|
|
6927
|
+
"improved",
|
|
6928
|
+
"increased",
|
|
6929
|
+
"maximized",
|
|
6930
|
+
"minimized",
|
|
6931
|
+
"outperformed",
|
|
6932
|
+
"pioneered",
|
|
6933
|
+
"recovered",
|
|
6934
|
+
"reduced",
|
|
6935
|
+
"saved",
|
|
6936
|
+
"simplified",
|
|
6937
|
+
"solved",
|
|
6938
|
+
"surpassed",
|
|
6939
|
+
"transformed",
|
|
6940
|
+
"tripled",
|
|
6941
|
+
// Communication & Collaboration
|
|
6942
|
+
"advised",
|
|
6943
|
+
"advocated",
|
|
6944
|
+
"briefed",
|
|
6945
|
+
"collaborated",
|
|
6946
|
+
"communicated",
|
|
6947
|
+
"consulted",
|
|
6948
|
+
"convinced",
|
|
6949
|
+
"counseled",
|
|
6950
|
+
"defined",
|
|
6951
|
+
"demonstrated",
|
|
6952
|
+
"documented",
|
|
6953
|
+
"educated",
|
|
6954
|
+
"facilitated",
|
|
6955
|
+
"guided",
|
|
6956
|
+
"influenced",
|
|
6957
|
+
"informed",
|
|
6958
|
+
"instructed",
|
|
6959
|
+
"liaised",
|
|
6960
|
+
"negotiated",
|
|
6961
|
+
"partnered",
|
|
6962
|
+
"persuaded",
|
|
6963
|
+
"presented",
|
|
6964
|
+
"promoted",
|
|
6965
|
+
"proposed",
|
|
6966
|
+
"published",
|
|
6967
|
+
"recommended",
|
|
6968
|
+
"represented",
|
|
6969
|
+
"trained",
|
|
6970
|
+
// Analysis & Research
|
|
6971
|
+
"analyzed",
|
|
6972
|
+
"assessed",
|
|
6973
|
+
"audited",
|
|
6974
|
+
"benchmarked",
|
|
6975
|
+
"calculated",
|
|
6976
|
+
"compared",
|
|
6977
|
+
"compiled",
|
|
6978
|
+
"conducted",
|
|
6979
|
+
"discovered",
|
|
6980
|
+
"evaluated",
|
|
6981
|
+
"examined",
|
|
6982
|
+
"explored",
|
|
6983
|
+
"forecasted",
|
|
6984
|
+
"identified",
|
|
6985
|
+
"inspected",
|
|
6986
|
+
"interpreted",
|
|
6987
|
+
"investigated",
|
|
6988
|
+
"mapped",
|
|
6989
|
+
"measured",
|
|
6990
|
+
"modeled",
|
|
6991
|
+
"monitored",
|
|
6992
|
+
"quantified",
|
|
6993
|
+
"researched",
|
|
6994
|
+
"reviewed",
|
|
6995
|
+
"surveyed",
|
|
6996
|
+
"synthesized",
|
|
6997
|
+
"tracked",
|
|
6998
|
+
"validated",
|
|
6999
|
+
"verified",
|
|
7000
|
+
// Creation & Innovation
|
|
7001
|
+
"conceptualized",
|
|
7002
|
+
"crafted",
|
|
7003
|
+
"created",
|
|
7004
|
+
"customized",
|
|
7005
|
+
"formulated",
|
|
7006
|
+
"founded",
|
|
7007
|
+
"initiated",
|
|
7008
|
+
"innovated",
|
|
7009
|
+
"introduced",
|
|
7010
|
+
"invented",
|
|
7011
|
+
"originated",
|
|
7012
|
+
"shaped"
|
|
7013
|
+
],
|
|
7014
|
+
pronouns: ["i", "me", "my", "mine", "myself", "we", "our", "ours"],
|
|
7015
|
+
stopWords: [
|
|
7016
|
+
"a",
|
|
7017
|
+
"an",
|
|
7018
|
+
"the",
|
|
7019
|
+
"and",
|
|
7020
|
+
"or",
|
|
7021
|
+
"but",
|
|
7022
|
+
"in",
|
|
7023
|
+
"on",
|
|
7024
|
+
"at",
|
|
7025
|
+
"to",
|
|
7026
|
+
"for",
|
|
7027
|
+
"of",
|
|
7028
|
+
"with",
|
|
7029
|
+
"by",
|
|
7030
|
+
"from",
|
|
7031
|
+
"is",
|
|
7032
|
+
"was",
|
|
7033
|
+
"are",
|
|
7034
|
+
"were",
|
|
7035
|
+
"be",
|
|
7036
|
+
"been",
|
|
7037
|
+
"being",
|
|
7038
|
+
"have",
|
|
7039
|
+
"has",
|
|
7040
|
+
"had",
|
|
7041
|
+
"do",
|
|
7042
|
+
"does",
|
|
7043
|
+
"did",
|
|
7044
|
+
"will",
|
|
7045
|
+
"would",
|
|
7046
|
+
"could",
|
|
7047
|
+
"should",
|
|
7048
|
+
"may",
|
|
7049
|
+
"might",
|
|
7050
|
+
"shall",
|
|
7051
|
+
"can",
|
|
7052
|
+
"this",
|
|
7053
|
+
"that",
|
|
7054
|
+
"these",
|
|
7055
|
+
"those",
|
|
7056
|
+
"it",
|
|
7057
|
+
"its",
|
|
7058
|
+
"as",
|
|
7059
|
+
"if",
|
|
7060
|
+
"not",
|
|
7061
|
+
"no",
|
|
7062
|
+
"so",
|
|
7063
|
+
"up",
|
|
7064
|
+
"out",
|
|
7065
|
+
"about",
|
|
7066
|
+
"into",
|
|
7067
|
+
"over",
|
|
7068
|
+
"after",
|
|
7069
|
+
"before",
|
|
7070
|
+
"between",
|
|
7071
|
+
"under",
|
|
7072
|
+
"above",
|
|
7073
|
+
"below",
|
|
7074
|
+
"all",
|
|
7075
|
+
"each",
|
|
7076
|
+
"every",
|
|
7077
|
+
"both",
|
|
7078
|
+
"few",
|
|
7079
|
+
"more",
|
|
7080
|
+
"most",
|
|
7081
|
+
"other",
|
|
7082
|
+
"some",
|
|
7083
|
+
"such",
|
|
7084
|
+
"than",
|
|
7085
|
+
"too",
|
|
7086
|
+
"very"
|
|
7087
|
+
]
|
|
7088
|
+
};
|
|
7089
|
+
var en_default = en;
|
|
7090
|
+
|
|
7091
|
+
// src/ats/i18n/de.ts
|
|
7092
|
+
init_cjs_shims();
|
|
7093
|
+
var de = {
|
|
7094
|
+
actionVerbs: [
|
|
7095
|
+
// Führung & Management
|
|
7096
|
+
"geleitet",
|
|
7097
|
+
"gef\xFChrt",
|
|
7098
|
+
"koordiniert",
|
|
7099
|
+
"organisiert",
|
|
7100
|
+
"verwaltet",
|
|
7101
|
+
"delegiert",
|
|
7102
|
+
"beaufsichtigt",
|
|
7103
|
+
"betreut",
|
|
7104
|
+
"eingestellt",
|
|
7105
|
+
"motiviert",
|
|
7106
|
+
"verantwortet",
|
|
7107
|
+
"gesteuert",
|
|
7108
|
+
"\xFCberwacht",
|
|
7109
|
+
"priorisiert",
|
|
7110
|
+
"geplant",
|
|
7111
|
+
// Technik & Entwicklung
|
|
7112
|
+
"entwickelt",
|
|
7113
|
+
"implementiert",
|
|
7114
|
+
"programmiert",
|
|
7115
|
+
"konfiguriert",
|
|
7116
|
+
"automatisiert",
|
|
7117
|
+
"deployt",
|
|
7118
|
+
"gebaut",
|
|
7119
|
+
"entworfen",
|
|
7120
|
+
"integriert",
|
|
7121
|
+
"migriert",
|
|
7122
|
+
"modernisiert",
|
|
7123
|
+
"optimiert",
|
|
7124
|
+
"refaktoriert",
|
|
7125
|
+
"skaliert",
|
|
7126
|
+
"standardisiert",
|
|
7127
|
+
"getestet",
|
|
7128
|
+
"aufgebaut",
|
|
7129
|
+
"eingef\xFChrt",
|
|
7130
|
+
"bereitgestellt",
|
|
7131
|
+
"umgesetzt",
|
|
7132
|
+
// Leistung & Ergebnisse
|
|
7133
|
+
"verbessert",
|
|
7134
|
+
"gesteigert",
|
|
7135
|
+
"reduziert",
|
|
7136
|
+
"beschleunigt",
|
|
7137
|
+
"erreicht",
|
|
7138
|
+
"\xFCbertroffen",
|
|
7139
|
+
"erweitert",
|
|
7140
|
+
"vereinfacht",
|
|
7141
|
+
"gel\xF6st",
|
|
7142
|
+
"transformiert",
|
|
7143
|
+
"erh\xF6ht",
|
|
7144
|
+
"verdoppelt",
|
|
7145
|
+
"verdreifacht",
|
|
7146
|
+
"generiert",
|
|
7147
|
+
"gespart",
|
|
7148
|
+
"maximiert",
|
|
7149
|
+
"minimiert",
|
|
7150
|
+
"eliminiert",
|
|
7151
|
+
"geliefert",
|
|
7152
|
+
"abgeschlossen",
|
|
7153
|
+
// Kommunikation & Zusammenarbeit
|
|
7154
|
+
"beraten",
|
|
7155
|
+
"pr\xE4sentiert",
|
|
7156
|
+
"dokumentiert",
|
|
7157
|
+
"geschult",
|
|
7158
|
+
"trainiert",
|
|
7159
|
+
"vermittelt",
|
|
7160
|
+
"kommuniziert",
|
|
7161
|
+
"verhandelt",
|
|
7162
|
+
"zusammengearbeitet",
|
|
7163
|
+
"unterst\xFCtzt",
|
|
7164
|
+
"gef\xF6rdert",
|
|
7165
|
+
"empfohlen",
|
|
7166
|
+
"vorgestellt",
|
|
7167
|
+
"publiziert",
|
|
7168
|
+
// Analyse & Forschung
|
|
7169
|
+
"analysiert",
|
|
7170
|
+
"bewertet",
|
|
7171
|
+
"evaluiert",
|
|
7172
|
+
"untersucht",
|
|
7173
|
+
"erforscht",
|
|
7174
|
+
"identifiziert",
|
|
7175
|
+
"gemessen",
|
|
7176
|
+
"\xFCberwacht",
|
|
7177
|
+
"validiert",
|
|
7178
|
+
"verifiziert",
|
|
7179
|
+
"gepr\xFCft",
|
|
7180
|
+
"verglichen",
|
|
7181
|
+
"recherchiert",
|
|
7182
|
+
"quantifiziert",
|
|
7183
|
+
// Kreation & Innovation
|
|
7184
|
+
"konzipiert",
|
|
7185
|
+
"erstellt",
|
|
7186
|
+
"gestaltet",
|
|
7187
|
+
"initiiert",
|
|
7188
|
+
"innoviert",
|
|
7189
|
+
"eingef\xFChrt",
|
|
7190
|
+
"gegr\xFCndet",
|
|
7191
|
+
"formuliert"
|
|
7192
|
+
],
|
|
7193
|
+
pronouns: ["ich", "mich", "mir", "mein", "meine", "meinem", "meiner", "meines", "wir", "unser", "unsere"],
|
|
7194
|
+
stopWords: [
|
|
7195
|
+
"ein",
|
|
7196
|
+
"eine",
|
|
7197
|
+
"einer",
|
|
7198
|
+
"eines",
|
|
7199
|
+
"einem",
|
|
7200
|
+
"der",
|
|
7201
|
+
"die",
|
|
7202
|
+
"das",
|
|
7203
|
+
"den",
|
|
7204
|
+
"dem",
|
|
7205
|
+
"des",
|
|
7206
|
+
"und",
|
|
7207
|
+
"oder",
|
|
7208
|
+
"aber",
|
|
7209
|
+
"in",
|
|
7210
|
+
"an",
|
|
7211
|
+
"auf",
|
|
7212
|
+
"zu",
|
|
7213
|
+
"f\xFCr",
|
|
7214
|
+
"von",
|
|
7215
|
+
"mit",
|
|
7216
|
+
"bei",
|
|
7217
|
+
"aus",
|
|
7218
|
+
"ist",
|
|
7219
|
+
"war",
|
|
7220
|
+
"sind",
|
|
7221
|
+
"waren",
|
|
7222
|
+
"wird",
|
|
7223
|
+
"wurde",
|
|
7224
|
+
"werden",
|
|
7225
|
+
"hat",
|
|
7226
|
+
"hatte",
|
|
7227
|
+
"haben",
|
|
7228
|
+
"hatten",
|
|
7229
|
+
"sein",
|
|
7230
|
+
"kann",
|
|
7231
|
+
"k\xF6nnte",
|
|
7232
|
+
"soll",
|
|
7233
|
+
"sollte",
|
|
7234
|
+
"muss",
|
|
7235
|
+
"musste",
|
|
7236
|
+
"darf",
|
|
7237
|
+
"diese",
|
|
7238
|
+
"dieser",
|
|
7239
|
+
"dieses",
|
|
7240
|
+
"diesem",
|
|
7241
|
+
"diesen",
|
|
7242
|
+
"als",
|
|
7243
|
+
"wenn",
|
|
7244
|
+
"nicht",
|
|
7245
|
+
"kein",
|
|
7246
|
+
"keine",
|
|
7247
|
+
"so",
|
|
7248
|
+
"auch",
|
|
7249
|
+
"noch",
|
|
7250
|
+
"schon",
|
|
7251
|
+
"nach",
|
|
7252
|
+
"vor",
|
|
7253
|
+
"\xFCber",
|
|
7254
|
+
"unter",
|
|
7255
|
+
"zwischen",
|
|
7256
|
+
"durch",
|
|
7257
|
+
"ohne",
|
|
7258
|
+
"um",
|
|
7259
|
+
"bis",
|
|
7260
|
+
"alle",
|
|
7261
|
+
"jede",
|
|
7262
|
+
"jeder",
|
|
7263
|
+
"jedes",
|
|
7264
|
+
"mehr",
|
|
7265
|
+
"viel",
|
|
7266
|
+
"sehr"
|
|
7267
|
+
]
|
|
7268
|
+
};
|
|
7269
|
+
var de_default = de;
|
|
7270
|
+
|
|
7271
|
+
// src/ats/i18n/index.ts
|
|
7272
|
+
var languages = { en: en_default, de: de_default };
|
|
7273
|
+
function getLanguageData(language) {
|
|
7274
|
+
return languages[language] ?? languages["en"] ?? en_default;
|
|
7275
|
+
}
|
|
7276
|
+
|
|
7277
|
+
// src/ats/genericChecks.ts
|
|
7278
|
+
function wordCount(text) {
|
|
7279
|
+
return text.trim().split(/\s+/).filter(Boolean).length;
|
|
7280
|
+
}
|
|
7281
|
+
function getFirstWord(text) {
|
|
7282
|
+
return text.trim().split(/\s+/)[0]?.toLowerCase().replace(/[^a-zA-ZäöüßÄÖÜàáâãéèêëíìîïóòôõúùûüñç]/g, "") || "";
|
|
7283
|
+
}
|
|
7284
|
+
var contactComplete = (resume) => {
|
|
7285
|
+
const b = resume.basics;
|
|
7286
|
+
const hasName = !!b?.name;
|
|
7287
|
+
const hasEmail = !!b?.email;
|
|
7288
|
+
const hasPhone = !!b?.phone;
|
|
7289
|
+
const hasCity = !!b?.location?.city;
|
|
7290
|
+
const fields = [hasName, hasEmail, hasPhone, hasCity];
|
|
7291
|
+
const presentCount = fields.filter(Boolean).length;
|
|
7292
|
+
const passed = presentCount === fields.length;
|
|
7293
|
+
const missing = [];
|
|
7294
|
+
if (!hasName) missing.push("name");
|
|
7295
|
+
if (!hasEmail) missing.push("email");
|
|
7296
|
+
if (!hasPhone) missing.push("phone");
|
|
7297
|
+
if (!hasCity) missing.push("location.city");
|
|
7298
|
+
return {
|
|
7299
|
+
id: "contact-complete",
|
|
7300
|
+
category: "contact",
|
|
7301
|
+
weight: "high",
|
|
7302
|
+
passed,
|
|
7303
|
+
score: Math.round(presentCount / fields.length * 100),
|
|
7304
|
+
message: passed ? "Contact information is complete." : `Missing contact fields: ${missing.join(", ")}.`,
|
|
7305
|
+
suggestion: passed ? void 0 : `Add the following to your basics section: ${missing.join(", ")}.`
|
|
7306
|
+
};
|
|
7307
|
+
};
|
|
7308
|
+
var hasSummary = (resume) => {
|
|
7309
|
+
const summary = resume.basics?.summary?.trim();
|
|
7310
|
+
if (!summary) {
|
|
7311
|
+
return {
|
|
7312
|
+
id: "has-summary",
|
|
7313
|
+
category: "content",
|
|
7314
|
+
weight: "high",
|
|
7315
|
+
passed: false,
|
|
7316
|
+
score: 0,
|
|
7317
|
+
message: "No professional summary found.",
|
|
7318
|
+
suggestion: "Add a 2-4 sentence professional summary to your basics section highlighting your experience and key skills."
|
|
7319
|
+
};
|
|
7320
|
+
}
|
|
7321
|
+
const words = wordCount(summary);
|
|
7322
|
+
const tooShort = words < 15;
|
|
7323
|
+
const tooLong = words > 100;
|
|
7324
|
+
const passed = !tooShort && !tooLong;
|
|
7325
|
+
let score = 100;
|
|
7326
|
+
if (tooShort) score = Math.round(words / 15 * 60);
|
|
7327
|
+
if (tooLong) score = Math.max(60, 100 - (words - 100));
|
|
7328
|
+
return {
|
|
7329
|
+
id: "has-summary",
|
|
7330
|
+
category: "content",
|
|
7331
|
+
weight: "high",
|
|
7332
|
+
passed,
|
|
7333
|
+
score,
|
|
7334
|
+
message: tooShort ? `Summary is too short (${words} words). Aim for 15-100 words.` : tooLong ? `Summary is too long (${words} words). Aim for 15-100 words.` : `Summary length is good (${words} words).`,
|
|
7335
|
+
suggestion: tooShort ? "Expand your summary to describe your experience, expertise, and career goals in 15-100 words." : tooLong ? "Shorten your summary to the most impactful 15-100 words. Focus on key achievements and expertise." : void 0
|
|
7336
|
+
};
|
|
7337
|
+
};
|
|
7338
|
+
var hasLinkedin = (resume) => {
|
|
7339
|
+
const profiles = resume.basics?.profiles || [];
|
|
7340
|
+
const linkedin = profiles.find(
|
|
7341
|
+
(p) => p.network?.toLowerCase() === "linkedin" || p.url?.toLowerCase().includes("linkedin.com")
|
|
7342
|
+
);
|
|
7343
|
+
return {
|
|
7344
|
+
id: "has-linkedin",
|
|
7345
|
+
category: "contact",
|
|
7346
|
+
weight: "medium",
|
|
7347
|
+
passed: !!linkedin,
|
|
7348
|
+
score: linkedin ? 100 : 0,
|
|
7349
|
+
message: linkedin ? "LinkedIn profile found." : "No LinkedIn profile found.",
|
|
7350
|
+
suggestion: linkedin ? void 0 : "Add a LinkedIn profile to your basics.profiles section."
|
|
7351
|
+
};
|
|
7352
|
+
};
|
|
7353
|
+
var workHighlights = (resume) => {
|
|
7354
|
+
const work = resume.work || [];
|
|
7355
|
+
if (work.length === 0) {
|
|
7356
|
+
return {
|
|
7357
|
+
id: "work-highlights",
|
|
7358
|
+
category: "content",
|
|
7359
|
+
weight: "high",
|
|
7360
|
+
passed: false,
|
|
7361
|
+
score: 0,
|
|
7362
|
+
message: "No work experience entries found.",
|
|
7363
|
+
suggestion: "Add work experience entries with highlights describing your accomplishments."
|
|
7364
|
+
};
|
|
7365
|
+
}
|
|
7366
|
+
const minHighlights = 2;
|
|
7367
|
+
const entriesWithEnough = work.filter((w) => (w.highlights?.length || 0) >= minHighlights);
|
|
7368
|
+
const passed = entriesWithEnough.length === work.length;
|
|
7369
|
+
const score = Math.round(entriesWithEnough.length / work.length * 100);
|
|
7370
|
+
const lacking = work.filter((w) => (w.highlights?.length || 0) < minHighlights).map((w) => `"${w.position || "Unknown"} at ${w.name || "Unknown"}" (${w.highlights?.length || 0} highlights)`);
|
|
7371
|
+
return {
|
|
7372
|
+
id: "work-highlights",
|
|
7373
|
+
category: "content",
|
|
7374
|
+
weight: "high",
|
|
7375
|
+
passed,
|
|
7376
|
+
score,
|
|
7377
|
+
message: passed ? "All work entries have sufficient highlights." : `Some work entries need more highlights: ${lacking.join("; ")}.`,
|
|
7378
|
+
suggestion: passed ? void 0 : `Add at least ${minHighlights} bullet-point highlights to each work entry describing specific accomplishments.`
|
|
7379
|
+
};
|
|
7380
|
+
};
|
|
7381
|
+
var actionVerbs = (resume, language) => {
|
|
7382
|
+
const langData = getLanguageData(language);
|
|
7383
|
+
const verbs = new Set(langData.actionVerbs);
|
|
7384
|
+
const allHighlights = [];
|
|
7385
|
+
for (const w of resume.work || []) {
|
|
7386
|
+
for (const h of w.highlights || []) {
|
|
7387
|
+
allHighlights.push({ text: h, source: `${w.position || ""} at ${w.name || ""}` });
|
|
7388
|
+
}
|
|
7389
|
+
}
|
|
7390
|
+
for (const p of resume.projects || []) {
|
|
7391
|
+
for (const h of p.highlights || []) {
|
|
7392
|
+
allHighlights.push({ text: h, source: `project "${p.name || ""}"` });
|
|
7393
|
+
}
|
|
7394
|
+
}
|
|
7395
|
+
for (const v of resume.volunteer || []) {
|
|
7396
|
+
for (const h of v.highlights || []) {
|
|
7397
|
+
allHighlights.push({ text: h, source: `volunteer at ${v.organization || ""}` });
|
|
7398
|
+
}
|
|
7399
|
+
}
|
|
7400
|
+
if (allHighlights.length === 0) {
|
|
7401
|
+
return {
|
|
7402
|
+
id: "action-verbs",
|
|
7403
|
+
category: "content",
|
|
7404
|
+
weight: "high",
|
|
7405
|
+
passed: false,
|
|
7406
|
+
score: 0,
|
|
7407
|
+
message: "No highlights found to check for action verbs.",
|
|
7408
|
+
suggestion: "Add highlights to your work, project, or volunteer entries starting with strong action verbs."
|
|
7409
|
+
};
|
|
7410
|
+
}
|
|
7411
|
+
const withActionVerb = allHighlights.filter((h) => verbs.has(getFirstWord(h.text)));
|
|
7412
|
+
const withoutActionVerb = allHighlights.filter((h) => !verbs.has(getFirstWord(h.text)));
|
|
7413
|
+
const passed = withoutActionVerb.length === 0;
|
|
7414
|
+
const score = Math.round(withActionVerb.length / allHighlights.length * 100);
|
|
7415
|
+
const examples = withoutActionVerb.slice(0, 3).map(
|
|
7416
|
+
(h) => `"${h.text.substring(0, 60)}${h.text.length > 60 ? "..." : ""}" (${h.source})`
|
|
7417
|
+
);
|
|
7418
|
+
return {
|
|
7419
|
+
id: "action-verbs",
|
|
7420
|
+
category: "content",
|
|
7421
|
+
weight: "high",
|
|
7422
|
+
passed,
|
|
7423
|
+
score,
|
|
7424
|
+
message: passed ? "All highlights start with action verbs." : `${withoutActionVerb.length} of ${allHighlights.length} highlights don't start with an action verb.`,
|
|
7425
|
+
suggestion: passed ? void 0 : `Start each highlight with a strong action verb (e.g., "Developed", "Implemented", "Led"). Fix: ${examples.join("; ")}.`
|
|
7426
|
+
};
|
|
7427
|
+
};
|
|
7428
|
+
var quantifiedImpact = (resume) => {
|
|
7429
|
+
const quantPattern = /\d+%?|\$[\d,]+|[\d,]+\+?\s*(users|clients|customers|people|team|members|projects|applications|servers|services|endpoints|requests|transactions)/i;
|
|
7430
|
+
const allHighlights = [];
|
|
7431
|
+
for (const w of resume.work || []) {
|
|
7432
|
+
allHighlights.push(...w.highlights || []);
|
|
7433
|
+
}
|
|
7434
|
+
for (const p of resume.projects || []) {
|
|
7435
|
+
allHighlights.push(...p.highlights || []);
|
|
7436
|
+
}
|
|
7437
|
+
if (allHighlights.length === 0) {
|
|
7438
|
+
return {
|
|
7439
|
+
id: "quantified-impact",
|
|
7440
|
+
category: "content",
|
|
7441
|
+
weight: "medium",
|
|
7442
|
+
passed: false,
|
|
7443
|
+
score: 0,
|
|
7444
|
+
message: "No highlights found to check for quantified impact.",
|
|
7445
|
+
suggestion: 'Add measurable results to your highlights (e.g., "Reduced load time by 40%", "Managed team of 8").'
|
|
7446
|
+
};
|
|
7447
|
+
}
|
|
7448
|
+
const quantified = allHighlights.filter((h) => quantPattern.test(h));
|
|
7449
|
+
const ratio = quantified.length / allHighlights.length;
|
|
7450
|
+
const passed = ratio >= 0.5;
|
|
7451
|
+
const score = Math.min(100, Math.round(ratio * 200));
|
|
7452
|
+
return {
|
|
7453
|
+
id: "quantified-impact",
|
|
7454
|
+
category: "content",
|
|
7455
|
+
weight: "medium",
|
|
7456
|
+
passed,
|
|
7457
|
+
score,
|
|
7458
|
+
message: passed ? `${quantified.length} of ${allHighlights.length} highlights include quantified results.` : `Only ${quantified.length} of ${allHighlights.length} highlights include numbers or metrics.`,
|
|
7459
|
+
suggestion: passed ? void 0 : 'Add specific numbers, percentages, or metrics to your highlights (e.g., "Improved performance by 30%", "Managed $2M budget").'
|
|
7460
|
+
};
|
|
7461
|
+
};
|
|
7462
|
+
var dateConsistency = (resume) => {
|
|
7463
|
+
const work = resume.work || [];
|
|
7464
|
+
if (work.length < 2) {
|
|
7465
|
+
return {
|
|
7466
|
+
id: "date-consistency",
|
|
7467
|
+
category: "structure",
|
|
7468
|
+
weight: "medium",
|
|
7469
|
+
passed: true,
|
|
7470
|
+
score: 100,
|
|
7471
|
+
message: "Date consistency check passed (fewer than 2 work entries)."
|
|
7472
|
+
};
|
|
7473
|
+
}
|
|
7474
|
+
const issues = [];
|
|
7475
|
+
for (const w of work) {
|
|
7476
|
+
if (!w.startDate) {
|
|
7477
|
+
issues.push(`"${w.position || "Unknown"} at ${w.name || "Unknown"}" is missing a start date.`);
|
|
7478
|
+
}
|
|
7479
|
+
}
|
|
7480
|
+
const sorted = [...work].filter((w) => Boolean(w.startDate)).sort((a, b) => a.startDate > b.startDate ? 1 : -1);
|
|
7481
|
+
for (let i = 0; i < sorted.length - 1; i++) {
|
|
7482
|
+
const current = sorted[i];
|
|
7483
|
+
const next = sorted[i + 1];
|
|
7484
|
+
const endDate = current.endDate ?? current.startDate;
|
|
7485
|
+
const gapMs = new Date(next.startDate).getTime() - new Date(endDate).getTime();
|
|
7486
|
+
const gapMonths = gapMs / (1e3 * 60 * 60 * 24 * 30);
|
|
7487
|
+
if (gapMonths > 6) {
|
|
7488
|
+
issues.push(
|
|
7489
|
+
`Gap of ~${Math.round(gapMonths)} months between "${current.name ?? "Unknown"}" (ended ${endDate}) and "${next.name ?? "Unknown"}" (started ${next.startDate}).`
|
|
7490
|
+
);
|
|
7491
|
+
}
|
|
7492
|
+
}
|
|
7493
|
+
const passed = issues.length === 0;
|
|
7494
|
+
return {
|
|
7495
|
+
id: "date-consistency",
|
|
7496
|
+
category: "structure",
|
|
7497
|
+
weight: "medium",
|
|
7498
|
+
passed,
|
|
7499
|
+
score: passed ? 100 : Math.max(0, 100 - issues.length * 25),
|
|
7500
|
+
message: passed ? "Work experience dates are consistent with no major gaps." : `Date issues found: ${issues.join(" ")}`,
|
|
7501
|
+
suggestion: passed ? void 0 : "Ensure all work entries have start dates. If there are employment gaps, consider adding freelance, volunteer, or education entries to fill them."
|
|
7502
|
+
};
|
|
7503
|
+
};
|
|
7504
|
+
var skillsPopulated = (resume) => {
|
|
7505
|
+
const skills = resume.skills || [];
|
|
7506
|
+
const minCategories = 3;
|
|
7507
|
+
const categoriesWithKeywords = skills.filter((s) => s.keywords && s.keywords.length > 0);
|
|
7508
|
+
const passed = categoriesWithKeywords.length >= minCategories;
|
|
7509
|
+
const score = Math.min(100, Math.round(categoriesWithKeywords.length / minCategories * 100));
|
|
7510
|
+
return {
|
|
7511
|
+
id: "skills-populated",
|
|
7512
|
+
category: "structure",
|
|
7513
|
+
weight: "medium",
|
|
7514
|
+
passed,
|
|
7515
|
+
score,
|
|
7516
|
+
message: passed ? `${categoriesWithKeywords.length} skill categories with keywords found.` : `Only ${categoriesWithKeywords.length} skill categories with keywords found (need at least ${minCategories}).`,
|
|
7517
|
+
suggestion: passed ? void 0 : `Add at least ${minCategories} skill categories with specific keywords (e.g., "Languages: TypeScript, Python", "Frameworks: React, Node.js").`
|
|
7518
|
+
};
|
|
7519
|
+
};
|
|
7520
|
+
var educationComplete = (resume) => {
|
|
7521
|
+
const education = resume.education || [];
|
|
7522
|
+
if (education.length === 0) {
|
|
7523
|
+
return {
|
|
7524
|
+
id: "education-complete",
|
|
7525
|
+
category: "structure",
|
|
7526
|
+
weight: "low",
|
|
7527
|
+
passed: false,
|
|
7528
|
+
score: 0,
|
|
7529
|
+
message: "No education entries found.",
|
|
7530
|
+
suggestion: "Add at least one education entry with institution, area, and studyType."
|
|
7531
|
+
};
|
|
7532
|
+
}
|
|
7533
|
+
const complete = education.filter((e) => e.institution && e.area && e.studyType);
|
|
7534
|
+
const passed = complete.length === education.length;
|
|
7535
|
+
const score = Math.round(complete.length / education.length * 100);
|
|
7536
|
+
const incomplete = education.filter((e) => !e.institution || !e.area || !e.studyType).map((e) => {
|
|
7537
|
+
const missing = [];
|
|
7538
|
+
if (!e.institution) missing.push("institution");
|
|
7539
|
+
if (!e.area) missing.push("area");
|
|
7540
|
+
if (!e.studyType) missing.push("studyType");
|
|
7541
|
+
return `"${e.institution || "Unknown"}" missing: ${missing.join(", ")}`;
|
|
7542
|
+
});
|
|
7543
|
+
return {
|
|
7544
|
+
id: "education-complete",
|
|
7545
|
+
category: "structure",
|
|
7546
|
+
weight: "low",
|
|
7547
|
+
passed,
|
|
7548
|
+
score,
|
|
7549
|
+
message: passed ? "All education entries are complete." : `Incomplete education entries: ${incomplete.join("; ")}.`,
|
|
7550
|
+
suggestion: passed ? void 0 : "Ensure each education entry has institution, area (field of study), and studyType (degree type)."
|
|
7551
|
+
};
|
|
7552
|
+
};
|
|
7553
|
+
var noPronouns = (resume, language) => {
|
|
7554
|
+
const langData = getLanguageData(language);
|
|
7555
|
+
const pronounSet = new Set(langData.pronouns);
|
|
7556
|
+
const textBlocks = [];
|
|
7557
|
+
if (resume.basics?.summary) {
|
|
7558
|
+
textBlocks.push({ text: resume.basics.summary, source: "summary" });
|
|
7559
|
+
}
|
|
7560
|
+
for (const w of resume.work || []) {
|
|
7561
|
+
if (w.summary) textBlocks.push({ text: w.summary, source: `work summary (${w.name || "Unknown"})` });
|
|
7562
|
+
for (const h of w.highlights || []) {
|
|
7563
|
+
textBlocks.push({ text: h, source: `work highlight (${w.name || "Unknown"})` });
|
|
7564
|
+
}
|
|
7565
|
+
}
|
|
7566
|
+
for (const p of resume.projects || []) {
|
|
7567
|
+
if (p.description) textBlocks.push({ text: p.description, source: `project (${p.name || "Unknown"})` });
|
|
7568
|
+
for (const h of p.highlights || []) {
|
|
7569
|
+
textBlocks.push({ text: h, source: `project highlight (${p.name || "Unknown"})` });
|
|
7570
|
+
}
|
|
7571
|
+
}
|
|
7572
|
+
const found = [];
|
|
7573
|
+
for (const block of textBlocks) {
|
|
7574
|
+
const words = block.text.toLowerCase().split(/\s+/);
|
|
7575
|
+
for (const word of words) {
|
|
7576
|
+
const clean = word.replace(/[^a-zA-ZäöüßÄÖÜ]/g, "");
|
|
7577
|
+
if (pronounSet.has(clean)) {
|
|
7578
|
+
found.push({ pronoun: clean, source: block.source });
|
|
7579
|
+
}
|
|
7580
|
+
}
|
|
7581
|
+
}
|
|
7582
|
+
const passed = found.length === 0;
|
|
7583
|
+
const uniquePronouns = [...new Set(found.map((f) => f.pronoun))];
|
|
7584
|
+
const examples = found.slice(0, 3).map((f) => `"${f.pronoun}" in ${f.source}`);
|
|
7585
|
+
return {
|
|
7586
|
+
id: "no-pronouns",
|
|
7587
|
+
category: "content",
|
|
7588
|
+
weight: "medium",
|
|
7589
|
+
passed,
|
|
7590
|
+
score: passed ? 100 : Math.max(0, 100 - found.length * 15),
|
|
7591
|
+
message: passed ? "No first-person pronouns found in resume content." : `Found ${found.length} first-person pronoun(s): ${uniquePronouns.join(", ")}.`,
|
|
7592
|
+
suggestion: passed ? void 0 : `Remove first-person pronouns from your resume. Instead of "I managed a team", write "Managed a team". Found: ${examples.join("; ")}.`
|
|
7593
|
+
};
|
|
7594
|
+
};
|
|
7595
|
+
var sectionCompleteness = (resume) => {
|
|
7596
|
+
const required = ["basics", "work", "education", "skills"];
|
|
7597
|
+
const present = required.filter((section) => {
|
|
7598
|
+
const value = resume[section];
|
|
7599
|
+
if (Array.isArray(value)) return value.length > 0;
|
|
7600
|
+
return value !== void 0;
|
|
7601
|
+
});
|
|
7602
|
+
const missing = required.filter((s) => !present.includes(s));
|
|
7603
|
+
const passed = missing.length === 0;
|
|
7604
|
+
return {
|
|
7605
|
+
id: "section-completeness",
|
|
7606
|
+
category: "structure",
|
|
7607
|
+
weight: "low",
|
|
7608
|
+
passed,
|
|
7609
|
+
score: Math.round(present.length / required.length * 100),
|
|
7610
|
+
message: passed ? "All essential resume sections are present." : `Missing essential sections: ${missing.join(", ")}.`,
|
|
7611
|
+
suggestion: passed ? void 0 : `Add the following sections to your resume: ${missing.join(", ")}.`
|
|
7612
|
+
};
|
|
7613
|
+
};
|
|
7614
|
+
var allChecks = [
|
|
7615
|
+
contactComplete,
|
|
7616
|
+
hasSummary,
|
|
7617
|
+
hasLinkedin,
|
|
7618
|
+
workHighlights,
|
|
7619
|
+
actionVerbs,
|
|
7620
|
+
quantifiedImpact,
|
|
7621
|
+
dateConsistency,
|
|
7622
|
+
skillsPopulated,
|
|
7623
|
+
educationComplete,
|
|
7624
|
+
noPronouns,
|
|
7625
|
+
sectionCompleteness
|
|
7626
|
+
];
|
|
7627
|
+
function runGenericChecks(resume, language) {
|
|
7628
|
+
return allChecks.map((check) => check(resume, language));
|
|
7629
|
+
}
|
|
7630
|
+
|
|
7631
|
+
// src/ats/jdMatcher.ts
|
|
7632
|
+
init_cjs_shims();
|
|
7633
|
+
function tokenize(text, stopWords) {
|
|
7634
|
+
return text.toLowerCase().replace(/[^a-zA-Z0-9äöüßÄÖÜàáâãéèêëíìîïóòôõúùûüñç\s-]/g, " ").split(/\s+/).filter((word) => word.length > 2 && !stopWords.has(word));
|
|
7635
|
+
}
|
|
7636
|
+
function simpleStem(word, language) {
|
|
7637
|
+
if (language === "de") {
|
|
7638
|
+
return word.replace(/(ung|heit|keit|schaft|lich|isch|iert|ieren|tion|ment)$/, "").replace(/(en|er|es|em|te|st)$/, "");
|
|
7639
|
+
}
|
|
7640
|
+
return word.replace(/(ment|ness|tion|sion|ance|ence|ity|ing|ous|ive|able|ible|ful|less)$/, "").replace(/(ies)$/, "y").replace(/(es|ed|s)$/, "");
|
|
7641
|
+
}
|
|
7642
|
+
function extractResumeText(resume) {
|
|
7643
|
+
const parts = [];
|
|
7644
|
+
if (resume.basics?.summary) parts.push(resume.basics.summary);
|
|
7645
|
+
if (resume.basics?.label) parts.push(resume.basics.label);
|
|
7646
|
+
for (const w of resume.work || []) {
|
|
7647
|
+
if (w.position) parts.push(w.position);
|
|
7648
|
+
if (w.summary) parts.push(w.summary);
|
|
7649
|
+
parts.push(...w.highlights || []);
|
|
7650
|
+
}
|
|
7651
|
+
for (const s of resume.skills || []) {
|
|
7652
|
+
if (s.name) parts.push(s.name);
|
|
7653
|
+
parts.push(...s.keywords || []);
|
|
7654
|
+
}
|
|
7655
|
+
for (const p of resume.projects || []) {
|
|
7656
|
+
if (p.name) parts.push(p.name);
|
|
7657
|
+
if (p.description) parts.push(p.description);
|
|
7658
|
+
parts.push(...p.highlights || []);
|
|
7659
|
+
}
|
|
7660
|
+
for (const e of resume.education || []) {
|
|
7661
|
+
if (e.area) parts.push(e.area);
|
|
7662
|
+
if (e.studyType) parts.push(e.studyType);
|
|
7663
|
+
parts.push(...e.courses || []);
|
|
7664
|
+
}
|
|
7665
|
+
for (const c of resume.certificates || []) {
|
|
7666
|
+
if (c.name) parts.push(c.name);
|
|
7667
|
+
}
|
|
7668
|
+
return parts.join(" ");
|
|
7669
|
+
}
|
|
7670
|
+
function buildTfMap(tokens) {
|
|
7671
|
+
const tf = /* @__PURE__ */ new Map();
|
|
7672
|
+
for (const token of tokens) {
|
|
7673
|
+
tf.set(token, (tf.get(token) || 0) + 1);
|
|
7674
|
+
}
|
|
7675
|
+
return tf;
|
|
7676
|
+
}
|
|
7677
|
+
function extractKeywords(text, language, maxKeywords = 30) {
|
|
7678
|
+
const langData = getLanguageData(language);
|
|
7679
|
+
const stopWords = new Set(langData.stopWords);
|
|
7680
|
+
const tokens = tokenize(text, stopWords);
|
|
7681
|
+
const stemmed = tokens.map((t) => simpleStem(t, language));
|
|
7682
|
+
const tf = buildTfMap(stemmed);
|
|
7683
|
+
const stemToOriginal = /* @__PURE__ */ new Map();
|
|
7684
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
7685
|
+
const stem = stemmed[i] ?? "";
|
|
7686
|
+
if (!stemToOriginal.has(stem)) {
|
|
7687
|
+
stemToOriginal.set(stem, tokens[i] ?? "");
|
|
7688
|
+
}
|
|
7689
|
+
}
|
|
7690
|
+
return [...tf.entries()].filter(([stem]) => stem.length > 2).sort((a, b) => b[1] - a[1]).slice(0, maxKeywords).map(([stem]) => stemToOriginal.get(stem) || stem);
|
|
7691
|
+
}
|
|
7692
|
+
function matchJobDescription(resume, jobDescription, language = "en") {
|
|
7693
|
+
const langData = getLanguageData(language);
|
|
7694
|
+
const stopWords = new Set(langData.stopWords);
|
|
7695
|
+
const jdKeywords = extractKeywords(jobDescription, language);
|
|
7696
|
+
const resumeText = extractResumeText(resume);
|
|
7697
|
+
const resumeTokens = tokenize(resumeText, stopWords);
|
|
7698
|
+
const resumeStems = new Set(resumeTokens.map((t) => simpleStem(t, language)));
|
|
7699
|
+
const resumeTokenSet = new Set(resumeTokens);
|
|
7700
|
+
const matched = [];
|
|
7701
|
+
const missing = [];
|
|
7702
|
+
for (const keyword of jdKeywords) {
|
|
7703
|
+
const stem = simpleStem(keyword, language);
|
|
7704
|
+
if (resumeStems.has(stem) || resumeTokenSet.has(keyword.toLowerCase())) {
|
|
7705
|
+
matched.push(keyword);
|
|
7706
|
+
} else {
|
|
7707
|
+
missing.push(keyword);
|
|
7708
|
+
}
|
|
7709
|
+
}
|
|
7710
|
+
const matchPercentage = jdKeywords.length > 0 ? Math.round(matched.length / jdKeywords.length * 100) : 0;
|
|
7711
|
+
return { matched, missing, matchPercentage };
|
|
7712
|
+
}
|
|
7713
|
+
|
|
7714
|
+
// src/ats/scoring.ts
|
|
7715
|
+
init_cjs_shims();
|
|
7716
|
+
var weightMultiplier = {
|
|
7717
|
+
high: 3,
|
|
7718
|
+
medium: 2,
|
|
7719
|
+
low: 1
|
|
7720
|
+
};
|
|
7721
|
+
function calculateScore(checks) {
|
|
7722
|
+
if (checks.length === 0) return 0;
|
|
7723
|
+
let weightedSum = 0;
|
|
7724
|
+
let totalWeight = 0;
|
|
7725
|
+
for (const check of checks) {
|
|
7726
|
+
const mult = weightMultiplier[check.weight] || 1;
|
|
7727
|
+
weightedSum += check.score * mult;
|
|
7728
|
+
totalWeight += 100 * mult;
|
|
7729
|
+
}
|
|
7730
|
+
return totalWeight > 0 ? Math.round(weightedSum / totalWeight * 100) : 0;
|
|
7731
|
+
}
|
|
7732
|
+
function calculateCombinedScore(genericScore, jdMatchPercentage) {
|
|
7733
|
+
if (jdMatchPercentage === void 0) return genericScore;
|
|
7734
|
+
return Math.round(genericScore * 0.6 + jdMatchPercentage * 0.4);
|
|
7735
|
+
}
|
|
7736
|
+
function scoreToRating(score) {
|
|
7737
|
+
if (score >= 90) return "excellent";
|
|
7738
|
+
if (score >= 75) return "good";
|
|
7739
|
+
if (score >= 60) return "needs-work";
|
|
7740
|
+
return "poor";
|
|
7741
|
+
}
|
|
7742
|
+
function generateSummary(score, rating, hasJd) {
|
|
7743
|
+
const ratingLabel = {
|
|
7744
|
+
excellent: "Excellent",
|
|
7745
|
+
good: "Good",
|
|
7746
|
+
"needs-work": "Needs Work",
|
|
7747
|
+
poor: "Poor"
|
|
7748
|
+
}[rating];
|
|
7749
|
+
const base = `ATS Score: ${score}/100 (${ratingLabel})`;
|
|
7750
|
+
if (hasJd) {
|
|
7751
|
+
return `${base} \u2014 includes job description keyword matching.`;
|
|
7752
|
+
}
|
|
7753
|
+
return `${base} \u2014 based on resume structure and content best practices.`;
|
|
7754
|
+
}
|
|
7755
|
+
|
|
7756
|
+
// src/ats/index.ts
|
|
7757
|
+
function analyzeAts(resume, options = {}) {
|
|
7758
|
+
const language = options.language || "en";
|
|
7759
|
+
const checks = runGenericChecks(resume, language);
|
|
7760
|
+
const genericScore = calculateScore(checks);
|
|
7761
|
+
let keywords;
|
|
7762
|
+
if (options.jobDescription) {
|
|
7763
|
+
keywords = matchJobDescription(resume, options.jobDescription, language);
|
|
7764
|
+
}
|
|
7765
|
+
const finalScore = calculateCombinedScore(genericScore, keywords?.matchPercentage);
|
|
7766
|
+
const rating = scoreToRating(finalScore);
|
|
7767
|
+
const summary = generateSummary(finalScore, rating, !!keywords);
|
|
7768
|
+
return {
|
|
7769
|
+
score: finalScore,
|
|
7770
|
+
rating,
|
|
7771
|
+
checks,
|
|
7772
|
+
keywords,
|
|
7773
|
+
summary
|
|
7774
|
+
};
|
|
7775
|
+
}
|
|
7776
|
+
|
|
6824
7777
|
// src/commands/validate.ts
|
|
7778
|
+
function formatAtsReport(result, debug, chalk6) {
|
|
7779
|
+
const scoreColor = result.score >= 75 ? chalk6.green : result.score >= 60 ? chalk6.yellow : chalk6.red;
|
|
7780
|
+
console.log("");
|
|
7781
|
+
console.log(chalk6.bold("\u2550\u2550\u2550 ATS Analysis Report \u2550\u2550\u2550"));
|
|
7782
|
+
console.log("");
|
|
7783
|
+
console.log(` Score: ${scoreColor(chalk6.bold(`${result.score}/100`))} (${result.rating.replace("-", " ")})`);
|
|
7784
|
+
console.log(` ${result.summary}`);
|
|
7785
|
+
console.log("");
|
|
7786
|
+
const categories = {};
|
|
7787
|
+
for (const check of result.checks) {
|
|
7788
|
+
const list = categories[check.category];
|
|
7789
|
+
if (!list) {
|
|
7790
|
+
categories[check.category] = [check];
|
|
7791
|
+
} else {
|
|
7792
|
+
list.push(check);
|
|
7793
|
+
}
|
|
7794
|
+
}
|
|
7795
|
+
const categoryLabels = {
|
|
7796
|
+
contact: "Contact Information",
|
|
7797
|
+
content: "Content Quality",
|
|
7798
|
+
structure: "Resume Structure",
|
|
7799
|
+
keywords: "Keywords"
|
|
7800
|
+
};
|
|
7801
|
+
for (const [cat, checks] of Object.entries(categories)) {
|
|
7802
|
+
const label = categoryLabels[cat] || cat;
|
|
7803
|
+
console.log(chalk6.bold(` ${label}`));
|
|
7804
|
+
for (const check of checks) {
|
|
7805
|
+
if (!debug && check.passed) continue;
|
|
7806
|
+
const icon = check.passed ? chalk6.green("\u2713") : chalk6.red("\u2717");
|
|
7807
|
+
const scoreText = chalk6.dim(`[${check.score}]`);
|
|
7808
|
+
console.log(` ${icon} ${check.message} ${scoreText}`);
|
|
7809
|
+
if (!check.passed && check.suggestion) {
|
|
7810
|
+
console.log(chalk6.dim(` \u2192 ${check.suggestion}`));
|
|
7811
|
+
}
|
|
7812
|
+
}
|
|
7813
|
+
console.log("");
|
|
7814
|
+
}
|
|
7815
|
+
if (result.keywords) {
|
|
7816
|
+
console.log(chalk6.bold(" Job Description Match"));
|
|
7817
|
+
const kw = result.keywords;
|
|
7818
|
+
const matchColor = kw.matchPercentage >= 70 ? chalk6.green : kw.matchPercentage >= 50 ? chalk6.yellow : chalk6.red;
|
|
7819
|
+
console.log(` Match: ${matchColor(`${kw.matchPercentage}%`)} (${kw.matched.length}/${kw.matched.length + kw.missing.length} keywords)`);
|
|
7820
|
+
if (kw.matched.length > 0) {
|
|
7821
|
+
console.log(chalk6.green(` \u2713 Matched: ${kw.matched.join(", ")}`));
|
|
7822
|
+
}
|
|
7823
|
+
if (kw.missing.length > 0) {
|
|
7824
|
+
console.log(chalk6.red(` \u2717 Missing: ${kw.missing.join(", ")}`));
|
|
7825
|
+
console.log(chalk6.dim(" \u2192 Consider incorporating these keywords into your resume where relevant."));
|
|
7826
|
+
}
|
|
7827
|
+
console.log("");
|
|
7828
|
+
}
|
|
7829
|
+
console.log(chalk6.dim("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"));
|
|
7830
|
+
}
|
|
6825
7831
|
async function validateAction(options) {
|
|
6826
7832
|
const chalk6 = (await import("chalk")).default;
|
|
6827
7833
|
console.log(chalk6.blue("Starting resuml validate..."));
|
|
@@ -6829,13 +7835,41 @@ async function validateAction(options) {
|
|
|
6829
7835
|
const inputPath = options.resume;
|
|
6830
7836
|
const { yamlContents } = await loadResumeFiles(inputPath);
|
|
6831
7837
|
console.log(chalk6.blue("Validating resume data..."));
|
|
7838
|
+
let resumeData;
|
|
6832
7839
|
try {
|
|
6833
|
-
await processResumeData(yamlContents);
|
|
7840
|
+
resumeData = await processResumeData(yamlContents);
|
|
6834
7841
|
console.log(chalk6.green("\u2713 Resume data is valid against the schema!"));
|
|
6835
7842
|
} catch (error) {
|
|
6836
7843
|
handleCommandError(error, "validate", options.debug);
|
|
6837
7844
|
return;
|
|
6838
7845
|
}
|
|
7846
|
+
if (options.ats) {
|
|
7847
|
+
console.log(chalk6.blue("Running ATS analysis..."));
|
|
7848
|
+
let jobDescription;
|
|
7849
|
+
if (options.jd) {
|
|
7850
|
+
try {
|
|
7851
|
+
jobDescription = import_fs2.default.readFileSync(options.jd, "utf8");
|
|
7852
|
+
} catch {
|
|
7853
|
+
console.error(chalk6.red(`Failed to read job description file: ${options.jd}`));
|
|
7854
|
+
return;
|
|
7855
|
+
}
|
|
7856
|
+
}
|
|
7857
|
+
const result = analyzeAts(resumeData, {
|
|
7858
|
+
language: "en",
|
|
7859
|
+
jobDescription
|
|
7860
|
+
});
|
|
7861
|
+
if (options.format === "json") {
|
|
7862
|
+
console.log(JSON.stringify(result, null, 2));
|
|
7863
|
+
} else {
|
|
7864
|
+
formatAtsReport(result, !!options.debug, chalk6);
|
|
7865
|
+
}
|
|
7866
|
+
const threshold = options.atsThreshold ? parseInt(options.atsThreshold, 10) : void 0;
|
|
7867
|
+
if (threshold !== void 0 && result.score < threshold) {
|
|
7868
|
+
console.error(chalk6.red(`
|
|
7869
|
+
ATS score ${result.score} is below threshold ${threshold}.`));
|
|
7870
|
+
process.exit(1);
|
|
7871
|
+
}
|
|
7872
|
+
}
|
|
6839
7873
|
} catch (error) {
|
|
6840
7874
|
handleCommandError(error, "validate", options.debug);
|
|
6841
7875
|
}
|
|
@@ -6843,7 +7877,7 @@ async function validateAction(options) {
|
|
|
6843
7877
|
|
|
6844
7878
|
// src/commands/tojson.ts
|
|
6845
7879
|
init_cjs_shims();
|
|
6846
|
-
var
|
|
7880
|
+
var import_fs3 = __toESM(require("fs"), 1);
|
|
6847
7881
|
async function toJsonAction(options) {
|
|
6848
7882
|
const chalk6 = (await import("chalk")).default;
|
|
6849
7883
|
console.log(chalk6.blue("Starting resuml tojson..."));
|
|
@@ -6854,7 +7888,7 @@ async function toJsonAction(options) {
|
|
|
6854
7888
|
const resumeData = await processResumeData(yamlContents);
|
|
6855
7889
|
console.log(chalk6.green("Processing and validation successful!"));
|
|
6856
7890
|
const jsonOutput = JSON.stringify(resumeData, null, 2);
|
|
6857
|
-
|
|
7891
|
+
import_fs3.default.writeFileSync(options.output, jsonOutput, "utf8");
|
|
6858
7892
|
console.log(chalk6.green(`Successfully wrote output to ${options.output}`));
|
|
6859
7893
|
} catch (error) {
|
|
6860
7894
|
handleCommandError(error, "tojson", options.debug);
|
|
@@ -6863,15 +7897,15 @@ async function toJsonAction(options) {
|
|
|
6863
7897
|
|
|
6864
7898
|
// src/commands/render.ts
|
|
6865
7899
|
init_cjs_shims();
|
|
6866
|
-
var
|
|
6867
|
-
var import_node_path2 = __toESM(require("path"));
|
|
7900
|
+
var import_fs4 = __toESM(require("fs"), 1);
|
|
7901
|
+
var import_node_path2 = __toESM(require("path"), 1);
|
|
6868
7902
|
|
|
6869
7903
|
// src/utils/themeLoader.ts
|
|
6870
7904
|
init_cjs_shims();
|
|
6871
7905
|
var import_child_process = require("child_process");
|
|
6872
7906
|
var import_module = require("module");
|
|
6873
7907
|
var require2 = (0, import_module.createRequire)(importMetaUrl);
|
|
6874
|
-
|
|
7908
|
+
function installTheme(packageName) {
|
|
6875
7909
|
try {
|
|
6876
7910
|
(0, import_child_process.execFileSync)("npm", ["install", packageName], {
|
|
6877
7911
|
stdio: ["inherit", "pipe", "pipe"],
|
|
@@ -6881,7 +7915,7 @@ async function installTheme(packageName) {
|
|
|
6881
7915
|
throw new Error(`Failed to install ${packageName}: ${error.message}`);
|
|
6882
7916
|
}
|
|
6883
7917
|
}
|
|
6884
|
-
|
|
7918
|
+
function loadTheme(themeName, options) {
|
|
6885
7919
|
let jsonResumeThemeName;
|
|
6886
7920
|
let nativeThemeName;
|
|
6887
7921
|
const autoInstall = options?.autoInstall !== false;
|
|
@@ -6902,7 +7936,7 @@ Please install the theme package manually.`
|
|
|
6902
7936
|
}
|
|
6903
7937
|
console.log(`\u{1F4E6} Theme ${jsonResumeThemeName} not found. Installing...`);
|
|
6904
7938
|
try {
|
|
6905
|
-
|
|
7939
|
+
installTheme(jsonResumeThemeName);
|
|
6906
7940
|
console.log(`\u2705 Successfully installed ${jsonResumeThemeName}`);
|
|
6907
7941
|
return require2(jsonResumeThemeName);
|
|
6908
7942
|
} catch (installError) {
|
|
@@ -6921,7 +7955,7 @@ Please install the theme package manually.`
|
|
|
6921
7955
|
}
|
|
6922
7956
|
|
|
6923
7957
|
// src/commands/render.ts
|
|
6924
|
-
var import_chalk = __toESM(require("chalk"));
|
|
7958
|
+
var import_chalk = __toESM(require("chalk"), 1);
|
|
6925
7959
|
async function renderAction(options) {
|
|
6926
7960
|
if (!options.theme) {
|
|
6927
7961
|
throw new Error(
|
|
@@ -6935,15 +7969,39 @@ async function renderAction(options) {
|
|
|
6935
7969
|
console.log(import_chalk.default.blue("Processing and validating resume data..."));
|
|
6936
7970
|
const resumeData = await processResumeData(yamlContents);
|
|
6937
7971
|
console.log(import_chalk.default.green("Resume data processing and validation successful!"));
|
|
6938
|
-
const theme =
|
|
7972
|
+
const theme = loadTheme(options.theme);
|
|
6939
7973
|
const htmlOutput = await theme.render(resumeData, {
|
|
6940
7974
|
locale: options.language
|
|
6941
7975
|
});
|
|
6942
|
-
const
|
|
6943
|
-
|
|
6944
|
-
|
|
6945
|
-
|
|
6946
|
-
|
|
7976
|
+
const defaultExtension = options.format;
|
|
7977
|
+
const defaultFilename = `resume.${defaultExtension}`;
|
|
7978
|
+
const outputPath = options.output || defaultFilename;
|
|
7979
|
+
if (options.format === "pdf") {
|
|
7980
|
+
console.log(import_chalk.default.blue(`Generating PDF output at ${outputPath}...`));
|
|
7981
|
+
const { chromium } = await import("playwright");
|
|
7982
|
+
const browser = await chromium.launch();
|
|
7983
|
+
const page = await browser.newPage();
|
|
7984
|
+
await page.setContent(htmlOutput, { waitUntil: "networkidle" });
|
|
7985
|
+
const pdfBuffer = await page.pdf({
|
|
7986
|
+
path: outputPath,
|
|
7987
|
+
format: "A4",
|
|
7988
|
+
printBackground: true,
|
|
7989
|
+
margin: {
|
|
7990
|
+
top: "1cm",
|
|
7991
|
+
right: "1cm",
|
|
7992
|
+
bottom: "1cm",
|
|
7993
|
+
left: "1cm"
|
|
7994
|
+
}
|
|
7995
|
+
});
|
|
7996
|
+
await browser.close();
|
|
7997
|
+
import_fs4.default.writeFileSync(outputPath, pdfBuffer);
|
|
7998
|
+
console.log(import_chalk.default.green(`Successfully wrote PDF output to ${outputPath}`));
|
|
7999
|
+
} else {
|
|
8000
|
+
console.log(import_chalk.default.blue(`Writing HTML output to ${outputPath}...`));
|
|
8001
|
+
import_fs4.default.mkdirSync(import_node_path2.default.dirname(outputPath), { recursive: true });
|
|
8002
|
+
import_fs4.default.writeFileSync(outputPath, htmlOutput, "utf8");
|
|
8003
|
+
console.log(import_chalk.default.green(`Successfully wrote HTML output to ${outputPath}`));
|
|
8004
|
+
}
|
|
6947
8005
|
} catch (error) {
|
|
6948
8006
|
handleCommandError(error, "render", options.debug);
|
|
6949
8007
|
}
|
|
@@ -6951,9 +8009,9 @@ async function renderAction(options) {
|
|
|
6951
8009
|
|
|
6952
8010
|
// src/commands/dev.ts
|
|
6953
8011
|
init_cjs_shims();
|
|
6954
|
-
var
|
|
6955
|
-
var import_node_path3 = __toESM(require("path"));
|
|
6956
|
-
var import_chalk2 = __toESM(require("chalk"));
|
|
8012
|
+
var import_fs5 = __toESM(require("fs"), 1);
|
|
8013
|
+
var import_node_path3 = __toESM(require("path"), 1);
|
|
8014
|
+
var import_chalk2 = __toESM(require("chalk"), 1);
|
|
6957
8015
|
async function devAction(options) {
|
|
6958
8016
|
if (!options.theme) {
|
|
6959
8017
|
throw new Error(
|
|
@@ -6970,10 +8028,14 @@ async function devAction(options) {
|
|
|
6970
8028
|
await renderResume(options);
|
|
6971
8029
|
console.log(import_chalk2.default.green(`\u{1F680} Development server running at http://localhost:${port}`));
|
|
6972
8030
|
console.log(import_chalk2.default.blue("Watching for file changes..."));
|
|
6973
|
-
if (
|
|
6974
|
-
watchDirectory(inputPath, () =>
|
|
6975
|
-
|
|
6976
|
-
|
|
8031
|
+
if (import_fs5.default.existsSync(inputPath) && import_fs5.default.statSync(inputPath).isDirectory()) {
|
|
8032
|
+
watchDirectory(inputPath, () => {
|
|
8033
|
+
void renderResume(options);
|
|
8034
|
+
});
|
|
8035
|
+
} else if (import_fs5.default.existsSync(inputPath)) {
|
|
8036
|
+
watchFile(inputPath, () => {
|
|
8037
|
+
void renderResume(options);
|
|
8038
|
+
});
|
|
6977
8039
|
}
|
|
6978
8040
|
await startDevServer(port);
|
|
6979
8041
|
} catch (error) {
|
|
@@ -6989,20 +8051,20 @@ async function renderResume(options) {
|
|
|
6989
8051
|
const { yamlContents } = await loadResumeFiles(inputPath);
|
|
6990
8052
|
console.log(import_chalk2.default.blue("\u{1F504} Processing resume data..."));
|
|
6991
8053
|
const resumeData = await processResumeData(yamlContents);
|
|
6992
|
-
const theme =
|
|
8054
|
+
const theme = loadTheme(options.theme ?? "stackoverflow");
|
|
6993
8055
|
const htmlOutput = await theme.render(resumeData, {
|
|
6994
8056
|
locale: options.language
|
|
6995
8057
|
});
|
|
6996
8058
|
const outputPath = import_node_path3.default.join(process.cwd(), ".resuml-dev", "index.html");
|
|
6997
|
-
|
|
6998
|
-
|
|
8059
|
+
import_fs5.default.mkdirSync(import_node_path3.default.dirname(outputPath), { recursive: true });
|
|
8060
|
+
import_fs5.default.writeFileSync(outputPath, htmlOutput, "utf8");
|
|
6999
8061
|
console.log(import_chalk2.default.green("\u2705 Resume updated!"));
|
|
7000
8062
|
} catch (error) {
|
|
7001
8063
|
console.error(import_chalk2.default.red("\u274C Error rendering resume:"), error.message);
|
|
7002
8064
|
}
|
|
7003
8065
|
}
|
|
7004
8066
|
function watchDirectory(dirPath, callback) {
|
|
7005
|
-
|
|
8067
|
+
import_fs5.default.watch(dirPath, { recursive: true }, (_eventType, filename) => {
|
|
7006
8068
|
if (filename && (filename.endsWith(".yaml") || filename.endsWith(".yml"))) {
|
|
7007
8069
|
console.log(import_chalk2.default.blue(`\u{1F4C1} File changed: ${filename}`));
|
|
7008
8070
|
callback();
|
|
@@ -7010,7 +8072,7 @@ function watchDirectory(dirPath, callback) {
|
|
|
7010
8072
|
});
|
|
7011
8073
|
}
|
|
7012
8074
|
function watchFile(filePath, callback) {
|
|
7013
|
-
|
|
8075
|
+
import_fs5.default.watch(filePath, (eventType) => {
|
|
7014
8076
|
if (eventType === "change") {
|
|
7015
8077
|
console.log(import_chalk2.default.blue(`\u{1F4C4} File changed: ${import_node_path3.default.basename(filePath)}`));
|
|
7016
8078
|
callback();
|
|
@@ -7025,8 +8087,8 @@ async function startDevServer(port) {
|
|
|
7025
8087
|
const pathname = parsedUrl.pathname || "/";
|
|
7026
8088
|
if (pathname === "/" || pathname === "/index.html") {
|
|
7027
8089
|
const htmlPath = import_node_path3.default.join(process.cwd(), ".resuml-dev", "index.html");
|
|
7028
|
-
if (
|
|
7029
|
-
const html =
|
|
8090
|
+
if (import_fs5.default.existsSync(htmlPath)) {
|
|
8091
|
+
const html = import_fs5.default.readFileSync(htmlPath, "utf8");
|
|
7030
8092
|
const liveReloadScript = `
|
|
7031
8093
|
<script>
|
|
7032
8094
|
setInterval(() => {
|
|
@@ -7060,10 +8122,10 @@ async function startDevServer(port) {
|
|
|
7060
8122
|
|
|
7061
8123
|
// src/commands/init.ts
|
|
7062
8124
|
init_cjs_shims();
|
|
7063
|
-
var
|
|
7064
|
-
var import_path2 = __toESM(require("path"));
|
|
7065
|
-
var import_readline = __toESM(require("readline"));
|
|
7066
|
-
var import_chalk3 = __toESM(require("chalk"));
|
|
8125
|
+
var import_fs6 = __toESM(require("fs"), 1);
|
|
8126
|
+
var import_path2 = __toESM(require("path"), 1);
|
|
8127
|
+
var import_readline = __toESM(require("readline"), 1);
|
|
8128
|
+
var import_chalk3 = __toESM(require("chalk"), 1);
|
|
7067
8129
|
function createReadlineInterface() {
|
|
7068
8130
|
return import_readline.default.createInterface({
|
|
7069
8131
|
input: process.stdin,
|
|
@@ -7221,7 +8283,7 @@ async function initAction(options) {
|
|
|
7221
8283
|
const fullPath = import_path2.default.resolve(outputPath);
|
|
7222
8284
|
const rl = createReadlineInterface();
|
|
7223
8285
|
try {
|
|
7224
|
-
if (
|
|
8286
|
+
if (import_fs6.default.existsSync(fullPath)) {
|
|
7225
8287
|
const overwrite = await ask(
|
|
7226
8288
|
rl,
|
|
7227
8289
|
`${import_chalk3.default.yellow("\u26A0")} ${outputPath} already exists. Overwrite? (y/N)`,
|
|
@@ -7237,8 +8299,8 @@ async function initAction(options) {
|
|
|
7237
8299
|
const email = await ask(rl, "Email address", "john@example.com");
|
|
7238
8300
|
const label = await ask(rl, "Professional title/label", "Software Engineer");
|
|
7239
8301
|
const yaml = generateResumeYaml(name, email, label);
|
|
7240
|
-
|
|
7241
|
-
|
|
8302
|
+
import_fs6.default.mkdirSync(import_path2.default.dirname(fullPath), { recursive: true });
|
|
8303
|
+
import_fs6.default.writeFileSync(fullPath, yaml, "utf8");
|
|
7242
8304
|
console.log(import_chalk3.default.green(`
|
|
7243
8305
|
\u2705 Created ${outputPath}`));
|
|
7244
8306
|
console.log(import_chalk3.default.blue("\nNext steps:"));
|
|
@@ -7252,18 +8314,17 @@ async function initAction(options) {
|
|
|
7252
8314
|
|
|
7253
8315
|
// src/commands/pdf.ts
|
|
7254
8316
|
init_cjs_shims();
|
|
7255
|
-
var
|
|
7256
|
-
var import_node_path4 = __toESM(require("path"));
|
|
7257
|
-
var import_chalk4 = __toESM(require("chalk"));
|
|
7258
|
-
async function
|
|
8317
|
+
var import_fs7 = __toESM(require("fs"), 1);
|
|
8318
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
8319
|
+
var import_chalk4 = __toESM(require("chalk"), 1);
|
|
8320
|
+
async function loadPlaywright() {
|
|
7259
8321
|
try {
|
|
7260
|
-
const
|
|
7261
|
-
return
|
|
8322
|
+
const { chromium } = await import("playwright");
|
|
8323
|
+
return chromium;
|
|
7262
8324
|
} catch {
|
|
7263
8325
|
throw new Error(
|
|
7264
|
-
`
|
|
7265
|
-
Install it with: ${import_chalk4.default.cyan("npm install
|
|
7266
|
-
Or for a smaller download: ${import_chalk4.default.cyan("npm install puppeteer-core")}`
|
|
8326
|
+
`Playwright is required for PDF export but is not installed.
|
|
8327
|
+
Install it with: ${import_chalk4.default.cyan("npm install playwright")}`
|
|
7267
8328
|
);
|
|
7268
8329
|
}
|
|
7269
8330
|
}
|
|
@@ -7271,13 +8332,13 @@ function parseMargin(margin) {
|
|
|
7271
8332
|
const defaultMargin = { top: "10mm", right: "10mm", bottom: "10mm", left: "10mm" };
|
|
7272
8333
|
if (!margin) return defaultMargin;
|
|
7273
8334
|
const parts = margin.split(",").map((s) => s.trim());
|
|
7274
|
-
if (parts.length === 1) {
|
|
8335
|
+
if (parts.length === 1 && parts[0]) {
|
|
7275
8336
|
return { top: parts[0], right: parts[0], bottom: parts[0], left: parts[0] };
|
|
7276
8337
|
}
|
|
7277
|
-
if (parts.length === 2) {
|
|
8338
|
+
if (parts.length === 2 && parts[0] && parts[1]) {
|
|
7278
8339
|
return { top: parts[0], right: parts[1], bottom: parts[0], left: parts[1] };
|
|
7279
8340
|
}
|
|
7280
|
-
if (parts.length === 4) {
|
|
8341
|
+
if (parts.length === 4 && parts[0] && parts[1] && parts[2] && parts[3]) {
|
|
7281
8342
|
return { top: parts[0], right: parts[1], bottom: parts[2], left: parts[3] };
|
|
7282
8343
|
}
|
|
7283
8344
|
return defaultMargin;
|
|
@@ -7295,28 +8356,28 @@ async function pdfAction(options) {
|
|
|
7295
8356
|
console.log(import_chalk4.default.blue("Processing and validating resume data..."));
|
|
7296
8357
|
const resumeData = await processResumeData(yamlContents);
|
|
7297
8358
|
console.log(import_chalk4.default.green("Resume data processing and validation successful!"));
|
|
7298
|
-
const theme =
|
|
8359
|
+
const theme = loadTheme(options.theme);
|
|
7299
8360
|
const htmlOutput = await theme.render(resumeData, {
|
|
7300
8361
|
locale: options.language
|
|
7301
8362
|
});
|
|
7302
|
-
console.log(import_chalk4.default.blue("Loading
|
|
7303
|
-
const
|
|
8363
|
+
console.log(import_chalk4.default.blue("Loading Playwright..."));
|
|
8364
|
+
const chromium = await loadPlaywright();
|
|
7304
8365
|
const outputPath = options.output || "resume.pdf";
|
|
7305
8366
|
const format = options.format === "Letter" ? "Letter" : "A4";
|
|
7306
8367
|
const margin = parseMargin(options.margin);
|
|
7307
8368
|
console.log(import_chalk4.default.blue(`Generating PDF (${format} format)...`));
|
|
7308
|
-
const browser = await
|
|
8369
|
+
const browser = await chromium.launch({ headless: true });
|
|
7309
8370
|
try {
|
|
7310
8371
|
const page = await browser.newPage();
|
|
7311
|
-
await page.setContent(htmlOutput, { waitUntil: "
|
|
8372
|
+
await page.setContent(htmlOutput, { waitUntil: "networkidle" });
|
|
7312
8373
|
const pdfBuffer = await page.pdf({
|
|
7313
8374
|
format,
|
|
7314
8375
|
margin,
|
|
7315
8376
|
printBackground: true,
|
|
7316
8377
|
preferCSSPageSize: true
|
|
7317
8378
|
});
|
|
7318
|
-
|
|
7319
|
-
|
|
8379
|
+
import_fs7.default.mkdirSync(import_node_path4.default.dirname(import_node_path4.default.resolve(outputPath)), { recursive: true });
|
|
8380
|
+
import_fs7.default.writeFileSync(outputPath, pdfBuffer);
|
|
7320
8381
|
console.log(import_chalk4.default.green(`\u2705 Successfully generated ${outputPath}`));
|
|
7321
8382
|
} finally {
|
|
7322
8383
|
await browser.close();
|
|
@@ -7328,7 +8389,7 @@ async function pdfAction(options) {
|
|
|
7328
8389
|
|
|
7329
8390
|
// src/commands/themes.ts
|
|
7330
8391
|
init_cjs_shims();
|
|
7331
|
-
var import_chalk5 = __toESM(require("chalk"));
|
|
8392
|
+
var import_chalk5 = __toESM(require("chalk"), 1);
|
|
7332
8393
|
var import_child_process2 = require("child_process");
|
|
7333
8394
|
var import_module2 = require("module");
|
|
7334
8395
|
var KNOWN_THEMES = [
|
|
@@ -7358,7 +8419,7 @@ function getInstalledVersion(pkg) {
|
|
|
7358
8419
|
try {
|
|
7359
8420
|
const require3 = (0, import_module2.createRequire)(process.cwd() + "/");
|
|
7360
8421
|
const pkgJson = require3(`${pkg}/package.json`);
|
|
7361
|
-
return pkgJson.version
|
|
8422
|
+
return pkgJson.version ?? null;
|
|
7362
8423
|
} catch {
|
|
7363
8424
|
return null;
|
|
7364
8425
|
}
|
|
@@ -7407,7 +8468,7 @@ Use it with: ${import_chalk5.default.cyan(`resuml render --theme ${known?.name |
|
|
|
7407
8468
|
`));
|
|
7408
8469
|
}
|
|
7409
8470
|
}
|
|
7410
|
-
|
|
8471
|
+
function themesAction(options) {
|
|
7411
8472
|
if (options.install) {
|
|
7412
8473
|
installTheme2(options.install);
|
|
7413
8474
|
} else {
|
|
@@ -7472,10 +8533,10 @@ function injectCss(html, css) {
|
|
|
7472
8533
|
var currentDir = import_path3.default.dirname((0, import_url.fileURLToPath)(importMetaUrl));
|
|
7473
8534
|
function getCliVersion() {
|
|
7474
8535
|
const packageJsonPath = import_path3.default.resolve(currentDir, "../package.json");
|
|
7475
|
-
if (
|
|
8536
|
+
if (import_fs8.default.existsSync(packageJsonPath)) {
|
|
7476
8537
|
try {
|
|
7477
|
-
const packageJson = JSON.parse(
|
|
7478
|
-
return packageJson.version
|
|
8538
|
+
const packageJson = JSON.parse(import_fs8.default.readFileSync(packageJsonPath, "utf8"));
|
|
8539
|
+
return packageJson.version ?? "0.0.0";
|
|
7479
8540
|
} catch {
|
|
7480
8541
|
return "0.0.0";
|
|
7481
8542
|
}
|
|
@@ -7484,29 +8545,30 @@ function getCliVersion() {
|
|
|
7484
8545
|
}
|
|
7485
8546
|
var program = new import_commander.Command();
|
|
7486
8547
|
program.name("resuml").description("CLI tool for managing resuml resume files.").version(getCliVersion());
|
|
7487
|
-
program.command("validate").description("Validates resume data against the schema.").option("-r, --resume <path>", "Input YAML file, directory, or glob pattern.").option("--debug", "Show detailed validation errors.").action(validateAction);
|
|
8548
|
+
program.command("validate").description("Validates resume data against the schema.").option("-r, --resume <path>", "Input YAML file, directory, or glob pattern.").option("--debug", "Show detailed validation errors.").option("--ats", "Run ATS (Applicant Tracking System) compatibility analysis.").option("--jd <path>", "Path to a job description file for keyword matching (requires --ats).").option("--ats-threshold <score>", "Minimum ATS score (0-100). Exit with code 1 if below threshold.").option("--format <type>", "Output format for ATS results (text or json).", "text").action(validateAction);
|
|
7488
8549
|
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);
|
|
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
|
|
8550
|
+
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 file path.").option("--format <type>", "Output format (html or pdf).", "html").option("--language <code>", "Language code for localization.", "en").option("--debug", "Show detailed validation and processing information.").action(renderAction);
|
|
7490
8551
|
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
8552
|
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
|
|
8553
|
+
program.command("pdf").description("Export resume as PDF using Playwright.").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
8554
|
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);
|
|
7494
|
-
if (process.env
|
|
7495
|
-
(async () => {
|
|
8555
|
+
if (process.env["NODE_ENV"] !== "test") {
|
|
8556
|
+
void (async () => {
|
|
7496
8557
|
try {
|
|
7497
8558
|
await program.parseAsync(process.argv);
|
|
7498
8559
|
} catch (e) {
|
|
7499
|
-
console.error("Command line error:", e
|
|
8560
|
+
console.error("Command line error:", e.message);
|
|
7500
8561
|
process.exit(1);
|
|
7501
8562
|
}
|
|
7502
8563
|
})();
|
|
7503
8564
|
}
|
|
7504
8565
|
// Annotate the CommonJS export names for ESM import in node:
|
|
7505
8566
|
0 && (module.exports = {
|
|
8567
|
+
analyzeAts,
|
|
7506
8568
|
loadResumeFiles,
|
|
7507
8569
|
loadTheme,
|
|
7508
8570
|
processResumeData,
|
|
7509
8571
|
program,
|
|
7510
8572
|
themeRender
|
|
7511
8573
|
});
|
|
7512
|
-
//# sourceMappingURL=index.
|
|
8574
|
+
//# sourceMappingURL=index.cjs.map
|