pure-engine
Advanced tools
Comparing version 0.9.14 to 0.9.15
{ | ||
"name": "pure-engine", | ||
"version": "0.9.14", | ||
"version": "0.9.15", | ||
"description": "Compile HTML templates into JS", | ||
@@ -43,2 +43,3 @@ "main": "index.js", | ||
"abstract-syntax-tree": "^1.0.2", | ||
"asttv": "^1.0.1", | ||
"himalaya": "^1.1.0", | ||
@@ -45,0 +46,0 @@ "himalaya-walk": "^1.0.0", |
@@ -21,2 +21,3 @@ const AbstractSyntaxTree = require('abstract-syntax-tree') | ||
} = require('./convert') | ||
const { parseYAML, parseJSON, parseJS } = require('./translations') | ||
const walk = require('himalaya-walk') | ||
@@ -27,7 +28,7 @@ const { SPECIAL_TAGS, SELF_CLOSING_TAGS, OPERATORS, OBJECT_VARIABLE, TEMPLATE_VARIABLE } = require('./enum') | ||
const { join, dirname } = require('path') | ||
const { parse } = require('./parser') | ||
const yaml = require('yaml-js') | ||
const parse = require('./parse') | ||
const size = require('image-size') | ||
const { normalize } = require('./array') | ||
const { clone } = require('./object') | ||
const { placeholderName, addPlaceholders } = require('./keywords') | ||
let asyncCounter = 0 | ||
@@ -179,3 +180,3 @@ | ||
const htmlTree = parse(content) | ||
const children = fragment.children | ||
let children = fragment.children | ||
walk(htmlTree, leaf => { | ||
@@ -186,2 +187,44 @@ leaf.imported = true | ||
} | ||
if (leaf.attributes) { | ||
// TODO optimize | ||
// check attributes and inline values | ||
// the code could be analyzed and simplified afterwards | ||
// to simplify some of the conditions | ||
// e.g. as a result you can get expressions like "hello" || "" | ||
leaf.attributes.forEach(attr => { | ||
const { value } = attr | ||
if ( | ||
value && | ||
value.startsWith('{') && | ||
value.endsWith('}') && | ||
// TODO reuse | ||
// add occurances method to pure-utilities | ||
(value.match(/{/g) || []).length === 1 && | ||
(value.match(/}/g) || []).length === 1 | ||
) { | ||
let source = value.substr(1, value.length - 2) | ||
source = addPlaceholders(source) | ||
const ast = new AbstractSyntaxTree(source) | ||
let replaced = false | ||
ast.replace({ | ||
enter: node => { | ||
// TODO investigate | ||
// this is too optimistic | ||
// should avoid member expressions etc. | ||
if (node.type === 'Identifier') { | ||
const variable = localVariables.find(variable => variable.key === node.name || variable.key === placeholderName(node.name)) | ||
if (variable) { | ||
replaced = true | ||
return { type: 'Literal', value: variable.value } | ||
} | ||
} | ||
return node | ||
} | ||
}) | ||
if (replaced) { | ||
attr.value = '{' + ast.toString().replace(/;$/, '') + '}' | ||
} | ||
} | ||
}) | ||
} | ||
}) | ||
@@ -206,2 +249,6 @@ | ||
if (current.attributes.length === 0) { | ||
// putting a slot into a slot is problematic | ||
if (children.length === 1 && children[0].tagName === 'slot') { | ||
children = children[0].children | ||
} | ||
if (slots === 0) { | ||
@@ -231,2 +278,9 @@ current.children = children | ||
fragment.children = htmlTree | ||
// component usage, e.g. <list></list> | ||
// can be imported in the top component as well | ||
// which would result in unnecessary evaluation | ||
// we need to ignore it | ||
// but we can't ignore children nodes | ||
// can we do it better than marking the node as a slot? | ||
fragment.tagName = 'slot' | ||
return { fragment, localVariables } | ||
@@ -531,24 +585,14 @@ } | ||
leaf.used = true | ||
let data = {} | ||
if (keys.includes('yaml')) { | ||
const data = yaml.load(leaf.content) | ||
for (let key in data) { | ||
if (translations[key]) { throw new Error('Translation already exists') } | ||
translations[key] = data[key] | ||
} | ||
data = parseYAML(leaf.content) | ||
} else if (keys.includes('json')) { | ||
const data = JSON.parse(leaf.content) | ||
for (let key in data) { | ||
if (translations[key]) { throw new Error('Translation already exists') } | ||
translations[key] = data[key] | ||
} | ||
data = parseJSON(leaf.content) | ||
} else { | ||
const ast = new AbstractSyntaxTree(leaf.content) | ||
const node = ast.first('ExportDefaultDeclaration') | ||
node.declaration.properties.forEach(property => { | ||
if (translations[property.key.name || property.key.value]) { | ||
throw new Error('Translation already exists') | ||
} | ||
translations[property.key.name || property.key.value] = property.value.elements.map(element => element.value) | ||
}) | ||
data = parseJS(leaf.content) | ||
} | ||
for (let key in data) { | ||
if (translations[key]) { throw new Error('Translation already exists') } | ||
translations[key] = data[key] | ||
} | ||
} else if (tag === 'style' || tag === 'script' || tag === 'template') { | ||
@@ -555,0 +599,0 @@ let content = `<${tag}` |
const AbstractSyntaxTree = require('abstract-syntax-tree') | ||
const { parse } = require('./parser') | ||
const walk = require('himalaya-walk') | ||
@@ -9,2 +8,3 @@ const { TEMPLATE_VARIABLE, OBJECT_VARIABLE, ESCAPE_VARIABLE, GLOBAL_VARIABLES } = require('./enum') | ||
const { array: { unique } } = require('pure-utilities') | ||
const Parser = require('./Parser') | ||
const Analyzer = require('./Analyzer') | ||
@@ -83,12 +83,4 @@ const Optimizer = require('./Optimizer') | ||
parse (source) { | ||
let template, rescue | ||
if (source.includes('<rescue>') && source.includes('</rescue>')) { | ||
const start = source.indexOf('<rescue>') | ||
const end = source.indexOf('</rescue>') | ||
const content = source.substring(start + '<rescue>'.length, end) | ||
rescue = parse(content) | ||
source = source.substring(0, start) + source.substring(end, source.length) | ||
} | ||
template = parse(source) | ||
return { template, rescue } | ||
const parser = new Parser() | ||
return parser.parse(source) | ||
} | ||
@@ -125,3 +117,2 @@ async transform ({ template, rescue }) { | ||
optimizer.optimize() | ||
const compiled = new Function(`return function render(${params}) {\n${program.toString()}}`)() // eslint-disable-line | ||
@@ -128,0 +119,0 @@ return { template: compiled, statistics, errors } |
@@ -17,2 +17,3 @@ const { OBJECT_VARIABLE, ESCAPE_VARIABLE, BOOLEAN_ATTRIBUTES, UNESCAPED_NAMES, GLOBAL_VARIABLES, RESERVED_KEYWORDS } = require('./enum') | ||
const { mergeTranslations } = require('./translations') | ||
const { placeholderName, addPlaceholders } = require('./keywords') | ||
@@ -48,10 +49,4 @@ function isUnescapedFilter (filter) { | ||
function placeholderName (keyword) { | ||
return `__${keyword.toUpperCase()}_PLACEHOLDER__` | ||
} | ||
function convertToExpression (string) { | ||
RESERVED_KEYWORDS.forEach(keyword => { | ||
string = string.replace(new RegExp(`\\b${keyword}\\b`, 'g'), placeholderName(keyword)) | ||
}) | ||
string = addPlaceholders(string) | ||
const tree = new AbstractSyntaxTree(string) | ||
@@ -58,0 +53,0 @@ tree.replace({ |
@@ -22,4 +22,4 @@ const { TEMPLATE_VARIABLE } = require('./enum') | ||
concatenateLiterals () { | ||
let body = this.program.body() | ||
body = body.reduce((result, node) => { | ||
let body = this.program.body() | ||
body = body.reduce((result, node) => { | ||
const last = result[result.length - 1] | ||
@@ -26,0 +26,0 @@ if (isAssignmentExpressionWithLiteral(node)) { |
@@ -0,10 +1,43 @@ | ||
const AbstractSyntaxTree = require('abstract-syntax-tree') | ||
const { load } = require('yaml-js') | ||
const { readFileSync } = require('fs') | ||
const { load } = require('yaml-js') | ||
const { extname } = require('path') | ||
const convert = require('asttv') | ||
function parseYAML (content) { | ||
try { | ||
return load(content) | ||
} catch (exception) { | ||
throw new Error('YAML translation is unparseable') | ||
} | ||
} | ||
function parseJSON (content) { | ||
try { | ||
return JSON.parse(content) | ||
} catch (exception) { | ||
throw new Error('JSON translation is unparseable') | ||
} | ||
} | ||
function parseJS (content) { | ||
try { | ||
const ast = new AbstractSyntaxTree(content) | ||
const node = ast.first('ExportDefaultDeclaration') | ||
return convert(node.declaration) | ||
} catch (exception) { | ||
throw new Error('JS translation is unparseable') | ||
} | ||
} | ||
function parseTranslations (format, content) { | ||
if (format === '.yaml') return parseYAML(content) | ||
if (format === '.json') return parseJSON(content) | ||
return parseJS(content) | ||
} | ||
function readTranslations (path) { | ||
const content = readFileSync(path, 'utf8') | ||
const extension = extname(path) | ||
// TODO handle error and print better error message | ||
return extension === '.yaml' ? load(content) : JSON.parse(content) | ||
return parseTranslations(extension, content) | ||
} | ||
@@ -33,3 +66,6 @@ | ||
module.exports = { | ||
mergeTranslations | ||
mergeTranslations, | ||
parseYAML, | ||
parseJSON, | ||
parseJS | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
90722
23
2283
9
+ Addedasttv@^1.0.1
+ Addedasttv@1.0.1(transitive)