Skip to content

Commit

Permalink
feat(examples): add xml-converter example
Browse files Browse the repository at this point in the history
  • Loading branch information
postspectacular committed Sep 24, 2018
1 parent 8cbfb97 commit cb26300
Show file tree
Hide file tree
Showing 6 changed files with 234 additions and 0 deletions.
5 changes: 5 additions & 0 deletions examples/xml-converter/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.cache
out
node_modules
yarn.lock
*.js
26 changes: 26 additions & 0 deletions examples/xml-converter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# xml-converter

[Live demo](http://demo.thi.ng/umbrella/xml-converter/)

This example uses
[@thi.ng/sax](https://github.com/thi-ng/umbrella/tree/master/packages/sax)
to convert XML/HTML syntax into
[@thi.ng/hiccup](https://github.com/thi-ng/umbrella/tree/master/packages/hiccup)
syntax.

TODO better output formatting, html boolean attribs

```bash
git clone https://github.com/thi-ng/umbrella.git
cd umbrella/examples/xml-converter
yarn install
yarn start
```

## Authors

- Karsten Schmidt

## License

© 2018 Karsten Schmidt // Apache Software License 2.0
28 changes: 28 additions & 0 deletions examples/xml-converter/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>xml-converter</title>
<link href="https://unpkg.com/tachyons@4.9.1/css/tachyons.min.css" rel="stylesheet" />
<style>
</style>
</head>

<body class="ma0 pa2 sans-serif">
<div id="app"></div>
<div>
<h3>Current limitations</h3>
<ul>
<li>No HTML quirks allowed (well formed XML only)</li>
<li>No HTML boolean attribs</li>
<li>Probably many more... :)</li>
</ul>
<a class="link" href="https://github.com/thi-ng/umbrella/tree/master/examples/xml-converter">Source code</a>
</div>
<script type="text/javascript" src="./src/index.ts"></script>
</body>

</html>
29 changes: 29 additions & 0 deletions examples/xml-converter/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "xml-converter",
"version": "0.0.1",
"repository": "https://github.com/thi-ng/umbrella",
"author": "Karsten Schmidt <k+npm@thi.ng>",
"license": "Apache-2.0",
"scripts": {
"clean": "rm -rf .cache build out",
"build": "yarn clean && parcel build index.html -d out --public-url ./ --no-source-maps --no-cache --detailed-report",
"start": "parcel index.html -p 8080 --open"
},
"devDependencies": {
"parcel-bundler": "^1.9.7",
"terser": "^3.8.2",
"typescript": "^3.0.1"
},
"dependencies": {
"@thi.ng/rstream": "latest",
"@thi.ng/sax": "latest",
"@thi.ng/strings": "latest",
"@thi.ng/transducers-hdom": "latest"
},
"browserslist": [
"last 3 Chrome versions"
],
"browser": {
"process": false
}
}
135 changes: 135 additions & 0 deletions examples/xml-converter/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import { stream } from "@thi.ng/rstream/stream";
import { parse, Type } from "@thi.ng/sax";
import { maybeParseFloat } from "@thi.ng/strings/parse";
import { updateDOM } from "@thi.ng/transducers-hdom";
import { comp } from "@thi.ng/transducers/func/comp";
import { identity } from "@thi.ng/transducers/func/identity";
import { pairs } from "@thi.ng/transducers/iter/pairs";
import { assocObj } from "@thi.ng/transducers/rfn/assoc-obj";
import { last } from "@thi.ng/transducers/rfn/last";
import { push } from "@thi.ng/transducers/rfn/push";
import { transduce } from "@thi.ng/transducers/transduce";
import { filter } from "@thi.ng/transducers/xform/filter";
import { map } from "@thi.ng/transducers/xform/map";
import { multiplex } from "@thi.ng/transducers/xform/multiplex";

const parseXML = (src: string) =>
transduce(
comp(
parse({ trim: true }),
filter((e) => e.type === Type.ELEM_END || e.type === Type.ERROR)
),
last(),
src
);

const transformAttribs = (attribs: any) =>
transduce(
comp(
map(([k, v]) => [k, maybeParseFloat(v, null)]),
filter(([_, v]) => v !== null),
),
assocObj(),
attribs,
pairs(attribs)
);

const transformTree = (tree) => {
if (tree.type === Type.ERROR) {
return ["error", tree.body];
}
const res: any[] = [];
const attribs = transformAttribs(tree.attribs);
let tag = tree.tag;
if (attribs.id) {
tag += "#" + attribs.id;
delete attribs.id;
}
if (attribs.class) {
tag += "." + attribs.class.replace(/\s+/g, ".");
delete attribs.class;
}
res.push(tag);
if (Object.keys(attribs).length) {
res.push(attribs);
}
if (tree.body) {
res.push(tree.body);
}
if (tree.children && tree.children.length) {
transduce(map(transformTree), push(), res, tree.children)
}
return res;
};

const app = ([html, hiccup]) =>
["div.flex",
["div",
["h3", "XML/HTML source",
["small.fw1.ml2", "(must be well formed!)"]],
["textarea.mr2.f7.code.bg-light-yellow",
{
cols: 72,
rows: 25,
oninput: (e) => src.next(e.target.value),
value: html
}]
],
["div",
["h3", "Parsed Hiccup / JSON"],
["textarea.f7.code",
{
cols: 72,
rows: 25,
disabled: true
},
JSON.stringify(hiccup, null, 2)
]
]
];

const src = stream<string>()
.transform(
multiplex(
map(identity),
comp(
map(parseXML),
map(transformTree)
)
),
map(app),
updateDOM()
);

src.next(`<html lang="en">
<head>
<title>foo</title>
</head>
<body class="foo bar">
<div id="app"></div>
</body>
</html>`);

if (process.env.NODE_ENV !== "production") {
const hot = (<any>module).hot;
hot && hot.dispose(() => src.done());
}

["html",
{
"lang": "en"
},
[
"head",
[
"title",
"foo"
]
],
[
"body.foo.bar",
[
"div#app"
]
]
]
11 changes: 11 additions & 0 deletions examples/xml-converter/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": ".",
"target": "es6",
"sourceMap": true
},
"include": [
"./src/**/*.ts"
]
}

0 comments on commit cb26300

Please sign in to comment.