@cenk1cenk2/md-printer 2.21.0 → 3.0.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.
Files changed (80) hide show
  1. package/README.md +332 -48
  2. package/dist/_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorate.mjs +1 -2
  3. package/dist/_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorateMetadata.mjs +1 -2
  4. package/dist/_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorateParam.mjs +8 -0
  5. package/dist/commands/index.mjs +133 -295
  6. package/dist/components/Date.svelte +1 -0
  7. package/dist/components/Markdown.svelte +20 -0
  8. package/dist/components/Nodes.svelte +32 -0
  9. package/dist/components/Page.svelte +20 -0
  10. package/dist/components/PageBreak.svelte +5 -0
  11. package/dist/components/PageNumber.svelte +1 -0
  12. package/dist/components/SignatureBlock.svelte +56 -0
  13. package/dist/components/Title.svelte +1 -0
  14. package/dist/components/TotalPages.svelte +1 -0
  15. package/dist/components/index.ts +8 -0
  16. package/dist/constants/file.constants.mjs +1 -8
  17. package/dist/constants/index.mjs +3 -4
  18. package/dist/constants/template.constants.mjs +48 -10
  19. package/dist/interfaces/commands/index.mjs +1 -1
  20. package/dist/interfaces/commands/run.interface.mjs +1 -1
  21. package/dist/interfaces/index.mjs +1 -1
  22. package/dist/interfaces/markdown.interface.mjs +1 -0
  23. package/dist/interfaces/renderer.interface.mjs +1 -0
  24. package/dist/interfaces/session.interface.mjs +1 -0
  25. package/dist/interfaces/signature.interface.mjs +1 -1
  26. package/dist/interfaces/template.interface.mjs +1 -0
  27. package/dist/services/i18n.service.mjs +4 -8
  28. package/dist/services/index.mjs +9 -2
  29. package/dist/services/loopback.mjs +18 -0
  30. package/dist/services/markdown.service.mjs +123 -0
  31. package/dist/services/printer.module.mjs +41 -0
  32. package/dist/services/printer.service.mjs +171 -0
  33. package/dist/services/renderer/browser.mjs +41 -0
  34. package/dist/services/renderer/browser.service.mjs +56 -0
  35. package/dist/services/renderer/renderer.service.mjs +198 -0
  36. package/dist/services/session/Preview.svelte +238 -0
  37. package/dist/services/session/preview.service.mjs +187 -0
  38. package/dist/services/session/session.service.mjs +115 -0
  39. package/dist/services/signature/adapters/a-trust.adapter.mjs +27 -37
  40. package/dist/services/signature/index.mjs +1 -2
  41. package/dist/services/signature/signature.adapter.mjs +1 -2
  42. package/dist/services/signature/signature.service.mjs +1 -3
  43. package/dist/services/template/Document.svelte +21 -0
  44. package/dist/services/template/Margin.svelte +15 -0
  45. package/dist/services/template/assets.mjs +127 -0
  46. package/dist/services/template/render.entry.ts +32 -0
  47. package/dist/services/template/svelte.plugin.mjs +66 -0
  48. package/dist/services/template/template.service.mjs +211 -0
  49. package/oclif.manifest.json +45 -34
  50. package/package.json +64 -31
  51. package/templates/default/Template.svelte +83 -0
  52. package/templates/default/settings.json +1 -3
  53. package/templates/invoice/Template.svelte +247 -0
  54. package/templates/invoice/components/Client.svelte +42 -0
  55. package/templates/invoice/components/Company.svelte +41 -0
  56. package/templates/invoice/components/Items.svelte +66 -0
  57. package/templates/invoice/components/Notes.svelte +21 -0
  58. package/templates/invoice/components/Payment.svelte +25 -0
  59. package/templates/invoice/components/Signature.svelte +34 -0
  60. package/templates/invoice/components/Totals.svelte +47 -0
  61. package/templates/invoice/round.js +2 -0
  62. package/templates/invoice/settings.json +1 -4
  63. package/templates/kilic.dev/Template.svelte +102 -0
  64. package/templates/kilic.dev/settings.json +1 -3
  65. package/templates/mail/Template.svelte +166 -0
  66. package/templates/mail/settings.json +1 -3
  67. package/dist/hooks/not-found.hook.mjs +0 -7
  68. package/dist/hooks/update-notifier.hook.mjs +0 -7
  69. package/dist/interfaces/pupeteer.mjs +0 -1
  70. package/templates/default/main.css +0 -73
  71. package/templates/invoice/.gitignore +0 -1
  72. package/templates/invoice/footer.html +0 -18
  73. package/templates/invoice/tailwind.css +0 -164
  74. package/templates/invoice/template.html.j2 +0 -226
  75. package/templates/kilic.dev/footer.html +0 -26
  76. package/templates/kilic.dev/header.html +0 -16
  77. package/templates/kilic.dev/main.css +0 -74
  78. package/templates/mail/.gitignore +0 -1
  79. package/templates/mail/tailwind.css +0 -145
  80. package/templates/mail/template.html.j2 +0 -14
