Skip to content

Commit 265e5ec

Browse files
committed
Get initial ATTW processing working
1 parent 0734dad commit 265e5ec

File tree

5 files changed

+2108
-0
lines changed

5 files changed

+2108
-0
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.js
7+
8+
# testing
9+
/coverage
10+
11+
# production
12+
/build
13+
14+
# misc
15+
.DS_Store
16+
.env.local
17+
.env.development.local
18+
.env.test.local
19+
.env.production.local
20+
21+
npm-debug.log*
22+
yarn-debug.log*
23+
yarn-error.log*
24+
25+
typesversions
26+
.cache
27+
.yarnrc
28+
.yarn/*
29+
!.yarn/patches
30+
!.yarn/releases
31+
!.yarn/plugins
32+
!.yarn/sdks
33+
!.yarn/versions
34+
.pnp.*
35+
*.tgz
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
import path from 'path'
2+
import fs from 'fs'
3+
import util from 'util'
4+
5+
import { fileURLToPath } from 'node:url'
6+
import {
7+
checkTgz,
8+
summarizeProblems,
9+
getProblems,
10+
Analysis,
11+
ProblemSummary,
12+
Problem,
13+
ResolutionKind,
14+
ProblemKind,
15+
} from 'are-the-types-wrong-core'
16+
import React from 'react'
17+
import { render, Text, Box } from 'ink'
18+
19+
const allResolutionKinds: ResolutionKind[] = [
20+
'node10',
21+
'node16-cjs',
22+
'node16-esm',
23+
'bundler',
24+
]
25+
26+
const problemEmoji: Record<ProblemKind, string> = {
27+
Wildcard: '❓',
28+
NoResolution: '💀',
29+
UntypedResolution: '❌',
30+
FalseCJS: '🎭',
31+
FalseESM: '👺',
32+
CJSResolvesToESM: '⚠️',
33+
FallbackCondition: '🐛',
34+
CJSOnlyExportsDefault: '🤨',
35+
FalseExportDefault: '❗️',
36+
}
37+
38+
const problemShortDescriptions: Record<ProblemKind, string> = {
39+
Wildcard: `${problemEmoji.Wildcard} Unable to check`,
40+
NoResolution: `${problemEmoji.NoResolution} Failed to resolve`,
41+
UntypedResolution: `${problemEmoji.UntypedResolution} No types`,
42+
FalseCJS: `${problemEmoji.FalseCJS} Masquerading as CJS`,
43+
FalseESM: `${problemEmoji.FalseESM} Masquerading as ESM`,
44+
CJSResolvesToESM: `${problemEmoji.CJSResolvesToESM} ESM (dynamic import only)`,
45+
FallbackCondition: `${problemEmoji.FallbackCondition} Used fallback condition`,
46+
CJSOnlyExportsDefault: `${problemEmoji.CJSOnlyExportsDefault} CJS default export`,
47+
FalseExportDefault: `${problemEmoji.FalseExportDefault} Incorrect default export`,
48+
}
49+
50+
const resolutionKinds: Record<ResolutionKind, string> = {
51+
node10: 'node10',
52+
'node16-cjs': 'node16 (from CJS)',
53+
'node16-esm': 'node16 (from ESM)',
54+
bundler: 'bundler',
55+
}
56+
57+
const moduleKinds = {
58+
1: '(CJS)',
59+
99: '(ESM)',
60+
'': '',
61+
}
62+
63+
const __filename = fileURLToPath(import.meta.url)
64+
const __dirname = path.dirname(__filename)
65+
66+
interface Checks {
67+
analysis: Analysis
68+
problemSummaries?: ProblemSummary[]
69+
problems?: Problem[]
70+
}
71+
72+
const rtkPackagePath = path.join(__dirname, './package.tgz')
73+
74+
const rtkPackageTgzBytes = fs.readFileSync(rtkPackagePath)
75+
76+
function Header({ text, width }: { text: string; width: number | string }) {
77+
return (
78+
<Box borderStyle="single" width={width}>
79+
<Text color="blue">{text}</Text>
80+
</Box>
81+
)
82+
}
83+
84+
function ChecksTable(props: { checks?: Checks }) {
85+
if (!props.checks || !props.checks.analysis.containsTypes) {
86+
return null
87+
}
88+
89+
const { analysis, problems, problemSummaries } = props.checks
90+
const subpaths = Object.keys(analysis.entrypointResolutions).filter(
91+
(key) => !key.includes('package.json')
92+
)
93+
const entrypoints = subpaths.map((s) =>
94+
s === '.'
95+
? analysis.packageName
96+
: `${analysis.packageName}/${s.substring(2)}`
97+
)
98+
99+
const numColumns = entrypoints.length + 1
100+
101+
const columnWidth = `${100 / numColumns}%`
102+
103+
return (
104+
<Box flexDirection="column" width="100%">
105+
<Box>
106+
<Header key={'empty'} text={''} width={columnWidth} />
107+
{entrypoints.map((text) => {
108+
return <Header key={text} text={text} width={columnWidth} />
109+
})}
110+
</Box>
111+
{allResolutionKinds.map((resolutionKind) => {
112+
return (
113+
<Box key={resolutionKind} width="100%">
114+
<Box borderStyle="single" width={columnWidth}>
115+
<Text>{resolutionKinds[resolutionKind]}</Text>
116+
</Box>
117+
{subpaths.map((subpath) => {
118+
const problemsForCell = problems?.filter(
119+
(problem) =>
120+
problem.entrypoint === subpath &&
121+
problem.resolutionKind === resolutionKind
122+
)
123+
const resolution =
124+
analysis.entrypointResolutions[subpath][resolutionKind]
125+
.resolution
126+
127+
let content: React.ReactNode
128+
129+
if (problemsForCell?.length) {
130+
content = (
131+
<Box flexDirection="column">
132+
{problemsForCell.map((problem) => {
133+
return (
134+
<Box key={problem.kind}>
135+
<Text>{problemShortDescriptions[problem.kind]}</Text>
136+
</Box>
137+
)
138+
})}
139+
</Box>
140+
)
141+
} else if (resolution?.isJson) {
142+
content = <Text>✅ (JSON)</Text>
143+
} else {
144+
content = (
145+
<Text>
146+
{'✅ ' + moduleKinds[resolution?.moduleKind || '']}
147+
</Text>
148+
)
149+
}
150+
return (
151+
<Box key={subpath} width={columnWidth} borderStyle="single">
152+
{content}
153+
</Box>
154+
)
155+
})}
156+
</Box>
157+
)
158+
})}
159+
{problemSummaries?.map((summary) => {
160+
return (
161+
<Box width="100%" key={summary.kind} flexDirection="column">
162+
<Text color="red" bold>
163+
{summary.kind}: {summary.title}
164+
</Text>
165+
{summary.messages.map((message) => {
166+
return (
167+
<Text key={message.messageText}>{message.messageText}</Text>
168+
)
169+
})}
170+
</Box>
171+
)
172+
})}
173+
</Box>
174+
)
175+
}
176+
177+
;(async function main() {
178+
const analysis = await checkTgz(rtkPackageTgzBytes)
179+
if ('entrypointResolutions' in analysis) {
180+
const problems = analysis.containsTypes ? getProblems(analysis) : undefined
181+
182+
// console.log(
183+
// 'Analysis: ',
184+
// util.inspect(analysis.entrypointResolutions, { depth: 3 })
185+
// )
186+
if (problems) {
187+
// for (let problem of problems) {
188+
// console.log('Problem: ', problem)
189+
// }
190+
const problemSummaries = analysis.containsTypes
191+
? summarizeProblems(problems, analysis)
192+
: undefined
193+
// if (problemSummaries) {
194+
// for (let summary of problemSummaries) {
195+
// console.log('Summary: ', summary)
196+
// }
197+
// }
198+
const checks: Checks = {
199+
analysis,
200+
problems,
201+
problemSummaries,
202+
}
203+
204+
render(<ChecksTable checks={checks} />)
205+
}
206+
}
207+
})()
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"name": "are-the-types-wrong",
3+
"packageManager": "yarn@3.2.4",
4+
"type": "module",
5+
"dependencies": {
6+
"@tanstack/react-table": "^8.7.9",
7+
"are-the-types-wrong-core": "file:.yalc/are-the-types-wrong-core",
8+
"ink": "^4.0.0",
9+
"object-hash": "^3.0.0",
10+
"react": "^18.2.0"
11+
},
12+
"devDependencies": {
13+
"@types/react": "^18.0.28",
14+
"shelljs": "^0.8.5",
15+
"tsx": "^3.12.5"
16+
}
17+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"compilerOptions": {
3+
"target": "ESNext",
4+
"module": "esnext",
5+
"moduleResolution": "node",
6+
"esModuleInterop": true,
7+
8+
"jsx": "react",
9+
}
10+
}

0 commit comments

Comments
 (0)