From 14ed1577fbe88644abbb5552835cd2fff2c8ec92 Mon Sep 17 00:00:00 2001 From: SukkaW Date: Wed, 11 Oct 2023 11:25:52 +0800 Subject: [PATCH] chore: migrate single file codegen --- create.ts | 396 +++--------------- packages/data/single-file/package.json | 13 + .../src/array-buffer-byte-length.ts | 11 + .../src/asynciterator.prototype.ts | 7 + .../single-file/src/available-typed-arrays.ts | 6 + packages/data/single-file/src/deep-equal.ts | 5 + .../data/single-file/src/define-properties.ts | 1 + .../single-file/src/es-set-tostringtag.ts | 16 + .../single-file/src/get-symbol-description.ts | 2 + packages/data/single-file/src/gopd.ts | 1 + .../data/single-file/src/harmony-reflect.ts | 1 + .../src/has-property-descriptors.ts | 3 + packages/data/single-file/src/has-proto.ts | 2 + .../data/single-file/src/internal-slot.ts | 38 ++ packages/data/single-file/src/is-arguments.ts | 17 + .../data/single-file/src/is-array-buffer.ts | 16 + .../data/single-file/src/is-date-object.ts | 11 + .../single-file/src/is-generator-function.ts | 10 + packages/data/single-file/src/is-regex.ts | 6 + .../single-file/src/is-shared-array-buffer.ts | 16 + packages/data/single-file/src/is-string.ts | 10 + packages/data/single-file/src/is-symbol.ts | 12 + packages/data/single-file/src/is-weakref.ts | 10 + .../single-file/src/iterator.prototype.ts | 1 + .../data/single-file/src/safe-array-concat.ts | 18 + .../data/single-file/src/safe-regex-test.ts | 12 + packages/data/single-file/src/side-channel.ts | 39 ++ .../single-file/src/typed-array-buffer.ts | 3 + .../src/typed-array-byte-length.ts | 12 + .../src/typed-array-byte-offset.ts | 12 + .../single-file/src/typed-array-length.ts | 12 + .../data/single-file/src/unbox-primitive.ts | 25 ++ .../single-file/src/which-boxed-primitive.ts | 27 ++ .../data/single-file/src/which-typed-array.ts | 47 +++ pnpm-lock.yaml | 9 + 35 files changed, 483 insertions(+), 344 deletions(-) create mode 100644 packages/data/single-file/package.json create mode 100644 packages/data/single-file/src/array-buffer-byte-length.ts create mode 100644 packages/data/single-file/src/asynciterator.prototype.ts create mode 100644 packages/data/single-file/src/available-typed-arrays.ts create mode 100644 packages/data/single-file/src/deep-equal.ts create mode 100644 packages/data/single-file/src/define-properties.ts create mode 100644 packages/data/single-file/src/es-set-tostringtag.ts create mode 100644 packages/data/single-file/src/get-symbol-description.ts create mode 100644 packages/data/single-file/src/gopd.ts create mode 100644 packages/data/single-file/src/harmony-reflect.ts create mode 100644 packages/data/single-file/src/has-property-descriptors.ts create mode 100644 packages/data/single-file/src/has-proto.ts create mode 100644 packages/data/single-file/src/internal-slot.ts create mode 100644 packages/data/single-file/src/is-arguments.ts create mode 100644 packages/data/single-file/src/is-array-buffer.ts create mode 100644 packages/data/single-file/src/is-date-object.ts create mode 100644 packages/data/single-file/src/is-generator-function.ts create mode 100644 packages/data/single-file/src/is-regex.ts create mode 100644 packages/data/single-file/src/is-shared-array-buffer.ts create mode 100644 packages/data/single-file/src/is-string.ts create mode 100644 packages/data/single-file/src/is-symbol.ts create mode 100644 packages/data/single-file/src/is-weakref.ts create mode 100644 packages/data/single-file/src/iterator.prototype.ts create mode 100644 packages/data/single-file/src/safe-array-concat.ts create mode 100644 packages/data/single-file/src/safe-regex-test.ts create mode 100644 packages/data/single-file/src/side-channel.ts create mode 100644 packages/data/single-file/src/typed-array-buffer.ts create mode 100644 packages/data/single-file/src/typed-array-byte-length.ts create mode 100644 packages/data/single-file/src/typed-array-byte-offset.ts create mode 100644 packages/data/single-file/src/typed-array-length.ts create mode 100644 packages/data/single-file/src/unbox-primitive.ts create mode 100644 packages/data/single-file/src/which-boxed-primitive.ts create mode 100644 packages/data/single-file/src/which-typed-array.ts diff --git a/create.ts b/create.ts index 849a1c57..ddb2d656 100644 --- a/create.ts +++ b/create.ts @@ -79,347 +79,39 @@ const autoGeneratedPackagesList = [ ] as const; const singleFilePackagesList = [ - ['has-property-descriptors', `const hasPropertyDescriptors = () => true; -hasPropertyDescriptors.hasArrayLengthDefineBug = () => false; -module.exports = hasPropertyDescriptors;`], - ['gopd', 'module.exports = Object.getOwnPropertyDescriptor;'], - ['has-proto', 'module.exports = () => true;'], - ['get-symbol-description', `const { uncurryThis } = require('@nolyfill/shared'); -module.exports = uncurryThis(Object.getOwnPropertyDescriptor(Symbol.prototype, 'description').get);`, { '@nolyfill/shared': 'workspace:*' }], - ['is-array-buffer', `const { uncurryThis } = require('@nolyfill/shared'); -const bL = uncurryThis(Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, 'byteLength').get); -module.exports = (obj) => { - if (!obj || typeof obj !== 'object') { - return false; - } - try { - bL(obj); - return true; - } catch (_) { - return false; - } -};`, { '@nolyfill/shared': 'workspace:*' }], - ['is-shared-array-buffer', `const { uncurryThis } = require('@nolyfill/shared'); -const bL = uncurryThis(Object.getOwnPropertyDescriptor(SharedArrayBuffer.prototype, 'byteLength').get); -module.exports = (obj) => { - if (!obj || typeof obj !== 'object') { - return false; - } - try { - bL(obj); - return true; - } catch (_) { - return false; - } -};`, { '@nolyfill/shared': 'workspace:*' }], - ['typed-array-buffer', `const { uncurryThis } = require('@nolyfill/shared'); -module.exports = uncurryThis(Object.getOwnPropertyDescriptor(Object.getPrototypeOf(Int8Array.prototype), 'buffer').get);`, { '@nolyfill/shared': 'workspace:*' }], - ['typed-array-byte-length', `const { TypedArrayPrototype, uncurryThis } = require('@nolyfill/shared'); -const typedArrayByteLength = uncurryThis(Object.getOwnPropertyDescriptor(TypedArrayPrototype, 'byteLength').get); -module.exports = (value) => { - try { - return typedArrayByteLength(value); - } catch (e) { - return false; - } -};`, { '@nolyfill/shared': 'workspace:*' }], - ['typed-array-byte-offset', `const { TypedArrayPrototype, uncurryThis } = require('@nolyfill/shared'); -const typedArrayByteOffSet = uncurryThis(Object.getOwnPropertyDescriptor(TypedArrayPrototype, 'byteOffset').get); -module.exports = (value) => { - try { - return typedArrayByteOffSet(value); - } catch (e) { - return false; - } -};`, { '@nolyfill/shared': 'workspace:*' }], - ['typed-array-length', `const { TypedArrayPrototype, uncurryThis } = require('@nolyfill/shared'); -const typedArrayLength = uncurryThis(Object.getOwnPropertyDescriptor(TypedArrayPrototype, 'length').get); -module.exports = (value) => { - try { - return typedArrayLength(value); - } catch (e) { - return false; - } -};`, { '@nolyfill/shared': 'workspace:*' }], - ['harmony-reflect', 'module.exports = Reflect;'], - ['array-buffer-byte-length', `const { uncurryThis } = require('@nolyfill/shared'); -const isArrayBuffer = require('@nolyfill/is-array-buffer'); -const bL = uncurryThis(Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, 'byteLength').get); -module.exports = (ab) => { - if (!isArrayBuffer(ab)) return NaN; - return bL(ab); -};`, { '@nolyfill/is-array-buffer': 'workspace:*', '@nolyfill/shared': 'workspace:*' }], - ['iterator.prototype', 'module.exports = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]()));'], - ['available-typed-arrays', `module.exports = [ - 'BigInt64Array', 'BigUint64Array', - 'Float32Array', 'Float64Array', - 'Int16Array', 'Int32Array', 'Int8Array', - 'Uint16Array', 'Uint32Array', 'Uint8Array', 'Uint8ClampedArray' -];`], - ['which-typed-array', `const { uncurryThis } = require('@nolyfill/shared'); - -const cacheEntries = Object.entries([ - 'BigInt64Array', 'BigUint64Array', - 'Float32Array', 'Float64Array', - 'Int16Array', 'Int32Array', 'Int8Array', - 'Uint16Array', 'Uint32Array', 'Uint8Array', 'Uint8ClampedArray' -].reduce((acc, typedArray) => { - const proto = Object.getPrototypeOf(new globalThis[typedArray]()); - acc[\`$\${typedArray}\`] = uncurryThis(( - Object.getOwnPropertyDescriptor(proto, Symbol.toStringTag) - || Object.getOwnPropertyDescriptor(Object.getPrototypeOf(proto), Symbol.toStringTag) - ).get); - return acc; -}, Object.create(null))); - -const tryTypedArrays = (value) => { - let found = false; - cacheEntries.forEach(([typedArray, getter]) => { - if (!found) { - try { - if (\`$\${getter(value)}\` === typedArray) { - found = typedArray.slice(1); - } - } catch (e) { /**/ } - } - }); - return found; -}; - -module.exports = (value) => { - if (!value || typeof value !== 'object') { return false; } - return tryTypedArrays(value); -};`, { '@nolyfill/shared': 'workspace:*' }], - ['which-boxed-primitive', `module.exports = (value) => { - if (value == null || (typeof value !== 'object' && typeof value !== 'function')) return null; - if (typeof value === 'string') return 'String'; - if (typeof value === 'number') return 'Number'; - if (typeof value === 'boolean') return 'Boolean'; - if (typeof value === 'symbol') return 'Symbol'; - if (typeof value === 'bigint') return 'BigInt'; - if (typeof value === 'object') { - if (Object.prototype.toString.call(value) === '[object String]') return 'String'; - if (Object.prototype.toString.call(value) === '[object Number]') return 'Number'; - if (Object.prototype.toString.call(value) === '[object Boolean]') return 'Number'; - if ( - Object.prototype.toString.call(value) === '[object Symbol]' - && typeof value.valueOf() === 'symbol' - && Symbol.prototype.toString.call(value).startsWith('Symbol(') - ) return 'Symbol'; - try { - BigInt.prototype.valueOf.call(value); - return 'BigInt'; - } catch (_) {} - } -};`], - ['unbox-primitive', `module.exports = function unboxPrimitive(value) { - if (value == null || (typeof value !== 'object' && typeof value !== 'function')) { - throw new TypeError(value === null ? 'value is an unboxed primitive' : 'value is a non-boxed-primitive object'); - } - if (typeof value === 'string' || Object.prototype.toString.call(value) === '[object String]') { - return String.prototype.toString.call(value); - } - if (typeof value === 'number' || Object.prototype.toString.call(value) === '[object Number]') { - return Number.prototype.valueOf.call(value); - } - if (typeof value === 'boolean' || Object.prototype.toString.call(value) === '[object Boolean]') { - return Boolean.prototype.valueOf.call(value); - } - if (typeof value === 'symbol' || ( - Object.prototype.toString.call(value) === '[object Symbol]' - && typeof value.valueOf() === 'symbol' - && Symbol.prototype.toString.call(value).startsWith('Symbol(') - )) { - return Symbol.prototype.valueOf.call(value); - } - try { - return BigInt.prototype.valueOf.call(value); - } catch (_) {} - throw new RangeError('unknown boxed primitive'); -};`], - ['is-regex', `module.exports = (value) => { - if (!value || (typeof value !== 'object' && typeof value !== 'function')) return false; - return Object.prototype.toString.call(value) === '[object RegExp]'; -};`], - ['safe-regex-test', `module.exports = (r) => { - if ( - !r - || (typeof r !== 'object' && typeof r !== 'function') - || Object.prototype.toString.call(r) !== '[object RegExp]' - ) { - throw new TypeError('\`regex\` must be a RegExp'); - } - return (s) => RegExp.prototype.exec.call(r, s) !== null; -};`], - ['safe-array-concat', `const empty = []; -empty[Symbol.isConcatSpreadable] = true; -module.exports = (...args) => { - for (let i = 0, l = args.length; i < l; i += 1) { - const arg = args[i]; - if (arg && typeof arg === 'object' && typeof arg[Symbol.isConcatSpreadable] === 'boolean') { - const arr = Array.isArray(arg) ? Array.prototype.slice.call(arg) : [arg]; - arr[Symbol.isConcatSpreadable] = true; - args[i] = arr; - } - } - return Array.prototype.concat.apply(empty, args); -};`], - ['asynciterator.prototype', `/* globals AsyncIterator */ -const asyncIterProto = typeof AsyncIterator === 'function' ? AsyncIterator.prototype : {}; -if (!(Symbol.iterator in asyncIterProto)) { - asyncIterProto[Symbol.iterator] = function () { return this; }; -} -module.exports = asyncIterProto;`], - ['is-weakref', `/* globals WeakRef: false */ -module.exports = (value) => { - if (typeof WeakRef === 'undefined') return false; - if (!value || typeof value !== 'object') return false; - try { - WeakRef.prototype.deref.call(value); - return true; - } catch (e) { - return false; - } -};`], - ['is-symbol', `module.exports = (value) => { - if (typeof value === 'symbol') return true; - if (Object.prototype.toString.call(value) !== '[object Symbol]') return false; - try { - if (typeof value.valueOf() !== 'symbol') return false; - return Symbol.prototype.toString.call(value).startsWith('Symbol('); - } catch (e) { - return false; - } -};`], - ['is-string', `module.exports = (value) => { - if (typeof value === 'string') return true; - if (typeof value !== 'object') return false; - try { - String.prototype.valueOf.call(value); - return true; - } catch (e) { return false; } -};`], - ['is-date-object', `module.exports = (value) => { - if (typeof value !== 'object' || value === null) return false; - try { - Date.prototype.getDay.call(value); - return true; - } catch (e) { - return false; - } -};`], - ['es-set-tostringtag', `module.exports = (object, value, options = {}) => { - if (options.force || !Object.prototype.hasOwnProperty.call(object, Symbol.toStringTag)) { - Object.defineProperty(object, Symbol.toStringTag, { - configurable: true, - enumerable: false, - value, - writable: false - }); - } -};`], - ['define-properties', 'module.exports = require(\'@nolyfill/shared\').defineProperties', { '@nolyfill/shared': 'workspace:*' }], - ['deep-equal', 'module.exports = (foo, bar) => require(\'dequal\').dequal(foo, bar)', { dequal: '2.0.3' }], - ['is-arguments', `const isStandardArguments = (value) => ((value && typeof value === 'object' && Symbol.toStringTag in value) - ? false - : Object.prototype.toString.call(value) === '[object Arguments]'); -const isLegacyArguments = (value) => (isStandardArguments(value) - ? true - : ( - value !== null - && typeof value === 'object' - && typeof value.length === 'number' - && value.length >= 0 - && Object.prototype.toString.call(value) !== '[object Array]' - && Object.prototype.toString.call(value.callee) === '[object Function]') -); -// isStandardArguments.isLegacyArguments = isLegacyArguments; // for tests -// eslint-disable-next-line prefer-rest-params -- detect arguments object -module.exports = (function () { return isStandardArguments(arguments); }()) ? isStandardArguments : isLegacyArguments`], - ['is-generator-function', `const isFnRegex = /^\\s*(?:function)?\\*/; -// Node.js has full native support for generators since Node.js 6.4.0, so we don't need eval -const GeneratorFunction = Object.getPrototypeOf(function* () {}); -module.exports = function isGeneratorFunction(fn) { - if (typeof fn !== 'function') return false; - if (isFnRegex.test(Function.prototype.toString.call(fn))) return true; - return Object.getPrototypeOf(fn) === GeneratorFunction; -};`], + ['has-property-descriptors'], + ['gopd'], + ['has-proto'], + ['get-symbol-description', { '@nolyfill/shared': 'workspace:*' }], + ['is-array-buffer', { '@nolyfill/shared': 'workspace:*' }], + ['is-shared-array-buffer', { '@nolyfill/shared': 'workspace:*' }], + ['typed-array-buffer', { '@nolyfill/shared': 'workspace:*' }], + ['typed-array-byte-length', { '@nolyfill/shared': 'workspace:*' }], + ['typed-array-byte-offset', { '@nolyfill/shared': 'workspace:*' }], + ['typed-array-length', { '@nolyfill/shared': 'workspace:*' }], + ['harmony-reflect'], + ['array-buffer-byte-length', { '@nolyfill/is-array-buffer': 'workspace:*', '@nolyfill/shared': 'workspace:*' }], + ['iterator.prototype'], + ['available-typed-arrays'], + ['which-typed-array', { '@nolyfill/shared': 'workspace:*' }], + ['which-boxed-primitive'], + ['unbox-primitive'], + ['is-regex'], + ['safe-regex-test'], + ['safe-array-concat'], + ['asynciterator.prototype'], + ['is-weakref'], + ['is-symbol'], + ['is-string'], + ['is-date-object'], + ['es-set-tostringtag'], + ['define-properties', { '@nolyfill/shared': 'workspace:*' }], + ['deep-equal', { dequal: '2.0.3' }], + ['is-arguments'], + ['is-generator-function'], // ['is-negative-zero', 'module.exports = (n) => n === 0 && (1 / n) === -Infinity;'], - ['side-channel', `module.exports = () => { - let $wm, $m; - - const get = (key) => { - if (key && (typeof key === 'object' || typeof key === 'function')) { - if ($wm) return $wm.get(key); - } else if ($m) { - return $m.get(key); - } - return undefined; - }; - const set = (key, value) => { - if (key && (typeof key === 'object' || typeof key === 'function')) { - if (!$wm) $wm = new WeakMap(); - $wm.set(key, value); - } else { - if (!$m) $m = new Map(); - $m.set(key, value); - } - }; - const has = (key) => { - if (key && (typeof key === 'object' || typeof key === 'function')) { - if ($wm) { - return $wm.has(key); - } - } else if ($m) { - return $m.has(key); - } - return false; - }; - const assert = (key) => { - if (!has(key)) { - throw new TypeError('Side channel does not contain the given key'); - } - }; - return { get, set, has, assert }; -};`], - ['internal-slot', `const channel = new WeakMap(); -const check = (O, slot) => { - if (!O || (typeof O !== 'object' && typeof O !== 'function')) { - throw new TypeError('\`O\` is not an object'); - } - if (typeof slot !== 'string') { - throw new TypeError('\`slot\` must be a string'); - } -}; -const has = (O, slot) => { - check(O, slot); - const slots = channel.get(O); - return !!slots && Object.prototype.hasOwnProperty.call(slots, \`$\${slot}\`); -}; -const get = (O, slot) => { - check(O, slot); - const slots = channel.get(O); - return slots && slots[\`$\${slot}\`]; -}; -const set = (O, slot, V) => { - check(O, slot); - let slots = channel.get(O); - if (!slots) { - slots = {}; - channel.set(O, slots); - } - slots[\`$\${slot}\`] = V; -}; -const assert = (O, slot) => { - check(O, slot); - if (!channel.has(O)) { - throw new TypeError('Side channel does not contain the given key'); - } - if (!has(O, slot)) { - throw new TypeError(\`\\\`\${slot}\\\` is not present on \\\`O\\\`\`); - } -}; -module.exports = Object.freeze({ has, get, set, assert });`] + ['side-channel'], + ['internal-slot'] ] as const; const manualPackagesList = [ @@ -467,7 +159,7 @@ export const allPackages = ${JSON.stringify(allPackagesList, null, 2)};\n`; await Promise.all([ ...autoGeneratedPackagesList.map(pkg => createEsShimLikePackage(pkg[0], pkg[1], pkg[2])), - ...singleFilePackagesList.map(pkg => createSingleFilePackage(pkg[0], pkg[1], pkg[2])), + ...singleFilePackagesList.map(pkg => createSingleFilePackage(pkg[0], pkg[1])), compareAndWriteFile( path.join(__dirname, 'package.json'), `${JSON.stringify(newPackageJson, null, 2)}\n` @@ -511,7 +203,7 @@ async function createEsShimLikePackage( const pkg: VirtualPackage = { path: path.join(__dirname, 'packages/generated', packageName), files: { - 'entry.js': code + 'Object.assign(exports.default, exports);\nmodule.exports = exports.default;', + 'entry.js': code + 'Object.assign(exports.default, exports);\nmodule.exports = exports.default;\n', 'implementation.js': `'use strict';\nmodule.exports = require('./entry.js').implementation;\n`, 'polyfill.js': `'use strict';\nmodule.exports = require('./entry.js').polyfill;\n`, 'shim.js': `'use strict';\nmodule.exports = require('./entry.js').shim;\n`, @@ -545,16 +237,32 @@ async function createEsShimLikePackage( async function createSingleFilePackage( packageName: string, - implementation: string, extraDependencies: Record = {}, minimumNodeVersion = '>=12.4.0' ) { const currentPackageJson = await currentPackageJsonPromise; + const entryContent = await fsPromises.readFile( + path.join(__dirname, 'packages', 'data', 'single-file', 'src', `${packageName}.ts`), + { encoding: 'utf-8' } + ); + const { code } = await transform( + entryContent, + { + isModule: true, + jsc: { + parser: { + syntax: 'typescript' + } + }, + module: { type: 'commonjs' } + } + ); + const pkg: VirtualPackage = { path: path.join(__dirname, 'packages/generated', packageName), files: { - 'index.js': `'use strict';\n${implementation}\n` + 'index.js': code + 'Object.assign(exports.default, exports);\nmodule.exports = exports.default;\n', }, packageJson: { name: `@nolyfill/${packageName}`, diff --git a/packages/data/single-file/package.json b/packages/data/single-file/package.json new file mode 100644 index 00000000..78e211eb --- /dev/null +++ b/packages/data/single-file/package.json @@ -0,0 +1,13 @@ +{ + "name": "nolyfill-single-file", + "version": "0.0.0", + "private": true, + "license": "MIT", + "scripts": { + "lint": "eslint ." + }, + "dependencies": { + "@nolyfill/shared": "workspace:*", + "@nolyfill/is-array-buffer": "workspace:*" + } +} diff --git a/packages/data/single-file/src/array-buffer-byte-length.ts b/packages/data/single-file/src/array-buffer-byte-length.ts new file mode 100644 index 00000000..cdebeb87 --- /dev/null +++ b/packages/data/single-file/src/array-buffer-byte-length.ts @@ -0,0 +1,11 @@ +import { uncurryThis } from '@nolyfill/shared'; +// @ts-expect-error -- no types +import isArrayBuffer from '@nolyfill/is-array-buffer'; + +const bL = uncurryThis(Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, 'byteLength')!.get!); +const is = (ab: unknown) => { + if (!isArrayBuffer(ab)) return NaN; + return bL(ab); +}; + +export default is; diff --git a/packages/data/single-file/src/asynciterator.prototype.ts b/packages/data/single-file/src/asynciterator.prototype.ts new file mode 100644 index 00000000..e6fddccd --- /dev/null +++ b/packages/data/single-file/src/asynciterator.prototype.ts @@ -0,0 +1,7 @@ +// @ts-expect-error -- AsyncIterator is not a real global value, just a mock +const asyncIterProto = typeof AsyncIterator === 'function' ? AsyncIterator.prototype : {}; +if (!(Symbol.iterator in asyncIterProto)) { + asyncIterProto[Symbol.iterator] = function () { return this; }; +} + +export default asyncIterProto; diff --git a/packages/data/single-file/src/available-typed-arrays.ts b/packages/data/single-file/src/available-typed-arrays.ts new file mode 100644 index 00000000..faa34cb6 --- /dev/null +++ b/packages/data/single-file/src/available-typed-arrays.ts @@ -0,0 +1,6 @@ +export default [ + 'BigInt64Array', 'BigUint64Array', + 'Float32Array', 'Float64Array', + 'Int16Array', 'Int32Array', 'Int8Array', + 'Uint16Array', 'Uint32Array', 'Uint8Array', 'Uint8ClampedArray' +]; diff --git a/packages/data/single-file/src/deep-equal.ts b/packages/data/single-file/src/deep-equal.ts new file mode 100644 index 00000000..96388bb6 --- /dev/null +++ b/packages/data/single-file/src/deep-equal.ts @@ -0,0 +1,5 @@ +import { dequal } from "dequal" + +const deepEqual = (a: any, b: any) => dequal(a, b); +export default deepEqual; + diff --git a/packages/data/single-file/src/define-properties.ts b/packages/data/single-file/src/define-properties.ts new file mode 100644 index 00000000..ec5b1546 --- /dev/null +++ b/packages/data/single-file/src/define-properties.ts @@ -0,0 +1 @@ +export { defineProperties as default } from '@nolyfill/shared'; diff --git a/packages/data/single-file/src/es-set-tostringtag.ts b/packages/data/single-file/src/es-set-tostringtag.ts new file mode 100644 index 00000000..788611f0 --- /dev/null +++ b/packages/data/single-file/src/es-set-tostringtag.ts @@ -0,0 +1,16 @@ +interface SetToStringTagOption { + force?: boolean +} + +const set = (object: any, value: any, options: SetToStringTagOption = {}) => { + if (options.force || !Object.prototype.hasOwnProperty.call(object, Symbol.toStringTag)) { + Object.defineProperty(object, Symbol.toStringTag, { + configurable: true, + enumerable: false, + value, + writable: false + }); + } +}; + +export default set; diff --git a/packages/data/single-file/src/get-symbol-description.ts b/packages/data/single-file/src/get-symbol-description.ts new file mode 100644 index 00000000..85bd9b7e --- /dev/null +++ b/packages/data/single-file/src/get-symbol-description.ts @@ -0,0 +1,2 @@ +import { uncurryThis } from '@nolyfill/shared'; +export default uncurryThis(Object.getOwnPropertyDescriptor(Symbol.prototype, 'description')!.get!); diff --git a/packages/data/single-file/src/gopd.ts b/packages/data/single-file/src/gopd.ts new file mode 100644 index 00000000..365eccfe --- /dev/null +++ b/packages/data/single-file/src/gopd.ts @@ -0,0 +1 @@ +export default Object.getOwnPropertyDescriptors; diff --git a/packages/data/single-file/src/harmony-reflect.ts b/packages/data/single-file/src/harmony-reflect.ts new file mode 100644 index 00000000..5ce7643d --- /dev/null +++ b/packages/data/single-file/src/harmony-reflect.ts @@ -0,0 +1 @@ +export default Reflect; diff --git a/packages/data/single-file/src/has-property-descriptors.ts b/packages/data/single-file/src/has-property-descriptors.ts new file mode 100644 index 00000000..9c1e5b43 --- /dev/null +++ b/packages/data/single-file/src/has-property-descriptors.ts @@ -0,0 +1,3 @@ +const hasPropertyDescriptors = () => true; +hasPropertyDescriptors.hasArrayLengthDefineBug = () => false; +export default hasPropertyDescriptors; diff --git a/packages/data/single-file/src/has-proto.ts b/packages/data/single-file/src/has-proto.ts new file mode 100644 index 00000000..7d021ae0 --- /dev/null +++ b/packages/data/single-file/src/has-proto.ts @@ -0,0 +1,2 @@ +const hasProto = () => true; +export default hasProto; diff --git a/packages/data/single-file/src/internal-slot.ts b/packages/data/single-file/src/internal-slot.ts new file mode 100644 index 00000000..61806dea --- /dev/null +++ b/packages/data/single-file/src/internal-slot.ts @@ -0,0 +1,38 @@ +const channel = new WeakMap(); +const check = (O: WeakKey, slot: string) => { + if (!O || (typeof O !== 'object' && typeof O !== 'function')) { + throw new TypeError('`O` is not an object'); + } + if (typeof slot !== 'string') { + throw new TypeError('`slot` must be a string'); + } +}; +const has = (O: WeakKey, slot: string) => { + check(O, slot); + const slots = channel.get(O); + return !!slots && Object.prototype.hasOwnProperty.call(slots, `$${slot}`); +}; +const get = (O: WeakKey, slot: string) => { + check(O, slot); + const slots = channel.get(O); + return slots && slots[`$${slot}`]; +}; +const set = (O: WeakKey, slot: string, V: any) => { + check(O, slot); + let slots = channel.get(O); + if (!slots) { + slots = {}; + channel.set(O, slots); + } + slots[`$${slot}`] = V; +}; +const assert = (O: WeakKey, slot: string) => { + check(O, slot); + if (!channel.has(O)) { + throw new TypeError('Side channel does not contain the given key'); + } + if (!has(O, slot)) { + throw new TypeError(`"${slot}" is not present on "O"`); + } +}; +module.exports = Object.freeze({ has, get, set, assert }); diff --git a/packages/data/single-file/src/is-arguments.ts b/packages/data/single-file/src/is-arguments.ts new file mode 100644 index 00000000..650a785d --- /dev/null +++ b/packages/data/single-file/src/is-arguments.ts @@ -0,0 +1,17 @@ +const isStandardArguments = (value: any) => ((value && typeof value === 'object' && Symbol.toStringTag in value) + ? false + : Object.prototype.toString.call(value) === '[object Arguments]'); + +const isLegacyArguments = (value: any) => (isStandardArguments(value) + ? true + : ( + value !== null + && typeof value === 'object' + && typeof value.length === 'number' + && value.length >= 0 + && Object.prototype.toString.call(value) !== '[object Array]' + && Object.prototype.toString.call(value.callee) === '[object Function]') +); +// isStandardArguments.isLegacyArguments = isLegacyArguments; // for tests +// eslint-disable-next-line prefer-rest-params -- detect arguments object +module.exports = (function () { return isStandardArguments(arguments); }()) ? isStandardArguments : isLegacyArguments diff --git a/packages/data/single-file/src/is-array-buffer.ts b/packages/data/single-file/src/is-array-buffer.ts new file mode 100644 index 00000000..cd5dfb90 --- /dev/null +++ b/packages/data/single-file/src/is-array-buffer.ts @@ -0,0 +1,16 @@ +import { uncurryThis } from '@nolyfill/shared'; + +const bL = uncurryThis(Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, 'byteLength')!.get!); +const is = (obj: unknown): obj is ArrayBuffer => { + if (!obj || typeof obj !== 'object') { + return false; + } + try { + bL(obj); + return true; + } catch (_) { + return false; + } +}; + +export default is; diff --git a/packages/data/single-file/src/is-date-object.ts b/packages/data/single-file/src/is-date-object.ts new file mode 100644 index 00000000..a72f9c51 --- /dev/null +++ b/packages/data/single-file/src/is-date-object.ts @@ -0,0 +1,11 @@ +const is = (value: unknown): value is Date => { + if (typeof value !== 'object' || value === null) return false; + try { + Date.prototype.getDay.call(value); + return true; + } catch (e) { + return false; + } +}; + +export default is; diff --git a/packages/data/single-file/src/is-generator-function.ts b/packages/data/single-file/src/is-generator-function.ts new file mode 100644 index 00000000..80ffeb00 --- /dev/null +++ b/packages/data/single-file/src/is-generator-function.ts @@ -0,0 +1,10 @@ +const isFnRegex = /^\s*(?:function)?\*/; +// Node.js has full native support for generators since Node.js 6.4.0, so we don't need eval +const GeneratorFunction = Object.getPrototypeOf(function* () {}); +function isGeneratorFunction(fn: unknown): fn is Function { + if (typeof fn !== 'function') return false; + if (isFnRegex.test(Function.prototype.toString.call(fn))) return true; + return Object.getPrototypeOf(fn) === GeneratorFunction; +}; + +export default isGeneratorFunction; diff --git a/packages/data/single-file/src/is-regex.ts b/packages/data/single-file/src/is-regex.ts new file mode 100644 index 00000000..e196f8f9 --- /dev/null +++ b/packages/data/single-file/src/is-regex.ts @@ -0,0 +1,6 @@ +const is = (value: unknown): value is RegExp => { + if (!value || (typeof value !== 'object' && typeof value !== 'function')) return false; + return Object.prototype.toString.call(value) === '[object RegExp]'; +}; + +export default is; diff --git a/packages/data/single-file/src/is-shared-array-buffer.ts b/packages/data/single-file/src/is-shared-array-buffer.ts new file mode 100644 index 00000000..567430dd --- /dev/null +++ b/packages/data/single-file/src/is-shared-array-buffer.ts @@ -0,0 +1,16 @@ +import { uncurryThis } from '@nolyfill/shared'; + +const bL = uncurryThis(Object.getOwnPropertyDescriptor(SharedArrayBuffer.prototype, 'byteLength')!.get!); +const is = (obj: unknown): obj is SharedArrayBuffer => { + if (!obj || typeof obj !== 'object') { + return false; + } + try { + bL(obj); + return true; + } catch (_) { + return false; + } +}; + +export default is; diff --git a/packages/data/single-file/src/is-string.ts b/packages/data/single-file/src/is-string.ts new file mode 100644 index 00000000..f5167326 --- /dev/null +++ b/packages/data/single-file/src/is-string.ts @@ -0,0 +1,10 @@ +const is = (value: any): value is string => { + if (typeof value === 'string') return true; + if (typeof value !== 'object') return false; + try { + String.prototype.valueOf.call(value); + return true; + } catch (e) { return false; } +}; + +export default is; diff --git a/packages/data/single-file/src/is-symbol.ts b/packages/data/single-file/src/is-symbol.ts new file mode 100644 index 00000000..561128a5 --- /dev/null +++ b/packages/data/single-file/src/is-symbol.ts @@ -0,0 +1,12 @@ +const is = (value: unknown): value is symbol => { + if (typeof value === 'symbol') return true; + if (Object.prototype.toString.call(value) !== '[object Symbol]') return false; + try { + if (typeof (value as any).valueOf() !== 'symbol') return false; + return Symbol.prototype.toString.call(value).startsWith('Symbol('); + } catch (e) { + return false; + } +}; + +export default is; diff --git a/packages/data/single-file/src/is-weakref.ts b/packages/data/single-file/src/is-weakref.ts new file mode 100644 index 00000000..2491ceee --- /dev/null +++ b/packages/data/single-file/src/is-weakref.ts @@ -0,0 +1,10 @@ +const is = (value: unknown) => { + if (typeof WeakRef === 'undefined') return false; + if (!value || typeof value !== 'object') return false; + try { + WeakRef.prototype.deref.call(value); + return true; + } catch (e) { + return false; + } +} diff --git a/packages/data/single-file/src/iterator.prototype.ts b/packages/data/single-file/src/iterator.prototype.ts new file mode 100644 index 00000000..f25fe37f --- /dev/null +++ b/packages/data/single-file/src/iterator.prototype.ts @@ -0,0 +1 @@ +export default Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]())); diff --git a/packages/data/single-file/src/safe-array-concat.ts b/packages/data/single-file/src/safe-array-concat.ts new file mode 100644 index 00000000..887ff81c --- /dev/null +++ b/packages/data/single-file/src/safe-array-concat.ts @@ -0,0 +1,18 @@ +const empty: any[] = []; +// @ts-expect-error -- JS is awesome +empty[Symbol.isConcatSpreadable] = true; + +const concat = (...args: any[]) => { + for (let i = 0, l = args.length; i < l; i += 1) { + const arg = args[i]; + if (arg && typeof arg === 'object' && typeof arg[Symbol.isConcatSpreadable] === 'boolean') { + const arr = Array.isArray(arg) ? Array.prototype.slice.call(arg) : [arg]; + // @ts-expect-error -- JS is awesome + arr[Symbol.isConcatSpreadable] = true; + args[i] = arr; + } + } + return Array.prototype.concat.apply(empty, args); +}; + +export default concat; diff --git a/packages/data/single-file/src/safe-regex-test.ts b/packages/data/single-file/src/safe-regex-test.ts new file mode 100644 index 00000000..49418ebc --- /dev/null +++ b/packages/data/single-file/src/safe-regex-test.ts @@ -0,0 +1,12 @@ +const safeRegexTest = (r: RegExp) => { + if ( + !r + || (typeof r !== 'object' && typeof r !== 'function') + || Object.prototype.toString.call(r) !== '[object RegExp]' + ) { + throw new TypeError('\`regex\` must be a RegExp'); + } + return (s: string) => RegExp.prototype.exec.call(r, s) !== null; +}; + +export default safeRegexTest; diff --git a/packages/data/single-file/src/side-channel.ts b/packages/data/single-file/src/side-channel.ts new file mode 100644 index 00000000..ae81a423 --- /dev/null +++ b/packages/data/single-file/src/side-channel.ts @@ -0,0 +1,39 @@ +const create = () => { + let $wm: WeakMap, $m: Map; + + const get = (key: any) => { + if (key && (typeof key === 'object' || typeof key === 'function')) { + if ($wm) return $wm.get(key); + } else if ($m) { + return $m.get(key); + } + return undefined; + }; + const set = (key: any, value: any) => { + if (key && (typeof key === 'object' || typeof key === 'function')) { + if (!$wm) $wm = new WeakMap(); + $wm.set(key, value); + } else { + if (!$m) $m = new Map(); + $m.set(key, value); + } + }; + const has = (key: any) => { + if (key && (typeof key === 'object' || typeof key === 'function')) { + if ($wm) { + return $wm.has(key); + } + } else if ($m) { + return $m.has(key); + } + return false; + }; + const assert = (key: any) => { + if (!has(key)) { + throw new TypeError('Side channel does not contain the given key'); + } + }; + return { get, set, has, assert }; +}; + +export default create; diff --git a/packages/data/single-file/src/typed-array-buffer.ts b/packages/data/single-file/src/typed-array-buffer.ts new file mode 100644 index 00000000..692d3b65 --- /dev/null +++ b/packages/data/single-file/src/typed-array-buffer.ts @@ -0,0 +1,3 @@ +import { uncurryThis } from '@nolyfill/shared'; + +export default uncurryThis(Object.getOwnPropertyDescriptor(Object.getPrototypeOf(Int8Array.prototype), 'buffer')!.get!); diff --git a/packages/data/single-file/src/typed-array-byte-length.ts b/packages/data/single-file/src/typed-array-byte-length.ts new file mode 100644 index 00000000..e4a25b2a --- /dev/null +++ b/packages/data/single-file/src/typed-array-byte-length.ts @@ -0,0 +1,12 @@ +import { uncurryThis, TypedArrayPrototype } from '@nolyfill/shared'; + +const typedArrayByteLength = uncurryThis(Object.getOwnPropertyDescriptor(TypedArrayPrototype, 'byteLength')!.get!); +const g = (value: unknown) => { + try { + return typedArrayByteLength(value); + } catch (e) { + return false; + } +}; + +export default g; diff --git a/packages/data/single-file/src/typed-array-byte-offset.ts b/packages/data/single-file/src/typed-array-byte-offset.ts new file mode 100644 index 00000000..0f2b2b33 --- /dev/null +++ b/packages/data/single-file/src/typed-array-byte-offset.ts @@ -0,0 +1,12 @@ +import { uncurryThis, TypedArrayPrototype } from '@nolyfill/shared'; + +const typedArrayByteOffSet = uncurryThis(Object.getOwnPropertyDescriptor(TypedArrayPrototype, 'byteOffset')!.get!); +const g = (value: unknown) => { + try { + return typedArrayByteOffSet(value); + } catch (e) { + return false; + } +}; + +export default g; diff --git a/packages/data/single-file/src/typed-array-length.ts b/packages/data/single-file/src/typed-array-length.ts new file mode 100644 index 00000000..3e9bad89 --- /dev/null +++ b/packages/data/single-file/src/typed-array-length.ts @@ -0,0 +1,12 @@ +import { uncurryThis, TypedArrayPrototype } from '@nolyfill/shared'; + +const typedArrayLength = uncurryThis(Object.getOwnPropertyDescriptor(TypedArrayPrototype, 'length')!.get!); +const g = (value: unknown) => { + try { + return typedArrayLength(value); + } catch (e) { + return false; + } +}; + +export default g; diff --git a/packages/data/single-file/src/unbox-primitive.ts b/packages/data/single-file/src/unbox-primitive.ts new file mode 100644 index 00000000..6ba707bb --- /dev/null +++ b/packages/data/single-file/src/unbox-primitive.ts @@ -0,0 +1,25 @@ +export default function unboxPrimitive(value: unknown) { + if (value == null || (typeof value !== 'object' && typeof value !== 'function')) { + throw new TypeError(value === null ? 'value is an unboxed primitive' : 'value is a non-boxed-primitive object'); + } + if (typeof value === 'string' || Object.prototype.toString.call(value) === '[object String]') { + return String.prototype.toString.call(value); + } + if (typeof value === 'number' || Object.prototype.toString.call(value) === '[object Number]') { + return Number.prototype.valueOf.call(value); + } + if (typeof value === 'boolean' || Object.prototype.toString.call(value) === '[object Boolean]') { + return Boolean.prototype.valueOf.call(value); + } + if (typeof value === 'symbol' || ( + Object.prototype.toString.call(value) === '[object Symbol]' + && typeof value.valueOf() === 'symbol' + && Symbol.prototype.toString.call(value).startsWith('Symbol(') + )) { + return Symbol.prototype.valueOf.call(value); + } + try { + return BigInt.prototype.valueOf.call(value); + } catch (_) {} + throw new RangeError('unknown boxed primitive'); +}; diff --git a/packages/data/single-file/src/which-boxed-primitive.ts b/packages/data/single-file/src/which-boxed-primitive.ts new file mode 100644 index 00000000..f613bc98 --- /dev/null +++ b/packages/data/single-file/src/which-boxed-primitive.ts @@ -0,0 +1,27 @@ +const which = (value: unknown) => { + if (value == null || (typeof value !== 'object' && typeof value !== 'function')) return null; + if (typeof value === 'string') return 'String'; + if (typeof value === 'number') return 'Number'; + if (typeof value === 'boolean') return 'Boolean'; + if (typeof value === 'symbol') return 'Symbol'; + if (typeof value === 'bigint') return 'BigInt'; + if (typeof value === 'object') { + const stringTag = Object.prototype.toString.call(value); + + if (stringTag === '[object String]') return 'String'; + if (stringTag === '[object Number]') return 'Number'; + if (stringTag === '[object Boolean]') return 'Number'; + if ( + stringTag === '[object Symbol]' + && typeof value.valueOf() === 'symbol' + && Symbol.prototype.toString.call(value).startsWith('Symbol(') + ) return 'Symbol'; + try { + BigInt.prototype.valueOf.call(value); + return 'BigInt'; + } catch (_) {} + } + return; +}; + +export default which; diff --git a/packages/data/single-file/src/which-typed-array.ts b/packages/data/single-file/src/which-typed-array.ts new file mode 100644 index 00000000..7f610dff --- /dev/null +++ b/packages/data/single-file/src/which-typed-array.ts @@ -0,0 +1,47 @@ +import { uncurryThis } from '@nolyfill/shared'; + +const availableTypedArray = [ + 'BigInt64Array', 'BigUint64Array', + 'Float32Array', 'Float64Array', + 'Int16Array', 'Int32Array', 'Int8Array', + 'Uint16Array', 'Uint32Array', 'Uint8Array', 'Uint8ClampedArray' +] as const; + +type AvaliableTypedArray = typeof availableTypedArray[number]; + +const cacheEntries = Object.entries( + availableTypedArray.reduce>( + (acc, typedArray) => { + const proto = Object.getPrototypeOf(new globalThis[typedArray]()); + acc[`$${typedArray}`] = uncurryThis( + ( + Object.getOwnPropertyDescriptor(proto, Symbol.toStringTag) + || Object.getOwnPropertyDescriptor(Object.getPrototypeOf(proto), Symbol.toStringTag) + )!.get! + ); + return acc; + }, + Object.create(null) + ) +) as [`$${string}`, any][]; + +const tryTypedArrays = (value: unknown): false | AvaliableTypedArray => { + let found: false | AvaliableTypedArray = false; + cacheEntries.forEach(([typedArray, getter]) => { + if (!found) { + try { + if (`$${getter(value)}` === typedArray) { + found = typedArray.slice(1) as AvaliableTypedArray; + } + } catch (e) { /**/ } + } + }); + return found; +}; + +const t = (value: unknown) => { + if (!value || typeof value !== 'object') { return false; } + return tryTypedArrays(value); +}; + +export default t; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 57f4f537..69f4b192 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -169,6 +169,15 @@ importers: specifier: workspace:* version: link:../../tools/shared + packages/data/single-file: + dependencies: + '@nolyfill/is-array-buffer': + specifier: workspace:* + version: link:../../generated/is-array-buffer + '@nolyfill/shared': + specifier: workspace:* + version: link:../../tools/shared + packages/generated/array-buffer-byte-length: dependencies: '@nolyfill/is-array-buffer':