@d10f/asciidoc-astro-loader 0.0.3 → 0.0.5

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 CHANGED
@@ -179,7 +179,7 @@ Just like regular Asciidoctor.js, any files located here will be used to replace
179
179
 
180
180
  ### Registering A Templating Engine
181
181
 
182
- By default, only Handlebars and Nunjucks are available for processing templates, but you can create your own as well to leverage whatever other template engine you like. A template engine in the context of this package a class that extends the `AbstractEngine` class.
182
+ Templates can be written as plain functions that return an HTML string, or as templates written in a format supported by one of the registered templating engines. By default, only Handlebars and Nunjucks are supported, but you can create your own. A templating engine in the context of this package is a class that extends the `AbstractEngine` class:
183
183
 
184
184
  ```ts
185
185
  import { Php, Request } from '@platformatic/php-node';
@@ -290,16 +290,33 @@ Custom converters are refined versions of templates. The main difference is that
290
290
 
291
291
  For maximum flexibility, both custom converters and templates can be used at the same time. You can even define templates that aren't designed to be used to render nodes directly, but called directly from within your custom converters. This is why the use of interfaces when defining custom templates is important, to ensure consistency and type-safety.
292
292
 
293
- In general, prefer using converters for anything that requires heavy use of logic, and templates for simpler HTML output.
293
+ In general, prefer using converters for anything that requires heavy use of logic or that reads configuration options provided by the user, and templates for simpler HTML output.
294
+
295
+ Custom converters are provided as an array to the `document.converters` option.
296
+
297
+ ```ts
298
+ // src/content.config.ts
299
+
300
+ const blog = defineCollection({
301
+ loader: asciidocLoader({
302
+ base: ".src/content/blog",
303
+ document: {
304
+ converters: [
305
+ myCustomConverter({ /* ... */ })
306
+ ]
307
+ },
308
+ }),
309
+ });
310
+ ```
294
311
 
295
312
  ### Registering a custom converter
296
313
 
297
- A custom converter is declared as a factory function that returns another function. This allows you to provide whatever configuration options you want when registering this converter in the loader configuration.
314
+ A custom converter is declared as a factory function that accepts a configuration object, and returns an inner function that gets called automatically, receiving the options provided to the loader and the instance of the Shiki highlighter.
298
315
 
299
316
  ```ts
300
317
  import type { CustomConverterFactoryFn, NodeContext } from '@d10f/asciidoc-astro-loader';
301
318
 
