diff --git a/create.ts b/create.ts index 1a8746ca..d64a52ca 100644 --- a/create.ts +++ b/create.ts @@ -7,6 +7,8 @@ import { PathScurry } from 'path-scurry'; import colors from 'picocolors'; import { dequal } from 'dequal'; import { fileExists, compareAndWriteFile } from '@nolyfill/internal'; +import { transform } from '@swc/core'; + import type { PackageJson } from 'type-fest'; /** @@ -32,157 +34,122 @@ interface VirtualPackage { } const autoGeneratedPackagesList = [ - ['array-includes', 'Array.prototype.includes', false], - ['array.prototype.findlastindex', `Array.prototype.findLastIndex || function (callback, thisArg) { - for (let i = this.length - 1; i >= 0; i--) { - if (callback.call(thisArg, this[i], i, this)) return i; - } - return -1; -}`, false], - ['array.prototype.findlast', `Array.prototype.findLast || function (callback, thisArg) { - for (let i = this.length - 1; i >= 0; i--) { - const value = this[i]; - if (callback.call(thisArg, value, i, this)) return value; - } - return void undefined; -}`, false], - ['array.prototype.at', `Array.prototype.at || function at(n) { - n = Math.trunc(n) || 0; - if (n < 0) n += this.length; - if (n < 0 || n >= this.length) return undefined; - return this[n]; -}`, false], - ['string.prototype.at', `String.prototype.at || function at(n) { - n = Math.trunc(n) || 0; - if (n < 0) n += this.length; - if (n < 0 || n >= this.length) return undefined; - return String.prototype.charAt.call(this, n); -}`, false], - ['array.prototype.flat', 'Array.prototype.flat', false], - ['array.prototype.flatmap', 'Array.prototype.flatMap', false], - ['arraybuffer.prototype.slice', 'ArrayBuffer.prototype.slice', false], - ['function.prototype.name', 'Function.prototype.name', false], - ['has', 'Object.prototype.hasOwnProperty', false], - ['object-keys', 'Object.keys', true], - ['object.assign', 'Object.assign', true], - ['object.entries', 'Object.entries', true], - ['object.fromentries', 'Object.fromEntries', true], - ['object.hasown', 'Object.hasOwn || require(\'@nolyfill/shared\').uncurryThis(Object.prototype.hasOwnProperty)', true, { '@nolyfill/shared': 'workspace:*' }], - ['object.values', 'Object.values', true], - ['string.prototype.trim', 'String.prototype.trim', false], - ['string.prototype.trimend', 'String.prototype.trimEnd', false], - ['string.prototype.trimstart', 'String.prototype.trimStart', false], - ['string.prototype.trimleft', 'String.prototype.trimLeft', false], - ['string.prototype.trimright', 'String.prototype.trimRight', false], - ['string.prototype.matchall', 'String.prototype.matchAll', false], - ['regexp.prototype.flags', 'RegExp.prototype.flags', false], - // ['globalthis', 'globalThis', true], // globalthis package's entrypoint is a function, not the implementation - ['array.prototype.tosorted', `Array.prototype.toSorted || function (compareFn) { - const o = Object(this); - const l = Number(o.length); - const a = new Array(l); - for (let i = 0; i < l; i++) { - a[i] = o[i]; - } - Array.prototype.sort.call(a, compareFn); - return a; -}`, false], - ['object.groupby', `Object.groupBy || function (items, callbackfn) { - const o = Object.create(null); - let k = 0; - for (const value of items) { - const key = callbackfn(value, k++); - if (key in o) { - Array.prototype.push.call(o[key], value); - } else { - o[key] = [value]; - } - } - return o; -}`, true], - ['array.prototype.find', 'Array.prototype.find', false], - ['array.from', 'Array.from', true], - ['string.prototype.padend', 'String.prototype.padEnd', false], - ['string.prototype.padstart', 'String.prototype.padStart', false], - ['object.getownpropertydescriptors', 'Object.getOwnPropertyDescriptors', true], - ['array.prototype.reduce', 'Array.prototype.reduce', false], - ['object-is', 'Object.is', true], - ['reflect.ownkeys', 'Reflect.ownKeys', true], - // ['array.prototype.filter', 'Array.prototype.filter', false], - ['string.prototype.replaceall', 'String.prototype.replaceAll', false], - // ['array.prototype.map', 'Array.prototype.map', false], - ['reflect.getprototypeof', 'Reflect.getPrototypeOf', true], - // ['object.getprototypeof', 'Object.getPrototypeOf', true] - ['es-aggregate-error', `typeof AggregateError === 'function' - ? AggregateError - : (() => { - function AggregateError(errors, message) { - const error = new Error(message); - Object.setPrototypeOf(error, AggregateError.prototype); - delete error.constructor; - Object.defineProperty(error, 'errors', { value: Array.from(errors) }); - return error; - } - Object.defineProperty(AggregateError, 'prototype', { writable: false }); - Object.defineProperties(AggregateError.prototype, { - constructor: { - enumerable: false, - configurable: true, - writable: true, - value: AggregateError - }, - message: { - enumerable: false, - configurable: true, - writable: true, - value: '' - }, - name: { - enumerable: false, - configurable: true, - writable: true, - value: 'AggregateError' - } - }); - Object.setPrototypeOf(AggregateError.prototype, Error.prototype); - return AggregateError; - })()`, true], - ['promise.any', `Promise.any || function any(iterable) { - const AggregateError = require('@nolyfill/es-aggregate-error/polyfill')(); - const $reject = Promise.reject.bind(this); - const $resolve = Promise.resolve.bind(this); - const $all = Promise.all.bind(this); - - try { - return $all( - Array.from(iterable) - .map((item) => $resolve(item).then(x => $reject(x), x => x)) - ).then( - (errors) => { - throw new AggregateError(errors, 'Every promise rejected'); - }, - x => x - ); - } catch (e) { - return $reject(e); - } -}`, true, { '@nolyfill/es-aggregate-error': 'workspace:*' }, '>=12.4.0', 'Promise'], - ['promise.allsettled', `Promise.allSettled || function allSettled(iterable) { - const $reject = Promise.reject.bind(this); - const $resolve = Promise.resolve.bind(this); - const $all = Promise.all.bind(this); - return $all(Array.from(iterable).map((item) => { - const p = $resolve(item); - try { - return p.then( - (value) => ({ status: 'fulfilled', value }), - (reason) => ({ status: 'rejected', reason }) - ); - } catch (e) { - return $reject(e); - } - })); -}`, true, {}, '>=12.4.0', 'Promise'] + ['array-includes'], + ['array.prototype.findlastindex'], + ['array.prototype.findlast'], + ['array.prototype.at'] + // ['string.prototype.at', `String.prototype.at || function at(n) { + // n = Math.trunc(n) || 0; + // if (n < 0) n += this.length; + // if (n < 0 || n >= this.length) return undefined; + // return String.prototype.charAt.call(this, n); + // }`, false], + // ['array.prototype.flat', 'Array.prototype.flat', false], + // ['array.prototype.flatmap', 'Array.prototype.flatMap', false], + // ['arraybuffer.prototype.slice', 'ArrayBuffer.prototype.slice', false], + // ['function.prototype.name', 'Function.prototype.name', false], + // ['has', 'Object.prototype.hasOwnProperty', false], + // ['object-keys', 'Object.keys', true], + // ['object.assign', 'Object.assign', true], + // ['object.entries', 'Object.entries', true], + // ['object.fromentries', 'Object.fromEntries', true], + // ['object.hasown', 'Object.hasOwn || require(\'@nolyfill/shared\').uncurryThis(Object.prototype.hasOwnProperty)', true, { '@nolyfill/shared': 'workspace:*' }], + // ['object.values', 'Object.values', true], + // ['string.prototype.trim', 'String.prototype.trim', false], + // ['string.prototype.trimend', 'String.prototype.trimEnd', false], + // ['string.prototype.trimstart', 'String.prototype.trimStart', false], + // ['string.prototype.trimleft', 'String.prototype.trimLeft', false], + // ['string.prototype.trimright', 'String.prototype.trimRight', false], + // ['string.prototype.matchall', 'String.prototype.matchAll', false], + // ['regexp.prototype.flags', 'RegExp.prototype.flags', false], + // // ['globalthis', 'globalThis', true], // globalthis package's entrypoint is a function, not the implementation + // ['array.prototype.tosorted', `Array.prototype.toSorted || function (compareFn) { + // const o = Object(this); + // const l = Number(o.length); + // const a = new Array(l); + // for (let i = 0; i < l; i++) { + // a[i] = o[i]; + // } + // Array.prototype.sort.call(a, compareFn); + // return a; + // }`, false], + // ['object.groupby', `Object.groupBy || function (items, callbackfn) { + // const o = Object.create(null); + // let k = 0; + // for (const value of items) { + // const key = callbackfn(value, k++); + // if (key in o) { + // Array.prototype.push.call(o[key], value); + // } else { + // o[key] = [value]; + // } + // } + // return o; + // }`, true], + // ['array.prototype.find', 'Array.prototype.find', false], + // ['array.from', 'Array.from', true], + // ['string.prototype.padend', 'String.prototype.padEnd', false], + // ['string.prototype.padstart', 'String.prototype.padStart', false], + // ['object.getownpropertydescriptors', 'Object.getOwnPropertyDescriptors', true], + // ['array.prototype.reduce', 'Array.prototype.reduce', false], + // ['object-is', 'Object.is', true], + // ['reflect.ownkeys', 'Reflect.ownKeys', true], + // // ['array.prototype.filter', 'Array.prototype.filter', false], + // ['string.prototype.replaceall', 'String.prototype.replaceAll', false], + // // ['array.prototype.map', 'Array.prototype.map', false], + // ['reflect.getprototypeof', 'Reflect.getPrototypeOf', true], + // // ['object.getprototypeof', 'Object.getPrototypeOf', true] + // ['es-aggregate-error', `typeof AggregateError === 'function' + // ? AggregateError + // : (() => { + // function AggregateError(errors, message) { + // const error = new Error(message); + // Object.setPrototypeOf(error, AggregateError.prototype); + // delete error.constructor; + // Object.defineProperty(error, 'errors', { value: Array.from(errors) }); + // return error; + // } + // Object.defineProperty(AggregateError, 'prototype', { writable: false }); + // Object.defineProperties(AggregateError.prototype, { + // constructor: { + // enumerable: false, + // configurable: true, + // writable: true, + // value: AggregateError + // }, + // message: { + // enumerable: false, + // configurable: true, + // writable: true, + // value: '' + // }, + // name: { + // enumerable: false, + // configurable: true, + // writable: true, + // value: 'AggregateError' + // } + // }); + // Object.setPrototypeOf(AggregateError.prototype, Error.prototype); + // return AggregateError; + // })()`, true], + ['promise.any', { '@nolyfill/es-aggregate-error': 'workspace:*' }, '>=12.4.0'], + // ['promise.allsettled', `Promise.allSettled || function allSettled(iterable) { + // const $reject = Promise.reject.bind(this); + // const $resolve = Promise.resolve.bind(this); + // const $all = Promise.all.bind(this); + // return $all(Array.from(iterable).map((item) => { + // const p = $resolve(item); + // try { + // return p.then( + // (value) => ({ status: 'fulfilled', value }), + // (reason) => ({ status: 'rejected', reason }) + // ); + // } catch (e) { + // return $reject(e); + // } + // })); + // }`, true, {}, '>=12.4.0', 'Promise'] ] as const; const singleFilePackagesList = [ @@ -555,16 +522,16 @@ const nonNolyfillPackagesList = [ ...currentPackageJson, overrides: allPackagesList .reduce>((acc, packageName) => { - acc[packageName] = `npm:@nolyfill/${packageName}@latest`; - return acc; - }, {}), + acc[packageName] = `npm:@nolyfill/${packageName}@latest`; + return acc; + }, {}), pnpm: { ...currentPackageJson.pnpm, overrides: allPackagesList .reduce>((acc, packageName) => { - acc[packageName] = `workspace:@nolyfill/${packageName}@*`; - return acc; - }, {}) + acc[packageName] = `workspace:@nolyfill/${packageName}@*`; + return acc; + }, {}) } }; @@ -573,7 +540,7 @@ const nonNolyfillPackagesList = [ export const allPackages = ${JSON.stringify(allPackagesList, null, 2)};\n`; await Promise.all([ - ...autoGeneratedPackagesList.map(pkg => createEsShimLikePackage(pkg[0], pkg[1], pkg[2], pkg[3], pkg[4], pkg[5])), + ...autoGeneratedPackagesList.map(pkg => createEsShimLikePackage(pkg[0], pkg[1], pkg[2])), ...singleFilePackagesList.map(pkg => createSingleFilePackage(pkg[0], pkg[1], pkg[2])), compareAndWriteFile( path.join(__dirname, 'package.json'), @@ -595,32 +562,35 @@ export const allPackages = ${JSON.stringify(allPackagesList, null, 2)};\n`; async function createEsShimLikePackage( packageName: string, - packageImplementation: string, - isStatic: boolean, extraDependencies: Record = {}, - minimumNodeVersion = '>=12.4.0', - bindTo: string | null = null + minimumNodeVersion = '>=12.4.0' ) { + const entryContent = await fsPromises.readFile( + path.join(__dirname, 'packages', 'data', 'es-shim-like', '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: { - 'implementation.js': `'use strict';\nmodule.exports = ${packageImplementation};\n`, - 'polyfill.js': `'use strict';\nmodule.exports = () => ${packageImplementation};\n`, - 'shim.js': `'use strict';\nmodule.exports = () => ${packageImplementation};\n`, - 'auto.js': '\'use strict\';\n/* noop */\n', - 'index.js': [ - '\'use strict\';', - isStatic - ? 'const { makeEsShim } = require(\'@nolyfill/shared\');' - : 'const { uncurryThis, makeEsShim } = require(\'@nolyfill/shared\');', - `const impl = ${packageImplementation};`, - isStatic - ? `const bound = ${bindTo ? `impl.bind(${bindTo})` : 'impl'};` - : `const bound = ${bindTo ? `uncurryThis(impl).bind(${bindTo})` : 'uncurryThis(impl)'};`, - 'makeEsShim(bound, impl);', - 'module.exports = bound;', - '' - ].join('\n') + 'entry.js': code + 'Object.assign(exports.default, exports);\nmodule.exports = exports.default;', + '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`, + 'auto.js': `'use strict';\n/* noop */\n`, + 'index.js': `'use strict';\nmodule.exports = require('./entry.js').index();\n` }, packageJson: { name: `@nolyfill/${packageName}`, @@ -655,7 +625,7 @@ async function createSingleFilePackage( ) { const currentPackageJson = await currentPackageJsonPromise; - const pkg:VirtualPackage = { + const pkg: VirtualPackage = { path: path.join(__dirname, 'packages/generated', packageName), files: { 'index.js': `'use strict';\n${implementation}\n` diff --git a/packages/data/es-shim-like/package.json b/packages/data/es-shim-like/package.json new file mode 100644 index 00000000..7d2747b0 --- /dev/null +++ b/packages/data/es-shim-like/package.json @@ -0,0 +1,12 @@ +{ + "name": "es-shim-like", + "version": "0.0.0", + "private": true, + "license": "MIT", + "scripts": { + "lint": "eslint ." + }, + "dependencies": { + "@nolyfill/shared": "workspace:*" + } +} diff --git a/packages/data/es-shim-like/src/array-includes.ts b/packages/data/es-shim-like/src/array-includes.ts new file mode 100644 index 00000000..700da20e --- /dev/null +++ b/packages/data/es-shim-like/src/array-includes.ts @@ -0,0 +1,3 @@ +import { defineEsShim } from '@nolyfill/shared'; + +export default defineEsShim(Array.prototype.includes) diff --git a/packages/data/es-shim-like/src/array.prototype.at.ts b/packages/data/es-shim-like/src/array.prototype.at.ts new file mode 100644 index 00000000..723827ca --- /dev/null +++ b/packages/data/es-shim-like/src/array.prototype.at.ts @@ -0,0 +1,10 @@ +import { defineEsShim } from "@nolyfill/shared"; + +const implementation = Array.prototype.at || function at(this: T[], n: number) { + n = Math.trunc(n) || 0; + if (n < 0) n += this.length; + if (n < 0 || n >= this.length) return undefined; + return this[n]; +} + +export default defineEsShim(implementation) diff --git a/packages/data/es-shim-like/src/array.prototype.findlast.ts b/packages/data/es-shim-like/src/array.prototype.findlast.ts new file mode 100644 index 00000000..db6c2d5b --- /dev/null +++ b/packages/data/es-shim-like/src/array.prototype.findlast.ts @@ -0,0 +1,12 @@ +import { defineEsShim } from "@nolyfill/shared"; + +const implementation = Array.prototype.findLast + || function (this: T[], callback: (value: T, index: number, array: T[]) => unknown, thisArg: any) { + for (let i = this.length - 1; i >= 0; i--) { + const value = this[i]; + if (callback.call(thisArg, value, i, this)) return value; + } + return; + } + +export default defineEsShim(implementation) diff --git a/packages/data/es-shim-like/src/array.prototype.findlastindex.ts b/packages/data/es-shim-like/src/array.prototype.findlastindex.ts new file mode 100644 index 00000000..da7b9231 --- /dev/null +++ b/packages/data/es-shim-like/src/array.prototype.findlastindex.ts @@ -0,0 +1,11 @@ +import { defineEsShim } from "@nolyfill/shared"; + +const implementation = Array.prototype.findLastIndex + || function (this: T[], callback: (value: T, index: number, array: T[]) => unknown, thisArg: T[]) { + for (let i = this.length - 1; i >= 0; i--) { + if (callback.call(thisArg, this[i], i, this)) return i; + } + return -1; + }; + +export default defineEsShim(implementation) diff --git a/packages/data/es-shim-like/src/promise.any.ts b/packages/data/es-shim-like/src/promise.any.ts new file mode 100644 index 00000000..696cbe34 --- /dev/null +++ b/packages/data/es-shim-like/src/promise.any.ts @@ -0,0 +1,24 @@ +import { defineEsShim } from "@nolyfill/shared"; + +const implementation = Promise.any || function any(this: typeof Promise, iterable: ReadonlyArray> | Readonly>>): Promise { + const AggregateError = require('@nolyfill/es-aggregate-error/polyfill')(); + const $reject = Promise.reject.bind(this); + const $resolve = Promise.resolve.bind(this); + const $all = Promise.all.bind(this); + + try { + return $all( + Array.from(iterable) + .map((item) => $resolve(item).then(x => $reject(x), x => x)) + ).then( + (errors) => { + throw new AggregateError(errors, 'Every promise rejected'); + }, + x => x + ); + } catch (e) { + return $reject(e); + } +}; + +export default defineEsShim(implementation, true, implementation.bind(Promise)) diff --git a/packages/data/macro.ts b/packages/data/macro.ts deleted file mode 100644 index 14d45779..00000000 --- a/packages/data/macro.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* eslint-disable @typescript-eslint/unbound-method -- codegen */ -export interface defineEsShimParameters { - name: string, - dependencies: Record, - polyfill(): void, - auto(): void, - implementation: any, - index(): void -} - -export const defineEsShim = ({ - polyfill, - auto, - implementation, - index -}: defineEsShimParameters) => { - return { - auto, - polyfill, - implementation, - index - }; -}; - -defineEsShim({ - name: 'array-includes', - dependencies: {}, - implementation: Array.prototype.includes, - index() { - const { uncurryThis, makeEsShim } = require('@nolyfill/shared'); - const impl = Array.prototype.includes; - const bound = uncurryThis(impl); - makeEsShim(bound, impl); - return bound; - }, - polyfill() { - return Array.prototype.includes; - }, - shim() { - return Array.prototype.includes; - } -}); diff --git a/packages/data/package.json b/packages/data/package.json deleted file mode 100644 index 78f51226..00000000 --- a/packages/data/package.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "@nolyfill/data", - "version": "1.0.21", - "private": true, - "main": "./index.js", - "types": "./index.d.ts", - "license": "MIT", - "scripts": {}, - "dependencies": {}, - "engines": { - "node": ">=12.4.0" - } -}