@lwc/ssr-runtime
Advanced tools
Comparing version 8.1.2 to 8.1.3
@@ -9,2 +9,50 @@ /** | ||
/* | ||
* Copyright (c) 2024, Salesforce, Inc. | ||
* All rights reserved. | ||
* SPDX-License-Identifier: MIT | ||
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT | ||
*/ | ||
/** | ||
* Per the HTML spec on restrictions for "raw text elements" like `<style>`: | ||
* | ||
* > The text in raw text and escapable raw text elements must not contain any occurrences of the string | ||
* > "</" (U+003C LESS-THAN SIGN, U+002F SOLIDUS) followed by characters that case-insensitively match the tag name of | ||
* > the element followed by one of: | ||
* > - U+0009 CHARACTER TABULATION (tab) | ||
* > - U+000A LINE FEED (LF) | ||
* > - U+000C FORM FEED (FF) | ||
* > - U+000D CARRIAGE RETURN (CR) | ||
* > - U+0020 SPACE | ||
* > - U+003E GREATER-THAN SIGN (>), or | ||
* > - U+002F SOLIDUS (/) | ||
* @see https://html.spec.whatwg.org/multipage/syntax.html#cdata-rcdata-restrictions | ||
*/ | ||
const INVALID_STYLE_CONTENT = /<\/style[\t\n\f\r >/]/i; | ||
/** | ||
* The text content inside `<style>` is a special case. It is _only_ rendered by the LWC engine itself; `<style>` tags | ||
* are disallowed inside of HTML templates. | ||
* | ||
* The `<style>` tag is unusual in how it's defined in HTML. Like `<script>`, it is considered a "raw text element," | ||
* which means that it is parsed as raw text, but certain character sequences are disallowed, namely to avoid XSS | ||
* attacks like `</style><script>alert("pwned")</script>`. | ||
* | ||
* This also means that we cannot use "normal" HTML escaping inside `<style>` tags, e.g. we cannot use `<`, | ||
* `>`, etc., because these are treated as-is by the HTML parser. | ||
* | ||
* | ||
* @param contents CSS source to validate | ||
* @throws Throws if the contents provided are not valid. | ||
* @see https://html.spec.whatwg.org/multipage/syntax.html#raw-text-elements | ||
* @see https://github.com/salesforce/lwc/issues/3439 | ||
* @example | ||
* validateStyleTextContents('div { color: red }') // Ok | ||
* validateStyleTextContents('</style><script>alert("pwned")</script>') // Throws | ||
*/ | ||
function validateStyleTextContents(contents) { | ||
if (INVALID_STYLE_CONTENT.test(contents)) { | ||
throw new Error('CSS contains unsafe characters and cannot be serialized inside a style element'); | ||
} | ||
} | ||
/* | ||
* Copyright (c) 2024, salesforce.com, inc. | ||
@@ -15,2 +63,9 @@ * All rights reserved. | ||
*/ | ||
// At runtime, we don't have access to the DOM, so we don't want TypeScript to allow accessing DOM | ||
// globals. However, we're mimicking DOM functionality here, so we *do* want access to DOM types. | ||
// To access the real DOM types when writing new code, uncomment the line below and comment out the | ||
// stub types. Switch them back when you're done to validate that you're not accidentally using | ||
// DOM globals. IMPORTANT: The comment below is a "triple slash directive", it must start with /// | ||
// and be located before import statements. | ||
// /// <reference lib="dom" /> | ||
const MULTI_SPACE = /\s+/g; | ||
@@ -66,2 +121,20 @@ class ClassList { | ||
} | ||
get value() { | ||
return this.el.className; | ||
} | ||
toString() { | ||
return this.el.className; | ||
} | ||
item(_index) { | ||
throw new Error('Method "item" not implemented.'); | ||
} | ||
supports(_token) { | ||
throw new Error('Method "supports" not implemented.'); | ||
} | ||
forEach(_callbackfn, _thisArg) { | ||
throw new Error('Method "forEach" not implemented.'); | ||
} | ||
get length() { | ||
throw new Error('Property "length" not implemented.'); | ||
} | ||
} | ||
@@ -109,5 +182,86 @@ class LightningElement { | ||
getAttribute(attrName) { | ||
const value = this.__attrs?.[attrName]; | ||
return value === true ? '' : (value ?? null); | ||
return this.__attrs[attrName] ?? null; | ||
} | ||
setAttribute(attrName, value) { | ||
this.__attrs[attrName] = String(value); | ||
} | ||
hasAttribute(attrName) { | ||
return Boolean(this.__attrs && attrName in this.__attrs); | ||
} | ||
removeAttribute(attrName) { | ||
this.__attrs[attrName] = null; | ||
} | ||
addEventListener(_type, _listener, _options) { | ||
// noop | ||
} | ||
removeEventListener(_type, _listener, _options) { | ||
// noop | ||
} | ||
// ----------------------------------------------------------- // | ||
// Props/methods explicitly not available in this environment // | ||
// Getters are named "get*" for parity with @lwc/engine-server // | ||
// ----------------------------------------------------------- // | ||
get children() { | ||
throw new TypeError('"getChildren" is not supported in this environment'); | ||
} | ||
get childNodes() { | ||
throw new TypeError('"getChildNodes" is not supported in this environment'); | ||
} | ||
get firstChild() { | ||
throw new TypeError('"getFirstChild" is not supported in this environment'); | ||
} | ||
get firstElementChild() { | ||
throw new TypeError('"getFirstElementChild" is not supported in this environment'); | ||
} | ||
get hostElement() { | ||
// Intentionally different to match @lwc/engine-*core* | ||
throw new TypeError('this.hostElement is not supported in this environment'); | ||
} | ||
get lastChild() { | ||
throw new TypeError('"getLastChild" is not supported in this environment'); | ||
} | ||
get lastElementChild() { | ||
throw new TypeError('"getLastElementChild" is not supported in this environment'); | ||
} | ||
get ownerDocument() { | ||
// Intentionally not "get*" to match @lwc/engine-server | ||
throw new TypeError('"ownerDocument" is not supported in this environment'); | ||
} | ||
get style() { | ||
// Intentionally not "get*" to match @lwc/engine-server | ||
throw new TypeError('"style" is not supported in this environment'); | ||
} | ||
attachInternals() { | ||
throw new TypeError('"attachInternals" is not supported in this environment'); | ||
} | ||
dispatchEvent(_event) { | ||
throw new TypeError('"dispatchEvent" is not supported in this environment'); | ||
} | ||
getBoundingClientRect() { | ||
throw new TypeError('"getBoundingClientRect" is not supported in this environment'); | ||
} | ||
getElementsByClassName(_classNames) { | ||
throw new TypeError('"getElementsByClassName" is not supported in this environment'); | ||
} | ||
getElementsByTagName(_qualifiedName) { | ||
throw new TypeError('"getElementsByTagName" is not supported in this environment'); | ||
} | ||
querySelector(_selectors) { | ||
throw new TypeError('"querySelector" is not supported in this environment'); | ||
} | ||
querySelectorAll(_selectors) { | ||
throw new TypeError('"querySelectorAll" is not supported in this environment'); | ||
} | ||
getAttributeNS(_namespace, _localName) { | ||
throw new Error('Method "getAttributeNS" not implemented.'); | ||
} | ||
hasAttributeNS(_namespace, _localName) { | ||
throw new Error('Method "hasAttributeNS" not implemented.'); | ||
} | ||
removeAttributeNS(_namespace, _localName) { | ||
throw new Error('Method "removeAttributeNS" not implemented.'); | ||
} | ||
setAttributeNS(_namespace, _qualifiedName, _value) { | ||
throw new Error('Method "setAttributeNS" not implemented.'); | ||
} | ||
} | ||
@@ -120,10 +274,8 @@ const escapeAttrVal = (attrVal) => attrVal.replaceAll('&', '&').replaceAll('"', '"'); | ||
for (const [key, val] of Object.entries(attrs)) { | ||
if (val) { | ||
if (typeof val === 'string') { | ||
yield ` ${key}="${escapeAttrVal(val)}"`; | ||
} | ||
else { | ||
yield ` ${key}`; | ||
} | ||
if (typeof val === 'string') { | ||
yield val === '' ? ` ${key}` : ` ${key}="${escapeAttrVal(val)}"`; | ||
} | ||
else if (val === null) { | ||
return ''; | ||
} | ||
} | ||
@@ -148,3 +300,4 @@ } | ||
exports.serverSideRenderComponent = serverSideRenderComponent; | ||
/** version: 8.1.2 */ | ||
exports.validateStyleTextContents = validateStyleTextContents; | ||
/** version: 8.1.3 */ | ||
//# sourceMappingURL=index.cjs.js.map |
@@ -1,4 +0,10 @@ | ||
type Attributes = Record<string, string | true>; | ||
export { validateStyleTextContents } from './validate-style-text-contents'; | ||
type DOMTokenList = object; | ||
type EventListenerOrEventListenerObject = unknown; | ||
type AddEventListenerOptions = unknown; | ||
type EventListenerOptions = unknown; | ||
type ShadowRoot = unknown; | ||
type Attributes = Record<string, string | null>; | ||
type LightningElementConstructor = typeof LightningElement; | ||
declare class ClassList { | ||
declare class ClassList implements DOMTokenList { | ||
el: LightningElement; | ||
@@ -11,18 +17,63 @@ constructor(el: LightningElement); | ||
toggle(classNameToToggle: string, force?: boolean): boolean; | ||
get value(): string; | ||
toString(): string; | ||
[index: number]: never; | ||
item(_index: number): string | null; | ||
supports(_token: string): boolean; | ||
forEach(_callbackfn: (value: string, key: number, parent: DOMTokenList) => void, _thisArg?: any): void; | ||
get length(): number; | ||
} | ||
export declare class LightningElement { | ||
interface PropsAvailableAtConstruction { | ||
tagName: string; | ||
} | ||
export declare class LightningElement implements PropsAvailableAtConstruction { | ||
static renderMode?: 'light' | 'shadow'; | ||
isConnected: boolean; | ||
className: string; | ||
__attrs?: Attributes; | ||
__classList: ClassList | null; | ||
constructor(propsAvailableAtConstruction: Record<string, any>); | ||
__internal__setState(props: Record<string, any>, reflectedProps: string[], attrs: Record<string, any>): void; | ||
private __attrs; | ||
private __classList; | ||
tagName: string; | ||
constructor(propsAvailableAtConstruction: PropsAvailableAtConstruction & Record<string, unknown>); | ||
private __internal__setState; | ||
get classList(): ClassList; | ||
getAttribute(attrName: string): string | null; | ||
setAttribute(attrName: string, value: string | null): void; | ||
hasAttribute(attrName: string): boolean; | ||
removeAttribute(attrName: string): void; | ||
addEventListener(_type: string, _listener: EventListenerOrEventListenerObject, _options?: boolean | AddEventListenerOptions): void; | ||
removeEventListener(_type: string, _listener: EventListenerOrEventListenerObject, _options?: boolean | EventListenerOptions): void; | ||
get children(): never; | ||
get childNodes(): never; | ||
get firstChild(): never; | ||
get firstElementChild(): never; | ||
get hostElement(): never; | ||
get lastChild(): never; | ||
get lastElementChild(): never; | ||
get ownerDocument(): never; | ||
get style(): never; | ||
attachInternals(): never; | ||
dispatchEvent(_event: Event): never; | ||
getBoundingClientRect(): never; | ||
getElementsByClassName(_classNames: string): never; | ||
getElementsByTagName(_qualifiedName: unknown): never; | ||
querySelector(_selectors: string): never; | ||
querySelectorAll(_selectors: string): never; | ||
accessKey?: string; | ||
dir?: string; | ||
draggable?: boolean; | ||
hidden?: boolean; | ||
id?: string; | ||
lang?: string; | ||
shadowRoot?: ShadowRoot | null; | ||
spellcheck?: boolean; | ||
tabIndex?: number; | ||
title?: string; | ||
getAttributeNS(_namespace: string | null, _localName: string): string | null; | ||
hasAttributeNS(_namespace: string | null, _localName: string): boolean; | ||
removeAttributeNS(_namespace: string | null, _localName: string): void; | ||
setAttributeNS(_namespace: string | null, _qualifiedName: string, _value: string): void; | ||
} | ||
export declare function renderAttrs(attrs: Attributes): Generator<string, void, unknown>; | ||
export declare function renderAttrs(attrs: Attributes): Generator<string, "" | undefined, unknown>; | ||
export declare function fallbackTmpl(_props: unknown, _attrs: unknown, _slotted: unknown, Cmp: LightningElementConstructor, _instance: unknown): Generator<string, void, unknown>; | ||
export type GenerateMarkupFn = (tagName: string, props: Record<string, any> | null, attrs: Attributes | null, slotted: Record<number | string, AsyncGenerator<string>> | null) => AsyncGenerator<string>; | ||
export declare function serverSideRenderComponent(tagName: string, compiledGenerateMarkup: GenerateMarkupFn, props: Record<string, any>): Promise<string>; | ||
export {}; |
@@ -5,2 +5,50 @@ /** | ||
/* | ||
* Copyright (c) 2024, Salesforce, Inc. | ||
* All rights reserved. | ||
* SPDX-License-Identifier: MIT | ||
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT | ||
*/ | ||
/** | ||
* Per the HTML spec on restrictions for "raw text elements" like `<style>`: | ||
* | ||
* > The text in raw text and escapable raw text elements must not contain any occurrences of the string | ||
* > "</" (U+003C LESS-THAN SIGN, U+002F SOLIDUS) followed by characters that case-insensitively match the tag name of | ||
* > the element followed by one of: | ||
* > - U+0009 CHARACTER TABULATION (tab) | ||
* > - U+000A LINE FEED (LF) | ||
* > - U+000C FORM FEED (FF) | ||
* > - U+000D CARRIAGE RETURN (CR) | ||
* > - U+0020 SPACE | ||
* > - U+003E GREATER-THAN SIGN (>), or | ||
* > - U+002F SOLIDUS (/) | ||
* @see https://html.spec.whatwg.org/multipage/syntax.html#cdata-rcdata-restrictions | ||
*/ | ||
const INVALID_STYLE_CONTENT = /<\/style[\t\n\f\r >/]/i; | ||
/** | ||
* The text content inside `<style>` is a special case. It is _only_ rendered by the LWC engine itself; `<style>` tags | ||
* are disallowed inside of HTML templates. | ||
* | ||
* The `<style>` tag is unusual in how it's defined in HTML. Like `<script>`, it is considered a "raw text element," | ||
* which means that it is parsed as raw text, but certain character sequences are disallowed, namely to avoid XSS | ||
* attacks like `</style><script>alert("pwned")</script>`. | ||
* | ||
* This also means that we cannot use "normal" HTML escaping inside `<style>` tags, e.g. we cannot use `<`, | ||
* `>`, etc., because these are treated as-is by the HTML parser. | ||
* | ||
* | ||
* @param contents CSS source to validate | ||
* @throws Throws if the contents provided are not valid. | ||
* @see https://html.spec.whatwg.org/multipage/syntax.html#raw-text-elements | ||
* @see https://github.com/salesforce/lwc/issues/3439 | ||
* @example | ||
* validateStyleTextContents('div { color: red }') // Ok | ||
* validateStyleTextContents('</style><script>alert("pwned")</script>') // Throws | ||
*/ | ||
function validateStyleTextContents(contents) { | ||
if (INVALID_STYLE_CONTENT.test(contents)) { | ||
throw new Error('CSS contains unsafe characters and cannot be serialized inside a style element'); | ||
} | ||
} | ||
/* | ||
* Copyright (c) 2024, salesforce.com, inc. | ||
@@ -11,2 +59,9 @@ * All rights reserved. | ||
*/ | ||
// At runtime, we don't have access to the DOM, so we don't want TypeScript to allow accessing DOM | ||
// globals. However, we're mimicking DOM functionality here, so we *do* want access to DOM types. | ||
// To access the real DOM types when writing new code, uncomment the line below and comment out the | ||
// stub types. Switch them back when you're done to validate that you're not accidentally using | ||
// DOM globals. IMPORTANT: The comment below is a "triple slash directive", it must start with /// | ||
// and be located before import statements. | ||
// /// <reference lib="dom" /> | ||
const MULTI_SPACE = /\s+/g; | ||
@@ -62,2 +117,20 @@ class ClassList { | ||
} | ||
get value() { | ||
return this.el.className; | ||
} | ||
toString() { | ||
return this.el.className; | ||
} | ||
item(_index) { | ||
throw new Error('Method "item" not implemented.'); | ||
} | ||
supports(_token) { | ||
throw new Error('Method "supports" not implemented.'); | ||
} | ||
forEach(_callbackfn, _thisArg) { | ||
throw new Error('Method "forEach" not implemented.'); | ||
} | ||
get length() { | ||
throw new Error('Property "length" not implemented.'); | ||
} | ||
} | ||
@@ -105,5 +178,86 @@ class LightningElement { | ||
getAttribute(attrName) { | ||
const value = this.__attrs?.[attrName]; | ||
return value === true ? '' : (value ?? null); | ||
return this.__attrs[attrName] ?? null; | ||
} | ||
setAttribute(attrName, value) { | ||
this.__attrs[attrName] = String(value); | ||
} | ||
hasAttribute(attrName) { | ||
return Boolean(this.__attrs && attrName in this.__attrs); | ||
} | ||
removeAttribute(attrName) { | ||
this.__attrs[attrName] = null; | ||
} | ||
addEventListener(_type, _listener, _options) { | ||
// noop | ||
} | ||
removeEventListener(_type, _listener, _options) { | ||
// noop | ||
} | ||
// ----------------------------------------------------------- // | ||
// Props/methods explicitly not available in this environment // | ||
// Getters are named "get*" for parity with @lwc/engine-server // | ||
// ----------------------------------------------------------- // | ||
get children() { | ||
throw new TypeError('"getChildren" is not supported in this environment'); | ||
} | ||
get childNodes() { | ||
throw new TypeError('"getChildNodes" is not supported in this environment'); | ||
} | ||
get firstChild() { | ||
throw new TypeError('"getFirstChild" is not supported in this environment'); | ||
} | ||
get firstElementChild() { | ||
throw new TypeError('"getFirstElementChild" is not supported in this environment'); | ||
} | ||
get hostElement() { | ||
// Intentionally different to match @lwc/engine-*core* | ||
throw new TypeError('this.hostElement is not supported in this environment'); | ||
} | ||
get lastChild() { | ||
throw new TypeError('"getLastChild" is not supported in this environment'); | ||
} | ||
get lastElementChild() { | ||
throw new TypeError('"getLastElementChild" is not supported in this environment'); | ||
} | ||
get ownerDocument() { | ||
// Intentionally not "get*" to match @lwc/engine-server | ||
throw new TypeError('"ownerDocument" is not supported in this environment'); | ||
} | ||
get style() { | ||
// Intentionally not "get*" to match @lwc/engine-server | ||
throw new TypeError('"style" is not supported in this environment'); | ||
} | ||
attachInternals() { | ||
throw new TypeError('"attachInternals" is not supported in this environment'); | ||
} | ||
dispatchEvent(_event) { | ||
throw new TypeError('"dispatchEvent" is not supported in this environment'); | ||
} | ||
getBoundingClientRect() { | ||
throw new TypeError('"getBoundingClientRect" is not supported in this environment'); | ||
} | ||
getElementsByClassName(_classNames) { | ||
throw new TypeError('"getElementsByClassName" is not supported in this environment'); | ||
} | ||
getElementsByTagName(_qualifiedName) { | ||
throw new TypeError('"getElementsByTagName" is not supported in this environment'); | ||
} | ||
querySelector(_selectors) { | ||
throw new TypeError('"querySelector" is not supported in this environment'); | ||
} | ||
querySelectorAll(_selectors) { | ||
throw new TypeError('"querySelectorAll" is not supported in this environment'); | ||
} | ||
getAttributeNS(_namespace, _localName) { | ||
throw new Error('Method "getAttributeNS" not implemented.'); | ||
} | ||
hasAttributeNS(_namespace, _localName) { | ||
throw new Error('Method "hasAttributeNS" not implemented.'); | ||
} | ||
removeAttributeNS(_namespace, _localName) { | ||
throw new Error('Method "removeAttributeNS" not implemented.'); | ||
} | ||
setAttributeNS(_namespace, _qualifiedName, _value) { | ||
throw new Error('Method "setAttributeNS" not implemented.'); | ||
} | ||
} | ||
@@ -116,10 +270,8 @@ const escapeAttrVal = (attrVal) => attrVal.replaceAll('&', '&').replaceAll('"', '"'); | ||
for (const [key, val] of Object.entries(attrs)) { | ||
if (val) { | ||
if (typeof val === 'string') { | ||
yield ` ${key}="${escapeAttrVal(val)}"`; | ||
} | ||
else { | ||
yield ` ${key}`; | ||
} | ||
if (typeof val === 'string') { | ||
yield val === '' ? ` ${key}` : ` ${key}="${escapeAttrVal(val)}"`; | ||
} | ||
else if (val === null) { | ||
return ''; | ||
} | ||
} | ||
@@ -140,4 +292,4 @@ } | ||
export { LightningElement, fallbackTmpl, renderAttrs, serverSideRenderComponent }; | ||
/** version: 8.1.2 */ | ||
export { LightningElement, fallbackTmpl, renderAttrs, serverSideRenderComponent, validateStyleTextContents }; | ||
/** version: 8.1.3 */ | ||
//# sourceMappingURL=index.js.map |
@@ -7,3 +7,3 @@ { | ||
"name": "@lwc/ssr-runtime", | ||
"version": "8.1.2", | ||
"version": "8.1.3", | ||
"description": "Runtime complement to @lwc/ssr-compiler", | ||
@@ -10,0 +10,0 @@ "keywords": [ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
No README
QualityPackage does not have a README. This may indicate a failed publish or a low quality package.
Found 1 instance in 1 package
50658
9
679
0
4