@@ -0,0 +1,211 @@
1
+ import "../../constants/template.constants.mjs";
2
+ import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorateMetadata.mjs";
3
+ import __decorate from "../../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorate.mjs";
4
+ import { inlineCss, inlineHtml } from "./assets.mjs";
5
+ import { sveltePlugin } from "./svelte.plugin.mjs";
6
+ import { dirname, isAbsolute, join, resolve } from "path";
7
+ import { FileSystemService } from "@cenk1cenk2/oclif-common";
8
+ import { Injectable } from "@nestjs/common";
9
+ import { fileURLToPath } from "url";
10
+ import { homedir } from "os";
11
+ import { compile } from "@tailwindcss/node";
12
+ import { Scanner } from "@tailwindcss/oxide";
13
+ import { kebabCase } from "change-case";
14
+ import enhancedResolve from "enhanced-resolve";
15
+ import { decodeHTML } from "entities";
16
+ import { readFileSync } from "fs";
17
+ import { createRequire } from "module";
18
+ import { rolldown } from "rolldown";
19
+ import { render } from "svelte/server";
20
+ //#region src/services/template/template.service.ts
21
+ var _TemplateService;
22
+ let TemplateService = class TemplateService {
23
+ static {
24
+ _TemplateService = this;
25
+ }
26
+ fs;
27
+ static ROOT = fileURLToPath(new URL("../../../", import.meta.url));
28
+ static COMPONENTS = fileURLToPath(new URL(`../../components/index.ts`, import.meta.url));
29
+ static ENTRY = fileURLToPath(new URL("./render.entry.ts", import.meta.url));
30
+ require = createRequire(_TemplateService.ROOT);
31
+ stylesheets = enhancedResolve.create.sync({
32
+ extensions: [".css"],
33
+ mainFields: ["style"],
34
+ conditionNames: ["style"]
35
+ });
36
+ modules = enhancedResolve.create.sync({
37
+ extensions: [
38
+ ".js",
39
+ ".json",
40
+ ".node",
41
+ ".ts"
42
+ ],
43
+ conditionNames: ["node", "import"]
44
+ });
45
+ constructor(fs) {
46
+ this.fs = fs;
47
+ }
48
+ resolve(template) {
49
+ const path = template.replace(/^~(?=\/|$)/, homedir());
50
+ const directory = isAbsolute(path) || path.startsWith(".") || /[\\/]/.test(path) ? resolve(path) : join(_TemplateService.ROOT, "templates", path);
51
+ if (!this.fs.exists(join(directory, "Template.svelte"))) throw new Error(`Template does not exist, expected Template.svelte in: ${directory}`);
52
+ return directory;
53
+ }
54
+ async settings(directory) {
55
+ const file = join(directory, "settings.json");
56
+ if (!this.fs.exists(file)) return {};
57
+ return JSON.parse(await this.fs.read(file));
58
+ }
59
+ async bundle(directory) {
60
+ const stylesheets = [];
61
+ const { module: entry, modules } = await this.compile(_TemplateService.ENTRY, join(directory, "Template.svelte"), stylesheets);
62
+ return {
63
+ entry,
64
+ modules,
65
+ stylesheets,
66
+ directives: new Map(Object.keys(entry.components).map((name) => [kebabCase(name), name]))
67
+ };
68
+ }
69
+ async page(file) {
70
+ const { module } = await this.compile(file, file, []);
71
+ return `<!doctype html>${render(module.default).body}`;
72
+ }
73
+ async render(directory, bundle, document, markdown, options) {
74
+ const context = [
75
+ ["md-printer:document", document],
76
+ ["md-printer:markdown", markdown],
77
+ ["md-printer:components", bundle.entry.components]
78
+ ];
79
+ const props = {
80
+ ...document,
81
+ content: bundle.entry.content(markdown, context)
82
+ };
83
+ const [body, header, footer] = await Promise.all([
84
+ "body",
85
+ "header",
86
+ "footer"
87
+ ].map((mode) => bundle.entry.part(props, [...context, ["md-printer:mode", mode]])));
88
+ const dependencies = [];
89
+ const cache = /* @__PURE__ */ new Map();
90
+ const css = `<style>${await this.css(directory, bundle, [
91
+ body,
92
+ header,
93
+ footer
94
+ ].map((part) => part.body).join(""), options.highlight, dependencies)}</style>`;
95
+ const extracted = body.head.match(/<title>([\s\S]*?)<\/title>/)?.[1];
96
+ const title = options.title ?? (extracted && decodeHTML(extracted)) ?? options.fallbackTitle;
97
+ const head = body.head.replace(/<title>[\s\S]*?<\/title>/, "");
98
+ const styles = [...head.matchAll(/<style[^>]*>[\s\S]*?<\/style>/g)].map(([style]) => style).join("") + css;
99
+ return {
100
+ html: bundle.entry.document({
101
+ lang: options.language,
102
+ title,
103
+ head: head + css,
104
+ body: body.body
105
+ }),
106
+ header: await this.margin(bundle, header, styles, directory, cache, dependencies),
107
+ footer: await this.margin(bundle, footer, styles, directory, cache, dependencies),
108
+ dependencies
109
+ };
110
+ }
111
+ async compile(input, template, stylesheets) {
112
+ const build = await rolldown({
113
+ input,
114
+ platform: "node",
115
+ logLevel: "silent",
116
+ plugins: [sveltePlugin({
117
+ template,
118
+ components: _TemplateService.COMPONENTS,
119
+ root: _TemplateService.ROOT,
120
+ stylesheets
121
+ })]
122
+ });
123
+ try {
124
+ const { output: [chunk] } = await build.generate({
125
+ format: "esm",
126
+ sourcemap: "inline"
127
+ });
128
+ return {
129
+ module: await import(`data:text/javascript;base64,${Buffer.from(chunk.code).toString("base64")}`),
130
+ modules: chunk.moduleIds.filter((id) => isAbsolute(id))
131
+ };
132
+ } finally {
133
+ await build.close();
134
+ }
135
+ }
136
+ async margin(bundle, part, styles, directory, cache, dependencies) {
137
+ if (!part.body.replace(/<!--[\s\S]*?-->/g, "").trim()) return;
138
+ const { content, assets } = await inlineHtml(bundle.entry.margin({
139
+ styles,
140
+ body: part.body
141
+ }), directory, {
142
+ remote: true,
143
+ cache
144
+ });
145
+ dependencies.push(...assets);
146
+ return content;
147
+ }
148
+ async css(directory, bundle, html, highlight, dependencies) {
149
+ const theme = `:root { ${readFileSync(this.highlightTheme(highlight), "utf8")} pre:has(> code.hljs) { padding: 0; background: transparent; } }`;
150
+ const compiler = await compile([theme, ...bundle.stylesheets.map(({ source }) => source)].join("\n"), {
151
+ base: directory,
152
+ from: bundle.stylesheets[0]?.file ?? join(directory, "Template.svelte"),
153
+ shouldRewriteUrls: true,
154
+ onDependency: (path) => dependencies.push(path),
155
+ customCssResolver: async (id, base) => this.resolveFrom(this.stylesheets, id, [
156
+ base,
157
+ directory,
158
+ _TemplateService.ROOT
159
+ ]),
160
+ customJsResolver: async (id, base) => this.resolveFrom(this.modules, id, [
161
+ base,
162
+ directory,
163
+ _TemplateService.ROOT
164
+ ])
165
+ });
166
+ const scanner = new Scanner({ sources: [
167
+ ...compiler.sources.map(({ base, pattern, negated }) => ({
168
+ base,
169
+ pattern,
170
+ negated
171
+ })),
172
+ {
173
+ base: directory,
174
+ pattern: "**/*",
175
+ negated: false
176
+ },
177
+ {
178
+ base: dirname(_TemplateService.COMPONENTS),
179
+ pattern: "**/*",
180
+ negated: false
181
+ }
182
+ ] });
183
+ const { content, assets } = await inlineCss(compiler.build([...scanner.scan(), ...scanner.scanFiles([{
184
+ content: html,
185
+ extension: "html"
186
+ }])]), directory);
187
+ dependencies.push(...assets);
188
+ return content;
189
+ }
190
+ /**
191
+ * Tries every base in turn, since a template directory usually has no `node_modules` and falls back to md-printer's own dependencies.
192
+ */
193
+ resolveFrom(resolver, id, bases) {
194
+ for (const base of bases) try {
195
+ const resolved = resolver(base, id);
196
+ if (resolved) return resolved;
197
+ } catch {
198
+ continue;
199
+ }
200
+ }
201
+ highlightTheme(name) {
202
+ try {
203
+ return this.require.resolve(`highlight.js/styles/${name}.css`);
204
+ } catch {
205
+ throw new Error(`Unknown highlight style "${name}", see the files in ${dirname(this.require.resolve("highlight.js/styles/github.css"))}.`);
206
+ }
207
+ }
208
+ };
209
+ TemplateService = _TemplateService = __decorate([Injectable(), __decorateMetadata("design:paramtypes", [typeof FileSystemService === "undefined" ? Object : FileSystemService])], TemplateService);
210
+ //#endregion
211
+ export { TemplateService };
@@ -4,16 +4,16 @@
4
4
  "aliases": [],
