diff --git a/CHANGELOG.md b/CHANGELOG.md index b6e9515..0b994b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). --- +## [0.26.0] +### Changed +* [#335]: **BREAKING CHANGE**: invalid `exports` shapes (both subpaths and `import`) are no longer supported. + ## [0.25.0] – 2024-11-16 ### Added * [#275]: support for `exports` as a string. @@ -445,7 +449,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/). [#321]: https://github.com/Comandeer/rollup-lib-bundler/issues/321 [#327]: https://github.com/Comandeer/rollup-lib-bundler/issues/327 [#332]: https://github.com/Comandeer/rollup-lib-bundler/issues/332 +[#335]: https://github.com/Comandeer/rollup-lib-bundler/issues/335 +[0.26.0]: https://github.com/Comandeer/rollup-lib-bundler/compare/v0.25.0...v0.26.0 [0.25.0]: https://github.com/Comandeer/rollup-lib-bundler/compare/v0.24.0...v0.25.0 [0.24.0]: https://github.com/Comandeer/rollup-lib-bundler/compare/v0.23.0...v0.24.0 [0.23.0]: https://github.com/Comandeer/rollup-lib-bundler/compare/v0.22.1...v0.23.0 diff --git a/package-lock.json b/package-lock.json index 3102f93..219bc21 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,9 +37,12 @@ "devDependencies": { "@comandeer/eslint-config": "^0.15.0", "@comandeer/rollup-lib-bundler": "^0.23.0", + "@types/babel__preset-env": "^7.9.7", + "@types/mock-fs": "^4.13.4", "@types/node": "^20.11.0", "@types/semver": "^7.5.8", "@types/sinon": "^17.0.3", + "@types/sourcemap-validator": "^2.1.2", "ava": "^6.1.3", "c8": "^10.1.2", "commitplease": "^3.2.0", @@ -3734,6 +3737,13 @@ "dev": true, "optional": true }, + "node_modules/@types/babel__preset-env": { + "version": "7.9.7", + "resolved": "https://registry.npmjs.org/@types/babel__preset-env/-/babel__preset-env-7.9.7.tgz", + "integrity": "sha512-m63P4DQR9d0/g8GwRsmyizGqfCGWI6LVnuNg4OV8YhNM+VMBAepJ4394Z/rJA0pBYV+AXgFfHP4RiIlk9mYVVQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", @@ -3752,6 +3762,16 @@ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, + "node_modules/@types/mock-fs": { + "version": "4.13.4", + "resolved": "https://registry.npmjs.org/@types/mock-fs/-/mock-fs-4.13.4.tgz", + "integrity": "sha512-mXmM0o6lULPI8z3XNnQCpL0BGxPwx1Ul1wXYEPBGl4efShyxW2Rln0JOPEWGyZaYZMM6OVXM/15zUuFMY52ljg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/node": { "version": "20.11.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.0.tgz", @@ -3784,6 +3804,13 @@ "integrity": "sha512-9GcLXF0/v3t80caGs5p2rRfkB+a8VBGLJZVih6CNFkx8IZ994wiKKLSRs9nuFwk1HevWs/1mnUmkApGrSGsShA==", "dev": true }, + "node_modules/@types/sourcemap-validator": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@types/sourcemap-validator/-/sourcemap-validator-2.1.2.tgz", + "integrity": "sha512-YZbT6a2x1pN/SBGr+jqtOzXnRjP5v4k5WwTWNh6IkbnpIxjObuyokGIAcQYH4l3OiMSJl793ozz6SBQ1ugMNZw==", + "dev": true, + "license": "MIT" + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.8.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.8.0.tgz", diff --git a/package.json b/package.json index 74da32a..1aeec33 100644 --- a/package.json +++ b/package.json @@ -70,9 +70,12 @@ "devDependencies": { "@comandeer/eslint-config": "^0.15.0", "@comandeer/rollup-lib-bundler": "^0.23.0", + "@types/babel__preset-env": "^7.9.7", + "@types/mock-fs": "^4.13.4", "@types/node": "^20.11.0", "@types/semver": "^7.5.8", "@types/sinon": "^17.0.3", + "@types/sourcemap-validator": "^2.1.2", "ava": "^6.1.3", "c8": "^10.1.2", "commitplease": "^3.2.0", diff --git a/src/OutputController.ts b/src/OutputController.ts index 398c8bd..c1faff8 100644 --- a/src/OutputController.ts +++ b/src/OutputController.ts @@ -16,7 +16,7 @@ interface ConsoleLike { error: ( ...args: Array ) => void; } -interface StackableError extends Error { +export interface StackableError extends Error { stack?: string; } diff --git a/src/bundler/bundleTypes.ts b/src/bundler/bundleTypes.ts index e48e29c..d8f1276 100644 --- a/src/bundler/bundleTypes.ts +++ b/src/bundler/bundleTypes.ts @@ -41,7 +41,7 @@ export default async function bundleTypes( { absolute: true, cwd: projectPath } ); - const emittedFiles = {}; + const emittedFiles: Record = {}; const host = ts.createCompilerHost( compilerOptions ); host.writeFile = ( filePath: string, contents: string ): void => { diff --git a/src/bundler/bundleTypesImports.d.ts b/src/bundler/bundleTypesImports.d.ts new file mode 100644 index 0000000..db4818b --- /dev/null +++ b/src/bundler/bundleTypesImports.d.ts @@ -0,0 +1,7 @@ +declare module '@babel/plugin-syntax-import-assertions' { + export default Record; +} + +declare module 'rollup-plugin-preserve-shebang' { + export default function(): unknown; +} diff --git a/src/index.ts b/src/index.ts index c8e7776..d9ff466 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,10 +1,9 @@ import { rimraf } from 'rimraf'; import chalk from 'chalk'; import bundler from './bundler.js'; -import OutputController from './OutputController.js'; +import OutputController, { StackableError } from './OutputController.js'; import packageParser from './packageParser.js'; import getDistDirPaths from './utils/getDistDirPaths.js'; -import { RollupLog } from 'rollup'; export default async function rlb(): Promise { const outputController = new OutputController(); @@ -21,7 +20,7 @@ export default async function rlb(): Promise { await rimraf( distPaths ); await bundler( { - onWarn( warning: RollupLog ): void { + onWarn( warning ): void { outputController.addWarning( warning ); }, packageMetadata @@ -29,7 +28,7 @@ export default async function rlb(): Promise { outputController.addLog( chalk.green.bold( 'Bundling complete!' ) ); } catch ( error ) { - await outputController.displayError( error ); + await outputController.displayError( error as StackableError ); outputController.addLog( chalk.red.bold( 'Bundling failed!' ) ); } finally { await outputController.display(); diff --git a/src/packageParser.ts b/src/packageParser.ts index 0e3b199..65716e3 100644 --- a/src/packageParser.ts +++ b/src/packageParser.ts @@ -1,11 +1,9 @@ import { normalize as normalizePath } from 'pathe'; import semver from 'semver'; -import loadAndParsePackageJSONFile, { - PackageJSON, - PackageJSONVersion -} from './packageParser/loadAndParsePackageJSONFile.js'; +import loadAndParsePackageJSONFile from './packageParser/loadAndParsePackageJSONFile.js'; // eslint-disable-next-line @typescript-eslint/consistent-type-imports import { type DistMetadata, prepareDistMetadata, type SubPathMetadata } from './packageParser/prepareDistMetadata.js'; +import { PackageJSON, PackageJSONVersion } from './packageParser/PackageJSON.js'; export { DistMetadata, SubPathMetadata }; @@ -35,7 +33,7 @@ export default async function packageParser( packageDir: string ): Promise { +async function prepareMetadata( packageDir: string, metadata: PackageJSON ): Promise { const project = normalizePath( packageDir ); return { diff --git a/src/packageParser/PackageJSON.ts b/src/packageParser/PackageJSON.ts new file mode 100644 index 0000000..bad01e4 --- /dev/null +++ b/src/packageParser/PackageJSON.ts @@ -0,0 +1,72 @@ +export type PackageJSONVersion = `${ number}.${ number }.${ number }`; + +export type PackageJSONSubPath = '.' | `.${ string }`; + +export interface PackageJSONConditionalExport { + readonly import: string; + readonly types?: string; + readonly requires?: string; +} + +export type PackageJSONSubPathExports = Readonly>; + +export type PackageJSONExports = +| string +| PackageJSONSubPathExports +| PackageJSONConditionalExport; + +export type PackageJSONAuthor = string | { + name: string; +}; + +export type PackageJSONBin = string | Record; + +export interface PackageJSONEngines { + readonly node?: string; +} + +export interface PackageJSON { + readonly name: string; + readonly version: PackageJSONVersion; + readonly author: PackageJSONAuthor; + readonly license: string; + readonly exports: PackageJSONExports; + readonly bin?: PackageJSONBin; + readonly engines?: PackageJSONEngines; +} + +export function isConditionalExport( obj: unknown ): obj is PackageJSONConditionalExport { + if ( obj === undefined || obj === null ) { + return false; + } + + const keys = Object.keys( obj ); + + if ( keys.length === 0 ) { + return false; + } + + return keys.every( ( key ) => { + return key === 'import' || key === 'types' || key === 'require'; + } ); +} + +export function isSubPathExports( obj: unknown ): obj is PackageJSONSubPathExports { + if ( obj === undefined || obj === null ) { + return false; + } + + const keys = Object.keys( obj ); + + if ( keys.length === 0 ) { + return false; + } + + return keys.every( ( key ) => { + return isSubPath( key ); + } ); +} + +export function isSubPath( value: unknown ): value is PackageJSONSubPath { + return typeof value === 'string' && value.startsWith( '.' ); +} diff --git a/src/packageParser/loadAndParsePackageJSONFile.ts b/src/packageParser/loadAndParsePackageJSONFile.ts index 7f14d83..b8440f0 100644 --- a/src/packageParser/loadAndParsePackageJSONFile.ts +++ b/src/packageParser/loadAndParsePackageJSONFile.ts @@ -1,39 +1,6 @@ import { access, readFile } from 'node:fs/promises'; import { resolve as resolvePath } from 'pathe'; - -export type PackageJSONVersion = `${ number}.${ number }.${ number }`; - -type PackageJSONSubPathExport = '.' | `.${ string }`; - -interface PackageJSONConditionalExport { - readonly import?: string; - readonly types?: string; -} - -type PackageJSONExports = -| string -| Readonly> -| PackageJSONConditionalExport; - -type PackageJSONAuthor = string | { - name: string; -}; - -type PackageJSONBin = string | Record; - -interface PackageJSONEngines { - readonly node?: string; -} - -export interface PackageJSON { - readonly name: string; - readonly version: PackageJSONVersion; - readonly author: PackageJSONAuthor; - readonly license: string; - readonly exports: PackageJSONExports; - readonly bin?: PackageJSONBin; - readonly engines?: PackageJSONEngines; -} +import { isConditionalExport, isSubPathExports, PackageJSON } from './PackageJSON.js'; type UnvalidatedPackageJSON = Partial; @@ -69,14 +36,7 @@ function validatePackageJSON( obj: UnvalidatedPackageJSON ): void { throw new ReferenceError( 'Package metadata must contain "version" property.' ); } - const isESMEntryPointPresent = obj.exports !== undefined && ( - typeof obj.exports === 'string' || - typeof obj.exports[ '.' ] === 'string' || - 'import' in obj.exports || - typeof obj.exports[ '.' ]?.import !== 'undefined' - ); - - if ( !isESMEntryPointPresent ) { + if ( !isESMEntryPointPresent( obj ) ) { throw new ReferenceError( 'Package metadata must contain at least one of "exports[ \'.\' ].import" and "exports.import" properties ' + 'or the "exports" property must contain the path.' @@ -91,3 +51,19 @@ function validatePackageJSON( obj: UnvalidatedPackageJSON ): void { throw new ReferenceError( 'Package metadata must contain "license" property.' ); } } + +function isESMEntryPointPresent( { exports }: UnvalidatedPackageJSON ): boolean { + if ( typeof exports === 'string' ) { + return true; + } + + if ( isConditionalExport( exports ) ) { + return true; + } + + if ( isSubPathExports( exports ) ) { + return true; + } + + return false; +} diff --git a/src/packageParser/prepareDistMetadata.ts b/src/packageParser/prepareDistMetadata.ts index a105ab5..76330bf 100644 --- a/src/packageParser/prepareDistMetadata.ts +++ b/src/packageParser/prepareDistMetadata.ts @@ -1,7 +1,7 @@ import assert from 'node:assert/strict'; import { globby } from 'globby'; import { extname, join as joinPath, resolve as resolvePath } from 'pathe'; -import { PackageJSON } from './loadAndParsePackageJSONFile.js'; +import { isConditionalExport, isSubPath, isSubPathExports, PackageJSON, PackageJSONBin, PackageJSONSubPath } from './PackageJSON.js'; export interface SubPathMetadata { esm: string; @@ -16,7 +16,7 @@ export type EntryPointType = 'js' | 'ts'; export type ExportType = 'import' | 'types'; export async function prepareDistMetadata( packageDir: string, metadata: PackageJSON ): Promise { - const subpaths = [ + const subpaths: ReadonlyArray = [ ...getExportsSubPaths( metadata ), ...getBinSubPaths( metadata ) ]; @@ -30,7 +30,7 @@ export async function prepareDistMetadata( packageDir: string, metadata: Package return distMetadata; } -function getExportsSubPaths( metadata: PackageJSON ): Array { +function getExportsSubPaths( metadata: PackageJSON ): Array { const exports = metadata.exports; // `exports` as a string is equal to having a one subpath of `.`. @@ -40,8 +40,8 @@ function getExportsSubPaths( metadata: PackageJSON ): Array { ]; } - const subPaths = Object.keys( exports ).filter( ( subpath ) => { - return subpath.startsWith( '.' ); + const subPaths = Object.keys( exports ).filter( ( subPath ) => { + return isSubPath( subPath ); } ); if ( !subPaths.includes( '.' ) ) { @@ -51,7 +51,7 @@ function getExportsSubPaths( metadata: PackageJSON ): Array { return subPaths; } -function getBinSubPaths( { bin, name }: PackageJSON ): Array { +function getBinSubPaths( { bin, name }: PackageJSON ): Array { if ( typeof bin === 'undefined' ) { return []; } @@ -63,13 +63,13 @@ function getBinSubPaths( { bin, name }: PackageJSON ): Array { } const binSubPaths = Object.keys( bin ).map( ( bin ) => { - return `./__bin__/${ bin }`; + return `./__bin__/${ bin }` as PackageJSONSubPath; } ); return binSubPaths; } -async function prepareSubPathMetadata( packageDir, metadata, subPath ): Promise { +async function prepareSubPathMetadata( packageDir: string, metadata: PackageJSON, subPath: PackageJSONSubPath ): Promise { const subPathFilePath = await getSubPathFilePath( packageDir, subPath ); const srcPath = joinPath( 'src', subPathFilePath ); const isBin = isBinSubPath( subPath ); @@ -144,24 +144,23 @@ function isBinSubPath( subPath: string ): boolean { return subPath.startsWith( './__bin__' ); } -function getESMTarget( { exports }: PackageJSON, subPath: string ): string { +function getESMTarget( { exports }: PackageJSON, subPath: PackageJSONSubPath ): string { if ( typeof exports === 'string' ) { return exports; } - if ( typeof exports[ subPath ] === 'string' ) { - return exports[ subPath ]; + if ( isConditionalExport( exports ) && subPath === '.' ) { + return exports.import; } - if ( - exports[ subPath ] === undefined && - subPath === '.' && - 'import' in exports - ) { - return exports.import; + assert( isSubPathExports( exports ), 'Incorrect format of \'exports\' package metadata' ); + assert( exports[ subPath ] !== undefined, `Missing target for the '${ subPath }' export` ); + + if ( isConditionalExport( exports[ subPath ] ) ) { + return exports[ subPath ].import; } - return exports[ subPath ].import; + return exports[ subPath ]; } function getBinTarget( { bin, name }: PackageJSON, subPath: string ): string { @@ -174,26 +173,32 @@ function getBinTarget( { bin, name }: PackageJSON, subPath: string ): string { return bin; } - return bin[ binName ]; + assert( isComplexBin( bin ), 'Incorrect format of the bin property' ); + + return bin[ binName ]!; } -function getTypesTarget( { exports }: PackageJSON, subPath: string ): string | undefined { - if ( typeof exports === 'string' || typeof exports[ subPath ] === 'string' ) { +function isComplexBin( bin: PackageJSONBin ): bin is Record { + return typeof bin !== 'string'; +} + +function getTypesTarget( { exports }: PackageJSON, subPath: PackageJSONSubPath ): string | undefined { + if ( typeof exports === 'string' ) { return undefined; } - if ( exports[ subPath ] === undefined && subPath === '.' && 'types' in exports ) { + if ( subPath === '.' && 'types' in exports ) { return exports.types; } - if ( exports[ subPath ] !== undefined ) { + if ( isSubPathExports( exports ) && isConditionalExport( exports[ subPath ] ) ) { return exports[ subPath ].types; } return undefined; } -async function getTSConfigPath( packageDir ): Promise { +async function getTSConfigPath( packageDir: string ): Promise { const tsConfigGlobPattern = 'tsconfig?(.rlb).json'; const matchedFiles = await globby( tsConfigGlobPattern, { cwd: packageDir diff --git a/tests/__helpers__/checkDistFiles.ts b/tests/__helpers__/checkDistFiles.ts index 7201dd2..0dc0d9c 100644 --- a/tests/__helpers__/checkDistFiles.ts +++ b/tests/__helpers__/checkDistFiles.ts @@ -23,7 +23,7 @@ export type CheckStrategyCallback = ( t: ExecutionContext, path: string, code: string, - options?: CheckStrategyCallbackOptions + options: CheckStrategyCallbackOptions ) => Promise | void; export type CheckStrategiesMap = Map; @@ -157,7 +157,7 @@ async function checkSourceMapFile( t: ExecutionContext, path: string, sourceMap: const jsCode = await readFile( jsFilePath, 'utf8' ); t.notThrows( () => { - return validateSourceMap( jsCode, sourceMap ); + validateSourceMap( jsCode, sourceMap ); } ); // Check if mappings are not empty (#105). diff --git a/tests/__helpers__/createPackageMetadata.ts b/tests/__helpers__/createPackageMetadata.ts index 1239010..caae97b 100644 --- a/tests/__helpers__/createPackageMetadata.ts +++ b/tests/__helpers__/createPackageMetadata.ts @@ -13,9 +13,12 @@ const DEFAULT_METADATA: PackageMetadata = { } }; +type SimplifiedSubPathMetadata = Exclude; +type SimplifiedDistMetadata = Record; + export default function createPackageMetadata( fixturePath: string, - distMetadata = {}, + distMetadata: SimplifiedDistMetadata = {}, projectMetadata = DEFAULT_METADATA ): PackageMetadata { const parsedDistMetadata = Object.fromEntries( Object.entries( distMetadata ).map( ( metadata ) => { @@ -30,10 +33,10 @@ export default function createPackageMetadata( }; } -function createFileMetadata( fixturePath, [ filePath, entryPoints ] ): [ string, SubPathMetadata ] { +function createFileMetadata( fixturePath: string, [ filePath, entryPoints ]: [ string, SubPathMetadata ] ): [ string, SubPathMetadata ] { const fullFilePath = resolvePath( fixturePath, filePath ); const parsedEntryPoints = Object.fromEntries( Object.entries( entryPoints ).map( - ( [ entryPointName, entryPointPath ]: [ keyof SubPathMetadata, string ] ): [ keyof SubPathMetadata, string ] => { + ( [ entryPointName, entryPointPath ]: [ keyof SimplifiedDistMetadata, string ] ): [ string, string ] => { if ( entryPointName === 'type' ) { return [ entryPointName, entryPointPath ]; } diff --git a/tests/bundler.ts b/tests/bundler.ts index 1d85456..eb922bb 100644 --- a/tests/bundler.ts +++ b/tests/bundler.ts @@ -18,7 +18,8 @@ test( 'bundler() throws error when any error is encountered', async ( t ) => { const packageMetadata = createPackageMetadata( errorPackageFixturePath, { 'src/index.js': { esm: './dist/index.mjs', - type: 'js' + type: 'js', + isBin: false } } ); @@ -36,7 +37,8 @@ test( 'bundler() handle warnings via provided onWarn() method', testWithSinonSan const packageMetadata = createPackageMetadata( externalDepPackageFixturePath, { 'src/index.js': { esm: './dist/index.mjs', - type: 'js' + type: 'js', + isBin: false } } ); const onWarnSpy = sandbox.spy(); diff --git a/tests/cli.ts b/tests/cli.ts index 685264e..59baf50 100644 --- a/tests/cli.ts +++ b/tests/cli.ts @@ -929,7 +929,7 @@ test.serial( } ); -async function createDummyDists( packagePath, distDirs = [ 'dist' ] ): Promise { +async function createDummyDists( packagePath: string, distDirs = [ 'dist' ] ): Promise { const distDirsPromises = distDirs.map( async ( distDir ) => { const distPath = resolvePath( packagePath, distDir ); const dummyFilePath = resolvePath( distPath, 'dummy.js' ); diff --git a/tests/generateBanner.ts b/tests/generateBanner.ts index e9e1193..0af50ba 100644 --- a/tests/generateBanner.ts +++ b/tests/generateBanner.ts @@ -9,7 +9,10 @@ test( 'generateBanner() produces correct banner', ( t ) => { author: 'Comandeer', license: 'MIT', version: '9.0.1', - dist: {} + dist: {}, + targets: { + node: 'current' + } }; const expected = `/*! test-package v9.0.1 | (c) ${ new Date().getFullYear() } Comandeer | MIT license (see LICENSE) */`; const banner = generateBanner( metadata ); diff --git a/tests/packageParser.ts b/tests/packageParser.ts index 349ee16..8641ca4 100644 --- a/tests/packageParser.ts +++ b/tests/packageParser.ts @@ -1,7 +1,7 @@ import mockFS from 'mock-fs'; import { resolve as resolvePath } from 'pathe'; import test from 'ava'; -import packageParser, { DistMetadata, PackageMetadata, PackageMetadataTargets, SubPathMetadata } from '../src/packageParser.js'; +import packageParser, { DistMetadata, PackageMetadata, PackageMetadataTargets } from '../src/packageParser.js'; const packageJSONFixtures = { invalid: '', @@ -144,7 +144,7 @@ const packageJSONFixtures = { license: 'ISC' }, - exportsDotImportOverExportsImport: { + invalidExportsShape: { name: 'test-package', version: '9.0.1', author: 'Comandeer', @@ -432,6 +432,7 @@ test.before( () => { ...createMockedPackage( 'noESMEntrypoint', 'js' ), ...createMockedPackage( 'noAuthor', 'js' ), ...createMockedPackage( 'noLicense', 'js' ), + ...createMockedPackage( 'invalidExportsShape', 'js' ), ...createMockedPackage( 'validExports', 'js' ), ...createMockedPackage( 'validExports', 'mjs' ), ...createMockedPackage( 'validExports', 'mixedJS' ), @@ -443,7 +444,6 @@ test.before( () => { ...createMockedPackage( 'tsProject', 'mts' ), ...createMockedPackage( 'tsProject', 'tsConfig' ), ...createMockedPackage( 'tsProject', 'noTSConfig' ), - ...createMockedPackage( 'exportsDotImportOverExportsImport', 'js' ), ...createMockedPackage( 'authorAsObject', 'js' ), ...createMockedPackage( 'mixedProject', 'mixedProject' ), ...createMockedPackage( 'noTypes', 'ts' ), @@ -566,6 +566,18 @@ test( 'packageParser() linter requires the license property', async ( t ) => { } ); } ); +// #185 +test( 'packageParser() linter requires valid shape of the exports metadata', async ( t ) => { + const mockedPackagePath = getMockedPackagePath( 'invalidExportsShape', 'js' ); + + await t.throwsAsync( () => { + return packageParser( mockedPackagePath ); + }, { + instanceOf: ReferenceError, + message: INVALID_ESM_METADATA_ERROR + } ); +} ); + // #61 test( 'packageParser() returns simplified metadata', async ( t ) => { const mockedPackagePath = getMockedPackagePath( 'validExports', 'js' ); @@ -676,16 +688,6 @@ test( 'packageParser() returns simplified metadata for package with CJS subpath t.deepEqual( actualMetadata, expectedMetadata ); } ); -// #185 -test( 'packageParser() prefers exports[ \'.\' ].import over exports.import', async ( t ) => { - const mockedPackagePath = getMockedPackagePath( 'exportsDotImportOverExportsImport', 'js' ); - const expectedDistPath = packageJSONFixtures.exportsDotImportOverExportsImport.exports[ '.' ].import; - const indexDistMetadata = await parseMetadataAndGetDistInfo( mockedPackagePath ); - const actualDistPath = indexDistMetadata.esm; - - t.is( actualDistPath, expectedDistPath ); -} ); - test( 'packageParser() parses author object into string', async ( t ) => { const mockedPackagePath = getMockedPackagePath( 'authorAsObject', 'js' ); const expectedAuthor = packageJSONFixtures.authorAsObject.author.name; @@ -1217,12 +1219,6 @@ test( } ); -async function parseMetadataAndGetDistInfo( mockedPackagePath, srcFile = 'src/index.js' ): Promise { - const parsedMetadata = await packageParser( mockedPackagePath ); - - return parsedMetadata.dist[ srcFile ]!; -} - interface MockedFSEntry { [x: string]: string | MockedFSEntry; } diff --git a/tests/utils/getDistDirPaths.ts b/tests/utils/getDistDirPaths.ts index e9e17d2..3be53b5 100644 --- a/tests/utils/getDistDirPaths.ts +++ b/tests/utils/getDistDirPaths.ts @@ -38,6 +38,9 @@ test( '#getDistDirPaths() returns an array of absolute paths to dist directories type: 'js', isBin: true } + }, + targets: { + node: 'current' } }; const distDirPaths = getDistDirPaths( packageMetadata ); diff --git a/tsconfig.json b/tsconfig.json index 6c8394b..f41e18c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -17,8 +17,7 @@ "skipLibCheck": true, "sourceMap": true, "strictNullChecks": true, - // It needs to wait after the code is rewritten. - // "strict": true, + "strict": true, "target": "esnext" }, "include": [