@jeefo/component
Advanced tools
Comparing version 0.0.10 to 0.0.11
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. | ||
* File Name : compiler.js | ||
* Created at : 2019-06-23 | ||
* Updated at : 2020-06-23 | ||
* Updated at : 2020-10-23 | ||
* Author : jeefo | ||
@@ -18,3 +18,3 @@ * Purpose : | ||
const JeefoDOMParser = require("./dom_parser"); | ||
const JeefoDOMParser = require("@jeefo/jqlite/dom_parser"); | ||
const definitions_table = require("./definitions_table"); | ||
@@ -41,5 +41,3 @@ const Directive = require("./components/directive"); | ||
if (def && def.is_structure) { | ||
if (definition && def.priority < definition.priority) { | ||
continue; | ||
} | ||
if (definition && def.priority < definition.priority) continue; | ||
name = attr.name; | ||
@@ -109,5 +107,3 @@ definition = def; | ||
element.setAttribute("jf-bind", element.textContent); | ||
if (! component) { | ||
component = new_binding_component(element, parent); | ||
} | ||
if (! component) component = new_binding_component(element, parent); | ||
} | ||
@@ -114,0 +110,0 @@ |
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. | ||
* File Name : component_definition.js | ||
* Created at : 2019-06-24 | ||
* Updated at : 2020-06-08 | ||
* Updated at : 2020-10-23 | ||
* Author : jeefo | ||
@@ -26,70 +26,86 @@ * Purpose : | ||
class ComponentDefinition extends IDefinition { | ||
constructor (selectors, path) { | ||
super(selectors, path); | ||
this.template_handler = null; | ||
this.transclude_controller = null; | ||
} | ||
const pendings = Object.create(null); | ||
async resolve () { | ||
const { | ||
type, style, template, controller, controller_name, | ||
bindings, dependencies = {} | ||
} = await jeefo.require(this.path); | ||
const _resolve = async instance => { | ||
const { | ||
type, style, template, controller, controller_name, | ||
bindings, dependencies = {} | ||
} = await jeefo.require(instance.path); | ||
// Type | ||
if (type) { | ||
if (type.toLowerCase() === "structure") { | ||
this.is_structure = true; | ||
} else { | ||
throw new SyntaxError("Invalid definition type"); | ||
} | ||
// Type | ||
if (type) { | ||
if (type.toLowerCase() === "structure") { | ||
instance.is_structure = true; | ||
} else { | ||
throw new SyntaxError("Invalid definition type"); | ||
} | ||
} | ||
// Style | ||
if (style) { | ||
const selectors = this.selectors.map(s => `"${s.toLowerCase()}"`); | ||
styles.add_style(style, { | ||
"component-selectors" : `[${ selectors.join(", ") }]` | ||
}); | ||
} | ||
// Style | ||
if (style) { | ||
const selectors = instance.selectors.map(s => `"${s.toLowerCase()}"`); | ||
styles.add_style(style, { | ||
"component-selectors" : `[${ selectors.join(", ") }]` | ||
}); | ||
} | ||
// Template | ||
if (typeof template === "string") { | ||
this.transclude_controller = new TranscludeController(template); | ||
} else if (typeof template === "function") { | ||
this.template_handler = template; | ||
} else { | ||
this.transclude_controller = new TranscludeController(); | ||
} | ||
// Template | ||
if (typeof template === "string") { | ||
instance.transclude_controller = new TranscludeController(template); | ||
} else if (typeof template === "function") { | ||
instance.template_handler = template; | ||
} else { | ||
instance.transclude_controller = new TranscludeController(); | ||
} | ||
// Conroller | ||
if (controller) { | ||
let Ctrl; | ||
if (typeof controller === "function") { | ||
if (is_class(controller)) { | ||
Ctrl = controller; | ||
} else { | ||
class Controller {} | ||
extend_member(Controller, "on_init", controller); | ||
Ctrl = Controller; | ||
} | ||
// Conroller | ||
if (controller) { | ||
let Ctrl; | ||
if (typeof controller === "function") { | ||
if (is_class(controller)) { | ||
Ctrl = controller; | ||
} else { | ||
class Controller {} | ||
object_for_each(controller, (key, value) => { | ||
extend_member(Controller, key, value); | ||
}); | ||
extend_member(Controller, "on_init", controller); | ||
Ctrl = Controller; | ||
} | ||
this.Controller = Ctrl; | ||
if (controller_name) { | ||
this.controller_name = controller_name; | ||
} | ||
} else { | ||
class Controller {} | ||
object_for_each(controller, (key, value) => { | ||
extend_member(Controller, key, value); | ||
}); | ||
Ctrl = Controller; | ||
} | ||
instance.Controller = Ctrl; | ||
if (controller_name) { | ||
instance.controller_name = controller_name; | ||
} | ||
} | ||
super.set_binders(bindings); | ||
super.set_dependencies(dependencies); | ||
this.is_resolved = true; | ||
return {bindings, dependencies}; | ||
}; | ||
class ComponentDefinition extends IDefinition { | ||
constructor (selectors, path) { | ||
super(selectors, path); | ||
this.template_handler = null; | ||
this.transclude_controller = null; | ||
} | ||
resolve () { | ||
if (pendings[this.selectors[0]]) { | ||
return pendings[this.selectors[0]]; | ||
} | ||
pendings[this.selectors[0]] = new Promise(async resolver => { | ||
const {bindings, dependencies} = await _resolve(this); | ||
super.set_binders(bindings); | ||
super.set_dependencies(dependencies); | ||
this.is_resolved = true; | ||
resolver(); | ||
}); | ||
return pendings[this.selectors[0]]; | ||
} | ||
transclude (element) { | ||
@@ -96,0 +112,0 @@ this.transclude_controller.transclude(element); |
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. | ||
* File Name : conditional_component.js | ||
* Created at : 2020-06-09 | ||
* Updated at : 2020-06-12 | ||
* Updated at : 2020-10-23 | ||
* Author : jeefo | ||
@@ -19,6 +19,6 @@ * Purpose : | ||
const jqlite = require("@jeefo/jqlite"); | ||
const JeefoDOMParser = require("@jeefo/jqlite/dom_parser"); | ||
const array_remove = require("@jeefo/utils/array/remove"); | ||
const compile = require("../compiler"); | ||
const IComponent = require("../interfaces/i_component"); | ||
const JeefoDOMParser = require("../dom_parser"); | ||
@@ -25,0 +25,0 @@ class ConditionalComponent extends IComponent { |
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. | ||
* File Name : invisible_component.js | ||
* Created at : 2020-06-08 | ||
* Updated at : 2020-06-12 | ||
* Updated at : 2020-10-23 | ||
* Author : jeefo | ||
@@ -25,5 +25,3 @@ * Purpose : | ||
this.parent = parent; | ||
if (parent) { | ||
parent.children.push(this); | ||
} | ||
if (parent) parent.children.push(this); | ||
} | ||
@@ -39,3 +37,3 @@ | ||
} | ||
if (this.is_destroyed) { return; } | ||
if (this.is_destroyed) return; | ||
} | ||
@@ -49,5 +47,3 @@ this.is_initialized = true; | ||
} | ||
for (const child of this.children) { | ||
await child.destroy(); | ||
} | ||
for (const child of this.children) await child.destroy(); | ||
array_remove(this.parent.children, this); | ||
@@ -59,5 +55,3 @@ this.is_destroyed = true; | ||
if (this.is_initialized) { | ||
for (const child of this.children) { | ||
await child.digest(); | ||
} | ||
for (const child of this.children) await child.digest(); | ||
} | ||
@@ -64,0 +58,0 @@ } |
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. | ||
* File Name : renderable_component.js | ||
* Created at : 2019-06-26 | ||
* Updated at : 2020-07-06 | ||
* Updated at : 2020-10-23 | ||
* Author : jeefo | ||
@@ -19,2 +19,3 @@ * Purpose : | ||
const jqlite = require("@jeefo/jqlite"); | ||
const debounce = require("@jeefo/utils/debounce"); | ||
const array_remove = require("@jeefo/utils/array/remove"); | ||
@@ -27,5 +28,5 @@ const IRenderable = require("../interfaces/i_renderable"); | ||
class EventBinder { | ||
constructor ($element) { | ||
this.$this = null; | ||
this.$event = null; | ||
constructor (instance, event, $element) { | ||
this.$this = instance; | ||
this.$event = event; | ||
this.$element = $element; | ||
@@ -35,2 +36,3 @@ } | ||
const DEBOUNCE_EVENT = /^(.+)\-debounce\-(\d+)$/; | ||
const JEEFO_BINDER_REGEX = /{{\s*\S+.*}}/m; | ||
@@ -45,2 +47,8 @@ | ||
const temp_event_binder = { | ||
$this : null, | ||
$event : null, | ||
$element : null, | ||
}; | ||
class RenderableComponent extends IRenderable { | ||
@@ -74,3 +82,3 @@ constructor (name, element, definition, parent) { | ||
const { DOM_element: element } = $element; | ||
const {DOM_element: element} = $element; | ||
@@ -91,3 +99,3 @@ // Step 1: bind events | ||
if (this.is_destroyed) { return; } | ||
if (this.is_destroyed) return; | ||
} | ||
@@ -106,3 +114,3 @@ } | ||
for (const dir of this.directives) { | ||
if (name === dir.name) { continue LOOP; } | ||
if (name === dir.name) continue LOOP; | ||
} | ||
@@ -127,3 +135,3 @@ | ||
await directive.initialize(this); | ||
if (this.is_destroyed) { return; } | ||
if (this.is_destroyed) return; | ||
} | ||
@@ -133,6 +141,4 @@ | ||
for (const child of this.children) { | ||
if (! child.is_destroyed) { | ||
await child.initialize(); | ||
} | ||
if (this.is_destroyed) { return; } | ||
if (! child.is_destroyed) await child.initialize(); | ||
if (this.is_destroyed) return; | ||
} | ||
@@ -197,27 +203,38 @@ | ||
const event_handler_factory = expression => function (event) { | ||
const event_handler_factory = expression => { | ||
// Event binder template cannot be binded component itself. | ||
const {parent} = self; | ||
const binder = parent.event_binder = new EventBinder($element); | ||
try { | ||
binder.$this = this; | ||
binder.$event = event; | ||
const interpreter = new Interpreter(expression, parent); | ||
interpreter.getter(interpreter.ctrls); | ||
/* | ||
const script = event_binder_template.replace("ANON_FN", () => { | ||
return interpreter.getter.toString(); | ||
}); | ||
// jshint evil:true | ||
interpreter.getter = new Function("this_arg", "$ctrls", script); | ||
// jshint evil:false | ||
interpreter.getter(self, interpreter.ctrls); | ||
*/ | ||
} catch (e) { | ||
console.error(e); | ||
} | ||
parent.event_binder = temp_event_binder; | ||
const interpreter = new Interpreter(expression, parent); | ||
return function (event) { | ||
try { | ||
const binder = new EventBinder(this, event, $element); | ||
interpreter.ctrls.event_binder = binder; | ||
interpreter.getter(interpreter.ctrls); | ||
/* | ||
const script = event_binder_template.replace("ANON_FN", () => { | ||
return interpreter.getter.toString(); | ||
}); | ||
// jshint evil:true | ||
interpreter.getter = new Function("this_arg", "$ctrls", script); | ||
// jshint evil:false | ||
interpreter.getter(self, interpreter.ctrls); | ||
*/ | ||
} catch (e) { | ||
console.error(e); | ||
} | ||
}; | ||
}; | ||
for (const {event_name, expression} of this.binding_events) { | ||
this.$element.on(event_name, event_handler_factory(expression)); | ||
for (let {event_name, expression} of this.binding_events) { | ||
const matches = event_name.match(DEBOUNCE_EVENT); | ||
let event_handler = event_handler_factory(expression); | ||
if (matches) { | ||
event_name = matches[1]; | ||
event_handler = debounce(event_handler, +(matches[2])); | ||
} | ||
this.$element.on(event_name, event_handler); | ||
} | ||
@@ -224,0 +241,0 @@ } |
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. | ||
* File Name : structure_component.js | ||
* Created at : 2019-06-26 | ||
* Updated at : 2020-06-12 | ||
* Updated at : 2020-10-23 | ||
* Author : jeefo | ||
@@ -53,5 +53,3 @@ * Purpose : | ||
// DEBUG_END | ||
for (const child of this.children) { | ||
await child.destroy(); | ||
} | ||
for (const child of this.children) await child.destroy(); | ||
array_remove(this.parent.children, this); | ||
@@ -66,5 +64,3 @@ this.is_destroyed = true; | ||
} | ||
for (const child of this.children) { | ||
await child.digest(); | ||
} | ||
for (const child of this.children) await child.digest(); | ||
} | ||
@@ -79,5 +75,3 @@ } | ||
// DEBUG_END | ||
for (const child of this.children) { | ||
child.trigger_render(); | ||
} | ||
for (const child of this.children) child.trigger_render(); | ||
this.is_rendered = true; | ||
@@ -84,0 +78,0 @@ } |
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. | ||
* File Name : directive_definition.js | ||
* Created at : 2017-08-07 | ||
* Updated at : 2020-06-08 | ||
* Updated at : 2020-10-23 | ||
* Author : jeefo | ||
@@ -6,0 +6,0 @@ * Purpose : |
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. | ||
* File Name : for_each.js | ||
* Created at : 2017-07-25 | ||
* Updated at : 2020-06-22 | ||
* Updated at : 2020-10-23 | ||
* Author : jeefo | ||
@@ -60,8 +60,14 @@ * Purpose : | ||
async function create_new_child (value, index, component) { | ||
const { element, variable_name, index_name } = component; | ||
const {element, variable_name, index_name} = component; | ||
const wrapper = await new ConditionalComponent("foreach--wrapper", element); | ||
wrapper.controller = new ForEachElement(); | ||
wrapper.index = wrapper.controller[index_name] = index; | ||
wrapper.value = wrapper.controller[variable_name] = value; | ||
wrapper.index = index; | ||
wrapper.value = value; | ||
Object.defineProperty(wrapper.controller, index_name, { | ||
get: () => wrapper.index, | ||
}); | ||
Object.defineProperty(wrapper.controller, variable_name, { | ||
get: () => wrapper.value, | ||
}); | ||
@@ -82,5 +88,5 @@ return wrapper; | ||
async function sync_children (instance) { | ||
const values = instance[values_prop]; | ||
const component = instance[comp_prop]; | ||
const { children } = component; | ||
const values = instance[values_prop]; | ||
const component = instance[comp_prop]; | ||
const {children} = component; | ||
@@ -96,2 +102,3 @@ let is_dirty = false; | ||
component.is_syncing = true; | ||
OUTER_LOOP: | ||
while (! is_synced(values, children) && ! is_canceled) { | ||
@@ -105,3 +112,3 @@ is_dirty = true; | ||
if (i < children.length) { | ||
if (children[i].value === value) { continue; } | ||
if (children[i].value === value) continue; | ||
@@ -117,2 +124,3 @@ for (let j = i + 1; j < children.length; j += 1) { | ||
const new_child = await create_new_child(value, i, component); | ||
if (is_canceled) break OUTER_LOOP; | ||
children.splice(i, 0, new_child); | ||
@@ -125,2 +133,3 @@ new_child.parent = component; | ||
await Promise.all(dead_children.map(c => c.destroy())); | ||
if (is_canceled) break OUTER_LOOP; | ||
} | ||
@@ -131,3 +140,3 @@ | ||
if (! child.is_initialized) await child.initialize(); | ||
if (is_canceled) break; | ||
if (is_canceled) break OUTER_LOOP; | ||
} | ||
@@ -166,8 +175,6 @@ } | ||
component.interpreter = new Interpreter(script, component); | ||
if (expr.left.id !== "Primary expression") { | ||
throw new Error("Invalid left hand side expression"); | ||
} | ||
switch (expr.left.expression.id) { | ||
switch (expr.left.id) { | ||
case "Identifier reference" : | ||
component.variable_name = expr.left.expression.value; | ||
const {identifier: {identifier_name: id}} = expr.left; | ||
component.variable_name = id.value; | ||
break; | ||
@@ -179,3 +186,3 @@ default: | ||
const comment = ` For each: ${ component.expression } `; | ||
const comment = ` For each: ${component.expression} `; | ||
$element.replace(document.createComment(comment)); | ||
@@ -202,3 +209,3 @@ component.$placeholder = $element; | ||
if (component.is_syncing) { | ||
// TODO: Maybe i need to make a waiting list for make sure | ||
// TODO: Maybe i need to make a waiting list queue for make sure | ||
// multiple digest methods not collide after canceled... | ||
@@ -209,13 +216,25 @@ await component.cancel_syncing(); | ||
try { | ||
const is_changed = await sync_children(this); | ||
if (! is_changed) return; | ||
await sync_children(this); | ||
const {index_name} = component; | ||
const move = (index, child) => { | ||
const {index: old_index} = child; | ||
const move = (index, child) => { | ||
const a = children[index].$element.DOM_element; | ||
const b = children[old_index].$element.DOM_element; | ||
const temp = new Comment("temp"); | ||
a.parentNode.insertBefore(temp, a); | ||
b.parentNode.insertBefore(a, b); | ||
temp.parentNode.insertBefore(b, temp); | ||
temp.parentNode.removeChild(temp); | ||
child.index = index; | ||
children[old_index].index = old_index; | ||
}; | ||
const insert = (index, child) => { | ||
if (index === 0) { | ||
$placeholder.after(child.$element); | ||
} else { | ||
const prev = children[index - 1]; | ||
prev.$element.after(child.$element); | ||
children[index - 1].$element.after(child.$element); | ||
} | ||
@@ -226,3 +245,3 @@ }; | ||
if (! child.is_attached) { | ||
move(index, child); | ||
insert(index, child); | ||
child.is_attached = true; | ||
@@ -232,8 +251,9 @@ } else if (child.index !== index) { | ||
old_index : child.index, | ||
new_index : index | ||
old_value : child.value, | ||
new_index : index, | ||
new_value : null, | ||
}; | ||
move(index, child); | ||
child.index = child.controller[index_name] = index; | ||
if (child.is_rendered) { | ||
child.$element.trigger("foreach:move", { data }); | ||
child.$element.trigger("foreach:move", {data}); | ||
} | ||
@@ -240,0 +260,0 @@ } |
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. | ||
* File Name : if.js | ||
* Created at : 2017-09-17 | ||
* Updated at : 2020-06-12 | ||
* Updated at : 2020-10-23 | ||
* Author : jeefo | ||
@@ -35,3 +35,3 @@ * Purpose : | ||
$comment.after(wrapper.$element); | ||
if (component.is_rendered) { wrapper.trigger_render(); } | ||
if (component.is_rendered) wrapper.trigger_render(); | ||
} | ||
@@ -38,0 +38,0 @@ } |
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. | ||
* File Name : jf_bind.js | ||
* Created at : 2017-07-26 | ||
* Updated at : 2020-06-11 | ||
* Updated at : 2020-10-23 | ||
* Author : jeefo | ||
@@ -25,3 +25,3 @@ * Purpose : | ||
break; | ||
case "null" : | ||
case null : | ||
$element.text = "null"; | ||
@@ -28,0 +28,0 @@ break; |
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. | ||
* File Name : switch.js | ||
* Created at : 2019-07-12 | ||
* Updated at : 2020-06-12 | ||
* Updated at : 2020-10-23 | ||
* Author : jeefo | ||
@@ -62,3 +62,3 @@ * Purpose : | ||
const node = element.childNodes[i]; | ||
if (! is_element(node)) { continue; } | ||
if (! is_element(node)) continue; | ||
@@ -91,3 +91,3 @@ if (node.hasAttribute("case")) { | ||
component.is_initialized = true; | ||
compile_self(component); | ||
await compile_self(component); | ||
@@ -94,0 +94,0 @@ this[prop_component] = component; |
11
index.js
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. | ||
* File Name : index.js | ||
* Created at : 2017-08-08 | ||
* Updated at : 2020-06-09 | ||
* Updated at : 2020-10-23 | ||
* Author : jeefo | ||
@@ -28,4 +28,5 @@ * Purpose : | ||
"jf_class", | ||
"jf_bind_html", | ||
].forEach(filename => { | ||
const path = `${ __dirname }/directives/${ filename }`; | ||
const path = `${__dirname}/directives/${filename}`; | ||
const selector = filename.replace(REGEX_UNDERLINE, '-'); | ||
@@ -35,3 +36,3 @@ definitions_table.register_directive(selector, path); | ||
const switch_placeholder_path = `${ __dirname }/directives/switch_placeholder`; | ||
const switch_placeholder_path = `${__dirname}/directives/switch_placeholder`; | ||
definitions_table.register_component( | ||
@@ -42,2 +43,3 @@ "switch-placeholder", switch_placeholder_path | ||
module.exports = { | ||
compile : require("./compiler"), | ||
IComponent : require("./interfaces/i_component"), | ||
@@ -51,6 +53,3 @@ IRenderable : require("./interfaces/i_renderable"), | ||
compile : require("./compiler"), | ||
JeefoDOMParser : require("./dom_parser"), | ||
definitions_table | ||
}; |
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. | ||
* File Name : ast_node_table.js | ||
* Created at : 2017-09-18 | ||
* Updated at : 2020-06-11 | ||
* Updated at : 2020-10-23 | ||
* Author : jeefo | ||
@@ -29,2 +29,5 @@ * Purpose : | ||
} = require("@jeefo/ecma_parser/es6/enums/states_enum"); | ||
const { | ||
get_last_non_comment_node, | ||
} = require("@jeefo/ecma_parser/helpers"); | ||
@@ -36,3 +39,3 @@ const ast_node_table = new AST_Node_Table(); | ||
const initialize = node => { | ||
throw new Error(`'${ node.id }' cannot be initialized`); | ||
throw new Error(`'${node.id}' cannot be initialized`); | ||
}; | ||
@@ -47,3 +50,3 @@ | ||
for (let path of operators) { | ||
require(`${ proj_dir }/${ path }`)(ast_node_table); | ||
require(`${proj_dir}/${path}`)(ast_node_table); | ||
} | ||
@@ -53,3 +56,6 @@ | ||
// 11.6.2.1 - Keywords | ||
"es8/terminals/keyword", | ||
"es8/identifiers/keyword", | ||
"es8/identifiers/identifier", | ||
"es8/identifiers/identifier_name", | ||
// 11.7 - Punctuators | ||
@@ -61,5 +67,3 @@ "es8/terminals/punctuator", | ||
// -------------------------- | ||
"es8/expressions/primary_expression", | ||
// 12.1 - Identifiers | ||
"es5/expressions/identifier_name", | ||
"es8/expressions/binding_identifier", | ||
@@ -73,3 +77,2 @@ "es8/expressions/identifier_reference", | ||
"es6/literals/array_literal", | ||
"es5/expressions/elision", | ||
// 12.2.6 - Object literal | ||
@@ -81,3 +84,3 @@ "es6/literals/object_literal", | ||
"es6/expressions/cover_initialized_name", | ||
"es6/expressions/computed_property_name", | ||
"es5/expressions/computed_member_expression", | ||
"es6/expressions/property_definition", | ||
@@ -96,9 +99,5 @@ | ||
// --------------------------------- | ||
"es8/expressions/new_expression", | ||
"es8/expressions/member_expression", | ||
"es8/binary_operators/member_operator", | ||
"es8/expressions/left_hand_side_expression", | ||
"es8/operators/member_operator", | ||
// 12.3.4 - Function calls | ||
"es8/expressions/super_call", | ||
"es8/expressions/call_expression", | ||
"es8/expressions/function_call_expression", | ||
@@ -117,3 +116,3 @@ // 12.3.6 - Arguments | ||
"es8/expressions/assignment_expression", | ||
"es8/binary_operators/assignment_operator", | ||
"es8/operators/assignment_operator", | ||
// 12.15.5 - Destructuring assignment | ||
@@ -137,3 +136,2 @@ // array | ||
"es5/expressions/expression", | ||
"es5/expressions/sequence_expression", | ||
@@ -162,2 +160,4 @@ // 13....... - Expression statement | ||
ast_node_table.register_reserved_words(["true", "false"], bool); | ||
const _new = require(`${ proj_dir }/es8/expressions/new_expression`); | ||
ast_node_table.register_reserved_word("new", _new); | ||
@@ -284,4 +284,6 @@ // Jeefo binder | ||
parser.prepare_next_state("expression", true); | ||
const expression = parser.parse_next_node(TERMINATION); | ||
parser.parse_next_node(TERMINATION); | ||
const expr = get_last_non_comment_node(parser, true); | ||
parser.end(expr); | ||
parser.prepare_next_state("punctuator"); | ||
parser.expect("}}", () => { | ||
@@ -292,5 +294,6 @@ return parser.next_token.id === "Delimiter" && | ||
}); | ||
parser.is_terminated = false; | ||
streamer.cursor.move(1); | ||
node.expression = expression; | ||
node.expression = expr; | ||
node.start = start; | ||
@@ -297,0 +300,0 @@ node.end = streamer.clone_cursor_position(); |
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. | ||
* File Name : tokenizer.js | ||
* Created at : 2019-07-09 | ||
* Updated at : 2020-06-06 | ||
* Updated at : 2020-10-23 | ||
* Author : jeefo | ||
@@ -6,0 +6,0 @@ * Purpose : |
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. | ||
* File Name : i_definition.js | ||
* Created at : 2019-07-05 | ||
* Updated at : 2020-06-08 | ||
* Updated at : 2020-10-23 | ||
* Author : jeefo | ||
@@ -21,2 +21,3 @@ * Purpose : | ||
const {getOwnPropertySymbols} = Object; | ||
const CAPTURE_DEPENDENCY_REGEX = /^([\^\?]+)?(.+)$/; | ||
@@ -69,3 +70,3 @@ | ||
}); | ||
Object.getOwnPropertySymbols(bindings).forEach(symbol => { | ||
getOwnPropertySymbols(bindings).forEach(symbol => { | ||
const value = bindings[symbol]; | ||
@@ -83,3 +84,3 @@ const operator = value.charAt(0); | ||
}); | ||
Object.getOwnPropertySymbols(dependencies).forEach(symbol => { | ||
getOwnPropertySymbols(dependencies).forEach(symbol => { | ||
const dependency_str = dependencies[symbol]; | ||
@@ -86,0 +87,0 @@ this.dependencies.push(parse_dependency(dependency_str, symbol)); |
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. | ||
* File Name : i_renderable.js | ||
* Created at : 2020-06-08 | ||
* Updated at : 2020-07-06 | ||
* Updated at : 2020-10-23 | ||
* Author : jeefo | ||
@@ -70,7 +70,7 @@ * Purpose : | ||
this.binders.forEach(({ property, operator, attribute_name }) => { | ||
if (! element.hasAttribute(attribute_name)) { return; } | ||
if (! element.hasAttribute(attribute_name)) return; | ||
const script = element.getAttribute(attribute_name).trim(); | ||
element.removeAttribute(attribute_name); | ||
if (! script) { return; } | ||
if (! script) return; | ||
@@ -118,5 +118,3 @@ let interpreter; | ||
observe (property, notify_handler) { | ||
if (! this.observer) { | ||
this.observer = new Observer(this.controller); | ||
} | ||
if (! this.observer) this.observer = new Observer(this.controller); | ||
this.observer.on(property, notify_handler); | ||
@@ -123,0 +121,0 @@ } |
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. | ||
* File Name : interpreter.js | ||
* Created at : 2019-06-30 | ||
* Updated at : 2020-06-11 | ||
* Updated at : 2020-10-23 | ||
* Author : jeefo | ||
@@ -23,3 +23,3 @@ * Purpose : | ||
const is_event_binder = ({event_binder}, prop) => { | ||
return event_binder && prop in event_binder; | ||
return event_binder && event_binder.hasOwnProperty(prop); | ||
}; | ||
@@ -81,15 +81,14 @@ | ||
case "Property name" : | ||
case "New expression" : | ||
case "Call expression" : | ||
case "Member expression" : | ||
case "Primary expression" : | ||
case "Assignment expression" : | ||
case "Left hand side expression" : | ||
return compile(node.expression, controllers, component); | ||
case "New expression" : | ||
console.log("Hello ???"); | ||
console.log(node); | ||
debugger; | ||
break; | ||
case "String literal" : | ||
const { quote } = node; | ||
return `${ quote }${ node.value }${ quote }`; | ||
return `${node.quote}${node.value}${node.quote}`; | ||
case "Identifier reference" : | ||
const script = find_controller( | ||
node.value, controllers, component | ||
node.identifier.identifier_name.value, controllers, component | ||
); | ||
@@ -115,3 +114,3 @@ if (! script) { | ||
const value = compile(node.expression, controllers, component); | ||
return `${ prop } : ${ value }`; | ||
return `${prop} : ${value}`; | ||
case "Positive plus operator" : | ||
@@ -122,55 +121,60 @@ case "Negation minus operator" : | ||
case "Logical not operator" : | ||
return `! ${ compile(node.expression, controllers, component) }`; | ||
case "Logical or operator" : | ||
case "Logical and operator" : | ||
const left = compile(node.left, controllers, component); | ||
const right = compile(node.right, controllers, component); | ||
return `${ left } ${ node.operator.value } ${ right }`; | ||
case "Conditional operator" : | ||
const falsy = compile( | ||
node.falsy_expression, controllers, component | ||
); | ||
const truthy = compile( | ||
node.truthy_expression, controllers, component | ||
); | ||
const condition = compile(node.condition, controllers, component); | ||
return `${ condition } ? ${ truthy } : ${ falsy }`; | ||
return `! ${compile(node.expression, controllers, component)}`; | ||
case "Member operator" : { | ||
const object = compile(node.object, controllers, component); | ||
return `${ object }.${ node.property.value }`; | ||
return `${object}.${node.property.value}`; | ||
} | ||
case "Computed member expression" : { | ||
debugger | ||
const object = compile( | ||
node.object, controllers, component, is_member); | ||
const expression = compile( | ||
node.expression, controllers, component); | ||
return `${ object }[${ expression }]`; | ||
const object = compile(node.object, controllers, component); | ||
const expr = compile(node.member, controllers, component); | ||
return `${object}[${expr}]`; | ||
} | ||
case "Equality operator" : | ||
case "Arithmetic operator" : | ||
case "Assignment operator" : | ||
case "Comparision operator" : { | ||
// Conditional expression | ||
case "Conditional operator" : | ||
let { | ||
condition, | ||
falsy_expression : falsy, | ||
truthy_expression : truthy, | ||
} = node; | ||
falsy = compile(falsy, controllers, component); | ||
truthy = compile(truthy, controllers, component); | ||
condition = compile(condition, controllers, component); | ||
return `${condition} ? ${truthy} : ${falsy}`; | ||
// Binary operators | ||
case "Assignment operator" : | ||
case "Logical or operator" : | ||
case "Logical and operator" : | ||
case "Bitwise or operator" : | ||
case "Bitwise xor operator" : | ||
case "Bitwise and operator" : | ||
case "Equality operator" : | ||
case "Relational operator" : | ||
case "Bitwise shift operator" : | ||
case "Additive operator" : | ||
case "Multiplicative operator" : | ||
case "Exponentiation operator" : | ||
case "Relational in operator" : | ||
case "Relational instanceof operator" : { | ||
const left = compile(node.left , controllers, component); | ||
const right = compile(node.right, controllers, component); | ||
return `${ left } ${ node.operator.value } ${ right }`; | ||
return `${left} ${node.operator.value} ${right}`; | ||
} | ||
case "Function call expression" : | ||
const callee = compile( | ||
node.callee, controllers, component); | ||
const args = node.arguments.list.map(arg => { | ||
return compile(arg, controllers, component); | ||
}); | ||
return `${ callee }(${ args.join(", ") })`; | ||
const callee = compile(node.callee, controllers, component); | ||
const args = node.arguments.list.map(arg => compile( | ||
arg, controllers, component | ||
)); | ||
return `${callee}(${args.join(", ")})`; | ||
case "Expression statement" : | ||
return compile(node.expression, controllers, component); | ||
case "Template literal" : | ||
return node.body.map(element => { | ||
if (element.id === "Template literal string") { | ||
return `"${ element.value }"`; | ||
} | ||
const expr = compile( | ||
element.expression, controllers, component | ||
); | ||
return `(${ expr })`; | ||
return node.body.map(({id, expression, value}) => { | ||
if (id === "Template literal string") return `"${value}"`; | ||
const expr = compile(expression, controllers, component); | ||
return `(${expr})`; | ||
}).join(" + "); | ||
@@ -189,14 +193,9 @@ | ||
const build_setter = (stmt, controllers, component) => { | ||
const has_error_occurred = ( | ||
stmt.length !== 1 || | ||
stmt[0].id !== "Expression statement" || | ||
stmt[0].expression.id !== "Primary expression" | ||
); | ||
if (has_error_occurred) { | ||
if (stmt.length !== 1 || stmt[0].id !== "Expression statement") { | ||
throw new Error("Invalid expression in two way bindings"); | ||
} | ||
let lvalue; | ||
const expression = stmt[0].expression.expression; | ||
const expr = stmt[0].expression; | ||
switch (expression.id) { | ||
switch (expr.id) { | ||
case "Null literal" : | ||
@@ -208,5 +207,4 @@ case "String literal" : | ||
case "Identifier reference" : { | ||
const property = expression.value; | ||
lvalue = find_controller( | ||
property, controllers, component | ||
expr.identifier.identifier_name.value, controllers, component | ||
); | ||
@@ -223,7 +221,7 @@ break; | ||
throw new Error( | ||
`Invalid AST_Node in two way bindings: '${ expression.id }'` | ||
`Invalid AST_Node in two way bindings: '${expr.id}'` | ||
); | ||
} | ||
const fn_body = `${ lvalue } = value;`; | ||
const fn_body = `${lvalue} = value;`; | ||
return new Function("$ctrls", "value", fn_body); // jshint ignore:line | ||
@@ -230,0 +228,0 @@ }; |
{ | ||
"name": "@jeefo/component", | ||
"version": "0.0.10", | ||
"version": "0.0.11", | ||
"homepage": "https://github.com/je3f0o/jeefo_component", | ||
"copyright": "2019", | ||
"description": "Part of jeefo framework.", | ||
"description": "One of core modules of jeefo framework. (under development...)", | ||
"author": { | ||
@@ -8,0 +8,0 @@ "name": "je3f0o", |
@@ -1,1 +0,1 @@ | ||
@jeefo/component part of jeefo framework. | ||
One of core modules of jeefo framework. (under development...) |
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. | ||
* File Name : transclude_controller.js | ||
* Created at : 2019-06-26 | ||
* Updated at : 2020-06-06 | ||
* Updated at : 2020-10-23 | ||
* Author : jeefo | ||
@@ -19,5 +19,27 @@ * Purpose : | ||
const Transcluder = require("./transcluder"); | ||
const JeefoDOMParser = require("./dom_parser"); | ||
const JeefoDOMParser = require("@jeefo/jqlite/dom_parser"); | ||
function find_transcluders (elements, indices, transclude_controller) { | ||
class DefaultTranscluder { | ||
constructor (transcluder) { | ||
this.elements = transcluder ? transcluder.elements : []; | ||
this.transcluder = transcluder; | ||
} | ||
set_placeholder (body) { | ||
this.transcluder && this.transcluder.set_placeholder(body); | ||
} | ||
transclude (parent_element) { | ||
if (this.transcluder) { | ||
this.transcluder.transclude(parent_element); | ||
} else for (const e of this.elements) parent_element.appendChild(e); | ||
} | ||
} | ||
const template_elems = ["JF-CONTENT", "JF-TEMPLATE"]; | ||
const is_default_transcluder = ({selector_type, tag_name}) => | ||
selector_type === Node.ELEMENT_NODE && template_elems.includes(tag_name); | ||
function find_transcluders (elements, indices, instance) { | ||
for (let i = 0; i < elements.length; i += 1) { | ||
@@ -27,7 +49,22 @@ const element = elements[i]; | ||
if (element.tagName.toLowerCase() === "jf-content") { | ||
const selector_name = element.getAttribute("select"); | ||
transclude_controller.add(selector_name, indices); | ||
if (template_elems.includes(element.tagName)) { | ||
const transcluder = new Transcluder(element, indices); | ||
if (is_default_transcluder(transcluder)) { | ||
if (instance.default_transcluder) { | ||
throw new Error("Ambigious transcluder detected."); | ||
} | ||
instance.default_transcluder = new DefaultTranscluder( | ||
transcluder | ||
); | ||
} else { | ||
const found = instance.transcluders.find(t => { | ||
return t.tag_name === transcluder.tag_name && | ||
t.selector_type === transcluder.selector_type; | ||
}); | ||
if (found) throw new Error("Duplicated transcluder detected."); | ||
instance.transcluders.push(transcluder); | ||
} | ||
} else { | ||
find_transcluders(element.children, indices, transclude_controller); | ||
find_transcluders(element.children, indices, instance); | ||
} | ||
@@ -40,37 +77,14 @@ indices.pop(); | ||
constructor (markup = '') { | ||
this.dom_parser = new JeefoDOMParser(markup); | ||
this.named_transcluders = []; | ||
this.default_transcluder = null; | ||
this.dom_parser = new JeefoDOMParser(markup); | ||
this.transcluders = []; | ||
if (this.dom_parser.elements.length) { | ||
find_transcluders(this.dom_parser.elements, [], this); | ||
} else { | ||
this.default_transcluder = new Transcluder(null, []); | ||
this.default_transcluder = new DefaultTranscluder(); | ||
} | ||
// TODO: sort transcluders here | ||
} | ||
add (selector_name, indices) { | ||
const transcluder = new Transcluder(selector_name, indices); | ||
if (selector_name) { | ||
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); | ||
} else if (! this.default_transcluder) { | ||
this.default_transcluder = transcluder; | ||
} else { | ||
throw new Error("Ambigious transcluder detected."); | ||
} | ||
} | ||
// TODO: sort transcluders and transclude from behind | ||
transclude (element) { | ||
if (this.dom_parser.elements.length === 0) { return; } | ||
const body = this.dom_parser.document.body.cloneNode(true); | ||
@@ -80,10 +94,10 @@ | ||
const child = element.removeChild(element.firstChild); | ||
let named_transcluder; | ||
let transcluder; | ||
if (child.nodeType === Node.ELEMENT_NODE) { | ||
named_transcluder = this.named_transcluders.find(t => { | ||
return t.selector_name === child.tagName.toLowerCase(); | ||
transcluder = this.transcluders.find(t => { | ||
return t.tag_name === child.tagName; | ||
}); | ||
} | ||
if (named_transcluder) { | ||
named_transcluder.elements.push(child); | ||
if (transcluder) { | ||
transcluder.elements.push(child); | ||
} else if (this.default_transcluder) { | ||
@@ -96,6 +110,3 @@ this.default_transcluder.elements.push(child); | ||
let i = this.named_transcluders.length; | ||
while (i--) { | ||
this.named_transcluders[i].set_placeholder(body); | ||
} | ||
for (const t of this.transcluders) t.set_placeholder(body); | ||
if (this.default_transcluder) { | ||
@@ -105,13 +116,6 @@ 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(); | ||
} | ||
for (const t of this.transcluders) t.transclude(); | ||
this.default_transcluder && this.default_transcluder.transclude(); | ||
while (body.firstChild) { | ||
element.appendChild(body.firstChild); | ||
} | ||
while (body.firstChild) element.appendChild(body.firstChild); | ||
} | ||
@@ -118,0 +122,0 @@ } |
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. | ||
* File Name : transcluder.js | ||
* Created at : 2017-08-26 | ||
* Updated at : 2020-06-05 | ||
* Updated at : 2020-10-23 | ||
* Author : jeefo | ||
@@ -17,8 +17,20 @@ * Purpose : | ||
const ATTRIBUTE_SELECTOR = "select"; | ||
class Transcluder { | ||
constructor (selector_name, indices) { | ||
this.indices = indices.concat(); | ||
this.elements = []; | ||
this.placeholder = null; | ||
this.selector_name = selector_name; | ||
constructor (element, indices) { | ||
this.indices = indices.concat(); | ||
this.elements = []; | ||
this.css_class = element.classList.value; | ||
this.attributes = element.attributes; | ||
if (element.hasAttribute(ATTRIBUTE_SELECTOR)) { | ||
const selector = element.getAttribute(ATTRIBUTE_SELECTOR); | ||
this.tag_name = selector.toUpperCase(); | ||
this.selector_type = Node.ATTRIBUTE_NODE; | ||
element.removeAttribute(ATTRIBUTE_SELECTOR); | ||
} else { | ||
this.tag_name = element.tagName; | ||
this.selector_type = Node.ELEMENT_NODE; | ||
} | ||
} | ||
@@ -29,8 +41,8 @@ | ||
for (let i = 0; i < length; ++i) { | ||
const index = this.indices[i]; | ||
const index = this.indices[i]; | ||
parent_element = parent_element.children[index]; | ||
} | ||
const index = this.indices[this.indices.length - 1]; | ||
this.placeholder = parent_element.children[index]; | ||
const last_index = this.indices[this.indices.length - 1]; | ||
this.placeholder = parent_element.children[last_index]; | ||
} | ||
@@ -41,8 +53,10 @@ | ||
while (this.elements.length) { | ||
parent_element.insertBefore( | ||
this.elements.pop(), this.placeholder.nextSibling | ||
); | ||
const element = this.elements.pop(); | ||
if (this.css_class) element.classList.value = this.css_class; | ||
for (const attr of this.attributes) { | ||
element.setAttribute(attr.name, attr.value); | ||
} | ||
parent_element.insertBefore(element, this.placeholder.nextSibling); | ||
} | ||
parent_element.removeChild(this.placeholder); | ||
this.placeholder = null; | ||
} | ||
@@ -49,0 +63,0 @@ } |
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
101686
2849
9