@cenk1cenk2/md-printer 2.5.7 → 2.6.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.
@@ -1,68 +1,65 @@
1
- import { RequiredTemplateFiles, TEMPLATE_DIRECTORY, TemplateFiles } from "../constants/template.constants.js";
2
1
  import { OUTPUT_FILE_ACCEPTED_TYPES } from "../constants/file.constants.js";
2
+ import { RequiredTemplateFiles, TEMPLATE_DIRECTORY, TemplateFiles } from "../constants/template.constants.js";
3
3
  import "../constants/index.js";
4
4
  import tailwind from "@tailwindcss/postcss";
5
5
  import { watch } from "chokidar";
6
6
  import graymatter from "gray-matter";
7
- import { mdToPdf } from "md-to-pdf";
7
+ import { defaultConfig } from "md-to-pdf/dist/lib/config.js";
8
+ import { convertMdToPdf } from "md-to-pdf/dist/lib/md-to-pdf.js";
9
+ import { serveDirectory } from "md-to-pdf/dist/lib/serve-dir.js";
8
10
  import Nunjucks from "nunjucks";
9
11
  import { basename, dirname, extname, join } from "path";
10
12
  import postcss from "postcss";
13
+ import puppeteer from "puppeteer";
11
14
  import showdown from "showdown";
12
- import { Args, Command, ConfigService, FileSystemService, Flags, JsonParser, ParserService, YamlParser } from "@cenk1cenk2/oclif-common";
15
+ import { Args, Command, ConfigService, FileSystemService, Flags, JsonParser, MergeStrategy, ParserService, YamlParser, merge } from "@cenk1cenk2/oclif-common";
13
16
 
14
17
  //#region src/commands/index.ts
