Huge News!Announcing our $40M Series B led by Abstract Ventures.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.9.3 to 1.0.0

browser.js

2

docs/00-als-render.md

@@ -8,4 +8,4 @@ # ALS-Render

ALS-Render is a versatile library that enables rendering of JSX like code into raw HTML. It supports both Server-Side Rendering (SSR) and Client-Side Rendering, providing seamless integration for dynamic web applications.
ALS-Render is a versatile library that enables rendering of JS or JSX like code into raw HTML. It supports both Server-Side Rendering (SSR) and Client-Side Rendering, providing seamless integration for dynamic web applications.
**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.

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

const render = require('./lib/index')
const Require = require('als-require');
const Lang = require('als-lang');
const RenderJsx = require('als-render-jsx');
global.Component = require('als-component');
Require.minifyOptions = { keep_fnames: true }
const { join, dirname } = require('path'), { readFileSync } = require('fs');
const stringComponent = readFileSync(join(dirname(require.resolve('als-component')), 'component.js'), 'utf-8');
class Render {
static Require = Require
static jsx = true
module.exports = render
constructor(path, options = {}) {
const { context = {}, contextBrowser = {}, langs, includebundle = true, defaultLang } = options
const mod = new Require(path)
mod.getContent()
if (Render.jsx) for (const path in mod.contents) {
mod.contents[path] = RenderJsx.render(mod.contents[path]);
}
this.MainClass = mod.build(context)
this.includebundle = includebundle
this.bundle = includebundle ? mod.bundle(contextBrowser, '\n' + stringComponent) : ''
this.langsObj = langs ? new Lang(langs,defaultLang) : { replace(result) { return result } }
}
build(data, lang) { return this.MainClass.isAsync ? this.buildAsync(data, lang) : this.buildSync(data, lang) }
async buildAsync(data, lang) { return this.result(await new this.MainClass(data).call(), lang, data) }
buildSync(data, lang) { return this.result(new this.MainClass(data).call(), lang, data) }
result(result, lang, data) {
return this.langsObj.replace(result, lang) + (this.includebundle
? `<script>${this.langsObj.replace(this.bundle, lang)}\nnew ${Require.bundleName}(${JSON.stringify(data)}).build(false)</script>`
: '')
}
}
module.exports = Render
{
"name": "als-render",
"version": "0.9.3",
"version": "1.0.0",
"main": "index.js",

@@ -8,5 +8,4 @@ "scripts": {

"report": "node --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=lcov.info ./tests/index.test.js",
"readme":"node build-readme.js",
"build":"node build.js",
"todos":"node ./projects/build.js todos"
"build-browser": "node ./scripts/build-browser.js",
"build-docs": "node ./scripts/build-docs.js"
},

@@ -19,7 +18,4 @@ "keywords": [

"client-side rendering",
"JavaScript library",
"no virtual DOM",
"web development",
"component model",
"event handling"
"component model"
],

@@ -30,8 +26,8 @@ "author": "Alex Sorkin<alexsorkin1980@gmail.com>",

"dependencies": {
"als-require": "^1.6.0",
"uglify-js": "^3.18.0"
},
"devDependencies": {
"als-browser-test": "^1.1.0"
"als-component": "^1.2.0",
"als-lang": "^1.0.0",
"als-render-jsx": "^1.0.0",
"als-require": "^2.2.0",
"uglify-js": "^3.19.3"
}
}

@@ -8,3 +8,3 @@ # ALS-Render

ALS-Render is a versatile library that enables rendering of JSX like code into raw HTML. It supports both Server-Side Rendering (SSR) and Client-Side Rendering, providing seamless integration for dynamic web applications.
ALS-Render is a versatile library that enables rendering of JS or JSX like code into raw HTML. It supports both Server-Side Rendering (SSR) and Client-Side Rendering, providing seamless integration for dynamic web applications.

@@ -24,6 +24,61 @@ **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.

## Usage
## Usage in browser
### Server-Side Rendering (Node.js)
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="/node_modules/als-render/render.min.js"></script>
<title>Todos</title>
</head>
<body>
</body>
<script>
const langs = {
langs:['ru','he'],
dictionary:{Increase:['Увеличить','להגדיל'], Decrease:['Уменьшить','להקטין']}
}
const props = {count:0}
const options = {jsx:true,selector:'body',langs,lang:'ru'}
render('./App',props,options)
</script>
</html>
```
App.js
```js
const Counter = require('./Counter')
class App extends Component{
constructor(props) {super(props)}
render({count}) {
return (<div>
<Counter count={count} />
</div>)
}
}
module.exports = App
```
Counter.js
```js
class Counter extends Component {
constructor(props) {super(props)}
render({count}) {
return (<div>
<button onclick={() => this.update({count:count+1})}>~Increase~</button>
<span>{count}</span>
<button onclick={() => this.update({count:count-1})}>~Decrease~</button>
</div>)
}
}
module.exports = Counter
```
## Server-Side Rendering (Node.js)
In a Node.js environment, `render` is used to pre-render JSX to HTML on the server, allowing for faster initial page loads and SEO optimization. Here’s how to use it:

@@ -36,3 +91,3 @@

const layout = (rawHtml,bundle) => `<!DOCTYPE html>
const layout = (rawHtml) => `<!DOCTYPE html>
<html lang="en">

@@ -42,3 +97,2 @@ <head>

<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/path/to/css/style.css">
<title>Your Application</title>

@@ -49,111 +103,59 @@ </head>

</body>
<script>${bundle}</script>
</html>`;
const path = './path/to/your/JSXComponent';
Render.contextName = 'context';
const minified = false;
const path = './path/to/your/JSXComponent', options = { langs:{...} };
const todosScreen = new Render(path,options)
app.get('/',(req,res) => {
const data = {};
const { rawHtml, bundle } = Render.render(path,data,minified);
res.end(layout(rawHtml, bundle))
const data = {},lang='ru';
res.end(layout(todoScreen.build(data,lang)))
})
```
### Client-Side Rendering (Browser)
## API
In the browser, `render` dynamically converts JSX into HTML and handles client-side updates. This method is particularly useful for Single Page Applications (SPAs) where dynamic content loading is necessary.
### Render in NodeJS
Include the ALS-Render script in your HTML and call `render` as shown below:
```js
global.Component = require('als-component');
Require.minifyOptions = { keep_fnames: true }
class Render {
static Require = Require // Can set settings for Require (like Require.minified = true)
static jsx = true
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./path/to/css/app.css">
<title>Your Application</title>
</head>
<body>
</body>
<!-- Include ALS-Render library -->
<script src="/path/to/als-render/render.min.js"></script>
<script>
const data = {}
const selector = 'body' // optional. Default 'body'
const version = '1.0.0' // optional. Default undefined
const contextName = 'contextName' // optional. Default 'context'
const path = './path/to/your/JSXComponent'
render(path, data, {selector,version})
.then(() => {
console.log('Component rendered successfully');
});
</script>
</html>
MainClass // The Main component class
includebundle // if true including bundle inside script
bundle // created bundle to include
langsObj // the dictionary object if options.langs included
constructor(path, options = {}) {
const {
context = {}, // context for server side rendering
contextBrowser = {}, // context for bundle version
langs, // langs object for als-lang
defaultLang, // default language for als-lang
includebundle = true, // include bundle script in rawHTML
} = options
}
build(data, lang) { } // return rawHtml or Promise for rawHtml if render isAsync
}
```
## ALS-Render Features Overview
### Browser version
While ALS-Render handles JSX, its usage differs from React. Here's how you can work with React-like code but adapted for ALS-Render:
```js
async function render(path, data = {}, options = {}) {
const {
selector, // selector for outerHTML. If not provided, updated to [component=MainComponentName]
version,
jsx = true, // if true, parse jsx before running
context={}, // context for require
langs,lang // languages and choosen language for als-lang
} = options
Require.version = version
* **CommonJs** - ALS-Render using CommonJs instead module (require instead import).
* **Components** - Components in ALS-Render are defined as functions that return raw HTML. This approach emphasizes a more direct interaction with the DOM, bypassing the need for a virtual DOM layer typically found in frameworks like React.
/*...*/
* **State Management** - State management in ALS-Render is handled manually. Each component can include an `update` method that can be called to re-render the component with new state. Unlike React, this method must be explicitly invoked to reflect state changes in the UI.
* **Event Handling** - Event handling in ALS-Render is streamlined by automating the addition of event listeners. All event functions are stored in `component.actions` and are automatically attached to elements as listeners after each update. This setup allows for a more declarative attachment of events compared to manual management.
* **Styles** - The `style` attribute in ALS-Render can be only a string
* **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.
* **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.
* **Rendering** - **Server-Side Rendering (SSR)**: The server-side render function in ALS-Render returns an object containing `rawHtml`and `bundle`, facilitating the generation and manipulation of HTML server-side before sending it to the client.
- **Browser Rendering**: In the browser, ALS-Render directly inserts generated HTML into the DOM, streamlining the rendering process by eliminating additional abstraction layers.
* **Lifecycle Hooks** - ALS-Render provides lifecycle hooks as mount and unmount.
* inside component available `this.on('mount',(element) => {})` and `this.on('unmount',() => {})`
* **onload** - ALS-Render has onload event for each element.
* **updating** - Each component has `this.update(props,inner)`
* **parentComponent** - Each component has `this.parentComponent` - the access to parent component
* **context.link** - by using `context.link(href)` you can add link stylesheet to html
* **context.style** - by using `context.style(cssStyles)` you can add css styles to html
* **context.browser** - true inside browser and false in Nodejs
* **context.ssr** - true if html rendered on NodeJS
* **context.data** - includes data passed in render function
* **component(name)** - returns component object (name = componentName+key)
## Counter example
App.js
```js
const Counter = require('./Counter')
function App({count}) {
return (<div>
<Counter count={count} />
</div>)
return context
}
module.exports = App
```
Counter.js
```js
function Counter({count}) {
return (<div>
<button onclick={() => this.update({count:count+1})}>Increase</button>
<span>{count}</span>
<button onclick={() => this.update({count:count-1})}>Decrease</button>
</div>)
}
module.exports = Counter
```

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

const Require = (function(){
const packageJsonCache = {};
function getFullPath(path, relative) {
const render = (function(){
const Require = (function(){
const packageJsonCache = {};
const standartNodeModules = ["assert","async_hooks","buffer","child_process","cluster","console","constants","crypto","dgram","diagnostics_channel","dns","domain","events","fs","http","http2","https","inspector","module","net","os","path","perf_hooks","process","punycode","querystring","readline","repl","stream","string_decoder","sys","timers","timers/promises","tls","trace_events","tty","url","util","v8","vm","wasi","worker_threads","zlib","test","abort_controller"]
function getFullPath(path, relative) {
const pathParts = path.split('/');

@@ -17,8 +19,16 @@ const relativeParts = relative.split('/').slice(0, -1);

}
async function getNodeModules(nodeModules, children, content,Require) {
async function getNodeModules(nodeModules, children, content, Require) {
const { logger = console } = Require
if (nodeModules.length === 0) return content
for (let { match, modulePath } of nodeModules) {
let fullPath,relativePath,filename,moduleDir = modulePath
const r = new RegExp(`require\\((["'\`])${modulePath}["'\`]\\)`)
const replaceAndWarn = () => {
content = content.replace(r, '{}')
logger.warn(`The module "${modulePath}" can't be imported and will be replaced with {}`)
}
if (modulePath.startsWith('node:') || standartNodeModules.includes(modulePath)) { replaceAndWarn(); continue; }
if(modulePath.includes('/')) {
let fullPath, relativePath, filename, moduleDir = modulePath
if (modulePath.includes('/')) {
const arr = modulePath.split('/')

@@ -29,11 +39,6 @@ moduleDir = arr.shift()

let pkgJsonPath = `/node_modules/${moduleDir}/package.json`
const exists = await fetch(pkgJsonPath, { method: 'HEAD' })
const r = new RegExp(`require\\((["'\`])${modulePath}["'\`]\\)`)
if (exists.ok === false) {
content = content.replace(r, '{}')
console.warn(`The module "${modulePath}" can't be imported and will be replaced with {}`)
continue
}
if(packageJsonCache[pkgJsonPath]) filename = packageJsonCache[pkgJsonPath]
if (exists.ok === false) { replaceAndWarn(); continue; }
if (packageJsonCache[pkgJsonPath]) filename = packageJsonCache[pkgJsonPath]
else {

@@ -45,14 +50,9 @@ const { main = 'index.js' } = await Require.fetch(pkgJsonPath, 'json')

if(relativePath) {
const relativeDir = filename.split('/')
relativeDir.pop()
fullPath = `/node_modules/${moduleDir}/${relativeDir.join('/')}/${relativePath}`
} else {
fullPath = `/node_modules/${moduleDir}/${filename}`
}
fullPath = fullPath.replace(/\/\.?\//g,'/')
if(!fullPath.endsWith('.js')) fullPath += '.js'
if (relativePath) fullPath = `/node_modules/${moduleDir}/${relativePath}`
else fullPath = `/node_modules/${moduleDir}/${filename}`
fullPath = fullPath.replace(/\/\.?\//g, '/')
if (!fullPath.endsWith('.js')) fullPath += '.js'
Require.isCyclyc(fullPath, modulePath)
children.push(fullPath);
content = content.replace(match, match.replace(r, (m,quoute) => {
content = content.replace(match, match.replace(r, (m, quoute) => {
return `require(${quoute}${fullPath}${quoute})`

@@ -88,35 +88,2 @@ }))

}
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='context',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) {

@@ -139,4 +106,47 @@ let [message, ...stack] = error.stack.split('\n')

}
function getFns(contextName,obj, scriptBefore = '', scriptAfter = '') {
function buildFn(fnBody,path) {
return /*js*/`modules['${path}'] = function ____(){
const module = { exports: {} }
const exports = module.exports
${fnBody}
return module.exports;
};`
}
const before = [
parseError.toString(),
/*js*/`function require(path) {
if(typeof modules[path] === 'function' && modules[path].name === '____') modules[path] = modules[path]()
return modules[path] || null
};`,
scriptBefore,
].join('\n')
const modulesLines = {};
let curLastLine = 3+before.split('\n').length;
const fns = obj.keys.map((path, i) => {
let code = buildFn(obj.contents[path],path)
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 params = [contextName,'modules={}',`curLastLine = ${curLastLine}`,`modulesLines = ${JSON.stringify(modulesLines)}`].join(',')
const body = [
before,
/*js*/`try {
${fns}
} catch (error) { parseError(error, modulesLines, curLastLine) }`,
scriptAfter,
].join('\n')
const fn = new Function(params, body)
return fn
}
class Require {
static contents = {}
static cyclicDependencies = false
static contextName = 'context'
static logger = console
static version

@@ -157,6 +167,6 @@

static async getModule(path, context, contextName, modules) {
static async getModule(path, context) {
const mod = new Require(path)
await mod.getContent()
return mod.build(modules, context, contextName)
return mod.build(context)
}

@@ -174,3 +184,3 @@

await getContents(this, Require)
this.keys = getKeys(this.contents,Require)
this.keys = Object.keys(this.contents).reverse()
this.contentReady = true

@@ -180,64 +190,27 @@ 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)}
build(context = {},scriptBefore,scriptAfter,modules = {}) {
const fn = getFns(Require.contextName,this,scriptBefore,scriptAfter)
return fn(context,modules)
}
}
return Require;
Require.getFullPath = getFullPath;Require.getNodeModules = getNodeModules;Require.getContents = getContents;Require.parseError = parseError;Require.getFns = getFns;Require.Require = Require;
Require.standartNodeModules = standartNodeModules;
return Require;
})()
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 fn = function anonymous(modules,context
) {
function require(path) { return modules[path] || null };
modules['/lib/utils/remove-comments.js'] = (function (){
const module = { exports: {} }
const exports = module.exports
const RenderJsx = (function(){
const singleProps = ["disabled","checked","readonly","required","hidden","autofocus","multiple","selected","controls","loop","muted","open","spellcheck","draggable","contenteditable","novalidate"]
function removeComments(code) {
const r = /`.*?\/\/.*?`|".*?\/\/.*?"|'.*?\/\/.*?'/
return code
.replace(/^(.*)(\/\/.*)($|\n)/gm,(m,before,comment) => {
const stringResult = (before+comment).match(r)
if(stringResult && stringResult.index < before.length) return m // string starts before //
return before
})
.replace(/\{?\/\*[\s\S]*?\*\/\}?/gm, '')
const stringPattern = /(['"`])(\\?.)*?\1/g;
const commentPattern = /(^|[^\\])((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm;
const stringMatches = [];
code = code.replace(stringPattern, (match) => {
stringMatches.push(match);
return `__STRING_PLACEHOLDER__`;
});
code = code.replace(commentPattern, '$1');
return code.replace(/__STRING_PLACEHOLDER__/g, () => stringMatches.shift());
}
module.exports = removeComments
return module.exports;
})();
modules['/lib/jsx/breckets.js'] = (function (){
const module = { exports: {} }
const exports = module.exports
function getInsideBreckets(i, content) {

@@ -272,102 +245,2 @@ let count = 0;

}
module.exports = getInsideBreckets
return module.exports;
})();
modules['/lib/build-component/get-function.js'] = (function (){
const module = { exports: {} }
const exports = module.exports
const getInsideBreckets = require('/lib/jsx/breckets.js')
function getFunction(content, componentName) {
const all = '[\\s\\S]*?', s = '\\s*?'
const r = new RegExp(`^\\s*?(async\\s)?function${s}${componentName}${s}\\(${all}\\)${all}{`, 'm')
const fnStart = content.match(r)
if (!fnStart) return null
const start = fnStart.index + fnStart[0].length
const end = getInsideBreckets(start, content)
return content.slice(fnStart.index, end)
}
module.exports = getFunction
return module.exports;
})();
modules['/lib/build-component/index.js'] = (function (){
const module = { exports: {} }
const exports = module.exports
const getFunction = require('/lib/build-component/get-function.js')
function buildComponentFn(content,componentName) {
if(/[A-Z]/.test(componentName[0]) === false) return content
const originalFn = getFunction(content,componentName)
if(originalFn === null) return content
const isAsync = originalFn.startsWith('async')
const newFunction = /*js*/`${isAsync ? 'async ' : ''}function ${componentName}(props={},inner,parentComponent) {
let originalFn = ${originalFn}
const component = context.getComponent('${componentName}',props,inner)
component.parentComponent = parentComponent
originalFn = originalFn.bind(component)
const result = ${isAsync ? 'await ' : ''}originalFn(props,inner,this)
component.addToUpdated()
return result
}
context.addComponentFn('${componentName}',${componentName})
`
return content.replace(originalFn,newFunction)
}
module.exports = buildComponentFn
return module.exports;
})();
modules['/lib/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) {
let vars = [...props,...attributes.map(([k,v]) => ([k,'"'+v+'"']))]
.map(([name,value]) => `${name}:${value}`)
if(rest) vars.push(rest)
props = '{'+ vars.join(',') + '}'
outer = '${'+`${tagName}(${props},\`${inner}\`)`+'}'
} else {
if(tagName === '') {
if(inner) return inner
return ''
}
props = props.map(([name,value]) => ([name,'${'+value+'}']))
const atts = [...attributes,...props].map(([name,value]) => {
if(value) return `${name}="${value.replace(/\"/g,'\\\"')}"`
else return name
}).join(' ')
outer = `<${tagName}${atts.length ? ' '+atts : ''}>`
if(!selfClosed) outer += inner + `</${tagName}>`
}
return outer
}
module.exports = getOuter
return module.exports;
})();
modules['/lib/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()
value = '$'+`{this.addAction('${event}',${value})}`
element.attributes.push([event,value])
}
module.exports = buildAction
return module.exports;
})();
modules['/lib/jsx/attributes/build-prop.js'] = (function (){
const module = { exports: {} }
const exports = module.exports
const singleProps = ["disabled", "checked", "readonly", "required", "hidden", "autofocus", "multiple", "selected", "controls", "loop", "muted", "open", "spellcheck", "draggable", "contenteditable", "novalidate"];
const buildAction = require('/lib/jsx/attributes/build-action.js')
function buildProp(toAdd, to, element) {

@@ -377,16 +250,9 @@ if (!toAdd) return

if (name === 'className') name = 'class'
if (singleProps.includes(name)) {
if(name === 'async') element.async = true
else if (singleProps.includes(name)) {
if(value) name = `\${${value} ? '${name}' : ''}`
element.attributes.push([name])
} else if (to === 'props' && name.startsWith('on')) buildAction(toAdd, element)
} else if (to === 'props' && name.startsWith('on')) element.buildAction([name,value])
else element[to].push([name, value])
}
module.exports = buildProp
return module.exports;
})();
modules['/lib/jsx/attributes/get-attributes.js'] = (function (){
const module = { exports: {} }
const exports = module.exports
const buildProp = require('/lib/jsx/attributes/build-prop.js')
function getAttributes(char, i, element, content) {

@@ -461,20 +327,65 @@ let prop = '', value = '', parsingProp = true, parsingValue = false, open, count = 0;

}
function getOuter(element,componentFn) {
let { tagName, selfClosed, attributes, props, isComponent, rest, inner } = element
module.exports = getAttributes
return module.exports;
})();
modules['/lib/jsx/element.js'] = (function (){
const module = { exports: {} }
const exports = module.exports
const getAttributes = require('/lib/jsx/attributes/get-attributes.js')
const getInsideBreckets = require('/lib/jsx/breckets.js')
const getOuter = require('/lib/jsx/outer.js')
class Element {
let outer = ''
if (isComponent) {
let vars = [...props, ...attributes.map(([k, v]) => ([k, '"' + v + '"']))]
.map(([name, value]) => `${name}:${value}`)
if (rest) vars.push(rest)
const isAwait = element.async ? 'await ' : ''
props = '{' + vars.join(',') + '}'
outer = '${' + componentFn(isAwait, tagName, props, inner) + '}'
} else {
if (tagName === '') {
if (inner) return inner
return ''
}
props = props.map(([name, value]) => ([name, '${' + value + '}']))
const atts = [...attributes, ...props].map(([name, value]) => {
if (value) return `${name}="${value.replace(/\"/g, '\\\"')}"`
else return name
}).join(' ')
outer = `<${tagName}${atts.length ? ' ' + atts : ''}>`
if (!selfClosed) outer += inner + `</${tagName}>`
}
return outer
}
class RenderJsx {
static render(content) { return RenderJsx.jsxParser(removeComments(content)) }
static componentFn(isAwait, tagName, props, inner) {
return `${isAwait}(new ${tagName}(${props},\`${inner}\`)).call()`
}
static buildAction([name, value]) {
const event = name.split('on')[1].toLowerCase()
value = '$' + `{this.action('${event}',${value})}`
return [event, value]
}
static getOuter(element) { return getOuter(element,RenderJsx.componentFn) }
static 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 RenderJsx(content, i)
i = element.i
newContent += '`' + element.outer + '`'
while (content[i] !== ')') { i++ }
} else newContent += content.slice(start, i + 1)
} else newContent += content[i]
}
return newContent
}
tagName = ''; rest = ''; inner = ''; attributes = []; props = []; selfClosed = false;
constructor(content, i,componentName) {
if(content[i + 1] === '>') {
constructor(content, i) {
if (content[i + 1] === '>') {
this.isComponent = false
this.tagName = ''
this.i = i+2
this.i = i + 2
} else {

@@ -487,5 +398,2 @@ this.isComponent = /[A-Z]/.test(content[i + 1])

}
if(componentName) {
this.attributes.push(['component',`\${this.name}`])
}
this.i = getAttributes(content[i], i, this, content)

@@ -496,3 +404,4 @@ }

get outer() { return getOuter(this) }
get outer() { return RenderJsx.getOuter(this) }
buildAction([name,value]) { this.attributes.push(RenderJsx.buildAction([name,value])) }

@@ -524,3 +433,3 @@ getInner(content) {

if (this.inner[i] === '<') {
const element = new Element(this.inner, i)
const element = new RenderJsx(this.inner, i)
newInner += element.outer

@@ -531,4 +440,4 @@ i = element.i

i = getInsideBreckets(i, this.inner)
const inside = this.inner.slice(start, i+1)
newInner += '$' + Element.jsxParser(inside)
const inside = this.inner.slice(start, i + 1)
newInner += '$' + RenderJsx.jsxParser(inside)
} else newInner += this.inner[i]

@@ -539,68 +448,70 @@ }

}
return RenderJsx;
})()
module.exports = Element
return module.exports;
})();
modules['/lib/jsx/jsx-parser.js'] = (function (){
const module = { exports: {} }
const exports = module.exports
const Element = require('/lib/jsx/element.js')
class Lang {
static _start = '~'; static _end = '~';
set start(v) {this._start = v.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}
set end(v) {this._end = v.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}
function jsxParser(content,componentName) {
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,componentName)
i = element.i
newContent += '`'+element.outer+'`'
while(content[i] !== ')') {i++}
} else newContent += content.slice(start,i+1)
} else newContent += content[i]
constructor(data = {}, defaultLang = 'en') {
const { dictionary = {}, langs = [] } = data;
if (!Array.isArray(langs)) throw new Error("Langs must be an array");
this.defaultLang = defaultLang;
this.regex = new RegExp( Lang._start + '([\\s\\S]*?)' + Lang._end,'g');
this.langs = {};
langs.forEach(lang => (this.langs[lang] = {}));
for (const original in dictionary) {
if (!Array.isArray(dictionary[original]) || dictionary[original].length !== langs.length) {
throw new Error(`Translations for "${original}" do not match the number of languages.`);
}
langs.forEach((lang, i) => { this.langs[lang][original] = dictionary[original][i] });
}
}
return newContent
}
Element.jsxParser = jsxParser
dictionary(lang) {
const dictionary = this.langs[lang] || this.langs[this.defaultLang] || {};
return (m, text) => dictionary[text] || text;
}
module.exports = jsxParser
return module.exports;
})();
modules['/lib/context/component.js'] = (function (){
const module = { exports: {} }
const exports = module.exports
replace(text, lang) {
return text.replace(this.regex, this.dictionary(lang));
}
}
class Component {
static context; // added on context initiation - instance of Context
static fns = {};
static components = {};
static componentsToUpdate = {};
static isBrowser = true
static componentsToUpdate = new Set()
static components = new WeakMap()
static qs(selector, host = document) { return host.querySelector(selector) }
static qsa(selector, host = document) { return [...host.querySelectorAll(selector)] }
static get isAsync() { return this.prototype.render.constructor.name === 'AsyncFunction' };
constructor(componentName, props = {},inner) {
const { key = '' } = props;
const name = componentName + key ;
const component = Component.components[name];
if (component) return component.init(props,inner);
Component.components[name] = this;
this.mounted = false;
this.name = name;
this.selector = `[component=${this.name}]`;
this.fn = Component.fns[componentName];
this.init();
actions = []; counter = 0;
get element() { return Component.isBrowser ? document.querySelector(this.selector) : null }
set elementOuter(v) {
const element = this.element;
if (element) element.outerHTML = v
}
addToUpdated() { Component.componentsToUpdate[this.name] = this }
init(props,inner) {
this.actions = [];
this.counter = 0;
constructor(props = {}, inner) {
this.isAsync = this.constructor.isAsync
this.props = props;
this.inner = inner;
this.hooks = { mount: [() => this.mounted = true], unmount: [] };
return this;
this.name = this.constructor.name + (this.props.key ? this.props.key : '');
this.selector = `[component=${this.name}]`;
this.hooks = { mount: [], unmount: [] };
Component.components[this.name] = this
this.Component = Component
}
addAction(event, fn) {
on(event, fn) { if (this.hooks[event]) this.hooks[event].push(fn) }
async callAsync() { return (await this.render(this.props, this.inner)).replace(/^\<\w\w*/, m => `${m} component="${this.name}"`) }
callSync() { return this.render(this.props, this.inner).replace(/^\<\w\w*/, m => `${m} component="${this.name}"`) }
call() { this.Component.componentsToUpdate.add(this); return this.isAsync ? this.callAsync() : this.callSync() }
action(event, fn) {
const id = this.name + this.counter++;

@@ -611,155 +522,74 @@ this.actions.push({ event, id, fn });

on(event, fn) {
if (!this.hooks[event]) return;
this.hooks[event].push(fn);
async buildAsync(updateElement = true) {
const result = await this.call()
if (updateElement) this.elementOuter = result
if (this.Component.isBrowser) this.runActions()
return result
}
update(props=this.props,inner=this.inner) {
Component.componentsToUpdate = {};
this.init(props,inner);
const element = document.querySelector(this.selector);
if(!element || !this.fn) return;
const newHtml = this.fn.apply(this, [props,inner,this]);
if(newHtml instanceof Promise) newHtml.then(html => this.publish(element,html));
else this.publish(element,newHtml);
buildSync(updateElement = true) {
const result = this.call()
if (updateElement) this.elementOuter = result
if (this.Component.isBrowser) this.runActions()
return result
}
publish(element,html) {
element.outerHTML = html;
this.addToUpdated();
Component.context.runActions();
}
}
build(updateElement) { return this.isAsync ? this.buildAsync(updateElement) : this.buildSync(updateElement) }
update(props = this.props, inner = this.inner) { this.props = props; this.inner = inner; return this.build(true) }
module.exports = Component
return module.exports;
})();
modules['/lib/context/context.js'] = (function (){
const module = { exports: {} }
const exports = module.exports
const Component = require('/lib/context/component.js');
class Context {
links = []; styles = []; counter = 0;
constructor(browser = true, ssr = false) {
Component.context = this;
this.browser = browser;
this.ssr = ssr;
}
component(name) { return Component.components[name] }
addComponentFn(name, fn) { Component.fns[name] = fn } // used in build-component
getComponent(name, props, inner) { return new Component(name, props, inner) } // used in build-component
style(styles) { this.styles.push(styles) }
runActions() {
for (const name in Component.componentsToUpdate) {
const component = Component.componentsToUpdate[name];
const { components, componentsToUpdate } = this.Component
componentsToUpdate.forEach(component => {
const { actions, hooks, selector } = component;
const element = document.querySelector(selector);
const parent = element || document;
const parent = element && element.childNodes.length ? element : document;
hooks.mount.forEach(fn => fn(element));
actions.forEach(({ event, fn, id }) => {
const elementForEvent = parent.querySelector(`[${event}="${id}"]`);
if (!elementForEvent) return;
if (event === 'load') fn(elementForEvent);
else elementForEvent.addEventListener(event, fn);
let elementsForEvent = parent.querySelectorAll(`[${event}="${id}"]`);
if (elementsForEvent.length === 0) elementsForEvent = document.querySelectorAll(`[${event}="${id}"]`)
if (elementsForEvent.length === 0) return;
elementsForEvent.forEach(elementForEvent => {
if (event === 'load') fn(elementForEvent);
else if (typeof elementForEvent.addEventListener === 'function') {
elementForEvent.addEventListener(event, fn);
}
})
})
component.actions = [];
component.hooks.mount = [];
}
component.count = 0;
})
for (const name in Component.components) { // check if there are element's components which removed
const { selector, hooks } = Component.components[name]
for (const name in components) { // check if there are element's components which removed
const { selector, hooks } = components[name]
if (document.querySelector(selector)) continue;
hooks.unmount.forEach(fn => fn());
delete Component.components[name];
hooks.unmount.forEach(fn => fn(name));
delete components[name];
}
Component.componentsToUpdate = {}
this.Component.componentsToUpdate.clear()
}
link(link) {
const arr = this.currentPath.split('/');
arr.pop();
link.split('/').forEach(part => {
if (part === '..') arr.pop();
else if (part !== '.') arr.push(part);
})
this.links.push(arr.join('/'));
}
}
module.exports = Context;
return module.exports;
})();
modules['/lib/build.js'] = (function (){
const module = { exports: {} }
const exports = module.exports
const Context = require('/lib/context/context.js')
const jsxParser = require('/lib/jsx/jsx-parser.js')
const buildComponent = require('/lib/build-component/index.js')
const removeComments = require('/lib/utils/remove-comments.js')
function build(modules, contextName = 'context',browser,ssr) {
const context = new Context(browser,ssr)
for (const path in modules.contents) {
const componentName = path.split('/').pop().replace(/\.js$/,'')
const curPath = `context.currentPath = '${path}';\n`
const newContent = curPath+jsxParser(removeComments(modules.contents[path]),componentName)
modules.contents[path] = buildComponent(newContent,componentName)
}
const resultFn = modules.build({}, context, contextName)
let add = ''
let { links, styles } = context
if((ssr && !browser) || (!ssr && browser)) {
add = [
...links.map(link => /*html*/`<link rel="stylesheet" href="${link}">`),
styles.length ? /*html*/`<style>${styles.join('\n')}</style>` : ''
].filter(Boolean).join('\n') + '\n'
}
return { resultFn, context, add }
}
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, data = {}, options = {}) {
const { selector = 'body', contextName, version } = options
return async function render(path, data = {}, options = {}) {
const { selector, version, jsx = true, context={}, langs, lang, cyclicDependencies, logger } = options
Require.version = version
if(cyclicDependencies !== undefined) Require.cyclicDependencies = cyclicDependencies
if(logger !== undefined) Require.logger = logger
const modules = new Require(path)
await modules.getContent()
const { resultFn, context, add } = build(modules, contextName, true, false)
context.data = data
if (selector) {
const element = document.querySelector(selector)
if (element) {
const result = await resultFn(data)
element.innerHTML = add + result.trim()
context.runActions()
if(langs) {
const langsObj = new Lang(langs)
for (const path in modules.contents) {
modules.contents[path] = langsObj.replace(modules.contents[path],lang);
}
}
if (jsx) for (const path in modules.contents) {
modules.contents[path] = RenderJsx.render(modules.contents[path]);
}
const MainClass = modules.build(context,Component.toString())
const obj = new MainClass(data)
if(selector) obj.selector = selector
obj.update()
return context
}
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/utils/remove-comments.js":{"from":4,"to":20},"/lib/jsx/breckets.js":{"from":21,"to":56},"/lib/build-component/get-function.js":{"from":57,"to":75},"/lib/build-component/index.js":{"from":76,"to":102},"/lib/jsx/outer.js":{"from":103,"to":133},"/lib/jsx/attributes/build-action.js":{"from":134,"to":146},"/lib/jsx/attributes/build-prop.js":{"from":147,"to":166},"/lib/jsx/attributes/get-attributes.js":{"from":167,"to":243},"/lib/jsx/element.js":{"from":244,"to":316},"/lib/jsx/jsx-parser.js":{"from":317,"to":344},"/lib/context/component.js":{"from":345,"to":408},"/lib/context/context.js":{"from":409,"to":467},"/lib/build.js":{"from":468,"to":499},"/lib/browser.js":{"from":500,"to":526}}, 526)
}
})()
})()

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

let Require=(()=>{let d={};function a(t,e){var n,t=t.split("/"),s=[];for(n of[...e.split("/").slice(0,-1),...t])".."===n?0<s.length&&".."!==s[s.length-1]?s.pop():s.push(n):"."!==n&&s.push(n);e=s.join("/");return e.endsWith(".js")?e:e+".js"}async function t({contents:n,fullPath:t},i){let s=async o=>{if(void 0===n[o]){if(!i.contents[o]){let t=await i.fetch(o),s=[],r=[];t=t.replace(/^(?!\/\/|\/\*.*\*\/).*require\(["'`](.*)["'`]\)/gm,(t,e)=>{var n;return e.startsWith(".")?(n=a(e,o),i.isCyclyc(n,o),s.push(n),t.replace(e,n)):(r.push({match:t,modulePath:e}),t)}),t=await(async(t,r,o,i)=>{if(0!==t.length)for(var{match:a,modulePath:c}of t){let n,t,e,s=c;c.includes("/")&&(l=c.split("/"),s=l.shift(),t=l.join("/"));var l=`/node_modules/${s}/package.json`,u=await fetch(l,{method:"HEAD"}),h=new RegExp(`require\\((["'\`])${c}["'\`]\\)`);!1===u.ok?(o=o.replace(h,"{}"),console.warn(`The module "${c}" can't be imported and will be replaced with {}`)):(e=d[l]||({main:u="index.js"}=await i.fetch(l,"json"),d[l]=u),(n=(n=t?((u=e.split("/")).pop(),`/node_modules/${s}/${u.join("/")}/`+t):`/node_modules/${s}/`+e).replace(/\/\.?\//g,"/")).endsWith(".js")||(n+=".js"),i.isCyclyc(n,c),r.push(n),o=o.replace(a,a.replace(h,(t,e)=>`require(${e}${n}${e})`)))}return o})(r,s,t,i),i.contents[o]={content:t,children:s}}let{content:t,children:e}=i.contents[o];n[o]=t,await Promise.all(e.map(t=>s(t)))}};await s(t)}class r{static contents={};static version;static isCyclyc(t,e){if(this.contents[t]&&this.contents[t].children.includes(e))throw`cyclic dependency between ${e} and `+t}static async fetch(t,e="text"){this.version&&(t+="?version="+this.version);t=await fetch(t);return t.ok||console.error("HTTP error! status: "+t.status),t[e]()}static async getModule(t,e,n,s){t=new r(t);return await t.getContent(),t.build(s,e,n)}constructor(t){this.contents={},this.path=t,this.fullPath=a(t,location.pathname),this.contentReady=!1}async getContent(){return this.contentReady||(await t(this,r),this.keys=((e,n)=>{let s=new Set,r=t=>{t.forEach(t=>{e[t]&&(r(n.contents[t].children),s.add(t))})};return r(Object.keys(e).reverse()),Array.from(s)})(this.contents,r),this.contentReady=!0),this}build(t={},e={},s="context"){var{fn:s,modulesLines:r,curLastLine:o}=((t="context",s)=>{let r={},o=3;var e=s.keys.map((t,e)=>{let n=`modules['${t}'] = (function (){
const module = { exports: {} }
const exports = module.exports
${s.contents[t]}
return module.exports;
})();`;return e===s.keys.length-1&&(n+=`
return modules['${t}']`),r[t]={from:o+1},o+=n.split("\n").length,r[t].to=o,n}).join("\n");return{fn:new Function("modules",t,`function require(path) { return modules[path] || null };
`+e),modulesLines:r,curLastLine:o}})(s,this);try{return s(t,e)}catch(n){{s=n;var i=r;var a=o;let[t,...e]=s.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!==a){var s,r,e=Number(e[2]),o=Object.entries(i).filter(([,{from:t,to:e}])=>n>=t&&n<=e);if(0!==o.length)return[o,{from:s,to:r}]=o[0],` at ${t.match(/at\s(.*?)\s/)[1]} ${o} (${n-s-2}:${e})`}}}).filter(Boolean),s.stack=t+"\n"+e.join("\n"),s;return}}}}return r})(),require=Require.getModule;
const render = (()=>{function t(e,t){function n(t){return e[t]||null}var s;return e["/lib/utils/remove-comments.js"]=((s={exports:{}}).exports=function(t){let s=/`.*?\/\/.*?`|".*?\/\/.*?"|'.*?\/\/.*?'/;return t.replace(/^(.*)(\/\/.*)($|\n)/gm,(t,e,n)=>{n=(e+n).match(s);return n&&n.index<e.length?t:e}).replace(/\{?\/\*[\s\S]*?\*\/\}?/gm,"")},s.exports),e["/lib/jsx/breckets.js"]=((s={exports:{}}).exports=function(e,n){let t=0,s={'"':[],"'":[],"`":[]};for(n.replace(/["'`]/g,(t,e)=>{"\\"!==n[e-1]&&s[t].push(e)});e<n.length;){var r=n[++e];if(s[r]&&s[r].length){let t;for(var o of s[r])if(o>e){t=o;break}t&&(e=t,s[r]=s[r].filter(t=>e<t))}else if("{"===r)t++;else if("}"===r){if(!(0<t))break;t--}}return e+1},s.exports),e["/lib/build-component/get-function.js"]=(()=>{var t={exports:{}};let s=n("/lib/jsx/breckets.js");return t.exports=function(t,e){var n="[\\s\\S]*?",e=new RegExp(`^\\s*?(async\\s)?function\\s*?${e}\\s*?\\(${n}\\)${n}{`,"m");return(n=t.match(e))?(e=n.index+n[0].length,e=s(e,t),t.slice(n.index,e)):null},t.exports})(),e["/lib/build-component/index.js"]=(()=>{var t={exports:{}};let r=n("/lib/build-component/get-function.js");return t.exports=function(t,e){var n,s;return!1===/[A-Z]/.test(e[0])||null===(n=r(t,e))?t:(s=n.startsWith("async"),t.replace(n,`${s?"async ":""}function ${e}(props={},inner,parentComponent) {
let originalFn = ${n}
const component = context.getComponent('${e}',props,inner)
component.parentComponent = parentComponent
originalFn = originalFn.bind(component)
const result = ${s?"await ":""}originalFn(props,inner,this)
component.addToUpdated()
return result
}
context.addComponentFn('${e}',${e})
`))},t.exports})(),e["/lib/jsx/outer.js"]=((s={exports:{}}).exports=function(t){let{tagName:e,selfClosed:n,attributes:s,props:r,isComponent:o,rest:i,inner:l}=t,a="";if(o){t=[...r,...s.map(([t,e])=>[t,'"'+e+'"'])].map(([t,e])=>t+":"+e);i&&t.push(i),r="{"+t.join(",")+"}",a="${"+`${e}(${r},\`${l}\`)`+"}"}else{if(""===e)return l||"";r=r.map(([t,e])=>[t,"${"+e+"}"]);t=[...s,...r].map(([t,e])=>e?`${t}="${e.replace(/\"/g,'\\"')}"`:t).join(" ");a=`<${e}${t.length?" "+t:""}>`,n||(a+=l+`</${e}>`)}return a},s.exports),e["/lib/jsx/attributes/build-action.js"]=((s={exports:{}}).exports=function(t,e){var[t,n]=t,t=t.split("on")[1].toLowerCase();e.attributes.push([t,"$"+`{this.addAction('${t}',${n})}`])},s.exports),e["/lib/jsx/attributes/build-prop.js"]=(()=>{var t={exports:{}};let o=["disabled","checked","readonly","required","hidden","autofocus","multiple","selected","controls","loop","muted","open","spellcheck","draggable","contenteditable","novalidate"],i=n("/lib/jsx/attributes/build-action.js");return t.exports=function(n,s,r){if(n){let[t,e]=n;"className"===t&&(t="class"),o.includes(t)?(e&&(t=`\${${e} ? '${t}' : ''}`),r.attributes.push([t])):"props"===s&&t.startsWith("on")?i(n,r):r[s].push([t,e])}},t.exports})(),e["/lib/jsx/attributes/get-attributes.js"]=(()=>{var t={exports:{}};let p=n("/lib/jsx/attributes/build-prop.js");return t.exports=function(t,e,s,r){let o="",i="",l=!0,a=!1,u,n=0;function c(t,e,n="attributes"){for(p(e,n,s),l=!0,a=!1,o="",i="",u=null;0===r[t].trim().length;)t++;return t}for(;">"!==t&&!(e>=r.length);){if(l)if("{"===t){for(;e<r.length&&"}"!==(t=r[++e]);)s.rest+=t;c(e)}else if("="===t||0===t.trim().length)0<o.length&&(" "===t&&"="!==r[e+1]?(s.attributes.push([o]),o=""):(l=!1,a=!0));else{if(">"===r[e+1]){"/"===t?s.selfClosed=!0:""!==o&&s.attributes.push([o+t]),e++;break}o+=t}else a&&(u?"{"===u?(i+=t,"{"===t?n++:"}"===t&&(0<n?n--:e=c(e,[o,i.slice(0,-1)],"props"))):"\\"!==r[e-1]&&t===u?e=c(e,[o,i]):i+=t:/["'`{]/.test(t)?u=t:/[a-zA-Z]/.test(t)&&(""!==o&&s.attributes.push([o]),l=!0,a=!1,o=t));">"===(t=r[++e])&&a&&(i+=t,t=r[++e])}return++e},t.exports})(),e["/lib/jsx/element.js"]=(()=>{var t={exports:{}};let s=n("/lib/jsx/attributes/get-attributes.js"),r=n("/lib/jsx/breckets.js"),e=n("/lib/jsx/outer.js");class o{tagName="";rest="";inner="";attributes=[];props=[];selfClosed=!1;constructor(t,e,n){if(">"===t[e+1])this.isComponent=!1,this.tagName="",this.i=e+2;else{for(this.isComponent=/[A-Z]/.test(t[e+1]);e<t.length&&!1!==/[A-Za-z0-9.]/.test(t[++e]);)this.tagName+=t[e];n&&this.attributes.push(["component","${this.name}"]),this.i=s(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(var s="</>"==e?"<>":"<"+this.tagName;this.i<t.length;){if(this.inner+=t[this.i],this.inner.endsWith(s)&&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,s;"<"===this.inner[t]?(n=new o(this.inner,t),e+=n.outer,t=n.i):"{"===this.inner[t]?(n=t,t=r(t,this.inner),s=this.inner.slice(n,t+1),e+="$"+o.jsxParser(s)):e+=this.inner[t]}this.inner=e}}}return t.exports=o,t.exports})(),e["/lib/jsx/jsx-parser.js"]=(()=>{var t={exports:{}};let i=n("/lib/jsx/element.js");function e(e,n){let s="";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 o=new i(e,t,n);for(t=o.i,s+="`"+o.outer+"`";")"!==e[t];)t++}else s+=e.slice(r,t+1)}else s+=e[t];return s}return i.jsxParser=e,t.exports=e,t.exports})(),e["/lib/context/component.js"]=(()=>{var t={exports:{}};class o{static context;static fns={};static components={};static componentsToUpdate={};constructor(t,e={},n){var{key:s=""}=e,s=t+s,r=o.components[s];if(r)return r.init(e,n);(o.components[s]=this).mounted=!1,this.name=s,this.selector=`[component=${this.name}]`,this.fn=o.fns[t],this.init()}addToUpdated(){o.componentsToUpdate[this.name]=this}init(t,e){return this.actions=[],this.counter=0,this.props=t,this.inner=e,this.hooks={mount:[()=>this.mounted=!0],unmount:[]},this}addAction(t,e){var n=this.name+this.counter++;return this.actions.push({event:t,id:n,fn:e}),n}on(t,e){this.hooks[t]&&this.hooks[t].push(e)}update(t=this.props,e=this.inner){o.componentsToUpdate={},this.init(t,e);let n=document.querySelector(this.selector);n&&this.fn&&((t=this.fn.apply(this,[t,e,this]))instanceof Promise?t.then(t=>this.publish(n,t)):this.publish(n,t))}publish(t,e){t.outerHTML=e,this.addToUpdated(),o.context.runActions()}}return t.exports=o,t.exports})(),e["/lib/context/context.js"]=(()=>{var t={exports:{}};let l=n("/lib/context/component.js");return t.exports=class{links=[];styles=[];counter=0;constructor(t=!0,e=!1){(l.context=this).browser=t,this.ssr=e}component(t){return l.components[t]}addComponentFn(t,e){l.fns[t]=e}getComponent(t,e,n){return new l(t,e,n)}style(t){this.styles.push(t)}runActions(){for(var t in l.componentsToUpdate){var t=l.componentsToUpdate[t],{actions:n,hooks:r,selector:o}=t;let e=document.querySelector(o),s=e||document;r.mount.forEach(t=>t(e)),n.forEach(({event:t,fn:e,id:n})=>{n=s.querySelector(`[${t}="${n}"]`);n&&("load"===t?e(n):n.addEventListener(t,e))}),t.actions=[],t.hooks.mount=[]}for(var e in l.components){var{selector:s,hooks:i}=l.components[e];document.querySelector(s)||(i.unmount.forEach(t=>t()),delete l.components[e])}l.componentsToUpdate={}}link(t){let e=this.currentPath.split("/");e.pop(),t.split("/").forEach(t=>{".."===t?e.pop():"."!==t&&e.push(t)}),this.links.push(e.join("/"))}},t.exports})(),e["/lib/build.js"]=(()=>{var t={exports:{}};let p=n("/lib/context/context.js"),h=n("/lib/jsx/jsx-parser.js"),m=n("/lib/build-component/index.js"),b=n("/lib/utils/remove-comments.js");return t.exports=function(t,e="context",n,s){var r,o=new p(n,s);for(r in t.contents){var i=r.split("/").pop().replace(/\.js$/,""),l=`context.currentPath = '${r}';
`+h(b(t.contents[r]),i);t.contents[r]=m(l,i)}let a="";var{links:u,styles:c}=o;return{resultFn:t.build({},o,e),context:o,add:a=s&&!n||!s&&n?[...u.map(t=>`<link rel="stylesheet" href="${t}">`),c.length?`<style>${c.join("\n")}</style>`:""].filter(Boolean).join("\n")+"\n":a}},t.exports})(),e["/lib/browser.js"]=(()=>{var t={exports:{}};let o=n("/lib/build.js");return t.exports=async function(t,e={},n={}){var{selector:n="body",contextName:s,version:r}=n;Require.version=r;await(r=new Require(t)).getContent();var{resultFn:t,context:r,add:s}=o(r,s,!0,!1);return r.data=e,n&&(n=document.querySelector(n))&&(t=await t(e),n.innerHTML=s+t.trim(),r.runActions()),r},t.exports})(),e["/lib/browser.js"]}{var e;let s=new Function("return "+"{}")();(function t(e){for(var n in e)"function"==typeof e[n]&&e[n].name===Obj.recursiveName?e[n]=e[n](s):null!==e[n]&&"object"==typeof e[n]&&t(e[n])})(s),s}try{t({})}catch(n){{var s=n;var i={"/lib/utils/remove-comments.js":{from:4,to:20},"/lib/jsx/breckets.js":{from:21,to:56},"/lib/build-component/get-function.js":{from:57,to:75},"/lib/build-component/index.js":{from:76,to:102},"/lib/jsx/outer.js":{from:103,to:133},"/lib/jsx/attributes/build-action.js":{from:134,to:146},"/lib/jsx/attributes/build-prop.js":{from:147,to:166},"/lib/jsx/attributes/get-attributes.js":{from:167,to:243},"/lib/jsx/element.js":{from:244,to:316},"/lib/jsx/jsx-parser.js":{from:317,to:344},"/lib/context/component.js":{from:345,to:408},"/lib/context/context.js":{from:409,to:467},"/lib/build.js":{from:468,to:499},"/lib/browser.js":{from:500,to:526}};var l=526;let[t,...e]=s.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 s,r,e=Number(e[2]),o=Object.entries(i).filter(([,{from:t,to:e}])=>n>=t&&n<=e);if(0!==o.length)return[o,{from:s,to:r}]=o[0],` at ${t.match(/at\s(.*?)\s/)[1]} ${o} (${n-s-2}:${e})`}}}).filter(Boolean),s.stack=t+"\n"+e.join("\n"),s;return}}})();
const render = (function(){
let Require=(()=>{let d={},n=["assert","async_hooks","buffer","child_process","cluster","console","constants","crypto","dgram","diagnostics_channel","dns","domain","events","fs","http","http2","https","inspector","module","net","os","path","perf_hooks","process","punycode","querystring","readline","repl","stream","string_decoder","sys","timers","timers/promises","tls","trace_events","tty","url","util","v8","vm","wasi","worker_threads","zlib","test","abort_controller"];function getFullPath(e,t){var n,e=e.split("/"),s=[];for(n of[...t.split("/").slice(0,-1),...e])".."===n?0<s.length&&".."!==s[s.length-1]?s.pop():s.push(n):"."!==n&&s.push(n);t=s.join("/");return t.endsWith(".js")?t:t+".js"}async function getNodeModules(e,a,l,c){let{logger:t=console}=c;if(0!==e.length)for(let{match:o,modulePath:i}of e){let r=new RegExp(`require\\((["'\`])${i}["'\`]\\)`);var u=()=>{l=l.replace(r,"{}"),t.warn(`The module "${i}" can't be imported and will be replaced with {}`)};if(i.startsWith("node:")||n.includes(i))u();else{let n,e,t,s=i;i.includes("/")&&(h=i.split("/"),s=h.shift(),e=h.join("/"));var h=`/node_modules/${s}/package.json`;!1===(await fetch(h,{method:"HEAD"})).ok?u():(t=d[h]||({main:u="index.js"}=await c.fetch(h,"json"),d[h]=u),(n=(n=e?`/node_modules/${s}/`+e:`/node_modules/${s}/`+t).replace(/\/\.?\//g,"/")).endsWith(".js")||(n+=".js"),c.isCyclyc(n,i),a.push(n),l=l.replace(o,o.replace(r,(e,t)=>`require(${t}${n}${t})`)))}}return l}async function getContents({contents:n,fullPath:e},i){let s=async o=>{if(void 0===n[o]){if(!i.contents[o]){let e=await i.fetch(o),s=[],r=[];e=e.replace(/^(?!\/\/|\/\*.*\*\/).*require\(["'`](.*)["'`]\)/gm,(e,t)=>{var n;return t.startsWith(".")?(n=getFullPath(t,o),i.isCyclyc(n,o),s.push(n),e.replace(t,n)):(r.push({match:e,modulePath:t}),e)}),e=await getNodeModules(r,s,e,i),i.contents[o]={content:e,children:s}}let{content:e,children:t}=i.contents[o];n[o]=e,await Promise.all(t.map(e=>s(e)))}};await s(e)}function parseError(e,i,a){let[t,...n]=e.stack.split("\n");throw n=n.map(e=>{var t=e.match(/<anonymous>:(\d*):(\d*)\)$/);if(t){let n=Number(t[1]);if(n+1!==a){var s,r,t=Number(t[2]),o=Object.entries(i).filter(([,{from:e,to:t}])=>n>=e&&n<=t);if(0!==o.length)return[o,{from:s,to:r}]=o[0],` at ${e.match(/at\s(.*?)\s/)[1]} ${o} (${n-s-2}:${t})`}}}).filter(Boolean),e.stack=t+"\n"+n.join("\n"),e}function getFns(e,s,t="",n=""){t=[parseError.toString(),`function require(path) {
if(typeof modules[path] === 'function' && modules[path].name === '____') modules[path] = modules[path]()
return modules[path] || null
};`,t].join("\n");let r={},o=3+t.split("\n").length;var i=s.keys.map((e,t)=>{let n=function buildFn(e,t){return`modules['${t}'] = function ____(){
const module = { exports: {} }
const exports = module.exports
${e}
return module.exports;
};`}(s.contents[e],e);return t===s.keys.length-1&&(n+=`
return modules['${e}']()`),r[e]={from:o+1},o+=n.split("\n").length,r[e].to=o,n}).join("\n"),e=[e,"modules={}","curLastLine = "+o,"modulesLines = "+JSON.stringify(r)].join(","),t=[t,`try {
${i}
} catch (error) { parseError(error, modulesLines, curLastLine) }`,n].join("\n");return new Function(e,t)}class Require{static contents={};static cyclicDependencies=!1;static contextName="context";static logger=console;static version;static isCyclyc(e,t){if(this.contents[e]&&this.contents[e].children.includes(t))throw`cyclic dependency between ${t} and `+e}static async fetch(e,t="text"){this.version&&(e+="?version="+this.version);e=await fetch(e);return e.ok||console.error("HTTP error! status: "+e.status),e[t]()}static async getModule(e,t){e=new Require(e);return await e.getContent(),e.build(t)}constructor(e){this.contents={},this.path=e,this.fullPath=getFullPath(e,location.pathname),this.contentReady=!1}async getContent(){return this.contentReady||(await getContents(this,Require),this.keys=Object.keys(this.contents).reverse(),this.contentReady=!0),this}build(e={},t,n,s={}){return getFns(Require.contextName,this,t,n)(e,s)}}return Require.getFullPath=getFullPath,Require.getNodeModules=getNodeModules,Require.getContents=getContents,Require.parseError=parseError,Require.getFns=getFns,(Require.Require=Require).standartNodeModules=n,Require})();
const require=Require.getModule;
let RenderJsx=(()=>{let f=["disabled","checked","readonly","required","hidden","autofocus","multiple","selected","controls","loop","muted","open","spellcheck","draggable","contenteditable","novalidate"];function i(e,t,n,l){let a="",h="",o=!0,u=!1,c,i=0;function s(e,i,s="attributes"){var r=n;if(i){let[e,t]=i;"async"===(e="className"===e?"class":e)?r.async=!0:f.includes(e)?(t&&(e=`\${${t} ? '${e}' : ''}`),r.attributes.push([e])):"props"===s&&e.startsWith("on")?r.buildAction([e,t]):r[s].push([e,t])}for(o=!0,u=!1,a="",h="",c=null;0===l[e].trim().length;)e++;return e}for(;">"!==e&&!(t>=l.length);){if(o)if("{"===e){for(;t<l.length&&"}"!==(e=l[++t]);)n.rest+=e;s(t)}else if("="===e||0===e.trim().length)0<a.length&&(" "===e&&"="!==l[t+1]?(n.attributes.push([a]),a=""):(o=!1,u=!0));else{if(">"===l[t+1]){"/"===e?n.selfClosed=!0:""!==a&&n.attributes.push([a+e]),t++;break}a+=e}else u&&(c?"{"===c?(h+=e,"{"===e?i++:"}"===e&&(0<i?i--:t=s(t,[a,h.slice(0,-1)],"props"))):"\\"!==l[t-1]&&e===c?t=s(t,[a,h]):h+=e:/["'`{]/.test(e)?c=e:/[a-zA-Z]/.test(e)&&(""!==a&&n.attributes.push([a]),o=!0,u=!1,a=e));">"===(e=l[++t])&&u&&(h+=e,e=l[++t])}return++t}class c{static render(e){return c.jsxParser((e=>{let t=[];return(e=(e=e.replace(/(['"`])(\\?.)*?\1/g,e=>(t.push(e),"__STRING_PLACEHOLDER__"))).replace(/(^|[^\\])((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm,"$1")).replace(/__STRING_PLACEHOLDER__/g,()=>t.shift())})(e))}static componentFn(e,t,i,s){return e+`(new ${t}(${i},\`${s}\`)).call()`}static buildAction([e,t]){e=e.split("on")[1].toLowerCase();return[e,t="$"+`{this.action('${e}',${t})}`]}static getOuter(h){{var o=c.componentFn;let{tagName:e,selfClosed:t,attributes:i,props:s,isComponent:r,rest:n,inner:l}=h,a="";if(r){var u=[...s,...i.map(([e,t])=>[e,'"'+t+'"'])].map(([e,t])=>e+":"+t),h=(n&&u.push(n),h.async?"await ":"");s="{"+u.join(",")+"}",a="${"+o(h,e,s,l)+"}"}else{if(""===e)return l||"";s=s.map(([e,t])=>[e,"${"+t+"}"]);u=[...i,...s].map(([e,t])=>t?`${e}="${t.replace(/\"/g,'\\"')}"`:e).join(" ");a=`<${e}${u.length?" "+u:""}>`,t||(a+=l+`</${e}>`)}return a}}static jsxParser(t){let i="";for(let e=0;e<t.length;e++)if("("===t[e]){var s=e;for(e++;0===t[e].trim().length;)e++;if("<"===t[e]){var r=new c(t,e);for(e=r.i,i+="`"+r.outer+"`";")"!==t[e];)e++}else i+=t.slice(s,e+1)}else i+=t[e];return i}tagName="";rest="";inner="";attributes=[];props=[];selfClosed=!1;constructor(e,t){if(">"===e[t+1])this.isComponent=!1,this.tagName="",this.i=t+2;else{for(this.isComponent=/[A-Z]/.test(e[t+1]);t<e.length&&!1!==/[A-Za-z0-9.]/.test(e[++t]);)this.tagName+=e[t];this.i=i(e[t],t,this,e)}!1===this.selfClosed&&this.getInner(e)}get outer(){return c.getOuter(this)}buildAction([e,t]){this.attributes.push(c.buildAction([e,t]))}getInner(e){var t=`</${this.tagName}>`;let i=0;for(var s="</>"==t?"<>":"<"+this.tagName;this.i<e.length;){if(this.inner+=e[this.i],this.inner.endsWith(s)&&i++,this.inner.endsWith(t)){if(!(0<i)){this.inner=this.inner.slice(0,-t.length).trim();break}i--}this.i++}this.buildInner()}buildInner(){let t="";if(!(this.inner.trim().length<2)&&(this.inner.includes("<")||this.inner.includes("{"))){for(let e=0;e<this.inner.length;e++){var i,s;"<"===this.inner[e]?(i=new c(this.inner,e),t+=i.outer,e=i.i):"{"===this.inner[e]?(e=((t,i)=>{let e=0,s={'"':[],"'":[],"`":[]};for(i.replace(/["'`]/g,(e,t)=>{"\\"!==i[t-1]&&s[e].push(t)});t<i.length;){var r=i[++t];if(s[r]&&s[r].length){let e;for(var n of s[r])if(n>t){e=n;break}e&&(t=e,s[r]=s[r].filter(e=>t<e))}else if("{"===r)e++;else if("}"===r){if(!(0<e))break;e--}}return t+1})(i=e,this.inner),s=this.inner.slice(i,e+1),t+="$"+c.jsxParser(s)):t+=this.inner[e]}this.inner=t}}}return c})();
class Lang{static _start="~";static _end="~";set start(t){this._start=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}set end(t){this._end=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}constructor(t={},r="en"){let{dictionary:s={},langs:e=[]}=t;if(!Array.isArray(e))throw new Error("Langs must be an array");this.defaultLang=r,this.regex=new RegExp(Lang._start+"([\\s\\S]*?)"+Lang._end,"g"),this.langs={},e.forEach(t=>this.langs[t]={});for(let a in s){if(!Array.isArray(s[a])||s[a].length!==e.length)throw new Error(`Translations for "${a}" do not match the number of languages.`);e.forEach((t,r)=>{this.langs[t][a]=s[a][r]})}}dictionary(t){let a=this.langs[t]||this.langs[this.defaultLang]||{};return(t,r)=>a[r]||r}replace(t,r){return t.replace(this.regex,this.dictionary(r))}}
class Component{static isBrowser=!0;static componentsToUpdate=new Set;static components=new WeakMap;static qs(t,e=document){return e.querySelector(t)}static qsa(t,e=document){return[...e.querySelectorAll(t)]}static get isAsync(){return"AsyncFunction"===this.prototype.render.constructor.name}actions=[];counter=0;get element(){return Component.isBrowser?document.querySelector(this.selector):null}set elementOuter(t){var e=this.element;e&&(e.outerHTML=t)}constructor(t={},e){this.isAsync=this.constructor.isAsync,this.props=t,this.inner=e,this.name=this.constructor.name+(this.props.key||""),this.selector=`[component=${this.name}]`,this.hooks={mount:[],unmount:[]},(Component.components[this.name]=this).Component=Component}on(t,e){this.hooks[t]&&this.hooks[t].push(e)}async callAsync(){return(await this.render(this.props,this.inner)).replace(/^\<\w\w*/,t=>`${t} component="${this.name}"`)}callSync(){return this.render(this.props,this.inner).replace(/^\<\w\w*/,t=>`${t} component="${this.name}"`)}call(){return this.Component.componentsToUpdate.add(this),this.isAsync?this.callAsync():this.callSync()}action(t,e){var n=this.name+this.counter++;return this.actions.push({event:t,id:n,fn:e}),n}async buildAsync(t=!0){var e=await this.call();return t&&(this.elementOuter=e),this.Component.isBrowser&&this.runActions(),e}buildSync(t=!0){var e=this.call();return t&&(this.elementOuter=e),this.Component.isBrowser&&this.runActions(),e}build(t){return this.isAsync?this.buildAsync(t):this.buildSync(t)}update(t=this.props,e=this.inner){return this.props=t,this.inner=e,this.build(!0)}runActions(){var{components:t,componentsToUpdate:e}=this.Component;e.forEach(t=>{var{actions:e,hooks:n,selector:s}=t;let o=document.querySelector(s),r=o&&o.childNodes.length?o:document;n.mount.forEach(t=>t(o)),e.forEach(({event:e,fn:n,id:t})=>{let s=r.querySelectorAll(`[${e}="${t}"]`);0!==(s=0===s.length?document.querySelectorAll(`[${e}="${t}"]`):s).length&&s.forEach(t=>{"load"===e?n(t):"function"==typeof t.addEventListener&&t.addEventListener(e,n)})}),t.actions=[],t.hooks.mount=[],t.count=0});for(let e in t){var{selector:n,hooks:s}=t[e];document.querySelector(n)||(s.unmount.forEach(t=>t(e)),delete t[e])}this.Component.componentsToUpdate.clear()}}
return async function render(e,n={},t={}){var{selector:t,version:r,jsx:o=!0,context:c={},langs:i,lang:s,cyclicDependencies:l,logger:a}=t,d=(Require.version=r,void 0!==l&&(Require.cyclicDependencies=l),void 0!==a&&(Require.logger=a),new Require(e));if(await d.getContent(),i){var g=new Lang(i);for(let e in d.contents)d.contents[e]=g.replace(d.contents[e],s)}if(o)for(let e in d.contents)d.contents[e]=RenderJsx.render(d.contents[e]);r=new(d.build(c,Component.toString()))(n);return t&&(r.selector=t),r.update(),c}
})()
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