Commit f56761e0 authored by Himanshu Kapoor's avatar Himanshu Kapoor Committed by Illya Klymov

Add support for linting based on schemas in WebIDE

This allows us to lint our .gitlab-ci.yml file and other yaml
files in general
parent 1c9315e3
......@@ -8,9 +8,10 @@ import ModelManager from './common/model_manager';
import { editorOptions, defaultEditorOptions, defaultDiffEditorOptions } from './editor_options';
import { themes } from './themes';
import languages from './languages';
import schemas from './schemas';
import keymap from './keymap.json';
import { clearDomElement } from '~/editor/utils';
import { registerLanguages } from '../utils';
import { registerLanguages, registerSchemas } from '../utils';
function setupThemes() {
themes.forEach(theme => {
......@@ -44,6 +45,7 @@ export default class Editor {
setupThemes();
registerLanguages(...languages);
registerSchemas(...schemas);
this.debouncedUpdate = debounce(() => {
this.updateDimensions();
......
import json from './json';
import yaml from './yaml';
export default [json, yaml];
export default {
language: 'json',
options: {
validate: true,
enableSchemaRequest: true,
schemas: [],
},
};
export default {
uri: 'https://json.schemastore.org/gitlab-ci',
fileMatch: ['*.gitlab-ci.yml'],
};
import gitlabCi from './gitlab_ci';
export default {
language: 'yaml',
options: {
validate: true,
enableSchemaRequest: true,
hover: true,
completion: true,
schemas: [gitlabCi],
},
};
......@@ -66,7 +66,7 @@ export const trimPathComponents = path =>
.join('/');
export function registerLanguages(def, ...defs) {
if (defs.length) defs.forEach(lang => registerLanguages(lang));
defs.forEach(lang => registerLanguages(lang));
const languageId = def.id;
......@@ -75,6 +75,19 @@ export function registerLanguages(def, ...defs) {
languages.setLanguageConfiguration(languageId, def.conf);
}
export function registerSchemas({ language, options }, ...schemas) {
schemas.forEach(schema => registerSchemas(schema));
const defaults = {
json: languages.json.jsonDefaults,
yaml: languages.yaml.yamlDefaults,
};
if (defaults[language]) {
defaults[language].setDiagnosticsOptions(options);
}
}
export const otherSide = side => (side === SIDE_RIGHT ? SIDE_LEFT : SIDE_RIGHT);
export function trimTrailingWhitespace(content) {
......
---
title: Add support for linting based on schemas in WebIDE
merge_request: 35838
author:
type: added
const { languagesArr } = require('monaco-editor-webpack-plugin/out/languages');
// monaco-yaml library doesn't play so well with monaco-editor-webpack-plugin
// so the only way to include its workers is by patching the list of languages
// in monaco-editor-webpack-plugin and adding support for yaml workers. This is
// a known issue in the library and this workaround was suggested here:
// https://github.com/pengx17/monaco-yaml/issues/20
const yamlLang = languagesArr.find(t => t.label === 'yaml');
yamlLang.entry = [yamlLang.entry, '../../monaco-yaml/esm/monaco.contribution'];
yamlLang.worker = {
id: 'vs/language/yaml/yamlWorker',
entry: '../../monaco-yaml/esm/yaml.worker.js',
};
module.exports = require('monaco-editor-webpack-plugin');
......@@ -5,7 +5,7 @@ const webpack = require('webpack');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const StatsWriterPlugin = require('webpack-stats-plugin').StatsWriterPlugin;
const CompressionPlugin = require('compression-webpack-plugin');
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
const MonacoWebpackPlugin = require('./plugins/monaco_webpack');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const CopyWebpackPlugin = require('copy-webpack-plugin');
const vendorDllHash = require('./helpers/vendor_dll_hash');
......@@ -241,7 +241,7 @@ module.exports = {
},
{
test: /\.(eot|ttf|woff|woff2)$/,
include: /node_modules\/katex\/dist\/fonts/,
include: /node_modules\/(katex\/dist\/fonts|monaco-editor)/,
loader: 'file-loader',
options: {
name: '[name].[contenthash:8].[ext]',
......
......@@ -82,7 +82,9 @@ module.exports = path => {
'^.+\\.js$': 'babel-jest',
'^.+\\.vue$': 'vue-jest',
},
transformIgnorePatterns: ['node_modules/(?!(@gitlab/ui|bootstrap-vue|three|monaco-editor)/)'],
transformIgnorePatterns: [
'node_modules/(?!(@gitlab/ui|bootstrap-vue|three|monaco-editor|monaco-yaml)/)',
],
timers: 'fake',
testEnvironment: '<rootDir>/spec/frontend/environment.js',
testEnvironmentOptions: {
......
......@@ -97,6 +97,7 @@
"jquery.caret": "^0.3.1",
"jquery.waitforimages": "^2.2.0",
"js-cookie": "^2.2.1",
"js-yaml": "^3.13.1",
"jszip": "^3.1.3",
"jszip-utils": "^0.0.2",
"katex": "^0.10.0",
......@@ -105,8 +106,9 @@
"mermaid": "^8.5.2",
"mersenne-twister": "1.1.0",
"minimatch": "^3.0.4",
"monaco-editor": "^0.18.1",
"monaco-editor-webpack-plugin": "^1.7.0",
"monaco-editor": "^0.20.0",
"monaco-editor-webpack-plugin": "^1.9.0",
"monaco-yaml": "^2.4.0",
"mousetrap": "^1.4.6",
"pdfjs-dist": "^2.0.943",
"pikaday": "^1.8.0",
......@@ -220,7 +222,7 @@
},
"resolutions": {
"chokidar": "^3.4.0",
"monaco-editor": "0.18.1",
"monaco-editor": "0.20.0",
"vue-jest/ts-jest": "24.0.0"
},
"engines": {
......
......@@ -8,9 +8,11 @@ import 'monaco-editor/esm/vs/language/css/monaco.contribution';
import 'monaco-editor/esm/vs/language/json/monaco.contribution';
import 'monaco-editor/esm/vs/language/html/monaco.contribution';
import 'monaco-editor/esm/vs/basic-languages/monaco.contribution';
import 'monaco-yaml/esm/monaco.contribution';
// This language starts trying to spin up web workers which obviously breaks in Jest environment
jest.mock('monaco-editor/esm/vs/language/typescript/tsMode');
jest.mock('monaco-yaml/esm/yamlMode');
export * from 'monaco-editor/esm/vs/editor/editor.api';
export default global.monaco;
......@@ -637,6 +637,8 @@ describe('RepoEditor', () => {
// set cursor to line 2, column 1
vm.editor.instance.setSelection(new Range(2, 1, 2, 1));
vm.editor.instance.focus();
jest.spyOn(vm.editor.instance, 'hasTextFocus').mockReturnValue(true);
});
});
......
......@@ -199,6 +199,14 @@ describe('Multi-file editor library', () => {
});
});
describe('schemas', () => {
it('registers custom schemas defined with Monaco', () => {
expect(monacoLanguages.yaml.yamlDefaults.diagnosticsOptions).toMatchObject({
schemas: [{ fileMatch: ['*.gitlab-ci.yml'] }],
});
});
});
describe('replaceSelectedText', () => {
let model;
let editor;
......
import {
isTextFile,
registerLanguages,
registerSchemas,
trimPathComponents,
insertFinalNewline,
trimTrailingWhitespace,
......@@ -158,6 +159,57 @@ describe('WebIDE utils', () => {
});
});
describe('registerSchemas', () => {
let options;
beforeEach(() => {
options = {
validate: true,
enableSchemaRequest: true,
hover: true,
completion: true,
schemas: [
{
uri: 'http://myserver/foo-schema.json',
fileMatch: ['*'],
schema: {
id: 'http://myserver/foo-schema.json',
type: 'object',
properties: {
p1: { enum: ['v1', 'v2'] },
p2: { $ref: 'http://myserver/bar-schema.json' },
},
},
},
{
uri: 'http://myserver/bar-schema.json',
schema: {
id: 'http://myserver/bar-schema.json',
type: 'object',
properties: { q1: { enum: ['x1', 'x2'] } },
},
},
],
};
jest.spyOn(languages.json.jsonDefaults, 'setDiagnosticsOptions');
jest.spyOn(languages.yaml.yamlDefaults, 'setDiagnosticsOptions');
});
it.each`
language | defaultsObj
${'json'} | ${languages.json.jsonDefaults}
${'yaml'} | ${languages.yaml.yamlDefaults}
`(
'registers the given schemas with monaco for lang: $language',
({ language, defaultsObj }) => {
registerSchemas({ language, options });
expect(defaultsObj.setDiagnosticsOptions).toHaveBeenCalledWith(options);
},
);
});
describe('trimTrailingWhitespace', () => {
it.each`
input | output
......
......@@ -1171,11 +1171,6 @@
dependencies:
"@toast-ui/editor" "^2.2.0"
"@types/anymatch@*":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.0.tgz#d1d55958d1fccc5527d4aba29fc9c4b942f563ff"
integrity sha512-7WcbyctkE8GTzogDb0ulRAEw7v8oIS54ft9mQTU7PfM0hp5e+8kpa+HeQ7IQrFbKtJXBKcZ4bh+Em9dTw5L6AQ==
"@types/babel__core@^7.1.0":
version "7.1.2"
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.2.tgz#608c74f55928033fce18b99b213c16be4b3d114f"
......@@ -1285,11 +1280,6 @@
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e"
integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==
"@types/tapable@*":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.4.tgz#b4ffc7dc97b498c969b360a41eee247f82616370"
integrity sha512-78AdXtlhpCHT0K3EytMpn4JNxaf5tbqbLcbIRoQIHzpTIyjpxLQKRoxU55ujBXAtg3Nl2h/XWvfDa9dsMOd0pQ==
"@types/tern@*":
version "0.23.3"
resolved "https://registry.yarnpkg.com/@types/tern/-/tern-0.23.3.tgz#4b54538f04a88c9ff79de1f6f94f575a7f339460"
......@@ -1297,13 +1287,6 @@
dependencies:
"@types/estree" "*"
"@types/uglify-js@*":
version "3.0.4"
resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.0.4.tgz#96beae23df6f561862a830b4288a49e86baac082"
integrity sha512-SudIN9TRJ+v8g5pTG8RRCqfqTMNqgWCKKd3vtynhGzkIIjxaicNAMuY5TRadJ6tzDu3Dotf3ngaMILtmOdmWEQ==
dependencies:
source-map "^0.6.1"
"@types/unist@*", "@types/unist@^2.0.0":
version "2.0.3"
resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.3.tgz#9c088679876f374eb5983f150d4787aa6fb32d7e"
......@@ -1326,17 +1309,6 @@
"@types/unist" "*"
"@types/vfile-message" "*"
"@types/webpack@^4.4.19":
version "4.4.23"
resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.4.23.tgz#059d6f4598cfd65ddee0e2db38317ef989696712"
integrity sha512-WswyG+2mRg0ul/ytPpCSWo+kOlVVPW/fKCBEVwqmPVC/2ffWEwhsCEQgnFbWDf8EWId2qGcpL623EjLfNTRk9A==
dependencies:
"@types/anymatch" "*"
"@types/node" "*"
"@types/tapable" "*"
"@types/uglify-js" "*"
source-map "^0.6.0"
"@types/yargs-parser@*":
version "15.0.0"
resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d"
......@@ -8252,17 +8224,24 @@ moment-mini@^2.22.1:
resolved "https://registry.yarnpkg.com/moment-mini/-/moment-mini-2.22.1.tgz#bc32d73e43a4505070be6b53494b17623183420d"
integrity sha512-OUCkHOz7ehtNMYuZjNciXUfwTuz8vmF1MTbAy59ebf+ZBYZO5/tZKuChVWCX+uDo+4idJBpGltNfV8st+HwsGw==
monaco-editor-webpack-plugin@^1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/monaco-editor-webpack-plugin/-/monaco-editor-webpack-plugin-1.7.0.tgz#920cbeecca25f15d70d568a7e11b0ba4daf1ae83"
integrity sha512-oItymcnlL14Sjd7EF7q+CMhucfwR/2BxsqrXIBrWL6LQplFfAfV+grLEQRmVHeGSBZ/Gk9ptzfueXnWcoEcFuA==
monaco-editor-webpack-plugin@^1.9.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/monaco-editor-webpack-plugin/-/monaco-editor-webpack-plugin-1.9.0.tgz#5b547281b9f404057dc5d8c5722390df9ac90be6"
integrity sha512-tOiiToc94E1sb50BgZ8q8WK/bxus77SRrwCqIpAB5er3cpX78SULbEBY4YPOB8kDolOzKRt30WIHG/D6gz69Ww==
dependencies:
"@types/webpack" "^4.4.19"
loader-utils "^1.2.3"
monaco-editor@0.18.1, monaco-editor@^0.18.1:
version "0.18.1"
resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.18.1.tgz#ced7c305a23109875feeaf395a504b91f6358cfc"
integrity sha512-fmL+RFZ2Hrezy+X/5ZczQW51LUmvzfcqOurnkCIRFTyjdVjzR7JvENzI6+VKBJzJdPh6EYL4RoWl92b2Hrk9fw==
monaco-editor@0.20.0, monaco-editor@^0.20.0:
version "0.20.0"
resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.20.0.tgz#5d5009343a550124426cb4d965a4d27a348b4dea"
integrity sha512-hkvf4EtPJRMQlPC3UbMoRs0vTAFAYdzFQ+gpMb8A+9znae1c43q8Mab9iVsgTcg/4PNiLGGn3SlDIa8uvK1FIQ==
monaco-yaml@^2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/monaco-yaml/-/monaco-yaml-2.4.0.tgz#027307a231d809c416babf1cf89b4c1bb940e55d"
integrity sha512-ElUS6uBqEjA2/o2gLuNdnqWSAAQXh8ISr1kwlFErm3t5IXO74TNfS3gnjO6Kv9TXS7LImjGfgPAZei7o8zNTHw==
optionalDependencies:
prettier "^1.19.1"
mousetrap@^1.4.6:
version "1.4.6"
......@@ -9387,11 +9366,16 @@ prettier@1.16.3:
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.16.3.tgz#8c62168453badef702f34b45b6ee899574a6a65d"
integrity sha512-kn/GU6SMRYPxUakNXhpP0EedT/KmaPzr0H5lIsDogrykbaxOpOfAFfk5XA7DZrJyMAv1wlMV3CPcZruGXVVUZw==
prettier@1.18.2, prettier@^1.18.2:
prettier@1.18.2:
version "1.18.2"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.18.2.tgz#6823e7c5900017b4bd3acf46fe9ac4b4d7bda9ea"
integrity sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==
prettier@^1.18.2, prettier@^1.19.1:
version "1.19.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb"
integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==
pretty-format@^24.8.0:
version "24.8.0"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.8.0.tgz#8dae7044f58db7cb8be245383b565a963e3c27f2"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment