webkooljs
Version:
Webkool javascript library for nodejs
396 lines (357 loc) • 10.3 kB
JavaScript
/*
* Copyright (C) 2005-2020 Haruni SARL.
* Written by Sébastien BUREL <sb@haruni.net>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
;
var webkool = require("./webkool");
var json = function(data) {
return JSON.stringify(data, null, 4);
};
function include(url,scope) {
return webkool.application.render(url, scope);
}
var squareArgs = ['json','include'];
var squareValues = [json, include];
class Block {
constructor(container) {
this.container = container;
this.contents = [];
}
prepare(buffer) {
var contents = this.contents, c = contents.length, i;
for (i = 0; i < c; i += 1) {
contents[i].prepare(buffer);
}
}
render(scope, args, values) {
var contents = this.contents, length = contents.length, result = "";
for (var i = 0; i < length; i += 1) {
result += contents[i].render(scope, args, values);
}
return result;
}
}
class Text {
constructor(container, offset) {
this.container = container;
this.start = offset;
this.stop = offset;
this.buffer = null;
}
prepare(buffer) {
this.buffer = buffer.substring(this.start, this.stop);
}
render(scope, args, values) {
return (this.buffer) ? this.buffer : "";
}
}
class Variable {
constructor(container, start, stop, path, line) {
this.container = container;
this.start = start;
this.stop = stop;
this.path = path;
this.line = line;
this.contents = [];
this.script = null;
}
prepare(buffer) {
this.script = buffer.substring(this.start, this.stop);
this.script = this.script.replace(/\\"/g, '"');
var contents = this.contents, c = contents.length, i;
for (i = 0; i < c; i += 1) {
contents[i].prepare(buffer);
}
}
render(scope, args, values) {
try {
var blocks = this.contents;
switch (blocks.length) {
case 0: {
let f = Function.apply(undefined, args.concat('return (' + this.script + ');'));
return f.apply(undefined, values);
}
break;
case 1: {
let f = Function.apply(undefined, args.concat('return (' + this.script + ');'));
if (f.apply(undefined, values)) {
return blocks[0].render(scope, args, values);
}
else {
return "";
}
}
break;
case 2:
let f = Function.apply(undefined, args.concat('return (' + this.script + ');'));
if (f.apply(undefined, values)) {
return blocks[0].render(scope, args, values);
}
else {
return blocks[1].render(scope, args, values);
}
break;
case 3: {
let f = Function.apply(undefined, args.concat('return (' + this.script + ');'));
var $$ = f.apply(undefined, values);
var $c = $$.length;
var result = blocks[0].render(scope, args, values);
for (var $i = 0; $i < $c; $i += 1) {
var $ = $$[$i];
result += blocks[1].render(scope, args.concat(['$', '$i', '$c', '$$']), values.concat([$, $i, $c, $$]));
}
result += blocks[2].render(scope, args, values);
return result;
}
break;
}
}
catch(e) {
console.log("# Square failed '" + this.script + "' : " + e.toString());
return "";
}
}
}
class Square {
constructor(buffer, path) {
this.contents = [];
this.currentBlock = this;
this.currentText = null;
this.line = 1;
this.path = path;
this.parse(buffer);
this.prepare(buffer);
}
parse(buffer) {
var c, head, tail, offset = 0, former, start, stop;
this.startText(offset);
while (c = buffer.charCodeAt(offset)) {
switch (c) {
case 10:
this.line += 1;
offset += 1;
break;
case 13:
this.line += 1;
offset += 1;
c = buffer.charCodeAt(offset);
if (c == 10)
offset += 1;
break;
case 35: // #
former = offset;
offset += 1;
start = offset;
c = buffer.charCodeAt(offset);
if (c == 123) { // {
offset += 1;
start = offset;
for (;;) {
c = buffer.charCodeAt(offset);
if (c == 10) {
this.line += 1;
offset += 1;
}
else if (c == 13) {
this.line += 1;
offset += 1;
c = buffer.charCodeAt(offset);
if (c == 10)
offset += 1;
}
else if ((c == 125) && ((buffer.charCodeAt(offset+1)==35) || (buffer.charCodeAt(offset+1)==91))) // }# }[
break;
else
offset += 1;
}
stop = offset;
offset += 1;
c = buffer.charCodeAt(offset);
}
else {
for (;;) {
c = buffer.charCodeAt(offset);
if (((48 <= c) && (c <= 57)) || ((65 <= c) && (c <= 90)) || ((97 <= c) && (c <= 122)) || (c == 36) || (c == 95) || (c == 46))
offset += 1;
else
break;
}
stop = offset;
}
if (c == 35) { // #
this.stopText(former);
if (start == stop)
this.reportError('missing variable');
else {
this.pushVariable(start, stop);
this.popVariable();
}
offset += 1;
this.startText(offset);
}
else if (c == 91) { // [
this.stopText(former);
if (start == stop)
this.reportError('missing id');
else {
this.pushVariable(start, stop);
this.pushBlock();
}
offset += 1;
this.startText(offset);
}
break;
case 93: // ]
former = offset;
offset += 1;
c = buffer.charCodeAt(offset);
if (c == 35) { // #
this.stopText(former);
this.popBlock();
this.popVariable();
offset += 1;
this.startText(offset);
}
else if (c == 91) { // [
this.stopText(former);
this.popBlock();
this.pushBlock();
offset += 1;
this.startText(offset);
}
break;
case 60: // <
former = offset;
head = buffer.toString(null, offset, offset + 9);
if (head.indexOf('<![CDATA[') == 0) {
head = buffer.toString(null, offset + 9);
tail = head.indexOf(']]>');
if (tail >= 0)
former = offset + 9 + tail + 3;
else
this.reportError('missing ]]>');
}
else if (head.indexOf('<!--') == 0) {
head = buffer.toString(null, offset + 4);
tail = head.indexOf('-->');
if (tail >= 0)
former = offset + 4 + tail + 3;
else
this.reportError('missing -->');
}
offset += 1;
while (offset < former) {
c = buffer.charCodeAt(offset);
switch (c) {
case 10:
this.line += 1;
offset += 1;
break;
case 13:
this.line += 1;
offset += 1;
c = buffer.charCodeAt(offset);
if (c == 10)
offset += 1;
break;
default:
offset += 1;
break;
}
}
break;
default:
offset += 1;
break;
}
}
this.stopText(offset);
}
popBlock() {
if (this.currentBlock.container) {
this.currentBlock = this.currentBlock.container;
}
else
this.reportError('unexpected ]');
}
popVariable() {
if (this.currentBlock.container) {
this.currentBlock = this.currentBlock.container;
}
else
this.reportError('unexpected ]]');
}
prepare(buffer) {
var contents = this.contents, c = contents.length, i;
for (i = 0; i < c; i += 1) {
contents[i].prepare(buffer);
}
}
pushBlock() {
var block = new Block(this.currentBlock);
this.currentBlock.contents.push(block);
this.currentBlock = block;
}
pushVariable(start, stop) {
var variable = new Variable(this.currentBlock, start, stop, this.path, this.line);
this.currentBlock.contents.push(variable);
this.currentBlock = variable;
}
reportError(message) {
console.log(this.path + ':' + this.line + ': error:' + message);
}
startText(offset) {
var text = new Text(this.currentBlock, offset);
this.currentBlock.contents.push(text);
this.currentText = text;
}
stopText(offset) {
if (this.currentText.start < offset)
this.currentText.stop = offset;
else
this.currentBlock.contents.pop();
this.currentText = null;
}
render(scope, args, values) {
var contents = this.contents, length = contents.length;
var result = "";
for (var i = 0; i < length; i += 1) {
result += contents[i].render(scope, args, values);
}
return result;
}
}
function square(parts/*, ...args*/) {
/* Compatibility */
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key];
}
/* Compatibility */
var square = new Square(parts[0], "");
return function(handler, scope) {
var args = squareArgs.concat('scope'), values = squareValues.concat(scope);
for (var s in scope) {
args.push(s);
values.push(scope[s]);
}
return square.render(scope, args, values);
};
};
exports.square = square;
function squareExtends(arg, value) {
squareArgs.push(arg);
squareValues.push(value);
}
exports.squareExtends = squareExtends;