302
- export const customConverter: CustomConverterFactoryFn = ({ nodeContext }) => {
319
+ export const myCustomConverter: CustomConverterFactoryFn = ({ nodeContext }) => {
303
320
  return (options, highlighter) => {
304
321
  return {
305
322
 
@@ -324,3 +341,4 @@ export const customConverter: CustomConverterFactoryFn = ({ nodeContext }) => {
324
341
  }
325
342
  ```
326
343
 
344
+ In addition, the `convert` method receives the node that is being processed, as well as an instance of the template engine registry. You can use this to render the HTML from a template as well, combining both to get the best of both worlds.
@@ -4,7 +4,9 @@ import {
4
4
 
5
5
  // src/lib/asciidoc/converters/sourceCodeConverter.ts
6
6
  import { resolve } from "path";
7
- var sourceCodeConverter = ({ transformers, template }) => {
7
+ var sourceCodeConverter = (converterOptions) => {
8
+ const transformers = converterOptions?.transformers;
9
+ const template = converterOptions?.template;
8
10
  return (options, highlighter) => {
9
11
  return {
10
12
  nodeContext: "listing",
@@ -333,6 +333,22 @@ declare class TemplateEngineRegistry {
333
333
  private loadTemplates;
334
334
  }
335
335
 
336
+ /**
337
+ * Checks if the given property K is required in object T.
338
+ *
339
+ * @credit Chris Cook
340
+ * @see https://zirkelc.dev/posts/typescript-how-to-check-for-optional-properties
341
+ */
342
+ type IsRequired<T, K extends keyof T> = undefined extends T[K] ? object extends Pick<T, K> ? false : true : true;
343
+ /**
344
+ * Checks if any of the properties in T are required.
345
+ *
346
+ * @credit Chris Cook
347
+ * @see https://zirkelc.dev/posts/typescript-how-to-check-for-optional-properties
348
+ */
349
+ type HasRequiredKeys<T extends object> = keyof {
350
+ [K in keyof T as IsRequired<T, K> extends true ? K : never]: T[K];
351
+ } extends never ? false : true;
336
352
  type CustomConverter = {
337
353
  /**
338
354
  * The node context, or node type, that this converter will act upon.
@@ -353,9 +369,9 @@ type CustomConverter = {
353
369
  */
354
370
  convert(node: AbstractNode, templateEngine?: TemplateEngineRegistry): string | null | undefined;
355
371
  };
356
- type CustomConverterFactoryFn<T extends object | undefined> = (converterOptions: T) => CustomConverterFn;
372
+ type CustomConverterFactoryFn<T extends object> = HasRequiredKeys<T> extends true ? (converterOptions: T) => CustomConverterFn : (converterOptions?: T) => CustomConverterFn;
357
373
  type CustomConverterFn = (opts: RequiredOptions, highlighter: HighlighterCore) => CustomConverter;
358
- type ShikiTransformerFactory<T extends object> = (options?: T) => ShikiTransformerFactoryFn;
374
+ type ShikiTransformerFactory<T extends object> = HasRequiredKeys<T> extends true ? (options: T) => ShikiTransformerFactoryFn : (options?: T) => ShikiTransformerFactoryFn;
359
375
  type ShikiTransformerFactoryFn = (node: AbstractNode) => ShikiTransformer;
360
376
  type CalloutOptions = Partial<{
361
377
  /**
@@ -526,4 +542,4 @@ interface RawTemplate {
526
542
  renderString(content: string, options?: Record<string, unknown>): string;
527
543
  }
528
544
 
529
- export { type AsciidocLoader as A, type CustomConverterFactoryFn as C, type FilesystemTemplate as F, type NodeContext as N, type RawTemplate as R, type ShikiTransformerFactoryFn as S, type TemplateModule as T, type AsciidocTemplate as a, type ShikiTransformerFactory as b, AbstractEngine as c };
545
+ export { type AsciidocLoader as A, type CustomConverterFactoryFn as C, type FilesystemTemplate as F, type NodeContext as N, type RawTemplate as R, type ShikiTransformerFactory as S, type TemplateModule as T, type AsciidocTemplate as a, type ShikiTransformerFactoryFn as b, AbstractEngine as c };
@@ -333,6 +333,22 @@ declare class TemplateEngineRegistry {
333
333
  private loadTemplates;
334
334
  }
335
335
 
336
+ /**
337
+ * Checks if the given property K is required in object T.
338
+ *
339
+ * @credit Chris Cook
340
+ * @see https://zirkelc.dev/posts/typescript-how-to-check-for-optional-properties
341
+ */
342
+ type IsRequired<T, K extends keyof T> = undefined extends T[K] ? object extends Pick<T, K> ? false : true : true;
343
+ /**
344
+ * Checks if any of the properties in T are required.
345
+ *
346
+ * @credit Chris Cook
347
+ * @see https://zirkelc.dev/posts/typescript-how-to-check-for-optional-properties
348
+ */
349
+ type HasRequiredKeys<T extends object> = keyof {
350
+ [K in keyof T as IsRequired<T, K> extends true ? K : never]: T[K];
351
+ } extends never ? false : true;
336
352
  type CustomConverter = {
337
353
  /**
338
354
  * The node context, or node type, that this converter will act upon.
@@ -353,9 +369,9 @@ type CustomConverter = {
353
369
  */
354
370
  convert(node: AbstractNode, templateEngine?: TemplateEngineRegistry): string | null | undefined;
355
371
  };
356
- type CustomConverterFactoryFn<T extends object | undefined> = (converterOptions: T) => CustomConverterFn;
372
+ type CustomConverterFactoryFn<T extends object> = HasRequiredKeys<T> extends true ? (converterOptions: T) => CustomConverterFn : (converterOptions?: T) => CustomConverterFn;
357
373
  type CustomConverterFn = (opts: RequiredOptions, highlighter: HighlighterCore) => CustomConverter;
358
- type ShikiTransformerFactory<T extends object> = (options?: T) => ShikiTransformerFactoryFn;
374
+ type ShikiTransformerFactory<T extends object> = HasRequiredKeys<T> extends true ? (options: T) => ShikiTransformerFactoryFn : (options?: T) => ShikiTransformerFactoryFn;
359
375
  type ShikiTransformerFactoryFn = (node: AbstractNode) => ShikiTransformer;
360
376
  type CalloutOptions = Partial<{
361
377
  /**
@@ -526,4 +542,4 @@ interface RawTemplate {
526
542
  renderString(content: string, options?: Record<string, unknown>): string;
527
543
  }
528
544
 
529
- export { type AsciidocLoader as A, type CustomConverterFactoryFn as C, type FilesystemTemplate as F, type NodeContext as N, type RawTemplate as R, type ShikiTransformerFactoryFn as S, type TemplateModule as T, type AsciidocTemplate as a, type ShikiTransformerFactory as b, AbstractEngine as c };
545
+ export { type AsciidocLoader as A, type CustomConverterFactoryFn as C, type FilesystemTemplate as F, type NodeContext as N, type RawTemplate as R, type ShikiTransformerFactory as S, type TemplateModule as T, type AsciidocTemplate as a, type ShikiTransformerFactoryFn as b, AbstractEngine as c };
package/dist/index.cjs CHANGED
@@ -260,6 +260,15 @@ var AsciidocDocument = class {
260
260
  const [preambleBlock] = documentBlock?.getBlocks();
261
261
  if (preambleBlock) return preambleBlock.getSourceLines()[0];
262
262
  }
263
+ get description() {
264
+ return this.document.getAttribute("description", "");
265
+ }
266
+ get author() {
267
+ return this.document.getAuthor();
268
+ }
269
+ get authors() {
270
+ return this.document.getAuthors();
271
+ }
263
272
  get version() {
264
273
  return this.document.getRevisionNumber();
265
274
  }
@@ -416,6 +425,26 @@ var NunjucksEngine = class extends AbstractEngine {
416
425
  }
417
426
  };
418
427
 
428
+ // src/lib/asciidoc/templates/engines/TemplateStr.ts
429
+ var TemplateStr = class extends AbstractEngine {
430
+ renderMap;
431
+ constructor(name = "templateStr", extensions = ["ts", "js"]) {
432
+ super(name, extensions);
433
+ this.renderMap = /* @__PURE__ */ new Map();
434
+ }
435
+ async load() {
436
+ for (const [context, path] of this.templateList.entries()) {
437
+ const templateFn = await import(path);
438
+ this.renderMap.set(context, templateFn.default);
439
+ }
440
+ }
441
+ renderNode(node, options) {
442
+ const context = node.getNodeName();
443
+ const renderFn = this.renderMap.get(context);
444
+ return renderFn ? renderFn(node, options) : "";
445
+ }
446
+ };
447
+
419
448
  // src/schemas/index.ts
420
449
  var import_zod3 = require("astro/zod");
421
450
 
@@ -519,7 +548,9 @@ async function createHighlighter(documents, themes) {
519
548
 
520
549
  // src/lib/asciidoc/converters/sourceCodeConverter.ts
521
550
  var import_node_path2 = require("path");
522
- var sourceCodeConverter = ({ transformers, template }) => {
551
+ var sourceCodeConverter = (converterOptions) => {
552
+ const transformers = converterOptions?.transformers;
553
+ const template = converterOptions?.template;
523
554
  return (options, highlighter) => {
524
555
  return {
525
556
  nodeContext: "listing",
@@ -622,7 +653,8 @@ function asciidocLoader(_options) {
622
653
  if (options.document.templateEngines === void 0) {
623
654
  options.document.templateEngines = [
624
655
  new HandlebarsEngine(),
625
- new NunjucksEngine()
656
+ new NunjucksEngine(),
657
+ new TemplateStr()
626
658
  ];
627
659
  }
628
660
  let highlighter;
@@ -713,8 +745,16 @@ async function setDocument(doc, converters, templateEngine, { parseData, store }
713
745
  id: doc.slug,
714
746
  data: {
715
747
  title: doc.title,
748
+ subtitle: doc.subtitle,
749
+ author: doc.author,
750
+ authors: doc.authors,
751
+ version: doc.version,
716
752
  createdAt: new Date(doc.createdAt),
717
- description: doc.preamble
753
+ email: doc.authors.at(0)?.getEmail(),
754
+ description: doc.description,
755
+ slug: doc.slug,
756
+ preamble: doc.preamble,
757
+ keywords: doc.keywords
718
758
  }
719
759
  });
720
760
  store.set({
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { LoaderContext } from 'astro/loaders';
2
- import { A as AsciidocLoader } from './index-sFlXF8Qm.cjs';
3
- export { a as AsciidocTemplate, C as CustomConverterFactoryFn, F as FilesystemTemplate, N as NodeContext, R as RawTemplate } from './index-sFlXF8Qm.cjs';
2
+ import { A as AsciidocLoader } from './index-R3g0cYiE.cjs';
3
+ export { a as AsciidocTemplate, C as CustomConverterFactoryFn, F as FilesystemTemplate, N as NodeContext, R as RawTemplate } from './index-R3g0cYiE.cjs';
4
4
  import 'shiki';
5
5
  import 'asciidoctor';
6
6
  import 'astro/zod';
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { LoaderContext } from 'astro/loaders';
2
- import { A as AsciidocLoader } from './index-sFlXF8Qm.js';
3
- export { a as AsciidocTemplate, C as CustomConverterFactoryFn, F as FilesystemTemplate, N as NodeContext, R as RawTemplate } from './index-sFlXF8Qm.js';
2
+ import { A as AsciidocLoader } from './index-R3g0cYiE.js';
3
+ export { a as AsciidocTemplate, C as CustomConverterFactoryFn, F as FilesystemTemplate, N as NodeContext, R as RawTemplate } from './index-R3g0cYiE.js';
4
4
  import 'shiki';
5
5
  import 'asciidoctor';
6
6
  import 'astro/zod';
package/dist/index.js CHANGED
@@ -1,14 +1,15 @@
1
- import {
2
- sourceCodeConverter
3
- } from "./chunk-KZRXEKZK.js";
4
1
  import {
5
2
  transformAsciidocCallout
6
3
  } from "./chunk-5P6LDJGO.js";
4
+ import {
5
+ sourceCodeConverter
6
+ } from "./chunk-NC6IZHLR.js";
7
7
  import {
8
8
  slugify,
9
9
  splitFilenameComponents
10
10
  } from "./chunk-2UGTFP4R.js";
11
11
  import {
12
+ AbstractEngine,
12
13
  HandlebarsEngine,
13
14
  NunjucksEngine
14
15
  } from "./chunk-2F52PMNV.js";
@@ -222,6 +223,15 @@ var AsciidocDocument = class {
222
223
  const [preambleBlock] = documentBlock?.getBlocks();
223
224
  if (preambleBlock) return preambleBlock.getSourceLines()[0];
224
225
  }
226
+ get description() {
227
+ return this.document.getAttribute("description", "");
228
+ }
229
+ get author() {
230
+ return this.document.getAuthor();
231
+ }
232
+ get authors() {
233
+ return this.document.getAuthors();
234
+ }
225
235
  get version() {
226
236
  return this.document.getRevisionNumber();
227
237
  }
@@ -249,6 +259,26 @@ var AsciidocDocument = class {
249
259
  }
250
260
  };
251
261
 
262
+ // src/lib/asciidoc/templates/engines/TemplateStr.ts
263
+ var TemplateStr = class extends AbstractEngine {
264
+ renderMap;
265
+ constructor(name = "templateStr", extensions = ["ts", "js"]) {
266
+ super(name, extensions);
267
+ this.renderMap = /* @__PURE__ */ new Map();
268
+ }
269
+ async load() {
270
+ for (const [context, path] of this.templateList.entries()) {
271
+ const templateFn = await import(path);
272
+ this.renderMap.set(context, templateFn.default);
273
+ }
274
+ }
275
+ renderNode(node, options) {
276
+ const context = node.getNodeName();
277
+ const renderFn = this.renderMap.get(context);
278
+ return renderFn ? renderFn(node, options) : "";
279
+ }
280
+ };
281
+
252
282
  // src/schemas/index.ts
253
283
  import { z as z3 } from "astro/zod";
254
284
 
@@ -359,7 +389,8 @@ function asciidocLoader(_options) {
359
389
  if (options.document.templateEngines === void 0) {
360
390
  options.document.templateEngines = [
361
391
  new HandlebarsEngine(),
362
- new NunjucksEngine()
392
+ new NunjucksEngine(),
393
+ new TemplateStr()
363
394
  ];
364
395
  }
365
396
  let highlighter;
@@ -450,8 +481,16 @@ async function setDocument(doc, converters, templateEngine, { parseData, store }
450
481
  id: doc.slug,
451
482
  data: {
452
483
  title: doc.title,
484
+ subtitle: doc.subtitle,
485
+ author: doc.author,
486
+ authors: doc.authors,
487
+ version: doc.version,
453
488
  createdAt: new Date(doc.createdAt),
454
- description: doc.preamble
489
+ email: doc.authors.at(0)?.getEmail(),
490
+ description: doc.description,
491
+ slug: doc.slug,
492
+ preamble: doc.preamble,
493
+ keywords: doc.keywords
455
494
  }
456
495
  });
457
496
  store.set({
@@ -38,7 +38,9 @@ function splitFilenameComponents(filename) {
38
38
  }
39
39
 
40
40
  // src/lib/asciidoc/converters/sourceCodeConverter.ts
41
- var sourceCodeConverter = ({ transformers, template }) => {
41
+ var sourceCodeConverter = (converterOptions) => {
42
+ const transformers = converterOptions?.transformers;
43
+ const template = converterOptions?.template;
42
44
  return (options, highlighter) => {
43
45
  return {
44
46
  nodeContext: "listing",
@@ -1,12 +1,12 @@
1
1
  import { ShikiTransformer } from 'shiki';
2
- import { C as CustomConverterFactoryFn, S as ShikiTransformerFactoryFn } from '../../../index-sFlXF8Qm.cjs';
2
+ import { C as CustomConverterFactoryFn, b as ShikiTransformerFactoryFn } from '../../../index-R3g0cYiE.cjs';
3
3
  import 'asciidoctor';
4
4
  import 'astro/zod';
5
5
 
6
- type CodeBlockConverterOptions = {
6
+ type CodeBlockConverterOptions = Partial<{
7
7
  transformers: Array<ShikiTransformer | ShikiTransformerFactoryFn>;
8
8
  template: string;
9
- };
10
- declare const sourceCodeConverter: CustomConverterFactoryFn<Partial<CodeBlockConverterOptions>>;
9
+ }>;
10
+ declare const sourceCodeConverter: CustomConverterFactoryFn<CodeBlockConverterOptions>;
11
11
 
12
12
  export { sourceCodeConverter };
@@ -1,12 +1,12 @@
1
1
  import { ShikiTransformer } from 'shiki';
2
- import { C as CustomConverterFactoryFn, S as ShikiTransformerFactoryFn } from '../../../index-sFlXF8Qm.js';
2
+ import { C as CustomConverterFactoryFn, b as ShikiTransformerFactoryFn } from '../../../index-R3g0cYiE.js';
3
3
  import 'asciidoctor';
4
4
  import 'astro/zod';
5
5
 
6
- type CodeBlockConverterOptions = {
6
+ type CodeBlockConverterOptions = Partial<{
7
7
  transformers: Array<ShikiTransformer | ShikiTransformerFactoryFn>;
8
8
  template: string;
9
- };
10
- declare const sourceCodeConverter: CustomConverterFactoryFn<Partial<CodeBlockConverterOptions>>;
9
+ }>;
10
+ declare const sourceCodeConverter: CustomConverterFactoryFn<CodeBlockConverterOptions>;
11
11
 
12
12
  export { sourceCodeConverter };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  sourceCodeConverter
3
- } from "../../../chunk-KZRXEKZK.js";
3
+ } from "../../../chunk-NC6IZHLR.js";
4
4
  import "../../../chunk-2UGTFP4R.js";
5
5
  export {
6
6
  sourceCodeConverter
@@ -1,4 +1,4 @@
1
- import { c as AbstractEngine, a as AsciidocTemplate, T as TemplateModule, F as FilesystemTemplate, R as RawTemplate } from '../../../../index-sFlXF8Qm.cjs';
1
+ import { c as AbstractEngine, a as AsciidocTemplate, T as TemplateModule, F as FilesystemTemplate, R as RawTemplate } from '../../../../index-R3g0cYiE.cjs';
2
2
  import { AbstractBlock } from 'asciidoctor';
3
3
  import 'shiki';
4
4
  import 'astro/zod';
@@ -1,4 +1,4 @@
1
- import { c as AbstractEngine, a as AsciidocTemplate, T as TemplateModule, F as FilesystemTemplate, R as RawTemplate } from '../../../../index-sFlXF8Qm.js';
1
+ import { c as AbstractEngine, a as AsciidocTemplate, T as TemplateModule, F as FilesystemTemplate, R as RawTemplate } from '../../../../index-R3g0cYiE.js';
2
2
  import { AbstractBlock } from 'asciidoctor';
3
3
  import 'shiki';
4
4
  import 'astro/zod';
@@ -21,7 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var transformers_exports = {};
22
22
  __export(transformers_exports, {
23
23
  transformAsciidocCallout: () => transformAsciidocCallout,
24
- transformConsolePrompt: () => transformConsolePrompt
24
+ transformerPrompt: () => transformerPrompt
25
25
  });
26
26
  module.exports = __toCommonJS(transformers_exports);
27
27
 
@@ -89,42 +89,31 @@ var transformAsciidocCallout = (options) => {
89
89
  };
90
90
  };
91
91
 
92
- // src/lib/shiki/transformers/transformConsolePrompt.ts
93
- var transformConsolePrompt = (options) => {
92
+ // src/lib/shiki/transformers/transformerPrompt.ts
93
+ var transformerPrompt = (options) => {
94
94
  return (node) => {
95
95
  const language = node.getAttribute("language");
96
- const cssClasses = options?.cssClasses;
97
- const promptChar = options?.promptChar ?? "$";
98
- const unselectablePrompt = `<span $1 class="${cssClasses}">${promptChar}</span>`;
99
- const linePrefix = '<span class="line[^>]+?>';
100
- const splitPrompt = new RegExp(
101
- `(?<=${linePrefix})(?:<span (style="[^"]*?")>\\s*?\\${promptChar}\\s+?([^<]))`
102
- );
103
- const trimWhitespace = new RegExp(
104
- `(?<=${linePrefix})(?:<span (style="[^"]*?")>\\s*?\\${promptChar}\\s*?<\\/span>(?:<span>\\s+<\\/span>)?)`
105
- );
106
- const trimWhitespaceAhead = new RegExp(
107
- `(?<=${linePrefix}<span [^>]+?>\\${promptChar}<\\/span>)(<span style="[^"]+?">)\\s+?`
96
+ const customPrompt = node.getAttribute(
97
+ options?.promptAttribute ?? "custom-prompt"
108
98
  );
99
+ const promptToAdd = customPrompt ?? (options?.langs && options.langs[language]);
100
+ const cssClasses = typeof promptToAdd === "object" ? promptToAdd.cssClasses : options?.cssClasses;
109
101
  return {
110
102
  line(hast) {
111
- if (language !== "console") return;
112
- const textNode = hast.children.at(0)?.children.at(0);
113
- if (textNode && textNode.type === "text") {
114
- const leadingChar = textNode.value;
115
- if (!leadingChar.startsWith(promptChar)) {
116
- textNode.value = promptChar + " " + textNode.value;
117
- }
118
- }
119
- },
120
- postprocess: (html) => {
121
- if (language !== "console") return;
122
- return html.split("\n").map((line) => {
123
- return line.replace(
124
- splitPrompt,
125
- unselectablePrompt + "<span $1>$2"
126
- ).replace(trimWhitespace, unselectablePrompt).replace(trimWhitespaceAhead, "$1");
127
- }).join("\n");
103
+ if (!promptToAdd) return;
104
+ hast.children.unshift({
105
+ type: "element",
106
+ tagName: "span",
107
+ properties: {
108
+ class: cssClasses
109
+ },
110
+ children: [
111
+ {
112
+ type: "text",
113
+ value: typeof promptToAdd === "object" ? promptToAdd.prompt : promptToAdd
114
+ }
115
+ ]
116
+ });
128
117
  }
129
118
  };
130
119
  };
@@ -132,5 +121,5 @@ var transformConsolePrompt = (options) => {
132
121
  // Annotate the CommonJS export names for ESM import in node:
133
122
  0 && (module.exports = {
134
123
  transformAsciidocCallout,
135
- transformConsolePrompt
124
+ transformerPrompt
136
125
  });
@@ -1,4 +1,5 @@
1
- import { b as ShikiTransformerFactory } from '../../../index-sFlXF8Qm.cjs';
1
+ import { S as ShikiTransformerFactory } from '../../../index-R3g0cYiE.cjs';
2
+ import { BundledLanguage } from 'shiki/types';
2
3
  import 'shiki';
3
4
  import 'asciidoctor';
4
5
  import 'astro/zod';
@@ -8,43 +9,32 @@ type TransformerOptions = Partial<{
8
9
  }>;
9
10
  declare const transformAsciidocCallout: ShikiTransformerFactory<TransformerOptions>;
10
11
 
12
+ type PromptOptions = {
13
+ prompt: string;
14
+ cssClasses: string;
15
+ };
11
16
  type TransformOptions = {
12
17
  /**
13
18
  * String of CSS classes to apply to leading prompt character(s) on
14
19
  * source code blocks of type console.
15
20
  */
16
- cssClasses: string;
21
+ cssClasses?: string;
22
+ /**
23
+ * An object mapping each language block to a prompt string. An object
24
+ * can also be provided specified with two keys, the prompt and the
25
+ * css classes that modify this prompt in particular. Useful when you
26
+ * want to style them differently from the
27
+ * If not provided, it will default to look at the block attribute.
28
+ */
29
+ langs?: Partial<Record<BundledLanguage, PromptOptions | string>>;
17
30
  /**
18
- * The prompt character representing the actual console prompt.
31
+ * The name of the block attribute on the original document to look
32
+ * for and use as the prompt for this block.
19
33
  *
20
- * @default $
34
+ * @default custom-prompt
21
35
  */
22
- promptChar?: string;
36
+ promptAttribute?: string;
23
37
  };
24
- /**
25
- * For code blocks of language "console", prepends each line with a
26
- * prompt character(s), where applicable. By default, a "$" is used but
27
- * this can be controlled via the *promptChar* option.
28
- * Use the *cssClasses* option to style this prompt for things like
29
- * making it unselectable, or dimmed..
30
- *
31
- * In addition, the leading spaces before the actual command are deleted
32
- * from the span elements generated by Shiki to avoid accidentally
33
- * running commands that would not appear in the shell history.
34
- *
35
- * @example
36
- * before: <span>$ npm run dev</span>
37
- * after: <span>$</span><span>npm run dev</span>
38
- *
39
- * @example
40
- * before: <span> $ </span><span> </span>
41
- * before: <span> $ </span>
42
- * after: <span>$</span>
43
- *
44
- * @example
45
- * before: <span>$</span><span> npm run dev</span>
46
- * after: <span>$</span><span>npm run dev</span>
47
- */
48
- declare const transformConsolePrompt: ShikiTransformerFactory<TransformOptions>;
38
+ declare const transformerPrompt: ShikiTransformerFactory<TransformOptions>;
49
39
 
50
- export { transformAsciidocCallout, transformConsolePrompt };
40
+ export { transformAsciidocCallout, transformerPrompt };
@@ -1,4 +1,5 @@
1
- import { b as ShikiTransformerFactory } from '../../../index-sFlXF8Qm.js';
1
+ import { S as ShikiTransformerFactory } from '../../../index-R3g0cYiE.js';
2
+ import { BundledLanguage } from 'shiki/types';
2
3
  import 'shiki';
3
4
  import 'asciidoctor';
4
5
  import 'astro/zod';
@@ -8,43 +9,32 @@ type TransformerOptions = Partial<{
8
9
  }>;
9
10
  declare const transformAsciidocCallout: ShikiTransformerFactory<TransformerOptions>;
10
11
 
12
+ type PromptOptions = {
13
+ prompt: string;
14
+ cssClasses: string;
15
+ };
11
16
  type TransformOptions = {
12
17
  /**
13
18
  * String of CSS classes to apply to leading prompt character(s) on
14
19
  * source code blocks of type console.
15
20
  */
16
- cssClasses: string;
21
+ cssClasses?: string;
22
+ /**
23
+ * An object mapping each language block to a prompt string. An object
24
+ * can also be provided specified with two keys, the prompt and the
25
+ * css classes that modify this prompt in particular. Useful when you
26
+ * want to style them differently from the
27
+ * If not provided, it will default to look at the block attribute.
28
+ */
29
+ langs?: Partial<Record<BundledLanguage, PromptOptions | string>>;
17
30
  /**
18
- * The prompt character representing the actual console prompt.
31
+ * The name of the block attribute on the original document to look
32
+ * for and use as the prompt for this block.
19
33
  *
20
- * @default $
34
+ * @default custom-prompt
21
35
  */
22
- promptChar?: string;
36
+ promptAttribute?: string;
23
37
  };
24
- /**
25
- * For code blocks of language "console", prepends each line with a
26
- * prompt character(s), where applicable. By default, a "$" is used but
27
- * this can be controlled via the *promptChar* option.
28
- * Use the *cssClasses* option to style this prompt for things like
29
- * making it unselectable, or dimmed..
30
- *
31
- * In addition, the leading spaces before the actual command are deleted
32
- * from the span elements generated by Shiki to avoid accidentally
33
- * running commands that would not appear in the shell history.
34
- *
35
- * @example
36
- * before: <span>$ npm run dev</span>
37
- * after: <span>$</span><span>npm run dev</span>
38
- *
39
- * @example
40
- * before: <span> $ </span><span> </span>
41
- * before: <span> $ </span>
42
- * after: <span>$</span>
43
- *
44
- * @example
45
- * before: <span>$</span><span> npm run dev</span>
46
- * after: <span>$</span><span>npm run dev</span>
47
- */
48
- declare const transformConsolePrompt: ShikiTransformerFactory<TransformOptions>;
38
+ declare const transformerPrompt: ShikiTransformerFactory<TransformOptions>;
49
39
 
50
- export { transformAsciidocCallout, transformConsolePrompt };
40
+ export { transformAsciidocCallout, transformerPrompt };
@@ -3,47 +3,36 @@ import {
3
3
  } from "../../../chunk-5P6LDJGO.js";
4
4
  import "../../../chunk-2UGTFP4R.js";
5
5
 
6
- // src/lib/shiki/transformers/transformConsolePrompt.ts
7
- var transformConsolePrompt = (options) => {
6
+ // src/lib/shiki/transformers/transformerPrompt.ts
7
+ var transformerPrompt = (options) => {
8
8
  return (node) => {
9
9
  const language = node.getAttribute("language");
10
- const cssClasses = options?.cssClasses;
11
- const promptChar = options?.promptChar ?? "$";
12
- const unselectablePrompt = `<span $1 class="${cssClasses}">${promptChar}</span>`;
13
- const linePrefix = '<span class="line[^>]+?>';
14
- const splitPrompt = new RegExp(
15
- `(?<=${linePrefix})(?:<span (style="[^"]*?")>\\s*?\\${promptChar}\\s+?([^<]))`
16
- );
17
- const trimWhitespace = new RegExp(
18
- `(?<=${linePrefix})(?:<span (style="[^"]*?")>\\s*?\\${promptChar}\\s*?<\\/span>(?:<span>\\s+<\\/span>)?)`
19
- );
20
- const trimWhitespaceAhead = new RegExp(
21
- `(?<=${linePrefix}<span [^>]+?>\\${promptChar}<\\/span>)(<span style="[^"]+?">)\\s+?`
10
+ const customPrompt = node.getAttribute(
11
+ options?.promptAttribute ?? "custom-prompt"
22
12
  );
13
+ const promptToAdd = customPrompt ?? (options?.langs && options.langs[language]);
14
+ const cssClasses = typeof promptToAdd === "object" ? promptToAdd.cssClasses : options?.cssClasses;
23
15
  return {
24
16
  line(hast) {
25
- if (language !== "console") return;
26
- const textNode = hast.children.at(0)?.children.at(0);
27
- if (textNode && textNode.type === "text") {
28
- const leadingChar = textNode.value;
29
- if (!leadingChar.startsWith(promptChar)) {
30
- textNode.value = promptChar + " " + textNode.value;
31
- }
32
- }
33
- },
34
- postprocess: (html) => {
35
- if (language !== "console") return;
36
- return html.split("\n").map((line) => {
37
- return line.replace(
38
- splitPrompt,
39
- unselectablePrompt + "<span $1>$2"
40
- ).replace(trimWhitespace, unselectablePrompt).replace(trimWhitespaceAhead, "$1");
41
- }).join("\n");
17
+ if (!promptToAdd) return;
18
+ hast.children.unshift({
19
+ type: "element",
20
+ tagName: "span",
21
+ properties: {
22
+ class: cssClasses
23
+ },
24
+ children: [
25
+ {
26
+ type: "text",
27
+ value: typeof promptToAdd === "object" ? promptToAdd.prompt : promptToAdd
28
+ }
29
+ ]
30
+ });
42
31
  }
43
32
  };
44
33
  };
45
34
  };
46
35
  export {
47
36
  transformAsciidocCallout,
48
- transformConsolePrompt
37
+ transformerPrompt
49
38
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@d10f/asciidoc-astro-loader",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "description": "An Astro collections loader for Asciidoc files",
5
5
  "author": "D10f",
6
6
  "license": "MIT",