Skip to content

Commit

Permalink
fix(): Actually allow for custom properties that look like objects (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
asturur authored Aug 6, 2024
1 parent 4e661ef commit c363039
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 1 deletion.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## [next]

- feat(): Add has method to classRegistry to allow to check if a class exists. (fixes #10001)

## [6.1.0]

- fix(): Avoid errors on restoring custom properties that pass the lazy detection of shadow,gradient,pattern and clipPath. [#10001](https://github.com/fabricjs/fabric.js/issues/10001)
Expand Down
39 changes: 39 additions & 0 deletions src/ClassRegistry.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { ClassRegistry } from './ClassRegistry';

describe('ClassRegistry', () => {
let classRegistry: ClassRegistry;
beforeEach(() => {
classRegistry = new ClassRegistry();
});
it('will error if a class is request that is not registered', () => {
expect(() => classRegistry.getClass('any')).toThrow(
'No class registered for any'
);
});
it('will return a class previously registered', () => {
classRegistry.setClass(Set, 'any');
expect(classRegistry.getClass('any')).toBe(Set);
});
it('will check if a class was previously registered', () => {
expect(classRegistry.has('any')).toBe(false);
classRegistry.setClass(Set, 'any');
expect(classRegistry.has('any')).toBe(true);
});
it('not specified will register the class using the type static prop', () => {
class Set2 extends Set {
static type = 'SETABC';
}
classRegistry.setClass(Set2);
expect(classRegistry.has('SETABC')).toBe(true);
expect(classRegistry.getClass('SETABC')).toBe(Set2);
expect(classRegistry.getClass('setabc')).toBe(Set2);
});
it('has a method for SVG parsing classes', () => {
class Set2 extends Set {
static type = 'SETABC';
}
classRegistry.setSVGClass(Set2);
expect(classRegistry.getSVGClass('SETABC')).toBe(undefined);
expect(classRegistry.getSVGClass('setabc')).toBe(Set2);
});
});
4 changes: 4 additions & 0 deletions src/ClassRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ export class ClassRegistry {
this[SVG] = new Map();
}

has(classType: string): boolean {
return this[JSON].has(classType);
}

getClass<T>(classType: string): T {
const constructor = this[JSON].get(classType);
if (!constructor) {
Expand Down
68 changes: 68 additions & 0 deletions src/util/misc/objectEnlive.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { enlivenObjects } from './objectEnlive';
import { Rect, type RectProps } from '../../shapes/Rect';
import { Shadow } from '../../Shadow';
import { classRegistry } from '../../ClassRegistry';

const mockedRectWithCustomProperty = {
type: 'rect',
width: 100,
// will become a shadow
shadow: {
type: 'shadow',
blur: 5,
},
// will become a rect
custom1: {
type: 'rect',
width: 50,
},
custom2: {
type: 'nothing',
value: 3,
},
// will become a set
custom3: {
type: 'registered',
},
};

describe('enlivenObjects', () => {
it('will enlive correctly', async () => {
const [rect] = await enlivenObjects<Rect<RectProps>>([
mockedRectWithCustomProperty,
]);
expect(rect).toBeInstanceOf(Rect);
expect(rect.shadow).toBeInstanceOf(Shadow);
expect(rect.custom1).toBeInstanceOf(Rect);
expect(rect.custom2).toEqual({
type: 'nothing',
value: 3,
});
expect(rect.custom3).toEqual({
type: 'registered',
});
});
it('will enlive correctly newly registered props', async () => {
class Test {
declare opts: any;
constructor(opts: any) {
this.opts = opts;
}
static async fromObject(opts: any) {
return new this(opts);
}
}
classRegistry.setClass(Test, 'registered');
const [rect] = await enlivenObjects<Rect<RectProps>>([
mockedRectWithCustomProperty,
]);
expect(rect).toBeInstanceOf(Rect);
expect(rect.shadow).toBeInstanceOf(Shadow);
expect(rect.custom1).toBeInstanceOf(Rect);
expect(rect.custom2).toEqual({
type: 'nothing',
value: 3,
});
expect(rect.custom3).toBeInstanceOf(Test);
});
});
2 changes: 1 addition & 1 deletion src/util/misc/objectEnlive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ export const enlivenObjectEnlivables = <
* If we have a type and there is a classe registered for it, we enlive it.
* If there is no class registered for it we return the value as is
* */
if (value.type && classRegistry.getClass(value.type)) {
if (value.type && classRegistry.has(value.type)) {
return enlivenObjects<FabricObject | Shadow | TFiller>([value], {
signal,
}).then(([enlived]) => {
Expand Down

0 comments on commit c363039

Please sign in to comment.