Update docs.
parent
1b922b5155
commit
d4a145b96b
25
README.md
25
README.md
|
@ -1,6 +1,5 @@
|
|||
# @thefarce/loom
|
||||
|
||||
|
||||
## What is this?
|
||||
|
||||
Loom is a tool for weaving form data with content data in nodejs. It does
|
||||
|
@ -39,7 +38,8 @@ console.log(
|
|||
interpolate(
|
||||
transform(
|
||||
parseHtml('<p>Hello, {name}!</p>'),
|
||||
[],
|
||||
() => { ... },
|
||||
[funcA, funcB, funcC],
|
||||
),
|
||||
{ name: 'Othello' },
|
||||
)
|
||||
|
@ -55,31 +55,30 @@ Running this script produces the following output:
|
|||
|
||||
## API
|
||||
|
||||
### renderHtml(ast)
|
||||
### astToHtml(ast)
|
||||
|
||||
### parseHtml(html)
|
||||
### htmlToAst(html)
|
||||
|
||||
### interpolate(ast, data)
|
||||
|
||||
### transform(ast, plugins)
|
||||
|
||||
See the [transformations documentation](./docs/transformations.md) for more
|
||||
information.
|
||||
|
||||
Transform the AST according to plugins.
|
||||
|
||||
#### ast
|
||||
## Glossary
|
||||
|
||||
### ast
|
||||
|
||||
The AST to be transformed. This can be any AST that conforms to the
|
||||
Unified.js specification, especially the
|
||||
[hast](https://github.com/syntax-tree/hast) AST.
|
||||
|
||||
#### plugins
|
||||
## Contributing to Loom
|
||||
|
||||
Plugins are pairs of functions.
|
||||
|
||||
The *selector* function
|
||||
|
||||
The *transformer* function
|
||||
|
||||
## Development
|
||||
Contributions to Loom are welcome.
|
||||
|
||||
### VIM
|
||||
|
||||
|
|
|
@ -1,83 +0,0 @@
|
|||
# Components
|
||||
|
||||
## Architecture
|
||||
|
||||
Fundamentally, we want to do (approximately) 4 steps, some of which are
|
||||
optional.
|
||||
|
||||
1. Template parsing. Transforms templates into ASTs.
|
||||
1. Template integration. Combines two templates into a single template.
|
||||
1. Content parsing. Structures content for template AST rendering.
|
||||
1. Rendering. Concretize the AST into a document structure with
|
||||
the available content added.
|
||||
|
||||
|
||||
## Thoughts
|
||||
|
||||
It is not at all clear to me that components should be in HTML. It seems
|
||||
like a natural starting point, though, since we want to stay close to our
|
||||
bare-metal technologies.
|
||||
|
||||
Perhaps components should be in the style of HTML or JSX fragments. I
|
||||
borrowed heavily from Svelte for this.
|
||||
|
||||
I'm somewhat dissatisfied with the syntax of svelte's "directives" like
|
||||
{#if} and {/if}. They feel like they were put in as a concession to
|
||||
script interpolation. I think I prefer the JSX approach that uses {}
|
||||
to run arbitrary script content.
|
||||
|
||||
I don't know if there's any concepts we should bring in from XSLT for
|
||||
this, but it's already a technology mechanis,
|
||||
|
||||
|
||||
|
||||
```
|
||||
// This "<loom-module>" tag could be created automatically before inserting.
|
||||
<loom-module>
|
||||
<script type="text/loom-module">
|
||||
/**
|
||||
* Key script features:
|
||||
* - Assume ES6?
|
||||
* - Maybe allow other languages that transpile to JS?
|
||||
* - Automatically sandbox css?
|
||||
* - Everything here needs to be available only during interpretation
|
||||
* of this HTML and css.
|
||||
*/
|
||||
</script>
|
||||
|
||||
<ul>
|
||||
<li>Allow multiple comment styles?</li>
|
||||
<li>Plugin-based transformations (AST)</li>
|
||||
<li>Some kind of script scoping</li>
|
||||
<li>Allow some bits of code using JSX-style {} syntax.</li>
|
||||
</ul>
|
||||
|
||||
<style type="test/scss">
|
||||
/**
|
||||
* Key styling features:
|
||||
*
|
||||
* - Allow all three comment types here? Make this a setting?
|
||||
* - Bake-in postcss transformers? Maybe project-agnostic...
|
||||
* - Automatically sandbox css
|
||||
*/
|
||||
</style>
|
||||
|
||||
</loom-module>
|
||||
```
|
||||
|
||||
|
||||
If the component defines something like this:
|
||||
|
||||
```
|
||||
<script>
|
||||
import Item from 'https://.../Item.component.xml';
|
||||
</script>
|
||||
|
||||
<Item data={item}/>
|
||||
```
|
||||
|
||||
Then the "import" node of the AST would be replaced by a function that
|
||||
provides the requested content (from Item.component.xml) like a macro. When
|
||||
the `<Item/>` node is hit, it will be interpreted according to the imported
|
||||
component macro.
|
||||
|
107
docs/markup.md
107
docs/markup.md
|
@ -1,107 +0,0 @@
|
|||
# Markup
|
||||
|
||||
## Considerations
|
||||
|
||||
Hypothetically, markup doesn't really matter for this. A component is a
|
||||
component if it can be translated into an AST that a renderer can render.
|
||||
|
||||
Practically, markup matters a lot. People will have strong preferences
|
||||
about their favourite versions of things. One solution to this is to open
|
||||
everything wide: "Just make parsers, transformers, and renderers that suit
|
||||
your need." The advantage of this is it gives people a lot of power to do
|
||||
whatever they want. Practically, the disadvantage is that poor taste will
|
||||
prevail. This is mostly just because good taste requires lots of hard work
|
||||
and most people haven't had time to do sufficient hard work to have good
|
||||
taste (disregarding the tendency not to want to do that work). It's
|
||||
probably worth noting that good taste can have strong aesthetic differences.
|
||||
Two people who disagree strongly can both have excellent tastes, differing
|
||||
in influences.
|
||||
|
||||
I think the approach I prefer is to leave it open in principle but obscured
|
||||
from most consumers of the tool. This would be effectively to make the Loom
|
||||
toolkit work with any style of markup and plugins, but not to popularize
|
||||
that feature (for quite some time), preferring instead to create
|
||||
concretizations of the toolkit in the form of frameworks. These will help
|
||||
guide consumers in taste, while not restricting those who want to apply more
|
||||
work to develop their own aesthetic sensibilities.
|
||||
|
||||
## Key Elements
|
||||
|
||||
Fundamentally, we want to integrate _form data_ with _content data_. There
|
||||
are probably better and worse paradigms for how to accomplish this. I'd say
|
||||
probably _logic_ style. This is a paradigm that would let
|
||||
producers ignore the mechanisms of integration.
|
||||
|
||||
Another excellent (and opposite) approach could be a _functional_ style. In
|
||||
this paradigm, the producer is concerned with mechanisms of data
|
||||
transformation.
|
||||
|
||||
## Other thoughts
|
||||
|
||||
It is not at all clear to me that components should be in HTML. It seems
|
||||
like a natural starting point, though, since we want to stay close to our
|
||||
bare-metal technologies.
|
||||
|
||||
Perhaps components should be in the style of HTML or JSX fragments. I
|
||||
borrowed heavily from Svelte for this.
|
||||
|
||||
I'm somewhat dissatisfied with the syntax of svelte's "directives" like
|
||||
{#if} and {/if}. They feel like they were put in as a concession to
|
||||
script interpolation. I think I prefer the JSX approach that uses {}
|
||||
to run arbitrary script content.
|
||||
|
||||
I don't know if there's any concepts we should bring in from XSLT for
|
||||
this, but it's already a technology mechanism that operates in this domain.
|
||||
|
||||
|
||||
|
||||
```
|
||||
// This "<loom-module>" tag could be created automatically before inserting.
|
||||
<loom-module>
|
||||
<script type="text/loom-module">
|
||||
/**
|
||||
* Key script features:
|
||||
* - Assume ES6?
|
||||
* - Maybe allow other languages that transpile to JS?
|
||||
* - Automatically sandbox css?
|
||||
* - Everything here needs to be available only during interpretation
|
||||
* of this HTML and css.
|
||||
*/
|
||||
</script>
|
||||
|
||||
<ul>
|
||||
<li>Allow multiple comment styles?</li>
|
||||
<li>Plugin-based transformations (AST)</li>
|
||||
<li>Some kind of script scoping</li>
|
||||
<li>Allow some bits of code using JSX-style {} syntax.</li>
|
||||
</ul>
|
||||
|
||||
<style type="test/scss">
|
||||
/**
|
||||
* Key styling features:
|
||||
*
|
||||
* - Allow all three comment types here? Make this a setting?
|
||||
* - Bake-in postcss transformers? Maybe project-agnostic...
|
||||
* - Automatically sandbox css
|
||||
*/
|
||||
</style>
|
||||
|
||||
</loom-module>
|
||||
```
|
||||
|
||||
|
||||
If the component defines something like this:
|
||||
|
||||
```
|
||||
<script>
|
||||
import Item from 'https://.../Item.component.xml';
|
||||
</script>
|
||||
|
||||
<Item data={item}/>
|
||||
```
|
||||
|
||||
Then the "import" node of the AST would be replaced by a function that
|
||||
provides the requested content (from Item.component.xml) like a macro. When
|
||||
the `<Item/>` node is hit, it will be interpreted according to the imported
|
||||
component macro.
|
||||
|
|
@ -1,86 +0,0 @@
|
|||
|
||||
# Process
|
||||
|
||||
* Load one or more modules
|
||||
* Load one or more HTML fragments
|
||||
* Render each fragment against the relevant data.
|
||||
|
||||
# Loom Modules
|
||||
|
||||
Loom modules are bundles of:
|
||||
|
||||
1. Form data
|
||||
2. Process data
|
||||
3. Event data
|
||||
4. Content data
|
||||
|
||||
Each element of a module is sandboxed. The data can be accessed externally,
|
||||
but need not be.
|
||||
|
||||
Loom modules are represented by an abstract syntax tree.
|
||||
|
||||
The `content` element of a node can be any single value that is one of an
|
||||
boolean, string, number, object/map, array, or undefined/null.
|
||||
|
||||
The `process` element of a node can be any set of functions that can be fully
|
||||
serialized to a string round-trip.
|
||||
|
||||
The `event` element of a node is a dictionary of events keyed to a name with
|
||||
a value that is always an array of handlers. Each handler takes an event
|
||||
object as the first (or only) argument. Handler functions can either be
|
||||
functions or registry names of `process` functions.
|
||||
|
||||
In this way, data and processes can be attached to any node as local state.
|
||||
|
||||
Consider the following HTML snippet
|
||||
|
||||
<div>Title</div>
|
||||
|
||||
and (an elided form of) its AST:
|
||||
|
||||
```
|
||||
{
|
||||
"type" : "root",
|
||||
"children" : [
|
||||
{
|
||||
"type" : "element",
|
||||
"tagName" : "div",
|
||||
"properties" : {},
|
||||
"children" : [
|
||||
{
|
||||
"type" : "text",
|
||||
"value" : "Test",
|
||||
}
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
Going further
|
||||
|
||||
The following defines an HTML template with inline process data.
|
||||
|
||||
```
|
||||
<div
|
||||
loom-process={{
|
||||
'changeTitle': ($) => { $.content = 'New Title' }
|
||||
}}
|
||||
>Title</div>
|
||||
```
|
||||
|
||||
As written, the `changeTitle` process will never be called. Let's attach
|
||||
it to an event.
|
||||
|
||||
```
|
||||
<div
|
||||
events={{
|
||||
click: ($,e) => $.process.changeTitle('New Title'),
|
||||
}}
|
||||
|
||||
loom-process={{
|
||||
'changeTitle': ($) => { $.content = 'New Title' },
|
||||
}}
|
||||
>Title</div>
|
||||
```
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
# Transformation
|
||||
|
||||
In Loom, *transformation* refers to the process of modifying an abstract
|
||||
syntax tree (AST), especially through the use of *transformers*.
|
||||
|
||||
Transformers are arrays of functions.
|
||||
|
||||
The mechanism provided by loom for these transformations is the
|
||||
`transform()` function.
|
||||
|
||||
The first argument to the `transform` function is an AST. Each node in the
|
||||
AST will be considered for transformation.
|
||||
|
||||
After the AST, any number of additional arguments may be passed to the
|
||||
`transform` function. Each of these should be a *transformer function* or
|
||||
an array of such.
|
||||
|
||||
## Transformation functions
|
||||
|
||||
Transformer functions take _a copy_ of an AST node. Because it is a copy,
|
||||
the changes made to the node received by the transformer function will have
|
||||
no effect on the tree. To change the tree, return a new AST node.
|
||||
|
||||
### Return values
|
||||
|
||||
Transformation functions may return one of three recognized value types. If
|
||||
a different value is returned, the `transform` function will throw an error.
|
||||
|
||||
#### AST node
|
||||
|
||||
If the transformation function returns an AST node, that node will be used
|
||||
to replace the original node in the original tree. Subsequent transformer
|
||||
functions will recieve a copy of the _new_ node, not the original.
|
||||
|
||||
For convenience, new tree nodes can be created with the
|
||||
`util.createAstNode()` or `util.cloneNode(node)` function. The
|
||||
determination of whether or not the returned value is an AST node is made
|
||||
using the `util.isAstNode()` utility function.
|
||||
|
||||
#### null
|
||||
|
||||
If the transformation function returns `null`, the original node will be
|
||||
removed from the AST. No further transformation functions will be called on
|
||||
the same node.
|
||||
|
||||
#### undefined
|
||||
|
||||
If the transformation function returns `undefined`, the original node will
|
||||
be left in the AST unchanged. The next transformation function will be
|
||||
called on the same node.
|
||||
|
||||
### _other values_
|
||||
|
||||
In the event that a transformation function returns any other value than
|
||||
`null`, `undefined`, or an AST node--as determined by `util.isAstNode()`,
|
||||
the `transform()` function will throw an error.
|
|
@ -1,3 +0,0 @@
|
|||
# Loading templates
|
||||
|
||||
|
Loading…
Reference in New Issue