~shulhan/asciidoctor-go

64bd8146914636d395ecd50bf2623b5353976521 — Shulhan 3 months ago f4c31c2
all: refactoring DocumentAttribute into struct

Using struct limit the value to only string, while some attributes
can be an integer value, for example "leveloffset".
M document.go => document.go +37 -37
@@ 118,7 118,7 @@ func Open(file string) (doc *Document, err error) {
	doc = newDocument()
	doc.fpath = filepath.Join(wd, file)
	doc.file = file
	doc.Attributes[docAttrLastUpdateValue] = fi.ModTime().Round(time.Second).Format(`2006-01-02 15:04:05 Z0700`)
	doc.Attributes.Entry[docAttrLastUpdateValue] = fi.ModTime().Round(time.Second).Format(`2006-01-02 15:04:05 Z0700`)

	parse(doc, raw)



@@ 143,7 143,7 @@ func parse(doc *Document, content []byte) {
	docp.parseHeader()
	docp.doc.postParseHeader()

	sectLevel, ok = doc.Attributes[docAttrSectNumLevel]
	sectLevel, ok = doc.Attributes.Entry[docAttrSectNumLevel]
	if ok {
		doc.sectLevel, _ = strconv.Atoi(sectLevel)
	}


@@ 186,22 186,22 @@ func (doc *Document) ToHTML(out io.Writer) (err error) {

	fmt.Fprint(buf, _htmlBegin)

	docAttrValue = doc.Attributes[DocAttrGenerator]
	docAttrValue = doc.Attributes.Entry[DocAttrGenerator]
	if len(docAttrValue) > 0 {
		fmt.Fprintf(buf, "\n<meta name=%q content=%q>", DocAttrGenerator, docAttrValue)
	}

	docAttrValue = doc.Attributes[DocAttrDescription]
	docAttrValue = doc.Attributes.Entry[DocAttrDescription]
	if len(docAttrValue) > 0 {
		fmt.Fprintf(buf, "\n<meta name=%q content=%q>", DocAttrDescription, docAttrValue)
	}

	docAttrValue = doc.Attributes[DocAttrKeywords]
	docAttrValue = doc.Attributes.Entry[DocAttrKeywords]
	if len(docAttrValue) > 0 {
		fmt.Fprintf(buf, "\n<meta name=%q content=%q>", DocAttrKeywords, docAttrValue)
	}

	docAttrValue = doc.Attributes[DocAttrAuthorNames]
	docAttrValue = doc.Attributes.Entry[DocAttrAuthorNames]
	if len(docAttrValue) > 0 {
		fmt.Fprintf(buf, "\n<meta name=%q content=%q>", DocAttrAuthor, docAttrValue)
	}


@@ 217,7 217,7 @@ func (doc *Document) ToHTML(out io.Writer) (err error) {
		isWithHeaderFooter = true
		ok                 bool
	)
	_, ok = doc.Attributes[docAttrNoHeaderFooter]
	_, ok = doc.Attributes.Entry[docAttrNoHeaderFooter]
	if ok {
		isWithHeaderFooter = false
	}


@@ 244,7 244,7 @@ func (doc *Document) ToHTMLBody(out io.Writer) (err error) {

func (doc *Document) generateClasses() {
	doc.classes.add(classNameArticle)
	doc.tocPosition, doc.tocIsEnabled = doc.Attributes[docAttrTOC]
	doc.tocPosition, doc.tocIsEnabled = doc.Attributes.Entry[docAttrTOC]

	switch doc.tocPosition {
	case docAttrValueLeft:


@@ 282,7 282,7 @@ func (doc *Document) toHTMLBody(buf *bytes.Buffer, withHeaderFooter bool) {
	)

	if withHeaderFooter {
		_, ok = doc.Attributes[docAttrNoHeader]
		_, ok = doc.Attributes.Entry[docAttrNoHeader]
		if !ok {
			htmlWriteHeader(doc, buf)
		}


@@ 293,7 293,7 @@ func (doc *Document) toHTMLBody(buf *bytes.Buffer, withHeaderFooter bool) {
	htmlWriteFootnoteDefs(doc, buf)

	if withHeaderFooter {
		_, ok = doc.Attributes[docAttrNoFooter]
		_, ok = doc.Attributes.Entry[docAttrNoFooter]
		if !ok {
			htmlWriteFooter(doc, buf)
		}


@@ 362,7 362,7 @@ func (doc *Document) tocHTML(out io.Writer) {
		ok bool
	)

	v, ok = doc.Attributes[docAttrTOCLevels]
	v, ok = doc.Attributes.Entry[docAttrTOCLevels]
	if ok {
		doc.TOCLevel, _ = strconv.Atoi(v)
		if doc.TOCLevel <= 0 {


@@ 370,7 370,7 @@ func (doc *Document) tocHTML(out io.Writer) {
		}
	}

	v, ok = doc.Attributes[docAttrTOCTitle]
	v, ok = doc.Attributes.Entry[docAttrTOCTitle]
	if ok && len(v) > 0 {
		doc.tocTitle = v
	}


@@ 395,11 395,11 @@ func (doc *Document) unpackRawAuthor() {
	)

	if len(doc.rawAuthors) == 0 {
		v = doc.Attributes[DocAttrAuthor]
		v = doc.Attributes.Entry[DocAttrAuthor]
		if len(v) > 0 {
			sb.WriteString(v)
		}
		v = doc.Attributes[docAttrEmail]
		v = doc.Attributes.Entry[docAttrEmail]
		if len(v) > 0 {
			sb.WriteString(` <`)
			sb.WriteString(v)


@@ 442,12 442,12 @@ func (doc *Document) unpackRawAuthor() {
		sb.WriteString(author.FullName())

		if x == 0 {
			doc.Attributes[authorKey] = author.FullName()
			doc.Attributes[emailKey] = author.Email
			doc.Attributes[initialsKey] = author.Initials
			doc.Attributes[firstNameKey] = author.FirstName
			doc.Attributes[middleNameKey] = author.MiddleName
			doc.Attributes[lastNameKey] = author.LastName
			doc.Attributes.Entry[authorKey] = author.FullName()
			doc.Attributes.Entry[emailKey] = author.Email
			doc.Attributes.Entry[initialsKey] = author.Initials
			doc.Attributes.Entry[firstNameKey] = author.FirstName
			doc.Attributes.Entry[middleNameKey] = author.MiddleName
			doc.Attributes.Entry[lastNameKey] = author.LastName

			// No continue, the first author have two keys, one is
			// `author` and another is `author_1`.


@@ 460,31 460,31 @@ func (doc *Document) unpackRawAuthor() {
		middleNameKey = fmt.Sprintf(`%s_%d`, docAttrMiddleName, x+1)
		lastNameKey = fmt.Sprintf(`%s_%d`, docAttrLastName, x+1)

		doc.Attributes[authorKey] = author.FullName()
		doc.Attributes[emailKey] = author.Email
		doc.Attributes[initialsKey] = author.Initials
		doc.Attributes[firstNameKey] = author.FirstName
		doc.Attributes[middleNameKey] = author.MiddleName
		doc.Attributes[lastNameKey] = author.LastName
		doc.Attributes.Entry[authorKey] = author.FullName()
		doc.Attributes.Entry[emailKey] = author.Email
		doc.Attributes.Entry[initialsKey] = author.Initials
		doc.Attributes.Entry[firstNameKey] = author.FirstName
		doc.Attributes.Entry[middleNameKey] = author.MiddleName
		doc.Attributes.Entry[lastNameKey] = author.LastName
	}

	v = sb.String()
	if len(v) > 0 {
		doc.Attributes[DocAttrAuthorNames] = v
		doc.Attributes.Entry[DocAttrAuthorNames] = v
	}
}

func (doc *Document) unpackRawRevision() {
	if len(doc.rawRevision) > 0 {
		doc.Revision = parseRevision(doc.rawRevision)
		doc.Attributes[docAttrRevNumber] = doc.Revision.Number
		doc.Attributes[docAttrRevDate] = doc.Revision.Date
		doc.Attributes[docAttrRevRemark] = doc.Revision.Remark
		doc.Attributes.Entry[docAttrRevNumber] = doc.Revision.Number
		doc.Attributes.Entry[docAttrRevDate] = doc.Revision.Date
		doc.Attributes.Entry[docAttrRevRemark] = doc.Revision.Remark
		return
	}
	doc.Revision.Number = doc.Attributes[docAttrRevNumber]
	doc.Revision.Date = doc.Attributes[docAttrRevDate]
	doc.Revision.Remark = doc.Attributes[docAttrRevRemark]
	doc.Revision.Number = doc.Attributes.Entry[docAttrRevNumber]
	doc.Revision.Date = doc.Attributes.Entry[docAttrRevDate]
	doc.Revision.Remark = doc.Attributes.Entry[docAttrRevRemark]
}

func (doc *Document) unpackRawTitle() {


@@ 495,9 495,9 @@ func (doc *Document) unpackRawTitle() {
	)

	if len(doc.Title.raw) == 0 {
		doc.Title.raw = doc.Attributes[docAttrDocTitle]
		doc.Title.raw = doc.Attributes.Entry[docAttrDocTitle]
		if len(doc.Title.raw) == 0 {
			doc.Title.raw = doc.Attributes[docAttrTitle]
			doc.Title.raw = doc.Attributes.Entry[docAttrTitle]
			if len(doc.Title.raw) == 0 {
				return
			}


@@ 506,7 506,7 @@ func (doc *Document) unpackRawTitle() {

	doc.Title.el = parseInlineMarkup(doc, []byte(doc.Title.raw))
	title = doc.Title.el.toText()
	doc.Attributes[docAttrDocTitle] = title
	doc.Attributes.Entry[docAttrDocTitle] = title

	for x = len(title) - 1; x > 0; x-- {
		if title[x] == doc.Title.sep {


@@ 531,7 531,7 @@ func (doc *Document) unpackTitleSeparator() {
		ok bool
	)

	v, ok = doc.Attributes[docAttrTitleSeparator]
	v, ok = doc.Attributes.Entry[docAttrTitleSeparator]
	if ok {
		v = strings.TrimSpace(v)
		if len(v) > 0 {

M document_attribute.go => document_attribute.go +25 -16
@@ 56,27 56,36 @@ const (

// DocumentAttribute contains the mapping of global attribute keys in the
// headers with its value.
type DocumentAttribute map[string]string
type DocumentAttribute struct {
	Entry map[string]string
}

func newDocumentAttribute() DocumentAttribute {
	return DocumentAttribute{
		DocAttrGenerator:       `asciidoctor-go ` + Version,
		docAttrLastUpdateLabel: `Last updated`,
		docAttrLastUpdateValue: ``,
		docAttrSectIDs:         ``,
		docAttrShowTitle:       ``,
		docAttrTableCaption:    ``,
		docAttrVersionLabel:    ``,
		Entry: map[string]string{
			DocAttrGenerator:       `asciidoctor-go ` + Version,
			docAttrLastUpdateLabel: `Last updated`,
			docAttrLastUpdateValue: ``,
			docAttrSectIDs:         ``,
			docAttrShowTitle:       ``,
			docAttrTableCaption:    ``,
			docAttrVersionLabel:    ``,
		},
	}
}

func (entry *DocumentAttribute) apply(key, val string) {
	switch {
	case key[0] == '!':
		delete(*entry, strings.TrimSpace(key[1:]))
	case key[len(key)-1] == '!':
		delete(*entry, strings.TrimSpace(key[:len(key)-1]))
	default:
		(*entry)[key] = val
func (docAttr *DocumentAttribute) apply(key, val string) {
	if key[0] == '!' {
		key = strings.TrimSpace(key[1:])
		delete(docAttr.Entry, key)
		return
	}
	var n = len(key)
	if key[n-1] == '!' {
		key = strings.TrimSpace(key[:n-1])
		delete(docAttr.Entry, key)
		return
	}

	docAttr.Entry[key] = val
}

M document_parser.go => document_parser.go +2 -2
@@ 51,8 51,8 @@ func parseSub(parentDoc *Document, content []byte) (subdoc *Document) {

	subdoc = newDocument()

	for k, v = range parentDoc.Attributes {
		subdoc.Attributes[k] = v
	for k, v = range parentDoc.Attributes.Entry {
		subdoc.Attributes.Entry[k] = v
	}

	docp = newDocumentParser(subdoc, content)

M document_test.go => document_test.go +1 -1
@@ 24,7 24,7 @@ func TestOpen(t *testing.T) {

	// Since we cannot overwrite the asciidoctor output for
	// generator, we override ourself.
	doc.Attributes[DocAttrGenerator] = `Asciidoctor 2.0.18`
	doc.Attributes.Entry[DocAttrGenerator] = `Asciidoctor 2.0.18`

	fout, err = os.OpenFile(`testdata/test.got.html`, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
	if err != nil {

M element.go => element.go +2 -2
@@ 578,7 578,7 @@ func (el *element) parseSection(doc *Document, isDiscrete bool) {
	el.Text = container.toText()

	if len(el.ID) == 0 {
		_, ok = doc.Attributes[docAttrSectIDs]
		_, ok = doc.Attributes.Entry[docAttrSectIDs]
		if ok {
			el.ID = generateID(doc, el.Text)
			el.ID = doc.registerAnchor(el.ID, el.Text)


@@ 596,7 596,7 @@ func (el *element) parseSection(doc *Document, isDiscrete bool) {
	}
	doc.titleID[el.Text] = el.ID

	_, ok = doc.Attributes[docAttrSectNums]
	_, ok = doc.Attributes.Entry[docAttrSectNums]
	if ok && !isDiscrete {
		el.sectnums = doc.sectnums.set(el.level)
	}

M html_backend.go => html_backend.go +10 -10
@@ 294,7 294,7 @@ func htmlSubsAttr(doc *Document, input []byte) []byte {
			continue
		}

		val, ok = doc.Attributes[key]
		val, ok = doc.Attributes.Entry[key]
		if !ok {
			bb.WriteByte(c)
			continue


@@ 909,7 909,7 @@ func htmlWriteFooter(doc *Document, out io.Writer) {
<div id="footer-text">`)

	if len(doc.Revision.Number) > 0 {
		label, ok = doc.Attributes[docAttrVersionLabel]
		label, ok = doc.Attributes.Entry[docAttrVersionLabel]
		if ok && len(label) == 0 {
			label = `Version `
		} else {


@@ 919,9 919,9 @@ func htmlWriteFooter(doc *Document, out io.Writer) {
		fmt.Fprintf(out, "\n%s%s<br>", label, doc.Revision.Number)
	}

	label, ok = doc.Attributes[docAttrLastUpdateLabel]
	label, ok = doc.Attributes.Entry[docAttrLastUpdateLabel]
	if ok {
		value = doc.Attributes[docAttrLastUpdateValue]
		value = doc.Attributes.Entry[docAttrLastUpdateValue]
		if len(value) != 0 {
			fmt.Fprintf(out, "\n%s %s", label, value)
		}


@@ 992,9 992,9 @@ func htmlWriteHeader(doc *Document, out io.Writer) {
		ok     bool
	)

	_, ok = doc.Attributes[docAttrShowTitle]
	_, ok = doc.Attributes.Entry[docAttrShowTitle]
	if ok {
		_, ok = doc.Attributes[docAttrNoTitle]
		_, ok = doc.Attributes.Entry[docAttrNoTitle]
		if !ok && doc.Title.el != nil {
			fmt.Fprint(out, "\n<h1>")
			doc.Title.el.toHTML(doc, out)


@@ 1027,7 1027,7 @@ func htmlWriteHeader(doc *Document, out io.Writer) {
	}

	if len(doc.Revision.Number) > 0 {
		prefix, ok = doc.Attributes[docAttrVersionLabel]
		prefix, ok = doc.Attributes.Entry[docAttrVersionLabel]
		if ok && len(prefix) == 0 {
			prefix = defVersionPrefix
		} else {


@@ 1206,11 1206,11 @@ func htmlWriteSection(doc *Document, el *element, out io.Writer) {
		withSectlinks   bool
	)

	_, withSectAnchors = doc.Attributes[docAttrSectAnchors]
	_, withSectAnchors = doc.Attributes.Entry[docAttrSectAnchors]
	if withSectAnchors {
		fmt.Fprintf(out, `<a class="anchor" href="#%s"></a>`, el.ID)
	}
	_, withSectlinks = doc.Attributes[docAttrSectLinks]
	_, withSectlinks = doc.Attributes.Entry[docAttrSectLinks]
	if withSectlinks {
		fmt.Fprintf(out, `<a class="link" href="#%s">`, el.ID)
	}


@@ 1283,7 1283,7 @@ func htmlWriteTable(doc *Document, el *element, out io.Writer) {
		)

		doc.counterTable++
		_, withTableCaption = doc.Attributes[docAttrTableCaption]
		_, withTableCaption = doc.Attributes.Entry[docAttrTableCaption]

		if withTableCaption {
			caption, ok = el.Attrs[attrNameCaption]

M inline_parser_test.go => inline_parser_test.go +4 -2
@@ 15,8 15,10 @@ import (
func TestInlineParser(t *testing.T) {
	var (
		_testDoc = &Document{
			Attributes: map[string]string{
				`x`: `https://kilabit.info`,
			Attributes: DocumentAttribute{
				Entry: map[string]string{
					`x`: `https://kilabit.info`,
				},
			},

			anchors: map[string]*anchor{

M parser.go => parser.go +3 -3
@@ 380,7 380,7 @@ func generateID(doc *Document, str string) string {
		ok   bool
	)

	v, ok = doc.Attributes[docAttrIDPrefix]
	v, ok = doc.Attributes.Entry[docAttrIDPrefix]
	if ok {
		v = strings.TrimSpace(v)
		if len(v) > 0 {


@@ 390,7 390,7 @@ func generateID(doc *Document, str string) string {

	bout = make([]byte, 0, len(str))

	v, ok = doc.Attributes[docAttrIDSeparator]
	v, ok = doc.Attributes.Entry[docAttrIDSeparator]
	if ok {
		v = strings.TrimSpace(v)
		if len(v) == 0 {


@@ 536,7 536,7 @@ func parseAttrRef(doc *Document, content []byte, x int) (newContent []byte, ok b
	name = string(bytes.TrimSpace(bytes.ToLower(attrName)))
	attrValue, ok = _attrRef[name]
	if !ok {
		attrValue, ok = doc.Attributes[name]
		attrValue, ok = doc.Attributes.Entry[name]
		if !ok {
			return nil, false
		}

M parser_test.go => parser_test.go +13 -5
@@ 29,7 29,9 @@ func TestGenerateID(t *testing.T) {
		desc: `With idprefix`,
		doc: &Document{
			Attributes: DocumentAttribute{
				docAttrIDPrefix: `123`,
				Entry: map[string]string{
					docAttrIDPrefix: `123`,
				},
			},
		},
		inputExp: map[string]string{


@@ 40,7 42,9 @@ func TestGenerateID(t *testing.T) {
		desc: `With empty idseparator`,
		doc: &Document{
			Attributes: DocumentAttribute{
				docAttrIDSeparator: ``,
				Entry: map[string]string{
					docAttrIDSeparator: ``,
				},
			},
		},
		inputExp: map[string]string{


@@ 51,7 55,9 @@ func TestGenerateID(t *testing.T) {
		desc: `With idseparator`,
		doc: &Document{
			Attributes: DocumentAttribute{
				docAttrIDSeparator: `-`,
				Entry: map[string]string{
					docAttrIDSeparator: `-`,
				},
			},
		},
		inputExp: map[string]string{


@@ 62,8 68,10 @@ func TestGenerateID(t *testing.T) {
		desc: `With idprefix and idseparator`,
		doc: &Document{
			Attributes: DocumentAttribute{
				docAttrIDPrefix:    `id_`,
				docAttrIDSeparator: `-`,
				Entry: map[string]string{
					docAttrIDPrefix:    `id_`,
					docAttrIDSeparator: `-`,
				},
			},
		},
		inputExp: map[string]string{