Compare commits

..

No commits in common. "main" and "v0.14.3" have entirely different histories.

1051 changed files with 252973 additions and 448672 deletions

View file

@ -1,106 +0,0 @@
###############################################################################################
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
###############################################################################################
name: $(Date:yyyyMMdd)$(Rev:.r)
trigger: none
pr: none
schedules:
- cron: '0 7 * * *'
displayName: Daily release
branches:
include:
- main
always: true
resources:
repositories:
- repository: templates
type: github
name: microsoft/vscode-engineering
ref: main
endpoint: Monaco
parameters:
- name: publishMonacoEditorCore
displayName: 🚀 Publish Monaco Editor Core
type: boolean
default: true
- name: publishMonacoEditor
displayName: 🚀 Publish Monaco Editor
type: boolean
default: true
- name: vscodeRef
displayName: The VS Code commit id.
type: string
default: 'main'
- name: prereleaseVersion
displayName: The prerelease version.
type: string
default: 'dev-${today}'
extends:
template: azure-pipelines/npm-package/pipeline.yml@templates
parameters:
cgIgnoreDirectories: $(Build.SourcesDirectory)/dependencies/vscode
npmPackages:
- name: monaco-editor-core
workingDirectory: $(Build.SourcesDirectory)/dependencies/vscode/out-monaco-editor-core
testPlatforms: []
skipAPIScan: true # package build requires Linux
buildSteps:
- task: NodeTool@0
inputs:
versionSource: fromFile
versionFilePath: .nvmrc
- script: sudo apt install -y libkrb5-dev
displayName: Install libkrb5-dev
- 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 }}
PRERELEASE_VERSION: ${{ parameters.prereleaseVersion }}
retryCountOnTaskFailure: 5
displayName: Setup, Build & Test monaco-editor-core
tag: next
ghCreateTag: false
publishPackage: ${{ parameters.publishMonacoEditorCore }}
publishRequiresApproval: false
- name: monaco-editor
dependsOn: monaco-editor-core
workingDirectory: $(Build.SourcesDirectory)/out/monaco-editor
testPlatforms: []
skipAPIScan: true # package build requires Linux
buildSteps:
- task: NodeTool@0
inputs:
versionSource: fromFile
versionFilePath: .nvmrc
- 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-pkg nightly
env:
VSCODE_REF: ${{ parameters.vscodeRef }}
PRERELEASE_VERSION: ${{ parameters.prereleaseVersion }}
retryCountOnTaskFailure: 5
displayName: Setup, Build & Test monaco-editor
tag: next
publishPackage: ${{ parameters.publishMonacoEditor }}
publishRequiresApproval: false

View file

@ -1,105 +0,0 @@
###############################################################################################
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
###############################################################################################
name: $(Date:yyyyMMdd)$(Rev:.r)
trigger: none
pr: none
resources:
repositories:
- repository: templates
type: github
name: microsoft/vscode-engineering
ref: main
endpoint: Monaco
parameters:
- name: publishMonacoEditorCore
displayName: 🚀 Publish Monaco Editor Core
type: boolean
default: false
- name: publishMonacoEditor
displayName: 🚀 Publish Monaco Editor
type: boolean
default: false
- name: publishWebpackPlugin
displayName: 🚀 Publish Webpack Plugin
type: boolean
default: false
extends:
template: azure-pipelines/npm-package/pipeline.yml@templates
parameters:
cgIgnoreDirectories: $(Build.SourcesDirectory)/dependencies/vscode
npmPackages:
- name: monaco-editor-core
workingDirectory: $(Build.SourcesDirectory)/dependencies/vscode/out-monaco-editor-core
testPlatforms: []
skipAPIScan: true # package build requires Linux
buildSteps:
- task: NodeTool@0
inputs:
versionSource: fromFile
versionFilePath: .nvmrc
- script: sudo apt install -y libkrb5-dev
displayName: Install libkrb5-dev
- 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
tag: latest
ghCreateTag: false
publishPackage: ${{ parameters.publishMonacoEditorCore }}
publishRequiresApproval: false
- name: monaco-editor
dependsOn: monaco-editor-core
workingDirectory: $(Build.SourcesDirectory)/out/monaco-editor
testPlatforms: []
skipAPIScan: true # package build requires Linux
buildSteps:
- task: NodeTool@0
inputs:
versionSource: fromFile
versionFilePath: .nvmrc
- 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-pkg stable
displayName: Setup, Build & Test monaco-editor
tag: latest
publishPackage: ${{ parameters.publishMonacoEditor }}
publishRequiresApproval: false
- name: monaco-editor-webpack-plugin
dependsOn: monaco-editor
workingDirectory: $(Build.SourcesDirectory)/webpack-plugin
testPlatforms: []
packagePlatform: Windows
buildSteps:
- script: npm ci
displayName: Install NPM dependencies
workingDirectory: $(Build.SourcesDirectory)/webpack-plugin
- script: npm run compile
displayName: Build plugin
workingDirectory: $(Build.SourcesDirectory)/webpack-plugin
tag: latest
ghCreateTag: false
publishPackage: ${{ parameters.publishWebpackPlugin }}
publishRequiresApproval: false

View file

@ -1,8 +0,0 @@
{
"image": "mcr.microsoft.com/devcontainers/typescript-node",
"customizations": {
"vscode": {
"extensions": ["ms-vscode.js-debug-nightly"]
}
}
}

1
.gitattributes vendored
View file

@ -1 +0,0 @@
* text=auto

View file

@ -1,57 +0,0 @@
name: Bug Report
description: File a bug report
title: '[Bug] '
body:
- type: markdown
attributes:
value: |
To help us processing your bug report, please fill out this form.
- type: checkboxes
id: reproducible-in-vscode
attributes:
label: Reproducible in vscode.dev or in VS Code Desktop?
description: Can you reproduce the bug in [vscode.dev](https://vscode.dev) or in VS Code Desktop? If so, please create [an issue in the VS Code repository](https://github.com/microsoft/vscode/issues). **VS Code issues are usually looked at within a couple of days.**
options:
- label: Not reproducible in [vscode.dev](https://vscode.dev) or VS Code Desktop
required: true
- type: checkboxes
id: reproducible-in-monaco-playground
attributes:
label: Reproducible in the monaco editor playground?
description: Can you reproduce the bug in [the monaco editor playground](https://microsoft.github.io/monaco-editor/playground.html)? A minimal reproducible example will make it significantly easier for us to get this bug fixed.
options:
- label: Not reproducible in [the monaco editor playground](https://microsoft.github.io/monaco-editor/playground.html)
- type: textarea
id: playgroundLink
attributes:
label: Monaco Editor Playground Link
description: Please share the link to the [monaco editor playground](https://microsoft.github.io/monaco-editor/playground.html) after you entered your example. In case of regressions, please also provide the first broken version.
- type: textarea
id: playgroundSourceCode
attributes:
label: Monaco Editor Playground Code
description: Please provide the code from the monaco editor playground example.
render: typescript
- type: textarea
id: steps
attributes:
label: Reproduction Steps
description: Please describe the steps (in the playground) that lead to the problematic behavior
- type: textarea
id: actual-behavior
attributes:
label: Actual (Problematic) Behavior
description: Please describe the actual (problematic) behavior, as observed in the playground.
- type: textarea
id: expected-behavior
attributes:
label: Expected Behavior
description: Please describe the expected behavior.
- type: textarea
id: additional-context
attributes:
label: Additional Context
description: Please provide additional context.

View file

@ -1,38 +0,0 @@
name: Feature Request
description: Suggest an idea for this project
title: '[Feature Request] '
labels:
- 'feature-request'
body:
- type: markdown
attributes:
value: |
To help us efficiently reviewing your feature request, please fill out this form.
- type: checkboxes
id: not
attributes:
label: Context
options:
- label: This issue is not a bug report. *(please use a different template for reporting a bug)*
required: true
- label: This issue is not a duplicate of an existing issue. *(please use the [search](https://github.com/microsoft/monaco-editor/issues) to find existing issues)*
required: true
- type: textarea
id: description
attributes:
label: Description
description: Please describe your feature request.
- type: textarea
id: relevantCodePlaygroundLink
attributes:
label: Monaco Editor Playground Link
description: If applicable, please share the link to a relevant [monaco editor playground sample](https://microsoft.github.io/monaco-editor/playground.html)
- type: textarea
id: releveantCode
attributes:
label: Monaco Editor Playground Code
description: If applicable, please share the code from the monaco editor playground sample.
render: typescript

View file

@ -1,4 +0,0 @@
---
name: Other Request (For Maintainers Only)
about: This issue template should only be used by maintainers.
---

View file

@ -1,5 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: Question
url: https://stackoverflow.com/questions/tagged/monaco-editor
about: Please ask and answer questions here.

150
.github/commands.json vendored
View file

@ -1,150 +0,0 @@
[
{
"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!"
}
]

View file

@ -1,7 +0,0 @@
---
title: NPM Publishing Failed
assignees: []
labels: bug
---
NPM publishing failed. Check the last GitHub Action log.

View file

@ -1,100 +0,0 @@
name: CI
on: [push, pull_request]
jobs:
build:
name: CI
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
- name: Cache node modules
id: cacheNodeModules
uses: actions/cache@v4
with:
path: '**/node_modules'
key: ${{ runner.os }}-cacheNodeModules2-${{ hashFiles('**/package-lock.json', '**/package.json') }}
restore-keys: ${{ runner.os }}-cacheNodeModules2-
- name: Install build tools
if: steps.cache-node-modules.outputs.cache-hit != 'true'
run: |
sudo apt update -y
sudo apt install -y build-essential pkg-config libx11-dev libx11-xcb-dev libxkbfile-dev libnotify-bin libkrb5-dev
- name: execute `npm ci` (1)
if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }}
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
ELECTRON_SKIP_BINARY_DOWNLOAD: 1
run: |
npm ci
- name: Download Playwright
run: npx playwright install --with-deps
- name: execute `npm ci` (2)
if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }}
run: npm ci --prefix webpack-plugin
# CI steps temporarily disabled (enable by end of august 2025)
# # <building-from-source>
# - name: Setup, Build & Test monaco-editor-core
# run: yarn ts-node ./scripts/ci/build-monaco-editor-core-pkg nightly
# env:
# VSCODE_REF: 'main'
# PRERELEASE_VERSION: 'dev-${today}'
# - name: Link monaco-editor-core
# run: npm link
# working-directory: ./dependencies/vscode/out-monaco-editor-core
# - name: Link monaco-editor-core
# run: npm link monaco-editor-core
# # </building-from-source>
# TODO: prettier formatting
# - name: Check prettier
# run: npm run prettier-check
- name: Build
run: npm run build
- name: Run unit tests
run: npm test
- name: Compile webpack plugin
run: npm run compile --prefix webpack-plugin
- name: Package using webpack plugin
run: npm run package-for-smoketest
# - name: Package using parcel
# run: npm run package-for-smoketest-parcel --prefix test/smoke/parcel
# Disabled for now, as the parcel bundler cannot deal with VS Code process variable
- name: Run smoke test
run: npm run smoketest
- name: Install website node modules
working-directory: website
run: npm ci
- name: Install most recent version of monaco-editor
working-directory: website
run: npm install monaco-editor
- name: Build website
working-directory: website
run: npm run build
- name: Test website
working-directory: website
run: npm run test

View file

@ -1,72 +0,0 @@
name: Publish Website
on:
schedule:
- cron: 0 23 * * *
workflow_dispatch: {}
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
concurrency:
group: 'pages'
cancel-in-progress: false
jobs:
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
- name: Cache node modules
id: cacheNodeModules
uses: actions/cache@v4
with:
path: '**/node_modules'
key: ${{ runner.os }}-cacheNodeModules2-${{ hashFiles('**/package-lock.json') }}
restore-keys: ${{ runner.os }}-cacheNodeModules2-
- name: execute `npm ci` (1)
if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }}
run: npm ci
# For TypeDoc
- name: Build
run: npm run build
- name: Install website node modules
working-directory: website
run: npm ci
- name: Install most recent version of monaco-editor
working-directory: website
run: npm install monaco-editor
- name: Build website
working-directory: website
run: npm run build
- name: Test website
working-directory: website
run: npm run test
- name: Setup Pages
uses: actions/configure-pages@v5
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
# Upload entire repository
path: './website/dist'
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4

10
.gitignore vendored
View file

@ -1,8 +1,2 @@
**/node_modules/ /node_modules/
**/dependencies/ /release/
/test/manual/generated/**
/test/smoke/vite/dist/**
/test/smoke/parcel/dist/**
/test/smoke/parcel/.cache/**
**/dist/
**/out/

View file

@ -1,2 +0,0 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

View file

@ -1,4 +0,0 @@
{
"delay": true,
"ui": "tdd"
}

1
.nvmrc
View file

@ -1 +0,0 @@
22.21.1

View file

@ -1,17 +0,0 @@
**/node_modules/
**/dist/
**/out/
/samples/browser-esm-parcel/.parcel-cache/
/samples/browser-esm-parcel/dist/
/samples/browser-esm-vite-react/dist/**/*.js
/samples/browser-esm-webpack/dist/*.js
/samples/browser-esm-webpack-monaco-plugin/dist/*.js
/samples/browser-esm-webpack-small/dist/*.js
/samples/browser-esm-webpack-typescript/dist/*.js
/samples/browser-esm-webpack-typescript-react/dist/*.js
/src/language/typescript/lib/
/test/manual/generated/
/website/lib/
/website/typedoc/monaco.d.ts
/test/smoke/vite/dist
/test/smoke/parcel/dist

View file

@ -1,8 +0,0 @@
{
"arrowParens": "always",
"singleQuote": true,
"trailingComma": "none",
"semi": true,
"useTabs": true,
"printWidth": 100
}

68
.vscode/launch.json vendored
View file

@ -1,68 +0,0 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Monaco Editor Playground (Languages from source, needs 'npm run watch', no JSON/CSS/... workers!)",
"type": "chrome",
"request": "launch",
"url": "https://microsoft.github.io/monaco-editor/playground.html?sourceLanguages=http%3A%2F%2Flocalhost%3A5002%2Fout%2Flanguages%2Famd-tsc",
"preLaunchTask": "Launch Http Server",
"presentation": {
"group": "monaco",
"order": 1
}
},
{
"name": "Monaco Editor Playground (Languages locally bundled, needs 'npm run build')",
"type": "chrome",
"request": "launch",
"url": "https://microsoft.github.io/monaco-editor/playground.html?sourceLanguages=http%3A%2F%2Flocalhost%3A5002%2Fout%2Flanguages%2Fbundled%2Famd-dev%2Fvs",
"preLaunchTask": "Launch Http Server",
"presentation": {
"group": "monaco",
"order": 1
}
},
{
"name": "Website",
"type": "chrome",
"request": "launch",
"url": "http://localhost:8080/"
},
{
// Clone VS Code and make sure the task "Launch Http Server" runs.
// Then the editor is build from sources.
// We recommend to use the workspace feature for this.
"name": "Monaco Editor Playground (Load From VS Code Http Server)",
"type": "chrome",
"request": "launch",
"url": "https://microsoft.github.io/monaco-editor/playground.html?sourceLanguages=http%3A%2F%2Flocalhost%3A5002%2Fout%2Flanguages%2Famd-tsc&source=http%3A%2F%2Flocalhost%3A5001%2Fout%2Fvs",
"preLaunchTask": "Launch Http Server",
"presentation": {
"group": "monaco",
"order": 1
}
},
{
"type": "node",
"request": "launch",
"name": "Monaco Languages Unit Tests",
"skipFiles": ["<node_internals>/**"],
"program": "${workspaceRoot}/node_modules/mocha/bin/_mocha",
"args": ["-r", "test/unit/all.js"],
"outFiles": ["${workspaceFolder}/**/*.js"]
},
{
"type": "node",
"request": "launch",
"name": "webpack plugin test",
"skipFiles": ["<node_internals>/**"],
"program": "${workspaceFolder}/webpack-plugin/node_modules/.bin/webpack",
"args": ["--config", "test/webpack.config.js"],
"cwd": "${workspaceFolder}/webpack-plugin/"
}
]
}

13
.vscode/settings.json vendored
View file

@ -1,17 +1,10 @@
// Place your settings in this file to overwrite default and user settings. // Place your settings in this file to overwrite default and user settings.
{ {
"editor.tabSize": 4,
"editor.insertSpaces": false,
"files.insertFinalNewline": true,
"files.trimTrailingWhitespace": true, "files.trimTrailingWhitespace": true,
"search.exclude": { "search.exclude": {
"**/node_modules": true, "**/node_modules": true,
"**/dist": true, "**/bower_components": true,
"**/out": true "**/release": true
}, },
"typescript.tsdk": "./node_modules/typescript/lib", "typescript.tsdk": "./node_modules/typescript/lib"
"git.branchProtection": ["main", "release/*"],
"git.branchProtectionPrompt": "alwaysCommitToNewBranch",
"git.branchRandomName.enable": true,
"editor.formatOnSave": true
} }

30
.vscode/tasks.json vendored
View file

