Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor compiler post-processing #278

Merged
merged 3 commits into from
Mar 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</head>
<body>
<div id="idyll-mount">

</div>
<script src="index.js"></script>
</body>
Expand Down
4 changes: 1 addition & 3 deletions packages/idyll-cli/test/batteries-included/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,9 @@ test('creates the expected files', () => {
})
test('should construct the AST properly', () => {
const ast = [
['TextContainer', [], [
["Header",[["title",["value","Welcome to Idyll"]],["subtitle",["value","Open index.idl to start writing"]],["author",["value","Your Name Here"]],["authorLink",["value","https://idyll-lang.github.io"]]],[]],["p",[],["This is an Idyll file. Write text\nas you please in here. To add interactivity,\nyou can add different components to the text."]],["p",[],["Here is how you can use a variable:"]],
]],
["var",[["name",["value","exampleVar"]],["value",["value",5]]],[]],
['TextContainer', [], [
["Header",[["title",["value","Welcome to Idyll"]],["subtitle",["value","Open index.idl to start writing"]],["author",["value","Your Name Here"]],["authorLink",["value","https://idyll-lang.github.io"]]],[]],["p",[],["This is an Idyll file. Write text\nas you please in here. To add interactivity,\nyou can add different components to the text."]],["p",[],["Here is how you can use a variable:"]],
["Range",[["min",["value",0]],["max",["value",10]],["value",["variable","exampleVar"]]],[]],["Display",[["value",["variable","exampleVar"]]],[]],["pre",[],[["code",[],["var code = true;"]]]],["p",[],["And here is a custom component:"]],["p",[],["You can use standard html tags if a\ncomponent with the same name\ndoesn’t exist."]]
]]
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
<body>
<div id="idyll-mount"><div class="idyll-root" data-reactroot=""><div style="max-width:600px;margin:0 auto" class=" idyll-text-container"><div class="article-header"><h1 class="hed">Welcome to Idyll</h1><h2 class="dek">Open index.idl to start writing</h2><div class="byline">By: <a href="https://idyll-lang.github.io">Your Name Here</a></div></div><p>This is an Idyll file. Write text
as you please in here. To add interactivity,
you can add different components to the text.</p><data name="myData" source="example-data.json"></data><div class="ReactTable table "><div class="rt-table"><div class="rt-thead -header" style="min-width:200px"><div class="rt-tr"><div class="rt-th rt-resizable-header -cursor-pointer" role="heading" style="flex:100 0 auto;width:100px"><div class="rt-resizable-header-content">x</div><div class="rt-resizer"></div></div><div class="rt-th rt-resizable-header -cursor-pointer" role="heading" style="flex:100 0 auto;width:100px"><div class="rt-resizable-header-content">y</div><div class="rt-resizer"></div></div></div></div><div class="rt-tbody" style="min-width:200px"><div class="rt-tr-group"><div class="rt-tr -odd"><div class="rt-td" style="flex:100 0 auto;width:100px">0</div><div class="rt-td" style="flex:100 0 auto;width:100px">0</div></div></div><div class="rt-tr-group"><div class="rt-tr -even"><div class="rt-td" style="flex:100 0 auto;width:100px">1</div><div class="rt-td" style="flex:100 0 auto;width:100px">1</div></div></div></div></div><div class="-loading"><div class="-loading-inner">Loading...</div></div></div><p>Here is how you can use a variable:</p></div><div style="max-width:600px;margin:0 auto" class=" idyll-text-container"><input type="range" value="5" min="0" max="10" step="1"/><span>5.00</span><pre style="display:block;overflow-x:auto;padding:0.5em;color:#333;background:#f8f8f8"><code><span style="color:#333;font-weight:bold">var</span> code = <span style="color:#008080">true</span>;</code></pre><p>And here is a custom component:</p><div idyll="[object Object]">This is a custom component</div><p>You can use standard html tags if a
you can add different components to the text.</p><div class="ReactTable table "><div class="rt-table"><div class="rt-thead -header" style="min-width:200px"><div class="rt-tr"><div class="rt-th rt-resizable-header -cursor-pointer" role="heading" style="flex:100 0 auto;width:100px"><div class="rt-resizable-header-content">x</div><div class="rt-resizer"></div></div><div class="rt-th rt-resizable-header -cursor-pointer" role="heading" style="flex:100 0 auto;width:100px"><div class="rt-resizable-header-content">y</div><div class="rt-resizer"></div></div></div></div><div class="rt-tbody" style="min-width:200px"><div class="rt-tr-group"><div class="rt-tr -odd"><div class="rt-td" style="flex:100 0 auto;width:100px">0</div><div class="rt-td" style="flex:100 0 auto;width:100px">0</div></div></div><div class="rt-tr-group"><div class="rt-tr -even"><div class="rt-td" style="flex:100 0 auto;width:100px">1</div><div class="rt-td" style="flex:100 0 auto;width:100px">1</div></div></div></div></div><div class="-loading"><div class="-loading-inner">Loading...</div></div></div><p>Here is how you can use a variable:</p><input type="range" value="5" min="0" max="10" step="1"/><span>5.00</span><pre style="display:block;overflow-x:auto;padding:0.5em;color:#333;background:#f8f8f8"><code><span style="color:#333;font-weight:bold">var</span> code = <span style="color:#008080">true</span>;</code></pre><p>And here is a custom component:</p><div>This is a custom component</div><p>You can use standard html tags if a
component with the same name
doesn’t exist.</p><svg viewBox="0 0 100 100"><g transform="rotate(-90 50 50)"><path d="M 50,50 l 49,0 a49,49 0 0,0 -9.358167275627572,-28.801477362331184 z" fill="#7b3af5"></path><path d="M 50,50 l 39.64183272437243,-28.801477362331184 a49,49 0 1,0 9.358167275627572,28.801477362331195 z" fill="#EAE7D6"></path></g></svg><div idyll="[object Object]">This is a custom component</div><p>This adds support for indexed components: <div idyll="[object Object]">This is another custom component</div></p><div>Let&#x27;s put the fun back in functional!</div><div>This is some text<button>And a button</button>Then some more text</div><div idyll="[object Object]">This is a custom component</div></div></div></div>
doesn’t exist.</p><svg viewBox="0 0 100 100"><g transform="rotate(-90 50 50)"><path d="M 50,50 l 49,0 a49,49 0 0,0 -9.358167275627572,-28.801477362331184 z" fill="#7b3af5"></path><path d="M 50,50 l 39.64183272437243,-28.801477362331184 a49,49 0 1,0 9.358167275627572,28.801477362331195 z" fill="#EAE7D6"></path></g></svg><div>This is a custom component</div><p>This adds support for indexed components: <div>This is another custom component</div></p><div>Let&#x27;s put the fun back in functional!</div><div>This is some text<button>And a button</button>Then some more text</div><div>This is a custom component</div></div></div></div>
<script src="index.js"></script>
</body>
</html>
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const React = require('react');

class PascalComponent extends React.PureComponent {
render() {
const {hasError, updateProps, ...props} = this.props;
const {hasError, updateProps, idyll, ...props} = this.props;

return (
<div {...props}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const React = require('react');

class CustomComponent extends React.PureComponent {
render() {
const {hasError, updateProps, ...props} = this.props;
const {hasError, updateProps, idyll, ...props} = this.props;
return (
<div {...props}>
This is a custom component
Expand All @@ -15,7 +15,7 @@ module.exports = CustomComponent;

module.exports.IndexedComponent = class extends React.PureComponent {
render() {
const {hasError, updateProps, ...props} = this.props;
const {hasError, updateProps, idyll, ...props} = this.props;
return (
<div {...props}>
This is another custom component
Expand Down
5 changes: 2 additions & 3 deletions packages/idyll-cli/test/test-project/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,10 @@ test('creates the expected HTML', () => {
// })
test('should construct the AST properly', () => {
const ast = [
['TextContainer', [], [
["Header", [["title", ["value", "Welcome to Idyll"]], ["subtitle", ["value", "Open index.idl to start writing"]], ["author", ["value", "Your Name Here"]], ["authorLink", ["value", "https://idyll-lang.github.io"]]], []], ["p", [], ["This is an Idyll file. Write text\nas you please in here. To add interactivity,\nyou can add different components to the text."]], ["data", [["name", ["value", "myData"]], ["source", ["value", "example-data.json"]]], []], ["Table", [["data", ["variable", "myData"]]], []], ["p", [], ["Here is how you can use a variable:"]],
]],
["var", [["name", ["value", "exampleVar"]], ["value", ["value", 5]]], []],
["data", [["name", ["value", "myData"]], ["source", ["value", "example-data.json"]]], []],
['TextContainer', [], [
["Header", [["title", ["value", "Welcome to Idyll"]], ["subtitle", ["value", "Open index.idl to start writing"]], ["author", ["value", "Your Name Here"]], ["authorLink", ["value", "https://idyll-lang.github.io"]]], []], ["p", [], ["This is an Idyll file. Write text\nas you please in here. To add interactivity,\nyou can add different components to the text."]], ["Table", [["data", ["variable", "myData"]]], []], ["p", [], ["Here is how you can use a variable:"]],
["Range", [["min", ["value", 0]], ["max", ["value", 10]], ["value", ["variable", "exampleVar"]]], []], ["Display", [["value", ["variable", "exampleVar"]]], []], ["CodeHighlight", [["language", ["value", "js"]]], ["var code = true;"]], ["p", [], ["And here is a custom component:"]], ["CustomComponent", [], []], ["p", [], ["You can use standard html tags if a\ncomponent with the same name\ndoesn’t exist."]], ["ReactSimplePieChart",[["slices",["expression","[{\n color: '#7b3af5',\n value: 0.1,\n }, {\n color: '#EAE7D6',\n value: 0.9, },\n ]"]]],[]], ["PackageJsonComponentTest", [], []], ["p", [], ["This adds support for indexed components: ", ["CustomComponent.IndexedComponent", [], []]]], ["FunctionalComponent", [], []], ["FunctionalDefaultComponent", [], []], ["CapitalPascal", [], []]
]]
];
Expand Down
198 changes: 135 additions & 63 deletions packages/idyll-compiler/src/ast.js
Original file line number Diff line number Diff line change
@@ -1,93 +1,165 @@
/**
*
* This module contains utility functions
* module contains utility functions
* for dealing with Idyll's internal representation
* of an AST. The ast object is an array of nodes,
* where each node is defined like:
*
* [ name, [
* [property1, [valueType, value ]],
* [property2, [valueType, value ]]
* ], [
* child1,
* child2,
* ...
* ] ]
*
* ], [
* child1,
* child2,
* ...
* ] ]
*
*/


module.exports = {
const appendNodes = function(ast, nodes) {
return [].concat(ast, nodes);
};

const getChildren = function(node) {
return node[2] || [];
};

const modifyChildren = function(node, modifier) {
if (typeof node === 'string') {
return node;
}
node[2] = getChildren(node).map((child) => {
return modifier(child);
});
return node;
};

const getNodesByName = function(ast, name) {
const handleNode = (acc, node) => {
if (node[0].toLowerCase() === name.toLowerCase()) {
acc.push(node);
}

const children = getChildren(node);

if (!children || typeof children === 'string') {
return acc;
}

getChildren: function(node) {
return node[2] || [];
},
return children.reduce(handleNode, acc);
};

modifyChildren: function(node, modifier) {
return ast.reduce(handleNode, []);
};

const filterChildren = function(node, filter) {
if (typeof node === 'string') {
return node;
}
node[2] = getChildren(node).filter((child) => {
return filter(child);
});
return node;
};

const filterNodes = function(ast, filter) {
return ast.filter(filter).map((node) => {
if (typeof node === 'string') {
return node;
}
node[2] = this.getChildren(node).map((child) => {
return modifier(child);
});
return node;
},

modifyNodesByName: function(ast, name, modifier) {
const handleNode = (node) => {
if (typeof node === 'string') {
return node;
}
if (node[0].toLowerCase() === name.toLowerCase()) {
node = modifier(node);
}
node[2] = filterNodes(node[2] || [], filter);
return node;
})
};

node = this.modifyChildren(node, handleNode);
const modifyNodesByName = function(ast, name, modifier) {
const handleNode = (node) => {
if (typeof node === 'string') {
return node;
}
if (node[0].toLowerCase() === name.toLowerCase()) {
node = modifier(node);
}

ast = ast.map((node) => {
return handleNode(node);
});
return ast;
},
node = modifyChildren(node, handleNode);
return node;
}

getProperty: function(node, key) {
node[1].forEach((element) => {
if (element[0] === key) {
return element[1];
}
});
},

setProperty: function(node, key, value) {
let hasSet = false;
node[1].forEach((element) => {
if (element[0] === key) {
hasSet = true;
}
});
if (!hasSet) {
node[1] = node[1].concat([[key, value]]);
ast = ast.map((node) => {
return handleNode(node);
});
return ast;
};

const getProperty = function(node, key) {
node[1].forEach((element) => {
if (element[0] === key) {
return element[1];
}
});
};

return node;
},
const prependNodes = function(ast, nodes) {
return [].concat(nodes, ast);
};

setProperties: function(node, properties) {
Object.keys(properties).forEach((key) => {
node = this.setProperty(node, key, properties[key]);
})
return node;
},
const removeNodesByName = function(ast, name) {
return filterNodes(ast, (node) => {
if (typeof node === 'string') {
return true;
}
if (node[0].toLowerCase() === name.toLowerCase()) {
return false;
}
return true;
});
};

removeProperty: function(node, key) {
node[1] = node[1].filter(([propName, propVale]) => {
if (propName === key) {
return false;
const setProperty = function(node, key, value) {
let hasSet = false;
node[1].forEach((element) => {
if (element[0] === key) {
hasSet = true;
}
return true;
})
return node;
});
if (!hasSet) {
node[1] = node[1].concat([[key, value]]);
}

return node;
};

const setProperties = function(node, properties) {
Object.keys(properties).forEach((key) => {
node = setProperty(node, key, properties[key]);
})
return node;
};

const removeProperty = function(node, key) {
node[1] = node[1].filter(([propName, propVal]) => {
if (propName === key) {
return false;
}
return true;
})
return node;
};

module.exports = {
appendNodes,
getChildren,
getNodesByName,
filterChildren,
filterNodes,
modifyChildren,
modifyNodesByName,
getProperty,
prependNodes,
removeNodesByName,
setProperties,
setProperty,
removeProperty
}
17 changes: 15 additions & 2 deletions packages/idyll-compiler/src/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@

const parse = require('./parser');
const Lexer = require('./lexer');
const process = require('./processors');
const preProcessors = require('./processors/pre');
const { hoistVariables, flattenChildren, cleanResults, makeFullWidth, wrapText } = require('./processors/post');
const matter = require('gray-matter');


const cleanNewlines = (input) => {
return input.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
}
Expand All @@ -14,5 +18,14 @@ module.exports = function(input, options) {
const lex = Lexer();
const lexResults = lex(content);
const output = parse(content, lexResults.tokens.join(' '), lexResults.positions, options);
return output;
}

const ret = process(output, options)
.pipe(hoistVariables)
.pipe(flattenChildren)
.pipe(makeFullWidth)
.pipe(wrapText)
.pipe(cleanResults)
.end();

return ret;
}
Loading