mirror of
https://github.com/microsoft/monaco-editor.git
synced 2025-12-22 22:02:55 +01:00
Compare commits
74 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ec78a33c7b | ||
|
|
165cfcb101 | ||
|
|
09eede5b26 | ||
|
|
7649edb383 | ||
|
|
b8fa85f6c8 | ||
|
|
ebe111d469 | ||
|
|
02a9562005 | ||
|
|
94a5762a32 | ||
|
|
c619ef9a3d | ||
|
|
bf4931bb98 | ||
|
|
516f350bda | ||
|
|
9221aa0ef8 | ||
|
|
d678c1d32d | ||
|
|
f047a08481 | ||
|
|
220c1cab84 | ||
|
|
1b175c701c | ||
|
|
574b846ad2 | ||
|
|
5486e82ffa | ||
|
|
e70b6618f4 | ||
|
|
36efbe07d9 | ||
|
|
422d19e3d6 | ||
|
|
3ebf03ad14 | ||
|
|
2baf3291e9 | ||
|
|
f42be23bf6 | ||
|
|
ecd2990fb9 | ||
|
|
d84acb4d8f | ||
|
|
abae948dc3 | ||
|
|
925720b094 | ||
|
|
e7c9226d78 | ||
|
|
d38215cf6b | ||
|
|
b62a81677f | ||
|
|
81b06fd717 | ||
|
|
d89eb54d17 | ||
|
|
b3250fa2b9 | ||
|
|
9c7b547a98 | ||
|
|
ca5dfa5092 | ||
|
|
e8e70b3154 | ||
|
|
a2b9eb07f2 | ||
|
|
c0063aedfa | ||
|
|
c8b3ac9087 | ||
|
|
7102eff209 | ||
|
|
473bc634aa | ||
|
|
3b30c6efb1 | ||
|
|
96665ee0e3 | ||
|
|
93c8b62ea6 | ||
|
|
3a25d8ef40 | ||
|
|
649d4c35e5 | ||
|
|
32f1053239 | ||
|
|
268d8ce6a7 | ||
|
|
1889c7e7dd | ||
|
|
d3a3c45f48 | ||
|
|
04e09e38ce | ||
|
|
d3649a2a6b | ||
|
|
708c529972 | ||
|
|
ca96114e39 | ||
|
|
5a7e917587 | ||
|
|
0fd6f29a23 | ||
|
|
a59f6c8a72 | ||
|
|
298ad9e43d | ||
|
|
892ca6497e | ||
|
|
56b58b5674 | ||
|
|
52ceb953bf | ||
|
|
a30f4f9920 | ||
|
|
e2764eac56 | ||
|
|
f5e7e16b8f | ||
|
|
558def6f54 | ||
|
|
b16daf88e2 | ||
|
|
6194383804 | ||
|
|
953f4ecc85 | ||
|
|
e979ae38e3 | ||
|
|
3b2be8eda6 | ||
|
|
c998a7c80f | ||
|
|
699cae24be | ||
|
|
cdc4da5d91 |
308 changed files with 223741 additions and 193197 deletions
|
|
@ -62,6 +62,9 @@ extends:
|
|||
- script: npm ci
|
||||
displayName: Install NPM dependencies
|
||||
|
||||
- script: npx playwright install --with-deps
|
||||
displayName: Install Playwright Dependencies
|
||||
|
||||
- script: yarn ts-node ./scripts/ci/build-monaco-editor-core-pkg nightly
|
||||
env:
|
||||
VSCODE_REF: ${{ parameters.vscodeRef }}
|
||||
|
|
|
|||
|
|
@ -50,6 +50,9 @@ extends:
|
|||
- script: npm ci
|
||||
displayName: Install NPM dependencies
|
||||
|
||||
- script: npx playwright install --with-deps
|
||||
displayName: Install Playwright Dependencies
|
||||
|
||||
- script: yarn ts-node ./scripts/ci/build-monaco-editor-core-pkg stable
|
||||
displayName: Setup, Build & Test monaco-editor-core
|
||||
|
||||
|
|
|
|||
150
.github/commands.json
vendored
Normal file
150
.github/commands.json
vendored
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
[
|
||||
{
|
||||
"type": "comment",
|
||||
"name": "question",
|
||||
"allowUsers": [],
|
||||
"action": "updateLabels",
|
||||
"addLabel": "*question"
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "*question",
|
||||
"action": "close",
|
||||
"reason": "not_planned",
|
||||
"comment": "We closed this issue because it is a question about using Monaco Editor rather than an issue or feature request. Please search for help on [StackOverflow](https://stackoverflow.com/questions/tagged/monaco-editor), where the community has already answered many similar questions. See also our [issue reporting guidelines](https://github.com/microsoft/monaco-editor#contributing).\n\nHappy Coding!"
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "*out-of-scope",
|
||||
"action": "close",
|
||||
"reason": "not_planned",
|
||||
"comment": "We closed this issue because we don't plan to address it in the foreseeable future. If you disagree and feel that this issue is crucial: we are happy to listen and to reconsider.\n\nThanks for your understanding, and happy coding!"
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "wont-fix",
|
||||
"action": "close",
|
||||
"reason": "not_planned",
|
||||
"comment": "We closed this issue because we don't plan to address it.\n\nThanks for your understanding, and happy coding!"
|
||||
},
|
||||
{
|
||||
"type": "comment",
|
||||
"name": "duplicate",
|
||||
"allowUsers": [],
|
||||
"action": "updateLabels",
|
||||
"addLabel": "*duplicate"
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "*duplicate",
|
||||
"action": "close",
|
||||
"reason": "not_planned",
|
||||
"comment": "Thanks for creating this issue! We figured it's covering the same as another one we already have. Thus, we closed this one as a duplicate. You can search for [existing issues](https://github.com/microsoft/monaco-editor/issues).\n\nHappy Coding!"
|
||||
},
|
||||
{
|
||||
"type": "comment",
|
||||
"name": "verified",
|
||||
"allowUsers": [
|
||||
"@author"
|
||||
],
|
||||
"action": "updateLabels",
|
||||
"addLabel": "verified",
|
||||
"removeLabel": "author-verification-requested",
|
||||
"requireLabel": "author-verification-requested",
|
||||
"disallowLabel": "unreleased"
|
||||
},
|
||||
{
|
||||
"type": "comment",
|
||||
"name": "confirm",
|
||||
"allowUsers": [],
|
||||
"action": "updateLabels",
|
||||
"addLabel": "confirmed",
|
||||
"removeLabel": "confirmation-pending"
|
||||
},
|
||||
{
|
||||
"type": "comment",
|
||||
"name": "confirmationPending",
|
||||
"allowUsers": [],
|
||||
"action": "updateLabels",
|
||||
"addLabel": "confirmation-pending",
|
||||
"removeLabel": "confirmed"
|
||||
},
|
||||
{
|
||||
"type": "comment",
|
||||
"name": "needsMoreInfo",
|
||||
"allowUsers": [],
|
||||
"action": "updateLabels",
|
||||
"addLabel": "~info-needed"
|
||||
},
|
||||
{
|
||||
"type": "comment",
|
||||
"name": "closedWith",
|
||||
"allowUsers": [],
|
||||
"action": "close",
|
||||
"reason": "completed",
|
||||
"addLabel": "unreleased"
|
||||
},
|
||||
{
|
||||
"type": "comment",
|
||||
"name": "spam",
|
||||
"allowUsers": [],
|
||||
"action": "close",
|
||||
"reason": "not_planned",
|
||||
"addLabel": "invalid"
|
||||
},
|
||||
{
|
||||
"__comment__": "Allows folks on the team to label issues by commenting: `\\label My-Label` ",
|
||||
"type": "comment",
|
||||
"name": "label",
|
||||
"allowUsers": []
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "~verification-steps-needed",
|
||||
"action": "updateLabels",
|
||||
"addLabel": "verification-steps-needed",
|
||||
"removeLabel": "~verification-steps-needed",
|
||||
"comment": "Friendly ping! Looks like this issue requires some further steps to be verified. Please provide us with the steps necessary to verify this issue."
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "~info-needed",
|
||||
"action": "updateLabels",
|
||||
"addLabel": "info-needed",
|
||||
"removeLabel": "~info-needed",
|
||||
"comment": "Thanks for creating this issue! We figured it's missing some basic information or doesn't follow our issue reporting guidelines. Please take the time to review these and update the issue.\n\nHappy Coding!"
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "~version-info-needed",
|
||||
"action": "updateLabels",
|
||||
"addLabel": "info-needed",
|
||||
"removeLabel": "~version-info-needed",
|
||||
"comment": "Thanks for creating this issue! We figured it's missing some basic information, such as a version number. Please take the time to update the issue with the Monaco Editor version you're using.\n\nHappy Coding!"
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "~confirmation-needed",
|
||||
"action": "updateLabels",
|
||||
"addLabel": "info-needed",
|
||||
"removeLabel": "~confirmation-needed",
|
||||
"comment": "Please try to reproduce this issue with the latest version of Monaco Editor. If the issue persists, please update the issue with confirmation.\n\nHappy Coding!"
|
||||
},
|
||||
{
|
||||
"type": "comment",
|
||||
"name": "gifPlease",
|
||||
"allowUsers": [],
|
||||
"action": "comment",
|
||||
"addLabel": "info-needed",
|
||||
"comment": "Thanks for reporting this issue! Unfortunately, it's hard for us to understand what issue you're seeing. Please help us out by providing a screen recording showing exactly what isn't working as expected. While we can work with most standard formats, `.gif` files are preferred as they are displayed inline on GitHub. You may find https://gifcap.dev helpful as a browser-based gif recording tool.\n\nHappy coding!"
|
||||
},
|
||||
{
|
||||
"type": "comment",
|
||||
"name": "upstream",
|
||||
"allowUsers": [],
|
||||
"action": "close",
|
||||
"reason": "not_planned",
|
||||
"addLabel": "upstream",
|
||||
"comment": "This issue is caused by an upstream dependency (VS Code editor core). The fix needs to happen in the [VS Code repository](https://github.com/microsoft/vscode). Please check if there's already an issue filed there, or create one if not.\n\nHappy Coding!"
|
||||
}
|
||||
]
|
||||
30
.github/workflows/ci.yml
vendored
30
.github/workflows/ci.yml
vendored
|
|
@ -74,13 +74,7 @@ jobs:
|
|||
run: npm run compile --prefix webpack-plugin
|
||||
|
||||
- name: Package using webpack plugin
|
||||
run: npm run package-for-smoketest-webpack
|
||||
|
||||
- name: Package using esbuild
|
||||
run: npm run package-for-smoketest-esbuild
|
||||
|
||||
- name: Package using vite
|
||||
run: npm run package-for-smoketest-vite
|
||||
run: npm run package-for-smoketest
|
||||
|
||||
# - name: Package using parcel
|
||||
# run: npm run package-for-smoketest-parcel --prefix test/smoke/parcel
|
||||
|
|
@ -89,14 +83,18 @@ jobs:
|
|||
- name: Run smoke test
|
||||
run: npm run smoketest
|
||||
|
||||
# - name: Install website node modules
|
||||
# working-directory: website
|
||||
# run: yarn install --frozen-lockfile
|
||||
- name: Install website node modules
|
||||
working-directory: website
|
||||
run: npm ci
|
||||
|
||||
# - name: Build website
|
||||
# working-directory: website
|
||||
# run: yarn run build
|
||||
- name: Install most recent version of monaco-editor
|
||||
working-directory: website
|
||||
run: npm install monaco-editor
|
||||
|
||||
# - name: Test website
|
||||
# working-directory: website
|
||||
# run: yarn test
|
||||
- name: Build website
|
||||
working-directory: website
|
||||
run: npm run build
|
||||
|
||||
- name: Test website
|
||||
working-directory: website
|
||||
run: npm run test
|
||||
|
|
|
|||
14
.github/workflows/website.yml
vendored
14
.github/workflows/website.yml
vendored
|
|
@ -39,20 +39,26 @@ jobs:
|
|||
- name: execute `npm ci` (1)
|
||||
if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }}
|
||||
run: npm ci
|
||||
|
||||
# For TypeDoc
|
||||
- name: Build
|
||||
run: npm run build-monaco-editor
|
||||
run: npm run build
|
||||
|
||||
- name: Install website node modules
|
||||
working-directory: website
|
||||
run: yarn install --frozen-lockfile
|
||||
run: npm ci
|
||||
|
||||
- name: Install most recent version of monaco-editor
|
||||
working-directory: website
|
||||
run: yarn add monaco-editor
|
||||
run: npm install monaco-editor
|
||||
|
||||
- name: Build website
|
||||
working-directory: website
|
||||
run: yarn run build
|
||||
run: npm run build
|
||||
|
||||
- name: Test website
|
||||
working-directory: website
|
||||
run: npm run test
|
||||
|
||||
- name: Setup Pages
|
||||
uses: actions/configure-pages@v5
|
||||
|
|
|
|||
|
|
@ -1,4 +1,2 @@
|
|||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
npm run pretty-quick
|
||||
|
|
|
|||
2
.nvmrc
2
.nvmrc
|
|
@ -1 +1 @@
|
|||
22.18.0
|
||||
22.21.1
|
||||
|
|
|
|||
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
|
@ -12,5 +12,6 @@
|
|||
"typescript.tsdk": "./node_modules/typescript/lib",
|
||||
"git.branchProtection": ["main", "release/*"],
|
||||
"git.branchProtectionPrompt": "alwaysCommitToNewBranch",
|
||||
"git.branchRandomName.enable": true
|
||||
"git.branchRandomName.enable": true,
|
||||
"editor.formatOnSave": true
|
||||
}
|
||||
|
|
|
|||
15
CHANGELOG.md
15
CHANGELOG.md
|
|
@ -1,5 +1,20 @@
|
|||
# Monaco Editor Changelog
|
||||
|
||||
## [0.55.1]
|
||||
|
||||
- Fixes missing language exports (monaco.json/typescript/...) due to wrong "types" path - [#5123](https://github.com/microsoft/monaco-editor/issues/5123)
|
||||
|
||||
## [0.55.0]
|
||||
|
||||
### Breaking Changes
|
||||
- Moves nested namespaces (`languages.css`, `languages.html`, `languages.json`, `languages.typescript`) to top level namespaces (`css`, `html`, `json`, `typescript`) to simplify the build process and align with typescript recommendations.
|
||||
|
||||
### New Features
|
||||
- Adds native LSP support (see new `lsp` namespace).
|
||||
|
||||
### Bug Fixes
|
||||
- Updates dompurify to 3.2.7
|
||||
|
||||
## [0.54.0]
|
||||
|
||||
- Adds option `editor.mouseMiddleClickAction`
|
||||
|
|
|
|||
|
|
@ -28,6 +28,15 @@ You will get:
|
|||
|
||||
:warning: The monaco editor also ships an `AMD` build for backwards-compatibility reasons, but the `AMD` support is deprecated and will be removed in future versions.
|
||||
|
||||
## Localization
|
||||
|
||||
To load the editor in a specific language, make sure that the corresponding nls script file is loaded before the main monaco editor script. For example, to load the editor in German, include the following script tag:
|
||||
```html
|
||||
<script src="path/to/monaco-editor/esm/nls.messages.de.js"></script>
|
||||
```
|
||||
|
||||
Check the sources for available languages.
|
||||
|
||||
## Concepts
|
||||
|
||||
Monaco editor is best known for being the text editor that powers VS Code. However, it's a bit more nuanced. Some basic understanding about the underlying concepts is needed to use Monaco editor effectively.
|
||||
|
|
|
|||
|
|
@ -4,4 +4,5 @@ export async function buildAmdMinDev() {
|
|||
const rootPath = __dirname;
|
||||
await run('npx vite build --mode development', { cwd: rootPath });
|
||||
await run('npx vite build', { cwd: rootPath });
|
||||
await run('npx rollup -c rollup-types.config.mjs', { cwd: rootPath });
|
||||
}
|
||||
|
|
|
|||
44
build/amd/rollup-types.config.mjs
Normal file
44
build/amd/rollup-types.config.mjs
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* 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';
|
||||
import { dtsDeprecationWarning, mapModuleId } from '../shared.mjs';
|
||||
|
||||
export default defineConfig({
|
||||
input: {
|
||||
types: join(import.meta.dirname, './src/types.ts')
|
||||
},
|
||||
output: {
|
||||
dir: join(import.meta.dirname, './out'),
|
||||
format: 'es',
|
||||
preserveModules: false,
|
||||
entryFileNames: function (chunkInfo) {
|
||||
const moduleId = chunkInfo.facadeModuleId;
|
||||
if (moduleId) {
|
||||
const m = mapModuleId(moduleId, '.d.ts');
|
||||
if (m !== undefined) {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
return '[name].d.ts';
|
||||
}
|
||||
},
|
||||
external: [/.*\.css/],
|
||||
plugins: [
|
||||
nodeResolve(),
|
||||
dts({
|
||||
compilerOptions: {
|
||||
stripInternal: true
|
||||
},
|
||||
includeExternal: ['monaco-editor-core', '@vscode/monaco-lsp-client']
|
||||
}),
|
||||
dtsDeprecationWarning(),
|
||||
]
|
||||
});
|
||||
|
|
@ -1,10 +1,30 @@
|
|||
/// @ts-ignore
|
||||
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 = {
|
||||
getWorker: function (_moduleId, label) {
|
||||
if (label === 'json') {
|
||||
return new Worker(
|
||||
getWorkerBootstrapUrl(
|
||||
/// @ts-ignore
|
||||
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') {
|
||||
return new Worker(
|
||||
getWorkerBootstrapUrl(
|
||||
/// @ts-ignore
|
||||
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') {
|
||||
return new Worker(
|
||||
getWorkerBootstrapUrl(
|
||||
/// @ts-ignore
|
||||
new URL('../../../src/language/html/html.worker.ts?worker', import.meta.url)
|
||||
)
|
||||
);
|
||||
|
|
@ -26,17 +48,22 @@ self.MonacoEnvironment = {
|
|||
if (label === 'typescript' || label === 'javascript') {
|
||||
return new Worker(
|
||||
getWorkerBootstrapUrl(
|
||||
/// @ts-ignore
|
||||
new URL('../../../src/language/typescript/ts.worker.ts?worker', import.meta.url)
|
||||
)
|
||||
);
|
||||
}
|
||||
return new Worker(
|
||||
/// @ts-ignore
|
||||
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(
|
||||
[
|
||||
[
|
||||
|
|
@ -54,11 +81,10 @@ function getWorkerBootstrapUrl(workerScriptUrl) {
|
|||
}
|
||||
|
||||
import 'vs/nls.messages-loader!';
|
||||
import '../../../src/basic-languages/monaco.contribution';
|
||||
import '../../../src/language/css/monaco.contribution';
|
||||
import '../../../src/language/html/monaco.contribution';
|
||||
import '../../../src/language/json/monaco.contribution';
|
||||
import '../../../src/language/typescript/monaco.contribution';
|
||||
import * as monaco from '../../../src/editor/editor.main';
|
||||
export * from '../../../src/editor/editor.main';
|
||||
|
||||
globalThis.monaco = monaco;
|
||||
|
||||
const styleSheetUrl = require.toUrl('vs/editor/editor.main.css');
|
||||
|
||||
|
|
@ -66,5 +92,3 @@ const link = document.createElement('link');
|
|||
link.rel = 'stylesheet';
|
||||
link.href = styleSheetUrl;
|
||||
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 };
|
||||
|
|
@ -1,36 +1,26 @@
|
|||
import { readFileSync } from 'node:fs';
|
||||
import { glob } from 'node:fs/promises';
|
||||
import { basename, dirname, join, resolve } from 'node:path';
|
||||
import { dirname, resolve } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { defineConfig } from 'vite';
|
||||
import { urlToEsmPlugin } from './plugin';
|
||||
import { getNlsEntryPoints } from '../shared.mjs';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
export default defineConfig(async (args) => {
|
||||
const monacoEditorCoreDir = join(
|
||||
dirname(require.resolve('monaco-editor-core/package.json')),
|
||||
'esm'
|
||||
);
|
||||
const nlsEntries = {};
|
||||
for await (const path of glob(`${monacoEditorCoreDir}/nls.messages.*.js`)) {
|
||||
const entryName = basename(path).replace('.js', '');
|
||||
nlsEntries[entryName] = path;
|
||||
}
|
||||
|
||||
/** @type {import('vite').UserConfig} */
|
||||
return {
|
||||
base: './',
|
||||
define: {
|
||||
AMD: false
|
||||
resolve: {
|
||||
dedupe: ['monaco-editor-core']
|
||||
},
|
||||
build: {
|
||||
lib: {
|
||||
cssFileName: 'editor/editor.main',
|
||||
entry: {
|
||||
...nlsEntries,
|
||||
...getNlsEntryPoints(),
|
||||
'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(
|
||||
__dirname,
|
||||
'../../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,35 +5,27 @@
|
|||
|
||||
import path = require('path');
|
||||
import fs = require('fs');
|
||||
import {
|
||||
REPO_ROOT,
|
||||
readFiles,
|
||||
writeFiles,
|
||||
IFile,
|
||||
readFile,
|
||||
build,
|
||||
bundledFileHeader
|
||||
} from '../build/utils';
|
||||
import { removeDir } from '../build/fs';
|
||||
import { generateMetadata } from './releaseMetadata';
|
||||
import { REPO_ROOT, readFiles, writeFiles } from '../build/utils';
|
||||
import { generateEsmMetadataJsAndDTs } from './releaseMetadata';
|
||||
import { buildESM } from './esm/build.script';
|
||||
import { buildAmdMinDev } from './amd/build.script';
|
||||
import ts = require('typescript');
|
||||
import { rm } from 'fs/promises';
|
||||
|
||||
removeDir(`out/monaco-editor`);
|
||||
async function run() {
|
||||
await rm(path.join(REPO_ROOT, './out/monaco-editor'), { recursive: true, force: true });
|
||||
|
||||
buildAmdMinDev();
|
||||
await buildESM();
|
||||
await buildAmdMinDev();
|
||||
|
||||
// esm folder
|
||||
ESM_release();
|
||||
// copy types.d.ts from build/amd/out/ to out/monaco-editor/monaco.d.ts (and append `declare global { export import monaco = editor_main; }`)
|
||||
(() => {
|
||||
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
|
||||
releaseDTS();
|
||||
|
||||
// ThirdPartyNotices.txt
|
||||
releaseThirdPartyNotices();
|
||||
|
||||
// esm/metadata.d.ts, esm/metadata.js
|
||||
generateMetadata();
|
||||
createThirdPartyNoticesDotTxt();
|
||||
generateEsmMetadataJsAndDTs();
|
||||
|
||||
// package.json
|
||||
(() => {
|
||||
|
|
@ -61,305 +53,13 @@ generateMetadata();
|
|||
|
||||
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:
|
||||
* - append ThirdPartyNotices.txt from plugins
|
||||
*/
|
||||
function releaseThirdPartyNotices() {
|
||||
function createThirdPartyNoticesDotTxt() {
|
||||
const tpn = readFiles('node_modules/monaco-editor-core/ThirdPartyNotices.txt', {
|
||||
base: 'node_modules/monaco-editor-core'
|
||||
})[0];
|
||||
|
|
@ -377,3 +77,5 @@ function releaseThirdPartyNotices() {
|
|||
|
||||
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"
|
||||
}
|
||||
}
|
||||
47
build/esm/rollup-types.config.mjs
Normal file
47
build/esm/rollup-types.config.mjs
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* 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";
|
||||
import { dtsDeprecationWarning, mapModuleId } from '../shared.mjs';
|
||||
|
||||
const root = join(import.meta.dirname, '../../');
|
||||
|
||||
export default defineConfig({
|
||||
input: {
|
||||
entry: join(root, './src/editor/editor.main.ts'),
|
||||
editorApi: join(root, './src/editor/editor.api.ts'),
|
||||
},
|
||||
output: {
|
||||
dir: join(root, './out/monaco-editor/esm'),
|
||||
format: 'es',
|
||||
preserveModules: false,
|
||||
entryFileNames: function (chunkInfo) {
|
||||
const moduleId = chunkInfo.facadeModuleId;
|
||||
if (moduleId) {
|
||||
const m = mapModuleId(moduleId, '.d.ts');
|
||||
if (m !== undefined) {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
return '[name].d.ts';
|
||||
},
|
||||
},
|
||||
external: [/.*\.css/],
|
||||
plugins: [
|
||||
nodeResolve(),
|
||||
dts({
|
||||
compilerOptions: {
|
||||
stripInternal: true,
|
||||
},
|
||||
includeExternal: ['monaco-editor-core', '@vscode/monaco-lsp-client']
|
||||
}),
|
||||
dtsDeprecationWarning(f => f.endsWith('editor.api.d.ts')),
|
||||
],
|
||||
});
|
||||
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
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
86
build/esm/rollup.config.mjs
Normal file
86
build/esm/rollup.config.mjs
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { getNlsEntryPoints, mapModuleId } from '../shared.mjs';
|
||||
import { readFileSync } from 'fs';
|
||||
|
||||
|
||||
const root = join(import.meta.dirname, '../../');
|
||||
const outDir = join(root, './out/monaco-editor/esm');
|
||||
|
||||
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'),
|
||||
...getNlsEntryPoints(),
|
||||
},
|
||||
|
||||
output: {
|
||||
dir: outDir,
|
||||
format: 'es',
|
||||
|
||||
entryFileNames: function (chunkInfo) {
|
||||
const moduleId = chunkInfo.facadeModuleId;
|
||||
if (moduleId) {
|
||||
const r = mapModuleId(moduleId, '.js');
|
||||
if (r !== undefined) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
return '[name].js';
|
||||
},
|
||||
preserveModules: true,
|
||||
},
|
||||
|
||||
|
||||
plugins: [
|
||||
del({ targets: outDir, force: true }),
|
||||
|
||||
{
|
||||
name: 'copy-codicon-font',
|
||||
generateBundle() {
|
||||
this.emitFile({
|
||||
type: 'asset',
|
||||
fileName: 'vs/base/browser/ui/codicons/codicon/codicon.ttf',
|
||||
source: readFileSync(join(root, 'node_modules/monaco-editor-core/esm/vs/base/browser/ui/codicons/codicon/codicon.ttf'))
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
urlToEsmPlugin(),
|
||||
esbuild(),
|
||||
|
||||
keepCssImports({
|
||||
/**
|
||||
* @param {string} assetId
|
||||
*/
|
||||
outputPath: (assetId) => {
|
||||
const r = mapModuleId(assetId, '.css');
|
||||
if (r !== undefined) {
|
||||
return join(outDir, r);
|
||||
}
|
||||
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;
|
||||
}
|
||||
13
build/fs.ts
13
build/fs.ts
|
|
@ -29,19 +29,6 @@ export function ensureDir(dirname: string) {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy a file.
|
||||
*/
|
||||
export function copyFile(_source: string, _destination: string) {
|
||||
const source = path.join(REPO_ROOT, _source);
|
||||
const destination = path.join(REPO_ROOT, _destination);
|
||||
|
||||
ensureDir(path.dirname(destination));
|
||||
fs.writeFileSync(destination, fs.readFileSync(source));
|
||||
|
||||
console.log(`Copied ${_source} to ${_destination}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a directory and all its contents.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ function getAdvancedLanguages(): Promise<
|
|||
}
|
||||
}
|
||||
|
||||
export function generateMetadata() {
|
||||
export function generateEsmMetadataJsAndDTs() {
|
||||
return Promise.all([getBasicLanguages(), getAdvancedLanguages()]).then(
|
||||
([basicLanguages, advancedLanguages]) => {
|
||||
basicLanguages.sort((a, b) => strcmp(a.entry, b.entry));
|
||||
|
|
|
|||
96
build/shared.mjs
Normal file
96
build/shared.mjs
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { dirname, join } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { readdirSync } from 'fs';
|
||||
|
||||
/**
|
||||
* @param {string} filePath
|
||||
* @param {string} newExt
|
||||
*/
|
||||
export function changeExt(filePath, newExt) {
|
||||
const idx = filePath.lastIndexOf('.');
|
||||
if (idx === -1) {
|
||||
return filePath + newExt;
|
||||
} else {
|
||||
return filePath.substring(0, idx) + newExt;
|
||||
}
|
||||
}
|
||||
|
||||
export function getNlsEntryPoints() {
|
||||
const nlsDir = dirname(fileURLToPath(import.meta.resolve('monaco-editor-core/esm/nls.messages.en.js')));
|
||||
const nlsFiles = readdirSync(nlsDir)
|
||||
.filter(file => file.startsWith('nls.messages.') && file.endsWith('.js'))
|
||||
.reduce((acc, file) => {
|
||||
// @ts-ignore
|
||||
acc[file] = join(nlsDir, file);
|
||||
return acc;
|
||||
}, {});
|
||||
return nlsFiles;
|
||||
}
|
||||
|
||||
const root = join(import.meta.dirname, '../');
|
||||
|
||||
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/',
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} moduleId
|
||||
* @param {string} newExt (with leading .)
|
||||
* @returns {string | undefined}
|
||||
*/
|
||||
export function mapModuleId(moduleId, newExt) {
|
||||
for (const [key, val] of Object.entries(mappedPaths)) {
|
||||
if (moduleId.startsWith(key)) {
|
||||
const relativePath = moduleId.substring(key.length);
|
||||
return changeExt(join(val, relativePath), newExt);
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {(moduleId: string) => boolean} [filter]
|
||||
* @return {import('rollup').Plugin}
|
||||
*/
|
||||
export function dtsDeprecationWarning(filter) {
|
||||
return {
|
||||
name: 'add-dts-deprecation-warning',
|
||||
generateBundle(options, bundle) {
|
||||
for (const fileName in bundle) {
|
||||
if (filter && !filter(fileName)) {
|
||||
continue;
|
||||
}
|
||||
const file = bundle[fileName];
|
||||
if (file.type === 'chunk' && fileName.endsWith('.d.ts')) {
|
||||
let content = file.code.toString();
|
||||
content = content + `
|
||||
declare namespace languages {
|
||||
/** @deprecated Use the new top level "css" namespace instead. */
|
||||
export const css: { deprecated: true };
|
||||
|
||||
/** @deprecated Use the new top level "html" namespace instead. */
|
||||
export const html: { deprecated: true };
|
||||
|
||||
/** @deprecated Use the new top level "json" namespace instead. */
|
||||
export const json: { deprecated: true };
|
||||
|
||||
/** @deprecated Use the new top level "typescript" namespace instead. */
|
||||
export const typescript: { deprecated: true };
|
||||
}
|
||||
`;
|
||||
file.code = content;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
179
build/utils.ts
179
build/utils.ts
|
|
@ -5,190 +5,11 @@
|
|||
|
||||
import * as fs from 'fs';
|
||||
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 { ensureDir } from './fs';
|
||||
|
||||
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 {
|
||||
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();
|
||||
}
|
||||
1607
monaco-lsp-client/package-lock.json
generated
Normal file
1607
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;
|
||||
}
|
||||
}
|
||||
3826
package-lock.json
generated
3826
package-lock.json
generated
File diff suppressed because it is too large
Load diff
49
package.json
49
package.json
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "monaco-editor",
|
||||
"version": "0.54.0",
|
||||
"vscodeRef": "484fdf69b8509c1c9370d913b32e9f6d3a68cc99",
|
||||
"version": "0.55.1",
|
||||
"vscodeRef": "86f5a62f058e3905f74a9fa65d04b2f3b533408e",
|
||||
"private": true,
|
||||
"description": "A browser based code editor",
|
||||
"homepage": "https://github.com/microsoft/monaco-editor",
|
||||
|
|
@ -14,33 +14,49 @@
|
|||
"prettier": "prettier --write .",
|
||||
"pretty-quick": "pretty-quick --staged",
|
||||
"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-cross-origin": "ts-node ./test/smoke/package-webpack --cross-origin",
|
||||
"package-for-smoketest-esbuild": "ts-node ./test/smoke/package-esbuild",
|
||||
"package-for-smoketest-vite": "ts-node ./test/smoke/package-vite",
|
||||
"smoketest": "node ./test/smoke/runner.js",
|
||||
"smoketest-debug": "node ./test/smoke/runner.js --debug-tests",
|
||||
"smoketest": "playwright test --config=test/smoke/playwright.config.ts",
|
||||
"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",
|
||||
"deps-all-remove": "ts-node ./build/npm/removeAll",
|
||||
"deps-all-install": "ts-node ./build/npm/installAll",
|
||||
"update-actions": "pin-github-action ./.github/workflows/website.yml",
|
||||
"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": "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.main.d.ts",
|
||||
"main": "./min/vs/editor/editor.main.js",
|
||||
"module": "./esm/vs/editor/editor.main.js",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./esm/vs/editor/editor.main.d.ts",
|
||||
"import": "./esm/vs/editor/editor.main.js",
|
||||
"require": "./min/vs/editor/editor.main.js"
|
||||
},
|
||||
"./*": "./*"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/microsoft/monaco-editor"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.53.2",
|
||||
"@types/mocha": "^9.1.0",
|
||||
"@playwright/test": "^1.56.1",
|
||||
"@rollup/plugin-alias": "^5.1.1",
|
||||
"@rollup/plugin-node-resolve": "^16.0.2",
|
||||
"@types/mocha": "^10.0.10",
|
||||
"@types/shelljs": "^0.8.11",
|
||||
"@types/trusted-types": "^1.0.6",
|
||||
"@typescript/vfs": "^1.3.5",
|
||||
"@vscode/monaco-lsp-client": "file:./monaco-lsp-client",
|
||||
"chai": "^4.3.6",
|
||||
"clean-css": "^5.2.4",
|
||||
"css-loader": "^6.7.1",
|
||||
|
|
@ -52,19 +68,26 @@
|
|||
"husky": "^7.0.4",
|
||||
"jsdom": "^19.0.0",
|
||||
"jsonc-parser": "^3.0.0",
|
||||
"mocha": "^9.2.0",
|
||||
"monaco-editor-core": "^0.54.0-dev-20251002",
|
||||
"mocha": "^11.7.4",
|
||||
"monaco-editor-core": "^0.55.0-rc",
|
||||
"parcel": "^2.7.0",
|
||||
"pin-github-action": "^1.8.0",
|
||||
"postcss-url": "^10.1.3",
|
||||
"prettier": "^2.5.1",
|
||||
"pretty-quick": "^3.1.3",
|
||||
"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",
|
||||
"style-loader": "^3.3.1",
|
||||
"terser": "^5.14.2",
|
||||
"ts-node": "^10.6.0",
|
||||
"typescript": "^5.4.5",
|
||||
"vite": "^7.1.5",
|
||||
"typescript": "^5.9.3",
|
||||
"vite": "^7.1.11",
|
||||
"vscode-css-languageservice": "6.2.14",
|
||||
"vscode-html-languageservice": "5.2.0",
|
||||
"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",
|
||||
"@vitejs/plugin-react": "^1.1.4",
|
||||
"typescript": "^5.4.5",
|
||||
"vite": "^2.9.17"
|
||||
"vite": "^5.4.21"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2
samples/browser-esm-vite/.gitignore
vendored
Normal file
2
samples/browser-esm-vite/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
dist
|
||||
src/**/*.js
|
||||
12
samples/browser-esm-vite/index.html
Normal file
12
samples/browser-esm-vite/index.html
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>browser-esm-vite</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
13
samples/browser-esm-vite/main.ts
Normal file
13
samples/browser-esm-vite/main.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import './style.css';
|
||||
import * as monaco from '../../src/editor/editor.main';
|
||||
|
||||
monaco.languages.register({ id: 'typescript' });
|
||||
|
||||
const tm = monaco.editor.createModel(`class Test {}`, 'typescript',
|
||||
monaco.Uri.parse('file:///main.ts'));
|
||||
|
||||
const editor = monaco.editor.create(document.getElementById('root')!, {
|
||||
model: tm,
|
||||
language: 'typescript',
|
||||
theme: 'vs-dark',
|
||||
});
|
||||
1663
samples/browser-esm-vite/package-lock.json
generated
Normal file
1663
samples/browser-esm-vite/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
14
samples/browser-esm-vite/package.json
Normal file
14
samples/browser-esm-vite/package.json
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"name": "browser-esm-vite",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"serve": "vite preview"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"monaco-editor": "^0.54.0",
|
||||
"typescript": "^5.9.3",
|
||||
"vite": "^7.1.11"
|
||||
}
|
||||
}
|
||||
8
samples/browser-esm-vite/style.css
Normal file
8
samples/browser-esm-vite/style.css
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
html,
|
||||
body,
|
||||
#root {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
11
samples/browser-esm-vite/tsconfig.json
Normal file
11
samples/browser-esm-vite/tsconfig.json
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"strict": true,
|
||||
"module": "ESNext",
|
||||
"jsx": "react-jsx",
|
||||
"moduleResolution": "node",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["./"]
|
||||
}
|
||||
19
samples/browser-esm-vite/vite.config.ts
Normal file
19
samples/browser-esm-vite/vite.config.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import { defineConfig } from 'vite';
|
||||
import { join } from 'path';
|
||||
|
||||
export default defineConfig({
|
||||
server: {
|
||||
fs: {
|
||||
allow: ['../../', '../../../vscode']
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
alias: [{
|
||||
find: 'monaco-editor-core/esm/vs',
|
||||
replacement: join(__dirname, '../../../vscode/src/vs')
|
||||
}, {
|
||||
find: 'monaco-editor-core',
|
||||
replacement: join(__dirname, '../../../vscode/src/vs/editor/editor.main.ts')
|
||||
}],
|
||||
}
|
||||
});
|
||||
70
samples/package-lock.json
generated
70
samples/package-lock.json
generated
|
|
@ -721,6 +721,7 @@
|
|||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
|
|
@ -747,6 +748,7 @@
|
|||
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"fast-uri": "^3.0.1",
|
||||
|
|
@ -962,6 +964,7 @@
|
|||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"caniuse-lite": "^1.0.30001737",
|
||||
"electron-to-chromium": "^1.5.211",
|
||||
|
|
@ -1259,35 +1262,34 @@
|
|||
}
|
||||
},
|
||||
"node_modules/compression": {
|
||||
"version": "1.7.4",
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz",
|
||||
"integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"accepts": "~1.3.5",
|
||||
"bytes": "3.0.0",
|
||||
"compressible": "~2.0.16",
|
||||
"bytes": "3.1.2",
|
||||
"compressible": "~2.0.18",
|
||||
"debug": "2.6.9",
|
||||
"on-headers": "~1.0.2",
|
||||
"safe-buffer": "5.1.2",
|
||||
"negotiator": "~0.6.4",
|
||||
"on-headers": "~1.1.0",
|
||||
"safe-buffer": "5.2.1",
|
||||
"vary": "~1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/compression/node_modules/bytes": {
|
||||
"version": "3.0.0",
|
||||
"node_modules/compression/node_modules/negotiator": {
|
||||
"version": "0.6.4",
|
||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz",
|
||||
"integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/compression/node_modules/safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/concat-map": {
|
||||
"version": "0.0.1",
|
||||
"dev": true,
|
||||
|
|
@ -2184,6 +2186,21 @@
|
|||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
|
|
@ -3160,11 +3177,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/monaco-editor": {
|
||||
"version": "0.53.0-dev-20250905",
|
||||
"resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.53.0-dev-20250905.tgz",
|
||||
"integrity": "sha512-dz8KD6kfIkQ9vQgUlUPBf24zFiDo/tPbI6HmDoBToURc3vXSlmxnR3NccA5NAaG/k3SrYZ+m4Pd+sjGtc7SV8w==",
|
||||
"version": "0.53.0",
|
||||
"resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.53.0.tgz",
|
||||
"integrity": "sha512-0WNThgC6CMWNXXBxTbaYYcunj08iB5rnx4/G56UOPeL9UVIUGGHA1GR0EWIh9Ebabj7NpCRawQ5b0hfN1jQmYQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/trusted-types": "^1.0.6"
|
||||
}
|
||||
|
|
@ -3241,9 +3259,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/node-forge": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
|
||||
"integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==",
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.3.tgz",
|
||||
"integrity": "sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg==",
|
||||
"dev": true,
|
||||
"license": "(BSD-3-Clause OR GPL-2.0)",
|
||||
"engines": {
|
||||
|
|
@ -3343,7 +3361,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/on-headers": {
|
||||
"version": "1.0.2",
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz",
|
||||
"integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
|
|
@ -3561,6 +3581,7 @@
|
|||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.6",
|
||||
"picocolors": "^1.0.0",
|
||||
|
|
@ -3992,6 +4013,7 @@
|
|||
"version": "6.12.6",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
|
|
@ -4723,7 +4745,8 @@
|
|||
"node_modules/tslib": {
|
||||
"version": "2.4.0",
|
||||
"dev": true,
|
||||
"license": "0BSD"
|
||||
"license": "0BSD",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/tunnel": {
|
||||
"version": "0.0.6",
|
||||
|
|
@ -4765,6 +4788,7 @@
|
|||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
|
||||
"integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
|
|
@ -4894,6 +4918,7 @@
|
|||
"integrity": "sha512-7b0dTKR3Ed//AD/6kkx/o7duS8H3f1a4w3BYpIriX4BzIhjkn4teo05cptsxvLesHFKK5KObnadmCHBwGc+51A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/eslint-scope": "^3.7.7",
|
||||
"@types/estree": "^1.0.8",
|
||||
|
|
@ -4941,6 +4966,7 @@
|
|||
"version": "4.10.0",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@discoveryjs/json-ext": "^0.5.0",
|
||||
"@webpack-cli/configtest": "^1.2.0",
|
||||
|
|
|
|||
|
|
@ -81,7 +81,6 @@ async function buildAndTest() {
|
|||
// Run checks and compilation
|
||||
await run('npm run gulp hygiene', { cwd: vscodePath });
|
||||
await run('npm run valid-layers-check', { cwd: vscodePath });
|
||||
await run('npm run compile', { cwd: join(vscodePath, 'build') });
|
||||
await run('npm run eslint', { cwd: vscodePath });
|
||||
await run('npm run monaco-compile-check', { cwd: vscodePath });
|
||||
await run('npm run --max_old_space_size=4095 compile', { cwd: vscodePath });
|
||||
|
|
@ -89,10 +88,8 @@ async function buildAndTest() {
|
|||
// Build editor distribution
|
||||
await run('npm run gulp editor-distro', { cwd: vscodePath });
|
||||
|
||||
return; // To save CI time.
|
||||
|
||||
// Run browser tests
|
||||
await run('npm run test-browser --browser chromium', { cwd: vscodePath });
|
||||
await run('npm run test-browser -- --browser chromium', { cwd: vscodePath });
|
||||
|
||||
// TypeScript typings test
|
||||
await run('mkdir typings-test', { cwd: vscodePath });
|
||||
|
|
@ -110,6 +107,4 @@ async function buildAndTest() {
|
|||
await run('npm test', { cwd: testMonacoDir });
|
||||
}
|
||||
|
||||
//buildAndTest();
|
||||
//prepareMonacoEditorCoreRelease('0.99.0', 'main');
|
||||
prepareMonacoEditorCoreReleaseStableOrNightly();
|
||||
|
|
|
|||
|
|
@ -43,36 +43,32 @@ async function prepareMonacoEditorRelease(monacoEditorCoreVersion: string) {
|
|||
});
|
||||
|
||||
await group('Set Version & Update monaco-editor-core Version', async () => {
|
||||
const packageJson = JSON.parse(
|
||||
await readFile(monacoEditorPackageJsonPath, { encoding: 'utf-8' })
|
||||
) as PackageJson;
|
||||
|
||||
const packageJson = JSON.parse(await readFile(monacoEditorPackageJsonPath, { encoding: 'utf-8' })) as PackageJson;
|
||||
packageJson.version = monacoEditorCoreVersion;
|
||||
packageJson.devDependencies['monaco-editor-core'] = monacoEditorCoreVersion;
|
||||
await writeJsonFile(monacoEditorPackageJsonPath, packageJson);
|
||||
});
|
||||
|
||||
const monacoEditorCorePackageJson = JSON.parse(
|
||||
await readFile(monacoEditorCorePackageJsonPath, { encoding: 'utf-8' })
|
||||
) as PackageJson;
|
||||
await group('npm install to pick up monaco-editor-core', async () => {
|
||||
await run('npm install', { cwd: rootPath });
|
||||
});
|
||||
|
||||
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 (!packageJson.dependencies) {
|
||||
packageJson.dependencies = {};
|
||||
}
|
||||
|
||||
objectMergeThrowIfSet(
|
||||
packageJson.dependencies,
|
||||
monacoEditorCorePackageJson.dependencies,
|
||||
'dependencies'
|
||||
);
|
||||
}
|
||||
|
||||
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 () => {
|
||||
const monacoEditorCorePackageJson = JSON.parse(
|
||||
await readFile(monacoEditorCorePackageJsonPath, { encoding: 'utf-8' })
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ export async function gitShallowClone(
|
|||
await run(`git fetch --depth 1 origin ${ref}`, options);
|
||||
await run(`git checkout ${ref}`, options);
|
||||
const commitId = await gitCommitId(targetPath);
|
||||
console.log(`Cloned ${repositoryUrl} (${commitId}) to ${targetPath}`);
|
||||
return { commitId };
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* 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 {
|
||||
loader: () => Promise<ILangImpl>;
|
||||
|
|
|
|||
|
|
@ -5,20 +5,9 @@
|
|||
|
||||
import { registerLanguage } from '../_.contribution';
|
||||
|
||||
declare var AMD: any;
|
||||
declare var require: any;
|
||||
|
||||
registerLanguage({
|
||||
id: 'abap',
|
||||
extensions: ['.abap'],
|
||||
aliases: ['abap', 'ABAP'],
|
||||
loader: () => {
|
||||
if (AMD) {
|
||||
return new Promise((resolve, reject) => {
|
||||
require(['vs/basic-languages/abap/abap'], resolve, reject);
|
||||
});
|
||||
} else {
|
||||
return import('./abap');
|
||||
}
|
||||
}
|
||||
loader: () => 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 = {
|
||||
comments: {
|
||||
|
|
|
|||
|
|
@ -5,21 +5,10 @@
|
|||
|
||||
import { registerLanguage } from '../_.contribution';
|
||||
|
||||
declare var AMD: any;
|
||||
declare var require: any;
|
||||
|
||||
registerLanguage({
|
||||
id: 'apex',
|
||||
extensions: ['.cls'],
|
||||
aliases: ['Apex', 'apex'],
|
||||
mimetypes: ['text/x-apex-source', 'text/x-apex'],
|
||||
loader: () => {
|
||||
if (AMD) {
|
||||
return new Promise((resolve, reject) => {
|
||||
require(['vs/basic-languages/apex/apex'], resolve, reject);
|
||||
});
|
||||
} else {
|
||||
return import('./apex');
|
||||
}
|
||||
}
|
||||
loader: () => import('./apex')
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* 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 = {
|
||||
// the default separators except `@$`
|
||||
|
|
|
|||
|
|
@ -5,20 +5,9 @@
|
|||
|
||||
import { registerLanguage } from '../_.contribution';
|
||||
|
||||
declare var AMD: any;
|
||||
declare var require: any;
|
||||
|
||||
registerLanguage({
|
||||
id: 'azcli',
|
||||
extensions: ['.azcli'],
|
||||
aliases: ['Azure CLI', 'azcli'],
|
||||
loader: () => {
|
||||
if (AMD) {
|
||||
return new Promise((resolve, reject) => {
|
||||
require(['vs/basic-languages/azcli/azcli'], resolve, reject);
|
||||
});
|
||||
} else {
|
||||
return import('./azcli');
|
||||
}
|
||||
}
|
||||
loader: () => import('./azcli')
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* 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 = {
|
||||
comments: {
|
||||
|
|
|
|||
|
|
@ -5,20 +5,9 @@
|
|||
|
||||
import { registerLanguage } from '../_.contribution';
|
||||
|
||||
declare var AMD: any;
|
||||
declare var require: any;
|
||||
|
||||
registerLanguage({
|
||||
id: 'bat',
|
||||
extensions: ['.bat', '.cmd'],
|
||||
aliases: ['Batch', 'bat'],
|
||||
loader: () => {
|
||||
if (AMD) {
|
||||
return new Promise((resolve, reject) => {
|
||||
require(['vs/basic-languages/bat/bat'], resolve, reject);
|
||||
});
|
||||
} else {
|
||||
return import('./bat');
|
||||
}
|
||||
}
|
||||
loader: () => import('./bat')
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* 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 = {
|
||||
comments: {
|
||||
|
|
|
|||
|
|
@ -5,20 +5,9 @@
|
|||
|
||||
import { registerLanguage } from '../_.contribution';
|
||||
|
||||
declare var AMD: any;
|
||||
declare var require: any;
|
||||
|
||||
registerLanguage({
|
||||
id: 'bicep',
|
||||
extensions: ['.bicep'],
|
||||
aliases: ['Bicep'],
|
||||
loader: () => {
|
||||
if (AMD) {
|
||||
return new Promise((resolve, reject) => {
|
||||
require(['vs/basic-languages/bicep/bicep'], resolve, reject);
|
||||
});
|
||||
} else {
|
||||
return import('./bicep');
|
||||
}
|
||||
}
|
||||
loader: () => import('./bicep')
|
||||
});
|
||||
|
|
|
|||
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