gutterpress 0.10.6 → 0.10.7-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +71 -3
  2. package/dist/api/index.d.ts +1 -1
  3. package/dist/api/index.js +4 -2
  4. package/dist/{audit-0a4sp2w5.js → audit-82jr4qhw.js} +4 -4
  5. package/dist/{build-z53bbxtx.js → build-e53pjtez.js} +4 -4
  6. package/dist/checks/source/css-ownership.d.ts +43 -0
  7. package/dist/checks/source/index.d.ts +1 -0
  8. package/dist/{cli-he23vgjj.js → cli-08psmhr5.js} +15 -2
  9. package/dist/{cli-m99hj80k.js → cli-mk1s46mx.js} +1 -1
  10. package/dist/{cli-bwbs3qm4.js → cli-s8q42x3r.js} +1 -1
  11. package/dist/{cli-kwt5ftvc.js → cli-w6h5zegm.js} +4991 -3933
  12. package/dist/cli.js +70 -37
  13. package/dist/{doctor-d8vpv1pt.js → doctor-50j69ryq.js} +2 -2
  14. package/dist/{engine-4ctgbwj5.js → engine-88mynx9a.js} +2 -2
  15. package/dist/{engine-bhhcne06.js → engine-pb6h089e.js} +1 -1
  16. package/dist/{index-k5hcp8wj.js → index-837htyjy.js} +1 -1
  17. package/dist/{index-1rcfsx67.js → index-9zf8mtk7.js} +2586 -2073
  18. package/dist/{index-eyzv51dw.js → index-a0xpm188.js} +1 -1
  19. package/dist/index.js +5 -3
  20. package/dist/lib/cli-args.d.ts +9 -0
  21. package/dist/lib/manifest-doc.d.ts +8 -2
  22. package/dist/lib/markdown/assemble.d.ts +24 -7
  23. package/dist/lib/markdown/gfm-alerts.d.ts +7 -0
  24. package/dist/lib/markdown/gutterpress-css.d.ts +1 -1
  25. package/dist/lib/markdown/index.d.ts +16 -0
  26. package/dist/lib/markdown/plugins.d.ts +8 -12
  27. package/dist/lib/markdown/renderer.d.ts +48 -1
  28. package/dist/lib/style-declarations.d.ts +20 -0
  29. package/dist/lib/style-resolver.d.ts +2 -0
  30. package/dist/lib/theme-manager.d.ts +110 -9
  31. package/dist/{lint-nm57gn26.js → lint-zbymjr1z.js} +4 -4
  32. package/dist/{manifest.schema-hn6ac0ae.json → manifest.schema-kwnrwv8b.json} +11 -8
  33. package/dist/{new-sawc7zh4.js → new-78j4mx60.js} +4 -4
  34. package/dist/{plugin-p8yghztz.js → plugin-rahnkax3.js} +5 -11
  35. package/dist/{preflight-48kwf2pm.js → preflight-qdmqf3j6.js} +4 -4
  36. package/dist/{preview-10r4dk3d.js → preview-yekma94n.js} +4 -4
  37. package/dist/{publish-cd05sbdx.js → publish-tm2rqyme.js} +4 -4
  38. package/dist/render.js +155 -52
  39. package/dist/schema/manifest.types.d.ts +20 -7
  40. package/dist/theme-j7f6aegv.js +323 -0
  41. package/dist/{validate-70ta3br9.js → validate-3ztxavd0.js} +4 -4
  42. package/package.json +1 -1
