Merge branch 'main' into vite-example

This commit is contained in:
Remco Haszing 2021-11-15 17:05:21 +01:00
commit e0d2f4ade6
No known key found for this signature in database
GPG key ID: 40D9F5FE9155FD3C
15 changed files with 149 additions and 13004 deletions

View file

@ -42,16 +42,15 @@ jobs:
with: { node-version: 16 } with: { node-version: 16 }
- run: npm ci - run: npm ci
- run: npx tsc - run: npx tsc
# release:
release: # runs-on: ubuntu-latest
runs-on: ubuntu-latest # needs: [eslint, pack, prettier, tsc]
needs: [eslint, pack, prettier, tsc] # if: startsWith(github.ref, 'refs/tags/')
if: startsWith(github.ref, 'refs/tags/') # steps:
steps: # - uses: actions/checkout@v2
- uses: actions/checkout@v2 # - uses: actions/setup-node@v2
- uses: actions/setup-node@v2 # with: { node-version: 16 }
with: { node-version: 16 } # - run: npm ci
- run: npm ci # - run: npm publish
- run: npm publish # env:
env: # NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

1
.npmrc Normal file
View file

@ -0,0 +1 @@
lockfile-version = 3

View file

@ -85,7 +85,43 @@ editor.create(document.createElement('editor'), {
}); });
``` ```
Also make sure to register the web worker. Also make sure to register the web worker. When using Webpack 5, this looks like the code below.
Other bundlers may use a different syntax, but the idea is the same. Languages you dont used can be
omitted.
```js
window.MonacoEnvironment = {
getWorker(moduleId, label) {
switch (label) {
case 'editorWorkerService':
return new Worker(new URL('monaco-editor/esm/vs/editor/editor.worker', import.meta.url));
case 'css':
case 'less':
case 'scss':
return new Worker(new URL('monaco-editor/esm/vs/language/css/css.worker', import.meta.url));
case 'handlebars':
case 'html':
case 'razor':
return new Worker(
new URL('monaco-editor/esm/vs/language/html/html.worker', import.meta.url),
);
case 'json':
return new Worker(
new URL('monaco-editor/esm/vs/language/json/json.worker', import.meta.url),
);
case 'javascript':
case 'typescript':
return new Worker(
new URL('monaco-editor/esm/vs/language/typescript/ts.worker', import.meta.url),
);
case 'yaml':
return new Worker(new URL('monaco-yaml/lib/esm/yaml.worker', import.meta.url));
default:
throw new Error(`Unknown label ${label}`);
}
},
};
```
## Examples ## Examples
@ -96,6 +132,66 @@ A running example: ![demo-image](test-demo.png)
Some usage examples can be found in the Some usage examples can be found in the
[examples](https://github.com/remcohaszing/monaco-yaml/tree/main/examples) directory. [examples](https://github.com/remcohaszing/monaco-yaml/tree/main/examples) directory.
## FAQ
### Does this work with the Monaco UMD bundle?
No. Only ESM is supported.
### Does this work with Monaco Editor from a CDN?
No, because these use a UMD bundle, which isnt supported.
### Does this work with `@monaco-editor/loader` or `@monaco-editor/react`?
No. These packages pull in the Monaco UMD bundle from a CDN. Because UMD isnt supported, neither
are these packages.
### Is the web worker necessary?
Yes. The web worker provides the core functionality of `monaco-yaml`.
### Does it work without a bundler?
No. `monaco-yaml` uses dependencies from `node_modules`, so they can be deduped and your bundle size
is decreased. This comes at the cost of not being able to use it without a bundler.
### How do I integrate `monaco-yaml` with a framework? (Angular, React, Vue, etc.)
`monaco-yaml` only uses the Monaco Editor. Its not tied to a framework, all thats needed is a DOM
node to attach the Monaco Editor to. See the
[Monaco Editor examples](https://github.com/microsoft/monaco-editor/tree/main/monaco-editor-samples)
for examples on how to integrate Monaco Editor in your project, then configure `monaco-yaml` as
described above.
### Does `monaco-yaml` work with `create-react-app`?
Yes, but youll have to eject. See
[#92 (comment)](https://github.com/remcohaszing/monaco-yaml/issues/92#issuecomment-905836058) for
details.
### Why isnt `monaco-yaml` working? Official Monaco language extensions do work.
This is most likely due to the fact that `monaco-yaml` is using a different instance of the
`monaco-editor` package than you are. This is something youll want to avoid regardless of
`monaco-editor`, because it means your bundle is significantly larger than it needs to be. This is
likely caused by one of the following issues:
- A code splitting misconfiguration
To solve this, try inspecting your bundle using for example
[webpack-bundle-analyzer](https://github.com/webpack-contrib/webpack-bundle-analyzer). If
`monaco-editor` is in there twice, this is the issue. Its up to you to solve this, as its
project-specific.
- Youre using a package which imports `monaco-editor` for you, but its using a different version.
You can find out why the `monaco-editor` is installed using `npm ls monaco-editor` or
`yarn why monaco-editor`. It should exist only once, but its ok if its deduped.
You may be able to solve this by deleting your `node_modules` folder and `package-lock.json` or
`yarn.lock`, then running `npm install` or `yarn install` respectively.
## Contributing ## Contributing
Please see our [contributing guidelines](CONTRIBUTING.md) Please see our [contributing guidelines](CONTRIBUTING.md)

View file

@ -13,7 +13,7 @@
"css-minimizer-webpack-plugin": "^3.0.0", "css-minimizer-webpack-plugin": "^3.0.0",
"html-webpack-plugin": "^5.0.0", "html-webpack-plugin": "^5.0.0",
"mini-css-extract-plugin": "^2.0.0", "mini-css-extract-plugin": "^2.0.0",
"monaco-editor": "^0.27.0", "monaco-editor": "^0.30.0",
"monaco-yaml": "file:../..", "monaco-yaml": "file:../..",
"ts-loader": "^9.0.0", "ts-loader": "^9.0.0",
"typescript": "^4.0.0", "typescript": "^4.0.0",

View file

@ -152,7 +152,10 @@ fetch('https://www.schemastore.org/api/json/catalog.json').then(async (response)
}); });
select.addEventListener('change', () => { select.addEventListener('change', () => {
ed.setModel(editor.createModel(ed.getValue(), 'yaml', Uri.parse(select.value))); const oldModel = ed.getModel();
const newModel = editor.createModel(oldModel.getValue(), 'yaml', Uri.parse(select.value));
ed.setModel(newModel);
oldModel.dispose();
}); });
function* iterateSymbols( function* iterateSymbols(

View file

@ -6,6 +6,7 @@ module.exports = {
output: { output: {
filename: '[contenthash].js', filename: '[contenthash].js',
}, },
devtool: 'source-map',
resolve: { resolve: {
extensions: ['.mjs', '.js', '.ts'], extensions: ['.mjs', '.js', '.ts'],
fallback: { fallback: {

View file

@ -7,8 +7,8 @@
"build": "vite build" "build": "vite build"
}, },
"dependencies": { "dependencies": {
"monaco-editor": "^0.27.0", "monaco-editor": "^0.30.0",
"monaco-yaml": "file:../..", "monaco-yaml": "file:../..",
"vite": "^2.0.8" "vite": "^2.0.0"
} }
} }

12933
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
{ {
"name": "monaco-yaml", "name": "monaco-yaml",
"version": "3.2.1", "version": "4.0.0-alpha.0",
"description": "YAML plugin for the Monaco Editor", "description": "YAML plugin for the Monaco Editor",
"homepage": "https://monaco-yaml.js.org", "homepage": "https://monaco-yaml.js.org",
"scripts": { "scripts": {
@ -47,7 +47,7 @@
"yaml-language-server-parser": "^0.1.0" "yaml-language-server-parser": "^0.1.0"
}, },
"peerDependencies": { "peerDependencies": {
"monaco-editor": ">=0.22" "monaco-editor": ">=0.30"
}, },
"devDependencies": { "devDependencies": {
"@typescript-eslint/eslint-plugin": "^4.0.0", "@typescript-eslint/eslint-plugin": "^4.0.0",
@ -57,7 +57,7 @@
"eslint-config-remcohaszing": "^3.0.0", "eslint-config-remcohaszing": "^3.0.0",
"husky": "^7.0.0", "husky": "^7.0.0",
"lint-staged": "^11.0.0", "lint-staged": "^11.0.0",
"monaco-editor": "^0.27.0", "monaco-editor": "^0.30.0",
"type-fest": "^2.0.0", "type-fest": "^2.0.0",
"typescript": "^4.0.0", "typescript": "^4.0.0",
"yaml-language-server": "^0.22.0" "yaml-language-server": "^0.22.0"

1
src/constants.ts Normal file
View file

@ -0,0 +1 @@
export const languageId = 'yaml';

View file

@ -1,7 +1,6 @@
import { import {
editor, editor,
IDisposable, IDisposable,
IMarkdownString,
languages, languages,
MarkerSeverity, MarkerSeverity,
Position, Position,
@ -11,6 +10,7 @@ import {
import * as ls from 'vscode-languageserver-types'; import * as ls from 'vscode-languageserver-types';
import { CustomFormatterOptions } from 'yaml-language-server/lib/esm/languageservice/yamlLanguageService'; import { CustomFormatterOptions } from 'yaml-language-server/lib/esm/languageservice/yamlLanguageService';
import { languageId } from './constants';
import { YAMLWorker } from './yamlWorker'; import { YAMLWorker } from './yamlWorker';
export type WorkerAccessor = (...more: Uri[]) => PromiseLike<YAMLWorker>; export type WorkerAccessor = (...more: Uri[]) => PromiseLike<YAMLWorker>;
@ -46,7 +46,6 @@ function toDiagnostics(diag: ls.Diagnostic): editor.IMarkerData {
} }
export function createDiagnosticsAdapter( export function createDiagnosticsAdapter(
languageId: string,
getWorker: WorkerAccessor, getWorker: WorkerAccessor,
defaults: languages.yaml.LanguageServiceDefaults, defaults: languages.yaml.LanguageServiceDefaults,
): void { ): void {
@ -57,21 +56,20 @@ export function createDiagnosticsAdapter(
worker.resetSchema(String(resource)); worker.resetSchema(String(resource));
}; };
const doValidate = async (resource: Uri, languageId: string): Promise<void> => { const doValidate = async (resource: Uri): Promise<void> => {
const worker = await getWorker(resource); const worker = await getWorker(resource);
const diagnostics = await worker.doValidation(String(resource)); const diagnostics = await worker.doValidation(String(resource));
const markers = diagnostics.map(toDiagnostics); const markers = diagnostics.map(toDiagnostics);
const model = editor.getModel(resource); const model = editor.getModel(resource);
// Return value from getModel can be null if model not found // Return value from getModel can be null if model not found
// (e.g. if user navigates away from editor) // (e.g. if user navigates away from editor)
if (model && model.getModeId() === languageId) { if (model && model.getLanguageId() === languageId) {
editor.setModelMarkers(model, languageId, markers); editor.setModelMarkers(model, languageId, markers);
} }
}; };
const onModelAdd = (model: editor.IModel): void => { const onModelAdd = (model: editor.IModel): void => {
const modeId = model.getModeId(); if (model.getLanguageId() !== languageId) {
if (modeId !== languageId) {
return; return;
} }
@ -80,11 +78,11 @@ export function createDiagnosticsAdapter(
String(model.uri), String(model.uri),
model.onDidChangeContent(() => { model.onDidChangeContent(() => {
clearTimeout(handle); clearTimeout(handle);
handle = setTimeout(() => doValidate(model.uri, modeId), 500); handle = setTimeout(() => doValidate(model.uri), 500);
}), }),
); );
doValidate(model.uri, modeId); doValidate(model.uri);
}; };
const onModelRemoved = (model: editor.IModel): void => { const onModelRemoved = (model: editor.IModel): void => {
@ -109,7 +107,7 @@ export function createDiagnosticsAdapter(
}); });
defaults.onDidChange(() => { defaults.onDidChange(() => {
for (const model of editor.getModels()) { for (const model of editor.getModels()) {
if (model.getModeId() === languageId) { if (model.getLanguageId() === languageId) {
onModelRemoved(model); onModelRemoved(model);
onModelAdd(model); onModelAdd(model);
} }
@ -254,42 +252,6 @@ export function createCompletionItemProvider(
}; };
} }
function isMarkupContent(thing: unknown): thing is ls.MarkupContent {
return thing && typeof thing === 'object' && typeof (thing as ls.MarkupContent).kind === 'string';
}
function toMarkdownString(entry: ls.MarkedString | ls.MarkupContent): IMarkdownString {
if (typeof entry === 'string') {
return {
value: entry,
};
}
if (isMarkupContent(entry)) {
if (entry.kind === 'plaintext') {
return {
value: entry.value.replace(/[!#()*+.[\\\]_`{}-]/g, '\\$&'),
};
}
return {
value: entry.value,
};
}
return { value: `\`\`\`${entry.language}\n${entry.value}\n\`\`\`\n` };
}
function toMarkedStringArray(
contents: ls.MarkedString | ls.MarkedString[] | ls.MarkupContent,
): IMarkdownString[] {
if (!contents) {
return;
}
if (Array.isArray(contents)) {
return contents.map(toMarkdownString);
}
return [toMarkdownString(contents)];
}
// --- hover ------ // --- hover ------
export function createHoverProvider(getWorker: WorkerAccessor): languages.HoverProvider { export function createHoverProvider(getWorker: WorkerAccessor): languages.HoverProvider {
@ -304,7 +266,7 @@ export function createHoverProvider(getWorker: WorkerAccessor): languages.HoverP
} }
return { return {
range: toRange(info.range), range: toRange(info.range),
contents: toMarkedStringArray(info.contents), contents: [{ value: (info.contents as ls.MarkupContent).value }],
}; };
}, },
}; };

View file

@ -1,11 +1,11 @@
import { Emitter, languages } from 'monaco-editor/esm/vs/editor/editor.api'; import { Emitter, languages } from 'monaco-editor/esm/vs/editor/editor.api';
import { languageId } from './constants';
import { setupMode } from './yamlMode'; import { setupMode } from './yamlMode';
// --- YAML configuration and defaults --------- // --- YAML configuration and defaults ---------
export function createLanguageServiceDefaults( export function createLanguageServiceDefaults(
languageId: string,
initialDiagnosticsOptions: languages.yaml.DiagnosticsOptions, initialDiagnosticsOptions: languages.yaml.DiagnosticsOptions,
): languages.yaml.LanguageServiceDefaults { ): languages.yaml.LanguageServiceDefaults {
const onDidChange = new Emitter<languages.yaml.LanguageServiceDefaults>(); const onDidChange = new Emitter<languages.yaml.LanguageServiceDefaults>();
@ -39,7 +39,7 @@ const diagnosticDefault: languages.yaml.DiagnosticsOptions = {
enableSchemaRequest: false, enableSchemaRequest: false,
}; };
const yamlDefaults = createLanguageServiceDefaults('yaml', diagnosticDefault); const yamlDefaults = createLanguageServiceDefaults(diagnosticDefault);
// Export API // Export API
function createAPI(): typeof languages.yaml { function createAPI(): typeof languages.yaml {
@ -52,7 +52,7 @@ languages.yaml = createAPI();
// --- Registration to monaco editor --- // --- Registration to monaco editor ---
languages.register({ languages.register({
id: 'yaml', id: languageId,
extensions: ['.yaml', '.yml'], extensions: ['.yaml', '.yml'],
aliases: ['YAML', 'yaml', 'YML', 'yml'], aliases: ['YAML', 'yaml', 'YML', 'yml'],
mimetypes: ['application/x-yaml'], mimetypes: ['application/x-yaml'],

View file

@ -47,7 +47,6 @@ export function createWorkerManager(
// Passed in to the create() method // Passed in to the create() method
createData: { createData: {
languageSettings: defaults.diagnosticsOptions, languageSettings: defaults.diagnosticsOptions,
languageId: defaults.languageId,
enableSchemaRequest: defaults.diagnosticsOptions.enableSchemaRequest, enableSchemaRequest: defaults.diagnosticsOptions.enableSchemaRequest,
prefix: defaults.diagnosticsOptions.prefix, prefix: defaults.diagnosticsOptions.prefix,
isKubernetes: defaults.diagnosticsOptions.isKubernetes, isKubernetes: defaults.diagnosticsOptions.isKubernetes,

View file

@ -1,5 +1,6 @@
import { languages } from 'monaco-editor/esm/vs/editor/editor.api'; import { languages } from 'monaco-editor/esm/vs/editor/editor.api';
import { languageId } from './constants';
import { import {
createCompletionItemProvider, createCompletionItemProvider,
createDiagnosticsAdapter, createDiagnosticsAdapter,
@ -45,8 +46,6 @@ const richEditConfiguration: languages.LanguageConfiguration = {
export function setupMode(defaults: languages.yaml.LanguageServiceDefaults): void { export function setupMode(defaults: languages.yaml.LanguageServiceDefaults): void {
const worker = createWorkerManager(defaults); const worker = createWorkerManager(defaults);
const { languageId } = defaults;
languages.registerCompletionItemProvider(languageId, createCompletionItemProvider(worker)); languages.registerCompletionItemProvider(languageId, createCompletionItemProvider(worker));
languages.registerHoverProvider(languageId, createHoverProvider(worker)); languages.registerHoverProvider(languageId, createHoverProvider(worker));
languages.registerDocumentSymbolProvider(languageId, createDocumentSymbolProvider(worker)); languages.registerDocumentSymbolProvider(languageId, createDocumentSymbolProvider(worker));
@ -55,6 +54,6 @@ export function setupMode(defaults: languages.yaml.LanguageServiceDefaults): voi
createDocumentFormattingEditProvider(worker), createDocumentFormattingEditProvider(worker),
); );
languages.registerLinkProvider(languageId, createLinkProvider(worker)); languages.registerLinkProvider(languageId, createLinkProvider(worker));
createDiagnosticsAdapter(languageId, worker, defaults); createDiagnosticsAdapter(worker, defaults);
languages.setLanguageConfiguration(languageId, richEditConfiguration); languages.setLanguageConfiguration(languageId, richEditConfiguration);
} }

View file

@ -8,6 +8,8 @@ import {
LanguageSettings, LanguageSettings,
} from 'yaml-language-server/lib/esm/languageservice/yamlLanguageService'; } from 'yaml-language-server/lib/esm/languageservice/yamlLanguageService';
import { languageId } from './constants';
let defaultSchemaRequestService: (url: string) => Promise<string>; let defaultSchemaRequestService: (url: string) => Promise<string>;
if (typeof fetch !== 'undefined') { if (typeof fetch !== 'undefined') {
@ -32,13 +34,7 @@ export interface YAMLWorker {
export function createYAMLWorker( export function createYAMLWorker(
ctx: worker.IWorkerContext, ctx: worker.IWorkerContext,
{ { enableSchemaRequest, isKubernetes = false, languageSettings, prefix = '' }: ICreateData,
enableSchemaRequest,
isKubernetes = false,
languageId,
languageSettings,
prefix = '',
}: ICreateData,
): YAMLWorker { ): YAMLWorker {
const service = (url: string): Promise<string> => defaultSchemaRequestService(`${prefix}${url}`); const service = (url: string): Promise<string> => defaultSchemaRequestService(`${prefix}${url}`);
const languageService = getLanguageService(enableSchemaRequest && service, null, null, null); const languageService = getLanguageService(enableSchemaRequest && service, null, null, null);
@ -99,7 +95,6 @@ export function createYAMLWorker(
} }
export interface ICreateData { export interface ICreateData {
languageId: string;
languageSettings: LanguageSettings; languageSettings: LanguageSettings;
enableSchemaRequest: boolean; enableSchemaRequest: boolean;
prefix?: string; prefix?: string;