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

paramax-framework

Package Overview
Dependencies
Maintainers
0
Versions
14
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

paramax-framework - npm Package Compare versions

Comparing version 1.0.5 to 1.0.6

1164

dist/fe-fwk.js

@@ -0,4 +1,71 @@

function setAttributes(el, attrs) {
const { class: className, style, ...otherAttrs } = attrs;
delete otherAttrs.key;
if (className) {
setClass(el, className);
}
if (style) {
Object.entries(style).forEach(([prop, value]) => {
setStyle(el, prop, value);
});
}
for (const [name, value] of Object.entries(otherAttrs)) {
setAttribute(el, name, value);
}
}
function setAttribute(el, name, value) {
if (value == null) {
removeAttribute(el, name);
} else if (name.startsWith('data-')) {
el.setAttribute(name, value);
} else {
el[name] = value;
}
}
function setClass(el, className) {
el.className = '';
if (typeof className === 'string') {
el.className = className;
}
if (Array.isArray(className)) {
el.classList.add(...className);
}
}
function setStyle(el, name, value) {
el.style[name] = value;
}
function removeStyle(el, name) {
el.style[name] = null;
}
function removeAttribute(el, name) {
try {
el[name] = null;
} catch {
console.warn(`Failed to set "${name}" to null on ${el.tagName}`);
}
el.removeAttribute(name);
}
function addEventListener(eventName, handler, el, hostComponent = null) {
function boundHandler(event) {
event.preventDefault();
event.stopPropagation();
hostComponent
? handler.apply(hostComponent, arguments)
: handler(...arguments);
}
el.addEventListener(eventName, boundHandler);
return boundHandler;
}
function addEventListeners(listeners = {}, el, hostComponent = null) {
const addedListeners = {};
Object.entries(listeners).forEach(([eventName, handler]) => {
const listener = addEventListener(eventName, handler, el, hostComponent);
addedListeners[eventName] = listener;
});
return addedListeners;
}
function removeEventListeners(listeners = {}, el) {
Object.entries(listeners).forEach(([eventName, handler]) => {
el.removeEventListener(eventName, handler);
el.removeEventListener(eventName, handler);
});

@@ -8,5 +75,145 @@ }

