@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.
- package/README.md +332 -48
- package/dist/_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorate.mjs +1 -2
- package/dist/_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorateMetadata.mjs +1 -2
- package/dist/_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorateParam.mjs +8 -0
- package/dist/commands/index.mjs +133 -295
- package/dist/components/Date.svelte +1 -0
- package/dist/components/Markdown.svelte +20 -0
- package/dist/components/Nodes.svelte +32 -0
- package/dist/components/Page.svelte +20 -0
- package/dist/components/PageBreak.svelte +5 -0
- package/dist/components/PageNumber.svelte +1 -0
- package/dist/components/SignatureBlock.svelte +56 -0
- package/dist/components/Title.svelte +1 -0
- package/dist/components/TotalPages.svelte +1 -0
- package/dist/components/index.ts +8 -0
- package/dist/constants/file.constants.mjs +1 -8
- package/dist/constants/index.mjs +3 -4
- package/dist/constants/template.constants.mjs +48 -10
- package/dist/interfaces/commands/index.mjs +1 -1
- package/dist/interfaces/commands/run.interface.mjs +1 -1
- package/dist/interfaces/index.mjs +1 -1
- package/dist/interfaces/markdown.interface.mjs +1 -0
- package/dist/interfaces/renderer.interface.mjs +1 -0
- package/dist/interfaces/session.interface.mjs +1 -0
- package/dist/interfaces/signature.interface.mjs +1 -1
- package/dist/interfaces/template.interface.mjs +1 -0
- package/dist/services/i18n.service.mjs +4 -8
- package/dist/services/index.mjs +9 -2
- package/dist/services/loopback.mjs +18 -0
- package/dist/services/markdown.service.mjs +123 -0
- package/dist/services/printer.module.mjs +41 -0
- package/dist/services/printer.service.mjs +171 -0
- package/dist/services/renderer/browser.mjs +41 -0
- package/dist/services/renderer/browser.service.mjs +56 -0
- package/dist/services/renderer/renderer.service.mjs +198 -0
- package/dist/services/session/Preview.svelte +238 -0
- package/dist/services/session/preview.service.mjs +187 -0
- package/dist/services/session/session.service.mjs +115 -0
- package/dist/services/signature/adapters/a-trust.adapter.mjs +27 -37
- package/dist/services/signature/index.mjs +1 -2
- package/dist/services/signature/signature.adapter.mjs +1 -2
- package/dist/services/signature/signature.service.mjs +1 -3
- package/dist/services/template/Document.svelte +21 -0
- package/dist/services/template/Margin.svelte +15 -0
- package/dist/services/template/assets.mjs +127 -0
- package/dist/services/template/render.entry.ts +32 -0
- package/dist/services/template/svelte.plugin.mjs +66 -0
- package/dist/services/template/template.service.mjs +211 -0
- package/oclif.manifest.json +45 -34
- package/package.json +64 -31
- package/templates/default/Template.svelte +83 -0
- package/templates/default/settings.json +1 -3
- package/templates/invoice/Template.svelte +247 -0
- package/templates/invoice/components/Client.svelte +42 -0
- package/templates/invoice/components/Company.svelte +41 -0
- package/templates/invoice/components/Items.svelte +66 -0
- package/templates/invoice/components/Notes.svelte +21 -0
- package/templates/invoice/components/Payment.svelte +25 -0
- package/templates/invoice/components/Signature.svelte +34 -0
- package/templates/invoice/components/Totals.svelte +47 -0
- package/templates/invoice/round.js +2 -0
- package/templates/invoice/settings.json +1 -4
- package/templates/kilic.dev/Template.svelte +102 -0
- package/templates/kilic.dev/settings.json +1 -3
- package/templates/mail/Template.svelte +166 -0
- package/templates/mail/settings.json +1 -3
- package/dist/hooks/not-found.hook.mjs +0 -7
- package/dist/hooks/update-notifier.hook.mjs +0 -7
- package/dist/interfaces/pupeteer.mjs +0 -1
- package/templates/default/main.css +0 -73
- package/templates/invoice/.gitignore +0 -1
- package/templates/invoice/footer.html +0 -18
- package/templates/invoice/tailwind.css +0 -164
- package/templates/invoice/template.html.j2 +0 -226
- package/templates/kilic.dev/footer.html +0 -26
- package/templates/kilic.dev/header.html +0 -16
- package/templates/kilic.dev/main.css +0 -74
- package/templates/mail/.gitignore +0 -1
- package/templates/mail/tailwind.css +0 -145
- package/templates/mail/template.html.j2 +0 -14
|
@@ -1,10 +1,4 @@
|
|
|
1
1
|
//#region src/constants/file.constants.ts
|
|
2
|
-
const OUTPUT_FILE_ACCEPTED_TYPES = [".pdf"];
|
|
3
|
-
const INPUT_FILE_ACCEPTED_TYPES = [
|
|
4
|
-
".md",
|
|
5
|
-
".yml",
|
|
6
|
-
".yaml"
|
|
7
|
-
];
|
|
8
2
|
let OutputFileType = /* @__PURE__ */ function(OutputFileType) {
|
|
9
3
|
OutputFileType["PDF"] = "pdf";
|
|
10
4
|
OutputFileType["HTML"] = "html";
|
|
@@ -16,6 +10,5 @@ let InputFileType = /* @__PURE__ */ function(InputFileType) {
|
|
|
16
10
|
InputFileType["YAML_SHORT"] = "yml";
|
|
17
11
|
return InputFileType;
|
|
18
12
|
}({});
|
|
19
|
-
|
|
20
13
|
//#endregion
|
|
21
|
-
export {
|
|
14
|
+
export { InputFileType, OutputFileType };
|
package/dist/constants/index.mjs
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { DEFAULT_LANGUAGE, I18N_ACCEPTED_TYPES,
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
export { DEFAULT_LANGUAGE, I18N_ACCEPTED_TYPES, I18N_DIRECTORY, INPUT_FILE_ACCEPTED_TYPES, InputFileType, OUTPUT_FILE_ACCEPTED_TYPES, OutputFileType, RequiredTemplateFiles, TEMPLATE_DIRECTORY, TemplateFiles };
|
|
1
|
+
import { ContextKey, DEFAULT_HIGHLIGHT_STYLE, DEFAULT_LANGUAGE, DEFAULT_PDF_OPTIONS, DEFAULT_TEMPLATE, DIRECTIVE_TAG, Directory, I18N_ACCEPTED_TYPES, MediaType, ModuleSpecifier, PAGE_BREAK_CLASS, PRINTER_MODULE_OPTIONS, RenderMode, TAILWIND_STYLE_LANG, TemplateFiles } from "./template.constants.mjs";
|
|
2
|
+
import { InputFileType, OutputFileType } from "./file.constants.mjs";
|
|
3
|
+
export { ContextKey, DEFAULT_HIGHLIGHT_STYLE, DEFAULT_LANGUAGE, DEFAULT_PDF_OPTIONS, DEFAULT_TEMPLATE, DIRECTIVE_TAG, Directory, I18N_ACCEPTED_TYPES, InputFileType, MediaType, ModuleSpecifier, OutputFileType, PAGE_BREAK_CLASS, PRINTER_MODULE_OPTIONS, RenderMode, TAILWIND_STYLE_LANG, TemplateFiles };
|
|
@@ -1,22 +1,60 @@
|
|
|
1
1
|
//#region src/constants/template.constants.ts
|
|
2
2
|
let TemplateFiles = /* @__PURE__ */ function(TemplateFiles) {
|
|
3
|
-
TemplateFiles["
|
|
4
|
-
TemplateFiles["HEADER"] = "header.html";
|
|
5
|
-
TemplateFiles["TEMPLATE"] = "template.html.j2";
|
|
6
|
-
TemplateFiles["TAILWIND_CSS"] = "tailwind.css";
|
|
7
|
-
TemplateFiles["CSS"] = "main.css";
|
|
3
|
+
TemplateFiles["TEMPLATE"] = "Template.svelte";
|
|
8
4
|
TemplateFiles["SETTINGS"] = "settings.json";
|
|
9
5
|
return TemplateFiles;
|
|
10
6
|
}({});
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
let RenderMode = /* @__PURE__ */ function(RenderMode) {
|
|
8
|
+
RenderMode["BODY"] = "body";
|
|
9
|
+
RenderMode["HEADER"] = "header";
|
|
10
|
+
RenderMode["FOOTER"] = "footer";
|
|
11
|
+
return RenderMode;
|
|
12
|
+
}({});
|
|
13
|
+
let MediaType = /* @__PURE__ */ function(MediaType) {
|
|
14
|
+
MediaType["SCREEN"] = "screen";
|
|
15
|
+
MediaType["PRINT"] = "print";
|
|
16
|
+
return MediaType;
|
|
17
|
+
}({});
|
|
18
|
+
let Directory = /* @__PURE__ */ function(Directory) {
|
|
19
|
+
Directory["TEMPLATES"] = "templates";
|
|
20
|
+
Directory["COMPONENTS"] = "components";
|
|
21
|
+
Directory["I18N"] = "i18n";
|
|
22
|
+
return Directory;
|
|
23
|
+
}({});
|
|
24
|
+
let ModuleSpecifier = /* @__PURE__ */ function(ModuleSpecifier) {
|
|
25
|
+
ModuleSpecifier["TEMPLATE"] = "md-printer:template";
|
|
26
|
+
ModuleSpecifier["COMPONENTS"] = "@cenk1cenk2/md-printer/components";
|
|
27
|
+
ModuleSpecifier["TEMPLATE_COMPONENTS"] = "md-printer:template-components";
|
|
28
|
+
return ModuleSpecifier;
|
|
29
|
+
}({});
|
|
30
|
+
let ContextKey = /* @__PURE__ */ function(ContextKey) {
|
|
31
|
+
ContextKey["RENDER_MODE"] = "md-printer:mode";
|
|
32
|
+
ContextKey["DOCUMENT"] = "md-printer:document";
|
|
33
|
+
ContextKey["MARKDOWN"] = "md-printer:markdown";
|
|
34
|
+
ContextKey["COMPONENTS"] = "md-printer:components";
|
|
35
|
+
return ContextKey;
|
|
36
|
+
}({});
|
|
37
|
+
const TAILWIND_STYLE_LANG = "postcss";
|
|
38
|
+
const PAGE_BREAK_CLASS = "page-break";
|
|
39
|
+
const DIRECTIVE_TAG = "md-printer-directive";
|
|
40
|
+
const PRINTER_MODULE_OPTIONS = Symbol("md-printer:options");
|
|
14
41
|
const I18N_ACCEPTED_TYPES = [
|
|
15
42
|
".yaml",
|
|
16
43
|
".yml",
|
|
17
44
|
".json"
|
|
18
45
|
];
|
|
19
46
|
const DEFAULT_LANGUAGE = "en";
|
|
20
|
-
|
|
47
|
+
const DEFAULT_TEMPLATE = "default";
|
|
48
|
+
const DEFAULT_HIGHLIGHT_STYLE = "atom-one-dark";
|
|
49
|
+
const DEFAULT_PDF_OPTIONS = {
|
|
50
|
+
format: "A4",
|
|
51
|
+
printBackground: true,
|
|
52
|
+
margin: {
|
|
53
|
+
top: "30mm",
|
|
54
|
+
right: "40mm",
|
|
55
|
+
bottom: "30mm",
|
|
56
|
+
left: "20mm"
|
|
57
|
+
}
|
|
58
|
+
};
|
|
21
59
|
//#endregion
|
|
22
|
-
export { DEFAULT_LANGUAGE, I18N_ACCEPTED_TYPES,
|
|
60
|
+
export { ContextKey, DEFAULT_HIGHLIGHT_STYLE, DEFAULT_LANGUAGE, DEFAULT_PDF_OPTIONS, DEFAULT_TEMPLATE, DIRECTIVE_TAG, Directory, I18N_ACCEPTED_TYPES, MediaType, ModuleSpecifier, PAGE_BREAK_CLASS, PRINTER_MODULE_OPTIONS, RenderMode, TAILWIND_STYLE_LANG, TemplateFiles };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { I18N_ACCEPTED_TYPES } from "../constants/template.constants.mjs";
|
|
2
2
|
import __decorateMetadata from "../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorateMetadata.mjs";
|
|
3
3
|
import __decorate from "../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorate.mjs";
|
|
4
4
|
import { basename, extname, join } from "path";
|
|
5
5
|
import { ConfigService, FileSystemService } from "@cenk1cenk2/oclif-common";
|
|
6
6
|
import { Injectable } from "@nestjs/common";
|
|
7
7
|
import i18next from "i18next";
|
|
8
|
-
|
|
9
8
|
//#region src/services/i18n.service.ts
|
|
10
9
|
let I18nService = class I18nService {
|
|
11
10
|
fs;
|
|
@@ -15,26 +14,23 @@ let I18nService = class I18nService {
|
|
|
15
14
|
this.cs = cs;
|
|
16
15
|
}
|
|
17
16
|
async load(directory, options) {
|
|
18
|
-
if (!this.fs.exists(directory)) return;
|
|
19
17
|
const instance = i18next.createInstance();
|
|
20
18
|
await instance.init({
|
|
21
19
|
lng: options.language,
|
|
22
20
|
fallbackLng: options.fallback ?? options.language ?? "en",
|
|
23
|
-
resources: await this.resources(directory),
|
|
21
|
+
resources: this.fs.exists(directory) ? await this.resources(directory) : {},
|
|
24
22
|
interpolation: { escapeValue: false }
|
|
25
23
|
});
|
|
26
24
|
return instance.getFixedT(options.language);
|
|
27
25
|
}
|
|
28
26
|
async resources(directory) {
|
|
29
|
-
const files = (await this.fs.extra.readdir(directory)).filter((file) => I18N_ACCEPTED_TYPES.includes(extname(file)));
|
|
30
27
|
const resources = {};
|
|
31
|
-
await Promise.all(
|
|
28
|
+
await Promise.all((await this.fs.extra.readdir(directory)).filter((file) => I18N_ACCEPTED_TYPES.includes(extname(file))).map(async (file) => {
|
|
32
29
|
resources[basename(file, extname(file))] = { translation: await this.cs.read(join(directory, file)) };
|
|
33
30
|
}));
|
|
34
31
|
return resources;
|
|
35
32
|
}
|
|
36
33
|
};
|
|
37
34
|
I18nService = __decorate([Injectable(), __decorateMetadata("design:paramtypes", [typeof FileSystemService === "undefined" ? Object : FileSystemService, typeof ConfigService === "undefined" ? Object : ConfigService])], I18nService);
|
|
38
|
-
|
|
39
35
|
//#endregion
|
|
40
|
-
export { I18nService };
|
|
36
|
+
export { I18nService };
|
package/dist/services/index.mjs
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import { I18nService } from "./i18n.service.mjs";
|
|
2
|
+
import { MarkdownService } from "./markdown.service.mjs";
|
|
3
|
+
import { BrowserService } from "./renderer/browser.service.mjs";
|
|
4
|
+
import { RendererService } from "./renderer/renderer.service.mjs";
|
|
2
5
|
import { SignatureAdapter } from "./signature/signature.adapter.mjs";
|
|
3
6
|
import { ATrustAdapter } from "./signature/adapters/a-trust.adapter.mjs";
|
|
4
7
|
import { SignatureService } from "./signature/signature.service.mjs";
|
|
8
|
+
import { TemplateService } from "./template/template.service.mjs";
|
|
9
|
+
import { PrinterService } from "./printer.service.mjs";
|
|
10
|
+
import { PreviewService } from "./session/preview.service.mjs";
|
|
11
|
+
import { SessionService } from "./session/session.service.mjs";
|
|
12
|
+
import { PrinterModule } from "./printer.module.mjs";
|
|
5
13
|
import "./signature/index.mjs";
|
|
6
|
-
|
|
7
|
-
export { ATrustAdapter, I18nService, SignatureAdapter, SignatureService };
|
|
14
|
+
export { ATrustAdapter, BrowserService, I18nService, MarkdownService, PreviewService, PrinterModule, PrinterService, RendererService, SessionService, SignatureAdapter, SignatureService, TemplateService };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region src/services/loopback.ts
|
|
2
|
+
const LOOPBACK = [
|
|
3
|
+
"localhost",
|
|
4
|
+
"127.0.0.1",
|
|
5
|
+
"[::1]"
|
|
6
|
+
];
|
|
7
|
+
/**
|
|
8
|
+
* Accepts only requests addressed to a loopback host and, when a page sent them, coming from one: another site can then reach the local
|
|
9
|
+
* servers neither through DNS rebinding nor through a cross-site form post. With an expected `origin`, the request must come from exactly
|
|
10
|
+
* that origin, which also shuts out other local servers.
|
|
11
|
+
*/
|
|
12
|
+
function isLoopbackRequest({ headers }, origin) {
|
|
13
|
+
if (!LOOPBACK.includes(URL.parse(`http://${headers.host}`)?.hostname)) return false;
|
|
14
|
+
if (origin) return headers.origin === origin;
|
|
15
|
+
return !headers.origin || LOOPBACK.includes(URL.parse(headers.origin)?.hostname);
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
export { isLoopbackRequest };
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { DIRECTIVE_TAG, PAGE_BREAK_CLASS } from "../constants/template.constants.mjs";
|
|
2
|
+
import __decorate from "../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorate.mjs";
|
|
3
|
+
import { Injectable } from "@nestjs/common";
|
|
4
|
+
import { toHtml } from "hast-util-to-html";
|
|
5
|
+
import { all } from "lowlight";
|
|
6
|
+
import { find, html } from "property-information";
|
|
7
|
+
import rehypeHighlight from "rehype-highlight";
|
|
8
|
+
import rehypeRaw from "rehype-raw";
|
|
9
|
+
import rehypeSlug from "rehype-slug";
|
|
10
|
+
import remarkDirective from "remark-directive";
|
|
11
|
+
import remarkFrontmatter from "remark-frontmatter";
|
|
12
|
+
import remarkGfm from "remark-gfm";
|
|
13
|
+
import remarkParse from "remark-parse";
|
|
14
|
+
import remarkRehype from "remark-rehype";
|
|
15
|
+
import { unified } from "unified";
|
|
16
|
+
import { EXIT, SKIP, visit } from "unist-util-visit";
|
|
17
|
+
import { VFile } from "vfile";
|
|
18
|
+
import { matter } from "vfile-matter";
|
|
19
|
+
//#region src/services/markdown.service.ts
|
|
20
|
+
let MarkdownService = class MarkdownService {
|
|
21
|
+
processor = unified().use(remarkParse).use(remarkFrontmatter).use(remarkGfm).use(remarkDirective).use(() => (tree, file) => {
|
|
22
|
+
visit(tree, [
|
|
23
|
+
"containerDirective",
|
|
24
|
+
"leafDirective",
|
|
25
|
+
"textDirective"
|
|
26
|
+
], (node) => {
|
|
27
|
+
if (node.type === "leafDirective" && node.name === "pagebreak") {
|
|
28
|
+
node.data = {
|
|
29
|
+
hName: "div",
|
|
30
|
+
hProperties: { className: [PAGE_BREAK_CLASS] }
|
|
31
|
+
};
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
node.data = {
|
|
35
|
+
hName: DIRECTIVE_TAG,
|
|
36
|
+
hProperties: {
|
|
37
|
+
dataType: node.type,
|
|
38
|
+
dataName: node.name,
|
|
39
|
+
dataAttributes: JSON.stringify(Object.fromEntries(Object.entries(node.attributes ?? {}).map(([key, value]) => [key, value ?? ""]))),
|
|
40
|
+
dataSource: String(file.value).slice(node.position.start.offset, node.position.end.offset)
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
});
|
|
44
|
+
}).use(remarkRehype, { allowDangerousHtml: true }).use(rehypeRaw).use(rehypeHighlight, { languages: all }).freeze();
|
|
45
|
+
parse(source) {
|
|
46
|
+
const file = new VFile(source);
|
|
47
|
+
matter(file);
|
|
48
|
+
return {
|
|
49
|
+
markdown: this.processor.runSync(this.processor.parse(file), file),
|
|
50
|
+
data: file.data.matter ?? {}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Splits the document into HTML and the elements on the way to a component, so only directives render as components.
|
|
55
|
+
*/
|
|
56
|
+
resolve(tree, directives) {
|
|
57
|
+
const resolved = unified().use(() => (root) => {
|
|
58
|
+
visit(root, {
|
|
59
|
+
type: "element",
|
|
60
|
+
tagName: DIRECTIVE_TAG
|
|
61
|
+
}, (node, index, parent) => {
|
|
62
|
+
if (directives.has(String(node.properties.dataName))) return;
|
|
63
|
+
const text = {
|
|
64
|
+
type: "text",
|
|
65
|
+
value: String(node.properties.dataSource)
|
|
66
|
+
};
|
|
67
|
+
parent.children[index] = node.properties.dataType === "textDirective" ? text : {
|
|
68
|
+
type: "element",
|
|
69
|
+
tagName: "p",
|
|
70
|
+
properties: {},
|
|
71
|
+
children: [text]
|
|
72
|
+
};
|
|
73
|
+
return SKIP;
|
|
74
|
+
});
|
|
75
|
+
}).use(rehypeSlug).runSync(structuredClone(tree));
|
|
76
|
+
return this.nodes(resolved.children, directives);
|
|
77
|
+
}
|
|
78
|
+
nodes(children, directives) {
|
|
79
|
+
return children.reduce((nodes, child) => {
|
|
80
|
+
const node = this.node(child, directives);
|
|
81
|
+
const last = nodes.at(-1);
|
|
82
|
+
if (node.type === "html" && last?.type === "html") last.html += node.html;
|
|
83
|
+
else nodes.push(node);
|
|
84
|
+
return nodes;
|
|
85
|
+
}, []);
|
|
86
|
+
}
|
|
87
|
+
node(child, directives) {
|
|
88
|
+
let directive = false;
|
|
89
|
+
visit(child, {
|
|
90
|
+
type: "element",
|
|
91
|
+
tagName: DIRECTIVE_TAG
|
|
92
|
+
}, () => {
|
|
93
|
+
directive = true;
|
|
94
|
+
return EXIT;
|
|
95
|
+
});
|
|
96
|
+
if (child.type !== "element" || !directive) return {
|
|
97
|
+
type: "html",
|
|
98
|
+
html: toHtml(child)
|
|
99
|
+
};
|
|
100
|
+
if (child.tagName === "md-printer-directive") return {
|
|
101
|
+
type: "component",
|
|
102
|
+
name: directives.get(String(child.properties.dataName)),
|
|
103
|
+
props: JSON.parse(String(child.properties.dataAttributes)),
|
|
104
|
+
children: this.nodes(child.children, directives)
|
|
105
|
+
};
|
|
106
|
+
return {
|
|
107
|
+
type: "element",
|
|
108
|
+
tag: child.tagName,
|
|
109
|
+
attributes: this.attributes(child.properties),
|
|
110
|
+
children: this.nodes(child.children, directives)
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
attributes(properties) {
|
|
114
|
+
return Object.fromEntries(Object.entries(properties).flatMap(([key, value]) => {
|
|
115
|
+
if (value === null || value === void 0 || value === false) return [];
|
|
116
|
+
const { attribute, commaSeparated } = find(html, key);
|
|
117
|
+
return [[attribute, value === true ? true : Array.isArray(value) ? value.join(commaSeparated ? ", " : " ") : String(value)]];
|
|
118
|
+
}));
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
MarkdownService = __decorate([Injectable()], MarkdownService);
|
|
122
|
+
//#endregion
|
|
123
|
+
export { MarkdownService };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { PRINTER_MODULE_OPTIONS } from "../constants/template.constants.mjs";
|
|
2
|
+
import __decorate from "../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorate.mjs";
|
|
3
|
+
import { I18nService } from "./i18n.service.mjs";
|
|
4
|
+
import { MarkdownService } from "./markdown.service.mjs";
|
|
5
|
+
import { BrowserService } from "./renderer/browser.service.mjs";
|
|
6
|
+
import { RendererService } from "./renderer/renderer.service.mjs";
|
|
7
|
+
import { ATrustAdapter } from "./signature/adapters/a-trust.adapter.mjs";
|
|
8
|
+
import { SignatureService } from "./signature/signature.service.mjs";
|
|
9
|
+
import { TemplateService } from "./template/template.service.mjs";
|
|
10
|
+
import { PrinterService } from "./printer.service.mjs";
|
|
11
|
+
import { PreviewService } from "./session/preview.service.mjs";
|
|
12
|
+
import { SessionService } from "./session/session.service.mjs";
|
|
13
|
+
import { Module } from "@nestjs/common";
|
|
14
|
+
//#region src/services/printer.module.ts
|
|
15
|
+
var _PrinterModule;
|
|
16
|
+
let PrinterModule = _PrinterModule = class PrinterModule {
|
|
17
|
+
static forRoot(options) {
|
|
18
|
+
return {
|
|
19
|
+
module: _PrinterModule,
|
|
20
|
+
providers: [
|
|
21
|
+
{
|
|
22
|
+
provide: PRINTER_MODULE_OPTIONS,
|
|
23
|
+
useValue: options
|
|
24
|
+
},
|
|
25
|
+
I18nService,
|
|
26
|
+
MarkdownService,
|
|
27
|
+
TemplateService,
|
|
28
|
+
BrowserService,
|
|
29
|
+
RendererService,
|
|
30
|
+
ATrustAdapter,
|
|
31
|
+
SignatureService,
|
|
32
|
+
PrinterService,
|
|
33
|
+
SessionService,
|
|
34
|
+
PreviewService
|
|
35
|
+
]
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
PrinterModule = _PrinterModule = __decorate([Module({})], PrinterModule);
|
|
40
|
+
//#endregion
|
|
41
|
+
export { PrinterModule };
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { DEFAULT_PDF_OPTIONS } from "../constants/template.constants.mjs";
|
|
2
|
+
import { OutputFileType } from "../constants/file.constants.mjs";
|
|
3
|
+
import __decorateMetadata from "../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorateMetadata.mjs";
|
|
4
|
+
import __decorate from "../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorate.mjs";
|
|
5
|
+
import { I18nService } from "./i18n.service.mjs";
|
|
6
|
+
import { MarkdownService } from "./markdown.service.mjs";
|
|
7
|
+
import { inlineHtml } from "./template/assets.mjs";
|
|
8
|
+
import { RendererService } from "./renderer/renderer.service.mjs";
|
|
9
|
+
import { SignatureService } from "./signature/signature.service.mjs";
|
|
10
|
+
import { TemplateService } from "./template/template.service.mjs";
|
|
11
|
+
import { basename, dirname, extname, join, resolve } from "path";
|
|
12
|
+
import { FileSystemService, LoggerService, MergeStrategy, merge } from "@cenk1cenk2/oclif-common";
|
|
13
|
+
import { Injectable } from "@nestjs/common";
|
|
14
|
+
import { parse } from "yaml";
|
|
15
|
+
//#region src/services/printer.service.ts
|
|
16
|
+
let PrinterService = class PrinterService {
|
|
17
|
+
fs;
|
|
18
|
+
logger;
|
|
19
|
+
i18n;
|
|
20
|
+
markdown;
|
|
21
|
+
template;
|
|
22
|
+
renderer;
|
|
23
|
+
signature;
|
|
24
|
+
constructor(fs, logger, i18n, markdown, template, renderer, signature) {
|
|
25
|
+
this.fs = fs;
|
|
26
|
+
this.logger = logger;
|
|
27
|
+
this.i18n = i18n;
|
|
28
|
+
this.markdown = markdown;
|
|
29
|
+
this.template = template;
|
|
30
|
+
this.renderer = renderer;
|
|
31
|
+
this.signature = signature;
|
|
32
|
+
this.logger.setup(this.constructor.name);
|
|
33
|
+
}
|
|
34
|
+
async input(flags) {
|
|
35
|
+
let file;
|
|
36
|
+
let source;
|
|
37
|
+
if (flags.file) {
|
|
38
|
+
file = resolve(flags.file);
|
|
39
|
+
if (!this.fs.exists(file)) throw new Error(`File does not exist: ${file}`);
|
|
40
|
+
source = await this.fs.read(file);
|
|
41
|
+
} else if (flags.stdin !== void 0) source = flags.stdin;
|
|
42
|
+
else throw new Error("Either --stdin or file argument must be provided.");
|
|
43
|
+
const type = flags.inputFiletype ?? (file ? extname(file).replace(/^\./, "") : "md");
|
|
44
|
+
if (type === "yaml" || type === "yml") return {
|
|
45
|
+
file,
|
|
46
|
+
directory: file ? dirname(file) : process.cwd(),
|
|
47
|
+
markdown: {
|
|
48
|
+
type: "root",
|
|
49
|
+
children: []
|
|
50
|
+
},
|
|
51
|
+
data: parse(source) ?? {}
|
|
52
|
+
};
|
|
53
|
+
return {
|
|
54
|
+
file,
|
|
55
|
+
directory: file ? dirname(file) : process.cwd(),
|
|
56
|
+
...this.markdown.parse(source)
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
async options(flags, input) {
|
|
60
|
+
const { data } = input;
|
|
61
|
+
const template = this.template.resolve(flags.template ?? data.template ?? "default");
|
|
62
|
+
const settings = await this.template.settings(template);
|
|
63
|
+
const output = flags.outputFiletype ?? data.outputFiletype ?? "pdf";
|
|
64
|
+
if (!Object.values(OutputFileType).includes(output)) throw new Error(`Output file type is not supported: ${output}, use one of ${Object.values(OutputFileType).join(", ")}.`);
|
|
65
|
+
const dest = flags.stdout ? void 0 : flags.output ?? data.dest ?? (input.file ? `${basename(input.file, extname(input.file))}.${output}` : void 0);
|
|
66
|
+
return {
|
|
67
|
+
template,
|
|
68
|
+
output,
|
|
69
|
+
dest: dest && resolve(dest),
|
|
70
|
+
title: flags.title ?? data.documentTitle,
|
|
71
|
+
language: flags.language ?? data.language ?? settings.i18n?.language ?? "en",
|
|
72
|
+
continuous: flags.continuous || data.continuous === true || settings.continuous === true,
|
|
73
|
+
media: settings.media ?? "screen",
|
|
74
|
+
highlight: settings.highlightStyle ?? "atom-one-dark",
|
|
75
|
+
pdf: this.pdfOptions(settings.pdfOptions, data.pdfOptions),
|
|
76
|
+
i18n: settings.i18n ?? {},
|
|
77
|
+
sign: this.signOptions(flags, settings.sign, data.sign)
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
bundle(options) {
|
|
81
|
+
return this.template.bundle(options.template);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Resolves the signing time and the visible signature description, which the template renders before the document is signed.
|
|
85
|
+
*/
|
|
86
|
+
async prepare(ctx) {
|
|
87
|
+
if (!ctx.options.sign.enabled) return;
|
|
88
|
+
if (ctx.options.output !== "pdf") throw new Error("Signing is only supported for PDF output.");
|
|
89
|
+
this.signature.adapter(ctx.options.sign.provider);
|
|
90
|
+
ctx.signingTime = /* @__PURE__ */ new Date();
|
|
91
|
+
ctx.certificate = ctx.options.sign.certificate ? await this.signature.certificate(ctx.options.sign.certificate, ctx.signingTime) : void 0;
|
|
92
|
+
ctx.signature = this.signature.describe(ctx.signingTime, ctx.certificate);
|
|
93
|
+
}
|
|
94
|
+
async document(ctx, bundle) {
|
|
95
|
+
const { input, options } = ctx;
|
|
96
|
+
const document = await this.template.render(options.template, bundle, {
|
|
97
|
+
data: input.data,
|
|
98
|
+
t: await this.i18n.load(join(options.template, "i18n"), {
|
|
99
|
+
...options.i18n,
|
|
100
|
+
language: options.language
|
|
101
|
+
}),
|
|
102
|
+
language: options.language,
|
|
103
|
+
signature: ctx.signature
|
|
104
|
+
}, this.markdown.resolve(input.markdown, bundle.directives), {
|
|
105
|
+
language: options.language,
|
|
106
|
+
title: options.title,
|
|
107
|
+
fallbackTitle: input.file && basename(input.file, extname(input.file)),
|
|
108
|
+
highlight: options.highlight
|
|
109
|
+
});
|
|
110
|
+
this.logger.debug("Rendered document: %d bytes, header: %d bytes, footer: %d bytes", document.html.length, document.header?.length ?? 0, document.footer?.length ?? 0);
|
|
111
|
+
return document;
|
|
112
|
+
}
|
|
113
|
+
async output(ctx, document) {
|
|
114
|
+
if (ctx.options.output === "html") {
|
|
115
|
+
const { content, assets } = await inlineHtml(document.html, ctx.input.directory, { confined: true });
|
|
116
|
+
return {
|
|
117
|
+
content: Buffer.from(content),
|
|
118
|
+
assets
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
const { pdf, assets } = await this.renderer.render(document, {
|
|
122
|
+
directory: ctx.input.directory,
|
|
123
|
+
pdf: ctx.options.pdf,
|
|
124
|
+
media: ctx.options.media,
|
|
125
|
+
continuous: ctx.options.continuous
|
|
126
|
+
});
|
|
127
|
+
return {
|
|
128
|
+
content: pdf,
|
|
129
|
+
assets
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
sign(ctx, pdf) {
|
|
133
|
+
return this.signature.sign(pdf, {
|
|
134
|
+
...ctx.options.sign,
|
|
135
|
+
date: ctx.signingTime,
|
|
136
|
+
certificate: ctx.certificate
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
signOptions(flags, ...sources) {
|
|
140
|
+
return {
|
|
141
|
+
...Object.assign({}, ...sources),
|
|
142
|
+
...flags.sign ? { enabled: true } : {},
|
|
143
|
+
...flags.signProvider ? { provider: flags.signProvider } : {},
|
|
144
|
+
...flags.signCertificate ? { certificate: flags.signCertificate } : {}
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
pdfOptions(...sources) {
|
|
148
|
+
const pdf = merge(MergeStrategy.EXTEND, {}, DEFAULT_PDF_OPTIONS, ...sources.map((source) => source ?? {}));
|
|
149
|
+
if (typeof pdf.margin === "string") {
|
|
150
|
+
const [top, right = top, bottom = top, left = right] = pdf.margin.trim().split(/\s+/);
|
|
151
|
+
pdf.margin = {
|
|
152
|
+
top,
|
|
153
|
+
right,
|
|
154
|
+
bottom,
|
|
155
|
+
left
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
return pdf;
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
PrinterService = __decorate([Injectable(), __decorateMetadata("design:paramtypes", [
|
|
162
|
+
typeof FileSystemService === "undefined" ? Object : FileSystemService,
|
|
163
|
+
typeof LoggerService === "undefined" ? Object : LoggerService,
|
|
164
|
+
typeof I18nService === "undefined" ? Object : I18nService,
|
|
165
|
+
typeof MarkdownService === "undefined" ? Object : MarkdownService,
|
|
166
|
+
typeof TemplateService === "undefined" ? Object : TemplateService,
|
|
167
|
+
typeof RendererService === "undefined" ? Object : RendererService,
|
|
168
|
+
typeof SignatureService === "undefined" ? Object : SignatureService
|
|
169
|
+
])], PrinterService);
|
|
170
|
+
//#endregion
|
|
171
|
+
export { PrinterService };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import which from "which";
|
|
2
|
+
//#region src/services/renderer/browser.ts
|
|
3
|
+
var BrowserNotFoundError = class extends Error {
|
|
4
|
+
tried;
|
|
5
|
+
constructor(tried) {
|
|
6
|
+
super([
|
|
7
|
+
"Can not find a Chromium-based browser to print with.",
|
|
8
|
+
`Tried: ${tried.join(", ")}`,
|
|
9
|
+
"Pass --browser <path> or set PUPPETEER_EXECUTABLE_PATH."
|
|
10
|
+
].join("\n"));
|
|
11
|
+
this.tried = tried;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Resolves the browser executable: explicit path, environment overrides, then Brave, Chrome, Chromium and Edge from PATH.
|
|
16
|
+
*/
|
|
17
|
+
function discoverBrowser(explicit, env) {
|
|
18
|
+
const candidates = explicit ? [explicit] : [
|
|
19
|
+
env.PUPPETEER_EXECUTABLE_PATH,
|
|
20
|
+
env.CHROME_PATH,
|
|
21
|
+
"brave",
|
|
22
|
+
"brave-browser",
|
|
23
|
+
"brave-browser-stable",
|
|
24
|
+
"google-chrome-stable",
|
|
25
|
+
"google-chrome",
|
|
26
|
+
"chromium",
|
|
27
|
+
"chromium-browser",
|
|
28
|
+
"microsoft-edge-stable",
|
|
29
|
+
"microsoft-edge"
|
|
30
|
+
].filter(Boolean);
|
|
31
|
+
for (const candidate of candidates) {
|
|
32
|
+
const path = which.sync(candidate, {
|
|
33
|
+
path: env.PATH,
|
|
34
|
+
nothrow: true
|
|
35
|
+
});
|
|
36
|
+
if (path) return path;
|
|
37
|
+
}
|
|
38
|
+
throw new BrowserNotFoundError(candidates);
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
export { BrowserNotFoundError, discoverBrowser };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { PRINTER_MODULE_OPTIONS } from "../../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 { discoverBrowser } from "./browser.mjs";
|
|
5
|
+
import __decorateParam from "../../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorateParam.mjs";
|
|
6
|
+
import { LoggerService } from "@cenk1cenk2/oclif-common";
|
|
7
|
+
import { Inject, Injectable } from "@nestjs/common";
|
|
8
|
+
import puppeteer from "puppeteer-core";
|
|
9
|
+
//#region src/services/renderer/browser.service.ts
|
|
10
|
+
let BrowserService = class BrowserService {
|
|
11
|
+
logger;
|
|
12
|
+
options;
|
|
13
|
+
browser;
|
|
14
|
+
constructor(logger, options) {
|
|
15
|
+
this.logger = logger;
|
|
16
|
+
this.options = options;
|
|
17
|
+
this.logger.setup(this.constructor.name);
|
|
18
|
+
}
|
|
19
|
+
executable() {
|
|
20
|
+
return discoverBrowser(this.options.browser, process.env);
|
|
21
|
+
}
|
|
22
|
+
get() {
|
|
23
|
+
this.browser ??= this.launch().catch((err) => {
|
|
24
|
+
this.browser = void 0;
|
|
25
|
+
throw err;
|
|
26
|
+
});
|
|
27
|
+
return this.browser;
|
|
28
|
+
}
|
|
29
|
+
async onModuleDestroy() {
|
|
30
|
+
const browser = await this.browser?.catch(() => void 0);
|
|
31
|
+
this.browser = void 0;
|
|
32
|
+
await browser?.close();
|
|
33
|
+
}
|
|
34
|
+
async launch() {
|
|
35
|
+
const executablePath = this.executable();
|
|
36
|
+
this.logger.debug("Launching browser: %s", executablePath);
|
|
37
|
+
const browser = await puppeteer.launch({
|
|
38
|
+
executablePath,
|
|
39
|
+
handleSIGINT: false,
|
|
40
|
+
handleSIGTERM: false,
|
|
41
|
+
handleSIGHUP: false,
|
|
42
|
+
args: process.getuid?.() === 0 || process.env.CI ? ["--no-sandbox"] : []
|
|
43
|
+
});
|
|
44
|
+
browser.on("disconnected", () => {
|
|
45
|
+
this.browser = void 0;
|
|
46
|
+
});
|
|
47
|
+
return browser;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
BrowserService = __decorate([
|
|
51
|
+
Injectable(),
|
|
52
|
+
__decorateParam(1, Inject(PRINTER_MODULE_OPTIONS)),
|
|
53
|
+
__decorateMetadata("design:paramtypes", [typeof LoggerService === "undefined" ? Object : LoggerService, Object])
|
|
54
|
+
], BrowserService);
|
|
55
|
+
//#endregion
|
|
56
|
+
export { BrowserService };
|