@@ -0,0 +1,323 @@
1
+ import {
2
+ BUILT_IN_THEME_IDS,
3
+ applyTheme,
4
+ detectLegacyForkedTheme,
5
+ getActiveTheme,
6
+ getPreviousTheme,
7
+ importThemeFromFile,
8
+ importThemeFromFolder,
9
+ importThemeFromUrl,
10
+ listBuiltInThemes,
11
+ listProjectThemes,
12
+ removeProjectTheme,
13
+ revertTheme
14
+ } from "./cli-w6h5zegm.js";
15
+ import"./cli-mk1s46mx.js";
16
+ import {
17
+ UsageError,
18
+ exitForUsage,
19
+ rejectExtraPositionals,
20
+ rejectUnknownFlags,
21
+ resolveProjectDir
22
+ } from "./cli-08psmhr5.js";
23
+ import"./cli-s8q42x3r.js";
24
+ import"./cli-c41yr7he.js";
25
+ import {
26
+ EXIT_CODES
27
+ } from "./cli-46ycxe6r.js";
28
+ import"./cli-w692g6dx.js";
29
+ import"./cli-v5mp7a6q.js";
30
+ import"./cli-37x76zdn.js";
31
+
32
+ // src/commands/theme.ts
33
+ import { defineCommand } from "citty";
34
+ import { stat } from "node:fs/promises";
35
+ import path from "node:path";
36
+ var dirArg = {
37
+ type: "positional",
38
+ description: "Project directory (defaults to the current directory)",
39
+ required: false
40
+ };
41
+ var themeListArgs = { dir: dirArg };
42
+ var themeApplyArgs = {
43
+ id: {
44
+ type: "positional",
45
+ description: "Theme id to apply — a built-in id (clean-book, zine, technical-doc) or an already-imported project theme id",
46
+ required: true
47
+ },
48
+ dir: dirArg
49
+ };
50
+ var themeImportArgs = {
51
+ source: {
52
+ type: "positional",
53
+ description: "Theme source: a folder, a .zip package, a .css file, or an http(s) URL",
54
+ required: true
55
+ },
56
+ dir: dirArg
57
+ };
58
+ var themeRevertArgs = { dir: dirArg };
59
+ var themeRemoveArgs = {
60
+ id: {
61
+ type: "positional",
62
+ description: "Project theme id to remove",
63
+ required: true
64
+ },
65
+ dir: dirArg
66
+ };
67
+ var parentArgs = {};
68
+ var THEME_SUBCOMMANDS = ["list", "apply", "import", "revert", "remove"];
69
+ function rejectParentFlags(rawArgs) {
70
+ const first = rawArgs[0];
71
+ if (first === undefined || THEME_SUBCOMMANDS.includes(first))
72
+ return;
73
+ if (!first.startsWith("-"))
74
+ return;
75
+ try {
76
+ rejectUnknownFlags(rawArgs, parentArgs, "theme");
77
+ } catch (error) {
78
+ exitForUsage(error);
79
+ }
80
+ }
81
+ function themeLine(id, rest) {
82
+ return ` ${id.padEnd(16)} ${rest}`;
83
+ }
84
+ async function resolveApplyTarget(projectDir, id) {
85
+ const projectThemes = await listProjectThemes(projectDir);
86
+ if (projectThemes.some((t) => t.id === id))
87
+ return { kind: "project", id };
88
+ if (BUILT_IN_THEME_IDS.includes(id))
89
+ return { kind: "builtin", id };
90
+ const known = [
91
+ `built-in: ${BUILT_IN_THEME_IDS.join(", ")}`,
92
+ ...projectThemes.length > 0 ? [`project: ${projectThemes.map((t) => t.id).join(", ")}`] : []
93
+ ].join("; ");
94
+ throw new UsageError(`gutterpress theme apply: unknown theme "${id}" (${known}). Run "gutterpress theme list" to see them.`);
95
+ }
96
+ async function printThemeList(projectDir) {
97
+ const [builtins, projectThemes, active, previous] = await Promise.all([
98
+ listBuiltInThemes(),
99
+ listProjectThemes(projectDir),
100
+ getActiveTheme(projectDir),
101
+ getPreviousTheme(projectDir)
102
+ ]);
103
+ console.log(`Project: ${projectDir}`);
104
+ console.log(`Active theme: ${active ? `${active.name} (${active.id})` : "none"}`);
105
+ console.log("");
106
+ console.log("Built-in themes (gutterpress theme apply <id>):");
107
+ for (const t of builtins) {
108
+ const marker = active?.id === t.id ? " [active]" : "";
109
+ console.log(themeLine(t.id, `${t.name}${marker}`));
110
+ if (t.description)
111
+ console.log(themeLine("", t.description));
112
+ }
113
+ console.log("");
114
+ if (projectThemes.length === 0) {
115
+ console.log("Project themes: none yet — apply a built-in or import one to get started.");
116
+ } else {
117
+ console.log("Project themes (already vendored under this project's themes/ folder):");
118
+ for (const t of projectThemes) {
119
+ const marker = active?.id === t.id ? " [active]" : "";
120
+ const author = t.author ? ` — by ${t.author}` : "";
121
+ console.log(themeLine(t.id, `${t.name}${author}${marker}`));
122
+ }
123
+ }
124
+ if (previous) {
125
+ console.log("");
126
+ console.log(`Previous theme: ${previous.name} (${previous.id}) — restore it with "gutterpress theme revert".`);
127
+ }
128
+ const legacyFork = await detectLegacyForkedTheme(projectDir, active);
129
+ if (legacyFork) {
130
+ console.log("");
131
+ console.log(`Note: styles/book.css is byte-identical to the built-in theme "${legacyFork.name}" (${legacyFork.id}).`);
132
+ console.log(" This looks like a project scaffolded before Gutterpress 0.10.7, which copied a theme's");
133
+ console.log(" CSS into styles/book.css instead of tracking it. It still renders correctly, but it");
134
+ console.log(" won't show up as an active theme, and it will keep loading AFTER any theme you apply —");
135
+ console.log(` silently overriding it. To adopt the tracked layout, run: gutterpress theme apply ${legacyFork.id}`);
136
+ console.log(" (then fold any customizations from styles/book.css in as overrides, or clear the file).");
137
+ }
138
+ }
139
+ function printImported(theme, projectDir) {
140
+ console.log(`Imported theme: ${theme.name} (${theme.id})`);
141
+ console.log(` project: ${projectDir}`);
142
+ console.log(` vendored under: themes/${theme.id}`);
143
+ console.log(`Not yet active — apply it with: gutterpress theme apply ${theme.id}`);
144
+ }
145
+ var list = defineCommand({
146
+ meta: { name: "list", description: "List built-in and project themes, and the active one" },
147
+ args: themeListArgs,
148
+ async run({ args, rawArgs }) {
149
+ try {
150
+ rejectUnknownFlags(rawArgs, themeListArgs, "theme list");
151
+ rejectExtraPositionals(args._, 1, "theme list");
152
+ } catch (error) {
153
+ exitForUsage(error);
154
+ }
155
+ await printThemeList(resolveProjectDir(args.dir));
156
+ }
157
+ });
158
+ var apply = defineCommand({
159
+ meta: { name: "apply", description: "Apply a built-in or project theme, wiring it into the manifest" },
160
+ args: themeApplyArgs,
161
+ async run({ args, rawArgs }) {
162
+ try {
163
+ rejectUnknownFlags(rawArgs, themeApplyArgs, "theme apply");
164
+ rejectExtraPositionals(args._, 2, "theme apply");
165
+ } catch (error) {
166
+ exitForUsage(error);
167
+ }
168
+ const projectDir = resolveProjectDir(args.dir);
169
+ const id = String(args.id);
170
+ let target;
171
+ try {
172
+ target = await resolveApplyTarget(projectDir, id);
173
+ } catch (error) {
174
+ exitForUsage(error);
175
+ }
176
+ try {
177
+ const applied = await applyTheme(projectDir, target);
178
+ console.log(`Applied theme: ${applied.name} (${applied.id})`);
179
+ console.log(` project: ${projectDir}`);
180
+ const label = applied.styles.length > 1 ? "stylesheets" : "stylesheet";
181
+ console.log(` ${label}: ${applied.styles.map((rel) => `themes/${applied.id}/${rel}`).join(", ")}`);
182
+ if (applied.id !== id) {
183
+ console.log(` note: an existing "${id}" theme was already customized, so this copy was applied as "${applied.id}" instead of overwriting it.`);
184
+ }
185
+ } catch (error) {
186
+ console.error(`Could not apply theme: ${error instanceof Error ? error.message : String(error)}`);
187
+ process.exit(EXIT_CODES.PIPELINE);
188
+ }
189
+ }
190
+ });
191
+ var themeImport = defineCommand({
192
+ meta: { name: "import", description: "Import a theme from a folder, .zip, .css file, or URL" },
193
+ args: themeImportArgs,
194
+ async run({ args, rawArgs }) {
195
+ try {
196
+ rejectUnknownFlags(rawArgs, themeImportArgs, "theme import");
197
+ rejectExtraPositionals(args._, 2, "theme import");
198
+ } catch (error) {
199
+ exitForUsage(error);
200
+ }
201
+ const projectDir = resolveProjectDir(args.dir);
202
+ const source = String(args.source);
203
+ let url;
204
+ try {
205
+ url = new URL(source);
206
+ } catch {
207
+ url = undefined;
208
+ }
209
+ if (url && (url.protocol === "http:" || url.protocol === "https:")) {
210
+ try {
211
+ printImported(await importThemeFromUrl(projectDir, source), projectDir);
212
+ } catch (error) {
213
+ console.error(`Could not import theme: ${error instanceof Error ? error.message : String(error)}`);
214
+ process.exit(EXIT_CODES.PIPELINE);
215
+ }
216
+ return;
217
+ }
218
+ const resolvedSource = path.resolve(source);
219
+ let sourceStat;
220
+ try {
221
+ sourceStat = await stat(resolvedSource);
222
+ } catch {
223
+ exitForUsage(new UsageError(`gutterpress theme import: source not found: ${resolvedSource}`));
224
+ }
225
+ if (sourceStat.isDirectory()) {
226
+ try {
227
+ printImported(await importThemeFromFolder(projectDir, resolvedSource), projectDir);
228
+ } catch (error) {
229
+ console.error(`Could not import theme: ${error instanceof Error ? error.message : String(error)}`);
230
+ process.exit(EXIT_CODES.PIPELINE);
231
+ }
232
+ return;
233
+ }
234
+ const ext = path.extname(resolvedSource).toLowerCase();
235
+ if (ext !== ".zip" && ext !== ".css") {
236
+ exitForUsage(new UsageError(`gutterpress theme import: unsupported file type "${ext || path.basename(resolvedSource)}". ` + "Expected a theme folder, a .zip package, a .css file, or an http(s) URL."));
237
+ }
238
+ try {
239
+ const result = await importThemeFromFile(projectDir, resolvedSource);
240
+ printImported(result.theme, projectDir);
241
+ for (const warning of result.warnings)
242
+ console.warn(`Warning: ${warning.message}`);
243
+ } catch (error) {
244
+ console.error(`Could not import theme: ${error instanceof Error ? error.message : String(error)}`);
245
+ process.exit(EXIT_CODES.PIPELINE);
246
+ }
247
+ }
248
+ });
249
+ var revert = defineCommand({
250
+ meta: { name: "revert", description: "Revert to the theme that was active before the current one" },
251
+ args: themeRevertArgs,
252
+ async run({ args, rawArgs }) {
253
+ try {
254
+ rejectUnknownFlags(rawArgs, themeRevertArgs, "theme revert");
255
+ rejectExtraPositionals(args._, 1, "theme revert");
256
+ } catch (error) {
257
+ exitForUsage(error);
258
+ }
259
+ const projectDir = resolveProjectDir(args.dir);
260
+ const previous = await getPreviousTheme(projectDir);
261
+ if (!previous) {
262
+ exitForUsage(new UsageError(`gutterpress theme revert: there is no previous theme to revert to in ${projectDir}.`));
263
+ }
264
+ try {
265
+ const reverted = await revertTheme(projectDir);
266
+ console.log(`Reverted to theme: ${reverted.name} (${reverted.id})`);
267
+ console.log(` project: ${projectDir}`);
268
+ } catch (error) {
269
+ console.error(`Could not revert theme: ${error instanceof Error ? error.message : String(error)}`);
270
+ process.exit(EXIT_CODES.PIPELINE);
271
+ }
272
+ }
273
+ });
274
+ var remove = defineCommand({
275
+ meta: { name: "remove", description: "Remove a project theme (never touches a built-in)" },
276
+ args: themeRemoveArgs,
277
+ async run({ args, rawArgs }) {
278
+ try {
279
+ rejectUnknownFlags(rawArgs, themeRemoveArgs, "theme remove");
280
+ rejectExtraPositionals(args._, 2, "theme remove");
281
+ } catch (error) {
282
+ exitForUsage(error);
283
+ }
284
+ const projectDir = resolveProjectDir(args.dir);
285
+ const id = String(args.id);
286
+ const projectThemes = await listProjectThemes(projectDir);
287
+ const target = projectThemes.find((t) => t.id === id);
288
+ if (!target) {
289
+ exitForUsage(new UsageError(`gutterpress theme remove: "${id}" is not a theme in this project.` + (projectThemes.length > 0 ? ` Project themes: ${projectThemes.map((t) => t.id).join(", ")}.` : "")));
290
+ }
291
+ const activeBefore = await getActiveTheme(projectDir);
292
+ try {
293
+ await removeProjectTheme(projectDir, id);
294
+ console.log(`Removed theme: ${target.name} (${id})`);
295
+ if (activeBefore?.id === id) {
296
+ console.log(" it was the active theme — no theme is applied now.");
297
+ console.log(' run "gutterpress theme apply <id>" to pick one.');
298
+ }
299
+ } catch (error) {
300
+ console.error(`Could not remove theme: ${error instanceof Error ? error.message : String(error)}`);
301
+ process.exit(EXIT_CODES.PIPELINE);
302
+ }
303
+ }
304
+ });
305
+ var theme_default = defineCommand({
306
+ meta: {
307
+ name: "theme",
308
+ description: "List, apply, import, revert, or remove project themes"
309
+ },
310
+ args: parentArgs,
311
+ setup({ rawArgs }) {
312
+ rejectParentFlags(rawArgs);
313
+ },
314
+ subCommands: { list, apply, import: themeImport, revert, remove }
315
+ });
316
+ export {
317
+ themeRevertArgs,
318
+ themeRemoveArgs,
319
+ themeListArgs,
320
+ themeImportArgs,
321
+ themeApplyArgs,
322
+ theme_default as default
323
+ };
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  executeAndReport
3
- } from "./cli-kwt5ftvc.js";
3
+ } from "./cli-w6h5zegm.js";
4
4
  import {
5
5
  log
6
- } from "./cli-m99hj80k.js";
6
+ } from "./cli-mk1s46mx.js";
7
7
  import {
8
8
  UsageError,
9
9
  rejectExtraPositionals,
10
10
  rejectUnknownFlags
11
- } from "./cli-he23vgjj.js";
12
- import"./cli-bwbs3qm4.js";
11
+ } from "./cli-08psmhr5.js";
12
+ import"./cli-s8q42x3r.js";
13
13
  import"./cli-c41yr7he.js";
14
14
  import {
15
15
  EXIT_CODES
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gutterpress",
3
- "version": "0.10.6",
3
+ "version": "0.10.7-beta.1",
4
4
  "description": "Markdown-to-PDF converter for professional print layout using a native Chromium print engine and Ghostscript.",
5
5
  "author": "itlackey",
6
6
  "license": "MPL-2.0",