Repository navigation
Architecture
OXVG's artifacts are distributed in the following ways
- Binaries for use as an executable
- Crates for use as a Rust dependency
- Packages for use as a Node dependency
OXVG processed documents through a series of tasks. Whether this is optimising, linting, or transforming it always runs as a set of tasks against a parsed document.
stateDiagram-v2
[*] --> Parse
state fork_state <<fork>>
Parse --> fork_state
fork_state --> markup5ever
fork_state --> roxmltree
state join_state <<join>>
markup5ever --> join_state
roxmltree --> join_state
note left of join_state
parsers build to common tree representation
end note
join_state --> Process
note right of Process
processors visit and may may manipulate the tree
end note
Process --> Output
Output --> [*]
OXVG will process documents in three phases
- Parse an SVG document using one of the parsers in
oxvg_ast::parseinto a tree represented asoxvg_ast::node::Ref - The tasks to process the document (e.g. those in
oxvg_optimiser::jobs) will each run against the document by implementingoxvg_ast::visitor::Visitorto walk across the document and manipulate it as needed. - Once the tasks are completed, oxvg will output the result as needed. This is usually by serializing the tree using
oxvg_ast::serialize::Node
There are two main parts to the representation of an SVG
- AST, in
oxvg_astwhich represents the tree of nodes in an SVG document - Collections, in
oxvg_collections, which represents the different types of elements, attributes, and data in an SVG document
There are three planned processors
- Optimiser, in
oxvg_optimiser, to shrink an SVG document - Linter, in
oxvg_lint, to report errors to stdout or lang-server - Actions, in
oxvg_actions, to process commands sent by an editor to manipulate the document
What can be parellelised should be parallelised to achieve high performance. Threads should be used for dividing operations and async for handling non-blocking io.
| Process | Threadable/Asyncable? | Threaded/Async? |
|---|---|---|
| Walking | Threadable | Threaded |
| Visitor | Threadable (when immutable) | No |
| Optimisation Jobs | No (Mutates shared document) | No |
| Linting attribute list | Threadable | Threaded |
| Linting elements | Threadable | No |
| Linting LSP | Asyncable | Async |
SVG paths are handled in the oxvg_path crate, it's main purpose is to provide various path representations and the means to convert between them. Each path representation comes with a set of available features.
SVG paths are designed to be as compressible as possible in a string representation. A path is a set of commands which consist of a command, specified by a character followed by a fixed number of float arguments.
In OXVG, this is primarily used for parsing and serializing paths from SVG documents.
-
Pathis a set ofData -
Datais an enum of 20 variants -
Data::*variants each have a fixed array off64arguments. -
Data::Implicitis a special recursive variant that omits the command char.
By only parsing and serializing a path, you will be given the smallest non-destructive representation of the path as possible.
- Each
Data::*variant has an associated char - Each
f64ofDatahas the following possible variations of printing- A signed/unsigned float (e.g.
-0.1) - A signed/unsigned integer (e.g.
1) - A signed/unsigned exponential (e.g.
1e6or1e-6)
- A signed/unsigned float (e.g.
- Each pair of
f64Data has the following possible variations of printing- A normal pair (e.g.
0.1 2cannot have it's space omitted;1 0.2cannot have the leading0omitted) - A float followed by a float <0 (e.g
0.1.1is0.1 0.1) - Any number followed by a negative (e.g.
-2.5e-6-2is-2.5e-6 -2) - Implicit data can also make use of these rules (e.g.
M0.1-2-5.1.6isM0.1 -2 L-5.1 0.6)
- A normal pair (e.g.
Segment paths are designed to be as computationally straightforward as possible. The 20 different command types are distilled into 3 types with a richer set of methods available to them.
Segment paths has methods more useful for manipulation and calculations
-
iter_start_cursoranditer_start_cursor_mutiterates through the segment with it'sItemproviding useful context for each command visited. -
oxvg_path::algorithmwith various geospacial algorithms -
simplify, used as part ofoxvg_path::svg::Path::optimizeto clean up and minify path data.- Some of options in
oxvg_path::optimize::Optionsare directly applied by this method
- Some of options in
-
from_svgandto_svgto convert fromoxvg_path::svg::Path- By converting between representations, you will be given an improved representation by selecting the best options of relative/absolute commands and line/curve shorthands
-
Pathis a set ofSegments -
SegmentrepresentsM/mcommands as it'sstartproperty -
Segmenthas a set ofData -
Datais an enum of 3 variants -
Data::LineTocontainsPointrepresenting the equialentLcommand and arguments -
Data::CurveTocontainsCurverepresenting the equivalentCcommand and arguments -
Data::ArcTocontainsArcrepresenting the equivalentAcommand with it's arguments converted to a computationally friendly representation.
The binary is defined in crates/oxvg/ and allows a user to invoke OXVG's features from the CLI.
- Unix Philosophy. Each command should "do one thing"
- Ease of use. Each command can break "do one thing" within reason (e.g. for walking directories)
These are the individual features that can be invoked by a command. The planned features are as follows
- Optimise
- Format
- Lint
- Actions
- TUI/Editor
These are the features that may be shared between commands
- Walking directories
- Config loading
All development should handled through cargo for crates and pnpm for packages.
The following dependencies are essential to the OXVG binary
- lightningcss & cssparser for stylesheets and presentation attributes
- roxmltree/markup5ever for parsing
- selectors for querying styles
- typed-arena for tree allocations
The following dependencies are essential for the NAPI package
- napi for linking node to rust libraries
The following dependencies are essential for the WASM package
- wasm-bindgen for compiling rust libraries to wasm
- tsify for typescript codegen