@ -1,30 +0,0 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Launch Http Server",
"type": "shell",
"command": "node_modules/.bin/http-server --cors --port 5002 -a 127.0.0.1 -c-1",
"isBackground": true,
"problemMatcher": {
"pattern": {
"regexp": "does not support problems"
},
"background": {
"activeOnStart": true,
"beginsPattern": "Shutting down http-server (will never match)",
"endsPattern": "Starting up http-server"
}
},
"dependsOn": ["npm: watch"]
},
{
"type": "npm",
"script": "watch",
"group": "build",
"problemMatcher": ["$tsc-watch"],
"isBackground": true,
"label": "npm: watch"
}
]
}

File diff suppressed because it is too large Load diff

View file

@ -1,125 +1,153 @@
# Contributing / Dev Setup # Contributing & Maintaining
## Source Code Structure This guide contains the lightweight setup version (that **only requires you to have node.js installed**).
If you wish to be able to run vscode from source, please see [VSCode's How to Contribute](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#build-and-run-from-source).
It is important to understand that the Monaco Editor _Core_ is built directly from the [VS Code source code](https://github.com/microsoft/vscode). ## A brief explanation on the source code structure
The Monaco Editor then enhances the Monaco Editor Core with some basic language features.
This diagram describes the relationships between the repositories and the npm packages: This repository contains no source code, it only contains the scripts to package everything together and ship the `monaco-editor` npm module:
![](./docs/code-structure.dio.svg) These packages are described in the root file called `metadata.js` and it is possible to create an editor distribution that contains only certain plugins by editing that file.
By default, `monaco-editor-core` is installed from npm (through the initial `npm install`), so you can work on Monaco Editor language features without having to build the core editor / VS Code. | repository | npm module | explanation |
The nightly builds build a fresh version of `monaco-editor-core` from the `main` branch of VS Code. |------------|------------|-------------|
For a stable release, the commit specified in `vscodeRef` in [package.json](./package.json) specifies the commit of VS Code that is used to build `monaco-editor-core`. | [vscode](https://github.com/Microsoft/vscode) | [monaco-editor-core](https://www.npmjs.com/package/monaco-editor-core) | editor core functionality (language agnostic) is shipped out of vscode. |
| [monaco-languages](https://github.com/Microsoft/monaco-languages) | [monaco-languages](https://www.npmjs.com/package/monaco-languages) | plugin that adds colorization and basic supports for dozens of languages. |
| [monaco-typescript](https://github.com/Microsoft/monaco-typescript) | [monaco-typescript](https://www.npmjs.com/package/monaco-typescript) | plugin that adds rich language support for JavaScript and TypeScript. |
| [monaco-css](https://github.com/Microsoft/monaco-css) | [monaco-css](https://www.npmjs.com/package/monaco-css) | plugin that adds rich language support for CSS, LESS and SCSS. |
| [monaco-json](https://github.com/Microsoft/monaco-json) | [monaco-json](https://www.npmjs.com/package/monaco-json) | plugin that adds rich language support for JSON. |
| [monaco-html](https://github.com/Microsoft/monaco-html) | [monaco-html](https://www.npmjs.com/package/monaco-html) | plugin that adds rich language support for HTML. |
## Contributing a new tokenizer / a new language
Please understand that we only bundle languages with the monaco editor that have a significant relevance (for example, those that have an article in Wikipedia). ## Running the editor from source
- create `$/src/basic-languages/{myLang}/{myLang}.contribution.ts` You need to have all the build setup of being able to build VS Code to be able to build the Monaco Editor.
- create `$/src/basic-languages/{myLang}/{myLang}.ts`
- create `$/src/basic-languages/{myLang}/{myLang}.test.ts`
- edit `$/src/basic-languages/monaco.contribution.ts` and register your new language
- create `$/website/index/samples/sample.{myLang}.txt`
```js * Install all the prerequisites: https://github.com/Microsoft/vscode/wiki/How-to-Contribute#installing-prerequisites
import './{myLang}/{myLang}.contribution';
### OS X and Linux
```
/src> git clone https://github.com/microsoft/vscode
/src> cd vscode
# install npm deps for vscode
/src/vscode> ./scripts/npm.sh install
# start the compiler in the background
/src/vscode> npm run watch
``` ```
## Debugging / Developing The Core Editor ### Windows
```
/src> git clone https://github.com/microsoft/vscode
/src> cd vscode
# install npm deps for vscode
/src/vscode> scripts\npm.bat install
# start the compiler in the background
/src/vscode> npm run watch
```
To debug core editor issues. * For the monaco editor test pages:
This can be done directly from the VS Code repository and does not involve the monaco editor repository.
- Clone the [VS Code repository](https://github.com/microsoft/vscode): `git clone https://github.com/microsoft/vscode`
- Open the repository in VS Code: `code vscode`
- Run `yarn install`
- Select and run the launch configuration "Monaco Editor Playground" (this might take a while, as it compiles the sources):
![](./docs/launch%20config.png)
- Now you can set breakpoints and change the source code
![](./docs/debugging-core.gif)
- Optionally, you can build `monaco-editor-core` and link it to the monaco editor repository:
```bash ```bash
# builds out-monaco-editor-core # clone monaco-editor (note the folders must be siblings!)
> yarn gulp editor-distro /src> git clone https://github.com/Microsoft/monaco-editor
> cd out-monaco-editor-core # install npm deps for monaco-editor
> npm link /src/monaco-editor> npm install .
> cd ../path/to/monaco-editor
# symlinks the monaco-editor-core package to the out-monaco-editor-core folder we just built # start a local http server in the background
> npm link monaco-editor-core /src/monaco-editor> npm run simpleserver
``` ```
## Debugging / Developing Language Support Open [http://localhost:8080/monaco-editor/test/?editor=src](http://localhost:8080/monaco-editor/test/?editor=src) to run.
To debug bundled languages, such as JSON, HTML or TypeScript/JavaScript. ## Running a plugin from source (e.g. monaco-typescript)
- Clone the [monaco editor repository](https://github.com/microsoft/monaco-editor): `git clone https://github.com/microsoft/monaco-editor`
- Open the repository in VS Code: `code monaco-editor`
- Run `npm install`
- Select and run the launch configuration "Monaco Editor Playground" (this might take a while, as it compiles the sources):
![](./docs/launch%20config.png)
- Now you can set breakpoints and change the source code
![](./docs/debugging-languages.gif)
- Optionally, you can build `monaco-editor` and link it if you want to test your changes in a real application:
```bash ```bash
# builds out/monaco-editor # clone monaco-typescript
> npm run build-monaco-editor /src> git clone https://github.com/Microsoft/monaco-typescript
> cd out/monaco-editor # install npm deps for monaco-typescript
> npm link /src/monaco-typescript> npm install .
> cd ../path/to/my-app # start the compiler in the background
> npm link monaco-editor /src/monaco-typescript> npm run watch
``` ```
Open [http://localhost:8080/monaco-editor/test/?editor=src&monaco-typescript=src](http://localhost:8080/monaco-editor/test/?editor=src&monaco-typescript=src) to run.
## Running the editor tests ## Running the editor tests
```bash ```bash
> npm run build-monaco-editor /src/vscode> npm run monaco-editor-test
> npm run test # or run a test page http://localhost:8080/monaco-editor/test/?editor=src
> npm run compile --prefix webpack-plugin
> npm run package-for-smoketest-webpack
> npm run package-for-smoketest-esbuild
> npm run package-for-smoketest-vite
> npm run package-for-smoketest-parcel --prefix test/smoke/parcel
> npm run smoketest-debug
``` ```
## Running the website locally > Tip: All folders must be cloned as siblings.
> Tip: When running the test pages, use the control panel in the top right corner to switch between running from source, running from npm or running from the local release:
![image](https://cloud.githubusercontent.com/assets/5047891/19599080/eb0d7622-979e-11e6-96ce-dde98cd95dc1.png)
## Running the website
```bash ```bash
> npm install # create a local release
> npm run build-monaco-editor /src/monaco-editor> npm run release
> cd website # open http://localhost:8080/monaco-editor/website/
> yarn install
> yarn typedoc # build the website
> yarn dev /src/monaco-editor> npm run website
# open http://localhost:8080/monaco-editor-website/
# publish the website
/src/monaco-editor-website> git push origin gh-pages --force
``` ```
Now webpack logs the path to the website. ---
## Out Folders ## Shipping a new monaco-editor npm module
This diagram describes the output folders of the build process: #### 1. Ship a new `monaco-editor-core` npm module
* bump version in `/src/vscode/build/monaco/package.json`
* **[important]** push all local changes to the remote to get a good public commit id.
* generate npm package `/src/vscode> node_modules/.bin/gulp editor-distro`
* publish npm package `/src/vscode/out-monaco-editor-core> npm publish`
![](./docs/out-folders.dio.svg) #### 2. Adopt new `monaco-editor-core` in plugins
* if there are breaking API changes that affect the language plugins, adopt the new API in:
* [repo - monaco-typescript](https://github.com/Microsoft/monaco-typescript)
* [repo - monaco-languages](https://github.com/Microsoft/monaco-languages)
* [repo - monaco-css](https://github.com/Microsoft/monaco-css)
* [repo - monaco-json](https://github.com/Microsoft/monaco-json)
* [repo - monaco-html](https://github.com/Microsoft/monaco-html)
* publish new versions of those plugins to npm as necessary.
## Maintaining #### 3. Update package.json
* edit `/src/monaco-editor/package.json` and update the version (as necessary):
* [npm - monaco-editor-core](https://www.npmjs.com/package/monaco-editor-core)
* [npm - monaco-typescript](https://www.npmjs.com/package/monaco-typescript)
* [npm - monaco-languages](https://www.npmjs.com/package/monaco-languages)
* [npm - monaco-css](https://www.npmjs.com/package/monaco-css)
* [npm - monaco-json](https://www.npmjs.com/package/monaco-json)
* [npm - monaco-html](https://www.npmjs.com/package/monaco-html)
* **[important]** fetch latest deps by running `/src/monaco-editor> npm install .`
Checkout [MAINTAINING.md](./MAINTAINING.md) for common maintaining tasks (for maintainers only). #### 4. Generate and try out the local release
* `/src/monaco-editor> npm run release`
* try as many test pages as you think are relevant. e.g.:
* open `http://localhost:8080/monaco-editor/test/?editor=releaseDev`
* open `http://localhost:8080/monaco-editor/test/?editor=releaseMin`
* open `http://localhost:8080/monaco-editor/test/smoketest.html?editor=releaseDev`
* open `http://localhost:8080/monaco-editor/test/smoketest.html?editor=releaseMin`
#### 5. Update release note.
* API Change/Breaking Change/New and noteworthy
* Thank you
#### 6. Publish
* `/src/monaco-editor> npm version minor`
* `/src/monaco-editor/release> npm publish`
* `/src/monaco-editor> git push --tags`

5
ISSUE_TEMPLATE Normal file
View file

@ -0,0 +1,5 @@
<!-- Do you have a question? Please ask it on https://stackoverflow.com/questions/tagged/monaco-editor -->
monaco-editor version: 0.X.Y
Browser:
OS:
Steps or JS usage snippet reproducing the issue:

View file

@ -1,6 +1,6 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2016 - present Microsoft Corporation Copyright (c) 2018 Microsoft Corporation
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View file

@ -1,55 +0,0 @@
# Maintaining
(For maintainers only)
Make sure every unassigned issue is labeled properly:
- [Inbox Queue](https://github.com/microsoft/monaco-editor/issues?q=is%3Aissue+is%3Aopen+no%3Aassignee+-label%3Afeature-request+-label%3Aupstream+-label%3A%22info-needed%22++-label%3Abug+)
## Publishing a stable build monaco-editor build
- Trigger an rc-build
- Go to https://github.com/microsoft/vscode/tree/release/1.89 (use latest VS Code version instead of .89!) and copy the id of the latest commit
- Go to https://dev.azure.com/monacotools/Monaco/_build?definitionId=421 and click on "Run pipeline"
- Use the copied commit id for `The VS Code commit id.`
- Use `rc` for `The prerelease version.`
- Wait until pipeline completes
- [Compare Last Stable With Nightly](https://microsoft.github.io/monaco-editor/playground.html?source=v0.40.0-dev.20230704#XQAAAAIGBwAAAAAAAABBqQkHQ5NjdMjwa-jY7SIQ9S7DNlzs5W-mwj0fe1ZCDRFc9ws9XQE0SJE1jc2VKxhaLFIw9vEWSxW3yscxAWG5G70rT-mLieOxDi0igaBcv2nRy9q6wT9hrC3N47TPeSd0URO3iwn_firHxVGLm2_8QMEuG2aOJ-jnXkHfLAawVi9XJdfEkOLYHqAT78XFdClh7HNBHFpSfLkCNQ3vE811FAdf6WYL_UK2n1jfGRMcnWqaztoAOTcWNn5qQ9RusryNfDBRqtjOJktItFKSNuOcLg104A0xatH8uXcfAULeE9RZRf41YqC9wbcZDEp7Mnul26YzW_IBv-vL-EGPcEFiu34YZPHQguQiuU8L4VXh7uAtKRWehN9N2m2XFF3yHCBpSGiN8qmBi4HSBRjbhkEKka_icj87t3Lfmg15PMqKgTr7l73XusvkQCZDvqumlN-mcVTZiIdD51m-OFugmn0Cq_ZPU2zq45rRtk1he8PcWiZpPSbCknJsHs4D-mKcc-ypq6CLYlqO8Cvc5lRWzwD-pG6e6uPAQsRAOJ45-mySqhRo_MGJ7aLfkhe7fVn9OvOm6BRsDAYmNVZqpA5aKJzwjeUwQqHwV8CW-b4hrZooiPavu8m2XgbiSW_5nmzbjQ-SaPnBsJxcAewWB_NiYiU3H_Gfhi8K0qQZlBxaetqYX5Ns1Ww6S_By4izRxeEln7McyDQxKk-tnywSCklMhZPiMaR0AZsXs5DQSxGTlB5q61e7Wtxb0RLdk5einYvNwXDooi5Vi5go_ZsO7JYmzylxi-T_hdsPgKNoy6j9IVh5BZb_HgRoaGCrojOWJdYpNNrPJJG_1fyZ8Bk80eYNmHHPJ7Q-pdXqQuAZBdd9Grv4UfXoY1R3Sl529QkIjEHTzgzYGn4C5KE5IGhEfu49Ugy0fFHU-yJGY__aPECJ)
- Check the metadata and verify that the last stable is on the left and the the last rc build is on the right
- Update [package.json](./package.json)
- set `version` to _lastNightly.nextStableVersion_ (from the compare step)
- set `vscodeRef` to _lastNightly.vscodeCommitId_
- update `devDependencies.monaco-editor-core` to _lastNightly.currentVersion_
- Run `npm install` to update lockfile
- Update [CHANGELOG.md](./CHANGELOG.md)
- API Changes / Breaking Changes / New and noteworthy (use the diff from the compare step)
- Add thank you mentions ([use this tool](https://tools.code.visualstudio.com/acknowledgement) and select only the monaco-editor)
- Commit & Create PR
- [Trigger build](https://dev.azure.com/monacotools/Monaco/_build?definitionId=416) once merged. Tick the following checkboxes:
- Publish Monaco Editor Core
- Publish Monaco Editor
#### Publish new webpack plugin
- **TBD**
- https://github.com/microsoft/monaco-editor/tree/main/webpack-plugin
- `npm install .`
- `npm run import-editor`
- if there are no changes generated after the script:
- update the peer dependency in `package.json` and use the `||` format e.g. `"monaco-editor": "0.27.x || 0.28.x"`
- update the version matrix in the README.md and add the new editor version to the plugin's current major version
- use `npm version minor`
- publish using `npm publish`
- if there are any changes generated after the script:
- update the peer dependency in `package.json` e.g. `"monaco-editor": "0.29.x"`
- update the version matrix in the README.md and add a new row with the new major version
- use `npm version major`
- publish using `npm publish`
- remember to push tags upstream
## Updating TypeScript
- change typescript's version in `package.json`.
- execute `npm install .`
- execute `npm run import-typescript`
- adopt new APIs

107
README.md
View file

@ -1,81 +1,48 @@
# Monaco Editor # Monaco Editor
[![Versions](https://img.shields.io/npm/v/monaco-editor)](https://www.npmjs.com/package/monaco-editor) The Monaco Editor is the code editor that powers [VS Code](https://github.com/Microsoft/vscode), a good page describing the code editor's features is [here](https://code.visualstudio.com/docs/editor/editingevolved).
[![Versions](https://img.shields.io/npm/v/monaco-editor/next)](https://www.npmjs.com/package/monaco-editor)
[![Feature Requests](https://img.shields.io/github/issues/microsoft/monaco-editor/feature-request.svg)](https://github.com/microsoft/monaco-editor/issues?q=is%3Aopen+is%3Aissue+label%3Afeature-request+sort%3Areactions-%2B1-desc)
[![Bugs](https://img.shields.io/github/issues/microsoft/monaco-editor/bug.svg)](https://github.com/microsoft/monaco-editor/issues?utf8=✓&q=is%3Aissue+is%3Aopen+label%3Abug)
The Monaco Editor is the fully featured code editor from [VS Code](https://github.com/microsoft/vscode). Check out the [VS Code docs](https://code.visualstudio.com/docs/editor/editingevolved) to see some of the supported features. ![image](https://cloud.githubusercontent.com/assets/5047891/19600675/5eaae9e6-97a6-11e6-97ad-93903167d8ba.png)
![image](https://user-images.githubusercontent.com/5047891/94183711-290c0780-fea3-11ea-90e3-c88ff9d21bd6.png)
## Try it out ## Try it out
Try out the editor and see various examples [in our interactive playground](https://microsoft.github.io/monaco-editor/playground.html). See the editor in action [on the website](https://microsoft.github.io/monaco-editor/index.html).
The playground is the best way to learn about how to use the editor, which features is supports, to try out different versions and to create minimal reproducible examples for bug reports.
## Installing ## Installing
``` ```
> npm install monaco-editor $ npm install monaco-editor
``` ```
You will get: You will get:
* inside `esm`: ESM version of the editor (compatible with e.g. webpack)
* inside `dev`: AMD bundled, not minified
* inside `min`: AMD bundled, and minified
* inside `min-maps`: source maps for `min`
* `monaco.d.ts`: this specifies the API of the editor (this is what is actually versioned, everything else is considered private and might break with any release).
- inside `/esm`: ESM version of the editor (compatible with e.g. webpack) It is recommended to develop against the `dev` version, and in production to use the `min` version.
- `monaco.d.ts`: this specifies the API of the editor (this is what is actually versioned, everything else is considered private and might break with any release).
: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.
### Models
Models are at the heart of Monaco editor. It's what you interact with when managing content. A model represents a file that has been opened. This could represent a file that exists on a file system, but it doesn't have to. For example, the model holds the text content, determines the language of the content, and tracks the edit history of the content.
### URIs
Each model is identified by a URI. This is why it's not possible for two models to have the same URI. Ideally when you represent content in Monaco editor, you should think of a virtual file system that matches the files your users are editing. For example, you could use `file:///` as a base path. If a model is created without a URI, its URI will be `inmemory://model/1`. The number increases as more models are created.
### Editors
An editor is a user facing view of the model. This is what gets attached to the DOM and what your users see visually. Typical editor operations are displaying a model, managing the view state, or executing actions or commands.
### Providers
Providers provide smart editor features. For example, this includes completion and hover information. It is not the same as, but often maps to [language server protocol](https://microsoft.github.io/language-server-protocol) features.
Providers work on models. Some smart features depends on the file URI. For example, for TypeScript to resolve imports, or for JSON IntelliSense to determine which JSON schema to apply to which model. So it's important to choose proper model URIs.
### Disposables
Many Monaco related objects often implement the `.dispose()` method. This method is intended to perform cleanups when a resource is no longer needed. For example, calling `model.dispose()` will unregister it, freeing up the URI for a new model. Editors should be disposed to free up resources and remove their model listeners.
## Documentation ## Documentation
- Learn how to integrate the editor with these [complete samples](./samples/). * Learn how to integrate the editor with these [complete samples](https://github.com/Microsoft/monaco-editor-samples/).
- [Integrate the ESM version](./docs/integrate-esm.md) * [Integrate the AMD version](./docs/integrate-amd.md).
- Learn how to use the editor API and try out your own customizations in the [playground](https://microsoft.github.io/monaco-editor/playground.html). * [Integrate the AMD version cross-domain](./docs/integrate-amd-cross.md)
- Explore the [API docs](https://microsoft.github.io/monaco-editor/docs.html) or read them straight from [`monaco.d.ts`](https://github.com/microsoft/monaco-editor/blob/gh-pages/node_modules/monaco-editor/monaco.d.ts). * [Integrate the ESM version](./docs/integrate-esm.md)
- Read [this guide](https://github.com/microsoft/monaco-editor/wiki/Accessibility-Guide-for-Integrators) to ensure the editor is accessible to all your users! * Learn how to use the editor API and try out your own customizations in the [playground](https://microsoft.github.io/monaco-editor/playground.html).
- Create a Monarch tokenizer for a new programming language [in the Monarch playground](https://microsoft.github.io/monaco-editor/monarch.html). * Explore the [API docs](https://microsoft.github.io/monaco-editor/api/index.html) or read them straight from [`monaco.d.ts`](https://github.com/Microsoft/monaco-editor/blob/master/website/playground/monaco.d.ts.txt).
- Ask questions on [StackOverflow](https://stackoverflow.com/questions/tagged/monaco-editor)! Search open and closed issues, there are a lot of tips in there! * Read [this guide](https://github.com/Microsoft/monaco-editor/wiki/Accessibility-Guide-for-Integrators) to ensure the editor is accessible to all your users!
* Create a Monarch tokenizer for a new programming language [in the Monarch playground](https://microsoft.github.io/monaco-editor/monarch.html).
* Ask questions on [StackOverflow](https://stackoverflow.com/questions/tagged/monaco-editor)!
* Search open and closed issues, there are a lot of tips in there!
## Issues ## Issues
Create [issues](https://github.com/microsoft/monaco-editor/issues) in this repository for anything related to the Monaco Editor. Please search for existing issues to avoid duplicates. Create issues in this repository for anything Monaco Editor related. Always mention **the version** of the editor when creating issues and **the browser** you're having trouble in. Please search for existing issues to avoid duplicates.
## Known issues
In IE 11, the editor must be completely surrounded in the body element, otherwise the hit testing we do for mouse operations does not work. You can inspect this using F12 and clicking on the body element and confirm that visually it surrounds the editor.
## FAQ ## FAQ
@ -95,11 +62,15 @@ No.
❓ **Why all these web workers and why should I care?** ❓ **Why all these web workers and why should I care?**
Language services create web workers to compute heavy stuff outside of the UI thread. They cost hardly anything in terms of resource overhead and you shouldn't worry too much about them, as long as you get them to work (see above the cross-domain case). Language services create web workers to compute heavy stuff outside the UI thread. They cost hardly anything in terms of resource overhead and you shouldn't worry too much about them, as long as you get them to work (see above the cross-domain case).
❓ **What is this `loader.js`? Can I use `require.js`?**
It is an AMD loader that we use in VS Code. Yes.
❓ **I see the warning "Could not create web worker". What should I do?** ❓ **I see the warning "Could not create web worker". What should I do?**
HTML5 does not allow pages loaded on `file://` to create web workers. Please load the editor with a web server on `http://` or `https://` schemes. HTML5 does not allow pages loaded on `file://` to create web workers. Please load the editor with a web server on `http://` or `https://` schemes. Please also see the cross domain case above.
❓ **Is the editor supported in mobile browsers or mobile web app frameworks?** ❓ **Is the editor supported in mobile browsers or mobile web app frameworks?**
@ -107,17 +78,21 @@ No.
❓ **Why doesn't the editor support TextMate grammars?** ❓ **Why doesn't the editor support TextMate grammars?**
- Please see https://github.com/bolinfest/monaco-tm which puts together `monaco-editor`, `vscode-oniguruma` and `vscode-textmate` to get TM grammar support in the editor. * all the regular expressions in TM grammars are based on [oniguruma](https://github.com/kkos/oniguruma), a regular expression library written in C.
* the only way to interpret the grammars and get anywhere near original fidelity is to use the exact same regular expression library (with its custom syntax constructs)
* in VSCode, our runtime is node.js and we can use a node native module that exposes the library to JavaScript
* in Monaco, we are constrained to a browser environment where we cannot do anything similar
* we have experimented with Emscripten to compile the C library to asm.js, but performance was very poor even in Firefox (10x slower) and extremely poor in Chrome (100x slower).
* we can revisit this once WebAssembly gets traction in the major browsers, but we will still need to consider the browser matrix we support. i.e. if we support IE11 and only Edge will add WebAssembly support, what will the experience be in IE11, etc.
## Contributing / Local Development ## Development setup
We are welcoming contributions from the community! Please see [CONTRIBUTING](./CONTRIBUTING.md)
Please see [CONTRIBUTING](./CONTRIBUTING.md) for details how you can contribute effectively, how you can run the editor from sources and how you can debug and fix issues.
## Code of Conduct ## Code of Conduct
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
## License
Licensed under the [MIT](https://github.com/microsoft/monaco-editor/blob/main/LICENSE.txt) License. ## License
[MIT](https://github.com/Microsoft/monaco-editor/blob/master/LICENSE.md)

View file

@ -1,41 +0,0 @@
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.5 BLOCK -->
## Security
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](<https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)>), please report it to us as described below.
## Reporting Security Issues
**Please do not report security vulnerabilities through public GitHub issues.**
Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report).
If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc).
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).
Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
- Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
- Full paths of source file(s) related to the manifestation of the issue
- The location of the affected source code (tag/branch/commit or direct URL)
- Any special configuration required to reproduce the issue
- Step-by-step instructions to reproduce the issue
- Proof-of-concept or exploit code (if possible)
- Impact of the issue, including how an attacker might exploit the issue
This information will help us triage your report more quickly.
If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs.
## Preferred Languages
We prefer all communications to be in English.
## Policy
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd).
<!-- END MICROSOFT SECURITY.MD BLOCK -->

File diff suppressed because one or more lines are too long

View file

@ -1,8 +0,0 @@
import { run } from '../../scripts/lib/index';
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 });
}

View file

@ -1,60 +0,0 @@
/*---------------------------------------------------------------------------------------------
* 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;
}
let idx = 0;
// Look for `new URL("...?worker", import.meta.url)` patterns.
const regex = /new\s+URL\s*\(\s*(['"`])(.*?)\?worker\1\s*,\s*import\.meta\.url\s*\)?/g;
let match;
let modified = false;
let result = code;
let offset = 0;
/** @type {string[]} */
const additionalImports = [];
while ((match = regex.exec(code)) !== null) {
let path = match[2];
if (!path.startsWith('.') && !path.startsWith('/')) {
path = `./${path}`;
}
const start = match.index;
const end = start + match[0].length;
const varName = `__worker_url_${idx++}__`;
additionalImports.push(`import ${varName} from ${JSON.stringify(path + '?worker&url')};`);
const replacement = varName;
result = result.slice(0, start + offset) + replacement + result.slice(end + offset);
offset += replacement.length - (end - start);
modified = true;
}
if (!modified) {
return null;
}
result = additionalImports.join('\n') + '\n' + result;
return {
code: result,
map: null
};
}
};
}

View file

@ -1,44 +0,0 @@
/*---------------------------------------------------------------------------------------------
* 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(),
]
});

View file

@ -1,94 +0,0 @@
/// @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)
)
);
}
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)
)
);
}
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)
)
);
}
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: string | URL) {
if (typeof workerScriptUrl !== 'string') {
workerScriptUrl = workerScriptUrl.toString();
}
const blob = new Blob(
[
[
`const ttPolicy = globalThis.trustedTypes?.createPolicy('defaultWorkerFactory', { createScriptURL: value => value });`,
`globalThis.workerttPolicy = ttPolicy;`,
`importScripts(ttPolicy?.createScriptURL(${JSON.stringify(
workerScriptUrl
)}) ?? ${JSON.stringify(workerScriptUrl)});`,
`globalThis.postMessage({ type: 'vscode-worker-ready' });`
].join('')
],
{ type: 'application/javascript' }
);
return URL.createObjectURL(blob);
}
import 'vs/nls.messages-loader!';
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');
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = styleSheetUrl;
document.head.appendChild(link);

File diff suppressed because it is too large Load diff

View file

@ -1,10 +0,0 @@
export function load(name, req, load, config) {
const requestedLanguage = config['vs/nls']?.availableLanguages?.['*'];
if (!requestedLanguage || requestedLanguage === 'en') {
load({});
} else {
req([`vs/nls.messages.${requestedLanguage}`], () => {
load({});
});
}
}

View file

@ -1,3 +0,0 @@
import * as m from './editor.main';
export { m };

View file

@ -1,82 +0,0 @@
import { readFileSync } from 'node:fs';
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) => {
/** @type {import('vite').UserConfig} */
return {
base: './',
resolve: {
dedupe: ['monaco-editor-core']
},
build: {
lib: {
cssFileName: 'editor/editor.main',
entry: {
...getNlsEntryPoints(),
'nls.messages-loader': resolve(__dirname, 'src/nls.messages-loader.js'),
'editor/editor.main': resolve(__dirname, 'src/editor.main.ts'),
'basic-languages/monaco.contribution': resolve(
__dirname,
'../../src/basic-languages/monaco.contribution.ts'
),
'language/css/monaco.contribution': resolve(
__dirname,
'../../src/language/css/monaco.contribution.ts'
),
'language/html/monaco.contribution': resolve(
__dirname,
'../../src/language/html/monaco.contribution.ts'
),
'language/json/monaco.contribution': resolve(
__dirname,
'../../src/language/json/monaco.contribution.ts'
),
'language/typescript/monaco.contribution': resolve(
__dirname,
'../../src/language/typescript/monaco.contribution.ts'
)
},
name: 'monaco-editor',
fileName: (_format, entryName) => entryName + '.js',
formats: ['amd']
},
outDir: resolve(
__dirname,
'../../out/monaco-editor/',
args.mode === 'development' ? 'dev' : 'min',
'vs'
),
rollupOptions: {
external: ['require', 'vs/nls.messages-loader!'],
output: {
amd: {
basePath: 'vs',
autoId: true
}
}
},
minify: args.mode !== 'development',
emptyOutDir: true
},
plugins: [
{
name: 'copy-loader',
apply: 'build',
generateBundle() {
this.emitFile({
type: 'asset',
fileName: 'loader.js',
source: readFileSync(resolve(__dirname, './src/loader.js'), 'utf-8')
});
}
},
urlToEsmPlugin()
]
};
});

View file

@ -1,81 +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 path = require('path');
import fs = require('fs');
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 { rm } from 'fs/promises';
async function run() {
await rm(path.join(REPO_ROOT, './out/monaco-editor'), { recursive: true, force: true });
await buildESM();
await buildAmdMinDev();
// 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);
})();
createThirdPartyNoticesDotTxt();
generateEsmMetadataJsAndDTs();
// package.json
(() => {
const packageJSON = readFiles('package.json', { base: '' })[0];
const json = JSON.parse(packageJSON.contents.toString());
json.private = false;
delete json.scripts['postinstall'];
packageJSON.contents = Buffer.from(JSON.stringify(json, null, ' '));
writeFiles([packageJSON], `out/monaco-editor`);
})();
(() => {
/** @type {IFile[]} */
let otherFiles = [];
otherFiles = otherFiles.concat(readFiles('README.md', { base: '' }));
otherFiles = otherFiles.concat(readFiles('CHANGELOG.md', { base: '' }));
otherFiles = otherFiles.concat(
readFiles('node_modules/monaco-editor-core/LICENSE', {
base: 'node_modules/monaco-editor-core/'
})
);
writeFiles(otherFiles, `out/monaco-editor`);
})();
}
/**
* Edit ThirdPartyNotices.txt:
* - append ThirdPartyNotices.txt from plugins
*/
function createThirdPartyNoticesDotTxt() {
const tpn = readFiles('node_modules/monaco-editor-core/ThirdPartyNotices.txt', {
base: 'node_modules/monaco-editor-core'
})[0];
let contents = tpn.contents.toString();
console.log('ADDING ThirdPartyNotices from ./ThirdPartyNotices.txt');
let thirdPartyNoticeContent = fs
.readFileSync(path.join(REPO_ROOT, 'ThirdPartyNotices.txt'))
.toString();
thirdPartyNoticeContent = thirdPartyNoticeContent.split('\n').slice(8).join('\n');
contents += '\n' + thirdPartyNoticeContent;
tpn.contents = Buffer.from(contents);
writeFiles([tpn], `out/monaco-editor`);
}
run();

View file

@ -1,53 +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 * as fs from 'fs';
import * as glob from 'glob';
import * as path from 'path';
import { REPO_ROOT } from './utils';
checkEveryMonacoLanguageHasASample();
function checkEveryMonacoLanguageHasASample() {
let languages = glob
.sync('src/basic-languages/*/*.contribution.ts', { cwd: REPO_ROOT })
.map((f) => path.dirname(f))
.map((f) => f.substring('src/basic-languages/'.length));
languages.push('css');
languages.push('html');
languages.push('json');
languages.push('typescript');
// some languages have a different id than their folder
languages = languages.map((l) => {
switch (l) {
case 'coffee':
return 'coffeescript';
case 'protobuf':
return 'proto';
case 'solidity':
return 'sol';
case 'sophia':
return 'aes';
default:
return l;
}
});
let fail = false;
for (const language of languages) {
const expectedSamplePath = path.join(
REPO_ROOT,
`website/src/website/data/home-samples/sample.${language}.txt`
);
if (!fs.existsSync(expectedSamplePath)) {
console.error(`Missing sample for ${language} at ${expectedSamplePath}`);
fail = true;
}
}
if (fail) {
process.exit(1);
}
}

View file

@ -1,7 +0,0 @@
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 });
}

View file

@ -1 +0,0 @@
!dist

View file

@ -1,21 +0,0 @@
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.

View file

@ -1,2 +0,0 @@
See https://www.npmjs.com/package/rollup-plugin-keep-css-imports.
Compare index.mjs with index.original.mjs to see the patch.

View file

@ -1,25 +0,0 @@
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 {};

View file

@ -1,31 +0,0 @@
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 {};

View file

@ -1,3 +0,0 @@
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]";

View file

@ -1,52 +0,0 @@
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;
}>;

View file

@ -1,4 +0,0 @@
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;

View file

@ -1,487 +0,0 @@
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 };

View file

@ -1,489 +0,0 @@
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 };

View file

@ -1,110 +0,0 @@
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 {};

View file

@ -1,74 +0,0 @@
{
"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"
}
}

View file

@ -1,47 +0,0 @@
/*---------------------------------------------------------------------------------------------
* 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')),
],
});

View file

@ -1,63 +0,0 @@
/*---------------------------------------------------------------------------------------------
* 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
};
}
};
}

View file

@ -1,86 +0,0 @@
/*---------------------------------------------------------------------------------------------
* 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,
}),
],
});

View file

@ -1,67 +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 * as fs from 'fs';
import * as path from 'path';
const REPO_ROOT = path.join(__dirname, '../');
const existingDirCache = new Set();
export function ensureDir(dirname: string) {
/** @type {string[]} */
const dirs = [];
while (dirname.length > REPO_ROOT.length) {
dirs.push(dirname);
dirname = path.dirname(dirname);
}
dirs.reverse();
dirs.forEach((dir) => {
if (!existingDirCache.has(dir)) {
try {
fs.mkdirSync(dir);
} catch (err) { }
existingDirCache.add(dir);
}
});
}
/**
* Remove a directory and all its contents.
*/
export function removeDir(_dirPath: string, keep?: (filename: string) => boolean) {
if (typeof keep === 'undefined') {
keep = () => false;
}
const dirPath = path.join(REPO_ROOT, _dirPath);
if (!fs.existsSync(dirPath)) {
return;
}
rmDir(dirPath, _dirPath);
console.log(`Deleted ${_dirPath}`);
function rmDir(dirPath: string, relativeDirPath: string): boolean {
let keepsFiles = false;
const entries = fs.readdirSync(dirPath);
for (const entry of entries) {
const filePath = path.join(dirPath, entry);
const relativeFilePath = path.join(relativeDirPath, entry);
if (keep!(relativeFilePath)) {
keepsFiles = true;
continue;
}
if (fs.statSync(filePath).isFile()) {
fs.unlinkSync(filePath);
} else {
keepsFiles = rmDir(filePath, relativeFilePath) || keepsFiles;
}
}
if (!keepsFiles) {
fs.rmdirSync(dirPath);
}
return keepsFiles;
}
}

View file

@ -1,192 +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 path = require('path');
import fs = require('fs');
import child_process = require('child_process');
import { REPO_ROOT } from './utils';
const generatedNote = `//
// **NOTE**: Do not edit directly! This file is generated using \`npm run import-typescript\`
//
`;
const TYPESCRIPT_LIB_SOURCE = path.join(REPO_ROOT, 'node_modules/typescript/lib');
const TYPESCRIPT_LIB_DESTINATION = path.join(REPO_ROOT, 'src/language/typescript/lib');
(function () {
try {
fs.statSync(TYPESCRIPT_LIB_DESTINATION);
} catch (err) {
fs.mkdirSync(TYPESCRIPT_LIB_DESTINATION);
}
importLibs();
const npmLsOutput = JSON.parse(
child_process.execSync('npm ls typescript --depth=0 --json=true', { cwd: REPO_ROOT }).toString()
);
const typeScriptDependencyVersion = npmLsOutput.dependencies.typescript.version;
fs.writeFileSync(
path.join(TYPESCRIPT_LIB_DESTINATION, 'typescriptServicesMetadata.ts'),
`${generatedNote}
export const typescriptVersion = "${typeScriptDependencyVersion}";\n`
);
let tsServices = fs.readFileSync(path.join(TYPESCRIPT_LIB_SOURCE, 'typescript.js')).toString();
tsServices = tsServices
.replace(
'const path = matchedStar ? subst.replace("*", matchedStar) : subst;',
'const path = matchedStar ? subst.replace("*", matchedStar) : subst; // CodeQL [SM02383] This is a false positive, the code is from the TypeScript compiler'
)
.replace(
'return key.replace("*", matchedStar);',
'return key.replace("*", matchedStar); // CodeQL [SM02383] This is a false positive, the code is from the TypeScript compiler'
);
// The output from this build will only be accessible via ESM; rather than removing
// references to require/module, define them as dummy variables that bundlers will ignore.
// The TS code can figure out that it's not running under Node even with these defined.
tsServices =
`
/* MONACOCHANGE */
var require = undefined;
var module = { exports: {} };
/* END MONACOCHANGE */
` + tsServices;
const tsServices_esm =
generatedNote +
tsServices +
`
// MONACOCHANGE
export var createClassifier = ts.createClassifier;
export var createLanguageService = ts.createLanguageService;
export var displayPartsToString = ts.displayPartsToString;
export var EndOfLineState = ts.EndOfLineState;
export var flattenDiagnosticMessageText = ts.flattenDiagnosticMessageText;
export var IndentStyle = ts.IndentStyle;
export var ScriptKind = ts.ScriptKind;
export var ScriptTarget = ts.ScriptTarget;
export var TokenClass = ts.TokenClass;
export var typescript = ts;
// END MONACOCHANGE
`;
fs.writeFileSync(
path.join(TYPESCRIPT_LIB_DESTINATION, 'typescriptServices.js'),
stripSourceMaps(tsServices_esm)
);
let dtsServices = fs.readFileSync(path.join(TYPESCRIPT_LIB_SOURCE, 'typescript.d.ts')).toString();
fs.writeFileSync(
path.join(TYPESCRIPT_LIB_DESTINATION, 'typescriptServices.d.ts'),
generatedNote + dtsServices
);
})();
function importLibs() {
function readLibFile(name) {
const srcPath = path.join(TYPESCRIPT_LIB_SOURCE, name);
return fs.readFileSync(srcPath).toString();
}
let strLibResult = `/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
${generatedNote}
/** Contains all the lib files */
export const libFileMap: Record<string, string> = {}
`;
let strIndexResult = `/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
${generatedNote}
/** Contains all the lib files */
export const libFileSet: Record<string, boolean> = {}
`;
const dtsFiles = fs.readdirSync(TYPESCRIPT_LIB_SOURCE).filter((f) => f.includes('lib.'));
while (dtsFiles.length > 0) {
const name = dtsFiles.shift();
const output = readLibFile(name).replace(/\r\n/g, '\n');
strLibResult += `libFileMap['${name}'] = "${escapeText(output)}";\n`;
strIndexResult += `libFileSet['${name}'] = true;\n`;
}
fs.writeFileSync(path.join(TYPESCRIPT_LIB_DESTINATION, 'lib.ts'), strLibResult);
fs.writeFileSync(path.join(TYPESCRIPT_LIB_DESTINATION, 'lib.index.ts'), strIndexResult);
}
/**
* Escape text such that it can be used in a javascript string enclosed by double quotes (")
*/
function escapeText(text) {
// See http://www.javascriptkit.com/jsref/escapesequence.shtml
const _backspace = '\b'.charCodeAt(0);
const _formFeed = '\f'.charCodeAt(0);
const _newLine = '\n'.charCodeAt(0);
const _nullChar = 0;
const _carriageReturn = '\r'.charCodeAt(0);
const _tab = '\t'.charCodeAt(0);
const _verticalTab = '\v'.charCodeAt(0);
const _backslash = '\\'.charCodeAt(0);
const _doubleQuote = '"'.charCodeAt(0);
const len = text.length;
let startPos = 0;
let chrCode;
let replaceWith = null;
let resultPieces = [];
for (let i = 0; i < len; i++) {
chrCode = text.charCodeAt(i);
switch (chrCode) {
case _backspace:
replaceWith = '\\b';
break;
case _formFeed:
replaceWith = '\\f';
break;
case _newLine:
replaceWith = '\\n';
break;
case _nullChar:
replaceWith = '\\0';
break;
case _carriageReturn:
replaceWith = '\\r';
break;
case _tab:
replaceWith = '\\t';
break;
case _verticalTab:
replaceWith = '\\v';
break;
case _backslash:
replaceWith = '\\\\';
break;
case _doubleQuote:
replaceWith = '\\"';
break;
}
if (replaceWith !== null) {
resultPieces.push(text.substring(startPos, i));
resultPieces.push(replaceWith);
startPos = i + 1;
replaceWith = null;
}
}
resultPieces.push(text.substring(startPos, len));
return resultPieces.join('');
}
function stripSourceMaps(str) {
return str.replace(/\/\/# sourceMappingURL[^\n]+/gm, '');
}

View file

@ -1,44 +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 = require('glob');
import path = require('path');
import fs = require('fs');
import cp = require('child_process');
const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm';
import { REPO_ROOT } from '../utils';
const files = glob.sync('**/package.json', {
cwd: REPO_ROOT,
ignore: ['**/node_modules/**', '**/dist/**', '**/out/**']
});
for (const file of files) {
const filePath = path.join(REPO_ROOT, file);
const contents = JSON.parse(fs.readFileSync(filePath).toString());
if (!contents.dependencies && !contents.devDependencies && !contents.optionalDependencies) {
// nothing to install
continue;
}
npmInstall(path.dirname(file));
}
function npmInstall(location) {
const stdio = 'inherit';
const args = ['install'];
console.log(`Installing dependencies in ${location}...`);
console.log(`$ npm ${args.join(' ')}`);
const result = cp.spawnSync(npm, args, {
env: process.env,
cwd: location,
stdio
});
if (result.error || result.status !== 0) {
process.exit(1);
}
}

View file

@ -1,20 +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 path from 'path';
import fs from 'fs';
import { REPO_ROOT } from '../utils';
const files = glob.sync('**/package-lock.json', {
cwd: REPO_ROOT,
ignore: ['**/node_modules/**', '**/out/**']
});
for (const file of files) {
const filePath = path.join(REPO_ROOT, file);
console.log(`Deleting ${file}...`);
fs.unlinkSync(filePath);
}

View file

@ -1,23 +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 cp = require('child_process');
import path = require('path');
function huskyInstall() {
console.log(`Installing husky hooks...`);
console.log(`$ husky install`);
const result = cp.spawnSync(
process.execPath,
[path.join(__dirname, '../node_modules/husky/lib/bin.js'), 'install'],
{ stdio: 'inherit' }
);
if (result.error || result.status !== 0) {
process.exit(1);
}
}
huskyInstall();

View file

@ -1,280 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import glob = require('glob');
import path = require('path');
import fs = require('fs');
import { REPO_ROOT } from './utils';
import { ensureDir } from './fs';
const customFeatureLabels = {
'vs/editor/browser/controller/coreCommands': 'coreCommands',
'vs/editor/contrib/caretOperations/caretOperations': 'caretOperations',
'vs/editor/contrib/caretOperations/transpose': 'transpose',
'vs/editor/contrib/colorPicker/colorDetector': 'colorDetector',
'vs/editor/contrib/rename/onTypeRename': 'onTypeRename',
'vs/editor/contrib/gotoSymbol/link/goToDefinitionAtPosition': 'gotoSymbol',
'vs/editor/contrib/snippet/snippetController2': 'snippets',
'vs/editor/standalone/browser/quickAccess/standaloneGotoLineQuickAccess': 'gotoLine',
'vs/editor/standalone/browser/quickAccess/standaloneCommandsQuickAccess': 'quickCommand',
'vs/editor/standalone/browser/quickAccess/standaloneGotoSymbolQuickAccess': 'quickOutline',
'vs/editor/standalone/browser/quickAccess/standaloneHelpQuickAccess': 'quickHelp'
};
function getBasicLanguages(): Promise<{ label: string; entry: string }[]> {
return new Promise((resolve, reject) => {
glob(
'./out/monaco-editor/esm/vs/basic-languages/*/*.contribution.js',
{ cwd: path.dirname(__dirname) },
(err, files) => {
if (err) {
reject(err);
return;
}
resolve(
files.map((file) => {
const entry = file.substring('./out/monaco-editor/esm/'.length).replace(/\.js$/, '');
const label = path.basename(file).replace(/\.contribution\.js$/, '');
return {
label: label,
entry: entry
};
})
);
}
);
});
}
function readAdvancedLanguages(): Promise<string[]> {
return new Promise((resolve, reject) => {
glob(
'./out/monaco-editor/esm/vs/language/*/monaco.contribution.js',
{ cwd: path.dirname(__dirname) },
(err, files) => {
if (err) {
reject(err);
return;
}
resolve(
files
.map((file) => file.substring('./out/monaco-editor/esm/vs/language/'.length))
.map((file) => file.substring(0, file.length - '/monaco.contribution.js'.length))
);
}
);
});
}
function getAdvancedLanguages(): Promise<
{ label: string; entry: string; worker: { id: string; entry: string } }[]
> {
return readAdvancedLanguages().then((languages) => {
let result = [];
for (const lang of languages) {
let shortLang = lang === 'typescript' ? 'ts' : lang;
const entry = `vs/language/${lang}/monaco.contribution`;
checkFileExists(entry);
const workerId = `vs/language/${lang}/${shortLang}Worker`;
const workerEntry = `vs/language/${lang}/${shortLang}.worker`;
checkFileExists(workerEntry);
result.push({
label: lang,
entry: entry,
worker: {
id: workerId,
entry: workerEntry
}
});
}
return result;
});
function checkFileExists(moduleName) {
const filePath = path.join(REPO_ROOT, 'out/monaco-editor/esm', `${moduleName}.js`);
if (!fs.existsSync(filePath)) {
console.error(`Could not find ${filePath}.`);
process.exit(1);
}
}
}
export function generateEsmMetadataJsAndDTs() {
return Promise.all([getBasicLanguages(), getAdvancedLanguages()]).then(
([basicLanguages, advancedLanguages]) => {
basicLanguages.sort((a, b) => strcmp(a.entry, b.entry));
advancedLanguages.sort((a, b) => strcmp(a.entry, b.entry));
let i = 0,
len = basicLanguages.length;
let j = 0,
lenJ = advancedLanguages.length;
let languages = [];
while (i < len || j < lenJ) {
if (i < len && j < lenJ) {
if (basicLanguages[i].label === advancedLanguages[j].label) {
let entry = [];
entry.push(basicLanguages[i].entry);
entry.push(advancedLanguages[j].entry);
languages.push({
label: basicLanguages[i].label,
entry: entry,
worker: advancedLanguages[j].worker
});
i++;
j++;
} else if (basicLanguages[i].label < advancedLanguages[j].label) {
languages.push(basicLanguages[i]);
i++;
} else {
languages.push(advancedLanguages[j]);
j++;
}
} else if (i < len) {
languages.push(basicLanguages[i]);
i++;
} else {
languages.push(advancedLanguages[j]);
j++;
}
}
const features = getFeatures();
const dtsContents = `
/*!----------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Released under the MIT license
* https://github.com/microsoft/monaco-editor/blob/main/LICENSE.txt
*----------------------------------------------------------------*/
export interface IWorkerDefinition {
id: string;
entry: string;
}
export interface IFeatureDefinition {
label: string;
entry: string | string[] | undefined;
worker?: IWorkerDefinition;
}
export const features: IFeatureDefinition[];
export const languages: IFeatureDefinition[];
export type EditorLanguage = ${languages.map((el) => `'${el.label}'`).join(' | ')};
export type EditorFeature = ${features.map((el) => `'${el.label}'`).join(' | ')};
export type NegatedEditorFeature = ${features.map((el) => `'!${el.label}'`).join(' | ')};
`;
const dtsDestination = path.join(REPO_ROOT, 'out/monaco-editor/esm/metadata.d.ts');
ensureDir(path.dirname(dtsDestination));
fs.writeFileSync(dtsDestination, dtsContents.replace(/\r\n/g, '\n'));
const jsContents = `
exports.features = ${JSON.stringify(features, null, ' ')};
exports.languages = ${JSON.stringify(languages, null, ' ')};
`;
const jsDestination = path.join(REPO_ROOT, 'out/monaco-editor/esm/metadata.js');
ensureDir(path.dirname(jsDestination));
fs.writeFileSync(jsDestination, jsContents.replace(/\r\n/g, '\n'));
for (const feature of [...features, ...languages]) {
const entries = [].concat(feature.entry);
for (const entry of entries) {
const dtsDestination = path.join(REPO_ROOT, 'out/monaco-editor/esm', entry) + '.d.ts';
ensureDir(path.dirname(dtsDestination));
fs.writeFileSync(dtsDestination, 'export {}\n');
}
}
}
);
}
function strcmp(a: string, b: string) {
if (a < b) {
return -1;
}
if (a > b) {
return 1;
}
return 0;
}
function getFeatures(): { label: string; entry: string | string[] }[] {
const skipImports = [
'vs/editor/browser/widget/codeEditorWidget',
'vs/editor/browser/widget/diffEditorWidget',
'vs/editor/browser/widget/diffNavigator',
'vs/editor/common/standaloneStrings',
'vs/editor/contrib/tokenization/tokenization',
'vs/editor/editor.all',
'vs/base/browser/ui/codicons/codiconStyles',
'vs/editor/contrib/gotoSymbol/documentSymbols'
];
let features: string[] = [];
const files =
fs
.readFileSync(path.join(REPO_ROOT, 'out/monaco-editor/esm/vs/editor/edcore.main.js'))
.toString() +
fs
.readFileSync(path.join(REPO_ROOT, 'out/monaco-editor/esm/vs/editor/editor.all.js'))
.toString();
files.split(/\r\n|\n/).forEach((line) => {
const m = line.match(/import '([^']+)'/);
if (m) {
const tmp = path.posix.join('vs/editor', m[1]).replace(/\.js$/, '');
if (skipImports.indexOf(tmp) === -1) {
features.push(tmp);
}
}
});
let result: { label: string; entry: any }[] = features.map((feature) => {
/** @type {string} */ let label;
if (customFeatureLabels[feature]) {
label = customFeatureLabels[feature];
} else {
const m1 = feature.match(/^vs\/editor\/contrib\/([^\/]+)/);
if (m1) {
// for editor/contrib features, use the first segment
label = m1[1];
} else {
// for everything else, use the last segment folder
label = path.basename(path.dirname(feature));
}
}
return {
label: label,
entry: feature
};
});
result.sort((a, b) => {
const labelCmp = strcmp(a.label, b.label);
if (labelCmp === 0) {
return strcmp(a.entry, b.entry);
}
return labelCmp;
});
for (let i = 0; i < result.length; i++) {
if (i + 1 < result.length && result[i].label === result[i + 1].label) {
if (typeof result[i].entry === 'string') {
result[i].entry = [result[i].entry];
}
result[i].entry.push(result[i + 1].entry);
result.splice(i + 1, 1);
}
}
return result;
}

View file

@ -1,96 +0,0 @@
/*---------------------------------------------------------------------------------------------
* 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;
}
}
}
};
}

View file

@ -1,69 +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 fs = require('fs');
import path = require('path');
import http = require('http');
import yaserver = require('yaserver');
import { REPO_ROOT } from './utils';
import { ensureDir } from './fs';
generateTestSamplesTask();
const SERVER_ROOT = path.normalize(path.join(REPO_ROOT, '../'));
createSimpleServer(SERVER_ROOT, 8080);
createSimpleServer(SERVER_ROOT, 8088);
function generateTestSamplesTask() {
const sampleNames = fs.readdirSync(path.join(REPO_ROOT, 'test/manual/samples'));
let samples = sampleNames.map((sampleName) => {
const samplePath = path.join(REPO_ROOT, 'test/manual/samples', sampleName);
const sampleContent = fs.readFileSync(samplePath).toString();
return {
name: sampleName,
content: sampleContent
};
});
// Add samples from website
{
let sampleNames = fs.readdirSync(path.join(REPO_ROOT, 'website/index/samples'));
sampleNames = sampleNames.filter((name) => /^sample/.test(name));
samples = samples.concat(
sampleNames.map((sampleName) => {
const samplePath = path.join(REPO_ROOT, 'website/index/samples', sampleName);
const sampleContent = fs.readFileSync(samplePath).toString();
return {
name: sampleName,
content: sampleContent
};
})
);
}
const prefix =
'//This is a generated file via `npm run simpleserver`\ndefine([], function() { return';
const suffix = '; });';
const destination = path.join(REPO_ROOT, 'test/manual/generated/all-samples.js');
ensureDir(path.dirname(destination));
fs.writeFileSync(destination, prefix + JSON.stringify(samples, null, '\t') + suffix);
}
function createSimpleServer(rootDir: string, port: number) {
yaserver
.createServer({
rootDir: rootDir
})
.then((staticServer) => {
const server = http.createServer((request, response) => {
return staticServer.handle(request, response);
});
server.listen(port, '127.0.0.1', () => {
console.log(`Running at http://127.0.0.1:${port}`);
});
});
}

View file

@ -1,8 +0,0 @@
{
"compilerOptions": {
"noEmit": true,
"module": "CommonJS",
"esModuleInterop": true
},
"include": ["./**/*"]
}

View file

@ -1,52 +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 * as fs from 'fs';
import * as path from 'path';
import * as glob from 'glob';
import { ensureDir } from './fs';
export const REPO_ROOT = path.join(__dirname, '../');
export interface IFile {
path: string;
contents: Buffer;
}
export function readFiles(
pattern: string,
options: { base: string; ignore?: string[]; dot?: boolean }
): IFile[] {
let files = glob.sync(pattern, { cwd: REPO_ROOT, ignore: options.ignore, dot: options.dot });
// remove dirs
files = files.filter((file) => {
const fullPath = path.join(REPO_ROOT, file);
const stats = fs.statSync(fullPath);
return stats.isFile();
});
const base = options.base;
return files.map((file) => readFile(file, base));
}
export function readFile(file: string, base: string = '') {
const baseLength = base === '' ? 0 : base.endsWith('/') ? base.length : base.length + 1;
const fullPath = path.join(REPO_ROOT, file);
const contents = fs.readFileSync(fullPath);
const relativePath = file.substring(baseLength);
return {
path: relativePath,
contents
};
}
export function writeFiles(files: IFile[], dest: string) {
for (const file of files) {
const fullPath = path.join(REPO_ROOT, dest, file.path);
ensureDir(path.dirname(fullPath));
fs.writeFileSync(fullPath, file.contents);
}
}

View file

@ -1,275 +0,0 @@
<svg host="65bd71144e" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="601px" height="391px" viewBox="-0.5 -0.5 601 391" content="&lt;mxfile&gt;&lt;diagram id=&quot;cU4r2CM7fKKh95v30pN0&quot; name=&quot;Page-1&quot;&gt;1Vpdk9osFP41XrqThBj1sqvd9qKd6XTfmbaXmKChjSED8au//j0kkA+IdtXo7t6sgcAJPOechwfYAZqt9584zuKvLCLJwHOi/QDNB57nOhMHfmTNoayZ+KpixWmkGtUVz/Qv0T1V7YZGRLQa5owlOc3alSFLUxLmrTrMOdu1my1Z0v5qhlfEqngOcWLX/qBRHqtZeOO6/jOhq1h/2Q2m5Zs11o3VTESMI7ZrVKGPAzTjjOXl03o/I4kET+NS9ns68rYaGCdp/pIOHlLjyA96ciSCuapiylL4eYzzdQIlFx7JnuY/4dl5GKnSr8abuXSxowsHXUhzfmh0ksVfzXd1t6Kk+5VDk+M5OjtVJdiGh7pVoCIC8xXRzcYVthCUhK0JfAfacJLgnG7b9rGKjlXVrgYQHhSG3Xgir7SxxclGWf3G2bYIVxhSTOrByrjjneh/wQtImBbsOKGrFJ5DmDnhULElPKcQkR/UizWNImnjkRNB/+JFYU+CmDGa5sWMRo+D0byCVRog+0FHuqjOdZA2AS8DxkZSWXIeIJnLXiq3FSAvRlqZ/iaHXdsdul7L6tD32ybYcinA26arqhG+yHs6dBre+0Tzz5sF1H0nGRM0Z3KUQQJoPC7Ae8FKPq1pyJlgS/j+01aEwHeWX3cxzclzhoso3QEttv171CdWsB+F3tXuUhAFU1Xe1RTlauaNG/QUONfHvTu2kEuzdTH+8I9kUxszluKQDUkkMR2GjJ+N2ZImyYwlkEQVUZlZkbPsNuBWK9a/wHWdPtCdXh+XLbzPhbob1w4H9AA1mvw7jpHfBbXbA9TazxcG8ivkPZq28XIdryM2gxslPhrdV0B4ZykIkkYfpN6TK2eChaBhWflEk7YHzhUZlexsiIyGgLtMZBRdYbz40Gig1u+jK6M/NphpZCg+sz0y2k8cw9/lCC5dQ5G9EjQUUILT1aZII2dJcL7htSASdmrRNEw2EU1X0Oi/QwYSnNMM5jKTgSxDqngKhSgffguW2kZwGsE7BtqLi85Yfctyq0yvE3ILTYO2MlLGr9VbuovWW1p/9aq39EcasfIEezHCbS+CKcHDV6DXkdPOl3HXyu90sOuoj9XIv5RdG9xaM203u0ZYxCTSBm7GmF4f7GgFanUmoOnM1FslQ6te10WrrcLmRAAlLSSJxYCZPIaAP4sNTaJ3RzVlrJ2gGteZGJsw1AvXGNJ6aBjoh2nsffkppinWGXu1uL+Yuy/bjC9lGyXLzhVz47PE3J14SgnaXo+PLlJ2gdbWmtrMszwzjwLnVPvrlZ29NZqTLVTMSQbIkzQ8vD/SO+LZivTGAGubnrx+SK9tdHIDzkPBxel8h2y+awK/ztYsMBMSnU7gkaFlpqjnBJ5YCaxONR7KrdM7S94ywE9tjnyt2Qxtce3uqG01GN9CsYxsxUKTjvMnMHTSi7cXLYH7iqIF3fkG640cQKE3cwBl7sCm0/MOoIz217OcbyWOdQVXXjc4+sy2PoF6bwx4+jZu6Dw4vtvrfdxNBYt9HCRimmUg+o+76A4Xa+aJadfFWtf5un8+vUGxvvwvIaz/hQJ9/B8=&lt;/diagram&gt;&lt;/mxfile&gt;">
<defs/>
<g>
<path d="M 90 60 L 90 143.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 90 148.88 L 86.5 141.88 L 90 143.63 L 93.5 141.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 74px; margin-left: 80px;">
<div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
Provides the source for
</div>
</div>
</div>
</foreignObject>
<text x="80" y="77" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">
Provides the source for
</text>
</switch>
</g>
<rect x="0" y="0" width="180" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 30px; margin-left: 1px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
GitHub Repository
<br/>
microsoft/vscode
</div>
</div>
</div>
</foreignObject>
<text x="90" y="34" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
GitHub Repository...
</text>
</switch>
</g>
<rect x="0" y="150" width="180" height="100" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 157px; margin-left: 1px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
npm package
<br/>
monaco-editor-core
</div>
</div>
</div>
</foreignObject>
<text x="90" y="169" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
npm package...
</text>
</switch>
</g>
<rect x="260" y="0" width="340" height="110" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 338px; height: 1px; padding-top: 7px; margin-left: 261px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
GitHub Repository
<br/>
microsoft/monaco-editor
</div>
</div>
</div>
</foreignObject>
<text x="430" y="19" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
GitHub Repository...
</text>
</switch>
</g>
<rect x="270" y="330" width="160" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 360px; margin-left: 271px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
npm package
<br/>
monaco-editor
</div>
</div>
</div>
</foreignObject>
<text x="350" y="364" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
npm package...
</text>
</switch>
</g>
<path d="M 430 100 L 358 154 Q 350 160 342 166 L 318 184 Q 310 190 310 200 L 310 323.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 310 328.88 L 306.5 321.88 L 310 323.63 L 313.5 321.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 231px; margin-left: 290px;">
<div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
Provides language feature sources
<br/>
including TypeScript, html, css, json
<br/>
and others
</div>
</div>
</div>
</foreignObject>
<text x="290" y="234" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">
Provides language feature sources...
</text>
</switch>
</g>
<rect x="380" y="50" width="100" height="50" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 75px; margin-left: 381px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
Folder
<br/>
/src
</div>
</div>
</div>
</foreignObject>
<text x="430" y="79" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
Folder...
</text>
</switch>
</g>
<path d="M 270 75 L 96.25 108.78" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/>
<path d="M 91.1 109.79 L 97.3 105.01 L 96.25 108.78 L 98.64 111.89 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 91px; margin-left: 190px;">
<div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
Describe how to build
</div>
</div>
</div>
</foreignObject>
<text x="190" y="94" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">
Describe how to build
</text>
</switch>
</g>
<rect x="270" y="50" width="100" height="50" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 75px; margin-left: 271px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
Folder
<br/>
/scripts
</div>
</div>
</div>
</foreignObject>
<text x="320" y="79" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
Folder...
</text>
</switch>
</g>
<path d="M 515 100 L 515 120 Q 515 130 505 130 L 150 130 Q 140 130 138.27 136.91 L 136.54 143.82" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/>
<path d="M 135.27 148.92 L 133.57 141.28 L 136.54 143.82 L 140.36 142.97 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 120px; margin-left: 181px;">
<div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
Dev Dependency
</div>
</div>
</div>
</foreignObject>
<text x="181" y="124" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">
Dev Dependency
</text>
</switch>
</g>
<path d="M 540 100 L 540 130 Q 540 140 531.68 145.55 L 398.32 234.45 Q 390 240 390 250 L 390 323.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 390 328.88 L 386.5 321.88 L 390 323.63 L 393.5 321.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 300px; margin-left: 391px;">
<div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
package.json
</div>
</div>
</div>
</foreignObject>
<text x="391" y="303" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">
package.json
</text>
</switch>
</g>
<rect x="490" y="50" width="100" height="50" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 75px; margin-left: 491px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
File
<br/>
/package.json
</div>
</div>
</div>
</foreignObject>
<text x="540" y="79" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
File...
</text>
</switch>
</g>
<path d="M 90 240 L 90 290 Q 90 300 100 300 L 300 300 Q 310 300 310 310 L 310 323.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 310 328.88 L 306.5 321.88 L 310 323.63 L 313.5 321.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 290px; margin-left: 179px;">
<div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
Provides the core editor sources
</div>
</div>
</div>
</foreignObject>
<text x="179" y="294" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">
Provides the core editor sources
</text>
</switch>
</g>
<rect x="10" y="200" width="160" height="40" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 220px; margin-left: 11px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
shipped sources
</div>
</div>
</div>
</foreignObject>
<text x="90" y="224" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
shipped sources
</text>
</switch>
</g>
</g>
<switch>
<g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/>
<a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank">
<text text-anchor="middle" font-size="10px" x="50%" y="100%">
Text is not SVG - cannot display
</text>
</a>
</switch>
</svg>

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 249 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 200 KiB

View file

@ -0,0 +1,78 @@
## Integrating the AMD version of the Monaco Editor in a cross-domain setup
Here is the most basic HTML page that embeds the editor, using AMD, in the case that the editor sources are hosted on a different domain (e.g. CDN) than the document origin.
More self-contained samples are available at [monaco-editor-samples](https://github.com/Microsoft/monaco-editor-samples).
If you are hosting your `.js` on a different domain (e.g. on a CDN) than the HTML, you should know that the Monaco Editor creates web workers for smart language features. Cross-domain web workers are not allowed, but here is how you can proxy their loading and get them to work:
Assuming the HTML lives on `www.mydomain.com` and the editor is hosted on `www.mycdn.com`.
----
# Option 1: Use a data: worker URI
* `https://www.mydomain.com/index.html`:
```html
<script type="text/javascript" src="http://www.mycdn.com/monaco-editor/min/vs/loader.js"></script>
<script>
require.config({ paths: { 'vs': 'http://www.mycdn.com/monaco-editor/min/vs' }});
// Before loading vs/editor/editor.main, define a global MonacoEnvironment that overwrites
// the default worker url location (used when creating WebWorkers). The problem here is that
// HTML5 does not allow cross-domain web workers, so we need to proxy the instantiation of
// a web worker through a same-domain script
window.MonacoEnvironment = {
getWorkerUrl: function(workerId, label) {
return `data:text/javascript;charset=utf-8,${encodeURIComponent(`
self.MonacoEnvironment = {
baseUrl: 'http://www.mycdn.com/monaco-editor/min/'
};
importScripts('http://www.mycdn.com/monaco-editor/min/vs/base/worker/workerMain.js');`
)}`;
}
};
require(["vs/editor/editor.main"], function () {
// ...
});
</script>
```
----
# Option 2: Host on your domain a worker proxy
* `https://www.mydomain.com/index.html`:
```html
<script type="text/javascript" src="http://www.mycdn.com/monaco-editor/min/vs/loader.js"></script>
<script>
require.config({ paths: { 'vs': 'http://www.mycdn.com/monaco-editor/min/vs' }});
// Before loading vs/editor/editor.main, define a global MonacoEnvironment that overwrites
// the default worker url location (used when creating WebWorkers). The problem here is that
// HTML5 does not allow cross-domain web workers, so we need to proxy the instantiation of
// a web worker through a same-domain script
window.MonacoEnvironment = {
getWorkerUrl: function(workerId, label) {
return 'monaco-editor-worker-loader-proxy.js';
}
};
require(["vs/editor/editor.main"], function () {
// ...
});
</script>
```
* `https://www.mydomain.com/monaco-editor-worker-loader-proxy.js`:
```js
self.MonacoEnvironment = {
baseUrl: 'http://www.mycdn.com/monaco-editor/min/'
};
importScripts('www.mycdn.com/monaco-editor/min/vs/base/worker/workerMain.js');
```
----
That's it. You're good to go! :)

34
docs/integrate-amd.md Normal file
View file

@ -0,0 +1,34 @@
## Integrating the AMD version of the Monaco Editor
Here is the most basic HTML page that embeds the editor using AMD.
More self-contained samples are available at [monaco-editor-samples](https://github.com/Microsoft/monaco-editor-samples).
```html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
</head>
<body>
<div id="container" style="width:800px;height:600px;border:1px solid grey"></div>
<script src="monaco-editor/min/vs/loader.js"></script>
<script>
require.config({ paths: { 'vs': 'monaco-editor/min/vs' }});
require(['vs/editor/editor.main'], function() {
var editor = monaco.editor.create(document.getElementById('container'), {
value: [
'function x() {',
'\tconsole.log("Hello world!");',
'}'
].join('\n'),
language: 'javascript'
});
});
</script>
</body>
</html>
```

View file

@ -1,36 +1,32 @@
## Integrating the ESM version of the Monaco Editor ## Integrating the ESM version of the Monaco Editor
- [Webpack](#using-webpack)
- [Option 1: Using the Monaco Editor WebPack Plugin](#option-1-using-the-monaco-editor-webpack-plugin)
- [Option 2: Using plain webpack](#option-2-using-plain-webpack)
- [Parcel](#using-parcel)
- [Vite](#using-vite)
### Using webpack ### Using webpack
Here is the most basic script that imports the editor using ESM with webpack. Here is the most basic script that imports the editor using ESM with webpack.
More self-contained samples are available in the [samples folder](../samples/). More self-contained samples are available at [monaco-editor-samples](https://github.com/Microsoft/monaco-editor-samples).
--- ---
### Option 1: Using the Monaco Editor WebPack Plugin ### Option 1: Using the Monaco Editor Loader Plugin
This is the easiest method, and it allows for options to be passed into the plugin in order to select only a subset of editor features or editor languages. Read more about the [Monaco Editor WebPack Plugin](../webpack-plugin/), which is a community authored plugin. This is the easiest method, and it allows for options to be passed in to the plugin in order to select only a subset of editor features or editor languages. Read more about the [Monaco Editor Loader Plugin](https://github.com/Microsoft/monaco-editor-webpack-plugin), which is a community authored plugin.
- `index.js`
* `index.js`
```js ```js
import * as monaco from 'monaco-editor'; import * as monaco from 'monaco-editor';
monaco.editor.create(document.getElementById('container'), { monaco.editor.create(document.getElementById('container'), {
value: ['function x() {', '\tconsole.log("Hello world!");', '}'].join('\n'), value: [
'function x() {',
'\tconsole.log("Hello world!");',
'}'
].join('\n'),
language: 'javascript' language: 'javascript'
}); });
``` ```
- `webpack.config.js` * `webpack.config.js`
```js ```js
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin'); const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
const path = require('path'); const path = require('path');
@ -42,18 +38,14 @@ module.exports = {
filename: 'app.js' filename: 'app.js'
}, },
module: { module: {
rules: [ rules: [{
{
test: /\.css$/, test: /\.css$/,
use: ['style-loader', 'css-loader'] use: ['style-loader', 'css-loader']
}]
}, },
{ plugins: [
test: /\.ttf$/, new MonacoWebpackPlugin()
use: ['file-loader']
}
] ]
},
plugins: [new MonacoWebpackPlugin()]
}; };
``` ```
@ -61,10 +53,7 @@ module.exports = {
### Option 2: Using plain webpack ### Option 2: Using plain webpack
Full working samples are available at https://github.com/microsoft/monaco-editor/tree/main/samples/browser-esm-webpack or https://github.com/microsoft/monaco-editor/tree/main/samples/browser-esm-webpack-small * `index.js`
- `index.js`
```js ```js
import * as monaco from 'monaco-editor'; import * as monaco from 'monaco-editor';
@ -76,10 +65,10 @@ self.MonacoEnvironment = {
if (label === 'json') { if (label === 'json') {
return './json.worker.bundle.js'; return './json.worker.bundle.js';
} }
if (label === 'css' || label === 'scss' || label === 'less') { if (label === 'css') {
return './css.worker.bundle.js'; return './css.worker.bundle.js';
} }
if (label === 'html' || label === 'handlebars' || label === 'razor') { if (label === 'html') {
return './html.worker.bundle.js'; return './html.worker.bundle.js';
} }
if (label === 'typescript' || label === 'javascript') { if (label === 'typescript' || label === 'javascript') {
@ -87,28 +76,31 @@ self.MonacoEnvironment = {
} }
return './editor.worker.bundle.js'; return './editor.worker.bundle.js';
} }
}; }
monaco.editor.create(document.getElementById('container'), { monaco.editor.create(document.getElementById('container'), {
value: ['function x() {', '\tconsole.log("Hello world!");', '}'].join('\n'), value: [
'function x() {',
'\tconsole.log("Hello world!");',
'}'
].join('\n'),
language: 'javascript' language: 'javascript'
}); });
``` ```
- `webpack.config.js`: * `webpack.config.js`:
```js ```js
const path = require('path'); const path = require('path');
module.exports = { module.exports = {
entry: { entry: {
app: './index.js', "app": './index.js',
// Package each language's worker and give these filenames in `getWorkerUrl` // Package each language's worker and give these filenames in `getWorkerUrl`
'editor.worker': 'monaco-editor/esm/vs/editor/editor.worker.js', "editor.worker": 'monaco-editor/esm/vs/editor/editor.worker.js',
'json.worker': 'monaco-editor/esm/vs/language/json/json.worker', "json.worker": 'monaco-editor/esm/vs/language/json/json.worker',
'css.worker': 'monaco-editor/esm/vs/language/css/css.worker', "css.worker": 'monaco-editor/esm/vs/language/css/css.worker',
'html.worker': 'monaco-editor/esm/vs/language/html/html.worker', "html.worker": 'monaco-editor/esm/vs/language/html/html.worker',
'ts.worker': 'monaco-editor/esm/vs/language/typescript/ts.worker' "ts.worker": 'monaco-editor/esm/vs/language/typescript/ts.worker',
}, },
output: { output: {
globalObject: 'self', globalObject: 'self',
@ -116,114 +108,10 @@ module.exports = {
path: path.resolve(__dirname, 'dist') path: path.resolve(__dirname, 'dist')
}, },
module: { module: {
rules: [ rules: [{
{
test: /\.css$/, test: /\.css$/,
use: ['style-loader', 'css-loader'] use: ['style-loader', 'css-loader']
}, }]
{
test: /\.ttf$/,
use: ['file-loader']
}
]
} }
}; };
``` ```
---
### Using parcel
A full working sample is available at https://github.com/microsoft/monaco-editor/tree/main/samples/browser-esm-parcel
When using parcel, we need to use the `getWorkerUrl` function and build the workers seperately from our main source. To simplify things, we can write a tiny bash script to build the workers for us.
- `index.js`
```js
import * as monaco from 'monaco-editor';
self.MonacoEnvironment = {
getWorkerUrl: function (moduleId, label) {
if (label === 'json') {
return './json.worker.js';
}
if (label === 'css' || label === 'scss' || label === 'less') {
return './css.worker.js';
}
if (label === 'html' || label === 'handlebars' || label === 'razor') {
return './html.worker.js';
}
if (label === 'typescript' || label === 'javascript') {
return './ts.worker.js';
}
return './editor.worker.js';
}
};
monaco.editor.create(document.getElementById('container'), {
value: ['function x() {', '\tconsole.log("Hello world!");', '}'].join('\n'),
language: 'javascript'
});
```
- `build_workers.sh`
```sh
ROOT=$PWD/node_modules/monaco-editor/esm/vs
OPTS="--no-source-maps --log-level 1" # Parcel options - See: https://parceljs.org/cli.html
parcel build $ROOT/language/json/json.worker.js $OPTS
parcel build $ROOT/language/css/css.worker.js $OPTS
parcel build $ROOT/language/html/html.worker.js $OPTS
parcel build $ROOT/language/typescript/ts.worker.js $OPTS
parcel build $ROOT/editor/editor.worker.js $OPTS
```
Then, simply run `sh ./build_workers.sh && parcel index.html`. This builds the workers into the same directory as your main bundle (usually `./dist`). If you want to change the `--out-dir` of the workers, you must change the paths in `index.js` to reflect their new location.
_note - the `getWorkerUrl` paths are relative to the build directory of your src bundle_
---
### Using Vite
Adding monaco editor to [Vite](https://vitejs.dev/) is simple since it has built-in support for web workers. You only need to implement the `getWorker` function (NOT the `getWorkerUrl`) to use Vite's output ([Source](https://github.com/vitejs/vite/discussions/1791#discussioncomment-321046)):
```js
import * as monaco from 'monaco-editor';
self.MonacoEnvironment = {
getWorker: function (workerId, label) {
const getWorkerModule = (moduleUrl, label) => {
return new Worker(self.MonacoEnvironment.getWorkerUrl(moduleUrl), {
name: label,
type: 'module'
});
};
switch (label) {
case 'json':
return getWorkerModule('/monaco-editor/esm/vs/language/json/json.worker?worker', label);
case 'css':
case 'scss':
case 'less':
return getWorkerModule('/monaco-editor/esm/vs/language/css/css.worker?worker', label);
case 'html':
case 'handlebars':
case 'razor':
return getWorkerModule('/monaco-editor/esm/vs/language/html/html.worker?worker', label);
case 'typescript':
case 'javascript':
return getWorkerModule('/monaco-editor/esm/vs/language/typescript/ts.worker?worker', label);
default:
return getWorkerModule('/monaco-editor/esm/vs/editor/editor.worker?worker', label);
}
}
};
monaco.editor.create(document.getElementById('container'), {
value: "function hello() {\n\talert('Hello world!');\n}",
language: 'javascript'
});
```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

View file

@ -1,347 +0,0 @@
<svg host="65bd71144e" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="772px" height="562px" viewBox="-0.5 -0.5 772 562" content="&lt;mxfile&gt;&lt;diagram id=&quot;cU4r2CM7fKKh95v30pN0&quot; name=&quot;Page-1&quot;&gt;7Vvdc9o4EP9rmLnrDIzlL+AxIaV9aG4yk4e7PgosQFfb4mQRoH/9SZZkbEmEj5hAp3lprJW0lnb399NqTTvBKNt8oXC5eCQJSju+l2w6wUPH96Owz/8Vgq0UxEAJ5hQnUgR2gmf8Eymhp6QrnKCiMZARkjK8bAqnJM/RlDVkkFKybg6bkbT51iWcI0vwPIWpLf0bJ2whpQO/v5N/RXi+0G8G8VD2ZFAPVjspFjAh65oo+NwJRpQQJp+yzQilwnbaLnLeeE9vtTCKcnbMhFAt7AWmK7W5fJmVKqY/hBX8OOWK7ieUP83FU0ZyOCVdlGBGqNoE22rLrBeYoWc+WbTX3Pl8xoJlKW8B/viCKMPcjncpnudcxogYMMNpOiIpVxc85CTnU+/tfaitCQ1oUxOpfX1BJEOMbvmQjQ6qSE5RQQYiZfP1zmV+oMYsau7yh2ogVGEyr3TvLMkflDHLJpn8KwLN91I4QamcJpVoS/u1xSon1OyGEh5gqqlMUDMb2mD2T+35O3/2epFqPYgNe7qx1Y2cr1hM6no9zwNaIqcG/VALdrPLVmP6E6KY7xxRJdzrlYKs6FRtRYGAQTpHatRAisQmX/UcRSlk+KWJMpcX1NQngnO283jlOO1x05FyTWqW4ctqGS738qbysBtGgYUiVkwtcIj9f5PxUfcuVGCYcqsKU1soyXCSCB33FBX4J5yU+oQ/lmIn5d6i+0704PSQvwc3FTsqfQ0CcuGJx5Ef+oov3ugpDU09g8xmBTrRJzaXWU5AxWSFObf73ufnR6c7TsVc/0jQeU28RQfQdi6whkcCS5mdM0EVEKd58I5SuK0NUJG3H4pxE4q+FzXPoQPjA+AZ0SBXYMxuNX6iMyOkFhXfa123ESEAXIR7T40H0Df8O3zFv2f4Ln4F+3ePD7dBxVFbVOz1wjBqZjdRK7ysCUUp7V6CpvuWq/iMgtrH5YFcci8ijk8RB0a+ENsZItCZej1DjNtKEMdkxWXjFObzFc+2OYDGMEu6VfKgbTaobcNOHm8o6Q78wyb1XSYdnG7SQ0lZOGjlyL/iiT+0+TxoPZfeY13LnPZN0Rm/k1XOGZLz7hgVmeUASng3SpQRXIF7gSCsgutQEJ6Ba/sK7lmb/sWiTqcMjTQivFbY6dUcH3eCQTv9+wS9dHyu3stw3unbKcBVQjE4lg9bCUX/Vw/F8F1C8ayMNjIy2ujADccc33YGDOwaxCmVvO6UUGSFyw1lFkauFoaOXK3vABII20CSXVuoSMgoiI5vhXri6DD1gMGFqEenKccY7Gp5gmkhV55wMQuF18wT/FbYOXDkp/rTzqVrvZFR67VKintqvW+lef2eM2nbdQ381Et6cgk1/AxrSzr5xtcCNip+rQp4NjaGDmgEb77HOW/Kfb6ncUWrQkGNWStIgSsbDRjZXjh8L6PZ9HJuNfN2cr/AZpf2b7/nkYJBPlF4IPczxr9a3T6PRKpDtAqA4MbAEAXXA4Oz5ujORmS7RslXz0oczHuxrES/u2EpwwrFAi7F43RF0+095dcLAU+nOWoRtbOdaM1SvPyqnssofiIFZpiIWwSVW6puF9+M/qoGr6v1KZrVx9u1esKgmtsdCs8V8hclkqhacFkUhw2XxcDymOuOXyHkTR5z1UfkVS/BLw3Pxf+tSHkF5C6bl/7gt77ynnYnKHM++cMXXxXECVt/+LM0kjcjOevOYIbTrZzAFcJMeFmpHcFiChMMedeIJMjslvpGJC9IyjesDnJDBed/jDgMvb/Q2q2A45MUZZS1rW+3SxkfYo8ALDeyI8U56mrvlV1D1RVX+uS9Wpufa82d9t/3DlMRK7p5aUivVxa4ys9Z8m/XoC35RvEhpXxpcyEidRKhoKUGnnmQs8t9BoMrRhTehOqCUfIDGeUBR8VA2EiLEjSDq1RbTv0cDLSW6IIGdge+jd2onWPKxq7/m7Kt4xOo5cS9HvONA/Jd2dZVCPpg2yuyrSxy0pWgWkWRvwfrvQ1DoIkhV+ULXIr1IgeGPljv0DlleKwLov5RvBcGcQs+s39g88F7t8V7e1PCDxbch6kANO9tvs2C1e377SWK3a/6ZYln918jgs//Aw==&lt;/diagram&gt;&lt;/mxfile&gt;">
<defs/>
<g>
<rect x="535" y="130" width="235" height="290" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 233px; height: 1px; padding-top: 137px; margin-left: 536px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
npm package
<br/>
monaco-editor
</div>
</div>
</div>
</foreignObject>
<text x="653" y="149" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
npm package...
</text>
</switch>
</g>
<path d="M 120 170 L 233.41 169.92" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 238.66 169.92 L 231.66 173.43 L 233.41 169.92 L 231.66 166.43 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 170px; margin-left: 180px;">
<div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
tsc
</div>
</div>
</div>
</foreignObject>
<text x="180" y="174" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">
tsc
</text>
</switch>
</g>
<path d="M 120 185 L 170 185 Q 180 185 180 195 L 180 280 Q 180 290 190 290 L 233.63 290" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 238.88 290 L 231.88 293.5 L 233.63 290 L 231.88 286.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 240px; margin-left: 180px;">
<div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
esbuild ESM
</div>
</div>
</div>
</foreignObject>
<text x="180" y="243" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">
esbuild ESM
</text>
</switch>
</g>
<path d="M 90 200 L 90 360 Q 90 370 100 370 L 233.63 370" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 238.88 370 L 231.88 373.5 L 233.63 370 L 231.88 366.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 360px; margin-left: 181px;">
<div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
esbuild AMD
</div>
</div>
</div>
</foreignObject>
<text x="181" y="364" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">
esbuild AMD
</text>
</switch>
</g>
<rect x="0" y="140" width="120" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 170px; margin-left: 1px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
/src
</div>
</div>
</div>
</foreignObject>
<text x="60" y="174" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
/src
</text>
</switch>
</g>
<rect x="240" y="140" width="220" height="80" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 218px; height: 1px; padding-top: 147px; margin-left: 241px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
/out/languages/amd-tsc
</div>
</div>
</div>
</foreignObject>
<text x="350" y="159" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
/out/languages/amd-tsc
</text>
</switch>
</g>
<path d="M 460 290 L 563.63 290" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 568.88 290 L 561.88 293.5 L 563.63 290 L 561.88 286.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/>
<rect x="240" y="260" width="220" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 218px; height: 1px; padding-top: 290px; margin-left: 241px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
/out/languages/bundled/esm
</div>
</div>
</div>
</foreignObject>
<text x="350" y="294" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
/out/languages/bundled/esm
</text>
</switch>
</g>
<path d="M 460 370 L 563.63 370" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 568.88 370 L 561.88 373.5 L 563.63 370 L 561.88 366.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/>
<rect x="240" y="340" width="220" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 218px; height: 1px; padding-top: 370px; margin-left: 241px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
/out/languages/bundled/amd-{dev, min}
</div>
</div>
</div>
</foreignObject>
<text x="350" y="374" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
/out/languages/bundled/amd-{dev, min}
</text>
</switch>
</g>
<path d="M 130 485 L 480 485 Q 490 485 490 475 L 490 380 Q 490 370 500 370 L 563.63 370" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 568.88 370 L 561.88 373.5 L 563.63 370 L 561.88 366.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/>
<rect x="0" y="420" width="170" height="140" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 168px; height: 1px; padding-top: 427px; margin-left: 1px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
npm package
<br/>
monaco-editor-core
</div>
</div>
</div>
</foreignObject>
<text x="85" y="439" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
npm package...
</text>
</switch>
</g>
<rect x="570" y="340" width="180" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 370px; margin-left: 571px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
/out/monaco-editor/{dev, min}
</div>
</div>
</div>
</foreignObject>
<text x="660" y="374" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
/out/monaco-editor/{dev, min}
</text>
</switch>
</g>
<rect x="570" y="260" width="180" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 290px; margin-left: 571px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
/out/monaco-editor/esm
</div>
</div>
</div>
</foreignObject>
<text x="660" y="294" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
/out/monaco-editor/esm
</text>
</switch>
</g>
<path d="M 450 195 L 480 195 Q 490 195 500 195 L 563.63 195" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 568.88 195 L 561.88 198.5 L 563.63 195 L 561.88 191.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/>
<rect x="360" y="180" width="90" height="30" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 195px; margin-left: 361px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
*.d.ts
</div>
</div>
</div>
</foreignObject>
<text x="405" y="199" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
*.d.ts
</text>
</switch>
</g>
<rect x="40" y="470" width="90" height="30" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 485px; margin-left: 41px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
{/dev, /min}
</div>
</div>
</div>
</foreignObject>
<text x="85" y="489" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
{/dev, /min}
</text>
</switch>
</g>
<path d="M 130 525 L 500 525 Q 510 525 510 515 L 510 300 Q 510 290 520 290 L 563.63 290" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 568.88 290 L 561.88 293.5 L 563.63 290 L 561.88 286.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/>
<rect x="40" y="510" width="90" height="30" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 525px; margin-left: 41px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
esm
</div>
</div>
</div>
</foreignObject>
<text x="85" y="529" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
esm
</text>
</switch>
</g>
<rect x="570" y="180" width="180" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 210px; margin-left: 571px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
/out/monaco-editor/monaco.d.ts
</div>
</div>
</div>
</foreignObject>
<text x="660" y="214" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
/out/monaco-editor/monaco.d.ts
</text>
</switch>
</g>
<path d="M 504 41 L 499 41 Q 494 41 494 51 L 494 91 Q 494 101 489 101 L 486.5 101 Q 484 101 489 101 L 491.5 101 Q 494 101 494 111 L 494 151 Q 494 161 499 161 L 504 161" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" transform="translate(494,0)scale(-1,1)translate(-494,0)rotate(90,494,101)" pointer-events="all"/>
<rect x="361" y="62" width="250" height="30" fill="none" stroke="none" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 77px; margin-left: 486px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;">
<div style="background-color: rgb(255, 255, 255); font-family: &quot;Cascadia Code&quot;, Consolas, &quot;Courier New&quot;, monospace, Consolas, &quot;Courier New&quot;, monospace; font-size: 11px; line-height: 19px;">
<span style="font-size: 11px;">
ts-node ./build/build-monaco-editor
</span>
</div>
</div>
</div>
</div>
</foreignObject>
<text x="486" y="80" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">
ts-node ./build/build-monaco-editor
</text>
</switch>
</g>
<path d="M 190 41 L 185 41 Q 180 41 180 51 L 180 91 Q 180 101 175 101 L 172.5 101 Q 170 101 175 101 L 177.5 101 Q 180 101 180 111 L 180 151 Q 180 161 185 161 L 190 161" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" transform="translate(180,0)scale(-1,1)translate(-180,0)rotate(90,180,101)" pointer-events="all"/>
<rect x="130" y="60" width="110" height="30" fill="none" stroke="none" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 75px; margin-left: 185px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;">
<div style="background-color: rgb(255, 255, 255); font-family: &quot;Cascadia Code&quot;, Consolas, &quot;Courier New&quot;, monospace, Consolas, &quot;Courier New&quot;, monospace; font-size: 11px; line-height: 19px;">
npm run build
</div>
</div>
</div>
</div>
</foreignObject>
<text x="185" y="78" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">
npm run build
</text>
</switch>
</g>
<path d="M 350 -177 L 345 -177 Q 340 -177 340 -167 L 340 31 Q 340 41 335 41 L 332.5 41 Q 330 41 335 41 L 337.5 41 Q 340 41 340 51 L 340 249 Q 340 259 345 259 L 350 259" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" transform="translate(340,0)scale(-1,1)translate(-340,0)rotate(90,340,41)" pointer-events="all"/>
<rect x="234" y="0" width="200" height="30" fill="none" stroke="none" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 15px; margin-left: 334px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;">
<div style="background-color: rgb(255, 255, 255); font-family: &quot;Cascadia Code&quot;, Consolas, &quot;Courier New&quot;, monospace, Consolas, &quot;Courier New&quot;, monospace; font-size: 11px; line-height: 19px;">
npm run build-monaco-editor
</div>
</div>
</div>
</div>
</foreignObject>
<text x="334" y="18" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">
npm run build-monaco-editor
</text>
</switch>
</g>
</g>
<switch>
<g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/>
<a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank">
<text text-anchor="middle" font-size="10px" x="50%" y="100%">
Text is not SVG - cannot display
</text>
</a>
</switch>
</svg>

Before

Width:  |  Height:  |  Size: 31 KiB

View file

@ -1,13 +0,0 @@
{
"folders": [
{
"path": "../vscode"
},
{
"path": "../vscode-loc"
},
{
"path": "."
}
]
}

View file

@ -1,9 +1,781 @@
const gulp = require('gulp'); const gulp = require('gulp');
const metadata = require('./metadata');
const es = require('event-stream'); const es = require('event-stream');
const path = require('path'); const path = require('path');
const fs = require('fs'); const fs = require('fs');
const rimraf = require('rimraf'); const rimraf = require('rimraf');
const cp = require('child_process'); const cp = require('child_process');
const os = require('os');
const httpServer = require('http-server');
const typedoc = require("gulp-typedoc");
const CleanCSS = require('clean-css'); const CleanCSS = require('clean-css');
const uncss = require('uncss'); const uncss = require('uncss');
const File = require('vinyl'); const File = require('vinyl');
const ts = require('typescript');
const WEBSITE_GENERATED_PATH = path.join(__dirname, 'website/playground/new-samples');
const MONACO_EDITOR_VERSION = (function() {
const packageJsonPath = path.join(__dirname, 'package.json');
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath).toString());
const version = packageJson.version;
if (!/\d+\.\d+\.\d+/.test(version)) {
console.log('unrecognized package.json version: ' + version);
process.exit(0);
}
return version;
})();
gulp.task('clean-release', function(cb) { rimraf('release', { maxBusyTries: 1 }, cb); });
gulp.task('release', ['clean-release'], function() {
return es.merge(
// dev folder
releaseOne('dev'),
// min folder
releaseOne('min'),
// esm folder
ESM_release(),
// package.json
gulp.src('package.json')
.pipe(es.through(function(data) {
var json = JSON.parse(data.contents.toString());
json.private = false;
data.contents = new Buffer(JSON.stringify(json, null, ' '));
this.emit('data', data);
}))
.pipe(gulp.dest('release')),
gulp.src('CHANGELOG.md')
.pipe(gulp.dest('release')),
// min-maps folder
gulp.src('node_modules/monaco-editor-core/min-maps/**/*').pipe(gulp.dest('release/min-maps')),
// other files
gulp.src([
'node_modules/monaco-editor-core/LICENSE',
'node_modules/monaco-editor-core/monaco.d.ts',
'node_modules/monaco-editor-core/ThirdPartyNotices.txt',
'README.md'
])
.pipe(addPluginDTS())
.pipe(addPluginThirdPartyNotices())
.pipe(gulp.dest('release'))
)
});
/**
* Release to `dev` or `min`.
*/
function releaseOne(type) {
return es.merge(
gulp.src('node_modules/monaco-editor-core/' + type + '/**/*')
.pipe(addPluginContribs(type))
.pipe(gulp.dest('release/' + type)),
pluginStreams(type, 'release/' + type + '/')
)
}
/**
* Release plugins to `dev` or `min`.
*/
function pluginStreams(type, destinationPath) {
return es.merge(
metadata.METADATA.PLUGINS.map(function(plugin) {
return pluginStream(plugin, type, destinationPath);
})
);
}
/**
* Release a plugin to `dev` or `min`.
*/
function pluginStream(plugin, type, destinationPath) {
var pluginPath = plugin.paths[`npm/${type}`]; // npm/dev or npm/min
var contribPath = path.join(pluginPath, plugin.contrib.substr(plugin.modulePrefix.length)) + '.js';
return (
gulp.src([
pluginPath + '/**/*',
'!' + contribPath
])
.pipe(es.through(function(data) {
if (!/_\.contribution/.test(data.path)) {
this.emit('data', data);
return;
}
let contents = data.contents.toString();
contents = contents.replace('define(["require", "exports"],', 'define(["require", "exports", "vs/editor/editor.api"],');
data.contents = new Buffer(contents);
this.emit('data', data);
}))
.pipe(gulp.dest(destinationPath + plugin.modulePrefix))
);
}
/**
* Edit editor.main.js:
* - rename the AMD module 'vs/editor/editor.main' to 'vs/editor/edcore.main'
* - append monaco.contribution modules from plugins
* - append new AMD module 'vs/editor/editor.main' that stiches things together
*/
function addPluginContribs(type) {
return es.through(function(data) {
if (!/editor\.main\.js$/.test(data.path)) {
this.emit('data', data);
return;
}
var contents = data.contents.toString();
// Rename the AMD module 'vs/editor/editor.main' to 'vs/editor/edcore.main'
contents = contents.replace(/"vs\/editor\/editor\.main\"/, '"vs/editor/edcore.main"');
var extraContent = [];
var allPluginsModuleIds = [];
metadata.METADATA.PLUGINS.forEach(function(plugin) {
allPluginsModuleIds.push(plugin.contrib);
var pluginPath = plugin.paths[`npm/${type}`]; // npm/dev or npm/min
var contribPath = path.join(__dirname, pluginPath, plugin.contrib.substr(plugin.modulePrefix.length)) + '.js';
var contribContents = fs.readFileSync(contribPath).toString();
// Check for the anonymous define call case 1
// transform define(function() {...}) to define("moduleId",["require"],function() {...})
var anonymousContribDefineCase1 = contribContents.indexOf('define(function');
if (anonymousContribDefineCase1 >= 0) {
contribContents = (
contribContents.substring(0, anonymousContribDefineCase1)
+ `define("${plugin.contrib}",["require"],function`
+ contribContents.substring(anonymousContribDefineCase1 + 'define(function'.length)
);
}
// Check for the anonymous define call case 2
// transform define([ to define("moduleId",[
var anonymousContribDefineCase2 = contribContents.indexOf('define([');
if (anonymousContribDefineCase2 >= 0) {
contribContents = (
contribContents.substring(0, anonymousContribDefineCase2)
+ `define("${plugin.contrib}",[`
+ contribContents.substring(anonymousContribDefineCase2 + 'define(['.length)
);
}
var contribDefineIndex = contribContents.indexOf('define("' + plugin.contrib);
if (contribDefineIndex === -1) {
contribDefineIndex = contribContents.indexOf('define(\'' + plugin.contrib);
if (contribDefineIndex === -1) {
console.error('(1) CANNOT DETERMINE AMD define location for contribution', pluginPath);
process.exit(-1);
}
}
var depsEndIndex = contribContents.indexOf(']', contribDefineIndex);
if (contribDefineIndex === -1) {
console.error('(2) CANNOT DETERMINE AMD define location for contribution', pluginPath);
process.exit(-1);
}
contribContents = contribContents.substring(0, depsEndIndex) + ',"vs/editor/editor.api"' + contribContents.substring(depsEndIndex);
contribContents = contribContents.replace(
'define("vs/basic-languages/_.contribution",["require","exports"],',
'define("vs/basic-languages/_.contribution",["require","exports","vs/editor/editor.api"],',
);
extraContent.push(contribContents);
});
extraContent.push(`define("vs/editor/editor.main", ["vs/editor/edcore.main","${allPluginsModuleIds.join('","')}"], function(api) { return api; });`);
var insertIndex = contents.lastIndexOf('//# sourceMappingURL=');
if (insertIndex === -1) {
insertIndex = contents.length;
}
contents = contents.substring(0, insertIndex) + '\n' + extraContent.join('\n') + '\n' + contents.substring(insertIndex);
data.contents = new Buffer(contents);
this.emit('data', data);
});
}
function ESM_release() {
return es.merge(
gulp.src([
'node_modules/monaco-editor-core/esm/**/*',
// we will create our own editor.api.d.ts which also contains the plugins API
'!node_modules/monaco-editor-core/esm/vs/editor/editor.api.d.ts'
])
.pipe(ESM_addImportSuffix())
.pipe(ESM_addPluginContribs('release/esm'))
.pipe(gulp.dest('release/esm')),
ESM_pluginStreams('release/esm/')
)
}
/**
* Release plugins to `esm`.
*/
function ESM_pluginStreams(destinationPath) {
return es.merge(
metadata.METADATA.PLUGINS.map(function(plugin) {
return ESM_pluginStream(plugin, destinationPath);
})
);
}
/**
* 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_pluginStream(plugin, destinationPath) {
const DESTINATION = path.join(__dirname, destinationPath);
let pluginPath = plugin.paths[`esm`];
return (
gulp.src([
pluginPath + '/**/*'
])
.pipe(es.through(function(data) {
if (!/\.js$/.test(data.path)) {
this.emit('data', data);
return;
}
let contents = data.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 (!/(^\.\/)|(^\.\.\/)/.test(importText)) {
// non-relative import
if (!/^monaco-editor-core/.test(importText)) {
console.error(`Non-relative import for unknown module: ${importText} in ${data.path}`);
process.exit(0);
}
const myFileDestPath = path.join(DESTINATION, plugin.modulePrefix, data.relative);
const importFilePath = path.join(DESTINATION, importText.substr('monaco-editor-core/esm/'.length));
let relativePath = path.relative(path.dirname(myFileDestPath), importFilePath);
if (!/(^\.\/)|(^\.\.\/)/.test(relativePath)) {
relativePath = './' + relativePath;
}
contents = (
contents.substring(0, pos + 1)
+ relativePath
+ contents.substring(end + 1)
);
}
}
data.contents = new Buffer(contents);
this.emit('data', data);
}))
.pipe(es.through(function(data) {
if (!/monaco\.contribution\.js$/.test(data.path)) {
this.emit('data', data);
return;
}
const myFileDestPath = path.join(DESTINATION, plugin.modulePrefix, data.relative);
const apiFilePath = path.join(DESTINATION, 'vs/editor/editor.api');
let relativePath = path.relative(path.dirname(myFileDestPath), apiFilePath);
if (!/(^\.\/)|(^\.\.\/)/.test(relativePath)) {
relativePath = './' + relativePath;
}
let contents = data.contents.toString();
contents = (
`import '${relativePath}';\n` +
contents
);
data.contents = new Buffer(contents);
this.emit('data', data);
}))
.pipe(ESM_addImportSuffix())
.pipe(gulp.dest(destinationPath + plugin.modulePrefix))
);
}
function ESM_addImportSuffix() {
return es.through(function(data) {
if (!/\.js$/.test(data.path)) {
this.emit('data', data);
return;
}
let contents = data.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$/.test(importText)) {
continue;
}
contents = (
contents.substring(0, pos + 1)
+ importText + '.js'
+ contents.substring(end + 1)
);
}
data.contents = new Buffer(contents);
this.emit('data', data);
});
}
/**
* - 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(dest) {
const DESTINATION = path.join(__dirname, dest);
return es.through(function(data) {
if (!/editor\.main\.js$/.test(data.path)) {
this.emit('data', data);
return;
}
this.emit('data', new File({
path: data.path.replace(/editor\.main/, 'edcore.main'),
base: data.base,
contents: data.contents
}));
const mainFileDestPath = path.join(DESTINATION, 'vs/editor/editor.main.js');
let mainFileImports = [];
metadata.METADATA.PLUGINS.forEach(function(plugin) {
const contribDestPath = path.join(DESTINATION, plugin.contrib);
let relativePath = path.relative(path.dirname(mainFileDestPath), contribDestPath);
if (!/(^\.\/)|(^\.\.\/)/.test(relativePath)) {
relativePath = './' + relativePath;
}
mainFileImports.push(relativePath);
});
let mainFileContents = (
mainFileImports.map((name) => `import '${name}';`).join('\n')
+ `\n\nexport * from './edcore.main';`
);
this.emit('data', new File({
path: data.path,
base: data.base,
contents: new Buffer(mainFileContents)
}));
});
}
/**
* Edit monaco.d.ts:
* - append monaco.d.ts from plugins
*/
function addPluginDTS() {
return es.through(function(data) {
if (!/monaco\.d\.ts$/.test(data.path)) {
this.emit('data', data);
return;
}
var contents = data.contents.toString();
var extraContent = [];
metadata.METADATA.PLUGINS.forEach(function(plugin) {
var pluginPath = plugin.paths[`npm/min`]; // npm/dev or npm/min
var dtsPath = path.join(pluginPath, '../monaco.d.ts');
try {
let plugindts = fs.readFileSync(dtsPath).toString();
plugindts = plugindts.replace('declare module', 'declare namespace');
extraContent.push(plugindts);
} catch (err) {
return;
}
});
contents = [
'/*!-----------------------------------------------------------',
' * Copyright (c) Microsoft Corporation. All rights reserved.',
' * Type definitions for monaco-editor v'+MONACO_EDITOR_VERSION,
' * Released under the MIT license',
'*-----------------------------------------------------------*/',
].join('\n') + '\n' + contents + '\n' + extraContent.join('\n');
// Ensure consistent indentation and line endings
contents = cleanFile(contents);
data.contents = new Buffer(contents);
this.emit('data', new File({
path: path.join(path.dirname(data.path), 'esm/vs/editor/editor.api.d.ts'),
base: data.base,
contents: new Buffer(toExternalDTS(contents))
}));
fs.writeFileSync('website/playground/monaco.d.ts.txt', contents);
fs.writeFileSync('monaco.d.ts', contents);
this.emit('data', data);
});
}
function toExternalDTS(contents) {
let lines = contents.split('\n');
let killNextCloseCurlyBrace = false;
for (let i = 0; i < lines.length; i++) {
let 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 ');
}
}
return lines.join('\n');
}
/**
* Normalize line endings and ensure consistent 4 spaces indentation
*/
function cleanFile(contents) {
return contents.split(/\r\n|\r|\n/).map(function(line) {
var m = line.match(/^(\t+)/);
if (!m) {
return line;
}
var tabsCount = m[1].length;
var newIndent = '';
for (var i = 0; i < 4 * tabsCount; i++) {
newIndent += ' ';
}
return newIndent + line.substring(tabsCount);
}).join('\n');
}
/**
* Edit ThirdPartyNotices.txt:
* - append ThirdPartyNotices.txt from plugins
*/
function addPluginThirdPartyNotices() {
return es.through(function(data) {
if (!/ThirdPartyNotices\.txt$/.test(data.path)) {
this.emit('data', data);
return;
}
var contents = data.contents.toString();
var extraContent = [];
metadata.METADATA.PLUGINS.forEach(function(plugin) {
if (!plugin.thirdPartyNotices) {
return;
}
console.log('ADDING ThirdPartyNotices from ' + plugin.thirdPartyNotices);
var thirdPartyNoticeContent = fs.readFileSync(plugin.thirdPartyNotices).toString();
thirdPartyNoticeContent = thirdPartyNoticeContent.split('\n').slice(8).join('\n');
extraContent.push(thirdPartyNoticeContent);
});
contents += '\n' + extraContent.join('\n');
data.contents = new Buffer(contents);
this.emit('data', data);
});
}
// --- website
gulp.task('clean-website', function(cb) { rimraf('../monaco-editor-website', { maxBusyTries: 1 }, cb); });
gulp.task('website', ['clean-website'], function() {
const initialCWD = process.cwd();
function replaceWithRelativeResource(dataPath, contents, regex, callback) {
return contents.replace(regex, function(_, m0) {
var filePath = path.join(path.dirname(dataPath), m0);
return callback(m0, fs.readFileSync(filePath));
});
}
var waiting = 0;
var done = false;
return (
es.merge(
gulp.src([
'website/**/*',
'!website/typedoc-theme/**'
], { dot: true })
.pipe(es.through(function(data) {
if (!data.contents || !/\.(html)$/.test(data.path) || /new-samples/.test(data.path)) {
return this.emit('data', data);
}
var contents = data.contents.toString();
contents = contents.replace(/\.\.\/release\/dev/g, 'node_modules/monaco-editor/min');
contents = contents.replace(/{{version}}/g, MONACO_EDITOR_VERSION);
// contents = contents.replace('&copy; 2017 Microsoft', '&copy; 2017 Microsoft [' + builtTime + ']');
// Preload xhr contents
contents = replaceWithRelativeResource(data.path, contents, /<pre data-preload="([^"]+)".*/g, function(m0, fileContents) {
return (
'<pre data-preload="' + m0 + '" style="display:none">'
+ fileContents.toString('utf8')
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
+ '</pre>'
);
});
// Inline fork.png
contents = replaceWithRelativeResource(data.path, contents, /src="(\.\/fork.png)"/g, function(m0, fileContents) {
return (
'src="data:image/png;base64,' + fileContents.toString('base64') + '"'
);
});
var allCSS = '';
var tmpcontents = replaceWithRelativeResource(data.path, contents, /<link data-inline="yes-please" href="([^"]+)".*/g, function(m0, fileContents) {
allCSS += fileContents.toString('utf8');
return '';
});
tmpcontents = tmpcontents.replace(/<script.*/g, '');
tmpcontents = tmpcontents.replace(/<link.*/g, '');
waiting++;
uncss(tmpcontents, {
raw: allCSS,
ignore: [/\.alert\b/, /\.alert-error\b/, /\.playground-page\b/]
}, function(err, output) {
waiting--;
if (!err) {
output = new CleanCSS().minify(output).styles;
var isFirst = true;
contents = contents.replace(/<link data-inline="yes-please" href="([^"]+)".*/g, function(_, m0) {
if (isFirst) {
isFirst = false;
return '<style>' + output + '</style>';
}
return '';
});
}
// Inline javascript
contents = replaceWithRelativeResource(data.path, contents, /<script data-inline="yes-please" src="([^"]+)".*/g, function(m0, fileContents) {
return '<script>' + fileContents.toString('utf8') + '</script>';
});
data.contents = new Buffer(contents.split(/\r\n|\r|\n/).join('\n'));
this.emit('data', data);
if (done && waiting === 0) {
this.emit('end');
}
}.bind(this));
}, function() {
done = true;
if (waiting === 0) {
this.emit('end');
}
}))
.pipe(gulp.dest('../monaco-editor-website')),
// TypeDoc is silly and consumes the `exclude` option.
// This option does not make it to typescript compiler, which ends up including /node_modules/ .d.ts files.
// We work around this by changing the cwd... :O
gulp.src('monaco.d.ts')
.pipe(es.through(undefined, function() {
process.chdir(os.tmpdir());
this.emit('end');
}))
.pipe(typedoc({
mode: 'file',
out: path.join(__dirname, '../monaco-editor-website/api'),
includeDeclarations: true,
theme: path.join(__dirname, 'website/typedoc-theme'),
entryPoint: 'monaco',
name: 'Monaco Editor API v' + MONACO_EDITOR_VERSION,
readme: 'none',
hideGenerator: true
}))
.pipe(es.through(undefined, function() {
process.chdir(initialCWD);
this.emit('end');
}))
)
.pipe(es.through(function(data) {
this.emit('data', data);
}, function() {
// temporarily create package.json so that npm install doesn't bark
fs.writeFileSync('../monaco-editor-website/package.json', '{}');
fs.writeFileSync('../monaco-editor-website/.nojekyll', '');
cp.execSync('npm install monaco-editor', {
cwd: path.join(__dirname, '../monaco-editor-website')
});
fs.unlink('../monaco-editor-website/package.json');
cp.execSync('git init', {
cwd: path.join(__dirname, '../monaco-editor-website')
});
cp.execSync('git remote add origin https://github.com/Microsoft/monaco-editor.git', {
cwd: path.join(__dirname, '../monaco-editor-website')
});
cp.execSync('git checkout -b gh-pages', {
cwd: path.join(__dirname, '../monaco-editor-website')
});
cp.execSync('git add .', {
cwd: path.join(__dirname, '../monaco-editor-website')
});
cp.execSync('git commit -m "Publish website"', {
cwd: path.join(__dirname, '../monaco-editor-website')
});
console.log('RUN monaco-editor-website>git push origin gh-pages --force')
this.emit('end');
}))
);
});
gulp.task('generate-test-samples', function() {
var sampleNames = fs.readdirSync(path.join(__dirname, 'test/samples'));
var samples = sampleNames.map(function(sampleName) {
var samplePath = path.join(__dirname, 'test/samples', sampleName);
var sampleContent = fs.readFileSync(samplePath).toString();
return {
name: sampleName,
content: sampleContent
};
});
var prefix = '//This is a generated file via gulp generate-test-samples\ndefine([], function() { return';
var suffix = '; });'
fs.writeFileSync(path.join(__dirname, 'test/samples-all.generated.js'), prefix + JSON.stringify(samples, null, '\t') + suffix );
var PLAY_SAMPLES = require(path.join(WEBSITE_GENERATED_PATH, 'all.js')).PLAY_SAMPLES;
var locations = [];
for (var i = 0; i < PLAY_SAMPLES.length; i++) {
var sample = PLAY_SAMPLES[i];
var sampleId = sample.id;
var samplePath = path.join(WEBSITE_GENERATED_PATH, sample.path);
var html = fs.readFileSync(path.join(samplePath, 'sample.html'));
var js = fs.readFileSync(path.join(samplePath, 'sample.js'));
var css = fs.readFileSync(path.join(samplePath, 'sample.css'));
var result = [
'<!DOCTYPE html>',
'<!-- THIS IS A GENERATED FILE VIA gulp generate-test-samples -->',
'<html>',
'<head>',
' <base href="..">',
' <meta http-equiv="X-UA-Compatible" content="IE=edge" />',
' <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />',
'</head>',
'<body>',
'<style>',
'/*----------------------------------------SAMPLE CSS START*/',
'',
css,
'',
'/*----------------------------------------SAMPLE CSS END*/',
'</style>',
'<a class="loading-opts" href="playground.generated/index.html">[&lt;&lt; BACK]</a> <br/>',
'THIS IS A GENERATED FILE VIA gulp generate-test-samples',
'',
'<div id="bar" style="margin-bottom: 6px;"></div>',
'',
'<div style="clear:both"></div>',
'<div id="outer-container" style="width:800px;height:450px;border: 1px solid grey">',
'<!-- ----------------------------------------SAMPLE HTML START-->',
'',
html,
'',
'<!-- ----------------------------------------SAMPLE HTML END-->',
'</div>',
'<div style="clear:both"></div>',
'',
'<script src="../metadata.js"></script>',
'<script src="dev-setup.js"></script>',
'<script>',
'loadEditor(function() {',
'/*----------------------------------------SAMPLE JS START*/',
'',
js,
'',
'/*----------------------------------------SAMPLE CSS END*/',
'});',
'</script>',
'</body>',
'</html>',
];
fs.writeFileSync(path.join(__dirname, 'test/playground.generated/' + sampleId + '.html'), result.join('\n'));
locations.push({
path: sampleId + '.html',
name: sample.chapter + ' &gt; ' + sample.name
})
}
var index = [
'<!DOCTYPE html>',
'<!-- THIS IS A GENERATED FILE VIA gulp generate-test-samples -->',
'<html>',
'<head>',
' <base href="..">',
'</head>',
'<body>',
'<a class="loading-opts" href="index.html">[&lt;&lt; BACK]</a><br/>',
'THIS IS A GENERATED FILE VIA gulp generate-test-samples<br/><br/>',
locations.map(function(location) {
return '<a class="loading-opts" href="playground.generated/' + location.path + '">' + location.name + '</a>';
}).join('<br/>\n'),
'<script src="../metadata.js"></script>',
'<script src="dev-setup.js"></script>',
'</body>',
'</html>',
]
fs.writeFileSync(path.join(__dirname, 'test/playground.generated/index.html'), index.join('\n'));
});
gulp.task('simpleserver', ['generate-test-samples'], function(cb) {
httpServer.createServer({ root: '../', cache: 5 }).listen(8080);
httpServer.createServer({ root: '../', cache: 5 }).listen(8088);
console.log('LISTENING on 8080 and 8088');
});

82
metadata.js Normal file
View file

@ -0,0 +1,82 @@
(function () {
var METADATA = {
CORE: {
paths: {
src: '/vscode/out/vs',
'npm/dev': 'node_modules/monaco-editor-core/dev/vs',
'npm/min': 'node_modules/monaco-editor-core/min/vs',
built: '/vscode/out-monaco-editor-core/min/vs',
releaseDev: 'release/dev/vs',
releaseMin: 'release/min/vs',
}
},
PLUGINS: [
{
name: 'monaco-typescript',
contrib: 'vs/language/typescript/monaco.contribution',
modulePrefix: 'vs/language/typescript',
thirdPartyNotices: 'node_modules/monaco-typescript/ThirdPartyNotices.txt',
paths: {
src: '/monaco-typescript/release/dev',
'npm/dev': 'node_modules/monaco-typescript/release/dev',
'npm/min': 'node_modules/monaco-typescript/release/min',
esm: 'node_modules/monaco-typescript/release/esm',
}
},
{
name: 'monaco-css',
contrib: 'vs/language/css/monaco.contribution',
modulePrefix: 'vs/language/css',
paths: {
src: '/monaco-css/release/dev',
'npm/dev': 'node_modules/monaco-css/release/dev',
'npm/min': 'node_modules/monaco-css/release/min',
esm: 'node_modules/monaco-css/release/esm',
}
},
{
name: 'monaco-json',
contrib: 'vs/language/json/monaco.contribution',
modulePrefix: 'vs/language/json',
paths: {
src: '/monaco-json/release/dev',
'npm/dev': 'node_modules/monaco-json/release/dev',
'npm/min': 'node_modules/monaco-json/release/min',
esm: 'node_modules/monaco-json/release/esm',
}
},
{
name: 'monaco-html',
contrib: 'vs/language/html/monaco.contribution',
modulePrefix: 'vs/language/html',
thirdPartyNotices: 'node_modules/monaco-html/ThirdPartyNotices.txt',
paths: {
src: '/monaco-html/release/dev',
'npm/dev': 'node_modules/monaco-html/release/dev',
'npm/min': 'node_modules/monaco-html/release/min',
esm: 'node_modules/monaco-html/release/esm',
}
},
{
name: 'monaco-languages',
contrib: 'vs/basic-languages/monaco.contribution',
modulePrefix: 'vs/basic-languages',
thirdPartyNotices: 'node_modules/monaco-languages/ThirdPartyNotices.txt',
paths: {
src: '/monaco-languages/release/dev',
'npm/dev': 'node_modules/monaco-languages/release/dev',
'npm/min': 'node_modules/monaco-languages/release/min',
esm: 'node_modules/monaco-languages/release/esm',
}
}
]
}
if (typeof exports !== 'undefined') {
exports.METADATA = METADATA
} else {
self.METADATA = METADATA;
}
})();

View file

@ -1,5 +0,0 @@
# 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.

View file

@ -1,687 +0,0 @@
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();
}

File diff suppressed because it is too large Load diff

View file

@ -1,26 +0,0 @@
{
"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"
}
}

View file

@ -1,33 +0,0 @@
// @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
})
]
});

View file

@ -1,40 +0,0 @@
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;
}

View file

@ -1,254 +0,0 @@
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);
}
}

View file

@ -1,90 +0,0 @@
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;
}
}

View file

@ -1,13 +0,0 @@
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,
) { }
}

View file

@ -1,183 +0,0 @@
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,
}
};
}

View file

@ -1,169 +0,0 @@
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 };
}

View file

@ -1,90 +0,0 @@
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;
}
}

View file

@ -1,202 +0,0 @@
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,
};
}

View file

@ -1,60 +0,0 @@
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);
}
}

View file

@ -1,60 +0,0 @@
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);
}
}

View file

@ -1,208 +0,0 @@
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();
}
}

View file

@ -1,58 +0,0 @@
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),
}));
}
}

View file

@ -1,71 +0,0 @@
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;
}
}

View file

@ -1,101 +0,0 @@
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: [],
};
}

View file

@ -1,63 +0,0 @@
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),
}));
}
}

View file

@ -1,60 +0,0 @@
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,
}));
}
}

View file

@ -1,79 +0,0 @@
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 };
}

View file

@ -1,60 +0,0 @@
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);
}
}

View file

@ -1,212 +0,0 @@
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,
};
}

Some files were not shown because too many files have changed in this diff Show more