als-render
Advanced tools
Comparing version 0.3.0 to 0.4.0
const render = require('./lib/index') | ||
module.exports = render |
@@ -1,17 +0,23 @@ | ||
const renderJsx = require('./render-jsx') | ||
const build = require('./build') | ||
const Require = require('als-require') | ||
const bundleFn = require('./bundle') | ||
const getBundle = require('./get-bundle') | ||
const UglifyJS = require("uglify-js"); | ||
function render(path,selector = 'body',data={}) { | ||
const app = new Require(path) | ||
app.getContent() | ||
for (const path in app.contents) { | ||
app.contents[path] = renderJsx(app.contents[path],path) | ||
const cache = {} | ||
function render(path, data = {},contextName = 'context',minified = false) { | ||
if (cache[path]) { | ||
const { resultFn, bundle } = cache[path] | ||
const rawHtml = resultFn(data).trim() | ||
return { rawHtml, bundle } | ||
} | ||
const context = {actions:[],components:{},counter:0} | ||
const resultFn = app.build({}, context, 'context') | ||
const modules = new Require(path) | ||
modules.getContent() | ||
const { resultFn, context } = build(modules,contextName) | ||
const rawHtml = resultFn(data).trim() | ||
return { rawHtml, bundle:bundleFn(app,selector,data) } | ||
let bundle = '(' + getBundle(modules,contextName).toString() + ')()' | ||
if(minified) bundle = UglifyJS.minify(bundle).code | ||
cache[path] = { resultFn, bundle } | ||
return { rawHtml, bundle } | ||
} | ||
module.exports = render |
{ | ||
"name": "als-render", | ||
"version": "0.3.0", | ||
"version": "0.4.0", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
}, | ||
"keywords": [ | ||
@@ -21,9 +18,11 @@ "ALS-Render", | ||
"author": "Alex Sorkin<alexsorkin1980@gmail.com>", | ||
"license": "ISC", | ||
"license": "MIT", | ||
"description": "Lightweight JS library for transforming JSX into raw HTML, enabling both server-side and client-side rendering without a virtual DOM. It offers a simplified component model with automated event handling and global state management.", | ||
"dependencies": { | ||
"als-object-serializer": "^1.0.0", | ||
"als-require": "1.0.1", | ||
"als-require": "^1.2.0", | ||
"uglify-js": "^3.18.0" | ||
}, | ||
"devDependencies": { | ||
"als-browser-test": "^1.1.0" | ||
} | ||
} |
# ALS-Render | ||
**Beta testing** | ||
**Alpha testing** | ||
**Not for production use** | ||
@@ -33,5 +33,3 @@ | ||
const { rawHtml, bundle } = render('./path/to/your/JSXComponent','body'); | ||
const page = `<!DOCTYPE html> | ||
const layout = (rawHtml,bundle) => `<!DOCTYPE html> | ||
<html lang="en"> | ||
@@ -47,5 +45,14 @@ <head> | ||
</body> | ||
<script>${bundle(false, true)}</script> | ||
<script>${bundle}</script> | ||
</html>`; | ||
app.get('/',(req,res) => res.end(page)) | ||
const path = './path/to/your/JSXComponent'; | ||
const contextName = 'context'; | ||
const minified = false; | ||
app.get('/',(req,res) => { | ||
const data = {}; | ||
const { rawHtml, bundle } = render(path,data,contextName,minified); | ||
res.end(layout(rawHtml, bundle)) | ||
}) | ||
``` | ||
@@ -74,4 +81,6 @@ | ||
<script> | ||
render('./path/to/your/JSXComponent', 'body') | ||
.then(() => { | ||
const data = {} | ||
const selector = 'body' | ||
const path = './path/to/your/JSXComponent' | ||
render(path, selector, data).then(() => { | ||
console.log('Component rendered successfully'); | ||
@@ -99,3 +108,3 @@ }); | ||
* **Context** - ALS-Render provides a global `context` variable accessible by default in each component. This context can be used to share data and functions across components, simplifying the management of global states or configurations. | ||
* The context includes properties: components,actions,counter,update and buildComponent which should stay without modification | ||
* The context includes properties: components,actions,counter,update and more which should stay without modification | ||
@@ -107,3 +116,6 @@ * **Event Naming** - Events in ALS-Render follow the standard HTML naming conventions (e.g., `onclick` instead of `onClick`). This adherence simplifies the learning curve for those familiar with traditional HTML and JavaScript. | ||
**No Lifecycle Hooks** - ALS-Render does not provide lifecycle hooks like those found in React (e.g., `useEffect`, `componentDidMount`). Developers need to manually manage setup, updates, and teardown of components, offering more control over these operations but requiring a more hands-on approach to managing component lifecycles. | ||
* **No Lifecycle Hooks** - ALS-Render does not provide lifecycle hooks like those found in React (e.g., `useEffect`, `componentDidMount`). Developers need to manually manage setup, updates, and teardown of components, offering more control over these operations but requiring a more hands-on approach to managing component lifecycles. | ||
* **onload** - ALS-Render has onload event for each element. | ||
* **updating** - Each component has `this.update(state,attributes,inner)` |
754
render.js
@@ -1,2 +0,1 @@ | ||
const render = (function() { | ||
const Require = (function(){ | ||
@@ -12,2 +11,3 @@ function isCyclyc(fullPath, path) { | ||
const fullPathParts = []; | ||
for (let part of [...relativeParts, ...pathParts]) { | ||
@@ -33,2 +33,3 @@ if (part === '..') { | ||
if (!exists.ok) { | ||
content = content.replace(match, '') | ||
console.warn(`The module "${modulePath}" can't be imported and will be replaced with null`) | ||
@@ -84,3 +85,3 @@ continue | ||
} | ||
function getFns(contextName,obj) { | ||
function getFns(contextName='context',obj) { | ||
const modulesLines = {} | ||
@@ -102,2 +103,3 @@ let curLastLine = 3 | ||
}).join('\n') | ||
const fn = new Function('modules', contextName, `function require(path) { return modules[path] || null }; | ||
@@ -115,3 +117,5 @@ ${fns}`) | ||
const char = Number(m[2]) | ||
const [path, { from, to }] = Object.entries(modulesLines).filter(([path, { from, to }]) => line >= from && line <= to)[0] | ||
const errorLines = Object.entries(modulesLines).filter(([path, { from, to }]) => line >= from && line <= to) | ||
if(errorLines.length === 0) return | ||
const [path, { from, to }] = errorLines[0] | ||
const at = string.match(/at\s(.*?)\s/)[1] | ||
@@ -130,2 +134,3 @@ return ` at ${at} ${path} (${line - from - 2}:${char})` | ||
} | ||
constructor(path) { | ||
@@ -137,2 +142,3 @@ this.contents = {} | ||
} | ||
async getContent() { | ||
@@ -145,2 +151,3 @@ if (this.contentReady) return this | ||
} | ||
build(modules = {}, context = {}, contextName = 'context') { | ||
@@ -154,334 +161,489 @@ const { fn, modulesLines, curLastLine } = getFns(contextName,this) | ||
})() | ||
async function render(path, selector = 'body', data = {}) { | ||
const context = { actions: [], components: {}, counter: 0 } | ||
const app = new Require(path) | ||
await app.getContent() | ||
for (const path in app.contents) { | ||
app.contents[path] = renderJsx(app.contents[path],path) | ||
const require = Require.getModule; | ||
const render = (function() { | ||
function parseError(error, modulesLines, curLastLine) { | ||
let [message, ...stack] = error.stack.split('\n') | ||
stack = stack.map(string => { | ||
const m = string.match(/<anonymous>:(\d*):(\d*)\)$/) | ||
if (!m) return | ||
const line = Number(m[1]) | ||
if (line + 1 === curLastLine) return | ||
const char = Number(m[2]) | ||
const errorLines = Object.entries(modulesLines).filter(([path, { from, to }]) => line >= from && line <= to) | ||
if(errorLines.length === 0) return | ||
const [path, { from, to }] = errorLines[0] | ||
const at = string.match(/at\s(.*?)\s/)[1] | ||
return ` at ${at} ${path} (${line - from - 2}:${char})` | ||
}).filter(Boolean) | ||
error.stack = message + '\n' + stack.join('\n') | ||
throw error | ||
} | ||
function parse(string) { | ||
const self = new Function(`return ${string}`)() | ||
function updateRecursive(obj) { | ||
for(let key in obj) { | ||
if(typeof obj[key] === 'function' && obj[key].name === Obj.recursiveName) obj[key] = obj[key](self) | ||
else if(obj[key] !== null && typeof obj[key] === 'object') updateRecursive(obj[key]) | ||
} | ||
} | ||
updateRecursive(self) | ||
return self | ||
} | ||
const resultFn = app.build({}, context, 'context') | ||
const rawHtml = resultFn(data).trim() | ||
bind(selector, rawHtml, context) | ||
} | ||
function bind(selector,rawHtml,context,update = true) { | ||
function actionToElement(selector,action) { | ||
const fn = function anonymous(modules,context | ||
) { | ||
function require(path) { return modules[path] || null }; | ||
modules['/lib/context.js'] = (function (){ | ||
const module = { exports: {} } | ||
const exports = module.exports | ||
class Context { | ||
constructor() { | ||
this.counter = 0; | ||
this.actions = []; | ||
this.components = {}; | ||
this.states = {}; | ||
} | ||
component(componentName, key) { | ||
const selector = `[component=${componentName}${key || ''}]` | ||
const element = document.querySelector(selector) | ||
if(!element) return | ||
action(element) | ||
return element | ||
} | ||
if(update) actionToElement(selector,element => element.innerHTML = rawHtml) | ||
context.actions.forEach(({key,selector,event,fn}) => { | ||
actionToElement(selector,element => element.addEventListener(event,fn)) | ||
}); | ||
context.actions = [] | ||
} | ||
function buildComponent(newBody,componentName,params) { | ||
return `function ${componentName}(props={},atts=[],inner='') { | ||
const originalFn = (${params}) => { | ||
${newBody} | ||
runActions() { | ||
this.actions.forEach(({ event, fn, selector }) => { | ||
const element = document.querySelector(selector); | ||
if (!element) return | ||
if(event === 'load') fn(element) | ||
else element.addEventListener(event, fn) | ||
}) | ||
this.actions = [] | ||
} | ||
let result = originalFn(props,inner) | ||
if(!result.startsWith('<>')) { | ||
result = result.replace(/<([\\s\\S]*?)\\>/,(m) => { // get first tag. | ||
atts.push('component="${componentName}"') | ||
if(props.key !== undefined) atts.push('key="'+props.key+'"') | ||
return m.slice(0,-1) + ' '+atts.join(' ')+'>' | ||
modifyResult(result, attributes=[], componentName, props={},inner) { | ||
const key = props.key || '' | ||
this.states[`${componentName}${key}`] = { attributes, props, inner } | ||
if (result.startsWith('<>')) return result.replace(/\<\/?\>/g, '') | ||
const curAttributes = [['component',componentName+key],...attributes] | ||
return result.replace(/<([\s\S]*?)\>/, (m) => { // get first tag. | ||
const attributes = curAttributes.map(([name,value]) => value ? `${name}="${value}"` : name) | ||
// TODO update style and class by adding | ||
return m.slice(0, -1) + ' ' + attributes + '>' | ||
}) | ||
} | ||
result = result.replace(/\\<\\/?\\>/g,'') | ||
return result | ||
update(componentName, props, attributes, inner) { | ||
const key = props.key || '' | ||
const selector = `${componentName}${key}` | ||
const lastState = this.states[selector] | ||
// if(lastState.props === props) return | ||
const element = this.component(componentName, key) | ||
if(!attributes) attributes = lastState.attributes | ||
if(!inner) inner = lastState.inner | ||
const componentFn = this.components[componentName] | ||
if (element && componentFn) { | ||
element.outerHTML = componentFn(props,attributes,inner) | ||
this.runActions() | ||
} | ||
} | ||
} | ||
${componentName}.update = function(props={},atts=[],inner) { | ||
let selector = '[component="${componentName}"]' | ||
if(props.key !== undefined) selector = [key="\${key}"]+selector | ||
document.querySelector(selector).outerHTML = ${componentName}(props,atts,inner) | ||
context.actions.forEach(({ selector, event, fn }) => { | ||
const element = document.querySelector(selector) | ||
if(element) element.addEventListener(event, fn); | ||
}); | ||
context.actions = [] | ||
module.exports = Context | ||
return module.exports; | ||
})(); | ||
modules['/lib/build-content/remove-comments.js'] = (function (){ | ||
const module = { exports: {} } | ||
const exports = module.exports | ||
function removeComments(code) { | ||
return code | ||
.replace(/\/\/.*(?=\n|$)/g, '') // Удаление однострочных комментариев | ||
.replace(/\{?\/\*[\s\S]*?\*\/\}?/g, '') // Удаление многострочных комментариев | ||
} | ||
context.components.${componentName} = ${componentName} | ||
` | ||
} | ||
function renderJsx(content,path) { | ||
const componentName = path.split('/').pop().replace('.js','') | ||
const isComponent = /[A-z]/.test(componentName[0]) | ||
const r = new RegExp('^.*'+componentName+'\\s*?\\(([\\s\\S]*?)\\)\\s*?\\{([\\s\\S]*)\\}','m') | ||
if(!isComponent) return content | ||
content = content.replace(r,(m,params,componentBody) => { | ||
const nodes = findJsx(componentBody) | ||
const tree = buildTree(nodes) | ||
let newBody = tree[0] | ||
return buildComponent(newBody,componentName,params) | ||
}) | ||
// console.log(content) | ||
return content | ||
} | ||
function findJsx(content) { | ||
const found = [] | ||
const openTagGroup = content.match(/\(\s*?\<([\s\S]*?)\>/) | ||
if (!openTagGroup) return [content] | ||
const openIndex = openTagGroup.index | ||
if (openIndex > 0) found.push(content.slice(0, openIndex)) | ||
if (openTagGroup[1].endsWith('/')) { | ||
const nodes = parser(openTagGroup[0]) | ||
nodes.forEach(node => found.push(node)); | ||
const leftNodes = findJsx(content.slice(openIndex + openTagGroup[0].length)) | ||
leftNodes.forEach(node => found.push(node)); | ||
return found | ||
} | ||
const closeIndex = getClose(content.slice(openIndex), openIndex, openTagGroup, content) | ||
if (closeIndex) { | ||
let nodes = parser(content.slice(openIndex, closeIndex)) | ||
nodes = nodes.map(node => { | ||
const { text, type } = node | ||
if (type === undefined && text.startsWith('{') && text.endsWith('}')) { | ||
const newNodes = findJsx(text) | ||
if (newNodes[0] === text) return node | ||
return newNodes | ||
module.exports = removeComments | ||
return module.exports; | ||
})(); | ||
modules['/lib/build-content/build-component/get-function.js'] = (function (){ | ||
const module = { exports: {} } | ||
const exports = module.exports | ||
function getFunction(content,componentName) { | ||
const all = '[\\s\\S]*?',s = '\\s*?' | ||
const r = new RegExp(`^\\s*?function${s}${componentName}${s}\\(${all}\\)${all}{`,'m') | ||
const fnStart = content.match(r) | ||
if(!fnStart) return null | ||
let count = 0,end; | ||
for(let i = fnStart.index+fnStart[0].length; i<content.length; i++) { | ||
let char = content[i],prevChar = content[i-1] | ||
if(char.match(/["'`]/) && prevChar !== '\\') { | ||
do { | ||
prevChar = content[i] | ||
i++ | ||
} while(content[i] !== char && prevChar !== '\\') | ||
} | ||
if(char === '{') count++ | ||
else if(char === '}') { | ||
if(count > 0) count -- | ||
else if(count === 0) { | ||
end = i+1 | ||
break | ||
} | ||
return node | ||
}); | ||
found.push(nodes) | ||
if (closeIndex < content.length) { | ||
const newNodes = findJsx(content.slice(closeIndex)) | ||
if (newNodes.length === 1) found.push(newNodes[0]) | ||
else found.push(newNodes) | ||
} | ||
} | ||
return found | ||
return content.slice(fnStart.index,end) | ||
} | ||
function getClose(temp,add,openTagGroup,content) { | ||
const r = new RegExp('<(\\/?)'+openTagGroup[1].split(' ')[0]+'(\\s|\>)') | ||
let opens = 0 | ||
function findClose(temp,add=0) { | ||
const match = temp.match(r) | ||
if(match === null) return null | ||
if(match[1] === '') opens++ | ||
if(match[1] === '/') opens-- | ||
let from = match.index+match[0].length | ||
if(opens === 0) { | ||
let closeIndex = from+add | ||
for(let i = closeIndex; i < content.length; i++) { | ||
if(content[i] !== ')') continue | ||
closeIndex = i+1 | ||
break | ||
} | ||
return closeIndex | ||
} else { | ||
return findClose(temp.slice(from),add+from) | ||
module.exports = getFunction | ||
return module.exports; | ||
})(); | ||
modules['/lib/build-content/build-component/index.js'] = (function (){ | ||
const module = { exports: {} } | ||
const exports = module.exports | ||
const getFunction = require('/lib/build-content/build-component/get-function.js') | ||
function buildComponentFn(content,componentName) { | ||
const originalFn = getFunction(content,componentName) | ||
if(originalFn === null) return content | ||
const newFunction = /*js*/`function ${componentName}(props={},attributes=[],inner) { | ||
const selector = '${componentName}'+(props.key || '') | ||
const main = { | ||
selector, | ||
update(props,$attributes=attributes,$inner = inner) { | ||
context.update('${componentName}',props,attributes,inner) | ||
}, | ||
get element() {return document.querySelector(selector)} | ||
} | ||
let originalFn = ${originalFn} | ||
originalFn = originalFn.bind(main) | ||
let result = originalFn(props,inner) | ||
return context.modifyResult(result,attributes,'${componentName}',props,inner) | ||
} | ||
return findClose(temp,add) | ||
context.components.${componentName} = ${componentName} | ||
context.components.${componentName}.update = (props,attributes,inner) => { | ||
context.update('${componentName}',props,attributes,inner) | ||
} | ||
` | ||
return content.replace(originalFn,newFunction) | ||
} | ||
function parser(jsx) { | ||
const nodes = [] | ||
let curNode = '', type, lastNode | ||
function addNode(text, curNodeText) { | ||
text.replace(/\s*/,(space) => { | ||
if(space.length > 0 && nodes[nodes.length-1].text !== space) { | ||
nodes.push({text:space,type:undefined}) | ||
} | ||
// return '' | ||
}) | ||
text = text.trim() | ||
lastNode = { text, type } | ||
type = undefined | ||
if (text.length === 0) return | ||
nodes.push(lastNode) | ||
curNode = curNodeText | ||
module.exports = buildComponentFn | ||
return module.exports; | ||
})(); | ||
modules['/lib/build-content/jsx/outer.js'] = (function (){ | ||
const module = { exports: {} } | ||
const exports = module.exports | ||
function getOuter(element) { | ||
let { tagName, selfClosed, attributes, props, isComponent, rest, inner } = element | ||
let outer = '' | ||
if(isComponent) { | ||
props = '{'+props.map(([name,value]) => `${name}:${value}`).join(',')+ (rest ? ','+rest : '') + '}' | ||
outer = '${'+`${tagName}(${props},${JSON.stringify(attributes)},\`${inner}\`)`+'}' | ||
} else { | ||
props = props.map(([name,value]) => ([name,'${'+value+'}'])) | ||
const atts = [...attributes,...props].map(([name,value]) => { | ||
return value ? `${name}="${value}"` : name | ||
}).join(' ') | ||
outer = `<${tagName}${atts.length ? ' '+atts : ''}>` | ||
if(!selfClosed) outer += inner + `</${tagName}>` | ||
} | ||
let skipBraces = 0 | ||
for (let i = 0; i < jsx.length; i++) { | ||
const char = jsx[i], prevChar = jsx[i - 1], nextChar = jsx[i + 1] | ||
let lastCurNode = curNode | ||
curNode = curNode + char | ||
if (char === '{') { | ||
if(nextChar === '/' && jsx[i+2] === '*') { // remove comments | ||
for (let k = i+2; k < jsx.length; k++) { | ||
if(jsx[k] !== '*') continue | ||
if(jsx[k+1] !== '/') continue | ||
if(jsx[k+2] !== '}') continue | ||
i = k+2; | ||
curNode = curNode.slice(0,-1) | ||
break | ||
} | ||
} else skipBraces++ | ||
} else if (skipBraces) { | ||
if (char === '}') skipBraces-- | ||
} else if (char === '<') { | ||
addNode(lastCurNode, '<') | ||
if (nextChar === '/') type = 'close' | ||
else type = 'open' | ||
} else if (char === '>') { | ||
if (type === 'open') addNode(curNode,'') | ||
else { | ||
if (prevChar === '/') { | ||
if(jsx[i-2] === '<') type = 'close' | ||
else type = 'single' | ||
} | ||
addNode(curNode, '') | ||
return outer | ||
} | ||
module.exports = getOuter | ||
return module.exports; | ||
})(); | ||
modules['/lib/build-content/jsx/breckets.js'] = (function (){ | ||
const module = { exports: {} } | ||
const exports = module.exports | ||
function getInsideBreckets(i, content) { | ||
let count = 0, quote = null; | ||
while (i < content.length) { | ||
i++ | ||
if (quote === null && /["'`]/.test(content[i])) quote = content[i] | ||
else if (quote) { | ||
if (content[i] === quote && content[i - 1] !== '\\') quote = null | ||
} else { | ||
if (content[i] === '{') count++ | ||
else if (content[i] === '}') { | ||
if (count > 0) count-- | ||
else break | ||
} | ||
} | ||
if (i === jsx.length - 1) addNode(curNode, '') | ||
} | ||
return nodes | ||
i++ | ||
return i | ||
} | ||
function buildAction(propname,value,attributes) { | ||
const event = propname.split('on')[1].toLowerCase() | ||
propname = event | ||
module.exports = getInsideBreckets | ||
return module.exports; | ||
})(); | ||
modules['/lib/build-content/jsx/attributes/build-action.js'] = (function (){ | ||
const module = { exports: {} } | ||
const exports = module.exports | ||
function buildAction(toAdd,element) { | ||
let [name,value] = toAdd | ||
const event = name.split('on')[1].toLowerCase() | ||
const fn = value | ||
value = '${context.counter++}' | ||
const selector = `[${propname}="\${context.counter-1}"]` | ||
const selector = `[${event}="\${context.counter-1}"]` | ||
const addToActions = '$'+`{context.actions.push({selector:\`${selector}\`,event:'${event}',fn:${fn}}) ? '' : ''}` | ||
value = value + addToActions | ||
attributes.push(`${propname}="${value}"`) | ||
element.attributes.push([event,value]) | ||
} | ||
function buildElement(isComponent, attributes, props, tagName, children) { | ||
if (!children) { | ||
const atts = `[${attributes.map(att => '`' + att + '`').join(',')}]` | ||
if (isComponent) return '$' + `{${tagName}(${props},${atts})}` | ||
else { | ||
const atts = attributes.length ? ' ' + attributes.join(' ') : '' | ||
return '<' + tagName + atts + '>' | ||
module.exports = buildAction | ||
return module.exports; | ||
})(); | ||
modules['/lib/build-content/jsx/attributes/build-prop.js'] = (function (){ | ||
const module = { exports: {} } | ||
const exports = module.exports | ||
const singleProps = ['checked', 'disabled', 'selected'] | ||
const buildAction = require('/lib/build-content/jsx/attributes/build-action.js') | ||
function buildProp(toAdd, to, element) { | ||
if(!toAdd) return | ||
let [name, value] = toAdd | ||
if(name === 'className') name = 'class' | ||
if(singleProps.includes(name)) { | ||
name = `\${${value} ? ${name} : ''}` | ||
value = undefined | ||
element.attributes.push([name]) | ||
} else if(to === 'props' && name.startsWith('on')) buildAction(toAdd,element) | ||
else element[to].push([name,value]) | ||
} | ||
module.exports = buildProp | ||
return module.exports; | ||
})(); | ||
modules['/lib/build-content/jsx/attributes/get-attributes.js'] = (function (){ | ||
const module = { exports: {} } | ||
const exports = module.exports | ||
const buildProp = require('/lib/build-content/jsx/attributes/build-prop.js') | ||
function getAttributes(char, i, element, content) { | ||
let prop = '', value = '', parsingProp = true, parsingValue = false, open, count = 0; | ||
function add(i,toAdd,to='attributes') { | ||
buildProp(toAdd,to, element) | ||
parsingProp = true; parsingValue = false; prop = ''; value = ''; open = null; | ||
while (content[i] === ' ') {i++} | ||
return i | ||
} | ||
while (char !== '>') { | ||
if(i >= content.length) break | ||
if (parsingProp) { | ||
if (char === '{') { | ||
while (i < content.length) { | ||
i++ | ||
char = content[i] | ||
if (char === '}') break | ||
element.rest += char | ||
} | ||
add(i) | ||
} else if (char === '=' || char === ' ') { | ||
if (prop.length > 0) { | ||
parsingProp = false; | ||
parsingValue = true | ||
} | ||
} else if(content[i+1] === '>') { | ||
if(char === '/') element.selfClosed = true | ||
else if (prop !== '') element.attributes.push([prop+char]) | ||
i++ | ||
break | ||
} else prop += char | ||
} else if (parsingValue) { | ||
if (!open) { | ||
if (/["'`{]/.test(char)) open = char | ||
else if (/[a-zA-Z]/.test(char)) { | ||
if (prop !== '') element.attributes.push([prop]) | ||
parsingProp = true; | ||
parsingValue = false | ||
prop = char; | ||
} | ||
} else { | ||
if (open === '{') { | ||
value += char | ||
if (char === '{') count++ | ||
else if (char === '}') { | ||
if (count > 0) count-- | ||
else i = add(i,[prop,value.slice(0,-1)],'props') | ||
} | ||
} else { | ||
if (content[i - 1] !== '\\' && char === open) i = add(i,[prop,value]) | ||
else value += char | ||
} | ||
} | ||
} | ||
i++ | ||
char = content[i] | ||
if (char === '>' && parsingValue) { | ||
value += char | ||
i++ | ||
char = content[i] | ||
} | ||
} | ||
if (isComponent) { | ||
const atts = `[${attributes.map(att => '`' + att + '`').join(',')}]` | ||
let inner = children.join('') | ||
if (inner.startsWith('${') && inner.endsWith('}')) inner = inner.slice(2, -1) | ||
else inner = '`' + inner + '`' | ||
return '$' + `{${tagName}(${props},${atts},${inner})}` | ||
} else { | ||
const atts = attributes.length ? ' ' + attributes.join(' ') : '' | ||
const openTag = '<' + tagName + atts + '>' | ||
const closeTag = '</' + tagName + '>' | ||
if (children.length === 0) return openTag + closeTag | ||
return openTag + children.join('') + closeTag | ||
i++ | ||
return i | ||
} | ||
module.exports = getAttributes | ||
return module.exports; | ||
})(); | ||
modules['/lib/build-content/jsx/element.js'] = (function (){ | ||
const module = { exports: {} } | ||
const exports = module.exports | ||
const getAttributes = require('/lib/build-content/jsx/attributes/get-attributes.js') | ||
const getInsideBreckets = require('/lib/build-content/jsx/breckets.js') | ||
const getOuter = require('/lib/build-content/jsx/outer.js') | ||
class Element { | ||
tagName = ''; rest = ''; inner = ''; attributes = []; props = []; selfClosed = false; | ||
constructor(content, i) { | ||
this.isComponent = /[A-Z]/.test(content[i + 1]) | ||
while (i < content.length) { | ||
i++ | ||
if (/[A-Za-z0-9.]/.test(content[i]) === false) break | ||
this.tagName += content[i] | ||
} | ||
this.i = getAttributes(content[i], i, this, content) | ||
if (this.selfClosed === false) this.getInner(content) | ||
} | ||
} | ||
function buildString(node) { | ||
if (typeof node === 'string') { | ||
const trimed = node.trim() | ||
if (node.startsWith('{')) return '$' + node | ||
else if (trimed.startsWith('(')) return node.replace('(', '`') | ||
else if (trimed.startsWith(')')) { | ||
if(trimed.startsWith(')}')) { | ||
if(trimed.slice(2).trim().startsWith('{')) return node.replace(')','`').replace('{','${') | ||
if(node === ')}') return node | ||
get outer() { return getOuter(this) } | ||
getInner(content) { | ||
const close = `</${this.tagName}>` | ||
let count = 0; | ||
while (this.i < content.length) { | ||
this.inner += content[this.i] | ||
if (this.inner.endsWith(`<${this.tagName}`)) count++ | ||
if (this.inner.endsWith(close)) { | ||
if (count > 0) count-- | ||
else { | ||
this.inner = this.inner.slice(0, - close.length).trim() | ||
break | ||
} | ||
} | ||
if(node.startsWith(').')) return node | ||
return node.replace(')', '`') | ||
this.i++ | ||
} | ||
node = node.replace(/\}[\s\S]*?(\$?\{)/g,(m,brace) => { | ||
if(brace === '{') { | ||
if(m.match(/const|let|var|\)|\(|,\s*?\{$/)) return m | ||
return m.slice(0,-1)+'${' | ||
} | ||
return m | ||
}) | ||
return node | ||
this.buildInner() | ||
} | ||
if (node.type === undefined) { | ||
if(/\{.*\}/.test(node.text)) return node.text.replace('{','${') | ||
if (node.text === '(' || node.text === ')') return '`' | ||
return node.text | ||
buildInner() { | ||
let newInner = '' | ||
if (this.inner.trim().length < 2) return | ||
if (!this.inner.includes('<') && !this.inner.includes('{')) return | ||
for (let i = 0; i < this.inner.length; i++) { | ||
if (this.inner[i] === '<') { | ||
const element = new Element(this.inner, i) | ||
newInner += element.outer | ||
i = element.i | ||
} else if (this.inner[i] === '{') { | ||
const start = i | ||
i = getInsideBreckets(i, this.inner) | ||
const inside = this.inner.slice(start, i) | ||
newInner += '$' + Element.jsxParser(inside) | ||
} else newInner += this.inner[i] | ||
} | ||
this.inner = newInner | ||
} | ||
} | ||
function buildTree(nodes) { | ||
let maxIndex = 0; | ||
function getChildren(tagName,i) { | ||
const closeTagIndex = findCloseTag(nodes, i, tagName) | ||
if (closeTagIndex > maxIndex) maxIndex = closeTagIndex | ||
return buildTree(nodes.slice(i + 1, closeTagIndex)) | ||
module.exports = Element | ||
return module.exports; | ||
})(); | ||
modules['/lib/build-content/jsx/jsx-parser.js'] = (function (){ | ||
const module = { exports: {} } | ||
const exports = module.exports | ||
const Element = require('/lib/build-content/jsx/element.js') | ||
function jsxParser(content) { | ||
let newContent = '' | ||
for (let i = 0; i < content.length; i++) { | ||
if(content[i] === '(') { | ||
let start = i; | ||
i++ | ||
while(content[i].trim().length === 0) {i++} | ||
if(content[i] === '<') { | ||
const element = new Element(content,i) | ||
i = element.i | ||
newContent += '`'+element.outer+'`' | ||
while(content[i] !== ')') {i++} | ||
} else newContent += content.slice(start,i+1) | ||
} else newContent += content[i] | ||
} | ||
nodes = nodes.map((node, i) => { | ||
if (i < maxIndex) return | ||
if (Array.isArray(node)) return buildTree(node) | ||
if (typeof node === 'string' || node.type === undefined) return buildString(node) | ||
if (node.text === '<>') return '<>'+getChildren('>',i)+'</>' | ||
const tagGroup = node.text.match(/^\<(\w.*?)(\s|\>)/) | ||
if (tagGroup === null || node.type !== 'open') return | ||
const { isComponent, tagName, attributes, props } = getElement(node) | ||
if (node.type === 'single') return buildElement(isComponent, attributes, props, tagName) | ||
return buildElement(isComponent, attributes, props, tagName, getChildren(tagName,i)) | ||
}).filter(Boolean); | ||
if (nodes.length >= 3 && nodes[0] === '`' && nodes[nodes.length - 1] === '`') { | ||
const code = nodes.flat()[1].trim() | ||
if (code.startsWith('${')) return [code.slice(2, -1)] | ||
return newContent | ||
} | ||
Element.jsxParser = jsxParser | ||
module.exports = jsxParser | ||
return module.exports; | ||
})(); | ||
modules['/lib/build-content/index.js'] = (function (){ | ||
const module = { exports: {} } | ||
const exports = module.exports | ||
const jsxParser = require('/lib/build-content/jsx/jsx-parser.js') | ||
const buildComponent = require('/lib/build-content/build-component/index.js') | ||
const removeComments = require('/lib/build-content/remove-comments.js') | ||
function buildContent(content,path) { | ||
const componentName = path.split('/').pop().replace(/\.js$/,'') | ||
const newContent = jsxParser(removeComments(content)) | ||
return buildComponent(newContent,componentName) | ||
} | ||
module.exports = buildContent | ||
return module.exports; | ||
})(); | ||
modules['/lib/build.js'] = (function (){ | ||
const module = { exports: {} } | ||
const exports = module.exports | ||
const buildContent = require('/lib/build-content/index.js') | ||
const Context = require('/lib/context.js') | ||
function build(app,contextName='context') { | ||
const context = new Context() | ||
for (const path in app.contents) { | ||
app.contents[path] = buildContent(app.contents[path],path) | ||
} | ||
if (nodes.flat().every(child => typeof child === 'string')) return [nodes.join('')] | ||
return nodes | ||
const resultFn = app.build({}, context, contextName) | ||
return {resultFn,context} | ||
} | ||
function findCloseTag(nodes,i,tagName) { | ||
let opens = 0, closeTagIndex; | ||
for (let k = i + 1; k < nodes.length; k++) { | ||
if (Array.isArray(nodes[k])) continue | ||
if (nodes[k].type === 'open' && nodes[k].text.startsWith('<' + tagName)) opens++ | ||
if (nodes[k].type === 'close' && nodes[k].text.startsWith('</' + tagName)) { | ||
if (opens > 0) opens-- | ||
else { | ||
closeTagIndex = k | ||
break | ||
} | ||
module.exports = build | ||
return module.exports; | ||
})(); | ||
modules['/lib/browser.js'] = (function (){ | ||
const module = { exports: {} } | ||
const exports = module.exports | ||
const build = require('/lib/build.js') | ||
async function render(path, selector = 'body', data = {}, contextName) { | ||
const modules = new Require(path) | ||
await modules.getContent() | ||
const { resultFn, context } = build(modules, contextName) | ||
if (selector) { | ||
const element = document.querySelector(selector) | ||
if(element) { | ||
element.innerHTML = resultFn(data).trim() | ||
context.runActions() | ||
} | ||
} | ||
return closeTagIndex | ||
return context | ||
} | ||
function getAttributes(segments, isComponent) { | ||
const attributes = [], props = []; | ||
let rest; | ||
for (let i = 0; i < segments.length; i++) { | ||
let hasBraces = false | ||
let [propname, value] = segments[i].split('=') | ||
if (propname === '/') continue | ||
if (value && value.startsWith('{')) { | ||
hasBraces = true | ||
while (!value.endsWith('}')) { | ||
i++ | ||
value = value + ' ' +segments[i] | ||
} | ||
} else if(value) { | ||
const quote = value[0] | ||
while (!value.endsWith(quote)) { | ||
i++ | ||
value = value + ' ' + segments[i] | ||
} | ||
} | ||
if (propname.startsWith('{...')) { | ||
rest = propname.slice(1, -1) | ||
continue | ||
} | ||
if (value) value = value.slice(1, -1) | ||
if (propname === 'checked' || propname === 'disabled') { | ||
attributes.push('${' + value + ` ? '${propname}' : ''}`) | ||
continue | ||
} | ||
if (propname === 'className') propname = 'class' | ||
else if (propname.startsWith('on')) { | ||
buildAction(propname,value,attributes) | ||
continue | ||
} | ||
if (!value) attributes.push(propname) | ||
else if (!hasBraces) attributes.push(`${propname}="${value}"`) | ||
else if (isComponent) props.push(`${propname}:${value}`) | ||
else attributes.push(`${propname}="\${${value}}"`) | ||
module.exports = render | ||
return module.exports; | ||
})(); | ||
return modules['/lib/browser.js'] | ||
}; | ||
const modules = {} | ||
const context = parse(`{}`); | ||
try { | ||
let result = fn(modules, context) | ||
return result | ||
} catch(error) { | ||
parseError(error, {"/lib/context.js":{"from":4,"to":62},"/lib/build-content/remove-comments.js":{"from":63,"to":74},"/lib/build-content/build-component/get-function.js":{"from":75,"to":106},"/lib/build-content/build-component/index.js":{"from":107,"to":140},"/lib/build-content/jsx/outer.js":{"from":141,"to":163},"/lib/build-content/jsx/breckets.js":{"from":164,"to":188},"/lib/build-content/jsx/attributes/build-action.js":{"from":189,"to":205},"/lib/build-content/jsx/attributes/build-prop.js":{"from":206,"to":225},"/lib/build-content/jsx/attributes/get-attributes.js":{"from":226,"to":297},"/lib/build-content/jsx/element.js":{"from":298,"to":360},"/lib/build-content/jsx/jsx-parser.js":{"from":361,"to":388},"/lib/build-content/index.js":{"from":389,"to":405},"/lib/build.js":{"from":406,"to":423},"/lib/browser.js":{"from":424,"to":446}}, 446) | ||
} | ||
if (rest) props.push(rest) | ||
return { attributes, props:`{${props.join(',')}}` } | ||
} | ||
function getElement(node) { | ||
const segments = node.text.trim().slice(1, -1).split(/\s/).filter(Boolean) | ||
if (segments.length === 1 && segments[0].endsWith('/')) { | ||
node.type = 'single'; | ||
segments[0] = segments[0].slice(0, -1) | ||
} else if (segments[segments.length - 1] === '/') node.type = 'single' | ||
if (node.type === 'single' && segments.length > 1) segments.pop() | ||
const tagName = segments.shift() | ||
const isComponent = tagName.match(/[A-Z]/) !== null | ||
let { attributes, props } = getAttributes(segments, isComponent) | ||
return { tagName, isComponent, attributes, props } | ||
} | ||
return render | ||
})() | ||
})() |
@@ -1,2 +0,2 @@ | ||
let render=function(){let l=function(){function l(t,e){if(s.contents[t]&&s.contents[t].children.includes(e))throw`cyclic dependency between ${e} and `+t}function c(t,e){var n,t=t.split("/"),r=[];for(n of[...e.split("/").slice(0,-1),...t])".."===n?0<r.length&&".."!==r[r.length-1]?r.pop():r.push(n):"."!==n&&r.push(n);e=r.join("/");return e.endsWith(".js")?e:e+".js"}async function a(t,e="text"){t=await fetch(t);if(t.ok)return t[e]();throw new Error("HTTP error! status: "+t.status)}async function t({contents:r,fullPath:t},o){let s=async i=>{if(void 0===r[i]){if(!o.contents[i]){let t=await a(i),r=[],s=[];t=t.replace(/^(?!\/\/|\/\*.*\*\/).*require\(["'`](.*)["'`]\)/gm,(t,e)=>{var n;return e.startsWith(".")?(l(n=c(e,i),i),r.push(n),t.replace(e,n)):(s.push({match:t,modulePath:e}),t)}),t=await async function(t,e,n){if(0!==t.length)for(var{match:r,modulePath:s}of t){var i=`/node_modules/${s}/package.json`;(await fetch(i,{method:"HEAD"})).ok?({main:i="index.js"}=await a(i,"json"),l(i=`/node_modules/${s}/`+i,s),e.push(i),n=n.replace(r,r.replace(s,i))):console.warn(`The module "${s}" can't be imported and will be replaced with null`)}return n}(s,r,t),o.contents[i]={content:t,children:r}}let{content:t,children:e}=o.contents[i];r[i]=t;for(var n of e)await s(n)}};await s(t)}class s{static contents={};static async getModule(t,e,n,r){t=new s(t);return await t.getContent(),t.build(r,e,n)}constructor(t){this.contents={},this.path=t,this.fullPath=c(t,location.pathname),this.contentReady=!1}async getContent(){return this.contentReady||(await t(this,s),this.keys=function(e,n){let r=new Set,s=t=>{t.forEach(t=>{e[t]&&(s(n.contents[t].children),r.add(t))})};return s(Object.keys(e).reverse()),Array.from(r)}(this.contents,s),this.contentReady=!0),this}build(t={},e={},r="context"){var{fn:r,modulesLines:s,curLastLine:i}=function(t,r){let s={},i=3;var e=r.keys.map((t,e)=>{let n=`modules['${t}'] = (function (){ | ||
let Require=function(){function i(t,e){if(o.contents[t]&&o.contents[t].children.includes(e))throw`cyclic dependency between ${e} and `+t}function c(t,e){var n,t=t.split("/"),r=[];for(n of[...e.split("/").slice(0,-1),...t])".."===n?0<r.length&&".."!==r[r.length-1]?r.pop():r.push(n):"."!==n&&r.push(n);e=r.join("/");return e.endsWith(".js")?e:e+".js"}async function u(t,e="text"){t=await fetch(t);if(t.ok)return t[e]();throw new Error("HTTP error! status: "+t.status)}async function t({contents:r,fullPath:t},a){let o=async s=>{if(void 0===r[s]){if(!a.contents[s]){let t=await u(s),r=[],o=[];t=t.replace(/^(?!\/\/|\/\*.*\*\/).*require\(["'`](.*)["'`]\)/gm,(t,e)=>{var n;return e.startsWith(".")?(i(n=c(e,s),s),r.push(n),t.replace(e,n)):(o.push({match:t,modulePath:e}),t)}),t=await async function(t,e,n){if(0!==t.length)for(var{match:r,modulePath:o}of t){var s=`/node_modules/${o}/package.json`;(await fetch(s,{method:"HEAD"})).ok?({main:s="index.js"}=await u(s,"json"),i(s=`/node_modules/${o}/`+s,o),e.push(s),n=n.replace(r,r.replace(o,s))):console.warn(`The module "${o}" can't be imported and will be replaced with null`)}return n}(o,r,t),a.contents[s]={content:t,children:r}}let{content:t,children:e}=a.contents[s];r[s]=t;for(var n of e)await o(n)}};await o(t)}class o{static contents={};static async getModule(t,e,n,r){t=new o(t);return await t.getContent(),t.build(r,e,n)}constructor(t){this.contents={},this.path=t,this.fullPath=c(t,location.pathname),this.contentReady=!1}async getContent(){return this.contentReady||(await t(this,o),this.keys=function(e,n){let r=new Set,o=t=>{t.forEach(t=>{e[t]&&(o(n.contents[t].children),r.add(t))})};return o(Object.keys(e).reverse()),Array.from(r)}(this.contents,o),this.contentReady=!0),this}build(t={},e={},r="context"){var{fn:r,modulesLines:o,curLastLine:s}=function(t="context",r){let o={},s=3;var e=r.keys.map((t,e)=>{let n=`modules['${t}'] = (function (){ | ||
const module = { exports: {} } | ||
@@ -7,29 +7,22 @@ const exports = module.exports | ||
})();`;return e===r.keys.length-1&&(n+=` | ||
return modules['${t}']`),s[t]={from:i+1},i+=n.split("\n").length,s[t].to=i,n}).join("\n");return{fn:new Function("modules",t,`function require(path) { return modules[path] || null }; | ||
`+e),modulesLines:s,curLastLine:i}}(r,this);try{return r(t,e)}catch(n){{r=n;var o=s;var l=i;let[t,...e]=r.stack.split("\n");throw e=e.map(t=>{var e,r,s,i=t.match(/<anonymous>:(\d*):(\d*)\)$/);if(i){let n=Number(i[1]);if(n+1!==l)return i=Number(i[2]),[e,{from:r,to:s}]=Object.entries(o).filter(([,{from:t,to:e}])=>n>=t&&n<=e)[0],` at ${t.match(/at\s(.*?)\s/)[1]} ${e} (${n-r-2}:${i})`}}).filter(Boolean),r.stack=t+"\n"+e.join("\n"),r;return}}}}return s}();l.getModule;function c(t,e,n,s){let i=new RegExp("<(\\/?)"+n[1].split(" ")[0]+"(\\s|>)"),o=0;return function t(e,n=0){var r=e.match(i);if(null===r)return null;""===r[1]&&o++,"/"===r[1]&&o--;r=r.index+r[0].length;if(0!==o)return t(e.slice(r),n+r);{let e=r+n;for(let t=e;t<s.length;t++)if(")"===s[t]){e=t+1;break}return e}}(t,e)}function a(n){let r=[],s="",i,o;function t(t,e){t.replace(/\s*/,t=>{0<t.length&&r[r.length-1].text!==t&&r.push({text:t,type:void 0})}),t=t.trim(),o={text:t,type:i},i=void 0,0!==t.length&&(r.push(o),s=e)}let l=0;for(let e=0;e<n.length;e++){var c=n[e],a=n[e-1],u=n[e+1],f=s;if(s+=c,"{"===c)if("/"===u&&"*"===n[e+2]){for(let t=e+2;t<n.length;t++)if("*"===n[t]&&"/"===n[t+1]&&"}"===n[t+2]){e=t+2,s=s.slice(0,-1);break}}else l++;else l?"}"===c&&l--:"<"===c?(t(f,"<"),i="/"===u?"close":"open"):">"===c&&("open"!==i&&"/"===a&&(i="<"===n[e-2]?"close":"single"),t(s,""));e===n.length-1&&t(s,"")}return r}function u(t,e,n,r,s){if(!s)return i=`[${e.map(t=>"`"+t+"`").join(",")}]`,t?"$"+`{${r}(${n},${i})}`:"<"+r+(e.length?" "+e.join(" "):"")+">";if(t){var i=`[${e.map(t=>"`"+t+"`").join(",")}]`;let t=s.join("");return"$"+`{${r}(${n},${i},${t=t.startsWith("${")&&t.endsWith("}")?t.slice(2,-1):"`"+t+"`"})}`}return t="<"+r+(e.length?" "+e.join(" "):"")+">",n="</"+r+">",0===s.length?t+n:t+s.join("")+n}function f(t){if("string"==typeof t){var e=t.trim();if(t.startsWith("{"))return"$"+t;if(e.startsWith("("))return t.replace("(","`");if(e.startsWith(")")){if(e.startsWith(")}")){if(e.slice(2).trim().startsWith("{"))return t.replace(")","`").replace("{","${");if(")}"===t)return t}return t.startsWith(").")?t:t.replace(")","`")}return t=t.replace(/\}[\s\S]*?(\$?\{)/g,(t,e)=>"{"!==e||t.match(/const|let|var|\)|\(|,\s*?\{$/)?t:t.slice(0,-1)+"${")}if(void 0===t.type)return/\{.*\}/.test(t.text)?t.text.replace("{","${"):"("===t.text||")"===t.text?"`":t.text}function p(e,n,r){let s=0,i;for(let t=n+1;t<e.length;t++)if(!Array.isArray(e[t])&&("open"===e[t].type&&e[t].text.startsWith("<"+r)&&s++,"close"===e[t].type)&&e[t].text.startsWith("</"+r)){if(!(0<s)){i=t;break}s--}return i}function h(t){var e=t.text.trim().slice(1,-1).split(/\s/).filter(Boolean),t=(1===e.length&&e[0].endsWith("/")?(t.type="single",e[0]=e[0].slice(0,-1)):"/"===e[e.length-1]&&(t.type="single"),"single"===t.type&&1<e.length&&e.pop(),e.shift()),n=null!==t.match(/[A-Z]/),{attributes:e,props:r}=function(s,i){var o,l,c,a,u,f,p=[],h=[];let d;for(let r=0;r<s.length;r++){let t=!1,[e,n]=s[r].split("=");if("/"!==e){if(n&&n.startsWith("{"))for(t=!0;!n.endsWith("}");)r++,n=n+" "+s[r];else if(n)for(var m=n[0];!n.endsWith(m);)r++,n=n+" "+s[r];if(e.startsWith("{..."))d=e.slice(1,-1);else if(n=n&&n.slice(1,-1),"checked"===e||"disabled"===e)p.push("${"+n+` ? '${e}' : ''}`);else{if("className"===e)e="class";else if(e.startsWith("on")){o=e,l=n,c=p,f=u=a=void 0,a=o.split("on")[1].toLowerCase(),u=l,l="${context.counter++}",f=`[${o=a}="\${context.counter-1}"]`,c.push(o+`="${l+="$"+`{context.actions.push({selector:\`${f}\`,event:'${a}',fn:${u}}) ? '' : ''}`}"`);continue}n?t?i?h.push(e+":"+n):p.push(`${e}="\${${n}}"`):p.push(`${e}="${n}"`):p.push(e)}}}return d&&h.push(d),{attributes:p,props:`{${h.join(",")}}`}}(e,n);return{tagName:t,isComponent:n,attributes:e,props:r}}return async function(t,e="body",n={}){var r={actions:[],components:{},counter:0},s=new l(t);await s.getContent();for(let t in s.contents)s.contents[t]=function(t,e){let s=e.split("/").pop().replace(".js",""),n=/[A-z]/.test(s[0]),r=new RegExp("^.*"+s+"\\s*?\\(([\\s\\S]*?)\\)\\s*?\\{([\\s\\S]*)\\}","m");return t=n?t.replace(r,(t,e,n)=>{var r,n=function r(s){let o=0;function l(t,e){let n=p(s,e,t);return n>o&&(o=n),r(s.slice(e+1,n))}s=s.map((s,i)=>{if(!(i<o)){if(Array.isArray(s))return r(s);if("string"==typeof s||void 0===s.type)return f(s);if("<>"===s.text)return"<>"+l(">",i)+"</>";let t=s.text.match(/^\<(\w.*?)(\s|\>)/);if(null!==t&&"open"===s.type){let{isComponent:t,tagName:e,attributes:n,props:r}=h(s);return"single"===s.type?u(t,n,r,e):u(t,n,r,e,l(e,i))}}}).filter(Boolean);if(3<=s.length&&"`"===s[0]&&"`"===s[s.length-1]){let t=s.flat()[1].trim();if(t.startsWith("${"))return[t.slice(2,-1)]}if(s.flat().every(t=>"string"==typeof t))return[s.join("")];return s}(function r(n){let s=[];let i=n.match(/\(\s*?\<([\s\S]*?)\>/);if(!i)return[n];let o=i.index;0<o&&s.push(n.slice(0,o));if(i[1].endsWith("/")){let t=a(i[0]),e=(t.forEach(t=>s.push(t)),r(n.slice(o+i[0].length)));return e.forEach(t=>s.push(t)),s}let e=c(n.slice(o),o,i,n);if(e){let t=a(n.slice(o,e));if(t=t.map(e=>{let{text:n,type:t}=e;if(void 0===t&&n.startsWith("{")&&n.endsWith("}")){let t=r(n);return t[0]===n?e:t}return e}),s.push(t),e<n.length){let t=r(n.slice(e));1===t.length?s.push(t[0]):s.push(t)}}return s}(n))[0];return n=n,`function ${r=s}(props={},atts=[],inner='') { | ||
const originalFn = (${e}) => { | ||
${n} | ||
return modules['${t}']`),o[t]={from:s+1},s+=n.split("\n").length,o[t].to=s,n}).join("\n");return{fn:new Function("modules",t,`function require(path) { return modules[path] || null }; | ||
`+e),modulesLines:o,curLastLine:s}}(r,this);try{return r(t,e)}catch(n){{r=n;var a=o;var i=s;let[t,...e]=r.stack.split("\n");throw e=e.map(t=>{var e=t.match(/<anonymous>:(\d*):(\d*)\)$/);if(e){let n=Number(e[1]);if(n+1!==i){var r,o,e=Number(e[2]),s=Object.entries(a).filter(([,{from:t,to:e}])=>n>=t&&n<=e);if(0!==s.length)return[s,{from:r,to:o}]=s[0],` at ${t.match(/at\s(.*?)\s/)[1]} ${s} (${n-r-2}:${e})`}}}).filter(Boolean),r.stack=t+"\n"+e.join("\n"),r;return}}}}return o}(),require=Require.getModule; | ||
const render = (()=>{function t(e,t){function l(t){return e[t]||null}var n;return e["/lib/context.js"]=((n={exports:{}}).exports=class{constructor(){this.counter=0,this.actions=[],this.components={},this.states={}}component(t,e){return document.querySelector(`[component=${t}${e||""}]`)}runActions(){this.actions.forEach(({event:t,fn:e,selector:n})=>{n=document.querySelector(n);n&&("load"===t?e(n):n.addEventListener(t,e))}),this.actions=[]}modifyResult(t,e=[],n,r={},s){var i=r.key||"";if(this.states[""+n+i]={attributes:e,props:r,inner:s},t.startsWith("<>"))return t.replace(/\<\/?\>/g,"");let o=[["component",n+i],...e];return t.replace(/<([\s\S]*?)\>/,t=>{var e=o.map(([t,e])=>e?t+`="${e}"`:t);return t.slice(0,-1)+" "+e+">"})}update(t,e,n,r){var s=e.key||"",i=this.states[""+t+s],s=this.component(t,s),i=(n=n||i.attributes,r=r||i.inner,this.components[t]);s&&i&&(s.outerHTML=i(e,n,r),this.runActions())}},n.exports),e["/lib/build-content/remove-comments.js"]=((n={exports:{}}).exports=function(t){return t.replace(/\/\/.*(?=\n|$)/g,"").replace(/\{?\/\*[\s\S]*?\*\/\}?/g,"")},n.exports),e["/lib/build-content/build-component/get-function.js"]=((n={exports:{}}).exports=function(r,t){var e="[\\s\\S]*?",t=new RegExp(`^\\s*?function\\s*?${t}\\s*?\\(${e}\\)${e}{`,"m");if(!(e=r.match(t)))return null;let s=0,i;for(let n=e.index+e[0].length;n<r.length;n++){let t=r[n],e=r[n-1];if(t.match(/["'`]/)&&"\\"!==e)for(;e=r[n],r[++n]!==t&&"\\"!==e;);if("{"===t)s++;else if("}"===t)if(0<s)s--;else if(0===s){i=n+1;break}}return r.slice(e.index,i)},n.exports),e["/lib/build-content/build-component/index.js"]=(()=>{var t={exports:{}};let r=l("/lib/build-content/build-component/get-function.js");return t.exports=function(t,e){var n=r(t,e);return null===n?t:t.replace(n,`function ${e}(props={},attributes=[],inner) { | ||
const selector = '${e}'+(props.key || '') | ||
const main = { | ||
selector, | ||
update(props,$attributes=attributes,$inner = inner) { | ||
context.update('${e}',props,attributes,inner) | ||
}, | ||
get element() {return document.querySelector(selector)} | ||
} | ||
let originalFn = ${n} | ||
originalFn = originalFn.bind(main) | ||
let result = originalFn(props,inner) | ||
return context.modifyResult(result,attributes,'${e}',props,inner) | ||
} | ||
let result = originalFn(props,inner) | ||
if(!result.startsWith('<>')) { | ||
result = result.replace(/<([\\s\\S]*?)\\>/,(m) => { // get first tag. | ||
atts.push('component="${r}"') | ||
if(props.key !== undefined) atts.push('key="'+props.key+'"') | ||
return m.slice(0,-1) + ' '+atts.join(' ')+'>' | ||
}) | ||
context.components.${e} = ${e} | ||
context.components.${e}.update = (props,attributes,inner) => { | ||
context.update('${e}',props,attributes,inner) | ||
} | ||
result = result.replace(/\\<\\/?\\>/g,'') | ||
return result | ||
} | ||
${r}.update = function(props={},atts=[],inner) { | ||
let selector = '[component="${r}"]' | ||
if(props.key !== undefined) selector = [key="\${key}"]+selector | ||
document.querySelector(selector).outerHTML = ${r}(props,atts,inner) | ||
context.actions.forEach(({ selector, event, fn }) => { | ||
const element = document.querySelector(selector) | ||
if(element) element.addEventListener(event, fn); | ||
}); | ||
context.actions = [] | ||
} | ||
context.components.${r} = ${r} | ||
`}):t}(s.contents[t],t);var[t,i,e,n=!0]=[e,s.build({},r,"context")(n).trim(),r];function o(t,e){t=document.querySelector(t);t&&e(t)}n&&o(t,t=>t.innerHTML=i),e.actions.forEach(({selector:t,event:e,fn:n})=>{o(t,t=>t.addEventListener(e,n))}),e.actions=[]}}(); | ||
`)},t.exports})(),e["/lib/build-content/jsx/outer.js"]=((n={exports:{}}).exports=function(t){let{tagName:e,selfClosed:n,attributes:r,props:s,isComponent:i,rest:o,inner:l}=t,u="";return i?(s="{"+s.map(([t,e])=>t+":"+e).join(",")+(o?","+o:"")+"}",u="${"+`${e}(${s},${JSON.stringify(r)},\`${l}\`)`+"}"):(s=s.map(([t,e])=>[t,"${"+e+"}"]),t=[...r,...s].map(([t,e])=>e?t+`="${e}"`:t).join(" "),u=`<${e}${t.length?" "+t:""}>`,n||(u+=l+`</${e}>`)),u},n.exports),e["/lib/build-content/jsx/breckets.js"]=((n={exports:{}}).exports=function(t,e){let n=0,r=null;for(;t<e.length;)if(t++,null===r&&/["'`]/.test(e[t]))r=e[t];else if(r)e[t]===r&&"\\"!==e[t-1]&&(r=null);else if("{"===e[t])n++;else if("}"===e[t]){if(!(0<n))break;n--}return++t},n.exports),e["/lib/build-content/jsx/attributes/build-action.js"]=((n={exports:{}}).exports=function(t,e){var[t,n]=t,t=t.split("on")[1].toLowerCase(),r=n,n="${context.counter++}";e.attributes.push([t,n+="$"+`{context.actions.push({selector:\`${`[${t}="\${context.counter-1}"]`}\`,event:'${t}',fn:${r}}) ? '' : ''}`])},n.exports),e["/lib/build-content/jsx/attributes/build-prop.js"]=(()=>{var t={exports:{}};let i=["checked","disabled","selected"],o=l("/lib/build-content/jsx/attributes/build-action.js");return t.exports=function(n,r,s){if(n){let[t,e]=n;"className"===t&&(t="class"),i.includes(t)?(t=`\${${e} ? ${t} : ''}`,e=void 0,s.attributes.push([t])):"props"===r&&t.startsWith("on")?o(n,s):s[r].push([t,e])}},t.exports})(),e["/lib/build-content/jsx/attributes/get-attributes.js"]=(()=>{var t={exports:{}};let a=l("/lib/build-content/jsx/attributes/build-prop.js");return t.exports=function(t,e,r,s){let i="",o="",l=!0,u=!1,c,n=0;function b(t,e,n="attributes"){for(a(e,n,r),l=!0,u=!1,i="",o="",c=null;" "===s[t];)t++;return t}for(;">"!==t&&!(e>=s.length);){if(l)if("{"===t){for(;e<s.length&&"}"!==(t=s[++e]);)r.rest+=t;b(e)}else if("="===t||" "===t)0<i.length&&(l=!1,u=!0);else{if(">"===s[e+1]){"/"===t?r.selfClosed=!0:""!==i&&r.attributes.push([i+t]),e++;break}i+=t}else u&&(c?"{"===c?(o+=t,"{"===t?n++:"}"===t&&(0<n?n--:e=b(e,[i,o.slice(0,-1)],"props"))):"\\"!==s[e-1]&&t===c?e=b(e,[i,o]):o+=t:/["'`{]/.test(t)?c=t:/[a-zA-Z]/.test(t)&&(""!==i&&r.attributes.push([i]),l=!0,u=!1,i=t));">"===(t=s[++e])&&u&&(o+=t,t=s[++e])}return++e},t.exports})(),e["/lib/build-content/jsx/element.js"]=(()=>{var t={exports:{}};let n=l("/lib/build-content/jsx/attributes/get-attributes.js"),s=l("/lib/build-content/jsx/breckets.js"),e=l("/lib/build-content/jsx/outer.js");class i{tagName="";rest="";inner="";attributes=[];props=[];selfClosed=!1;constructor(t,e){for(this.isComponent=/[A-Z]/.test(t[e+1]);e<t.length&&!1!==/[A-Za-z0-9.]/.test(t[++e]);)this.tagName+=t[e];this.i=n(t[e],e,this,t),!1===this.selfClosed&&this.getInner(t)}get outer(){return e(this)}getInner(t){var e=`</${this.tagName}>`;let n=0;for(;this.i<t.length;){if(this.inner+=t[this.i],this.inner.endsWith("<"+this.tagName)&&n++,this.inner.endsWith(e)){if(!(0<n)){this.inner=this.inner.slice(0,-e.length).trim();break}n--}this.i++}this.buildInner()}buildInner(){let e="";if(!(this.inner.trim().length<2)&&(this.inner.includes("<")||this.inner.includes("{"))){for(let t=0;t<this.inner.length;t++){var n,r;"<"===this.inner[t]?(n=new i(this.inner,t),e+=n.outer,t=n.i):"{"===this.inner[t]?(n=t,t=s(t,this.inner),r=this.inner.slice(n,t),e+="$"+i.jsxParser(r)):e+=this.inner[t]}this.inner=e}}}return t.exports=i,t.exports})(),e["/lib/build-content/jsx/jsx-parser.js"]=(()=>{var t={exports:{}};let i=l("/lib/build-content/jsx/element.js");function e(e){let n="";for(let t=0;t<e.length;t++)if("("===e[t]){var r=t;for(t++;0===e[t].trim().length;)t++;if("<"===e[t]){var s=new i(e,t);for(t=s.i,n+="`"+s.outer+"`";")"!==e[t];)t++}else n+=e.slice(r,t+1)}else n+=e[t];return n}return i.jsxParser=e,t.exports=e,t.exports})(),e["/lib/build-content/index.js"]=(()=>{var t={exports:{}};let n=l("/lib/build-content/jsx/jsx-parser.js"),r=l("/lib/build-content/build-component/index.js"),s=l("/lib/build-content/remove-comments.js");return t.exports=function(t,e){return e=e.split("/").pop().replace(/\.js$/,""),t=n(s(t)),r(t,e)},t.exports})(),e["/lib/build.js"]=(()=>{var t={exports:{}};let s=l("/lib/build-content/index.js"),i=l("/lib/context.js");return t.exports=function(t,e="context"){var n,r=new i;for(n in t.contents)t.contents[n]=s(t.contents[n],n);return{resultFn:t.build({},r,e),context:r}},t.exports})(),e["/lib/browser.js"]=(()=>{var t={exports:{}};let s=l("/lib/build.js");return t.exports=async function(t,e="body",n={},r){await(t=new Require(t)).getContent();var{resultFn:t,context:r}=s(t,r);return e&&(e=document.querySelector(e))&&(e.innerHTML=t(n).trim(),r.runActions()),r},t.exports})(),e["/lib/browser.js"]}{var e;let r=new Function("return "+"{}")();(function t(e){for(var n in e)"function"==typeof e[n]&&e[n].name===Obj.recursiveName?e[n]=e[n](r):null!==e[n]&&"object"==typeof e[n]&&t(e[n])})(r),r}try{t({})}catch(n){{var r=n;var o={"/lib/context.js":{from:4,to:62},"/lib/build-content/remove-comments.js":{from:63,to:74},"/lib/build-content/build-component/get-function.js":{from:75,to:106},"/lib/build-content/build-component/index.js":{from:107,to:140},"/lib/build-content/jsx/outer.js":{from:141,to:163},"/lib/build-content/jsx/breckets.js":{from:164,to:188},"/lib/build-content/jsx/attributes/build-action.js":{from:189,to:205},"/lib/build-content/jsx/attributes/build-prop.js":{from:206,to:225},"/lib/build-content/jsx/attributes/get-attributes.js":{from:226,to:297},"/lib/build-content/jsx/element.js":{from:298,to:360},"/lib/build-content/jsx/jsx-parser.js":{from:361,to:388},"/lib/build-content/index.js":{from:389,to:405},"/lib/build.js":{from:406,to:423},"/lib/browser.js":{from:424,to:446}};var l=446;let[t,...e]=r.stack.split("\n");throw e=e.map(t=>{var e=t.match(/<anonymous>:(\d*):(\d*)\)$/);if(e){let n=Number(e[1]);if(n+1!==l){var r,s,e=Number(e[2]),i=Object.entries(o).filter(([,{from:t,to:e}])=>n>=t&&n<=e);if(0!==i.length)return[i,{from:r,to:s}]=i[0],` at ${t.match(/at\s(.*?)\s/)[1]} ${i} (${n-r-2}:${e})`}}}).filter(Boolean),r.stack=t+"\n"+e.join("\n"),r;return}}})(); |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
Found 1 instance in 1 package
79017
2
32
1478
2
117
1
14
+ Addedals-require@1.7.0(transitive)
- Removedals-object-serializer@^1.0.0
- Removedals-require@1.0.1(transitive)
Updatedals-require@^1.2.0