Skip to content

Commit

Permalink
Export-based init/preprocess/postprocess (fix #100)
Browse files Browse the repository at this point in the history
* Replace `svgtiler.{init,preprocess,postprocess}` multiple callbacks
  with single `export {init,prepreprocess,postprocess}`.
* Arrays for easy sequential function composition
* `export map` is now recommended alternative to `export default`
* `svgtiler.background` no longer supported at top level
* `currentMapping`, `getMapping`, `runWithMapping` removed
  • Loading branch information
edemaine committed Oct 28, 2022
1 parent 97a8a0b commit ff4a24f
Show file tree
Hide file tree
Showing 18 changed files with 158 additions and 136 deletions.
67 changes: 37 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,13 +180,15 @@ O O.svg

In the **.js / .coffee / .jsx / .cjsx formats**, the file consists of
JavaScript / CoffeeScript code that gets loaded as a NodeJS module.
The code specifies a `mapping` in one of three ways:
The code specifies a `mapping` in one of a few ways:

1. `export default mapping` (ECMAScript modules style)
2. `exports.default = mapping` (CommonJS modules style)
3. Writing a `mapping` expression at the end of the file (implicit export),
which must be a top-level object, array, or function expression
(without e.g. being assigned to a variable).
1. `export map = mapping` or `export default mapping`
(ECMAScript modules style)
2. `exports.map = mapping` or `exports.default = mapping`
(CommonJS modules style)
3. Writing a top-level object, array, or function expression
at the end of the file (without e.g. being assigned to a variable),
which triggers an implicit `export default`.

In any case, `mapping` should be one of the following types of **mapping**
objects:
Expand Down Expand Up @@ -336,28 +338,32 @@ The `Context` object has the following properties and methods:
functions within the same drawing (but not between separate drawings).
This can be useful for drawing-specific state.

The top-level code of your .js or .coffee mapping file can also call:
The top-level code of your .js or .coffee mapping file can also export
the following functions:

* `svgtiler.onInit(callback)` to schedule calling `callback()` whenever
this mapping file is listed on the command line (including right after
the mapping file is first loaded), and when state gets reset via a `)`
command-line argument. Note that each mapping file gets loaded (`require`d)
* `export init` to schedule calling `init(mapping)` whenever
this mapping file is listed on the command line
(including right after the mapping file is first loaded), and
when state gets reset (e.g. via a `)` command-line argument).
Note that each mapping file gets loaded (`require`d)
as a NodeJS module, which happens only once, so if your file uses any
side effects (in particular, reading or writing to the `share` object
for communication with other mapping files), it's important to wrap that code
in `svgtiler.onInit`, so that SVG Tiler can correctly limit and restore
these side effects in the presence of parentheses on the command line.
* `svgtiler.preprocess(callback)` to schedule calling `callback(render)`
for communication with other mapping files), it's important to put that code
in an `init` function instead of at the top level, so that SVG Tiler
can correctly limit and restore these side effects in the presence of
parentheses on the command line or when running multiple build rules.
* `export preprocess` to schedule calling `preprocess(render)`
when preparing to rendering each drawing, e.g.,
to initialize drawing-specific data or globally examine the drawing.
The `callback`'s argument (and `this`) is set to a `Render` instance,
The `render` argument (and `this`) is set to a `Render` instance,
which in particular has `drawing`, `mappings`, and `styles` attributes.
You can even modify the drawing's `keys` at this stage,
by modifying `render.drawing.keys`.
You can also add SVG content via `render.add` or `svgtiler.add`,
e.g., add metadata like `svgtiler.add(<title>My drawing</title>)`
(see below for more details).
* `svgtiler.postprocess(callback)` to schedule calling `callback(render)`
e.g., add metadata like `svgtiler.add(<title>My drawing</title>)`;
or set a default background color via `render.background(color)` or
`svgtiler.background(color)`.
* `export postprocess` to schedule calling `postprocess(render)`
after rendering each drawing, e.g., to modify or add to the drawing.
During the callback, `render` has properties about the rendering's
bounding box: `xMin`, `xMax`, `yMin`, `yMax`, `width`, `height`.
Expand All @@ -368,14 +374,16 @@ The top-level code of your .js or .coffee mapping file can also call:
or overlays/underlays.
Specify [`boundingBox`](#overflow-and-bounding-box) to increase the
overall size of the rendered drawing.
* `svgtiler.background(fillColor)` to set the default background color
for the SVG drawing (implemented via a `<rect>` underneath the bounding box).
When used called more than once, only the final background color gets
rendered. When used only once, equivalent to
`svgtiler.postprocess((render) => render.add(<rect z-index="-Infinity" fill={fillColor} x={render.xMin} y={render.yMin} width={render.width} height={render.height}/>))`.
You can also call `svgtiler.background` within a tile definition function or
a `preprocess`/`postprocess` callback to set the background dynamically,
or set the global default via the `--bg`/`--background` command-line option.
You can also set the final background color via
`render.background(color)` or `svgtiler.background(color)`.
When used only once, this is equivalent to the postprocess step of
`render.add(<rect z-index="-Infinity" fill={fillColor} x={render.xMin} y={render.yMin} width={render.width} height={render.height}/>)`.

You can call `svgtiler.background(color)` in `preprocess`, `postprocess`,
or tile definition functions. Only the final color will end up being
rendered, as a single background `<rect>` beneath the whole drawing's
bounding box. You can also set a global default background color via the
`--bg`/`--background` command-line option.

Like other [NodeJS modules](https://nodejs.org/api/modules.html),
.js and .coffee files can access `__dirname` and `__filename`,
Expand Down Expand Up @@ -493,8 +501,7 @@ See the [animation example](examples/anim) for sample usage of a .css or

If you'd rather generate a `<style>` tag dynamically depending on the
drawing content, you can do so in a .js or .coffee mapping file by calling
`svgtiler.add` during an `svgtiler.preprocess` or `svgtiler.postprocess`
callback.
`svgtiler.add` during a `preprocess` or `postprocess` export.

## Layout Algorithm

Expand Down Expand Up @@ -797,7 +804,7 @@ The file can provide build rules in one of a few ways:
1. `export make = ...` (ESM) or `exports.make = ...` (CommonJS)
2. `export default ...` (ESM) or `exports.default = ...` (CommonJS)
3. Writing a top-level object, array, or function expression
(without e.g. being assigned to a variable),
at the end of the file (without e.g. being assigned to a variable),
which triggers an implicit `export default`.

The exported rules can be one of the following types:
Expand Down
2 changes: 1 addition & 1 deletion examples/chess/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
* JSX notation for creating and composing symbols
* `svgtiler.background` for rendering a background white rectangle
* [CoffeeScript file](graph.coffee) for rendering the graph of attacks,
illustrating more advanced `svgtiler.postprocess` usage.
illustrating more advanced `export postprocess` usage.

## Piece Shapes

Expand Down
2 changes: 1 addition & 1 deletion examples/chess/graph.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pieces.add lc.toUpperCase() for lc in (x for x from pieces)
player = (key) ->
key == key.toLowerCase()

svgtiler.postprocess (render) ->
export postprocess = (render) ->
{drawing} = render
edges = []
for row, y in drawing.keys
Expand Down
7 changes: 3 additions & 4 deletions examples/chess/map.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,11 @@ read = (filename) ->
# {dom.props.children}
#</symbol>

svgtiler.preprocess ({drawing}) ->
export preprocess = ({drawing}) ->
svgtiler.add <title z-index="-Infinity">Chess diagram {drawing.filename}</title>

svgtiler.background 'white'
svgtiler.background 'white'
## Equivalent:
#svgtiler.postprocess (render) -> render.add \
#export postprocess = (render) -> render.add \
# <rect fill="white" z-index="-Infinity"
# x={render.xMin} y={render.yMin} width={render.width} height={render.height}/>

Expand Down
20 changes: 12 additions & 8 deletions examples/chess/map.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,19 @@ function read(filename) {
return dom.props.children;
}

svgtiler.preprocess(({drawing}) => svgtiler.add(
<title z-index="-Infinity">Chess diagram {drawing.filename}</title>));

svgtiler.background('white');
export function preprocess({drawing}) {
svgtiler.add(
<title z-index="-Infinity">Chess diagram {drawing.filename}</title>
);
svgtiler.background('white');
};
// Equivalent:
//svgtiler.postprocess((render) => render.add(
// <rect fill="white" z-index="-Infinity"
// x={render.xMin} y={render.yMin} width={render.width} height={render.height}/>
//));
//export function postprocess(render) {
// render.add(
// <rect fill="white" z-index="-Infinity"
// x={render.xMin} y={render.yMin} width={render.width} height={render.height}/>
// );
//};

(key, context) => {
// Map blanks to empty string
Expand Down
2 changes: 1 addition & 1 deletion examples/grid-graph/flip_parity.coffee
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
svgtiler.onInit ->
export init = ->
share.flipParity = 1
2 changes: 1 addition & 1 deletion examples/grid-graph/path.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ arrowSize = 2.5
viewBox = "#{-size/2} #{-size/2} #{size} #{size}"

parity = null
svgtiler.onInit ->
export init = ->
parity = (share.flipParity ? 0) * 2

blank = <symbol viewBox={viewBox} boundingBox="0 0 0 0"/>
Expand Down
2 changes: 1 addition & 1 deletion examples/mario/mario.coffee
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
palette = background = map = null

svgtiler.onInit ->
export init = ->
palette = share.palette ? 'overworld'
console.log "Using Mario #{palette} palette"

Expand Down
2 changes: 2 additions & 0 deletions examples/test/Maketile.args
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
( mapping.coffee mapping.ssv )
( mappings.coffee -O mappings mapping.ssv )

( inline.coffee )

( set.coffee set.asc )

## Test )'s ability to reset share object
Expand Down
2 changes: 1 addition & 1 deletion examples/test/at.coffee
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
keepUneven = null
svgtiler.onInit ->
export init = ->
keepUneven = svgtiler.getSettings().keepUneven
console.log 'Testing with --uneven =', keepUneven

Expand Down
4 changes: 4 additions & 0 deletions examples/test/inline.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
mapping =
init: -> console.log 'Success!'

svgtiler mapping
2 changes: 1 addition & 1 deletion examples/test/mapping.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export map2 = (key) ->
<circle r="17" fill={key}/>
</symbol>

export default new svgtiler.Mapping -> [
export map = new svgtiler.Mapping -> [
map1
map2
]
2 changes: 1 addition & 1 deletion examples/test/mappings.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ import {map1, map2} from './mapping'

escapeMap = svgtiler.require './escape.txt'

export default new svgtiler.Mappings map1, map2, escapeMap
export map = new svgtiler.Mappings map1, map2, escapeMap
4 changes: 2 additions & 2 deletions examples/test/set.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ showRow = (row) ->
''
).join ''

svgtiler.preprocess ->
export preprocess = ->
console.assert @drawing.keys.length == 1
console.log 'Before substitution:', showRow @drawing.keys[0]
svgtiler.postprocess ->
export postprocess = ->
console.assert @drawing.keys.length == 2
console.log 'After substitution: ', showRow @drawing.keys[0]
console.log ' ', showRow @drawing.keys[1]
Expand Down
4 changes: 2 additions & 2 deletions examples/test/share-undefined.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
svgtiler.onInit(() => {
export function init() {
if (share.data == null)
console.log('Success!!');
else
console.log('FAILURE!!');
});
};
4 changes: 2 additions & 2 deletions examples/test/share-user.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
svgtiler.onInit(() => {
export function init() {
console.log(share.data);
});
};
2 changes: 1 addition & 1 deletion examples/tetris/NES_level7.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ kind =
L: 'other'
Z: 'other'

svgtiler.background 'black'
export preprocess = -> svgtiler.background 'black'

(key) ->
if key.trim() == ''
Expand Down
Loading

0 comments on commit ff4a24f

Please sign in to comment.