resuml 1.2.5 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +144 -58
- package/dist/api.js +36 -37
- package/dist/api.js.map +1 -1
- package/dist/index.js +447 -88
- package/dist/index.js.map +1 -1
- package/package.json +45 -21
package/README.md
CHANGED
|
@@ -1,6 +1,60 @@
|
|
|
1
|
-
|
|
1
|
+
<h1 align="center">✨ Resuml</h1>
|
|
2
|
+
<p align="center"><strong>Write your resume in YAML. Render it beautifully.</strong></p>
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
<p align="center">
|
|
5
|
+
<a href="https://www.npmjs.com/package/resuml"><img src="https://img.shields.io/npm/v/resuml.svg" alt="npm version"></a>
|
|
6
|
+
<a href="https://www.npmjs.com/package/resuml"><img src="https://img.shields.io/npm/dm/resuml.svg" alt="npm downloads"></a>
|
|
7
|
+
<a href="https://github.com/phoinixi/resuml/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/resuml.svg" alt="license"></a>
|
|
8
|
+
<a href="https://github.com/phoinixi/resuml"><img src="https://img.shields.io/github/stars/phoinixi/resuml.svg?style=social" alt="GitHub stars"></a>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://www.buymeacoffee.com/leekbeds55j">
|
|
13
|
+
<img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" width="150" />
|
|
14
|
+
</a>
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
### YAML in → Beautiful resume out
|
|
20
|
+
|
|
21
|
+
```yaml
|
|
22
|
+
# resume.yaml
|
|
23
|
+
basics:
|
|
24
|
+
name: Jane Smith
|
|
25
|
+
label: Senior Software Engineer
|
|
26
|
+
email: jane@example.com
|
|
27
|
+
summary: >-
|
|
28
|
+
Passionate engineer with 8+ years
|
|
29
|
+
building scalable distributed systems.
|
|
30
|
+
work:
|
|
31
|
+
- name: Acme Corp
|
|
32
|
+
position: Lead Engineer
|
|
33
|
+
startDate: 2020-01-15
|
|
34
|
+
highlights:
|
|
35
|
+
- Reduced deploy time by 60%
|
|
36
|
+
- Led team of 12 engineers
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
resuml render --resume resume.yaml --theme stackoverflow --output resume.html
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Your YAML becomes a polished, professional resume — ready to share, print, or export to PDF.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Why YAML?
|
|
48
|
+
|
|
49
|
+
| | YAML | JSON |
|
|
50
|
+
|---|---|---|
|
|
51
|
+
| **Comments** | ✅ `# explain your choices` | ❌ Not supported |
|
|
52
|
+
| **Multi-line strings** | ✅ `summary: >-` block syntax | ❌ Escape everything |
|
|
53
|
+
| **Readability** | ✅ Clean, minimal syntax | ⚠️ Brackets & quotes everywhere |
|
|
54
|
+
| **Diffing** | ✅ Clean git diffs | ⚠️ Noisy diffs |
|
|
55
|
+
| **Compatibility** | ✅ Valid JSON Resume schema | ✅ Native |
|
|
56
|
+
|
|
57
|
+
YAML is a superset of JSON — your resume stays fully compatible with the [JSON Resume](https://jsonresume.org/) ecosystem while being far more pleasant to write and maintain.
|
|
4
58
|
|
|
5
59
|
## Prerequisites
|
|
6
60
|
|
|
@@ -29,44 +83,48 @@ npm install -g resuml
|
|
|
29
83
|
resuml render --resume resume.yaml --theme stackoverflow --output resume.html
|
|
30
84
|
```
|
|
31
85
|
|
|
32
|
-
##
|
|
86
|
+
## Commands
|
|
33
87
|
|
|
34
|
-
|
|
88
|
+
| Command | Description |
|
|
89
|
+
|---------|-------------|
|
|
90
|
+
| `validate` | Validate resume data against the JSON Resume schema |
|
|
91
|
+
| `tojson` | Convert YAML resume data to JSON format |
|
|
92
|
+
| `render` | Render the resume using a specified theme |
|
|
93
|
+
| `dev` | Start a development server with hot-reload |
|
|
35
94
|
|
|
36
|
-
|
|
37
|
-
resuml validate --resume resume.yaml
|
|
38
|
-
```
|
|
95
|
+
## Options
|
|
39
96
|
|
|
40
|
-
|
|
97
|
+
| Option | Alias | Description |
|
|
98
|
+
|--------|-------|-------------|
|
|
99
|
+
| `--resume` | `-r` | Input YAML file(s) or directory |
|
|
100
|
+
| `--output` | `-o` | Output file path |
|
|
101
|
+
| `--theme` | `-t` | Theme to use for rendering |
|
|
102
|
+
| `--port` | `-p` | Port for dev server (default: 3000) |
|
|
103
|
+
| `--language` | | Language code for localization (default: `en`) |
|
|
104
|
+
| `--debug` | | Enable debug mode for detailed errors |
|
|
41
105
|
|
|
42
|
-
|
|
43
|
-
resuml tojson --resume resume.yaml --output resume.json
|
|
44
|
-
```
|
|
106
|
+
## Compatible Themes
|
|
45
107
|
|
|
46
|
-
|
|
108
|
+
Resuml supports themes from the JSON Resume ecosystem. Install a theme, then pass its name to `--theme`:
|
|
47
109
|
|
|
48
110
|
```bash
|
|
49
|
-
|
|
111
|
+
npm install jsonresume-theme-stackoverflow
|
|
112
|
+
resuml render --resume resume.yaml --theme stackoverflow
|
|
50
113
|
```
|
|
51
114
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
115
|
+
| Theme | Install | Style |
|
|
116
|
+
|-------|---------|-------|
|
|
117
|
+
| [stackoverflow](https://github.com/francoislaberge/jsonresume-theme-stackoverflow) | `npm i jsonresume-theme-stackoverflow` | Clean, professional |
|
|
118
|
+
| [elegant](https://github.com/mudassir0909/jsonresume-theme-elegant) | `npm i jsonresume-theme-elegant` | Modern, elegant |
|
|
119
|
+
| [kendall](https://github.com/LinuxBozo/jsonresume-theme-kendall) | `npm i jsonresume-theme-kendall` | Minimal, classic |
|
|
120
|
+
| [flat](https://github.com/erming/jsonresume-theme-flat) | `npm i jsonresume-theme-flat` | Flat design |
|
|
121
|
+
| [onepage](https://github.com/aonemd/jsonresume-theme-onepage) | `npm i jsonresume-theme-onepage` | Single page |
|
|
55
122
|
|
|
56
|
-
|
|
123
|
+
> Browse all themes at [jsonresume.org/themes](https://jsonresume.org/themes/) — any `jsonresume-theme-*` package works with resuml.
|
|
57
124
|
|
|
58
|
-
|
|
59
|
-
- `tojson` - Converts YAML resume data to JSON format
|
|
60
|
-
- `render` - Renders the resume using a specified theme
|
|
61
|
-
- `dev` - Starts a development server with hot-reload
|
|
62
|
-
|
|
63
|
-
## Options
|
|
125
|
+
## Examples
|
|
64
126
|
|
|
65
|
-
|
|
66
|
-
- `--output, -o` - Output file path
|
|
67
|
-
- `--theme, -t` - Theme to use for rendering
|
|
68
|
-
- `--port, -p` - Port for development server (default: 3000)
|
|
69
|
-
- `--debug` - Enable debug mode for detailed error messages
|
|
127
|
+
For detailed examples and usage instructions, see the [examples/README.md](examples/README.md) file.
|
|
70
128
|
|
|
71
129
|
## Example YAML Structure
|
|
72
130
|
|
|
@@ -91,24 +149,76 @@ work:
|
|
|
91
149
|
summary: Led development of...
|
|
92
150
|
```
|
|
93
151
|
|
|
94
|
-
##
|
|
152
|
+
## CI/CD: Auto-build on Push
|
|
95
153
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
154
|
+
Use GitHub Actions to automatically rebuild your resume when you push changes:
|
|
155
|
+
|
|
156
|
+
```yaml
|
|
157
|
+
# .github/workflows/resume.yml
|
|
158
|
+
name: Build Resume
|
|
159
|
+
|
|
160
|
+
on:
|
|
161
|
+
push:
|
|
162
|
+
paths: ['resume.yaml', 'resume/*.yaml']
|
|
163
|
+
|
|
164
|
+
jobs:
|
|
165
|
+
build:
|
|
166
|
+
runs-on: ubuntu-latest
|
|
167
|
+
steps:
|
|
168
|
+
- uses: actions/checkout@v4
|
|
169
|
+
|
|
170
|
+
- uses: actions/setup-node@v4
|
|
171
|
+
with:
|
|
172
|
+
node-version: 20
|
|
173
|
+
|
|
174
|
+
- run: npm install -g resuml
|
|
175
|
+
- run: npm install jsonresume-theme-stackoverflow
|
|
176
|
+
|
|
177
|
+
- run: resuml render --resume resume.yaml --theme stackoverflow --output resume.html
|
|
178
|
+
- run: resuml tojson --resume resume.yaml --output resume.json
|
|
179
|
+
|
|
180
|
+
- uses: actions/upload-artifact@v4
|
|
181
|
+
with:
|
|
182
|
+
name: resume
|
|
183
|
+
path: |
|
|
184
|
+
resume.html
|
|
185
|
+
resume.json
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Node.js API Usage
|
|
189
|
+
|
|
190
|
+
You can use resuml programmatically from Node.js:
|
|
191
|
+
|
|
192
|
+
```js
|
|
193
|
+
import {
|
|
194
|
+
processResumeData,
|
|
195
|
+
loadResumeFiles,
|
|
196
|
+
loadTheme,
|
|
197
|
+
themeRender
|
|
198
|
+
} from 'resuml';
|
|
199
|
+
|
|
200
|
+
// Load YAML files
|
|
201
|
+
const { yamlContents } = await loadResumeFiles('resume.yaml');
|
|
202
|
+
// Validate and merge
|
|
203
|
+
const resume = await processResumeData(yamlContents);
|
|
204
|
+
// Load a theme
|
|
205
|
+
const theme = await loadTheme('stackoverflow');
|
|
206
|
+
// Render HTML
|
|
207
|
+
const html = await theme.render(resume, { locale: 'en' });
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
See the CLI and API for more details.
|
|
99
211
|
|
|
100
212
|
## Troubleshooting
|
|
101
213
|
|
|
102
214
|
### Common Issues
|
|
103
215
|
|
|
104
216
|
1. **Validation Errors**
|
|
105
|
-
|
|
106
217
|
- Ensure your YAML follows the JSON Resume schema
|
|
107
218
|
- Check for proper indentation in your YAML file
|
|
108
219
|
- Verify all required fields are present
|
|
109
220
|
|
|
110
221
|
2. **Theme Rendering Issues**
|
|
111
|
-
|
|
112
222
|
- Make sure the theme is properly installed
|
|
113
223
|
- Check if all required theme dependencies are installed
|
|
114
224
|
- Try running with `--debug` flag for more information
|
|
@@ -125,27 +235,3 @@ Contributions are welcome! Please feel free to submit a Pull Request.
|
|
|
125
235
|
## License
|
|
126
236
|
|
|
127
237
|
ISC
|
|
128
|
-
|
|
129
|
-
## Node.js API Usage
|
|
130
|
-
|
|
131
|
-
You can use resuml programmatically from Node.js:
|
|
132
|
-
|
|
133
|
-
```js
|
|
134
|
-
import {
|
|
135
|
-
processResumeData,
|
|
136
|
-
loadResumeFiles,
|
|
137
|
-
loadTheme,
|
|
138
|
-
themeRender
|
|
139
|
-
} from 'resuml';
|
|
140
|
-
|
|
141
|
-
// Load YAML files
|
|
142
|
-
const { yamlContents } = await loadResumeFiles('resume.yaml');
|
|
143
|
-
// Validate and merge
|
|
144
|
-
const resume = await processResumeData(yamlContents);
|
|
145
|
-
// Load a theme
|
|
146
|
-
const theme = await loadTheme('stackoverflow');
|
|
147
|
-
// Render HTML
|
|
148
|
-
const html = await theme.render(resume, { locale: 'en' });
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
See the CLI and API for more details.
|
package/dist/api.js
CHANGED
|
@@ -38,7 +38,7 @@ var getImportMetaUrl, importMetaUrl;
|
|
|
38
38
|
var init_cjs_shims = __esm({
|
|
39
39
|
"node_modules/tsup/assets/cjs_shims.js"() {
|
|
40
40
|
"use strict";
|
|
41
|
-
getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.src
|
|
41
|
+
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;
|
|
42
42
|
importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
43
43
|
}
|
|
44
44
|
});
|
|
@@ -180,7 +180,7 @@ var require_brace_expansion = __commonJS({
|
|
|
180
180
|
var isSequence = isNumericSequence || isAlphaSequence;
|
|
181
181
|
var isOptions = m.body.indexOf(",") >= 0;
|
|
182
182
|
if (!isSequence && !isOptions) {
|
|
183
|
-
if (m.post.match(
|
|
183
|
+
if (m.post.match(/,(?!,).*\}/)) {
|
|
184
184
|
str = m.pre + "{" + m.body + escClose + m.post;
|
|
185
185
|
return expand2(str);
|
|
186
186
|
}
|
|
@@ -261,7 +261,7 @@ __export(themeLoader_exports, {
|
|
|
261
261
|
});
|
|
262
262
|
async function installTheme(packageName) {
|
|
263
263
|
try {
|
|
264
|
-
(0, import_child_process.
|
|
264
|
+
(0, import_child_process.execFileSync)("npm", ["install", packageName], {
|
|
265
265
|
stdio: ["inherit", "pipe", "pipe"],
|
|
266
266
|
encoding: "utf8"
|
|
267
267
|
});
|
|
@@ -1066,7 +1066,7 @@ var path = {
|
|
|
1066
1066
|
};
|
|
1067
1067
|
var sep = defaultPlatform === "win32" ? path.win32.sep : path.posix.sep;
|
|
1068
1068
|
minimatch.sep = sep;
|
|
1069
|
-
var GLOBSTAR = Symbol("globstar **");
|
|
1069
|
+
var GLOBSTAR = /* @__PURE__ */ Symbol("globstar **");
|
|
1070
1070
|
minimatch.GLOBSTAR = GLOBSTAR;
|
|
1071
1071
|
var qmark2 = "[^/]";
|
|
1072
1072
|
var star2 = qmark2 + "*?";
|
|
@@ -1771,7 +1771,6 @@ if (typeof AC === "undefined") {
|
|
|
1771
1771
|
};
|
|
1772
1772
|
}
|
|
1773
1773
|
var shouldWarn = (code) => !warned.has(code);
|
|
1774
|
-
var TYPE = Symbol("type");
|
|
1775
1774
|
var isPosInt = (n) => n && n === Math.floor(n) && n > 0 && isFinite(n);
|
|
1776
1775
|
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;
|
|
1777
1776
|
var ZeroArray = class extends Array {
|
|
@@ -3116,37 +3115,37 @@ var isStream = (s) => !!s && typeof s === "object" && (s instanceof Minipass ||
|
|
|
3116
3115
|
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
|
|
3117
3116
|
s.pipe !== import_node_stream.default.Writable.prototype.pipe;
|
|
3118
3117
|
var isWritable = (s) => !!s && typeof s === "object" && s instanceof import_node_events.EventEmitter && typeof s.write === "function" && typeof s.end === "function";
|
|
3119
|
-
var EOF = Symbol("EOF");
|
|
3120
|
-
var MAYBE_EMIT_END = Symbol("maybeEmitEnd");
|
|
3121
|
-
var EMITTED_END = Symbol("emittedEnd");
|
|
3122
|
-
var EMITTING_END = Symbol("emittingEnd");
|
|
3123
|
-
var EMITTED_ERROR = Symbol("emittedError");
|
|
3124
|
-
var CLOSED = Symbol("closed");
|
|
3125
|
-
var READ = Symbol("read");
|
|
3126
|
-
var FLUSH = Symbol("flush");
|
|
3127
|
-
var FLUSHCHUNK = Symbol("flushChunk");
|
|
3128
|
-
var ENCODING = Symbol("encoding");
|
|
3129
|
-
var DECODER = Symbol("decoder");
|
|
3130
|
-
var FLOWING = Symbol("flowing");
|
|
3131
|
-
var PAUSED = Symbol("paused");
|
|
3132
|
-
var RESUME = Symbol("resume");
|
|
3133
|
-
var BUFFER = Symbol("buffer");
|
|
3134
|
-
var PIPES = Symbol("pipes");
|
|
3135
|
-
var BUFFERLENGTH = Symbol("bufferLength");
|
|
3136
|
-
var BUFFERPUSH = Symbol("bufferPush");
|
|
3137
|
-
var BUFFERSHIFT = Symbol("bufferShift");
|
|
3138
|
-
var OBJECTMODE = Symbol("objectMode");
|
|
3139
|
-
var DESTROYED = Symbol("destroyed");
|
|
3140
|
-
var ERROR = Symbol("error");
|
|
3141
|
-
var EMITDATA = Symbol("emitData");
|
|
3142
|
-
var EMITEND = Symbol("emitEnd");
|
|
3143
|
-
var EMITEND2 = Symbol("emitEnd2");
|
|
3144
|
-
var ASYNC = Symbol("async");
|
|
3145
|
-
var ABORT = Symbol("abort");
|
|
3146
|
-
var ABORTED = Symbol("aborted");
|
|
3147
|
-
var SIGNAL = Symbol("signal");
|
|
3148
|
-
var DATALISTENERS = Symbol("dataListeners");
|
|
3149
|
-
var DISCARDED = Symbol("discarded");
|
|
3118
|
+
var EOF = /* @__PURE__ */ Symbol("EOF");
|
|
3119
|
+
var MAYBE_EMIT_END = /* @__PURE__ */ Symbol("maybeEmitEnd");
|
|
3120
|
+
var EMITTED_END = /* @__PURE__ */ Symbol("emittedEnd");
|
|
3121
|
+
var EMITTING_END = /* @__PURE__ */ Symbol("emittingEnd");
|
|
3122
|
+
var EMITTED_ERROR = /* @__PURE__ */ Symbol("emittedError");
|
|
3123
|
+
var CLOSED = /* @__PURE__ */ Symbol("closed");
|
|
3124
|
+
var READ = /* @__PURE__ */ Symbol("read");
|
|
3125
|
+
var FLUSH = /* @__PURE__ */ Symbol("flush");
|
|
3126
|
+
var FLUSHCHUNK = /* @__PURE__ */ Symbol("flushChunk");
|
|
3127
|
+
var ENCODING = /* @__PURE__ */ Symbol("encoding");
|
|
3128
|
+
var DECODER = /* @__PURE__ */ Symbol("decoder");
|
|
3129
|
+
var FLOWING = /* @__PURE__ */ Symbol("flowing");
|
|
3130
|
+
var PAUSED = /* @__PURE__ */ Symbol("paused");
|
|
3131
|
+
var RESUME = /* @__PURE__ */ Symbol("resume");
|
|
3132
|
+
var BUFFER = /* @__PURE__ */ Symbol("buffer");
|
|
3133
|
+
var PIPES = /* @__PURE__ */ Symbol("pipes");
|
|
3134
|
+
var BUFFERLENGTH = /* @__PURE__ */ Symbol("bufferLength");
|
|
3135
|
+
var BUFFERPUSH = /* @__PURE__ */ Symbol("bufferPush");
|
|
3136
|
+
var BUFFERSHIFT = /* @__PURE__ */ Symbol("bufferShift");
|
|
3137
|
+
var OBJECTMODE = /* @__PURE__ */ Symbol("objectMode");
|
|
3138
|
+
var DESTROYED = /* @__PURE__ */ Symbol("destroyed");
|
|
3139
|
+
var ERROR = /* @__PURE__ */ Symbol("error");
|
|
3140
|
+
var EMITDATA = /* @__PURE__ */ Symbol("emitData");
|
|
3141
|
+
var EMITEND = /* @__PURE__ */ Symbol("emitEnd");
|
|
3142
|
+
var EMITEND2 = /* @__PURE__ */ Symbol("emitEnd2");
|
|
3143
|
+
var ASYNC = /* @__PURE__ */ Symbol("async");
|
|
3144
|
+
var ABORT = /* @__PURE__ */ Symbol("abort");
|
|
3145
|
+
var ABORTED = /* @__PURE__ */ Symbol("aborted");
|
|
3146
|
+
var SIGNAL = /* @__PURE__ */ Symbol("signal");
|
|
3147
|
+
var DATALISTENERS = /* @__PURE__ */ Symbol("dataListeners");
|
|
3148
|
+
var DISCARDED = /* @__PURE__ */ Symbol("discarded");
|
|
3150
3149
|
var defer = (fn) => Promise.resolve().then(fn);
|
|
3151
3150
|
var nodefer = (fn) => fn();
|
|
3152
3151
|
var isEndish = (ev) => ev === "end" || ev === "finish" || ev === "prefinish";
|
|
@@ -4059,7 +4058,7 @@ var ChildrenCache = class extends LRUCache {
|
|
|
4059
4058
|
});
|
|
4060
4059
|
}
|
|
4061
4060
|
};
|
|
4062
|
-
var setAsCwd = Symbol("PathScurry setAsCwd");
|
|
4061
|
+
var setAsCwd = /* @__PURE__ */ Symbol("PathScurry setAsCwd");
|
|
4063
4062
|
var PathBase = class {
|
|
4064
4063
|
/**
|
|
4065
4064
|
* the basename of this path
|