From ca9657260b37aff1ba4520cc9d694ae932b8ccc8 Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Tue, 25 Mar 2025 22:34:18 +0000 Subject: [PATCH] Migrate Record to a factory class --- __tests__/Record.ts | 4 +- __tests__/RecordJS.js | 4 +- __tests__/utils.js | 2 +- src/Record.js | 117 +++++++++++++++++++++--------------------- src/Repeat.js | 2 +- 5 files changed, 64 insertions(+), 65 deletions(-) diff --git a/__tests__/Record.ts b/__tests__/Record.ts index 415b27f1d4..e186c3262e 100644 --- a/__tests__/Record.ts +++ b/__tests__/Record.ts @@ -7,10 +7,10 @@ describe('Record', () => { const t1 = MyType(); const t2 = t1.set('a', 10); - expect(t1 instanceof Record).toBe(true); + expect(Record.isRecord(t1)).toBe(true); expect(t1 instanceof MyType).toBe(true); - expect(t2 instanceof Record).toBe(true); + expect(Record.isRecord(t2)).toBe(true); expect(t2 instanceof MyType).toBe(true); expect(t1.get('a')).toBe(1); diff --git a/__tests__/RecordJS.js b/__tests__/RecordJS.js index 2453e51e78..519bae1878 100644 --- a/__tests__/RecordJS.js +++ b/__tests__/RecordJS.js @@ -41,8 +41,8 @@ describe('Record', () => { const t = new Alphabet(); const t2 = t.set('b', 200); - expect(t instanceof Record); - expect(t instanceof Alphabet); + expect(Record.isRecord(t)).toBe(true); + expect(t instanceof Alphabet).toBe(true); expect(t.soup()).toBe(6); expect(t2.soup()).toBe(204); diff --git a/__tests__/utils.js b/__tests__/utils.js index 1d1c6b0e44..604d9be5b8 100644 --- a/__tests__/utils.js +++ b/__tests__/utils.js @@ -23,7 +23,7 @@ describe('Utils', () => { ['Number primitive ', 5], ['String primitive ', 'P'], ['Number Object', Number(6)], - ['Immutable.List', new List()], + ['Immutable.List', List()], ['simple array', ['one']], ['Error', Error], ['Internal namespaces', Math], diff --git a/src/Record.js b/src/Record.js index b210145265..8c43b45bbc 100644 --- a/src/Record.js +++ b/src/Record.js @@ -43,73 +43,72 @@ function throwOnInvalidDefaultValues(defaultValues) { } } -export class Record { - constructor(defaultValues, name) { - let hasInitialized; +export const Record = (defaultValues, name) => { + let hasInitialized; - throwOnInvalidDefaultValues(defaultValues); + throwOnInvalidDefaultValues(defaultValues); - const RecordType = function Record(values) { - if (values instanceof RecordType) { - return values; - } - if (!(this instanceof RecordType)) { - return new RecordType(values); - } - if (!hasInitialized) { - hasInitialized = true; - const keys = Object.keys(defaultValues); - const indices = (RecordTypePrototype._indices = {}); - // Deprecated: left to attempt not to break any external code which - // relies on a ._name property existing on record instances. - // Use Record.getDescriptiveName() instead - RecordTypePrototype._name = name; - RecordTypePrototype._keys = keys; - RecordTypePrototype._defaultValues = defaultValues; - for (let i = 0; i < keys.length; i++) { - const propName = keys[i]; - indices[propName] = i; - if (RecordTypePrototype[propName]) { - /* eslint-disable no-console */ - // eslint-disable-next-line @typescript-eslint/no-unused-expressions -- TODO enable eslint here - typeof console === 'object' && - console.warn && - console.warn( - 'Cannot define ' + - recordName(this) + - ' with property "' + - propName + - '" since that property name is part of the Record API.' - ); - /* eslint-enable no-console */ - } else { - setProp(RecordTypePrototype, propName); - } + const RecordType = function Record(values) { + if (values instanceof RecordType) { + return values; + } + if (!(this instanceof RecordType)) { + return new RecordType(values); + } + if (!hasInitialized) { + hasInitialized = true; + const keys = Object.keys(defaultValues); + const indices = (RecordTypePrototype._indices = {}); + // Deprecated: left to attempt not to break any external code which + // relies on a ._name property existing on record instances. + // Use Record.getDescriptiveName() instead + RecordTypePrototype._name = name; + RecordTypePrototype._keys = keys; + RecordTypePrototype._defaultValues = defaultValues; + for (let i = 0; i < keys.length; i++) { + const propName = keys[i]; + indices[propName] = i; + if (RecordTypePrototype[propName]) { + /* eslint-disable no-console */ + // eslint-disable-next-line @typescript-eslint/no-unused-expressions -- TODO enable eslint here + typeof console === 'object' && + console.warn && + console.warn( + 'Cannot define ' + + recordName(this) + + ' with property "' + + propName + + '" since that property name is part of the Record API.' + ); + /* eslint-enable no-console */ + } else { + setProp(RecordTypePrototype, propName); } } - this.__ownerID = undefined; - this._values = List().withMutations((l) => { - l.setSize(this._keys.length); - KeyedCollection(values).forEach((v, k) => { - l.set(this._indices[k], v === this._defaultValues[k] ? undefined : v); - }); + } + this.__ownerID = undefined; + this._values = List().withMutations((l) => { + l.setSize(this._keys.length); + KeyedCollection(values).forEach((v, k) => { + l.set(this._indices[k], v === this._defaultValues[k] ? undefined : v); }); - return this; - }; - - const RecordTypePrototype = (RecordType.prototype = - Object.create(RecordPrototype)); - RecordTypePrototype.constructor = RecordType; - RecordTypePrototype.create = RecordType; + }); + return this; + }; - if (name) { - RecordType.displayName = name; - } + const RecordTypePrototype = (RecordType.prototype = + Object.create(RecordPrototype)); + RecordTypePrototype.constructor = RecordType; + RecordTypePrototype.create = RecordType; - // eslint-disable-next-line no-constructor-return - return RecordType; + if (name) { + RecordType.displayName = name; } + return RecordType; +}; + +export class RecordImpl { toString() { let str = recordName(this) + ' { '; const keys = this._keys; @@ -212,7 +211,7 @@ export class Record { Record.isRecord = isRecord; Record.getDescriptiveName = recordName; -const RecordPrototype = Record.prototype; +const RecordPrototype = RecordImpl.prototype; RecordPrototype[IS_RECORD_SYMBOL] = true; RecordPrototype[DELETE] = RecordPrototype.remove; RecordPrototype.deleteIn = RecordPrototype.removeIn = deleteIn; diff --git a/src/Repeat.js b/src/Repeat.js index c428e213d0..ddaacc2ef2 100644 --- a/src/Repeat.js +++ b/src/Repeat.js @@ -47,7 +47,7 @@ export class RepeatImpl extends IndexedSeqImpl { const size = this.size; return wholeSlice(begin, end, size) ? this - : new Repeat( + : new RepeatImpl( this._value, resolveEnd(end, size) - resolveBegin(begin, size) );