Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: error on bad type export #578

Merged
merged 2 commits into from
Sep 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 33 additions & 3 deletions src/lint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,23 @@ import path from 'path'
import { parseExports } from './exports'
import { logger } from './logger'
import { PackageMetadata } from './types'
import { hasCjsExtension, isESModulePackage } from './utils'
import { hasCjsExtension, isESModulePackage, isTypeFile } from './utils'

type BadExportItem = {
value: boolean
paths: string[]
}

function validateTypesFieldCondition(pair: [string, string]) {
const [outputPath, composedExportType] = pair
const exportTypes = new Set(composedExportType.split('.'))

if (!exportTypes.has('types') && isTypeFile(outputPath)) {
return true
}
return false
}

export function lint(pkg: PackageMetadata) {
const { name, main, exports } = pkg
const isESM = isESModulePackage(pkg.type)
Expand All @@ -26,6 +36,7 @@ export function lint(pkg: PackageMetadata) {
badCjsImportExport: BadExportItem
badEsmRequireExport: BadExportItem
badEsmImportExport: BadExportItem
badTypesExport: [string, string][]
} = {
badMainExtension: false,
badMainExport: false,
Expand All @@ -46,6 +57,7 @@ export function lint(pkg: PackageMetadata) {
value: false,
paths: [],
},
badTypesExport: [],
}

// Validate ESM package
Expand All @@ -59,7 +71,12 @@ export function lint(pkg: PackageMetadata) {
state.invalidExportsFieldType = true
} else {
parsedExports.forEach((outputPairs) => {
for (const [outputPath, composedExportType] of outputPairs) {
for (const outputPair of outputPairs) {
const [outputPath, composedExportType] = outputPair
if (validateTypesFieldCondition([outputPath, composedExportType])) {
state.badTypesExport.push([outputPath, composedExportType])
}

const exportTypes = new Set(composedExportType.split('.'))
let requirePath: string = ''
let importPath: string = ''
Expand Down Expand Up @@ -97,7 +114,11 @@ export function lint(pkg: PackageMetadata) {
state.invalidExportsFieldType = true
} else {
parsedExports.forEach((outputPairs) => {
for (const [outputPath, composedExportType] of outputPairs) {
for (const outputPair of outputPairs) {
const [outputPath, composedExportType] = outputPair
if (validateTypesFieldCondition([outputPath, composedExportType])) {
state.badTypesExport.push([outputPath, composedExportType])
}
const exportTypes = new Set(composedExportType.split('.'))
let requirePath: string = ''
let importPath: string = ''
Expand Down Expand Up @@ -179,4 +200,13 @@ export function lint(pkg: PackageMetadata) {
logger.warn(` ${p}`)
})
}

if (state.badTypesExport.length) {
state.badTypesExport.forEach(([outputPath, composedExportType]) => {
logger.error(
`Bad export types field with ${composedExportType} in ${outputPath}, use "types" export condition for it`,
)
})
process.exit(1)
}
}
10 changes: 1 addition & 9 deletions src/plugins/output-state-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
getSpecialExportTypeFromComposedExportPath,
normalizeExportPath,
} from '../entries'
import { isBinExportPath } from '../utils'
import { isBinExportPath, isTypeFile } from '../utils'

// [filename, sourceFileName, size]
type FileState = [string, string, number]
Expand Down Expand Up @@ -91,14 +91,6 @@ function createOutputState({ entries }: { entries: Entries }): {
}
}

function isTypeFile(filename: string) {
return (
filename.endsWith('.d.ts') ||
filename.endsWith('.d.mts') ||
filename.endsWith('.d.cts')
)
}

function normalizeExportName(exportName: string): string {
const isBinary = isBinExportPath(exportName)
let result = exportName
Expand Down
8 changes: 8 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,3 +226,11 @@ export async function removeOutputDir(output: OutputOptions, cwd: string) {
export function isBinExportPath(exportPath: string) {
return exportPath === BINARY_TAG || exportPath.startsWith(BINARY_TAG + '/')
}

export function isTypeFile(filename: string) {
return (
filename.endsWith('.d.ts') ||
filename.endsWith('.d.mts') ||
filename.endsWith('.d.cts')
)
}
21 changes: 21 additions & 0 deletions test/integration/js-bad-configured-types/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { createIntegrationTest } from '../utils'

describe('integration js-bad-configured-types', () => {
it('should error when types is not correctly configured', async () => {
await createIntegrationTest(
{
directory: __dirname,
},
async ({ stderr, code }) => {
expect(code).toBe(1)

expect(stderr).toContain(
`Bad export types field with import.require in ./dist/index.d.mts, use "types" export condition for it`,
)
expect(stderr).toContain(
`Bad export types field with require in ./dist/index.d.ts, use "types" export condition for it`,
)
},
)
})
})
15 changes: 15 additions & 0 deletions test/integration/js-bad-configured-types/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"types": "./dist/index.d.ts",
"exports": {
".": {
"import": {
"require": "./dist/index.d.mts",
"default": "./dist/index.mjs"
},
"require": {
"require": "./dist/index.d.ts",
"default": "./dist/index.js"
}
}
}
}
3 changes: 3 additions & 0 deletions test/integration/js-bad-configured-types/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function foo() {
return 'foo'
}
Loading