Skip to content

Commit

Permalink
fix(build): enhance type check (element-plus#7880)
Browse files Browse the repository at this point in the history
* fix(build): enhance type check

* feat: stricter ts check
  • Loading branch information
sxzz authored May 24, 2022
1 parent 87bc353 commit 7ff199c
Show file tree
Hide file tree
Showing 20 changed files with 387 additions and 140 deletions.
8 changes: 8 additions & 0 deletions .github/workflows/test-unit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,15 @@ jobs:
include:
- node-version: '16'
node-name: 'Latest'

steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0

- name: Add dev branch
run: git branch dev origin/dev

- name: Setup pnpm
uses: pnpm/action-setup@v2

Expand All @@ -31,7 +34,12 @@ jobs:

- name: Install dependencies
run: pnpm i --frozen-lockfile

- name: Lint
run: pnpm lint

- name: Type Check
run: pnpm typecheck

- name: Test
run: pnpm test
153 changes: 85 additions & 68 deletions internal/build/src/tasks/types-definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import path from 'path'
import fs from 'fs/promises'
import consola from 'consola'
import * as vueCompiler from 'vue/compiler-sfc'
import { Project } from 'ts-morph'
import glob from 'fast-glob'
import chalk from 'chalk'
import { Project } from 'ts-morph'
import {
buildOutput,
epRoot,
Expand All @@ -15,51 +15,98 @@ import {
} from '@element-plus/build-utils'
import { pathRewriter } from '../utils'
import typeUnsafe from '../type-unsafe.json'

import type { SourceFile } from 'ts-morph'
import typeUnsafeStricter from '../type-unsafe-stricter.json'
import type { CompilerOptions, SourceFile } from 'ts-morph'

const TSCONFIG_PATH = path.resolve(projRoot, 'tsconfig.web.json')
const outDir = path.resolve(buildOutput, 'types')

// Type unsafe list. The TS errors are not all fixed yet, so we need a list of which files are not fixed with TS errors to prevent accidental TS errors.
const typeUnsafePaths = typeUnsafe.map((_path) => {
let paths = path.resolve(projRoot, _path)
if (_path.endsWith('/')) paths += path.sep
return paths
})

/**
* fork = require( https://github.com/egoist/vue-dts-gen/blob/main/src/index.ts
*/
export const generateTypesDefinitions = async () => {
const compilerOptions: CompilerOptions = {
emitDeclarationOnly: true,
outDir,
baseUrl: projRoot,
preserveSymlinks: true,
skipLibCheck: true,
noImplicitAny: false,
}
const project = new Project({
compilerOptions: {
emitDeclarationOnly: true,
outDir,
baseUrl: projRoot,
paths: {
'@element-plus/*': ['packages/*'],
},
preserveSymlinks: true,
types: [
path.resolve(projRoot, 'typings/env'),
'unplugin-vue-define-options',
],
},
compilerOptions,
tsConfigFilePath: TSCONFIG_PATH,
skipAddingFilesFromTsConfig: true,
})

const globAnyFile = '**/*.{js?(x),ts?(x),vue}'
const sourceFiles = await addSourceFiles(project)
consola.success('Added source files')

typeCheck(project, typeUnsafeStricter)
consola.success('Stricter type check passed!')

compilerOptions.noImplicitAny = false
project.compilerOptions.set(compilerOptions)

typeCheck(project, typeUnsafe)
consola.success('Type check passed!')

await project.emit({
emitOnlyDtsFiles: true,
})

const tasks = sourceFiles.map(async (sourceFile) => {
const relativePath = path.relative(pkgRoot, sourceFile.getFilePath())
consola.trace(
chalk.yellow(
`Generating definition for file: ${chalk.bold(relativePath)}`
)
)

const emitOutput = sourceFile.getEmitOutput()
const emitFiles = emitOutput.getOutputFiles()
if (emitFiles.length === 0) {
throw new Error(`Emit no file: ${chalk.bold(relativePath)}`)
}

const tasks = emitFiles.map(async (outputFile) => {
const filepath = outputFile.getFilePath()
await fs.mkdir(path.dirname(filepath), {
recursive: true,
})

await fs.writeFile(
filepath,
pathRewriter('esm')(outputFile.getText()),
'utf8'
)

consola.success(
chalk.green(
`Definition for file: ${chalk.bold(relativePath)} generated`
)
)
})

await Promise.all(tasks)
})

await Promise.all(tasks)
}

async function addSourceFiles(project: Project) {
project.addSourceFileAtPath(path.resolve(projRoot, 'typings/env.d.ts'))

const globSourceFile = '**/*.{js?(x),ts?(x),vue}'
const filePaths = excludeFiles(
await glob([globAnyFile, '!element-plus/**/*'], {
await glob([globSourceFile, '!element-plus/**/*'], {
cwd: pkgRoot,
absolute: true,
onlyFiles: true,
})
)
const epPaths = excludeFiles(
await glob(globAnyFile, {
await glob(globSourceFile, {
cwd: epRoot,
onlyFiles: true,
})
Expand Down Expand Up @@ -102,58 +149,28 @@ export const generateTypesDefinitions = async () => {
}),
])

return sourceFiles
}

function typeCheck(project: Project, paths: string[]) {
// Type unsafe list. The TS errors are not all fixed yet, so we need a list of which files are not fixed with TS errors to prevent accidental TS errors.
const typeUnsafePaths = paths.map((_path) => {
let paths = path.resolve(projRoot, _path)
if (_path.endsWith('/')) paths += path.sep
return paths
})

const diagnostics = project.getPreEmitDiagnostics().filter((diagnostic) => {
const filePath = diagnostic.getSourceFile()?.getFilePath()!
if (!filePath) return false
const file = path.normalize(filePath)
return !typeUnsafePaths.some((safePath) => file.startsWith(safePath))
})

if (diagnostics.length > 0) {
consola.error(project.formatDiagnosticsWithColorAndContext(diagnostics))
const err = new Error('Failed to generate dts.')
consola.error(err)
throw err
}

await project.emit({
emitOnlyDtsFiles: true,
})

const tasks = sourceFiles.map(async (sourceFile) => {
const relativePath = path.relative(pkgRoot, sourceFile.getFilePath())
consola.trace(
chalk.yellow(
`Generating definition for file: ${chalk.bold(relativePath)}`
)
)

const emitOutput = sourceFile.getEmitOutput()
const emitFiles = emitOutput.getOutputFiles()
if (emitFiles.length === 0) {
throw new Error(`Emit no file: ${chalk.bold(relativePath)}`)
}

const tasks = emitFiles.map(async (outputFile) => {
const filepath = outputFile.getFilePath()
await fs.mkdir(path.dirname(filepath), {
recursive: true,
})

await fs.writeFile(
filepath,
pathRewriter('esm')(outputFile.getText()),
'utf8'
)

consola.success(
chalk.green(
`Definition for file: ${chalk.bold(relativePath)} generated`
)
)
})

await Promise.all(tasks)
})

await Promise.all(tasks)
}
66 changes: 66 additions & 0 deletions internal/build/src/type-unsafe-stricter.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
[
"packages/components/autocomplete/",
"packages/components/cascader-panel/",
"packages/components/cascader/",
"packages/components/checkbox/",
"packages/components/col/",
"packages/components/collapse-transition/",
"packages/components/collection/",
"packages/components/color-picker/",
"packages/components/date-picker/",
"packages/components/descriptions/",
"packages/components/dialog/",
"packages/components/drawer/",
"packages/components/dropdown/",
"packages/components/focus-trap/",
"packages/components/image-viewer/",
"packages/components/infinite-scroll/",
"packages/components/input-number/",
"packages/components/input/",
"packages/components/loading/",
"packages/components/menu/",
"packages/components/message-box/",
"packages/components/message/",
"packages/components/notification/",
"packages/components/option-group/",
"packages/components/option/",
"packages/components/overlay/",
"packages/components/popconfirm/",
"packages/components/popover/",
"packages/components/popper/",
"packages/components/result/",
"packages/components/roving-focus-group/",
"packages/components/scrollbar/",
"packages/components/select-v2/",
"packages/components/select/",
"packages/components/skeleton-item/",
"packages/components/skeleton/",
"packages/components/slider/",
"packages/components/space/",
"packages/components/steps/",
"packages/components/table-column/",
"packages/components/table-v2/",
"packages/components/table/",
"packages/components/tabs/",
"packages/components/time-picker/",
"packages/components/time-select/",
"packages/components/timeline-item/",
"packages/components/timeline/",
"packages/components/tooltip-v2/",
"packages/components/tooltip/",
"packages/components/transfer/",
"packages/components/tree-select/",
"packages/components/tree-v2/",
"packages/components/tree/",
"packages/components/upload/",
"packages/components/virtual-list/",
"packages/components/visual-hidden/",
"packages/directives/",
"packages/hooks/use-floating/",
"packages/hooks/use-forward-ref/",
"packages/hooks/use-global-config/",
"packages/hooks/use-prop/",
"packages/make-installer.ts",
"packages/utils/dom/",
"packages/utils/vue/"
]
11 changes: 0 additions & 11 deletions internal/build/tsconfig.json

This file was deleted.

4 changes: 2 additions & 2 deletions internal/metadata/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"access": "public"
},
"scripts": {
"build": "concurrently \"pnpm run build:contributor\" \"pnpm run build:components\"",
"build": "run-p build:*",
"build:contributor": "tsx src/contributor.ts",
"build:components": "tsx src/components.ts",
"dev": "cross-env DEV=1 pnpm run build"
Expand All @@ -24,11 +24,11 @@
"@element-plus/build-utils": "^0.0.1",
"@types/lodash-es": "^4.17.6",
"chalk": "^5.0.1",
"concurrently": "^7.2.0",
"consola": "^2.15.3",
"cross-env": "^7.0.3",
"fast-glob": "^3.2.11",
"lodash-es": "^4.17.21",
"npm-run-all": "^4.1.5",
"octokit": "^1.7.1",
"tsx": "^3.4.0"
}
Expand Down
9 changes: 8 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@
"lint": "eslint . --ext .vue,.js,.ts,.jsx,.tsx,.md,.json --max-warnings 0 && pretty-quick --check --branch dev",
"lint:fix": "eslint --fix . --ext .vue,.js,.ts,.jsx,.tsx,.md,.json && pretty-quick --branch dev",
"lint:commit": "commitlint --from $(git merge-base dev HEAD) --to HEAD > ./commit-lint.txt",
"typecheck": "run-p typecheck:node typecheck:vite-config",
"typecheck:web": "vue-tsc -p tsconfig.web.json --composite false --noEmit",
"typecheck:node": "tsc -p tsconfig.node.json --noEmit",
"typecheck:play": "vue-tsc -p tsconfig.play.json --composite false --noEmit",
"typecheck:vite-config": "vue-tsc -p tsconfig.vite-config.json --composite false --noEmit",
"typecheck:vitest": "vue-tsc -p tsconfig.vitest.json --composite false --noEmit",
"docs:dev": "pnpm run -C docs dev",
"docs:build": "pnpm run -C docs build",
"docs:serve": "pnpm run -C docs serve",
Expand Down Expand Up @@ -73,13 +79,13 @@
"@pnpm/types": "^8.0.1",
"@types/fs-extra": "^9.0.13",
"@types/gulp": "^4.0.9",
"@types/jsdom": "^16.2.14",
"@types/node": "*",
"@types/sass": "^1.43.1",
"@vitejs/plugin-vue": "^2.3.3",
"@vitejs/plugin-vue-jsx": "^1.3.10",
"@vitest/ui": "^0.12.6",
"@vue/test-utils": "^2.0.0-rc.21",
"@vue/tsconfig": "^0.1.3",
"c8": "^7.11.3",
"chalk": "^5.0.1",
"concurrently": "^7.2.0",
Expand All @@ -93,6 +99,7 @@
"husky": "^8.0.1",
"jsdom": "16.4.0",
"lint-staged": "^12.4.1",
"npm-run-all": "^4.1.5",
"prettier": "^2.6.2",
"pretty-quick": "^3.1.3",
"puppeteer": "^14.1.1",
Expand Down
5 changes: 0 additions & 5 deletions packages/theme-chalk/tsconfig.json

This file was deleted.

2 changes: 2 additions & 0 deletions play/env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/// <reference types="vite/client" />
/// <reference types="vue/macros-global" />
13 changes: 0 additions & 13 deletions play/tsconfig.json

This file was deleted.

Loading

0 comments on commit 7ff199c

Please sign in to comment.