Skip to content

Commit

Permalink
chore: rework workflow testing suite (#2132)
Browse files Browse the repository at this point in the history
  • Loading branch information
joshuaellis committed Apr 9, 2023
1 parent 508b28e commit 5a70f61
Show file tree
Hide file tree
Showing 127 changed files with 36,046 additions and 324 deletions.
35 changes: 35 additions & 0 deletions .github/publish-ci/are-the-types-wrong/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# production
/build

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*

typesversions
.cache
.yarnrc
.yarn/*
!.yarn/patches
!.yarn/releases
!.yarn/plugins
!.yarn/sdks
!.yarn/versions
.pnp.*
*.tgz
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
diff --git a/package.json b/package.json
index 60791b6ccd3575279eddef2ac795802bd5044abd..41be518d2f21a659ca71095850cb18264a814f8d 100644
--- a/package.json
+++ b/package.json
@@ -25,6 +25,7 @@
"prepublishOnly": "npm run tsc && npm run test"
},
"type": "module",
+ "types": "./dist/index.d.ts",
"exports": {
".": {
"development": "./src/index.ts",
268 changes: 268 additions & 0 deletions .github/publish-ci/are-the-types-wrong/main.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
import path from 'path'
import fs from 'fs'

import { fileURLToPath } from 'node:url'
import type {
Analysis,
ProblemSummary,
Problem,
ResolutionKind,
ProblemKind,
} from '@arethetypeswrong/core'
import {
checkTgz,
summarizeProblems,
getProblems,
} from '@arethetypeswrong/core'
import React from 'react'
import { render, Text, Box, Static } from 'ink'

const allResolutionKinds: ResolutionKind[] = [
'node10',
'node16-cjs',
'node16-esm',
'bundler',
]

const problemEmoji: Record<ProblemKind, string> = {
Wildcard: '❓',
NoResolution: '💀',
UntypedResolution: '❌',
FalseCJS: '🎭',
FalseESM: '👺',
CJSResolvesToESM: '⚠️',
FallbackCondition: '🐛',
CJSOnlyExportsDefault: '🤨',
FalseExportDefault: '❗️',
UnexpectedESMSyntax: '🚭',
UnexpectedCJSSyntax: '🚱',
}

const problemShortDescriptions: Record<ProblemKind, string> = {
Wildcard: `${problemEmoji.Wildcard} Unable to check`,
NoResolution: `${problemEmoji.NoResolution} Failed to resolve`,
UntypedResolution: `${problemEmoji.UntypedResolution} No types`,
FalseCJS: `${problemEmoji.FalseCJS} Masquerading as CJS`,
FalseESM: `${problemEmoji.FalseESM} Masquerading as ESM`,
CJSResolvesToESM: `${problemEmoji.CJSResolvesToESM} ESM (dynamic import only)`,
FallbackCondition: `${problemEmoji.FallbackCondition} Used fallback condition`,
CJSOnlyExportsDefault: `${problemEmoji.CJSOnlyExportsDefault} CJS default export`,
FalseExportDefault: `${problemEmoji.FalseExportDefault} Incorrect default export`,
UnexpectedESMSyntax: `${problemEmoji.UnexpectedESMSyntax} Unexpected ESM syntax`,
UnexpectedCJSSyntax: `${problemEmoji.UnexpectedCJSSyntax} Unexpected CJS syntax`,
}

const resolutionKinds: Record<ResolutionKind, string> = {
node10: 'node10',
'node16-cjs': 'node16 (from CJS)',
'node16-esm': 'node16 (from ESM)',
bundler: 'bundler',
}

const moduleKinds = {
1: '(CJS)',
99: '(ESM)',
'': '',
}

const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)

interface Checks {
analysis: Analysis
problemSummaries?: ProblemSummary[]
problems?: Problem[]
}

const packagePath = path.join(__dirname, './package.tgz')

const packageTgzBytes = fs.readFileSync(packagePath)

function Header({ text, width }: { text: string; width: number | string }) {
return (
<Box borderStyle="single" width={width}>
<Text color="blue">{text}</Text>
</Box>
)
}

function Traces({
analysis,
subpaths,
}: {
analysis: Analysis
subpaths: string[]
}) {
if (!('entrypointResolutions' in analysis)) {
return null
}

return (
<Box flexDirection="column" width="100%">
{subpaths.map(subpath => {
const resolutionDetails = Object.entries(
analysis.entrypointResolutions[subpath]
)
return (
<Box width="100%" key={'traces-' + subpath} flexDirection="column">
<Text color="blue" bold>
Traces for Subpath: {subpath}
</Text>
{resolutionDetails.map(([resolutionKind, details]) => {
return (
<Box
width="100%"
key={`resolutionDetails-${resolutionKind}-${subpath}`}
flexDirection="column"
>
<Text bold>{resolutionKind} Traces:</Text>
<Box flexDirection="column">
{details.trace.map((traceLine, i) => {
return (
<Text
key={`resolutionDetails-traces-${subpath}-${resolutionKind}-${i}`}
>
{traceLine}
</Text>
)
})}
</Box>
</Box>
)
})}
</Box>
)
})}
</Box>
)
}

function ChecksTable(props: { checks?: Checks }) {
if (!props.checks || !props.checks.analysis.containsTypes) {
return null
}

const { analysis, problems, problemSummaries } = props.checks
const subpaths = Object.keys(analysis.entrypointResolutions).filter(
key => !key.includes('package.json')
)
const entrypoints = subpaths.map(s =>
s === '.'
? analysis.packageName
: `${analysis.packageName}/${s.substring(2)}`
)

const numColumns = entrypoints.length + 1

const columnWidth = `${100 / numColumns}%`

return (
<Box flexDirection="column" width="100%">
<Box>
<Header key={'empty'} text={''} width={columnWidth} />
{entrypoints.map(text => {
return <Header key={text} text={text} width={columnWidth} />
})}
</Box>
{allResolutionKinds.map(resolutionKind => {
return (
<Box key={resolutionKind} width="100%">
<Box borderStyle="single" width={columnWidth}>
<Text>{resolutionKinds[resolutionKind]}</Text>
</Box>
{subpaths.map(subpath => {
const problemsForCell = problems?.filter(
problem =>
problem.entrypoint === subpath &&
problem.resolutionKind === resolutionKind
)
const resolution =
analysis.entrypointResolutions[subpath][resolutionKind]
.resolution

let content: React.ReactNode

if (problemsForCell?.length) {
content = (
<Box flexDirection="column">
{problemsForCell.map(problem => {
return (
<Box key={problem.kind}>
<Text>{problemShortDescriptions[problem.kind]}</Text>
</Box>
)
})}
</Box>
)
} else if (resolution?.isJson) {
content = <Text>✅ (JSON)</Text>
} else {
content = (
<Text>
{'✅ ' +
moduleKinds[resolution?.moduleKind?.detectedKind || '']}
</Text>
)
}
return (
<Box key={subpath} width={columnWidth} borderStyle="single">
{content}
</Box>
)
})}
</Box>
)
})}
{problemSummaries?.map(summary => {
return (
<Box width="100%" key={summary.kind} flexDirection="column">
<Text color="red" bold>
{summary.kind}: {summary.title}
</Text>
{summary.messages.map(message => {
return (
<Text key={message.messageText}>{message.messageText}</Text>
)
})}
</Box>
)
})}
<Traces analysis={analysis} subpaths={subpaths} />
</Box>
)
}

;(async function main() {
const analysis = await checkTgz(packageTgzBytes)

const checks: Checks = {
analysis,
problems: undefined,
problemSummaries: undefined,
}
if ('entrypointResolutions' in analysis) {
const problems = analysis.containsTypes ? getProblems(analysis) : undefined
checks.problems = problems

if (problems) {
const problemSummaries = analysis.containsTypes
? summarizeProblems(problems, analysis)
: undefined
checks.problemSummaries = problemSummaries
}
}

// Ink will duplicate all of its output if it is longer than the terminal height.
// Known bug with the underlying rendering: https://github.com/vadimdemedes/ink/issues/48
// Solution is to mark the entire content as "static" so it won't get updated, but flushed.
render(
<Static items={[checks]}>
{(checks: Checks, index: number) => {
return <ChecksTable key={`checks-${index}`} checks={checks} />
}}
</Static>
)

const exitCode = checks.problems?.length ?? 0
process.exit(exitCode)
})()
26 changes: 26 additions & 0 deletions .github/publish-ci/are-the-types-wrong/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "are-the-types-wrong",
"packageManager": "yarn@3.2.4",
"type": "module",
"scripts": {
"build": "echo Nothing to build",
"test": "yarn tsx main.tsx"
},
"dependencies": {
"ink": "^4.0.0",
"object-hash": "^3.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-spring": "^9.7.1"
},
"devDependencies": {
"@arethetypeswrong/core": "^0.0.4",
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"shelljs": "^0.8.5",
"tsx": "^3.12.5"
},
"resolutions": {
"@arethetypeswrong/core@^0.0.4": "patch:@arethetypeswrong/core@npm%3A0.0.4#./.yarn/patches/@arethetypeswrong-core-npm-0.0.4-edb717a66b.patch"
}
}
10 changes: 10 additions & 0 deletions .github/publish-ci/are-the-types-wrong/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "esnext",
"moduleResolution": "node",
"esModuleInterop": true,

"jsx": "react",
}
}

1 comment on commit 5a70f61

@vercel
Copy link

@vercel vercel bot commented on 5a70f61 Apr 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.