mirror of
https://github.com/kovetskiy/mark.git
synced 2025-06-02 03:32:42 +08:00
Add support for d2lang
This commit is contained in:
parent
d1aee4d571
commit
3cc39ffe79
2
Makefile
2
Makefile
@ -19,7 +19,7 @@ build:
|
||||
-gcflags "-trimpath $(GOPATH)/src"
|
||||
|
||||
test:
|
||||
go test -race -coverprofile=profile.cov ./...
|
||||
go test -race -coverprofile=profile.cov ./... -v
|
||||
|
||||
image:
|
||||
@echo :: building image $(NAME):$(VERSION)
|
||||
|
71
README.md
71
README.md
@ -719,7 +719,7 @@ Currently this is not compatible with the automated upload of inline images.
|
||||
### Render Mermaid Diagram
|
||||
|
||||
Confluence doesn't provide [mermaid.js](https://github.com/mermaid-js/mermaid) support natively. Mark provides a convenient way to enable the feature like [Github does](https://github.blog/2022-02-14-include-diagrams-markdown-files-mermaid/).
|
||||
As long as you have a code block and are marked as "mermaid", the mark will automatically render it as a PNG image and insert into before the code block.
|
||||
As long as you have a code block marked as "mermaid", mark will automatically render it as a PNG image and attach it to the page as a rendered version of the code block.
|
||||
|
||||
```mermaid title diagrams_example
|
||||
graph TD;
|
||||
@ -729,7 +729,17 @@ A-->B;
|
||||
In order to properly render mermaid, you can choose between the following mermaid providers:
|
||||
|
||||
* "mermaid-go" via [mermaid.go](https://github.com/dreampuf/mermaid.go)
|
||||
* "cloudscript" via [cloudscript-io-mermaid-addon](https://marketplace.atlassian.com/apps/1219878/cloudscript-io-mermaid-addon)
|
||||
* "cloudscript" via [cloudscript-io-mermaid-addon](https://marketplace.atlassian.com/apps/1219878/cloudscript-io-mermaid-addon) (deprecated)
|
||||
|
||||
### Render D2 Diagram
|
||||
|
||||
Optionally you can enable [D2](https://github.com/terrastruct/d2) rendering via `--features="d2"`.
|
||||
This will transform the d2 diagram into a png that will be attached to Confluence, similar to how mermaid-go support works.
|
||||
All you need is a codeblock marked as "d2".
|
||||
|
||||
```d2
|
||||
X -> Y
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
@ -789,33 +799,36 @@ DESCRIPTION:
|
||||
Mark is a tool to update Atlassian Confluence pages from markdown. Documentation is available here: https://github.com/kovetskiy/mark
|
||||
|
||||
GLOBAL OPTIONS:
|
||||
--files value, -f value use specified markdown file(s) for converting to html. Supports file globbing patterns (needs to be quoted). [$MARK_FILES]
|
||||
--compile-only show resulting HTML and don't update Confluence page content. (default: false) [$MARK_COMPILE_ONLY]
|
||||
--dry-run resolve page and ancestry, show resulting HTML and exit. (default: false) [$MARK_DRY_RUN]
|
||||
--edit-lock, -k lock page editing to current user only to prevent accidental manual edits over Confluence Web UI. (default: false) [$MARK_EDIT_LOCK]
|
||||
--drop-h1, --h1_drop don't include the first H1 heading in Confluence output. (default: false) [$MARK_H1_DROP]
|
||||
--strip-linebreaks, -L remove linebreaks inside of tags, to accommodate non-standard Confluence behavior (default: false) [$MARK_STRIP_LINEBREAKS]
|
||||
--title-from-h1, --h1_title extract page title from a leading H1 heading. If no H1 heading on a page exists, then title must be set in the page metadata. (default: false) [$MARK_H1_TITLE]
|
||||
--title-append-generated-hash appends a short hash generated from the path of the page (space, parents, and title) to the title (default: false) [$MARK_TITLE_APPEND_GENERATED_HASH]
|
||||
--minor-edit don't send notifications while updating Confluence page. (default: false) [$MARK_MINOR_EDIT]
|
||||
--version-message value add a message to the page version, to explain the edit (default: "") [$MARK_VERSION_MESSAGE]
|
||||
--color value display logs in color. Possible values: auto, never. (default: "auto") [$MARK_COLOR]
|
||||
--log-level value set the log level. Possible values: TRACE, DEBUG, INFO, WARNING, ERROR, FATAL. (default: "info") [$MARK_LOG_LEVEL]
|
||||
--username value, -u value use specified username for updating Confluence page. [$MARK_USERNAME]
|
||||
--password value, -p value use specified token for updating Confluence page. Specify - as password to read password from stdin, or your Personal access token. Username is not mandatory if personal access token is provided. For more info please see: https://developer.atlassian.com/server/confluence/confluence-server-rest-api/#authentication. [$MARK_PASSWORD]
|
||||
--target-url value, -l value edit specified Confluence page. If -l is not specified, file should contain metadata (see above). [$MARK_TARGET_URL]
|
||||
--base-url value, -b value, --base_url value base URL for Confluence. Alternative option for base_url config field. [$MARK_BASE_URL]
|
||||
--config value, -c value use the specified configuration file. (default: System specific) [$MARK_CONFIG]
|
||||
--ci run on CI mode. It won't fail if files are not found. (default: false) [$MARK_CI]
|
||||
--space value use specified space key. If the space key is not specified, it must be set in the page metadata. [$MARK_SPACE]
|
||||
--parents value A list containing the parents of the document separated by parents-delimiter (default: '/'). These will be prepended to the ones defined in the document itself. [$MARK_PARENTS]
|
||||
--parents-delimiter value The delimiter used for the parents list (default: "/") [$MARK_PARENTS_DELIMITER]
|
||||
--mermaid-provider value defines the mermaid provider to use. Supported options are: cloudscript, mermaid-go. (default: "cloudscript") [$MARK_MERMAID_PROVIDER]
|
||||
--mermaid-scale value defines the scaling factor for mermaid renderings. (default: 1) [$MARK_MERMAID_SCALE]
|
||||
--include-path value Path for shared includes, used as a fallback if the include doesn't exist in the current directory. [$MARK_INCLUDE_PATH]
|
||||
--changes-only Avoids re-uploading pages that haven't changed since the last run. (default: false) [$MARK_CHANGES_ONLY]
|
||||
--help, -h show help
|
||||
--version, -v print the version
|
||||
--files string, -f string use specified markdown file(s) for converting to html. Supports file globbing patterns (needs to be quoted). [$MARK_FILES]
|
||||
--continue-on-error don't exit if an error occurs while processing a file, continue processing remaining files. (default: false) [$MARK_CONTINUE_ON_ERROR]
|
||||
--compile-only show resulting HTML and don't update Confluence page content. (default: false) [$MARK_COMPILE_ONLY]
|
||||
--dry-run resolve page and ancestry, show resulting HTML and exit. (default: false) [$MARK_DRY_RUN]
|
||||
--edit-lock, -k lock page editing to current user only to prevent accidental manual edits over Confluence Web UI. (default: false) [$MARK_EDIT_LOCK]
|
||||
--drop-h1, --h1_drop don't include the first H1 heading in Confluence output. (default: false) [$MARK_H1_DROP]
|
||||
--strip-linebreaks, -L remove linebreaks inside of tags, to accommodate non-standard Confluence behavior (default: false) [$MARK_STRIP_LINEBREAKS]
|
||||
--title-from-h1, --h1_title extract page title from a leading H1 heading. If no H1 heading on a page exists, then title must be set in the page metadata. (default: false) [$MARK_H1_TITLE]
|
||||
--title-append-generated-hash appends a short hash generated from the path of the page (space, parents, and title) to the title (default: false) [$MARK_TITLE_APPEND_GENERATED_HASH]
|
||||
--minor-edit don't send notifications while updating Confluence page. (default: false) [$MARK_MINOR_EDIT]
|
||||
--version-message string add a message to the page version, to explain the edit (default: "") [$MARK_VERSION_MESSAGE]
|
||||
--color string display logs in color. Possible values: auto, never. (default: "auto") [$MARK_COLOR]
|
||||
--log-level string set the log level. Possible values: TRACE, DEBUG, INFO, WARNING, ERROR, FATAL. (default: "info") [$MARK_LOG_LEVEL]
|
||||
--username string, -u string use specified username for updating Confluence page. [$MARK_USERNAME]
|
||||
--password string, -p string use specified token for updating Confluence page. Specify - as password to read password from stdin, or your Personal access token. Username is not mandatory if personal access token is provided. For more info please see: https://developer.atlassian.com/server/confluence/confluence-server-rest-api/#authentication. [$MARK_PASSWORD]
|
||||
--target-url string, -l string edit specified Confluence page. If -l is not specified, file should contain metadata (see above). [$MARK_TARGET_URL]
|
||||
--base-url string, -b string, --base_url string base URL for Confluence. Alternative option for base_url config field. [$MARK_BASE_URL]
|
||||
--config string, -c string use the specified configuration file. (default: "/home/mrueg/.config/mark") [$MARK_CONFIG]
|
||||
--ci run on CI mode. It won't fail if files are not found. (default: false) [$MARK_CI]
|
||||
--space string use specified space key. If the space key is not specified, it must be set in the page metadata. [$MARK_SPACE]
|
||||
--parents string A list containing the parents of the document separated by parents-delimiter (default: '/'). These will be prepended to the ones defined in the document itself. [$MARK_PARENTS]
|
||||
--parents-delimiter string The delimiter used for the parents list (default: "/") [$MARK_PARENTS_DELIMITER]
|
||||
--mermaid-provider string defines the mermaid provider to use. Supported options are: cloudscript, mermaid-go. (default: "cloudscript") [$MARK_MERMAID_PROVIDER]
|
||||
--mermaid-scale float defines the scaling factor for mermaid renderings. (default: 1) [$MARK_MERMAID_SCALE]
|
||||
--include-path string Path for shared includes, used as a fallback if the include doesn't exist in the current directory. [$MARK_INCLUDE_PATH]
|
||||
--changes-only Avoids re-uploading pages that haven't changed since the last run. (default: false) [$MARK_CHANGES_ONLY]
|
||||
--d2-scale float defines the scaling factor for d2 renderings. (default: 1) [$MARK_D2_SCALE]
|
||||
--features string [ --features string ] Enables optional features. Current features: d2, mermaid (default: "mermaid") [$MARK_FEATURES]
|
||||
--help, -h show help
|
||||
--version, -v print the version
|
||||
```
|
||||
|
||||
You can store user credentials in the configuration file, which should be
|
||||
|
@ -45,7 +45,7 @@ func TestPrepareAttachmentsWithWorkDirBase(t *testing.T) {
|
||||
}
|
||||
|
||||
attaches, err := prepareAttachments(testingOpener, ".", replacements)
|
||||
t.Logf("attaches: %s", err)
|
||||
t.Logf("attaches: %v", err)
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
t.Fatal(err)
|
||||
|
107
d2/d2.go
Normal file
107
d2/d2.go
Normal file
@ -0,0 +1,107 @@
|
||||
package d2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/chromedp/cdproto/dom"
|
||||
"github.com/chromedp/chromedp"
|
||||
|
||||
"github.com/kovetskiy/mark/attachment"
|
||||
"github.com/reconquest/pkg/log"
|
||||
|
||||
"oss.terrastruct.com/d2/d2graph"
|
||||
"oss.terrastruct.com/d2/d2layouts/d2dagrelayout"
|
||||
"oss.terrastruct.com/d2/d2lib"
|
||||
"oss.terrastruct.com/d2/d2renderers/d2svg"
|
||||
"oss.terrastruct.com/d2/d2themes/d2themescatalog"
|
||||
d2log "oss.terrastruct.com/d2/lib/log"
|
||||
"oss.terrastruct.com/d2/lib/textmeasure"
|
||||
"oss.terrastruct.com/util-go/go2"
|
||||
)
|
||||
|
||||
var renderTimeout = 120 * time.Second
|
||||
|
||||
func ProcessD2(title string, d2Diagram []byte, scale float64) (attachment.Attachment, error) {
|
||||
ctx, cancel := context.WithTimeout(context.TODO(), renderTimeout)
|
||||
ctx = d2log.WithDefault(ctx)
|
||||
defer cancel()
|
||||
|
||||
ruler, err := textmeasure.NewRuler()
|
||||
if err != nil {
|
||||
return attachment.Attachment{}, err
|
||||
}
|
||||
layoutResolver := func(engine string) (d2graph.LayoutGraph, error) {
|
||||
return d2dagrelayout.DefaultLayout, nil
|
||||
}
|
||||
renderOpts := &d2svg.RenderOpts{
|
||||
Pad: go2.Pointer(int64(5)),
|
||||
ThemeID: &d2themescatalog.GrapeSoda.ID,
|
||||
}
|
||||
compileOpts := &d2lib.CompileOptions{
|
||||
LayoutResolver: layoutResolver,
|
||||
Ruler: ruler,
|
||||
}
|
||||
|
||||
diagram, _, err := d2lib.Compile(ctx, string(d2Diagram), compileOpts, renderOpts)
|
||||
if err != nil {
|
||||
return attachment.Attachment{}, err
|
||||
}
|
||||
|
||||
out, err := d2svg.Render(diagram, renderOpts)
|
||||
if err != nil {
|
||||
return attachment.Attachment{}, err
|
||||
}
|
||||
|
||||
log.Debugf(nil, "Rendering: %q", title)
|
||||
pngBytes, boxModel, err := convertSVGtoPNG(ctx, out, scale)
|
||||
if err != nil {
|
||||
return attachment.Attachment{}, err
|
||||
}
|
||||
|
||||
checkSum, err := attachment.GetChecksum(bytes.NewReader(d2Diagram))
|
||||
log.Debugf(nil, "Checksum: %q -> %s", title, checkSum)
|
||||
|
||||
if err != nil {
|
||||
return attachment.Attachment{}, err
|
||||
}
|
||||
if title == "" {
|
||||
title = checkSum
|
||||
}
|
||||
|
||||
fileName := title + ".png"
|
||||
|
||||
return attachment.Attachment{
|
||||
ID: "",
|
||||
Name: title,
|
||||
Filename: fileName,
|
||||
FileBytes: pngBytes,
|
||||
Checksum: checkSum,
|
||||
Replace: title,
|
||||
Width: strconv.FormatInt(boxModel.Width, 10),
|
||||
Height: strconv.FormatInt(boxModel.Height, 10),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func convertSVGtoPNG(ctx context.Context, svg []byte, scale float64) (png []byte, m *dom.BoxModel, err error) {
|
||||
var (
|
||||
result []byte
|
||||
model *dom.BoxModel
|
||||
)
|
||||
ctx, cancel := chromedp.NewContext(ctx)
|
||||
defer cancel()
|
||||
|
||||
err = chromedp.Run(ctx,
|
||||
chromedp.Navigate(fmt.Sprintf("data:image/svg+xml;base64,%s", base64.StdEncoding.EncodeToString(svg))),
|
||||
chromedp.ScreenshotScale(`document.querySelector("svg > svg")`, scale, &result, chromedp.ByJSPath),
|
||||
chromedp.Dimensions(`document.querySelector("svg > svg")`, &model, chromedp.ByJSPath),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return result, model, err
|
||||
}
|
102
d2/d2_test.go
Normal file
102
d2/d2_test.go
Normal file
@ -0,0 +1,102 @@
|
||||
package d2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/kovetskiy/mark/attachment"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var diagram string = `d2
|
||||
vars: {
|
||||
d2-config: {
|
||||
layout-engine: elk
|
||||
# Terminal theme code
|
||||
theme-id: 300
|
||||
}
|
||||
}
|
||||
network: {
|
||||
cell tower: {
|
||||
satellites: {
|
||||
shape: stored_data
|
||||
style.multiple: true
|
||||
}
|
||||
|
||||
transmitter
|
||||
|
||||
satellites -> transmitter: send
|
||||
satellites -> transmitter: send
|
||||
satellites -> transmitter: send
|
||||
}
|
||||
|
||||
online portal: {
|
||||
ui: {shape: hexagon}
|
||||
}
|
||||
|
||||
data processor: {
|
||||
storage: {
|
||||
shape: cylinder
|
||||
style.multiple: true
|
||||
}
|
||||
}
|
||||
|
||||
cell tower.transmitter -> data processor.storage: phone logs
|
||||
}
|
||||
|
||||
user: {
|
||||
shape: person
|
||||
width: 130
|
||||
}
|
||||
|
||||
user -> network.cell tower: make call
|
||||
user -> network.online portal.ui: access {
|
||||
style.stroke-dash: 3
|
||||
}
|
||||
|
||||
api server -> network.online portal.ui: display
|
||||
api server -> logs: persist
|
||||
logs: {shape: page; style.multiple: true}
|
||||
|
||||
network.data processor -> api server
|
||||
`
|
||||
|
||||
func TestExtractD2Image(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
markdown []byte
|
||||
scale float64
|
||||
want attachment.Attachment
|
||||
wantErr assert.ErrorAssertionFunc
|
||||
}{
|
||||
{"example", []byte(diagram), 1.0, attachment.Attachment{
|
||||
// This is only the PNG Magic Header
|
||||
FileBytes: []byte{0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa},
|
||||
Filename: "example.png",
|
||||
Name: "example",
|
||||
Replace: "example",
|
||||
Checksum: "58fa387384181445e2d8f90a8c7fda945cb75174f73e8b9853ff59b9e0103ddd",
|
||||
ID: "",
|
||||
Width: "198",
|
||||
Height: "441",
|
||||
},
|
||||
assert.NoError},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := ProcessD2(tt.name, tt.markdown, tt.scale)
|
||||
if !tt.wantErr(t, err, fmt.Sprintf("processD2(%v, %v)", tt.name, string(tt.markdown))) {
|
||||
return
|
||||
}
|
||||
assert.Equal(t, tt.want.Filename, got.Filename, "processD2(%v, %v)", tt.name, string(tt.markdown))
|
||||
// We only test for the header as png changes based on system png library
|
||||
assert.Equal(t, tt.want.FileBytes, got.FileBytes[0:8], "processD2(%v, %v)", tt.name, string(tt.markdown))
|
||||
assert.Equal(t, tt.want.Name, got.Name, "processD2(%v, %v)", tt.name, string(tt.markdown))
|
||||
assert.Equal(t, tt.want.Replace, got.Replace, "processD2(%v, %v)", tt.name, string(tt.markdown))
|
||||
assert.Equal(t, tt.want.Checksum, got.Checksum, "processD2(%v, %v)", tt.name, string(tt.markdown))
|
||||
assert.Equal(t, tt.want.ID, got.ID, "processD2(%v, %v)", tt.name, string(tt.markdown))
|
||||
assert.Equal(t, tt.want.Width, got.Width, "processD2(%v, %v)", tt.name, string(tt.markdown))
|
||||
assert.Equal(t, tt.want.Height, got.Height, "processD2(%v, %v)", tt.name, string(tt.markdown))
|
||||
})
|
||||
}
|
||||
}
|
23
go.mod
23
go.mod
@ -6,6 +6,8 @@ toolchain go1.24.2
|
||||
|
||||
require (
|
||||
github.com/bmatcuk/doublestar/v4 v4.8.1
|
||||
github.com/chromedp/cdproto v0.0.0-20250319231242-a755498943c8
|
||||
github.com/chromedp/chromedp v0.13.3
|
||||
github.com/dreampuf/mermaid.go v0.0.27
|
||||
github.com/kovetskiy/gopencils v0.0.0-20250404051442-0b776066936a
|
||||
github.com/kovetskiy/lorg v1.2.1-0.20240830111423-ba4fe8b6f7c4
|
||||
@ -18,22 +20,39 @@ require (
|
||||
github.com/yuin/goldmark v1.7.12
|
||||
golang.org/x/tools v0.33.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
oss.terrastruct.com/d2 v0.7.0
|
||||
oss.terrastruct.com/util-go v0.0.0-20250213174338-243d8661088a
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.5.0 // indirect
|
||||
github.com/chromedp/cdproto v0.0.0-20250319231242-a755498943c8 // indirect
|
||||
github.com/chromedp/chromedp v0.13.3 // indirect
|
||||
github.com/PuerkitoBio/goquery v1.10.0 // indirect
|
||||
github.com/alecthomas/chroma/v2 v2.14.0 // indirect
|
||||
github.com/andybalholm/cascadia v1.3.2 // indirect
|
||||
github.com/chromedp/sysutil v1.1.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dlclark/regexp2 v1.11.4 // indirect
|
||||
github.com/dop251/goja v0.0.0-20240927123429-241b342198c2 // indirect
|
||||
github.com/go-json-experiment/json v0.0.0-20250211171154-1ae217ad3535 // indirect
|
||||
github.com/go-sourcemap/sourcemap v2.1.4+incompatible // indirect
|
||||
github.com/gobwas/httphead v0.1.0 // indirect
|
||||
github.com/gobwas/pool v0.2.1 // indirect
|
||||
github.com/gobwas/ws v1.4.0 // indirect
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||
github.com/google/pprof v0.0.0-20240927180334-d43a67379298 // indirect
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||
github.com/mazznoer/csscolorparser v0.1.5 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/reconquest/cog v0.0.0-20240830113510-c7ba12d0beeb // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/zazab/zhash v0.0.0-20221031090444-2b0d50417446 // indirect
|
||||
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect
|
||||
golang.org/x/image v0.20.0 // indirect
|
||||
golang.org/x/net v0.40.0 // indirect
|
||||
golang.org/x/sys v0.33.0 // indirect
|
||||
golang.org/x/text v0.25.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
|
||||
gonum.org/v1/plot v0.14.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
|
||||
)
|
||||
|
96
go.sum
96
go.sum
@ -1,9 +1,27 @@
|
||||
git.sr.ht/~sbinet/gg v0.5.0 h1:6V43j30HM623V329xA9Ntq+WJrMjDxRjuAB1LFWF5m8=
|
||||
git.sr.ht/~sbinet/gg v0.5.0/go.mod h1:G2C0eRESqlKhS7ErsNey6HHrqU1PwsnCQlekFi9Q2Oo=
|
||||
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
||||
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
|
||||
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
|
||||
github.com/PuerkitoBio/goquery v1.10.0 h1:6fiXdLuUvYs2OJSvNRqlNPoBm6YABE226xrbavY5Wv4=
|
||||
github.com/PuerkitoBio/goquery v1.10.0/go.mod h1:TjZZl68Q3eGHNBA8CWaxAN7rOU1EbDz3CWuolcO5Yu4=
|
||||
github.com/Shopify/toxiproxy/v2 v2.12.0 h1:d1x++lYZg/zijXPPcv7PH0MvHMzEI5aX/YuUi/Sw+yg=
|
||||
github.com/Shopify/toxiproxy/v2 v2.12.0/go.mod h1:R9Z38Pw6k2cGZWXHe7tbxjGW9azmY1KbDQJ1kd+h7Tk=
|
||||
github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b h1:slYM766cy2nI3BwyRiyQj/Ud48djTMtMebDqepE95rw=
|
||||
github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM=
|
||||
github.com/alecthomas/assert/v2 v2.7.0 h1:QtqSACNS3tF7oasA8CU6A6sXZSBDqnm7RfpLl9bZqbE=
|
||||
github.com/alecthomas/assert/v2 v2.7.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
|
||||
github.com/alecthomas/chroma/v2 v2.14.0 h1:R3+wzpnUArGcQz7fCETQBzO5n9IMNi13iIs46aU4V9E=
|
||||
github.com/alecthomas/chroma/v2 v2.14.0/go.mod h1:QolEbTfmUHIMVpBqxeDnNBj2uoeI4EbYP4i6n68SG4I=
|
||||
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
|
||||
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
||||
github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss=
|
||||
github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU=
|
||||
github.com/bmatcuk/doublestar/v4 v4.8.1 h1:54Bopc5c2cAvhLRAzqOGCYHYyhcDHsFF4wWIR5wKP38=
|
||||
github.com/bmatcuk/doublestar/v4 v4.8.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
|
||||
github.com/campoy/embedmd v1.0.0 h1:V4kI2qTJJLf4J29RzI/MAt2c3Bl4dQSYPuflzwFH2hY=
|
||||
github.com/campoy/embedmd v1.0.0/go.mod h1:oxyr9RCiSXg0M3VJ3ks0UGfp98BpSSGr0kpiX3MzVl8=
|
||||
github.com/chromedp/cdproto v0.0.0-20250319231242-a755498943c8 h1:AqW2bDQf67Zbq6Tpop/+yJSIknxhiQecO2B8jNYTAPs=
|
||||
github.com/chromedp/cdproto v0.0.0-20250319231242-a755498943c8/go.mod h1:NItd7aLkcfOA/dcMXvl8p1u+lQqioRMq/SqDp71Pb/k=
|
||||
github.com/chromedp/chromedp v0.13.3 h1:c6nTn97XQBykzcXiGYL5LLebw3h3CEyrCihm4HquYh0=
|
||||
@ -13,16 +31,34 @@ github.com/chromedp/sysutil v1.1.0/go.mod h1:WiThHUdltqCNKGc4gaU50XgYjwjYIhKWoHG
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo=
|
||||
github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/dop251/goja v0.0.0-20240927123429-241b342198c2 h1:Ux9RXuPQmTB4C1MKagNLme0krvq8ulewfor+ORO/QL4=
|
||||
github.com/dop251/goja v0.0.0-20240927123429-241b342198c2/go.mod h1:MxLav0peU43GgvwVgNbLAj1s/bSGboKkhuULvq/7hx4=
|
||||
github.com/dreampuf/mermaid.go v0.0.27 h1:uriWHpcc4clTaAUdJqpyDzyGvAZumeLb61n2VBxc0ZQ=
|
||||
github.com/dreampuf/mermaid.go v0.0.27/go.mod h1:13PeW5y49ouLGlP3RdZm6ke+lQIcz3z7rdVoqRkt5hY=
|
||||
github.com/go-fonts/liberation v0.3.1 h1:9RPT2NhUpxQ7ukUvz3jeUckmN42T9D9TpjtQcqK/ceM=
|
||||
github.com/go-fonts/liberation v0.3.1/go.mod h1:jdJ+cqF+F4SUL2V+qxBth8fvBpBDS7yloUL5Fi8GTGY=
|
||||
github.com/go-json-experiment/json v0.0.0-20250211171154-1ae217ad3535 h1:yE7argOs92u+sSCRgqqe6eF+cDaVhSPlioy1UkA0p/w=
|
||||
github.com/go-json-experiment/json v0.0.0-20250211171154-1ae217ad3535/go.mod h1:BWmvoE1Xia34f3l/ibJweyhrT+aROb/FQ6d+37F0e2s=
|
||||
github.com/go-latex/latex v0.0.0-20230307184459-12ec69307ad9 h1:NxXI5pTAtpEaU49bpLpQoDsu1zrteW/vxzTz8Cd2UAs=
|
||||
github.com/go-latex/latex v0.0.0-20230307184459-12ec69307ad9/go.mod h1:gWuR/CrFDDeVRFQwHPvsv9soJVB/iqymhuZQuJ3a9OM=
|
||||
github.com/go-pdf/fpdf v0.8.0 h1:IJKpdaagnWUeSkUFUjTcSzTppFxmv8ucGQyNPQWxYOQ=
|
||||
github.com/go-pdf/fpdf v0.8.0/go.mod h1:gfqhcNwXrsd3XYKte9a7vM3smvU/jB4ZRDrmWSxpfdc=
|
||||
github.com/go-sourcemap/sourcemap v2.1.4+incompatible h1:a+iTbH5auLKxaNwQFg0B+TCYl6lbukKPc7b5x0n1s6Q=
|
||||
github.com/go-sourcemap/sourcemap v2.1.4+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
|
||||
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
|
||||
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
||||
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
||||
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||
github.com/gobwas/ws v1.4.0 h1:CTaoG1tojrh4ucGPcoJFiAQUAsEWekEWvLy7GsVNqGs=
|
||||
github.com/gobwas/ws v1.4.0/go.mod h1:G3gNqMNtPppf5XUz7O4shetPpcZ1VJ7zt18dlUeakrc=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||
github.com/google/pprof v0.0.0-20240927180334-d43a67379298 h1:dMHbguTqGtorivvHTaOnbYp+tFzrw5M9gjkU4lCplgg=
|
||||
github.com/google/pprof v0.0.0-20240927180334-d43a67379298/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
||||
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
|
||||
github.com/kovetskiy/gopencils v0.0.0-20250404051442-0b776066936a h1:OPt6gCghZXQ/WZpT6EhGkA7v+YMAYzcCb8SPQWmsb/8=
|
||||
github.com/kovetskiy/gopencils v0.0.0-20250404051442-0b776066936a/go.mod h1:gRW37oDEg9LzOHApv31YzxKBICcCmPtDogaImsxZ6xc=
|
||||
github.com/kovetskiy/lorg v1.2.1-0.20240830111423-ba4fe8b6f7c4 h1:2eV8tF1u58dqRJMlFUD/Df26BxcIlGVy71rZHN+aNoI=
|
||||
@ -33,6 +69,10 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80 h1:6Yzfa6GP0rIo/kULo2bwGEkFvCePZ3qHDDTC3/J9Swo=
|
||||
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/mazznoer/csscolorparser v0.1.5 h1:Wr4uNIE+pHWN3TqZn2SGpA2nLRG064gB7WdSfSS5cz4=
|
||||
github.com/mazznoer/csscolorparser v0.1.5/go.mod h1:OQRVvgCyHDCAquR1YWfSwwaDcM0LhnSffGnlbOew/3I=
|
||||
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde h1:x0TT0RDC7UhAVbbWWBzr41ElhJx5tXPWkIHA2HWPRuw=
|
||||
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
@ -46,6 +86,8 @@ github.com/reconquest/pkg v1.3.1-0.20240901105413-68c2adbf2b64 h1:OBNLiZay5PYLmG
|
||||
github.com/reconquest/pkg v1.3.1-0.20240901105413-68c2adbf2b64/go.mod h1:r1Z1JNh3in9xLWbhv5u7cdox9vvGFjlKp89VI10Jrdo=
|
||||
github.com/reconquest/regexputil-go v0.0.0-20160905154124-38573e70c1f4 h1:bcDXaTFC09IIg13Z8gfQHk4gSu001ET7ssW/wKRvPzg=
|
||||
github.com/reconquest/regexputil-go v0.0.0-20160905154124-38573e70c1f4/go.mod h1:OI1di2iiFSwX3D70iZjzdmCPPfssjOl+HX40tI3VaXA=
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
@ -54,15 +96,63 @@ github.com/urfave/cli-altsrc/v3 v3.0.1 h1:v+gHk59syLk8ao9rYybZs43+D5ut/gzj0omqQ1
|
||||
github.com/urfave/cli-altsrc/v3 v3.0.1/go.mod h1:8UtsKKcxFVzvaoySFPfvQOk413T+IXJhaCWyyoPW3yM=
|
||||
github.com/urfave/cli/v3 v3.3.3 h1:byCBaVdIXuLPIDm5CYZRVG6NvT7tv1ECqdU4YzlEa3I=
|
||||
github.com/urfave/cli/v3 v3.3.3/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yuin/goldmark v1.7.12 h1:YwGP/rrea2/CnCtUHgjuolG/PnMxdQtPMO5PvaE2/nY=
|
||||
github.com/yuin/goldmark v1.7.12/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
|
||||
github.com/zazab/zhash v0.0.0-20221031090444-2b0d50417446 h1:75pcOSsb40+ub185cJI7g5uykl9Uu76rD5ONzK/4s40=
|
||||
github.com/zazab/zhash v0.0.0-20221031090444-2b0d50417446/go.mod h1:NtepZ8TEXErPsmQDMUoN72f8aIy4+xNinSJ3f1giess=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk=
|
||||
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY=
|
||||
golang.org/x/image v0.20.0 h1:7cVCUjQwfL18gyBJOmYvptfSHS8Fb3YUDtfLIZ7Nbpw=
|
||||
golang.org/x/image v0.20.0/go.mod h1:0a88To4CYVBAHp5FXJm8o7QbUl37Vd85ply1vyD8auM=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
|
||||
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
|
||||
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
|
||||
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY=
|
||||
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
|
||||
gonum.org/v1/plot v0.14.0 h1:+LBDVFYwFe4LHhdP8coW6296MBEY4nQ+Y4vuUpJopcE=
|
||||
gonum.org/v1/plot v0.14.0/go.mod h1:MLdR9424SJed+5VqC6MsouEpig9pZX2VZ57H9ko2bXU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
@ -70,3 +160,9 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
oss.terrastruct.com/d2 v0.7.0 h1:nFTap/RgAQtm1aAmUOOJxO8vgSCj3SLILcOkStnyHeI=
|
||||
oss.terrastruct.com/d2 v0.7.0/go.mod h1:QseS95MrwfSRDJcFmVpBBIKuPIr8/RUoR3526QQ3rVk=
|
||||
oss.terrastruct.com/util-go v0.0.0-20250213174338-243d8661088a h1:UXF/Z9i9tOx/wqGUOn/T12wZeez1Gg0sAVKKl7YUDwM=
|
||||
oss.terrastruct.com/util-go v0.0.0-20250213174338-243d8661088a/go.mod h1:eMWv0sOtD9T2RUl90DLWfuShZCYp4NrsqNpI8eqO6U4=
|
||||
rsc.io/pdf v0.1.1 h1:k1MczvYDUvJBe93bYd7wrZLLUEcLZAuF824/I4e5Xr4=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
|
10
main.go
10
main.go
@ -17,11 +17,11 @@ const (
|
||||
|
||||
func main() {
|
||||
cmd := &cli.Command{
|
||||
Name: "mark",
|
||||
Usage: usage,
|
||||
Description: description,
|
||||
Version: version,
|
||||
Flags: util.Flags,
|
||||
Name: "mark",
|
||||
Usage: usage,
|
||||
Description: description,
|
||||
Version: version,
|
||||
Flags: util.Flags,
|
||||
EnableShellCompletion: true,
|
||||
HideHelpCommand: true,
|
||||
Action: util.RunMark,
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
cparser "github.com/kovetskiy/mark/parser"
|
||||
crenderer "github.com/kovetskiy/mark/renderer"
|
||||
"github.com/kovetskiy/mark/stdlib"
|
||||
"github.com/kovetskiy/mark/types"
|
||||
"github.com/reconquest/pkg/log"
|
||||
"github.com/yuin/goldmark"
|
||||
|
||||
@ -20,26 +21,20 @@ import (
|
||||
// Renderer renders anchor [Node]s.
|
||||
type ConfluenceExtension struct {
|
||||
html.Config
|
||||
Stdlib *stdlib.Lib
|
||||
Path string
|
||||
MermaidProvider string
|
||||
MermaidScale float64
|
||||
DropFirstH1 bool
|
||||
StripNewlines bool
|
||||
Attachments []attachment.Attachment
|
||||
Stdlib *stdlib.Lib
|
||||
Path string
|
||||
MarkConfig types.MarkConfig
|
||||
Attachments []attachment.Attachment
|
||||
}
|
||||
|
||||
// NewConfluenceRenderer creates a new instance of the ConfluenceRenderer
|
||||
func NewConfluenceExtension(stdlib *stdlib.Lib, path string, mermaidProvider string, mermaidScale float64, dropFirstH1 bool, stripNewlines bool) *ConfluenceExtension {
|
||||
func NewConfluenceExtension(stdlib *stdlib.Lib, path string, cfg types.MarkConfig) *ConfluenceExtension {
|
||||
return &ConfluenceExtension{
|
||||
Config: html.NewConfig(),
|
||||
Stdlib: stdlib,
|
||||
Path: path,
|
||||
MermaidProvider: mermaidProvider,
|
||||
MermaidScale: mermaidScale,
|
||||
DropFirstH1: dropFirstH1,
|
||||
StripNewlines: stripNewlines,
|
||||
Attachments: []attachment.Attachment{},
|
||||
Config: html.NewConfig(),
|
||||
Stdlib: stdlib,
|
||||
Path: path,
|
||||
MarkConfig: cfg,
|
||||
Attachments: []attachment.Attachment{},
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,12 +45,12 @@ func (c *ConfluenceExtension) Attach(a attachment.Attachment) {
|
||||
func (c *ConfluenceExtension) Extend(m goldmark.Markdown) {
|
||||
|
||||
m.Renderer().AddOptions(renderer.WithNodeRenderers(
|
||||
util.Prioritized(crenderer.NewConfluenceTextRenderer(c.StripNewlines), 100),
|
||||
util.Prioritized(crenderer.NewConfluenceTextRenderer(c.MarkConfig.StripNewlines), 100),
|
||||
util.Prioritized(crenderer.NewConfluenceBlockQuoteRenderer(), 100),
|
||||
util.Prioritized(crenderer.NewConfluenceCodeBlockRenderer(c.Stdlib, c.Path), 100),
|
||||
util.Prioritized(crenderer.NewConfluenceFencedCodeBlockRenderer(c.Stdlib, c, c.MermaidProvider, c.MermaidScale), 100),
|
||||
util.Prioritized(crenderer.NewConfluenceFencedCodeBlockRenderer(c.Stdlib, c, c.MarkConfig), 100),
|
||||
util.Prioritized(crenderer.NewConfluenceHTMLBlockRenderer(c.Stdlib), 100),
|
||||
util.Prioritized(crenderer.NewConfluenceHeadingRenderer(c.DropFirstH1), 100),
|
||||
util.Prioritized(crenderer.NewConfluenceHeadingRenderer(c.MarkConfig.DropFirstH1), 100),
|
||||
util.Prioritized(crenderer.NewConfluenceImageRenderer(c.Stdlib, c, c.Path), 100),
|
||||
util.Prioritized(crenderer.NewConfluenceParagraphRenderer(), 100),
|
||||
util.Prioritized(crenderer.NewConfluenceLinkRenderer(), 100),
|
||||
@ -68,10 +63,10 @@ func (c *ConfluenceExtension) Extend(m goldmark.Markdown) {
|
||||
))
|
||||
}
|
||||
|
||||
func CompileMarkdown(markdown []byte, stdlib *stdlib.Lib, path string, mermaidProvider string, mermaidScale float64, dropFirstH1 bool, stripNewlines bool) (string, []attachment.Attachment) {
|
||||
func CompileMarkdown(markdown []byte, stdlib *stdlib.Lib, path string, cfg types.MarkConfig) (string, []attachment.Attachment) {
|
||||
log.Tracef(nil, "rendering markdown:\n%s", string(markdown))
|
||||
|
||||
confluenceExtension := NewConfluenceExtension(stdlib, path, mermaidProvider, mermaidScale, dropFirstH1, stripNewlines)
|
||||
confluenceExtension := NewConfluenceExtension(stdlib, path, cfg)
|
||||
|
||||
converter := goldmark.New(
|
||||
goldmark.WithExtensions(
|
||||
@ -81,7 +76,7 @@ func CompileMarkdown(markdown []byte, stdlib *stdlib.Lib, path string, mermaidPr
|
||||
extension.WithTableCellAlignMethod(extension.TableCellAlignStyle),
|
||||
),
|
||||
confluenceExtension,
|
||||
extension.GFM,
|
||||
extension.GFM,
|
||||
),
|
||||
goldmark.WithParserOptions(
|
||||
parser.WithAutoHeadingID(),
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
|
||||
mark "github.com/kovetskiy/mark/markdown"
|
||||
"github.com/kovetskiy/mark/stdlib"
|
||||
"github.com/kovetskiy/mark/types"
|
||||
"github.com/kovetskiy/mark/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/urfave/cli/v3"
|
||||
@ -55,8 +56,17 @@ func TestCompileMarkdown(t *testing.T) {
|
||||
panic(err)
|
||||
}
|
||||
markdown, htmlname, html := loadData(t, filename, "")
|
||||
actual, _ := mark.CompileMarkdown(markdown, lib, filename, "", 1.0, false, false)
|
||||
test.EqualValues(string(html), actual, filename+" vs "+htmlname)
|
||||
|
||||
cfg := types.MarkConfig{
|
||||
MermaidProvider: "",
|
||||
MermaidScale: 1.0,
|
||||
DropFirstH1: false,
|
||||
StripNewlines: false,
|
||||
Features: []string{},
|
||||
}
|
||||
|
||||
actual, _ := mark.CompileMarkdown(markdown, lib, filename, cfg)
|
||||
test.EqualValues(strings.TrimSuffix(string(html), "\n"), strings.TrimSuffix(actual, "\n"), filename+" vs "+htmlname)
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,8 +98,18 @@ func TestCompileMarkdownDropH1(t *testing.T) {
|
||||
variant = ""
|
||||
}
|
||||
markdown, htmlname, html := loadData(t, filename, variant)
|
||||
actual, _ := mark.CompileMarkdown(markdown, lib, filename, "", 1.0, true, false)
|
||||
test.EqualValues(string(html), actual, filename+" vs "+htmlname)
|
||||
|
||||
cfg := types.MarkConfig{
|
||||
MermaidProvider: "",
|
||||
MermaidScale: 1.0,
|
||||
DropFirstH1: true,
|
||||
StripNewlines: false,
|
||||
Features: []string{},
|
||||
}
|
||||
|
||||
actual, _ := mark.CompileMarkdown(markdown, lib, filename, cfg)
|
||||
test.EqualValues(strings.TrimSuffix(string(html), "\n"), strings.TrimSuffix(actual, "\n"), filename+" vs "+htmlname)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -122,8 +142,18 @@ func TestCompileMarkdownStripNewlines(t *testing.T) {
|
||||
}
|
||||
|
||||
markdown, htmlname, html := loadData(t, filename, variant)
|
||||
actual, _ := mark.CompileMarkdown(markdown, lib, filename, "", 1.0, false, true)
|
||||
test.EqualValues(string(html), actual, filename+" vs "+htmlname)
|
||||
|
||||
cfg := types.MarkConfig{
|
||||
MermaidProvider: "",
|
||||
MermaidScale: 1.0,
|
||||
DropFirstH1: false,
|
||||
StripNewlines: true,
|
||||
Features: []string{},
|
||||
}
|
||||
|
||||
actual, _ := mark.CompileMarkdown(markdown, lib, filename, cfg)
|
||||
test.EqualValues(strings.TrimSuffix(string(html), "\n"), strings.TrimSuffix(actual, "\n"), filename+" vs "+htmlname)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ import (
|
||||
"github.com/reconquest/pkg/log"
|
||||
)
|
||||
|
||||
var renderTimeout = 90 * time.Second
|
||||
var renderTimeout = 120 * time.Second
|
||||
|
||||
func ProcessMermaidLocally(title string, mermaidDiagram []byte, scale float64) (attachment.Attachment, error) {
|
||||
ctx, cancel := context.WithTimeout(context.TODO(), renderTimeout)
|
||||
|
@ -11,7 +11,6 @@ type ConfluenceIDs struct {
|
||||
Values map[string]bool
|
||||
}
|
||||
|
||||
|
||||
// https://github.com/yuin/goldmark/blob/d9c03f07f08c2d36f23afe52dda865f05320ac86/parser/parser.go#L75
|
||||
func (s *ConfluenceIDs) Generate(value []byte, kind ast.NodeKind) []byte {
|
||||
value = util.TrimLeftSpace(value)
|
||||
|
@ -3,11 +3,14 @@ package renderer
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/kovetskiy/mark/attachment"
|
||||
"github.com/kovetskiy/mark/d2"
|
||||
"github.com/kovetskiy/mark/mermaid"
|
||||
"github.com/kovetskiy/mark/stdlib"
|
||||
"github.com/kovetskiy/mark/types"
|
||||
"github.com/reconquest/pkg/log"
|
||||
|
||||
"github.com/yuin/goldmark/ast"
|
||||
@ -18,10 +21,9 @@ import (
|
||||
|
||||
type ConfluenceFencedCodeBlockRenderer struct {
|
||||
html.Config
|
||||
Stdlib *stdlib.Lib
|
||||
MermaidProvider string
|
||||
MermaidScale float64
|
||||
Attachments attachment.Attacher
|
||||
Stdlib *stdlib.Lib
|
||||
MarkConfig types.MarkConfig
|
||||
Attachments attachment.Attacher
|
||||
}
|
||||
|
||||
var reBlockDetails = regexp.MustCompile(
|
||||
@ -31,13 +33,12 @@ var reBlockDetails = regexp.MustCompile(
|
||||
)
|
||||
|
||||
// NewConfluenceRenderer creates a new instance of the ConfluenceRenderer
|
||||
func NewConfluenceFencedCodeBlockRenderer(stdlib *stdlib.Lib, attachments attachment.Attacher, mermaidProvider string, mermaidScale float64, opts ...html.Option) renderer.NodeRenderer {
|
||||
func NewConfluenceFencedCodeBlockRenderer(stdlib *stdlib.Lib, attachments attachment.Attacher, cfg types.MarkConfig, opts ...html.Option) renderer.NodeRenderer {
|
||||
return &ConfluenceFencedCodeBlockRenderer{
|
||||
Config: html.NewConfig(),
|
||||
Stdlib: stdlib,
|
||||
MermaidProvider: mermaidProvider,
|
||||
MermaidScale: mermaidScale,
|
||||
Attachments: attachments,
|
||||
Config: html.NewConfig(),
|
||||
Stdlib: stdlib,
|
||||
MarkConfig: cfg,
|
||||
Attachments: attachments,
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,8 +127,39 @@ func (r *ConfluenceFencedCodeBlockRenderer) renderFencedCodeBlock(writer util.Bu
|
||||
lval = append(lval, line.Value(source)...)
|
||||
}
|
||||
|
||||
if lang == "mermaid" && r.MermaidProvider == "mermaid-go" {
|
||||
attachment, err := mermaid.ProcessMermaidLocally(title, lval, r.MermaidScale)
|
||||
if lang == "d2" && slices.Contains(r.MarkConfig.Features, "d2") {
|
||||
attachment, err := d2.ProcessD2(title, lval, r.MarkConfig.D2Scale)
|
||||
if err != nil {
|
||||
log.Debugf(nil, "error: %v", err)
|
||||
return ast.WalkStop, err
|
||||
}
|
||||
r.Attachments.Attach(attachment)
|
||||
err = r.Stdlib.Templates.ExecuteTemplate(
|
||||
writer,
|
||||
"ac:image",
|
||||
struct {
|
||||
Width string
|
||||
Height string
|
||||
Title string
|
||||
Alt string
|
||||
Attachment string
|
||||
Url string
|
||||
}{
|
||||
attachment.Width,
|
||||
attachment.Height,
|
||||
attachment.Name,
|
||||
"",
|
||||
attachment.Filename,
|
||||
"",
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return ast.WalkStop, err
|
||||
}
|
||||
|
||||
} else if lang == "mermaid" && slices.Contains(r.MarkConfig.Features, "mermaid") && r.MarkConfig.MermaidProvider == "mermaid-go" {
|
||||
attachment, err := mermaid.ProcessMermaidLocally(title, lval, r.MarkConfig.MermaidScale)
|
||||
if err != nil {
|
||||
log.Debugf(nil, "error: %v", err)
|
||||
return ast.WalkStop, err
|
||||
|
51
testdata/codes-stripnewlines.html
vendored
51
testdata/codes-stripnewlines.html
vendored
@ -16,4 +16,53 @@ with multiple lines]]></ac:plain-text-body></ac:structured-macro><ac:structured-
|
||||
A-->B;
|
||||
A-->C;
|
||||
B-->D;
|
||||
C-->D;]]></ac:plain-text-body></ac:structured-macro>
|
||||
C-->D;]]></ac:plain-text-body></ac:structured-macro><ac:structured-macro ac:name="code"><ac:parameter ac:name="language">d2</ac:parameter><ac:parameter ac:name="collapse">false</ac:parameter><ac:plain-text-body><![CDATA[vars: {
|
||||
d2-config: {
|
||||
layout-engine: elk
|
||||
# Terminal theme code
|
||||
theme-id: 300
|
||||
}
|
||||
}
|
||||
network: {
|
||||
cell tower: {
|
||||
satellites: {
|
||||
shape: stored_data
|
||||
style.multiple: true
|
||||
}
|
||||
|
||||
transmitter
|
||||
|
||||
satellites -> transmitter: send
|
||||
satellites -> transmitter: send
|
||||
satellites -> transmitter: send
|
||||
}
|
||||
|
||||
online portal: {
|
||||
ui: {shape: hexagon}
|
||||
}
|
||||
|
||||
data processor: {
|
||||
storage: {
|
||||
shape: cylinder
|
||||
style.multiple: true
|
||||
}
|
||||
}
|
||||
|
||||
cell tower.transmitter -> data processor.storage: phone logs
|
||||
}
|
||||
|
||||
user: {
|
||||
shape: person
|
||||
width: 130
|
||||
}
|
||||
|
||||
user -> network.cell tower: make call
|
||||
user -> network.online portal.ui: access {
|
||||
style.stroke-dash: 3
|
||||
}
|
||||
|
||||
api server -> network.online portal.ui: display
|
||||
api server -> logs: persist
|
||||
logs: {shape: page; style.multiple: true}
|
||||
|
||||
network.data processor -> api server]]></ac:plain-text-body></ac:structured-macro>
|
||||
|
51
testdata/codes.html
vendored
51
testdata/codes.html
vendored
@ -17,4 +17,53 @@ with multiple lines]]></ac:plain-text-body></ac:structured-macro><ac:structured-
|
||||
A-->B;
|
||||
A-->C;
|
||||
B-->D;
|
||||
C-->D;]]></ac:plain-text-body></ac:structured-macro>
|
||||
C-->D;]]></ac:plain-text-body></ac:structured-macro><ac:structured-macro ac:name="code"><ac:parameter ac:name="language">d2</ac:parameter><ac:parameter ac:name="collapse">false</ac:parameter><ac:plain-text-body><![CDATA[vars: {
|
||||
d2-config: {
|
||||
layout-engine: elk
|
||||
# Terminal theme code
|
||||
theme-id: 300
|
||||
}
|
||||
}
|
||||
network: {
|
||||
cell tower: {
|
||||
satellites: {
|
||||
shape: stored_data
|
||||
style.multiple: true
|
||||
}
|
||||
|
||||
transmitter
|
||||
|
||||
satellites -> transmitter: send
|
||||
satellites -> transmitter: send
|
||||
satellites -> transmitter: send
|
||||
}
|
||||
|
||||
online portal: {
|
||||
ui: {shape: hexagon}
|
||||
}
|
||||
|
||||
data processor: {
|
||||
storage: {
|
||||
shape: cylinder
|
||||
style.multiple: true
|
||||
}
|
||||
}
|
||||
|
||||
cell tower.transmitter -> data processor.storage: phone logs
|
||||
}
|
||||
|
||||
user: {
|
||||
shape: person
|
||||
width: 130
|
||||
}
|
||||
|
||||
user -> network.cell tower: make call
|
||||
user -> network.online portal.ui: access {
|
||||
style.stroke-dash: 3
|
||||
}
|
||||
|
||||
api server -> network.online portal.ui: display
|
||||
api server -> logs: persist
|
||||
logs: {shape: page; style.multiple: true}
|
||||
|
||||
network.data processor -> api server]]></ac:plain-text-body></ac:structured-macro>
|
||||
|
53
testdata/codes.md
vendored
53
testdata/codes.md
vendored
@ -65,3 +65,56 @@ graph TD;
|
||||
B-->D;
|
||||
C-->D;
|
||||
```
|
||||
|
||||
```d2
|
||||
vars: {
|
||||
d2-config: {
|
||||
layout-engine: elk
|
||||
# Terminal theme code
|
||||
theme-id: 300
|
||||
}
|
||||
}
|
||||
network: {
|
||||
cell tower: {
|
||||
satellites: {
|
||||
shape: stored_data
|
||||
style.multiple: true
|
||||
}
|
||||
|
||||
transmitter
|
||||
|
||||
satellites -> transmitter: send
|
||||
satellites -> transmitter: send
|
||||
satellites -> transmitter: send
|
||||
}
|
||||
|
||||
online portal: {
|
||||
ui: {shape: hexagon}
|
||||
}
|
||||
|
||||
data processor: {
|
||||
storage: {
|
||||
shape: cylinder
|
||||
style.multiple: true
|
||||
}
|
||||
}
|
||||
|
||||
cell tower.transmitter -> data processor.storage: phone logs
|
||||
}
|
||||
|
||||
user: {
|
||||
shape: person
|
||||
width: 130
|
||||
}
|
||||
|
||||
user -> network.cell tower: make call
|
||||
user -> network.online portal.ui: access {
|
||||
style.stroke-dash: 3
|
||||
}
|
||||
|
||||
api server -> network.online portal.ui: display
|
||||
api server -> logs: persist
|
||||
logs: {shape: page; style.multiple: true}
|
||||
|
||||
network.data processor -> api server
|
||||
```
|
||||
|
10
types/types.go
Normal file
10
types/types.go
Normal file
@ -0,0 +1,10 @@
|
||||
package types
|
||||
|
||||
type MarkConfig struct {
|
||||
MermaidProvider string
|
||||
MermaidScale float64
|
||||
D2Scale float64
|
||||
DropFirstH1 bool
|
||||
StripNewlines bool
|
||||
Features []string
|
||||
}
|
20
util/cli.go
20
util/cli.go
@ -23,6 +23,7 @@ import (
|
||||
"github.com/kovetskiy/mark/metadata"
|
||||
"github.com/kovetskiy/mark/page"
|
||||
"github.com/kovetskiy/mark/stdlib"
|
||||
"github.com/kovetskiy/mark/types"
|
||||
"github.com/kovetskiy/mark/vfs"
|
||||
"github.com/reconquest/karma-go"
|
||||
"github.com/reconquest/pkg/log"
|
||||
@ -217,7 +218,15 @@ func processFile(
|
||||
"the leading H1 heading will be excluded from the Confluence output",
|
||||
)
|
||||
}
|
||||
html, _ := mark.CompileMarkdown(markdown, stdlib, file, cmd.String("mermaid-provider"), cmd.Float("mermaid-scale"), cmd.Bool("drop-h1"), cmd.Bool("strip-linebreaks"))
|
||||
|
||||
cfg := types.MarkConfig{
|
||||
MermaidProvider: cmd.String("mermaid-provider"),
|
||||
MermaidScale: cmd.Float("mermaid-scale"),
|
||||
DropFirstH1: cmd.Bool("drop-h1"),
|
||||
StripNewlines: cmd.Bool("strip-linebreaks"),
|
||||
Features: cmd.StringSlice("features"),
|
||||
}
|
||||
html, _ := mark.CompileMarkdown(markdown, stdlib, file, cfg)
|
||||
fmt.Println(html)
|
||||
return nil
|
||||
}
|
||||
@ -289,8 +298,15 @@ func processFile(
|
||||
"the leading H1 heading will be excluded from the Confluence output",
|
||||
)
|
||||
}
|
||||
cfg := types.MarkConfig{
|
||||
MermaidProvider: cmd.String("mermaid-provider"),
|
||||
MermaidScale: cmd.Float("mermaid-scale"),
|
||||
DropFirstH1: cmd.Bool("drop-h1"),
|
||||
StripNewlines: cmd.Bool("strip-linebreaks"),
|
||||
Features: cmd.StringSlice("features"),
|
||||
}
|
||||
|
||||
html, inlineAttachments := mark.CompileMarkdown(markdown, stdlib, file, cmd.String("mermaid-provider"), cmd.Float("mermaid-scale"), cmd.Bool("drop-h1"), cmd.Bool("strip-linebreaks"))
|
||||
html, inlineAttachments := mark.CompileMarkdown(markdown, stdlib, file, cfg)
|
||||
|
||||
// Resolve attachements detected from markdown
|
||||
_, err = attachment.ResolveAttachments(
|
||||
|
@ -55,7 +55,7 @@ var Flags = []cli.Flag{
|
||||
Name: "strip-linebreaks",
|
||||
Value: false,
|
||||
Aliases: []string{"L"},
|
||||
Usage: "remove linebreaks inside of tags, to accomodate non-standard Confluence behavior",
|
||||
Usage: "remove linebreaks inside of tags, to accommodate non-standard Confluence behavior",
|
||||
Sources: cli.NewValueSourceChain(cli.EnvVar("MARK_STRIP_LINEBREAKS"), altsrctoml.TOML("strip_linebreaks", configFile)),
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
@ -127,12 +127,12 @@ var Flags = []cli.Flag{
|
||||
altsrctoml.TOML("base_url", configFile)),
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "config",
|
||||
Aliases: []string{"c"},
|
||||
Value: ConfigFilePath(),
|
||||
Usage: "use the specified configuration file.",
|
||||
TakesFile: true,
|
||||
Sources: cli.NewValueSourceChain(cli.EnvVar("MARK_CONFIG")),
|
||||
Name: "config",
|
||||
Aliases: []string{"c"},
|
||||
Value: ConfigFilePath(),
|
||||
Usage: "use the specified configuration file.",
|
||||
TakesFile: true,
|
||||
Sources: cli.NewValueSourceChain(cli.EnvVar("MARK_CONFIG")),
|
||||
Destination: &filename,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
@ -184,4 +184,17 @@ var Flags = []cli.Flag{
|
||||
Usage: "Avoids re-uploading pages that haven't changed since the last run.",
|
||||
Sources: cli.NewValueSourceChain(cli.EnvVar("MARK_CHANGES_ONLY"), altsrctoml.TOML("changes_only", configFile)),
|
||||
},
|
||||
&cli.FloatFlag{
|
||||
Name: "d2-scale",
|
||||
Value: 1.0,
|
||||
Usage: "defines the scaling factor for d2 renderings.",
|
||||
Sources: cli.NewValueSourceChain(cli.EnvVar("MARK_D2_SCALE"), altsrctoml.TOML("d2_scale", configFile)),
|
||||
},
|
||||
|
||||
&cli.StringSliceFlag{
|
||||
Name: "features",
|
||||
Value: []string{"mermaid"},
|
||||
Usage: "Enables optional features. Current features: d2, mermaid",
|
||||
Sources: cli.NewValueSourceChain(cli.EnvVar("MARK_FEATURES"), altsrctoml.TOML("features", configFile)),
|
||||
},
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user