Skip to content

Commit

Permalink
feat: [#1079] Adds support for all SVG elements (#1572)
Browse files Browse the repository at this point in the history
  • Loading branch information
capricorn86 authored Nov 1, 2024
1 parent afd256b commit 33a72ca
Show file tree
Hide file tree
Showing 314 changed files with 41,236 additions and 2,286 deletions.
660 changes: 284 additions & 376 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"semver": "^7.3.5",
"turbo": "^1.11.3",
"typescript": "^5.0.4",
"vitest": "^2.0.5"
"vitest": "^2.1.4"
},
"happyLintChanged": {
"rules": [
Expand Down
2 changes: 1 addition & 1 deletion packages/happy-dom/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
"test": "vitest run",
"test:ui": "vitest --ui",
"test:watch": "vitest",
"test:debug": "vitest run --inspect-brk --threads=false"
"test:debug": "vitest run --inspect-brk --no-file-parallelism"
},
"dependencies": {
"entities": "^4.5.0",
Expand Down
112 changes: 49 additions & 63 deletions packages/happy-dom/src/ClassMethodBinder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,79 +2,65 @@
* Node utility.
*/
export default class ClassMethodBinder {
private target: Object;
private classes: any[];
private cache = new Map<string | symbol, Boolean>();

/**
* Binds methods to a target.
* Constructor.
*
* @param target Target.
* @param classes Classes.
* @param [options] Options.
* @param [options.bindSymbols] Bind symbol methods.
* @param [options.forwardToPrototype] Forwards the method calls to the prototype. This makes it possible for test tools to override methods on the prototype (e.g. Object.defineProperty(HTMLCollection.prototype, 'item', {})).
* @param [options.proxy] Bind methods using a proxy.
*/
public static bindMethods(
target: Object,
classes: any[],
options?: { bindSymbols?: boolean; forwardToPrototype?: boolean; proxy?: any }
): void {
for (const _class of classes) {
const propertyDescriptors = Object.getOwnPropertyDescriptors(_class.prototype);
const keys: Array<string | symbol> = Object.keys(propertyDescriptors);
constructor(target: Object, classes: any[]) {
this.target = target;
this.classes = classes;
}

if (options?.bindSymbols) {
for (const symbol of Object.getOwnPropertySymbols(propertyDescriptors)) {
keys.push(symbol);
}
}
/**
* Binds method, getters and setters to a target.
*
* @param name Method name.
*/
public bind(name: string | symbol): void {
if (this.cache.has(name)) {
return;
}

const scope = options?.proxy ? options.proxy : target;
this.cache.set(name, true);

if (options?.forwardToPrototype) {
for (const key of keys) {
const descriptor = propertyDescriptors[<string>key];
if (descriptor.get || descriptor.set) {
Object.defineProperty(target, key, {
...descriptor,
get:
descriptor.get &&
(() => Object.getOwnPropertyDescriptor(_class.prototype, key).get.call(scope)),
set:
descriptor.set &&
((newValue) =>
Object.getOwnPropertyDescriptor(_class.prototype, key).set.call(scope, newValue))
});
} else if (
key !== 'constructor' &&
typeof descriptor.value === 'function' &&
!descriptor.value.toString().startsWith('class ')
) {
Object.defineProperty(target, key, {
...descriptor,
value: (...args) => _class.prototype[key].apply(scope, args)
});
}
}
} else {
for (const key of keys) {
const descriptor = propertyDescriptors[<string>key];
if (descriptor.get || descriptor.set) {
Object.defineProperty(target, key, {
...descriptor,
get: descriptor.get?.bind(scope),
set: descriptor.set?.bind(scope)
});
} else if (
key !== 'constructor' &&
typeof descriptor.value === 'function' &&
!descriptor.value.toString().startsWith('class ')
) {
Object.defineProperty(target, key, {
...descriptor,
value: descriptor.value.bind(scope)
});
}
const target = this.target;

if (!(name in target)) {
return;
}

for (const _class of this.classes) {
const descriptor = Object.getOwnPropertyDescriptor(_class.prototype, name);
if (descriptor) {
if (typeof descriptor.value === 'function') {
Object.defineProperty(target, name, {
...descriptor,
value: descriptor.value.bind(target)
});
} else if (descriptor.get !== undefined) {
Object.defineProperty(target, name, {
...descriptor,
get: descriptor.get?.bind(target),
set: descriptor.set?.bind(target)
});
}
return;
}
}
}

/**
* Prevents a method, getter or setter from being bound.
*
* @param name Method name.
*/
public preventBinding(name: string | symbol): void {
this.cache.set(name, true);
}
}
145 changes: 144 additions & 1 deletion packages/happy-dom/src/PropertySymbol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ export const mode = Symbol('mode');
export const host = Symbol('host');
export const setURL = Symbol('setURL');
export const localName = Symbol('localName');
export const registedClass = Symbol('registedClass');
export const classRegistry = Symbol('classRegistry');
export const nodeStream = Symbol('nodeStream');
export const location = Symbol('location');
export const history = Symbol('history');
Expand Down Expand Up @@ -232,3 +232,146 @@ export const destroyed = Symbol('destroyed');
export const aborted = Symbol('aborted');
export const browserFrames = Symbol('browserFrames');
export const windowInternalId = Symbol('windowInternalId');
export const getItemList = Symbol('getItemList');
export const requiredExtensions = Symbol('requiredExtensions');
export const systemLanguage = Symbol('systemLanguage');
export const transform = Symbol('transform');
export const baseVal = Symbol('baseVal');
export const animVal = Symbol('animVal');
export const pathLength = Symbol('pathLength');
export const unitType = Symbol('unitType');
export const viewBox = Symbol('viewBox');
export const markerUnits = Symbol('markerUnits');
export const markerWidth = Symbol('markerWidth');
export const markerHeight = Symbol('markerHeight');
export const values = Symbol('values');
export const orientType = Symbol('orientType');
export const orientAngle = Symbol('orientAngle');
export const refX = Symbol('refX');
export const refY = Symbol('refY');
export const readOnly = Symbol('readOnly');
export const preserveAspectRatio = Symbol('preserveAspectRatio');
export const animatedPoints = Symbol('animatedPoints');
export const points = Symbol('points');
export const rx = Symbol('rx');
export const ry = Symbol('ry');
export const cx = Symbol('cx');
export const cy = Symbol('cy');
export const r = Symbol('r');
export const clipPathUnits = Symbol('clipPathUnits');
export const maskUnits = Symbol('maskUnits');
export const maskContentUnits = Symbol('maskContentUnits');
export const filterUnits = Symbol('filterUnits');
export const primitiveUnits = Symbol('primitiveUnits');
export const href = Symbol('href');
export const x1 = Symbol('x1');
export const y1 = Symbol('y1');
export const x2 = Symbol('x2');
export const y2 = Symbol('y2');
export const gradientUnits = Symbol('gradientUnits');
export const gradientTransform = Symbol('gradientTransform');
export const spreadMethod = Symbol('spreadMethod');
export const patternUnits = Symbol('patternUnits');
export const patternContentUnits = Symbol('patternContentUnits');
export const patternTransform = Symbol('patternTransform');
export const fx = Symbol('fx');
export const fy = Symbol('fy');
export const offset = Symbol('offset');
export const disabled = Symbol('disabled');
export const textLength = Symbol('textLength');
export const lengthAdjust = Symbol('lengthAdjust');
export const getAttribute = Symbol('getAttribute');
export const setAttribute = Symbol('setAttribute');
export const z = Symbol('z');
export const w = Symbol('w');
export const toArray = Symbol('toArray');
export const fromString = Symbol('fromString');
export const fromArray = Symbol('fromArray');
export const angle = Symbol('angle');
export const m11 = Symbol('m11');
export const m12 = Symbol('m12');
export const m13 = Symbol('m13');
export const m14 = Symbol('m14');
export const m21 = Symbol('m21');
export const m22 = Symbol('m22');
export const m23 = Symbol('m23');
export const m24 = Symbol('m24');
export const m31 = Symbol('m31');
export const m32 = Symbol('m32');
export const m33 = Symbol('m33');
export const m34 = Symbol('m34');
export const m41 = Symbol('m41');
export const m42 = Symbol('m42');
export const m43 = Symbol('m43');
export const m44 = Symbol('m44');
export const setMatrixValue = Symbol('setMatrixValue');
export const translateSelf = Symbol('translateSelf');
export const rotateSelf = Symbol('rotateSelf');
export const rotateAxisAngleSelf = Symbol('rotateAxisAngleSelf');
export const scaleSelf = Symbol('scaleSelf');
export const scale3dSelf = Symbol('scale3dSelf');
export const scaleNonUniformSelf = Symbol('scaleNonUniformSelf');
export const skewXSelf = Symbol('skewXSelf');
export const skewYSelf = Symbol('skewYSelf');
export const multiplySelf = Symbol('multiplySelf');
export const matrix = Symbol('matrix');
export const domMatrix = Symbol('domMatrix');
export const getDOMMatrix = Symbol('getDOMMatrix');
export const setDOMMatrix = Symbol('setDOMMatrix');
export const attributeValue = Symbol('attributeValue');
export const startOffset = Symbol('startOffset');
export const method = Symbol('method');
export const spacing = Symbol('spacing');
export const in1 = Symbol('in1');
export const in2 = Symbol('in2');
export const result = Symbol('result');
export const bias = Symbol('bias');
export const divisor = Symbol('divisor');
export const edgeMode = Symbol('edgeMode');
export const kernelMatrix = Symbol('kernelMatrix');
export const kernelUnitLengthX = Symbol('kernelUnitLengthX');
export const kernelUnitLengthY = Symbol('kernelUnitLengthY');
export const orderX = Symbol('orderX');
export const orderY = Symbol('orderY');
export const preserveAlpha = Symbol('preserveAlpha');
export const targetX = Symbol('targetX');
export const targetY = Symbol('targetY');
export const diffuseConstant = Symbol('diffuseConstant');
export const surfaceScale = Symbol('surfaceScale');
export const scale = Symbol('scale');
export const xChannelSelector = Symbol('xChannelSelector');
export const yChannelSelector = Symbol('yChannelSelector');
export const azimuth = Symbol('azimuth');
export const elevation = Symbol('elevation');
export const dx = Symbol('dx');
export const dy = Symbol('dy');
export const stdDeviationX = Symbol('stdDeviationX');
export const stdDeviationY = Symbol('stdDeviationY');
export const tableValues = Symbol('tableValues');
export const slope = Symbol('slope');
export const intercept = Symbol('intercept');
export const amplitude = Symbol('amplitude');
export const exponent = Symbol('exponent');
export const crossOrigin = Symbol('crossOrigin');
export const operator = Symbol('operator');
export const radiusX = Symbol('radiusX');
export const radiusY = Symbol('radiusY');
export const specularConstant = Symbol('specularConstant');
export const specularExponent = Symbol('specularExponent');
export const pointsAtX = Symbol('pointsAtX');
export const pointsAtY = Symbol('pointsAtY');
export const pointsAtZ = Symbol('pointsAtZ');
export const limitingConeAngle = Symbol('limitingConeAngle');
export const baseFrequencyX = Symbol('baseFrequencyX');
export const baseFrequencyY = Symbol('baseFrequencyY');
export const numOctaves = Symbol('numOctaves');
export const seed = Symbol('seed');
export const stitchTiles = Symbol('stitchTiles');
export const rotateFromVectorSelf = Symbol('rotateFromVectorSelf');
export const flipXSelf = Symbol('flipXSelf');
export const flipYSelf = Symbol('flipYSelf');
export const invertSelf = Symbol('invertSelf');
export const getLength = Symbol('getLength');
export const currentScale = Symbol('currentScale');
export const rotate = Symbol('rotate');
export const bindMethods = Symbol('bindMethods');
57 changes: 57 additions & 0 deletions packages/happy-dom/src/StringUtility.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
const ASCII_LOWER_CASE_CACHE: Map<string, string> = new Map();
const ASCII_UPPER_CASE_CACHE: Map<string, string> = new Map();

/**
* String utility.
*/
export default class StringUtility {
/**
* ASCII lowercase.
*
* @see https://infra.spec.whatwg.org/#ascii-lowercase
* @param text Text.
* @returns Lowercase text.
*/
public static asciiLowerCase(text: string): string {
const cached = ASCII_LOWER_CASE_CACHE.get(text);
if (cached) {
return cached;
}
let newText = '';
for (const char of text) {
const value = char.charCodeAt(0);
if (value >= 65 && value <= 90) {
newText += String.fromCharCode(value + 32);
} else {
newText += char;
}
}
ASCII_LOWER_CASE_CACHE.set(text, newText);
return newText;
}

/**
* ASCII uppercase.
*
* @see https://infra.spec.whatwg.org/#ascii-uppercase
* @param text Text.
* @returns Uppercase text.
*/
public static asciiUpperCase(text: string): string {
const cached = ASCII_UPPER_CASE_CACHE.get(text);
if (cached) {
return cached;
}
let newText = '';
for (const char of text) {
const value = char.charCodeAt(0);
if (value >= 97 && value <= 122) {
newText += String.fromCharCode(value - 32);
} else {
newText += char;
}
}
ASCII_UPPER_CASE_CACHE.set(text, newText);
return newText;
}
}
Loading

0 comments on commit 33a72ca

Please sign in to comment.