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

ltl

Package Overview
Dependencies
Maintainers
1
Versions
22
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ltl - npm Package Compare versions

Comparing version 0.2.0 to 0.3.1

173

common/object/lru-cache.js

@@ -5,7 +5,7 @@ /**

* @origin https://github.com/lighterio/lighter-common/common/object/lru-cache.js
* @version 0.0.1
* @version 0.0.2
* @import object/type
*/
var Type = require('./type');
var Type = require('./type')
module.exports = Type.extend({

@@ -17,5 +17,8 @@

init: function (options) {
options = options || {};
this.maxSize = options.maxSize || 1e4;
this.clear();
if (typeof options === 'number') {
options = {maxSize: options}
}
options = options || {}
this.maxSize = options.maxSize || 1e6
this.clear()
},

@@ -27,6 +30,6 @@

clear: function () {
this.size = 0;
this.map = {};
this._next = this;
this._prev = this;
this.size = 0
this.map = {}
this._next = this
this._prev = this
},

@@ -38,9 +41,9 @@

get: function (key) {
var item = this.map[key];
var item = this.map[key]
if (item) {
if (item != this._next) {
item.unlink();
item.link(this);
if (item !== this._next) {
item.unlink()
item.link(this)
}
return item.value;
return item.value
}

@@ -53,25 +56,23 @@ },

set: function (key, value) {
var item = this.map[key];
var item = this.map[key]
if (item) {
item.value = value;
if (item != this._next) {
item.unlink();
item.link(this);
item.value = value
if (item !== this._next) {
item.unlink()
item.link(this)
}
}
else {
} else {
// Create an item and add it to the head of the loop.
item = this.map[key] = new Item(key, value);
item.link(this);
item = this.map[key] = new Item(key, value)
item.link(this)
// Remove the tail if necessary.
if (this.size < this.maxSize) {
this.size++;
this.size++
} else {
var tail = this._prev
tail.unlink()
delete this.map[tail.key]
}
else {
var tail = this._prev;
tail.unlink();
delete this.map[tail.key];
}
}

@@ -84,9 +85,9 @@ },

remove: function (key) {
var item = this.map[key];
var item = this.map[key]
if (item) {
var prev = item._prev;
var next = item._next;
prev._next = next;
next._prev = prev;
delete this.map[key];
var prev = item._prev
var next = item._next
prev._next = next
next._prev = prev
delete this.map[key]
}

@@ -99,6 +100,6 @@ },

each: function (fn) {
var item = this._next;
while (item != this) {
fn(item.key, item.value);
item = item._next;
var item = this._next
while (item !== this) {
fn(item.key, item.value)
item = item._next
}

@@ -111,6 +112,6 @@ },

forEach: function (fn) {
var item = this._next;
while (item != this) {
fn(item.value, item.key);
item = item._next;
var item = this._next
while (item !== this) {
fn(item.value, item.key)
item = item._next
}

@@ -123,9 +124,9 @@ },

getMap: function () {
var map = {};
var item = this._next;
while (item != this) {
map[item.key] = item.value;
item = item._next;
var map = {}
var item = this._next
while (item !== this) {
map[item.key] = item.value
item = item._next
}
return map;
return map
},

@@ -137,10 +138,10 @@

getKeys: function () {
var keys = new Array(this.size);
var index = 0;
var item = this._next;
while (item != this) {
keys[index++] = item.key;
item = item._next;
var keys = new Array(this.size)
var index = 0
var item = this._next
while (item !== this) {
keys[index++] = item.key
item = item._next
}
return keys;
return keys
},

@@ -152,10 +153,10 @@

getValues: function () {
var values = new Array(this.size);
var index = 0;
var item = this._next;
while (item != this) {
values[index++] = item.value;
item = item._next;
var values = new Array(this.size)
var index = 0
var item = this._next
while (item !== this) {
values[index++] = item.value
item = item._next
}
return values;
return values
},

@@ -167,13 +168,13 @@

getItems: function () {
var items = new Array(this.size);
var index = 0;
var item = this._next;
while (item != this) {
items[index++] = item;
item = item._next;
var items = new Array(this.size)
var index = 0
var item = this._next
while (item !== this) {
items[index++] = item
item = item._next
}
return items;
return items
}
});
})

@@ -183,7 +184,7 @@ /**

*/
function Item(key, value) {
this.key = key;
this.value = value;
this._prev = null;
this._next = null;
function Item (key, value) {
this.key = key
this.value = value
this._prev = null
this._next = null
}

@@ -197,6 +198,6 @@

unlink: function () {
var prev = this._prev;
var next = this._next;
prev._next = next;
next._prev = prev;
var prev = this._prev
var next = this._next
prev._next = next
next._prev = prev
},

@@ -208,9 +209,9 @@

link: function (prev) {
var next = prev._next;
this._prev = prev;
this._next = next;
prev._next = this;
next._prev = this;
var next = prev._next
this._prev = prev
this._next = next
prev._next = this
next._prev = this
}
};
}

@@ -10,3 +10,3 @@ /**

// The default constructor does nothing.
var Type = module.exports = function () {};
var Type = module.exports = function () {}

@@ -17,20 +17,19 @@ /**

Type.extend = function (properties) {
// Create the constructor, using a new or inherited `init` method.
var type = properties.init || function () {
if (this.init) {
this.init.apply(this, arguments);
if (this.init) {
this.init.apply(this, arguments)
}
}
};
// Copy the parent and its prototype.
var parent = type.parent = this;
Type.decorate(type, parent);
Type.decorate(type.prototype, parent.prototype);
var parent = type.parent = this
Type.decorate(type, parent)
Type.decorate(type.prototype, parent.prototype)
// Copy the properties that extend the parent.
Type.decorate(type.prototype, properties);
Type.decorate(type.prototype, properties)
return type;
};
return type
}

@@ -41,7 +40,7 @@ /**

Type.decorate = function (object, properties) {
properties = properties || this.prototype;
properties = properties || this.prototype
for (var key in properties) {
object[key] = properties[key];
object[key] = properties[key]
}
return object;
};
return object
}

@@ -13,7 +13,7 @@ /**

var LruCache = require('../object/lru-cache');
var LruCache = require('../object/lru-cache')
// Initialize the cache if it doesn't already exist.
var cacheKey = '_lighterProcessCache_0';
var processCache = process[cacheKey];
var cacheKey = '_lighterProcessCache_0'
var processCache = process[cacheKey]
if (!processCache) {

@@ -23,10 +23,10 @@ Object.defineProperty(process, cacheKey, {

value: new LruCache()
});
}
})
// If it exists but doesn't look like a cache, replace it.
else if (!processCache.get || !processCache.set) {
process[cacheKey] = new LruCache();
} else if (!processCache.get || !processCache.set) {
process[cacheKey] = new LruCache()
}
// Export the cache, whether newly-created or existing.
module.exports = process[cacheKey];
module.exports = process[cacheKey]

@@ -7,8 +7,8 @@ /**

* @origin https://github.com/lighterio/lighter-common/common/vm/run.js
* @version 0.0.1
* @version 0.0.2
* @import process/cache
*/
var vm = require('vm');
var cache = require('../process/cache');
var vm = require('vm')
var cache = require('../process/cache')

@@ -18,22 +18,40 @@ /**

*
* @param {String} code A piece of JavaScript code to run.
* @param {String} path An optional path for the file, used for debugging, etc.
* @return {Any} The value extracted from the scripts context.
* @param {String} code A piece of JavaScript code to run.
* @param {String} path An optional path for the file, used for debugging, etc.
* @param {Object} context An optional context to run in.
* @return {Any} The value extracted from the scripts context.
*/
var run = module.exports = function (code, path) {
path = (path || 'run' + (++run._id)) + '.vm.js';
var key = (path[0] == '/') ? path : '/tmp/' + path;
var src = 'var o=' + code;
var context = {};
cache.set(key, src);
var run = module.exports = function (code, path, context) {
path = (path || 'run' + (++run._id)) + '.vm.js'
context = context || run._context
var key = (path[0] === '/') ? path : '/tmp/' + path
var src = 'var o=' + code.replace(/\[\]/g, 'new Array()')
cache.set(key, src)
try {
vm.runInNewContext(src, context, key);
vm.runInNewContext(src, context, key)
} catch (e) {
console.log('WTF')
e.message += '\n' + src + '\n' + (e instanceof SyntaxError)
throw e
}
catch (e) {
e.message += '\n' + src + '\n' + (e instanceof SyntaxError);
throw e;
return context.o
}
// Override for production.
var env = process.env.NODE_ENV || ''
if (env[0] !== 'd') {
run = module.exports = function (code) {
eval('var window={};eval.o=' + code.replace(/\[\]/g, 'new Array()'))
return eval.o
}
return context.o;
};
}
run._id = 0;
// Enable auto-incrementing of auto-generated code paths.
run._id = 0
// Default context for running code.
run._context = {
window: {},
console: console,
Array: Array
}

@@ -11,3 +11,3 @@ /**

// Allow users to see what version of Ltl they're using.
version: '0.2.0',
version: '0.3.1',

@@ -18,5 +18,5 @@ // Some HTML tags won't have end tags.

// Supported control keywords (usage appears like tags).
controlPattern: /^(for|if|else)\b/,
controlPattern: /^(for|if|else|break|continue)\b/,
// Pattern for a Jasignment.
// Pattern for assignment.
assignmentPattern: /^([$A-Za-z_][$A-Za-z_0-9\.\[\]'"]*\s*=[^\{])/,

@@ -27,9 +27,6 @@

// JavaScript tokens that don't need the state "s" prepended for interpolation.
// JavaScript tokens that don't need the scope "scope" prepended for interpolation.
// TODO: Flesh out this list?
jsPattern: /^(undefined|true|false|null|function|NaN|Infinity|window|location|document|console|this|Math|Object|Date|Error|RegExp|JSON)$/,
jsPattern: /^(undefined|true|false|null|function|NaN|Infinity|window|location|document|console|new|this|typeof|instanceof|Math|Object|Array|Date|Error|RegExp|JSON|Jymin|scope|state|setTimeout|clearTimeout)$/,
// Stores available single character variable names.
vars: 'abcdefghijklmnqrtuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
// Register several languages and their targets.

@@ -48,40 +45,40 @@ languages: {

// Remove starting/ending whitespace.
trim: function(text) {
return text.replace(/(^\s+|\s+$)/g, '');
trim: function (text) {
return text.replace(/(^\s+|\s+$)/g, '')
},
// Repeat a string.
repeat: function(text, times) {
return times > 0 ? (new Array(times + 1)).join(text) : '';
repeat: function (text, times) {
return times > 0 ? (new Array(times + 1)).join(text) : ''
},
// Escape single quotes with a backslash.
escapeSingleQuotes: function(text) {
return text.replace(/'/g, '\\\'');
escapeSingleQuotes: function (text) {
return text.replace(/'/g, '\\\'')
},
// Escape text with possible line breaks for appending to a string.
escapeBlock: function(text) {
return text.replace(/'/g, '\\\'').replace(/\n/g, '\\n');
escapeBlock: function (text) {
return text.replace(/'/g, '\\\'').replace(/\n/g, '\\n')
},
// Get a module for filtering.
getFilter: function(name) {
var filters = ltl.filters;
var filter = filters[name];
getFilter: function (name) {
var filters = ltl.filters
var filter = filters[name]
if (!filter) {
filter = filters[name] = ltl.scope[name] || (typeof require != 'undefined' ? require(name) : null);
filter = filters[name] = ltl.scope[name] || (typeof require !== 'undefined' ? require(name) : null)
}
if (!filter) {
var todo;
var into = ' into function that accepts a string and returns a string.';
var todo
var into = ' into function that accepts a string and returns a string.'
if (ltl.scope.cwd) {
var cmd = 'cd ' + ltl.scope.cwd() + '; npm install --save ' + name;
todo = 'Run "' + cmd + '", or make require("ltl").filters.' + name;
var cmd = 'cd ' + ltl.scope.cwd() + '; npm install --save ' + name
todo = 'Run "' + cmd + '", or make require("ltl").filters.' + name
} else {
todo = 'Set window.ltl.filters.' + name;
todo = 'Set window.ltl.filters.' + name
}
throw new Error('[Ltl] Unknown filter: "' + name + '". ' + todo + into);
throw new Error('[Ltl] Unknown filter: "' + name + '". ' + todo + into)
}
return filter;
return filter
},

@@ -91,31 +88,31 @@

run: (
(typeof require == 'function') ?
(typeof require === 'function') ?
require('./common/vm/run') :
function (src, name) {
var f;
var f
try {
eval('f=' + src); // jshint ignore:line
}
catch (e) {
e.message = '[Ltl] ' + e.message;
} catch (e) {
e.message = '[Ltl] ' + e.message
if (name) {
e.message += '\nTemplate: ' + name;
e.message += '\nTemplate: ' + name
}
e.message += '\nFunction: ' + src;
throw e.stack && e;
e.message += '\nFunction: ' + src
throw e.stack && e
}
return f;
return f
}
),
// Store all of the templates that have been compiled.
// Store templates that have been compiled.
// Include 2 built-ins for interpolation.
cache: {
'-': function(v){return '<!--'+(JSON.stringify(v)||'').replace(/-->/g,'--\\>')+'-->';},
'$': function(v){return (!v&&v!==0?'':(typeof v=='object'?JSON.stringify(v)||'':''+v)).replace(/</g,'&lt;');},
'&': function(v){return encodeURIComponent(!v&&v!==0?'':''+v);}
'$': function (v) {
return (!v && v !== 0 ? '' : (typeof v === 'object' ? JSON.stringify(v) || '' : '' + v)).replace(/</g, '&lt;')
},
'&': function (v) {
return encodeURIComponent(!v && v !== 0 ? '' : '' + v)
}
},
// Last value of an auto-incremented ID.
lastId: 0,
// Store filter modules, such as "coffee-script" and "marked".

@@ -127,9 +124,6 @@ filters: {

// Store tags that evaluate elsewhere.
tags: {},
// Default compile settings.
options: {
tabWidth: 4,
enableDebug: false
defaultTag: 'div'
},

@@ -139,6 +133,6 @@

setOption: function (name, value) {
this.options[name] = value;
this.options[name] = value
},
// Create a function that accepts state and returns markup.
// Create a function that accepts scope and returns markup.
compile: function (code, options) {

@@ -149,101 +143,99 @@

tabWidth: this.options.tabWidth,
space: this.options.space,
enableDebug: this.options.enableDebug
};
defaultTag: this.options.defaultTag,
space: this.options.space
}
for (var name in options) {
settings[name] = options[name];
settings[name] = options[name]
}
if (settings.enableDebug && !settings.space) {
settings.space = ' ';
}
var getPattern = /s\.get\.([$A-Za-z_][$A-Za-z_\d]*)/g;
if (settings.space) {
settings.space = ltl.escapeBlock(settings.space);
settings.space = ltl.escapeBlock(settings.space)
}
// Replace carriage returns for Windows compatibility.
code = code.replace(/\r/g, '');
code = code.replace(/\r/g, '')
// Be lenient with mixed tabs and spaces, assuming tab width of 4.
var tabReplacement = Array(settings.tabWidth + 1).join(' ');
code = code.replace(/\t/g, tabReplacement);
var tabReplacement = Array(settings.tabWidth + 1).join(' ')
code = code.replace(/\t/g, tabReplacement)
// We'll auto-detect tab width.
var currentTabWidth = 0;
var currentTabWidth = 0
// Initialize the code, and start at level zero with no nesting.
var lines = code.split('\n');
var lineIndex;
var lineCount = lines.length;
var lines = code.split('\n')
var lineIndex
var lineCount = lines.length
var globalSpaces = 0;
var indent = 0;
var stack = [];
var mode = 'html';
var previousTag;
var hasHtmlTag = false;
var hasHtmlOutput = false;
var hasAssignments = false;
var hasContent = false;
var tagDepth = 0;
var newLine = settings.space ? '\n' : ''
var output = "var o='";
var globalSpaces = 0
var indent = 0
var stack = []
var mode = 'html'
var previousTag
var hasHtmlTag = false
var hasHtmlOutput = false
var hasAssignments = false
var hasContent = false
var useCache = false
var tagDepth = 0
var varIndex = 0;
var escapeHtmlVar = false;
var encodeUriVar = false;
var escapeCommentVar = false;
var loopVars = [];
var output = "var output='"
var varIndex = 0
var escapeHtmlVar = false
var encodeUriVar = false
var escapeCommentVar = false
var loopVars = []
// If we end up in a dot block, remember the starting indent and filter, and gather lines.
var blockIndent = 0;
var blockFilter = '';
var blockLines = null;
var blockTag = null;
var blockName = '';
var blockContent = '';
var blockSets = null;
var hasGets = false;
var inComment = false;
var blockIndent = 0
var blockFilter = ''
var blockLines = null
var blockTag = null
var blockName = ''
var blockContent = ''
var blockScope = null
var inComment = false
// Support adding properties like "js" to the template function.
var properties = {};
var blockProperty;
var blockTarget;
var eventLanguage;
var properties = {}
var blockProperty
var blockTarget
var eventLanguage
// Allow event listeners to be added.
var bindings = {};
var bindings = {}
function appendText(textMode, text) {
if (textMode != mode) {
if (mode == 'html') {
output += "'" + (text == '}' ? '' : ';');
function appendText (textMode, text) {
if (textMode !== mode) {
if (mode === 'html') {
output += "'" + (text === '}' ? '' : ';' + newLine)
} else {
output += "output+='"
}
else {
output += "o+='";
}
mode = textMode;
mode = textMode
}
if (mode == 'html') {
text = interpolate(text);
if (mode === 'html') {
text = interpolate(text)
}
output += text;
output += text
}
function startBlock(filter, content) {
blockIndent = indent + 1;
blockFilter = filter;
blockLines = [];
function startBlock (filter, content) {
blockIndent = indent + 1
blockFilter = filter
blockLines = []
if (content) {
(blockLines = blockLines || []).push(content);
blockLines = blockLines || []
blockLines.push(content)
}
}
function appendBlock() {
var text = blockLines.join('\n');
function appendBlock () {
var text = blockLines.join('\n')
// Reset the blockage.
blockIndent = 0;
blockIndent = 0

@@ -254,36 +246,26 @@ // Some options should be passed through.

enableDebug: settings.enableDebug
};
}
// If we're in a "call" block, call another template with compiled parts.
if (blockFilter == 'call') {
// If there's a key, pass a sub-state.
// * With a sub-state: this['VIEW'].call((s['KEY']._='KEY')&&s['KEY'])
// * Without sub-state: this['VIEW'].call(s)
var key = ltl.trim(blockContent || '');
var state = key ? "s['" + key + "']" : 's';
appendText('html',
"'+this['" + blockName + "'].call(this," + state +
(text ? ',' + ltl.compile(text, blockOptions) : '') + ")+'");
return;
}
// For a "set" block, add to the array of "set" block values.
else if (blockFilter == 'set' || blockFilter == 'set:') {
var block;
if (blockFilter == 'set') {
block = ltl.compile(text, blockOptions).toString();
} else {
block = "function(){return '" + ltl.escapeBlock(text) + "'}";
if (blockFilter === 'call') {
if (/\S/.test(text)) {
blockScope = blockScope || []
var blockJs = ltl.compile(text, blockOptions).toString()
blockJs = blockJs.replace(/^.*?\)/, 'function()')
blockScope.push('block:' + blockJs)
}
(blockSets = blockSets || []).push("'" + ltl.escapeSingleQuotes(blockName) + "':" + block);
return;
}
blockScope = blockScope ? blockScope.join(',') : ''
appendText('html', "'+cache['" + blockName + "']({" + blockScope + "},state)+'")
useCache = true
blockScope = null
return
// If there's a filter, get its module.
else if (blockFilter) {
if (blockFilter == 'coffee') {
blockFilter = 'coffee-script';
} else if (blockFilter) {
if (blockFilter === 'coffee') {
blockFilter = 'coffee-script'
} else if (blockFilter === 'md') {
blockFilter = 'marked'
}
else if (blockFilter == 'md') {
blockFilter = 'marked';
}
var compiler = ltl.getFilter(blockFilter);
var compiler = ltl.getFilter(blockFilter)

@@ -294,43 +276,37 @@ if (compiler.renderSync) {

compressed: true
});
}
else if (compiler.render) {
if (blockFilter == 'less') {
})
} else if (compiler.render) {
if (blockFilter === 'less') {
compiler.render(text, function (err, result) {
if (err) {
throw err;
throw err
}
text = result.css;
});
text = result.css
})
} else {
text = compiler.render(text)
}
else {
text = compiler.render(text);
}
}
else if (compiler.compile) {
var nowrap = /^[^A-Z]*NOWRAP/.test(text);
text = compiler.compile(text);
} else if (compiler.compile) {
var nowrap = /^[^A-Z]*NOWRAP/.test(text)
text = compiler.compile(text)
if (nowrap) {
text = text.replace(/(^\(function\(\) \{\s*|\s*\}\)\.call\(this\);\s*$)/g, '');
text = text.replace(/(^\(function\(\) \{\s*|\s*\}\)\.call\(this\);\s*$)/g, '')
}
} else if (compiler.parse) {
text = compiler.parse(text)
} else if (typeof compiler === 'function') {
text = compiler(text)
}
else if (compiler.parse) {
text = compiler.parse(text);
}
else if (typeof compiler == 'function') {
text = compiler(text);
}
} else {
blockFilter = 'text'
}
else {
blockFilter = 'text';
}
text = ltl.trim(text);
text = ltl.trim(text)
if (settings.space) {
if (hasHtmlOutput) {
text = '\n' + text;
text = '\n' + text
}
text = text.replace(/\n/g, '\n' + ltl.repeat(settings.space, tagDepth));
text = text.replace(/\n/g, '\n' + ltl.repeat(settings.space, tagDepth))
if (blockTag) {
text += '\n' + ltl.repeat(settings.space, tagDepth - 1);
text += '\n' + ltl.repeat(settings.space, tagDepth - 1)
}

@@ -340,48 +316,44 @@ }

if (blockProperty) {
var value = properties[blockProperty];
value = (value ? value + '\n' : '') + text;
properties[blockProperty] = value;
var value = properties[blockProperty]
value = (value ? value + '\n' : '') + text
properties[blockProperty] = value
} else if (blockTarget === 'js') {
text = text.replace(/;?$/, ';')
appendText('script', text)
} else {
appendText('html', ltl.escapeBlock(text))
}
else if (blockTarget == 'js') {
appendText('script', text);
}
else {
appendText('html', ltl.escapeBlock(text));
}
blockTag = null;
blockFilter = null;
blockProperty = null;
blockTarget = null;
blockTag = null
blockFilter = null
blockProperty = null
blockTarget = null
blockScope = null
}
function backtrackIndent() {
function backtrackIndent () {
while (stack.length > indent) {
var tags = stack.pop();
var tags = stack.pop()
if (tags) {
tags = tags.split(/,/g);
tags = tags.split(/,/g)
for (var i = tags.length - 1; i >= 0; i--) {
var tag = tags[i];
if (tag == '//') {
inComment = false;
}
else if (tag == '-') {
appendText('html', '-->');
}
else if (ltl.controlPattern.test(tag)) {
appendText('script', '}');
if (tag == 'for') {
loopVars.pop();
var tag = tags[i]
if (tag === '//') {
inComment = false
} else if (tag === '-') {
appendText('html', '-->')
} else if (ltl.controlPattern.test(tag)) {
appendText('script', '}')
if (tag === 'for') {
loopVars.pop()
}
}
else if (!ltl.selfClosePattern.test(tag)) {
var html = '</' + tag + '>';
tagDepth--;
if (tag == previousTag) {
previousTag = null;
} else if (!ltl.selfClosePattern.test(tag)) {
var html = '</' + tag + '>'
tagDepth--
if (tag === previousTag) {
previousTag = null
} else if (settings.space) {
html = '\\n' + ltl.repeat(settings.space, tagDepth) + html
}
else if (settings.space) {
html = '\\n' + ltl.repeat(settings.space, tagDepth) + html;
}
appendText('html', html);
appendText('html', html)
}

@@ -393,67 +365,77 @@ }

function transformScript(script) {
var found = false;
function transformScript (script) {
var found = false
script = script.replace(/^(for)\s+([$A-Za-z_][$A-Za-z_\d]*)\s+in\s+([$A-Za-z_][$A-Za-z_\d\.]*)\s*$/,
function(match, keyword, item, array) {
found = true;
var i = ltl.vars[varIndex++];
var l = ltl.vars[varIndex++];
var e = ltl.vars[varIndex++];
loopVars.push([[item, e]]);
return 'for(var ' + e + ',' + i + '=0,' + l + '=s.' + array + '.length;' +
i + '<' + l + ';++' + i + ')' +
'{' + e + '=s.' + array + '[' + i + ']' + ';';
});
script = script.replace(/^for\s+([$A-Za-z_][$A-Za-z_\d]*)\s+in\s+([$A-Za-z_][$A-Za-z_\d\.]*)\s*$/,
function (match, item, array) {
found = true
var i = 'ltl' + varIndex++
var l = 'ltl' + varIndex++
var e = 'ltl' + varIndex++
loopVars.push([[item, e]])
return 'for(var ' + e + ',' + i + '=0,' + l + '=scope.' + array + '.length;' +
i + '<' + l + ';++' + i + ')' + '{' + newLine +
e + '=scope.' + array + '[' + i + ']' + ';' + newLine
})
if (found) {
stack.push('for');
return script;
stack.push('for')
return script
}
script = script.replace(/^(for)\s+([$A-Za-z_][$A-Za-z_\d]*)\s*,\s*([$A-Za-z_][$A-Za-z_\d]*)\s+of\s+([$A-Za-z_][$A-Za-z_\d\.]*)\s*$/,
function(match, keyword, key, value, object) {
found = true;
var k = ltl.vars[varIndex++];
var v = ltl.vars[varIndex++];
loopVars.push([[key, k], [value, v]]);
return 'for(var ' + k + ' in s.' + object + ')' +
'{if(!s.' + object + '.hasOwnProperty(' + k + '))continue;' +
v + '=s.' + object + '[' + k + ']' + ';';
});
script = script.replace(/^for\s+([$A-Za-z_][$A-Za-z_\d]*)\s*,\s*([$A-Za-z_][$A-Za-z_\d]*)\s+of\s+([$A-Za-z_][$A-Za-z_\d\.]*)\s*$/,
function (match, key, value, object) {
found = true
var k = 'ltl' + varIndex++
var v = 'ltl' + varIndex++
loopVars.push([[key, k], [value, v]])
return 'for(var ' + k + ' in scope.' + object + '){' + newLine +
'if(!scope.' + object + '.hasOwnProperty(' + k + '))continue;' + newLine +
v + '=scope.' + object + '[' + k + ']' + ';' + newLine
})
if (found) {
stack.push('for');
return script;
stack.push('for')
return script
}
script = script.replace(/^(else if|else|if)\s*(.*)\s*$/i,
function(match, keyword, condition) {
found = true;
return keyword + (condition ? '(' + prependState(condition) + ')' : '') + '{';
});
function (match, keyword, condition) {
found = true
return keyword + (condition ? '(' + scopify(condition) + ')' : '') + '{' + newLine
})
stack.push('if');
return script;
if (found) {
stack.push('if')
return script
}
/*
script = script.replace(/^(break|continue)(\s+.*)$/i,
function (match, keyword, condition) {
found = true
return keyword + (condition ? '(' + scopify(condition) + ')' : '') + '{' + newLine
})
*/
}
/**
* Give scope to a JavaScript expression by prepending the state variable "s".
* TODO: Parse using acorn so that strings can't be interpreted as ltl.vars.
* Give scope to a JavaScript expression by prepending the scope variable "scope".
* TODO: Parse using acorn so that strings can't be interpreted as vars.
*/
function prependState(code, unescapeSingleQuotes) {
function scopify (code, unescapeSingleQuotes) {
// Interpolations got escaped as HTML and must be unescaped to be JS.
if (unescapeSingleQuotes) {
code = code.replace(/\\'/g, "'");
code = code.replace(/\\'/g, "'")
}
var tokens = code.split(/\b/);
var isProperty = false;
var isLoopVar = false;
var isInString = false;
var tokens = code.split(/\b/)
var isProperty = false
var isLoopVar = false
var isInString = false
for (var i = 0; i < tokens.length; i++) {
var token = tokens[i];
var stringTokens = token.match(/['"]/g);
var token = tokens[i]
var stringTokens = token.match(/['"]/g)
if (stringTokens) {
isInString = ((isInString ? 1 : 0 ) + stringTokens.length) % 2;
}
else if (!isInString) {
isInString = ((isInString ? 1 : 0 ) + stringTokens.length) % 2
} else if (!isInString) {
if (/^[a-z_]/i.test(token)) {

@@ -463,5 +445,5 @@ if (!ltl.jsPattern.test(token)) {

for (var k = 0; k < loopVars[j].length; k++) {
if (token == loopVars[j][k][0]) {
isLoopVar = true;
tokens[i] = loopVars[j][k][1];
if (token === loopVars[j][k][0]) {
isLoopVar = true
tokens[i] = loopVars[j][k][1]
}

@@ -471,50 +453,43 @@ }

if (!isProperty && !isLoopVar) {
tokens[i] = 's.' + token;
tokens[i] = 'scope.' + token
}
}
}
isProperty = token[token.length - 1] == '.';
isLoopVar = false;
isProperty = token[token.length - 1] === '.'
isLoopVar = false
}
}
code = tokens.join('');
getPattern = /s\.get\.([$A-Za-z_][$A-Za-z_\d]*)/g;
code = code.replace(getPattern, function (match, part) {
hasGets = true;
return "p['" + part + "'].call(this,s)";
});
return code;
code = tokens.join('')
return code
}
/**
* Find ={...}, ${...}, &{...}, and -{...} interpolations.
* Turn them into state-aware insertions unless escaped.
* Find ={...}, ${...} and &{...} interpolations.
* Turn them into scope-aware insertions unless escaped.
*/
function interpolate(code) {
return code.replace(/(\\?)([$=&-])\{([^\}]+)\}/g, function(match, backslash, symbol, expression) {
function interpolate (code) {
return code.replace(/(\\?)([$=&])\{([^\}]+)\}/g, function (match, backslash, symbol, expression) {
if (backslash) {
return symbol + '{' + expression + '}';
return symbol + '{' + expression + '}'
}
if (symbol == '-') {
if (!escapeCommentVar) {
escapeCommentVar = ltl.vars[varIndex++];
}
return "'+" + escapeCommentVar + '(' + prependState(expression, true) + ")+'";
if (expression === 'block') {
expression = 'scope.block.call(cache,scope)'
useCache = true
} else {
expression = scopify(expression, true)
}
else if (symbol == '$') {
if (symbol === '$') {
if (!escapeHtmlVar) {
escapeHtmlVar = ltl.vars[varIndex++];
escapeHtmlVar = 'ltl' + varIndex++
}
return "'+" + escapeHtmlVar + '(' + prependState(expression, true) + ")+'";
}
else if (symbol == '&') {
return "'+" + escapeHtmlVar + '(' + expression + ")+'"
} else if (symbol === '&') {
if (!encodeUriVar) {
encodeUriVar = ltl.vars[varIndex++];
encodeUriVar = 'ltl' + varIndex++
}
return "'+" + encodeUriVar + '(' + prependState(expression, true) + ")+'";
return "'+" + encodeUriVar + '(' + expression + ")+'"
} else {
return "'+(" + expression + ")+'"
}
else {
return "'+" + prependState(expression, true) + "+'";
}
});
})
}

@@ -524,6 +499,6 @@

for (lineIndex = 0; lineIndex < lineCount; lineIndex++) {
var line = lines[lineIndex];
var line = lines[lineIndex]
// Mitigate recursion past 100 deep.
var maxT = 1e2;
var maxT = 1e2

@@ -533,25 +508,25 @@ // If the line is all whitespace, ignore it.

if (blockIndent) {
(blockLines = blockLines || []).push('');
(blockLines = blockLines || []).push('')
}
continue;
continue
}
// Find the number of leading spaces.
var spaces = line.search(/[^ ]/);
var spaces = line.search(/[^ ]/)
// If the first line with content has leading spaces, assume they all do.
if (!hasContent) {
globalSpaces = spaces;
hasContent = true;
globalSpaces = spaces
hasContent = true
}
var adjustedSpaces = Math.max(spaces - globalSpaces, 0);
var adjustedSpaces = Math.max(spaces - globalSpaces, 0)
// If this is our first time seeing leading spaces, that's our tab width.
if (adjustedSpaces > 0 && !currentTabWidth) {
currentTabWidth = adjustedSpaces;
currentTabWidth = adjustedSpaces
}
// Calculate the number of levels of indentation.
indent = adjustedSpaces ? Math.round(adjustedSpaces / currentTabWidth) : 0;
indent = adjustedSpaces ? Math.round(adjustedSpaces / currentTabWidth) : 0

@@ -562,9 +537,10 @@ // If we're in a block, we can append or close it.

if (indent < blockIndent) {
appendBlock();
}
appendBlock()
// If we're still in the block, append to the block code.
else {
line = line.substring(Math.min(spaces, currentTabWidth * blockIndent));
(blockLines = blockLines || []).push(line);
continue;
} else {
line = line.substring(Math.min(spaces, currentTabWidth * blockIndent))
blockLines = blockLines || []
blockLines.push(line)
continue
}

@@ -574,8 +550,8 @@ }

// Strip the leading spaces.
line = line.substring(spaces);
line = line.substring(spaces)
// Backtrack, closing any nested tags that need to be closed.
backtrackIndent();
backtrackIndent()
if (inComment) {
continue;
continue
}

@@ -585,188 +561,138 @@

if (ltl.controlPattern.test(line)) {
var script = transformScript(line);
appendText('script', script);
}
var script = transformScript(line)
appendText('script', script)
// Assignment patterns just need to be stateified.
else if (ltl.assignmentPattern.test(line)) {
hasAssignments = true;
line = prependState(line) + ';';
appendText('script', line);
}
} else if (ltl.assignmentPattern.test(line)) {
hasAssignments = true
line = scopify(line) + ';'
appendText('script', line)
// Expression patterns make things append.
else if (ltl.commandPattern.test(line)) {
var data = ltl.trim(line).split(/\s+/);
var command = data.shift();
blockName = data.shift();
blockContent = data.join(' ');
var pair = blockName.split(':');
blockName = pair[0];
if (command == 'get') {
appendText('html', "'+" + "p['" + blockName + "'].call(this,s)+'");
hasGets = true;
}
else {
if (pair[1] === '') {
command += ':';
} else if (line[0] === '@') {
line.replace(/@([^\s\(\[]+)([\(\[][^\)\]]*[\)\]])?(.*)/, function (match, path, attributes, rest) {
blockName = path
blockContent = rest
if (attributes) {
blockScope = []
attributes = attributes.substr(1, attributes.length - 2)
attributes.replace(/([^\s]+?)(=(['"])?[^'"]*?\3)?(\s|$)/g, function (match, name, value, space) {
blockScope.push(name + ':' + (value ? scopify(value.substr(1)) : true))
})
}
startBlock(command, blockContent);
}
}
startBlock('call', blockContent)
})
// Tags must be parsed for id/class/attributes/content.
else {
var rest = line;
var t = 0;
} else {
var rest = line
var t = 0
// Process the rest of the line recursively.
while (rest && (++t < maxT)) {
var tag = '';
var id = '';
var autoClass = '';
var classes = [];
var attributes = '';
var character = '';
var end = 0;
var content = '';
var tag = ''
var id = ''
var autoClass = ''
var classes = []
var attributes = ''
var character = ''
var end = 0
var content = ''
// Process the rest of the line recursively.
while (rest && (++t < maxT)) {
character = rest[0];
character = rest[0]
// If it's an ID, read up to the next thing, and save the ID.
if (character == '#') {
end = rest.search(/([\.\(>:\s]|$)/);
id = id || rest.substring(1, end);
rest = rest.substring(end);
}
if (character === '#') {
end = rest.search(/([\.\(>:\s]|$)/)
id = id || rest.substring(1, end)
rest = rest.substring(end)
// If it's a class, read up to the next thing, and save the class.
else if (character == '.') {
end = rest.search(/([@#\(>:\s]|$)/);
classes.push(rest.substring(1, end).replace(/\./g, ' '));
rest = rest.substring(end);
}
} else if (character === '.') {
end = rest.search(/([@#\(>:\s]|$)/)
classes.push(rest.substring(1, end).replace(/\./g, ' '))
rest = rest.substring(end)
// If it's the beginning of a list of attributes, iterate through them.
else if (character == '(') {
} else if (character === '(' || character === '[') {
// Move on from the parentheses.
rest = rest.substring(1);
rest = rest.substring(1)
// Build attributes.
attributes = '';
attributes = ''
while (rest && (++t < maxT)) {
// Find quoted attributes or the end of the list.
end = rest.search(/[\)"']/);
end = rest.search(/[\)\]"']/)
// If there's no end, read what's left as attributes.
if (end < 0) {
attributes += rest;
rest = '';
break;
attributes += rest
rest = ''
break
}
character = rest[end];
character = rest[end]
// If it's the end, get any remaining attribute and get out.
if (character == ')') {
attributes += rest.substring(0, end);
rest = rest.substring(end + 1);
break;
}
if (character === ')' || character === ']') {
attributes += rest.substring(0, end)
rest = rest.substring(end + 1)
break
// If it's not the end, read a quoted param.
else {
} else {
// Allow for attributes to be comma separated or not.
// Also allow for valueless attributes.
attributes += rest.substring(0, end).replace(/[,\s]+/g, ' ');
rest = rest.substring(end);
attributes += rest.substring(0, end).replace(/[,\s]+/g, ' ')
rest = rest.substring(end)
// Find the next end quote.
// TODO: Deal with backslash-delimited quotes.
end = rest.indexOf(character, 1);
end = rest.indexOf(character, 1)
// Read to the end of the attribute.
attributes += rest.substring(0, end + 1);
rest = rest.substring(end + 1);
attributes += rest.substring(0, end + 1)
rest = rest.substring(end + 1)
}
}
}
// If the next character is a greater than symbol, break for inline nesting.
else if (character == '>') {
rest = rest.replace(/^>\s*/, '');
break;
}
} else if (character === '>') {
rest = rest.replace(/^>\s*/, '')
break
// If the next character is a colon, enter a filter block.
else if (character == ':') {
blockTag = tag;
rest = rest.substring(1).split(' ');
startBlock(rest.shift(), rest.join(' '));
rest = '';
break;
}
} else if (character === ':') {
blockTag = tag
rest = rest.substring(1).split(' ')
startBlock(rest.shift(), rest.join(' '))
rest = ''
break
// If the next character is a plus, store it as a property.
else if (character == '+') {
} else if (character === '+') {
rest.replace(/^\+([^:\s]+):?(\S*)\s?(.*)$/, function (match, name, filter, content) {
var target = ltl.languages[name] || name;
blockProperty = target;
blockTag = '';
filter = (name == target ? '' : name) || filter;
startBlock(filter, content);
});
rest = '';
break;
}
var target = ltl.languages[name] || name
blockProperty = target
blockTag = ''
filter = (name === target ? '' : name) || filter
startBlock(filter, content)
})
rest = ''
break
// If the next character is an "at" symbol, create event listener references.
else if (character == '@') {
rest = rest.replace(/^@([$a-z0-9_~@]*)/i, function (match, events) {
autoClass = autoClass || '_ltl' + (++ltl.lastId);
classes.push(autoClass);
var bind = bindings[autoClass] = bindings[autoClass] || {};
events = events.split('@');
for (var e = 0; e < events.length; e++) {
var listeners = events[e].split('~');
var eventName = listeners.shift();
var listen = bind[eventName] = bind[eventName] || [];
for (var l = 0; l < listeners.length; l++) {
listen.push(listeners[l]);
}
}
});
}
// If the next character is a tilde, it's an event listener or language.
else if (character == '~') {
rest.replace(/^(~[^:\s]+):?(\S*)\s?(.*)$/, function (match, name, filter, content) {
var target = ltl.languages[name];
if (target) {
eventLanguage = name;
}
else {
blockProperty = name;
blockTag = '';
startBlock(filter || eventLanguage, content);
}
});
rest = '';
break;
}
// If the next character is a space, it's the start of content.
else if (character == ' ') {
content = ltl.trim(rest);
rest = '';
}
} else if (character === ' ') {
content = ltl.trim(rest)
rest = ''
// If the next character isn't special, it's part of a tag.
else {
end = rest.search(/([#\.\(>:\s@]|$)/);
} else {
end = rest.search(/([#\.\(>:\s@]|$)/)
// Prevent overwriting the tag.
tag = tag || rest.substring(0, end);
rest = rest.substring(end);
tag = tag || rest.substring(0, end)
rest = rest.substring(end)
}

@@ -777,6 +703,6 @@ }

if (ltl.languages[tag]) {
blockTarget = ltl.languages[tag];
var filter = (tag == blockTarget ? '' : tag) || filter;
tag = blockTag = blockTarget == 'css' ? 'style' : '//';
startBlock(filter, content);
blockTarget = ltl.languages[tag]
var filter = (tag === blockTarget ? '' : tag) || filter
tag = blockTag = blockTarget === 'css' ? 'style' : '//'
startBlock(filter, content)
}

@@ -786,15 +712,14 @@

if (tag.indexOf('//') === 0) {
tag = '//';
inComment = true;
}
tag = '//'
inComment = true
// If it's not a comment, we'll add some HTML.
else {
var className = classes.join(' ');
} else {
var className = classes.join(' ')
// Default to a <div> unless we're in a tagless block.
if (!tag) {
var useDefault = (blockTag === null) || id || className || attributes;
var useDefault = (blockTag === null) || id || className || attributes
if (useDefault) {
tag = blockTag = 'div';
tag = blockTag = settings.defaultTag
}

@@ -804,37 +729,36 @@ }

// Convert ! or doctype into !DOCTYPE and assume html.
if (tag == '!' || tag == 'doctype') {
tag = '!DOCTYPE';
attributes = attributes || 'html';
if (tag === '!' || tag === 'doctype') {
tag = '!DOCTYPE'
attributes = attributes || 'html'
}
// Add attributes to the tag.
var html = tag;
var html = tag
if (id) {
html += ' id="' + id + '"';
html += ' id="' + id + '"'
}
if (className) {
html += ' class="' + className + '"';
html += ' class="' + className + '"'
}
if (attributes) {
html += ' ' + attributes;
html += ' ' + attributes
}
// Convert space tag to a space character.
if (tag == 'space') {
html = ' ' + content;
}
if (tag === 'space') {
html = ' ' + content
// Convert minus to a comment.
else if (tag == '-') {
html = '<!--' + content;
} else if (tag === '-') {
html = '<!--' + content
} else {
html = '<' + html + '>' + content
}
else {
html = '<' + html + '>' + content;
}
html = ltl.escapeSingleQuotes(html);
if (tag == 'html') {
// If there's an HTML tag, don't wrap with a state.
hasHtmlTag = true;
html = ltl.escapeSingleQuotes(html)
if (tag === 'html') {
// If there's an HTML tag, don't wrap with a scope.
hasHtmlTag = true
if (!/DOCTYPE/.test(output)) {
html = '<!DOCTYPE html>' + (settings.space ? '\\n' : '') + html;
html = '<!DOCTYPE html>' + (settings.space ? '\\n' : '') + html
}

@@ -845,6 +769,6 @@ }

if (settings.space) {
html = ltl.repeat(settings.space, tagDepth) + html;
html = ltl.repeat(settings.space, tagDepth) + html
// Prepend a line break if this isn't the first tag.
if (hasHtmlOutput) {
html = '\\n' + html;
html = '\\n' + html
}

@@ -855,4 +779,4 @@ }

if (tag) {
appendText('html', html);
hasHtmlOutput = true;
appendText('html', html)
hasHtmlOutput = true
}

@@ -865,20 +789,19 @@ }

if (stack[indent]) {
stack[indent] += ',' + tag;
stack[indent] += ',' + tag
} else {
stack[indent] = tag
}
else {
stack[indent] = tag;
}
// Allow same-line tag open/close in settings.space mode.
previousTag = tag;
previousTag = tag
if (!ltl.selfClosePattern.test(tag)) {
tagDepth++;
tagDepth++
}
}
tag = '';
id = '';
classes = [];
attributes = '';
content = '';
tag = ''
id = ''
classes = []
attributes = ''
content = ''
}

@@ -889,84 +812,76 @@ }

// We've reached the end, so unindent all the way.
indent = 0;
indent = 0
if (blockIndent) {
appendBlock();
appendBlock()
}
backtrackIndent();
backtrackIndent()
// Add the return statement (ending concatenation, where applicable).
appendText('script', 'return o');
appendText('script', 'return output')
if (blockSets) {
return '{' + blockSets.join(',') + '}';
}
// Create the function.
if (escapeCommentVar) {
output = (settings.name ?
'var ' + escapeCommentVar + "=this['-'];" :
ltl.cache['-'].toString().replace(/\(/, escapeCommentVar + '(') + ';') + output;
'var ' + escapeCommentVar + "=cache['-'];" + newLine :
ltl.cache['-'].toString().replace(/\(/, escapeCommentVar + '(') + ';' + newLine) + output
useCache = true
}
if (escapeHtmlVar) {
output = (settings.name ?
'var ' + escapeHtmlVar + "=this.$;" :
ltl.cache.$.toString().replace(/\(/, escapeHtmlVar + '(') + ';') + output;
'var ' + escapeHtmlVar + "=cache.$;" + newLine :
ltl.cache.$.toString().replace(/\(/, escapeHtmlVar + '(') + ';' + newLine) + output
useCache = true
}
if (encodeUriVar) {
output = (settings.name ?
'var ' + encodeUriVar + "=this['&'];" :
ltl.cache['&'].toString().replace(/\(/, encodeUriVar + '(') + ';') + output;
'var ' + encodeUriVar + "=cache['&'];" + newLine :
ltl.cache['&'].toString().replace(/\(/, encodeUriVar + '(') + ';' + newLine) + output
useCache = true
}
if (hasAssignments) {
output = 's=s||{};' + output;
if (useCache) {
output = 'var cache=this;' + newLine + output
}
output = 'function(s' + (hasGets ? ',p' : '') + '){' + output + '}';
var index = 0
output = output.replace(/state=state\|\|scope;\s*var cache=this;\s*/g, function (match) {
return index++ ? '' : match
})
if (/\bstate\b/.test(output)) {
output = 'function(scope,state){' + newLine +
'state=state||scope;' + newLine + output + newLine + '}'
} else {
output = 'function(scope){' + newLine + output + newLine + '}'
}
// Evaluate the template as a function.
name = settings.name;
var template;
name = settings.name
var template
try {
template = ltl.run(output, name);
template = ltl.run(output, name)
} catch (e) {
name = (name ? '"' + name + '"' : 'template')
e.message = '[Ltl] Failed to compile ' + name + '. ' + e.message
throw e
}
catch (e) {
name = (name ? '"' + name + '"' : 'template');
e.message = '[Ltl] Failed to compile ' + name + '. ' + e.message;
throw e;
}
// If there's a name specified, cache it and refer to it.
if (name) {
ltl.cache[name] = template;
template.key = name;
template.cache = ltl.cache;
ltl.cache[name] = template
template.key = name
template.cache = ltl.cache
}
// Add event bindings to the JS property.
for (var key in bindings) {
var events = bindings[key];
for (var event in events) {
var listeners = events[event];
for (var i = 0; i < listeners.length; i++) {
var listener = listeners[i];
var js = properties['~' + listener];
properties.js = properties.js ? properties.js + '\n' : '';
properties.js += 'Jymin.on(".' + key + '","' + event + '",' +
'function(element,event,target){' + js + '});';
}
}
}
// Add any discovered properties to the template.
for (name in properties) {
if (name[0] != '~') {
template[name] = template[name] || properties[name];
}
template[name] = template[name] || properties[name]
}
return template;
return template
}
};
}
// Export Ltl as a CommonJS module.
if (typeof module !== 'undefined') {
module.exports = ltl;
module.exports = ltl
}
{
"name": "ltl",
"version": "0.2.0",
"version": "0.3.1",
"description": "Lean Template Language for JavaScript and HTML",

@@ -9,5 +9,5 @@ "dependencies": {},

"dot": "^1.0.3",
"exam": "^0.2.4",
"exam": ">=0.3.2",
"jade": "^1.9.2",
"jsx": "0.9.89",
"jsx": "^0.9.89",
"less": "^2.4.0",

@@ -14,0 +14,0 @@ "markdown": "0.5.0",

@@ -268,11 +268,16 @@ # <a href="http://lighter.io/ltl" style="font-size:40px;text-decoration:none;color:#000"><img src="https://cdn.rawgit.com/lighterio/lighter.io/master/public/ltl.svg" style="width:90px;height:90px"> Ltl</a>

Use `for..of` to iterate over an object's keys.
Use `for..of` to iterate over object keys.
*State:* `{pairings: {Coffee: 'coding', Beer: 'bloviating'}}`
```jade
```
for drink, activity of pairings
. ${field} is for ${value}.
.
b \\${field}
space
: is for
space
i \\${value}.
```
```html
<div>Coffee is for coding.</div><div>Beer is for bloviating</div>
<div><b>Coffee</b> is for <i>coding</i>.</div><div><b>Beer</b> is for <i>bloviating</i>.</div>
```

@@ -429,3 +434,3 @@

coffee
s.linkText = 'hello'
state.linkText = 'hello'

@@ -435,3 +440,3 @@ a ${linkText}

The state variable in a template is called `s`, so the above would set the
The state variable in a template is called `state`, so the above would set the
`linkText` value in the state object, and then it would render the following

@@ -449,3 +454,3 @@ HTML if called:

Additionally, huge thanks go to [TUNE](http://www.tune.com) for employing
Additionally, huge thanks go to [Goin’](https://goin.io) for employing
and supporting [Ltl](http://lighter.io/ltl) project maintainers,

@@ -452,0 +457,0 @@ and for being an epically awesome place to work (and play).

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