als-render
Advanced tools
Comparing version 0.9.3 to 1.0.0
@@ -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. |
37
index.js
@@ -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" | ||
} | ||
} |
200
readme.md
@@ -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 | ||
``` |
684
render.js
@@ -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} | ||
})() |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
0
1
156
5
49189
5
14
705
5
+ Addedals-component@^1.2.0
+ Addedals-lang@^1.0.0
+ Addedals-render-jsx@^1.0.0
+ Addedals-component@1.2.0(transitive)
+ Addedals-lang@1.3.0(transitive)
+ Addedals-remove-js-comments@2.0.0(transitive)
+ Addedals-render-jsx@1.3.0(transitive)
+ Addedals-require@2.2.0(transitive)
- Removedals-require@1.7.0(transitive)
Updatedals-require@^2.2.0
Updateduglify-js@^3.19.3