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

als-render

Package Overview
Dependencies
Maintainers
0
Versions
30
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

als-render - npm Package Compare versions

Comparing version 0.2.31 to 0.3.0

lib/bundle.js

21

browser/build.js

@@ -1,19 +0,19 @@

const { readdirSync, readFileSync, writeFileSync } = require('fs')
const { readdirSync, readFileSync, writeFileSync,statSync } = require('fs')
const {join} = require('path')
const UglifyJS = require("uglify-js");
const root = join(__dirname,'..')
const libDir =join(root,'lib')
const libDir = join(root,'lib')
const nodeModulesDir = join(root,'node_modules')
const fileNames = readdirSync(libDir)
const ReplaceBetween = readFileSync(`${nodeModulesDir}/als-replace-between/replace-between.js`)
const fileNames = readdirSync(libDir,{recursive:true})
const Require = readFileSync(`${nodeModulesDir}/als-require/require.js`)
const renderConent = readFileSync(join(__dirname,'render.js'),'utf-8').replace(/.*require\(.*\).*?|module.exports.*/g,'')
const renderConent = readFileSync(join(__dirname,'render.js'),'utf-8')
.replace(/.*require\(.*\).*?|module.exports.*/g,'')
const excludes = ['index.js','bundle.js']
const contents = fileNames.map(filename => {
if(filename === 'index.js') return ''
let content = readFileSync(`${libDir}/${filename}`,'utf-8')
const path = `${libDir}/${filename}`
if(excludes.includes(filename) || statSync(path).isDirectory()) return ''
let content = readFileSync(path,'utf-8')
return content.replace(/.*require\(.*\).*?|module.exports.*/g,'')
}).filter(Boolean);
contents.unshift(ReplaceBetween)
contents.unshift(Require)
contents.unshift(renderConent)
contents.unshift(Require,renderConent)
let ready = `const render = (function() {

@@ -26,5 +26,4 @@ ${contents.join('\n')}

const minified = UglifyJS.minify(ready).code
writeFileSync(join(root,'render.min.js'),minified,'utf-8')
writeFileSync(join(root,'render.js'),ready,'utf-8')
const renderJsx = require('../lib/render-jsx')
const newContext = require('../lib/new-context')
const bind = require('../lib/bind')
const { parse } = require('als-object-serializer')
const Simple = require('als-simple-css')
async function render(path,selector='body') {
let styles = []
const context = newContext()
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],styles)
for (const path in app.contents) {
app.contents[path] = renderJsx(app.contents[path],path)
}
if(styles.length) {
const simple = new Simple(styles.map((style,i) => ({[`[style${i}]`]:parse(style)})))
styles = `<style>${simple.stylesheet()}</style>`
} else styles = ''
const result = app.build({},context,'context')
const rawHtml = result()+styles
bind(selector,rawHtml,context)
const resultFn = app.build({}, context, 'context')
const rawHtml = resultFn(data).trim()
bind(selector, rawHtml, context)
}
module.exports = render
function bind(selector,rawHtml,context,update = true) {
function getElement(selector) {
function actionToElement(selector,action) {
const element = document.querySelector(selector)
if(!element) throw `The element with selector "${selector}" not exists`
return element
if(!element) return
action(element)
}
if(update) getElement(selector).innerHTML = rawHtml
context.actions.forEach(({ fn, id, event }) => {
getElement('#'+id).addEventListener(event, fn);
if(update) actionToElement(selector,element => element.innerHTML = rawHtml)
context.actions.forEach(({key,selector,event,fn}) => {
actionToElement(selector,element => element.addEventListener(event,fn))
});

@@ -11,0 +11,0 @@ context.actions = []

const renderJsx = require('./render-jsx')
const newContext = require('./new-context')
const bind = require('./bind')
const Require = require('als-require')
const Simple = require('als-simple-css')
const { parse } = require('als-object-serializer')
Require.requireClassMinified
const UglifyJS = require("uglify-js");
const bindSrginfified = UglifyJS.minify(bind.toString()).code + '\n'
const bundleFn = require('./bundle')
function render(path) {
let styles = []
const context = newContext()
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],styles)
app.contents[path] = renderJsx(app.contents[path],path)
}
if(styles.length) {
const simple = new Simple(styles.map((style,i) => ({[`[style${i}]`]:parse(style)})))
styles = `<style>${simple.stylesheet()}</style>`
} else styles = ''
const result = app.build({}, context, 'context')
const rawHtml = result()+styles
function bundle(selector = 'body', update = false, minified = true) {
return app.bundle({
script: bindSrginfified + `\nbind('${selector}',result(),context,${update.toString()})`,
context: newContext(),
minified
})
}
return { rawHtml, bundle }
const context = {actions:[],components:{},counter:0}
const resultFn = app.build({}, context, 'context')
const rawHtml = resultFn(data).trim()
return { rawHtml, bundle:bundleFn(app,selector,data) }
}
module.exports = render

@@ -1,22 +0,19 @@

const ReplaceBetween = require('als-replace-between')
const replaceComponents = require('./replace-components')
const replaceActions = require('./replace-actions')
const removeComments = str => str.replace(/\/\/.*$/gm, '').replace(/\/\*[\s\S]*?\*\//gm, '')
const buildTree = require('./tree/build-tree')
const findJsx = require('./jsx/find-jsx')
const buildComponent = require('./component')
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 renderJsx(content,styles) {
const transformer = new ReplaceBetween(content, new RegExp(/\(\s*?</), new RegExp(/\>\s*?\)/))
if (transformer.children.length === 0) return content
transformer.before = removeComments(transformer.before)
transformer.after = removeComments(transformer.after)
const componentNames = []
transformer.walkNodes([node => replaceComponents(node, componentNames)])
transformer.children.forEach(node => replaceActions(node,styles));
const fns = componentNames.map(cName => `context.buildComponent(${cName},'${cName}')`).join('\n')
content = transformer.outer
.replace(/className\=/g, 'class=')
.replace(/^\s*$(?:\r\n?|\n)/gm, '')
return content + '\n' + fns
};
module.exports = renderJsx
{
"name": "als-render",
"version": "0.2.31",
"version": "0.3.0",
"main": "index.js",

@@ -25,7 +25,5 @@ "scripts": {

"als-object-serializer": "^1.0.0",
"als-replace-between": "3.3.1",
"als-require": "^0.9.0",
"als-simple-css": "^9.1.0",
"als-require": "1.0.1",
"uglify-js": "^3.18.0"
}
}
# ALS-Render
**Alpha testing**
**Beta testing**
**Not for production use**

@@ -10,3 +10,3 @@

**Important Note**: ALS-Render does not use React nor is it a complete replacement for React. This library focuses specifically on the transformation of code. The operational behavior of applications using ALS-Render differs significantly from React applications. For example, objects in style attribute use another interface, `innerHTML` within components, or various React hooks like `useEffect` (instead useEffect, used `component.update` method). Additionally, the context handling in ALS-Render operates differently.
**Important Note**: ALS-Render does not use React nor is it a complete replacement for React. This library focuses specifically on the transformation of code. The operational behavior of applications using ALS-Render differs significantly from React applications. For example, objects in style attribute use another interface, or various React hooks like `useEffect` (instead useEffect, used `component.update` method). Additionally, the context handling in ALS-Render operates differently.

@@ -34,3 +34,3 @@ ## Installation

const { rawHtml, bundle } = render('./path/to/your/JSXComponent');
const { rawHtml, bundle } = render('./path/to/your/JSXComponent','body');

@@ -48,3 +48,3 @@ const page = `<!DOCTYPE html>

</body>
<script>${bundle('body', false, true)}</script>
<script>${bundle(false, true)}</script>
</html>`;

@@ -94,3 +94,3 @@ app.get('/',(req,res) => res.end(page))

* **Styles** - The `style` attribute in ALS-Render can be a string or object for `als-simple-css`.
* **Styles** - The `style` attribute in ALS-Render can be only a string

@@ -100,2 +100,3 @@ * **Class Attribute** - Unlike React's `className` attribute for specifying CSS classes, ALS-Render uses the standard HTML `class` attribute. This simplifies integration with conventional HTML and CSS practices.

* **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

@@ -102,0 +103,0 @@ * **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.

const render = (function() {
async function render(path,selector='body') { let styles = [] const context = newContext() const app = new Require(path) await app.getContent() for(const path in app.contents) { app.contents[path] = renderJsx(app.contents[path],styles) } if(styles.length) { const simple = new Simple(styles.map((style,i) => ({[`[style${i}]`]:parse(style)}))) styles = `<style>${simple.stylesheet()}</style>` } else styles = '' const result = app.build({},context,'context') const rawHtml = result()+styles bind(selector,rawHtml,context) } class Require { static contents = {} static async fetch(path, type = 'text') { let response = await fetch(path) if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); return await response[type]() } static isCyclyc(fullPath, path) { if (Require.contents[fullPath] && Require.contents[fullPath].children.includes(path)) { throw `cyclic dependency between ${path} and ${fullPath}` } } static async getModule(path, context, contextName, modules) { const mod = new Require(path) await mod.getContent() return mod.build(modules, context, contextName) } static getFullPath(path, relative) { const pathParts = path.split('/'); const relativeParts = relative.split('/').slice(0, -1); const fullPathParts = []; for (let part of [...relativeParts, ...pathParts]) { if (part === '..') { if (fullPathParts.length > 0 && fullPathParts[fullPathParts.length - 1] !== '..') fullPathParts.pop(); else fullPathParts.push(part); } else if (part !== '.') fullPathParts.push(part); } let fullPath = fullPathParts.join('/'); return fullPath.endsWith('.js') ? fullPath : fullPath + '.js' } static async getNodeModules(nodeModules, children, content) { if (nodeModules.length === 0) return content for (const { match, modulePath } of nodeModules) { const pkgJsonPath = `/node_modules/${modulePath}/package.json` const exists = await fetch(pkgJsonPath, { method: 'HEAD' }) if (!exists.ok) { console.warn(`The module "${modulePath}" can't be imported and will be replaced with null`) continue } const { main: filename = 'index.js' } = await Require.fetch(pkgJsonPath, 'json') const fullPath = `/node_modules/${modulePath}/${filename}` Require.isCyclyc(fullPath, modulePath) children.push(fullPath); content = content.replace(match, match.replace(modulePath, fullPath)) } return content } static relativePath = location.pathname constructor(path) { this.contents = {} this.path = path this.fullPath = Require.getFullPath(path, Require.relativePath) this.contentReady = false } async getContent() { if (this.contentReady) return this const getContent = async (path) => { if (this.contents[path] !== undefined) return // allready fetched if (!Require.contents[path]) { let content = await Require.fetch(path) const children = [], nodeModules = []; content = content.replace(/^(?!\/\/|\/\*.*\*\/).*require\(["'`](.*)["'`]\)/gm, (match, modulePath) => { if (!modulePath.startsWith('.')) { nodeModules.push({ match, modulePath }) return match } const fullPath = Require.getFullPath(modulePath, path) Require.isCyclyc(fullPath, path) children.push(fullPath); return match.replace(modulePath, fullPath) }); content = await Require.getNodeModules(nodeModules, children, content) Require.contents[path] = { content, children } } const { content, children } = Require.contents[path] this.contents[path] = content for (let childPath of children) { await getContent(childPath) } } await getContent(this.fullPath) this.contentReady = true this.prepareContents() return this } prepareContents() { const newKeys = new Set() const addKeys = (keys) => { keys.forEach(key => { if (!this.contents[key]) return addKeys(Require.contents[key].children) newKeys.add(key) }) } addKeys(Object.keys(this.contents).reverse()) this.keys = Array.from(newKeys) } build(modules = {}, context = {}, contextName = 'context') { function require(path) { return modules[path] || null } this.keys.map(path => { const module = { exports: {} } const params = { module, require, exports: module.exports, [contextName]: context } try { new Function(...Object.keys(params), this.contents[path])(...Object.values(params)) } catch (error) { this.error(error, path) } modules[path] = module.exports }) return modules[this.keys[this.keys.length - 1]] } error(error, path) { const stack = [], contents = Require.contents; const pathes = Object.keys(contents).reverse() function addToStack(curPath) { stack.push(curPath) for (const modPath of pathes) { if (contents[modPath].children.includes(curPath)) { addToStack(` at ${modPath}`) break } } } addToStack(path) const errorsStack = error.stack.split('\n') errorsStack.splice(1, 1, ...stack) error.stack = errorsStack.join('\n') throw error } }; const require = Require.getModule;
const ReplaceBetween = (function() {
class BaseNode { constructor() {this.children = []} get outer() { return this.before + this.inner + this.after } get inner() {return this.children.map(child => child.outer).join('')} set outer(value) {this.inner = value; this.before = ''; this.after = ''} set inner(value) {this.children = []; this.children.push(new TextNode(value,this))} walkNodes(modifiers=[],parent = this) { parent.children.forEach(child => { if(child instanceof BaseNode === false) return this.walkNodes(modifiers,child) this.runModifiers(modifiers,child,true) }); } walkTextNodes(modifiers=[],parent = this) { parent.children.forEach(child => { if(child instanceof BaseNode) this.walkTextNodes(modifiers,child) else this.runModifiers(modifiers,child,false) }); } walk(modifiers=[],parent = this) { parent.children.forEach(child => { const isNode = child instanceof BaseNode if(isNode) this.walk(modifiers,child) this.runModifiers(modifiers,child,isNode) }); } runModifiers(modifiers,child,isNode) { for(const modifier of modifiers) { const result = modifier(child,isNode) if(result === false) return false } } } function buildTree(starts, ends) { if(starts[0].n > ends[0].n) ends.shift() if(starts[starts.length-1].n > ends[ends.length-1].n) starts.pop() if (starts.length !== ends.length) throw new Error(`Parsing error: unmatched tags detected. (${starts.length},${ends.length})`); let pairs = starts.map((start, i) => ({ start, end: ends[i], children: [] })); pairs.forEach((curPair, i) => { for (let k = i; k < pairs.length; k++) { if (curPair.end.n > pairs[k].start.n) { const end = pairs[k].end const curEnd = curPair.end curPair.end = end pairs[k].end = curEnd } } }) pairs.sort((a, b) => a.end.n - b.end.n); pairs.forEach((curPair, i) => { for (let k = i; k < pairs.length; k++) { if (curPair.start.n > pairs[k].start.n && curPair.end.n < pairs[k].end.n) { if (!curPair.level) curPair.level = 0 curPair.level++ pairs[k].children.push(curPair) } } }); function filterPairs(pairs, curLevel = 0) { pairs = pairs.filter(({ level }) => (!level || level <= curLevel)) pairs.forEach(pair => { if (pair.children.length === 0) return pair.children = filterPairs(pair.children, curLevel + 1) }); return pairs } pairs = filterPairs(pairs) return pairs } function find(string, r, add, offset = 0) { const arr = [] while (true) { const match = string.match(r) if (!match) break offset += match.index + 1 const n = add < 0 ? add : add * (match[0].length - 1) arr.push({n:offset + n,length:match[0].length}) string = string.slice(match.index + 1) } return arr } class ReplaceBetween extends BaseNode { constructor(content, startR, endR) { super() if (typeof content !== 'string') throw `Expected 'content' to be a string, but got '${typeof content}'` if (startR instanceof RegExp == false) throw '"startR" should be an instance of RegExp.' if (endR instanceof RegExp == false) throw '"endR" should be an instance of RegExp.' this.content = content this.startR = startR this.endR = endR this.build() } build() { const { content, startR, endR } = this const starts = find(content, startR, -1) const ends = find(content, endR, 1) if(starts.length === 0 || ends.length === 0) return const children = buildTree(starts, ends) if(children.length === 0) return const start = children[0].start.n const end = children[children.length - 1].end.n this.before = start > 0 ? content.slice(0, start) : '' this.after = end < content.length ? content.slice(end, content.length) : '' children.forEach((child,i) => { this.children.push(new Node(this, child, this)) if(i === children.length-1) return const nextStart = children[i+1].start.n const curendEnd = child.end.n if(nextStart !== curendEnd) { this.children.push(new TextNode(content.slice(curendEnd,nextStart),this)) } }); } } class Node extends BaseNode { constructor(root, obj, parent = null) { super() this.parent = parent if(parent) this.index = parent.children.length this.root = root this.addChildren(obj) } addChildren(obj) { const { start, end, children } = obj const root = this.root let curStart = start.n + start.length, curEnd = end.n - end.length this.open = root.content.slice(start.n, curStart) children.forEach((child,i) => { if(child.start.n > curStart) this.children.push(new TextNode(root.content.slice(curStart, child.start.n),this)) this.children.push(new Node(root, child, this)) curStart = child.end.n }); if(curEnd > curStart) this.children.push(new TextNode(root.content.slice(curStart,curEnd),this)) this.close = root.content.slice(curEnd, end.n) return this } get outer() {return this.open + this.inner + this.close} set outer(value) {this.inner = value; this.open = ''; this.close = ''} get prev() {return this.parent ? this.parent.children[this.index - 1] : null} get next() {return this.parent ? this.parent.children[this.index + 1] : null} } class TextNode { constructor(content,parent) { this.outer = content this.parent = parent if(parent) this.index = parent.children.length this.open = '' this.close = '' } get prev() {return this.parent.children[this.index - 1] || null} get next() {return this.parent.children[this.index + 1] || null} } return ReplaceBetween
const Require = (function(){
function isCyclyc(fullPath, path) {
if (Require.contents[fullPath] && Require.contents[fullPath].children.includes(path)) {
throw `cyclic dependency between ${path} and ${fullPath}`
}
}
function getFullPath(path, relative) {
const pathParts = path.split('/');
const relativeParts = relative.split('/').slice(0, -1);
const fullPathParts = [];
for (let part of [...relativeParts, ...pathParts]) {
if (part === '..') {
if (fullPathParts.length > 0 && fullPathParts[fullPathParts.length - 1] !== '..') fullPathParts.pop();
else fullPathParts.push(part);
} else if (part !== '.') fullPathParts.push(part);
}
let fullPath = fullPathParts.join('/');
return fullPath.endsWith('.js') ? fullPath : fullPath + '.js'
}
async function $fetch(path, type = 'text') {
let response = await fetch(path)
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
return await response[type]()
}
async function getNodeModules(nodeModules, children, content) {
if (nodeModules.length === 0) return content
for (const { match, modulePath } of nodeModules) {
const pkgJsonPath = `/node_modules/${modulePath}/package.json`
const exists = await fetch(pkgJsonPath, { method: 'HEAD' })
if (!exists.ok) {
console.warn(`The module "${modulePath}" can't be imported and will be replaced with null`)
continue
}
const { main: filename = 'index.js' } = await $fetch(pkgJsonPath, 'json')
const fullPath = `/node_modules/${modulePath}/${filename}`
isCyclyc(fullPath, modulePath)
children.push(fullPath);
content = content.replace(match, match.replace(modulePath, fullPath))
}
return content
}
async function getContents({contents, fullPath},Require) {
const getContent = async (path) => {
if (contents[path] !== undefined) return // allready fetched
if (!Require.contents[path]) {
let content = await $fetch(path)
const children = [], nodeModules = [];
content = content.replace(/^(?!\/\/|\/\*.*\*\/).*require\(["'`](.*)["'`]\)/gm, (match, modulePath) => {
if (!modulePath.startsWith('.')) {
nodeModules.push({ match, modulePath })
return match
}
const fullPath = getFullPath(modulePath, path)
isCyclyc(fullPath, path)
children.push(fullPath);
return match.replace(modulePath, fullPath)
});
content = await getNodeModules(nodeModules, children, content)
Require.contents[path] = { content, children }
}
const { content, children } = Require.contents[path]
contents[path] = content
for (let childPath of children) {
await getContent(childPath)
}
}
await getContent(fullPath)
}
function getKeys(contents, Require) {
const newKeys = new Set()
const addKeys = (keys) => {
keys.forEach(key => {
if (!contents[key]) return
addKeys(Require.contents[key].children)
newKeys.add(key)
})
}
addKeys(Object.keys(contents).reverse())
return Array.from(newKeys)
}
function getFns(contextName,obj) {
const modulesLines = {}
let curLastLine = 3
const fns = obj.keys.map((path, i) => {
const fnBody = obj.contents[path];
let code = `modules['${path}'] = (function (){
const module = { exports: {} }
const exports = module.exports
${fnBody}
return module.exports;
})();`
if (i === obj.keys.length - 1) code += `\nreturn modules['${path}']`
modulesLines[path] = { from: curLastLine + 1 }
curLastLine += code.split('\n').length
modulesLines[path].to = curLastLine
return code
}).join('\n')
const fn = new Function('modules', contextName, `function require(path) { return modules[path] || null };
${fns}`)
return { fn, modulesLines, curLastLine }
}
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 [path, { from, to }] = Object.entries(modulesLines).filter(([path, { from, to }]) => line >= from && line <= to)[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
}
class Require {
static contents = {}
static async getModule(path, context, contextName, modules) {
const mod = new Require(path)
await mod.getContent()
return mod.build(modules, context, contextName)
}
constructor(path) {
this.contents = {}
this.path = path
this.fullPath = getFullPath(path, location.pathname)
this.contentReady = false
}
async getContent() {
if (this.contentReady) return this
await getContents(this, Require)
this.keys = getKeys(this.contents,Require)
this.contentReady = true
return this
}
build(modules = {}, context = {}, contextName = 'context') {
const { fn, modulesLines, curLastLine } = getFns(contextName,this)
try {return fn(modules, context)}
catch (error) {parseError(error, modulesLines, curLastLine)}
}
}
return Require;
})()
function bind(selector,rawHtml,context,update = true) { function getElement(selector) { const element = document.querySelector(selector) if(!element) throw `The element with selector "${selector}" not exists` return element } if(update) getElement(selector).innerHTML = rawHtml context.actions.forEach(({ fn, id, event }) => { getElement('#'+id).addEventListener(event, fn); }); context.actions = [] } function newContext() { const context = { components: {}, actions: [], counter: 0, update: (componentName,newParams, key) => { const component = context.components[componentName] const selector = `[component=${ componentName}]`; if (key) selector += `[key=${key}]`; const element = document.querySelector(selector) element.outerHTML = component(newParams); context.actions = context.actions.map(({ fn, id, event }) => { const element = document.getElementById(id) if(element) element.addEventListener(event, fn); return false; }).filter(Boolean); } } context.buildComponent = function(componentFn,componentName) { if(context.components[componentName]) return componentFn.update = function(newParams,key) {context.update(componentName,newParams,key)} context.components[componentName] = function(props) { let result = componentFn(props).trim() if(result.startsWith('<>')) return result.slice(2,-3) // remove <> and </> result = result.replace(/^<\w*/,(tag) => { key = props.key ? ` key="${props.key}"` : '' return tag + ` component="${componentName}"${key}` }) return result } context.components[componentName].update = function(newParams,key) {context.update(componentName,newParams,key)} } return context } const removeComments = str => str.replace(/\/\/.*$/gm, '').replace(/\/\*[\s\S]*?\*\//gm, '') function renderJsx(content,styles) { const transformer = new ReplaceBetween(content, new RegExp(/\(\s*?</), new RegExp(/\>\s*?\)/)) if (transformer.children.length === 0) return content transformer.before = removeComments(transformer.before) transformer.after = removeComments(transformer.after) const componentNames = [] transformer.walkNodes([node => replaceComponents(node, componentNames)]) transformer.children.forEach(node => replaceActions(node,styles)); const fns = componentNames.map(cName => `context.buildComponent(${cName},'${cName}')`).join('\n') content = transformer.outer .replace(/className\=/g, 'class=') .replace(/^\s*$(?:\r\n?|\n)/gm, '') return content + '\n' + fns }; function buildAction(event, value) { const obj = `{event:'${event}',fn:${value},id:'action'+(context.counter++).toString()}` return '"${' + `context.actions.push(${obj})` + ` ? '' : ''}" id="\${'action'+(context.counter-1).toString()}" ` } function getBefore(node) { if (node.prev) return { beforeNode: node.prev, before: node.prev.outer.trim() } if (node.parent.before) return { beforeNode: node.parent, before: node.parent.before.trim() } return getBefore(node.parent) } function replaceActions(node, styles) { if (!node.inner) return const varTransformer = new ReplaceBetween(node.inner, /\{/, /\}/) if (varTransformer.children.length === 0) return varTransformer.walkNodes([node => { const outer = node.outer if (node.inner.startsWith('...')) return // Spreaded variable if (outer.startsWith('{/*') && outer.endsWith('*/}')) { // comment node.outer = ''; return; } const { before, beforeNode } = getBefore(node) const lastChar = before[before.length - 1]; if (lastChar === '$') return if (before[before.length - 2] + lastChar === '=>') return // Arrow function body if (lastChar === '(' || lastChar === ',') return // variable is part of object if (lastChar === '=') { let propName = '', i = before.length - 2 while (i >= 0) { propName = before[i] + propName i-- if (before[i] === ' ') break } if (propName === 'style') { if(node.parent.open === '{' && node.parent.close === '}') { styles.push(outer) if(beforeNode.before) beforeNode.before = beforeNode.before.slice(0,-1)+String(styles.length-1) node.parent.outer = '' return } } if (propName.startsWith('on')) { node.outer = buildAction(propName.split('on')[1].toLowerCase(), node.inner) } else node.outer = '"${' + `${node.inner}}"` } else if(node.open === '{') { // if((node.prev ? node.prev.outer : node.parent.before).slice(-1) === '$') return node.open = '${' } }]) node.inner = varTransformer.outer } function replaceComponents(node,componentNames) { const inner = '<'+node.inner.trim()+'>' node.open = '`'; node.close = '`'; node.inner = inner.replace(/\<([A-Z]\w*)[\s\S]*?\/\>/g,(m,cName,index) => { componentNames.push(cName) let props = [], restParams = ''; m.replace(/(\w*)\s*?\=\"([\s\S]*?)\"/g, (m1, name, val) => {props.push(`${name}:"${val}"`)}) m.replace(/(\w*)\s*?\=\s*?\{\{?(.*?)\}?\}/g, (m1, name, val) => {props.push(`${name}:${val}`)}) m.replace(/\{(\.\.\..*?)\}/, (m1, varName) => {props.push(varName)}) const code = `context.components.${cName}({${props.join()}${restParams}})` if(index === 0 && m.length === inner.length) { node.open = ''; node.close = ''; return code } return '${'+code+'}' }) .replace(/(checked|disabled)\=\{([\s\S]*?)\}/g,(m,prop,condition) => '${'+`${condition} ? '${prop}' : '' `+'}') .replace(/\/>/g, '>') } return render
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 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 element = document.querySelector(selector)
if(!element) return
action(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}
}
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(' ')+'>'
})
}
result = result.replace(/\\<\\/?\\>/g,'')
return result
}
${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 = []
}
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
}
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
}
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)
}
}
return findClose(temp,add)
}
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
}
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, '')
}
}
if (i === jsx.length - 1) addNode(curNode, '')
}
return nodes
}
function buildAction(propname,value,attributes) {
const event = propname.split('on')[1].toLowerCase()
propname = event
const fn = value
value = '${context.counter++}'
const selector = `[${propname}="\${context.counter-1}"]`
const addToActions = '$'+`{context.actions.push({selector:\`${selector}\`,event:'${event}',fn:${fn}}) ? '' : ''}`
value = value + addToActions
attributes.push(`${propname}="${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 + '>'
}
}
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
}
}
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
}
if(node.startsWith(').')) return node
return node.replace(')', '`')
}
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
}
if (node.type === undefined) {
if(/\{.*\}/.test(node.text)) return node.text.replace('{','${')
if (node.text === '(' || node.text === ')') return '`'
return node.text
}
}
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))
}
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)]
}
if (nodes.flat().every(child => typeof child === 'string')) return [nodes.join('')]
return nodes
}
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
}
}
}
return closeTagIndex
}
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}}"`)
}
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,1 +0,34 @@

let render=function(){class h{static contents={};static async fetch(e,t="text"){e=await fetch(e);if(e.ok)return e[t]();throw new Error("HTTP error! status: "+e.status)}static isCyclyc(e,t){if(h.contents[e]&&h.contents[e].children.includes(t))throw`cyclic dependency between ${t} and `+e}static async getModule(e,t,n,r){e=new h(e);return await e.getContent(),e.build(r,t,n)}static getFullPath(e,t){var n,e=e.split("/"),r=[];for(n of[...t.split("/").slice(0,-1),...e])".."===n?0<r.length&&".."!==r[r.length-1]?r.pop():r.push(n):"."!==n&&r.push(n);t=r.join("/");return t.endsWith(".js")?t:t+".js"}static async getNodeModules(e,t,n){if(0!==e.length)for(var{match:r,modulePath:s}of e){var i=`/node_modules/${s}/package.json`;(await fetch(i,{method:"HEAD"})).ok?({main:i="index.js"}=await h.fetch(i,"json"),i=`/node_modules/${s}/`+i,h.isCyclyc(i,s),t.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}static relativePath=location.pathname;constructor(e){this.contents={},this.path=e,this.fullPath=h.getFullPath(e,h.relativePath),this.contentReady=!1}async getContent(){if(!this.contentReady){let r=async i=>{if(void 0===this.contents[i]){if(!h.contents[i]){let e=await h.fetch(i),r=[],s=[];e=e.replace(/^(?!\/\/|\/\*.*\*\/).*require\(["'`](.*)["'`]\)/gm,(e,t)=>{var n;return t.startsWith(".")?(n=h.getFullPath(t,i),h.isCyclyc(n,i),r.push(n),e.replace(t,n)):(s.push({match:e,modulePath:t}),e)}),e=await h.getNodeModules(s,r,e),h.contents[i]={content:e,children:r}}let{content:e,children:t}=h.contents[i];this.contents[i]=e;for(var n of t)await r(n)}};await r(this.fullPath),this.contentReady=!0,this.prepareContents()}return this}prepareContents(){let t=new Set,n=e=>{e.forEach(e=>{this.contents[e]&&(n(h.contents[e].children),t.add(e))})};n(Object.keys(this.contents).reverse()),this.keys=Array.from(t)}build(r={},s={},i="context"){function o(e){return r[e]||null}return this.keys.map(t=>{var e={exports:{}},n={module:e,require:o,exports:e.exports,[i]:s};try{new Function(...Object.keys(n),this.contents[t])(...Object.values(n))}catch(e){this.error(e,t)}r[t]=e.exports}),r[this.keys[this.keys.length-1]]}error(e,t){let r=[],s=h.contents,i=Object.keys(s).reverse();!function e(t){r.push(t);for(var n of i)if(s[n].children.includes(t)){e(" at "+n);break}}(t);t=e.stack.split("\n");throw t.splice(1,1,...r),e.stack=t.join("\n"),e}}h;let c=function(){class r{constructor(){this.children=[]}get outer(){return this.before+this.inner+this.after}get inner(){return this.children.map(e=>e.outer).join("")}set outer(e){this.inner=e,this.before="",this.after=""}set inner(e){this.children=[],this.children.push(new c(e,this))}walkNodes(t=[],e=this){e.children.forEach(e=>{e instanceof r!=!1&&(this.walkNodes(t,e),this.runModifiers(t,e,!0))})}walkTextNodes(t=[],e=this){e.children.forEach(e=>{e instanceof r?this.walkTextNodes(t,e):this.runModifiers(t,e,!1)})}walk(n=[],e=this){e.children.forEach(e=>{var t=e instanceof r;t&&this.walk(n,e),this.runModifiers(n,e,t)})}runModifiers(e,t,n){for(var r of e)if(!1===r(t,n))return!1}}function o(e,n){if(e[0].n>n[0].n&&n.shift(),e[e.length-1].n>n[n.length-1].n&&e.pop(),e.length!==n.length)throw new Error(`Parsing error: unmatched tags detected. (${e.length},${n.length})`);let i=e.map((e,t)=>({start:e,end:n[t],children:[]}));return i.forEach((t,n)=>{for(let e=n;e<i.length;e++){var r,s;t.end.n>i[e].start.n&&(r=i[e].end,s=t.end,t.end=r,i[e].end=s)}}),i.sort((e,t)=>e.end.n-t.end.n),i.forEach((t,n)=>{for(let e=n;e<i.length;e++)t.start.n>i[e].start.n&&t.end.n<i[e].end.n&&(t.level||(t.level=0),t.level++,i[e].children.push(t))}),i=function t(e,n=0){return(e=e.filter(({level:e})=>!e||e<=n)).forEach(e=>{0!==e.children.length&&(e.children=t(e.children,n+1))}),e}(i)}function n(e,t,n,r=0){for(var s=[];;){var i=e.match(t);if(!i)break;r+=i.index+1;var o=n<0?n:n*(i[0].length-1);s.push({n:r+o,length:i[0].length}),e=e.slice(i.index+1)}return s}r;class h extends r{constructor(e,t,n=null){super(),(this.parent=n)&&(this.index=n.children.length),this.root=e,this.addChildren(t)}addChildren(e){var{start:e,end:t,children:n}=e;let r=this.root,s=e.n+e.length,i=t.n-t.length;return this.open=r.content.slice(e.n,s),n.forEach((e,t)=>{e.start.n>s&&this.children.push(new c(r.content.slice(s,e.start.n),this)),this.children.push(new h(r,e,this)),s=e.end.n}),i>s&&this.children.push(new c(r.content.slice(s,i),this)),this.close=r.content.slice(i,t.n),this}get outer(){return this.open+this.inner+this.close}set outer(e){this.inner=e,this.open="",this.close=""}get prev(){return this.parent?this.parent.children[this.index-1]:null}get next(){return this.parent?this.parent.children[this.index+1]:null}}class c{constructor(e,t){this.outer=e,(this.parent=t)&&(this.index=t.children.length),this.open="",this.close=""}get prev(){return this.parent.children[this.index-1]||null}get next(){return this.parent.children[this.index+1]||null}}return class extends r{constructor(e,t,n){if(super(),"string"!=typeof e)throw`Expected 'content' to be a string, but got '${typeof e}'`;if(t instanceof RegExp==0)throw'"startR" should be an instance of RegExp.';if(n instanceof RegExp==0)throw'"endR" should be an instance of RegExp.';this.content=e,this.startR=t,this.endR=n,this.build()}build(){let{content:r,startR:e,endR:t}=this;var s=n(r,e,-1),i=n(r,t,1);if(0!==s.length&&0!==i.length){let n=o(s,i);0!==n.length&&(s=n[0].start.n,i=n[n.length-1].end.n,this.before=0<s?r.slice(0,s):"",this.after=i<r.length?r.slice(i,r.length):"",n.forEach((e,t)=>{this.children.push(new h(this,e,this)),t!==n.length-1&&(t=n[t+1].start.n)!==(e=e.end.n)&&this.children.push(new c(r.slice(e,t),this))}))}}}}();let l=e=>e.replace(/\/\/.*$/gm,"").replace(/\/\*[\s\S]*?\*\//gm,"");return async function(e,t="body"){let n=[];var r=function(){let i={components:{},actions:[],counter:0,update:(e,t,n)=>{var r=i.components[e];const s=`[component=${e}]`;n&&(s+=`[key=${n}]`),document.querySelector(s).outerHTML=r(t),i.actions=i.actions.map(({fn:e,id:t,event:n})=>{t=document.getElementById(t);return t&&t.addEventListener(n,e),!1}).filter(Boolean)},buildComponent:function(n,r){i.components[r]||(n.update=function(e,t){i.update(r,e,t)},i.components[r]=function(t){let e=n(t).trim();return e.startsWith("<>")?e.slice(2,-3):e=e.replace(/^<\w*/,e=>(key=t.key?` key="${t.key}"`:"",e+(` component="${r}"`+key)))},i.components[r].update=function(e,t){i.update(r,e,t)})}};return i}(),s=new h(e);await s.getContent();for(let e in s.contents)s.contents[e]=function(e,n){var t=new c(e,new RegExp(/\(\s*?</),new RegExp(/\>\s*?\)/));if(0===t.children.length)return e;t.before=l(t.before),t.after=l(t.after);let r=[],s=(t.walkNodes([e=>{{var i=e,o=r;let s="<"+i.inner.trim()+">";i.open="`",i.close="`",i.inner=s.replace(/\<([A-Z]\w*)[\s\S]*?\/\>/g,(e,t,n)=>{o.push(t);let r=[];e.replace(/(\w*)\s*?\=\"([\s\S]*?)\"/g,(e,t,n)=>{r.push(t+`:"${n}"`)}),e.replace(/(\w*)\s*?\=\s*?\{\{?(.*?)\}?\}/g,(e,t,n)=>{r.push(t+":"+n)}),e.replace(/\{(\.\.\..*?)\}/,(e,t)=>{r.push(t)});t=`context.components.${t}({${r.join()}${""}})`;return 0===n&&e.length===s.length?(i.open="",i.close="",t):"${"+t+"}"}).replace(/(checked|disabled)\=\{([\s\S]*?)\}/g,(e,t,n)=>"${"+n+` ? '${t}' : '' `+"}").replace(/\/>/g,">")}}]),t.children.forEach(e=>{var o,t;o=n,(e=e).inner&&0!==(t=new c(e.inner,/\{/,/\}/)).children.length&&(t.walkNodes([n=>{var r=n.outer;if(!n.inner.startsWith("..."))if(r.startsWith("{/*")&&r.endsWith("*/}"))n.outer="";else{var{before:s,beforeNode:i}=function e(t){if(t.prev)return{beforeNode:t.prev,before:t.prev.outer.trim()};if(t.parent.before)return{beforeNode:t.parent,before:t.parent.before.trim()};return e(t.parent)}(n),e=s[s.length-1];if("$"!==e&&s[s.length-2]+e!=="=>"&&"("!==e&&","!==e)if("="===e){let e="",t=s.length-2;for(;0<=t&&(e=s[t]+e," "!==s[--t]););"style"===e&&"{"===n.parent.open&&"}"===n.parent.close?(o.push(r),i.before&&(i.before=i.before.slice(0,-1)+String(o.length-1)),n.parent.outer=""):e.startsWith("on")?n.outer=function(e,t){e=`{event:'${e}',fn:${t},id:'action'+(context.counter++).toString()}`;return'"${'+`context.actions.push(${e})`+` ? '' : ''}" id="\${'action'+(context.counter-1).toString()}" `}(e.split("on")[1].toLowerCase(),n.inner):n.outer='"${'+n.inner+'}"'}else"{"===n.open&&(n.open="${")}}]),e.inner=t.outer)}),r.map(e=>`context.buildComponent(${e},'${e}')`).join("\n"));return(e=t.outer.replace(/className\=/g,"class=").replace(/^\s*$(?:\r\n?|\n)/gm,""))+"\n"+s}(s.contents[e],n);n=n.length?`<style>${new Simple(n.map((e,t)=>({[`[style${t}]`]:parse(e)}))).stylesheet()}</style>`:"";var[e,t,r,i=!0]=[t,s.build({},r,"context")()+n,r];function o(e){var t=document.querySelector(e);if(t)return t;throw`The element with selector "${e}" not exists`}i&&(o(e).innerHTML=t),r.actions.forEach(({fn:e,id:t,event:n})=>{o("#"+t).addEventListener(n,e)}),r.actions=[]}}();
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 (){
const module = { exports: {} }
const exports = module.exports
${r.contents[t]}
return 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}
}
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(' ')+'>'
})
}
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=[]}}();
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