/
json-schema-provider.ts
116 lines (100 loc) · 4.06 KB
/
json-schema-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
import * as vscode from 'vscode'
import { readFile } from 'fs'
import { promisify } from 'util'
import { resolve } from 'path'
import fetch from 'node-fetch'
import { CliProvider } from './flow-cli/cli-provider'
const CADENCE_SCHEMA_URI = 'cadence-schema'
const GET_FLOW_SCHEMA_URL = (version: string): string => `https://raw.githubusercontent.com/onflow/flow-cli/v${version}/flowkit/schema.json`
// This class provides the JSON schema for the flow.json file
// It is accessible via the URI scheme "cadence-schema:///flow.json"
export class JSONSchemaProvider implements vscode.FileSystemProvider, vscode.Disposable {
#contentProviderDisposable: vscode.Disposable | undefined
#extensionPath: string
#cliProvider: CliProvider
#schemaCache: { [version: string]: Promise<string> } = {}
constructor (
extensionPath: string,
cliProvider: CliProvider
) {
this.#extensionPath = extensionPath
this.#cliProvider = cliProvider
// Register the schema provider
this.#contentProviderDisposable = vscode.workspace.registerFileSystemProvider(
CADENCE_SCHEMA_URI,
this
)
}
async #getFlowSchema (): Promise<string> {
const cliBinary = await this.#cliProvider.getCurrentBinary()
if (cliBinary == null) {
throw new Error('No flow-cli binary found')
}
const version = cliBinary.version.format()
if (this.#schemaCache[version] == null) {
this.#schemaCache[version] = (async () => {
// Try to get schema from flow-cli repo based on the flow-cli version
return fetch(GET_FLOW_SCHEMA_URL(version)).then(async (response: Response) => {
if (!response.ok) {
throw new Error(`Failed to fetch schema from flow-cli repo: ${response.statusText}`)
}
return await response.text()
}).catch(async () => {
const schemaUrl = resolve(this.#extensionPath, 'flow-schema.json')
return await promisify(readFile)(schemaUrl).then(x => x.toString())
})
})()
}
return this.#schemaCache[version]
}
async readFile (uri: vscode.Uri): Promise<Uint8Array> {
if (uri.path === '/flow.json') {
const schema = await this.#getFlowSchema()
return Buffer.from(schema)
} else {
throw new Error('Unknown schema')
}
}
async stat (uri: vscode.Uri): Promise<vscode.FileStat> {
if (uri.path === '/flow.json') {
// Mocked values
return {
type: vscode.FileType.File,
ctime: 0,
mtime: 0,
size: await this.#getFlowSchema().then(x => x.length)
}
} else {
throw new Error('Unknown schema')
}
}
dispose (): void {
if (this.#contentProviderDisposable != null) {
this.#contentProviderDisposable.dispose()
}
}
// Unsupported file system provider methods
// These methods are required to implement the vscode.FileSystemProvider interface
onDidChangeFile: vscode.Event<vscode.FileChangeEvent[]> = new vscode.EventEmitter<vscode.FileChangeEvent[]>().event
watch (uri: vscode.Uri, options: { readonly recursive: boolean, readonly excludes: readonly string[] }): vscode.Disposable {
throw new Error('Method not implemented.')
}
readDirectory (uri: vscode.Uri): Array<[string, vscode.FileType]> | Thenable<Array<[string, vscode.FileType]>> {
throw new Error('Method not implemented.')
}
createDirectory (uri: vscode.Uri): void | Thenable<void> {
throw new Error('Method not implemented.')
}
writeFile (uri: vscode.Uri, content: Uint8Array, options: { readonly create: boolean, readonly overwrite: boolean }): void | Thenable<void> {
throw new Error('Method not implemented.')
}
delete (uri: vscode.Uri, options: { readonly recursive: boolean }): void | Thenable<void> {
throw new Error('Method not implemented.')
}
rename (oldUri: vscode.Uri, newUri: vscode.Uri, options: { readonly overwrite: boolean }): void | Thenable<void> {
throw new Error('Method not implemented.')
}
copy? (source: vscode.Uri, destination: vscode.Uri, options: { readonly overwrite: boolean }): void | Thenable<void> {
throw new Error('Method not implemented.')
}
}