Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@jeefo/component

Package Overview
Dependencies
Maintainers
1
Versions
18
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@jeefo/component - npm Package Compare versions

Comparing version 0.0.9 to 0.0.10

components/conditional_component.js

252

compiler.js
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
* File Name : compiler.js
* Created at : 2019-06-23
* Updated at : 2019-12-07
* Updated at : 2020-06-23
* Author : jeefo

@@ -18,26 +18,29 @@ * Purpose :

const jqlite = require("@jeefo/jqlite");
const definitions_table = require("./definitions_table");
const StructureComponent = require("./structure_component");
const DirectiveComponent = require("./directive_component");
const JeefoDOMParser = require("./dom_parser");
const definitions_table = require("./definitions_table");
const Directive = require("./components/directive");
const StructureComponent = require("./components/structure_component");
const RenderableComponent = require("./components/renderable_component");
const { MARKER } = StructureComponent;
const BINDER = /{{\s*\S+.*}}/m;
const single_tag_elements = ["img"];
const new_binding_component = (element, parent) => {
return new RenderableComponent("binding--component", element, {}, parent);
};
const is_element = n => n instanceof Element;
// Higher order structure diretive like: forEach="item in items"
async function find_structure_directive (node, parent) {
async function find_structure (element, parent) {
let name, definition;
for (const [attr_name] of node.attrs) {
const _definition = await definitions_table.get_directive(attr_name);
if (_definition && _definition.is_structure) {
if (definition) {
if (_definition.priority > definition.priority) {
name = attr_name;
definition = _definition;
if (element.hasAttributes()) {
for (const attr of element.attributes) {
const def = await definitions_table.get_directive(attr.name);
if (def && def.is_structure) {
if (definition && def.priority < definition.priority) {
continue;
}
} else {
name = attr_name;
definition = _definition;
name = attr.name;
definition = def;
}

@@ -47,54 +50,49 @@ }

if (! definition) { return; }
if (definition) {
const component = new StructureComponent(
name, element, definition, parent
);
component.expression = element.getAttribute(name);
element.removeAttribute(name);
const component = new StructureComponent(null, definition, parent);
component.node = node;
component.expression = node.attrs.get(name);
node.attrs.remove(name);
return component;
}
return component;
name = element.tagName.toLowerCase();
definition = await definitions_table.get_component(name);
if (definition && definition.is_structure) {
return new StructureComponent(name, element, definition, parent);
}
}
const fake_definition = {
binders : [],
dependencies : [],
Controller : class Controller {},
controller_name : null,
is_self_required : false,
};
async function find_component (node, parent) {
async function find_component (element, parent) {
const name = element.tagName.toLowerCase();
let component = null;
let definition = await definitions_table.get_component(node.name);
let definition = await definitions_table.get_component(name);
if (definition) {
component = new StructureComponent(node.name, definition, parent);
if (definition.is_structure) {
component.node = node;
return component;
}
// TODO: think about better way, maybe return jeefo template or
// something...
if (definition.template_handler) {
definition.template_handler(node);
const new_element = definition.template_handler(element);
if (is_element(new_element)) {
if (element.parentNode) {
element.parentNode.replaceChild(new_element, element);
}
element = new_element;
}
} else {
node.children = definition.transclude(node.children);
definition.transclude(element);
}
}
// Content binding
if (node.children.length === 0 &&
node.content && node.content.includes("${")) {
if (! node.attrs.has("jf-bind")) {
node.attrs.set("jf-bind", node.content);
}
node.content = null;
component = new RenderableComponent(name, element, definition, parent);
}
if (! component) {
// Attribute binding or has directive
for (const [attr_name, value] of node.attrs) {
const def = await definitions_table.get_directive(attr_name);
if (def || (value && value.includes("${"))) {
component = new StructureComponent(
null, fake_definition, parent
);
// Attribute binding or has directive
if (! component && element.hasAttributes()) {
for (const {name, value} of element.attributes) {
const def = await definitions_table.get_directive(name);
if (def || BINDER.test(value) || name.startsWith("on--")) {
component = new_binding_component(element, parent);
break;

@@ -105,106 +103,66 @@ }

if (node.events.length) {
// Content binding
if (element.children.length === 0 && BINDER.test(element.textContent)) {
if (element.hasAttribute("js-bind")) {
throw new Error("Ambiguous binding");
}
element.setAttribute("jf-bind", element.textContent);
if (! component) {
component = new StructureComponent(null, fake_definition, parent);
component = new_binding_component(element, parent);
}
component.binding_events = node.events;
}
return component;
}
async function resolve_template (nodes, parent_component) {
const results = [];
async function resolve_components (elements, parent) {
const components = [];
for (const node of nodes) {
for (let elem of elements) {
// Structure directive is higher order
let component = await find_structure_directive(node, parent_component);
let component = await find_structure(elem, parent);
if (component) {
parent_component.children.push(component);
results.push(
`<${node.name} ${ component.get_marker() }></${node.name}>`
);
components.push(component);
continue;
}
let attrs = '';
let content = '';
component = await find_component(node, parent_component);
component = await find_component(elem, parent);
if (component) {
attrs += ` ${ component.get_marker() }`;
parent_component.children.push(component);
components.push(component);
const {$element} = component;
elem = $element.DOM_element;
if (component.is_self_required) {
results.push(
`<${node.name}${attrs}></${node.name}>`
);
continue;
// Find directives
if (elem.hasAttributes()) {
let i = elem.attributes.length;
while (i--) {
const {name, value} = elem.attributes[i];
const def = await definitions_table.get_directive(name);
if (def) {
const directive = new Directive(name, $element, def);
component.directives.push(directive);
} else if (name.startsWith("on--")) {
component.binding_events.push({
event_name : name.substring(4),
expression : value,
});
elem.removeAttribute(name);
}
}
}
}
if (node.children.length) {
const parent = component || parent_component;
content = await resolve_template(node.children, parent);
} else if (node.content) {
content = node.content;
}
// Find directives
if (node.id) {
attrs += ` id="${ node.id }"`;
}
if (node.class_list.length) {
attrs += ` class="${ node.class_list.join(' ') }"`;
}
for (const [name, value] of node.attrs) {
attrs += ` ${ name }`;
if (value) {
attrs += `="${ value }"`;
}
const definition = await definitions_table.get_directive(name);
if (definition) {
const directive = new DirectiveComponent(name, definition);
component.directives.push(directive);
}
}
if (single_tag_elements.includes(node.name)) {
results.push(`<${node.name}${attrs}>`);
} else {
results.push(`<${node.name}${attrs}>${content}</${node.name}>`);
}
await resolve_components(elem.children, component || parent);
}
return results.join('');
return components;
}
function set_elements (components, $wrapper) {
components.forEach(component => {
if (! component.is_initialized) {
component.$element = $wrapper.first(component.selector);
component.$element.DOM_element.removeAttribute(MARKER);
}
set_elements(component.children, $wrapper);
});
}
async function compile_from_elements (elements, parent, to_initialize = true) {
const components = await resolve_components(elements, parent);
async function compile (nodes, parent_component, to_initialize = true) {
const template = await resolve_template(nodes, parent_component);
const $wrapper = jqlite("<div></div>");
const $elements = jqlite(template);
if ($elements.DOM_element) {
$wrapper.append($elements);
} else {
for (let i = 0; i < $elements.length; i+= 1) {
$wrapper.append($elements[i]);
}
}
set_elements(parent_component.children, $wrapper);
if (to_initialize) {
for (const component of parent_component.children) {
if (! component.is_initialized) {
await component.init();
for (const component of components) {
if (! component.is_initialized && ! component.is_destroyed) {
await component.initialize();
}

@@ -214,13 +172,17 @@ }

// Much faster way remove all child nodes
// ref: https://stackoverflow.com/questions/3955229/remove-all-child-elements-of-a-dom-node-in-javascript?answertab=votes#tab-top
const wrapper = $wrapper.DOM_element;
const elements = [];
while (wrapper.firstChild) {
elements.push(wrapper.firstChild);
wrapper.removeChild(wrapper.firstChild);
}
return elements;
}
async function compile (template, parent_component, to_initialize = true) {
const dom_parser = new JeefoDOMParser(template);
await compile_from_elements(
dom_parser.elements, parent_component, to_initialize
);
return dom_parser.detach();
}
compile.from_elements = compile_from_elements;
module.exports = compile;
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
* File Name : component_definition.js
* Created at : 2019-06-24
* Updated at : 2019-12-29
* Updated at : 2020-06-08
* Author : jeefo

@@ -19,10 +19,7 @@ * Purpose :

const extend_member = require("@jeefo/utils/class/extend_member");
const jeefo_template = require("@jeefo/template");
const object_for_each = require("@jeefo/utils/object/for_each");
const styles = require("./styles");
const IDefinition = require("./i_definition");
const IDefinition = require("./interfaces/i_definition");
const TranscludeController = require("./transclude_controller");
const STRING_TEMPLATE = /{{([^}]+)}}/g;
const is_class = value => value.toString().startsWith("class");

@@ -46,4 +43,3 @@

if (type.toLowerCase() === "structure") {
this.is_structure = true;
this.is_self_required = true;
this.is_structure = true;
} else {

@@ -56,3 +52,3 @@ throw new SyntaxError("Invalid definition type");

if (style) {
const selectors = this.selectors.map(s => `"${s}"`);
const selectors = this.selectors.map(s => `"${s.toLowerCase()}"`);
styles.add_style(style, {

@@ -65,11 +61,7 @@ "component-selectors" : `[${ selectors.join(", ") }]`

if (typeof template === "string") {
const _template = template.replace(STRING_TEMPLATE, (_, expr) => {
return `\${${ expr }}`;
});
const nodes = jeefo_template.parse(_template);
this.transclude_controller = new TranscludeController(nodes);
this.transclude_controller = new TranscludeController(template);
} else if (typeof template === "function") {
this.template_handler = template;
} else {
this.transclude_controller = new TranscludeController([]);
this.transclude_controller = new TranscludeController();
}

@@ -106,4 +98,4 @@

transclude (child_nodes) {
return this.transclude_controller.transclude(child_nodes);
transclude (element) {
this.transclude_controller.transclude(element);
}

@@ -110,0 +102,0 @@ }

/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
* File Name : directive_definition.js
* Created at : 2017-08-07
* Updated at : 2019-12-29
* Updated at : 2020-06-08
* Author : jeefo

@@ -21,3 +21,3 @@ * Purpose :

const styles = require("./styles");
const IDefinition = require("./i_definition");
const IDefinition = require("./interfaces/i_definition");

@@ -41,4 +41,3 @@ const is_class = value => value.toString().startsWith("class");

if (type.toLowerCase() === "structure") {
this.is_structure = true;
this.is_self_required = true;
this.is_structure = true;
} else {

@@ -45,0 +44,0 @@ throw new SyntaxError("Invalid directive type");

/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
* File Name : for_each.js
* Created at : 2017-07-25
* Updated at : 2020-06-01
* Updated at : 2020-06-22
* Author : jeefo

@@ -16,9 +16,37 @@ * Purpose :

// jshint curly: false
/* maybe useful some time
const filter_children = async from => {
const seen = [];
const filtered_children = [];
NEXT:
for (let i = children.length - 1; i >= from; i -= 1) {
const child = children[i];
let j = values.length;
while (j--) {
if (values[j] === child.value && ! seen.includes(j)) {
seen.push(j);
continue NEXT;
}
}
filtered_children.push(child);
children.splice(i, 1);
}
if (filtered_children.length) {
return Promise.all(filtered_children.map(c => c.destroy()));
}
};
await filter_children(0);
*/
// ignore:end
const jqlite = require("@jeefo/jqlite");
const parser = require("../input/parser");
const compile = require("../compiler");
const Interpreter = require("../interpreter");
const StructureComponent = require("../structure_component");
const parser = require("../input/parser");
const Interpreter = require("../interpreter");
const ConditionalComponent = require("../components/conditional_component");

@@ -28,23 +56,27 @@ const comp_prop = Symbol("component");

const definition = {
binders : [],
dependencies : [],
Controller : class ForEachDirectiveController {},
controller_name : null,
is_self_required : false,
};
class ForEachElement {}
const CODE_CANCEL = Math.random();
async function create_new_child (value, index, component) {
const { variable_name, index_name } = component;
const new_child = new StructureComponent(null, definition, component);
const { element, variable_name, index_name } = component;
const wrapper = await new ConditionalComponent("foreach--wrapper", element);
new_child.index = new_child.controller[index_name] = index;
new_child.value = new_child.controller[variable_name] = value;
wrapper.controller = new ForEachElement();
wrapper.index = wrapper.controller[index_name] = index;
wrapper.value = wrapper.controller[variable_name] = value;
const elements = await compile([component.node.clone(true)], new_child);
new_child.$element = jqlite(elements[0]);
return new_child;
return wrapper;
}
const is_synced = (values, children) => {
if (values.length === children.length) {
let i = values.length;
while (i--) {
if (values[i] !== children[i].value) return false;
}
return true;
}
};
async function sync_children (instance) {

@@ -55,27 +87,4 @@ const values = instance[values_prop];

const is_synced = () => {
return (
values.length === children.length &&
values.every((v, i) => v === children[i].value)
);
};
let is_dirty = false;
let i = children.length;
while (i--) {
if (! values.includes(children[i].value)) {
await children[i].destroy();
}
}
const destroy_from = from => {
for (let i = children.length - 1; i >= from; i -= 1) {
const index = values.indexOf(children[i].value, from);
if (index === -1) {
children[i].destroy();
}
}
};
destroy_from(0);
let is_canceled = false, cancel_resolver;

@@ -86,6 +95,11 @@ component.cancel_syncing = () => {

};
component.is_syncing = true;
LOOP:
while (! is_synced()) {
for (let [i, value] of values.entries()) {
while (! is_synced(values, children) && ! is_canceled) {
is_dirty = true;
LOOP:
for (let i = 0; i < values.length; i+= 1) {
const value = values[i];
if (i < children.length) {

@@ -95,3 +109,3 @@ if (children[i].value === value) { continue; }

for (let j = i + 1; j < children.length; j += 1) {
if (children[j] === value) {
if (children[j].value === value) {
children.splice(i, 0, children.splice(j, 1)[0]);

@@ -105,12 +119,25 @@ continue LOOP;

children.splice(i, 0, new_child);
if (is_canceled) { break; }
destroy_from(i + 1);
continue LOOP;
new_child.parent = component;
}
if (children.length > values.length) {
const dead_children = children.splice(values.length);
await Promise.all(dead_children.map(c => c.destroy()));
}
if (component.is_initialized) {
for (const child of children) {
if (! child.is_initialized) await child.initialize();
if (is_canceled) break;
}
}
}
component.is_syncing = false;
if (is_canceled) {
component.cancel_syncing = null;
cancel_resolver();
throw CODE_CANCEL;
}
return is_dirty;
}

@@ -125,2 +152,3 @@

this[comp_prop] = component;
component.element.removeAttribute("for-each");

@@ -152,5 +180,8 @@ try {

$element.replace(document.createComment(comment));
component.$placeholder = $element;
component.is_initialized = true;
await this.on_digest();
} catch (e) {
// WTF ???
throw e;

@@ -163,7 +194,5 @@ }

const {
$element : $comment,
children,
index_name,
interpreter,
is_attached,
$placeholder,
} = component;

@@ -177,28 +206,44 @@ this[values_prop] = interpreter.get_value();

}
await sync_children(this);
if ($comment.DOM_element.parentNode === null) {
const frag = document.createDocumentFragment();
frag.appendChild($comment.DOM_element);
}
try {
const is_changed = await sync_children(this);
if (! is_changed) return;
children.forEach((child, index) => {
if (! child.is_attached || child.index !== index) {
const {index_name} = component;
const move = (index, child) => {
if (index === 0) {
$comment.after(child.$element);
$placeholder.after(child.$element);
} else {
const prev = component.children[index - 1];
const prev = children[index - 1];
prev.$element.after(child.$element);
}
};
child.index = index;
child.controller[index_name] = index;
if (is_attached && ! child.is_attached) {
child.trigger_renderable();
for (const [index, child] of children.entries()) {
if (! child.is_attached) {
move(index, child);
child.is_attached = true;
} else if (child.index !== index) {
const data = {
old_index : child.index,
new_index : index
};
move(index, child);
child.index = child.controller[index_name] = index;
if (child.is_rendered) {
child.$element.trigger("foreach:move", { data });
}
}
}
});
if (component.is_rendered)
for (const child of children)
if (! child.is_rendered) child.trigger_render();
} catch (e) {
if (e !== CODE_CANCEL) throw e;
}
},
}
};
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
* File Name : if.js
* Created at : 2017-09-17
* Updated at : 2019-12-03
* Updated at : 2020-06-12
* Author : jeefo

@@ -18,6 +18,5 @@ * Purpose :

const jqlite = require("@jeefo/jqlite");
const compile = require("../compiler");
const Interpreter = require("../interpreter");
const StructureComponent = require("../structure_component");
const jqlite = require("@jeefo/jqlite");
const Interpreter = require("../interpreter");
const ConditionalComponent = require("../components/conditional_component");

@@ -27,24 +26,13 @@ const prop_comment = Symbol("$comment");

const definition = {
binders : [],
Controller : class Controller {},
dependencies : [],
};
const compile_component = async (component, $comment) => {
const child = new StructureComponent(null, definition, component);
component.children.push(child);
const wrapper = await new ConditionalComponent(
"if--rendered", component.element, component
);
const elements = await compile([component.node.clone(true)], child, false);
child.$element = jqlite(elements[0]);
if (! wrapper.is_destroyed) {
await wrapper.initialize();
if (! child.is_destroyed) {
$comment.after(child.$element);
if (component.is_initialized) {
await child.init();
if (! child.is_destroyed && component.is_attached) {
child.trigger_renderable();
}
if (! wrapper.is_destroyed) {
$comment.after(wrapper.$element);
if (component.is_rendered) { wrapper.trigger_render(); }
}

@@ -65,2 +53,3 @@ }

component.interpreter = new Interpreter(expression, component);
component.element.removeAttribute("if");

@@ -67,0 +56,0 @@ this[prop_comment] = jqlite(comment);

/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
* File Name : jf_bind_directive.js
* File Name : jf_bind.js
* Created at : 2017-07-26
* Updated at : 2019-07-21
* Updated at : 2020-06-11
* Author : jeefo

@@ -25,3 +25,3 @@ * Purpose :

break;
case null :
case "null" :
$element.text = "null";

@@ -39,4 +39,4 @@ break;

},
controller : {
on_init : function ($element) {
controller : class Binder {
on_init ($element) {
bind($element, this["(bind)"]);

@@ -43,0 +43,0 @@ const observer = new Observer(this);

/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
* File Name : switch.js
* Created at : 2019-07-12
* Updated at : 2020-01-02
* Updated at : 2020-06-12
* Author : jeefo

@@ -18,42 +18,30 @@ * Purpose :

const jqlite = require("@jeefo/jqlite");
const Events = require("@jeefo/template/tokens/events");
const Attributes = require("@jeefo/template/tokens/attributes");
const NodeElement = require("@jeefo/template/node_element");
const compile = require("../compiler");
const Interpreter = require("../interpreter");
const StructureComponent = require("../structure_component");
const jqlite = require("@jeefo/jqlite");
const compile = require("../compiler");
const is_element = require("../is_element");
const Interpreter = require("../interpreter");
const ConditionalComponent = require("../components/conditional_component");
const prop_component = Symbol("component");
const definition = {
binders : [],
Controller : class Controller {},
dependencies : [],
};
const compile_child = async (component, {element, $placeholder}) => {
const wrapper = await new ConditionalComponent(
"switch-wrapper", element, component
);
const find_case = (cases, value) => {
return cases.find(node => {
if (node.interpreter) {
return node.interpreter.get_value() === value;
if (! wrapper.is_destroyed) {
await wrapper.initialize();
if (! wrapper.is_destroyed) {
$placeholder.after(wrapper.$element);
if (component.is_rendered) { wrapper.trigger_render(); }
}
return node;
});
}
return wrapper;
};
const compile_component = async (node, component) => {
const child = new StructureComponent(null, definition, component);
const elements = await compile([node.clone(true)], child, false);
child.$element = jqlite(elements[0]);
return child;
const compile_self = async instance => {
await compile.from_elements([instance.element], instance);
};
const placeholder_node = new NodeElement(null, {
name : "switch-placeholder",
class_list : [],
content : null,
attrs : new Attributes(),
events : new Events(),
});
module.exports = {

@@ -66,38 +54,42 @@ type : "structure",

async on_init ($element, component) {
const { node, expression } = component;
const {element, expression} = component;
element.removeAttribute("switch");
const cases = [];
const placeholder_clone = placeholder_node.clone();
placeholder_clone.attrs.set("switch-id", component.id);
node.children = node.children.map(child => {
if (child.attrs.has("case")) {
const expr = child.attrs.get("case");
child.interpreter = new Interpreter(expr, component);
component.cases = [];
component.interpreter = new Interpreter(expression, component);
cases.push(child);
return placeholder_clone;
} else if (child.attrs.has("default")) {
cases.push(child);
return placeholder_clone;
} else {
return child;
let i = element.childNodes.length;
while (i--) {
const node = element.childNodes[i];
if (! is_element(node)) { continue; }
if (node.hasAttribute("case")) {
const expr = node.getAttribute("case");
const comment = `switch-case: ${expr}`;
const comment_el = document.createComment(comment);
component.cases.push({
element : node,
interpreter : new Interpreter(expr, component),
$placeholder : jqlite(comment_el),
});
node.removeAttribute("case");
element.replaceChild(comment_el, node);
} else if (node.hasAttribute("default")) {
if (component.default_case) {
throw new Error("Multiple default case found in switch.");
}
const comment = document.createComment("switch-default");
component.default_case = {
element : node,
$placeholder : jqlite(comment),
};
node.removeAttribute("default");
element.replaceChild(comment, node);
}
});
component.cases = cases;
component.interpreter = new Interpreter(expression, component);
component.placeholders = [];
const elements = await compile([node], component);
$element.replace(elements[0]);
if (component.children[0].$element.DOM_element === elements[0]) {
component.$element = null;
}
component.placeholders.forEach((p, i) => {
p.node = cases[i];
});
component.is_initialized = true;
compile_self(component);
this[prop_component] = component;
await this.on_digest();

@@ -107,41 +99,20 @@ }

async on_digest () {
const component = this[prop_component];
const value = component.interpreter.get_value();
let matched_node = find_case(component.cases, value);
const component = this[prop_component];
const value = component.interpreter.get_value();
// Cleaning old switch-case
if (component.matched_node) {
if (component.matched_node === matched_node) {
matched_node = null;
} else {
if (component.active_child) {
component.active_child.destroy();
}
component.matched_node = component.active_child = null;
let matched_case = component.cases.find(node => {
return node.interpreter.get_value() === value;
}) || component.default_case;
if (component.matched_case !== matched_case) {
// Cleaning old switch-case
if (component.instance) {
component.instance.destroy();
component.instance = null;
}
}
if (matched_node) {
component.matched_node = matched_node;
const child = await compile_component(matched_node, component);
if (! child.is_destroyed) {
const placeholder = component.placeholders.find(p => {
return p.node === matched_node;
});
const child_index = component.children.findIndex(child => {
return child === placeholder;
});
component.children.splice(child_index + 1, 0, child);
placeholder.$element.after(child.$element);
component.active_child = child;
if (component.is_initialized) {
await child.init();
if (! child.is_destroyed && component.is_attached) {
child.trigger_renderable();
}
}
}
component.matched_case = matched_case;
component.instance = await compile_child(
component, matched_case
);
}

@@ -148,0 +119,0 @@ }

/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
* File Name : index.js
* Created at : 2017-08-08
* Updated at : 2019-11-29
* Updated at : 2020-06-09
* Author : jeefo

@@ -39,2 +39,15 @@ * Purpose :

module.exports = definitions_table;
module.exports = {
IComponent : require("./interfaces/i_component"),
IRenderable : require("./interfaces/i_renderable"),
IDefinition : require("./interfaces/i_definition"),
Directive : require("./components/directive"),
InvisibleComponent : require("./components/invisible_component"),
StructureComponent : require("./components/structure_component"),
RenderableComponent : require("./components/renderable_component"),
compile : require("./compiler"),
JeefoDOMParser : require("./dom_parser"),
definitions_table
};
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
* File Name : ast_node_table.js
* Created at : 2017-09-18
* Updated at : 2019-10-31
* Updated at : 2020-06-11
* Author : jeefo

@@ -17,3 +17,14 @@ * Purpose :

const { AST_Node_Table } = require("@jeefo/parser");
const {
AST_Node_Table,
AST_Node_Definition
} = require("@jeefo/parser");
const {
PRIMITIVE,
TERMINATION
} = require("@jeefo/ecma_parser/es6/enums/precedence_enum");
const {
expression,
primary_expression
} = require("@jeefo/ecma_parser/es6/enums/states_enum");

@@ -67,4 +78,7 @@ const ast_node_table = new AST_Node_Table();

"es6/expressions/property_definition",
// 12.2.9 - Template literal
"es6/literals/template_literal",
// replaced by jeefo binder
//"es6/literals/template_literal",
// 12.2.10 - The grouping operator

@@ -129,2 +143,7 @@ "es8/expressions/cover_parenthesized_expression_and_arrow_parameters",

// DEBUG_START
const debugger_stmt = require(`${proj_dir}/es5/statements/debugger_statement`);
ast_node_table.register_reserved_word("debugger", debugger_stmt);
// DEBUG_END
const _this = require(`${ proj_dir }/es8/expressions/this_keyword`);

@@ -137,2 +156,193 @@ ast_node_table.register_reserved_word("this", _this);

// Jeefo binder
const template_string = new AST_Node_Definition({
id : "Template literal string",
type : "Primitive",
precedence : -1,
is : () => {},
initialize : (node, current_token, parser) => {
const { streamer } = parser.tokenizer;
let length = 0;
let current_index = streamer.cursor.position.index;
let virtual_length = 0;
let next_character = streamer.get_current_character();
let start, end, last_pos;
if (parser.last_position) {
start = parser.last_position.clone();
start.index += 1;
start.column += 1;
start.virtual_column += 1;
} else {
start = streamer.clone_cursor_position();
}
const get_next_character = (next_length = 1) => {
return streamer.at(current_index + length + next_length);
};
LOOP:
while (true) {
switch (next_character) {
case '\t' :
virtual_length += streamer.tab_size - 1;
break;
case '\n' :
next_character = get_next_character();
if (next_character === '`') {
if (parser.last_position) {
end = start.clone();
streamer.cursor.position.line -= 1;
} else {
streamer.cursor.move(length, virtual_length);
end = streamer.clone_cursor_position();
}
streamer.cursor.position.line += 1;
streamer.cursor.position.column = 0;
streamer.cursor.position.virtual_column = 0;
break LOOP;
} else {
if (parser.last_position) {
last_pos = start.clone();
parser.last_position = null;
} else {
if (length) {
streamer.cursor.move(length, virtual_length);
last_pos = streamer.clone_cursor_position();
}
streamer.cursor.position.line += 1;
}
streamer.cursor.position.column = 0;
streamer.cursor.position.virtual_column = 0;
current_index = streamer.cursor.position.index;
length = virtual_length = 0;
}
break;
case '{':
if (get_next_character() === '{') {
const is_new_line = (
length === 1 &&
streamer.cursor.position.column === 0 &&
last_pos
);
streamer.cursor.move(length-1, virtual_length - 1);
if (is_new_line) {
end = last_pos;
} else {
end = streamer.clone_cursor_position();
}
break LOOP;
}
break;
case '`':
streamer.cursor.move(length - 1, virtual_length - 1);
end = streamer.clone_cursor_position();
break LOOP;
case '\\':
length += 1;
virtual_length += 1;
break;
case null: parser.throw_unexpected_end_of_stream();
}
next_character = get_next_character();
length += 1;
virtual_length += 1;
}
node.value = streamer.substring_from_offset(start.index);
node.start = start;
node.end = end;
}
});
const jeefo_binder_expression = new AST_Node_Definition({
id : "Jeefo binder expression",
type : "Primitive",
precedence : -1,
is : () => {},
initialize : (node, current_token, parser) => {
const start = current_token.start;
const {streamer} = parser.tokenizer;
streamer.cursor.move(1);
parser.prepare_next_state("expression", true);
const expression = parser.parse_next_node(TERMINATION);
parser.expect("}}", () => {
return parser.next_token.id === "Delimiter" &&
parser.next_token.value === '}' &&
streamer.is_next_character('}');
});
streamer.cursor.move(1);
node.expression = expression;
node.start = start;
node.end = streamer.clone_cursor_position();
}
});
ast_node_table.register_node_definition({
id : "Template literal",
type : "Primitive",
precedence : PRIMITIVE,
is : (token, { current_state }) => {
return current_state === expression && token.id === "Backtick";
},
initialize : (node, current_token, parser) => {
const body = [];
const { streamer } = parser.tokenizer;
const start_position = streamer.clone_cursor_position();
if (streamer.get_next_character() === '\n') {
parser.last_position = streamer.clone_cursor_position();
}
let next_character = streamer.next();
LOOP:
while (true) {
switch (next_character) {
case '`' : break LOOP;
case null:
parser.throw_unexpected_end_of_stream();
break;
}
if (next_character === '{' && streamer.is_next_character('{')) {
body.push(jeefo_binder_expression.generate_new_node(parser));
} else {
body.push(template_string.generate_new_node(parser));
}
next_character = streamer.get_next_character();
if (next_character === '\n') {
parser.last_position = streamer.clone_cursor_position();
} else {
parser.last_position = null;
}
if (streamer.get_current_character() === '\n') {
streamer.cursor.position.line -= 1;
}
streamer.next();
}
delete parser.last_position;
node.body = body;
node.start = start_position;
node.end = streamer.clone_cursor_position();
// It's important, since there is no real next token
parser.next_token = node;
parser.current_state = primary_expression;
}
});
module.exports = ast_node_table;
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
* File Name : tokenizer.js
* Created at : 2019-07-09
* Updated at : 2019-10-31
* Updated at : 2020-06-06
* Author : jeefo

@@ -24,2 +24,20 @@ * Purpose :

tokenizer.register({
id : "JeefoBinder",
priority : 41,
is : (current_character, streamer) => {
return current_character === '{' && streamer.is_next_character('{');
},
initialize : (token, character, streamer) => {
const start = streamer.clone_cursor_position();
streamer.cursor.move(1);
token.value = "{{";
token.start = start;
token.end = streamer.clone_cursor_position();
}
});
module.exports = tokenizer;
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
* File Name : interpreter.js
* Created at : 2019-06-30
* Updated at : 2020-03-08
* Updated at : 2020-06-11
* Author : jeefo

@@ -22,24 +22,32 @@ * Purpose :

const is_event_binder = ({event_binder}, prop) => {
return event_binder && prop in event_binder;
};
function find_controller (property, controllers, input_component) {
const build_script = ({ id, controller }) => {
const ctrl_name = `ctrl_${ id }`;
controllers[ctrl_name] = controller;
return `$ctrls.${ ctrl_name }.${ property }`;
};
if (is_event_binder(input_component, property)) {
controllers.event_binder = input_component.event_binder;
return `$ctrls.event_binder.${property}`;
}
const is_matched = ({ controller, controller_name }) => {
return (
property === controller_name ||
(controller && property in controller)
);
const build_script = ({ id, controller, controller_name }) => {
if (controller_name) {
if (controller_name === property) {
controllers[controller_name] = controller;
return `$ctrls.${controller_name}`;
}
} else if (controller && property in controller) {
const ctrl_name = `ctrl_${ id }`;
controllers[ctrl_name] = controller;
return `$ctrls.${ctrl_name}.${property}`;
}
};
const _find_controller = component => {
if (is_matched(component)) {
return build_script(component);
}
const script = build_script(component);
if (script) { return script; }
const directive = component.directives.find(is_matched);
if (directive) {
return build_script(directive);
for (const directive of component.directives) {
const script = build_script(directive);
if (script) { return script; }
}

@@ -58,6 +66,4 @@ };

if (window[property]) {
return build_script({
id : "global",
controller : window
});
controllers.__global = window;
return `$ctrls.__global.${property}`;
}

@@ -110,2 +116,6 @@ }

return `${ prop } : ${ value }`;
case "Positive plus operator" :
case "Negation minus operator" :
const { operator: {value: op}, expression } = node;
return `${op}${compile(expression, controllers, component)}`;
case "Logical not operator" :

@@ -166,2 +176,8 @@ return `! ${ compile(node.expression, controllers, component) }`;

}).join(" + ");
// DEBUG_START
case "Debugger statement" :
return node.keyword.value;
// DEBUG_END
default:

@@ -239,3 +255,5 @@ throw new Error(`Invalid AST_Node: '${ node.id }'`);

const last_stmt = compiled_stmts[last_index];
compiled_stmts[last_index] = `result = ${ last_stmt }`;
if (statements[statements.length - 1].id !== "Debugger statement") {
compiled_stmts[last_index] = `result = ${ last_stmt }`;
}

@@ -242,0 +260,0 @@ const code = build_fn_body(compiled_stmts);

{
"name": "@jeefo/component",
"version": "0.0.9",
"version": "0.0.10",
"homepage": "https://github.com/je3f0o/jeefo_component",

@@ -5,0 +5,0 @@ "copyright": "2019",

/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
* File Name : transclude_controller.js
* Created at : 2019-06-26
* Updated at : 2019-07-21
* Updated at : 2020-06-06
* Author : jeefo

@@ -18,29 +18,28 @@ * Purpose :

const Transcluder = require("./transcluder");
const Transcluder = require("./transcluder");
const JeefoDOMParser = require("./dom_parser");
function find_transcluders (nodes, parent_indices, transclude_controller) {
nodes.forEach((node, index) => {
const parent_position = parent_indices.concat();
parent_position.push(index);
function find_transcluders (elements, indices, transclude_controller) {
for (let i = 0; i < elements.length; i += 1) {
const element = elements[i];
indices.push(i);
if (node.name === "jf-content") {
const selector_name = node.attrs.get("select") || null;
transclude_controller.add(selector_name, parent_position);
} else if (node.children.length) {
find_transcluders(
node.children, parent_position, transclude_controller
);
if (element.tagName.toLowerCase() === "jf-content") {
const selector_name = element.getAttribute("select");
transclude_controller.add(selector_name, indices);
} else {
find_transcluders(element.children, indices, transclude_controller);
}
});
indices.pop();
}
}
class TranscludeController {
constructor (structure_nodes) {
this.structure_nodes = structure_nodes;
this.default_transcluder = null;
this.named_transcluders = [];
this.named_transcluders_map = Object.create(null);
constructor (markup = '') {
this.dom_parser = new JeefoDOMParser(markup);
this.named_transcluders = [];
this.default_transcluder = null;
if (structure_nodes.length) {
find_transcluders(structure_nodes, [], this);
if (this.dom_parser.elements.length) {
find_transcluders(this.dom_parser.elements, [], this);
} else {

@@ -53,19 +52,17 @@ this.default_transcluder = new Transcluder(null, []);

get (selector_name) {
return this.named_transcluders_map[selector_name] || null;
}
add (selector_name, indices) {
const transcluder = new Transcluder(selector_name, indices);
add (selector_name, parent_position) {
const transcluder = new Transcluder(selector_name, parent_position);
if (selector_name) {
if (this.named_transcluders_map[selector_name]) {
throw new Error(`Duplicated transcluder detected.`);
const named_transcluder = this.named_transcluders.find(t => {
return t.selector_name === selector_name;
});
if (named_transcluder) {
throw new Error("Duplicated transcluder detected.");
}
this.named_transcluders.push(transcluder);
this.named_transcluders_map[selector_name] = transcluder;
} else if (! this.default_transcluder) {
this.default_transcluder = transcluder;
} else {
throw new Error(`Ambigious transcluder detected.`);
throw new Error("Ambigious transcluder detected.");
}

@@ -75,29 +72,43 @@ }

// TODO: sort transcluders and transclude from behind
transclude (child_nodes) {
if (this.structure_nodes.length === 0) { return child_nodes; }
const nodes = this.structure_nodes.map(node => node.clone(true));
transclude (element) {
if (this.dom_parser.elements.length === 0) { return; }
if (child_nodes.length) {
child_nodes.forEach(child_node => {
const selector_name = child_node.name;
const named_transcluder = this.get(selector_name);
if (named_transcluder) {
named_transcluder.add_node(child_node);
} else if (this.default_transcluder) {
this.default_transcluder.add_node(child_node);
} else {
throw new Error("Transcluder is not found");
}
});
const body = this.dom_parser.document.body.cloneNode(true);
let i = this.named_transcluders.length;
while (i--) {
this.named_transcluders[i].transclude(nodes);
while (element.firstChild) {
const child = element.removeChild(element.firstChild);
let named_transcluder;
if (child.nodeType === Node.ELEMENT_NODE) {
named_transcluder = this.named_transcluders.find(t => {
return t.selector_name === child.tagName.toLowerCase();
});
}
if (this.default_transcluder) {
this.default_transcluder.transclude(nodes);
if (named_transcluder) {
named_transcluder.elements.push(child);
} else if (this.default_transcluder) {
this.default_transcluder.elements.push(child);
} else {
throw new Error("Transcluder is not found");
}
}
return nodes;
let i = this.named_transcluders.length;
while (i--) {
this.named_transcluders[i].set_placeholder(body);
}
if (this.default_transcluder) {
this.default_transcluder.set_placeholder(body);
}
i = this.named_transcluders.length;
while (i--) {
this.named_transcluders[i].transclude();
}
if (this.default_transcluder) {
this.default_transcluder.transclude();
}
while (body.firstChild) {
element.appendChild(body.firstChild);
}
}

@@ -104,0 +115,0 @@ }

/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
* File Name : transcluder.js
* Created at : 2017-08-26
* Updated at : 2019-07-21
* Updated at : 2020-06-05
* Author : jeefo

@@ -17,30 +17,33 @@ * Purpose :

const splice = Array.prototype.splice;
class Transcluder {
constructor (selector_name, parent_position) {
this.nodes = [];
this.selector_name = selector_name;
this.parent_position = parent_position;
constructor (selector_name, indices) {
this.indices = indices.concat();
this.elements = [];
this.placeholder = null;
this.selector_name = selector_name;
}
add_node (node) {
this.nodes.push(node);
}
transclude (structure_nodes) {
// TODO: replace this temporary solution
let parent_container = structure_nodes;
const length = this.parent_position.length - 1;
set_placeholder (parent_element) {
const length = this.indices.length - 1;
for (let i = 0; i < length; ++i) {
const index = this.parent_position[i];
parent_container = parent_container[index].children;
const index = this.indices[i];
parent_element = parent_element.children[index];
}
const args = [this.parent_position.last(), 1].concat(this.nodes);
splice.apply(parent_container, args);
this.nodes = [];
const index = this.indices[this.indices.length - 1];
this.placeholder = parent_element.children[index];
}
transclude () {
const parent_element = this.placeholder.parentNode;
while (this.elements.length) {
parent_element.insertBefore(
this.elements.pop(), this.placeholder.nextSibling
);
}
parent_element.removeChild(this.placeholder);
this.placeholder = null;
}
}
module.exports = Transcluder;
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