Skip to content

Commit

Permalink
feat: register this as an antora extension
Browse files Browse the repository at this point in the history
  • Loading branch information
lask79 committed Jan 16, 2024
1 parent be2f542 commit 10ecde0
Show file tree
Hide file tree
Showing 18 changed files with 289 additions and 615 deletions.
2 changes: 2 additions & 0 deletions .asciidoctorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
:icons: font
:source-highlighter: highlightjs
1 change: 0 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,4 @@
},
"asciidoc.extensions.registerWorkspaceExtensions": true,
"asciidoc.preview.refreshInterval": 500,

}
49 changes: 39 additions & 10 deletions README.adoc
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
= asciidoctor-treeview
:source-highlighter: highlight.js
:url-repo: https://github.com/lask79/asciidoctor-treeview
:url-antora-docs: https://docs.antora.org/antora/3.1
:toc: macro
Expand All @@ -21,6 +20,7 @@ toc::[]
|===

* No scripts used (no highlight.js or custom scripts)
* Supports Antora and Asciidoctor standalone

* Generates treeview based on:
** ascii-tree (using tree command on Linux or Windows)
Expand All @@ -39,20 +39,16 @@ toc::[]
* Uses different icons for dark and light mode
* Supports callouts / conums

**IN WORK**

* antora support to customize the treeview and css handling

== Installation

add this to your `package.json` to dependencies

```
npm i asciidoctor-treeview
```

== Register extension

=== Asciidoctor

.Asciidoctor
[source, javascript]
----
Expand All @@ -62,14 +58,47 @@ const registry = asciidoctor.Extensions.create()
asciidoctorTreeView.register(registry)
----

.Antora Playbook
NOTE: The needed css file is added via `DocInfoProcessor`.

=== Antora

==== Antora Playbook
[source, yaml]
----
asciidoc:
antora:
extensions:
- 'asciidoctor-treeview'
- require: "asciidoctor-treeview"
----

WARNING: Do not add the asciidoctor-treeview to the asciidoc.extensions. It will not work because then the needed css will not be added to the site.

==== Add handlebars template

You have to change 1 file in your Antora UI bundle or by overwriting it via supplemental-ui:

* add `{{> treeview-styles }}` to `partials/head-styles.hbs`

If you do not want to change your UI bundle or when you use the default ui bundle you can simply put the following lines into `supplemental-ui/partials/head-styles.hbs` next to your `antora playbook`:

.head-styles.hbs
[source,html]
----
<link rel="stylesheet" href="{{{uiRootPath}}}/css/site.css">
{{> treeview-styles }}
----

`{{> treeview-styles }}` will be replaced with the content of the file `treeview-styles.hbs` that provided by this extension.

.treeview-styles.hbs
[source,html]
----
<link rel="stylesheet" href="{{{uiRootPath}}}/css/treeview.css">
----

The `treeview.css` file contains some treeview specific styles that are needed to render the code blocks correctly and overrides some styles defined in the https://docs.antora.org/antora-ui-default/[Antora UI Default].

=== VSCode

