Compare commits

...

10 Commits

Author SHA1 Message Date
dependabot-preview[bot] 9d7852c4f9
Upgrade to GitHub-native Dependabot 2021-11-08 17:18:19 +08:00
PoiScript 71292fea36
chore(Cargo.toml): exclude /wasm and /.github 2021-11-08 17:08:38 +08:00
PoiScript 447894d23f
release: bump version to 0.9.0 2021-11-08 17:03:16 +08:00
PoiScript abf568b117
refactor: PropertiesMap 2021-11-08 16:17:12 +08:00
PoiScript 00b46a278a
feat: initial wasm support 2021-11-08 16:17:11 +08:00
PoiScript 2ebd47dbea
build: upgrade dependencies 2021-11-08 14:17:47 +08:00
PoiScript e255c57f39
chore: bump license year 2021-11-08 14:17:40 +08:00
Alex Roper e009e1c199
feat: provide preserve-property-order feature using IndexMap (#25) 2020-05-18 17:21:59 +08:00
PoiScript efdcb4e73a docs(SYNTAX.md): update formatting 2020-05-16 19:01:33 +08:00
PoiScript 630cfa1538 chore: update license year 2020-05-16 18:36:37 +08:00
26 changed files with 1674 additions and 354 deletions

8
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,8 @@
version: 2
updates:
- package-ecosystem: cargo
directory: "/"
schedule:
interval: weekly
time: "09:00"
open-pull-requests-limit: 10

View File

@ -1,17 +1,13 @@
name: Rust
on:
pull_request:
push:
branches:
- master
on: [push, pull_request]
jobs:
format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v2
- name: Run rustfmt
run: cargo fmt -- --check
@ -20,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v2
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1

34
.github/workflows/wasm.yml vendored Normal file
View File

@ -0,0 +1,34 @@
name: Wasm
on: [push, pull_request]
defaults:
run:
working-directory: wasm
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: "14"
- name: Install
run: |
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
yarn
- name: Build
run: |
wasm-pack build --target web --out-dir wasm/pkg -- --features wasm
yarn build
- name: Deploy to gh pages
uses: JamesIves/github-pages-deploy-action@4.1.5
with:
branch: gh-pages
folder: wasm/lib

View File

@ -1,6 +1,6 @@
[package]
name = "orgize"
version = "0.8.4"
version = "0.9.0"
authors = ["PoiScript <poiscript@gmail.com>"]
description = "A Rust library for parsing orgmode files."
repository = "https://github.com/PoiScript/orgize"
@ -8,6 +8,7 @@ readme = "README.md"
edition = "2018"
license = "MIT"
keywords = ["orgmode", "emacs", "parser"]
exclude = ["/wasm", "/.github"]
[package.metadata.docs.rs]
all-features = true
@ -15,24 +16,36 @@ all-features = true
[badges]
travis-ci = { repository = "PoiScript/orgize" }
[lib]
crate-type = ["cdylib", "rlib"]
[profile.release]
# Tell `rustc` to optimize for small code size.
opt-level = "s"
[features]
default = ["ser"]
ser = ["serde", "serde_indextree"]
wasm = ["serde-wasm-bindgen", "wasm-bindgen", "wee_alloc"]
ser = ["serde", "serde_indextree", "indexmap/serde-1"]
[dependencies]
bytecount = "0.6.0"
chrono = { version = "0.4.11", optional = true }
indextree = "4.0.0"
jetscii = "0.4.4"
lazy_static = "1.4.0"
memchr = "2.3.3"
# we don't need to parse any float number, so lexical crate is redundant
nom = { version = "5.1.1", default-features = false, features = ["std"] }
serde = { version = "1.0.106", optional = true, features = ["derive"] }
serde_indextree = { version = "0.2.0", optional = true }
syntect = { version = "4.1.0", optional = true }
bytecount = "0.6"
chrono = { version = "0.4", optional = true }
indextree = "4.3"
jetscii = "0.5"
lazy_static = "1.4"
memchr = "2.4"
nom = { version = "7.0", default-features = false, features = ["std"] }
serde = { version = "1.0", optional = true, features = ["derive"] }
serde_indextree = { version = "0.2", optional = true }
syntect = { version = "4.6", optional = true }
indexmap = { version = "1.7", features = ["serde-1"], optional = true }
# wasm stuff
serde-wasm-bindgen = { version = "0.3", optional = true }
wasm-bindgen = { version = "0.2", optional = true }
wee_alloc = { version = "0.4", optional = true }
[dev-dependencies]
pretty_assertions = "0.6.1"
serde_json = "1.0.51"
slugify = "0.1.0"
pretty_assertions = "1.0"
serde_json = "1.0"
slugify = "0.1"

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2019 Alex Lin (poi)
Copyright (c) 2019-2021 Alex Lin (poi)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -195,7 +195,7 @@ println!("{}", to_string(&org).unwrap());
## Features
By now, orgize provides three features:
By now, orgize provides four features:
+ `ser`: adds the ability to serialize `Org` and other elements using `serde`, enabled by default.
@ -203,6 +203,8 @@ By now, orgize provides three features:
+ `syntect`: provides `SyntectHtmlHandler` for highlighting code block, disabled by default.
+ `indexmap`: Uses `IndexMap` instead of `HashMap` for properties to preserve their order, disabled by default.
## License
MIT

View File

@ -27,7 +27,8 @@
1. [Entities and LaTeX Fragments](#Entities_and_LaTeX_Fragments)
2. [Export Snippets](#Export_Snippets)
3. [Footnote References](#Footnote_References)
4. [Inline Babel Calls and Source Blocks](#Inline_Babel_Calls_and_Source_Blocks)
4. [Inline Babel Calls and Source
Blocks](#Inline_Babel_Calls_and_Source_Blocks)
5. [Line Breaks](#Line_Breaks)
6. [Links](#Links)
7. [Macros](#Macros)
@ -38,29 +39,29 @@
12. [Timestamps](#Timestamp)
13. [Text Markup](#Emphasis_Markers)
This document describes and comments Org syntax as it is currently
read by its parser (Org Elements) and, therefore, by the export
framework. It also includes a few comments on that syntax.
This document describes and comments Org syntax as it is currently read by its
parser (Org Elements) and, therefore, by the export framework. It also includes
a few comments on that syntax.
A core concept in this syntax is that only headlines, sections,
planning lines and property drawers are context-free<sup><a id="fnr.1" class="footref" href="#fn.1">1</a></sup><sup>, </sup><sup><a id="fnr.2" class="footref" href="#fn.2">2</a></sup>.
Every other syntactical part only exists within specific environments.
A core concept in this syntax is that only headlines, sections, planning lines
and property drawers are context-free<sup><a id="fnr.1" class="footref"
href="#fn.1">1</a></sup><sup>, </sup><sup><a id="fnr.2" class="footref"
href="#fn.2">2</a></sup>. Every other syntactical part only exists within
specific environments.
Three categories are used to classify these environments: &ldquo;Greater
elements&rdquo;, &ldquo;elements&rdquo;, and &ldquo;objects&rdquo;, from the broadest scope to the
narrowest. The word &ldquo;element&rdquo; is used for both Greater and non-Greater
elements, the context should make that clear.
Three categories are used to classify these environments: **Greater elements**,
**elements**, and **objects**, from the broadest scope to the narrowest. The
word **element** is used for both Greater and non-Greater elements, the context
should make that clear.
The paragraph is the unit of measurement. An element defines
syntactical parts that are at the same level as a paragraph,
i.e. which cannot contain or be included in a paragraph. An object is
a part that could be included in an element. Greater elements are all
parts that can contain an element.
The paragraph is the unit of measurement. An element defines syntactical parts
that are at the same level as a paragraph, i.e. which cannot contain or be
included in a paragraph. An object is a part that could be included in an
element. Greater elements are all parts that can contain an element.
Empty lines belong to the largest element ending before them. For
example, in a list, empty lines between items belong are part of the
item before them, but empty lines at the end of a list belong to the
plain list element.
Empty lines belong to the largest element ending before them. For example, in a
list, empty lines between items belong are part of the item before them, but
empty lines at the end of a list belong to the plain list element.
Unless specified otherwise, case is not significant.
@ -72,24 +73,22 @@ A headline is defined as:
STARS KEYWORD PRIORITY TITLE TAGS
STARS is a string starting at column 0, containing at least one
asterisk (and up to `org-inlinetask-min-level` if `org-inlinetask`
library is loaded) and ended by a space character. The number of
asterisks is used to define the level of the headline. It&rsquo;s the
sole compulsory part of a headline.
STARS is a string starting at column 0, containing at least one asterisk (and up
to `org-inlinetask-min-level` if `org-inlinetask` library is loaded) and ended
by a space character. The number of asterisks is used to define the level of the
headline. It's the sole compulsory part of a headline.
KEYWORD is a TODO keyword, which has to belong to the list defined
in `org-todo-keywords-1`. Case is significant.
KEYWORD is a TODO keyword, which has to belong to the list defined in
`org-todo-keywords-1`. Case is significant.
PRIORITY is a priority cookie, i.e. a single letter preceded by
a hash sign # and enclosed within square brackets.
PRIORITY is a priority cookie, i.e. a single letter preceded by a hash sign #
and enclosed within square brackets.
TITLE can be made of any character but a new line. Though, it will
match after every other part have been matched.
TITLE can be made of any character but a new line. Though, it will match after
every other part have been matched.
TAGS is made of words containing any alpha-numeric character,
underscore, at sign, hash sign or percent sign, and separated with
colons.
TAGS is made of words containing any alpha-numeric character, underscore, at
sign, hash sign or percent sign, and separated with colons.
Examples of valid headlines include:
@ -101,21 +100,21 @@ Examples of valid headlines include:
**** TODO [#A] COMMENT Title :tag:a2%:
If the first word appearing in the title is &ldquo;COMMENT&rdquo;, the headline
will be considered as &ldquo;commented&rdquo;. Case is significant.
If the first word appearing in the title is `COMMENT`, the headline will be
considered as **commented**. Case is significant.
If its title is `org-footnote-section`, it will be considered as
a &ldquo;footnote section&rdquo;. Case is significant.
If its title is `org-footnote-section`, it will be considered as a **footnote
section**. Case is significant.
If &ldquo;ARCHIVE&rdquo; is one of its tags, it will be considered as
&ldquo;archived&rdquo;. Case is significant.
If `ARCHIVE` is one of its tags, it will be considered as **archived**. Case is
significant.
A headline contains directly one section (optionally), followed by
any number of deeper level headlines.
A headline contains directly one section (optionally), followed by any number of
deeper level headlines.
A section contains directly any greater element or element. Only
a headline can contain a section. As an exception, text before the
first headline in the document also belongs to a section.
A section contains directly any greater element or element. Only a headline can
contain a section. As an exception, text before the first headline in the
document also belongs to a section.
As an example, consider the following document:
@ -145,42 +144,44 @@ Its internal structure could be summarized as:
# Affiliated Keywords
With the exception of [inlinetasks](#Inlinetasks), [items](#Plain_Lists_and_Items), [planning](#Clock,_Diary_Sexp_and_Planning), [clocks](#Clock,_Diary_Sexp_and_Planning), [node
properties](#Node_Properties) and [table rows](#Table_Rows), every other element type can be assigned
With the exception of [inlinetasks](#Inlinetasks),
[items](#Plain_Lists_and_Items), [planning](#Clock,_Diary_Sexp_and_Planning),
[clocks](#Clock,_Diary_Sexp_and_Planning), [node properties](#Node_Properties)
and [table rows](#Table_Rows), every other element type can be assigned
attributes.
This is done by adding specific keywords, named &ldquo;affiliated
keywords&rdquo;, just above the element considered, no blank line
allowed.
This is done by adding specific keywords, named **affiliated keywords**, just
above the element considered, no blank line allowed.
Affiliated keywords are built upon one of the following patterns:
&ldquo;#+KEY: VALUE&rdquo;, &ldquo;#+KEY[OPTIONAL]: VALUE&rdquo; or &ldquo;#+ATTR<sub>BACKEND</sub>: VALUE&rdquo;.
Affiliated keywords are built upon one of the following patterns: `#+KEY: VALUE`,
`#+KEY[OPTIONAL]: VALUE` or `#+ATTR_BACKEND: VALUE`.
KEY is either &ldquo;CAPTION&rdquo;, &ldquo;HEADER&rdquo;, &ldquo;NAME&rdquo;, &ldquo;PLOT&rdquo; or &ldquo;RESULTS&rdquo;
string.
KEY is either `CAPTION`, `HEADER`, `NAME`, `PLOT` or `RESULTS` string.
BACKEND is a string constituted of alpha-numeric characters, hyphens
or underscores.
BACKEND is a string constituted of alpha-numeric characters, hyphens or
underscores.
OPTIONAL and VALUE can contain any character but a new line. Only
&ldquo;CAPTION&rdquo; and &ldquo;RESULTS&rdquo; keywords can have an optional value.
OPTIONAL and VALUE can contain any character but a new line. Only `CAPTION` and
`RESULTS` keywords can have an optional value.
An affiliated keyword can appear more than once if KEY is either
&ldquo;CAPTION&rdquo; or &ldquo;HEADER&rdquo; or if its pattern is &ldquo;#+ATTR<sub>BACKEND</sub>: VALUE&rdquo;.
An affiliated keyword can appear more than once if KEY is either `CAPTION` or
`HEADER` or if its pattern is `#+ATTR_BACKEND: VALUE`.
&ldquo;CAPTION&rdquo;, &ldquo;AUTHOR&rdquo;, &ldquo;DATE&rdquo; and &ldquo;TITLE&rdquo; keywords can contain objects
in their value and their optional value, if applicable.
`CAPTION`, `AUTHOR`, `DATE` and `TITLE` keywords can contain objects in their
value and their optional value, if applicable.
<a id="Greater_Elements"></a>
# Greater Elements
Unless specified otherwise, greater elements can contain directly
any other element or greater element excepted:
Unless specified otherwise, greater elements can contain directly any other
element or greater element excepted:
- elements of their own type,
- [node properties](#Node_Properties), which can only be found in [property drawers](#Property_Drawers),
- [items](#Plain_Lists_and_Items), which can only be found in [plain lists](#Plain_Lists_and_Items).
- [node properties](#Node_Properties), which can only be found in [property
drawers](#Property_Drawers),
- [items](#Plain_Lists_and_Items), which can only be found in [plain
lists](#Plain_Lists_and_Items).
<a id="Greater_Blocks"></a>
@ -194,18 +195,16 @@ Greater blocks consist in the following pattern:
NAME can contain any non-whitespace character.
PARAMETERS can contain any character other than new line, and can
be omitted.
PARAMETERS can contain any character other than new line, and can be omitted.
If NAME is &ldquo;CENTER&rdquo;, it will be a &ldquo;center block&rdquo;. If it is
&ldquo;QUOTE&rdquo;, it will be a &ldquo;quote block&rdquo;.
If NAME is `CENTER`, it will be a **center block**. If it is `QUOTE`, it will be
a **quote block**.
If the block is neither a center block, a quote block or a [block
element](#Blocks), it will be a &ldquo;special block&rdquo;.
element](#Blocks), it will be a **special block**.
CONTENTS can contain any element, except : a line `#+END_NAME` on
its own. Also lines beginning with STARS must be quoted by
a comma.
CONTENTS can contain any element, except : a line `#+END_NAME` on its own. Also
lines beginning with STARS must be quoted by a comma.
<a id="Drawers"></a>
@ -217,8 +216,7 @@ Pattern for drawers is:
CONTENTS
:END:
NAME can contain word-constituent characters, hyphens and
underscores.
NAME can contain word-constituent characters, hyphens and underscores.
CONTENTS can contain any element but another drawer.
@ -246,63 +244,58 @@ Pattern for footnote definitions is:
It must start at column 0.
LABEL is either a number or follows the pattern &ldquo;fn:WORD&rdquo;, where
word can contain any word-constituent character, hyphens and
underscore characters.
LABEL is either a number or follows the pattern `fn:WORD`, where word can
contain any word-constituent character, hyphens and underscore characters.
CONTENTS can contain any element excepted another footnote
definition. It ends at the next footnote definition, the next
headline, two consecutive empty lines or the end of buffer.
CONTENTS can contain any element excepted another footnote definition. It ends
at the next footnote definition, the next headline, two consecutive empty lines
or the end of buffer.
<a id="Inlinetasks"></a>
## Inlinetasks
Inlinetasks are defined by `org-inlinetask-min-level` contiguous
asterisk characters starting at column 0, followed by a whitespace
character.
Inlinetasks are defined by `org-inlinetask-min-level` contiguous asterisk
characters starting at column 0, followed by a whitespace character.
Optionally, inlinetasks can be ended with a string constituted of
`org-inlinetask-min-level` contiguous asterisk characters starting
at column 0, followed by a space and the &ldquo;END&rdquo; string.
`org-inlinetask-min-level` contiguous asterisk characters starting at column 0,
followed by a space and the `END` string.
Inlinetasks are recognized only after `org-inlinetask` library is
loaded.
Inlinetasks are recognized only after `org-inlinetask` library is loaded.
<a id="Plain_Lists_and_Items"></a>
## Plain Lists and Items
Items are defined by a line starting with the following pattern:
&ldquo;BULLET COUNTER-SET CHECK-BOX TAG&rdquo;, in which only BULLET is
mandatory.
`BULLET COUNTER-SET CHECK-BOX TAG`, in which only BULLET is mandatory.
BULLET is either an asterisk, a hyphen, a plus sign character or
follows either the pattern &ldquo;COUNTER.&rdquo; or &ldquo;COUNTER)&rdquo;. In any case,
BULLET is follwed by a whitespace character or line ending.
BULLET is either an asterisk, a hyphen, a plus sign character or follows either
the pattern `COUNTER.` or `COUNTER)`. In any case, BULLET is follwed by a
whitespace character or line ending.
COUNTER can be a number or a single letter.
COUNTER-SET follows the pattern [@COUNTER].
CHECK-BOX is either a single whitespace character, a &ldquo;X&rdquo; character
or a hyphen, enclosed within square brackets.
CHECK-BOX is either a single whitespace character, a `X` character or a hyphen,
enclosed within square brackets.
TAG follows &ldquo;TAG-TEXT ::&rdquo; pattern, where TAG-TEXT can contain any
character but a new line.
TAG follows `TAG-TEXT ::` pattern, where TAG-TEXT can contain any character but
a new line.
An item ends before the next item, the first line less or equally
indented than its starting line, or two consecutive empty lines.
Indentation of lines within other greater elements do not count,
neither do inlinetasks boundaries.
An item ends before the next item, the first line less or equally indented than
its starting line, or two consecutive empty lines. Indentation of lines within
other greater elements do not count, neither do inlinetasks boundaries.
A plain list is a set of consecutive items of the same indentation.
It can only directly contain items.
A plain list is a set of consecutive items of the same indentation. It can only
directly contain items.
If first item in a plain list has a counter in its bullet, the
plain list will be an &ldquo;ordered plain-list&rdquo;. If it contains a tag,
it will be a &ldquo;descriptive list&rdquo;. Otherwise, it will be an
&ldquo;unordered list&rdquo;. List types are mutually exclusive.
If first item in a plain list has a counter in its bullet, the plain list will
be an **ordered plain-list**. If it contains a tag, it will be a **descriptive
list**. Otherwise, it will be an **unordered list**. List types are mutually
exclusive.
For example, consider the following excerpt of an Org document:
@ -322,8 +315,8 @@ Its internal structure is as follows:
## Property Drawers
Property drawers are a special type of drawer containing properties
attached to a headline. They are located right after a [headline](#Headlines_and_Sections)
Property drawers are a special type of drawer containing properties attached to
a headline. They are located right after a [headline](#Headlines_and_Sections)
and its [planning](#Clock,_Diary_Sexp_and_Planning) information.
HEADLINE
@ -345,23 +338,22 @@ where CONTENTS consists of zero or more [node properties](#Node_Properties).
## Tables
Tables start at lines beginning with either a vertical bar or the
&ldquo;+-&rdquo; string followed by plus or minus signs only, assuming they are
not preceded with lines of the same type. These lines can be
indented.
Tables start at lines beginning with either a vertical bar or the `+-` string
followed by plus or minus signs only, assuming they are not preceded with lines
of the same type. These lines can be indented.
A table starting with a vertical bar has &ldquo;org&rdquo; type. Otherwise it
has &ldquo;table.el&rdquo; type.
A table starting with a vertical bar has `org` type. Otherwise it has `table.el`
type.
Org tables end at the first line not starting with a vertical bar.
Table.el tables end at the first line not starting with either
a vertical line or a plus sign. Such lines can be indented.
Org tables end at the first line not starting with a vertical bar. Table.el
tables end at the first line not starting with either a vertical line or a plus
sign. Such lines can be indented.
An org table can only contain table rows. A table.el table does
not contain anything.
An org table can only contain table rows. A table.el table does not contain
anything.
One or more &ldquo;#+TBLFM: FORMULAS&rdquo; lines, where &ldquo;FORMULAS&rdquo; can contain
any character, can follow an org table.
One or more `#+TBLFM: FORMULAS` lines, where `FORMULAS` can contain any
character, can follow an org table.
<a id="Elements"></a>
@ -370,8 +362,8 @@ any character, can follow an org table.
Elements cannot contain any other element.
Only [keywords](#Keywords) whose name belongs to
`org-element-document-properties`, [verse blocks](#Blocks) , [paragraphs](#Paragraphs) and
[table rows](#Table_Rows) can contain objects.
`org-element-document-properties`, [verse blocks](#Blocks) ,
[paragraphs](#Paragraphs) and [table rows](#Table_Rows) can contain objects.
<a id="Babel_Call"></a>
@ -395,33 +387,33 @@ Like [greater blocks](#Greater_Blocks), pattern for blocks is:
NAME cannot contain any whitespace character.
If NAME is &ldquo;COMMENT&rdquo;, it will be a &ldquo;comment block&rdquo;. If it is
&ldquo;EXAMPLE&rdquo;, it will be an &ldquo;example block&rdquo;. If it is &ldquo;EXPORT&rdquo;, it
will be an &ldquo;export block&rdquo;. If it is &ldquo;SRC&rdquo;, it will be a &ldquo;source
block&rdquo;. If it is &ldquo;VERSE&rdquo;, it will be a &ldquo;verse block&rdquo;.
1. If NAME is `COMMENT`, it will be a **comment block**.
2. If it is `EXAMPLE`, it will be an **example block**.
3. If it is `EXPORT`, it will be an **export block**.
4. If it is `SRC`, it will be a **source block**.
5. If it is `VERSE`, it will be a **verse block**.
DATA can contain any character but a new line. It can be ommitted,
unless the block is either a &ldquo;source block&rdquo; or an &ldquo;export block&rdquo;.
DATA can contain any character but a new line. It can be ommitted, unless the
block is either a **source block** or an **export block**.
In the latter case, it should be constituted of a single word.
In the former case, it must follow the pattern &ldquo;LANGUAGE SWITCHES
ARGUMENTS&rdquo;, where SWITCHES and ARGUMENTS are optional.
In the former case, it must follow the pattern `LANGUAGE SWITCHES ARGUMENTS`,
where SWITCHES and ARGUMENTS are optional.
LANGUAGE cannot contain any whitespace character.
SWITCHES is made of any number of &ldquo;SWITCH&rdquo; patterns, separated by
blank lines.
SWITCHES is made of any number of `SWITCH` patterns, separated by blank lines.
A SWITCH pattern is either &ldquo;-l &rdquo;FORMAT&ldquo;&rdquo;, where FORMAT can contain
any character but a double quote and a new line, &ldquo;-S&rdquo; or &ldquo;+S&rdquo;,
where S stands for a single letter.
A SWITCH pattern is either `-l FORMAT`, where FORMAT can contain any character
but a double quote and a new line, `-S` or `+S`, where S stands for a single
letter.
ARGUMENTS can contain any character but a new line.
CONTENTS can contain any character, including new lines. Though it
will only contain Org objects if the block is a verse block.
Otherwise, CONTENTS will not be parsed.
CONTENTS can contain any character, including new lines. Though it will only
contain Org objects if the block is a verse block. Otherwise, CONTENTS will not
be parsed.
<a id="Clock,_Diary_Sexp_and_Planning"></a>
@ -432,41 +424,39 @@ A clock follows either of the patterns below:
CLOCK: INACTIVE-TIMESTAMP
CLOCK: INACTIVE-TIMESTAMP-RANGE DURATION
INACTIVE-TIMESTAMP, resp. INACTIVE-TIMESTAMP-RANGE, is an inactive,
resp. inactive range, [timestamp](#Timestamp) object.
INACTIVE-TIMESTAMP, resp. INACTIVE-TIMESTAMP-RANGE, is an inactive, resp.
inactive range, [timestamp](#Timestamp) object.
DURATION follows the pattern:
=> HH:MM
HH is a number containing any number of digits. MM is a two digit
numbers.
HH is a number containing any number of digits. MM is a two digit numbers.
A diary sexp is a line starting at column 0 with &ldquo;%%(&rdquo; string. It
can then contain any character besides a new line.
A diary sexp is a line starting at column 0 with `%%(` string. It can then
contain any character besides a new line.
A planning is an element with the following pattern:
HEADLINE
PLANNING
where HEADLINE is a [headline](#Headlines_and_Sections) element and PLANNING is a line filled
with INFO parts, where each of them follows the pattern:
where HEADLINE is a [headline](#Headlines_and_Sections) element and PLANNING is
a line filled with INFO parts, where each of them follows the pattern:
KEYWORD: TIMESTAMP
KEYWORD is either &ldquo;DEADLINE&rdquo;, &ldquo;SCHEDULED&rdquo; or &ldquo;CLOSED&rdquo;. TIMESTAMP
is a [timestamp](#Timestamp) object.
KEYWORD is either `DEADLINE`, `SCHEDULED` or `CLOSED`. TIMESTAMP is a
[timestamp](#Timestamp) object.
In particular, no blank line is allowed between PLANNING and
HEADLINE.
In particular, no blank line is allowed between PLANNING and HEADLINE.
<a id="Comments"></a>
## Comments
A &ldquo;comment line&rdquo; starts with a hash signe and a whitespace
character or an end of line.
A **comment line** starts with a hash signe and a whitespace character or an end
of line.
Comments can contain any number of consecutive comment lines.
@ -474,18 +464,17 @@ Comments can contain any number of consecutive comment lines.
## Fixed Width Areas
A &ldquo;fixed-width line&rdquo; start with a colon character and a whitespace
or an end of line.
A **fixed-width line** start with a colon character and a whitespace or an end
of line.
Fixed width areas can contain any number of consecutive fixed-width
lines.
Fixed width areas can contain any number of consecutive fixed-width lines.
<a id="Horizontal_Rules"></a>
## Horizontal Rules
A horizontal rule is a line made of at least 5 consecutive hyphens.
It can be indented.
A horizontal rule is a line made of at least 5 consecutive hyphens. It can be
indented.
<a id="Keywords"></a>
@ -495,13 +484,12 @@ Keywords follow the syntax:
#+KEY: VALUE
KEY can contain any non-whitespace character, but it cannot be
equal to &ldquo;CALL&rdquo; or any affiliated keyword.
KEY can contain any non-whitespace character, but it cannot be equal to `CALL`
or any affiliated keyword.
VALUE can contain any character excepted a new line.
If KEY belongs to `org-element-document-properties`, VALUE can
contain objects.
If KEY belongs to `org-element-document-properties`, VALUE can contain objects.
<a id="LaTeX_Environments"></a>
@ -513,14 +501,14 @@ Pattern for LaTeX environments is:
NAME is constituted of alpha-numeric or asterisk characters.
CONTENTS can contain anything but the &ldquo;\end{NAME}&rdquo; string.
CONTENTS can contain anything but the `\end{NAME}` string.
<a id="Node_Properties"></a>
## Node Properties
Node properties can only exist in [property drawers](#Property_Drawers). Their pattern
is any of the following
Node properties can only exist in [property drawers](#Property_Drawers). Their
pattern is any of the following
:NAME: VALUE
@ -530,8 +518,8 @@ is any of the following
:NAME+:
NAME can contain any non-whitespace character but cannot end with
a plus sign. It cannot be the empty string.
NAME can contain any non-whitespace character but cannot end with a plus sign.
It cannot be the empty string.
VALUE can contain anything but a newline character.
@ -539,8 +527,8 @@ VALUE can contain anything but a newline character.
## Paragraphs
Paragraphs are the default element, which means that any
unrecognized context is a paragraph.
Paragraphs are the default element, which means that any unrecognized context is
a paragraph.
Empty lines and other elements end paragraphs.
@ -550,11 +538,11 @@ Paragraphs can contain every type of object.
## Table Rows
A table rows is either constituted of a vertical bar and any number
of [table cells](#Table_Cells) or a vertical bar followed by a hyphen.
A table rows is either constituted of a vertical bar and any number of [table
cells](#Table_Cells) or a vertical bar followed by a hyphen.
In the first case the table row has the &ldquo;standard&rdquo; type. In the
second case, it has the &ldquo;rule&rdquo; type.
In the first case the table row has the **standard** type. In the second case,
it has the **rule** type.
Table rows can only exist in [tables](#Tables).
@ -564,19 +552,18 @@ Table rows can only exist in [tables](#Tables).
Objects can only be found in the following locations:
- [affiliated keywords](#Affiliated_keywords) defined in `org-element-parsed-keywords`,
- [affiliated keywords](#Affiliated_keywords) defined in
`org-element-parsed-keywords`,
- [document properties](#Keywords),
- [headline](#Headlines_and_Sections) titles,
- [inlinetask](#Inlinetasks) titles,
- [item](#Plain_Lists_and_Items) tags,
- [paragraphs](#Paragraphs),
- [table cells](#Table_Cells),
- [table rows](#Table_Rows), which can only contain table cell
objects,
- [table rows](#Table_Rows), which can only contain table cell objects,
- [verse blocks](#Blocks).
Most objects cannot contain objects. Those which can will be
specified.
Most objects cannot contain objects. Those which can will be specified.
<a id="Entities_and_LaTeX_Fragments"></a>
@ -589,8 +576,8 @@ An entity follows the pattern:
where NAME has a valid association in either `org-entities` or
`org-entities-user`.
POST is the end of line, &ldquo;{}&rdquo; string, or a non-alphabetical
character. It isn&rsquo;t separated from NAME by a whitespace character.
POST is the end of line, `{}` string, or a non-alphabetical character. It isn't
separated from NAME by a whitespace character.
A LaTeX fragment can follow multiple patterns:
@ -601,48 +588,43 @@ A LaTeX fragment can follow multiple patterns:
PRE$CHAR$POST
PRE$BORDER1 BODY BORDER2$POST
NAME contains alphabetical characters only and must not have an
association in either `org-entities` or `org-entities-user`.
NAME contains alphabetical characters only and must not have an association in
either **org-entities** or **org-entities-user**.
BRACKETS is optional, and is not separated from NAME with white
spaces. It may contain any number of the following patterns:
BRACKETS is optional, and is not separated from NAME with white spaces. It may
contain any number of the following patterns:
[CONTENTS1]
{CONTENTS2}
where CONTENTS1 can contain any characters excepted &ldquo;{&rdquo; &ldquo;}&rdquo;, &ldquo;[&rdquo;
&ldquo;]&rdquo; and newline and CONTENTS2 can contain any character excepted
&ldquo;{&rdquo;, &ldquo;}&rdquo; and newline.
where CONTENTS1 can contain any characters excepted `{` `}`, `[` `]` and newline
and CONTENTS2 can contain any character excepted `{`, `}` and newline.
CONTENTS can contain any character but cannot contain &ldquo;\\)&rdquo; in the
second template or &ldquo;\\]&rdquo; in the third one.
CONTENTS can contain any character but cannot contain `\\)` in the second
template or `\\]` in the third one.
PRE is either the beginning of line or a character different from
`$`.
PRE is either the beginning of line or a character different from `$`.
CHAR is a non-whitespace character different from `.`, `,`, `?`,
`;`, `'` or a double quote.
CHAR is a non-whitespace character different from `.`, `,`, `?`, `;`, `'` or a
double quote.
POST is any punctuation (including parentheses and quotes) or space
character, or the end of line.
POST is any punctuation (including parentheses and quotes) or space character,
or the end of line.
BORDER1 is a non-whitespace character different from `.`, `,`, `;`
and `$`.
BORDER1 is a non-whitespace character different from `.`, `,`, `;` and `$`.
BODY can contain any character excepted `$`, and may not span over
more than 3 lines.
BODY can contain any character excepted `$`, and may not span over more than 3
lines.
BORDER2 is any non-whitespace character different from `,`, `.` and
`$`.
BORDER2 is any non-whitespace character different from `,`, `.` and `$`.
---
> It would introduce incompatibilities with previous Org versions,
> but support for `$...$` (and for symmetry, `$$...$$`) constructs
> ought to be removed.
> It would introduce incompatibilities with previous Org versions, but support
> for `$...$` (and for symmetry, `$$...$$`) constructs ought to be removed.
>
> They are slow to parse, fragile, redundant and imply false
> positives. &#x2014; ngz
> They are slow to parse, fragile, redundant and imply false positives. &#x2014;
> ngz
<a id="Export_Snippets"></a>
@ -654,7 +636,7 @@ Patter for export snippets is:
NAME can contain any alpha-numeric character and hyphens.
VALUE can contain anything but &ldquo;@@&rdquo; string.
VALUE can contain anything but `@@` string.
<a id="Footnote_References"></a>
@ -666,16 +648,15 @@ There are four patterns for footnote references:
[fn:LABEL:DEFINITION]
[fn::DEFINITION]
LABEL can contain any word constituent character, hyphens and
underscores.
LABEL can contain any word constituent character, hyphens and underscores.
DEFINITION can contain any character. Though opening and closing
square brackets must be balanced in it. It can contain any object
encountered in a paragraph, even other footnote references.
DEFINITION can contain any character. Though opening and closing square brackets
must be balanced in it. It can contain any object encountered in a paragraph,
even other footnote references.
If the reference follows the second pattern, it is called an
&ldquo;inline footnote&rdquo;. If it follows the third one, i.e. if LABEL is
omitted, it is an &ldquo;anonymous footnote&rdquo;.
If the reference follows the second pattern, it is called an **inline
footnote**. If it follows the third one, i.e. if LABEL is omitted, it is an
**anonymous footnote**.
<a id="Inline_Babel_Calls_and_Source_Blocks"></a>
@ -686,11 +667,11 @@ Inline Babel calls follow any of the following patterns:
call_NAME(ARGUMENTS)
call_NAME[HEADER](ARGUMENTS)[HEADER]
NAME can contain any character besides `(`, `)` and &ldquo;\n&rdquo;.
NAME can contain any character besides `(`, `)` and `\n`.
HEADER can contain any character besides `]` and &ldquo;\n&rdquo;.
HEADER can contain any character besides `]` and `\n`.
ARGUMENTS can contain any character besides `)` and &ldquo;\n&rdquo;.
ARGUMENTS can contain any character besides `)` and `\n`.
Inline source blocks follow any of the following patterns:
@ -699,14 +680,14 @@ Inline source blocks follow any of the following patterns:
LANG can contain any non-whitespace character.
OPTIONS and BODY can contain any character but &ldquo;\n&rdquo;.
OPTIONS and BODY can contain any character but `\n`.
<a id="Line_Breaks"></a>
## Line Breaks
A line break consists in &ldquo;\\\SPACE&rdquo; pattern at the end of an
otherwise non-empty line.
A line break consists in `\\\SPACE` pattern at the end of an otherwise non-empty
line.
SPACE can contain any number of tabs and spaces, including 0.
@ -723,25 +704,27 @@ There are 4 major types of links:
PRE1 and POST1, when they exist, are non alphanumeric characters.
RADIO is a string matched by some [radio target](#Targets_and_Radio_Targets). It may contain
[entities](#Entities_and_LaTeX_Fragments), [latex fragments](#Entities_and_LaTeX_Fragments), [subscript](#Subscript_and_Superscript) and [superscript](#Subscript_and_Superscript).
RADIO is a string matched by some [radio target](#Targets_and_Radio_Targets). It
may contain [entities](#Entities_and_LaTeX_Fragments), [latex
fragments](#Entities_and_LaTeX_Fragments),
[subscript](#Subscript_and_Superscript) and
[superscript](#Subscript_and_Superscript).
PROTOCOL is a string among `org-link-types`.
PATH can contain any character but `]`, `<`, `>` and `\n`.
PRE2 and POST2, when they exist, are non word constituent
characters.
PRE2 and POST2, when they exist, are non word constituent characters.
PATH2 can contain any non-whitespace character excepted `(`, `)`,
`<` and `>`. It must end with a word-constituent character, or any
non-whitespace non-punctuation character followed by `/`.
PATH2 can contain any non-whitespace character excepted `(`, `)`, `<` and `>`.
It must end with a word-constituent character, or any non-whitespace
non-punctuation character followed by `/`.
DESCRIPTION must be enclosed within square brackets. It can
contain any character but square brackets. It can contain any
object found in a paragraph excepted a [footnote reference](#Footnote_References), a [radio
target](#Targets_and_Radio_Targets) and a [line break](#Line_Breaks). It cannot contain another link either,
unless it is a plain or angular link.
DESCRIPTION must be enclosed within square brackets. It can contain any
character but square brackets. It can contain any object found in a paragraph
excepted a [footnote reference](#Footnote_References), a [radio
target](#Targets_and_Radio_Targets) and a [line break](#Line_Breaks). It cannot
contain another link either, unless it is a plain or angular link.
DESCRIPTION is optional.
@ -761,8 +744,8 @@ PATH4 can contain any character besides square brackets.
ID is constituted of hexadecimal numbers separated with hyphens.
PATH4, CUSTOM-ID, CODEREF and FUZZY can contain any character
besides square brackets.
PATH4, CUSTOM-ID, CODEREF and FUZZY can contain any character besides square
brackets.
<a id="Macros"></a>
@ -772,12 +755,12 @@ Macros follow the pattern:
{{{NAME(ARGUMENTS)}}}
NAME must start with a letter and can be followed by any number of
alpha-numeric characters, hyphens and underscores.
NAME must start with a letter and can be followed by any number of alpha-numeric
characters, hyphens and underscores.
ARGUMENTS can contain anything but &ldquo;}}}&rdquo; string. Values within
ARGUMENTS are separated by commas. Non-separating commas have to
be escaped with a backslash character.
ARGUMENTS can contain anything but `}}}` string. Values within ARGUMENTS are
separated by commas. Non-separating commas have to be escaped with a backslash
character.
<a id="Targets_and_Radio_Targets"></a>
@ -787,18 +770,19 @@ Radio targets follow the pattern:
<<<CONTENTS>>>
CONTENTS can be any character besides `<`, `>` and &ldquo;\n&rdquo;. It cannot
start or end with a whitespace character. As far as objects go, it
can contain [text markup](#Emphasis_Markers), [entities](#Entities_and_LaTeX_Fragments), [latex fragments](#Entities_and_LaTeX_Fragments), [subscript](#Subscript_and_Superscript) and
CONTENTS can be any character besides `<`, `>` and `\n`. It cannot start or end
with a whitespace character. As far as objects go, it can contain [text
markup](#Emphasis_Markers), [entities](#Entities_and_LaTeX_Fragments), [latex
fragments](#Entities_and_LaTeX_Fragments),
[subscript](#Subscript_and_Superscript) and
[superscript](#Subscript_and_Superscript) only.
Targets follow the pattern:
<<TARGET>>
TARGET can contain any character besides `<`, `>` and &ldquo;\n&rdquo;. It
cannot start or end with a whitespace character. It cannot contain
any object.
TARGET can contain any character besides `<`, `>` and `\n`. It cannot start or
end with a whitespace character. It cannot contain any object.
<a id="Statistics_Cookies"></a>
@ -825,9 +809,9 @@ Pattern for superscript is:
CHAR is any non-whitespace character.
SCRIPT can be `*` or an expression enclosed in parenthesis
(respectively curly brackets), possibly containing balanced
parenthesis (respectively curly brackets).
SCRIPT can be `*` or an expression enclosed in parenthesis (respectively curly
brackets), possibly containing balanced parenthesis (respectively curly
brackets).
SCRIPT can also follow the pattern:
@ -835,8 +819,8 @@ SCRIPT can also follow the pattern:
SIGN is either a plus sign, a minus sign, or an empty string.
CHARS is any number of alpha-numeric characters, commas,
backslashes and dots, or an empty string.
CHARS is any number of alpha-numeric characters, commas, backslashes and dots,
or an empty string.
FINAL is an alpha-numeric character.
@ -852,11 +836,10 @@ Table cells follow the pattern:
CONTENTS can contain any character excepted a vertical bar.
SPACES contains any number of space characters, including zero. It
can be used to align properly the table.
SPACES contains any number of space characters, including zero. It can be used
to align properly the table.
The final bar may be replaced with a newline character for the last
cell in row.
The final bar may be replaced with a newline character for the last cell in row.
<a id="Timestamp"></a>
@ -878,29 +861,28 @@ DATE follows the pattern:
YYYY-MM-DD DAYNAME
`Y`, `M` and `D` are digits. DAYNAME can contain any non
whitespace-character besides `+`, `-`, `]`, `>`, a digit or `\n`.
`Y`, `M` and `D` are digits. DAYNAME can contain any non whitespace-character
besides `+`, `-`, `]`, `>`, a digit or `\n`.
TIME follows the pattern `H:MM`. `H` can be one or two digit long
and can start with 0.
TIME follows the pattern `H:MM`. `H` can be one or two digit long and can start
with 0.
REPEATER-OR-DELAY follows the pattern:
MARK VALUE UNIT
MARK is `+` (cumulate type), `++` (catch-up type) or `.+` (restart
type) for a repeater, and `-` (all type) or `--` (first type) for
warning delays.
MARK is `+` (cumulate type), `++` (catch-up type) or `.+` (restart type) for a
repeater, and `-` (all type) or `--` (first type) for warning delays.
VALUE is a number.
UNIT is a character among `h` (hour), `d` (day), `w` (week), `m`
(month), `y` (year).
UNIT is a character among `h` (hour), `d` (day), `w` (week), `m` (month), `y`
(year).
MARK, VALUE and UNIT are not separated by whitespace characters.
There can be two REPEATER-OR-DELAY in the timestamp: one as
a repeater and one as a warning delay.
There can be two REPEATER-OR-DELAY in the timestamp: one as a repeater and one
as a warning delay.
<a id="Emphasis_Markers"></a>
@ -910,32 +892,30 @@ Text markup follows the pattern:
PRE MARKER CONTENTS MARKER POST
PRE is a whitespace character, `(`, `{` `'` or a double quote. It
can also be a beginning of line.
PRE is a whitespace character, `(`, `{` `'` or a double quote. It can also be a
beginning of line.
MARKER is a character among `*` (bold), `=` (verbatim), `/`
(italic), `+` (strike-through), `_` (underline), `~` (code).
MARKER is a character among `*` (bold), `=` (verbatim), `/` (italic), `+`
(strike-through), `_` (underline), `~` (code).
CONTENTS is a string following the pattern:
BORDER BODY BORDER
BORDER can be any non-whitespace character excepted `,`, `'` or
a double quote.
BORDER can be any non-whitespace character excepted `,`, `'` or a double quote.
BODY can contain contain any character but may not span over more
than 3 lines.
BODY can contain contain any character but may not span over more than 3 lines.
BORDER and BODY are not separated by whitespaces.
CONTENTS can contain any object encountered in a paragraph when
markup is &ldquo;bold&rdquo;, &ldquo;italic&rdquo;, &ldquo;strike-through&rdquo; or &ldquo;underline&rdquo;.
CONTENTS can contain any object encountered in a paragraph when markup is
**bold**, **italic**, **strike-through** or **underline**.
POST is a whitespace character, `-`, `.`, `,`, `:`, `!`, `?`, `'`,
`)`, `}` or a double quote. It can also be an end of line.
POST is a whitespace character, `-`, `.`, `,`, `:`, `!`, `?`, `'`, `)`, `}` or a
double quote. It can also be an end of line.
PRE, MARKER, CONTENTS, MARKER and POST are not separated by
whitespace characters.
PRE, MARKER, CONTENTS, MARKER and POST are not separated by whitespace
characters.
---
@ -944,19 +924,19 @@ whitespace characters.
>
> This should really be simplified.
>
> Also, CONTENTS should be anything within code and verbatim
> emphasis, by definition. &#x2014; ngz
> Also, CONTENTS should be anything within code and verbatim emphasis, by
> definition. &#x2014; ngz
# Footnotes
<sup><a id="fn.1" href="#fnr.1">1</a></sup> In particular, the parser requires stars at column 0 to be
quoted by a comma when they do not define a headline.
<sup><a id="fn.1" href="#fnr.1">1</a></sup> In particular, the parser requires
stars at column 0 to be quoted by a comma when they do not define a headline.
<sup><a id="fn.2" href="#fnr.2">2</a></sup> It also means that only headlines and sections can be
recognized just by looking at the beginning of the line. Planning
lines and property drawers can be recognized by looking at one or two
<sup><a id="fn.2" href="#fnr.2">2</a></sup> It also means that only headlines
and sections can be recognized just by looking at the beginning of the line.
Planning lines and property drawers can be recognized by looking at one or two
lines above.
As a consequence, using `org-element-at-point` or
`org-element-context` will move up to the parent headline, and parse
top-down from there until context around original location is found.
As a consequence, using `org-element-at-point` or `org-element-context` will
move up to the parent headline, and parse top-down from there until context
around original location is found.

View File

@ -50,7 +50,7 @@ pub use self::{
table::{Table, TableCell, TableRow},
target::Target,
timestamp::{Datetime, Timestamp},
title::Title,
title::{PropertiesMap, Title},
};
use std::borrow::Cow;

View File

@ -1,7 +1,7 @@
//! Headline Title
use std::borrow::Cow;
use std::collections::HashMap;
use std::{borrow::Cow, iter::FromIterator};
use memchr::memrchr2;
use nom::{
@ -43,8 +43,11 @@ pub struct Title<'a> {
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
pub planning: Option<Box<Planning<'a>>>,
/// Property drawer associated to this headline
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "HashMap::is_empty"))]
pub properties: HashMap<Cow<'a, str>, Cow<'a, str>>,
#[cfg_attr(
feature = "ser",
serde(skip_serializing_if = "PropertiesMap::is_empty")
)]
pub properties: PropertiesMap<'a>,
/// Numbers of blank lines between last title's line and next non-blank line
/// or buffer's end
pub post_blank: usize,
@ -99,11 +102,7 @@ impl Title<'_> {
keyword: self.keyword.map(Into::into).map(Cow::Owned),
raw: self.raw.into_owned().into(),
planning: self.planning.map(|p| Box::new(p.into_owned())),
properties: self
.properties
.into_iter()
.map(|(k, v)| (k.into_owned().into(), v.into_owned().into()))
.collect(),
properties: self.properties.into_owned(),
post_blank: self.post_blank,
}
}
@ -118,12 +117,66 @@ impl Default for Title<'_> {
keyword: None,
raw: Cow::Borrowed(""),
planning: None,
properties: HashMap::new(),
properties: PropertiesMap::new(),
post_blank: 0,
}
}
}
/// Properties
#[derive(Default, Debug, Clone)]
#[cfg_attr(test, derive(PartialEq))]
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
pub struct PropertiesMap<'a> {
pub pairs: Vec<(Cow<'a, str>, Cow<'a, str>)>,
}
impl<'a> PropertiesMap<'a> {
pub fn new() -> Self {
PropertiesMap { pairs: Vec::new() }
}
pub fn is_empty(&self) -> bool {
self.pairs.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = &(Cow<'a, str>, Cow<'a, str>)> {
self.pairs.iter()
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut (Cow<'a, str>, Cow<'a, str>)> {
self.pairs.iter_mut()
}
pub fn into_iter(self) -> impl Iterator<Item = (Cow<'a, str>, Cow<'a, str>)> {
self.pairs.into_iter()
}
pub fn into_hash_map(self) -> HashMap<Cow<'a, str>, Cow<'a, str>> {
self.pairs.into_iter().collect()
}
#[cfg(feature = "indexmap")]
pub fn into_index_map(self) -> indexmap::IndexMap<Cow<'a, str>, Cow<'a, str>> {
self.pairs.into_iter().collect()
}
pub fn into_owned(self) -> PropertiesMap<'static> {
self.pairs
.into_iter()
.map(|(k, v)| (k.into_owned().into(), v.into_owned().into()))
.collect()
}
}
impl<'a> FromIterator<(Cow<'a, str>, Cow<'a, str>)> for PropertiesMap<'a> {
fn from_iter<T: IntoIterator<Item = (Cow<'a, str>, Cow<'a, str>)>>(iter: T) -> Self {
let mut map = PropertiesMap::new();
map.pairs.extend(iter);
map
}
}
fn white_spaces_or_eol(input: &str) -> IResult<&str, &str, ()> {
alt((space1, line_ending))(input)
}
@ -204,16 +257,16 @@ fn is_tag_line(input: &str) -> bool {
}
#[inline]
fn parse_properties_drawer(input: &str) -> IResult<&str, HashMap<Cow<'_, str>, Cow<'_, str>>, ()> {
fn parse_properties_drawer(input: &str) -> IResult<&str, PropertiesMap<'_>, ()> {
let (input, (drawer, content)) = parse_drawer_without_blank(input.trim_start())?;
if drawer.name != "PROPERTIES" {
return Err(Err::Error(make_error(input, ErrorKind::Tag)));
}
let (_, map) = fold_many0(
parse_node_property,
HashMap::new(),
|mut acc: HashMap<_, _>, (name, value)| {
acc.insert(name.into(), value.into());
PropertiesMap::new,
|mut acc: PropertiesMap, (name, value)| {
acc.pairs.push((name.into(), value.into()));
acc
},
)(content)?;
@ -247,7 +300,7 @@ fn parse_title_() {
raw: "COMMENT Title".into(),
tags: vec!["tag".into(), "a2%".into()],
planning: None,
properties: HashMap::new(),
properties: PropertiesMap::new(),
post_blank: 0,
},
"COMMENT Title"
@ -266,7 +319,7 @@ fn parse_title_() {
raw: "ToDO [#A] COMMENT Title".into(),
tags: vec![],
planning: None,
properties: HashMap::new(),
properties: PropertiesMap::new(),
post_blank: 0,
},
"ToDO [#A] COMMENT Title"
@ -285,7 +338,7 @@ fn parse_title_() {
raw: "T0DO [#A] COMMENT Title".into(),
tags: vec![],
planning: None,
properties: HashMap::new(),
properties: PropertiesMap::new(),
post_blank: 0,
},
"T0DO [#A] COMMENT Title"
@ -304,7 +357,7 @@ fn parse_title_() {
raw: "[#1] COMMENT Title".into(),
tags: vec![],
planning: None,
properties: HashMap::new(),
properties: PropertiesMap::new(),
post_blank: 0,
},
"[#1] COMMENT Title"
@ -323,7 +376,7 @@ fn parse_title_() {
raw: "[#a] COMMENT Title".into(),
tags: vec![],
planning: None,
properties: HashMap::new(),
properties: PropertiesMap::new(),
post_blank: 0,
},
"[#a] COMMENT Title"
@ -344,7 +397,7 @@ fn parse_title_() {
raw: "[#B]::".into(),
tags: vec![],
planning: None,
properties: HashMap::new(),
properties: PropertiesMap::new(),
post_blank: 0,
},
"[#B]::"
@ -364,7 +417,7 @@ fn parse_title_() {
raw: "Title :tag:a2%".into(),
tags: vec![],
planning: None,
properties: HashMap::new(),
properties: PropertiesMap::new(),
post_blank: 0,
},
"Title :tag:a2%"
@ -383,7 +436,7 @@ fn parse_title_() {
raw: "Title tag:a2%:".into(),
tags: vec![],
planning: None,
properties: HashMap::new(),
properties: PropertiesMap::new(),
post_blank: 0,
},
"Title tag:a2%:"
@ -409,7 +462,7 @@ fn parse_title_() {
raw: "DONE Title".into(),
tags: vec![],
planning: None,
properties: HashMap::new(),
properties: PropertiesMap::new(),
post_blank: 0,
},
"DONE Title"
@ -434,7 +487,7 @@ fn parse_title_() {
raw: "Title".into(),
tags: vec![],
planning: None,
properties: HashMap::new(),
properties: PropertiesMap::new(),
post_blank: 0,
},
"Title"
@ -451,7 +504,48 @@ fn parse_properties_drawer_() {
"",
vec![("CUSTOM_ID".into(), "id".into())]
.into_iter()
.collect::<HashMap<_, _>>()
.collect::<PropertiesMap>()
))
)
}
#[test]
#[cfg(feature = "indexmap")]
fn preserve_properties_drawer_order() {
let mut vec = Vec::default();
// Use a large number of properties to reduce false pass rate, since HashMap
// is non-deterministic. There are roughly 10^18 possible derangements of this sequence.
for i in 0..20 {
// Avoid alphabetic or numeric order.
let j = (i + 7) % 20;
vec.push((
Cow::Owned(format!(
"{}{}",
if i % 3 == 0 {
"FOO"
} else if i % 3 == 1 {
"QUX"
} else {
"BAR"
},
j
)),
Cow::Owned(i.to_string()),
));
}
let mut s = String::default();
for (k, v) in &vec {
s += &format!(" :{}: {}\n", k, v);
}
let drawer = format!(" :PROPERTIES:\n{}:END:\n", &s);
let map = parse_properties_drawer(&drawer).unwrap().1.into_index_map();
// indexmap should be in the same order as vector
for (left, right) in vec.iter().zip(map) {
assert_eq!(left, &right);
}
}

View File

@ -269,7 +269,7 @@ impl OrgHandler<Error> for DefaultOrgHandler {
}
if !title.properties.is_empty() {
writeln!(&mut w, ":PROPERTIES:")?;
for (key, value) in &title.properties {
for (key, value) in title.properties.iter() {
writeln!(&mut w, ":{}: {}", key, value)?;
}
writeln!(&mut w, ":END:")?;

View File

@ -240,3 +240,6 @@ pub use elements::Element;
pub use headline::{Document, Headline};
pub use org::{Event, Org};
pub use validate::ValidationError;
#[cfg(feature = "wasm")]
mod wasm;

View File

@ -83,11 +83,7 @@ impl Org<'_> {
}
for child in children {
expect_element!(
child,
"Headline",
Element::Headline { .. }
);
expect_element!(child, "Headline", Element::Headline { .. });
}
}
Element::Headline { .. } => {
@ -107,11 +103,7 @@ impl Org<'_> {
}
for child in children {
expect_element!(
child,
"Headline",
Element::Headline { .. }
);
expect_element!(child, "Headline", Element::Headline { .. });
}
}
Element::Title(title) => {

189
src/wasm/mod.rs Normal file
View File

@ -0,0 +1,189 @@
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
use serde::Serialize;
use serde_wasm_bindgen::Serializer;
use wasm_bindgen::prelude::*;
use crate::{Element, Event};
#[wasm_bindgen]
pub struct Org(crate::Org<'static>);
#[wasm_bindgen]
impl Org {
#[wasm_bindgen]
pub fn parse(input: String) -> Self {
Org(crate::Org::parse_string(input))
}
#[wasm_bindgen(js_name = toJson)]
pub fn to_json(&self) -> JsValue {
to_value(&self.0)
}
}
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(skip_typescript)]
pub type Handler;
#[wasm_bindgen(method)]
pub fn text(this: &Handler, text: JsValue);
#[wasm_bindgen(method)]
pub fn code(this: &Handler, item: JsValue);
#[wasm_bindgen(method)]
pub fn cookie(this: &Handler, item: JsValue);
#[wasm_bindgen(method)]
pub fn rule(this: &Handler);
#[wasm_bindgen(method, js_name = exampleBlock)]
pub fn example_block(this: &Handler, item: JsValue);
#[wasm_bindgen(method, js_name = exportBlock)]
pub fn export_block(this: &Handler, item: JsValue);
#[wasm_bindgen(method, js_name = sourceBlock)]
pub fn source_block(this: &Handler, item: JsValue);
#[wasm_bindgen(method, js_name = inlineSrc)]
pub fn inline_src(this: &Handler, item: JsValue);
#[wasm_bindgen(method)]
pub fn link(this: &Handler, item: JsValue);
#[wasm_bindgen(method)]
pub fn snippet(this: &Handler, item: JsValue);
#[wasm_bindgen(method)]
pub fn timestamp(this: &Handler, item: JsValue);
#[wasm_bindgen(method)]
pub fn verbatim(this: &Handler, item: JsValue);
#[wasm_bindgen(method)]
pub fn fixedWidth(this: &Handler, item: JsValue);
#[wasm_bindgen(method)]
pub fn keyword(this: &Handler, item: JsValue);
#[wasm_bindgen(method, js_name = listStart)]
pub fn list_start(this: &Handler, item: JsValue);
#[wasm_bindgen(method, js_name = listEnd)]
pub fn list_end(this: &Handler, item: JsValue);
#[wasm_bindgen(method, js_name = tableStart)]
pub fn table_start(this: &Handler, item: JsValue);
#[wasm_bindgen(method, js_name = tableEnd)]
pub fn table_end(this: &Handler, item: JsValue);
#[wasm_bindgen(method, js_name = tableRowStart)]
pub fn table_row_start(this: &Handler, item: JsValue);
#[wasm_bindgen(method, js_name = tableRowEnd)]
pub fn table_row_end(this: &Handler, item: JsValue);
#[wasm_bindgen(method, js_name = tableCellStart)]
pub fn table_cell_start(this: &Handler, item: JsValue);
#[wasm_bindgen(method, js_name = tableCellEnd)]
pub fn table_cell_end(this: &Handler, item: JsValue);
#[wasm_bindgen(method, js_name = titleStart)]
pub fn title_start(this: &Handler, item: JsValue);
#[wasm_bindgen(method, js_name = titleEnd)]
pub fn title_end(this: &Handler, item: JsValue);
#[wasm_bindgen(method, js_name = boldStart)]
pub fn bold_start(this: &Handler);
#[wasm_bindgen(method, js_name = boldEnd)]
pub fn bold_end(this: &Handler);
#[wasm_bindgen(method, js_name = centerBlockStart)]
pub fn center_block_start(this: &Handler, item: JsValue);
#[wasm_bindgen(method, js_name = centerBlockEnd)]
pub fn center_block_end(this: &Handler, item: JsValue);
#[wasm_bindgen(method, js_name = documentStart)]
pub fn document_start(this: &Handler);
#[wasm_bindgen(method, js_name = documentEnd)]
pub fn document_end(this: &Handler);
#[wasm_bindgen(method, js_name = italicStart)]
pub fn italic_start(this: &Handler);
#[wasm_bindgen(method, js_name = italicEnd)]
pub fn italic_end(this: &Handler);
#[wasm_bindgen(method, js_name = listItemStart)]
pub fn list_item_start(this: &Handler);
#[wasm_bindgen(method, js_name = listItemEnd)]
pub fn list_item_end(this: &Handler);
#[wasm_bindgen(method, js_name = paragraphStart)]
pub fn paragraph_start(this: &Handler);
#[wasm_bindgen(method, js_name = paragraphEnd)]
pub fn paragraph_end(this: &Handler);
#[wasm_bindgen(method, js_name = quoteBlockStart)]
pub fn quote_block_start(this: &Handler, item: JsValue);
#[wasm_bindgen(method, js_name = quoteBlockEnd)]
pub fn quote_block_end(this: &Handler, item: JsValue);
#[wasm_bindgen(method, js_name = sectionStart)]
pub fn section_start(this: &Handler);
#[wasm_bindgen(method, js_name = sectionEnd)]
pub fn section_end(this: &Handler);
#[wasm_bindgen(method, js_name = strikeStart)]
pub fn strike_start(this: &Handler);
#[wasm_bindgen(method, js_name = strikeEnd)]
pub fn strike_end(this: &Handler);
#[wasm_bindgen(method, js_name = underlineStart)]
pub fn underline_start(this: &Handler);
#[wasm_bindgen(method, js_name = underlineEnd)]
pub fn underline_end(this: &Handler);
#[wasm_bindgen(method, js_name = verseBlockStart)]
pub fn verse_block_start(this: &Handler, item: JsValue);
#[wasm_bindgen(method, js_name = verseBlockEnd)]
pub fn verse_block_end(this: &Handler, item: JsValue);
}
#[wasm_bindgen]
pub fn handle(org: &Org, handler: Handler) {
for event in org.0.iter() {
use Element::*;
match event {
Event::Start(Text { value }) => handler.text(JsValue::from_str(value)),
Event::Start(ExampleBlock(block)) => handler.example_block(to_value(block)),
Event::Start(ExportBlock(block)) => handler.export_block(to_value(block)),
Event::Start(SourceBlock(block)) => handler.source_block(to_value(block)),
Event::Start(InlineSrc(src)) => handler.inline_src(to_value(src)),
Event::Start(Code { value }) => handler.code(JsValue::from_str(value)),
Event::Start(Link(link)) => handler.link(to_value(link)),
Event::Start(Snippet(snippet)) => handler.snippet(to_value(snippet)),
Event::Start(Timestamp(timestamp)) => handler.timestamp(to_value(timestamp)),
Event::Start(Verbatim { value }) => handler.verbatim(JsValue::from_str(value)),
Event::Start(FixedWidth(fixed_width)) => handler.fixedWidth(to_value(fixed_width)),
Event::Start(Rule(_)) => handler.rule(),
Event::Start(Cookie(cookie)) => handler.cookie(to_value(cookie)),
Event::Start(Keyword(keyword)) => handler.keyword(to_value(keyword)),
Event::Start(Table(table)) => handler.table_start(to_value(table)),
Event::End(Table(table)) => handler.table_start(to_value(table)),
Event::Start(TableRow(row)) => handler.table_row_start(to_value(row)),
Event::End(TableRow(row)) => handler.table_row_start(to_value(row)),
Event::Start(TableCell(cell)) => handler.table_cell_start(to_value(cell)),
Event::End(TableCell(cell)) => handler.table_cell_start(to_value(cell)),
Event::Start(Title(title)) => handler.title_start(to_value(title)),
Event::End(Title(title)) => handler.title_end(to_value(title)),
Event::Start(QuoteBlock(block)) => handler.quote_block_start(to_value(block)),
Event::End(QuoteBlock(block)) => handler.quote_block_end(to_value(block)),
Event::Start(CenterBlock(block)) => handler.center_block_start(to_value(block)),
Event::End(CenterBlock(block)) => handler.center_block_end(to_value(block)),
Event::Start(VerseBlock(block)) => handler.verse_block_start(to_value(block)),
Event::End(VerseBlock(block)) => handler.verse_block_end(to_value(block)),
Event::Start(Bold) => handler.bold_start(),
Event::End(Bold) => handler.bold_end(),
Event::Start(Document { .. }) => handler.document_start(),
Event::End(Document { .. }) => handler.document_end(),
Event::Start(List(list)) => handler.list_start(to_value(list)),
Event::End(List(list)) => handler.list_end(to_value(list)),
Event::Start(Italic) => handler.italic_start(),
Event::End(Italic) => handler.italic_end(),
Event::Start(ListItem(_)) => handler.list_item_start(),
Event::End(ListItem(_)) => handler.list_item_end(),
Event::Start(Paragraph { .. }) => handler.paragraph_start(),
Event::End(Paragraph { .. }) => handler.paragraph_end(),
Event::Start(Section) => handler.section_start(),
Event::End(Section) => handler.section_end(),
Event::Start(Strike) => handler.strike_start(),
Event::End(Strike) => handler.strike_end(),
Event::Start(Underline) => handler.underline_start(),
Event::End(Underline) => handler.underline_end(),
_ => continue,
};
}
}
pub fn to_value<T: Serialize + ?Sized>(value: &T) -> JsValue {
value
.serialize(&Serializer::new().serialize_maps_as_objects(true))
.unwrap()
}

6
wasm/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
/lib
/node_modules
/out-tsc
/package
/pkg
*.tgz

41
wasm/README.md Normal file
View File

@ -0,0 +1,41 @@
# orgize
![npm](https://img.shields.io/npm/v/orgize)
## Quick start
Install the package:
```sh
npm install orgize
yarn add orgize
```
Load the wasm module and init:
### Browser
```js
import { init, renderHtml } from "orgize";
init().then(() => {
console.log(renderHtml("* Hello, /world/!"));
});
```
### Node.js
```js
const { init, renderHtml } = require("orgize");
const { readFile } = require("fs/promises");
readFile(require.resolve("orgize/lib/orgize_bg.wasm"))
.then((bytes) => init(new WebAssembly.Module(bytes)))
.then(() => {
console.log(renderHtml("* Hello, /world/!"));
});
```
## License
MIT

71
wasm/index.html Normal file
View File

@ -0,0 +1,71 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Orgize wasm demo</title>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script defer src="https://unpkg.com/alpinejs@3/dist/cdn.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.0/beautify-html.js"></script>
<script src="./orgize.umd.js"></script>
<style>
h3 {
margin: 0;
}
body > * {
margin-bottom: 16px;
}
</style>
</head>
<body
x-data="{ loaded: false, org: '* Hello, /world/!', type: 'json' }"
x-init="orgize.init('./orgize_bg.wasm').then(() => loaded = true)"
>
<h2>Orgize wasm demo</h2>
<div>
<a href="https://github.com/PoiScript/orgize">GitHub</a>
<a href="https://www.npmjs.com/package/orgize">NPM</a>
<a href="https://crates.io/crates/orgize">crates.io</a>
</div>
<div>Input:</div>
<textarea
x-model="org"
style="width: 100%; height: 100px; margin-bottom: 16px"
></textarea>
<div>Type:</div>
<div>
<button @click="type = 'json'">JSON</button>
<button @click="type = 'html'">HTML</button>
<button @click="type = 'html-rendered'">HTML (Rendered)</button>
</div>
<div>Output:</div>
<noscript>
<p style="color: red">JavaScript is required.</p>
</noscript>
<pre
x-show="type === 'json'"
x-transition
x-text="loaded ? JSON.stringify(orgize.Org.parse(org).toJson(), null, 2) : 'Loading...'"
></pre>
<pre
x-show="type === 'html'"
x-transition
x-text="loaded ? html_beautify(orgize.renderHtml(org), { indent_size: 2 }) : 'Loading...'"
></pre>
<div
x-show="type === 'html-rendered'"
x-transition
x-html="loaded ? orgize.renderHtml(org) : 'Loading...'"
></div>
</body>
</html>

27
wasm/package.json Normal file
View File

@ -0,0 +1,27 @@
{
"name": "orgize",
"version": "0.0.3",
"license": "MIT",
"author": "PoiScript <poiscript@gmail.com>",
"main": "lib/orgize.umd.js",
"module": "lib/orgize.es.js",
"typings": "lib/orgize.d.ts",
"repository": {
"type": "git",
"url": "https://github.com/PoiScript/orgize"
},
"scripts": {
"prebuild": "rm -rf out-tsc/ lib/",
"build": "tsc && rollup -c rollup.js && cp pkg/orgize_bg.wasm lib/"
},
"devDependencies": {
"rollup": "^2.56.3",
"rollup-plugin-copy": "^3.4.0",
"rollup-plugin-dts": "^4.0.0",
"typescript": "^4.4.2"
},
"files": [
"lib",
"README.md"
]
}

31
wasm/rollup.js Normal file
View File

@ -0,0 +1,31 @@
import dts from "rollup-plugin-dts";
import copy from "rollup-plugin-copy";
export default [
{
input: "./out-tsc/index.d.ts",
output: {
file: "./lib/orgize.d.ts",
},
plugins: [dts()],
},
{
input: "./out-tsc/index.js",
output: [
{
file: "./lib/orgize.es.js",
format: "es",
},
{
name: "orgize",
file: "./lib/orgize.umd.js",
format: "umd",
},
],
plugins: [
copy({
targets: [{ src: "index.html", dest: "lib" }],
}),
],
},
];

102
wasm/src/handler.ts Normal file
View File

@ -0,0 +1,102 @@
export class Handler {
text(_text: string) {}
code(_item: string) {}
cookie(_item: Cookie) {}
rule() {}
exampleBlock(_item: Block) {}
exportBlock(_item: Block) {}
sourceBlock(_item: SourceBlock) {}
inlineSrc(_item: InlineSrc) {}
link(_item: Link) {}
snippet(_item: Snippet) {}
timestamp(_item: any) {}
verbatim(_item: string) {}
fixedWidth(_item: FixedWidth) {}
listStart(_item: List) {}
listEnd(_item: List) {}
tableStart(_item: any) {}
tableEnd(_item: any) {}
tableRowStart(_item: any) {}
tableRowEnd(_item: any) {}
tableCellStart(_item: any) {}
tableCellEnd(_item: any) {}
titleStart(_item: Title) {}
titleEnd(_item: Title) {}
boldStart() {}
boldEnd() {}
centerBlockStart(_item: any) {}
centerBlockEnd(_item: any) {}
documentStart() {}
documentEnd() {}
italicStart() {}
italicEnd() {}
listItemStart() {}
listItemEnd() {}
paragraphStart() {}
paragraphEnd() {}
quoteBlockStart(_item: any) {}
quoteBlockEnd(_item: any) {}
sectionStart() {}
sectionEnd() {}
strikeStart() {}
strikeEnd() {}
underlineStart() {}
underlineEnd() {}
verseBlockStart(_item: any) {}
verseBlockEnd(_item: any) {}
keyword(_item: Keyword) {}
}
export type Title = {
level: number;
priority?: string;
tags?: string[];
keyword?: string;
raw: string;
properties?: { [key: string]: string };
post_blank: number;
};
export type List = {
ordered: boolean;
};
export type Block = {
contents: string;
};
export type InlineSrc = {
lang: string;
body: string;
};
export type Link = {
path: string;
desc?: string;
};
export type FixedWidth = {
value: string;
};
export type Cookie = {
value: string;
};
export type SourceBlock = {
contents: string;
language: string;
arguments: string;
post_blank: number;
};
export type Keyword = {
key: string;
optional?: string;
value: string;
};
export type Snippet = {
name: string;
value: string;
};

160
wasm/src/html.ts Normal file
View File

@ -0,0 +1,160 @@
import {
Block,
Cookie,
FixedWidth,
Handler,
InlineSrc,
Link,
List,
Snippet,
Title,
} from "./handler";
const tags: { [tag: string]: string } = {
"&": "&amp;",
"<": "&lt;",
">": "&gt;",
'"': "&quot;",
"'": "&apos;",
};
const replaceTags = (tag: string): string => tags[tag];
export const escapeHtml = (str: string): string =>
str.replace(/[&<>"']/g, replaceTags);
export class HtmlHandler extends Handler {
result: string;
constructor(result: string = "") {
super();
this.result = result;
}
static escape(): string {
return "";
}
quoteBlockStart() {
this.result += "<blockquote>";
}
quoteBlockEnd() {
this.result += "</blockquote>";
}
centerBlockStart() {
this.result += '<div class="center">';
}
centerBlockEnd() {
this.result += "</div>";
}
verseBlockStart() {
this.result += '<p class="verse">';
}
verseBlockEnd() {
this.result += "</p>";
}
boldStart() {
this.result += "<b>";
}
boldEnd() {
this.result += "</b>";
}
documentStart() {
this.result += "<main>";
}
documentEnd() {
this.result += "</main>";
}
listStart(list: List) {
this.result += `<${list.ordered ? "o" : "u"}l>`;
}
listEnd(list: List) {
this.result += `</${list.ordered ? "o" : "u"}l>`;
}
italicStart() {
this.result += "<i>";
}
italicEnd() {
this.result += "</i>";
}
listItemStart() {
this.result += "<li>";
}
listItemEnd() {
this.result += "</li>";
}
paragraphStart() {
this.result += "<p>";
}
paragraphEnd() {
this.result += "</p>";
}
sectionStart() {
this.result += "<section>";
}
sectionEnd() {
this.result += "</section>";
}
strikeStart() {
this.result += "<s>";
}
strikeEnd() {
this.result += "</s>";
}
underlineStart() {
this.result += "<u>";
}
underlineEnd() {
this.result += "</u>";
}
exampleBlock(block: Block) {
this.result += `<pre class="example">${escapeHtml(block.contents)}</pre>`;
}
sourceBlock(block: Block) {
this.result += `<pre class="example">${escapeHtml(block.contents)}</pre>`;
}
inlineSrc(src: InlineSrc) {
this.result += `<code class="src src-${src.lang}">${escapeHtml(
src.body
)}</code>`;
}
code(value: string) {
this.result += `<code>${escapeHtml(value)}</code>`;
}
link(link: Link) {
this.result += `<a href="${link.path}">${escapeHtml(
link.desc || link.path
)}</a>`;
}
snippet(snippet: Snippet) {
if (snippet.name.toLowerCase() === "html") {
this.result += snippet.value;
}
}
text(value: string) {
this.result += escapeHtml(value);
}
verbatim(value: string) {
this.result += `<code>${escapeHtml(value)}</code>`;
}
fixedWidth(item: FixedWidth) {
this.result += `<pre class="example">${escapeHtml(item.value)}</pre>`;
}
rule() {
this.result += "<hr>";
}
cookie(cookie: Cookie) {
this.result += `<code>${escapeHtml(cookie.value)}</code>`;
}
titleStart(title: Title) {
this.result += `<h${Math.min(title.level, 6)}>`;
}
titleEnd(title: Title) {
this.result += `</h${Math.min(title.level, 6)}>`;
}
}

34
wasm/src/index.ts Normal file
View File

@ -0,0 +1,34 @@
import init, {
handle as internalHandle,
InitInput,
InitOutput,
Org,
} from "../pkg/orgize";
import { Handler } from "./handler";
import { HtmlHandler } from "./html";
import { CollectKeywords } from "./keyword";
export const handle = (org: Org | string, handler: Handler) => {
if (typeof org === "string") {
org = Org.parse(org);
}
internalHandle(org, handler);
};
export const renderHtml = (
org: Org | string,
handler: HtmlHandler = new HtmlHandler()
): string => {
handle(org, handler);
return handler.result;
};
export const keywords = (org: Org | string): { [key: string]: string[] } => {
const handler = new CollectKeywords();
handle(org, handler);
return handler.keywords;
};
export * from "./handler";
export * from "./html";
export { Org, init, InitInput, InitOutput };

10
wasm/src/keyword.ts Normal file
View File

@ -0,0 +1,10 @@
import { Handler, Keyword } from "./handler";
export class CollectKeywords extends Handler {
keywords: { [key: string]: string[] } = {};
keyword(keyword: Keyword) {
this.keywords[keyword.key] = this.keywords[keyword.key] || [];
this.keywords[keyword.key].push(keyword.value);
}
}

82
wasm/tests/html.js Normal file
View File

@ -0,0 +1,82 @@
const { readFile } = require("fs/promises");
const { resolve } = require("path");
const { strictEqual } = require("assert");
const { init, renderHtml } = require("../lib/orgize.umd");
const assert = (org, html) => strictEqual(renderHtml(org), html);
readFile(resolve(__dirname, "../lib/orgize_bg.wasm"))
.then((bytes) => new WebAssembly.Module(bytes))
.then((module) => init(module))
.then(() => {
assert(
"*bold*, /italic/,\n_underlined_, =verbatim= and ~code~",
"<main><section><p><b>bold</b>, <i>italic</i>,\n<u>underlined</u>, " +
"<code>verbatim</code> and <code>code</code></p></section></main>"
);
assert(
"Visit[[http://example.com][link1]]or[[http://example.com][link1]].",
`<main><section><p>Visit<a href="http://example.com">link1</a>or<a href="http://example.com">link1</a>.</p></section></main>`
);
assert(
`
* title 1
section 1
** title 2
section 2
* title 3
section 3
* title 4
section 4
`,
"<main><h1>title 1</h1><section><p>section 1</p></section>" +
"<h2>title 2</h2><section><p>section 2</p></section>" +
"<h1>title 3</h1><section><p>section 3</p></section>" +
"<h1>title 4</h1><section><p>section 4</p></section></main>"
);
assert(
`
+ 1
+ 2
- 3
- 4
+ 5
`,
"<main><section><ul>" +
"<li><p>1</p></li>" +
"<li><p>2</p><ul><li><p>3</p></li><li><p>4</p></li></ul></li>" +
"<li><p>5</p></li>" +
"</ul></section></main>"
);
assert(
"@@html:<del>@@delete this@@html:</del>@@",
"<main><section><p><del>delete this</del></p></section></main>"
);
assert(
`
* title
paragraph 1
paragraph 2
paragraph 3
paragraph 4
`,
"<main><h1>title</h1><section>" +
"<p>paragraph 1</p><p>paragraph 2</p>" +
"<p>paragraph 3</p><p>paragraph 4</p>" +
"</section></main>"
);
});

17
wasm/tests/keyword.js Normal file
View File

@ -0,0 +1,17 @@
const { readFile } = require("fs/promises");
const { resolve } = require("path");
const { deepStrictEqual } = require("assert");
const { init, keywords } = require("../lib/orgize.umd");
const assert = (org, kw) => deepStrictEqual(keywords(org), kw);
readFile(resolve(__dirname, "../lib/orgize_bg.wasm"))
.then((bytes) => new WebAssembly.Module(bytes))
.then((module) => init(module))
.then(() => {
assert("#+TITLE: orgize test cases\n#+FOO: bar", {
TITLE: ["orgize test cases"],
FOO: ["bar"],
});
});

12
wasm/tsconfig.json Normal file
View File

@ -0,0 +1,12 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"lib": ["ESNext", "WebWorker"],
"strict": true,
"outDir": "out-tsc",
"rootDir": "./src",
"declaration": true
},
"include": ["./src"]
}

416
wasm/yarn.lock Normal file
View File

@ -0,0 +1,416 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@babel/code-frame@^7.14.5":
version "7.14.5"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.14.5.tgz#23b08d740e83f49c5e59945fbf1b43e80bbf4edb"
integrity sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==
dependencies:
"@babel/highlight" "^7.14.5"
"@babel/helper-validator-identifier@^7.14.5":
version "7.14.9"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz#6654d171b2024f6d8ee151bf2509699919131d48"
integrity sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==
"@babel/highlight@^7.14.5":
version "7.14.5"
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9"
integrity sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==
dependencies:
"@babel/helper-validator-identifier" "^7.14.5"
chalk "^2.0.0"
js-tokens "^4.0.0"
"@nodelib/fs.scandir@2.1.5":
version "2.1.5"
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
dependencies:
"@nodelib/fs.stat" "2.0.5"
run-parallel "^1.1.9"
"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
version "2.0.5"
resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
"@nodelib/fs.walk@^1.2.3":
version "1.2.8"
resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
dependencies:
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
"@types/fs-extra@^8.0.1":
version "8.1.2"
resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-8.1.2.tgz#7125cc2e4bdd9bd2fc83005ffdb1d0ba00cca61f"
integrity sha512-SvSrYXfWSc7R4eqnOzbQF4TZmfpNSM9FrSWLU3EUnWBuyZqNBOrv1B1JA3byUDPUl9z4Ab3jeZG2eDdySlgNMg==
dependencies:
"@types/node" "*"
"@types/glob@^7.1.1":
version "7.2.0"
resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb"
integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==
dependencies:
"@types/minimatch" "*"
"@types/node" "*"
"@types/minimatch@*":
version "3.0.5"
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40"
integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==
"@types/node@*":
version "16.11.6"
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae"
integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w==
ansi-styles@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
dependencies:
color-convert "^1.9.0"
array-union@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
balanced-match@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
dependencies:
balanced-match "^1.0.0"
concat-map "0.0.1"
braces@^3.0.1:
version "3.0.2"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
dependencies:
fill-range "^7.0.1"
chalk@^2.0.0:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
dependencies:
ansi-styles "^3.2.1"
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
color-convert@^1.9.0:
version "1.9.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
dependencies:
color-name "1.1.3"
color-name@1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
colorette@^1.1.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40"
integrity sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
dir-glob@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==
dependencies:
path-type "^4.0.0"
escape-string-regexp@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
fast-glob@^3.0.3:
version "3.2.7"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1"
integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==
dependencies:
"@nodelib/fs.stat" "^2.0.2"
"@nodelib/fs.walk" "^1.2.3"
glob-parent "^5.1.2"
merge2 "^1.3.0"
micromatch "^4.0.4"
fastq@^1.6.0:
version "1.13.0"
resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c"
integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==
dependencies:
reusify "^1.0.4"
fill-range@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
dependencies:
to-regex-range "^5.0.1"
fs-extra@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0"
integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==
dependencies:
graceful-fs "^4.2.0"
jsonfile "^4.0.0"
universalify "^0.1.0"
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
fsevents@~2.3.2:
version "2.3.2"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
glob-parent@^5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
dependencies:
is-glob "^4.0.1"
glob@^7.1.3:
version "7.2.0"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023"
integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.0.4"
once "^1.3.0"
path-is-absolute "^1.0.0"
globby@10.0.1:
version "10.0.1"
resolved "https://registry.yarnpkg.com/globby/-/globby-10.0.1.tgz#4782c34cb75dd683351335c5829cc3420e606b22"
integrity sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==
dependencies:
"@types/glob" "^7.1.1"
array-union "^2.1.0"
dir-glob "^3.0.1"
fast-glob "^3.0.3"
glob "^7.1.3"
ignore "^5.1.1"
merge2 "^1.2.3"
slash "^3.0.0"
graceful-fs@^4.1.6, graceful-fs@^4.2.0:
version "4.2.8"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a"
integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==
has-flag@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
ignore@^5.1.1:
version "5.1.9"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.9.tgz#9ec1a5cbe8e1446ec60d4420060d43aa6e7382fb"
integrity sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ==
inflight@^1.0.4:
version "1.0.6"
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
dependencies:
once "^1.3.0"
wrappy "1"
inherits@2:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
is-extglob@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
is-glob@^4.0.1:
version "4.0.3"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
dependencies:
is-extglob "^2.1.1"
is-number@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
is-plain-object@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-3.0.1.tgz#662d92d24c0aa4302407b0d45d21f2251c85f85b"
integrity sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==
js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
jsonfile@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=
optionalDependencies:
graceful-fs "^4.1.6"
magic-string@^0.25.7:
version "0.25.7"
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051"
integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==
dependencies:
sourcemap-codec "^1.4.4"
merge2@^1.2.3, merge2@^1.3.0:
version "1.4.1"
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
micromatch@^4.0.4:
version "4.0.4"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9"
integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==
dependencies:
braces "^3.0.1"
picomatch "^2.2.3"
minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
dependencies:
brace-expansion "^1.1.7"
once@^1.3.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
dependencies:
wrappy "1"
path-is-absolute@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
path-type@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
picomatch@^2.2.3:
version "2.3.0"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972"
integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==
queue-microtask@^1.2.2:
version "1.2.3"
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
reusify@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
rollup-plugin-copy@^3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/rollup-plugin-copy/-/rollup-plugin-copy-3.4.0.tgz#f1228a3ffb66ffad8606e2f3fb7ff23141ed3286"
integrity sha512-rGUmYYsYsceRJRqLVlE9FivJMxJ7X6jDlP79fmFkL8sJs7VVMSVyA2yfyL+PGyO/vJs4A87hwhgVfz61njI+uQ==
dependencies:
"@types/fs-extra" "^8.0.1"
colorette "^1.1.0"
fs-extra "^8.1.0"
globby "10.0.1"
is-plain-object "^3.0.0"
rollup-plugin-dts@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/rollup-plugin-dts/-/rollup-plugin-dts-4.0.0.tgz#7645280183b7624e77375a548a11297f9916f6d8"
integrity sha512-tgUC8CxVgtlLDVloUEA9uACVaxjJHuYxlDSTp1LdCexA0bJx+RuMi45RjdLG9RTCgZlV5YBh3O7P2u6dS1KlnA==
dependencies:
magic-string "^0.25.7"
optionalDependencies:
"@babel/code-frame" "^7.14.5"
rollup@^2.56.3:
version "2.56.3"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.56.3.tgz#b63edadd9851b0d618a6d0e6af8201955a77aeff"
integrity sha512-Au92NuznFklgQCUcV96iXlxUbHuB1vQMaH76DHl5M11TotjOHwqk9CwcrT78+Tnv4FN9uTBxq6p4EJoYkpyekg==
optionalDependencies:
fsevents "~2.3.2"
run-parallel@^1.1.9:
version "1.2.0"
resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
dependencies:
queue-microtask "^1.2.2"
slash@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
sourcemap-codec@^1.4.4:
version "1.4.8"
resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
supports-color@^5.3.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
dependencies:
has-flag "^3.0.0"
to-regex-range@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
dependencies:
is-number "^7.0.0"
typescript@^4.4.2:
version "4.4.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.2.tgz#6d618640d430e3569a1dfb44f7d7e600ced3ee86"
integrity sha512-gzP+t5W4hdy4c+68bfcv0t400HVJMMd2+H9B7gae1nQlBzCqvrXX+6GL/b3GAgyTH966pzrZ70/fRjwAtZksSQ==
universalify@^0.1.0:
version "0.1.2"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=