mirror of
https://github.com/microsoft/monaco-editor.git
synced 2025-12-22 19:42:56 +01:00
Merge branch 'main' into fix-memory-leak-webpack-plugin
This commit is contained in:
commit
956a90ae86
283 changed files with 220819 additions and 193076 deletions
8
.github/workflows/ci.yml
vendored
8
.github/workflows/ci.yml
vendored
|
|
@ -74,13 +74,7 @@ jobs:
|
||||||
run: npm run compile --prefix webpack-plugin
|
run: npm run compile --prefix webpack-plugin
|
||||||
|
|
||||||
- name: Package using webpack plugin
|
- name: Package using webpack plugin
|
||||||
run: npm run package-for-smoketest-webpack
|
run: npm run package-for-smoketest
|
||||||
|
|
||||||
- name: Package using esbuild
|
|
||||||
run: npm run package-for-smoketest-esbuild
|
|
||||||
|
|
||||||
- name: Package using vite
|
|
||||||
run: npm run package-for-smoketest-vite
|
|
||||||
|
|
||||||
# - name: Package using parcel
|
# - name: Package using parcel
|
||||||
# run: npm run package-for-smoketest-parcel --prefix test/smoke/parcel
|
# run: npm run package-for-smoketest-parcel --prefix test/smoke/parcel
|
||||||
|
|
|
||||||
6
.github/workflows/website.yml
vendored
6
.github/workflows/website.yml
vendored
|
|
@ -44,15 +44,15 @@ jobs:
|
||||||
|
|
||||||
- name: Install website node modules
|
- name: Install website node modules
|
||||||
working-directory: website
|
working-directory: website
|
||||||
run: yarn install --frozen-lockfile
|
run: npm ci
|
||||||
|
|
||||||
- name: Install most recent version of monaco-editor
|
- name: Install most recent version of monaco-editor
|
||||||
working-directory: website
|
working-directory: website
|
||||||
run: yarn add monaco-editor
|
run: npm install monaco-editor
|
||||||
|
|
||||||
- name: Build website
|
- name: Build website
|
||||||
working-directory: website
|
working-directory: website
|
||||||
run: yarn run build
|
run: npm run build
|
||||||
|
|
||||||
- name: Setup Pages
|
- name: Setup Pages
|
||||||
uses: actions/configure-pages@v5
|
uses: actions/configure-pages@v5
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,2 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
. "$(dirname "$0")/_/husky.sh"
|
. "$(dirname "$0")/_/husky.sh"
|
||||||
|
|
||||||
npm run pretty-quick
|
|
||||||
|
|
|
||||||
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
|
@ -12,5 +12,6 @@
|
||||||
"typescript.tsdk": "./node_modules/typescript/lib",
|
"typescript.tsdk": "./node_modules/typescript/lib",
|
||||||
"git.branchProtection": ["main", "release/*"],
|
"git.branchProtection": ["main", "release/*"],
|
||||||
"git.branchProtectionPrompt": "alwaysCommitToNewBranch",
|
"git.branchProtectionPrompt": "alwaysCommitToNewBranch",
|
||||||
"git.branchRandomName.enable": true
|
"git.branchRandomName.enable": true,
|
||||||
|
"editor.formatOnSave": true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,10 @@
|
||||||
# Monaco Editor Changelog
|
# Monaco Editor Changelog
|
||||||
|
|
||||||
|
## [0.54.0]
|
||||||
|
|
||||||
|
- Adds option `editor.mouseMiddleClickAction`
|
||||||
|
- Various bug fixes
|
||||||
|
|
||||||
## [0.53.0]
|
## [0.53.0]
|
||||||
|
|
||||||
- :warning: This release deprecates the AMD build and ships with significant changes of the AMD build. The AMD build will still be shipped for a while, but we don't offer support for it anymore. Please migrate to the ESM build.
|
- :warning: This release deprecates the AMD build and ships with significant changes of the AMD build. The AMD build will still be shipped for a while, but we don't offer support for it anymore. Please migrate to the ESM build.
|
||||||
|
|
|
||||||
|
|
@ -4,4 +4,5 @@ export async function buildAmdMinDev() {
|
||||||
const rootPath = __dirname;
|
const rootPath = __dirname;
|
||||||
await run('npx vite build --mode development', { cwd: rootPath });
|
await run('npx vite build --mode development', { cwd: rootPath });
|
||||||
await run('npx vite build', { cwd: rootPath });
|
await run('npx vite build', { cwd: rootPath });
|
||||||
|
await run('npx rollup -c rollup-types.config.mjs', { cwd: rootPath });
|
||||||
}
|
}
|
||||||
|
|
|
||||||
66
build/amd/rollup-types.config.mjs
Normal file
66
build/amd/rollup-types.config.mjs
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
// @ts-check
|
||||||
|
|
||||||
|
import nodeResolve from '@rollup/plugin-node-resolve';
|
||||||
|
import { join } from 'path';
|
||||||
|
import { defineConfig } from 'rollup';
|
||||||
|
import { dts } from 'rollup-plugin-dts';
|
||||||
|
|
||||||
|
const root = join(import.meta.dirname, '../../');
|
||||||
|
const outDir = join(import.meta.dirname, './out');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} filePath
|
||||||
|
* @param {string} newExt
|
||||||
|
*/
|
||||||
|
function changeExt(filePath, newExt) {
|
||||||
|
const idx = filePath.lastIndexOf('.');
|
||||||
|
if (idx === -1) {
|
||||||
|
return filePath + newExt;
|
||||||
|
} else {
|
||||||
|
return filePath.substring(0, idx) + newExt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mappedPaths = {
|
||||||
|
[join(root, 'node_modules/monaco-editor-core/esm/')]: '.',
|
||||||
|
[join(root, 'node_modules/')]: 'external/',
|
||||||
|
[join(root, 'src/')]: 'vs/'
|
||||||
|
};
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
input: {
|
||||||
|
types: join(import.meta.dirname, './src/types.ts')
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
dir: outDir,
|
||||||
|
format: 'es',
|
||||||
|
preserveModules: false,
|
||||||
|
entryFileNames: function (chunkInfo) {
|
||||||
|
const moduleId = chunkInfo.facadeModuleId;
|
||||||
|
if (moduleId) {
|
||||||
|
for (const [key, val] of Object.entries(mappedPaths)) {
|
||||||
|
if (moduleId.startsWith(key)) {
|
||||||
|
const relativePath = moduleId.substring(key.length);
|
||||||
|
return changeExt(join(val, relativePath), '.d.ts');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return '[name].d.ts';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
external: [/.*\.css/],
|
||||||
|
plugins: [
|
||||||
|
nodeResolve(),
|
||||||
|
dts({
|
||||||
|
compilerOptions: {
|
||||||
|
stripInternal: true
|
||||||
|
},
|
||||||
|
includeExternal: ['monaco-editor-core', '@vscode/monaco-lsp-client']
|
||||||
|
})
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
@ -1,10 +1,30 @@
|
||||||
|
/// @ts-ignore
|
||||||
import * as require from 'require';
|
import * as require from 'require';
|
||||||
|
|
||||||
|
if (typeof (globalThis as any).require !== 'undefined' && typeof (globalThis as any).require.config === 'function') {
|
||||||
|
(globalThis as any).require.config({
|
||||||
|
ignoreDuplicateModules: [
|
||||||
|
'vscode-languageserver-types',
|
||||||
|
'vscode-languageserver-types/main',
|
||||||
|
'vscode-languageserver-textdocument',
|
||||||
|
'vscode-languageserver-textdocument/main',
|
||||||
|
'vscode-nls',
|
||||||
|
'vscode-nls/vscode-nls',
|
||||||
|
'jsonc-parser',
|
||||||
|
'jsonc-parser/main',
|
||||||
|
'vscode-uri',
|
||||||
|
'vscode-uri/index',
|
||||||
|
'vs/basic-languages/typescript/typescript'
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
self.MonacoEnvironment = {
|
self.MonacoEnvironment = {
|
||||||
getWorker: function (_moduleId, label) {
|
getWorker: function (_moduleId, label) {
|
||||||
if (label === 'json') {
|
if (label === 'json') {
|
||||||
return new Worker(
|
return new Worker(
|
||||||
getWorkerBootstrapUrl(
|
getWorkerBootstrapUrl(
|
||||||
|
/// @ts-ignore
|
||||||
new URL('../../../src/language/json/json.worker.ts?worker', import.meta.url)
|
new URL('../../../src/language/json/json.worker.ts?worker', import.meta.url)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
@ -12,6 +32,7 @@ self.MonacoEnvironment = {
|
||||||
if (label === 'css' || label === 'scss' || label === 'less') {
|
if (label === 'css' || label === 'scss' || label === 'less') {
|
||||||
return new Worker(
|
return new Worker(
|
||||||
getWorkerBootstrapUrl(
|
getWorkerBootstrapUrl(
|
||||||
|
/// @ts-ignore
|
||||||
new URL('../../../src/language/css/css.worker.ts?worker', import.meta.url)
|
new URL('../../../src/language/css/css.worker.ts?worker', import.meta.url)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
@ -19,6 +40,7 @@ self.MonacoEnvironment = {
|
||||||
if (label === 'html' || label === 'handlebars' || label === 'razor') {
|
if (label === 'html' || label === 'handlebars' || label === 'razor') {
|
||||||
return new Worker(
|
return new Worker(
|
||||||
getWorkerBootstrapUrl(
|
getWorkerBootstrapUrl(
|
||||||
|
/// @ts-ignore
|
||||||
new URL('../../../src/language/html/html.worker.ts?worker', import.meta.url)
|
new URL('../../../src/language/html/html.worker.ts?worker', import.meta.url)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
@ -26,17 +48,22 @@ self.MonacoEnvironment = {
|
||||||
if (label === 'typescript' || label === 'javascript') {
|
if (label === 'typescript' || label === 'javascript') {
|
||||||
return new Worker(
|
return new Worker(
|
||||||
getWorkerBootstrapUrl(
|
getWorkerBootstrapUrl(
|
||||||
|
/// @ts-ignore
|
||||||
new URL('../../../src/language/typescript/ts.worker.ts?worker', import.meta.url)
|
new URL('../../../src/language/typescript/ts.worker.ts?worker', import.meta.url)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return new Worker(
|
return new Worker(
|
||||||
|
/// @ts-ignore
|
||||||
getWorkerBootstrapUrl(new URL('../../../src/editor/editor.worker.ts?worker', import.meta.url))
|
getWorkerBootstrapUrl(new URL('../../../src/editor/editor.worker.ts?worker', import.meta.url))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function getWorkerBootstrapUrl(workerScriptUrl) {
|
function getWorkerBootstrapUrl(workerScriptUrl: string | URL) {
|
||||||
|
if (typeof workerScriptUrl !== 'string') {
|
||||||
|
workerScriptUrl = workerScriptUrl.toString();
|
||||||
|
}
|
||||||
const blob = new Blob(
|
const blob = new Blob(
|
||||||
[
|
[
|
||||||
[
|
[
|
||||||
|
|
@ -54,11 +81,10 @@ function getWorkerBootstrapUrl(workerScriptUrl) {
|
||||||
}
|
}
|
||||||
|
|
||||||
import 'vs/nls.messages-loader!';
|
import 'vs/nls.messages-loader!';
|
||||||
import '../../../src/basic-languages/monaco.contribution';
|
import * as monaco from '../../../src/editor/editor.main';
|
||||||
import '../../../src/language/css/monaco.contribution';
|
export * from '../../../src/editor/editor.main';
|
||||||
import '../../../src/language/html/monaco.contribution';
|
|
||||||
import '../../../src/language/json/monaco.contribution';
|
globalThis.monaco = monaco;
|
||||||
import '../../../src/language/typescript/monaco.contribution';
|
|
||||||
|
|
||||||
const styleSheetUrl = require.toUrl('vs/editor/editor.main.css');
|
const styleSheetUrl = require.toUrl('vs/editor/editor.main.css');
|
||||||
|
|
||||||
|
|
@ -66,5 +92,3 @@ const link = document.createElement('link');
|
||||||
link.rel = 'stylesheet';
|
link.rel = 'stylesheet';
|
||||||
link.href = styleSheetUrl;
|
link.href = styleSheetUrl;
|
||||||
document.head.appendChild(link);
|
document.head.appendChild(link);
|
||||||
|
|
||||||
export * as m from 'monaco-editor-core';
|
|
||||||
3
build/amd/src/types.ts
Normal file
3
build/amd/src/types.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
import * as m from './editor.main';
|
||||||
|
|
||||||
|
export { m };
|
||||||
|
|
@ -21,8 +21,8 @@ export default defineConfig(async (args) => {
|
||||||
/** @type {import('vite').UserConfig} */
|
/** @type {import('vite').UserConfig} */
|
||||||
return {
|
return {
|
||||||
base: './',
|
base: './',
|
||||||
define: {
|
resolve: {
|
||||||
AMD: false
|
dedupe: ['monaco-editor-core']
|
||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
lib: {
|
lib: {
|
||||||
|
|
@ -30,7 +30,7 @@ export default defineConfig(async (args) => {
|
||||||
entry: {
|
entry: {
|
||||||
...nlsEntries,
|
...nlsEntries,
|
||||||
'nls.messages-loader': resolve(__dirname, 'src/nls.messages-loader.js'),
|
'nls.messages-loader': resolve(__dirname, 'src/nls.messages-loader.js'),
|
||||||
'editor/editor.main': resolve(__dirname, 'src/editor.main.js'),
|
'editor/editor.main': resolve(__dirname, 'src/editor.main.ts'),
|
||||||
'basic-languages/monaco.contribution': resolve(
|
'basic-languages/monaco.contribution': resolve(
|
||||||
__dirname,
|
__dirname,
|
||||||
'../../src/basic-languages/monaco.contribution.ts'
|
'../../src/basic-languages/monaco.contribution.ts'
|
||||||
|
|
|
||||||
|
|
@ -1,127 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------------------------
|
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
||||||
*--------------------------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
import glob from 'glob';
|
|
||||||
import { runTsc, massageAndCopyDts, buildESM } from './utils';
|
|
||||||
import { removeDir } from './fs';
|
|
||||||
|
|
||||||
removeDir(`out/languages`);
|
|
||||||
|
|
||||||
runTsc(`src/tsconfig.json`);
|
|
||||||
|
|
||||||
//#region Type Defintion
|
|
||||||
|
|
||||||
massageAndCopyDts(
|
|
||||||
`out/languages/tsc/language/css/monaco.contribution.d.ts`,
|
|
||||||
`out/languages/bundled/css.d.ts`,
|
|
||||||
'monaco.languages.css'
|
|
||||||
);
|
|
||||||
massageAndCopyDts(
|
|
||||||
`out/languages/tsc/language/html/monaco.contribution.d.ts`,
|
|
||||||
`out/languages/bundled/html.d.ts`,
|
|
||||||
'monaco.languages.html'
|
|
||||||
);
|
|
||||||
massageAndCopyDts(
|
|
||||||
`out/languages/tsc/language/json/monaco.contribution.d.ts`,
|
|
||||||
`out/languages/bundled/json.d.ts`,
|
|
||||||
'monaco.languages.json'
|
|
||||||
);
|
|
||||||
massageAndCopyDts(
|
|
||||||
`out/languages/tsc/language/typescript/monaco.contribution.d.ts`,
|
|
||||||
`out/languages/bundled/typescript.d.ts`,
|
|
||||||
'monaco.languages.typescript'
|
|
||||||
);
|
|
||||||
|
|
||||||
//#endregion
|
|
||||||
|
|
||||||
//#region css
|
|
||||||
|
|
||||||
buildESM({
|
|
||||||
base: 'language/css',
|
|
||||||
entryPoints: [
|
|
||||||
'src/language/css/monaco.contribution.ts',
|
|
||||||
'src/language/css/cssMode.ts',
|
|
||||||
'src/language/css/css.worker.ts'
|
|
||||||
],
|
|
||||||
external: ['monaco-editor-core', '*/cssMode', '*/monaco.contribution']
|
|
||||||
});
|
|
||||||
|
|
||||||
//#endregion
|
|
||||||
|
|
||||||
//#region html
|
|
||||||
|
|
||||||
buildESM({
|
|
||||||
base: 'language/html',
|
|
||||||
entryPoints: [
|
|
||||||
'src/language/html/monaco.contribution.ts',
|
|
||||||
'src/language/html/htmlMode.ts',
|
|
||||||
'src/language/html/html.worker.ts'
|
|
||||||
],
|
|
||||||
external: ['monaco-editor-core', '*/htmlMode', '*/monaco.contribution']
|
|
||||||
});
|
|
||||||
|
|
||||||
//#endregion
|
|
||||||
|
|
||||||
//#region json
|
|
||||||
|
|
||||||
buildESM({
|
|
||||||
base: 'language/json',
|
|
||||||
entryPoints: [
|
|
||||||
'src/language/json/monaco.contribution.ts',
|
|
||||||
'src/language/json/jsonMode.ts',
|
|
||||||
'src/language/json/json.worker.ts'
|
|
||||||
],
|
|
||||||
external: ['monaco-editor-core', '*/jsonMode', '*/monaco.contribution']
|
|
||||||
});
|
|
||||||
|
|
||||||
//#endregion
|
|
||||||
|
|
||||||
//#region typescript
|
|
||||||
|
|
||||||
buildESM({
|
|
||||||
base: 'language/typescript',
|
|
||||||
entryPoints: [
|
|
||||||
'src/language/typescript/monaco.contribution.ts',
|
|
||||||
'src/language/typescript/tsMode.ts',
|
|
||||||
'src/language/typescript/ts.worker.ts'
|
|
||||||
],
|
|
||||||
external: ['monaco-editor-core', '*/tsMode', '*/monaco.contribution']
|
|
||||||
});
|
|
||||||
|
|
||||||
//#endregion
|
|
||||||
|
|
||||||
//#region basic-languages
|
|
||||||
|
|
||||||
glob('../src/basic-languages/*/*.contribution.ts', { cwd: __dirname }, function (err, files) {
|
|
||||||
if (err) {
|
|
||||||
console.error(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const languages = files.map((file) => file.split('/')[3]);
|
|
||||||
|
|
||||||
// ESM
|
|
||||||
{
|
|
||||||
/** @type {string[]} */
|
|
||||||
const entryPoints = [
|
|
||||||
'src/basic-languages/monaco.contribution.ts',
|
|
||||||
'src/basic-languages/_.contribution.ts'
|
|
||||||
];
|
|
||||||
const external = ['monaco-editor-core', '*/_.contribution'];
|
|
||||||
for (const language of languages) {
|
|
||||||
entryPoints.push(`src/basic-languages/${language}/${language}.contribution.ts`);
|
|
||||||
entryPoints.push(`src/basic-languages/${language}/${language}.ts`);
|
|
||||||
external.push(`*/${language}.contribution`);
|
|
||||||
external.push(`*/${language}`);
|
|
||||||
}
|
|
||||||
buildESM({
|
|
||||||
base: 'basic-languages',
|
|
||||||
entryPoints,
|
|
||||||
external
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//#endregion
|
|
||||||
|
|
@ -5,38 +5,30 @@
|
||||||
|
|
||||||
import path = require('path');
|
import path = require('path');
|
||||||
import fs = require('fs');
|
import fs = require('fs');
|
||||||
import {
|
import { REPO_ROOT, readFiles, writeFiles } from '../build/utils';
|
||||||
REPO_ROOT,
|
import { generateEsmMetadataJsAndDTs } from './releaseMetadata';
|
||||||
readFiles,
|
import { buildESM } from './esm/build.script';
|
||||||
writeFiles,
|
import { removeDir } from './fs';
|
||||||
IFile,
|
|
||||||
readFile,
|
|
||||||
build,
|
|
||||||
bundledFileHeader
|
|
||||||
} from '../build/utils';
|
|
||||||
import { removeDir } from '../build/fs';
|
|
||||||
import { generateMetadata } from './releaseMetadata';
|
|
||||||
import { buildAmdMinDev } from './amd/build.script';
|
import { buildAmdMinDev } from './amd/build.script';
|
||||||
import ts = require('typescript');
|
|
||||||
|
|
||||||
removeDir(`out/monaco-editor`);
|
async function run() {
|
||||||
|
removeDir(`out/monaco-editor`);
|
||||||
|
|
||||||
buildAmdMinDev();
|
await buildESM();
|
||||||
|
await buildAmdMinDev();
|
||||||
|
|
||||||
// esm folder
|
// copy types.d.ts from build/amd/out/ to out/monaco-editor/monaco.d.ts (and append `declare global { export import monaco = editor_main; }`)
|
||||||
ESM_release();
|
(() => {
|
||||||
|
let contents = fs.readFileSync('build/amd/out/types.d.ts', { encoding: 'utf8' });
|
||||||
|
contents += '\n\ndeclare global { export import monaco = editor_main; }\n';
|
||||||
|
fs.writeFileSync('out/monaco-editor/monaco.d.ts', contents);
|
||||||
|
})();
|
||||||
|
|
||||||
// monaco.d.ts, editor.api.d.ts
|
createThirdPartyNoticesDotTxt();
|
||||||
releaseDTS();
|
generateEsmMetadataJsAndDTs();
|
||||||
|
|
||||||
// ThirdPartyNotices.txt
|
// package.json
|
||||||
releaseThirdPartyNotices();
|
(() => {
|
||||||
|
|
||||||
// esm/metadata.d.ts, esm/metadata.js
|
|
||||||
generateMetadata();
|
|
||||||
|
|
||||||
// package.json
|
|
||||||
(() => {
|
|
||||||
const packageJSON = readFiles('package.json', { base: '' })[0];
|
const packageJSON = readFiles('package.json', { base: '' })[0];
|
||||||
const json = JSON.parse(packageJSON.contents.toString());
|
const json = JSON.parse(packageJSON.contents.toString());
|
||||||
|
|
||||||
|
|
@ -45,9 +37,9 @@ generateMetadata();
|
||||||
|
|
||||||
packageJSON.contents = Buffer.from(JSON.stringify(json, null, ' '));
|
packageJSON.contents = Buffer.from(JSON.stringify(json, null, ' '));
|
||||||
writeFiles([packageJSON], `out/monaco-editor`);
|
writeFiles([packageJSON], `out/monaco-editor`);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
(() => {
|
(() => {
|
||||||
/** @type {IFile[]} */
|
/** @type {IFile[]} */
|
||||||
let otherFiles = [];
|
let otherFiles = [];
|
||||||
|
|
||||||
|
|
@ -60,306 +52,14 @@ generateMetadata();
|
||||||
);
|
);
|
||||||
|
|
||||||
writeFiles(otherFiles, `out/monaco-editor`);
|
writeFiles(otherFiles, `out/monaco-editor`);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
function ESM_release() {
|
|
||||||
const coreFiles = readFiles(`node_modules/monaco-editor-core/esm/**/*`, {
|
|
||||||
base: 'node_modules/monaco-editor-core/esm',
|
|
||||||
// we will create our own editor.api.d.ts which also contains the plugins API
|
|
||||||
ignore: ['node_modules/monaco-editor-core/esm/vs/editor/editor.api.d.ts']
|
|
||||||
});
|
|
||||||
ESM_addImportSuffix(coreFiles);
|
|
||||||
ESM_addPluginContribs(coreFiles);
|
|
||||||
writeFiles(coreFiles, `out/monaco-editor/esm`);
|
|
||||||
|
|
||||||
ESM_releasePlugins();
|
|
||||||
|
|
||||||
build({
|
|
||||||
entryPoints: ['src/editor/editor.main.ts', 'src/editor/editor.worker.ts'],
|
|
||||||
bundle: true,
|
|
||||||
target: 'esnext',
|
|
||||||
format: 'esm',
|
|
||||||
drop: ['debugger'],
|
|
||||||
define: {
|
|
||||||
AMD: 'false'
|
|
||||||
},
|
|
||||||
banner: {
|
|
||||||
js: bundledFileHeader
|
|
||||||
},
|
|
||||||
external: ['./src/basic-languages/*', './edcore.main.js', './editor.worker.start'],
|
|
||||||
alias: {
|
|
||||||
'monaco-editor-core/esm/vs/editor/editor.worker.start': './editor.worker.start',
|
|
||||||
'monaco-editor-core': './edcore.main.js'
|
|
||||||
},
|
|
||||||
outbase: `src/`,
|
|
||||||
outdir: `out/monaco-editor/esm/vs/`,
|
|
||||||
plugins: [
|
|
||||||
{
|
|
||||||
name: 'example',
|
|
||||||
setup(build) {
|
|
||||||
build.onResolve({ filter: /\/language\/|\/basic-languages\// }, (args) => {
|
|
||||||
if (args.path.includes('monaco-editor-core')) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
return { external: true };
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Release a plugin to `esm`.
|
|
||||||
* Adds a dependency to 'vs/editor/editor.api' in contrib files in order for `monaco` to be defined.
|
|
||||||
* Rewrites imports for 'monaco-editor-core/**'
|
|
||||||
*/
|
|
||||||
function ESM_releasePlugins() {
|
|
||||||
const files = readFiles(`out/languages/bundled/esm/**/*`, { base: 'out/languages/bundled/esm/' });
|
|
||||||
|
|
||||||
for (const file of files) {
|
|
||||||
if (!/(\.js$)|(\.ts$)/.test(file.path)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let contents = file.contents.toString();
|
|
||||||
|
|
||||||
// WARNING: this only returns the first occurence of each imported file!
|
|
||||||
const info = ts.preProcessFile(contents);
|
|
||||||
for (let i = info.importedFiles.length - 1; i >= 0; i--) {
|
|
||||||
let importText = info.importedFiles[i].fileName;
|
|
||||||
const pos = info.importedFiles[i].pos;
|
|
||||||
const end = info.importedFiles[i].end;
|
|
||||||
|
|
||||||
if (!/(^\.\/)|(^\.\.\/)/.test(importText)) {
|
|
||||||
// non-relative import
|
|
||||||
if (!/^monaco-editor-core/.test(importText)) {
|
|
||||||
console.error(`Non-relative import for unknown module: ${importText} in ${file.path}`);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (importText === 'monaco-editor-core') {
|
|
||||||
importText = 'monaco-editor-core/esm/vs/editor/editor.api';
|
|
||||||
}
|
|
||||||
|
|
||||||
const importFilePath = importText.substring('monaco-editor-core/esm/'.length);
|
|
||||||
let relativePath = path
|
|
||||||
.relative(path.dirname(file.path), importFilePath)
|
|
||||||
.replace(/\\/g, '/');
|
|
||||||
if (!/(^\.\/)|(^\.\.\/)/.test(relativePath)) {
|
|
||||||
relativePath = './' + relativePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
contents = contents.substring(0, pos + 1) + relativePath + contents.substring(end + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
file.contents = Buffer.from(contents);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const file of files) {
|
|
||||||
if (!/monaco\.contribution\.js$/.test(file.path)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const apiFilePath = 'vs/editor/editor.api';
|
|
||||||
let relativePath = path.relative(path.dirname(file.path), apiFilePath).replace(/\\/g, '/');
|
|
||||||
if (!/(^\.\/)|(^\.\.\/)/.test(relativePath)) {
|
|
||||||
relativePath = './' + relativePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
let contents = file.contents.toString();
|
|
||||||
contents = `import '${relativePath}';\n` + contents;
|
|
||||||
file.contents = Buffer.from(contents);
|
|
||||||
}
|
|
||||||
|
|
||||||
ESM_addImportSuffix(files);
|
|
||||||
writeFiles(files, `out/monaco-editor/esm`);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds `.js` to all import statements.
|
|
||||||
*/
|
|
||||||
function ESM_addImportSuffix(files: IFile[]) {
|
|
||||||
for (const file of files) {
|
|
||||||
if (!/\.js$/.test(file.path)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let contents = file.contents.toString();
|
|
||||||
|
|
||||||
const info = ts.preProcessFile(contents);
|
|
||||||
for (let i = info.importedFiles.length - 1; i >= 0; i--) {
|
|
||||||
const importText = info.importedFiles[i].fileName;
|
|
||||||
const pos = info.importedFiles[i].pos;
|
|
||||||
const end = info.importedFiles[i].end;
|
|
||||||
|
|
||||||
if (/(\.css)|(\.js)$/.test(importText)) {
|
|
||||||
// A CSS import or an import already using .js
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
contents = contents.substring(0, pos + 1) + importText + '.js' + contents.substring(end + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
file.contents = Buffer.from(contents);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* - Rename esm/vs/editor/editor.main.js to esm/vs/editor/edcore.main.js
|
|
||||||
* - Create esm/vs/editor/editor.main.js that that stiches things together
|
|
||||||
*/
|
|
||||||
function ESM_addPluginContribs(files: IFile[]) {
|
|
||||||
for (const file of files) {
|
|
||||||
if (!/editor\.main\.js$/.test(file.path)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
file.path = file.path.replace(/editor\.main/, 'edcore.main');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Edit monaco.d.ts:
|
|
||||||
* - append monaco.d.ts from plugins
|
|
||||||
*/
|
|
||||||
function releaseDTS() {
|
|
||||||
const monacodts = readFiles('node_modules/monaco-editor-core/monaco.d.ts', {
|
|
||||||
base: 'node_modules/monaco-editor-core'
|
|
||||||
})[0];
|
|
||||||
|
|
||||||
let contents = monacodts.contents.toString();
|
|
||||||
|
|
||||||
const additionalDtsFiles: Record<string, string> = {
|
|
||||||
'out/languages/tsc/common/workers.d.ts': 'monaco.editor'
|
|
||||||
};
|
|
||||||
Object.entries(additionalDtsFiles).forEach(([filePath, namespace]) => {
|
|
||||||
try {
|
|
||||||
const dtsFile = readFile(filePath);
|
|
||||||
let dtsContent = dtsFile.contents.toString();
|
|
||||||
|
|
||||||
// Remove imports
|
|
||||||
dtsContent = dtsContent.replace(/import .*\n/gm, '');
|
|
||||||
dtsContent = dtsContent.replace(/export declare function/gm, 'export function');
|
|
||||||
|
|
||||||
// Wrap in namespace if specified
|
|
||||||
if (namespace) {
|
|
||||||
dtsContent = `declare namespace ${namespace} {\n${dtsContent
|
|
||||||
.split('\n')
|
|
||||||
.map((line) => (line ? ` ${line}` : line))
|
|
||||||
.join('\n')}\n}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
contents += '\n' + dtsContent;
|
|
||||||
} catch (error) {
|
|
||||||
console.warn(`Could not read d.ts file: ${filePath}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const extraContent = readFiles('out/languages/bundled/*.d.ts', {
|
|
||||||
base: 'out/languages/bundled/'
|
|
||||||
}).map((file) => {
|
|
||||||
return file.contents.toString().replace(/\/\/\/ <reference.*\n/m, '');
|
|
||||||
});
|
|
||||||
|
|
||||||
contents =
|
|
||||||
[
|
|
||||||
'/*!-----------------------------------------------------------',
|
|
||||||
' * Copyright (c) Microsoft Corporation. All rights reserved.',
|
|
||||||
' * Type definitions for monaco-editor',
|
|
||||||
' * Released under the MIT license',
|
|
||||||
'*-----------------------------------------------------------*/'
|
|
||||||
].join('\n') +
|
|
||||||
'\n' +
|
|
||||||
contents +
|
|
||||||
'\n' +
|
|
||||||
extraContent.join('\n');
|
|
||||||
|
|
||||||
// Ensure consistent indentation and line endings
|
|
||||||
contents = cleanFile(contents);
|
|
||||||
|
|
||||||
monacodts.contents = Buffer.from(contents);
|
|
||||||
|
|
||||||
const editorapidts = {
|
|
||||||
path: 'esm/vs/editor/editor.api.d.ts',
|
|
||||||
contents: Buffer.from(toExternalDTS(contents))
|
|
||||||
};
|
|
||||||
|
|
||||||
writeFiles([monacodts, editorapidts], `out/monaco-editor`);
|
|
||||||
|
|
||||||
// fs.writeFileSync('website/typedoc/monaco.d.ts', contents);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Transforms a .d.ts which uses internal modules (namespaces) to one which is usable with external modules
|
|
||||||
* This function is duplicated in the `vscode` repo.
|
|
||||||
* @param {string} contents
|
|
||||||
*/
|
|
||||||
function toExternalDTS(contents) {
|
|
||||||
const lines = contents.split(/\r\n|\r|\n/);
|
|
||||||
let killNextCloseCurlyBrace = false;
|
|
||||||
for (let i = 0; i < lines.length; i++) {
|
|
||||||
const line = lines[i];
|
|
||||||
|
|
||||||
if (killNextCloseCurlyBrace) {
|
|
||||||
if ('}' === line) {
|
|
||||||
lines[i] = '';
|
|
||||||
killNextCloseCurlyBrace = false;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.indexOf(' ') === 0) {
|
|
||||||
lines[i] = line.substr(4);
|
|
||||||
} else if (line.charAt(0) === '\t') {
|
|
||||||
lines[i] = line.substr(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('declare namespace monaco {' === line) {
|
|
||||||
lines[i] = '';
|
|
||||||
killNextCloseCurlyBrace = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.indexOf('declare namespace monaco.') === 0) {
|
|
||||||
lines[i] = line.replace('declare namespace monaco.', 'export namespace ');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.indexOf('declare var MonacoEnvironment') === 0) {
|
|
||||||
lines[i] = `declare global {\n var MonacoEnvironment: Environment | undefined;\n}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return lines.join('\n').replace(/\n\n\n+/g, '\n\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Normalize line endings and ensure consistent 4 spaces indentation
|
|
||||||
*/
|
|
||||||
function cleanFile(contents: string): string {
|
|
||||||
return contents
|
|
||||||
.split(/\r\n|\r|\n/)
|
|
||||||
.map(function (line) {
|
|
||||||
const m = line.match(/^(\t+)/);
|
|
||||||
if (!m) {
|
|
||||||
return line;
|
|
||||||
}
|
|
||||||
const tabsCount = m[1].length;
|
|
||||||
let newIndent = '';
|
|
||||||
for (let i = 0; i < 4 * tabsCount; i++) {
|
|
||||||
newIndent += ' ';
|
|
||||||
}
|
|
||||||
return newIndent + line.substring(tabsCount);
|
|
||||||
})
|
|
||||||
.join('\n');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Edit ThirdPartyNotices.txt:
|
* Edit ThirdPartyNotices.txt:
|
||||||
* - append ThirdPartyNotices.txt from plugins
|
* - append ThirdPartyNotices.txt from plugins
|
||||||
*/
|
*/
|
||||||
function releaseThirdPartyNotices() {
|
function createThirdPartyNoticesDotTxt() {
|
||||||
const tpn = readFiles('node_modules/monaco-editor-core/ThirdPartyNotices.txt', {
|
const tpn = readFiles('node_modules/monaco-editor-core/ThirdPartyNotices.txt', {
|
||||||
base: 'node_modules/monaco-editor-core'
|
base: 'node_modules/monaco-editor-core'
|
||||||
})[0];
|
})[0];
|
||||||
|
|
@ -377,3 +77,5 @@ function releaseThirdPartyNotices() {
|
||||||
|
|
||||||
writeFiles([tpn], `out/monaco-editor`);
|
writeFiles([tpn], `out/monaco-editor`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
run();
|
||||||
|
|
|
||||||
7
build/esm/build.script.ts
Normal file
7
build/esm/build.script.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { run } from '../../scripts/lib/index';
|
||||||
|
|
||||||
|
export async function buildESM() {
|
||||||
|
const rootPath = __dirname;
|
||||||
|
await run('npx rollup -c rollup.config.mjs', { cwd: rootPath });
|
||||||
|
await run('npx rollup -c rollup-types.config.mjs', { cwd: rootPath });
|
||||||
|
}
|
||||||
1
build/esm/rollup-plugin-keep-css-imports/.gitignore
vendored
Normal file
1
build/esm/rollup-plugin-keep-css-imports/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
!dist
|
||||||
21
build/esm/rollup-plugin-keep-css-imports/LICENSE
Normal file
21
build/esm/rollup-plugin-keep-css-imports/LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 Alexandr Yeskov
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
2
build/esm/rollup-plugin-keep-css-imports/README.md
Normal file
2
build/esm/rollup-plugin-keep-css-imports/README.md
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
See https://www.npmjs.com/package/rollup-plugin-keep-css-imports.
|
||||||
|
Compare index.mjs with index.original.mjs to see the patch.
|
||||||
25
build/esm/rollup-plugin-keep-css-imports/dist/ImportUpdater.d.ts
vendored
Normal file
25
build/esm/rollup-plugin-keep-css-imports/dist/ImportUpdater.d.ts
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
import MagicString from "magic-string";
|
||||||
|
import type { RenderedChunk } from "rollup";
|
||||||
|
import { OutputOptions, KeepCssImportsPluginContext } from "./types";
|
||||||
|
interface ChunkDetails {
|
||||||
|
chunk: RenderedChunk;
|
||||||
|
bundleOutDir: string;
|
||||||
|
moduleRoot: string;
|
||||||
|
}
|
||||||
|
export declare class ImportUpdater {
|
||||||
|
private _outputOptions;
|
||||||
|
private _pluginContext;
|
||||||
|
constructor(pluginContext: KeepCssImportsPluginContext, outputOptions: OutputOptions);
|
||||||
|
getMagicId(id: string): string;
|
||||||
|
updateImports(code: string, chunk: RenderedChunk, bundleOutDir: string, moduleRoot: string): {
|
||||||
|
code: string;
|
||||||
|
map: import("magic-string").SourceMap;
|
||||||
|
};
|
||||||
|
updateMatchedImport(m: RegExpMatchArray, magicString: MagicString, chunkDetails: ChunkDetails): void;
|
||||||
|
private addImportAndGetNewId;
|
||||||
|
private updateChunk;
|
||||||
|
private saveAndGetUpdatedImportPath;
|
||||||
|
private shouldAddPrefixCurrentDir;
|
||||||
|
private resolveOutputPath;
|
||||||
|
}
|
||||||
|
export {};
|
||||||
31
build/esm/rollup-plugin-keep-css-imports/dist/compileSass.d.ts
vendored
Normal file
31
build/esm/rollup-plugin-keep-css-imports/dist/compileSass.d.ts
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
import type { AsyncCompiler, Options } from "sass";
|
||||||
|
type SassAsyncCompiler = Pick<AsyncCompiler, "compileAsync" | "compileStringAsync">;
|
||||||
|
export type PostCssCompatible = {
|
||||||
|
process: (css: string, opt: {
|
||||||
|
from: string;
|
||||||
|
to: string;
|
||||||
|
map: {
|
||||||
|
prev: string;
|
||||||
|
inline: boolean;
|
||||||
|
} | null;
|
||||||
|
}) => string | {
|
||||||
|
css: string;
|
||||||
|
map?: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
export interface CompilationOptions {
|
||||||
|
outputExt: string;
|
||||||
|
sass?: SassAsyncCompiler;
|
||||||
|
postProcessor?: (css: string, map: string) => Promise<PostCssCompatible | string | {
|
||||||
|
css: string;
|
||||||
|
map?: string;
|
||||||
|
}>;
|
||||||
|
loadPaths?: string[];
|
||||||
|
sourceMap?: boolean;
|
||||||
|
sassOptions: Options<"async">;
|
||||||
|
}
|
||||||
|
export declare const compileSass: (sassPath: string, outWatchList: string[] | undefined, { outputExt, sass, postProcessor, loadPaths, sourceMap, sassOptions }: CompilationOptions) => Promise<{
|
||||||
|
css: string;
|
||||||
|
map: string;
|
||||||
|
}>;
|
||||||
|
export {};
|
||||||
3
build/esm/rollup-plugin-keep-css-imports/dist/constants.d.ts
vendored
Normal file
3
build/esm/rollup-plugin-keep-css-imports/dist/constants.d.ts
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
export declare const PLUGIN_NAME = "keep-css-imports";
|
||||||
|
export declare const FILE_URL_PREFIX: string;
|
||||||
|
export declare const KEY_EXT_STRING = ".[keep-css-imports-plugin-ext]";
|
||||||
52
build/esm/rollup-plugin-keep-css-imports/dist/helpers.d.ts
vendored
Normal file
52
build/esm/rollup-plugin-keep-css-imports/dist/helpers.d.ts
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
import { EmitFile } from "rollup";
|
||||||
|
import { StylesMap } from "./types";
|
||||||
|
export declare const escapeRegex: (val: any) => any;
|
||||||
|
export declare const assertDuplicates: (stylesToEmit: StylesMap) => void;
|
||||||
|
export declare const assertLocation: (outDir: any, assetPath: any) => void;
|
||||||
|
export declare const ensureSourceMap: ({ css, map }: {
|
||||||
|
css?: string | Uint8Array;
|
||||||
|
map?: string | Uint8Array;
|
||||||
|
}, includeSourceMap: boolean | "inline" | undefined, fileName: string, onEmit: EmitFile) => string | Uint8Array;
|
||||||
|
export declare const formatProcessedToCSS: (input: string | {
|
||||||
|
css: string;
|
||||||
|
map?: string | object;
|
||||||
|
}, sourceMap: boolean) => {
|
||||||
|
css: string;
|
||||||
|
map: string;
|
||||||
|
};
|
||||||
|
export declare const requireSass: () => Promise<{
|
||||||
|
default: typeof import("sass");
|
||||||
|
AsyncCompiler: typeof import("sass").AsyncCompiler;
|
||||||
|
Compiler: typeof import("sass").Compiler;
|
||||||
|
compile: typeof import("sass").compile;
|
||||||
|
compileAsync: typeof import("sass").compileAsync;
|
||||||
|
compileString: typeof import("sass").compileString;
|
||||||
|
compileStringAsync: typeof import("sass").compileStringAsync;
|
||||||
|
initCompiler: typeof import("sass").initCompiler;
|
||||||
|
initAsyncCompiler: typeof import("sass").initAsyncCompiler;
|
||||||
|
Exception: typeof import("sass").Exception;
|
||||||
|
Logger: typeof import("sass").Logger;
|
||||||
|
CalculationInterpolation: typeof import("sass").CalculationInterpolation;
|
||||||
|
CalculationOperation: typeof import("sass").CalculationOperation;
|
||||||
|
SassArgumentList: typeof import("sass").SassArgumentList;
|
||||||
|
SassBoolean: typeof import("sass").SassBoolean;
|
||||||
|
SassCalculation: typeof import("sass").SassCalculation;
|
||||||
|
SassColor: typeof import("sass").SassColor;
|
||||||
|
SassFunction: typeof import("sass").SassFunction;
|
||||||
|
SassList: typeof import("sass").SassList;
|
||||||
|
SassMap: typeof import("sass").SassMap;
|
||||||
|
SassMixin: typeof import("sass").SassMixin;
|
||||||
|
SassNumber: typeof import("sass").SassNumber;
|
||||||
|
SassString: typeof import("sass").SassString;
|
||||||
|
Value: typeof import("sass").Value;
|
||||||
|
sassFalse: import("sass").SassBoolean;
|
||||||
|
sassNull: import("sass").Value;
|
||||||
|
sassTrue: import("sass").SassBoolean;
|
||||||
|
FALSE: import("sass").types.Boolean<false>;
|
||||||
|
NULL: import("sass").types.Null;
|
||||||
|
TRUE: import("sass").types.Boolean<true>;
|
||||||
|
types: typeof import("sass").types;
|
||||||
|
render: typeof import("sass").render;
|
||||||
|
renderSync: typeof import("sass").renderSync;
|
||||||
|
info: string;
|
||||||
|
}>;
|
||||||
4
build/esm/rollup-plugin-keep-css-imports/dist/index.d.ts
vendored
Normal file
4
build/esm/rollup-plugin-keep-css-imports/dist/index.d.ts
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
import type { Plugin } from "rollup";
|
||||||
|
import { KeepCssImportsOptions } from "./types";
|
||||||
|
declare function keepCssImports({ outputExt, outputPath, skipCurrentFolderPart, includeRegexp, sass, postProcessor, sassOptions, ...options }?: KeepCssImportsOptions): Plugin;
|
||||||
|
export default keepCssImports;
|
||||||
487
build/esm/rollup-plugin-keep-css-imports/dist/index.mjs
vendored
Normal file
487
build/esm/rollup-plugin-keep-css-imports/dist/index.mjs
vendored
Normal file
|
|
@ -0,0 +1,487 @@
|
||||||
|
import { readFile } from 'fs/promises';
|
||||||
|
import * as path from 'path';
|
||||||
|
import MagicString from 'magic-string';
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
Copyright (c) Microsoft Corporation.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
|
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
|
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
|
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
|
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
***************************************************************************** */
|
||||||
|
/* global Reflect, Promise, SuppressedError, Symbol */
|
||||||
|
|
||||||
|
|
||||||
|
var __assign = function () {
|
||||||
|
__assign = Object.assign || function __assign(t) {
|
||||||
|
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
||||||
|
s = arguments[i];
|
||||||
|
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
};
|
||||||
|
return __assign.apply(this, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
function __rest(s, e) {
|
||||||
|
var t = {};
|
||||||
|
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
||||||
|
t[p] = s[p];
|
||||||
|
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
||||||
|
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
||||||
|
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
||||||
|
t[p[i]] = s[p[i]];
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
function __awaiter(thisArg, _arguments, P, generator) {
|
||||||
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||||
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||||
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function __generator(thisArg, body) {
|
||||||
|
var _ = { label: 0, sent: function () { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
||||||
|
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function () { return this; }), g;
|
||||||
|
function verb(n) { return function (v) { return step([n, v]); }; }
|
||||||
|
function step(op) {
|
||||||
|
if (f) throw new TypeError("Generator is already executing.");
|
||||||
|
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
||||||
|
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
||||||
|
if (y = 0, t) op = [op[0] & 2, t.value];
|
||||||
|
switch (op[0]) {
|
||||||
|
case 0: case 1: t = op; break;
|
||||||
|
case 4: _.label++; return { value: op[1], done: false };
|
||||||
|
case 5: _.label++; y = op[1]; op = [0]; continue;
|
||||||
|
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
||||||
|
default:
|
||||||
|
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
||||||
|
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
||||||
|
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
||||||
|
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
||||||
|
if (t[2]) _.ops.pop();
|
||||||
|
_.trys.pop(); continue;
|
||||||
|
}
|
||||||
|
op = body.call(thisArg, _);
|
||||||
|
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
||||||
|
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
||||||
|
var e = new Error(message);
|
||||||
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
||||||
|
};
|
||||||
|
|
||||||
|
var escapeRegex = function (val) { return val.replace(/[/\-\\^$*+?.()|[\]{}]/g, "\\$&"); };
|
||||||
|
var assertDuplicates = function (stylesToEmit) {
|
||||||
|
Object.values(stylesToEmit).forEach(function (v, i, all) {
|
||||||
|
if (all.some(function (av, ai) { return !!v.output && v.output === av.output && ai != i; })) {
|
||||||
|
throw new Error("Two or more assets have conflicting output path ".concat(v.output));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
var assertLocation = function (outDir, assetPath) {
|
||||||
|
if (!path.normalize(assetPath).startsWith(path.normalize(outDir))) {
|
||||||
|
throw new Error("Output path ".concat(assetPath, " must be in output directory ").concat(outDir));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var ensureSourceMap = function (_a, includeSourceMap, fileName, onEmit) {
|
||||||
|
var css = _a.css, map = _a.map;
|
||||||
|
if (map) {
|
||||||
|
if (includeSourceMap === "inline") {
|
||||||
|
css += "\n/*# sourceMappingURL=data:application/json;base64,".concat((map instanceof Uint8Array ? Buffer.from(map) : Buffer.from(map, "utf8")).toString("base64"), "*/");
|
||||||
|
}
|
||||||
|
else if (includeSourceMap === true) {
|
||||||
|
css += "\n/*# sourceMappingURL=".concat(path.basename(fileName), ".map */");
|
||||||
|
}
|
||||||
|
if (includeSourceMap === true) {
|
||||||
|
onEmit({
|
||||||
|
type: "asset",
|
||||||
|
fileName: fileName + ".map",
|
||||||
|
source: map,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return css;
|
||||||
|
};
|
||||||
|
var formatProcessedToCSS = function (input, sourceMap) {
|
||||||
|
return typeof input === "string"
|
||||||
|
? { css: input, map: "" }
|
||||||
|
: typeof input === "object"
|
||||||
|
? {
|
||||||
|
css: input.css,
|
||||||
|
map: !sourceMap ? "" : typeof input.map === "object" ? JSON.stringify(input.map) : input.map,
|
||||||
|
}
|
||||||
|
: input;
|
||||||
|
};
|
||||||
|
var requireSass = function () {
|
||||||
|
try {
|
||||||
|
return import('sass');
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
throw new Error("You have to install `sass` package! Try running\n\t" +
|
||||||
|
"npm install --save-dev sass\nor\nyarn add sass --dev\n" +
|
||||||
|
"or use `sass` option to pass processor");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function ensureCompiler(sass) {
|
||||||
|
return __awaiter(this, void 0, void 0, function () {
|
||||||
|
var sassProcessor, _a;
|
||||||
|
return __generator(this, function (_b) {
|
||||||
|
switch (_b.label) {
|
||||||
|
case 0:
|
||||||
|
_a = sass;
|
||||||
|
if (_a) return [3 /*break*/, 2];
|
||||||
|
return [4 /*yield*/, requireSass()];
|
||||||
|
case 1:
|
||||||
|
_a = (_b.sent());
|
||||||
|
_b.label = 2;
|
||||||
|
case 2:
|
||||||
|
sassProcessor = _a;
|
||||||
|
if (!("compileAsync" in sassProcessor)) {
|
||||||
|
throw new Error("You have to install `sass` package! Or provide an object which implements `compileAsync` as `sass` option");
|
||||||
|
}
|
||||||
|
return [2 /*return*/, sassProcessor];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
var isPostCssCompatible = function (result) {
|
||||||
|
return result && typeof result === "object" && "process" in result && typeof result.process === "function";
|
||||||
|
};
|
||||||
|
var compileSass = function (sassPath, outWatchList, _a) {
|
||||||
|
var outputExt = _a.outputExt, sass = _a.sass, postProcessor = _a.postProcessor, loadPaths = _a.loadPaths, sourceMap = _a.sourceMap, sassOptions = _a.sassOptions;
|
||||||
|
return __awaiter(void 0, void 0, void 0, function () {
|
||||||
|
var sassProcessor, watchListNeeded, compiled, css, mapObject, sources, map, result, _b, _c;
|
||||||
|
return __generator(this, function (_d) {
|
||||||
|
switch (_d.label) {
|
||||||
|
case 0:
|
||||||
|
if (!sassPath) {
|
||||||
|
return [2 /*return*/, { css: "", map: "" }];
|
||||||
|
}
|
||||||
|
return [4 /*yield*/, ensureCompiler(sass)];
|
||||||
|
case 1:
|
||||||
|
sassProcessor = _d.sent();
|
||||||
|
watchListNeeded = Array.isArray(outWatchList);
|
||||||
|
return [4 /*yield*/, sassProcessor.compileAsync(sassPath, __assign({ loadPaths: loadPaths, style: "expanded", sourceMap: !!sourceMap || watchListNeeded, sourceMapIncludeSources: !!sourceMap || watchListNeeded }, (sassOptions || [])))];
|
||||||
|
case 2:
|
||||||
|
compiled = _d.sent();
|
||||||
|
css = compiled.css.toString();
|
||||||
|
if (watchListNeeded && compiled.sourceMap && typeof compiled.sourceMap === "object") {
|
||||||
|
mapObject = "toJSON" in compiled.sourceMap && typeof compiled.sourceMap.toJSON === "function"
|
||||||
|
? compiled.sourceMap.toJSON()
|
||||||
|
: compiled.sourceMap;
|
||||||
|
sources = mapObject.sources || mapObject._sources;
|
||||||
|
outWatchList.push.apply(outWatchList, sources.filter(function (s) { return s && typeof s === "string"; }));
|
||||||
|
}
|
||||||
|
map = compiled.sourceMap
|
||||||
|
? typeof compiled.sourceMap === "object"
|
||||||
|
? JSON.stringify(compiled.sourceMap)
|
||||||
|
: compiled.sourceMap
|
||||||
|
: "";
|
||||||
|
if (!(typeof postProcessor === "function")) return [3 /*break*/, 7];
|
||||||
|
return [4 /*yield*/, postProcessor(css, map)];
|
||||||
|
case 3:
|
||||||
|
result = _d.sent();
|
||||||
|
if ((typeof result !== "string" && typeof result !== "object") || result === null) {
|
||||||
|
throw new Error("`postProcessor` must return string, object with `css` and `map` or PostCSS like object which implements `process` function");
|
||||||
|
}
|
||||||
|
_b = formatProcessedToCSS;
|
||||||
|
if (!isPostCssCompatible(result) // If PostCSS compatible result
|
||||||
|
) return [3 /*break*/, 5]; // If PostCSS compatible result
|
||||||
|
return [4 /*yield*/, Promise.resolve(result.process(css, {
|
||||||
|
from: sassPath,
|
||||||
|
to: path.parse(sassPath).name + outputExt,
|
||||||
|
map: map ? { prev: map, inline: false } : null,
|
||||||
|
}))];
|
||||||
|
case 4:
|
||||||
|
_c = _d.sent();
|
||||||
|
return [3 /*break*/, 6];
|
||||||
|
case 5:
|
||||||
|
_c = result;
|
||||||
|
_d.label = 6;
|
||||||
|
case 6: return [2 /*return*/, _b.apply(void 0, [_c, sourceMap])];
|
||||||
|
case 7: return [2 /*return*/, { css: css, map: sourceMap ? map : undefined }];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var PLUGIN_NAME = "keep-css-imports";
|
||||||
|
var FILE_URL_PREFIX = new URL("file://").toString();
|
||||||
|
var KEY_EXT_STRING = ".[keep-css-imports-plugin-ext]";
|
||||||
|
|
||||||
|
var createErrorMessage = function (message) { return "[".concat(PLUGIN_NAME, "] ").concat(message); };
|
||||||
|
var ImportUpdater = /** @class */ (function () {
|
||||||
|
function ImportUpdater(pluginContext, outputOptions) {
|
||||||
|
var _this = this;
|
||||||
|
this.addImportAndGetNewId = function (resolvedId) {
|
||||||
|
var moduleIndex = _this._pluginContext.allStyleImports.indexOf(resolvedId);
|
||||||
|
return !~moduleIndex ? _this._pluginContext.allStyleImports.push(resolvedId) - 1 : moduleIndex;
|
||||||
|
};
|
||||||
|
this._pluginContext = pluginContext;
|
||||||
|
this._outputOptions = outputOptions;
|
||||||
|
}
|
||||||
|
ImportUpdater.prototype.getMagicId = function (id) {
|
||||||
|
return "\0" + this.addImportAndGetNewId(id) + KEY_EXT_STRING;
|
||||||
|
};
|
||||||
|
ImportUpdater.prototype.updateImports = function (code, chunk, bundleOutDir, moduleRoot) {
|
||||||
|
var _this = this;
|
||||||
|
var magicString = new MagicString(code);
|
||||||
|
var matchRegex = new RegExp("\0([^\"']+)".concat(escapeRegex(KEY_EXT_STRING)), "g");
|
||||||
|
Array.from(code.matchAll(matchRegex))
|
||||||
|
.reverse()
|
||||||
|
.forEach(function (m) {
|
||||||
|
return _this.updateMatchedImport(m, magicString, {
|
||||||
|
chunk: chunk,
|
||||||
|
bundleOutDir: bundleOutDir,
|
||||||
|
moduleRoot: moduleRoot,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
code: magicString.toString(),
|
||||||
|
map: magicString.generateMap({ hires: true }),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
ImportUpdater.prototype.updateMatchedImport = function (m, magicString, chunkDetails) {
|
||||||
|
var importId = m[0];
|
||||||
|
var assetId = this._pluginContext.allStyleImports[m[1]];
|
||||||
|
if (!assetId || typeof assetId !== "string" || !this._pluginContext.stylesToEmit[assetId]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var updatedImport = this.saveAndGetUpdatedImportPath(assetId, chunkDetails);
|
||||||
|
var start = m.index;
|
||||||
|
var end = start + importId.length;
|
||||||
|
magicString.overwrite(start, end, updatedImport);
|
||||||
|
this.updateChunk(importId, updatedImport, chunkDetails.chunk);
|
||||||
|
};
|
||||||
|
ImportUpdater.prototype.updateChunk = function (importId, updatedImport, chunk) {
|
||||||
|
if (chunk.importedBindings[importId]) {
|
||||||
|
chunk.importedBindings[updatedImport] = chunk.importedBindings[importId];
|
||||||
|
if (updatedImport !== importId) {
|
||||||
|
delete chunk.importedBindings[importId];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var importIndex = chunk.imports.indexOf(importId);
|
||||||
|
if (~importIndex) {
|
||||||
|
chunk.imports[importIndex] = updatedImport;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ImportUpdater.prototype.saveAndGetUpdatedImportPath = function (assetId, _a) {
|
||||||
|
var bundleOutDir = _a.bundleOutDir, moduleRoot = _a.moduleRoot, chunk = _a.chunk;
|
||||||
|
var assetOutput = this.resolveOutputPath(bundleOutDir, assetId, moduleRoot);
|
||||||
|
var updatedImport = path
|
||||||
|
.relative(path.dirname(path.resolve(bundleOutDir, chunk.fileName)), assetOutput)
|
||||||
|
.replace(/\\/g, "/");
|
||||||
|
this._pluginContext.stylesToEmit[assetId].output = path.relative(path.resolve(bundleOutDir), assetOutput);
|
||||||
|
if (this.shouldAddPrefixCurrentDir(updatedImport) &&
|
||||||
|
!updatedImport.startsWith("./") &&
|
||||||
|
!updatedImport.startsWith("../") &&
|
||||||
|
!updatedImport.match(/^[a-zA-Z]:/)) {
|
||||||
|
updatedImport = "./" + updatedImport;
|
||||||
|
}
|
||||||
|
return updatedImport;
|
||||||
|
};
|
||||||
|
ImportUpdater.prototype.shouldAddPrefixCurrentDir = function (updatedImport) {
|
||||||
|
var skip = this._outputOptions.skipCurrentFolderPart;
|
||||||
|
return !skip || (skip instanceof RegExp && !skip.test(updatedImport));
|
||||||
|
};
|
||||||
|
ImportUpdater.prototype.resolveOutputPath = function (bundleOutDir, assetId, moduleRoot) {
|
||||||
|
var _a = this._outputOptions, outputPath = _a.outputPath, outputDir = _a.outputDir, outputExt = _a.outputExt;
|
||||||
|
var newPath = undefined;
|
||||||
|
if (typeof outputPath === "function") {
|
||||||
|
newPath = outputPath(assetId);
|
||||||
|
assertLocation(bundleOutDir, newPath);
|
||||||
|
}
|
||||||
|
else if (typeof outputPath === "string") {
|
||||||
|
newPath = path.resolve(bundleOutDir, outputDir, outputPath !== "keep" ? outputPath : path.relative(moduleRoot, assetId));
|
||||||
|
assertLocation(bundleOutDir, newPath);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new Error(createErrorMessage("Invalid outputPath option value!"));
|
||||||
|
}
|
||||||
|
return newPath.replace(/\.s[ca]ss$/, outputExt);
|
||||||
|
};
|
||||||
|
return ImportUpdater;
|
||||||
|
}());
|
||||||
|
|
||||||
|
var ensureStylesInfo = function (stylesMap, importer, resolvedId) {
|
||||||
|
stylesMap[resolvedId] = stylesMap[resolvedId] || { importers: [], watchList: [] };
|
||||||
|
stylesMap[resolvedId].importers.push(importer);
|
||||||
|
return stylesMap[resolvedId];
|
||||||
|
};
|
||||||
|
var ensureCodeAndWatchList = function (filePath, stylesInfo, isWatch, compilerOptions) {
|
||||||
|
return __awaiter(void 0, void 0, void 0, function () {
|
||||||
|
var outWatchList, _a, _b, css, map;
|
||||||
|
return __generator(this, function (_c) {
|
||||||
|
switch (_c.label) {
|
||||||
|
case 0:
|
||||||
|
outWatchList = [];
|
||||||
|
if (!filePath.endsWith(".css")) return [3 /*break*/, 2];
|
||||||
|
_a = stylesInfo;
|
||||||
|
return [4 /*yield*/, readFile(filePath, "utf8")];
|
||||||
|
case 1:
|
||||||
|
_a.css = _c.sent();
|
||||||
|
return [3 /*break*/, 4];
|
||||||
|
case 2: return [4 /*yield*/, compileSass(filePath, isWatch ? outWatchList : undefined, compilerOptions)];
|
||||||
|
case 3:
|
||||||
|
_b = _c.sent(), css = _b.css, map = _b.map;
|
||||||
|
stylesInfo.css = css;
|
||||||
|
stylesInfo.map = map;
|
||||||
|
_c.label = 4;
|
||||||
|
case 4:
|
||||||
|
outWatchList.push(filePath);
|
||||||
|
stylesInfo.watchList = outWatchList.map(function (watchFile) { return path.resolve(watchFile.replace(FILE_URL_PREFIX, "")); });
|
||||||
|
return [2 /*return*/];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
function keepCssImports(_a) {
|
||||||
|
if (_a === void 0) { _a = {}; }
|
||||||
|
var _b = _a.outputExt, outputExt = _b === void 0 ? ".css" : _b, _c = _a.outputPath, outputPath = _c === void 0 ? "keep" : _c, _d = _a.skipCurrentFolderPart, skipCurrentFolderPart = _d === void 0 ? false : _d, _e = _a.includeRegexp, includeRegexp = _e === void 0 ? /\.(?:s[ca]|c)ss$/ : _e, sass = _a.sass, postProcessor = _a.postProcessor, sassOptions = _a.sassOptions, options = __rest(_a, ["outputExt", "outputPath", "skipCurrentFolderPart", "includeRegexp", "sass", "postProcessor", "sassOptions"]);
|
||||||
|
var stylesOutputOptions = {
|
||||||
|
outputPath: outputPath,
|
||||||
|
outputExt: outputExt,
|
||||||
|
outputDir: options.outputDir ? path.resolve(options.outputDir) : "./",
|
||||||
|
skipCurrentFolderPart: skipCurrentFolderPart,
|
||||||
|
};
|
||||||
|
var context = {
|
||||||
|
allStyleImports: [],
|
||||||
|
modulesWithCss: new Set(),
|
||||||
|
stylesToEmit: {},
|
||||||
|
};
|
||||||
|
var importUpdater = new ImportUpdater(context, stylesOutputOptions);
|
||||||
|
var loadPaths = options.includePaths || ["node_modules/"];
|
||||||
|
loadPaths.push(process.cwd());
|
||||||
|
loadPaths = loadPaths.filter(function (v, i, a) { return a.indexOf(v) === i; });
|
||||||
|
var compilerOptions = {
|
||||||
|
outputExt: outputExt,
|
||||||
|
sass: sass,
|
||||||
|
postProcessor: typeof postProcessor === "function"
|
||||||
|
? function (css, map) { return postProcessor(css, map, context.stylesToEmit); }
|
||||||
|
: undefined,
|
||||||
|
loadPaths: loadPaths,
|
||||||
|
sourceMap: !!options.sourceMap,
|
||||||
|
sassOptions: sassOptions,
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
name: PLUGIN_NAME,
|
||||||
|
resolveId: function (source, importer, resolveOptions) {
|
||||||
|
return __awaiter(this, void 0, void 0, function () {
|
||||||
|
var _a, custom, _b, _c, _d, _e, _f, alreadyResolving, resolved, styleInfo;
|
||||||
|
var _g, _h;
|
||||||
|
var _this = this;
|
||||||
|
return __generator(this, function (_j) {
|
||||||
|
switch (_j.label) {
|
||||||
|
case 0:
|
||||||
|
if (!importer || !includeRegexp.test(source) || /\0/.test(source)) {
|
||||||
|
return [2 /*return*/, null];
|
||||||
|
}
|
||||||
|
_a = resolveOptions.custom, custom = _a === void 0 ? {} : _a;
|
||||||
|
_b = custom, _c = PLUGIN_NAME, _d = _b[_c], _e = _d === void 0 ? {} : _d, _f = _e.resolving, alreadyResolving = _f === void 0 ? false : _f;
|
||||||
|
if (alreadyResolving) {
|
||||||
|
return [2 /*return*/, null];
|
||||||
|
}
|
||||||
|
return [4 /*yield*/, this.resolve(source, importer, __assign(__assign({ skipSelf: true }, resolveOptions), { custom: __assign(__assign({}, custom), (_g = {}, _g[PLUGIN_NAME] = __assign(__assign({}, custom[PLUGIN_NAME]), { resolving: true }), _g)) }))];
|
||||||
|
case 1:
|
||||||
|
resolved = _j.sent();
|
||||||
|
if (!resolved || resolved.external) {
|
||||||
|
return [2 /*return*/, resolved];
|
||||||
|
}
|
||||||
|
context.modulesWithCss.add(importer);
|
||||||
|
styleInfo = ensureStylesInfo(context.stylesToEmit, importer, resolved.id);
|
||||||
|
return [4 /*yield*/, ensureCodeAndWatchList(resolved.id, styleInfo, this.meta.watchMode, compilerOptions)];
|
||||||
|
case 2:
|
||||||
|
_j.sent();
|
||||||
|
styleInfo.watchList.forEach(function (watchFile) {
|
||||||
|
_this.addWatchFile(watchFile);
|
||||||
|
});
|
||||||
|
return [2 /*return*/, {
|
||||||
|
id: importUpdater.getMagicId(resolved.id),
|
||||||
|
meta: (_h = {}, _h[PLUGIN_NAME] = { sourceId: resolved.id }, _h),
|
||||||
|
external: true,
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
buildStart: function () {
|
||||||
|
var _this = this;
|
||||||
|
// Every rebuild will refresh watcher, so we need to reattach
|
||||||
|
if (this.meta.watchMode) {
|
||||||
|
var allWatched_1 = this.getWatchFiles();
|
||||||
|
Object.values(context.stylesToEmit).forEach(function (styleInfo) {
|
||||||
|
return styleInfo.watchList.forEach(function (watchFile) {
|
||||||
|
if (!allWatched_1.find(function (watched) { return path.normalize(watched) === path.normalize(watchFile); })) {
|
||||||
|
_this.addWatchFile(watchFile);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watchChange: function (id) {
|
||||||
|
return __awaiter(this, void 0, void 0, function () {
|
||||||
|
var resolvedId, filesToUpdate;
|
||||||
|
var _this = this;
|
||||||
|
return __generator(this, function (_a) {
|
||||||
|
switch (_a.label) {
|
||||||
|
case 0:
|
||||||
|
resolvedId = path.resolve(id);
|
||||||
|
filesToUpdate = Object.entries(context.stylesToEmit).filter(function (_a) {
|
||||||
|
var styleInfo = _a[1];
|
||||||
|
return styleInfo.watchList.includes(resolvedId);
|
||||||
|
});
|
||||||
|
return [4 /*yield*/, Promise.all(filesToUpdate.map(function (_a) {
|
||||||
|
var fileName = _a[0], styleInfo = _a[1];
|
||||||
|
return ensureCodeAndWatchList(fileName, styleInfo, _this.meta.watchMode, compilerOptions);
|
||||||
|
}))];
|
||||||
|
case 1:
|
||||||
|
_a.sent();
|
||||||
|
return [2 /*return*/];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
renderChunk: function (code, chunk, outputOptions) {
|
||||||
|
var bundleOutDir = path.resolve(outputOptions.dir || path.dirname(outputOptions.file));
|
||||||
|
// Always do it, otherwise some modules are missed
|
||||||
|
var moduleRoot = outputOptions.preserveModulesRoot || process.cwd();
|
||||||
|
return importUpdater.updateImports(code, chunk, bundleOutDir, moduleRoot);
|
||||||
|
},
|
||||||
|
generateBundle: function (_, __, isWrite) {
|
||||||
|
if (!isWrite) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
assertDuplicates(context.stylesToEmit);
|
||||||
|
for (var file in context.stylesToEmit) {
|
||||||
|
var stylesInfo = context.stylesToEmit[file];
|
||||||
|
var fileName = stylesInfo.output;
|
||||||
|
var source = file.endsWith(".css")
|
||||||
|
? stylesInfo.css
|
||||||
|
: ensureSourceMap(stylesInfo, options.sourceMap || (sassOptions === null || sassOptions === void 0 ? void 0 : sassOptions.sourceMap), fileName, this.emitFile);
|
||||||
|
this.emitFile({
|
||||||
|
type: "asset",
|
||||||
|
fileName: fileName,
|
||||||
|
source: source,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export { keepCssImports as default };
|
||||||
489
build/esm/rollup-plugin-keep-css-imports/dist/index.original.mjs
vendored
Normal file
489
build/esm/rollup-plugin-keep-css-imports/dist/index.original.mjs
vendored
Normal file
|
|
@ -0,0 +1,489 @@
|
||||||
|
import { readFile } from 'fs/promises';
|
||||||
|
import * as path from 'path';
|
||||||
|
import MagicString from 'magic-string';
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
Copyright (c) Microsoft Corporation.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
|
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
|
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
|
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
|
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
***************************************************************************** */
|
||||||
|
/* global Reflect, Promise, SuppressedError, Symbol */
|
||||||
|
|
||||||
|
|
||||||
|
var __assign = function () {
|
||||||
|
__assign = Object.assign || function __assign(t) {
|
||||||
|
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
||||||
|
s = arguments[i];
|
||||||
|
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
};
|
||||||
|
return __assign.apply(this, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
function __rest(s, e) {
|
||||||
|
var t = {};
|
||||||
|
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
||||||
|
t[p] = s[p];
|
||||||
|
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
||||||
|
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
||||||
|
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
||||||
|
t[p[i]] = s[p[i]];
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
function __awaiter(thisArg, _arguments, P, generator) {
|
||||||
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||||
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||||
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function __generator(thisArg, body) {
|
||||||
|
var _ = { label: 0, sent: function () { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
||||||
|
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function () { return this; }), g;
|
||||||
|
function verb(n) { return function (v) { return step([n, v]); }; }
|
||||||
|
function step(op) {
|
||||||
|
if (f) throw new TypeError("Generator is already executing.");
|
||||||
|
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
||||||
|
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
||||||
|
if (y = 0, t) op = [op[0] & 2, t.value];
|
||||||
|
switch (op[0]) {
|
||||||
|
case 0: case 1: t = op; break;
|
||||||
|
case 4: _.label++; return { value: op[1], done: false };
|
||||||
|
case 5: _.label++; y = op[1]; op = [0]; continue;
|
||||||
|
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
||||||
|
default:
|
||||||
|
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
||||||
|
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
||||||
|
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
||||||
|
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
||||||
|
if (t[2]) _.ops.pop();
|
||||||
|
_.trys.pop(); continue;
|
||||||
|
}
|
||||||
|
op = body.call(thisArg, _);
|
||||||
|
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
||||||
|
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
||||||
|
var e = new Error(message);
|
||||||
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
||||||
|
};
|
||||||
|
|
||||||
|
var escapeRegex = function (val) { return val.replace(/[/\-\\^$*+?.()|[\]{}]/g, "\\$&"); };
|
||||||
|
var assertDuplicates = function (stylesToEmit) {
|
||||||
|
Object.values(stylesToEmit).forEach(function (v, i, all) {
|
||||||
|
if (all.some(function (av, ai) { return !!v.output && v.output === av.output && ai != i; })) {
|
||||||
|
throw new Error("Two or more assets have conflicting output path ".concat(v.output));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
var assertLocation = function (outDir, assetPath) {
|
||||||
|
if (!path.normalize(assetPath).startsWith(path.normalize(outDir))) {
|
||||||
|
throw new Error("Output path ".concat(assetPath, " must be in output directory ").concat(outDir));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var ensureSourceMap = function (_a, includeSourceMap, fileName, onEmit) {
|
||||||
|
var css = _a.css, map = _a.map;
|
||||||
|
if (map) {
|
||||||
|
if (includeSourceMap === "inline") {
|
||||||
|
css += "\n/*# sourceMappingURL=data:application/json;base64,".concat((map instanceof Uint8Array ? Buffer.from(map) : Buffer.from(map, "utf8")).toString("base64"), "*/");
|
||||||
|
}
|
||||||
|
else if (includeSourceMap === true) {
|
||||||
|
css += "\n/*# sourceMappingURL=".concat(path.basename(fileName), ".map */");
|
||||||
|
}
|
||||||
|
if (includeSourceMap === true) {
|
||||||
|
onEmit({
|
||||||
|
type: "asset",
|
||||||
|
fileName: fileName + ".map",
|
||||||
|
source: map,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return css;
|
||||||
|
};
|
||||||
|
var formatProcessedToCSS = function (input, sourceMap) {
|
||||||
|
return typeof input === "string"
|
||||||
|
? { css: input, map: "" }
|
||||||
|
: typeof input === "object"
|
||||||
|
? {
|
||||||
|
css: input.css,
|
||||||
|
map: !sourceMap ? "" : typeof input.map === "object" ? JSON.stringify(input.map) : input.map,
|
||||||
|
}
|
||||||
|
: input;
|
||||||
|
};
|
||||||
|
var requireSass = function () {
|
||||||
|
try {
|
||||||
|
return import('sass');
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
throw new Error("You have to install `sass` package! Try running\n\t" +
|
||||||
|
"npm install --save-dev sass\nor\nyarn add sass --dev\n" +
|
||||||
|
"or use `sass` option to pass processor");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function ensureCompiler(sass) {
|
||||||
|
return __awaiter(this, void 0, void 0, function () {
|
||||||
|
var sassProcessor, _a;
|
||||||
|
return __generator(this, function (_b) {
|
||||||
|
switch (_b.label) {
|
||||||
|
case 0:
|
||||||
|
_a = sass;
|
||||||
|
if (_a) return [3 /*break*/, 2];
|
||||||
|
return [4 /*yield*/, requireSass()];
|
||||||
|
case 1:
|
||||||
|
_a = (_b.sent());
|
||||||
|
_b.label = 2;
|
||||||
|
case 2:
|
||||||
|
sassProcessor = _a;
|
||||||
|
if (!("compileAsync" in sassProcessor)) {
|
||||||
|
throw new Error("You have to install `sass` package! Or provide an object which implements `compileAsync` as `sass` option");
|
||||||
|
}
|
||||||
|
return [2 /*return*/, sassProcessor];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
var isPostCssCompatible = function (result) {
|
||||||
|
return result && typeof result === "object" && "process" in result && typeof result.process === "function";
|
||||||
|
};
|
||||||
|
var compileSass = function (sassPath, outWatchList, _a) {
|
||||||
|
var outputExt = _a.outputExt, sass = _a.sass, postProcessor = _a.postProcessor, loadPaths = _a.loadPaths, sourceMap = _a.sourceMap, sassOptions = _a.sassOptions;
|
||||||
|
return __awaiter(void 0, void 0, void 0, function () {
|
||||||
|
var sassProcessor, watchListNeeded, compiled, css, mapObject, sources, map, result, _b, _c;
|
||||||
|
return __generator(this, function (_d) {
|
||||||
|
switch (_d.label) {
|
||||||
|
case 0:
|
||||||
|
if (!sassPath) {
|
||||||
|
return [2 /*return*/, { css: "", map: "" }];
|
||||||
|
}
|
||||||
|
return [4 /*yield*/, ensureCompiler(sass)];
|
||||||
|
case 1:
|
||||||
|
sassProcessor = _d.sent();
|
||||||
|
watchListNeeded = Array.isArray(outWatchList);
|
||||||
|
return [4 /*yield*/, sassProcessor.compileAsync(sassPath, __assign({ loadPaths: loadPaths, style: "expanded", sourceMap: !!sourceMap || watchListNeeded, sourceMapIncludeSources: !!sourceMap || watchListNeeded }, (sassOptions || [])))];
|
||||||
|
case 2:
|
||||||
|
compiled = _d.sent();
|
||||||
|
css = compiled.css.toString();
|
||||||
|
if (watchListNeeded && compiled.sourceMap && typeof compiled.sourceMap === "object") {
|
||||||
|
mapObject = "toJSON" in compiled.sourceMap && typeof compiled.sourceMap.toJSON === "function"
|
||||||
|
? compiled.sourceMap.toJSON()
|
||||||
|
: compiled.sourceMap;
|
||||||
|
sources = mapObject.sources || mapObject._sources;
|
||||||
|
outWatchList.push.apply(outWatchList, sources.filter(function (s) { return s && typeof s === "string"; }));
|
||||||
|
}
|
||||||
|
map = compiled.sourceMap
|
||||||
|
? typeof compiled.sourceMap === "object"
|
||||||
|
? JSON.stringify(compiled.sourceMap)
|
||||||
|
: compiled.sourceMap
|
||||||
|
: "";
|
||||||
|
if (!(typeof postProcessor === "function")) return [3 /*break*/, 7];
|
||||||
|
return [4 /*yield*/, postProcessor(css, map)];
|
||||||
|
case 3:
|
||||||
|
result = _d.sent();
|
||||||
|
if ((typeof result !== "string" && typeof result !== "object") || result === null) {
|
||||||
|
throw new Error("`postProcessor` must return string, object with `css` and `map` or PostCSS like object which implements `process` function");
|
||||||
|
}
|
||||||
|
_b = formatProcessedToCSS;
|
||||||
|
if (!isPostCssCompatible(result) // If PostCSS compatible result
|
||||||
|
) return [3 /*break*/, 5]; // If PostCSS compatible result
|
||||||
|
return [4 /*yield*/, Promise.resolve(result.process(css, {
|
||||||
|
from: sassPath,
|
||||||
|
to: path.parse(sassPath).name + outputExt,
|
||||||
|
map: map ? { prev: map, inline: false } : null,
|
||||||
|
}))];
|
||||||
|
case 4:
|
||||||
|
_c = _d.sent();
|
||||||
|
return [3 /*break*/, 6];
|
||||||
|
case 5:
|
||||||
|
_c = result;
|
||||||
|
_d.label = 6;
|
||||||
|
case 6: return [2 /*return*/, _b.apply(void 0, [_c, sourceMap])];
|
||||||
|
case 7: return [2 /*return*/, { css: css, map: sourceMap ? map : undefined }];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var PLUGIN_NAME = "keep-css-imports";
|
||||||
|
var FILE_URL_PREFIX = new URL("file://").toString();
|
||||||
|
var KEY_EXT_STRING = ".[keep-css-imports-plugin-ext]";
|
||||||
|
|
||||||
|
var createErrorMessage = function (message) { return "[".concat(PLUGIN_NAME, "] ").concat(message); };
|
||||||
|
var ImportUpdater = /** @class */ (function () {
|
||||||
|
function ImportUpdater(pluginContext, outputOptions) {
|
||||||
|
var _this = this;
|
||||||
|
this.addImportAndGetNewId = function (resolvedId) {
|
||||||
|
var moduleIndex = _this._pluginContext.allStyleImports.indexOf(resolvedId);
|
||||||
|
return !~moduleIndex ? _this._pluginContext.allStyleImports.push(resolvedId) - 1 : moduleIndex;
|
||||||
|
};
|
||||||
|
this._pluginContext = pluginContext;
|
||||||
|
this._outputOptions = outputOptions;
|
||||||
|
}
|
||||||
|
ImportUpdater.prototype.getMagicId = function (id) {
|
||||||
|
return "\0" + this.addImportAndGetNewId(id) + KEY_EXT_STRING;
|
||||||
|
};
|
||||||
|
ImportUpdater.prototype.updateImports = function (code, chunk, bundleOutDir, moduleRoot) {
|
||||||
|
var _this = this;
|
||||||
|
var magicString = new MagicString(code);
|
||||||
|
var matchRegex = new RegExp("\0([^\"']+)".concat(escapeRegex(KEY_EXT_STRING)), "g");
|
||||||
|
Array.from(code.matchAll(matchRegex))
|
||||||
|
.reverse()
|
||||||
|
.forEach(function (m) {
|
||||||
|
return _this.updateMatchedImport(m, magicString, {
|
||||||
|
chunk: chunk,
|
||||||
|
bundleOutDir: bundleOutDir,
|
||||||
|
moduleRoot: moduleRoot,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
code: magicString.toString(),
|
||||||
|
map: magicString.generateMap({ hires: true }),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
ImportUpdater.prototype.updateMatchedImport = function (m, magicString, chunkDetails) {
|
||||||
|
var importId = m[0];
|
||||||
|
var assetId = this._pluginContext.allStyleImports[m[1]];
|
||||||
|
if (!assetId || typeof assetId !== "string" || !this._pluginContext.stylesToEmit[assetId]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var updatedImport = this.saveAndGetUpdatedImportPath(assetId, chunkDetails);
|
||||||
|
var start = m.index;
|
||||||
|
var end = start + importId.length;
|
||||||
|
magicString.overwrite(start, end, updatedImport);
|
||||||
|
this.updateChunk(importId, updatedImport, chunkDetails.chunk);
|
||||||
|
};
|
||||||
|
ImportUpdater.prototype.updateChunk = function (importId, updatedImport, chunk) {
|
||||||
|
if (chunk.importedBindings[importId]) {
|
||||||
|
chunk.importedBindings[updatedImport] = chunk.importedBindings[importId];
|
||||||
|
if (updatedImport !== importId) {
|
||||||
|
delete chunk.importedBindings[importId];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var importIndex = chunk.imports.indexOf(importId);
|
||||||
|
if (~importIndex) {
|
||||||
|
chunk.imports[importIndex] = updatedImport;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ImportUpdater.prototype.saveAndGetUpdatedImportPath = function (assetId, _a) {
|
||||||
|
var bundleOutDir = _a.bundleOutDir, moduleRoot = _a.moduleRoot, chunk = _a.chunk;
|
||||||
|
var assetOutput = this.resolveOutputPath(bundleOutDir, assetId, moduleRoot);
|
||||||
|
var updatedImport = path
|
||||||
|
.relative(path.dirname(path.resolve(bundleOutDir, chunk.fileName)), assetOutput)
|
||||||
|
.replace(/\\/g, "/");
|
||||||
|
this._pluginContext.stylesToEmit[assetId].output = path.relative(path.resolve(bundleOutDir), assetOutput);
|
||||||
|
if (this.shouldAddPrefixCurrentDir(updatedImport) &&
|
||||||
|
!updatedImport.startsWith("./") &&
|
||||||
|
!updatedImport.startsWith("../") &&
|
||||||
|
!updatedImport.match(/^[a-zA-Z]:/)) {
|
||||||
|
updatedImport = "./" + updatedImport;
|
||||||
|
}
|
||||||
|
return updatedImport;
|
||||||
|
};
|
||||||
|
ImportUpdater.prototype.shouldAddPrefixCurrentDir = function (updatedImport) {
|
||||||
|
var skip = this._outputOptions.skipCurrentFolderPart;
|
||||||
|
return !skip || (skip instanceof RegExp && !skip.test(updatedImport));
|
||||||
|
};
|
||||||
|
ImportUpdater.prototype.resolveOutputPath = function (bundleOutDir, assetId, moduleRoot) {
|
||||||
|
var _a = this._outputOptions, outputPath = _a.outputPath, outputDir = _a.outputDir, outputExt = _a.outputExt;
|
||||||
|
var newPath = undefined;
|
||||||
|
if (typeof outputPath === "function") {
|
||||||
|
newPath = outputPath(assetId);
|
||||||
|
assertLocation(bundleOutDir, newPath);
|
||||||
|
}
|
||||||
|
else if (typeof outputPath === "string") {
|
||||||
|
newPath = path.resolve(bundleOutDir, outputDir, outputPath !== "keep" ? outputPath : path.relative(moduleRoot, assetId));
|
||||||
|
assertLocation(bundleOutDir, newPath);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new Error(createErrorMessage("Invalid outputPath option value!"));
|
||||||
|
}
|
||||||
|
return newPath.replace(/\.s[ca]ss$/, outputExt);
|
||||||
|
};
|
||||||
|
return ImportUpdater;
|
||||||
|
}());
|
||||||
|
|
||||||
|
var ensureStylesInfo = function (stylesMap, importer, resolvedId) {
|
||||||
|
stylesMap[resolvedId] = stylesMap[resolvedId] || { importers: [], watchList: [] };
|
||||||
|
stylesMap[resolvedId].importers.push(importer);
|
||||||
|
return stylesMap[resolvedId];
|
||||||
|
};
|
||||||
|
var ensureCodeAndWatchList = function (filePath, stylesInfo, isWatch, compilerOptions) {
|
||||||
|
return __awaiter(void 0, void 0, void 0, function () {
|
||||||
|
var outWatchList, _a, _b, css, map;
|
||||||
|
return __generator(this, function (_c) {
|
||||||
|
switch (_c.label) {
|
||||||
|
case 0:
|
||||||
|
outWatchList = [];
|
||||||
|
if (!filePath.endsWith(".css")) return [3 /*break*/, 2];
|
||||||
|
_a = stylesInfo;
|
||||||
|
return [4 /*yield*/, readFile(filePath, "utf8")];
|
||||||
|
case 1:
|
||||||
|
_a.css = _c.sent();
|
||||||
|
return [3 /*break*/, 4];
|
||||||
|
case 2: return [4 /*yield*/, compileSass(filePath, isWatch ? outWatchList : undefined, compilerOptions)];
|
||||||
|
case 3:
|
||||||
|
_b = _c.sent(), css = _b.css, map = _b.map;
|
||||||
|
stylesInfo.css = css;
|
||||||
|
stylesInfo.map = map;
|
||||||
|
_c.label = 4;
|
||||||
|
case 4:
|
||||||
|
outWatchList.push(filePath);
|
||||||
|
stylesInfo.watchList = outWatchList.map(function (watchFile) { return path.resolve(watchFile.replace(FILE_URL_PREFIX, "")); });
|
||||||
|
return [2 /*return*/];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
function keepCssImports(_a) {
|
||||||
|
if (_a === void 0) { _a = {}; }
|
||||||
|
var _b = _a.outputExt, outputExt = _b === void 0 ? ".css" : _b, _c = _a.outputPath, outputPath = _c === void 0 ? "keep" : _c, _d = _a.skipCurrentFolderPart, skipCurrentFolderPart = _d === void 0 ? false : _d, _e = _a.includeRegexp, includeRegexp = _e === void 0 ? /\.(?:s[ca]|c)ss$/ : _e, sass = _a.sass, postProcessor = _a.postProcessor, sassOptions = _a.sassOptions, options = __rest(_a, ["outputExt", "outputPath", "skipCurrentFolderPart", "includeRegexp", "sass", "postProcessor", "sassOptions"]);
|
||||||
|
var stylesOutputOptions = {
|
||||||
|
outputPath: outputPath,
|
||||||
|
outputExt: outputExt,
|
||||||
|
outputDir: options.outputDir ? path.resolve(options.outputDir) : "./",
|
||||||
|
skipCurrentFolderPart: skipCurrentFolderPart,
|
||||||
|
};
|
||||||
|
var context = {
|
||||||
|
allStyleImports: [],
|
||||||
|
modulesWithCss: new Set(),
|
||||||
|
stylesToEmit: {},
|
||||||
|
};
|
||||||
|
var importUpdater = new ImportUpdater(context, stylesOutputOptions);
|
||||||
|
var loadPaths = options.includePaths || ["node_modules/"];
|
||||||
|
loadPaths.push(process.cwd());
|
||||||
|
loadPaths = loadPaths.filter(function (v, i, a) { return a.indexOf(v) === i; });
|
||||||
|
var compilerOptions = {
|
||||||
|
outputExt: outputExt,
|
||||||
|
sass: sass,
|
||||||
|
postProcessor: typeof postProcessor === "function"
|
||||||
|
? function (css, map) { return postProcessor(css, map, context.stylesToEmit); }
|
||||||
|
: undefined,
|
||||||
|
loadPaths: loadPaths,
|
||||||
|
sourceMap: !!options.sourceMap,
|
||||||
|
sassOptions: sassOptions,
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
name: PLUGIN_NAME,
|
||||||
|
resolveId: function (source, importer, resolveOptions) {
|
||||||
|
return __awaiter(this, void 0, void 0, function () {
|
||||||
|
var _a, custom, _b, _c, _d, _e, _f, alreadyResolving, resolved, styleInfo;
|
||||||
|
var _g, _h;
|
||||||
|
var _this = this;
|
||||||
|
return __generator(this, function (_j) {
|
||||||
|
switch (_j.label) {
|
||||||
|
case 0:
|
||||||
|
if (!importer || !includeRegexp.test(source) || /\0/.test(source)) {
|
||||||
|
return [2 /*return*/, null];
|
||||||
|
}
|
||||||
|
_a = resolveOptions.custom, custom = _a === void 0 ? {} : _a;
|
||||||
|
_b = custom, _c = PLUGIN_NAME, _d = _b[_c], _e = _d === void 0 ? {} : _d, _f = _e.resolving, alreadyResolving = _f === void 0 ? false : _f;
|
||||||
|
if (alreadyResolving) {
|
||||||
|
return [2 /*return*/, null];
|
||||||
|
}
|
||||||
|
return [4 /*yield*/, this.resolve(source, importer, __assign(__assign({ skipSelf: true }, resolveOptions), { custom: __assign(__assign({}, custom), (_g = {}, _g[PLUGIN_NAME] = __assign(__assign({}, custom[PLUGIN_NAME]), { resolving: true }), _g)) }))];
|
||||||
|
case 1:
|
||||||
|
resolved = _j.sent();
|
||||||
|
if (!resolved || resolved.external) {
|
||||||
|
return [2 /*return*/, resolved];
|
||||||
|
}
|
||||||
|
context.modulesWithCss.add(importer);
|
||||||
|
styleInfo = ensureStylesInfo(context.stylesToEmit, importer, resolved.id);
|
||||||
|
return [4 /*yield*/, ensureCodeAndWatchList(resolved.id, styleInfo, this.meta.watchMode, compilerOptions)];
|
||||||
|
case 2:
|
||||||
|
_j.sent();
|
||||||
|
styleInfo.watchList.forEach(function (watchFile) {
|
||||||
|
_this.addWatchFile(watchFile);
|
||||||
|
});
|
||||||
|
return [2 /*return*/, {
|
||||||
|
id: importUpdater.getMagicId(resolved.id),
|
||||||
|
meta: (_h = {}, _h[PLUGIN_NAME] = { sourceId: resolved.id }, _h),
|
||||||
|
external: true,
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
buildStart: function () {
|
||||||
|
var _this = this;
|
||||||
|
// Every rebuild will refresh watcher, so we need to reattach
|
||||||
|
if (this.meta.watchMode) {
|
||||||
|
var allWatched_1 = this.getWatchFiles();
|
||||||
|
Object.values(context.stylesToEmit).forEach(function (styleInfo) {
|
||||||
|
return styleInfo.watchList.forEach(function (watchFile) {
|
||||||
|
if (!allWatched_1.find(function (watched) { return path.normalize(watched) === path.normalize(watchFile); })) {
|
||||||
|
_this.addWatchFile(watchFile);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watchChange: function (id) {
|
||||||
|
return __awaiter(this, void 0, void 0, function () {
|
||||||
|
var resolvedId, filesToUpdate;
|
||||||
|
var _this = this;
|
||||||
|
return __generator(this, function (_a) {
|
||||||
|
switch (_a.label) {
|
||||||
|
case 0:
|
||||||
|
resolvedId = path.resolve(id);
|
||||||
|
filesToUpdate = Object.entries(context.stylesToEmit).filter(function (_a) {
|
||||||
|
var styleInfo = _a[1];
|
||||||
|
return styleInfo.watchList.includes(resolvedId);
|
||||||
|
});
|
||||||
|
return [4 /*yield*/, Promise.all(filesToUpdate.map(function (_a) {
|
||||||
|
var fileName = _a[0], styleInfo = _a[1];
|
||||||
|
return ensureCodeAndWatchList(fileName, styleInfo, _this.meta.watchMode, compilerOptions);
|
||||||
|
}))];
|
||||||
|
case 1:
|
||||||
|
_a.sent();
|
||||||
|
return [2 /*return*/];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
renderChunk: function (code, chunk, outputOptions) {
|
||||||
|
var bundleOutDir = path.resolve(outputOptions.dir || path.dirname(outputOptions.file));
|
||||||
|
if (code && chunk.modules && Object.keys(chunk.modules).some(function (m) { return context.modulesWithCss.has(m); })) {
|
||||||
|
var moduleRoot = outputOptions.preserveModulesRoot || process.cwd();
|
||||||
|
return importUpdater.updateImports(code, chunk, bundleOutDir, moduleRoot);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
generateBundle: function (_, __, isWrite) {
|
||||||
|
if (!isWrite) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
assertDuplicates(context.stylesToEmit);
|
||||||
|
for (var file in context.stylesToEmit) {
|
||||||
|
var stylesInfo = context.stylesToEmit[file];
|
||||||
|
var fileName = stylesInfo.output;
|
||||||
|
var source = file.endsWith(".css")
|
||||||
|
? stylesInfo.css
|
||||||
|
: ensureSourceMap(stylesInfo, options.sourceMap || (sassOptions === null || sassOptions === void 0 ? void 0 : sassOptions.sourceMap), fileName, this.emitFile);
|
||||||
|
this.emitFile({
|
||||||
|
type: "asset",
|
||||||
|
fileName: fileName,
|
||||||
|
source: source,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export { keepCssImports as default };
|
||||||
110
build/esm/rollup-plugin-keep-css-imports/dist/types.d.ts
vendored
Normal file
110
build/esm/rollup-plugin-keep-css-imports/dist/types.d.ts
vendored
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
import { type CompilationOptions, PostCssCompatible } from "./compileSass";
|
||||||
|
import type { Options as SassOptions } from "sass";
|
||||||
|
export type KeepCssImportsOptions = OutputOptions & InputOptions & Extensions;
|
||||||
|
export type StyleRefInfo = {
|
||||||
|
/**
|
||||||
|
* Collection of files with reference to the current file
|
||||||
|
*/
|
||||||
|
importers: string[];
|
||||||
|
/**
|
||||||
|
* List of files which are used to render the current file
|
||||||
|
*/
|
||||||
|
watchList: string[];
|
||||||
|
/**
|
||||||
|
* Emit path
|
||||||
|
*/
|
||||||
|
output?: string;
|
||||||
|
/**
|
||||||
|
* Processed CSS content to emit
|
||||||
|
*/
|
||||||
|
css?: string | Uint8Array;
|
||||||
|
/**
|
||||||
|
* Processed CSS content map to emit
|
||||||
|
*/
|
||||||
|
map?: string | Uint8Array;
|
||||||
|
};
|
||||||
|
export type StylesMap = Record<string, StyleRefInfo>;
|
||||||
|
interface Extensions {
|
||||||
|
/**
|
||||||
|
* Customised SASS (SCSS) processor. If not provided plugin will try to
|
||||||
|
* import locally installed `sass` if required
|
||||||
|
*/
|
||||||
|
sass?: CompilationOptions["sass"];
|
||||||
|
/**
|
||||||
|
* An optional object that allows to provide additional options for the
|
||||||
|
* SASS compiler.
|
||||||
|
*/
|
||||||
|
sassOptions?: SassOptions<"async">;
|
||||||
|
/**
|
||||||
|
* Specifies the list of include paths for SASS to search when resolving imports.
|
||||||
|
*
|
||||||
|
* Default: `["node_modules/"]`
|
||||||
|
*/
|
||||||
|
includePaths?: string[];
|
||||||
|
/**
|
||||||
|
* An optional function that allows you to perform additional processing on the
|
||||||
|
* generated CSS, such as applying PostCSS plugins.
|
||||||
|
*/
|
||||||
|
postProcessor?: (css: string, map: string, stylesMap: StylesMap) => Promise<PostCssCompatible | string | {
|
||||||
|
css: string;
|
||||||
|
map?: string;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
type OutputPath = string | "keep" | ((assetId: string) => string);
|
||||||
|
export interface OutputOptions {
|
||||||
|
/**
|
||||||
|
* Specifies the file extension for the output CSS files.
|
||||||
|
*
|
||||||
|
* Default: `".css"`
|
||||||
|
*/
|
||||||
|
outputExt?: string;
|
||||||
|
/**
|
||||||
|
* Specifies the output directory for the generated CSS files.
|
||||||
|
* Relative to Rollup output folder.
|
||||||
|
*
|
||||||
|
* Default: `"./"`
|
||||||
|
*/
|
||||||
|
outputDir?: string;
|
||||||
|
/**
|
||||||
|
* Specifies the output path relative to `outputDir` for the generated CSS
|
||||||
|
* files.
|
||||||
|
* The default value, "keep", preserves the original file paths. It is also
|
||||||
|
* possible to provide a custom function to generate output paths based on
|
||||||
|
* the input file.
|
||||||
|
*
|
||||||
|
* Default: `"keep"`
|
||||||
|
*/
|
||||||
|
outputPath?: OutputPath;
|
||||||
|
/**
|
||||||
|
* Specifies whether to generate source maps for the compiled CSS.
|
||||||
|
* Use `"inline"` to inline source maps into CSS files.
|
||||||
|
*
|
||||||
|
* Default: `false`
|
||||||
|
*/
|
||||||
|
sourceMap?: boolean | "inline";
|
||||||
|
/**
|
||||||
|
* By default CSS paths will be prefixed with current folder mark `./`.
|
||||||
|
* To avoid this for CSS files use `true` or specify RegExp filter.
|
||||||
|
*
|
||||||
|
* If RegExp filter matches `./` won't be added to the path.
|
||||||
|
* This option may be helpful if you have some issues with external
|
||||||
|
* modules imports from `node_modules`
|
||||||
|
*
|
||||||
|
* Default: `false`
|
||||||
|
*/
|
||||||
|
skipCurrentFolderPart?: boolean | RegExp;
|
||||||
|
}
|
||||||
|
interface InputOptions {
|
||||||
|
/**
|
||||||
|
* Regular expression to test if an import should be processed by this plugin
|
||||||
|
*
|
||||||
|
* Default: `/\.(?:s[ca]|c)ss$/`
|
||||||
|
*/
|
||||||
|
includeRegexp?: RegExp;
|
||||||
|
}
|
||||||
|
export interface KeepCssImportsPluginContext {
|
||||||
|
allStyleImports: string[];
|
||||||
|
modulesWithCss: Set<string>;
|
||||||
|
stylesToEmit: StylesMap;
|
||||||
|
}
|
||||||
|
export {};
|
||||||
74
build/esm/rollup-plugin-keep-css-imports/package.json
Normal file
74
build/esm/rollup-plugin-keep-css-imports/package.json
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
{
|
||||||
|
"name": "rollup-plugin-keep-css-imports",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Rollup plugin that allows to maintain the original structure of style imports without altering them during the bundling process",
|
||||||
|
"main": "dist/index.cjs",
|
||||||
|
"module": "dist/index.mjs",
|
||||||
|
"types": "dist/index.d.ts",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"import": {
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"default": "./dist/index.mjs"
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"default": "./dist/index.cjs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist",
|
||||||
|
"README.md",
|
||||||
|
"LICENSE"
|
||||||
|
],
|
||||||
|
"keywords": [
|
||||||
|
"rollup",
|
||||||
|
"rollup-plugin",
|
||||||
|
"css-modules",
|
||||||
|
"sass",
|
||||||
|
"scss",
|
||||||
|
"keep",
|
||||||
|
"preserve",
|
||||||
|
"imports"
|
||||||
|
],
|
||||||
|
"homepage": "https://github.com/SLTKA/rollup-plugin-keep-css-imports",
|
||||||
|
"author": "Alexandr Yeskov",
|
||||||
|
"license": "MIT",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/SLTKA/rollup-plugin-keep-css-imports"
|
||||||
|
},
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/SLTKA/rollup-plugin-keep-css-imports/issues"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"prebuild": "rimraf -rf dist/",
|
||||||
|
"build": "rollup -c",
|
||||||
|
"test": "mocha",
|
||||||
|
"pretest": "yarn build"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@rollup/plugin-typescript": "^11.1.6",
|
||||||
|
"@types/mocha": "^10.0.6",
|
||||||
|
"@types/node": "^20.11.24",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^7.1.1",
|
||||||
|
"@typescript-eslint/parser": "^7.1.1",
|
||||||
|
"eslint": "^8.57.0",
|
||||||
|
"eslint-config-prettier": "^9.1.0",
|
||||||
|
"eslint-plugin-mocha": "^10.2.0",
|
||||||
|
"eslint-plugin-prettier": "^5.1.3",
|
||||||
|
"mocha": "^10.2.0",
|
||||||
|
"prettier": "^3.2.4",
|
||||||
|
"rimraf": "^5.0.5",
|
||||||
|
"rollup": "^4.9.5",
|
||||||
|
"rollup-plugin-dts": "^6.1.0",
|
||||||
|
"sass": "^1.70.0",
|
||||||
|
"ts-node": "^10.9.2",
|
||||||
|
"typescript": "^5.3.3",
|
||||||
|
"typescript-eslint": "^7.1.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"magic-string": "^0.30.5"
|
||||||
|
}
|
||||||
|
}
|
||||||
67
build/esm/rollup-types.config.mjs
Normal file
67
build/esm/rollup-types.config.mjs
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
// @ts-check
|
||||||
|
|
||||||
|
import nodeResolve from '@rollup/plugin-node-resolve';
|
||||||
|
import { join } from 'path';
|
||||||
|
import { defineConfig } from 'rollup';
|
||||||
|
import { dts } from "rollup-plugin-dts";
|
||||||
|
|
||||||
|
const root = join(import.meta.dirname, '../../');
|
||||||
|
const outDir = join(root, './out/monaco-editor/esm');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} filePath
|
||||||
|
* @param {string} newExt
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function changeExt(filePath, newExt) {
|
||||||
|
const idx = filePath.lastIndexOf('.');
|
||||||
|
if (idx === -1) {
|
||||||
|
return filePath + newExt;
|
||||||
|
} else {
|
||||||
|
return filePath.substring(0, idx) + newExt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mappedPaths = {
|
||||||
|
[join(root, 'node_modules/monaco-editor-core/esm/')]: '.',
|
||||||
|
[join(root, 'node_modules/')]: 'external/',
|
||||||
|
[join(root, 'src/')]: 'vs/',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
input: {
|
||||||
|
entry: join(root, './src/editor/editor.main.ts'),
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
dir: outDir,
|
||||||
|
format: 'es',
|
||||||
|
preserveModules: false,
|
||||||
|
entryFileNames: function (chunkInfo) {
|
||||||
|
const moduleId = chunkInfo.facadeModuleId;
|
||||||
|
if (moduleId) {
|
||||||
|
for (const [key, val] of Object.entries(mappedPaths)) {
|
||||||
|
if (moduleId.startsWith(key)) {
|
||||||
|
const relativePath = moduleId.substring(key.length);
|
||||||
|
return changeExt(join(val, relativePath), '.d.ts');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return '[name].d.ts';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
external: [/.*\.css/],
|
||||||
|
plugins: [
|
||||||
|
nodeResolve(),
|
||||||
|
dts({
|
||||||
|
compilerOptions: {
|
||||||
|
stripInternal: true,
|
||||||
|
},
|
||||||
|
includeExternal: ['monaco-editor-core', '@vscode/monaco-lsp-client']
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
63
build/esm/rollup-url-to-module-plugin/index.mjs
Normal file
63
build/esm/rollup-url-to-module-plugin/index.mjs
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {() => import('rollup').Plugin}
|
||||||
|
*/
|
||||||
|
export function urlToEsmPlugin() {
|
||||||
|
return {
|
||||||
|
name: 'import-meta-url',
|
||||||
|
async transform(code, id) {
|
||||||
|
if (this.environment?.mode === 'dev') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for `new URL(..., import.meta.url)` patterns.
|
||||||
|
const regex = /new\s+URL\s*\(\s*(['"`])(.*?)\1\s*,\s*import\.meta\.url\s*\)?/g;
|
||||||
|
|
||||||
|
let match;
|
||||||
|
let modified = false;
|
||||||
|
let result = code;
|
||||||
|
let offset = 0;
|
||||||
|
|
||||||
|
while ((match = regex.exec(code)) !== null) {
|
||||||
|
let path = match[2];
|
||||||
|
|
||||||
|
if (!path.startsWith('.') && !path.startsWith('/')) {
|
||||||
|
path = `./${path}`;
|
||||||
|
}
|
||||||
|
const resolved = await this.resolve(path, id);
|
||||||
|
|
||||||
|
if (!resolved) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the file as an entry point
|
||||||
|
const refId = this.emitFile({
|
||||||
|
type: 'chunk',
|
||||||
|
id: resolved.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const start = match.index;
|
||||||
|
const end = start + match[0].length;
|
||||||
|
|
||||||
|
const replacement = `import.meta.ROLLUP_FILE_URL_OBJ_${refId}`;
|
||||||
|
|
||||||
|
result = result.slice(0, start + offset) + replacement + result.slice(end + offset);
|
||||||
|
offset += replacement.length - (end - start);
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!modified) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
code: result,
|
||||||
|
map: null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
109
build/esm/rollup.config.mjs
Normal file
109
build/esm/rollup.config.mjs
Normal file
|
|
@ -0,0 +1,109 @@
|
||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
// @ts-check
|
||||||
|
|
||||||
|
import { join, relative } from 'path';
|
||||||
|
import { defineConfig } from 'rollup';
|
||||||
|
import esbuild from 'rollup-plugin-esbuild';
|
||||||
|
//import { urlToEsmPlugin } from '../rollup-url-to-module-plugin/index.mjs';
|
||||||
|
import del from 'rollup-plugin-delete';
|
||||||
|
import keepCssImports from './rollup-plugin-keep-css-imports/dist/index.mjs';
|
||||||
|
import nodeResolve from '@rollup/plugin-node-resolve';
|
||||||
|
import { urlToEsmPlugin } from './rollup-url-to-module-plugin/index.mjs';
|
||||||
|
import { copyFileSync, mkdirSync } from 'fs';
|
||||||
|
import { dirname } from 'path';
|
||||||
|
|
||||||
|
const root = join(import.meta.dirname, '../../');
|
||||||
|
const outDir = join(root, './out/monaco-editor/esm');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} filePath
|
||||||
|
* @param {string} newExt
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function changeExt(filePath, newExt) {
|
||||||
|
const idx = filePath.lastIndexOf('.');
|
||||||
|
if (idx === -1) {
|
||||||
|
return filePath + newExt;
|
||||||
|
} else {
|
||||||
|
return filePath.substring(0, idx) + newExt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mappedPaths = {
|
||||||
|
[join(root, 'node_modules/monaco-editor-core/esm/')]: '.',
|
||||||
|
[join(root, 'node_modules/')]: 'external/',
|
||||||
|
[join(root, 'monaco-lsp-client/')]: 'external/monaco-lsp-client/',
|
||||||
|
[join(root, 'src/')]: 'vs/',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
input: {
|
||||||
|
entry: join(root, './src/editor/editor.main.ts'),
|
||||||
|
editorAll: join(root, './src/editor/editor.all.ts'),
|
||||||
|
edcoreMain: join(root, './src/editor/edcore.main.ts'),
|
||||||
|
editorApi: join(root, './src/editor/editor.api.ts'),
|
||||||
|
editorWorker: join(root, './src/editor/editor.worker.ts'),
|
||||||
|
},
|
||||||
|
|
||||||
|
output: {
|
||||||
|
dir: outDir,
|
||||||
|
format: 'es',
|
||||||
|
|
||||||
|
entryFileNames: function (chunkInfo) {
|
||||||
|
const moduleId = chunkInfo.facadeModuleId;
|
||||||
|
if (moduleId) {
|
||||||
|
for (const [key, val] of Object.entries(mappedPaths)) {
|
||||||
|
if (moduleId.startsWith(key)) {
|
||||||
|
const relativePath = moduleId.substring(key.length);
|
||||||
|
return changeExt(join(val, relativePath), '.js');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return '[name].js';
|
||||||
|
},
|
||||||
|
preserveModules: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
plugins: [
|
||||||
|
del({ targets: outDir, force: true }),
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'copy-codicon-font',
|
||||||
|
buildEnd() {
|
||||||
|
const codiconSource = join(root, 'node_modules/monaco-editor-core/esm/vs/base/browser/ui/codicons/codicon/codicon.ttf');
|
||||||
|
const codiconDest = join(outDir, 'vs/base/browser/ui/codicons/codicon/codicon.ttf');
|
||||||
|
mkdirSync(dirname(codiconDest), { recursive: true });
|
||||||
|
copyFileSync(codiconSource, codiconDest);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
urlToEsmPlugin(),
|
||||||
|
esbuild(),
|
||||||
|
|
||||||
|
keepCssImports({
|
||||||
|
/**
|
||||||
|
* @param {string} assetId
|
||||||
|
*/
|
||||||
|
outputPath: (assetId) => {
|
||||||
|
for (const [key, val] of Object.entries(mappedPaths)) {
|
||||||
|
if (assetId.startsWith(key)) {
|
||||||
|
const relativePath = assetId.substring(key.length);
|
||||||
|
return changeExt(join(outDir, val, relativePath), '.css');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const relativePath = join(outDir, relative(root, assetId));
|
||||||
|
return relativePath.replace(/(\.s[ca]ss)$/, ".min$1")
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
nodeResolve({
|
||||||
|
dedupe: ['monaco-editor-core', '@vscode/monaco-lsp-client'],
|
||||||
|
browser: true,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------------------------
|
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
||||||
*--------------------------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
export interface Options {
|
|
||||||
locale?: string;
|
|
||||||
cacheLanguageResolution?: boolean;
|
|
||||||
}
|
|
||||||
export interface LocalizeInfo {
|
|
||||||
key: string;
|
|
||||||
comment: string[];
|
|
||||||
}
|
|
||||||
export interface LocalizeFunc {
|
|
||||||
(info: LocalizeInfo, message: string, ...args: any[]): string;
|
|
||||||
(key: string, message: string, ...args: any[]): string;
|
|
||||||
}
|
|
||||||
export interface LoadFunc {
|
|
||||||
(file?: string): LocalizeFunc;
|
|
||||||
}
|
|
||||||
|
|
||||||
function format(message: string, args: any[]): string {
|
|
||||||
let result: string;
|
|
||||||
|
|
||||||
if (args.length === 0) {
|
|
||||||
result = message;
|
|
||||||
} else {
|
|
||||||
result = message.replace(/\{(\d+)\}/g, (match, rest) => {
|
|
||||||
let index = rest[0];
|
|
||||||
return typeof args[index] !== 'undefined' ? args[index] : match;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function localize(key: string | LocalizeInfo, message: string, ...args: any[]): string {
|
|
||||||
return format(message, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function loadMessageBundle(file?: string): LocalizeFunc {
|
|
||||||
return localize;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function config(opt?: Options | string): LoadFunc {
|
|
||||||
return loadMessageBundle;
|
|
||||||
}
|
|
||||||
|
|
@ -103,7 +103,7 @@ function getAdvancedLanguages(): Promise<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function generateMetadata() {
|
export function generateEsmMetadataJsAndDTs() {
|
||||||
return Promise.all([getBasicLanguages(), getAdvancedLanguages()]).then(
|
return Promise.all([getBasicLanguages(), getAdvancedLanguages()]).then(
|
||||||
([basicLanguages, advancedLanguages]) => {
|
([basicLanguages, advancedLanguages]) => {
|
||||||
basicLanguages.sort((a, b) => strcmp(a.entry, b.entry));
|
basicLanguages.sort((a, b) => strcmp(a.entry, b.entry));
|
||||||
|
|
|
||||||
179
build/utils.ts
179
build/utils.ts
|
|
@ -5,190 +5,11 @@
|
||||||
|
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as cp from 'child_process';
|
|
||||||
import * as esbuild from 'esbuild';
|
|
||||||
import alias from 'esbuild-plugin-alias';
|
|
||||||
import * as glob from 'glob';
|
import * as glob from 'glob';
|
||||||
import { ensureDir } from './fs';
|
import { ensureDir } from './fs';
|
||||||
|
|
||||||
export const REPO_ROOT = path.join(__dirname, '../');
|
export const REPO_ROOT = path.join(__dirname, '../');
|
||||||
|
|
||||||
/**
|
|
||||||
* Launch the typescript compiler synchronously over a project.
|
|
||||||
*/
|
|
||||||
export function runTsc(_projectPath: string) {
|
|
||||||
const projectPath = path.join(REPO_ROOT, _projectPath);
|
|
||||||
console.log(`Launching compiler at ${_projectPath}...`);
|
|
||||||
const res = cp.spawnSync(
|
|
||||||
process.execPath,
|
|
||||||
[path.join(__dirname, '../node_modules/typescript/lib/tsc.js'), '-p', projectPath],
|
|
||||||
{ stdio: 'inherit' }
|
|
||||||
);
|
|
||||||
console.log(`Compiled ${_projectPath}`);
|
|
||||||
if (res.status !== 0) {
|
|
||||||
process.exit(res.status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Launch prettier on a specific file.
|
|
||||||
*/
|
|
||||||
export function prettier(_filePath: string) {
|
|
||||||
const filePath = path.join(REPO_ROOT, _filePath);
|
|
||||||
cp.spawnSync(
|
|
||||||
process.execPath,
|
|
||||||
[path.join(__dirname, '../node_modules/prettier/bin-prettier.js'), '--write', filePath],
|
|
||||||
{ stdio: 'inherit' }
|
|
||||||
);
|
|
||||||
|
|
||||||
console.log(`Ran prettier over ${_filePath}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Transform an external .d.ts file to an internal .d.ts file
|
|
||||||
*/
|
|
||||||
export function massageAndCopyDts(source: string, destination: string, namespace: string) {
|
|
||||||
const absoluteSource = path.join(REPO_ROOT, source);
|
|
||||||
const absoluteDestination = path.join(REPO_ROOT, destination);
|
|
||||||
|
|
||||||
const lines = fs
|
|
||||||
.readFileSync(absoluteSource)
|
|
||||||
.toString()
|
|
||||||
.split(/\r\n|\r|\n/);
|
|
||||||
|
|
||||||
let result = [
|
|
||||||
`/*---------------------------------------------------------------------------------------------`,
|
|
||||||
` * Copyright (c) Microsoft Corporation. All rights reserved.`,
|
|
||||||
` * Licensed under the MIT License. See License.txt in the project root for license information.`,
|
|
||||||
` *--------------------------------------------------------------------------------------------*/`,
|
|
||||||
``,
|
|
||||||
`declare namespace ${namespace} {`
|
|
||||||
];
|
|
||||||
for (let line of lines) {
|
|
||||||
if (/^import/.test(line)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (line === 'export {};') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
line = line.replace(/ /g, '\t');
|
|
||||||
line = line.replace(/declare /g, '');
|
|
||||||
if (line.length > 0) {
|
|
||||||
line = `\t${line}`;
|
|
||||||
result.push(line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result.push(`}`);
|
|
||||||
result.push(``);
|
|
||||||
|
|
||||||
ensureDir(path.dirname(absoluteDestination));
|
|
||||||
fs.writeFileSync(absoluteDestination, result.join('\n'));
|
|
||||||
|
|
||||||
prettier(destination);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function build(options: import('esbuild').BuildOptions) {
|
|
||||||
esbuild.build(options).then((result) => {
|
|
||||||
if (result.errors.length > 0) {
|
|
||||||
console.error(result.errors);
|
|
||||||
}
|
|
||||||
if (result.warnings.length > 0) {
|
|
||||||
console.error(result.warnings);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function buildESM(options: { base: string; entryPoints: string[]; external: string[] }) {
|
|
||||||
build({
|
|
||||||
entryPoints: options.entryPoints,
|
|
||||||
bundle: true,
|
|
||||||
target: 'esnext',
|
|
||||||
format: 'esm',
|
|
||||||
drop: ['debugger'],
|
|
||||||
define: {
|
|
||||||
AMD: 'false'
|
|
||||||
},
|
|
||||||
banner: {
|
|
||||||
js: bundledFileHeader
|
|
||||||
},
|
|
||||||
external: options.external,
|
|
||||||
outbase: `src/${options.base}`,
|
|
||||||
outdir: `out/languages/bundled/esm/vs/${options.base}/`,
|
|
||||||
plugins: [
|
|
||||||
alias({
|
|
||||||
'vscode-nls': path.join(__dirname, 'fillers/vscode-nls.ts')
|
|
||||||
})
|
|
||||||
]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getGitVersion() {
|
|
||||||
const git = path.join(REPO_ROOT, '.git');
|
|
||||||
const headPath = path.join(git, 'HEAD');
|
|
||||||
let head;
|
|
||||||
|
|
||||||
try {
|
|
||||||
head = fs.readFileSync(headPath, 'utf8').trim();
|
|
||||||
} catch (e) {
|
|
||||||
return void 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (/^[0-9a-f]{40}$/i.test(head)) {
|
|
||||||
return head;
|
|
||||||
}
|
|
||||||
|
|
||||||
const refMatch = /^ref: (.*)$/.exec(head);
|
|
||||||
|
|
||||||
if (!refMatch) {
|
|
||||||
return void 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ref = refMatch[1];
|
|
||||||
const refPath = path.join(git, ref);
|
|
||||||
|
|
||||||
try {
|
|
||||||
return fs.readFileSync(refPath, 'utf8').trim();
|
|
||||||
} catch (e) {
|
|
||||||
// noop
|
|
||||||
}
|
|
||||||
|
|
||||||
const packedRefsPath = path.join(git, 'packed-refs');
|
|
||||||
let refsRaw;
|
|
||||||
|
|
||||||
try {
|
|
||||||
refsRaw = fs.readFileSync(packedRefsPath, 'utf8').trim();
|
|
||||||
} catch (e) {
|
|
||||||
return void 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const refsRegex = /^([0-9a-f]{40})\s+(.+)$/gm;
|
|
||||||
let refsMatch;
|
|
||||||
const refs = {};
|
|
||||||
|
|
||||||
while ((refsMatch = refsRegex.exec(refsRaw))) {
|
|
||||||
refs[refsMatch[2]] = refsMatch[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
return refs[ref];
|
|
||||||
}
|
|
||||||
|
|
||||||
export const bundledFileHeader = (() => {
|
|
||||||
const sha1 = getGitVersion();
|
|
||||||
const semver = require('../package.json').version;
|
|
||||||
const headerVersion = semver + '(' + sha1 + ')';
|
|
||||||
|
|
||||||
const BUNDLED_FILE_HEADER = [
|
|
||||||
'/*!-----------------------------------------------------------------------------',
|
|
||||||
' * Copyright (c) Microsoft Corporation. All rights reserved.',
|
|
||||||
' * Version: ' + headerVersion,
|
|
||||||
' * Released under the MIT license',
|
|
||||||
' * https://github.com/microsoft/monaco-editor/blob/main/LICENSE.txt',
|
|
||||||
' *-----------------------------------------------------------------------------*/',
|
|
||||||
''
|
|
||||||
].join('\n');
|
|
||||||
|
|
||||||
return BUNDLED_FILE_HEADER;
|
|
||||||
})();
|
|
||||||
|
|
||||||
export interface IFile {
|
export interface IFile {
|
||||||
path: string;
|
path: string;
|
||||||
|
|
|
||||||
5
monaco-lsp-client/README.md
Normal file
5
monaco-lsp-client/README.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Monaco LSP Client
|
||||||
|
|
||||||
|
Provides a Language Server Protocol (LSP) client for the Monaco Editor.
|
||||||
|
|
||||||
|
This package is in alpha stage and might contain many bugs.
|
||||||
687
monaco-lsp-client/generator/index.ts
Normal file
687
monaco-lsp-client/generator/index.ts
Normal file
|
|
@ -0,0 +1,687 @@
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class for writing formatted code with proper indentation
|
||||||
|
*/
|
||||||
|
class LineWriter {
|
||||||
|
private lines: string[] = [];
|
||||||
|
private indentLevel: number = 0;
|
||||||
|
private indentStr: string = ' '; // 4 spaces
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write a line with current indentation
|
||||||
|
*/
|
||||||
|
writeLine(line: string = ''): void {
|
||||||
|
if (line.trim() === '') {
|
||||||
|
this.lines.push('');
|
||||||
|
} else {
|
||||||
|
this.lines.push(this.indentStr.repeat(this.indentLevel) + line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write text without adding a new line
|
||||||
|
*/
|
||||||
|
write(text: string): void {
|
||||||
|
if (this.lines.length === 0) {
|
||||||
|
this.lines.push('');
|
||||||
|
}
|
||||||
|
const lastIndex = this.lines.length - 1;
|
||||||
|
if (this.lines[lastIndex] === '') {
|
||||||
|
this.lines[lastIndex] = this.indentStr.repeat(this.indentLevel) + text;
|
||||||
|
} else {
|
||||||
|
this.lines[lastIndex] += text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increase indentation level
|
||||||
|
*/
|
||||||
|
indent(): void {
|
||||||
|
this.indentLevel++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrease indentation level
|
||||||
|
*/
|
||||||
|
outdent(): void {
|
||||||
|
if (this.indentLevel > 0) {
|
||||||
|
this.indentLevel--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the generated content as a string
|
||||||
|
*/
|
||||||
|
toString(): string {
|
||||||
|
return this.lines.join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear all content and reset indentation
|
||||||
|
*/
|
||||||
|
clear(): void {
|
||||||
|
this.lines = [];
|
||||||
|
this.indentLevel = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface definitions based on the metaModel schema
|
||||||
|
*/
|
||||||
|
interface MetaModel {
|
||||||
|
metaData: MetaData;
|
||||||
|
requests: Request[];
|
||||||
|
notifications: Notification[];
|
||||||
|
structures: Structure[];
|
||||||
|
enumerations: Enumeration[];
|
||||||
|
typeAliases: TypeAlias[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MetaData {
|
||||||
|
version: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Request {
|
||||||
|
method: string;
|
||||||
|
result: Type;
|
||||||
|
messageDirection: MessageDirection;
|
||||||
|
params?: Type | Type[];
|
||||||
|
partialResult?: Type;
|
||||||
|
errorData?: Type;
|
||||||
|
registrationOptions?: Type;
|
||||||
|
registrationMethod?: string;
|
||||||
|
documentation?: string;
|
||||||
|
since?: string;
|
||||||
|
proposed?: boolean;
|
||||||
|
deprecated?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Notification {
|
||||||
|
method: string;
|
||||||
|
messageDirection: MessageDirection;
|
||||||
|
params?: Type | Type[];
|
||||||
|
registrationOptions?: Type;
|
||||||
|
registrationMethod?: string;
|
||||||
|
documentation?: string;
|
||||||
|
since?: string;
|
||||||
|
proposed?: boolean;
|
||||||
|
deprecated?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Structure {
|
||||||
|
name: string;
|
||||||
|
properties: Property[];
|
||||||
|
extends?: Type[];
|
||||||
|
mixins?: Type[];
|
||||||
|
documentation?: string;
|
||||||
|
since?: string;
|
||||||
|
proposed?: boolean;
|
||||||
|
deprecated?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Property {
|
||||||
|
name: string;
|
||||||
|
type: Type;
|
||||||
|
optional?: boolean;
|
||||||
|
documentation?: string;
|
||||||
|
since?: string;
|
||||||
|
proposed?: boolean;
|
||||||
|
deprecated?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Enumeration {
|
||||||
|
name: string;
|
||||||
|
type: EnumerationType;
|
||||||
|
values: EnumerationEntry[];
|
||||||
|
supportsCustomValues?: boolean;
|
||||||
|
documentation?: string;
|
||||||
|
since?: string;
|
||||||
|
proposed?: boolean;
|
||||||
|
deprecated?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface EnumerationEntry {
|
||||||
|
name: string;
|
||||||
|
value: string | number;
|
||||||
|
documentation?: string;
|
||||||
|
since?: string;
|
||||||
|
proposed?: boolean;
|
||||||
|
deprecated?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface EnumerationType {
|
||||||
|
kind: 'base';
|
||||||
|
name: 'string' | 'integer' | 'uinteger';
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TypeAlias {
|
||||||
|
name: string;
|
||||||
|
type: Type;
|
||||||
|
documentation?: string;
|
||||||
|
since?: string;
|
||||||
|
proposed?: boolean;
|
||||||
|
deprecated?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type MessageDirection = 'clientToServer' | 'serverToClient' | 'both';
|
||||||
|
|
||||||
|
type Type =
|
||||||
|
| BaseType
|
||||||
|
| ReferenceType
|
||||||
|
| ArrayType
|
||||||
|
| MapType
|
||||||
|
| AndType
|
||||||
|
| OrType
|
||||||
|
| TupleType
|
||||||
|
| StructureLiteralType
|
||||||
|
| StringLiteralType
|
||||||
|
| IntegerLiteralType
|
||||||
|
| BooleanLiteralType;
|
||||||
|
|
||||||
|
interface BaseType {
|
||||||
|
kind: 'base';
|
||||||
|
name:
|
||||||
|
| 'URI'
|
||||||
|
| 'DocumentUri'
|
||||||
|
| 'integer'
|
||||||
|
| 'uinteger'
|
||||||
|
| 'decimal'
|
||||||
|
| 'RegExp'
|
||||||
|
| 'string'
|
||||||
|
| 'boolean'
|
||||||
|
| 'null';
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ReferenceType {
|
||||||
|
kind: 'reference';
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ArrayType {
|
||||||
|
kind: 'array';
|
||||||
|
element: Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MapType {
|
||||||
|
kind: 'map';
|
||||||
|
key: Type;
|
||||||
|
value: Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AndType {
|
||||||
|
kind: 'and';
|
||||||
|
items: Type[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OrType {
|
||||||
|
kind: 'or';
|
||||||
|
items: Type[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TupleType {
|
||||||
|
kind: 'tuple';
|
||||||
|
items: Type[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StructureLiteralType {
|
||||||
|
kind: 'literal';
|
||||||
|
value: StructureLiteral;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StructureLiteral {
|
||||||
|
properties: Property[];
|
||||||
|
documentation?: string;
|
||||||
|
since?: string;
|
||||||
|
proposed?: boolean;
|
||||||
|
deprecated?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StringLiteralType {
|
||||||
|
kind: 'stringLiteral';
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IntegerLiteralType {
|
||||||
|
kind: 'integerLiteral';
|
||||||
|
value: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BooleanLiteralType {
|
||||||
|
kind: 'booleanLiteral';
|
||||||
|
value: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TypeScript types generator for LSP client
|
||||||
|
*/
|
||||||
|
class LSPTypesGenerator {
|
||||||
|
private writer = new LineWriter();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load and parse the metaModel.json file
|
||||||
|
*/
|
||||||
|
private loadMetaModel(): MetaModel {
|
||||||
|
const metaModelPath = path.join(__dirname, '..', 'metaModel.json');
|
||||||
|
const content = fs.readFileSync(metaModelPath, 'utf-8');
|
||||||
|
return JSON.parse(content) as MetaModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert Type to TypeScript type string
|
||||||
|
*/
|
||||||
|
private typeToTypeScript(type: Type): string {
|
||||||
|
switch (type.kind) {
|
||||||
|
case 'base':
|
||||||
|
switch (type.name) {
|
||||||
|
case 'string':
|
||||||
|
case 'DocumentUri':
|
||||||
|
case 'URI':
|
||||||
|
return 'string';
|
||||||
|
case 'integer':
|
||||||
|
case 'uinteger':
|
||||||
|
case 'decimal':
|
||||||
|
return 'number';
|
||||||
|
case 'boolean':
|
||||||
|
return 'boolean';
|
||||||
|
case 'null':
|
||||||
|
return 'null';
|
||||||
|
case 'RegExp':
|
||||||
|
return 'RegExp';
|
||||||
|
default:
|
||||||
|
return 'any';
|
||||||
|
}
|
||||||
|
case 'reference':
|
||||||
|
return type.name;
|
||||||
|
case 'array':
|
||||||
|
return `(${this.typeToTypeScript(type.element)})[]`;
|
||||||
|
case 'map':
|
||||||
|
return `{ [key: ${this.typeToTypeScript(type.key)}]: ${this.typeToTypeScript(
|
||||||
|
type.value
|
||||||
|
)} }`;
|
||||||
|
case 'and':
|
||||||
|
return type.items.map((item) => this.typeToTypeScript(item)).join(' & ');
|
||||||
|
case 'or':
|
||||||
|
return type.items.map((item) => this.typeToTypeScript(item)).join(' | ');
|
||||||
|
case 'tuple':
|
||||||
|
return `[${type.items.map((item) => this.typeToTypeScript(item)).join(', ')}]`;
|
||||||
|
case 'literal':
|
||||||
|
return this.structureLiteralToTypeScript(type.value);
|
||||||
|
case 'stringLiteral':
|
||||||
|
return `'${type.value}'`;
|
||||||
|
case 'integerLiteral':
|
||||||
|
return type.value.toString();
|
||||||
|
case 'booleanLiteral':
|
||||||
|
return type.value.toString();
|
||||||
|
default:
|
||||||
|
return 'any';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert structure literal to TypeScript interface
|
||||||
|
*/
|
||||||
|
private structureLiteralToTypeScript(literal: StructureLiteral): string {
|
||||||
|
const properties = literal.properties.map((prop) => {
|
||||||
|
const optional = prop.optional ? '?' : '';
|
||||||
|
return `${prop.name}${optional}: ${this.typeToTypeScript(prop.type)}`;
|
||||||
|
});
|
||||||
|
return `{\n ${properties.join(';\n ')}\n}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate TypeScript interface for a structure
|
||||||
|
*/
|
||||||
|
private generateStructure(structure: Structure): void {
|
||||||
|
if (structure.documentation) {
|
||||||
|
this.writer.writeLine('/**');
|
||||||
|
this.writer.writeLine(` * ${structure.documentation.replace(/\n/g, '\n * ')}`);
|
||||||
|
this.writer.writeLine(' */');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build extends clause combining extends and mixins
|
||||||
|
const allParents: string[] = [];
|
||||||
|
|
||||||
|
if (structure.extends && structure.extends.length > 0) {
|
||||||
|
allParents.push(...structure.extends.map((type) => this.typeToTypeScript(type)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (structure.mixins && structure.mixins.length > 0) {
|
||||||
|
allParents.push(...structure.mixins.map((type) => this.typeToTypeScript(type)));
|
||||||
|
}
|
||||||
|
|
||||||
|
const extendsClause = allParents.length > 0 ? ` extends ${allParents.join(', ')}` : '';
|
||||||
|
|
||||||
|
this.writer.writeLine(`export interface ${structure.name}${extendsClause} {`);
|
||||||
|
this.writer.indent();
|
||||||
|
|
||||||
|
// Add properties
|
||||||
|
for (const property of structure.properties) {
|
||||||
|
if (property.documentation) {
|
||||||
|
this.writer.writeLine('/**');
|
||||||
|
this.writer.writeLine(` * ${property.documentation.replace(/\n/g, '\n * ')}`);
|
||||||
|
this.writer.writeLine(' */');
|
||||||
|
}
|
||||||
|
const optional = property.optional ? '?' : '';
|
||||||
|
this.writer.writeLine(
|
||||||
|
`${property.name}${optional}: ${this.typeToTypeScript(property.type)};`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.writer.outdent();
|
||||||
|
this.writer.writeLine('}');
|
||||||
|
this.writer.writeLine('');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate TypeScript enum for an enumeration
|
||||||
|
*/
|
||||||
|
private generateEnumeration(enumeration: Enumeration): void {
|
||||||
|
if (enumeration.documentation) {
|
||||||
|
this.writer.writeLine('/**');
|
||||||
|
this.writer.writeLine(` * ${enumeration.documentation.replace(/\n/g, '\n * ')}`);
|
||||||
|
this.writer.writeLine(' */');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.writer.writeLine(`export enum ${enumeration.name} {`);
|
||||||
|
this.writer.indent();
|
||||||
|
|
||||||
|
for (let i = 0; i < enumeration.values.length; i++) {
|
||||||
|
const entry = enumeration.values[i];
|
||||||
|
if (entry.documentation) {
|
||||||
|
this.writer.writeLine('/**');
|
||||||
|
this.writer.writeLine(` * ${entry.documentation.replace(/\n/g, '\n * ')}`);
|
||||||
|
this.writer.writeLine(' */');
|
||||||
|
}
|
||||||
|
const isLast = i === enumeration.values.length - 1;
|
||||||
|
const comma = isLast ? '' : ',';
|
||||||
|
if (typeof entry.value === 'string') {
|
||||||
|
this.writer.writeLine(`${entry.name} = '${entry.value}'${comma}`);
|
||||||
|
} else {
|
||||||
|
this.writer.writeLine(`${entry.name} = ${entry.value}${comma}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.writer.outdent();
|
||||||
|
this.writer.writeLine('}');
|
||||||
|
this.writer.writeLine('');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate TypeScript type alias
|
||||||
|
*/
|
||||||
|
private generateTypeAlias(typeAlias: TypeAlias): void {
|
||||||
|
if (typeAlias.documentation) {
|
||||||
|
this.writer.writeLine('/**');
|
||||||
|
this.writer.writeLine(` * ${typeAlias.documentation.replace(/\n/g, '\n * ')}`);
|
||||||
|
this.writer.writeLine(' */');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.writer.writeLine(
|
||||||
|
`export type ${typeAlias.name} = ${this.typeToTypeScript(typeAlias.type)};`
|
||||||
|
);
|
||||||
|
this.writer.writeLine('');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the Capability class
|
||||||
|
*/
|
||||||
|
private generateCapabilityClass(): void {
|
||||||
|
this.writer.writeLine('/**');
|
||||||
|
this.writer.writeLine(
|
||||||
|
' * Represents a capability with its associated method and registration options type'
|
||||||
|
);
|
||||||
|
this.writer.writeLine(' */');
|
||||||
|
this.writer.writeLine('export class Capability<T> {');
|
||||||
|
this.writer.indent();
|
||||||
|
this.writer.writeLine('constructor(public readonly method: string) {}');
|
||||||
|
this.writer.outdent();
|
||||||
|
this.writer.writeLine('}');
|
||||||
|
this.writer.writeLine('');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the capabilities map
|
||||||
|
*/
|
||||||
|
private generateCapabilitiesMap(metaModel: MetaModel): void {
|
||||||
|
this.writer.writeLine('/**');
|
||||||
|
this.writer.writeLine(' * Map of all LSP capabilities with their registration options');
|
||||||
|
this.writer.writeLine(' */');
|
||||||
|
this.writer.writeLine('export const capabilities = {');
|
||||||
|
this.writer.indent();
|
||||||
|
|
||||||
|
// Collect all requests and notifications with registration options
|
||||||
|
const itemsWithRegistration: Array<{ method: string; registrationOptions?: Type }> = [];
|
||||||
|
|
||||||
|
for (const request of metaModel.requests) {
|
||||||
|
if (request.registrationOptions) {
|
||||||
|
itemsWithRegistration.push({
|
||||||
|
method: request.method,
|
||||||
|
registrationOptions: request.registrationOptions
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const notification of metaModel.notifications) {
|
||||||
|
if (notification.registrationOptions) {
|
||||||
|
itemsWithRegistration.push({
|
||||||
|
method: notification.method,
|
||||||
|
registrationOptions: notification.registrationOptions
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate capability entries
|
||||||
|
for (const item of itemsWithRegistration) {
|
||||||
|
const methodIdentifier = this.methodToIdentifier(item.method);
|
||||||
|
const registrationType = item.registrationOptions
|
||||||
|
? this.typeToTypeScript(item.registrationOptions)
|
||||||
|
: 'unknown';
|
||||||
|
|
||||||
|
this.writer.writeLine(
|
||||||
|
`${methodIdentifier}: new Capability<${registrationType}>('${item.method}'),`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.writer.outdent();
|
||||||
|
this.writer.writeLine('};');
|
||||||
|
this.writer.writeLine('');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert LSP method name to valid JavaScript identifier
|
||||||
|
*/
|
||||||
|
private methodToIdentifier(method: string): string {
|
||||||
|
const parts = method
|
||||||
|
.replace(/\$/g, '') // Remove $ characters
|
||||||
|
.split('/') // Split on forward slashes
|
||||||
|
.filter((part) => part.length > 0); // Remove empty parts
|
||||||
|
|
||||||
|
return parts
|
||||||
|
.map((part, index) => {
|
||||||
|
// Convert kebab-case to camelCase for each part
|
||||||
|
const camelCase = part.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
|
||||||
|
// Capitalize first letter of all parts except the first non-empty part
|
||||||
|
return index === 0 ? camelCase : camelCase.charAt(0).toUpperCase() + camelCase.slice(1);
|
||||||
|
})
|
||||||
|
.join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the API contract object
|
||||||
|
*/
|
||||||
|
private generateApiContract(metaModel: MetaModel): void {
|
||||||
|
this.writer.writeLine('/**');
|
||||||
|
this.writer.writeLine(' * LSP API Contract');
|
||||||
|
this.writer.writeLine(' */');
|
||||||
|
|
||||||
|
this.writer.writeLine('export const api = contract({');
|
||||||
|
this.writer.indent();
|
||||||
|
|
||||||
|
this.writer.writeLine('name: "LSP",');
|
||||||
|
|
||||||
|
// Helper function to generate request entries
|
||||||
|
const generateRequest = (request: Request, isOptional: boolean = false) => {
|
||||||
|
const methodIdentifier = this.methodToIdentifier(request.method);
|
||||||
|
const paramsType = this.getParamsType(request.params);
|
||||||
|
const resultType = this.typeToTypeScript(request.result);
|
||||||
|
|
||||||
|
if (request.documentation) {
|
||||||
|
this.writer.writeLine('/**');
|
||||||
|
this.writer.writeLine(` * ${request.documentation.replace(/\n/g, '\n * ')}`);
|
||||||
|
this.writer.writeLine(' */');
|
||||||
|
}
|
||||||
|
|
||||||
|
const optional = isOptional ? '.optional()' : '';
|
||||||
|
this.writer.writeLine(
|
||||||
|
`${methodIdentifier}: unverifiedRequest<${paramsType}, ${resultType}>({ method: "${request.method}" })${optional},`
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper function to generate notification entries
|
||||||
|
const generateNotification = (notification: Notification) => {
|
||||||
|
const methodIdentifier = this.methodToIdentifier(notification.method);
|
||||||
|
const paramsType = this.getParamsType(notification.params);
|
||||||
|
|
||||||
|
if (notification.documentation) {
|
||||||
|
this.writer.writeLine('/**');
|
||||||
|
this.writer.writeLine(` * ${notification.documentation.replace(/\n/g, '\n * ')}`);
|
||||||
|
this.writer.writeLine(' */');
|
||||||
|
}
|
||||||
|
this.writer.writeLine(
|
||||||
|
`${methodIdentifier}: unverifiedNotification<${paramsType}>({ method: "${notification.method}" }),`
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Server section
|
||||||
|
this.writer.writeLine('server: {');
|
||||||
|
this.writer.indent();
|
||||||
|
|
||||||
|
// Server requests (sent from client to server)
|
||||||
|
for (const request of metaModel.requests) {
|
||||||
|
if (request.messageDirection === 'clientToServer' || request.messageDirection === 'both') {
|
||||||
|
generateRequest(request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Server notifications (sent from client to server)
|
||||||
|
for (const notification of metaModel.notifications) {
|
||||||
|
if (
|
||||||
|
notification.messageDirection === 'clientToServer' ||
|
||||||
|
notification.messageDirection === 'both'
|
||||||
|
) {
|
||||||
|
generateNotification(notification);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.writer.outdent();
|
||||||
|
this.writer.writeLine('},');
|
||||||
|
|
||||||
|
// Client section
|
||||||
|
this.writer.writeLine('client: {');
|
||||||
|
this.writer.indent();
|
||||||
|
|
||||||
|
// Client requests (handled by server)
|
||||||
|
for (const request of metaModel.requests) {
|
||||||
|
if (request.messageDirection === 'serverToClient' || request.messageDirection === 'both') {
|
||||||
|
generateRequest(request, true); // serverToClient requests are optional
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client notifications (sent from server to client)
|
||||||
|
for (const notification of metaModel.notifications) {
|
||||||
|
if (
|
||||||
|
notification.messageDirection === 'serverToClient' ||
|
||||||
|
notification.messageDirection === 'both'
|
||||||
|
) {
|
||||||
|
generateNotification(notification);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.writer.outdent();
|
||||||
|
this.writer.writeLine('}');
|
||||||
|
|
||||||
|
this.writer.outdent();
|
||||||
|
this.writer.writeLine('});');
|
||||||
|
this.writer.writeLine('');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method to get parameter type
|
||||||
|
*/
|
||||||
|
private getParamsType(params?: Type | Type[]): string {
|
||||||
|
if (!params) {
|
||||||
|
return 'void';
|
||||||
|
}
|
||||||
|
if (Array.isArray(params)) {
|
||||||
|
const paramTypes = params.map((p) => this.typeToTypeScript(p));
|
||||||
|
return `[${paramTypes.join(', ')}]`;
|
||||||
|
} else {
|
||||||
|
return this.typeToTypeScript(params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the complete TypeScript types
|
||||||
|
*/
|
||||||
|
generate(): void {
|
||||||
|
const metaModel = this.loadMetaModel();
|
||||||
|
|
||||||
|
this.writer.clear();
|
||||||
|
this.writer.writeLine('// Generated TypeScript definitions for LSP');
|
||||||
|
this.writer.writeLine(`// Protocol version: ${metaModel.metaData.version}`);
|
||||||
|
this.writer.writeLine('// This file is auto-generated. Do not edit manually.');
|
||||||
|
this.writer.writeLine('');
|
||||||
|
|
||||||
|
// Import contract types from @hediet/json-rpc
|
||||||
|
this.writer.writeLine('import {');
|
||||||
|
this.writer.indent();
|
||||||
|
this.writer.writeLine('contract,');
|
||||||
|
this.writer.writeLine('Contract,');
|
||||||
|
this.writer.writeLine('unverifiedRequest,');
|
||||||
|
this.writer.writeLine('unverifiedNotification,');
|
||||||
|
this.writer.outdent();
|
||||||
|
this.writer.writeLine('} from "@hediet/json-rpc";');
|
||||||
|
this.writer.writeLine('');
|
||||||
|
|
||||||
|
// Generate enumerations
|
||||||
|
for (const enumeration of metaModel.enumerations) {
|
||||||
|
this.generateEnumeration(enumeration);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate type aliases
|
||||||
|
for (const typeAlias of metaModel.typeAliases) {
|
||||||
|
this.generateTypeAlias(typeAlias);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate structures
|
||||||
|
for (const structure of metaModel.structures) {
|
||||||
|
this.generateStructure(structure);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate Capability class
|
||||||
|
this.generateCapabilityClass();
|
||||||
|
|
||||||
|
// Generate capabilities map
|
||||||
|
this.generateCapabilitiesMap(metaModel);
|
||||||
|
|
||||||
|
// Generate API contract
|
||||||
|
this.generateApiContract(metaModel);
|
||||||
|
|
||||||
|
// Write types file
|
||||||
|
const srcDir = path.join(__dirname, '..', 'src');
|
||||||
|
if (!fs.existsSync(srcDir)) {
|
||||||
|
fs.mkdirSync(srcDir, { recursive: true });
|
||||||
|
}
|
||||||
|
fs.writeFileSync(path.join(srcDir, 'types.ts'), this.writer.toString());
|
||||||
|
|
||||||
|
console.log('Generated LSP types file: src/types.ts');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the generator
|
||||||
|
if (require.main === module) {
|
||||||
|
const generator = new LSPTypesGenerator();
|
||||||
|
generator.generate();
|
||||||
|
}
|
||||||
1564
monaco-lsp-client/package-lock.json
generated
Normal file
1564
monaco-lsp-client/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
26
monaco-lsp-client/package.json
Normal file
26
monaco-lsp-client/package.json
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"name": "@vscode/monaco-lsp-client",
|
||||||
|
"description": "description",
|
||||||
|
"authors": "vscode",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"main": "out/index.js",
|
||||||
|
"types": "out/index.d.ts",
|
||||||
|
"dependencies": {
|
||||||
|
"@hediet/json-rpc": "^0.5.0",
|
||||||
|
"@hediet/json-rpc-browser": "^0.5.1",
|
||||||
|
"@hediet/json-rpc-websocket": "^0.5.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"monaco-editor-core": "^0.54.0-dev-20250929"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"rolldown": "^1.0.0-beta.41",
|
||||||
|
"rolldown-plugin-dts": "^0.16.11",
|
||||||
|
"rollup-plugin-delete": "^3.0.1"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "npx rolldown -c rolldown.config.mjs",
|
||||||
|
"dev": "npx rolldown -c rolldown.config.mjs --watch",
|
||||||
|
"generate": "tsx generator/index.ts"
|
||||||
|
}
|
||||||
|
}
|
||||||
33
monaco-lsp-client/rolldown.config.mjs
Normal file
33
monaco-lsp-client/rolldown.config.mjs
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
// @ts-check
|
||||||
|
|
||||||
|
import { join } from 'path';
|
||||||
|
import { defineConfig } from 'rolldown';
|
||||||
|
import { dts } from 'rolldown-plugin-dts';
|
||||||
|
import del from 'rollup-plugin-delete';
|
||||||
|
import alias from '@rollup/plugin-alias';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
input: {
|
||||||
|
index: join(import.meta.dirname, './src/index.ts')
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
dir: join(import.meta.dirname, './out'),
|
||||||
|
format: 'es'
|
||||||
|
},
|
||||||
|
external: ['monaco-editor-core'],
|
||||||
|
plugins: [
|
||||||
|
del({ targets: 'out/*' }),
|
||||||
|
alias({
|
||||||
|
entries: {
|
||||||
|
ws: 'undefined'
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
dts({
|
||||||
|
tsconfig: false,
|
||||||
|
compilerOptions: {
|
||||||
|
stripInternal: true
|
||||||
|
},
|
||||||
|
resolve: true
|
||||||
|
})
|
||||||
|
]
|
||||||
|
});
|
||||||
40
monaco-lsp-client/src/adapters/ITextModelBridge.ts
Normal file
40
monaco-lsp-client/src/adapters/ITextModelBridge.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
import * as monaco from 'monaco-editor-core';
|
||||||
|
import { Position, Range, TextDocumentIdentifier } from '../../src/types';
|
||||||
|
|
||||||
|
export interface ITextModelBridge {
|
||||||
|
translate(
|
||||||
|
textModel: monaco.editor.ITextModel,
|
||||||
|
monacoPos: monaco.Position
|
||||||
|
): {
|
||||||
|
textDocument: TextDocumentIdentifier;
|
||||||
|
position: Position;
|
||||||
|
};
|
||||||
|
|
||||||
|
translateRange(textModel: monaco.editor.ITextModel, monacoRange: monaco.Range): Range;
|
||||||
|
|
||||||
|
translateBack(
|
||||||
|
textDocument: TextDocumentIdentifier,
|
||||||
|
position: Position
|
||||||
|
): {
|
||||||
|
textModel: monaco.editor.ITextModel;
|
||||||
|
position: monaco.Position;
|
||||||
|
};
|
||||||
|
|
||||||
|
translateBackRange(
|
||||||
|
textDocument: TextDocumentIdentifier,
|
||||||
|
range: Range
|
||||||
|
): {
|
||||||
|
textModel: monaco.editor.ITextModel;
|
||||||
|
range: monaco.Range;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function assertTargetTextModel<T extends { textModel: monaco.editor.ITextModel }>(
|
||||||
|
input: T,
|
||||||
|
expectedTextModel: monaco.editor.ITextModel
|
||||||
|
): T {
|
||||||
|
if (input.textModel !== expectedTextModel) {
|
||||||
|
throw new Error(`Expected text model to be ${expectedTextModel}, but got ${input.textModel}`);
|
||||||
|
}
|
||||||
|
return input;
|
||||||
|
}
|
||||||
254
monaco-lsp-client/src/adapters/LspCapabilitiesRegistry.ts
Normal file
254
monaco-lsp-client/src/adapters/LspCapabilitiesRegistry.ts
Normal file
|
|
@ -0,0 +1,254 @@
|
||||||
|
import { TypedChannel } from '@hediet/json-rpc';
|
||||||
|
import { ClientCapabilities, Capability, ServerCapabilities, api, capabilities, TextDocumentChangeRegistrationOptions, TextDocumentSyncKind } from '../../src/types';
|
||||||
|
import { IDisposable, Disposable } from '../utils';
|
||||||
|
|
||||||
|
export interface ILspCapabilitiesRegistry {
|
||||||
|
addStaticClientCapabilities(capability: ClientCapabilities): IDisposable;
|
||||||
|
registerCapabilityHandler<T>(capability: Capability<T>, handleStaticCapability: boolean, handler: (capability: T) => IDisposable): IDisposable;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class LspCapabilitiesRegistry extends Disposable implements ILspCapabilitiesRegistry {
|
||||||
|
private readonly _staticCapabilities = new Set<{ cap: ClientCapabilities; }>();
|
||||||
|
private readonly _dynamicFromStatic = DynamicFromStaticOptions.create();
|
||||||
|
private readonly _registrations = new Map<Capability<any>, CapabilityInfo<any>>();
|
||||||
|
private _serverCapabilities: ServerCapabilities | undefined = undefined;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly _connection: TypedChannel
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this._register(this._connection.registerRequestHandler(api.client.clientRegisterCapability, async (params) => {
|
||||||
|
for (const registration of params.registrations) {
|
||||||
|
const capability = getCapabilityByMethod(registration.method);
|
||||||
|
const r = new CapabilityRegistration(registration.id, capability, registration.registerOptions, false);
|
||||||
|
this._registerCapabilityOptions(r);
|
||||||
|
}
|
||||||
|
return { ok: null };
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._register(this._connection.registerRequestHandler(api.client.clientUnregisterCapability, async (params) => {
|
||||||
|
for (const unregistration of params.unregisterations) {
|
||||||
|
const capability = getCapabilityByMethod(unregistration.method);
|
||||||
|
const info = this._registrations.get(capability);
|
||||||
|
const handlerInfo = info?.registrations.get(unregistration.id);
|
||||||
|
if (!handlerInfo) {
|
||||||
|
throw new Error(`No registration for method ${unregistration.method} with id ${unregistration.id}`);
|
||||||
|
}
|
||||||
|
handlerInfo?.handlerDisposables.forEach(d => d.dispose());
|
||||||
|
info?.registrations.delete(unregistration.id);
|
||||||
|
}
|
||||||
|
return { ok: null };
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
private _registerCapabilityOptions<T>(registration: CapabilityRegistration<T>) {
|
||||||
|
let registrationForMethod = this._registrations.get(registration.capability);
|
||||||
|
if (!registrationForMethod) {
|
||||||
|
registrationForMethod = new CapabilityInfo();
|
||||||
|
this._registrations.set(registration.capability, registrationForMethod);
|
||||||
|
}
|
||||||
|
if (registrationForMethod.registrations.has(registration.id)) {
|
||||||
|
throw new Error(`Handler for method ${registration.capability.method} with id ${registration.id} already registered`);
|
||||||
|
}
|
||||||
|
registrationForMethod.registrations.set(registration.id, registration);
|
||||||
|
for (const h of registrationForMethod.handlers) {
|
||||||
|
if (!h.handleStaticCapability && registration.isFromStatic) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
registration.handlerDisposables.set(h, h.handler(registration.options));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setServerCapabilities(serverCapabilities: ServerCapabilities) {
|
||||||
|
if (this._serverCapabilities) {
|
||||||
|
throw new Error('Server capabilities already set');
|
||||||
|
}
|
||||||
|
this._serverCapabilities = serverCapabilities;
|
||||||
|
for (const cap of Object.values(capabilities)) {
|
||||||
|
const options = this._dynamicFromStatic.getOptions(cap, serverCapabilities);
|
||||||
|
if (options) {
|
||||||
|
this._registerCapabilityOptions(new CapabilityRegistration(cap.method, cap, options, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getClientCapabilities(): ClientCapabilities {
|
||||||
|
const result: ClientCapabilities = {};
|
||||||
|
for (const c of this._staticCapabilities) {
|
||||||
|
deepAssign(result, c.cap);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
addStaticClientCapabilities(capability: ClientCapabilities): IDisposable {
|
||||||
|
const obj = { cap: capability };
|
||||||
|
this._staticCapabilities.add(obj);
|
||||||
|
return {
|
||||||
|
dispose: () => {
|
||||||
|
this._staticCapabilities.delete(obj);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
registerCapabilityHandler<T>(capability: Capability<T>, handleStaticCapability: boolean, handler: (capability: T) => IDisposable): IDisposable {
|
||||||
|
let info = this._registrations.get(capability);
|
||||||
|
if (!info) {
|
||||||
|
info = new CapabilityInfo();
|
||||||
|
this._registrations.set(capability, info);
|
||||||
|
}
|
||||||
|
const handlerInfo = new CapabilityHandler(capability, handleStaticCapability, handler);
|
||||||
|
info.handlers.add(handlerInfo);
|
||||||
|
|
||||||
|
for (const registration of info.registrations.values()) {
|
||||||
|
if (!handlerInfo.handleStaticCapability && registration.isFromStatic) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
registration.handlerDisposables.set(handlerInfo, handler(registration.options));
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
dispose: () => {
|
||||||
|
info.handlers.delete(handlerInfo);
|
||||||
|
for (const registration of info.registrations.values()) {
|
||||||
|
const disposable = registration.handlerDisposables.get(handlerInfo);
|
||||||
|
if (disposable) {
|
||||||
|
disposable.dispose();
|
||||||
|
registration.handlerDisposables.delete(handlerInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CapabilityHandler<T> {
|
||||||
|
constructor(
|
||||||
|
public readonly capability: Capability<T>,
|
||||||
|
public readonly handleStaticCapability: boolean,
|
||||||
|
public readonly handler: (capabilityOptions: T) => IDisposable
|
||||||
|
) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
class CapabilityRegistration<T> {
|
||||||
|
public readonly handlerDisposables = new Map<CapabilityHandler<any>, IDisposable>();
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public readonly id: string,
|
||||||
|
public readonly capability: Capability<T>,
|
||||||
|
public readonly options: T,
|
||||||
|
public readonly isFromStatic: boolean
|
||||||
|
) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
const capabilitiesByMethod = new Map([...Object.values(capabilities)].map(c => [c.method, c]));
|
||||||
|
function getCapabilityByMethod(method: string): Capability<any> {
|
||||||
|
const c = capabilitiesByMethod.get(method);
|
||||||
|
if (!c) {
|
||||||
|
throw new Error(`No capability found for method ${method}`);
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
class CapabilityInfo<T> {
|
||||||
|
public readonly handlers = new Set<CapabilityHandler<T>>();
|
||||||
|
public readonly registrations = new Map</* id */ string, CapabilityRegistration<T>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
class DynamicFromStaticOptions {
|
||||||
|
private readonly _mappings = new Map</* method */ string, (serverCapabilities: ServerCapabilities) => any>();
|
||||||
|
|
||||||
|
public static create(): DynamicFromStaticOptions {
|
||||||
|
const o = new DynamicFromStaticOptions();
|
||||||
|
o.set(capabilities.textDocumentDidChange, s => {
|
||||||
|
if (s.textDocumentSync === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (typeof s.textDocumentSync === 'object') {
|
||||||
|
return {
|
||||||
|
syncKind: s.textDocumentSync.change ?? TextDocumentSyncKind.None,
|
||||||
|
documentSelector: null,
|
||||||
|
} satisfies TextDocumentChangeRegistrationOptions;
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
syncKind: s.textDocumentSync,
|
||||||
|
documentSelector: null,
|
||||||
|
} satisfies TextDocumentChangeRegistrationOptions;
|
||||||
|
}
|
||||||
|
return null!;
|
||||||
|
});
|
||||||
|
|
||||||
|
o.set(capabilities.textDocumentCompletion, s => s.completionProvider);
|
||||||
|
o.set(capabilities.textDocumentHover, s => s.hoverProvider);
|
||||||
|
o.set(capabilities.textDocumentSignatureHelp, s => s.signatureHelpProvider);
|
||||||
|
o.set(capabilities.textDocumentDefinition, s => s.definitionProvider);
|
||||||
|
o.set(capabilities.textDocumentReferences, s => s.referencesProvider);
|
||||||
|
o.set(capabilities.textDocumentDocumentHighlight, s => s.documentHighlightProvider);
|
||||||
|
o.set(capabilities.textDocumentDocumentSymbol, s => s.documentSymbolProvider);
|
||||||
|
o.set(capabilities.textDocumentCodeAction, s => s.codeActionProvider);
|
||||||
|
o.set(capabilities.textDocumentCodeLens, s => s.codeLensProvider);
|
||||||
|
o.set(capabilities.textDocumentDocumentLink, s => s.documentLinkProvider);
|
||||||
|
o.set(capabilities.textDocumentFormatting, s => s.documentFormattingProvider);
|
||||||
|
o.set(capabilities.textDocumentRangeFormatting, s => s.documentRangeFormattingProvider);
|
||||||
|
o.set(capabilities.textDocumentOnTypeFormatting, s => s.documentOnTypeFormattingProvider);
|
||||||
|
o.set(capabilities.textDocumentRename, s => s.renameProvider);
|
||||||
|
o.set(capabilities.textDocumentFoldingRange, s => s.foldingRangeProvider);
|
||||||
|
o.set(capabilities.textDocumentDeclaration, s => s.declarationProvider);
|
||||||
|
o.set(capabilities.textDocumentTypeDefinition, s => s.typeDefinitionProvider);
|
||||||
|
o.set(capabilities.textDocumentImplementation, s => s.implementationProvider);
|
||||||
|
o.set(capabilities.textDocumentDocumentColor, s => s.colorProvider);
|
||||||
|
o.set(capabilities.textDocumentSelectionRange, s => s.selectionRangeProvider);
|
||||||
|
o.set(capabilities.textDocumentLinkedEditingRange, s => s.linkedEditingRangeProvider);
|
||||||
|
o.set(capabilities.textDocumentPrepareCallHierarchy, s => s.callHierarchyProvider);
|
||||||
|
o.set(capabilities.textDocumentSemanticTokensFull, s => s.semanticTokensProvider);
|
||||||
|
o.set(capabilities.textDocumentInlayHint, s => s.inlayHintProvider);
|
||||||
|
o.set(capabilities.textDocumentInlineValue, s => s.inlineValueProvider);
|
||||||
|
o.set(capabilities.textDocumentDiagnostic, s => s.diagnosticProvider);
|
||||||
|
o.set(capabilities.textDocumentMoniker, s => s.monikerProvider);
|
||||||
|
o.set(capabilities.textDocumentPrepareTypeHierarchy, s => s.typeHierarchyProvider);
|
||||||
|
o.set(capabilities.workspaceSymbol, s => s.workspaceSymbolProvider);
|
||||||
|
o.set(capabilities.workspaceExecuteCommand, s => s.executeCommandProvider);
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
set<T>(capability: Capability<T>, getOptionsFromStatic: (serverCapabilities: ServerCapabilities) => T | boolean | undefined): void {
|
||||||
|
if (this._mappings.has(capability.method)) {
|
||||||
|
throw new Error(`Capability for method ${capability.method} already registered`);
|
||||||
|
}
|
||||||
|
this._mappings.set(capability.method, getOptionsFromStatic);
|
||||||
|
}
|
||||||
|
|
||||||
|
getOptions<T>(capability: Capability<T>, serverCapabilities: ServerCapabilities): T | undefined {
|
||||||
|
const getter = this._mappings.get(capability.method);
|
||||||
|
if (!getter) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
const result = getter(serverCapabilities);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function deepAssign(target: any, source: any) {
|
||||||
|
for (const key of Object.keys(source)) {
|
||||||
|
const srcValue = source[key];
|
||||||
|
if (srcValue === undefined) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const tgtValue = target[key];
|
||||||
|
if (tgtValue === undefined) {
|
||||||
|
target[key] = srcValue;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof srcValue !== 'object' || srcValue === null) {
|
||||||
|
target[key] = srcValue;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (typeof tgtValue !== 'object' || tgtValue === null) {
|
||||||
|
target[key] = srcValue;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
deepAssign(tgtValue, srcValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
90
monaco-lsp-client/src/adapters/LspClient.ts
Normal file
90
monaco-lsp-client/src/adapters/LspClient.ts
Normal file
|
|
@ -0,0 +1,90 @@
|
||||||
|
import { IMessageTransport, TypedChannel } from "@hediet/json-rpc";
|
||||||
|
import { LspCompletionFeature } from "./languageFeatures/LspCompletionFeature";
|
||||||
|
import { LspHoverFeature } from "./languageFeatures/LspHoverFeature";
|
||||||
|
import { LspSignatureHelpFeature } from "./languageFeatures/LspSignatureHelpFeature";
|
||||||
|
import { LspDefinitionFeature } from "./languageFeatures/LspDefinitionFeature";
|
||||||
|
import { LspDeclarationFeature } from "./languageFeatures/LspDeclarationFeature";
|
||||||
|
import { LspTypeDefinitionFeature } from "./languageFeatures/LspTypeDefinitionFeature";
|
||||||
|
import { LspImplementationFeature } from "./languageFeatures/LspImplementationFeature";
|
||||||
|
import { LspReferencesFeature } from "./languageFeatures/LspReferencesFeature";
|
||||||
|
import { LspDocumentHighlightFeature } from "./languageFeatures/LspDocumentHighlightFeature";
|
||||||
|
import { LspDocumentSymbolFeature } from "./languageFeatures/LspDocumentSymbolFeature";
|
||||||
|
import { LspRenameFeature } from "./languageFeatures/LspRenameFeature";
|
||||||
|
import { LspCodeActionFeature } from "./languageFeatures/LspCodeActionFeature";
|
||||||
|
import { LspCodeLensFeature } from "./languageFeatures/LspCodeLensFeature";
|
||||||
|
import { LspDocumentLinkFeature } from "./languageFeatures/LspDocumentLinkFeature";
|
||||||
|
import { LspFormattingFeature } from "./languageFeatures/LspFormattingFeature";
|
||||||
|
import { LspRangeFormattingFeature } from "./languageFeatures/LspRangeFormattingFeature";
|
||||||
|
import { LspOnTypeFormattingFeature } from "./languageFeatures/LspOnTypeFormattingFeature";
|
||||||
|
import { LspFoldingRangeFeature } from "./languageFeatures/LspFoldingRangeFeature";
|
||||||
|
import { LspSelectionRangeFeature } from "./languageFeatures/LspSelectionRangeFeature";
|
||||||
|
import { LspInlayHintsFeature } from "./languageFeatures/LspInlayHintsFeature";
|
||||||
|
import { LspSemanticTokensFeature } from "./languageFeatures/LspSemanticTokensFeature";
|
||||||
|
import { LspDiagnosticsFeature } from "./languageFeatures/LspDiagnosticsFeature";
|
||||||
|
import { api } from "../../src/types";
|
||||||
|
import { LspConnection } from "./LspConnection";
|
||||||
|
import { LspCapabilitiesRegistry } from './LspCapabilitiesRegistry';
|
||||||
|
import { TextDocumentSynchronizer } from "./TextDocumentSynchronizer";
|
||||||
|
import { DisposableStore, IDisposable } from "../utils";
|
||||||
|
|
||||||
|
export class MonacoLspClient {
|
||||||
|
private _connection: LspConnection;
|
||||||
|
private readonly _capabilitiesRegistry: LspCapabilitiesRegistry;
|
||||||
|
private readonly _bridge: TextDocumentSynchronizer;
|
||||||
|
|
||||||
|
private _initPromise: Promise<void>;
|
||||||
|
|
||||||
|
constructor(transport: IMessageTransport) {
|
||||||
|
const c = TypedChannel.fromTransport(transport);
|
||||||
|
const s = api.getServer(c, {});
|
||||||
|
c.startListen();
|
||||||
|
|
||||||
|
this._capabilitiesRegistry = new LspCapabilitiesRegistry(c);
|
||||||
|
this._bridge = new TextDocumentSynchronizer(s.server, this._capabilitiesRegistry);
|
||||||
|
|
||||||
|
this._connection = new LspConnection(s.server, this._bridge, this._capabilitiesRegistry, c);
|
||||||
|
this.createFeatures();
|
||||||
|
|
||||||
|
this._initPromise = this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _init() {
|
||||||
|
const result = await this._connection.server.initialize({
|
||||||
|
processId: null,
|
||||||
|
capabilities: this._capabilitiesRegistry.getClientCapabilities(),
|
||||||
|
rootUri: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
this._connection.server.initialized({});
|
||||||
|
this._capabilitiesRegistry.setServerCapabilities(result.capabilities);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected createFeatures(): IDisposable {
|
||||||
|
const store = new DisposableStore();
|
||||||
|
|
||||||
|
store.add(new LspCompletionFeature(this._connection));
|
||||||
|
store.add(new LspHoverFeature(this._connection));
|
||||||
|
store.add(new LspSignatureHelpFeature(this._connection));
|
||||||
|
store.add(new LspDefinitionFeature(this._connection));
|
||||||
|
store.add(new LspDeclarationFeature(this._connection));
|
||||||
|
store.add(new LspTypeDefinitionFeature(this._connection));
|
||||||
|
store.add(new LspImplementationFeature(this._connection));
|
||||||
|
store.add(new LspReferencesFeature(this._connection));
|
||||||
|
store.add(new LspDocumentHighlightFeature(this._connection));
|
||||||
|
store.add(new LspDocumentSymbolFeature(this._connection));
|
||||||
|
store.add(new LspRenameFeature(this._connection));
|
||||||
|
store.add(new LspCodeActionFeature(this._connection));
|
||||||
|
store.add(new LspCodeLensFeature(this._connection));
|
||||||
|
store.add(new LspDocumentLinkFeature(this._connection));
|
||||||
|
store.add(new LspFormattingFeature(this._connection));
|
||||||
|
store.add(new LspRangeFormattingFeature(this._connection));
|
||||||
|
store.add(new LspOnTypeFormattingFeature(this._connection));
|
||||||
|
store.add(new LspFoldingRangeFeature(this._connection));
|
||||||
|
store.add(new LspSelectionRangeFeature(this._connection));
|
||||||
|
store.add(new LspInlayHintsFeature(this._connection));
|
||||||
|
store.add(new LspSemanticTokensFeature(this._connection));
|
||||||
|
store.add(new LspDiagnosticsFeature(this._connection));
|
||||||
|
|
||||||
|
return store;
|
||||||
|
}
|
||||||
|
}
|
||||||
13
monaco-lsp-client/src/adapters/LspConnection.ts
Normal file
13
monaco-lsp-client/src/adapters/LspConnection.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { TypedChannel } from '@hediet/json-rpc';
|
||||||
|
import { api } from '../../src/types';
|
||||||
|
import { ITextModelBridge } from './ITextModelBridge';
|
||||||
|
import { LspCapabilitiesRegistry } from './LspCapabilitiesRegistry';
|
||||||
|
|
||||||
|
export class LspConnection {
|
||||||
|
constructor(
|
||||||
|
public readonly server: typeof api.TServerInterface,
|
||||||
|
public readonly bridge: ITextModelBridge,
|
||||||
|
public readonly capabilities: LspCapabilitiesRegistry,
|
||||||
|
public readonly connection: TypedChannel,
|
||||||
|
) { }
|
||||||
|
}
|
||||||
183
monaco-lsp-client/src/adapters/TextDocumentSynchronizer.ts
Normal file
183
monaco-lsp-client/src/adapters/TextDocumentSynchronizer.ts
Normal file
|
|
@ -0,0 +1,183 @@
|
||||||
|
import * as monaco from 'monaco-editor-core';
|
||||||
|
import { api, capabilities, Position, Range, TextDocumentContentChangeEvent, TextDocumentIdentifier } from '../../src/types';
|
||||||
|
import { Disposable } from '../utils';
|
||||||
|
import { ITextModelBridge } from './ITextModelBridge';
|
||||||
|
import { ILspCapabilitiesRegistry } from './LspCapabilitiesRegistry';
|
||||||
|
|
||||||
|
export class TextDocumentSynchronizer extends Disposable implements ITextModelBridge {
|
||||||
|
private readonly _managedModels = new Map<monaco.editor.ITextModel, ManagedModel>();
|
||||||
|
private readonly _managedModelsReverse = new Map</* uri */ string, monaco.editor.ITextModel>();
|
||||||
|
|
||||||
|
private _started = false;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly _server: typeof api.TServerInterface,
|
||||||
|
private readonly _capabilities: ILspCapabilitiesRegistry,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this._register(this._capabilities.addStaticClientCapabilities({
|
||||||
|
textDocument: {
|
||||||
|
synchronization: {
|
||||||
|
dynamicRegistration: true,
|
||||||
|
willSave: false,
|
||||||
|
willSaveWaitUntil: false,
|
||||||
|
didSave: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._register(_capabilities.registerCapabilityHandler(capabilities.textDocumentDidChange, true, e => {
|
||||||
|
if (this._started) {
|
||||||
|
return {
|
||||||
|
dispose: () => {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._started = true;
|
||||||
|
this._register(monaco.editor.onDidCreateModel(m => {
|
||||||
|
this._getOrCreateManagedModel(m);
|
||||||
|
}));
|
||||||
|
for (const m of monaco.editor.getModels()) {
|
||||||
|
this._getOrCreateManagedModel(m);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
dispose: () => {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
private _getOrCreateManagedModel(m: monaco.editor.ITextModel) {
|
||||||
|
if (!this._started) {
|
||||||
|
throw new Error('Not started');
|
||||||
|
}
|
||||||
|
|
||||||
|
const uriStr = m.uri.toString(true).toLowerCase();
|
||||||
|
let mm = this._managedModels.get(m);
|
||||||
|
if (!mm) {
|
||||||
|
mm = new ManagedModel(m, this._server);
|
||||||
|
this._managedModels.set(m, mm);
|
||||||
|
this._managedModelsReverse.set(uriStr, m);
|
||||||
|
}
|
||||||
|
m.onWillDispose(() => {
|
||||||
|
mm!.dispose();
|
||||||
|
this._managedModels.delete(m);
|
||||||
|
this._managedModelsReverse.delete(uriStr);
|
||||||
|
});
|
||||||
|
return mm;
|
||||||
|
}
|
||||||
|
|
||||||
|
translateBack(textDocument: TextDocumentIdentifier, position: Position): { textModel: monaco.editor.ITextModel; position: monaco.Position; } {
|
||||||
|
const uri = textDocument.uri.toLowerCase();
|
||||||
|
const textModel = this._managedModelsReverse.get(uri);
|
||||||
|
if (!textModel) {
|
||||||
|
throw new Error(`No text model for uri ${uri}`);
|
||||||
|
}
|
||||||
|
const monacoPosition = new monaco.Position(position.line + 1, position.character + 1);
|
||||||
|
return { textModel, position: monacoPosition };
|
||||||
|
}
|
||||||
|
|
||||||
|
translateBackRange(textDocument: TextDocumentIdentifier, range: Range): { textModel: monaco.editor.ITextModel; range: monaco.Range; } {
|
||||||
|
const uri = textDocument.uri.toLowerCase();
|
||||||
|
const textModel = this._managedModelsReverse.get(uri);
|
||||||
|
if (!textModel) {
|
||||||
|
throw new Error(`No text model for uri ${uri}`);
|
||||||
|
}
|
||||||
|
const monacoRange = new monaco.Range(
|
||||||
|
range.start.line + 1,
|
||||||
|
range.start.character + 1,
|
||||||
|
range.end.line + 1,
|
||||||
|
range.end.character + 1
|
||||||
|
);
|
||||||
|
return { textModel, range: monacoRange };
|
||||||
|
}
|
||||||
|
|
||||||
|
translate(textModel: monaco.editor.ITextModel, monacoPos: monaco.Position): { textDocument: TextDocumentIdentifier; position: Position; } {
|
||||||
|
return {
|
||||||
|
textDocument: {
|
||||||
|
uri: textModel.uri.toString(true),
|
||||||
|
},
|
||||||
|
position: {
|
||||||
|
line: monacoPos.lineNumber - 1,
|
||||||
|
character: monacoPos.column - 1,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
translateRange(textModel: monaco.editor.ITextModel, monacoRange: monaco.Range): Range {
|
||||||
|
return {
|
||||||
|
start: {
|
||||||
|
line: monacoRange.startLineNumber - 1,
|
||||||
|
character: monacoRange.startColumn - 1,
|
||||||
|
},
|
||||||
|
end: {
|
||||||
|
line: monacoRange.endLineNumber - 1,
|
||||||
|
character: monacoRange.endColumn - 1,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ManagedModel extends Disposable {
|
||||||
|
constructor(
|
||||||
|
private readonly _textModel: monaco.editor.ITextModel,
|
||||||
|
private readonly _api: typeof api.TServerInterface
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
const uri = _textModel.uri.toString(true).toLowerCase();
|
||||||
|
|
||||||
|
this._api.textDocumentDidOpen({
|
||||||
|
textDocument: {
|
||||||
|
languageId: _textModel.getLanguageId(),
|
||||||
|
uri: uri,
|
||||||
|
version: _textModel.getVersionId(),
|
||||||
|
text: _textModel.getValue(),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this._register(_textModel.onDidChangeContent(e => {
|
||||||
|
const contentChanges = e.changes.map(c => toLspTextDocumentContentChangeEvent(c));
|
||||||
|
|
||||||
|
this._api.textDocumentDidChange({
|
||||||
|
textDocument: {
|
||||||
|
uri: uri,
|
||||||
|
version: _textModel.getVersionId(),
|
||||||
|
},
|
||||||
|
contentChanges: contentChanges
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._register({
|
||||||
|
dispose: () => {
|
||||||
|
this._api.textDocumentDidClose({
|
||||||
|
textDocument: {
|
||||||
|
uri: uri,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toLspTextDocumentContentChangeEvent(change: monaco.editor.IModelContentChange): TextDocumentContentChangeEvent {
|
||||||
|
return {
|
||||||
|
range: toLspRange(change.range),
|
||||||
|
rangeLength: change.rangeLength,
|
||||||
|
text: change.text,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function toLspRange(range: monaco.IRange): Range {
|
||||||
|
return {
|
||||||
|
start: {
|
||||||
|
line: range.startLineNumber - 1,
|
||||||
|
character: range.startColumn - 1,
|
||||||
|
},
|
||||||
|
end: {
|
||||||
|
line: range.endLineNumber - 1,
|
||||||
|
character: range.endColumn - 1,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,169 @@
|
||||||
|
import * as monaco from 'monaco-editor-core';
|
||||||
|
import { capabilities, CodeActionRegistrationOptions, Command, WorkspaceEdit, CodeAction } from '../../../src/types';
|
||||||
|
import { Disposable } from '../../utils';
|
||||||
|
import { LspConnection } from '../LspConnection';
|
||||||
|
import { toMonacoLanguageSelector } from './common';
|
||||||
|
import { lspCodeActionKindToMonacoCodeActionKind, toMonacoCodeActionKind, toLspDiagnosticSeverity, toLspCodeActionTriggerKind, toMonacoCommand } from './common';
|
||||||
|
|
||||||
|
export class LspCodeActionFeature extends Disposable {
|
||||||
|
constructor(
|
||||||
|
private readonly _connection: LspConnection,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.addStaticClientCapabilities({
|
||||||
|
textDocument: {
|
||||||
|
codeAction: {
|
||||||
|
dynamicRegistration: true,
|
||||||
|
codeActionLiteralSupport: {
|
||||||
|
codeActionKind: {
|
||||||
|
valueSet: Array.from(lspCodeActionKindToMonacoCodeActionKind.keys()),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isPreferredSupport: true,
|
||||||
|
disabledSupport: true,
|
||||||
|
dataSupport: true,
|
||||||
|
resolveSupport: {
|
||||||
|
properties: ['edit'],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.registerCapabilityHandler(capabilities.textDocumentCodeAction, true, capability => {
|
||||||
|
return monaco.languages.registerCodeActionProvider(
|
||||||
|
toMonacoLanguageSelector(capability.documentSelector),
|
||||||
|
new LspCodeActionProvider(this._connection, capability),
|
||||||
|
);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ExtendedCodeAction extends monaco.languages.CodeAction {
|
||||||
|
_lspAction?: CodeAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
class LspCodeActionProvider implements monaco.languages.CodeActionProvider {
|
||||||
|
public readonly resolveCodeAction;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly _client: LspConnection,
|
||||||
|
private readonly _capabilities: CodeActionRegistrationOptions,
|
||||||
|
) {
|
||||||
|
if (_capabilities.resolveProvider) {
|
||||||
|
this.resolveCodeAction = async (codeAction: ExtendedCodeAction, token: monaco.CancellationToken): Promise<ExtendedCodeAction> => {
|
||||||
|
if (codeAction._lspAction) {
|
||||||
|
const resolved = await this._client.server.codeActionResolve(codeAction._lspAction);
|
||||||
|
if (resolved.edit) {
|
||||||
|
codeAction.edit = toMonacoWorkspaceEdit(resolved.edit, this._client);
|
||||||
|
}
|
||||||
|
if (resolved.command) {
|
||||||
|
codeAction.command = toMonacoCommand(resolved.command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return codeAction;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async provideCodeActions(
|
||||||
|
model: monaco.editor.ITextModel,
|
||||||
|
range: monaco.Range,
|
||||||
|
context: monaco.languages.CodeActionContext,
|
||||||
|
token: monaco.CancellationToken
|
||||||
|
): Promise<monaco.languages.CodeActionList | null> {
|
||||||
|
const translated = this._client.bridge.translate(model, range.getStartPosition());
|
||||||
|
|
||||||
|
const result = await this._client.server.textDocumentCodeAction({
|
||||||
|
textDocument: translated.textDocument,
|
||||||
|
range: this._client.bridge.translateRange(model, range),
|
||||||
|
context: {
|
||||||
|
diagnostics: context.markers.map(marker => ({
|
||||||
|
range: this._client.bridge.translateRange(model, monaco.Range.lift(marker)),
|
||||||
|
message: marker.message,
|
||||||
|
severity: toLspDiagnosticSeverity(marker.severity),
|
||||||
|
})),
|
||||||
|
triggerKind: toLspCodeActionTriggerKind(context.trigger),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const actions = Array.isArray(result) ? result : [result];
|
||||||
|
|
||||||
|
return {
|
||||||
|
actions: actions.map(action => {
|
||||||
|
if ('title' in action && !('kind' in action)) {
|
||||||
|
// Command
|
||||||
|
const cmd = action as Command;
|
||||||
|
const monacoAction: ExtendedCodeAction = {
|
||||||
|
title: cmd.title,
|
||||||
|
command: toMonacoCommand(cmd),
|
||||||
|
};
|
||||||
|
return monacoAction;
|
||||||
|
} else {
|
||||||
|
// CodeAction
|
||||||
|
const codeAction = action as CodeAction;
|
||||||
|
const monacoAction: ExtendedCodeAction = {
|
||||||
|
title: codeAction.title,
|
||||||
|
kind: toMonacoCodeActionKind(codeAction.kind),
|
||||||
|
isPreferred: codeAction.isPreferred,
|
||||||
|
disabled: codeAction.disabled?.reason,
|
||||||
|
edit: codeAction.edit ? toMonacoWorkspaceEdit(codeAction.edit, this._client) : undefined,
|
||||||
|
command: toMonacoCommand(codeAction.command),
|
||||||
|
_lspAction: codeAction,
|
||||||
|
};
|
||||||
|
return monacoAction;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
dispose: () => { },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toMonacoWorkspaceEdit(
|
||||||
|
edit: WorkspaceEdit,
|
||||||
|
client: LspConnection
|
||||||
|
): monaco.languages.WorkspaceEdit {
|
||||||
|
const edits: monaco.languages.IWorkspaceTextEdit[] = [];
|
||||||
|
|
||||||
|
if (edit.changes) {
|
||||||
|
for (const uri in edit.changes) {
|
||||||
|
const textEdits = edit.changes[uri];
|
||||||
|
for (const textEdit of textEdits) {
|
||||||
|
const translated = client.bridge.translateBackRange({ uri }, textEdit.range);
|
||||||
|
edits.push({
|
||||||
|
resource: translated.textModel.uri,
|
||||||
|
versionId: undefined,
|
||||||
|
textEdit: {
|
||||||
|
range: translated.range,
|
||||||
|
text: textEdit.newText,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (edit.documentChanges) {
|
||||||
|
for (const change of edit.documentChanges) {
|
||||||
|
if ('textDocument' in change) {
|
||||||
|
const uri = change.textDocument.uri;
|
||||||
|
for (const textEdit of change.edits) {
|
||||||
|
const translated = client.bridge.translateBackRange({ uri }, textEdit.range);
|
||||||
|
edits.push({
|
||||||
|
resource: translated.textModel.uri,
|
||||||
|
versionId: change.textDocument.version ?? undefined,
|
||||||
|
textEdit: {
|
||||||
|
range: translated.range,
|
||||||
|
text: textEdit.newText,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { edits };
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,90 @@
|
||||||
|
import * as monaco from 'monaco-editor-core';
|
||||||
|
import { capabilities, CodeLensRegistrationOptions, CodeLens } from '../../../src/types';
|
||||||
|
import { Disposable } from '../../utils';
|
||||||
|
import { LspConnection } from '../LspConnection';
|
||||||
|
import { toMonacoLanguageSelector } from './common';
|
||||||
|
import { assertTargetTextModel } from '../ITextModelBridge';
|
||||||
|
import { toMonacoCommand } from './common';
|
||||||
|
|
||||||
|
export class LspCodeLensFeature extends Disposable {
|
||||||
|
constructor(
|
||||||
|
private readonly _connection: LspConnection,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.addStaticClientCapabilities({
|
||||||
|
textDocument: {
|
||||||
|
codeLens: {
|
||||||
|
dynamicRegistration: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.registerCapabilityHandler(capabilities.textDocumentCodeLens, true, capability => {
|
||||||
|
return monaco.languages.registerCodeLensProvider(
|
||||||
|
toMonacoLanguageSelector(capability.documentSelector),
|
||||||
|
new LspCodeLensProvider(this._connection, capability),
|
||||||
|
);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ExtendedCodeLens extends monaco.languages.CodeLens {
|
||||||
|
_lspCodeLens?: CodeLens;
|
||||||
|
}
|
||||||
|
|
||||||
|
class LspCodeLensProvider implements monaco.languages.CodeLensProvider {
|
||||||
|
constructor(
|
||||||
|
private readonly _client: LspConnection,
|
||||||
|
private readonly _capabilities: CodeLensRegistrationOptions,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
async provideCodeLenses(
|
||||||
|
model: monaco.editor.ITextModel,
|
||||||
|
token: monaco.CancellationToken
|
||||||
|
): Promise<monaco.languages.CodeLensList | null> {
|
||||||
|
const translated = this._client.bridge.translate(model, new monaco.Position(1, 1));
|
||||||
|
|
||||||
|
const result = await this._client.server.textDocumentCodeLens({
|
||||||
|
textDocument: translated.textDocument,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
lenses: result.map(lens => {
|
||||||
|
const monacoLens: ExtendedCodeLens = {
|
||||||
|
range: assertTargetTextModel(this._client.bridge.translateBackRange(translated.textDocument, lens.range), model).range,
|
||||||
|
command: toMonacoCommand(lens.command),
|
||||||
|
_lspCodeLens: lens,
|
||||||
|
};
|
||||||
|
return monacoLens;
|
||||||
|
}),
|
||||||
|
dispose: () => { },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async resolveCodeLens(
|
||||||
|
model: monaco.editor.ITextModel,
|
||||||
|
codeLens: ExtendedCodeLens,
|
||||||
|
token: monaco.CancellationToken
|
||||||
|
): Promise<monaco.languages.CodeLens> {
|
||||||
|
if (!this._capabilities.resolveProvider || !codeLens._lspCodeLens) {
|
||||||
|
return codeLens;
|
||||||
|
}
|
||||||
|
|
||||||
|
const resolved = await this._client.server.codeLensResolve(codeLens._lspCodeLens);
|
||||||
|
|
||||||
|
if (resolved.command) {
|
||||||
|
codeLens.command = {
|
||||||
|
id: resolved.command.command,
|
||||||
|
title: resolved.command.title,
|
||||||
|
arguments: resolved.command.arguments,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return codeLens;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,202 @@
|
||||||
|
import * as monaco from 'monaco-editor-core';
|
||||||
|
import { capabilities, CompletionRegistrationOptions, MarkupContent, CompletionItem, TextDocumentPositionParams } from '../../../src/types';
|
||||||
|
import { assertTargetTextModel, ITextModelBridge } from '../ITextModelBridge';
|
||||||
|
import { Disposable } from '../../utils';
|
||||||
|
import { LspConnection } from '../LspConnection';
|
||||||
|
import { toMonacoLanguageSelector } from './common';
|
||||||
|
import {
|
||||||
|
lspCompletionItemKindToMonacoCompletionItemKind,
|
||||||
|
lspCompletionItemTagToMonacoCompletionItemTag,
|
||||||
|
toMonacoCompletionItemKind,
|
||||||
|
toMonacoCompletionItemTag,
|
||||||
|
toLspCompletionTriggerKind,
|
||||||
|
toMonacoInsertTextRules,
|
||||||
|
toMonacoCommand,
|
||||||
|
} from './common';
|
||||||
|
|
||||||
|
export class LspCompletionFeature extends Disposable {
|
||||||
|
constructor(
|
||||||
|
private readonly _connection: LspConnection,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.addStaticClientCapabilities({
|
||||||
|
textDocument: {
|
||||||
|
completion: {
|
||||||
|
dynamicRegistration: true,
|
||||||
|
contextSupport: true,
|
||||||
|
completionItemKind: {
|
||||||
|
valueSet: Array.from(lspCompletionItemKindToMonacoCompletionItemKind.keys()),
|
||||||
|
},
|
||||||
|
completionItem: {
|
||||||
|
tagSupport: {
|
||||||
|
valueSet: Array.from(lspCompletionItemTagToMonacoCompletionItemTag.keys()),
|
||||||
|
},
|
||||||
|
commitCharactersSupport: true,
|
||||||
|
deprecatedSupport: true,
|
||||||
|
preselectSupport: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.registerCapabilityHandler(capabilities.textDocumentCompletion, true, capability => {
|
||||||
|
return monaco.languages.registerCompletionItemProvider(
|
||||||
|
toMonacoLanguageSelector(capability.documentSelector),
|
||||||
|
new LspCompletionProvider(this._connection, capability),
|
||||||
|
);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ExtendedCompletionItem extends monaco.languages.CompletionItem {
|
||||||
|
_lspItem: CompletionItem;
|
||||||
|
_translated: TextDocumentPositionParams;
|
||||||
|
_model: monaco.editor.ITextModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
class LspCompletionProvider implements monaco.languages.CompletionItemProvider {
|
||||||
|
public readonly resolveCompletionItem;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly _client: LspConnection,
|
||||||
|
private readonly _capabilities: CompletionRegistrationOptions,
|
||||||
|
) {
|
||||||
|
if (_capabilities.resolveProvider) {
|
||||||
|
this.resolveCompletionItem = async (item: ExtendedCompletionItem, token: monaco.CancellationToken): Promise<ExtendedCompletionItem> => {
|
||||||
|
const resolved = await this._client.server.completionItemResolve(item._lspItem);
|
||||||
|
applyLspCompletionItemProperties(item, resolved, this._client.bridge, item._translated, item._model);
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get triggerCharacters(): string[] | undefined {
|
||||||
|
return this._capabilities.triggerCharacters;
|
||||||
|
}
|
||||||
|
|
||||||
|
async provideCompletionItems(
|
||||||
|
model: monaco.editor.ITextModel,
|
||||||
|
position: monaco.Position,
|
||||||
|
context: monaco.languages.CompletionContext,
|
||||||
|
token: monaco.CancellationToken
|
||||||
|
): Promise<monaco.languages.CompletionList & { suggestions: ExtendedCompletionItem[] }> {
|
||||||
|
const translated = this._client.bridge.translate(model, position);
|
||||||
|
|
||||||
|
const result = await this._client.server.textDocumentCompletion({
|
||||||
|
textDocument: translated.textDocument,
|
||||||
|
position: translated.position,
|
||||||
|
context: context.triggerCharacter ? {
|
||||||
|
triggerKind: toLspCompletionTriggerKind(context.triggerKind),
|
||||||
|
triggerCharacter: context.triggerCharacter,
|
||||||
|
} : undefined,
|
||||||
|
});
|
||||||
|
if (!result) {
|
||||||
|
return { suggestions: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
const items = Array.isArray(result) ? result : result.items;
|
||||||
|
|
||||||
|
return {
|
||||||
|
suggestions: items.map<ExtendedCompletionItem>(i => {
|
||||||
|
const item: ExtendedCompletionItem = {
|
||||||
|
...convertLspToMonacoCompletionItem(
|
||||||
|
i,
|
||||||
|
this._client.bridge,
|
||||||
|
translated,
|
||||||
|
model,
|
||||||
|
position
|
||||||
|
),
|
||||||
|
_lspItem: i,
|
||||||
|
_translated: translated,
|
||||||
|
_model: model,
|
||||||
|
};
|
||||||
|
|
||||||
|
return item;
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertLspToMonacoCompletionItem(
|
||||||
|
lspItem: CompletionItem,
|
||||||
|
bridge: ITextModelBridge,
|
||||||
|
translated: TextDocumentPositionParams,
|
||||||
|
model: monaco.editor.ITextModel,
|
||||||
|
position: monaco.Position
|
||||||
|
): monaco.languages.CompletionItem {
|
||||||
|
let insertText = lspItem.insertText || lspItem.label;
|
||||||
|
let range: monaco.IRange | monaco.languages.CompletionItemRanges | undefined = undefined;
|
||||||
|
|
||||||
|
if (lspItem.textEdit) {
|
||||||
|
if ('range' in lspItem.textEdit) {
|
||||||
|
insertText = lspItem.textEdit.newText;
|
||||||
|
range = assertTargetTextModel(bridge.translateBackRange(translated.textDocument, lspItem.textEdit.range), model).range;
|
||||||
|
} else {
|
||||||
|
insertText = lspItem.textEdit.newText;
|
||||||
|
range = {
|
||||||
|
insert: assertTargetTextModel(bridge.translateBackRange(translated.textDocument, lspItem.textEdit.insert), model).range,
|
||||||
|
replace: assertTargetTextModel(bridge.translateBackRange(translated.textDocument, lspItem.textEdit.replace), model).range,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!range) {
|
||||||
|
range = monaco.Range.fromPositions(position, position);
|
||||||
|
}
|
||||||
|
|
||||||
|
const item: monaco.languages.CompletionItem = {
|
||||||
|
label: lspItem.label,
|
||||||
|
kind: toMonacoCompletionItemKind(lspItem.kind),
|
||||||
|
insertText,
|
||||||
|
sortText: lspItem.sortText,
|
||||||
|
filterText: lspItem.filterText,
|
||||||
|
preselect: lspItem.preselect,
|
||||||
|
commitCharacters: lspItem.commitCharacters,
|
||||||
|
range: range,
|
||||||
|
};
|
||||||
|
|
||||||
|
applyLspCompletionItemProperties(item, lspItem, bridge, translated, model);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyLspCompletionItemProperties(
|
||||||
|
monacoItem: monaco.languages.CompletionItem,
|
||||||
|
lspItem: CompletionItem,
|
||||||
|
bridge: ITextModelBridge,
|
||||||
|
translated: TextDocumentPositionParams,
|
||||||
|
targetModel: monaco.editor.ITextModel
|
||||||
|
): void {
|
||||||
|
if (lspItem.detail !== undefined) {
|
||||||
|
monacoItem.detail = lspItem.detail;
|
||||||
|
}
|
||||||
|
if (lspItem.documentation !== undefined) {
|
||||||
|
monacoItem.documentation = toMonacoDocumentation(lspItem.documentation);
|
||||||
|
}
|
||||||
|
if (lspItem.insertTextFormat !== undefined) {
|
||||||
|
const insertTextRules = toMonacoInsertTextRules(lspItem.insertTextFormat);
|
||||||
|
monacoItem.insertTextRules = insertTextRules;
|
||||||
|
}
|
||||||
|
if (lspItem.tags && lspItem.tags.length > 0) {
|
||||||
|
monacoItem.tags = lspItem.tags.map(toMonacoCompletionItemTag).filter((tag): tag is monaco.languages.CompletionItemTag => tag !== undefined);
|
||||||
|
}
|
||||||
|
if (lspItem.additionalTextEdits && lspItem.additionalTextEdits.length > 0) {
|
||||||
|
monacoItem.additionalTextEdits = lspItem.additionalTextEdits.map(edit => ({
|
||||||
|
range: assertTargetTextModel(bridge.translateBackRange(translated.textDocument, edit.range), targetModel).range,
|
||||||
|
text: edit.newText,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
if (lspItem.command) {
|
||||||
|
monacoItem.command = toMonacoCommand(lspItem.command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toMonacoDocumentation(doc: string | MarkupContent | undefined): string | monaco.IMarkdownString | undefined {
|
||||||
|
if (!doc) return undefined;
|
||||||
|
if (typeof doc === 'string') return doc;
|
||||||
|
return {
|
||||||
|
value: doc.value,
|
||||||
|
isTrusted: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
import * as monaco from 'monaco-editor-core';
|
||||||
|
import { capabilities, DeclarationRegistrationOptions } from '../../../src/types';
|
||||||
|
import { Disposable } from '../../utils';
|
||||||
|
import { LspConnection } from '../LspConnection';
|
||||||
|
import { toMonacoLanguageSelector } from './common';
|
||||||
|
import { toMonacoLocation } from "./common";
|
||||||
|
|
||||||
|
export class LspDeclarationFeature extends Disposable {
|
||||||
|
constructor(
|
||||||
|
private readonly _connection: LspConnection,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.addStaticClientCapabilities({
|
||||||
|
textDocument: {
|
||||||
|
declaration: {
|
||||||
|
dynamicRegistration: true,
|
||||||
|
linkSupport: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.registerCapabilityHandler(capabilities.textDocumentDeclaration, true, capability => {
|
||||||
|
return monaco.languages.registerDeclarationProvider(
|
||||||
|
toMonacoLanguageSelector(capability.documentSelector),
|
||||||
|
new LspDeclarationProvider(this._connection, capability),
|
||||||
|
);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LspDeclarationProvider implements monaco.languages.DeclarationProvider {
|
||||||
|
constructor(
|
||||||
|
private readonly _client: LspConnection,
|
||||||
|
private readonly _capabilities: DeclarationRegistrationOptions,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
async provideDeclaration(
|
||||||
|
model: monaco.editor.ITextModel,
|
||||||
|
position: monaco.Position,
|
||||||
|
token: monaco.CancellationToken
|
||||||
|
): Promise<monaco.languages.Definition | monaco.languages.LocationLink[] | null> {
|
||||||
|
const translated = this._client.bridge.translate(model, position);
|
||||||
|
|
||||||
|
const result = await this._client.server.textDocumentDeclaration({
|
||||||
|
textDocument: translated.textDocument,
|
||||||
|
position: translated.position,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(result)) {
|
||||||
|
return result.map(loc => toMonacoLocation(loc, this._client));
|
||||||
|
}
|
||||||
|
|
||||||
|
return toMonacoLocation(result, this._client);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
import * as monaco from 'monaco-editor-core';
|
||||||
|
import { capabilities, DefinitionRegistrationOptions } from '../../../src/types';
|
||||||
|
import { Disposable } from '../../utils';
|
||||||
|
import { LspConnection } from '../LspConnection';
|
||||||
|
import { toMonacoLanguageSelector } from './common';
|
||||||
|
import { toMonacoLocation } from "./common";
|
||||||
|
|
||||||
|
export class LspDefinitionFeature extends Disposable {
|
||||||
|
constructor(
|
||||||
|
private readonly _connection: LspConnection,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.addStaticClientCapabilities({
|
||||||
|
textDocument: {
|
||||||
|
definition: {
|
||||||
|
dynamicRegistration: true,
|
||||||
|
linkSupport: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.registerCapabilityHandler(capabilities.textDocumentDefinition, true, capability => {
|
||||||
|
return monaco.languages.registerDefinitionProvider(
|
||||||
|
toMonacoLanguageSelector(capability.documentSelector),
|
||||||
|
new LspDefinitionProvider(this._connection, capability),
|
||||||
|
);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LspDefinitionProvider implements monaco.languages.DefinitionProvider {
|
||||||
|
constructor(
|
||||||
|
private readonly _client: LspConnection,
|
||||||
|
private readonly _capabilities: DefinitionRegistrationOptions,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
async provideDefinition(
|
||||||
|
model: monaco.editor.ITextModel,
|
||||||
|
position: monaco.Position,
|
||||||
|
token: monaco.CancellationToken
|
||||||
|
): Promise<monaco.languages.Definition | monaco.languages.LocationLink[] | null> {
|
||||||
|
const translated = this._client.bridge.translate(model, position);
|
||||||
|
|
||||||
|
const result = await this._client.server.textDocumentDefinition({
|
||||||
|
textDocument: translated.textDocument,
|
||||||
|
position: translated.position,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(result)) {
|
||||||
|
return result.map(loc => toMonacoLocation(loc, this._client));
|
||||||
|
}
|
||||||
|
|
||||||
|
return toMonacoLocation(result, this._client);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,208 @@
|
||||||
|
import * as monaco from 'monaco-editor-core';
|
||||||
|
import { api, capabilities, Diagnostic, DiagnosticRegistrationOptions, DocumentDiagnosticReport, PublishDiagnosticsParams } from '../../../src/types';
|
||||||
|
import { Disposable, DisposableStore } from '../../utils';
|
||||||
|
import { LspConnection } from '../LspConnection';
|
||||||
|
import { lspDiagnosticTagToMonacoMarkerTag, matchesDocumentSelector, toDiagnosticMarker } from './common';
|
||||||
|
|
||||||
|
export class LspDiagnosticsFeature extends Disposable {
|
||||||
|
private readonly _diagnosticsMarkerOwner = 'lsp';
|
||||||
|
private readonly _pullDiagnosticProviders = new Map<monaco.editor.ITextModel, ModelDiagnosticProvider>();
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly _connection: LspConnection,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.addStaticClientCapabilities({
|
||||||
|
textDocument: {
|
||||||
|
publishDiagnostics: {
|
||||||
|
relatedInformation: true,
|
||||||
|
tagSupport: {
|
||||||
|
valueSet: [...lspDiagnosticTagToMonacoMarkerTag.keys()],
|
||||||
|
},
|
||||||
|
versionSupport: true,
|
||||||
|
codeDescriptionSupport: true,
|
||||||
|
dataSupport: true,
|
||||||
|
},
|
||||||
|
diagnostic: {
|
||||||
|
dynamicRegistration: true,
|
||||||
|
relatedDocumentSupport: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
debugger;
|
||||||
|
this._register(this._connection.connection.registerNotificationHandler(
|
||||||
|
api.client.textDocumentPublishDiagnostics,
|
||||||
|
(params) => this._handlePublishDiagnostics(params)
|
||||||
|
));
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.registerCapabilityHandler(
|
||||||
|
capabilities.textDocumentDiagnostic,
|
||||||
|
true,
|
||||||
|
(capability) => {
|
||||||
|
const disposables = new DisposableStore();
|
||||||
|
for (const model of monaco.editor.getModels()) {
|
||||||
|
this._addPullDiagnosticProvider(model, capability, disposables);
|
||||||
|
}
|
||||||
|
disposables.add(monaco.editor.onDidCreateModel(model => {
|
||||||
|
this._addPullDiagnosticProvider(model, capability, disposables);
|
||||||
|
}));
|
||||||
|
return disposables;
|
||||||
|
}
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
private _addPullDiagnosticProvider(
|
||||||
|
model: monaco.editor.ITextModel,
|
||||||
|
capability: DiagnosticRegistrationOptions,
|
||||||
|
disposables: DisposableStore
|
||||||
|
): void {
|
||||||
|
// Check if model matches the document selector
|
||||||
|
const languageId = model.getLanguageId();
|
||||||
|
|
||||||
|
if (!matchesDocumentSelector(model, capability.documentSelector)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const provider = new ModelDiagnosticProvider(
|
||||||
|
model,
|
||||||
|
this._connection,
|
||||||
|
this._diagnosticsMarkerOwner,
|
||||||
|
capability
|
||||||
|
);
|
||||||
|
|
||||||
|
this._pullDiagnosticProviders.set(model, provider);
|
||||||
|
disposables.add(provider);
|
||||||
|
|
||||||
|
disposables.add(model.onWillDispose(() => {
|
||||||
|
this._pullDiagnosticProviders.delete(model);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handlePublishDiagnostics(params: PublishDiagnosticsParams): void {
|
||||||
|
const uri = params.uri;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const translated = this._connection.bridge.translateBack({ uri }, { line: 0, character: 0 });
|
||||||
|
const model = translated.textModel;
|
||||||
|
|
||||||
|
if (!model || model.isDisposed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const markers = params.diagnostics.map(diagnostic =>
|
||||||
|
toDiagnosticMarker(diagnostic)
|
||||||
|
);
|
||||||
|
|
||||||
|
monaco.editor.setModelMarkers(model, this._diagnosticsMarkerOwner, markers);
|
||||||
|
} catch (error) {
|
||||||
|
// Model not found or already disposed - this is normal when files are closed
|
||||||
|
console.debug(`Could not set diagnostics for ${uri}:`, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages pull diagnostics for a single text model
|
||||||
|
*/
|
||||||
|
class ModelDiagnosticProvider extends Disposable {
|
||||||
|
private _updateHandle: number | undefined;
|
||||||
|
private _previousResultId: string | undefined;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly _model: monaco.editor.ITextModel,
|
||||||
|
private readonly _connection: LspConnection,
|
||||||
|
private readonly _markerOwner: string,
|
||||||
|
private readonly _capability: DiagnosticRegistrationOptions,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
this._register(this._model.onDidChangeContent(() => {
|
||||||
|
this._scheduleDiagnosticUpdate();
|
||||||
|
}));
|
||||||
|
this._scheduleDiagnosticUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private _scheduleDiagnosticUpdate(): void {
|
||||||
|
if (this._updateHandle !== undefined) {
|
||||||
|
clearTimeout(this._updateHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._updateHandle = window.setTimeout(() => {
|
||||||
|
this._updateHandle = undefined;
|
||||||
|
this._requestDiagnostics();
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _requestDiagnostics(): Promise<void> {
|
||||||
|
if (this._model.isDisposed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const translated = this._connection.bridge.translate(this._model, new monaco.Position(1, 1));
|
||||||
|
|
||||||
|
const result = await this._connection.server.textDocumentDiagnostic({
|
||||||
|
textDocument: translated.textDocument,
|
||||||
|
identifier: this._capability.identifier,
|
||||||
|
previousResultId: this._previousResultId,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this._model.isDisposed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._handleDiagnosticReport(result);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error requesting diagnostics:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleDiagnosticReport(report: DocumentDiagnosticReport): void {
|
||||||
|
if (report.kind === 'full') {
|
||||||
|
// Full diagnostic report
|
||||||
|
this._previousResultId = report.resultId;
|
||||||
|
|
||||||
|
const markers = report.items.map(diagnostic => toDiagnosticMarker(diagnostic));
|
||||||
|
monaco.editor.setModelMarkers(this._model, this._markerOwner, markers);
|
||||||
|
|
||||||
|
// Handle related documents if present
|
||||||
|
if ('relatedDocuments' in report && report.relatedDocuments) {
|
||||||
|
this._handleRelatedDocuments(report.relatedDocuments);
|
||||||
|
}
|
||||||
|
} else if (report.kind === 'unchanged') {
|
||||||
|
// Unchanged report - diagnostics are still valid
|
||||||
|
this._previousResultId = report.resultId;
|
||||||
|
// No need to update markers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleRelatedDocuments(relatedDocuments: { [key: string]: any }): void {
|
||||||
|
for (const [uri, report] of Object.entries(relatedDocuments)) {
|
||||||
|
try {
|
||||||
|
const translated = this._connection.bridge.translateBack({ uri }, { line: 0, character: 0 });
|
||||||
|
const model = translated.textModel;
|
||||||
|
|
||||||
|
if (!model || model.isDisposed()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (report.kind === 'full') {
|
||||||
|
const markers = report.items.map((diagnostic: Diagnostic) => toDiagnosticMarker(diagnostic));
|
||||||
|
monaco.editor.setModelMarkers(model, this._markerOwner, markers);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// Model not found - this is normal
|
||||||
|
console.debug(`Could not set related diagnostics for ${uri}:`, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override dispose(): void {
|
||||||
|
if (this._updateHandle !== undefined) {
|
||||||
|
clearTimeout(this._updateHandle);
|
||||||
|
this._updateHandle = undefined;
|
||||||
|
}
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
import * as monaco from 'monaco-editor-core';
|
||||||
|
import { capabilities, DocumentHighlightRegistrationOptions } from '../../../src/types';
|
||||||
|
import { Disposable } from '../../utils';
|
||||||
|
import { LspConnection } from '../LspConnection';
|
||||||
|
import { toMonacoLanguageSelector } from './common';
|
||||||
|
import { toMonacoDocumentHighlightKind } from './common';
|
||||||
|
|
||||||
|
export class LspDocumentHighlightFeature extends Disposable {
|
||||||
|
constructor(
|
||||||
|
private readonly _connection: LspConnection,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.addStaticClientCapabilities({
|
||||||
|
textDocument: {
|
||||||
|
documentHighlight: {
|
||||||
|
dynamicRegistration: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.registerCapabilityHandler(capabilities.textDocumentDocumentHighlight, true, capability => {
|
||||||
|
return monaco.languages.registerDocumentHighlightProvider(
|
||||||
|
toMonacoLanguageSelector(capability.documentSelector),
|
||||||
|
new LspDocumentHighlightProvider(this._connection, capability),
|
||||||
|
);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LspDocumentHighlightProvider implements monaco.languages.DocumentHighlightProvider {
|
||||||
|
constructor(
|
||||||
|
private readonly _client: LspConnection,
|
||||||
|
private readonly _capabilities: DocumentHighlightRegistrationOptions,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
async provideDocumentHighlights(
|
||||||
|
model: monaco.editor.ITextModel,
|
||||||
|
position: monaco.Position,
|
||||||
|
token: monaco.CancellationToken
|
||||||
|
): Promise<monaco.languages.DocumentHighlight[] | null> {
|
||||||
|
const translated = this._client.bridge.translate(model, position);
|
||||||
|
|
||||||
|
const result = await this._client.server.textDocumentDocumentHighlight({
|
||||||
|
textDocument: translated.textDocument,
|
||||||
|
position: translated.position,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.map(highlight => ({
|
||||||
|
range: this._client.bridge.translateBackRange(translated.textDocument, highlight.range).range,
|
||||||
|
kind: toMonacoDocumentHighlightKind(highlight.kind),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
import * as monaco from 'monaco-editor-core';
|
||||||
|
import { capabilities, DocumentLinkRegistrationOptions } from '../../../src/types';
|
||||||
|
import { Disposable } from '../../utils';
|
||||||
|
import { LspConnection } from '../LspConnection';
|
||||||
|
import { toMonacoLanguageSelector } from './common';
|
||||||
|
|
||||||
|
export class LspDocumentLinkFeature extends Disposable {
|
||||||
|
constructor(
|
||||||
|
private readonly _connection: LspConnection,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.addStaticClientCapabilities({
|
||||||
|
textDocument: {
|
||||||
|
documentLink: {
|
||||||
|
dynamicRegistration: true,
|
||||||
|
tooltipSupport: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.registerCapabilityHandler(capabilities.textDocumentDocumentLink, true, capability => {
|
||||||
|
return monaco.languages.registerLinkProvider(
|
||||||
|
toMonacoLanguageSelector(capability.documentSelector),
|
||||||
|
new LspDocumentLinkProvider(this._connection, capability),
|
||||||
|
);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LspDocumentLinkProvider implements monaco.languages.LinkProvider {
|
||||||
|
constructor(
|
||||||
|
private readonly _client: LspConnection,
|
||||||
|
private readonly _capabilities: DocumentLinkRegistrationOptions,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
async provideLinks(
|
||||||
|
model: monaco.editor.ITextModel,
|
||||||
|
token: monaco.CancellationToken
|
||||||
|
): Promise<monaco.languages.ILinksList | null> {
|
||||||
|
const translated = this._client.bridge.translate(model, new monaco.Position(1, 1));
|
||||||
|
|
||||||
|
const result = await this._client.server.textDocumentDocumentLink({
|
||||||
|
textDocument: translated.textDocument,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
links: result.map(link => ({
|
||||||
|
range: this._client.bridge.translateBackRange(translated.textDocument, link.range).range,
|
||||||
|
url: link.target,
|
||||||
|
tooltip: link.tooltip,
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async resolveLink(
|
||||||
|
link: monaco.languages.ILink,
|
||||||
|
token: monaco.CancellationToken
|
||||||
|
): Promise<monaco.languages.ILink> {
|
||||||
|
if (!this._capabilities.resolveProvider) {
|
||||||
|
return link;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Implement resolve
|
||||||
|
return link;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,101 @@
|
||||||
|
import * as monaco from 'monaco-editor-core';
|
||||||
|
import { capabilities, DocumentSymbolRegistrationOptions, DocumentSymbol, SymbolInformation, SymbolTag } from '../../../src/types';
|
||||||
|
import { Disposable } from '../../utils';
|
||||||
|
import { LspConnection } from '../LspConnection';
|
||||||
|
import { toMonacoLanguageSelector } from './common';
|
||||||
|
import { lspSymbolKindToMonacoSymbolKind, toMonacoSymbolKind, toMonacoSymbolTag } from './common';
|
||||||
|
|
||||||
|
export class LspDocumentSymbolFeature extends Disposable {
|
||||||
|
constructor(
|
||||||
|
private readonly _connection: LspConnection,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.addStaticClientCapabilities({
|
||||||
|
textDocument: {
|
||||||
|
documentSymbol: {
|
||||||
|
dynamicRegistration: true,
|
||||||
|
hierarchicalDocumentSymbolSupport: true,
|
||||||
|
symbolKind: {
|
||||||
|
valueSet: Array.from(lspSymbolKindToMonacoSymbolKind.keys()),
|
||||||
|
},
|
||||||
|
tagSupport: {
|
||||||
|
valueSet: [SymbolTag.Deprecated],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.registerCapabilityHandler(capabilities.textDocumentDocumentSymbol, true, capability => {
|
||||||
|
return monaco.languages.registerDocumentSymbolProvider(
|
||||||
|
toMonacoLanguageSelector(capability.documentSelector),
|
||||||
|
new LspDocumentSymbolProvider(this._connection, capability),
|
||||||
|
);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LspDocumentSymbolProvider implements monaco.languages.DocumentSymbolProvider {
|
||||||
|
constructor(
|
||||||
|
private readonly _client: LspConnection,
|
||||||
|
private readonly _capabilities: DocumentSymbolRegistrationOptions,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
async provideDocumentSymbols(
|
||||||
|
model: monaco.editor.ITextModel,
|
||||||
|
token: monaco.CancellationToken
|
||||||
|
): Promise<monaco.languages.DocumentSymbol[] | null> {
|
||||||
|
const translated = this._client.bridge.translate(model, new monaco.Position(1, 1));
|
||||||
|
|
||||||
|
const result = await this._client.server.textDocumentDocumentSymbol({
|
||||||
|
textDocument: translated.textDocument,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(result) && result.length > 0) {
|
||||||
|
if ('location' in result[0]) {
|
||||||
|
// SymbolInformation[]
|
||||||
|
return (result as SymbolInformation[]).map(symbol => toMonacoSymbolInformation(symbol, this._client));
|
||||||
|
} else {
|
||||||
|
// DocumentSymbol[]
|
||||||
|
return (result as DocumentSymbol[]).map(symbol => toMonacoDocumentSymbol(symbol, this._client, translated.textDocument));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toMonacoDocumentSymbol(
|
||||||
|
symbol: DocumentSymbol,
|
||||||
|
client: LspConnection,
|
||||||
|
textDocument: { uri: string }
|
||||||
|
): monaco.languages.DocumentSymbol {
|
||||||
|
return {
|
||||||
|
name: symbol.name,
|
||||||
|
detail: symbol.detail || '',
|
||||||
|
kind: toMonacoSymbolKind(symbol.kind),
|
||||||
|
tags: symbol.tags?.map(tag => toMonacoSymbolTag(tag)).filter((t): t is monaco.languages.SymbolTag => t !== undefined) || [],
|
||||||
|
range: client.bridge.translateBackRange(textDocument, symbol.range).range,
|
||||||
|
selectionRange: client.bridge.translateBackRange(textDocument, symbol.selectionRange).range,
|
||||||
|
children: symbol.children?.map(child => toMonacoDocumentSymbol(child, client, textDocument)) || [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function toMonacoSymbolInformation(
|
||||||
|
symbol: SymbolInformation,
|
||||||
|
client: LspConnection
|
||||||
|
): monaco.languages.DocumentSymbol {
|
||||||
|
return {
|
||||||
|
name: symbol.name,
|
||||||
|
detail: '',
|
||||||
|
kind: toMonacoSymbolKind(symbol.kind),
|
||||||
|
tags: symbol.tags?.map(tag => toMonacoSymbolTag(tag)).filter((t): t is monaco.languages.SymbolTag => t !== undefined) || [],
|
||||||
|
range: client.bridge.translateBackRange({ uri: symbol.location.uri }, symbol.location.range).range,
|
||||||
|
selectionRange: client.bridge.translateBackRange({ uri: symbol.location.uri }, symbol.location.range).range,
|
||||||
|
children: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
import * as monaco from 'monaco-editor-core';
|
||||||
|
import { capabilities, FoldingRangeRegistrationOptions, FoldingRangeKind } from '../../../src/types';
|
||||||
|
import { Disposable } from '../../utils';
|
||||||
|
import { LspConnection } from '../LspConnection';
|
||||||
|
import { toMonacoLanguageSelector } from './common';
|
||||||
|
import { toMonacoFoldingRangeKind } from './common';
|
||||||
|
|
||||||
|
export class LspFoldingRangeFeature extends Disposable {
|
||||||
|
constructor(
|
||||||
|
private readonly _connection: LspConnection,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.addStaticClientCapabilities({
|
||||||
|
textDocument: {
|
||||||
|
foldingRange: {
|
||||||
|
dynamicRegistration: true,
|
||||||
|
rangeLimit: 5000,
|
||||||
|
lineFoldingOnly: false,
|
||||||
|
foldingRangeKind: {
|
||||||
|
valueSet: [FoldingRangeKind.Comment, FoldingRangeKind.Imports, FoldingRangeKind.Region],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.registerCapabilityHandler(capabilities.textDocumentFoldingRange, true, capability => {
|
||||||
|
return monaco.languages.registerFoldingRangeProvider(
|
||||||
|
toMonacoLanguageSelector(capability.documentSelector),
|
||||||
|
new LspFoldingRangeProvider(this._connection, capability),
|
||||||
|
);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LspFoldingRangeProvider implements monaco.languages.FoldingRangeProvider {
|
||||||
|
constructor(
|
||||||
|
private readonly _client: LspConnection,
|
||||||
|
private readonly _capabilities: FoldingRangeRegistrationOptions,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
async provideFoldingRanges(
|
||||||
|
model: monaco.editor.ITextModel,
|
||||||
|
context: monaco.languages.FoldingContext,
|
||||||
|
token: monaco.CancellationToken
|
||||||
|
): Promise<monaco.languages.FoldingRange[] | null> {
|
||||||
|
const translated = this._client.bridge.translate(model, new monaco.Position(1, 1));
|
||||||
|
|
||||||
|
const result = await this._client.server.textDocumentFoldingRange({
|
||||||
|
textDocument: translated.textDocument,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.map(range => ({
|
||||||
|
start: range.startLine + 1,
|
||||||
|
end: range.endLine + 1,
|
||||||
|
kind: toMonacoFoldingRangeKind(range.kind),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
import * as monaco from 'monaco-editor-core';
|
||||||
|
import { capabilities, DocumentFormattingRegistrationOptions } from '../../../src/types';
|
||||||
|
import { Disposable } from '../../utils';
|
||||||
|
import { LspConnection } from '../LspConnection';
|
||||||
|
import { toMonacoLanguageSelector } from './common';
|
||||||
|
|
||||||
|
export class LspFormattingFeature extends Disposable {
|
||||||
|
constructor(
|
||||||
|
private readonly _connection: LspConnection,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.addStaticClientCapabilities({
|
||||||
|
textDocument: {
|
||||||
|
formatting: {
|
||||||
|
dynamicRegistration: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.registerCapabilityHandler(capabilities.textDocumentFormatting, true, capability => {
|
||||||
|
return monaco.languages.registerDocumentFormattingEditProvider(
|
||||||
|
toMonacoLanguageSelector(capability.documentSelector),
|
||||||
|
new LspDocumentFormattingProvider(this._connection, capability),
|
||||||
|
);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LspDocumentFormattingProvider implements monaco.languages.DocumentFormattingEditProvider {
|
||||||
|
constructor(
|
||||||
|
private readonly _client: LspConnection,
|
||||||
|
private readonly _capabilities: DocumentFormattingRegistrationOptions,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
async provideDocumentFormattingEdits(
|
||||||
|
model: monaco.editor.ITextModel,
|
||||||
|
options: monaco.languages.FormattingOptions,
|
||||||
|
token: monaco.CancellationToken
|
||||||
|
): Promise<monaco.languages.TextEdit[] | null> {
|
||||||
|
const translated = this._client.bridge.translate(model, new monaco.Position(1, 1));
|
||||||
|
|
||||||
|
const result = await this._client.server.textDocumentFormatting({
|
||||||
|
textDocument: translated.textDocument,
|
||||||
|
options: {
|
||||||
|
tabSize: options.tabSize,
|
||||||
|
insertSpaces: options.insertSpaces,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.map(edit => ({
|
||||||
|
range: this._client.bridge.translateBackRange(translated.textDocument, edit.range).range,
|
||||||
|
text: edit.newText,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
import * as monaco from 'monaco-editor-core';
|
||||||
|
import { capabilities, HoverRegistrationOptions, MarkupContent, MarkedString, MarkupKind } from '../../../src/types';
|
||||||
|
import { Disposable } from '../../utils';
|
||||||
|
import { LspConnection } from '../LspConnection';
|
||||||
|
import { toMonacoLanguageSelector } from './common';
|
||||||
|
|
||||||
|
export class LspHoverFeature extends Disposable {
|
||||||
|
constructor(
|
||||||
|
private readonly _connection: LspConnection,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.addStaticClientCapabilities({
|
||||||
|
textDocument: {
|
||||||
|
hover: {
|
||||||
|
dynamicRegistration: true,
|
||||||
|
contentFormat: [MarkupKind.Markdown, MarkupKind.PlainText],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.registerCapabilityHandler(capabilities.textDocumentHover, true, capability => {
|
||||||
|
return monaco.languages.registerHoverProvider(
|
||||||
|
toMonacoLanguageSelector(capability.documentSelector),
|
||||||
|
new LspHoverProvider(this._connection, capability),
|
||||||
|
);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LspHoverProvider implements monaco.languages.HoverProvider {
|
||||||
|
constructor(
|
||||||
|
private readonly _client: LspConnection,
|
||||||
|
private readonly _capabilities: HoverRegistrationOptions,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
async provideHover(
|
||||||
|
model: monaco.editor.ITextModel,
|
||||||
|
position: monaco.Position,
|
||||||
|
token: monaco.CancellationToken
|
||||||
|
): Promise<monaco.languages.Hover | null> {
|
||||||
|
const translated = this._client.bridge.translate(model, position);
|
||||||
|
|
||||||
|
const result = await this._client.server.textDocumentHover({
|
||||||
|
textDocument: translated.textDocument,
|
||||||
|
position: translated.position,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result || !result.contents) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
contents: toMonacoMarkdownString(result.contents),
|
||||||
|
range: result.range ? this._client.bridge.translateBackRange(translated.textDocument, result.range).range : undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toMonacoMarkdownString(
|
||||||
|
contents: MarkupContent | MarkedString | MarkedString[]
|
||||||
|
): monaco.IMarkdownString[] {
|
||||||
|
if (Array.isArray(contents)) {
|
||||||
|
return contents.map(c => toSingleMarkdownString(c));
|
||||||
|
}
|
||||||
|
return [toSingleMarkdownString(contents)];
|
||||||
|
}
|
||||||
|
|
||||||
|
function toSingleMarkdownString(content: MarkupContent | MarkedString): monaco.IMarkdownString {
|
||||||
|
if (typeof content === 'string') {
|
||||||
|
return { value: content, isTrusted: true };
|
||||||
|
}
|
||||||
|
if ('kind' in content) {
|
||||||
|
// MarkupContent
|
||||||
|
return { value: content.value, isTrusted: true };
|
||||||
|
}
|
||||||
|
// MarkedString with language
|
||||||
|
return { value: `\`\`\`${content.language}\n${content.value}\n\`\`\``, isTrusted: true };
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
import * as monaco from 'monaco-editor-core';
|
||||||
|
import { capabilities, ImplementationRegistrationOptions } from '../../../src/types';
|
||||||
|
import { Disposable } from '../../utils';
|
||||||
|
import { LspConnection } from '../LspConnection';
|
||||||
|
import { toMonacoLanguageSelector } from './common';
|
||||||
|
import { toMonacoLocation } from "./common";
|
||||||
|
|
||||||
|
export class LspImplementationFeature extends Disposable {
|
||||||
|
constructor(
|
||||||
|
private readonly _connection: LspConnection,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.addStaticClientCapabilities({
|
||||||
|
textDocument: {
|
||||||
|
implementation: {
|
||||||
|
dynamicRegistration: true,
|
||||||
|
linkSupport: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.registerCapabilityHandler(capabilities.textDocumentImplementation, true, capability => {
|
||||||
|
return monaco.languages.registerImplementationProvider(
|
||||||
|
toMonacoLanguageSelector(capability.documentSelector),
|
||||||
|
new LspImplementationProvider(this._connection, capability),
|
||||||
|
);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LspImplementationProvider implements monaco.languages.ImplementationProvider {
|
||||||
|
constructor(
|
||||||
|
private readonly _client: LspConnection,
|
||||||
|
private readonly _capabilities: ImplementationRegistrationOptions,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
async provideImplementation(
|
||||||
|
model: monaco.editor.ITextModel,
|
||||||
|
position: monaco.Position,
|
||||||
|
token: monaco.CancellationToken
|
||||||
|
): Promise<monaco.languages.Definition | monaco.languages.LocationLink[] | null> {
|
||||||
|
const translated = this._client.bridge.translate(model, position);
|
||||||
|
|
||||||
|
const result = await this._client.server.textDocumentImplementation({
|
||||||
|
textDocument: translated.textDocument,
|
||||||
|
position: translated.position,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(result)) {
|
||||||
|
return result.map(loc => toMonacoLocation(loc, this._client));
|
||||||
|
}
|
||||||
|
|
||||||
|
return toMonacoLocation(result, this._client);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,212 @@
|
||||||
|
import * as monaco from 'monaco-editor-core';
|
||||||
|
import { capabilities, InlayHintRegistrationOptions, InlayHint, MarkupContent, api } from '../../../src/types';
|
||||||
|
import { Disposable } from '../../utils';
|
||||||
|
import { LspConnection } from '../LspConnection';
|
||||||
|
import { toMonacoLanguageSelector } from './common';
|
||||||
|
import { assertTargetTextModel } from '../ITextModelBridge';
|
||||||
|
import { toMonacoCommand, toMonacoInlayHintKind } from './common';
|
||||||
|
|
||||||
|
export class LspInlayHintsFeature extends Disposable {
|
||||||
|
private readonly _providers = new Set<LspInlayHintsProvider>();
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly _connection: LspConnection,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.addStaticClientCapabilities({
|
||||||
|
textDocument: {
|
||||||
|
inlayHint: {
|
||||||
|
dynamicRegistration: true,
|
||||||
|
resolveSupport: {
|
||||||
|
properties: ['tooltip', 'textEdits', 'label.tooltip', 'label.location', 'label.command'],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
workspace: {
|
||||||
|
inlayHint: {
|
||||||
|
refreshSupport: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._register(this._connection.connection.registerRequestHandler(api.client.workspaceInlayHintRefresh, async () => {
|
||||||
|
// Fire onDidChangeInlayHints for all providers
|
||||||
|
for (const provider of this._providers) {
|
||||||
|
provider.refresh();
|
||||||
|
}
|
||||||
|
return { ok: null };
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.registerCapabilityHandler(capabilities.textDocumentInlayHint, true, capability => {
|
||||||
|
const provider = new LspInlayHintsProvider(this._connection, capability);
|
||||||
|
this._providers.add(provider);
|
||||||
|
|
||||||
|
const disposable = monaco.languages.registerInlayHintsProvider(
|
||||||
|
toMonacoLanguageSelector(capability.documentSelector),
|
||||||
|
provider,
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
dispose: () => {
|
||||||
|
this._providers.delete(provider);
|
||||||
|
disposable.dispose();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ExtendedInlayHint extends monaco.languages.InlayHint {
|
||||||
|
_lspInlayHint: InlayHint;
|
||||||
|
_targetUri: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
class LspInlayHintsProvider implements monaco.languages.InlayHintsProvider {
|
||||||
|
private readonly _onDidChangeInlayHints = new monaco.Emitter<void>();
|
||||||
|
public readonly onDidChangeInlayHints = this._onDidChangeInlayHints.event;
|
||||||
|
|
||||||
|
public readonly resolveInlayHint;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly _client: LspConnection,
|
||||||
|
private readonly _capabilities: InlayHintRegistrationOptions,
|
||||||
|
) {
|
||||||
|
if (_capabilities.resolveProvider) {
|
||||||
|
this.resolveInlayHint = async (hint: ExtendedInlayHint, token: monaco.CancellationToken): Promise<monaco.languages.InlayHint> => {
|
||||||
|
|
||||||
|
const resolved = await this._client.server.inlayHintResolve(hint._lspInlayHint);
|
||||||
|
|
||||||
|
if (resolved.tooltip) {
|
||||||
|
hint.tooltip = toMonacoTooltip(resolved.tooltip);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resolved.label !== hint._lspInlayHint.label) {
|
||||||
|
hint.label = toLspInlayHintLabel(resolved.label);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resolved.textEdits) {
|
||||||
|
hint.textEdits = resolved.textEdits.map(edit => {
|
||||||
|
const translated = this._client.bridge.translateBackRange(
|
||||||
|
{ uri: hint._targetUri },
|
||||||
|
edit.range
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
range: translated.range,
|
||||||
|
text: edit.newText,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return hint;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public refresh(): void {
|
||||||
|
this._onDidChangeInlayHints.fire();
|
||||||
|
}
|
||||||
|
|
||||||
|
async provideInlayHints(
|
||||||
|
model: monaco.editor.ITextModel,
|
||||||
|
range: monaco.Range,
|
||||||
|
token: monaco.CancellationToken
|
||||||
|
): Promise<monaco.languages.InlayHintList | null> {
|
||||||
|
const translated = this._client.bridge.translate(model, range.getStartPosition());
|
||||||
|
|
||||||
|
const result = await retryOnContentModified(async () =>
|
||||||
|
await this._client.server.textDocumentInlayHint({
|
||||||
|
textDocument: translated.textDocument,
|
||||||
|
range: this._client.bridge.translateRange(model, range),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
hints: result.map(hint => {
|
||||||
|
const monacoHint: ExtendedInlayHint = {
|
||||||
|
label: toLspInlayHintLabel(hint.label),
|
||||||
|
position: assertTargetTextModel(
|
||||||
|
this._client.bridge.translateBack(translated.textDocument, hint.position),
|
||||||
|
model
|
||||||
|
).position,
|
||||||
|
kind: toMonacoInlayHintKind(hint.kind),
|
||||||
|
tooltip: toMonacoTooltip(hint.tooltip),
|
||||||
|
paddingLeft: hint.paddingLeft,
|
||||||
|
paddingRight: hint.paddingRight,
|
||||||
|
textEdits: hint.textEdits?.map(edit => ({
|
||||||
|
range: assertTargetTextModel(
|
||||||
|
this._client.bridge.translateBackRange(translated.textDocument, edit.range),
|
||||||
|
model
|
||||||
|
).range,
|
||||||
|
text: edit.newText,
|
||||||
|
})),
|
||||||
|
_lspInlayHint: hint,
|
||||||
|
_targetUri: translated.textDocument.uri,
|
||||||
|
};
|
||||||
|
return monacoHint;
|
||||||
|
}),
|
||||||
|
dispose: () => { },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function retryOnContentModified<T>(cb: () => Promise<T>): Promise<T> {
|
||||||
|
const nRetries = 3;
|
||||||
|
for (let triesLeft = nRetries; ; triesLeft--) {
|
||||||
|
try {
|
||||||
|
return await cb();
|
||||||
|
} catch (e: any) {
|
||||||
|
if (e.message === 'content modified' && triesLeft > 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toLspInlayHintLabel(label: string | any[]): string | monaco.languages.InlayHintLabelPart[] {
|
||||||
|
if (typeof label === 'string') {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
return label.map(part => {
|
||||||
|
const monacoLabelPart: monaco.languages.InlayHintLabelPart = {
|
||||||
|
label: part.value,
|
||||||
|
tooltip: toMonacoTooltip(part.tooltip),
|
||||||
|
command: toMonacoCommand(part.command),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (part.location) {
|
||||||
|
monacoLabelPart.location = {
|
||||||
|
uri: monaco.Uri.parse(part.location.uri),
|
||||||
|
range: new monaco.Range(
|
||||||
|
part.location.range.start.line + 1,
|
||||||
|
part.location.range.start.character + 1,
|
||||||
|
part.location.range.end.line + 1,
|
||||||
|
part.location.range.end.character + 1
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return monacoLabelPart;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function toMonacoTooltip(tooltip: string | MarkupContent | undefined): string | monaco.IMarkdownString | undefined {
|
||||||
|
if (!tooltip) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof tooltip === 'string') {
|
||||||
|
return tooltip;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
value: tooltip.value,
|
||||||
|
isTrusted: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
import * as monaco from 'monaco-editor-core';
|
||||||
|
import { capabilities, DocumentOnTypeFormattingRegistrationOptions } from '../../../src/types';
|
||||||
|
import { Disposable } from '../../utils';
|
||||||
|
import { LspConnection } from '../LspConnection';
|
||||||
|
import { toMonacoLanguageSelector } from './common';
|
||||||
|
|
||||||
|
export class LspOnTypeFormattingFeature extends Disposable {
|
||||||
|
constructor(
|
||||||
|
private readonly _connection: LspConnection,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.addStaticClientCapabilities({
|
||||||
|
textDocument: {
|
||||||
|
onTypeFormatting: {
|
||||||
|
dynamicRegistration: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.registerCapabilityHandler(capabilities.textDocumentOnTypeFormatting, true, capability => {
|
||||||
|
return monaco.languages.registerOnTypeFormattingEditProvider(
|
||||||
|
toMonacoLanguageSelector(capability.documentSelector),
|
||||||
|
new LspOnTypeFormattingProvider(this._connection, capability),
|
||||||
|
);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LspOnTypeFormattingProvider implements monaco.languages.OnTypeFormattingEditProvider {
|
||||||
|
public readonly autoFormatTriggerCharacters: string[];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly _client: LspConnection,
|
||||||
|
private readonly _capabilities: DocumentOnTypeFormattingRegistrationOptions,
|
||||||
|
) {
|
||||||
|
this.autoFormatTriggerCharacters = [
|
||||||
|
_capabilities.firstTriggerCharacter,
|
||||||
|
...(_capabilities.moreTriggerCharacter || [])
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
async provideOnTypeFormattingEdits(
|
||||||
|
model: monaco.editor.ITextModel,
|
||||||
|
position: monaco.Position,
|
||||||
|
ch: string,
|
||||||
|
options: monaco.languages.FormattingOptions,
|
||||||
|
token: monaco.CancellationToken
|
||||||
|
): Promise<monaco.languages.TextEdit[] | null> {
|
||||||
|
const translated = this._client.bridge.translate(model, position);
|
||||||
|
|
||||||
|
const result = await this._client.server.textDocumentOnTypeFormatting({
|
||||||
|
textDocument: translated.textDocument,
|
||||||
|
position: translated.position,
|
||||||
|
ch,
|
||||||
|
options: {
|
||||||
|
tabSize: options.tabSize,
|
||||||
|
insertSpaces: options.insertSpaces,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.map(edit => ({
|
||||||
|
range: this._client.bridge.translateBackRange(translated.textDocument, edit.range).range,
|
||||||
|
text: edit.newText,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
import * as monaco from 'monaco-editor-core';
|
||||||
|
import { capabilities, DocumentRangeFormattingRegistrationOptions } from '../../../src/types';
|
||||||
|
import { Disposable } from '../../utils';
|
||||||
|
import { LspConnection } from '../LspConnection';
|
||||||
|
import { toMonacoLanguageSelector } from './common';
|
||||||
|
|
||||||
|
export class LspRangeFormattingFeature extends Disposable {
|
||||||
|
constructor(
|
||||||
|
private readonly _connection: LspConnection,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.addStaticClientCapabilities({
|
||||||
|
textDocument: {
|
||||||
|
rangeFormatting: {
|
||||||
|
dynamicRegistration: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.registerCapabilityHandler(capabilities.textDocumentRangeFormatting, true, capability => {
|
||||||
|
return monaco.languages.registerDocumentRangeFormattingEditProvider(
|
||||||
|
toMonacoLanguageSelector(capability.documentSelector),
|
||||||
|
new LspDocumentRangeFormattingProvider(this._connection, capability),
|
||||||
|
);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LspDocumentRangeFormattingProvider implements monaco.languages.DocumentRangeFormattingEditProvider {
|
||||||
|
constructor(
|
||||||
|
private readonly _client: LspConnection,
|
||||||
|
private readonly _capabilities: DocumentRangeFormattingRegistrationOptions,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
async provideDocumentRangeFormattingEdits(
|
||||||
|
model: monaco.editor.ITextModel,
|
||||||
|
range: monaco.Range,
|
||||||
|
options: monaco.languages.FormattingOptions,
|
||||||
|
token: monaco.CancellationToken
|
||||||
|
): Promise<monaco.languages.TextEdit[] | null> {
|
||||||
|
const translated = this._client.bridge.translate(model, range.getStartPosition());
|
||||||
|
|
||||||
|
const result = await this._client.server.textDocumentRangeFormatting({
|
||||||
|
textDocument: translated.textDocument,
|
||||||
|
range: this._client.bridge.translateRange(model, range),
|
||||||
|
options: {
|
||||||
|
tabSize: options.tabSize,
|
||||||
|
insertSpaces: options.insertSpaces,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.map(edit => ({
|
||||||
|
range: this._client.bridge.translateBackRange(translated.textDocument, edit.range).range,
|
||||||
|
text: edit.newText,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
import * as monaco from 'monaco-editor-core';
|
||||||
|
import { capabilities, ReferenceRegistrationOptions } from '../../../src/types';
|
||||||
|
import { Disposable } from '../../utils';
|
||||||
|
import { LspConnection } from '../LspConnection';
|
||||||
|
import { toMonacoLanguageSelector } from './common';
|
||||||
|
|
||||||
|
export class LspReferencesFeature extends Disposable {
|
||||||
|
constructor(
|
||||||
|
private readonly _connection: LspConnection,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.addStaticClientCapabilities({
|
||||||
|
textDocument: {
|
||||||
|
references: {
|
||||||
|
dynamicRegistration: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.registerCapabilityHandler(capabilities.textDocumentReferences, true, capability => {
|
||||||
|
return monaco.languages.registerReferenceProvider(
|
||||||
|
toMonacoLanguageSelector(capability.documentSelector),
|
||||||
|
new LspReferenceProvider(this._connection, capability),
|
||||||
|
);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LspReferenceProvider implements monaco.languages.ReferenceProvider {
|
||||||
|
constructor(
|
||||||
|
private readonly _client: LspConnection,
|
||||||
|
private readonly _capabilities: ReferenceRegistrationOptions,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
async provideReferences(
|
||||||
|
model: monaco.editor.ITextModel,
|
||||||
|
position: monaco.Position,
|
||||||
|
context: monaco.languages.ReferenceContext,
|
||||||
|
token: monaco.CancellationToken
|
||||||
|
): Promise<monaco.languages.Location[] | null> {
|
||||||
|
const translated = this._client.bridge.translate(model, position);
|
||||||
|
|
||||||
|
const result = await this._client.server.textDocumentReferences({
|
||||||
|
textDocument: translated.textDocument,
|
||||||
|
position: translated.position,
|
||||||
|
context: {
|
||||||
|
includeDeclaration: context.includeDeclaration,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.map(loc => {
|
||||||
|
const translated = this._client.bridge.translateBackRange({ uri: loc.uri }, loc.range);
|
||||||
|
return {
|
||||||
|
uri: translated.textModel.uri,
|
||||||
|
range: translated.range,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,142 @@
|
||||||
|
import * as monaco from 'monaco-editor-core';
|
||||||
|
import { capabilities, RenameRegistrationOptions } from '../../../src/types';
|
||||||
|
import { Disposable } from '../../utils';
|
||||||
|
import { LspConnection } from '../LspConnection';
|
||||||
|
import { toMonacoLanguageSelector } from './common';
|
||||||
|
|
||||||
|
export class LspRenameFeature extends Disposable {
|
||||||
|
constructor(
|
||||||
|
private readonly _connection: LspConnection,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.addStaticClientCapabilities({
|
||||||
|
textDocument: {
|
||||||
|
rename: {
|
||||||
|
dynamicRegistration: true,
|
||||||
|
prepareSupport: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.registerCapabilityHandler(capabilities.textDocumentRename, true, capability => {
|
||||||
|
return monaco.languages.registerRenameProvider(
|
||||||
|
toMonacoLanguageSelector(capability.documentSelector),
|
||||||
|
new LspRenameProvider(this._connection, capability),
|
||||||
|
);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LspRenameProvider implements monaco.languages.RenameProvider {
|
||||||
|
constructor(
|
||||||
|
private readonly _client: LspConnection,
|
||||||
|
private readonly _capabilities: RenameRegistrationOptions,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
async provideRenameEdits(
|
||||||
|
model: monaco.editor.ITextModel,
|
||||||
|
position: monaco.Position,
|
||||||
|
newName: string,
|
||||||
|
token: monaco.CancellationToken
|
||||||
|
): Promise<monaco.languages.WorkspaceEdit | null> {
|
||||||
|
const translated = this._client.bridge.translate(model, position);
|
||||||
|
|
||||||
|
const result = await this._client.server.textDocumentRename({
|
||||||
|
textDocument: translated.textDocument,
|
||||||
|
position: translated.position,
|
||||||
|
newName,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return toMonacoWorkspaceEdit(result, this._client);
|
||||||
|
}
|
||||||
|
|
||||||
|
async resolveRenameLocation(
|
||||||
|
model: monaco.editor.ITextModel,
|
||||||
|
position: monaco.Position,
|
||||||
|
token: monaco.CancellationToken
|
||||||
|
): Promise<monaco.languages.RenameLocation | null> {
|
||||||
|
if (!this._capabilities.prepareProvider) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const translated = this._client.bridge.translate(model, position);
|
||||||
|
|
||||||
|
const result = await this._client.server.textDocumentPrepareRename({
|
||||||
|
textDocument: translated.textDocument,
|
||||||
|
position: translated.position,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('range' in result && 'placeholder' in result) {
|
||||||
|
return {
|
||||||
|
range: this._client.bridge.translateBackRange(translated.textDocument, result.range).range,
|
||||||
|
text: result.placeholder,
|
||||||
|
};
|
||||||
|
} else if ('defaultBehavior' in result) {
|
||||||
|
return null;
|
||||||
|
} else if ('start' in result && 'end' in result) {
|
||||||
|
const range = this._client.bridge.translateBackRange(translated.textDocument, result).range;
|
||||||
|
return {
|
||||||
|
range,
|
||||||
|
text: model.getValueInRange(range),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toMonacoWorkspaceEdit(
|
||||||
|
edit: any,
|
||||||
|
client: LspConnection
|
||||||
|
): monaco.languages.WorkspaceEdit {
|
||||||
|
const edits: monaco.languages.IWorkspaceTextEdit[] = [];
|
||||||
|
|
||||||
|
if (edit.changes) {
|
||||||
|
for (const uri in edit.changes) {
|
||||||
|
const textEdits = edit.changes[uri];
|
||||||
|
for (const textEdit of textEdits) {
|
||||||
|
const translated = client.bridge.translateBackRange({ uri }, textEdit.range);
|
||||||
|
edits.push({
|
||||||
|
resource: translated.textModel.uri,
|
||||||
|
versionId: undefined,
|
||||||
|
textEdit: {
|
||||||
|
range: translated.range,
|
||||||
|
text: textEdit.newText,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (edit.documentChanges) {
|
||||||
|
for (const change of edit.documentChanges) {
|
||||||
|
if ('textDocument' in change) {
|
||||||
|
// TextDocumentEdit
|
||||||
|
const uri = change.textDocument.uri;
|
||||||
|
for (const textEdit of change.edits) {
|
||||||
|
const translated = client.bridge.translateBackRange({ uri }, textEdit.range);
|
||||||
|
edits.push({
|
||||||
|
resource: translated.textModel.uri,
|
||||||
|
versionId: change.textDocument.version,
|
||||||
|
textEdit: {
|
||||||
|
range: translated.range,
|
||||||
|
text: textEdit.newText,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: Handle CreateFile, RenameFile, DeleteFile
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { edits };
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
import * as monaco from 'monaco-editor-core';
|
||||||
|
import { capabilities, SelectionRangeRegistrationOptions } from '../../../src/types';
|
||||||
|
import { Disposable } from '../../utils';
|
||||||
|
import { LspConnection } from '../LspConnection';
|
||||||
|
import { toMonacoLanguageSelector } from './common';
|
||||||
|
|
||||||
|
export class LspSelectionRangeFeature extends Disposable {
|
||||||
|
constructor(
|
||||||
|
private readonly _connection: LspConnection,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.addStaticClientCapabilities({
|
||||||
|
textDocument: {
|
||||||
|
selectionRange: {
|
||||||
|
dynamicRegistration: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.registerCapabilityHandler(capabilities.textDocumentSelectionRange, true, capability => {
|
||||||
|
return monaco.languages.registerSelectionRangeProvider(
|
||||||
|
toMonacoLanguageSelector(capability.documentSelector),
|
||||||
|
new LspSelectionRangeProvider(this._connection, capability),
|
||||||
|
);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LspSelectionRangeProvider implements monaco.languages.SelectionRangeProvider {
|
||||||
|
constructor(
|
||||||
|
private readonly _client: LspConnection,
|
||||||
|
private readonly _capabilities: SelectionRangeRegistrationOptions,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
async provideSelectionRanges(
|
||||||
|
model: monaco.editor.ITextModel,
|
||||||
|
positions: monaco.Position[],
|
||||||
|
token: monaco.CancellationToken
|
||||||
|
): Promise<monaco.languages.SelectionRange[][] | null> {
|
||||||
|
const translated = this._client.bridge.translate(model, positions[0]);
|
||||||
|
|
||||||
|
const result = await this._client.server.textDocumentSelectionRange({
|
||||||
|
textDocument: translated.textDocument,
|
||||||
|
positions: positions.map(pos => this._client.bridge.translate(model, pos).position),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.map(selRange => this.convertSelectionRange(selRange, translated.textDocument));
|
||||||
|
}
|
||||||
|
|
||||||
|
private convertSelectionRange(
|
||||||
|
range: any,
|
||||||
|
textDocument: { uri: string }
|
||||||
|
): monaco.languages.SelectionRange[] {
|
||||||
|
const result: monaco.languages.SelectionRange[] = [];
|
||||||
|
let current = range;
|
||||||
|
|
||||||
|
while (current) {
|
||||||
|
result.push({
|
||||||
|
range: this._client.bridge.translateBackRange(textDocument, current.range).range,
|
||||||
|
});
|
||||||
|
current = current.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,130 @@
|
||||||
|
import * as monaco from 'monaco-editor-core';
|
||||||
|
import { capabilities, SemanticTokensRegistrationOptions, TokenFormat } from '../../../src/types';
|
||||||
|
import { Disposable } from '../../utils';
|
||||||
|
import { LspConnection } from '../LspConnection';
|
||||||
|
import { toMonacoLanguageSelector } from './common';
|
||||||
|
|
||||||
|
export class LspSemanticTokensFeature extends Disposable {
|
||||||
|
constructor(
|
||||||
|
private readonly _connection: LspConnection,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.addStaticClientCapabilities({
|
||||||
|
textDocument: {
|
||||||
|
semanticTokens: {
|
||||||
|
dynamicRegistration: true,
|
||||||
|
requests: {
|
||||||
|
range: true,
|
||||||
|
full: {
|
||||||
|
delta: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tokenTypes: [
|
||||||
|
'namespace', 'type', 'class', 'enum', 'interface', 'struct',
|
||||||
|
'typeParameter', 'parameter', 'variable', 'property', 'enumMember',
|
||||||
|
'event', 'function', 'method', 'macro', 'keyword', 'modifier',
|
||||||
|
'comment', 'string', 'number', 'regexp', 'operator', 'decorator'
|
||||||
|
],
|
||||||
|
tokenModifiers: [
|
||||||
|
'declaration', 'definition', 'readonly', 'static', 'deprecated',
|
||||||
|
'abstract', 'async', 'modification', 'documentation', 'defaultLibrary'
|
||||||
|
],
|
||||||
|
formats: [TokenFormat.Relative],
|
||||||
|
overlappingTokenSupport: false,
|
||||||
|
multilineTokenSupport: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.registerCapabilityHandler(capabilities.textDocumentSemanticTokensFull, true, capability => {
|
||||||
|
return monaco.languages.registerDocumentSemanticTokensProvider(
|
||||||
|
toMonacoLanguageSelector(capability.documentSelector),
|
||||||
|
new LspSemanticTokensProvider(this._connection, capability),
|
||||||
|
);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LspSemanticTokensProvider implements monaco.languages.DocumentSemanticTokensProvider {
|
||||||
|
constructor(
|
||||||
|
private readonly _client: LspConnection,
|
||||||
|
private readonly _capabilities: SemanticTokensRegistrationOptions,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
getLegend(): monaco.languages.SemanticTokensLegend {
|
||||||
|
return {
|
||||||
|
tokenTypes: this._capabilities.legend.tokenTypes,
|
||||||
|
tokenModifiers: this._capabilities.legend.tokenModifiers,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
releaseDocumentSemanticTokens(resultId: string | undefined): void {
|
||||||
|
// Monaco will call this when it's done with a result
|
||||||
|
// We can potentially notify the server if needed
|
||||||
|
}
|
||||||
|
|
||||||
|
async provideDocumentSemanticTokens(
|
||||||
|
model: monaco.editor.ITextModel,
|
||||||
|
lastResultId: string | null,
|
||||||
|
token: monaco.CancellationToken
|
||||||
|
): Promise<monaco.languages.SemanticTokens | monaco.languages.SemanticTokensEdits | null> {
|
||||||
|
const translated = this._client.bridge.translate(model, model.getPositionAt(0));
|
||||||
|
|
||||||
|
// Try delta request if we have a previous result and server supports it
|
||||||
|
const full = this._capabilities.full;
|
||||||
|
if (lastResultId && full && typeof full === 'object' && full.delta) {
|
||||||
|
const deltaResult = await this._client.server.textDocumentSemanticTokensFullDelta({
|
||||||
|
textDocument: translated.textDocument,
|
||||||
|
previousResultId: lastResultId,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!deltaResult) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if it's a delta or full result
|
||||||
|
if ('edits' in deltaResult) {
|
||||||
|
// It's a delta
|
||||||
|
return {
|
||||||
|
resultId: deltaResult.resultId,
|
||||||
|
edits: deltaResult.edits.map(edit => ({
|
||||||
|
start: edit.start,
|
||||||
|
deleteCount: edit.deleteCount,
|
||||||
|
data: edit.data ? new Uint32Array(edit.data) : undefined,
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// It's a full result
|
||||||
|
return {
|
||||||
|
resultId: deltaResult.resultId,
|
||||||
|
data: new Uint32Array(deltaResult.data),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Full request
|
||||||
|
const result = await this._client.server.textDocumentSemanticTokensFull({
|
||||||
|
textDocument: translated.textDocument,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
resultId: result.resultId,
|
||||||
|
data: new Uint32Array(result.data),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async provideDocumentSemanticTokensEdits?(
|
||||||
|
model: monaco.editor.ITextModel,
|
||||||
|
previousResultId: string,
|
||||||
|
token: monaco.CancellationToken
|
||||||
|
): Promise<monaco.languages.SemanticTokens | monaco.languages.SemanticTokensEdits | null> {
|
||||||
|
// This method is called when Monaco wants to use delta updates
|
||||||
|
// We can delegate to provideDocumentSemanticTokens which handles both
|
||||||
|
return this.provideDocumentSemanticTokens(model, previousResultId, token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,101 @@
|
||||||
|
import * as monaco from 'monaco-editor-core';
|
||||||
|
import { capabilities, SignatureHelpRegistrationOptions, MarkupContent, MarkupKind } from '../../../src/types';
|
||||||
|
import { Disposable } from '../../utils';
|
||||||
|
import { LspConnection } from '../LspConnection';
|
||||||
|
import { toMonacoLanguageSelector } from './common';
|
||||||
|
import { toLspSignatureHelpTriggerKind } from './common';
|
||||||
|
|
||||||
|
export class LspSignatureHelpFeature extends Disposable {
|
||||||
|
constructor(
|
||||||
|
private readonly _connection: LspConnection,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.addStaticClientCapabilities({
|
||||||
|
textDocument: {
|
||||||
|
signatureHelp: {
|
||||||
|
dynamicRegistration: true,
|
||||||
|
contextSupport: true,
|
||||||
|
signatureInformation: {
|
||||||
|
documentationFormat: [MarkupKind.Markdown, MarkupKind.PlainText],
|
||||||
|
parameterInformation: {
|
||||||
|
labelOffsetSupport: true,
|
||||||
|
},
|
||||||
|
activeParameterSupport: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.registerCapabilityHandler(capabilities.textDocumentSignatureHelp, true, capability => {
|
||||||
|
return monaco.languages.registerSignatureHelpProvider(
|
||||||
|
toMonacoLanguageSelector(capability.documentSelector),
|
||||||
|
new LspSignatureHelpProvider(this._connection, capability),
|
||||||
|
);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LspSignatureHelpProvider implements monaco.languages.SignatureHelpProvider {
|
||||||
|
public readonly signatureHelpTriggerCharacters?: readonly string[];
|
||||||
|
public readonly signatureHelpRetriggerCharacters?: readonly string[];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly _client: LspConnection,
|
||||||
|
private readonly _capabilities: SignatureHelpRegistrationOptions,
|
||||||
|
) {
|
||||||
|
this.signatureHelpTriggerCharacters = _capabilities.triggerCharacters;
|
||||||
|
this.signatureHelpRetriggerCharacters = _capabilities.retriggerCharacters;
|
||||||
|
}
|
||||||
|
|
||||||
|
async provideSignatureHelp(
|
||||||
|
model: monaco.editor.ITextModel,
|
||||||
|
position: monaco.Position,
|
||||||
|
token: monaco.CancellationToken,
|
||||||
|
context: monaco.languages.SignatureHelpContext
|
||||||
|
): Promise<monaco.languages.SignatureHelpResult | null> {
|
||||||
|
const translated = this._client.bridge.translate(model, position);
|
||||||
|
|
||||||
|
const result = await this._client.server.textDocumentSignatureHelp({
|
||||||
|
textDocument: translated.textDocument,
|
||||||
|
position: translated.position,
|
||||||
|
context: {
|
||||||
|
triggerKind: toLspSignatureHelpTriggerKind(context.triggerKind),
|
||||||
|
triggerCharacter: context.triggerCharacter,
|
||||||
|
isRetrigger: context.isRetrigger,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
value: {
|
||||||
|
signatures: result.signatures.map(sig => ({
|
||||||
|
label: sig.label,
|
||||||
|
documentation: toMonacoDocumentation(sig.documentation),
|
||||||
|
parameters: sig.parameters?.map(param => ({
|
||||||
|
label: param.label,
|
||||||
|
documentation: toMonacoDocumentation(param.documentation),
|
||||||
|
})) || [],
|
||||||
|
activeParameter: sig.activeParameter,
|
||||||
|
})),
|
||||||
|
activeSignature: result.activeSignature || 0,
|
||||||
|
activeParameter: result.activeParameter || 0,
|
||||||
|
},
|
||||||
|
dispose: () => { },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toMonacoDocumentation(
|
||||||
|
doc: string | MarkupContent | undefined
|
||||||
|
): string | monaco.IMarkdownString | undefined {
|
||||||
|
if (!doc) return undefined;
|
||||||
|
if (typeof doc === 'string') return doc;
|
||||||
|
return {
|
||||||
|
value: doc.value,
|
||||||
|
isTrusted: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
import * as monaco from 'monaco-editor-core';
|
||||||
|
import { capabilities, TypeDefinitionRegistrationOptions } from '../../../src/types';
|
||||||
|
import { Disposable } from '../../utils';
|
||||||
|
import { LspConnection } from '../LspConnection';
|
||||||
|
import { toMonacoLanguageSelector } from './common';
|
||||||
|
import { toMonacoLocation } from "./common";
|
||||||
|
|
||||||
|
export class LspTypeDefinitionFeature extends Disposable {
|
||||||
|
constructor(
|
||||||
|
private readonly _connection: LspConnection,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.addStaticClientCapabilities({
|
||||||
|
textDocument: {
|
||||||
|
typeDefinition: {
|
||||||
|
dynamicRegistration: true,
|
||||||
|
linkSupport: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._register(this._connection.capabilities.registerCapabilityHandler(capabilities.textDocumentTypeDefinition, true, capability => {
|
||||||
|
return monaco.languages.registerTypeDefinitionProvider(
|
||||||
|
toMonacoLanguageSelector(capability.documentSelector),
|
||||||
|
new LspTypeDefinitionProvider(this._connection, capability),
|
||||||
|
);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LspTypeDefinitionProvider implements monaco.languages.TypeDefinitionProvider {
|
||||||
|
constructor(
|
||||||
|
private readonly _client: LspConnection,
|
||||||
|
private readonly _capabilities: TypeDefinitionRegistrationOptions,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
async provideTypeDefinition(
|
||||||
|
model: monaco.editor.ITextModel,
|
||||||
|
position: monaco.Position,
|
||||||
|
token: monaco.CancellationToken
|
||||||
|
): Promise<monaco.languages.Definition | monaco.languages.LocationLink[] | null> {
|
||||||
|
const translated = this._client.bridge.translate(model, position);
|
||||||
|
|
||||||
|
const result = await this._client.server.textDocumentTypeDefinition({
|
||||||
|
textDocument: translated.textDocument,
|
||||||
|
position: translated.position,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(result)) {
|
||||||
|
return result.map(loc => toMonacoLocation(loc, this._client));
|
||||||
|
}
|
||||||
|
|
||||||
|
return toMonacoLocation(result, this._client);
|
||||||
|
}
|
||||||
|
}
|
||||||
401
monaco-lsp-client/src/adapters/languageFeatures/common.ts
Normal file
401
monaco-lsp-client/src/adapters/languageFeatures/common.ts
Normal file
|
|
@ -0,0 +1,401 @@
|
||||||
|
import * as monaco from 'monaco-editor-core';
|
||||||
|
import {
|
||||||
|
CodeActionKind,
|
||||||
|
CodeActionTriggerKind,
|
||||||
|
Command,
|
||||||
|
CompletionItemKind,
|
||||||
|
CompletionItemTag,
|
||||||
|
CompletionTriggerKind,
|
||||||
|
Diagnostic,
|
||||||
|
DiagnosticSeverity,
|
||||||
|
DiagnosticTag,
|
||||||
|
DocumentHighlightKind,
|
||||||
|
DocumentSelector,
|
||||||
|
FoldingRangeKind,
|
||||||
|
InlayHintKind,
|
||||||
|
InsertTextFormat,
|
||||||
|
Location,
|
||||||
|
LocationLink,
|
||||||
|
SignatureHelpTriggerKind,
|
||||||
|
SymbolKind,
|
||||||
|
SymbolTag,
|
||||||
|
} from '../../../src/types';
|
||||||
|
import { LspConnection } from '../LspConnection';
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Code Action Kind
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
export const lspCodeActionKindToMonacoCodeActionKind = new Map<CodeActionKind, string>([
|
||||||
|
[CodeActionKind.Empty, ''],
|
||||||
|
[CodeActionKind.QuickFix, 'quickfix'],
|
||||||
|
[CodeActionKind.Refactor, 'refactor'],
|
||||||
|
[CodeActionKind.RefactorExtract, 'refactor.extract'],
|
||||||
|
[CodeActionKind.RefactorInline, 'refactor.inline'],
|
||||||
|
[CodeActionKind.RefactorRewrite, 'refactor.rewrite'],
|
||||||
|
[CodeActionKind.Source, 'source'],
|
||||||
|
[CodeActionKind.SourceOrganizeImports, 'source.organizeImports'],
|
||||||
|
[CodeActionKind.SourceFixAll, 'source.fixAll'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
export function toMonacoCodeActionKind(kind: CodeActionKind | undefined): string | undefined {
|
||||||
|
if (!kind) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return lspCodeActionKindToMonacoCodeActionKind.get(kind) ?? kind;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Code Action Trigger Kind
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
export const monacoCodeActionTriggerTypeToLspCodeActionTriggerKind = new Map<monaco.languages.CodeActionTriggerType, CodeActionTriggerKind>([
|
||||||
|
[monaco.languages.CodeActionTriggerType.Invoke, CodeActionTriggerKind.Invoked],
|
||||||
|
[monaco.languages.CodeActionTriggerType.Auto, CodeActionTriggerKind.Automatic],
|
||||||
|
]);
|
||||||
|
|
||||||
|
export function toLspCodeActionTriggerKind(monacoTrigger: monaco.languages.CodeActionTriggerType): CodeActionTriggerKind {
|
||||||
|
return monacoCodeActionTriggerTypeToLspCodeActionTriggerKind.get(monacoTrigger) ?? CodeActionTriggerKind.Invoked;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Completion Item Kind
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
export const lspCompletionItemKindToMonacoCompletionItemKind = new Map<CompletionItemKind, monaco.languages.CompletionItemKind>([
|
||||||
|
[CompletionItemKind.Text, monaco.languages.CompletionItemKind.Text],
|
||||||
|
[CompletionItemKind.Method, monaco.languages.CompletionItemKind.Method],
|
||||||
|
[CompletionItemKind.Function, monaco.languages.CompletionItemKind.Function],
|
||||||
|
[CompletionItemKind.Constructor, monaco.languages.CompletionItemKind.Constructor],
|
||||||
|
[CompletionItemKind.Field, monaco.languages.CompletionItemKind.Field],
|
||||||
|
[CompletionItemKind.Variable, monaco.languages.CompletionItemKind.Variable],
|
||||||
|
[CompletionItemKind.Class, monaco.languages.CompletionItemKind.Class],
|
||||||
|
[CompletionItemKind.Interface, monaco.languages.CompletionItemKind.Interface],
|
||||||
|
[CompletionItemKind.Module, monaco.languages.CompletionItemKind.Module],
|
||||||
|
[CompletionItemKind.Property, monaco.languages.CompletionItemKind.Property],
|
||||||
|
[CompletionItemKind.Unit, monaco.languages.CompletionItemKind.Unit],
|
||||||
|
[CompletionItemKind.Value, monaco.languages.CompletionItemKind.Value],
|
||||||
|
[CompletionItemKind.Enum, monaco.languages.CompletionItemKind.Enum],
|
||||||
|
[CompletionItemKind.Keyword, monaco.languages.CompletionItemKind.Keyword],
|
||||||
|
[CompletionItemKind.Snippet, monaco.languages.CompletionItemKind.Snippet],
|
||||||
|
[CompletionItemKind.Color, monaco.languages.CompletionItemKind.Color],
|
||||||
|
[CompletionItemKind.File, monaco.languages.CompletionItemKind.File],
|
||||||
|
[CompletionItemKind.Reference, monaco.languages.CompletionItemKind.Reference],
|
||||||
|
[CompletionItemKind.Folder, monaco.languages.CompletionItemKind.Folder],
|
||||||
|
[CompletionItemKind.EnumMember, monaco.languages.CompletionItemKind.EnumMember],
|
||||||
|
[CompletionItemKind.Constant, monaco.languages.CompletionItemKind.Constant],
|
||||||
|
[CompletionItemKind.Struct, monaco.languages.CompletionItemKind.Struct],
|
||||||
|
[CompletionItemKind.Event, monaco.languages.CompletionItemKind.Event],
|
||||||
|
[CompletionItemKind.Operator, monaco.languages.CompletionItemKind.Operator],
|
||||||
|
[CompletionItemKind.TypeParameter, monaco.languages.CompletionItemKind.TypeParameter],
|
||||||
|
]);
|
||||||
|
|
||||||
|
export function toMonacoCompletionItemKind(kind: CompletionItemKind | undefined): monaco.languages.CompletionItemKind {
|
||||||
|
if (!kind) {
|
||||||
|
return monaco.languages.CompletionItemKind.Text;
|
||||||
|
}
|
||||||
|
return lspCompletionItemKindToMonacoCompletionItemKind.get(kind) ?? monaco.languages.CompletionItemKind.Text;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Completion Item Tag
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
export const lspCompletionItemTagToMonacoCompletionItemTag = new Map<CompletionItemTag, monaco.languages.CompletionItemTag>([
|
||||||
|
[CompletionItemTag.Deprecated, monaco.languages.CompletionItemTag.Deprecated],
|
||||||
|
]);
|
||||||
|
|
||||||
|
export function toMonacoCompletionItemTag(tag: CompletionItemTag): monaco.languages.CompletionItemTag | undefined {
|
||||||
|
return lspCompletionItemTagToMonacoCompletionItemTag.get(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Completion Trigger Kind
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
export const monacoCompletionTriggerKindToLspCompletionTriggerKind = new Map<monaco.languages.CompletionTriggerKind, CompletionTriggerKind>([
|
||||||
|
[monaco.languages.CompletionTriggerKind.Invoke, CompletionTriggerKind.Invoked],
|
||||||
|
[monaco.languages.CompletionTriggerKind.TriggerCharacter, CompletionTriggerKind.TriggerCharacter],
|
||||||
|
[monaco.languages.CompletionTriggerKind.TriggerForIncompleteCompletions, CompletionTriggerKind.TriggerForIncompleteCompletions],
|
||||||
|
]);
|
||||||
|
|
||||||
|
export function toLspCompletionTriggerKind(monacoKind: monaco.languages.CompletionTriggerKind): CompletionTriggerKind {
|
||||||
|
return monacoCompletionTriggerKindToLspCompletionTriggerKind.get(monacoKind) ?? CompletionTriggerKind.Invoked;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Insert Text Format
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
export const lspInsertTextFormatToMonacoInsertTextRules = new Map<InsertTextFormat, monaco.languages.CompletionItemInsertTextRule>([
|
||||||
|
[InsertTextFormat.Snippet, monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet],
|
||||||
|
]);
|
||||||
|
|
||||||
|
export function toMonacoInsertTextRules(format: InsertTextFormat | undefined): monaco.languages.CompletionItemInsertTextRule | undefined {
|
||||||
|
if (!format) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return lspInsertTextFormatToMonacoInsertTextRules.get(format);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Symbol Kind
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
export const lspSymbolKindToMonacoSymbolKind = new Map<SymbolKind, monaco.languages.SymbolKind>([
|
||||||
|
[SymbolKind.File, monaco.languages.SymbolKind.File],
|
||||||
|
[SymbolKind.Module, monaco.languages.SymbolKind.Module],
|
||||||
|
[SymbolKind.Namespace, monaco.languages.SymbolKind.Namespace],
|
||||||
|
[SymbolKind.Package, monaco.languages.SymbolKind.Package],
|
||||||
|
[SymbolKind.Class, monaco.languages.SymbolKind.Class],
|
||||||
|
[SymbolKind.Method, monaco.languages.SymbolKind.Method],
|
||||||
|
[SymbolKind.Property, monaco.languages.SymbolKind.Property],
|
||||||
|
[SymbolKind.Field, monaco.languages.SymbolKind.Field],
|
||||||
|
[SymbolKind.Constructor, monaco.languages.SymbolKind.Constructor],
|
||||||
|
[SymbolKind.Enum, monaco.languages.SymbolKind.Enum],
|
||||||
|
[SymbolKind.Interface, monaco.languages.SymbolKind.Interface],
|
||||||
|
[SymbolKind.Function, monaco.languages.SymbolKind.Function],
|
||||||
|
[SymbolKind.Variable, monaco.languages.SymbolKind.Variable],
|
||||||
|
[SymbolKind.Constant, monaco.languages.SymbolKind.Constant],
|
||||||
|
[SymbolKind.String, monaco.languages.SymbolKind.String],
|
||||||
|
[SymbolKind.Number, monaco.languages.SymbolKind.Number],
|
||||||
|
[SymbolKind.Boolean, monaco.languages.SymbolKind.Boolean],
|
||||||
|
[SymbolKind.Array, monaco.languages.SymbolKind.Array],
|
||||||
|
[SymbolKind.Object, monaco.languages.SymbolKind.Object],
|
||||||
|
[SymbolKind.Key, monaco.languages.SymbolKind.Key],
|
||||||
|
[SymbolKind.Null, monaco.languages.SymbolKind.Null],
|
||||||
|
[SymbolKind.EnumMember, monaco.languages.SymbolKind.EnumMember],
|
||||||
|
[SymbolKind.Struct, monaco.languages.SymbolKind.Struct],
|
||||||
|
[SymbolKind.Event, monaco.languages.SymbolKind.Event],
|
||||||
|
[SymbolKind.Operator, monaco.languages.SymbolKind.Operator],
|
||||||
|
[SymbolKind.TypeParameter, monaco.languages.SymbolKind.TypeParameter],
|
||||||
|
]);
|
||||||
|
|
||||||
|
export function toMonacoSymbolKind(kind: SymbolKind): monaco.languages.SymbolKind {
|
||||||
|
return lspSymbolKindToMonacoSymbolKind.get(kind) ?? monaco.languages.SymbolKind.File;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Symbol Tag
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
export const lspSymbolTagToMonacoSymbolTag = new Map<SymbolTag, monaco.languages.SymbolTag>([
|
||||||
|
[SymbolTag.Deprecated, monaco.languages.SymbolTag.Deprecated],
|
||||||
|
]);
|
||||||
|
|
||||||
|
export function toMonacoSymbolTag(tag: SymbolTag): monaco.languages.SymbolTag | undefined {
|
||||||
|
return lspSymbolTagToMonacoSymbolTag.get(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Document Highlight Kind
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
export const lspDocumentHighlightKindToMonacoDocumentHighlightKind = new Map<DocumentHighlightKind, monaco.languages.DocumentHighlightKind>([
|
||||||
|
[DocumentHighlightKind.Text, monaco.languages.DocumentHighlightKind.Text],
|
||||||
|
[DocumentHighlightKind.Read, monaco.languages.DocumentHighlightKind.Read],
|
||||||
|
[DocumentHighlightKind.Write, monaco.languages.DocumentHighlightKind.Write],
|
||||||
|
]);
|
||||||
|
|
||||||
|
export function toMonacoDocumentHighlightKind(kind: DocumentHighlightKind | undefined): monaco.languages.DocumentHighlightKind {
|
||||||
|
if (!kind) {
|
||||||
|
return monaco.languages.DocumentHighlightKind.Text;
|
||||||
|
}
|
||||||
|
return lspDocumentHighlightKindToMonacoDocumentHighlightKind.get(kind) ?? monaco.languages.DocumentHighlightKind.Text;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Folding Range Kind
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
export const lspFoldingRangeKindToMonacoFoldingRangeKind = new Map<FoldingRangeKind, monaco.languages.FoldingRangeKind>([
|
||||||
|
[FoldingRangeKind.Comment, monaco.languages.FoldingRangeKind.Comment],
|
||||||
|
[FoldingRangeKind.Imports, monaco.languages.FoldingRangeKind.Imports],
|
||||||
|
[FoldingRangeKind.Region, monaco.languages.FoldingRangeKind.Region],
|
||||||
|
]);
|
||||||
|
|
||||||
|
export function toMonacoFoldingRangeKind(kind: FoldingRangeKind | undefined): monaco.languages.FoldingRangeKind | undefined {
|
||||||
|
if (!kind) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return lspFoldingRangeKindToMonacoFoldingRangeKind.get(kind);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Diagnostic Severity
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
export const monacoMarkerSeverityToLspDiagnosticSeverity = new Map<monaco.MarkerSeverity, DiagnosticSeverity>([
|
||||||
|
[monaco.MarkerSeverity.Error, DiagnosticSeverity.Error],
|
||||||
|
[monaco.MarkerSeverity.Warning, DiagnosticSeverity.Warning],
|
||||||
|
[monaco.MarkerSeverity.Info, DiagnosticSeverity.Information],
|
||||||
|
[monaco.MarkerSeverity.Hint, DiagnosticSeverity.Hint],
|
||||||
|
]);
|
||||||
|
|
||||||
|
export function toLspDiagnosticSeverity(severity: monaco.MarkerSeverity): DiagnosticSeverity {
|
||||||
|
return monacoMarkerSeverityToLspDiagnosticSeverity.get(severity) ?? DiagnosticSeverity.Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const lspDiagnosticSeverityToMonacoMarkerSeverity = new Map<DiagnosticSeverity, monaco.MarkerSeverity>([
|
||||||
|
[DiagnosticSeverity.Error, monaco.MarkerSeverity.Error],
|
||||||
|
[DiagnosticSeverity.Warning, monaco.MarkerSeverity.Warning],
|
||||||
|
[DiagnosticSeverity.Information, monaco.MarkerSeverity.Info],
|
||||||
|
[DiagnosticSeverity.Hint, monaco.MarkerSeverity.Hint],
|
||||||
|
]);
|
||||||
|
|
||||||
|
export function toMonacoDiagnosticSeverity(severity: DiagnosticSeverity | undefined): monaco.MarkerSeverity {
|
||||||
|
if (!severity) {
|
||||||
|
return monaco.MarkerSeverity.Error;
|
||||||
|
}
|
||||||
|
return lspDiagnosticSeverityToMonacoMarkerSeverity.get(severity) ?? monaco.MarkerSeverity.Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Diagnostic Tag
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
export const lspDiagnosticTagToMonacoMarkerTag = new Map<DiagnosticTag, monaco.MarkerTag>([
|
||||||
|
[DiagnosticTag.Unnecessary, monaco.MarkerTag.Unnecessary],
|
||||||
|
[DiagnosticTag.Deprecated, monaco.MarkerTag.Deprecated],
|
||||||
|
]);
|
||||||
|
|
||||||
|
export function toMonacoDiagnosticTag(tag: DiagnosticTag): monaco.MarkerTag | undefined {
|
||||||
|
return lspDiagnosticTagToMonacoMarkerTag.get(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Signature Help Trigger Kind
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
export const monacoSignatureHelpTriggerKindToLspSignatureHelpTriggerKind = new Map<monaco.languages.SignatureHelpTriggerKind, SignatureHelpTriggerKind>([
|
||||||
|
[monaco.languages.SignatureHelpTriggerKind.Invoke, SignatureHelpTriggerKind.Invoked],
|
||||||
|
[monaco.languages.SignatureHelpTriggerKind.TriggerCharacter, SignatureHelpTriggerKind.TriggerCharacter],
|
||||||
|
[monaco.languages.SignatureHelpTriggerKind.ContentChange, SignatureHelpTriggerKind.ContentChange],
|
||||||
|
]);
|
||||||
|
|
||||||
|
export function toLspSignatureHelpTriggerKind(monacoKind: monaco.languages.SignatureHelpTriggerKind): SignatureHelpTriggerKind {
|
||||||
|
return monacoSignatureHelpTriggerKindToLspSignatureHelpTriggerKind.get(monacoKind) ?? SignatureHelpTriggerKind.Invoked;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Command
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
export function toMonacoCommand(command: Command | undefined): monaco.languages.Command | undefined {
|
||||||
|
if (!command) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
id: command.command,
|
||||||
|
title: command.title,
|
||||||
|
arguments: command.arguments,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Inlay Hint Kind
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
export const lspInlayHintKindToMonacoInlayHintKind = new Map<InlayHintKind, monaco.languages.InlayHintKind>([
|
||||||
|
[InlayHintKind.Type, monaco.languages.InlayHintKind.Type],
|
||||||
|
[InlayHintKind.Parameter, monaco.languages.InlayHintKind.Parameter],
|
||||||
|
]);
|
||||||
|
|
||||||
|
export function toMonacoInlayHintKind(kind: InlayHintKind | undefined): monaco.languages.InlayHintKind {
|
||||||
|
if (!kind) {
|
||||||
|
return monaco.languages.InlayHintKind.Type;
|
||||||
|
}
|
||||||
|
return lspInlayHintKindToMonacoInlayHintKind.get(kind) ?? monaco.languages.InlayHintKind.Type;
|
||||||
|
} export function toMonacoLocation(
|
||||||
|
location: Location | LocationLink,
|
||||||
|
client: LspConnection
|
||||||
|
): monaco.languages.Location | monaco.languages.LocationLink {
|
||||||
|
if ('targetUri' in location) {
|
||||||
|
// LocationLink
|
||||||
|
const translatedRange = client.bridge.translateBackRange({ uri: location.targetUri }, location.targetRange);
|
||||||
|
return {
|
||||||
|
uri: translatedRange.textModel.uri,
|
||||||
|
range: translatedRange.range,
|
||||||
|
originSelectionRange: location.originSelectionRange
|
||||||
|
? client.bridge.translateBackRange({ uri: location.targetUri }, location.originSelectionRange).range
|
||||||
|
: undefined,
|
||||||
|
targetSelectionRange: location.targetSelectionRange
|
||||||
|
? client.bridge.translateBackRange({ uri: location.targetUri }, location.targetSelectionRange).range
|
||||||
|
: undefined,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// Location
|
||||||
|
const translatedRange = client.bridge.translateBackRange({ uri: location.uri }, location.range);
|
||||||
|
return {
|
||||||
|
uri: translatedRange.textModel.uri,
|
||||||
|
range: translatedRange.range,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export function toMonacoLanguageSelector(s: DocumentSelector | null): monaco.languages.LanguageSelector {
|
||||||
|
if (!s || s.length === 0) {
|
||||||
|
return { language: '*' };
|
||||||
|
}
|
||||||
|
return s.map<monaco.languages.LanguageFilter>(s => {
|
||||||
|
if ('notebook' in s) {
|
||||||
|
if (typeof s.notebook === 'string') {
|
||||||
|
return { notebookType: s.notebook, language: s.language };
|
||||||
|
} else {
|
||||||
|
return { notebookType: s.notebook.notebookType, language: s.language, pattern: s.notebook.pattern, scheme: s.notebook.scheme };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return { language: s.language, pattern: s.pattern, scheme: s.scheme };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
export function matchesDocumentSelector(model: monaco.editor.ITextModel, selector: DocumentSelector | null): boolean {
|
||||||
|
if (!selector) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const languageId = model.getLanguageId();
|
||||||
|
const uri = model.uri.toString(true);
|
||||||
|
|
||||||
|
if (!selector || selector.length === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const filter of selector) {
|
||||||
|
if (filter.language && filter.language !== '*' && filter.language !== languageId) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
export function toDiagnosticMarker(diagnostic: Diagnostic): monaco.editor.IMarkerData {
|
||||||
|
const marker: monaco.editor.IMarkerData = {
|
||||||
|
severity: toMonacoDiagnosticSeverity(diagnostic.severity),
|
||||||
|
startLineNumber: diagnostic.range.start.line + 1,
|
||||||
|
startColumn: diagnostic.range.start.character + 1,
|
||||||
|
endLineNumber: diagnostic.range.end.line + 1,
|
||||||
|
endColumn: diagnostic.range.end.character + 1,
|
||||||
|
message: diagnostic.message,
|
||||||
|
source: diagnostic.source,
|
||||||
|
code: typeof diagnostic.code === 'string' ? diagnostic.code : diagnostic.code?.toString(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (diagnostic.tags) {
|
||||||
|
marker.tags = diagnostic.tags.map(tag => toMonacoDiagnosticTag(tag)).filter((tag): tag is monaco.MarkerTag => tag !== undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (diagnostic.relatedInformation) {
|
||||||
|
marker.relatedInformation = diagnostic.relatedInformation.map(info => ({
|
||||||
|
resource: monaco.Uri.parse(info.location.uri),
|
||||||
|
startLineNumber: info.location.range.start.line + 1,
|
||||||
|
startColumn: info.location.range.start.character + 1,
|
||||||
|
endLineNumber: info.location.range.end.line + 1,
|
||||||
|
endColumn: info.location.range.end.character + 1,
|
||||||
|
message: info.message,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
return marker;
|
||||||
|
}
|
||||||
|
|
||||||
5
monaco-lsp-client/src/index.ts
Normal file
5
monaco-lsp-client/src/index.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { MonacoLspClient } from './adapters/LspClient';
|
||||||
|
import { WebSocketTransport } from '@hediet/json-rpc-websocket';
|
||||||
|
import { createTransportToWorker, createTransportToIFrame } from '@hediet/json-rpc-browser';
|
||||||
|
|
||||||
|
export { MonacoLspClient, WebSocketTransport, createTransportToWorker, createTransportToIFrame };
|
||||||
7514
monaco-lsp-client/src/types.ts
Normal file
7514
monaco-lsp-client/src/types.ts
Normal file
File diff suppressed because it is too large
Load diff
75
monaco-lsp-client/src/utils.ts
Normal file
75
monaco-lsp-client/src/utils.ts
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
export interface IDisposable {
|
||||||
|
dispose(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Disposable implements IDisposable {
|
||||||
|
static None = Object.freeze<IDisposable>({ dispose() { } });
|
||||||
|
|
||||||
|
private _store = new DisposableStore();
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
public dispose(): void {
|
||||||
|
this._store.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected _register<T extends IDisposable>(t: T): T {
|
||||||
|
if ((t as any) === this) {
|
||||||
|
throw new Error('Cannot register a disposable on itself!');
|
||||||
|
}
|
||||||
|
return this._store.add(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DisposableStore implements IDisposable {
|
||||||
|
static DISABLE_DISPOSED_WARNING = false;
|
||||||
|
|
||||||
|
private _toDispose = new Set<IDisposable>();
|
||||||
|
private _isDisposed = false;
|
||||||
|
|
||||||
|
public dispose(): void {
|
||||||
|
if (this._isDisposed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._isDisposed = true;
|
||||||
|
this.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public clear(): void {
|
||||||
|
if (this._toDispose.size === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (const item of this._toDispose) {
|
||||||
|
item.dispose();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
this._toDispose.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public add<T extends IDisposable>(t: T): T {
|
||||||
|
if (!t) {
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
if ((t as any) === this) {
|
||||||
|
throw new Error('Cannot register a disposable on itself!');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._isDisposed) {
|
||||||
|
if (!DisposableStore.DISABLE_DISPOSED_WARNING) {
|
||||||
|
console.warn(
|
||||||
|
new Error(
|
||||||
|
'Trying to add a disposable to a DisposableStore that has already been disposed of. The added object will be leaked!'
|
||||||
|
).stack
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this._toDispose.add(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
}
|
||||||
3745
package-lock.json
generated
3745
package-lock.json
generated
File diff suppressed because it is too large
Load diff
47
package.json
47
package.json
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "monaco-editor",
|
"name": "monaco-editor",
|
||||||
"version": "0.53.0",
|
"version": "0.54.0",
|
||||||
"vscodeRef": "e296bdfe0313d571a6f58399b22afd199f6da454",
|
"vscodeRef": "484fdf69b8509c1c9370d913b32e9f6d3a68cc99",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "A browser based code editor",
|
"description": "A browser based code editor",
|
||||||
"homepage": "https://github.com/microsoft/monaco-editor",
|
"homepage": "https://github.com/microsoft/monaco-editor",
|
||||||
|
|
@ -14,33 +14,49 @@
|
||||||
"prettier": "prettier --write .",
|
"prettier": "prettier --write .",
|
||||||
"pretty-quick": "pretty-quick --staged",
|
"pretty-quick": "pretty-quick --staged",
|
||||||
"simpleserver": "ts-node ./build/simpleserver",
|
"simpleserver": "ts-node ./build/simpleserver",
|
||||||
|
"package-for-smoketest": "npm run package-for-smoketest-webpack && npm run package-for-smoketest-esbuild && npm run package-for-smoketest-vite",
|
||||||
"package-for-smoketest-webpack": "ts-node ./test/smoke/package-webpack",
|
"package-for-smoketest-webpack": "ts-node ./test/smoke/package-webpack",
|
||||||
"package-for-smoketest-webpack-cross-origin": "ts-node ./test/smoke/package-webpack --cross-origin",
|
"package-for-smoketest-webpack-cross-origin": "ts-node ./test/smoke/package-webpack --cross-origin",
|
||||||
"package-for-smoketest-esbuild": "ts-node ./test/smoke/package-esbuild",
|
"package-for-smoketest-esbuild": "ts-node ./test/smoke/package-esbuild",
|
||||||
"package-for-smoketest-vite": "ts-node ./test/smoke/package-vite",
|
"package-for-smoketest-vite": "ts-node ./test/smoke/package-vite",
|
||||||
"smoketest": "node ./test/smoke/runner.js",
|
"smoketest": "playwright test --config=test/smoke/playwright.config.ts",
|
||||||
"smoketest-debug": "node ./test/smoke/runner.js --debug-tests",
|
"smoketest-debug": "playwright test --config=test/smoke/playwright.config.ts --debug",
|
||||||
|
"smoketest-ui": "playwright test --config=test/smoke/playwright.config.ts --ui",
|
||||||
|
"smoketest-headed": "playwright test --config=test/smoke/playwright.config.ts --headed",
|
||||||
"test": "ts-node ./build/check-samples",
|
"test": "ts-node ./build/check-samples",
|
||||||
"deps-all-remove": "ts-node ./build/npm/removeAll",
|
"deps-all-remove": "ts-node ./build/npm/removeAll",
|
||||||
"deps-all-install": "ts-node ./build/npm/installAll",
|
"deps-all-install": "ts-node ./build/npm/installAll",
|
||||||
"update-actions": "pin-github-action ./.github/workflows/website.yml",
|
"update-actions": "pin-github-action ./.github/workflows/website.yml",
|
||||||
"watch": "tsc -w -p ./src",
|
"watch": "tsc -w -p ./src",
|
||||||
"build-languages": "ts-node ./build/build-languages",
|
"build-all": "npm run build-lsp && npm run build-monaco-editor && npm run package-for-smoketest",
|
||||||
|
"build": "npm run build-lsp && npm run build-monaco-editor",
|
||||||
"build-monaco-editor": "ts-node ./build/build-monaco-editor",
|
"build-monaco-editor": "ts-node ./build/build-monaco-editor",
|
||||||
"build": "npm run build-languages && npm run build-monaco-editor"
|
"build-lsp": "cd monaco-lsp-client && npm install && npm run build"
|
||||||
},
|
},
|
||||||
"typings": "./esm/vs/editor/editor.api.d.ts",
|
"typings": "./esm/vs/editor/editor.api.d.ts",
|
||||||
|
"main": "./min/vs/editor/editor.main.js",
|
||||||
"module": "./esm/vs/editor/editor.main.js",
|
"module": "./esm/vs/editor/editor.main.js",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"types": "./esm/vs/editor/editor.api.d.ts",
|
||||||
|
"import": "./esm/vs/editor/editor.main.js",
|
||||||
|
"require": "./min/vs/editor/editor.main.js"
|
||||||
|
},
|
||||||
|
"./*": "./*"
|
||||||
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/microsoft/monaco-editor"
|
"url": "https://github.com/microsoft/monaco-editor"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@playwright/test": "^1.53.2",
|
"@playwright/test": "^1.56.1",
|
||||||
"@types/mocha": "^9.1.0",
|
"@rollup/plugin-alias": "^5.1.1",
|
||||||
|
"@rollup/plugin-node-resolve": "^16.0.2",
|
||||||
|
"@types/mocha": "^10.0.10",
|
||||||
"@types/shelljs": "^0.8.11",
|
"@types/shelljs": "^0.8.11",
|
||||||
"@types/trusted-types": "^1.0.6",
|
"@types/trusted-types": "^1.0.6",
|
||||||
"@typescript/vfs": "^1.3.5",
|
"@typescript/vfs": "^1.3.5",
|
||||||
|
"@vscode/monaco-lsp-client": "file:./monaco-lsp-client",
|
||||||
"chai": "^4.3.6",
|
"chai": "^4.3.6",
|
||||||
"clean-css": "^5.2.4",
|
"clean-css": "^5.2.4",
|
||||||
"css-loader": "^6.7.1",
|
"css-loader": "^6.7.1",
|
||||||
|
|
@ -52,19 +68,26 @@
|
||||||
"husky": "^7.0.4",
|
"husky": "^7.0.4",
|
||||||
"jsdom": "^19.0.0",
|
"jsdom": "^19.0.0",
|
||||||
"jsonc-parser": "^3.0.0",
|
"jsonc-parser": "^3.0.0",
|
||||||
"mocha": "^9.2.0",
|
"mocha": "^11.7.4",
|
||||||
"monaco-editor-core": "^0.54.0-dev-20250926",
|
"monaco-editor-core": "^0.55.0-dev-20251008",
|
||||||
"parcel": "^2.7.0",
|
"parcel": "^2.7.0",
|
||||||
"pin-github-action": "^1.8.0",
|
"pin-github-action": "^1.8.0",
|
||||||
|
"postcss-url": "^10.1.3",
|
||||||
"prettier": "^2.5.1",
|
"prettier": "^2.5.1",
|
||||||
"pretty-quick": "^3.1.3",
|
"pretty-quick": "^3.1.3",
|
||||||
"requirejs": "^2.3.7",
|
"requirejs": "^2.3.7",
|
||||||
|
"rollup": "^4.52.4",
|
||||||
|
"rollup-plugin-delete": "^3.0.1",
|
||||||
|
"rollup-plugin-dts": "^6.2.3",
|
||||||
|
"rollup-plugin-esbuild": "^6.2.1",
|
||||||
|
"rollup-plugin-import-css": "^4.0.2",
|
||||||
|
"rollup-plugin-keep-css-imports": "^1.0.0",
|
||||||
"shelljs": "^0.8.5",
|
"shelljs": "^0.8.5",
|
||||||
"style-loader": "^3.3.1",
|
"style-loader": "^3.3.1",
|
||||||
"terser": "^5.14.2",
|
"terser": "^5.14.2",
|
||||||
"ts-node": "^10.6.0",
|
"ts-node": "^10.6.0",
|
||||||
"typescript": "^5.4.5",
|
"typescript": "^5.9.3",
|
||||||
"vite": "^7.1.5",
|
"vite": "^7.1.11",
|
||||||
"vscode-css-languageservice": "6.2.14",
|
"vscode-css-languageservice": "6.2.14",
|
||||||
"vscode-html-languageservice": "5.2.0",
|
"vscode-html-languageservice": "5.2.0",
|
||||||
"vscode-json-languageservice": "5.3.11",
|
"vscode-json-languageservice": "5.3.11",
|
||||||
|
|
|
||||||
1733
samples/browser-esm-vite-react/package-lock.json
generated
1733
samples/browser-esm-vite-react/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -15,6 +15,6 @@
|
||||||
"@types/react-dom": "^17.0.11",
|
"@types/react-dom": "^17.0.11",
|
||||||
"@vitejs/plugin-react": "^1.1.4",
|
"@vitejs/plugin-react": "^1.1.4",
|
||||||
"typescript": "^5.4.5",
|
"typescript": "^5.4.5",
|
||||||
"vite": "^2.9.17"
|
"vite": "^5.4.20"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,36 +43,32 @@ async function prepareMonacoEditorRelease(monacoEditorCoreVersion: string) {
|
||||||
});
|
});
|
||||||
|
|
||||||
await group('Set Version & Update monaco-editor-core Version', async () => {
|
await group('Set Version & Update monaco-editor-core Version', async () => {
|
||||||
const packageJson = JSON.parse(
|
const packageJson = JSON.parse(await readFile(monacoEditorPackageJsonPath, { encoding: 'utf-8' })) as PackageJson;
|
||||||
await readFile(monacoEditorPackageJsonPath, { encoding: 'utf-8' })
|
|
||||||
) as PackageJson;
|
|
||||||
|
|
||||||
packageJson.version = monacoEditorCoreVersion;
|
packageJson.version = monacoEditorCoreVersion;
|
||||||
packageJson.devDependencies['monaco-editor-core'] = monacoEditorCoreVersion;
|
packageJson.devDependencies['monaco-editor-core'] = monacoEditorCoreVersion;
|
||||||
|
await writeJsonFile(monacoEditorPackageJsonPath, packageJson);
|
||||||
|
});
|
||||||
|
|
||||||
const monacoEditorCorePackageJson = JSON.parse(
|
await group('npm install to pick up monaco-editor-core', async () => {
|
||||||
await readFile(monacoEditorCorePackageJsonPath, { encoding: 'utf-8' })
|
await run('npm install', { cwd: rootPath });
|
||||||
) as PackageJson;
|
});
|
||||||
|
|
||||||
|
await group('Pick up monaco-editor-core dependencies for CVE tracking', async () => {
|
||||||
|
const packageJson = JSON.parse(await readFile(monacoEditorPackageJsonPath, { encoding: 'utf-8' })) as PackageJson;
|
||||||
|
const monacoEditorCorePackageJson = JSON.parse(await readFile(monacoEditorCorePackageJsonPath, { encoding: 'utf-8' })) as PackageJson;
|
||||||
if (monacoEditorCorePackageJson.dependencies) {
|
if (monacoEditorCorePackageJson.dependencies) {
|
||||||
if (!packageJson.dependencies) {
|
if (!packageJson.dependencies) {
|
||||||
packageJson.dependencies = {};
|
packageJson.dependencies = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
objectMergeThrowIfSet(
|
objectMergeThrowIfSet(
|
||||||
packageJson.dependencies,
|
packageJson.dependencies,
|
||||||
monacoEditorCorePackageJson.dependencies,
|
monacoEditorCorePackageJson.dependencies,
|
||||||
'dependencies'
|
'dependencies'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
await writeJsonFile(monacoEditorPackageJsonPath, packageJson);
|
await writeJsonFile(monacoEditorPackageJsonPath, packageJson);
|
||||||
});
|
});
|
||||||
|
|
||||||
await group('npm install to pick up monaco-editor-core', async () => {
|
|
||||||
await run('npm install', { cwd: rootPath });
|
|
||||||
});
|
|
||||||
|
|
||||||
await group('Setting vscode commitId from monaco-editor-core', async () => {
|
await group('Setting vscode commitId from monaco-editor-core', async () => {
|
||||||
const monacoEditorCorePackageJson = JSON.parse(
|
const monacoEditorCorePackageJson = JSON.parse(
|
||||||
await readFile(monacoEditorCorePackageJsonPath, { encoding: 'utf-8' })
|
await readFile(monacoEditorCorePackageJsonPath, { encoding: 'utf-8' })
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { languages, editor } from '../fillers/monaco-editor-core';
|
import { languages, editor } from 'monaco-editor-core';
|
||||||
|
|
||||||
interface ILang extends languages.ILanguageExtensionPoint {
|
interface ILang extends languages.ILanguageExtensionPoint {
|
||||||
loader: () => Promise<ILangImpl>;
|
loader: () => Promise<ILangImpl>;
|
||||||
|
|
|
||||||
|
|
@ -5,20 +5,9 @@
|
||||||
|
|
||||||
import { registerLanguage } from '../_.contribution';
|
import { registerLanguage } from '../_.contribution';
|
||||||
|
|
||||||
declare var AMD: any;
|
|
||||||
declare var require: any;
|
|
||||||
|
|
||||||
registerLanguage({
|
registerLanguage({
|
||||||
id: 'abap',
|
id: 'abap',
|
||||||
extensions: ['.abap'],
|
extensions: ['.abap'],
|
||||||
aliases: ['abap', 'ABAP'],
|
aliases: ['abap', 'ABAP'],
|
||||||
loader: () => {
|
loader: () => import('./abap')
|
||||||
if (AMD) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
require(['vs/basic-languages/abap/abap'], resolve, reject);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return import('./abap');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
*
|
*
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import type { languages } from '../../fillers/monaco-editor-core';
|
import type { languages } from 'monaco-editor-core';
|
||||||
|
|
||||||
export const conf: languages.LanguageConfiguration = {
|
export const conf: languages.LanguageConfiguration = {
|
||||||
comments: {
|
comments: {
|
||||||
|
|
|
||||||
|
|
@ -5,21 +5,10 @@
|
||||||
|
|
||||||
import { registerLanguage } from '../_.contribution';
|
import { registerLanguage } from '../_.contribution';
|
||||||
|
|
||||||
declare var AMD: any;
|
|
||||||
declare var require: any;
|
|
||||||
|
|
||||||
registerLanguage({
|
registerLanguage({
|
||||||
id: 'apex',
|
id: 'apex',
|
||||||
extensions: ['.cls'],
|
extensions: ['.cls'],
|
||||||
aliases: ['Apex', 'apex'],
|
aliases: ['Apex', 'apex'],
|
||||||
mimetypes: ['text/x-apex-source', 'text/x-apex'],
|
mimetypes: ['text/x-apex-source', 'text/x-apex'],
|
||||||
loader: () => {
|
loader: () => import('./apex')
|
||||||
if (AMD) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
require(['vs/basic-languages/apex/apex'], resolve, reject);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return import('./apex');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import type { languages } from '../../fillers/monaco-editor-core';
|
import type { languages } from 'monaco-editor-core';
|
||||||
|
|
||||||
export const conf: languages.LanguageConfiguration = {
|
export const conf: languages.LanguageConfiguration = {
|
||||||
// the default separators except `@$`
|
// the default separators except `@$`
|
||||||
|
|
|
||||||
|
|
@ -5,20 +5,9 @@
|
||||||
|
|
||||||
import { registerLanguage } from '../_.contribution';
|
import { registerLanguage } from '../_.contribution';
|
||||||
|
|
||||||
declare var AMD: any;
|
|
||||||
declare var require: any;
|
|
||||||
|
|
||||||
registerLanguage({
|
registerLanguage({
|
||||||
id: 'azcli',
|
id: 'azcli',
|
||||||
extensions: ['.azcli'],
|
extensions: ['.azcli'],
|
||||||
aliases: ['Azure CLI', 'azcli'],
|
aliases: ['Azure CLI', 'azcli'],
|
||||||
loader: () => {
|
loader: () => import('./azcli')
|
||||||
if (AMD) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
require(['vs/basic-languages/azcli/azcli'], resolve, reject);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return import('./azcli');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import type { languages } from '../../fillers/monaco-editor-core';
|
import type { languages } from 'monaco-editor-core';
|
||||||
|
|
||||||
export const conf: languages.LanguageConfiguration = {
|
export const conf: languages.LanguageConfiguration = {
|
||||||
comments: {
|
comments: {
|
||||||
|
|
|
||||||
|
|
@ -5,20 +5,9 @@
|
||||||
|
|
||||||
import { registerLanguage } from '../_.contribution';
|
import { registerLanguage } from '../_.contribution';
|
||||||
|
|
||||||
declare var AMD: any;
|
|
||||||
declare var require: any;
|
|
||||||
|
|
||||||
registerLanguage({
|
registerLanguage({
|
||||||
id: 'bat',
|
id: 'bat',
|
||||||
extensions: ['.bat', '.cmd'],
|
extensions: ['.bat', '.cmd'],
|
||||||
aliases: ['Batch', 'bat'],
|
aliases: ['Batch', 'bat'],
|
||||||
loader: () => {
|
loader: () => import('./bat')
|
||||||
if (AMD) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
require(['vs/basic-languages/bat/bat'], resolve, reject);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return import('./bat');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import type { languages } from '../../fillers/monaco-editor-core';
|
import type { languages } from 'monaco-editor-core';
|
||||||
|
|
||||||
export const conf: languages.LanguageConfiguration = {
|
export const conf: languages.LanguageConfiguration = {
|
||||||
comments: {
|
comments: {
|
||||||
|
|
|
||||||
|
|
@ -5,20 +5,9 @@
|
||||||
|
|
||||||
import { registerLanguage } from '../_.contribution';
|
import { registerLanguage } from '../_.contribution';
|
||||||
|
|
||||||
declare var AMD: any;
|
|
||||||
declare var require: any;
|
|
||||||
|
|
||||||
registerLanguage({
|
registerLanguage({
|
||||||
id: 'bicep',
|
id: 'bicep',
|
||||||
extensions: ['.bicep'],
|
extensions: ['.bicep'],
|
||||||
aliases: ['Bicep'],
|
aliases: ['Bicep'],
|
||||||
loader: () => {
|
loader: () => import('./bicep')
|
||||||
if (AMD) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
require(['vs/basic-languages/bicep/bicep'], resolve, reject);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return import('./bicep');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// Copyright (c) Microsoft Corporation.
|
// Copyright (c) Microsoft Corporation.
|
||||||
// Licensed under the MIT License.
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
import type { languages } from '../../fillers/monaco-editor-core';
|
import type { languages } from 'monaco-editor-core';
|
||||||
|
|
||||||
const bounded = (text: string) => `\\b${text}\\b`;
|
const bounded = (text: string) => `\\b${text}\\b`;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,20 +5,9 @@
|
||||||
|
|
||||||
import { registerLanguage } from '../_.contribution';
|
import { registerLanguage } from '../_.contribution';
|
||||||
|
|
||||||
declare var AMD: any;
|
|
||||||
declare var require: any;
|
|
||||||
|
|
||||||
registerLanguage({
|
registerLanguage({
|
||||||
id: 'cameligo',
|
id: 'cameligo',
|
||||||
extensions: ['.mligo'],
|
extensions: ['.mligo'],
|
||||||
aliases: ['Cameligo'],
|
aliases: ['Cameligo'],
|
||||||
loader: () => {
|
loader: () => import('./cameligo')
|
||||||
if (AMD) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
require(['vs/basic-languages/cameligo/cameligo'], resolve, reject);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return import('./cameligo');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import type { languages } from '../../fillers/monaco-editor-core';
|
import type { languages } from 'monaco-editor-core';
|
||||||
|
|
||||||
export const conf: languages.LanguageConfiguration = {
|
export const conf: languages.LanguageConfiguration = {
|
||||||
comments: {
|
comments: {
|
||||||
|
|
|
||||||
|
|
@ -5,20 +5,9 @@
|
||||||
|
|
||||||
import { registerLanguage } from '../_.contribution';
|
import { registerLanguage } from '../_.contribution';
|
||||||
|
|
||||||
declare var AMD: any;
|
|
||||||
declare var require: any;
|
|
||||||
|
|
||||||
registerLanguage({
|
registerLanguage({
|
||||||
id: 'clojure',
|
id: 'clojure',
|
||||||
extensions: ['.clj', '.cljs', '.cljc', '.edn'],
|
extensions: ['.clj', '.cljs', '.cljc', '.edn'],
|
||||||
aliases: ['clojure', 'Clojure'],
|
aliases: ['clojure', 'Clojure'],
|
||||||
loader: () => {
|
loader: () => import('./clojure')
|
||||||
if (AMD) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
require(['vs/basic-languages/clojure/clojure'], resolve, reject);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return import('./clojure');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import type { languages } from '../../fillers/monaco-editor-core';
|
import type { languages } from 'monaco-editor-core';
|
||||||
|
|
||||||
export const conf: languages.LanguageConfiguration = {
|
export const conf: languages.LanguageConfiguration = {
|
||||||
comments: {
|
comments: {
|
||||||
|
|
|
||||||
|
|
@ -5,21 +5,10 @@
|
||||||
|
|
||||||
import { registerLanguage } from '../_.contribution';
|
import { registerLanguage } from '../_.contribution';
|
||||||
|
|
||||||
declare var AMD: any;
|
|
||||||
declare var require: any;
|
|
||||||
|
|
||||||
registerLanguage({
|
registerLanguage({
|
||||||
id: 'coffeescript',
|
id: 'coffeescript',
|
||||||
extensions: ['.coffee'],
|
extensions: ['.coffee'],
|
||||||
aliases: ['CoffeeScript', 'coffeescript', 'coffee'],
|
aliases: ['CoffeeScript', 'coffeescript', 'coffee'],
|
||||||
mimetypes: ['text/x-coffeescript', 'text/coffeescript'],
|
mimetypes: ['text/x-coffeescript', 'text/coffeescript'],
|
||||||
loader: () => {
|
loader: () => import('./coffee')
|
||||||
if (AMD) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
require(['vs/basic-languages/coffee/coffee'], resolve, reject);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return import('./coffee');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import type { languages } from '../../fillers/monaco-editor-core';
|
import type { languages } from 'monaco-editor-core';
|
||||||
|
|
||||||
export const conf: languages.LanguageConfiguration = {
|
export const conf: languages.LanguageConfiguration = {
|
||||||
wordPattern:
|
wordPattern:
|
||||||
|
|
|
||||||
|
|
@ -5,34 +5,15 @@
|
||||||
|
|
||||||
import { registerLanguage } from '../_.contribution';
|
import { registerLanguage } from '../_.contribution';
|
||||||
|
|
||||||
declare var AMD: any;
|
|
||||||
declare var require: any;
|
|
||||||
|
|
||||||
registerLanguage({
|
registerLanguage({
|
||||||
id: 'c',
|
id: 'c',
|
||||||
extensions: ['.c', '.h'],
|
extensions: ['.c', '.h'],
|
||||||
aliases: ['C', 'c'],
|
aliases: ['C', 'c'],
|
||||||
loader: () => {
|
loader: () => import('./cpp')
|
||||||
if (AMD) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
require(['vs/basic-languages/cpp/cpp'], resolve, reject);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return import('./cpp');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
registerLanguage({
|
registerLanguage({
|
||||||
id: 'cpp',
|
id: 'cpp',
|
||||||
extensions: ['.cpp', '.cc', '.cxx', '.hpp', '.hh', '.hxx'],
|
extensions: ['.cpp', '.cc', '.cxx', '.hpp', '.hh', '.hxx'],
|
||||||
aliases: ['C++', 'Cpp', 'cpp'],
|
aliases: ['C++', 'Cpp', 'cpp'],
|
||||||
loader: () => {
|
loader: () => import('./cpp')
|
||||||
if (AMD) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
require(['vs/basic-languages/cpp/cpp'], resolve, reject);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return import('./cpp');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import type { languages } from '../../fillers/monaco-editor-core';
|
import type { languages } from 'monaco-editor-core';
|
||||||
|
|
||||||
export const conf: languages.LanguageConfiguration = {
|
export const conf: languages.LanguageConfiguration = {
|
||||||
comments: {
|
comments: {
|
||||||
|
|
|
||||||
|
|
@ -5,20 +5,9 @@
|
||||||
|
|
||||||
import { registerLanguage } from '../_.contribution';
|
import { registerLanguage } from '../_.contribution';
|
||||||
|
|
||||||
declare var AMD: any;
|
|
||||||
declare var require: any;
|
|
||||||
|
|
||||||
registerLanguage({
|
registerLanguage({
|
||||||
id: 'csharp',
|
id: 'csharp',
|
||||||
extensions: ['.cs', '.csx', '.cake'],
|
extensions: ['.cs', '.csx', '.cake'],
|
||||||
aliases: ['C#', 'csharp'],
|
aliases: ['C#', 'csharp'],
|
||||||
loader: () => {
|
loader: () => import('./csharp')
|
||||||
if (AMD) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
require(['vs/basic-languages/csharp/csharp'], resolve, reject);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return import('./csharp');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import type { languages } from '../../fillers/monaco-editor-core';
|
import type { languages } from 'monaco-editor-core';
|
||||||
|
|
||||||
export const conf: languages.LanguageConfiguration = {
|
export const conf: languages.LanguageConfiguration = {
|
||||||
wordPattern:
|
wordPattern:
|
||||||
|
|
|
||||||
|
|
@ -5,20 +5,9 @@
|
||||||
|
|
||||||
import { registerLanguage } from '../_.contribution';
|
import { registerLanguage } from '../_.contribution';
|
||||||
|
|
||||||
declare var AMD: any;
|
|
||||||
declare var require: any;
|
|
||||||
|
|
||||||
registerLanguage({
|
registerLanguage({
|
||||||
id: 'csp',
|
id: 'csp',
|
||||||
extensions: ['.csp'],
|
extensions: ['.csp'],
|
||||||
aliases: ['CSP', 'csp'],
|
aliases: ['CSP', 'csp'],
|
||||||
loader: () => {
|
loader: () => import('./csp')
|
||||||
if (AMD) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
require(['vs/basic-languages/csp/csp'], resolve, reject);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return import('./csp');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import type { languages } from '../../fillers/monaco-editor-core';
|
import type { languages } from 'monaco-editor-core';
|
||||||
|
|
||||||
export const conf: languages.LanguageConfiguration = {
|
export const conf: languages.LanguageConfiguration = {
|
||||||
brackets: [],
|
brackets: [],
|
||||||
|
|
|
||||||
|
|
@ -5,21 +5,10 @@
|
||||||
|
|
||||||
import { registerLanguage } from '../_.contribution';
|
import { registerLanguage } from '../_.contribution';
|
||||||
|
|
||||||
declare var AMD: any;
|
|
||||||
declare var require: any;
|
|
||||||
|
|
||||||
registerLanguage({
|
registerLanguage({
|
||||||
id: 'css',
|
id: 'css',
|
||||||
extensions: ['.css'],
|
extensions: ['.css'],
|
||||||
aliases: ['CSS', 'css'],
|
aliases: ['CSS', 'css'],
|
||||||
mimetypes: ['text/css'],
|
mimetypes: ['text/css'],
|
||||||
loader: () => {
|
loader: () => import('./css')
|
||||||
if (AMD) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
require(['vs/basic-languages/css/css'], resolve, reject);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return import('./css');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import type { languages } from '../../fillers/monaco-editor-core';
|
import type { languages } from 'monaco-editor-core';
|
||||||
|
|
||||||
export const conf: languages.LanguageConfiguration = {
|
export const conf: languages.LanguageConfiguration = {
|
||||||
wordPattern: /(#?-?\d*\.\d\w*%?)|((::|[@#.!:])?[\w-?]+%?)|::|[@#.!:]/g,
|
wordPattern: /(#?-?\d*\.\d\w*%?)|((::|[@#.!:])?[\w-?]+%?)|::|[@#.!:]/g,
|
||||||
|
|
|
||||||
|
|
@ -5,20 +5,9 @@
|
||||||
|
|
||||||
import { registerLanguage } from '../_.contribution';
|
import { registerLanguage } from '../_.contribution';
|
||||||
|
|
||||||
declare var AMD: any;
|
|
||||||
declare var require: any;
|
|
||||||
|
|
||||||
registerLanguage({
|
registerLanguage({
|
||||||
id: 'cypher',
|
id: 'cypher',
|
||||||
extensions: ['.cypher', '.cyp'],
|
extensions: ['.cypher', '.cyp'],
|
||||||
aliases: ['Cypher', 'OpenCypher'],
|
aliases: ['Cypher', 'OpenCypher'],
|
||||||
loader: () => {
|
loader: () => import('./cypher')
|
||||||
if (AMD) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
require(['vs/basic-languages/cypher/cypher'], resolve, reject);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return import('./cypher');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { languages } from '../../fillers/monaco-editor-core';
|
import { languages } from 'monaco-editor-core';
|
||||||
|
|
||||||
export const conf: languages.LanguageConfiguration = {
|
export const conf: languages.LanguageConfiguration = {
|
||||||
comments: {
|
comments: {
|
||||||
|
|
|
||||||
|
|
@ -5,21 +5,10 @@
|
||||||
|
|
||||||
import { registerLanguage } from '../_.contribution';
|
import { registerLanguage } from '../_.contribution';
|
||||||
|
|
||||||
declare var AMD: any;
|
|
||||||
declare var require: any;
|
|
||||||
|
|
||||||
registerLanguage({
|
registerLanguage({
|
||||||
id: 'dart',
|
id: 'dart',
|
||||||
extensions: ['.dart'],
|
extensions: ['.dart'],
|
||||||
aliases: ['Dart', 'dart'],
|
aliases: ['Dart', 'dart'],
|
||||||
mimetypes: ['text/x-dart-source', 'text/x-dart'],
|
mimetypes: ['text/x-dart-source', 'text/x-dart'],
|
||||||
loader: () => {
|
loader: () => import('./dart')
|
||||||
if (AMD) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
require(['vs/basic-languages/dart/dart'], resolve, reject);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return import('./dart');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue