jsxte
Advanced tools
Comparing version 3.1.10-canary-5d95b153702c285c28febd4f5a03090a21cd6ef5.0 to 3.1.10-canary-99ea1f5a68f7eb363806037de4af6c5d92ba600b.0
@@ -31,12 +31,23 @@ "use strict"; | ||
var import_join = require("../utilities/join.js"); | ||
var import_self_closing_tag_list = require("../utilities/self-closing-tag-list.js"); | ||
var import_attribute_to_html_tag_string = require("./attribute-to-html-tag-string.js"); | ||
var import_self_closing_tag_list = require("../utilities/self-closing-tag-list.js"); | ||
function leftPad(str, padLength) { | ||
function leftPadHtml(str, padLength) { | ||
const pad = " ".repeat(padLength); | ||
let result = pad; | ||
let isPreformatted = false; | ||
for (let i = 0; i < str.length; i++) { | ||
const char = str[i]; | ||
if (char === "\n" && i + 1 < str.length) { | ||
result += char + pad; | ||
if (!isPreformatted) { | ||
if (char === "e" && i > 2 && str[i - 1] === "r" && str[i - 2] === "p" && str[i - 3] === "<") { | ||
isPreformatted = true; | ||
} | ||
if (char === "\n" && i + 1 < str.length) { | ||
result += char + pad; | ||
} else { | ||
result += char; | ||
} | ||
} else { | ||
if (char === "<" && i + 4 < str.length && str[i + 1] === "/" && str[i + 2] === "p" && str[i + 3] === "r" && str[i + 4] === "e") { | ||
isPreformatted = false; | ||
} | ||
result += char; | ||
@@ -51,3 +62,3 @@ } | ||
} | ||
prepareContent(content) { | ||
prepareContent(tag, content) { | ||
if (content.length === 0) | ||
@@ -58,3 +69,10 @@ return void 0; | ||
} | ||
return leftPad((0, import_join.join)(content, "\n"), 2); | ||
if (tag === "pre") { | ||
return (0, import_join.join)(content, ""); | ||
} | ||
const padded = leftPadHtml((0, import_join.join)(content, ""), this.options?.indent ?? 2); | ||
if (padded[padded.length - 1] === "\n") { | ||
return padded.slice(0, -1); | ||
} | ||
return padded; | ||
} | ||
@@ -64,19 +82,26 @@ generateTag(tag, attributes, content) { | ||
attributes = " " + attributes; | ||
} else { | ||
attributes = ""; | ||
} | ||
if (!content) { | ||
if (import_self_closing_tag_list.SELF_CLOSING_TAG_LIST.includes(tag)) { | ||
return `<${tag}${attributes} />`; | ||
return `<${tag}${attributes} /> | ||
`; | ||
} else { | ||
return `<${tag}${attributes}></${tag}>`; | ||
return `<${tag}${attributes}></${tag}> | ||
`; | ||
} | ||
} | ||
if (this.options?.compact === true) { | ||
return `<${tag}${attributes}>${content}</${tag}>`; | ||
return `<${tag}${attributes}>${content}</${tag}> | ||
`; | ||
} | ||
if (tag === "pre") { | ||
return `<${tag}${attributes}>${content}</${tag}>`; | ||
return `<${tag}${attributes}>${content}</${tag}> | ||
`; | ||
} | ||
return `<${tag}${attributes}> | ||
${content} | ||
</${tag}>`; | ||
</${tag}> | ||
`; | ||
} | ||
@@ -90,7 +115,7 @@ }; | ||
const attributesString = (0, import_attribute_to_html_tag_string.mapAttributesToHtmlTagString)(attributes); | ||
const content = this.prepareContent(children); | ||
const content = this.prepareContent(type, children); | ||
return this.generateTag(type, attributesString, content); | ||
} | ||
createFragment(children) { | ||
return this.prepareContent(children) ?? ""; | ||
return this.prepareContent("pre", children) ?? ""; | ||
} | ||
@@ -110,3 +135,3 @@ }; | ||
const attributesString = (0, import_attribute_to_html_tag_string.mapAttributesToHtmlTagString)(attributes); | ||
const content = this.prepareContent(children2); | ||
const content = this.prepareContent(type, children2); | ||
return this.generateTag(type, attributesString, content); | ||
@@ -120,3 +145,3 @@ }); | ||
return Promise.resolve(children).then((c) => Promise.all(c)).then((children2) => { | ||
return this.prepareContent(children2) ?? ""; | ||
return this.prepareContent("pre", children2) ?? ""; | ||
}); | ||
@@ -123,0 +148,0 @@ } |
@@ -39,9 +39,9 @@ "use strict"; | ||
__reExport(src_exports, require("./jsx/jsx.types.js"), module.exports); | ||
var import_component_api = require("./component-api/component-api.js"); | ||
var import_error_boundary = require("./error-boundary/error-boundary.js"); | ||
var import_component_api = require("./component-api/component-api.js"); | ||
var import_render_to_html = require("./html-renderer/render-to-html.js"); | ||
var import_render_to_json = require("./json-renderer/render-to-json.js"); | ||
var import_memo = require("./utilities/memo.js"); | ||
var import_jsx_runtime = require("./jsx/jsx-runtime.js"); | ||
var import_jsxte_render_error = require("./jsxte-render-error.js"); | ||
var import_renderer = require("./renderer/renderer.js"); | ||
var import_memo = require("./utilities/memo.js"); |
@@ -20,3 +20,3 @@ "use strict"; | ||
module.exports = __toCommonJS(jsx_runtime_exports); | ||
__reExport(jsx_runtime_exports, require("./jsx/jsx-runtime.js"), module.exports); | ||
__reExport(jsx_runtime_exports, require("./jsx/jsx.types.js"), module.exports); | ||
__reExport(jsx_runtime_exports, require("./jsx/jsx-runtime.js"), module.exports); |
@@ -38,2 +38,5 @@ "use strict"; | ||
} | ||
function isPromiseLike(obj) { | ||
return obj instanceof Promise || typeof obj === "object" && obj !== null && typeof obj.then === "function" && typeof obj.catch === "function"; | ||
} | ||
function asyncError() { | ||
@@ -108,3 +111,3 @@ throw new import_jsxte_render_error.JsxteRenderError( | ||
const result = func.apply(null, args); | ||
if (result instanceof Promise) { | ||
if (isPromiseLike(result)) { | ||
return result.catch((err) => { | ||
@@ -149,3 +152,3 @@ return this.handleError(err, args[2], args[1]); | ||
match(element, context) { | ||
if (element instanceof Promise) { | ||
if (isPromiseLike(element)) { | ||
if (this.options.allowAsync === false) { | ||
@@ -173,3 +176,3 @@ asyncError(); | ||
); | ||
if (r instanceof Promise) { | ||
if (isPromiseLike(r)) { | ||
if (this.options.allowAsync === false) { | ||
@@ -318,3 +321,3 @@ asyncError(); | ||
} | ||
if (result instanceof Promise) { | ||
if (isPromiseLike(result)) { | ||
return result.then((result2) => { | ||
@@ -321,0 +324,0 @@ if (result2 === NIL) { |
@@ -77,4 +77,5 @@ "use strict"; | ||
); | ||
if (cacheEntry && !cacheEntry.isExpired(Date.now())) | ||
if (cacheEntry && !cacheEntry.isExpired(Date.now())) { | ||
return cacheEntry.value; | ||
} | ||
return void 0; | ||
@@ -81,0 +82,0 @@ } |
@@ -26,9 +26,4 @@ "use strict"; | ||
module.exports = __toCommonJS(memo_exports); | ||
var import_render_to_html = require("../html-renderer/render-to-html.js"); | ||
var import_jsx_runtime = require("../jsx-runtime.js"); | ||
var import_cache = require("./cache.js"); | ||
var ReplaceMap = (props, context) => { | ||
context.ctx.replace(props.context.ctx); | ||
return (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, {}, props.children); | ||
}; | ||
var memo = (Component, options) => { | ||
@@ -47,8 +42,4 @@ const { | ||
return cachedResult; | ||
const result = await (0, import_render_to_html.renderToHtmlAsync)( | ||
(0, import_jsx_runtime.jsx)( | ||
ReplaceMap, | ||
{ context }, | ||
(0, import_jsx_runtime.jsx)(Component, { ...propsNoChildren }, children) | ||
) | ||
const result = await context.renderAsync( | ||
(0, import_jsx_runtime.createElement)(Component, { ...propsNoChildren }, children) | ||
); | ||
@@ -69,8 +60,4 @@ const textNode = { | ||
return cachedResult; | ||
const result = (0, import_render_to_html.renderToHtml)( | ||
(0, import_jsx_runtime.jsx)( | ||
ReplaceMap, | ||
{ context }, | ||
(0, import_jsx_runtime.jsx)(Component, { ...propsNoChildren }, children) | ||
) | ||
const result = context.render( | ||
(0, import_jsx_runtime.createElement)(Component, { ...propsNoChildren }, children) | ||
); | ||
@@ -77,0 +64,0 @@ const textNode = { |
@@ -7,3 +7,3 @@ import type { ComponentApi } from "../component-api/component-api"; | ||
constructor(options?: HtmlRenderOptions | undefined); | ||
protected prepareContent(content: string[]): string | undefined; | ||
protected prepareContent(tag: string, content: string[]): string | undefined; | ||
protected generateTag(tag: string, attributes?: string, content?: string): string; | ||
@@ -10,0 +10,0 @@ } |
export type HtmlRenderOptions = { | ||
/** | ||
* The number of spaces to use for indentation. | ||
* @default 2 | ||
*/ | ||
indent?: number; | ||
attributeMap?: Record<string, string>; | ||
/** | ||
* If true, the generated html will be compacted, removing all unnecessary | ||
* whitespace. | ||
*/ | ||
compact?: boolean; | ||
@@ -4,0 +13,0 @@ }; |
import "./utilities/array-flat-polyfill"; | ||
export * from "./express/index"; | ||
export * from "./jsx/jsx.types"; | ||
export { defineContext } from "./component-api/component-api"; | ||
export { ErrorBoundary } from "./error-boundary/error-boundary"; | ||
export { defineContext } from "./component-api/component-api"; | ||
export { renderToHtml, renderToHtmlAsync, } from "./html-renderer/render-to-html"; | ||
export { renderToJson, renderToJsonAsync, } from "./json-renderer/render-to-json"; | ||
export { memo } from "./utilities/memo"; | ||
export { createElement } from "./jsx/jsx-runtime"; | ||
@@ -13,10 +12,11 @@ export { JsxteRenderError } from "./jsxte-render-error"; | ||
export { JsxteRenderer } from "./renderer/renderer"; | ||
export type { ContextDefinition, ComponentApi, } from "./component-api/component-api"; | ||
export { memo } from "./utilities/memo"; | ||
export type { ComponentApi, ContextDefinition, } from "./component-api/component-api"; | ||
export type { HtmlRenderOptions } from "./html-renderer/render-to-html"; | ||
export type { JsxteJson } from "./json-renderer/jsx-elem-to-json"; | ||
export type { JsonRenderOptions } from "./json-renderer/render-to-json"; | ||
export type { AttributeBool, HTMLProps } from "./jsx/base-html-tag-props"; | ||
export type { InputType } from "./jsx/prop-types/input-jsx-props"; | ||
export type { Crossorigin } from "./jsx/prop-types/shared/crossorigin"; | ||
export type { RefererPolicy } from "./jsx/prop-types/shared/referer-policy"; | ||
export type { Target } from "./jsx/prop-types/shared/target"; | ||
export type { JsxteJson } from "./json-renderer/jsx-elem-to-json"; | ||
export type { InputType } from "./jsx/prop-types/input-jsx-props"; | ||
export type { HtmlRenderOptions } from "./html-renderer/render-to-html"; | ||
export type { JsonRenderOptions } from "./json-renderer/render-to-json"; |
@@ -0,2 +1,2 @@ | ||
export * from "./jsx/jsx-runtime"; | ||
export * from "./jsx/jsx.types"; | ||
export * from "./jsx/jsx-runtime"; |
@@ -5,2 +5,2 @@ import type { ComponentApi } from "../component-api/component-api"; | ||
declare const jsxDEV: (tag: string | ((props: any, contextMap: ComponentApi) => JSX.Element) | ((props: any, contextMap: ComponentApi) => Promise<JSX.Element>), props?: CreateElementProps) => JSX.Element; | ||
export { Fragment, jsx, jsxs, jsxDEV }; | ||
export { Fragment, jsx, jsxDEV, jsxs }; |
@@ -8,4 +8,4 @@ "use strict"; | ||
if ((from && typeof from === "object") || typeof from === "function") { | ||
for (let key of __getOwnPropNames(from)) | ||
if (!__hasOwnProp.call(to, key) && key !== except) | ||
for (let key of __getOwnPropNames(from)) { | ||
if (!__hasOwnProp.call(to, key) && key !== except) { | ||
__defProp(to, key, { | ||
@@ -15,2 +15,4 @@ get: () => from[key], | ||
}); | ||
} | ||
} | ||
} | ||
@@ -21,3 +23,3 @@ return to; | ||
__copyProps(target, mod, "default"), | ||
secondTarget && __copyProps(secondTarget, mod, "default") | ||
secondTarget && __copyProps(secondTarget, mod, "default") | ||
); | ||
@@ -24,0 +26,0 @@ var __toCommonJS = (mod) => |
@@ -8,4 +8,4 @@ "use strict"; | ||
if ((from && typeof from === "object") || typeof from === "function") { | ||
for (let key of __getOwnPropNames(from)) | ||
if (!__hasOwnProp.call(to, key) && key !== except) | ||
for (let key of __getOwnPropNames(from)) { | ||
if (!__hasOwnProp.call(to, key) && key !== except) { | ||
__defProp(to, key, { | ||
@@ -15,2 +15,4 @@ get: () => from[key], | ||
}); | ||
} | ||
} | ||
} | ||
@@ -21,3 +23,3 @@ return to; | ||
__copyProps(target, mod, "default"), | ||
secondTarget && __copyProps(secondTarget, mod, "default") | ||
secondTarget && __copyProps(secondTarget, mod, "default") | ||
); | ||
@@ -24,0 +26,0 @@ var __toCommonJS = (mod) => |
{ | ||
"name": "jsxte", | ||
"version": "3.1.10-canary-5d95b153702c285c28febd4f5a03090a21cd6ef5.0", | ||
"version": "3.1.10-canary-99ea1f5a68f7eb363806037de4af6c5d92ba600b.0", | ||
"description": "JSX-based html templating engine for browsers or Node environments.", | ||
@@ -39,3 +39,5 @@ "license": "MIT", | ||
"test:tsc": "tsc --noEmit", | ||
"test:unit": "vitest run" | ||
"test:unit": "vitest run", | ||
"test:fmt": "dprint check", | ||
"fmt": "dprint fmt" | ||
}, | ||
@@ -52,9 +54,8 @@ "author": { | ||
"@types/node": "^20.10.6", | ||
"@typescript-eslint/eslint-plugin": "~6.15.0", | ||
"@typescript-eslint/parser": "~6.13.1", | ||
"@typescript-eslint/eslint-plugin": "~6.17.0", | ||
"@typescript-eslint/parser": "~6.17.0", | ||
"axios": "~1.6.0", | ||
"dprint": "^0.45.0", | ||
"esbuild": "~0.19.5", | ||
"eslint": "~8.55.0", | ||
"eslint-config-prettier": "~9.1.0", | ||
"eslint-plugin-prettier": "~5.0.1", | ||
"eslint": "~8.56.0", | ||
"git-hook-tasks": "ncpa0cpl/git-hook-tasks", | ||
@@ -64,4 +65,2 @@ "husky": "~8.0.3", | ||
"pr-changelog-gen": "~1.1.3", | ||
"prettier": "~3.1.0", | ||
"prettier-plugin-jsdoc": "~1.1.1", | ||
"typescript": "latest", | ||
@@ -68,0 +67,0 @@ "vitest": "^1.1.1" |
@@ -18,8 +18,9 @@ # JSX Template Engine | ||
6. [toHtmlTag symbol](#tohtmltag-symbol) | ||
7. [Extending the typings](#extending-the-typings) | ||
7. [JsxteRenderer](#jsxterenderer) | ||
8. [Extending the typings](#extending-the-typings) | ||
1. [Adding custom web component tags](#adding-custom-web-component-tags) | ||
2. [Adding a global html attribute](#adding-a-global-html-attribute) | ||
8. [Express JS View Engine](#express-js-view-engine) | ||
9. [Monkey-Patching type definitions](#monkey-patching-type-definitions) | ||
10. [Contributing](#contributing) | ||
9. [Express JS View Engine](#express-js-view-engine) | ||
10. [Monkey-Patching type definitions](#monkey-patching-type-definitions) | ||
11. [Contributing](#contributing) | ||
@@ -60,3 +61,3 @@ ## Getting started | ||
```tsx | ||
import { renderToHtml, createElement } from "jsxte"; | ||
import { createElement, renderToHtml } from "jsxte"; | ||
@@ -285,2 +286,65 @@ const Header: JSXTE.Component<{ label: string }> = (props) => { | ||
## JsxteRenderer | ||
`JsxteRenderer` is a base class around which HTML and JSON renderer are built upon. This renderer requires a specific interface that provides methods for creating the final output format: | ||
```ts | ||
// T is the type of the renderer return value | ||
export interface ElementGenerator<T> { | ||
createElement( | ||
type: string, | ||
attributes: Array<[attributeName: string, attributeValue: any]>, | ||
children: Array<T>, | ||
): T; | ||
createTextNode(text: string | number | bigint): T; | ||
createFragment(children: Array<T>): T; | ||
} | ||
``` | ||
It is possible to render to other formats than HTML or JSON by providing a custom `ElementGenerator` implementation to the renderer. | ||
### Example | ||
```tsx | ||
import { JsxteRenderer } from "jsxte"; | ||
class DomGenerator | ||
implements ElementGenerator<HTMLElement | Text | DocumentFragment> | ||
{ | ||
createElement( | ||
type: string, | ||
attributes: Array<[attributeName: string, attributeValue: any]>, | ||
children: Array<HTMLElement | Text | DocumentFragment>, | ||
): HTMLElement | Text | DocumentFragment { | ||
const element = document.createElement(type); | ||
for (const [name, value] of attributes) { | ||
element.setAttribute(name, value); | ||
} | ||
for (const child of children) { | ||
element.appendChild(child); | ||
} | ||
return element; | ||
} | ||
createTextNode( | ||
text: string | number | bigint, | ||
): HTMLElement | Text | DocumentFragment { | ||
return document.createTextNode(String(text)); | ||
} | ||
createFragment( | ||
children: Array<HTMLElement | Text | DocumentFragment>, | ||
): HTMLElement | Text | DocumentFragment { | ||
const fragment = document.createDocumentFragment(); | ||
for (const child of children) { | ||
fragment.appendChild(child); | ||
} | ||
return fragment; | ||
} | ||
} | ||
const renderer = new JsxteRenderer(new DomGenerator()); | ||
const divElement = renderer.render(<div>Hello World!</div>); | ||
``` | ||
## Extending the typings | ||
@@ -308,3 +372,4 @@ | ||
const MyComponent: JSXTE.Component = () => ( | ||
<my-custom-web-component data-example-attribute="Hello"></my-custom-web-component> | ||
<my-custom-web-component data-example-attribute="Hello"> | ||
</my-custom-web-component> | ||
); | ||
@@ -311,0 +376,0 @@ ``` |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
267277
14
307
6841
463