.VSCode
[source,javascript]
----
Expand Down
6 changes: 6 additions & 0 deletions lib/css/treeview.css → data/css/treeview.css
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,19 @@
background-color: var(--treeview-background-color, #222);
color: var(--treeview-font-color, #d8dee9);
line-height: var(--treeview-line-height, 1);
padding: 0.5em;
border-radius: 4px;
}

.tv-line {
display: inline-flex;
align-items: center;
}

.tv-line-element {
display: contents;
}

.tv-line-element > img {
height: var(--treeview-icon-height, 18px);
width: var(--treeview-icon-width, 18px);
Expand Down
1 change: 1 addition & 0 deletions data/partials/treeview-styles.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<link rel="stylesheet" href="{{{uiRootPath}}}/css/treeview.css">
5 changes: 5 additions & 0 deletions docs/antora.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
name: treeview
title: TreeView Example
version: ~
nav:
- modules/ROOT/nav.adoc
563 changes: 0 additions & 563 deletions docs/index.html

This file was deleted.

1 change: 1 addition & 0 deletions docs/modules/ROOT/nav.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* xref:index.adoc[]
File renamed without changes.
59 changes: 59 additions & 0 deletions lib/antora/extension.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
'use strict'

const ospath = require('path')
const { name: packageName } = require('../../package.json')
const { assetFile, partialFile } = require('./utils/asset-utils')

module.exports = function (context, { playbook, config }) {
const logger = context.getLogger(packageName)

logger.info('Start extension')
logger.info(' > Register asciidoctor-treeview as asciidoc extension')
playbook.asciidoc.extensions.push('asciidoctor-treeview')

context.on('uiLoaded', async ({ playbook, uiCatalog }) => {
logger.info('Handle UICatalog files ...')

const extensionContext = {
logger,
}

const { uiOutputDir, cacheDir = './.cache/antora' } = getDirectories(playbook)
extensionContext.playbook = playbook
extensionContext.uiCatalog = uiCatalog
extensionContext.uiOutputDir = uiOutputDir
extensionContext.cacheDir = cacheDir
extensionContext.extensionCacheDir = ospath.join(cacheDir, '..', packageName)

await processAssets(extensionContext)
})

function getDirectories (playbook) {
return {
uiOutputDir: playbook.ui.outputDir,
cacheDir: playbook.runtime.cacheDir,
}
}

async function processAssets (extensionContext) {
copyTreeViewStyleCss(extensionContext)
copyTreeViewStyleHbs(extensionContext)
}

function copyTreeViewStyleCss (extensionContext) {
const { uiCatalog, uiOutputDir, logger } = extensionContext

const basename = 'treeview.css'
const cssDir = 'css'
assetFile(packageName, uiCatalog, logger, uiOutputDir, cssDir, basename)
}

function copyTreeViewStyleHbs (extensionContext) {
const { uiCatalog, uiOutputDir, logger } = extensionContext

const basename = 'treeview-styles.hbs'
const assetDir = 'partials'

partialFile(packageName, uiCatalog, logger, uiOutputDir, assetDir, basename)
}
}
90 changes: 90 additions & 0 deletions lib/antora/utils/asset-utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
const LazyReadable = require('./lazy-readable')
const fs = require('fs')
const path = require('path')

const ASSET_TYPE = 'asset'
const PARTIAL_TYPE = 'partial'
const DATA_DIR = path.join(__dirname, '../../../data')

function handleFile (
type,
packageName,
uiCatalog,
logger,
uiOutputDir,
assetDir,
basename,
createContents,
overwrite
) {
const assetPath = path.join(assetDir, basename)
const outputDir = path.join(uiOutputDir, assetDir)
const existingFiles = uiCatalog.findByType(type)
const existingFile = existingFiles.find((file) => file.path === assetPath)

if (existingFile) {
if (overwrite) {
logger.warn(` > Please remove the following file from your UI since it is managed by ${packageName}: ${assetPath}`)
existingFile.contents = createContents(assetPath)
delete existingFile.stat
} else {
logger.warn(' > The following file already exists in your UI => skipping ...')

const isUIBundle = !existingFile._cwd.endsWith('/supplemental-ui')

logger.info(` > ${assetPath} from ${existingFile._cwd} ${isUIBundle ? '(UI Bundle)' : ''}`)
}
} else {
const fileDetails = {
contents: createContents(assetPath),
type: type,
path: assetPath,
out: { dirname: outputDir, path: path.join(outputDir, basename), basename },
}

if (type === PARTIAL_TYPE) {
fileDetails.stem = basename.replace('.hbs', '')
}

logger.info(` > Copying ${assetPath} to ${outputDir}`)
uiCatalog.addFile(fileDetails)
}
}

function assetFile (packageName, uiCatalog, logger, uiOutputDir, assetDir, basename, overwrite = false) {
handleFile(
ASSET_TYPE,
packageName,
uiCatalog,
logger,
uiOutputDir,
assetDir,
basename,
(assetPath) => new LazyReadable(() => fs.createReadStream(path.join(DATA_DIR, assetPath))),
overwrite
)
}

function partialFile (packageName, uiCatalog, logger, uiOutputDir, assetDir, basename, overwrite = false) {
handleFile(
PARTIAL_TYPE,
packageName,
uiCatalog,
logger,
uiOutputDir,
assetDir,
basename,
(assetPath) => Buffer.from(fs.readFileSync(path.join(DATA_DIR, assetPath))),
overwrite
)
}

function getPartialFileContent (packageName, uiCatalog, logger, uiOutputDir, assetDir, basename) {
const assetPath = path.join(assetDir, basename)
const existingFiles = uiCatalog.findByType(PARTIAL_TYPE)
const existingFile = existingFiles.find((file) => file.path === assetPath)

return existingFile.contents.toString()
}

module.exports = { assetFile, partialFile, getPartialFileContent }
10 changes: 10 additions & 0 deletions lib/antora/utils/folder-utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const fs = require('fs')

function createFolder (folderPath, logger) {
if (!fs.existsSync(folderPath)) {
logger.debug(' > Create folder: ' + folderPath)
fs.mkdirSync(folderPath, { recursive: true })
}
}

module.exports = { createFolder }
18 changes: 18 additions & 0 deletions lib/antora/utils/lazy-readable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
'use strict'

const { PassThrough } = require('stream')

// adapted from https://github.com/jpommerening/node-lazystream/blob/master/lib/lazystream.js | license: MIT
class LazyReadable extends PassThrough {
constructor (fn, options) {
super(options)
this._read = function () {
delete this._read // restores original method
fn.call(this, options).on('error', this.emit.bind(this, 'error')).pipe(this)
return this._read.apply(this, arguments)
}
this.emit('readable')
}
}

module.exports = LazyReadable
14 changes: 10 additions & 4 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
'use strict'

const toProc = require('./util/to-proc')
const { readFileSync, createWriteStream } = require('fs')
const { readFileSync } = require('fs')

const calloutsSubs = require('./callouts/callouts-substitutor')

const registerAntoraExtension = require('./antora/extension')

const TreeViewRenderer = require('./renderer/treeview-renderer')
const treeViewRenderer = new TreeViewRenderer()

function register (registry) {
function register (registry, context) {
if (context?.playbook) {
registerAntoraExtension(registry, context)
return
}

if (!registry) return this.register('treeview', createExtensionGroup())
registry.$groups().$store('treeview', toProc(createExtensionGroup()))
return registry
Expand Down Expand Up @@ -36,7 +43,6 @@ function registerBlockProcessor (context) {
let renderedLines = renderedSource.split('\n')

if (callouts) {
// $FlowFixMe bug in Flow
renderedLines = renderedLines.map((line, ln) => insertBeforeLastSpan(line, `${callouts.convertLine(ln) || ''}`))
}

Expand All @@ -53,7 +59,7 @@ function registerDocInfoProcessor (context) {
const self = this
self.atLocation('header')
self.process(function (doc) {
const css = readFileSync(require.resolve('./css/treeview.css'), { encoding: 'utf8' })
const css = readFileSync(require.resolve('../data/css/treeview.css'), { encoding: 'utf8' })
return `<style>${css}</style>`
})
})
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
"prepublishOnly": "npx -y downdoc --prepublish"
},
"files": [
"lib"
"lib",
"data"
],
"keywords": [
"asciidoctor",
Expand Down
1 change: 0 additions & 1 deletion tests/extension.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,5 @@ root1
----`

const html = asciidoctor.convert(source, { extension_registry: registry })
console.log(html)
})
})
18 changes: 6 additions & 12 deletions tests/inputs/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@

[treeview]
----
README.adoc <.> <.>
README.md <.>
README.adoc <1> <2>
README.md <3>
----
<.> Conum 1
<.> Conum 2
<.> Conum 3
<1> Conum 1
<2> Conum 2
<3> Conum 3


.Test Directory Structure
Expand Down Expand Up @@ -205,10 +205,4 @@ README.adoc
- package.json
----

[myCustomBlock]
----
This is a custom block.
Here is a <1> example. <3>
Another <2> line.
----
<1>

Loading

0 comments on commit 10ecde0

Please sign in to comment.