-
Notifications
You must be signed in to change notification settings - Fork 11
/
script-task-provider.ts
147 lines (127 loc) · 3.52 KB
/
script-task-provider.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import * as vscode from 'vscode'
import { melosExecutableName } from './env'
import { info } from './logging'
import { isWorkspaceFolder } from './utils/vscode-utils'
import { loadMelosWorkspaceConfig } from './workspace-config'
export function registerMelosScriptTaskProvider(
context: vscode.ExtensionContext
) {
context.subscriptions.push(
vscode.tasks.registerTaskProvider(
'melos',
new MelosScriptTaskProvider(context)
)
)
}
/**
* A Melos script task definition.
*/
export interface MelosScriptTaskDefinition extends vscode.TaskDefinition {
type: 'melos'
/**
* The name of the script to run as defined in melos.yaml.
*/
script: string
}
/**
* A Melos script task definition for a script that uses `melos exec`.
*/
export interface MelosExecScriptTaskDefinition
extends MelosScriptTaskDefinition {
/**
* The options to pass to `melos exec`.
*/
execOptions?: string[]
/**
* The command to execute through `melos exec`.
*/
command: string
}
function isMelosScriptTaskDefinition(
definition: vscode.TaskDefinition
): definition is MelosScriptTaskDefinition {
return definition.type === 'melos' && typeof definition.script === 'string'
}
class MelosScriptTaskProvider implements vscode.TaskProvider {
constructor(private context: vscode.ExtensionContext) {}
public async provideTasks(): Promise<vscode.Task[]> {
const workspaceFolders = vscode.workspace.workspaceFolders
if (!workspaceFolders) {
return []
}
return (
await Promise.all(
workspaceFolders.map((folder) => this.loadWorkspaceFolderTasks(folder))
)
).flatMap((tasks) => tasks)
}
private async loadWorkspaceFolderTasks(
folder: vscode.WorkspaceFolder
): Promise<vscode.Task[]> {
const melosConfig = await loadMelosWorkspaceConfig(this.context, folder)
if (!melosConfig || !melosConfig.scripts) {
return []
}
info(
`Loaded scripts for tasks in '${folder.name}' folder`,
melosConfig.scripts.map((script) => script.name.value)
)
return melosConfig.scripts.map((script) => {
const task = buildMelosScriptTask(
{
type: 'melos',
script: script.name.value,
},
folder
)
task.detail = script.run?.value
return task
})
}
public resolveTask(_task: vscode.Task): vscode.Task | undefined {
const definition = _task.definition
if (!isMelosScriptTaskDefinition(definition)) {
return undefined
}
const scope = _task.scope
if (!isWorkspaceFolder(scope)) {
// Only WorkspaceFolder scope is supported since Melos scripts are
// defined in a melos.yaml in some workspace folder.
return undefined
}
return buildMelosScriptTask(definition, scope)
}
}
export function buildMelosScriptTask(
definition: MelosScriptTaskDefinition,
workspaceFolder: vscode.WorkspaceFolder
): vscode.Task {
return new vscode.Task(
definition,
workspaceFolder,
definition.script,
definition.type,
new vscode.ShellExecution(
`${melosExecutableName} run --no-select ${definition.script}`
)
)
}
export function buildMelosExecScriptTask(
definition: MelosExecScriptTaskDefinition,
workspaceFolder: vscode.WorkspaceFolder
) {
const commandLine = [
melosExecutableName,
'exec',
...(definition.execOptions ?? []),
'--',
definition.command,
]
return new vscode.Task(
definition,
workspaceFolder,
definition.script,
definition.type,
new vscode.ShellExecution(commandLine.join(' '))
)
}