coc-vscode-loader 1.2.5 → 1.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/assets/tui-preview.png +0 -0
- package/converter/README.md +28 -14
- package/converter/package-lock.json +2 -2
- package/converter/package.json +1 -1
- package/converter/src/convert.ts +2 -0
- package/converter/src/scanner.ts +1 -1
- package/converter/src/steps/index.ts +2 -0
- package/converter/src/steps/language-client.ts +14 -10
- package/converter/src/steps/snippets.ts +122 -0
- package/converter/src/transforms/class-to-factory.ts +3 -5
- package/converter/src/transforms/provider-register.ts +30 -8
- package/converter/src/types.ts +9 -1
- package/lib/index.js +438 -148
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -37,9 +37,10 @@ npm install coc-vscode-loader
|
|
|
37
37
|
| `x` | Toggle mark package for batch operations |
|
|
38
38
|
| `f` | Cycle filter: all → installed → available |
|
|
39
39
|
| `s` | Cycle sort: default → name → status → type |
|
|
40
|
+
| `j` / `k` | Scroll through packages (virtual scroll) |
|
|
40
41
|
| `gg` | Jump to first package |
|
|
41
42
|
| `G` | Jump to last package |
|
|
42
|
-
| `<CR>` |
|
|
43
|
+
| `<CR>` | Open detail popup (info / install log with syntax highlights) |
|
|
43
44
|
| `/` | Search filter |
|
|
44
45
|
| `q` | Close (auto `:CocRestart` if changes detected) |
|
|
45
46
|
| `<Esc>` | Help→Search→Clear marks→Cancel|Close |
|
|
@@ -60,12 +61,13 @@ npm install coc-vscode-loader
|
|
|
60
61
|
|
|
61
62
|
- **Real conversion pipeline** — git clone → converter → npm install → esbuild → register to coc
|
|
62
63
|
- **Auto-fetch registry** — remote registry fetched in background when TUI opens, no manual refresh needed
|
|
64
|
+
- **Virtual scrolling** — `j`/`k` smooth scroll through packages, handles 100k+ registry entries
|
|
63
65
|
- **Incremental cache** — source/ keeps git repo, updates via git pull only
|
|
64
66
|
- **Commit tracking** — records commit SHA after install, visible in detail view
|
|
65
67
|
- **Update check** — `C` key compares against remote HEAD, shows `↑` when outdated
|
|
66
68
|
- **Auto restart** — `:CocRestart` triggered automatically on close when changes detected
|
|
67
69
|
- **Manual registry update** — `:CocCommand loader.updateRegistry` also available for re-fetch
|
|
68
|
-
- **
|
|
70
|
+
- **Detail popup** — `<CR>` opens centered float window with package info or live install log (syntax highlighted, auto-scroll to latest)
|
|
69
71
|
- **Mark & batch** — `x` toggle mark, visual indicator, `D` clean orphaned packages
|
|
70
72
|
- **Filter & sort** — `f` cycle view filter, `s` cycle sort order (name/status/type)
|
|
71
73
|
- **Concurrency limit** — max 3 parallel operations for `U` (Update All)
|
package/assets/tui-preview.png
CHANGED
|
Binary file
|
package/converter/README.md
CHANGED
|
@@ -18,11 +18,25 @@ cd ~/.config/coc/extensions && npm install /path/to/coc-ext
|
|
|
18
18
|
|
|
19
19
|
## Verified conversions
|
|
20
20
|
|
|
21
|
-
| Plugin | Type |
|
|
22
|
-
|
|
23
|
-
| Volar (Vue) | TS bridge |
|
|
24
|
-
| Prisma | Pure LSP |
|
|
25
|
-
| HTML CSS Support | Direct API |
|
|
21
|
+
| Plugin | Type | Notes |
|
|
22
|
+
|--------|------|-------|
|
|
23
|
+
| Volar (Vue) | TS bridge | Requires modified coc-tsserver |
|
|
24
|
+
| Prisma | Pure LSP | Auto-detects bin entry |
|
|
25
|
+
| HTML CSS Support | Direct API | Handles API differences |
|
|
26
|
+
| Deno | Pure LSP | Binary server download |
|
|
27
|
+
| TOML (Taplo) | Pure LSP | Binary server download |
|
|
28
|
+
| Ansible | Pure LSP | npm package server + pip install |
|
|
29
|
+
| YAML | Pure LSP | npm package server |
|
|
30
|
+
| Tailwind CSS | Pure LSP | npm package server, bin entry |
|
|
31
|
+
| Biome | Pure LSP | Binary server download |
|
|
32
|
+
| Stylelint | Pure LSP | npm package server |
|
|
33
|
+
| Prettier | Direct API | Source transforms |
|
|
34
|
+
| Svelte | Pure LSP | npm package server |
|
|
35
|
+
| Astro | Pure LSP | npm package server |
|
|
36
|
+
| Lua | Pure LSP | npm package server |
|
|
37
|
+
| gitignore | Direct API | Source transforms |
|
|
38
|
+
|
|
39
|
+
See the [registry](https://github.com/coc-plugin/coc-vscode-registry) for the full list and latest status.
|
|
26
40
|
|
|
27
41
|
### Plugin types
|
|
28
42
|
|
|
@@ -77,21 +91,21 @@ const PRESETS = {
|
|
|
77
91
|
`convert.ts` only calls `getActivePresets()` + `generateBridgeCode()`, it never touches bridge logic directly.
|
|
78
92
|
Adding a new bridge type = add a new preset in `presets.ts`, no changes to main flow.
|
|
79
93
|
|
|
80
|
-
See [
|
|
94
|
+
See [../docs/converter-design-v2.md](../docs/converter-design-v2.md).
|
|
81
95
|
|
|
82
96
|
## File structure
|
|
83
97
|
|
|
84
98
|
| File | Lines | Description |
|
|
85
99
|
|------|-------|-------------|
|
|
86
|
-
| `src/cli.ts` |
|
|
87
|
-
| `src/convert.ts` |
|
|
88
|
-
| `src/scanner.ts` |
|
|
89
|
-
| `src/transforms/import-mapping.ts` |
|
|
100
|
+
| `src/cli.ts` | 59 | CLI entry |
|
|
101
|
+
| `src/convert.ts` | 461 | Main flow + template generation + API replacement |
|
|
102
|
+
| `src/scanner.ts` | 52 | API scanner + plugin classification |
|
|
103
|
+
| `src/transforms/import-mapping.ts` | 193 | Import replacement |
|
|
90
104
|
| `src/transforms/language-client.ts` | 48 | LanguageClient adaptation |
|
|
91
|
-
| `src/transforms/class-to-factory.ts` |
|
|
92
|
-
| `src/transforms/provider-register.ts` |
|
|
93
|
-
| `src/transforms/enum-offset.ts` |
|
|
94
|
-
| **Total** | **~
|
|
105
|
+
| `src/transforms/class-to-factory.ts` | 53 | new Xxx() → Xxx.create() |
|
|
106
|
+
| `src/transforms/provider-register.ts` | 61 | Provider registration signature fixes |
|
|
107
|
+
| `src/transforms/enum-offset.ts` | 32 | Enum value offset annotations |
|
|
108
|
+
| **Total** | **~959** | |
|
|
95
109
|
|
|
96
110
|
## Handled API differences
|
|
97
111
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "converter",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.7",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "converter",
|
|
9
|
-
"version": "1.2.
|
|
9
|
+
"version": "1.2.7",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"commander": "^15.0.0",
|
|
12
12
|
"ts-morph": "^28.0.0",
|
package/converter/package.json
CHANGED
package/converter/src/convert.ts
CHANGED
|
@@ -326,6 +326,7 @@ export async function convert(opts: ConvertOptions): Promise<void> {
|
|
|
326
326
|
command: c.command,
|
|
327
327
|
title: c.title,
|
|
328
328
|
})) || undefined,
|
|
329
|
+
snippets: origPkg.contributes?.snippets || undefined,
|
|
329
330
|
...(tsPlugins.length > 0 ? {
|
|
330
331
|
typescriptServerPlugins: tsPlugins.map(p => ({
|
|
331
332
|
...p,
|
|
@@ -338,6 +339,7 @@ export async function convert(opts: ConvertOptions): Promise<void> {
|
|
|
338
339
|
// Clean null fields
|
|
339
340
|
if (!pkg.contributes?.configuration) delete (pkg.contributes as any).configuration
|
|
340
341
|
if (!pkg.contributes?.commands) delete (pkg.contributes as any).commands
|
|
342
|
+
if (!pkg.contributes?.snippets) delete (pkg.contributes as any).snippets
|
|
341
343
|
if (Object.keys(pkg.contributes).length === 0) delete (pkg as any).contributes
|
|
342
344
|
|
|
343
345
|
fs.writeFileSync(path.join(output, 'package.json'), JSON.stringify(pkg, null, 2))
|
package/converter/src/scanner.ts
CHANGED
|
@@ -23,7 +23,7 @@ export function scan(dir: string): ScanResult {
|
|
|
23
23
|
const apis: string[] = []
|
|
24
24
|
const relative = path.relative(dir, filePath)
|
|
25
25
|
|
|
26
|
-
if (content.includes("from 'vscode'") || content.includes('from "vscode"') || content.includes('require("vscode")')) {
|
|
26
|
+
if (content.includes("from 'vscode'") || content.includes('from "vscode"') || content.includes('require("vscode")') || content.includes("require('vscode')")) {
|
|
27
27
|
apis.push('vscode')
|
|
28
28
|
}
|
|
29
29
|
|
|
@@ -3,6 +3,7 @@ import { languageClientGenerator } from './language-client.js'
|
|
|
3
3
|
import { sourceGenerator } from './source.js'
|
|
4
4
|
import { bridgeGenerator } from './bridge.js'
|
|
5
5
|
import { markUnsupportedGenerator } from './mark-unsupported.js'
|
|
6
|
+
import { snippetsGenerator } from './snippets.js'
|
|
6
7
|
|
|
7
8
|
const REGISTRY: Record<string, StepGenerator> = {}
|
|
8
9
|
|
|
@@ -27,3 +28,4 @@ registerGenerator(languageClientGenerator)
|
|
|
27
28
|
registerGenerator(sourceGenerator)
|
|
28
29
|
registerGenerator(bridgeGenerator)
|
|
29
30
|
registerGenerator(markUnsupportedGenerator)
|
|
31
|
+
registerGenerator(snippetsGenerator)
|
|
@@ -108,7 +108,7 @@ ${ls.verbose ? ` console.log('[${escapeStr(id)}] creating LanguageClient')\n`
|
|
|
108
108
|
{
|
|
109
109
|
documentSelector: ${docSelectorCode},
|
|
110
110
|
outputChannelName: '${escapeStr(description)}',
|
|
111
|
-
${ls.initializationOptions ? `initializationOptions: ${ls.initializationOptions},` : ''}
|
|
111
|
+
${ls.initializationOptions ? `initializationOptions: ${ls.initializationOptions.replace(/`/g, '\\`').replace(/\$\{/g, '\\${')},` : ''}
|
|
112
112
|
},
|
|
113
113
|
)
|
|
114
114
|
context.subscriptions.push({ dispose: () => c.stop() })
|
|
@@ -117,23 +117,27 @@ ${ls.verbose ? ` console.log('[${escapeStr(id)}] creating LanguageClient')\n`
|
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
${ls.verbose ? ` console.log('[${escapeStr(id)}] registering LanguageClient')\n` : ''}\
|
|
120
|
-
let
|
|
120
|
+
let clients: LanguageClient[]
|
|
121
121
|
if (${multiRoot ? 'workspace.workspaceFolders && workspace.workspaceFolders.length > 1' : 'false'}) {
|
|
122
122
|
${ls.verbose ? ` console.log('[${escapeStr(id)}] multiRoot mode')\n` : ''}\
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
123
|
+
clients = workspace.workspaceFolders.map(folder => {
|
|
124
|
+
const c = createClient()
|
|
125
|
+
c.start()
|
|
126
|
+
return c
|
|
127
|
+
})
|
|
127
128
|
} else {
|
|
128
|
-
|
|
129
|
+
const c = createClient()
|
|
129
130
|
${ls.verbose ? ` console.log('[${escapeStr(id)}] starting client')\n` : ''}\
|
|
130
|
-
|
|
131
|
+
c.start()
|
|
132
|
+
clients = [c]
|
|
131
133
|
}
|
|
132
134
|
|
|
133
135
|
context.subscriptions.push(
|
|
134
136
|
commands.registerCommand('${escapeStr(pluginName)}.restart', async () => {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
+
for (const c of clients) {
|
|
138
|
+
await c.stop()
|
|
139
|
+
await c.start()
|
|
140
|
+
}
|
|
137
141
|
}),
|
|
138
142
|
)
|
|
139
143
|
} catch (e: any) {
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import * as fs from 'fs'
|
|
2
|
+
import * as path from 'path'
|
|
3
|
+
import { execFileSync } from 'child_process'
|
|
4
|
+
import { StepGenerator, StepContext, SnippetsStep, StepResult } from '../types.js'
|
|
5
|
+
|
|
6
|
+
export const snippetsGenerator: StepGenerator = {
|
|
7
|
+
type: 'snippets',
|
|
8
|
+
|
|
9
|
+
generate(ctx: StepContext, step: any): StepResult {
|
|
10
|
+
const ss = step as SnippetsStep
|
|
11
|
+
const { input, output, origPkg, verbose } = ctx
|
|
12
|
+
|
|
13
|
+
const contributedSnippets: Array<{ language: string; path: string }> =
|
|
14
|
+
origPkg.contributes?.snippets || []
|
|
15
|
+
|
|
16
|
+
if (contributedSnippets.length === 0 && !ss.languages) {
|
|
17
|
+
throw new Error('snippets step: source package.json has no contributes.snippets, and no languages specified in step config')
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Collect unique (sourcePath → [languages]) mappings
|
|
21
|
+
const fileToLanguages = new Map<string, string[]>()
|
|
22
|
+
if (ss.languages) {
|
|
23
|
+
for (const lang of ss.languages) {
|
|
24
|
+
const entry = contributedSnippets.find(s => s.language === lang)
|
|
25
|
+
if (entry) {
|
|
26
|
+
const langs = fileToLanguages.get(entry.path) || []
|
|
27
|
+
langs.push(lang)
|
|
28
|
+
fileToLanguages.set(entry.path, langs)
|
|
29
|
+
} else {
|
|
30
|
+
const defaultPath = `./snippets/${lang}.json`
|
|
31
|
+
const fp = path.join(input, defaultPath)
|
|
32
|
+
if (fs.existsSync(fp)) {
|
|
33
|
+
const langs = fileToLanguages.get(defaultPath) || []
|
|
34
|
+
langs.push(lang)
|
|
35
|
+
fileToLanguages.set(defaultPath, langs)
|
|
36
|
+
} else if (verbose) {
|
|
37
|
+
console.warn(` snippets: no snippet file found for language "${lang}", skipping`)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
} else {
|
|
42
|
+
for (const s of contributedSnippets) {
|
|
43
|
+
const langs = fileToLanguages.get(s.path) || []
|
|
44
|
+
langs.push(s.language)
|
|
45
|
+
fileToLanguages.set(s.path, langs)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (fileToLanguages.size === 0) {
|
|
50
|
+
throw new Error('snippets step: no snippet files found to copy')
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Create output directories and copy files to original relative paths
|
|
54
|
+
const srcDir = path.join(output, 'src')
|
|
55
|
+
fs.mkdirSync(srcDir, { recursive: true })
|
|
56
|
+
|
|
57
|
+
const generatedFiles: Array<{ path: string; content: string }> = []
|
|
58
|
+
let copiedCount = 0
|
|
59
|
+
const allLanguages: string[] = []
|
|
60
|
+
|
|
61
|
+
for (const [sourceRelPath, languages] of fileToLanguages) {
|
|
62
|
+
const sourceFile = path.join(input, sourceRelPath)
|
|
63
|
+
if (!fs.existsSync(sourceFile)) {
|
|
64
|
+
if (verbose) console.warn(` snippets: source file not found: ${sourceFile}, skipping`)
|
|
65
|
+
continue
|
|
66
|
+
}
|
|
67
|
+
const dest = path.join(output, sourceRelPath)
|
|
68
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true })
|
|
69
|
+
fs.copyFileSync(sourceFile, dest)
|
|
70
|
+
copiedCount++
|
|
71
|
+
allLanguages.push(...languages)
|
|
72
|
+
if (verbose) console.log(` snippets: copied ${sourceRelPath} (${languages.join(', ')})`)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (copiedCount === 0 && ss.build) {
|
|
76
|
+
// Run build script to generate snippet files (e.g. node merge.js)
|
|
77
|
+
if (verbose) console.log(` snippets: running build: ${ss.build}`)
|
|
78
|
+
execFileSync('npm', ['install', '--legacy-peer-deps'], { cwd: input, stdio: verbose ? 'inherit' : 'pipe' })
|
|
79
|
+
const [cmd, ...args] = ss.build.split(' ')
|
|
80
|
+
execFileSync(cmd, args, { cwd: input, stdio: verbose ? 'inherit' : 'pipe' })
|
|
81
|
+
// Retry copying
|
|
82
|
+
for (const [sourceRelPath, languages] of fileToLanguages) {
|
|
83
|
+
const sourceFile = path.join(input, sourceRelPath)
|
|
84
|
+
if (fs.existsSync(sourceFile)) {
|
|
85
|
+
const dest = path.join(output, sourceRelPath)
|
|
86
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true })
|
|
87
|
+
fs.copyFileSync(sourceFile, dest)
|
|
88
|
+
copiedCount++
|
|
89
|
+
allLanguages.push(...languages)
|
|
90
|
+
if (verbose) console.log(` snippets: copied ${sourceRelPath} (${languages.join(', ')})`)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (copiedCount === 0) {
|
|
96
|
+
throw new Error('snippets step: no snippet files were copied')
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Generate empty src/index.ts
|
|
100
|
+
const indexContent = `\
|
|
101
|
+
import { ExtensionContext } from 'coc.nvim'
|
|
102
|
+
|
|
103
|
+
export function activate(context: ExtensionContext): void {
|
|
104
|
+
// coc-snippets discovers snippets via package.json's contributes.snippets
|
|
105
|
+
}
|
|
106
|
+
`
|
|
107
|
+
generatedFiles.push({ path: 'src/index.ts', content: indexContent })
|
|
108
|
+
|
|
109
|
+
const activationEvents = [...new Set(allLanguages)].map(l => `onLanguage:${l}`)
|
|
110
|
+
|
|
111
|
+
if (verbose) {
|
|
112
|
+
console.log(` snippets: ${copiedCount} files, ${new Set(allLanguages).size} languages`)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
generatedFiles,
|
|
117
|
+
entryPoint: 'src/index.ts',
|
|
118
|
+
keepDeps: {},
|
|
119
|
+
activationEvents,
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
}
|
|
@@ -20,16 +20,14 @@ export const transformClassToFactory: Transform = (ctx) => {
|
|
|
20
20
|
|
|
21
21
|
// AST approach: try to replace via ts-morph
|
|
22
22
|
const nodes = file.getDescendantsOfKind(SyntaxKind.NewExpression)
|
|
23
|
-
|
|
23
|
+
// Sort by position descending so inner nodes are processed first
|
|
24
|
+
nodes.sort((a, b) => b.getPos() - a.getPos())
|
|
24
25
|
for (const expr of nodes) {
|
|
25
26
|
const text = expr.getText()
|
|
26
27
|
const m = text.match(/^new\s+(\w+)\(/)
|
|
27
28
|
if (!m || !FACTORY_TYPES.has(m[1])) continue
|
|
28
29
|
const args = text.slice(m[0].length, -1)
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
for (const { node, text } of astReplacements) {
|
|
32
|
-
try { node.replaceWithText(text) } catch {}
|
|
30
|
+
try { expr.replaceWithText(`${m[1]}.create(${args})`) } catch {}
|
|
33
31
|
}
|
|
34
32
|
|
|
35
33
|
// Text fallback: catch remaining new Xxx() that AST might have missed
|
|
@@ -44,14 +44,36 @@ export const transformProviderRegister: Transform = (ctx) => {
|
|
|
44
44
|
`registerCompletionItemProvider('${pluginName}', '${shortcut}', `
|
|
45
45
|
)
|
|
46
46
|
// Wrap the last argument in an array if it's a string (trigger chars)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
47
|
+
// Use paren-balancing to handle nested parentheses in arguments
|
|
48
|
+
// Build result by iterating over all matches, replacing each full call
|
|
49
|
+
const providerRe = /registerCompletionItemProvider\(/g
|
|
50
|
+
let result = ''
|
|
51
|
+
let lastIdx = 0
|
|
52
|
+
let m: RegExpExecArray | null
|
|
53
|
+
while ((m = providerRe.exec(content)) !== null) {
|
|
54
|
+
const start = m.index
|
|
55
|
+
let depth = 1
|
|
56
|
+
let i = start + m[0].length
|
|
57
|
+
while (i < content.length && depth > 0) {
|
|
58
|
+
if (content[i] === '(') depth++
|
|
59
|
+
else if (content[i] === ')') depth--
|
|
60
|
+
i++
|
|
61
|
+
}
|
|
62
|
+
const end = i
|
|
63
|
+
const fullCall = content.slice(start, end)
|
|
64
|
+
const lastStrMatch = fullCall.match(/,?\s*'([^']+)'\s*\)$/)
|
|
65
|
+
const lastDblMatch = fullCall.match(/,?\s*"([^"]+)"\s*\)$/)
|
|
66
|
+
let replacement = fullCall
|
|
67
|
+
if (lastStrMatch) {
|
|
68
|
+
replacement = fullCall.slice(0, fullCall.length - lastStrMatch[0].length) + ', ["' + lastStrMatch[1] + '"])'
|
|
69
|
+
} else if (lastDblMatch) {
|
|
70
|
+
replacement = fullCall.slice(0, fullCall.length - lastDblMatch[0].length) + ', ["' + lastDblMatch[1] + '"])'
|
|
71
|
+
}
|
|
72
|
+
result += content.slice(lastIdx, start) + replacement
|
|
73
|
+
lastIdx = end
|
|
74
|
+
}
|
|
75
|
+
result += content.slice(lastIdx)
|
|
76
|
+
content = result
|
|
55
77
|
changed = true
|
|
56
78
|
}
|
|
57
79
|
|
package/converter/src/types.ts
CHANGED
|
@@ -73,7 +73,15 @@ export interface MarkUnsupportedStep {
|
|
|
73
73
|
verbose?: boolean
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
export
|
|
76
|
+
export interface SnippetsStep {
|
|
77
|
+
type: 'snippets'
|
|
78
|
+
/** Optional: override languages to generate (default: read from source package.json's contributes.snippets) */
|
|
79
|
+
languages?: string[]
|
|
80
|
+
/** Optional: build command to run in source dir before collecting snippet files (e.g. "node merge.js") */
|
|
81
|
+
build?: string
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export type ConvertStep = LanguageClientStep | SourceStep | BridgeStep | MarkUnsupportedStep | SnippetsStep
|
|
77
85
|
|
|
78
86
|
// ---- Step execution ----
|
|
79
87
|
|