Skip to content

Instantly share code, notes, and snippets.

@cef62
Created May 30, 2022 15:30
Show Gist options
  • Save cef62/a14c3003095fe56fba2b69d6c57e5777 to your computer and use it in GitHub Desktop.
Save cef62/a14c3003095fe56fba2b69d6c57e5777 to your computer and use it in GitHub Desktop.

Revisions

  1. cef62 created this gist May 30, 2022.
    88 changes: 88 additions & 0 deletions fixPackageJsonExports.mjs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,88 @@
    // @ts-check

    import path from 'path'
    import { readFile, writeFile } from 'fs/promises'
    import glob from 'tiny-glob'

    /**
    * @typedef {object} LegacyExportField
    * @property {string} [types]
    * @property {string} [import]
    * @property {string} [require]
    */

    /**
    * @typedef {object} ExportFieldEntry
    * @property {string} [types]
    * @property {string} [default]
    */

    /**
    * @typedef {object} ExportField
    * @property {ExportFieldEntry | string} [import]
    * @property {ExportFieldEntry | string} [require]
    */

    /**
    * @typedef {object} PackageJson
    * @property {string} [name]
    * @property {Record<string, LegacyExportField> | Record<string, ExportField>} [exports]
    */

    async function fixPackageJsonExports() {
    let packageJsonList = await glob('**/package.json')

    for (const packageJsonPath of packageJsonList) {
    try {
    const rootDir = '.'
    const pkgPath = path.join(rootDir, packageJsonPath)
    const pkgUrl = new URL(pkgPath, import.meta.url)

    /** @type {PackageJson} */
    const pkg = JSON.parse(await readFile(pkgUrl, { encoding: 'utf8' }))

    // skip projects without mapped exports
    if (!pkg.exports || Object.keys(pkg.exports).length === 0) continue

    for (const key of Object.keys(pkg.exports)) {
    const entry = pkg.exports?.[key]

    if (entry && 'types' in entry) {
    /** @type {LegacyExportField} */
    const field = entry

    pkg.exports[key] = {}

    if (field.types) {
    // the entry has types definitions

    if (field.import) {
    pkg.exports[key].import = { types: field.types, default: field.import }
    }

    if (field.require) {
    pkg.exports[key].require = { types: field.types, default: field.require }
    }
    } else {
    // the entry is withou types definitions

    if (field.import) {
    pkg.exports[key].import = field.import
    }

    if (field.require) {
    pkg.exports[key].require = field.require
    }
    }
    }
    }

    const content = JSON.stringify(pkg, null, 2) + '\n'
    await writeFile(pkgUrl, content, { encoding: 'utf8', flag: 'w' })
    } catch (e) {
    console.log(e)
    }
    }
    }

    fixPackageJsonExports()