Skip to content

Commit

Permalink
feat: Add minimal Object.assign ponyfill
Browse files Browse the repository at this point in the history
since we can not rely on it being present in all supported runtimes.
Even though the interface is the same as `Object.assign`,
it behaves slightly differently from the one provided by browsers.

This was extracted from xmldom#338 to support development in xmldom#367
  • Loading branch information
karfau committed Feb 15, 2022
1 parent 9c2f64b commit a740532
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 0 deletions.
26 changes: 26 additions & 0 deletions lib/conventions.js
Expand Up @@ -22,6 +22,31 @@ function freeze(object, oc) {
return oc && typeof oc.freeze === 'function' ? oc.freeze(object) : object
}

/**
* Since we can not rely on `Object.assign` we provide a simplified version
* that is sufficient for our needs.
*
* @param {Object} target
* @param {Object | null | undefined} source
*
* @returns {Object} target
* @throws TypeError if target is not an object
*
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
* @see https://tc39.es/ecma262/multipage/fundamental-objects.html#sec-object.assign
*/
function assign(target, source) {
if (target === null || typeof target !== 'object') {
throw new TypeError('target is not an object')
}
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key]
}
}
return target
}

/**
* All mime types that are allowed as input to `DOMParser.parseFromString`
*
Expand Down Expand Up @@ -139,6 +164,7 @@ var NAMESPACE = freeze({
XMLNS: 'http://www.w3.org/2000/xmlns/',
})

exports.assign = assign;
exports.freeze = freeze;
exports.MIME_TYPE = MIME_TYPE;
exports.NAMESPACE = NAMESPACE;
52 changes: 52 additions & 0 deletions test/conventions/assign.test.js
@@ -0,0 +1,52 @@
'use strict'
const { assign } = require('../../lib/conventions')

describe('assign', () => {
test.each([null, undefined, true, false, 0, NaN])(
'should throw when `target` is `%s`',
(target) => {
expect(() => assign(target, {})).toThrow(TypeError)
}
)
test('should return target', () => {
const target = {}
expect(assign(target, undefined)).toBe(target)
})
test('should copy all enumerable fields from source to target', () => {
const target = {}
const source = { a: 'A', 0: 0 }

assign(target, source)

expect(target).toEqual(source)
})
test('should not copy prototype properties to source', () => {
const target = {}
function Clazz(yes) {
this.yes = yes
}
Clazz.prototype.dont = 5
Clazz.prototype.hasOwnProperty = () => true
const source = new Clazz(1)

assign(target, source)

expect(target).toEqual({ yes: 1 })
})
test('should have no issue with null source', () => {
const target = {}
assign(target, null)
})
test('should have no issue with undefined source', () => {
const target = {}
assign(target, undefined)
})
test('should override existing keys', () => {
const target = { key: 4, same: 'same' }
const source = { key: undefined }

assign(target, source)

expect(target).toEqual({ key: undefined, same: 'same' })
})
})

0 comments on commit a740532

Please sign in to comment.