Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
sransara committed Jun 30, 2024
1 parent b5fed73 commit 4cc0a80
Show file tree
Hide file tree
Showing 17 changed files with 387 additions and 183 deletions.
34 changes: 20 additions & 14 deletions adocx.config.js → adocx/config.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,34 @@
import path from 'node:path';

// @ts-ignore: Types are not available
import { register as krokiPluginRegisterHandle } from 'asciidoctor-kroki';
import { register as converterRegisterHandle } from 'astro-adocx/converter';
import { register as inlineMacroCalloutRegisterHandle } from './adocx/extensions/inlineMacroCallout';
import type { AdocOptions, AstroAdocxOptions, Template } from 'astro-adocx/types';

import { register as inlineMacroCalloutRegisterHandle } from './extensions/inlineMacroCallout';

const astroFenced = `
import Katex from '@/src/lib/astro/katex/Katex.astro';
import Shiki from '@/src/lib/astro/shiki/Shiki.astro';
`;
const templates = Object.fromEntries(
Object.entries(import.meta.glob('./templates/*.ts', { eager: true })).map(([key, value]) => [
path.basename(key, '.ts'),
value as Template,
]),
);

const astroFenced = ``;

/** @type { import('astro-adocx/integration').AstroAdocxOptions } */
export const adocxConfig = {
astroFenced,
withAsciidocEngine(asciidoctorEngine) {
converterRegisterHandle(asciidoctorEngine);
krokiPluginRegisterHandle(asciidoctorEngine.Extensions);
inlineMacroCalloutRegisterHandle(asciidoctorEngine.Extensions);
},
};
withDocument(filePath, document) {
// useful for asciidoctor-diagrams/kroki
document.setAttribute('outdir', path.dirname(filePath));
},
templates,
} satisfies AstroAdocxOptions;

/** @type { import('astro-adocx/integration').AdocOptions } */
export const asciidoctorConfig = {
safe: 'server',
backend: 'html5',
standalone: false,
attributes: {
xrefstyle: 'full',
'listing-caption': 'Listing',
Expand All @@ -36,4 +42,4 @@ export const asciidoctorConfig = {
'kroki-fetch-diagram': true,
'kroki-default-format': 'png',
},
};
} satisfies AdocOptions;
12 changes: 12 additions & 0 deletions adocx/templates/inline_quoted.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { Inline } from 'asciidoctor';
import { UnsupportedNode, type Template } from 'astro-adocx/types.ts';
import { addOnceToAstroFence } from 'astro-adocx/utils/astroFence.ts';

export const convert: Template<Inline>['convert'] = (node: Inline, opts?: any) => {
const nodeType = node.getType();
if (['asciimath', 'latexmath'].includes(nodeType)) {
addOnceToAstroFence(node, "import Katex from '@/src/lib/astro/katex/Katex.astro';");
return `<Katex block={false} lang="${nodeType}" is:raw={true}>${node.getText()}</Katex>`;
}
return UnsupportedNode;
};
2 changes: 1 addition & 1 deletion astro.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import tailwind from '@astrojs/tailwind';
import { adocx } from 'astro-adocx/integration';
import { defineConfig } from 'astro/config';

import { adocxConfig, asciidoctorConfig } from './adocx.config.js';
import { adocxConfig, asciidoctorConfig } from './adocx/config.ts';
import siteValues from './site.values.js';

export default defineConfig({
Expand Down
31 changes: 19 additions & 12 deletions linkd/astro-adocx/converter.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import type { AbstractNode, Asciidoctor, Html5Converter } from 'asciidoctor';

export type Template = {
supports: (node: AbstractNode, opts?: any) => boolean;
convert: (node: AbstractNode, opts?: any) => string;
};
import { UnsupportedNode, type Template } from './types';

const imports = import.meta.glob('./templates/*.ts', { eager: true });
export const builtinTemplates = Object.fromEntries(
Expand All @@ -20,25 +16,36 @@ class Converter {
supports_templates: false,
};

constructor(asciidoctorEngine: Asciidoctor, templates: Record<string, Template> = {}) {
constructor(asciidoctorEngine: Asciidoctor, templates: Record<string, Template>) {
this.baseConverter = asciidoctorEngine.Html5Converter.create();
this.templates = templates;
}

convert(node: AbstractNode, transform?: string, opts?: any) {
const nodeName = transform ?? node.getNodeName();
// console.log(`Processing ${nodeName}`);
const template = this.templates[nodeName];
if (template && template.supports(node, opts)) {
return template.convert(node, opts);
if (template !== undefined) {
// console.log(`Found template ${nodeName}`);
const converted = template.convert(node, opts);
if (converted !== UnsupportedNode) {
return converted;
}
}
const builtinTemplate = builtinTemplates[nodeName];
if (builtinTemplate && builtinTemplate.supports(node, opts)) {
return builtinTemplate.convert(node, opts);
if (builtinTemplate !== undefined) {
// console.log(`Found builtin template ${nodeName}`);
const converted = builtinTemplate.convert(node, opts);
if (converted !== UnsupportedNode) {
return converted;
}
}
// console.log(`No template found for ${nodeName}`);
return this.baseConverter.convert(node, transform, opts);
}
}

export const register = (asciidoctorEngine: Asciidoctor) => {
asciidoctorEngine.ConverterFactory.register(new Converter(asciidoctorEngine), ['html5']);
export const register = (asciidoctorEngine: Asciidoctor, templates: Record<string, Template>) => {
const converter = new Converter(asciidoctorEngine, templates);
asciidoctorEngine.ConverterFactory.register(converter, ['html5']);
};
82 changes: 0 additions & 82 deletions linkd/astro-adocx/extensions/postProcessor.ts

This file was deleted.

112 changes: 57 additions & 55 deletions linkd/astro-adocx/integration.ts
Original file line number Diff line number Diff line change
@@ -1,52 +1,45 @@
import fs from 'node:fs';
import path from 'node:path';

import asciidoctor, { type Asciidoctor, type ProcessorOptions } from 'asciidoctor';
import type { Asciidoctor, ProcessorOptions } from 'asciidoctor';
import asciidoctor from 'asciidoctor';
import type { AstroIntegration } from 'astro';
import type { Plugin as VitePlugin } from 'vite';
import {
compileAstro,
type CompileAstroResult,
} from './node_modules/astro/dist/vite-plugin-astro/compile.js';

import { register as postProcessorRegisterHandle } from './extensions/postProcessor.ts';
import { register as converterRegisterHandle } from './converter.ts';
import subSpecialchars from './patches/sub_specialchars';

export type AstroAdocxOptions = {
astroFenced?: string;
withAsciidocEngine?: (asciidoctorEngine: Asciidoctor) => void;
};

export type AdocOptions = ProcessorOptions;
import type { AdocOptions, AstroAdocxOptions } from './types.js';
import { decodeSpecialChars } from './utils/astroFence.ts';

const adocxExtension = '.adoc';

function decodeSpecialChars(str: string) {
return str
.replace(/&lt;/g, '<')
.replace(/&gt;/g, '>')
.replace(/&amp;/g, '&')
.replace(/&lbrace;/g, '{')
.replace(/&rbrace;/g, '}');
}

async function compileAdoc(
asciidoctorEngine: Asciidoctor,
fileId: string,
adocxConfig: AstroAdocxOptions,
asciidoctorConfig: ProcessorOptions,
) {
const document = asciidoctorEngine.loadFile(fileId, asciidoctorConfig);
document.setAttribute('outdir', path.dirname(fileId));
adocxConfig.withDocument?.(fileId, document);

const converted = document.convert();
const docattrs = document.getAttributes() as Record<string, string | undefined>;
const astroFenced = decodeSpecialChars(document.getAttribute('front-matter') ?? '');

// Astro component's fenced code declared in the config
const adocxConfigAstroFenced = adocxConfig.astroFenced ?? '';
// Astro component's fenced code added by the templates
const astroFenced = decodeSpecialChars(document.getAttribute('astro-fenced') ?? '');
// Astro component's fenced code declared in the document itself
const frontMatter = decodeSpecialChars(document.getAttribute('front-matter') ?? '');

const astroComponent = `---
${(adocxConfig.astroFenced ?? '').trim()}
${adocxConfigAstroFenced.trim()}
export let docattrs = ${JSON.stringify(docattrs)};
${astroFenced.trim()}
${frontMatter.trim()}
---
${converted.trim()}
`;
Expand All @@ -65,16 +58,17 @@ export function adocx(
async 'astro:config:setup'({ config: astroConfig, updateConfig, logger }) {
const asciidoctorEngine = asciidoctor();
subSpecialchars.patch();
converterRegisterHandle(asciidoctorEngine, adocxConfig.templates ?? {});
adocxConfig.withAsciidocEngine?.(asciidoctorEngine);

postProcessorRegisterHandle(asciidoctorEngine.Extensions);
if (adocxConfig.withAsciidocEngine) {
adocxConfig.withAsciidocEngine(asciidoctorEngine);
}

// Default asciidoctor config that makes sense in this context
asciidoctorConfig.standalone = false;
asciidoctorConfig.safe = 'server';
asciidoctorConfig.backend = 'html5';
if (asciidoctorConfig.attributes === undefined) {
asciidoctorConfig.attributes = {};
}
// @ts-expect-error: Ignore error because types are confusing in asciidoctor
// allow astro code fences at the beginning
asciidoctorConfig.attributes['skip-front-matter'] = true;

_compileAdoc = async (filename) => {
Expand Down Expand Up @@ -106,11 +100,19 @@ export function adocx(
if (!fileId.endsWith(adocxExtension)) {
return;
}
const astroComponent = await _compileAdoc(fileId);
fs.writeFileSync(fileId.replace(adocxExtension, '.debug.astro'), astroComponent);
return {
code: astroComponent,
};
try {
const astroComponent = await _compileAdoc(fileId);
fs.writeFileSync(
fileId.replace(adocxExtension, '.debug.astro'),
astroComponent,
);
return {
code: astroComponent,
};
} catch (e) {
console.error(e);
throw new Error(`Error processing adoc file: ${fileId}: ${e}`);
}
},
async transform(source, fileId) {
if (!fileId.endsWith(adocxExtension)) {
Expand All @@ -120,31 +122,31 @@ export function adocx(
let transformResult: CompileAstroResult;
try {
transformResult = await _compileAstro(astroComponent, fileId);
} catch (err) {
const astroMetadata = {
clientOnlyComponents: transformResult.clientOnlyComponents,
hydratedComponents: transformResult.hydratedComponents,
scripts: transformResult.scripts,
containsHead: transformResult.containsHead,
propagation: transformResult.propagation ? 'self' : 'none',
pageOptions: {},
};
return {
code: transformResult.code,
map: transformResult.map,
meta: {
astro: astroMetadata,
vite: {
// Setting this vite metadata to `ts` causes Vite to resolve .js
// extensions to .ts files.
lang: 'ts',
},
},
};
} catch (e) {
// @ts-expect-error: Try to inject a file id to the error object
err.loc.file = `${fileId.replace(adocxExtension, '.astro')}`;
throw err;
throw e;
}
const astroMetadata = {
clientOnlyComponents: transformResult.clientOnlyComponents,
hydratedComponents: transformResult.hydratedComponents,
scripts: transformResult.scripts,
containsHead: transformResult.containsHead,
propagation: transformResult.propagation ? 'self' : 'none',
pageOptions: {},
};
return {
code: transformResult.code,
map: transformResult.map,
meta: {
astro: astroMetadata,
vite: {
// Setting this vite metadata to `ts` causes Vite to resolve .js
// extensions to .ts files.
lang: 'ts',
},
},
};
},
},
] as VitePlugin[],
Expand Down
Loading

0 comments on commit 4cc0a80

Please sign in to comment.