function withoutNulls(arr) {
return arr.filter((item) => item != null)
return arr.filter((item) => item != null);
}
function arraysDiff(oldArray, newArray) {
return {
added: newArray.filter((newItem) => !oldArray.includes(newItem)),
removed: oldArray.filter((oldItem) => !newArray.includes(oldItem)),
};
}
const ARRAY_DIFF_OP = {
ADD: "add",
REMOVE: "remove",
MOVE: "move",
NOOP: "noop",
};
function arraysDiffSequence(
oldArray,
newArray,
equalsFn = (a, b) => a === b
) {
const sequence = [];
const array = new ArrayWithOriginalIndices(oldArray, equalsFn);
for (let index = 0; index < newArray.length; index++) {
if (array.isRemoval(index, newArray)) {
sequence.push(array.removeItem(index));
index--;
continue;
}
if (array.isNoop(index, newArray)) {
sequence.push(array.noopItem(index));
continue;
}
const item = newArray[index];
if (array.isAddition(item, index)) {
sequence.push(array.addItem(item, index));
continue;
}
sequence.push(array.moveItem(item, index));
}
sequence.push(...array.removeItemsAfter(newArray.length));
return sequence;
}
class ArrayWithOriginalIndices {
#array = [];
#originalIndices = [];
#equalsFn;
constructor(array, equalsFn) {
this.#array = [...array];
this.#originalIndices = array.map((_, i) => i);
this.#equalsFn = equalsFn;
}
get length() {
return this.#array.length;
}
originalIndexAt(index) {
return this.#originalIndices[index];
}
findIndexFrom(item, fromIndex) {
for (let i = fromIndex; i < this.length; i++) {
if (this.#equalsFn(item, this.#array[i])) {
return i;
}
}
return -1;
}
isRemoval(index, newArray) {
if (index >= this.length) {
return false;
}
const item = this.#array[index];
const indexInNewArray = newArray.findIndex((newItem) =>
this.#equalsFn(item, newItem)
);
return indexInNewArray === -1;
}
removeItem(index) {
const operation = {
op: ARRAY_DIFF_OP.REMOVE,
index,
item: this.#array[index],
};
this.#array.splice(index, 1);
this.#originalIndices.splice(index, 1);
return operation;
}
isNoop(index, newArray) {
if (index >= this.length) {
return false;
}
const item = this.#array[index];
const newItem = newArray[index];
return this.#equalsFn(item, newItem);
}
noopItem(index) {
return {
op: ARRAY_DIFF_OP.NOOP,
index,
originalIndex: this.originalIndexAt(index),
item: this.#array[index],
};
}
isAddition(item, fromIdx) {
return this.findIndexFrom(item, fromIdx) === -1;
}
addItem(item, index) {
const operation = {
op: ARRAY_DIFF_OP.ADD,
index,
item,
};
this.#array.splice(index, 0, item);
this.#originalIndices.splice(index, 0, -1);
return operation;
}
moveItem(item, toIndex) {
const fromIndex = this.findIndexFrom(item, toIndex);
const operation = {
op: ARRAY_DIFF_OP.MOVE,
originalIndex: this.originalIndexAt(fromIndex),
from: fromIndex,
index: toIndex,
item: this.#array[fromIndex],
};
const [_item] = this.#array.splice(fromIndex, 1);
this.#array.splice(toIndex, 0, _item);
const [originalIndex] = this.#originalIndices.splice(fromIndex, 1);
this.#originalIndices.splice(toIndex, 0, originalIndex);
return operation;
}
removeItemsAfter(index) {
const operations = [];
while (this.length > index) {
operations.push(this.removeItem(index));
}
return operations;
}
}
function assert(condition, message = 'Assertion failed') {
if (!condition) {
throw new Error(message)
}
}
const DOM_TYPES = {

@@ -16,16 +223,26 @@ TEXT: 'text',

FRAGMENT: 'fragment',
COMPONENT: 'component',
SLOT: 'slot',
};
function h(tag, props = {}, children = []) {
const type =
typeof tag === 'string' ? DOM_TYPES.ELEMENT : DOM_TYPES.COMPONENT;
return {
tag,
props,
type,
children: mapTextNodes(withoutNulls(children)),
type: DOM_TYPES.ELEMENT,
}
}
function mapTextNodes(children) {
return children.map((child) =>
typeof child === 'string' ? hString(child) : child
)
let hSlotCalled = false;
function didCreateSlot() {
return hSlotCalled
}
function resetDidCreateSlot() {
hSlotCalled = false;
}
function hSlot(children = []) {
hSlotCalled = true;
return { type: DOM_TYPES.SLOT, children }
}
function hString(str) {

@@ -35,2 +252,3 @@ return { type: DOM_TYPES.TEXT, value: str }

function hFragment(vNodes) {
assert(Array.isArray(vNodes), 'hFragment expects an array of vNodes');
return {

@@ -41,3 +259,153 @@ type: DOM_TYPES.FRAGMENT,

}
function mapTextNodes(children) {
return children.map((child) =>
typeof child === 'string' ? hString(child) : child
)
}
function extractChildren(vdom) {
if (vdom.children == null) {
return []
}
const children = [];
for (const child of vdom.children) {
if (child.type === DOM_TYPES.FRAGMENT) {
children.push(...extractChildren(child));
} else {
children.push(child);
}
}
return children
}
let isScheduled = false;
const jobs = [];
function enqueueJob(job) {
jobs.push(job);
scheduleUpdate();
}
function scheduleUpdate() {
if (isScheduled) return
isScheduled = true;
queueMicrotask(processJobs);
}
function processJobs() {
while (jobs.length > 0) {
const job = jobs.shift();
const result = job();
Promise.resolve(result).then(
() => {
},
(error) => {
console.error(`[scheduler]: ${error}`);
}
);
}
isScheduled = false;
}
function nextTick() {
scheduleUpdate();
return flushPromises()
}
function flushPromises() {
return new Promise((resolve) => setTimeout(resolve))
}
function extractPropsAndEvents(vdom) {
const { on: events = {}, ...props } = vdom.props;
delete props.key;
return { props, events }
}
function mountDOM(vdom, parentEl, index, hostComponent = null) {
if (parentEl == null) {
throw new Error('Parent element is null')
}
switch (vdom.type) {
case DOM_TYPES.TEXT: {
createTextNode(vdom, parentEl, index);
break
}
case DOM_TYPES.ELEMENT: {
createElementNode(vdom, parentEl, index, hostComponent);
break
}
case DOM_TYPES.FRAGMENT: {
createFragmentNodes(vdom, parentEl, index, hostComponent);
break
}
case DOM_TYPES.COMPONENT: {
createComponentNode(vdom, parentEl, index, hostComponent);
enqueueJob(() => vdom.component.onMounted());
break
}
default: {
throw new Error(`Can't mount DOM of type: ${vdom.type}`)
}
}
}
function createTextNode(vdom, parentEl, index) {
const { value } = vdom;
const textNode = document.createTextNode(value);
vdom.el = textNode;
insert(textNode, parentEl, index);
}
function createElementNode(vdom, parentEl, index, hostComponent) {
const { tag, children } = vdom;
const element = document.createElement(tag);
addProps(element, vdom, hostComponent);
vdom.el = element;
children.forEach((child) => mountDOM(child, element, null, hostComponent));
insert(element, parentEl, index);
}
function addProps(el, vdom, hostComponent) {
const { props: attrs, events } = extractPropsAndEvents(vdom);
vdom.listeners = addEventListeners(events, el, hostComponent);
setAttributes(el, attrs);
}
function createFragmentNodes(vdom, parentEl, index, hostComponent) {
const { children } = vdom;
vdom.el = parentEl;
for (const child of children) {
mountDOM(child, parentEl, index, hostComponent);
if (index == null) {
continue
}
switch (child.type) {
case DOM_TYPES.FRAGMENT:
index += child.children.length;
break
case DOM_TYPES.COMPONENT:
index += child.component.elements.length;
break
default:
index++;
}
}
}
function createComponentNode(vdom, parentEl, index, hostComponent) {
const { tag: Component, children } = vdom;
const { props, events } = extractPropsAndEvents(vdom);
const component = new Component(props, events, hostComponent);
component.setExternalContent(children);
component.setAppContext(hostComponent?.appContext ?? {});
component.mount(parentEl, index);
vdom.component = component;
vdom.el = component.firstElement;
}
function insert(el, parentEl, index) {
if (index == null) {
parentEl.append(el);
return
}
if (index < 0) {
throw new Error(`Index must be a positive integer, got ${index}`)
}
const children = parentEl.childNodes;
if (index >= children.length) {
parentEl.append(el);
} else {
parentEl.insertBefore(el, children[index]);
}
}
function destroyDOM(vdom) {

@@ -82,113 +450,725 @@ const { type } = vdom;

function mountDOM(vdom, parentEl) {
switch (vdom.type) {
const CATCH_ALL_ROUTE = '*';
function makeRouteMatcher(route) {
return routeHasParams(route)
? makeMatcherWithParams(route)
: makeMatcherWithoutParams(route)
}
function routeHasParams({ path }) {
return path.includes(':')
}
function makeMatcherWithParams(route) {
const regex = makeRouteWithParamsRegex(route);
const isRedirect = typeof route.redirect === 'string';
return {
route,
isRedirect,
checkMatch(path) {
return regex.test(path)
},
extractParams(path) {
const { groups } = regex.exec(path);
return groups
},
extractQuery,
}
}
function makeRouteWithParamsRegex({ path }) {
const regex = path.replace(
/:([^/]+)/g,
(_, paramName) => `(?<${paramName}>[^/]+)`
);
return new RegExp(`^${regex}$`)
}
function makeMatcherWithoutParams(route) {
const regex = makeRouteWithoutParamsRegex(route);
const isRedirect = typeof route.redirect === 'string';
return {
route,
isRedirect,
checkMatch(path) {
return regex.test(path)
},
extractParams() {
return {}
},
extractQuery,
}
}
function makeRouteWithoutParamsRegex({ path }) {
if (path === CATCH_ALL_ROUTE) {
return new RegExp('^.*$')
}
return new RegExp(`^${path}$`)
}
function extractQuery(path) {
const queryIndex = path.indexOf('?');
if (queryIndex === -1) {
return {}
}
const search = new URLSearchParams(path.slice(queryIndex + 1));
return Object.fromEntries(search.entries())
}
class Dispatcher {
#subs = new Map()
#afterHandlers = []
subscribe(commandName, handler) {
if (!this.#subs.has(commandName)) {
this.#subs.set(commandName, []);
}
const handlers = this.#subs.get(commandName);
if (handlers.includes(handler)) {
return () => { }
}
handlers.push(handler);
return () => {
const idx = handlers.indexOf(handler);
handlers.splice(idx, 1);
}
}
afterEveryCommand(handler) {
this.#afterHandlers.push(handler);
return () => {
const idx = this.#afterHandlers.indexOf(handler);
this.#afterHandlers.splice(idx, 1);
}
}
dispatch(commandName, payload) {
if (this.#subs.has(commandName)) {
this.#subs.get(commandName).forEach((handler) => handler(payload));
} else {
console.warn(`No handlers for command: ${commandName}`);
}
this.#afterHandlers.forEach((handler) => handler());
}
}
const ROUTER_EVENT = "router-event";
class HashRouter {
#isInitialized = false;
#matchers = [];
#matchedRoute = null;
#dispatcher = new Dispatcher();
#subscriptions = new WeakMap();
#subscriberFns = new Set();
get matchedRoute() {
return this.#matchedRoute;
}
#params = {};
get params() {
return this.#params;
}
#query = {};
get query() {
return this.#query;
}
get #currentRouteHash() {
const hash = document.location.hash;
if (hash === "") {
return "/";
}
return hash.slice(1);
}
#onPopState = () => this.#matchCurrentRoute();
constructor(routes = []) {
assert(Array.isArray(routes), "Routes must be an array");
this.#matchers = routes.map(makeRouteMatcher);
}
async init() {
if (this.#isInitialized) {
return;
}
if (document.location.hash === "") {
window.history.replaceState({}, "", "#/");
}
window.addEventListener("popstate", this.#onPopState);
await this.#matchCurrentRoute();
this.#isInitialized = true;
}
destroy() {
if (!this.#isInitialized) {
return;
}
window.removeEventListener("popstate", this.#onPopState);
Array.from(this.#subscriberFns).forEach(this.unsubscribe, this);
this.#isInitialized = false;
}
async navigateTo(path) {
const matcher = this.#matchers.find((matcher) => matcher.checkMatch(path));
if (matcher == null) {
console.warn(`[Router] No route matches path "${path}"`);
this.#matchedRoute = null;
this.#params = {};
this.#query = {};
return;
}
if (matcher.isRedirect) {
return this.navigateTo(matcher.route.redirect);
}
const from = this.#matchedRoute;
const to = matcher.route;
const { shouldNavigate, shouldRedirect, redirectPath } =
await this.#canChangeRoute(from, to);
if (shouldRedirect) {
return this.navigateTo(redirectPath);
}
if (shouldNavigate) {
this.#matchedRoute = matcher.route;
this.#params = matcher.extractParams(path);
this.#query = matcher.extractQuery(path);
this.#pushState(path);
this.#dispatcher.dispatch(ROUTER_EVENT, { from, to, router: this });
}
}
back() {
window.history.back();
}
forward() {
window.history.forward();
}
subscribe(handler) {
const unsubscribe = this.#dispatcher.subscribe(ROUTER_EVENT, handler);
this.#subscriptions.set(handler, unsubscribe);
this.#subscriberFns.add(handler);
}
unsubscribe(handler) {
const unsubscribe = this.#subscriptions.get(handler);
if (unsubscribe) {
unsubscribe();
this.#subscriptions.delete(handler);
this.#subscriberFns.delete(handler);
}
}
#pushState(path) {
window.history.pushState({}, "", `#${path}`);
}
#matchCurrentRoute() {
return this.navigateTo(this.#currentRouteHash);
}
async #canChangeRoute(from, to) {
const guard = to.beforeEnter;
if (typeof guard !== "function") {
return {
shouldRedirect: false,
shouldNavigate: true,
redirectPath: null,
};
}
const result = await guard(from?.path, to?.path);
if (result === false) {
return {
shouldRedirect: false,
shouldNavigate: false,
redirectPath: null,
};
}
if (typeof result === "string") {
return {
shouldRedirect: true,
shouldNavigate: false,
redirectPath: result,
};
}
return {
shouldRedirect: false,
shouldNavigate: true,
redirectPath: null,
};
}
}
class NoopRouter {
init() { }
destroy() { }
navigateTo() { }
back() { }
forward() { }
subscribe() { }
unsubscribe() { }
}
function createApp(RootComponent, props = {}, options= {}) {
let parentEl = null;
let isMounted = false;
let vdom = null;
const context = {
router: options.router || new NoopRouter(),
};
function reset() {
parentEl = null;
isMounted = false;
vdom = null;
}
return {
mount(_parentEl) {
if (isMounted) {
throw new Error('The application is already mounted')
}
parentEl = _parentEl;
vdom = h(RootComponent, props);
mountDOM(vdom, parentEl, null, {appContext:context});
context.router.init();
isMounted = true;
},
unmount() {
if (!isMounted) {
throw new Error('The application is not mounted')
}
destroyDOM(vdom);
context.router.destroy();
reset();
},
}
}
function areNodesEqual(nodeOne, nodeTwo) {
if (nodeOne.type !== nodeTwo.type) {
return false
}
if (nodeOne.type === DOM_TYPES.ELEMENT) {
const {
tag: tagOne,
props: { key: keyOne },
} = nodeOne;
const {
tag: tagTwo,
props: { key: keyTwo },
} = nodeTwo;
return tagOne === tagTwo && keyOne === keyTwo
}
if (nodeOne.type === DOM_TYPES.COMPONENT) {
const {
tag: componentOne,
props: { key: keyOne },
} = nodeOne;
const {
tag: componentTwo,
props: { key: keyTwo },
} = nodeTwo;
return componentOne === componentTwo && keyOne === keyTwo
}
return true
}
function objectsDiff(oldObj, newObj) {
const oldKeys = Object.keys(oldObj);
const newKeys = Object.keys(newObj);
return {
added: newKeys.filter((key) => !(key in oldObj)),
removed: oldKeys.filter((key) => !(key in newObj)),
updated: newKeys.filter(
(key) => key in oldObj && oldObj[key] !== newObj[key]
),
}
}
function hasOwnProperty(obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop)
}
function isNotEmptyString(str) {
return str !== ''
}
function isNotBlankOrEmptyString(str) {
return isNotEmptyString(str.trim())
}
function patchDOM(oldVdom, newVdom, parentEl, hostComponent = null) {
if (!areNodesEqual(oldVdom, newVdom)) {
const index = findIndexInParent(parentEl, oldVdom.el);
destroyDOM(oldVdom);
mountDOM(newVdom, parentEl, index, hostComponent);
return newVdom
}
newVdom.el = oldVdom.el;
switch (newVdom.type) {
case DOM_TYPES.TEXT: {
createTextNode(vdom, parentEl);
break
patchText(oldVdom, newVdom);
return newVdom
}
case DOM_TYPES.ELEMENT: {
createElementNode(vdom, parentEl);
patchElement(oldVdom, newVdom, hostComponent);
break
}
case DOM_TYPES.FRAGMENT: {
createFragmentNodes(vdom, parentEl);
break;
case DOM_TYPES.COMPONENT: {
patchComponent(oldVdom, newVdom);
break
}
default: {
throw new Error(`Can't mount DOM of type: ${vdom.type}`)
}
}
patchChildren(oldVdom, newVdom, hostComponent);
return newVdom
}
function createTextNode(vdom, parentEl) {
const { value } = vdom;
const textNode = document.createTextNode(value);
vdom.el = textNode;
parentEl.append(textNode);
function findIndexInParent(parentEl, el) {
const index = Array.from(parentEl.childNodes).indexOf(el);
if (index < 0) {
return null
}
return index
}
function createElementNode(vdom, parentEl) {
const { tag, props, children } = vdom;
const element = document.createElement(tag);
addProps(element, props, vdom);
vdom.el = element;
children.forEach((child) => mountDOM(child, element));
parentEl.append(element);
function patchText(oldVdom, newVdom) {
const el = oldVdom.el;
const { value: oldText } = oldVdom;
const { value: newText } = newVdom;
if (oldText !== newText) {
el.nodeValue = newText;
}
}
function createFragmentNodes(vdom, parentEl) {
const fragment = document.createDocumentFragment();
vdom.children.forEach((child) => {
mountDOM(child, fragment);
});
parentEl.append(fragment);
function patchElement(oldVdom, newVdom, hostComponent) {
const el = oldVdom.el;
const {
class: oldClass,
style: oldStyle,
on: oldEvents,
...oldAttrs
} = oldVdom.props;
const {
class: newClass,
style: newStyle,
on: newEvents,
...newAttrs
} = newVdom.props;
const { listeners: oldListeners } = oldVdom;
patchAttrs(el, oldAttrs, newAttrs);
patchClasses(el, oldClass, newClass);
patchStyles(el, oldStyle, newStyle);
newVdom.listeners = patchEvents(
el,
oldListeners,
oldEvents,
newEvents,
hostComponent
);
}
function addProps(el, props, vdom) {
const { on: events, ...attrs } = props;
vdom.listeners = addEventListeners(events, el);
setAttributes(el, attrs);
function patchAttrs(el, oldAttrs, newAttrs) {
const { added, removed, updated } = objectsDiff(oldAttrs, newAttrs);
for (const attr of removed) {
removeAttribute(el, attr);
}
for (const attr of added.concat(updated)) {
setAttribute(el, attr, newAttrs[attr]);
}
}
let routes = [];
function createRouter(userRoutes) {
routes = userRoutes;
onRouteChange();
function patchClasses(el, oldClass, newClass) {
const oldClasses = toClassList(oldClass);
const newClasses = toClassList(newClass);
const { added, removed } = arraysDiff(oldClasses, newClasses);
if (removed.length > 0) {
el.classList.remove(...removed);
}
if (added.length > 0) {
el.classList.add(...added);
}
}
function getComponentForPath(path) {
const route = routes.find((r) => r.path === path);
return route ? route.component() : `<h1>404 - Not Found</h1>`;
function toClassList(classes = '') {
return Array.isArray(classes)
? classes.filter(isNotBlankOrEmptyString)
: classes.split(/(\s+)/).filter(isNotBlankOrEmptyString)
}
function onRouteChange() {
const path = window.location.pathname;
document.getElementById('app').innerHTML = getComponentForPath(path);
function patchStyles(el, oldStyle = {}, newStyle = {}) {
const { added, removed, updated } = objectsDiff(oldStyle, newStyle);
for (const style of removed) {
removeStyle(el, style);
}
for (const style of added.concat(updated)) {
setStyle(el, style, newStyle[style]);
}
}
function navigate(path) {
history.pushState({}, '', path);
onRouteChange();
function patchEvents(
el,
oldListeners = {},
oldEvents = {},
newEvents = {},
hostComponent
) {
const { removed, added, updated } = objectsDiff(oldEvents, newEvents);
for (const eventName of removed.concat(updated)) {
el.removeEventListener(eventName, oldListeners[eventName]);
}
const addedListeners = {};
for (const eventName of added.concat(updated)) {
const listener = addEventListener(
eventName,
newEvents[eventName],
el,
hostComponent
);
addedListeners[eventName] = listener;
}
return addedListeners
}
document.addEventListener('click', (event) => {
if (event.target.tagName === 'A' && event.target.hasAttribute('data-link')) {
event.preventDefault();
navigate(event.target.getAttribute('href'));
function patchComponent(oldVdom, newVdom) {
const { component } = oldVdom;
const { children } = newVdom;
const { props } = extractPropsAndEvents(newVdom);
component.setExternalContent(children);
component.updateProps(props);
newVdom.component = component;
newVdom.el = component.firstElement;
}
function patchChildren(oldVdom, newVdom, hostComponent) {
const oldChildren = extractChildren(oldVdom);
const newChildren = extractChildren(newVdom);
const parentEl = oldVdom.el;
const diffSeq = arraysDiffSequence(
oldChildren,
newChildren,
areNodesEqual
);
for (const operation of diffSeq) {
const { originalIndex, index, item } = operation;
const offset = hostComponent?.offset ?? 0;
switch (operation.op) {
case ARRAY_DIFF_OP.ADD: {
mountDOM(item, parentEl, index + offset, hostComponent);
break
}
case ARRAY_DIFF_OP.REMOVE: {
destroyDOM(item);
break
}
case ARRAY_DIFF_OP.MOVE: {
const oldChild = oldChildren[originalIndex];
const newChild = newChildren[index];
const el = oldChild.el;
const elAtTargetIndex = parentEl.childNodes[index + offset];
parentEl.insertBefore(el, elAtTargetIndex);
patchDOM(oldChild, newChild, parentEl, hostComponent);
break
}
case ARRAY_DIFF_OP.NOOP: {
patchDOM(
oldChildren[originalIndex],
newChildren[index],
parentEl,
hostComponent
);
break
}
}
}
});
class NoopRouter {
init() {
}
function traverseDFS(
vdom,
processNode,
shouldSkipBranch = () => false,
parentNode = null,
index = null
) {
if (shouldSkipBranch(vdom)) return
processNode(vdom, parentNode, index);
if (vdom.children) {
vdom.children.forEach((child, i) =>
traverseDFS(child, processNode, shouldSkipBranch, vdom, i)
);
}
destroy() {
}
function fillSlots(vdom, externalContent = []) {
function processNode(node, parent, index) {
insertViewInSlot(node, parent, index, externalContent);
}
traverseDFS(vdom, processNode, shouldSkipBranch);
}
window.addEventListener('popstate', onRouteChange);
function insertViewInSlot(node, parent, index, externalContent) {
if (node.type !== DOM_TYPES.SLOT) return
const defaultContent = node.children;
const views = externalContent.length > 0 ? externalContent : defaultContent;
const hasContent = views.length > 0;
if (hasContent) {
parent.children.splice(index, 1, hFragment(views));
} else {
parent.children.splice(index, 1);
}
}
function shouldSkipBranch(node) {
return node.type === DOM_TYPES.COMPONENT
}
function createApp(RootComponent, props = {}, options = {}) {
let parentEl = null;
let isMounted = false;
let vdom = null;
const context = {
router: options.router || new NoopRouter(),
};
function reset() {
parentEl = null;
isMounted = false;
vdom = null;
}
return {
mount(_parentEl) {
if (isMounted) {
throw new Error('The application is already mounted')
const emptyFn = () => { };
function defineComponent({
render,
state,
onMounted = emptyFn,
onUnmounted = emptyFn,
...methods
}) {
class Component {
#isMounted = false;
#vdom = null;
#hostEl = null;
#eventHandlers = null;
#parentComponent = null;
#dispatcher = new Dispatcher();
#subscriptions = [];
#appContext = null
#children = []
setExternalContent(children) {
this.#children = children;
}
constructor(props = {}, eventHandlers = {}, parentComponent = null) {
this.props = props;
this.state = state ? state(props) : {};
this.#eventHandlers = eventHandlers;
this.#parentComponent = parentComponent;
}
onMounted() {
return Promise.resolve(onMounted.call(this));
}
onUnmounted() {
return Promise.resolve(onUnmounted.call(this));
}
setAppContext(appContext) {
this.#appContext = appContext;
}
get appContext() {
return this.#appContext
}
get parentComponent() {
return this.#parentComponent;
}
get vdom() {
return this.#vdom;
}
get elements() {
if (this.#vdom == null) {
return [];
}
parentEl = _parentEl;
vdom = h(RootComponent, props);
mountDOM(vdom, parentEl);
context.router.init();
isMounted = true;
},
if (this.#vdom.type === DOM_TYPES.FRAGMENT) {
return extractChildren(this.#vdom).flatMap((child) => {
if (child.type === DOM_TYPES.COMPONENT) {
return child.component.elements;
}
return [child.el];
});
}
return [this.#vdom.el];
}
get firstElement() {
return this.elements[0];
}
get offset() {
if (this.#vdom.type === DOM_TYPES.FRAGMENT) {
return Array.from(this.#hostEl.children).indexOf(this.firstElement);
}
return 0;
}
updateProps(props) {
this.props = { ...this.props, ...props };
this.#patch();
}
updateState(state) {
this.state = { ...this.state, ...state };
this.#patch();
}
render() {
const vdom = render.call(this);
if (didCreateSlot()) {
fillSlots(vdom, this.#children);
resetDidCreateSlot();
}
return vdom
}
mount(hostEl, index = null) {
if (this.#isMounted) {
throw new Error("Component is already mounted");
}
this.#vdom = this.render();
mountDOM(this.#vdom, hostEl, index, this);
this.#wireEventHandlers();
this.#isMounted = true;
this.#hostEl = hostEl;
}
#wireEventHandlers() {
this.#subscriptions = Object.entries(this.#eventHandlers).map(
([eventName, handler]) => this.#wireEventHandler(eventName, handler)
);
}
#wireEventHandler(eventName, handler) {
return this.#dispatcher.subscribe(eventName, (payload) => {
if (this.#parentComponent) {
handler.call(this.#parentComponent, payload);
} else {
handler(payload);
}
});
}
unmount() {
if (!isMounted) {
throw new Error('The application is not mounted')
if (!this.#isMounted) {
throw new Error("Component is not mounted");
}
destroyDOM(vdom);
context.router.destroy();
reset();
},
destroyDOM(this.#vdom);
this.#subscriptions.forEach((unsubscribe) => unsubscribe());
this.#vdom = null;
this.#isMounted = false;
this.#hostEl = null;
this.#subscriptions = [];
}
emit(eventName, payload) {
this.#dispatcher.dispatch(eventName, payload);
}
#patch() {
if (!this.#isMounted) {
throw new Error("Component is not mounted");
}
const vdom = this.render();
this.#vdom = patchDOM(this.#vdom, vdom, this.#hostEl, this);
}
}
for (const methodName in methods) {
if (hasOwnProperty(Component, methodName)) {
throw new Error(
`Method "${methodName}()" already exists in the component. Can't override existing methods.`
);
}
Component.prototype[methodName] = methods[methodName];
}
return Component;
}
export { createApp, createRouter, h, hFragment, hString, navigate };
const RouterLink = defineComponent({
render() {
const { to } = this.props;
return h(
'a',
{
href: to,
on: {
click: (e) => {
e.preventDefault();
this.appContext.router.navigateTo(to);
},
},
},
[hSlot()]
)
},
});
const RouterOutlet = defineComponent({
state() {
return {
matchedRoute: null,
subscription: null,
}
},
onMounted() {
const subscription = this.appContext.router.subscribe(({ to }) => {
this.handleRouteChange(to);
});
this.updateState({ subscription });
},
onUnmounted() {
const { subscription } = this.state;
this.appContext.router.unsubscribe(subscription);
},
handleRouteChange(matchedRoute) {
this.updateState({ matchedRoute });
},
render() {
const { matchedRoute } = this.state;
return h('div', { id: 'router-outlet' }, [
matchedRoute ? h(matchedRoute.component) : null,
])
},
});
export { DOM_TYPES, HashRouter, RouterLink, RouterOutlet, createApp, defineComponent, h, hFragment, hSlot, hString, nextTick };

2

package.json
{
"name": "paramax-framework",
"version": "1.0.5",
"version": "1.0.6",
"description": "A lightweight framework",

@@ -5,0 +5,0 @@ "keywords": [

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