New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

pure-engine

Package Overview
Dependencies
Maintainers
1
Versions
68
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

pure-engine - npm Package Compare versions

Comparing version 0.10.3 to 0.10.4

src/extract.js

44

package.json
{
"name": "pure-engine",
"version": "0.10.3",
"version": "0.10.4",
"description": "Compile HTML templates into JS",

@@ -8,3 +8,3 @@ "main": "index.js",

"lint": "standard",
"test": "ava 'test/spec/**/*.js'",
"test": "ava test/spec/**/*.js",
"coverage": "nyc npm test",

@@ -14,5 +14,10 @@ "benchmark": "ava test/benchmark.js",

},
"husky": {
"hooks": {
"pre-push": "npm run test && npm run lint"
}
},
"engines": {
"node": ">= 10.14.0",
"npm": ">= 6.4.1"
"node": ">= 10.15.1",
"npm": ">= 6.7.0"
},

@@ -53,4 +58,5 @@ "repository": {

"negate-sentence": "^0.1.2",
"normalize-newline": "^3.0.0",
"pure-conditions": "^0.1.9",
"pure-utilities": "^1.1.8",
"pure-utilities": "^1.1.10",
"string-hash": "^1.1.3",

@@ -61,31 +67,13 @@ "words-to-numbers": "^1.5.1",

"devDependencies": {
"@babel/core": "^7.1.6",
"@babel/plugin-transform-react-jsx": "^7.1.6",
"ansi-colors": "^3.2.1",
"ava": "^1.2.0",
"babel-loader": "^8.0.4",
"babel-plugin-transform-react-jsx": "^6.24.1",
"@babel/core": "^7.3.3",
"ava": "^1.3.1",
"benchmark": "^2.1.4",
"coffeescript": "^2.3.2",
"escape-html": "^1.0.3",
"handlebars": "^4.0.12",
"husky": "^1.3.1",
"lodash.template": "^4.4.0",
"mustache": "^3.0.0",
"nyc": "^13.1.0",
"preact": "^8.3.1",
"preact-compat": "^3.18.4",
"react": "^16.6.3",
"react-bootstrap": "^0.32.4",
"react-dom": "^16.6.3",
"react-text-mask": "^5.4.3",
"rollup": "^0.67.1",
"rollup-plugin-babel": "^4.0.3",
"rollup-plugin-buble": "^0.19.4",
"rollup-plugin-commonjs": "^9.2.0",
"rollup-plugin-node-resolve": "^3.4.0",
"rollup-plugin-svelte": "^4.3.2",
"nyc": "^13.2.0",
"standard": "^11.0.1",
"svelte": "^2.15.3",
"underscore": "^1.9.1",
"webpack": "^4.26.1"
"underscore": "^1.9.1"
},

@@ -92,0 +80,0 @@ "standard": {

# pure-engine
> Compile HTML templates into JS
![npm (scoped)](https://img.shields.io/npm/v/pure-engine.svg)
[![Codeship Status for buxlabs/pure-engine](https://img.shields.io/codeship/0f4ad4f0-3059-0136-f8b6-0ef1398f25bc/master.svg)](https://app.codeship.com/projects/288586)
[REPL](https://buxlabs.pl/en/tools/js/pure-engine)
> Compile HTML templates into JS
## Description
## Table of Contents
- [Background](#background)
- [Install](#install)
- [Usage](#usage)
- [API](#api)
- [Examples](#examples)
- [Benchmarks](#benchmarks)
- [REPL](https://buxlabs.pl/en/tools/js/pure-engine)
- [Maintainers](#maintainers)
- [Contributing](#contributing)
- [License](#license)
## Background
Pure Engine is a library designed to compile HTML templates into JS. It analyses the template and generates an optimal rendering function that can be used on the client and the server. The compilation process should ideally happen in a build step (for the client) or the output could be memoized after first usage (for the server).

@@ -31,16 +42,24 @@

## Usage
## Install
`npm install pure-engine escape-html`
## Usage
```js
const { compile } = import 'pure-engine'
const escape = import 'escape-html'
// ... later, inside of an async function
const template = await compile('<div>{foo}</div>')
expect(template({ foo: 'bar' }, escape)).to.equal('<div>bar</div>')
async function example () {
const { template } = await compile('<div>{foo}</div>')
console.log(template({ foo: 'bar' }, escape))
}
example()
```
## Features
If you're using webpack you should use [pure-engine-loader](https://github.com/buxlabs/pure-engine-loader).
## API
* import and require tags

@@ -50,5 +69,3 @@

<import layout from="./layouts/default.html">
<import form from="./components/form.html">
<import input from="./components/input.html">
<import button from="./components/button.html">
<import { form, input, button } from="./components">

@@ -64,2 +81,4 @@ <layout>

It's possible to import multiple components from a given directory. Curly brackets within the import tag are optional.
* render, partial and include tags

@@ -143,3 +162,3 @@

## Input / Output
## Examples

@@ -202,4 +221,12 @@ ```

## Maintainers
[@emilos](https://github.com/emilos), [@pkonieczniak](https://github.com/pkonieczniak).
## Contributing
All contributions are highly appreciated. Please feel free to open new issues and send PRs.
## License
MIT

@@ -25,3 +25,3 @@ const AbstractSyntaxTree = require('abstract-syntax-tree')

const { readFileSync } = require('fs')
const { dirname } = require('path')
const { join, dirname } = require('path')
const parse = require('./html/parse')

@@ -34,4 +34,6 @@ const size = require('image-size')

const { findFile } = require('./files')
const { extractComponentNames } = require('./extract')
const { wordsToNumbers } = require('words-to-numbers')
const Component = require('./Component')
const normalizeNewline = require('normalize-newline')
let asyncCounter = 0

@@ -73,4 +75,18 @@

const attrs = fragment.attributes
const name = attrs[0].key
const path = attrs[1].value
const names = extractComponentNames(attrs)
if (names.length === 1) {
const name = names[0]
const path = attrs[1].value
collectComponent(name, path, statistics, components, component, options)
} else {
const lastAttribute = attrs[attrs.length - 1]
const dir = lastAttribute.value
names.forEach(name => {
const path = join(dir, `${name}.html`)
collectComponent(name, path, statistics, components, component, options)
})
}
}
function collectComponent (name, path, statistics, components, component, options) {
let paths = []

@@ -538,3 +554,4 @@ if (options.paths) {

findFile(path, options, location => {
content += readFileSync(location, 'utf8')
const string = readFileSync(location, 'utf8')
content += string.trim()
statistics.scripts.push({ path: location })

@@ -621,3 +638,4 @@ })

findFile(path, options, location => {
content += readFileSync(location, 'utf8')
const string = readFileSync(location, 'utf8')
content += string.trim()
statistics.stylesheets.push({ path: location })

@@ -652,3 +670,4 @@ })

findFile(path, options, location => {
const content = parse(readFileSync(location, 'utf8'))[0]
const string = readFileSync(location, 'utf8')
const content = parse(normalizeNewline(string).trim())[0]
statistics.svgs.push({ path: location })

@@ -677,3 +696,4 @@ fragment.attributes = content.attributes

findFile(path, options, location => {
const content = readFileSync(location, 'base64')
const string = readFileSync(location, 'base64')
const content = normalizeNewline(string).trim()
statistics.images.push({ path: location })

@@ -680,0 +700,0 @@ attr.value = `data:image/${extension};base64, ${content}`

@@ -16,2 +16,3 @@ const AbstractSyntaxTree = require('abstract-syntax-tree')

const BoxModelPlugin = require('./plugins/BoxModelPlugin')
const InlinePlugin = require('./plugins/InlinePlugin')

@@ -34,2 +35,3 @@ async function render (htmltree, options) {

const plugins = [
new InlinePlugin(),
new BoxModelPlugin(),

@@ -36,0 +38,0 @@ new CurlyStylesPlugin(),

@@ -28,3 +28,3 @@ const lexer = require('../lexer')

if (parent.type === 'MemberExpression' && node === parent.property) return node
if (parent.type === 'Property') return node
if (node.type === 'Identifier') {

@@ -72,2 +72,6 @@ const variable = variables.find(variable => variable.key === node.name)

function isObject (value) {
return isCurlyTag(value)
}
function falsyCodeRemoval (node) {

@@ -82,2 +86,3 @@ if (isExpressionStatement(node) && isFalsyNode(node.expression)) {

value = addPlaceholders(value)
if (isObject(value)) value = `(${value})`
const tree = new AbstractSyntaxTree(value)

@@ -145,5 +150,10 @@ // TODO: unify same thing is done in convert.js

})
return tokens.map(token => token.value).join('')
const value = tokens.map(token => token.value).join('')
return optimizeWhitespace(value)
}
function optimizeWhitespace (text) {
return text.trim().replace(/\s\s+/, ' ')
}
module.exports = curlyTagReduction

@@ -46,3 +46,4 @@ const assert = require('assert')

assert.deepEqual(curlyTagReduction('<div class="{foo}"></div>', [{ key: 'foo', value: null }]), `<div class='{null}'></div>`)
assert.deepEqual(curlyTagReduction('<div padding="{{bottom:30}}"></div>', []), `<div padding='{({\n bottom: 30\n})}'></div>`)
assert.deepEqual(curlyTagReduction('<style>.foo { color: red }</style>', []), `<style>.foo { color: red }</style>`)

@@ -82,3 +82,3 @@ const { OBJECT_VARIABLE, ESCAPE_VARIABLE, BOOLEAN_ATTRIBUTES, UNESCAPED_NAMES, GLOBAL_VARIABLES, RESERVED_KEYWORDS } = require('./enum')

}
return modify(getTemplateNode(expression, variables, unescape), filters, translations, languages, translationsPaths)
return modify(getTemplateNode(expression, variables, unescape), variables, filters, translations, languages, translationsPaths)
} else {

@@ -98,5 +98,5 @@ const nodes = values.map(({ value, filters = [] }, index) => {

}
return modify(getTemplateNode(expression, variables, unescape), filters, translations, languages, translationsPaths)
return modify(getTemplateNode(expression, variables, unescape), variables, filters, translations, languages, translationsPaths)
}
return modify(getLiteral(value), filters, translations, languages, translationsPaths)
return modify(getLiteral(value), variables, filters, translations, languages, translationsPaths)
})

@@ -141,2 +141,67 @@ const expression = convertToBinaryExpression(nodes)

function prependObjectVariableToProperty (node, variables) {
if (!variables.includes(node.key.name)) {
const object = getIdentifier(OBJECT_VARIABLE)
object.omit = true
node.value = {
type: 'MemberExpression',
object,
property: node.value
}
node.shorthand = false
node.value.omit = true
node.value.property.omit = true
}
return node
}
function prependObjectVariableToIdentifier (node, variables) {
if (!variables.includes(node.name)) {
node.omit = true
const object = getIdentifier(OBJECT_VARIABLE)
object.omit = true
node = {
type: 'MemberExpression',
object,
property: node,
omit: true
}
}
return node
}
function isPropertyPrependCandidate (node) {
return node.type === 'Property' && node.key === node.value
}
function isIdentifierPrependCandidate (node) {
return node.type === 'Identifier' && !node.omit && !GLOBAL_VARIABLES.includes(node.name)
}
function isMemberExpression (node) {
return node.type === 'MemberExpression'
}
function replaceCandidates (node, parent, variables) {
if (isPropertyPrependCandidate(node)) {
node = prependObjectVariableToProperty(node, variables)
} else if (parent && parent.type === 'Property' && node.type === 'Identifier' && parent.key === node) {
node.omit = true
} else if (isMemberExpression(node)) {
if (node.property.type === 'Identifier' && !node.computed) node.property.omit = true
} else if (isIdentifierPrependCandidate(node)) {
node = prependObjectVariableToIdentifier(node, variables)
}
return node
}
function prependObjectVariable (expression, variables) {
AbstractSyntaxTree.replace(expression, {
enter: (node, parent) => {
return replaceCandidates(node, parent, variables)
}
})
return expression
}
function getTemplateNode (expression, variables, unescape) {

@@ -159,37 +224,3 @@ if (expression.type === 'Literal') {

].includes(expression.type)) {
AbstractSyntaxTree.replace(expression, {
enter: (node, parent) => {
if (node.type === 'Property' && node.key === node.value) {
if (!variables.includes(node.key.name)) {
const object = getIdentifier(OBJECT_VARIABLE)
object.omit = true
node.value = {
type: 'MemberExpression',
object,
property: node.value
}
node.shorthand = false
node.value.omit = true
node.value.property.omit = true
}
} else if (parent.type === 'Property' && node.type === 'Identifier' && parent.key === node) {
node.omit = true
} else if (node.type === 'MemberExpression') {
if (node.property.type === 'Identifier' && !node.computed) node.property.omit = true
} else if (node.type === 'Identifier' && !node.omit && !GLOBAL_VARIABLES.includes(node.name)) {
if (!variables.includes(node.name)) {
node.omit = true
const object = getIdentifier(OBJECT_VARIABLE)
object.omit = true
node = {
type: 'MemberExpression',
object,
property: node,
omit: true
}
}
}
return node
}
})
expression = prependObjectVariable(expression, variables)
if (unescape || isBooleanReturnFromExpression(expression)) {

@@ -227,3 +258,3 @@ return expression

}
return modify(getTemplateNode(expression, variables, unescape), filters, translations, languages, translationsPaths)
return modify(getTemplateNode(expression, variables, unescape), variables, filters, translations, languages, translationsPaths)
}

@@ -239,3 +270,3 @@ return getLiteral(value)

function modify (node, filters, translations, languages, translationsPaths) {
function modify (node, variables, filters, translations, languages, translationsPaths) {
if (filters) {

@@ -246,2 +277,6 @@ return filters.reduce((leaf, filter) => {

if (node.type === 'CallExpression') {
const name = getFilterName(node.callee.name)
node.arguments = node.arguments.map(argument => {
return replaceCandidates(argument, null, variables)
})
return {

@@ -251,3 +286,3 @@ type: 'CallExpression',

type: 'Identifier',
name: getFilterName(node.callee.name)
name
},

@@ -273,2 +308,3 @@ arguments: [leaf].concat(node.arguments)

}
const name = getFilterName(node.name)
return {

@@ -278,3 +314,3 @@ type: 'CallExpression',

type: 'Identifier',
name: getFilterName(node.name)
name
},

@@ -281,0 +317,0 @@ arguments: args

@@ -1,11 +0,30 @@

const { parseDefaults } = require('himalaya')
const { parse, parseDefaults } = require('himalaya')
const { VOID_TAGS } = require('../enum')
const { extractComponentNames } = require('../extract')
const walk = require('himalaya-walk')
function regexp (tag, name) {
return new RegExp(`<${tag}\\s+${name}\\s+`)
function matchImportTags (source) {
return source.match(/<import[\s\S]*?>[\s\S]*?>/gi)
}
function getImportTags (source) {
const imports = matchImportTags(source)
if (!imports) return []
return imports.join('')
}
function deduceVoidTags (source) {
const tags = []
const imports = getImportTags(source)
const tree = parse(imports)
walk(tree, node => {
if (node.tagName === 'import' || node.tagName === 'require') {
extractComponentNames(node.attributes).forEach(tag => {
tags.push(tag)
})
}
})
return VOID_TAGS.concat(parseDefaults.voidTags).filter(name => {
return !regexp('import', name).test(source) && !regexp('require', name).test(source)
return !tags.includes(name)
})

@@ -12,0 +31,0 @@ }

const { isCurlyTag, getExpressionFromCurlyTag } = require('../string')
const serialize = require('asttv')
const AbstractSyntaxTree = require('abstract-syntax-tree')
const { flatten } = require('pure-utilities/object')
const { flatten } = require('pure-utilities/collection')
const Plugin = require('./Plugin')

@@ -6,0 +6,0 @@

@@ -7,6 +7,8 @@ const { parse, walk, generate } = require('css-tree')

const Plugin = require('./Plugin')
const normalize = require('normalize-newline')
function addScopeToCssSelectors (node, scopes) {
const id = `scope-${hash(node.content)}`
const tree = parse(node.content)
const content = normalize(node.content).trim()
const id = `scope-${hash(content)}`
const tree = parse(content)
walk(tree, node => {

@@ -48,4 +50,3 @@ if (node.type === 'SelectorList') {

class ScopedStylesPlugin extends Plugin {
constructor () {
super()
beforeprerun () {
this.scopes = []

@@ -63,4 +64,7 @@ }

}
afterrun () {
this.scopes = []
}
}
module.exports = ScopedStylesPlugin
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc