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

@erickmerchant/framework

Package Overview
Dependencies
Maintainers
1
Versions
244
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@erickmerchant/framework - npm Package Compare versions

Comparing version 48.4.0 to 49.0.0

morph.js

40

app.js

@@ -0,32 +1,38 @@

import {morph} from './morph.js';
export const createApp = (state) => {
let willCallView = false
const views = []
let willCallView = false;
const views = [];
const callView = () => {
if (willCallView) return
if (willCallView) return;
willCallView = true
willCallView = true;
Promise.resolve().then(() => {
willCallView = false
willCallView = false;
for (const view of views) view(state)
})
}
for (const [target, view] of views) morph(target, view(state));
});
};
return {
render(v) {
views.push(v)
render(view, target) {
if (typeof target === 'string') {
target = document.querySelector(target);
}
callView()
views.push([target, view]);
callView();
},
set state(val) {
state = val
state = val;
callView()
callView();
},
get state() {
return state
}
}
}
return state;
},
};
};

@@ -6,14 +6,14 @@ const obj = {

'"': '"',
"'": '''
}
const valuesArr = Object.values(obj)
const keysStr = Object.keys(obj).join('')
const regex = new RegExp(keysStr, 'g')
"'": ''',
};
const valuesArr = Object.values(obj);
const keysStr = Object.keys(obj).join('');
const regex = new RegExp(keysStr, 'g');
export const escape = (str) => {
try {
return str.replace(regex, (match) => valuesArr[keysStr.indexOf(match)])
return str.replace(regex, (match) => valuesArr[keysStr.indexOf(match)]);
} catch {
return str
return str;
}
}
};

@@ -1,6 +0,6 @@

const weakMap = new WeakMap()
const weakMap = new WeakMap();
const throwAssertionError = (actual, expected) => {
throw Error(`Expected ${expected}. Found ${actual}.`)
}
throw Error(`Expected ${expected}. Found ${actual}.`);
};

@@ -16,55 +16,55 @@ export const tokenTypes = {

constant: 'constant',
end: 'end'
}
end: 'end',
};
const valueTrue = {
const TRUE = {
type: tokenTypes.value,
value: true
}
value: true,
};
const END = {
type: tokenTypes.end
}
type: tokenTypes.end,
};
const createIsChar = (regex) => (char) => char && regex.test(char)
const createIsChar = (regex) => (char) => char && regex.test(char);
const isSpaceChar = createIsChar(/\s/)
const isNameChar = createIsChar(/[:@a-zA-Z0-9-]/)
const isQuoteChar = createIsChar(/["']/)
const isSpaceChar = createIsChar(/\s/);
const isNameChar = createIsChar(/[:@a-zA-Z0-9-]/);
const isQuoteChar = createIsChar(/["']/);
const tokenizer = {
*tokenize(acc, strs, vlength) {
let str, i, char
let str, i, char;
const nextChar = () => {
char = str.charAt(i++)
}
char = str.charAt(i++);
};
for (let index = 0, length = strs.length; index < length; index++) {
str = strs[index]
i = 0
str = strs[index];
i = 0;
nextChar()
nextChar();
let tag = acc.tag
let tag = acc.tag;
while (char) {
if (!tag) {
let value = ''
let value = '';
if (char === '<') {
let end = false
let end = false;
nextChar()
nextChar();
if (char === '/') {
end = true
end = true;
nextChar()
nextChar();
}
while (isNameChar(char)) {
value += char
value += char;
nextChar()
nextChar();
}

@@ -74,11 +74,11 @@

type: !end ? tokenTypes.tag : tokenTypes.endtag,
value
}
value,
};
tag = value
tag = value;
} else {
while (char && char !== '<') {
value += char
value += char;
nextChar()
nextChar();
}

@@ -89,10 +89,10 @@

type: tokenTypes.text,
value
}
value,
};
}
}
} else if (isSpaceChar(char)) {
nextChar()
nextChar();
} else if (char === '/') {
nextChar()
nextChar();

@@ -104,23 +104,23 @@ if (char === '>') {

type: tokenTypes.endtag,
value: tag
}
]
value: tag,
},
];
tag = false
tag = false;
nextChar()
nextChar();
}
} else if (char === '>') {
yield END
yield END;
tag = false
tag = false;
nextChar()
nextChar();
} else if (isNameChar(char)) {
let value = ''
let value = '';
while (isNameChar(char)) {
value += char
value += char;
nextChar()
nextChar();
}

@@ -130,37 +130,37 @@

type: tokenTypes.key,
value
}
value,
};
if (char === '=') {
nextChar()
nextChar();
let quote = ''
let value = ''
let quote = '';
let value = '';
if (isQuoteChar(char)) {
quote = char
quote = char;
nextChar()
nextChar();
while (char !== quote) {
if (char) {
value += char
value += char;
nextChar()
nextChar();
} else {
throwAssertionError('', quote)
throwAssertionError('', quote);
}
}
nextChar()
nextChar();
yield {
type: tokenTypes.value,
value
}
value,
};
} else if (char) {
throwAssertionError(char, '"')
throwAssertionError(char, '"');
}
} else {
yield valueTrue
yield TRUE;
}

@@ -170,3 +170,3 @@ }

acc.tag = tag
acc.tag = tag;

@@ -176,8 +176,8 @@ if (index < vlength) {

type: tokenTypes.variable,
value: index
}
value: index,
};
}
}
}
}
},
};

@@ -193,32 +193,32 @@ const parse = (read, parent, tag, variables) => {

attributes: 0,
children: null
}
}
children: null,
},
};
let token
let token;
while ((token = read())) {
if (token === END) break
if (token === END) break;
if (token.type === tokenTypes.key) {
const key = token.value
const key = token.value;
token = read()
token = read();
const firstChar = key.charAt(0)
const special = ':' === firstChar || '@' === firstChar
const firstChar = key.charAt(0);
const special = ':' === firstChar || '@' === firstChar;
let value = token.value
let constant = false
let value = token.value;
let constant = false;
if (token.type === tokenTypes.value) {
constant = true
constant = true;
} else if (token.type === tokenTypes.variable && !special && !html.dev) {
value = variables[value]
value = variables[value];
constant = true
constant = true;
}
if (constant) {
child.offsets.attributes++
child.offsets.attributes++;

@@ -228,6 +228,6 @@ child.attributes.unshift({

key,
value
})
value,
});
} else {
child.dynamic = true
child.dynamic = true;

@@ -237,7 +237,7 @@ child.attributes.push({

key,
value
})
value,
});
}
} else {
throwAssertionError(token.type, END.type)
throwAssertionError(token.type, END.type);
}

@@ -248,21 +248,21 @@ }

if (token.type === tokenTypes.endtag && token.value === child.tag) {
break
break;
} else if (token.type === tokenTypes.tag) {
const dynamic = parse(read, child, token.value, variables)
const dynamic = parse(read, child, token.value, variables);
child.dynamic ||= dynamic
child.dynamic ||= dynamic;
} else if (token.type === tokenTypes.text) {
child.children.push({
type: tokenTypes.text,
value: token.value
})
value: token.value,
});
} else if (token.type === tokenTypes.variable) {
child.dynamic = true
child.dynamic = true;
child.offsets.children ??= child.children.length
child.offsets.children ??= child.children.length;
child.children.push({
type: tokenTypes.variable,
value: token.value
})
value: token.value,
});
}

@@ -272,34 +272,34 @@ }

if (child.dynamic) {
parent.offsets.children ??= parent.children.length
parent.offsets.children ??= parent.children.length;
}
parent.children.push(child)
parent.children.push(child);
child.offsets.children ??= child.children.length
child.offsets.children ??= child.children.length;
return child.dynamic
}
return child.dynamic;
};
let id = 1
let id = 1;
export const html = (strs, ...variables) => {
let template = weakMap.get(strs)
let template = weakMap.get(strs);
if (!template) {
const acc = {
tag: false
}
tag: false,
};
const tokens = tokenizer.tokenize(acc, strs, variables.length)
const read = () => tokens.next().value
const tokens = tokenizer.tokenize(acc, strs, variables.length);
const read = () => tokens.next().value;
const children = []
const offsets = {children: null}
let token
const children = [];
const offsets = {children: null};
let token;
while ((token = read())) {
if (token.type === tokenTypes.tag) {
parse(read, {children, offsets}, token.value, variables)
parse(read, {children, offsets}, token.value, variables);
} else if (token.type === tokenTypes.text && token.value.trim()) {
throwAssertionError(token.type, tokenTypes.node)
throwAssertionError(token.type, tokenTypes.node);
}

@@ -309,10 +309,10 @@ }

if (children.length !== 1) {
throwAssertionError(children.length, 1)
throwAssertionError(children.length, 1);
}
template = children[0]
template = children[0];
template.view = id++
template.view = id++;
weakMap.set(strs, template)
weakMap.set(strs, template);
}

@@ -322,14 +322,14 @@

...template,
variables
}
}
variables,
};
};
html.dev = false
html.dev = false;
export const cache = (result) => {
if (html.dev) return result
if (html.dev) return result;
result.dynamic = false
result.dynamic = false;
return result
}
return result;
};

@@ -1,5 +0,3 @@

export {createDOMView} from './dom-view.js'
export {cache, html} from './html.js';
export {cache, html} from './html.js'
export {createApp} from './app.js'
export {createApp} from './app.js';
{
"name": "@erickmerchant/framework",
"version": "48.4.0",
"version": "49.0.0",
"description": "A front-end framework.",

@@ -23,3 +23,3 @@ "homepage": "https://github.com/erickmerchant/framework#readme",

"app.js",
"dom-view.js",
"morph.js",
"html.js"

@@ -36,4 +36,4 @@ ],

"@erickmerchant/eslint-config": "^3.0.0",
"@erickmerchant/prettier-config": "^1.2.0",
"jsdom": "^17.0.0",
"@erickmerchant/prettier-config": "^2.0.0",
"jsdom": "^18.0.0",
"tap": "^15.0.9"

@@ -40,0 +40,0 @@ },

@@ -7,7 +7,6 @@ # @erickmerchant/framework

```js
```javascript
import {
cache
createApp,
createDOMView,
html,

@@ -23,14 +22,12 @@ } from 'https://cdn.skypack.dev/@erickmerchant/framework?min'

```js
const target = document.querySelector('#app')
```javascript
const target = document.querySelector('#app');
const cls = getCls()
const cls = getCls();
const view = (state) => html`
<div id="app" class=${cls} />
`
`;
const domView = createDOMView(target, view)
app.render(domView)
app.render(view, target);
```

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

```js
```javascript
const view = (state) => html`

@@ -59,3 +56,3 @@ <div id="app">

</div>
`
`;
```

@@ -69,4 +66,4 @@

```js
const title = 'The heading'
```javascript
const title = 'The heading';

@@ -77,3 +74,3 @@ const heading = cache(

`
)
);

@@ -92,3 +89,3 @@ const view = (state) => html`

</div>
`
`;
```

@@ -100,7 +97,9 @@

```js
let hasFoo = true
Please note that `class` will get expanded to `className` and `for` will get expanded to `htmlFor`.
let barValue = "I'm the bar value"
```javascript
let hasFoo = true;
let barValue = "I'm the bar value";
const view = (state) => html`

@@ -117,3 +116,3 @@ <form id="app">

</form>
`
`;
```

@@ -125,6 +124,6 @@

```js
```javascript
const onClick = (e) => {
e.preventDefault()
}
e.preventDefault();
};

@@ -135,13 +134,15 @@ const view = (state) => html`

</div>
`
`;
```
The framework always uses event delegation. For instance with this click handler above a single event handler is added to the document with capture set to true. When a click occurs the target is checked to see if it was registered as having a handler. If it was then the handler is called with the event object.
## Changing state
```js
```javascript
const onClick = (e) => {
e.preventDefault()
e.preventDefault();
app.state = {count: app.state.count + 1}
}
app.state = {count: app.state.count + 1};
};

@@ -153,3 +154,3 @@ const view = (state) => html`

</div>
`
`;
```

@@ -159,4 +160,4 @@

```js
import {stringify, html} from '@erickmerchant/framework/stringify.js'
```javascript
import {stringify, html} from '@erickmerchant/framework/stringify.js';

@@ -174,7 +175,7 @@ const view = (state) => html`

</div>
`
`;
const staticHTML = stringify(view({items}))
const staticHTML = stringify(view({items}));
res.write(staticHTML)
res.write(staticHTML);
```

@@ -1,3 +0,3 @@

import {escape} from './escape.js'
import {tokenTypes} from './html.js'
import {escape} from './escape.js';
import {tokenTypes} from './html.js';

@@ -18,63 +18,63 @@ const selfClosing = [

'track',
'wbr'
]
'wbr',
];
export const stringify = (obj) => {
const {tag, attributes, children, variables} = obj
const {tag, attributes, children, variables} = obj;
let result = `<${tag}`
const isSelfClosing = selfClosing.includes(tag)
let result = `<${tag}`;
const isSelfClosing = selfClosing.includes(tag);
const reducedAttributes = []
const reducedAttributes = [];
for (let i = 0; i < attributes.length; i++) {
const attribute = attributes[i]
const attribute = attributes[i];
if (attribute.key.startsWith('@')) continue
if (attribute.key.startsWith('@')) continue;
const hasColon = attribute.key.startsWith(':')
const hasColon = attribute.key.startsWith(':');
if (hasColon) {
attribute.key = attribute.key.substring(1)
attribute.key = attribute.key.substring(1);
}
reducedAttributes.push(attribute)
reducedAttributes.push(attribute);
}
for (const attr of reducedAttributes) {
let value = attr.value
let value = attr.value;
if (attr.type === tokenTypes.variable) {
value = variables[value]
value = variables[value];
}
if (value === true) {
result += ` ${attr.key}`
result += ` ${attr.key}`;
} else if (value !== false) {
result += ` ${attr.key}="${escape(value)}"`
result += ` ${attr.key}="${escape(value)}"`;
}
}
result += '>'
result += '>';
if (!isSelfClosing) {
let i = 0
let i = 0;
const descendants = []
const descendants = [];
for (let i = 0; i < children.length; i++) {
let child = children[i]
let child = children[i];
if (child?.type === tokenTypes.variable) {
child = variables[child.value]
child = variables[child.value];
}
if (!Array.isArray(child)) {
child = [child]
child = [child];
}
for (let c of child) {
c ??= ''
c ??= '';
descendants.push(c)
descendants.push(c);
}

@@ -84,3 +84,3 @@ }

while (i < descendants.length) {
const child = descendants[i]
const child = descendants[i];

@@ -91,4 +91,4 @@ if (child) {

case tokenTypes.text:
result += tag !== 'style' ? escape(child.value) : child.value
break
result += tag !== 'style' ? escape(child.value) : child.value;
break;

@@ -98,18 +98,18 @@ case tokenTypes.node:

variables: child.view ? child.variables : variables,
...child
})
break
...child,
});
break;
}
} else {
result += tag !== 'style' ? escape(child) : child
result += tag !== 'style' ? escape(child) : child;
}
}
i++
i++;
}
result += `</${tag}>`
result += `</${tag}>`;
}
return result
}
return result;
};
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