Skip to content

Commit

Permalink
feat(cli,cli-service,cli-test-utils): add ts declaration (#5356)
Browse files Browse the repository at this point in the history
Co-authored-by: Haoqun Jiang <haoqunjiang@gmail.com>
  • Loading branch information
fangbinwei and sodatea committed Jul 15, 2020
1 parent 82d65e1 commit 725ca41
Show file tree
Hide file tree
Showing 20 changed files with 1,070 additions and 13 deletions.
3 changes: 3 additions & 0 deletions packages/@vue/cli-service/package.json
Expand Up @@ -26,6 +26,9 @@
"@intervolga/optimize-cssnano-plugin": "^1.0.5",
"@soda/friendly-errors-webpack-plugin": "^1.7.1",
"@soda/get-current-script": "^1.0.0",
"@types/minimist": "^1.2.0",
"@types/webpack": "^4.0.0",
"@types/webpack-dev-server": "^3.11.0",
"@vue/cli-overlay": "^4.4.6",
"@vue/cli-plugin-router": "^4.4.6",
"@vue/cli-plugin-vuex": "^4.4.6",
Expand Down
10 changes: 6 additions & 4 deletions packages/@vue/cli-service/types/ProjectOptions.d.ts
@@ -1,5 +1,5 @@
import ChainableWebpackConfig from 'webpack-chain'
import { WebpackOptions } from 'webpack/declarations/WebpackOptions'
import ChainableWebpackConfig = require('webpack-chain')
import { Configuration as WebpackOptions } from 'webpack'

type PageEntry = string | string[];

Expand Down Expand Up @@ -29,7 +29,7 @@ interface CSSOptions {
loaderOptions?: LoaderOptions;
}

export interface ProjectOptions {
interface ProjectOptions {
publicPath?: string;
outputDir?: string;
assetsDir?: string;
Expand Down Expand Up @@ -57,4 +57,6 @@ export interface ProjectOptions {
pluginOptions?: object;
}

export type ConfigFunction = () => ProjectOptions
type ConfigFunction = () => ProjectOptions

export { ProjectOptions, ConfigFunction }
64 changes: 64 additions & 0 deletions packages/@vue/cli-service/types/cli-service-test.ts
@@ -0,0 +1,64 @@
import { ServicePlugin } from '@vue/cli-service'

const servicePlugin: ServicePlugin = (api, options) => {
const version = api.version
api.assertVersion(4)
api.assertVersion('^100')
api.getCwd()
api.resolve('src/main.js')
api.hasPlugin('eslint')
api.registerCommand(
'lint',
{
description: 'lint and fix source files',
usage: 'vue-cli-service lint [options] [...files]',
options: {
'--format [formatter]': 'specify formatter (default: codeframe)'
},
details: 'For more options, see https://eslint.org/docs/user-guide/command-line-interface#options'
},
args => {
require('./lint')(args, api)
}
)
api.registerCommand('lint', args => {})

api.chainWebpack(webpackConfig => {
if (process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test') {
webpackConfig.devtool('cheap-module-eval-source-map')

webpackConfig.plugin('hmr').use(require('webpack/lib/HotModuleReplacementPlugin'))

webpackConfig.output.globalObject(`(typeof self !== 'undefined' ? self : this)`)
}
})

api.configureWebpack(config => {
config.output = {
path: 'test-dist-2'
}
})

api.configureWebpack(config => {
return {
devtool: config.devtool || 'source-map'
}
})

api.resolveWebpackConfig()

api.resolveWebpackConfig(api.resolveChainableWebpackConfig())

const { cacheIdentifier, cacheDirectory } = api.genCacheConfig(
'babel-loader',
{
'@babel/core': require('@babel/core/package.json').version,
'@vue/babel-preset-app': require('@vue/babel-preset-app/package.json').version,
'babel-loader': require('babel-loader/package.json').version,
modern: !!process.env.VUE_CLI_MODERN_BUILD,
browserslist: api.service.pkg.browserslist
},
['babel.config.js', '.browserslistrc']
)
}
export = servicePlugin
138 changes: 137 additions & 1 deletion packages/@vue/cli-service/types/index.d.ts
@@ -1 +1,137 @@
export { ProjectOptions, ConfigFunction } from './ProjectOptions'
import minimist = require('minimist')
import ChainableConfig = require('webpack-chain')
import webpack = require('webpack')
import WebpackDevServer = require('webpack-dev-server')
import express = require('express') // @types/webpack-dev-server depends on @types/express
import { ProjectOptions } from './ProjectOptions'

type RegisterCommandFn = (args: minimist.ParsedArgs, rawArgv: string[]) => any

type RegisterCommandOpts = Partial<{
description: string
usage: string
options: {
[flags: string]: string
}
details: string
}>

type WebpackChainFn = (chainableConfig: ChainableConfig) => void

type webpackRawConfigFn = ((config: webpack.Configuration) => webpack.Configuration | void) | webpack.Configuration

type DevServerConfigFn = (app: express.Application, server: WebpackDevServer) => void

interface CacheConfig {
cacheDirectory: string
cacheIdentifier: string
}
declare class PluginAPI {
id: string

service: any

readonly version: string

assertVersion(range: number | string): void

/**
* Current working directory.
*/
getCwd(): string

/**
* Resolve path for a project.
*
* @param _path - Relative path from project root
* @return The resolved absolute path.
*/
resolve(_path: string): string

/**
* Check if the project has a given plugin.
*
* @param id - Plugin id, can omit the (@vue/|vue-|@scope/vue)-cli-plugin- prefix
* @return `boolean`
*/
hasPlugin(id: string): boolean

/**
* Register a command that will become available as `vue-cli-service [name]`.
*
* @param name
* @param [opts]
* @param fn
*/
registerCommand(name: string, fn: RegisterCommandFn): void
registerCommand(name: string, opts: RegisterCommandOpts, fn: RegisterCommandFn): void

/**
* Register a function that will receive a chainable webpack config
* the function is lazy and won't be called until `resolveWebpackConfig` is
* called
*
* @param fn
*/
chainWebpack(fn: WebpackChainFn): void

/**
* Register
* - a webpack configuration object that will be merged into the config
* OR
* - a function that will receive the raw webpack config.
* the function can either mutate the config directly or return an object
* that will be merged into the config.
*
* @param fn
*/
configureWebpack(fn: webpackRawConfigFn): void

/**
* Register a dev serve config function. It will receive the express `app`
* instance of the dev server.
*
* @param fn
*/
configureDevServer(fn: DevServerConfigFn): void

/**
* Resolve the final raw webpack config, that will be passed to webpack.
*
* @param [chainableConfig]
* @return Raw webpack config.
*/
resolveWebpackConfig(chainableConfig?: ChainableConfig): webpack.Configuration

/**
* Resolve an intermediate chainable webpack config instance, which can be
* further tweaked before generating the final raw webpack config.
* You can call this multiple times to generate different branches of the
* base webpack config.
* See https://github.com/mozilla-neutrino/webpack-chain
*
* @return ChainableWebpackConfig
*/
resolveChainableWebpackConfig(): ChainableConfig

/**
* Generate a cache identifier from a number of variables
*/
genCacheConfig(id: string, partialIdentifier: any, configFiles?: string | string[]): CacheConfig
}

/**
* Service plugin serves for modifying webpack config,
* creating new vue-cli service commands or changing existing commands
*
* @param api - A PluginAPI instance
* @param options - An object containing project local options specified in vue.config.js,
* or in the "vue" field in package.json.
*/
type ServicePlugin = (
api: PluginAPI,
options: ProjectOptions
) => any

export { ProjectOptions, ServicePlugin, PluginAPI }
export { ConfigFunction } from './ProjectOptions'
22 changes: 22 additions & 0 deletions packages/@vue/cli-service/types/tsconfig.json
@@ -0,0 +1,22 @@
{
"files": [
"cli-service-test.ts",
"index.d.ts",
"ProjectOptions.d.ts"
],
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"esModuleInterop": true,
"strictFunctionTypes": true,
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true,
"baseUrl": "."
}
}
16 changes: 16 additions & 0 deletions packages/@vue/cli-test-utils/assertPromptModule.d.ts
@@ -0,0 +1,16 @@
import { PromptModuleAPI } from '@vue/cli'

interface CliPromptModule {
(api: PromptModuleAPI): void
}

declare function assertPromptModule(
module: CliPromptModule | CliPromptModule[],
expectedPrompts: object[],
expectedOptions: object,
opts?: {
pluginsOnly?: boolean
},
): Promise<void>

export = assertPromptModule
21 changes: 21 additions & 0 deletions packages/@vue/cli-test-utils/createJSONServer.d.ts
@@ -0,0 +1,21 @@
import { Application } from 'express'

declare function createJSONServer(
/**
* Either a path to a json file (e.g. 'db.json') or an object in memory
*
* Default:
*{
* 'posts': [
* { 'id': 1, 'title': 'json-server', 'author': 'typicode' }
* ],
* 'comments': [
* { 'id': 1, 'body': 'some comment', 'postId': 1 }
* ],
* 'profile': { 'name': 'typicode' }
*}
*/
data?: string | object,
): Application

export = createJSONServer
11 changes: 11 additions & 0 deletions packages/@vue/cli-test-utils/createServer.d.ts
@@ -0,0 +1,11 @@
/// <reference types="node" />
import * as http from 'http'

declare function createServer(options: {
/**
* Set a sub directory to be served
*/
root: string
}): http.Server

export = createServer
46 changes: 46 additions & 0 deletions packages/@vue/cli-test-utils/createTestProject.d.ts
@@ -0,0 +1,46 @@
import execa = require('execa') // execa@1.0.0 needs @types/execa
import { Preset } from '@vue/cli'

/**
* create project at path `cwd`
*/
declare function createTestProject(
/**
* project name
*/
name: string,
/**
* manual preset used to generate project.
*
* Example:
* {
* plugins: {
* '@vue/cli-plugin-babel': {}
* }
* }
*/
preset: Preset,
/** `path.resolve(cwd, name)` will be the project's root directory */
cwd?: string | null,
/**
* if init git repo
*
* Default:`true`
*/
initGit?: boolean,
): Promise<{
/** test project's root path */
dir: string
/** test if project contains the file */
has: (file: string) => boolean
/** read the content for the file */
read: (file: string) => Promise<string>
/** write file to project */
write: (file: string, content: any) => Promise<void>
/** execa command at root path of project */
run: (command: string, args?: ReadonlyArray<string>) => execa.ExecaChildProcess
/** delete the file of project */
rm: (file: string) => Promise<void>
}>

export = createTestProject
32 changes: 32 additions & 0 deletions packages/@vue/cli-test-utils/generateWithPlugin.d.ts
@@ -0,0 +1,32 @@
import { GeneratorAPI, Preset } from '@vue/cli'

type ApplyFn = (
api: GeneratorAPI,
options: any,
rootOptions: Preset,
invoking: boolean,
) => any
interface Plugin {
/** package name from plugin */
id: string
/** generator function from plugin */
apply: ApplyFn
/** parameter passed to generator function */
options?: any
}

/**
* invoke generator function, and generate file tree in memory
*/
declare function generateWithPlugin(
plugin: Plugin | Plugin[],
): Promise<{
/** package.json Object */
pkg: Record<string, any>
/** virtual file tree, file path is the key of Object */
files: {
[filePath: string]: string | Buffer
}
}>

export = generateWithPlugin

0 comments on commit 725ca41

Please sign in to comment.