5
5
  "args": {
6
6
  "file": {
7
- "description": "File to be processed.",
7
+ "description": "Markdown or yaml file to render.",
8
8
  "name": "file"
9
9
  },
10
10
  "output": {
11
- "description": "Output file that will be generated. Overwrites the one define in front-matter.",
11
+ "description": "Output file. Overwrites the one defined in front-matter.",
12
12
  "name": "output",
13
13
  "required": false
14
14
  }
15
15
  },
16
- "description": "Generates a PDF from the given markdown file with the selected HTML template.",
16
+ "description": "Renders a markdown or yaml file through a Svelte template into a PDF or HTML document.",
17
17
  "flags": {
18
18
  "log-level": {
19
19
  "description": "Set the log level of the application.",
@@ -57,20 +57,14 @@
57
57
  "stdin": {
58
58
  "char": "I",
59
59
  "description": "Read the input from stdin.",
60
- "exclusive": [
61
- "file"
62
- ],
63
60
  "name": "stdin",
64
- "required": false,
65
- "hasDynamicHelp": false,
66
- "multiple": false,
67
- "type": "option"
61
+ "allowNo": false,
62
+ "type": "boolean"
68
63
  },
69
64
  "input-filetype": {
70
65
  "char": "f",
71
- "description": "File type to be processed. By default it is detected by the file extension.",
66
+ "description": "Input file type. Detected from the file extension, markdown for stdin and unknown extensions.",
72
67
  "name": "input-filetype",
73
- "default": "md",
74
68
  "hasDynamicHelp": false,
75
69
  "multiple": false,
76
70
  "options": [
@@ -82,9 +76,8 @@
82
76
  },
83
77
  "output-filetype": {
84
78
  "char": "F",
85
- "description": "File type to be processed. By default it is detected by the file extension.",
79
+ "description": "Output file type, defaults to pdf. Overwrites the one defined in front-matter.",
86
80
  "name": "output-filetype",
87
- "default": "pdf",
88
81
  "hasDynamicHelp": false,
89
82
  "multiple": false,
90
83
  "options": [
@@ -95,23 +88,22 @@
95
88
  },
96
89
  "stdout": {
97
90
  "char": "O",
98
- "description": "Write to stdout instead of a file.",
91
+ "description": "Write the output to stdout instead of a file.",
99
92
  "name": "stdout",
100
93
  "allowNo": false,
101
94
  "type": "boolean"
102
95
  },
103
96
  "template": {
104
97
  "char": "t",
105
- "description": "HTML template for the generated PDF file.",
98
+ "description": "Built-in template name or path to a template directory, defaults to \"default\". Overwrites the one defined in front-matter.",
106
99
  "name": "template",
107
- "default": "default",
108
100
  "hasDynamicHelp": false,
109
101
  "multiple": false,
110
102
  "type": "option"
111
103
  },
112
104
  "title": {
113
105
  "char": "T",
114
- "description": "Overwrite document title.",
106
+ "description": "Document title. Overwrites the one defined in front-matter or the template.",
115
107
  "name": "title",
116
108
  "hasDynamicHelp": false,
117
109
  "multiple": false,
@@ -119,7 +111,7 @@
119
111
  },
120
112
  "language": {
121
113
  "char": "l",
122
- "description": "Language code for template translations. Overwrites the one defined in front-matter and template settings.",
114
+ "description": "Language for template translations. Overwrites the one defined in front-matter and template settings.",
123
115
  "name": "language",
124
116
  "hasDynamicHelp": false,
125
117
  "multiple": false,
@@ -127,31 +119,50 @@
127
119
  },
128
120
  "browser": {
129
121
  "char": "b",
130
- "description": "Browser path that is going to be used for the PDF generation.",
122
+ "description": "Browser executable used for printing. Discovered automatically when omitted (Brave, Chrome, Chromium, Edge).",
131
123
  "name": "browser",
132
- "default": "/usr/bin/brave",
133
124
  "hasDynamicHelp": false,
134
125
  "multiple": false,
135
126
  "type": "option"
136
127
  },
137
- "watch": {
138
- "char": "w",
139
- "description": "Watch the changes on the given file.",
140
- "name": "watch",
128
+ "continuous": {
129
+ "description": "Render the PDF as a single continuous page without page breaks.",
130
+ "name": "continuous",
141
131
  "allowNo": false,
142
132
  "type": "boolean"
143
133
  },
144
- "dev": {
145
- "char": "d",
146
- "description": "Run with Chrome browser instead of publishing the file.",
147
- "name": "dev",
134
+ "preview": {
135
+ "char": "p",
136
+ "description": "Rebuild whenever the input, the template or its assets change, show the HTML and the PDF in a live preview and rewrite the output file when there is one.",
137
+ "name": "preview",
148
138
  "allowNo": false,
149
139
  "type": "boolean"
150
140
  },
151
- "continuous": {
152
- "description": "Render PDF as a single continuous page without page breaks.",
153
- "name": "continuous",
154
- "allowNo": false,
141
+ "host": {
142
+ "description": "Loopback host for the preview server, it serves the files next to the input and is never exposed to the network.",
143
+ "name": "host",
144
+ "default": "127.0.0.1",
145
+ "hasDynamicHelp": false,
146
+ "multiple": false,
147
+ "options": [
148
+ "127.0.0.1",
149
+ "localhost",
150
+ "::1"
151
+ ],
152
+ "type": "option"
153
+ },
154
+ "port": {
155
+ "description": "Port for the preview server, random when 0.",
156
+ "name": "port",
157
+ "default": 0,
158
+ "hasDynamicHelp": false,
159
+ "multiple": false,
160
+ "type": "option"
161
+ },
162
+ "open": {
163
+ "description": "Open the preview window, --no-open keeps rebuilding and writing without one.",
164
+ "name": "open",
165
+ "allowNo": true,
155
166
  "type": "boolean"
156
167
  },
157
168
  "sign": {
@@ -185,5 +196,5 @@
185
196
  "enableJsonFlag": false
186
197
  }
187
198
  },
188
- "version": "2.21.0"
199
+ "version": "3.0.0"
189
200
  }
package/package.json CHANGED
@@ -1,12 +1,11 @@
1
1
  {
2
2
  "name": "@cenk1cenk2/md-printer",
3
- "version": "2.21.0",
4
- "description": "A markdown printer.",
5
- "module": "dist/index.mjs",
3
+ "version": "3.0.0",
4
+ "description": "Render markdown or yaml through Svelte templates into PDF or HTML with Puppeteer.",
6
5
  "type": "module",
7
6
  "repository": {
8
7
  "type": "git",
9
- "url": "https://gitlab.kilic.dev/utils/md-printer"
8
+ "url": "https://gitlab.kilic.dev/utils/md-printer.git"
10
9
  },
11
10
  "author": "Cenk Kilic",
12
11
  "license": "MIT",
@@ -17,7 +16,6 @@
17
16
  "access": "public"
18
17
  },
19
18
  "files": [
20
- "/config",
21
19
  "/bin",
22
20
  "/dist",
23
21
  "/oclif.manifest.json",
@@ -33,46 +31,73 @@
33
31
  "plugins": [
34
32
  "@oclif/plugin-help"
35
33
  ],
36
- "hooks": {
37
- "init": [
38
- "./dist/hooks/update-notifier.hook"
39
- ],
40
- "command_not_found": "./dist/hooks/not-found.hook"
41
- },
42
34
  "topicSeparator": " "
43
35
  },
44
36
  "engines": {
45
- "node": ">=24.0.0"
37
+ "node": ">=24.15.0"
46
38
  },
47
39
  "keywords": [
40
+ "markdown",
41
+ "pdf",
42
+ "svelte",
43
+ "tailwind",
44
+ "puppeteer",
45
+ "invoice",
46
+ "cli",
48
47
  "oclif",
49
48
  "cenk1cenk2"
50
49
  ],
51
50
  "dependencies": {
52
- "@cenk1cenk2/oclif-common": "^7.1.0",
51
+ "@cenk1cenk2/oclif-common": "^7.2.0",
52
+ "@fontsource/montserrat": "^5.3.0",
53
53
  "@listr2/manager": "^4.3.1",
54
54
  "@nestjs/common": "^12.1.2",
55
55
  "@oclif/core": "^5.1.2",
56
56
  "@oclif/plugin-help": "^7.0.2",
57
57
  "@signpdf/placeholder-plain": "^3.3.0",
58
58
  "@signpdf/utils": "^3.3.0",
59
- "@tailwindcss/forms": "^0.5.11",
60
- "@tailwindcss/postcss": "^4.3.3",
59
+ "@tailwindcss/node": "^4.3.3",
60
+ "@tailwindcss/oxide": "^4.3.3",
61
61
  "@tailwindcss/typography": "^0.5.20",
62
+ "change-case": "^5.4.4",
62
63
  "chokidar": "^5.0.0",
64
+ "enhanced-resolve": "^5.26.0",
65
+ "entities": "^8.1.0",
63
66
  "fs-extra": "^11.4.1",
64
- "get-port": "^7.2.0",
65
- "gray-matter": "^4.0.3",
67
+ "github-markdown-css": "^5.9.0",
68
+ "hast-util-from-html": "^2.0.3",
69
+ "hast-util-to-html": "^9.0.5",
70
+ "highlight.js": "^11.12.0",
66
71
  "i18next": "^26.4.2",
72
+ "lightningcss": "^1.33.0",
67
73
  "listr2": "^11.2.0",
68
- "md-to-pdf": "^5.2.5",
69
- "nunjucks": "^3.2.4",
70
- "postcss": "^8.5.29",
71
- "puppeteer": "^25.12.0",
74
+ "lowlight": "^3.3.0",
75
+ "mime": "^4.1.1",
76
+ "perfect-debounce": "^2.1.0",
77
+ "property-information": "^7.2.0",
78
+ "puppeteer-core": "^25.13.0",
79
+ "raw-body": "^4.0.0",
80
+ "rehype-highlight": "^7.0.2",
81
+ "rehype-raw": "^7.0.0",
82
+ "rehype-slug": "^6.0.0",
83
+ "remark-directive": "^4.0.0",
84
+ "remark-frontmatter": "^5.0.0",
85
+ "remark-gfm": "^4.0.1",
86
+ "remark-parse": "^11.0.0",
87
+ "remark-rehype": "^11.1.2",
88
+ "rolldown": "^1.2.13",
72
89
  "rxjs": "^7.8.2",
73
- "showdown": "^2.1.0",
90
+ "serve-static": "^2.2.1",
74
91
  "source-map-support": "^0.5.21",
92
+ "srcset": "^5.0.3",
93
+ "svelte": "^5.57.2",
75
94
  "tailwindcss": "^4.3.3",
95
+ "unified": "^11.0.5",
96
+ "unist-util-visit": "^5.1.0",
97
+ "vfile": "^6.0.3",
98
+ "vfile-matter": "^5.0.1",
99
+ "which": "^7.0.0",
100
+ "write-file-atomic": "^8.0.0",
76
101
  "yaml": "^2.9.1"
77
102
  },
78
103
  "devDependencies": {
@@ -80,36 +105,44 @@
80
105
  "@cenk1cenk2/eslint-config": "^3.3.9",
81
106
  "@tsconfig/node24": "^24.0.5",
82
107
  "@types/fs-extra": "^11.0.4",
108
+ "@types/hast": "^3.0.5",
109
+ "@types/mdast": "^4.0.4",
83
110
  "@types/node": "^24.19.1",
84
- "@types/nunjucks": "^3.2.6",
85
- "@types/showdown": "^2.0.6",
111
+ "@types/serve-static": "^2.2.0",
112
+ "@types/which": "^3.0.4",
113
+ "@types/write-file-atomic": "^4.0.3",
86
114
  "eslint": "^10.12.0",
115
+ "eslint-plugin-svelte": "^3.23.1",
87
116
  "execa": "^10.1.0",
88
- "globby": "^16.2.4",
89
117
  "oclif": "^6.0.2",
90
118
  "prettier": "^3.9.9",
91
- "prettier-plugin-jinja-template": "^2.2.0",
92
- "theme-colors": "^0.1.0",
93
- "tpm": "^1.4.14",
119
+ "prettier-plugin-svelte": "^4.1.1",
120
+ "svelte-eslint-parser": "^1.9.0",
94
121
  "ts-node": "^10.9.2",
95
122
  "tsconfig-paths": "^4.2.0",
96
123
  "tsdown": "^0.23.0",
97
- "typescript": "^6.0.3"
124
+ "typescript": "^6.0.3",
125
+ "vite": "^8.3.4",
126
+ "vitest": "^5.0.4"
98
127
  },
99
128
  "config": {
100
129
  "commitizen": {
101
130
  "path": "./node_modules/@cenk1cenk2/cz-cc"
102
131
  }
103
132
  },
133
+ "bugs": {
134
+ "url": "https://gitlab.kilic.dev/utils/md-printer/-/issues"
135
+ },
136
+ "homepage": "https://gitlab.kilic.dev/utils/md-printer",
104
137
  "scripts": {
105
138
  "dev": "./bin/dev.js",
106
139
  "start": "./bin/run.js",
107
140
  "build": "tsdown",
108
141
  "dev:start": "tsdown --watch src/",
109
- "clean": "rimraf oclif.manifest.json",
110
142
  "format": "prettier --write src/ --log-level warn && eslint --fix",
111
143
  "lint": "eslint",
112
144
  "manifest": "oclif manifest",
113
- "docs:toc": "oclif readme"
145
+ "typecheck": "tsc --noEmit",
146
+ "test": "vitest run"
114
147
  }
115
148
  }
@@ -0,0 +1,83 @@
1
+ <script>
2
+ import { Markdown, Page } from '@cenk1cenk2/md-printer/components'
3
+
4
+ let { data } = $props()
5
+ </script>
6
+
7
+ <svelte:head>
8
+ {#if data.documentTitle}
9
+ <title>{data.documentTitle}</title>
10
+ {/if}
11
+ </svelte:head>
12
+
13
+ <Page>
14
+ <Markdown />
15
+ </Page>
16
+
17
+ <style lang="postcss">
18
+ @import 'github-markdown-css/github-markdown-light.css';
19
+ @import '@fontsource/montserrat/latin-400.css';
20
+ @import '@fontsource/montserrat/latin-ext-400.css';
21
+ @import '@fontsource/montserrat/latin-700.css';
22
+ @import '@fontsource/montserrat/latin-ext-700.css';
23
+ @import '@fontsource/montserrat/latin-800.css';
24
+ @import '@fontsource/montserrat/latin-ext-800.css';
25
+
26
+ .markdown-body {
27
+ font-size: 11px;
28
+ font-family: 'Montserrat', sans-serif;
29
+ }
30
+
31
+ .markdown-body h1,
32
+ .markdown-body h2 {
33
+ font-weight: 800;
34
+ }
35
+
36
+ .markdown-body h3,
37
+ .markdown-body h4,
38
+ .markdown-body h5,
39
+ .markdown-body h6,
40
+ .markdown-body strong,
41
+ .markdown-body b {
42
+ font-weight: 700;
43
+ }
44
+
45
+ .markdown-body pre > code {
46
+ white-space: pre-wrap;
47
+ padding: 0;
48
+ margin: 0;
49
+ }
50
+
51
+ .markdown-body .document-title-header {
52
+ height: 500px;
53
+ margin: auto auto;
54
+ padding-top: 50%;
55
+ break-after: page;
56
+ border-bottom: 0;
57
+ font-size: 2.5em;
58
+ }
59
+
60
+ .markdown-body pre {
61
+ padding: 12px 8px;
62
+ }
63
+
64
+ .markdown-body output pre {
65
+ margin-top: -36px;
66
+ border-top-left-radius: 0;
67
+ border-top-right-radius: 0;
68
+ border-top: 2px solid #d1d9e0;
69
+ }
70
+
71
+ .markdown-body output::before {
72
+ padding: 4px 16px;
73
+ position: relative;
74
+ top: -24px;
75
+ border-top-left-radius: 4px;
76
+ border-top-right-radius: 4px;
77
+ border-top: 2px solid #d1d9e0;
78
+ color: #59636e;
79
+ background-color: #f6f8fa;
80
+ content: '> output';
81
+ font-size: 0.85em;
82
+ }
83
+ </style>
@@ -1,7 +1,5 @@
1
1
  {
2
- "body_class": ["markdown-body"],
3
- "highlight_style": "atom-one-dark",
4
- "pdf_options": {
2
+ "pdfOptions": {
5
3
  "format": "A4",
6
4
  "margin": "18mm 12mm",
7
5
  "printBackground": true