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

typed-dom

Package Overview
Dependencies
Maintainers
1
Versions
350
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

typed-dom - npm Package Compare versions

Comparing version 0.0.278 to 0.0.279

2

package.json
{
"name": "typed-dom",
"version": "0.0.278",
"version": "0.0.279",
"description": "A value-level and type-level DOM builder.",

@@ -5,0 +5,0 @@ "private": false,

@@ -5,2 +5,3 @@ import { Event } from 'spica/global';

import { identity } from './util/identity';
import { splice } from 'spica/array';

@@ -65,14 +66,3 @@ declare global {

namespace privates {
export const events = Symbol.for('typed-dom::events');
export const id = Symbol('id');
export const id_ = Symbol('id_');
export const query = Symbol('query');
export const query_ = Symbol('query_');
export const scope = Symbol('scope');
export const observe = Symbol('observe');
export const type = Symbol('type');
export const container = Symbol('container');
export const children = Symbol('children');
export const isInit = Symbol('isInit');
export const isObserverUpdate = Symbol('isObserverUpdate');
export const listeners = Symbol.for('typed-dom::listeners');
}

@@ -94,21 +84,21 @@

) {
const events = this[privates.events];
const listeners = this[privates.listeners];
assert('' != null);
events.mutate = 'onmutate' in element && element['onmutate'] != null;
events.connect = 'onconnect' in element && element['onconnect'] != null;
events.disconnect = 'ondisconnect' in element && element['ondisconnect'] != null;
this[privates.children] = children;
this[privates.container] = container;
listeners.mutate = 'onmutate' in element && element['onmutate'] != null;
listeners.connect = 'onconnect' in element && element['onconnect'] != null;
listeners.disconnect = 'ondisconnect' in element && element['ondisconnect'] != null;
this.children_ = children;
this.container = container;
switch (true) {
case children === void 0:
this[privates.type] = ElChildType.Void;
this.type = ElChildType.Void;
break;
case typeof children === 'string':
this[privates.type] = ElChildType.Text
this.type = ElChildType.Text
break;
case isArray(children):
this[privates.type] = ElChildType.Array;
this.type = ElChildType.Array;
break;
case children && typeof children === 'object':
this[privates.type] = ElChildType.Struct;
this.type = ElChildType.Struct;
break;

@@ -120,19 +110,19 @@ default:

this.element[proxy] = this;
switch (this[privates.type]) {
switch (this.type) {
case ElChildType.Void:
this[privates.isInit] = false;
this.isInit = false;
return;
case ElChildType.Text:
this.children = children as El.Setter<C>;
this[privates.isInit] = false;
this.isInit = false;
return;
case ElChildType.Array:
this[privates.children] = [] as El.Children.Array as C;
this.children_ = [] as El.Children.Array as C;
this.children = children as El.Setter<C>;
this[privates.isInit] = false;
this.isInit = false;
return;
case ElChildType.Struct:
this[privates.children] = this[privates.observe](children as El.Children.Struct) as C;
this.children_ = this.observe(children as El.Children.Struct) as C;
this.children = children as El.Setter<C>;
this[privates.isInit] = false;
this.isInit = false;
return;

@@ -143,12 +133,20 @@ default:

}
private readonly [privates.events] = {
private [privates.listeners] = {
mutate: false,
connect: false,
disconnect: false,
values: [] as El[],
add(child: El): void {
this.values.push(child);
},
delete(child: El): void {
assert(this.values.indexOf(child) > -1);
splice(this.values, this.values.indexOf(child), 1);
},
};
private [privates.id_] = '';
private get [privates.id](): string {
if (this[privates.id_]) return this[privates.id_];
this[privates.id_] = this.element.id;
if (/^[a-z][\w-]*$/i.test(this[privates.id_])) return this[privates.id_];
private id_ = '';
private get id(): string {
if (this.id_) return this.id_;
this.id_ = this.element.id;
if (/^[a-z][\w-]*$/i.test(this.id_)) return this.id_;
if (counter === 999) {

@@ -158,20 +156,20 @@ id = identity();

}
this[privates.id_] = `rnd-${id}-${++counter}`;
assert(!this.element.classList.contains(this[privates.id_]));
this.element.classList.add(this[privates.id_]);
return this[privates.id_];
this.id_ = `rnd-${id}-${++counter}`;
assert(!this.element.classList.contains(this.id_));
this.element.classList.add(this.id_);
return this.id_;
}
private [privates.query_] = '';
private get [privates.query](): string {
if (this[privates.query_]) return this[privates.query_];
private query_ = '';
private get query(): string {
if (this.query_) return this.query_;
switch (true) {
case this.element !== this[privates.container]:
return this[privates.query_] = ':host';
case this[privates.id] === this.element.id:
return this[privates.query_] = `#${this[privates.id]}`;
case this.element !== this.container:
return this.query_ = ':host';
case this.id === this.element.id:
return this.query_ = `#${this.id}`;
default:
return this[privates.query_] = `.${this[privates.id]}`;
return this.query_ = `.${this.id}`;
}
}
private [privates.scope](child: El): void {
private scope(child: El): void {
if (child.tag.toUpperCase() !== 'STYLE') return;

@@ -181,12 +179,12 @@ const source = child.element.innerHTML;

const scope = /(^|[>~+,}/])(\s*)\:scope(?!\w)(?=\s*[A-Za-z#.:[>~+,{/])/g;
const style = source.replace(scope, (...$) => `${$[1]}${$[2]}${this[privates.query]}`);
assert(!this[privates.query_] || style !== source);
const style = source.replace(scope, (...$) => `${$[1]}${$[2]}${this.query}`);
assert(!this.query_ || style !== source);
if (style === source) return;
child.element.innerHTML = style;
assert(/^[:#.][\w-]+$/.test(this[privates.query]));
assert(/^[:#.][\w-]+$/.test(this.query));
assert(child.element.children.length === 0);
child.element.firstElementChild && child.element.replaceChildren();
}
private [privates.isObserverUpdate] = false;
private [privates.observe](children: El.Children.Struct): El.Children.Struct {
private isObserverUpdate = false;
private observe(children: El.Children.Struct): El.Children.Struct {
return ObjectDefineProperties(children, ObjectKeys(children).reduce((obj, name) => {

@@ -202,7 +200,7 @@ if (name in {}) throw new Error(`TypedDOM: Child names conflicted with the object property names.`);

set: (newChild: El) => {
if (!this[privates.isObserverUpdate]) {
if (!this.isObserverUpdate) {
this.children = { [name]: newChild } as El.Setter<C>;
}
else {
this[privates.isObserverUpdate] = false;
this.isObserverUpdate = false;
}

@@ -215,25 +213,25 @@ child = newChild;

}
private readonly [privates.type]: ElChildType;
private readonly [privates.container]: Element | ShadowRoot;
private [privates.isInit] = true;
private [privates.children]: C;
private readonly type: ElChildType;
private readonly container: Element | ShadowRoot;
private isInit = true;
private children_: C;
public get children(): El.Getter<C> {
switch (this[privates.type]) {
switch (this.type) {
case ElChildType.Text:
return this[privates.container].textContent as El.Getter<C>;
return this.container.textContent as El.Getter<C>;
default:
return this[privates.children] as El.Getter<C>;
return this.children_ as El.Getter<C>;
}
}
public set children(children: El.Setter<C>) {
assert(!this[privates.isObserverUpdate]);
const container = this[privates.container];
assert(!this.isObserverUpdate);
const container = this.container;
const removedChildren: El[] = [];
const addedChildren: El[] = [];
let isMutated = false;
switch (this[privates.type]) {
switch (this.type) {
case ElChildType.Void:
return;
case ElChildType.Text: {
if (this[privates.isInit] || !this[privates.events].mutate) {
if (this.isInit || !this[privates.listeners].mutate) {
container.textContent = children as El.Children.Text;

@@ -252,3 +250,3 @@ isMutated = true;

const sourceChildren = children as El.Children.Array;
const targetChildren = this[privates.children] as El.Children.Array;
const targetChildren = this.children_ as El.Children.Array;
isMutated ||= sourceChildren.length !== targetChildren.length;

@@ -258,8 +256,8 @@ for (let i = 0; i < sourceChildren.length; ++i) {

const oldChild = targetChildren[i];
throwErrorIfNotUsable(newChild, this[privates.container]);
throwErrorIfNotUsable(newChild, this.container);
isMutated ||= newChild.element !== oldChild.element;
if (newChild.element.parentNode !== this.element) {
this[privates.scope](newChild);
this.scope(newChild);
assert(!addedChildren.includes(newChild));
events(newChild)?.connect && addedChildren.push(newChild);
hasListener(newChild) && addedChildren.push(newChild) && this[privates.listeners].add(newChild);
}

@@ -275,3 +273,3 @@ }

}
this[privates.children] = sourceChildren as C;
this.children_ = sourceChildren as C;
for (let i = 0; i < targetChildren.length; ++i) {

@@ -281,3 +279,3 @@ const oldChild = targetChildren[i];

assert(!removedChildren.includes(oldChild));
events(oldChild)?.disconnect && removedChildren.push(oldChild);
hasListener(oldChild) && removedChildren.push(oldChild) && this[privates.listeners].delete(oldChild);
assert(isMutated);

@@ -291,3 +289,3 @@ }

case ElChildType.Struct: {
if (this[privates.isInit]) {
if (this.isInit) {
container.firstChild && container.replaceChildren();

@@ -298,7 +296,7 @@ const sourceChildren = children as El.Children.Struct;

const newChild = sourceChildren[name];
throwErrorIfNotUsable(newChild, this[privates.container]);
this[privates.scope](newChild);
throwErrorIfNotUsable(newChild, this.container);
this.scope(newChild);
container.appendChild(newChild.element);
assert(!addedChildren.includes(newChild));
events(newChild)?.connect && addedChildren.push(newChild);
hasListener(newChild) && addedChildren.push(newChild) && this[privates.listeners].add(newChild);
isMutated = true;

@@ -309,3 +307,3 @@ }

const sourceChildren = children as El.Children.Struct;
const targetChildren = this[privates.children] as El.Children.Struct;
const targetChildren = this.children_ as El.Children.Struct;
if (sourceChildren === targetChildren) break;

@@ -318,11 +316,11 @@ for (const name in sourceChildren) {

if (newChild === oldChild) continue;
throwErrorIfNotUsable(newChild, this[privates.container]);
throwErrorIfNotUsable(newChild, this.container);
if (newChild !== oldChild && newChild.element.parentNode !== oldChild.element.parentNode) {
this[privates.scope](newChild);
this.scope(newChild);
container.replaceChild(newChild.element, oldChild.element);
assert(!oldChild.element.parentNode);
assert(!addedChildren.includes(newChild));
events(newChild)?.connect && addedChildren.push(newChild);
hasListener(newChild) && addedChildren.push(newChild) && this[privates.listeners].add(newChild);
assert(!removedChildren.includes(oldChild));
events(oldChild)?.disconnect && removedChildren.push(oldChild);
hasListener(oldChild) && removedChildren.push(oldChild) && this[privates.listeners].delete(oldChild);
}

@@ -336,6 +334,6 @@ else {

isMutated = true;
this[privates.isObserverUpdate] = true;
this.isObserverUpdate = true;
targetChildren[name] = newChild;
assert(!this[privates.isObserverUpdate]);
this[privates.isObserverUpdate] = false;
assert(!this.isObserverUpdate);
this.isObserverUpdate = false;
}

@@ -345,18 +343,43 @@ break;

}
for (let i = 0; i < removedChildren.length; ++i) {
removedChildren[i].element.dispatchEvent(new Event('disconnect', { bubbles: false, cancelable: true }));
}
for (let i = 0; i < addedChildren.length; ++i) {
addedChildren[i].element.dispatchEvent(new Event('connect', { bubbles: false, cancelable: true }));
}
this.dispatchDisconnectionEvent(removedChildren);
this.dispatchConnectionEvent(addedChildren);
assert(isMutated || removedChildren.length + addedChildren.length === 0);
if (isMutated && this[privates.events].mutate) {
if (isMutated && this[privates.listeners].mutate) {
this.element.dispatchEvent(new Event('mutate', { bubbles: false, cancelable: true }));
}
}
private get isConnected(): boolean {
return !!this.element.parentNode && this.element.isConnected;
}
private dispatchConnectionEvent(
listeners: El[] | undefined = this[privates.listeners].values,
isConnected = listeners.length !== 0 && this.isConnected,
): void {
if (listeners.length === 0) return;
if (listeners !== this[privates.listeners].values && !isConnected) return;
for (const listener of listeners) {
listener.element[proxy].dispatchConnectionEvent(void 0, isConnected);
getListeners(listener)?.connect && listener.element.dispatchEvent(new Event('connect', { bubbles: false, cancelable: true }));
}
}
private dispatchDisconnectionEvent(
listeners: El[] | undefined = this[privates.listeners].values,
isConnected = listeners.length !== 0 && this.isConnected,
): void {
if (listeners.length === 0) return;
if (listeners !== this[privates.listeners].values && !isConnected) return;
for (const listener of listeners) {
listener.element[proxy].dispatchDisconnectionEvent(void 0, isConnected);
getListeners(listener)?.disconnect && listener.element.dispatchEvent(new Event('disconnect', { bubbles: false, cancelable: true }));
}
}
}
function events(child: El): ElementProxy[typeof privates.events] | undefined {
return child[privates.events] ?? child.element[proxy]?.[privates.events];
function hasListener(child: El): boolean {
const ls = getListeners(child);
return ls?.connect || ls?.disconnect || ls?.values.length! > 0;
}
function getListeners(child: El): ElementProxy[typeof privates.listeners] | undefined {
return child[privates.listeners] ?? child.element[proxy]?.[privates.listeners];
}

@@ -363,0 +386,0 @@ function throwErrorIfNotUsable(child: El, newParent?: ParentNode): void {

@@ -16,2 +16,5 @@ import { Shadow, HTML, SVG, El, Attrs, shadow, html } from '../..';

const doc = Shadow.section([]);
document.body.appendChild(doc.element);
describe('Integration: Typed DOM', function () {

@@ -380,5 +383,5 @@ describe('spec', function () {

onconnect: ({ currentTarget: el }) =>
el.textContent += el.textContent!.toUpperCase(),
el.textContent += el.textContent![0].toUpperCase(),
ondisconnect: ({ currentTarget: el }) =>
el.textContent += el.textContent!,
el.textContent += el.textContent![0].toLowerCase(),
};

@@ -392,2 +395,9 @@ const dom = HTML.ul([

[
'a',
'b',
]);
doc.children = [dom];
assert.deepStrictEqual(
dom.children.map(child => child.children),
[
'aA',

@@ -409,2 +419,9 @@ 'bB',

[...dom.element.children]);
doc.children = [];
assert.deepStrictEqual(
dom.children.map(child => child.children),
[
'bBb',
'cCc',
]);
});

@@ -429,2 +446,12 @@

[
['a', 'a'],
['b', 'b'],
['c', 'c'],
['d', 'd'],
['e', 'e'],
]);
doc.children = [Shadow.section([dom])];
assert.deepStrictEqual(
Object.entries(dom.children).map(([k, v]) => [k, v.children]),
[
['a', 'aA'],

@@ -431,0 +458,0 @@ ['b', 'bB'],

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

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