15
18
  var MDPrinter = class extends Command {
16
- constructor(..._args) {
17
- super(..._args);
18
- this.nunjucks = Nunjucks.configure({
19
- autoescape: false,
20
- throwOnUndefined: true,
21
- trimBlocks: true,
22
- lstripBlocks: false
23
- });
24
- }
25
- static {
26
- this.description = "Generates a PDF from the given markdown file with the selected HTML template.";
27
- }
28
- static {
29
- this.flags = {
30
- template: Flags.string({
31
- char: "t",
32
- default: "default",
33
- description: "HTML template for the generated PDF file."
34
- }),
35
- title: Flags.string({
36
- char: "T",
37
- description: "Overwrite document title."
38
- }),
39
- browser: Flags.string({
40
- char: "b",
41
- description: "Browser path that is going to be used for the PDF generation.",
42
- default: "/usr/bin/brave"
43
- }),
44
- watch: Flags.boolean({
45
- char: "w",
46
- description: "Watch the changes on the given file."
47
- }),
48
- dev: Flags.boolean({
49
- char: "d",
50
- description: "Run with Chrome browser instead of publishing the file."
51
- })
52
- };
53
- }
54
- static {
55
- this.args = {
56
- file: Args.string({
57
- description: "File to be processed.",
58
- required: true
59
- }),
60
- output: Args.string({
61
- description: "Output file that will be generated. Overwrites the one define in front-matter.",
62
- required: false
63
- })
64
- };
65
- }
19
+ static description = "Generates a PDF from the given markdown file with the selected HTML template.";
20
+ static flags = {
21
+ template: Flags.string({
22
+ char: "t",
23
+ default: "default",
24
+ description: "HTML template for the generated PDF file."
25
+ }),
26
+ title: Flags.string({
27
+ char: "T",
28
+ description: "Overwrite document title."
29
+ }),
30
+ browser: Flags.string({
31
+ char: "b",
32
+ description: "Browser path that is going to be used for the PDF generation.",
33
+ default: "/usr/bin/brave"
34
+ }),
35
+ watch: Flags.boolean({
36
+ char: "w",
37
+ description: "Watch the changes on the given file."
38
+ }),
39
+ dev: Flags.boolean({
40
+ char: "d",
41
+ description: "Run with Chrome browser instead of publishing the file."
42
+ })
43
+ };
44
+ static args = {
45
+ file: Args.string({
46
+ description: "File to be processed.",
47
+ required: true
48
+ }),
49
+ output: Args.string({
50
+ description: "Output file that will be generated. Overwrites the one define in front-matter.",
51
+ required: false
52
+ })
53
+ };
54
+ nunjucks = Nunjucks.configure({
55
+ autoescape: false,
56
+ throwOnUndefined: true,
57
+ trimBlocks: true,
58
+ lstripBlocks: false
59
+ });
60
+ cs;
61
+ fs;
62
+ browser;
66
63
  async shouldRunBefore() {
67
64
  this.cs = this.app.get(ConfigService);
68
65
  this.fs = this.app.get(FileSystemService);
@@ -73,78 +70,69 @@ var MDPrinter = class extends Command {
73
70
  this.tasks.options = { silentRendererCondition: true };
74
71
  }
75
72
  async run() {
76
- this.tasks.add([
77
- { task: async (ctx) => {
78
- const file = join(process.cwd(), this.args.file);
79
- if (!this.fs.exists(file)) throw new Error(`File does not exists: ${file}`);
80
- this.logger.info("Loading file: %s", file);
81
- ctx.file = file;
82
- switch (extname(ctx.file)) {
83
- case ".md": {
84
- const data = graymatter.read(ctx.file);
85
- ctx.content = await this.fs.read(file);
86
- ctx.content = data.content;
87
- ctx.metadata = data.data;
88
- break;
89
- }
90
- case ".yml":
91
- ctx.content = await this.fs.read(file);
92
- ctx.metadata = await this.app.get(ParserService).parse(ctx.file, ctx.content);
93
- break;
94
- default: throw new Error("File type is not accepted.");
73
+ this.tasks.add([{ task: async (ctx) => {
74
+ const file = join(process.cwd(), this.args.file);
75
+ if (!this.fs.exists(file)) throw new Error(`File does not exists: ${file}`);
76
+ this.logger.info("Loading file: %s", file);
77
+ ctx.file = file;
78
+ switch (extname(ctx.file)) {
79
+ case ".md": {
80
+ const data = graymatter.read(ctx.file);
81
+ ctx.content = await this.fs.read(file);
82
+ ctx.content = data.content;
83
+ ctx.metadata = data.data;
84
+ break;
95
85
  }
96
- } },
97
- { task: async (ctx) => {
98
- const template = ctx.metadata?.template ?? this.flags.template;
99
- ctx.templates = (/* @__PURE__ */ new RegExp(/\.\.?\//)).test(template) ? join(process.cwd(), template) : join(this.config.root, TEMPLATE_DIRECTORY, template);
100
- this.logger.info("Loading template: %s from %s", template, ctx.templates);
101
- await Promise.all(RequiredTemplateFiles.map(async (file) => {
102
- const current = join(ctx.templates, file);
103
- if (!this.fs.exists(current)) throw new Error(`Template does not exists: ${current}`);
104
- }));
105
- const paths = {
106
- [TemplateFiles.SETTINGS]: join(ctx.templates, TemplateFiles.SETTINGS),
107
- [TemplateFiles.CSS]: join(ctx.templates, TemplateFiles.CSS),
108
- [TemplateFiles.TAILWIND_CSS]: join(ctx.templates, TemplateFiles.TAILWIND_CSS),
109
- [TemplateFiles.HEADER]: join(ctx.templates, TemplateFiles.HEADER),
110
- [TemplateFiles.FOOTER]: join(ctx.templates, TemplateFiles.FOOTER),
111
- [TemplateFiles.TEMPLATE]: join(ctx.templates, TemplateFiles.TEMPLATE)
112
- };
113
- ctx.options = await this.cs.extend([paths[TemplateFiles.SETTINGS], {
114
- dest: this.args?.output ?? ctx.metadata?.dest ?? `${basename(this.args.file, extname(this.args.file))}.pdf`,
115
- document_title: ctx.metadata?.document_title ?? this.flags.title ?? this.args.file,
116
- launch_options: { executablePath: this.flags.browser }
117
- }]);
118
- this.logger.debug("Options: %o", ctx.options);
119
- if (this.fs.exists(paths[TemplateFiles.HEADER])) {
120
- this.logger.debug("Header exists for template.");
121
- ctx.options.pdf_options.headerTemplate = await this.fs.read(paths[TemplateFiles.HEADER]);
122
- }
123
- if (this.fs.exists(paths[TemplateFiles.FOOTER])) {
124
- this.logger.debug("Footer exists for template.");
125
- ctx.options.pdf_options.footerTemplate = await this.fs.read(paths[TemplateFiles.FOOTER]);
126
- }
127
- if (this.fs.exists(paths[TemplateFiles.TEMPLATE])) {
128
- this.logger.debug("Design template exists for template.");
129
- ctx.template = await this.fs.read(paths[TemplateFiles.TEMPLATE]);
130
- this.logger.debug("Metadata: %o", ctx.metadata);
131
- }
132
- if (this.fs.exists(paths[TemplateFiles.CSS])) {
133
- this.logger.debug("CSS exists for template.");
134
- ctx.options.css = await this.fs.read(paths[TemplateFiles.CSS]);
135
- }
136
- if (this.fs.exists(paths[TemplateFiles.TAILWIND_CSS])) {
137
- this.logger.debug("Tailwind CSS exists for template: %s -> %s", paths[TemplateFiles.TAILWIND_CSS]);
138
- ctx.options.css = await postcss([tailwind({ base: ctx.templates })]).process(await this.fs.read(paths[TemplateFiles.TAILWIND_CSS]), { from: paths[TemplateFiles.TAILWIND_CSS] }).then((result) => result.css);
139
- }
140
- } },
141
- { task: async (ctx) => {
142
- if (this.flags.dev) {
143
- ctx.options.devtools = true;
144
- this.logger.info("Running in dev mode.");
145
- }
146
- } }
147
- ]);
86
+ case ".yml":
87
+ ctx.content = await this.fs.read(file);
88
+ ctx.metadata = await this.app.get(ParserService).parse(ctx.file, ctx.content);
89
+ break;
90
+ default: throw new Error("File type is not accepted.");
91
+ }
92
+ } }, { task: async (ctx) => {
93
+ const template = ctx.metadata?.template ?? this.flags.template;
94
+ ctx.templates = (/* @__PURE__ */ new RegExp(/\.\.?\//)).test(template) ? join(process.cwd(), template) : join(this.config.root, TEMPLATE_DIRECTORY, template);
95
+ this.logger.info("Loading template: %s from %s", template, ctx.templates);
96
+ await Promise.all(RequiredTemplateFiles.map(async (file) => {
97
+ const current = join(ctx.templates, file);
98
+ if (!this.fs.exists(current)) throw new Error(`Template does not exists: ${current}`);
99
+ }));
100
+ const paths = {
101
+ [TemplateFiles.SETTINGS]: join(ctx.templates, TemplateFiles.SETTINGS),
102
+ [TemplateFiles.CSS]: join(ctx.templates, TemplateFiles.CSS),
103
+ [TemplateFiles.TAILWIND_CSS]: join(ctx.templates, TemplateFiles.TAILWIND_CSS),
104
+ [TemplateFiles.HEADER]: join(ctx.templates, TemplateFiles.HEADER),
105
+ [TemplateFiles.FOOTER]: join(ctx.templates, TemplateFiles.FOOTER),
106
+ [TemplateFiles.TEMPLATE]: join(ctx.templates, TemplateFiles.TEMPLATE)
107
+ };
108
+ ctx.options = await this.cs.extend([paths[TemplateFiles.SETTINGS], {
109
+ dest: this.args?.output ?? ctx.metadata?.dest ?? `${basename(this.args.file, extname(this.args.file))}.pdf`,
110
+ document_title: ctx.metadata?.document_title ?? this.flags.title ?? this.args.file,
111
+ launch_options: { executablePath: this.flags.browser }
112
+ }]);
113
+ this.logger.debug("Options: %o", ctx.options);
114
+ if (this.fs.exists(paths[TemplateFiles.HEADER])) {
115
+ this.logger.debug("Header exists for template.");
116
+ ctx.options.pdf_options.headerTemplate = await this.fs.read(paths[TemplateFiles.HEADER]);
117
+ }
118
+ if (this.fs.exists(paths[TemplateFiles.FOOTER])) {
119
+ this.logger.debug("Footer exists for template.");
120
+ ctx.options.pdf_options.footerTemplate = await this.fs.read(paths[TemplateFiles.FOOTER]);
121
+ }
122
+ if (this.fs.exists(paths[TemplateFiles.TEMPLATE])) {
123
+ this.logger.debug("Design template exists for template.");
124
+ ctx.template = await this.fs.read(paths[TemplateFiles.TEMPLATE]);
125
+ this.logger.debug("Metadata: %o", ctx.metadata);
126
+ }
127
+ if (this.fs.exists(paths[TemplateFiles.CSS])) {
128
+ this.logger.debug("CSS exists for template.");
129
+ ctx.options.css = await this.fs.read(paths[TemplateFiles.CSS]);
130
+ }
131
+ if (this.fs.exists(paths[TemplateFiles.TAILWIND_CSS])) {
132
+ this.logger.debug("Tailwind CSS exists for template: %s -> %s", paths[TemplateFiles.TAILWIND_CSS]);
133
+ ctx.options.css = await postcss([tailwind({ base: ctx.templates })]).process(await this.fs.read(paths[TemplateFiles.TAILWIND_CSS]), { from: paths[TemplateFiles.TAILWIND_CSS] }).then((result) => result.css);
134
+ }
135
+ } }]);
148
136
  }
149
137
  async shouldRunAfter(ctx) {
150
138
  if (this.flags.watch) {
@@ -155,33 +143,48 @@ var MDPrinter = class extends Command {
155
143
  join(ctx.templates, "**/*")
156
144
  ]).on("change", async () => {
157
145
  await this.run();
158
- await this.runTasks();
146
+ const ctx$1 = await this.runTasks();
159
147
  this.logger.info("Waiting for the next change.");
160
- return this.runMd2Pdf(ctx);
148
+ return this.runMd2Pdf(ctx$1).catch((err) => {
149
+ this.logger.error(err);
150
+ throw err;
151
+ });
161
152
  });
153
+ return this.runMd2Pdf(ctx);
162
154
  }
163
- return this.runMd2Pdf(ctx);
155
+ await this.runMd2Pdf(ctx);
156
+ if (this.browser) await this.browser.close();
164
157
  }
165
158
  async runMd2Pdf(ctx) {
166
- let pdf;
159
+ const options = merge(MergeStrategy.EXTEND, { basedir: process.cwd() }, defaultConfig, ctx.options, { devtools: this.flags.dev });
160
+ this.browser ??= await puppeteer.launch({
161
+ devtools: options.devtools,
162
+ ...options.launch_options
163
+ });
164
+ const server = await serveDirectory(ctx.options);
165
+ options.port = server.address().port;
166
+ let output;
167
167
  if (ctx.template) {
168
168
  this.logger.info("Rendering as template.");
169
- pdf = await mdToPdf({ content: this.nunjucks.renderString(ctx.template, {
169
+ output = await convertMdToPdf({ content: this.nunjucks.renderString(ctx.template, {
170
170
  ...ctx.metadata ?? {},
171
171
  content: ctx.content
172
- }) }, ctx.options);
172
+ }) }, options, { browser: this.browser });
173
173
  } else {
174
174
  this.logger.info("Rendering as plain file.");
175
- pdf = await mdToPdf({ content: ctx.content }, ctx.options);
175
+ output = await convertMdToPdf({ content: ctx.content }, options, { browser: this.browser });
176
176
  }
177
- const output = pdf.filename;
178
- await this.fs.mkdir(dirname(output));
179
- if (!output) throw new Error("Output should either be defined with the variable or front-matter.");
180
- else if (!OUTPUT_FILE_ACCEPTED_TYPES.includes(extname(output))) throw new Error(`Output file should be ending with the extension: ${OUTPUT_FILE_ACCEPTED_TYPES.join(", ")} -> current: ${extname(output)}`);
181
- this.logger.info("Output file will be: %s", output);
182
- if (pdf) {
183
- this.logger.info("Writing file to output: %s", output);
184
- await this.fs.write(output, pdf.content);
177
+ await new Promise((resolve, reject) => server.close((err) => {
178
+ if (err) return reject(err);
179
+ resolve(null);
180
+ }));
181
+ if (output) {
182
+ if (!output.filename) throw new Error("Output should either be defined with the variable or front-matter.");
183
+ else if (!OUTPUT_FILE_ACCEPTED_TYPES.includes(extname(output.filename))) throw new Error(`Output file should be ending with the extension: ${OUTPUT_FILE_ACCEPTED_TYPES.join(", ")} -> current: ${extname(output.filename)}`);
184
+ this.logger.info("Output file will be: %s", output.filename);
185
+ await this.fs.mkdir(dirname(output.filename));
186
+ this.logger.info("Writing file to output: %s", output.filename);
187
+ await this.fs.write(output.filename, output.content);
185
188
  }
186
189
  }
187
190
  };
@@ -1,4 +1,4 @@
1
- import { RequiredTemplateFiles, TEMPLATE_DIRECTORY, TemplateFiles } from "./template.constants.js";
2
1
  import { OUTPUT_FILE_ACCEPTED_TYPES } from "./file.constants.js";
2
+ import { RequiredTemplateFiles, TEMPLATE_DIRECTORY, TemplateFiles } from "./template.constants.js";
3
3
 
4
4
  export { OUTPUT_FILE_ACCEPTED_TYPES, RequiredTemplateFiles, TEMPLATE_DIRECTORY, TemplateFiles };
@@ -1,3 +1,7 @@
1
1
  import { notFoundHook } from "@cenk1cenk2/oclif-common";
2
2
 
3
- export { notFoundHook as default };
3
+ //#region src/hooks/not-found.hook.ts
4
+ var not_found_hook_default = notFoundHook;
5
+
6
+ //#endregion
7
+ export { not_found_hook_default as default };
@@ -1,3 +1,7 @@
1
1
  import { updateNotifierHook } from "@cenk1cenk2/oclif-common";
2
2
 
3
- export { updateNotifierHook as default };
3
+ //#region src/hooks/update-notifier.hook.ts
4
+ var update_notifier_hook_default = updateNotifierHook;
5
+
6
+ //#endregion
7
+ export { update_notifier_hook_default as default };
@@ -106,5 +106,5 @@
106
106
  "enableJsonFlag": false
107
107
  }
108
108
  },
109
- "version": "2.5.6"
109
+ "version": "2.5.8"
110
110
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cenk1cenk2/md-printer",
3
- "version": "2.5.7",
3
+ "version": "2.6.0",
4
4
  "description": "A markdown printer.",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -16,8 +16,8 @@
16
16
  "scripts": {
17
17
  "dev": "./bin/dev.js",
18
18
  "start": "./bin/run.js",
19
- "build": "tsdown src/",
20
- "dev:start": "tsdown --watch src/",
19
+ "build": "tsdown",
20
+ "dev:start": "tsdown --watch",
21
21
  "clean": "rimraf oclif.manifset.json",
22
22
  "format": "prettier --write src/ --log-level warn && eslint --fix",
23
23
  "lint": "eslint",
@@ -63,27 +63,30 @@
63
63
  "topicSeparator": " "
64
64
  },
65
65
  "engines": {
66
- "node": ">=16.0.0"
66
+ "node": ">=20.0.0"
67
67
  },
68
68
  "keywords": [
69
69
  "oclif",
70
70
  "cenk1cenk2"
71
71
  ],
72
72
  "dependencies": {
73
- "@cenk1cenk2/oclif-common": "^6.4.9",
74
- "@listr2/manager": "^3.0.1",
73
+ "@cenk1cenk2/oclif-common": "^6.4.10",
74
+ "@listr2/manager": "^3.0.2",
75
75
  "@oclif/core": "^4.5.2",
76
76
  "@oclif/plugin-help": "^6.2.32",
77
77
  "@tailwindcss/forms": "^0.5.10",
78
78
  "@tailwindcss/postcss": "^4.1.12",
79
79
  "@tailwindcss/typography": "^0.5.16",
80
+ "@tsconfig/node20": "^20.1.6",
80
81
  "chokidar": "^4.0.3",
81
82
  "fs-extra": "^11.3.1",
83
+ "get-port": "^7.1.0",
82
84
  "gray-matter": "^4.0.3",
83
- "listr2": "^9.0.1",
85
+ "listr2": "^9.0.2",
84
86
  "md-to-pdf": "^5.2.4",
85
87
  "nunjucks": "^3.2.4",
86
88
  "postcss": "^8.5.6",
89
+ "puppeteer": "^24.17.0",
87
90
  "showdown": "^2.1.0",
88
91
  "source-map-support": "^0.5.21",
89
92
  "tailwindcss": "^4.1.12"
@@ -100,13 +103,13 @@
100
103
  "execa": "^9.6.0",
101
104
  "globby": "^14.1.0",
102
105
  "lint-staged": "^16.1.5",
103
- "oclif": "^4.22.12",
106
+ "oclif": "^4.22.14",
104
107
  "prettier": "^3.6.2",
105
108
  "simple-git-hooks": "^2.13.1",
106
109
  "theme-colors": "^0.1.0",
107
110
  "ts-node": "^10.9.2",
108
111
  "tsconfig-paths": "^4.2.0",
109
- "tsdown": "^0.13.4",
112
+ "tsdown": "^0.14.2",
110
113
  "typescript": "^5.9.2"
111
114
  },
112
115
  "config": {
@@ -114,5 +117,5 @@
114
117
  "path": "./node_modules/@cenk1cenk2/cz-cc"
115
118
  }
116
119
  },
117
- "packageManager": "pnpm@9.6.0"
120
+ "packageManager": "pnpm@10.15.0"
118
121
  }