Compare commits

...

185 commits
push ... main

Author SHA1 Message Date
Remco Haszing
4ab8e671e6
4.0.0-alpha.1 2022-02-15 14:04:19 +01:00
Remco Haszing
0e42b40a65
Merge pull request #151 from remcohaszing/update-dependencies
Update dependencies
2022-02-15 14:02:59 +01:00
Remco Haszing
45d8d1ae57
Update dependencies
This adds support for marker tags. This is used for unused anchors.
2022-02-15 11:24:56 +01:00
Remco Haszing
629aaaa2a8
Merge pull request #147 from remcohaszing/update-dependencies
Update dependencies
2022-02-15 11:13:47 +01:00
Remco Haszing
5efe47e449
Fix type issue 2022-01-18 10:19:41 +01:00
Remco Haszing
e28f7fec9f
Update dependencies
Most notably this updates yaml-language-server to 1.3.0.
2022-01-17 17:01:12 +01:00
Remco Haszing
c4ae02d2ef
Merge pull request #145 from remcohaszing/ci-test-example-builds
Build examples in CI
2021-11-27 15:22:46 +01:00
Remco Haszing
18cfa0a008
Build examples in CI
This doesn’t verify they actually work, but at least this verified they
can be built.
2021-11-25 21:29:34 +01:00
Remco Haszing
d35b72e1fe
Merge pull request #144 from domsew/fixExample
fix monaco-editor-webpack-plugin
2021-11-24 18:40:50 +01:00
Dominik Seweryn
0518312cac fix monaco-editor-webpack-plugin
after library output change
2021-11-24 18:37:48 +01:00
Remco Haszing
326a253813
Merge pull request #136 from remcohaszing/flatten-output-paths
Flatten output paths
2021-11-23 15:36:00 +01:00
Remco Haszing
928d33cdc3
Resolve merge isue 2021-11-23 15:12:20 +01:00
Remco Haszing
ef35d1be2b
Merge branch 'main' into flatten-output-paths 2021-11-23 15:10:34 +01:00
Remco Haszing
a959e028ce
Merge pull request #140 from remcohaszing/esm-import-extensions
Use extensions for directly importing files
2021-11-23 15:07:08 +01:00
Remco Haszing
38e61fc7be
Remove unused eslint-disable comment 2021-11-23 15:00:08 +01:00
Remco Haszing
f42c5e97e0
Merge pull request #139 from remcohaszing/fix-type-issue
Fix a small type issue
2021-11-23 14:51:45 +01:00
Remco Haszing
af88581fbb
Merge pull request #141 from remcohaszing/support-document-symbol-detail
Add support for document symbol details
2021-11-23 14:51:32 +01:00
Remco Haszing
a18a75d137
Merge pull request #142 from remcohaszing/remove-prefix-support
Remove support for the prefix option
2021-11-23 14:51:19 +01:00
Remco Haszing
9a2be95116
Merge pull request #135 from remcohaszing/contributing-docs
Enhance contribution instructions
2021-11-23 14:50:18 +01:00
Remco Haszing
bd0ae90018
Remove support for the prefix option
If it turns out people use this, we can support a custom schema request
service implementation instead.

Also error responses for schema requests are now handled.
2021-11-20 12:39:43 +01:00
Remco Haszing
934eb8d1e3
Fix ESLint issues 2021-11-20 12:23:11 +01:00
Remco Haszing
3a873e083c
Add support for document symbol details
This is set to the raw value for primitives by the YAML language service.

The demo now uses this value as the title attribute on the breadcrumbs.

Closes #137
2021-11-20 12:21:51 +01:00
Remco Haszing
ccfbbbe9d8
Use extensions for directly importing files
For better ESM compatibility, this adds a file extension for nested
package files.

This also removes the nested special handling of
`vscode-languageserver-types` and `vscode-languageserver-document`
imports. This is unnecessary, because they use the `"module"` field in
`package.json`.
2021-11-20 12:05:44 +01:00
Remco Haszing
5bb55b6e96
Fix a small type issue
The language server completion kind and monaco completion kind are
compatible by coincidence, not by definition.
2021-11-19 16:21:07 +01:00
Remco Haszing
90d895a214
Flatten output paths
`lib/esm/monaco.contribution.js` → `index.js`
`lib/esm/yaml.worker.js` → `yaml.worker.js`

Closes #132
2021-11-15 18:33:26 +01:00
Remco Haszing
72fc069c6d
Enhance contribution instructions
For both the project and all exmaples the prerequisites, setup steps,
and running instructions have been added.
2021-11-15 18:09:40 +01:00
Remco Haszing
545e6a6bc4
Merge pull request #126 from remcohaszing/update-dependencies
Update dependencies
2021-11-15 17:57:36 +01:00
Remco Haszing
f44c4e8e34
Update dependencies 2021-11-15 17:54:04 +01:00
Remco Haszing
56372c1c2a
Merge branch 'main' into update-dependencies 2021-11-15 17:31:25 +01:00
Remco Haszing
c008952c87
Merge pull request #116 from remcohaszing/vite-example
Add minimal vite example
2021-11-15 17:29:29 +01:00
Remco Haszing
2a80dc8913
Merge branch 'main' into vite-example 2021-11-15 17:09:35 +01:00
Remco Haszing
e0d2f4ade6
Merge branch 'main' into vite-example 2021-11-15 17:05:21 +01:00
Remco Haszing
f2948443e1
Merge pull request #128 from domsew/monaco-editor-webpack-plugin-example
Add monaco-editor-webpack-plugin-example
2021-11-15 17:03:45 +01:00
Dominik Seweryn
ed001fdc1c Add monaco-editor-webpack-plugin-example 2021-11-11 17:20:19 +01:00
Remco Haszing
786cdb5dbb
Implement definition provider 2021-11-10 22:28:06 +01:00
Remco Haszing
edf8623b78
Update dependencies 2021-11-10 21:59:05 +01:00
Remco Haszing
5507d53dee
Merge branch 'main' into update-dependencies 2021-11-10 21:40:56 +01:00
Remco Haszing
4f06c90e34
4.0.0-alpha.0 2021-11-09 21:56:55 +01:00
Remco Haszing
d15459091c
Disable automated publishing
It’s not working currently. It’s disabled while we’re in the pre-release
stage.
2021-11-09 21:53:29 +01:00
Remco Haszing
44e5c7b6b5
Merge pull request #134 from Nivl/ml/update-monaco-0.30
Update monaco to 0.30
2021-11-09 21:52:19 +01:00
Melvin Laplanche
f3decc20dd
Update monaco to 0.30 2021-11-09 10:43:15 -08:00
Remco Haszing
7fd3bc973b
Merge pull request #133 from remcohaszing/faq
Add FAQ entry in readme
2021-11-09 08:55:39 +01:00
Remco Haszing
eb0ce6dd0a
Merge pull request #130 from remcohaszing/specify-lockfile-version
Use lockfile version 3
2021-11-09 08:55:23 +01:00
Remco Haszing
fc405ef1b2
Add FAQ entry in readme
Closes #118
Closes #119
Closes #121
2021-11-07 15:00:01 +01:00
Remco Haszing
1b5fa06cc9
Use lockfile version 3
This saves half of the `package-lock.json` file.
2021-11-07 13:58:42 +01:00
Remco Haszing
c5d83c4543
Remove webpack buffer fallback
This was needed for `yaml-languagerserver-parser`, which is no longer
used.
2021-10-18 21:16:18 +02:00
Remco Haszing
90a7bcda0a
Fix ESLint issue 2021-10-17 13:23:08 +02:00
Remco Haszing
f7fce45714
Sync package-lock.json 2021-10-17 13:21:36 +02:00
Remco Haszing
554699887d
Update dependencies
- Both `js-yaml` and `yaml-languageserver-parser` have been replaced with
  `yaml`.
- `jsonc-parser` has been externalized.
- All defaults are now specified explicitly.
- The new property `yamlVersion` has been added to match
  `yaml-language-server`. The default is `1.2`.
- `DiagnosticsOptions` properties are now sorted alphabetically and
  documentation has been enhanced.

Closes #117
2021-10-17 12:32:19 +02:00
Remco Haszing
4e30f4cf16
Merge pull request #123 from remcohaszing/demo-source-map
Enable source maps for the demo
2021-10-06 09:09:27 +02:00
Remco Haszing
8d75a459ee
Enable source maps for the demo 2021-10-02 16:20:32 +02:00
Remco Haszing
0f2e5536bf
Merge pull request #114 from remcohaszing/remove-hover-content-checks
Remove checks for hover content
2021-10-02 16:16:00 +02:00
Remco Haszing
9987fbc7d5
Merge pull request #113 from remcohaszing/constant-language-id
Extract languageId into constants
2021-10-02 16:15:47 +02:00
Remco Haszing
4affa0963c
Merge pull request #112 from remcohaszing/demo-dispose-old-model
Dispose the old model before switching in demo
2021-10-02 16:15:41 +02:00
Remco Haszing
11f4465ee8
Add minimal vite example
Closes #115
2021-09-17 18:09:59 +02:00
Remco Haszing
da51564fbb
Remove checks for hover content
The hover implementation of the YAML language service always returns
`MarkupContent`.
2021-09-17 16:33:13 +02:00
Remco Haszing
7313780510
Extract languageId into constants
It was defined once, but it was passed into various functions. This
added unnecessary complexity.

It is now defined in a constants file, which is imported where
necessary.
2021-09-17 16:21:27 +02:00
Remco Haszing
3a0b164c51
Dispose the old model before switching in demo
This prevents errors.
2021-09-17 16:02:53 +02:00
Remco Haszing
979ed62d6f
3.2.1 2021-09-15 21:59:27 +02:00
Remco Haszing
65e91a1d43
Merge pull request #109 from patrickshipe/restore-options-updates
Restore ability to change options after loading
2021-09-15 21:52:57 +02:00
Remco Haszing
7bf8137107
Merge pull request #110 from patrickshipe/prevent-null-model-crash
Fix crashes from null model
2021-09-15 21:52:35 +02:00
Patrick Shipe
2bece31f56 Fix crashes from null model 2021-09-15 08:59:40 -06:00
Patrick Shipe
7a96d822b1 Restore ability to change options after loading 2021-09-14 13:37:14 -06:00
Remco Haszing
8d278d3d19
Merge pull request #101 from remcohaszing/stylistic-fixes
Apply various stylistic fixes
2021-09-06 12:11:42 +02:00
Remco Haszing
3d037a15a6
3.2.0 2021-09-06 10:05:52 +02:00
Remco Haszing
96abaa5bce
Merge pull request #103 from medihack/custom-tags
Add custom tags option
2021-09-06 10:04:58 +02:00
Kai Schlamp
04ba90907b
Fix ESLint issues 2021-09-05 10:39:30 +02:00
Kai Schlamp
9506aef618 Add custom tags option 2021-09-04 13:50:57 +00:00
Remco Haszing
9739d143d3
Apply various stylistic fixes
- ESLint config `remcohaszing/typechecking` is extended.
- Various previously disabled ESLint rules have now been enabled.
- Various `any` types have been fixed.
- Removed useless type check of diagnostic code.
- The diagnostics adapter listener has been turned into an actual map.
2021-09-02 22:11:00 +02:00
Remco Haszing
3541f69831
Merge pull request #100 from remcohaszing/update-dependencies
Update dependencies
2021-09-02 21:59:19 +02:00
Remco Haszing
5445cd8437
Widen webpack version range 2021-09-02 21:49:57 +02:00
Remco Haszing
99dcdff6fe
Update dependencies
All caret ranges are now defined as `^x.0.0`.

A small ESLint issue was fixed, which was reported by the updates ESLint
configuration.
2021-09-02 15:39:23 +02:00
Remco Haszing
f101c2fc1d
Merge pull request #99 from remcohaszing/remove-disposables
Remove logic for unloading the language
2021-09-02 09:21:56 +02:00
Remco Haszing
26173cdbad
Remove logic for unloading the language
It’s not supported in `monaco-editor` nor is it planned.

See https://github.com/microsoft/monaco-editor/issues/2642
2021-09-01 21:23:26 +02:00
Remco Haszing
b4ffefc00f
Merge pull request #97 from remcohaszing/schemastore-example
Let demo users select a schema from schema store
2021-08-29 12:53:08 +02:00
Remco Haszing
3361bfe233
Let demo users select a schema from schema store 2021-08-28 11:44:04 +02:00
Remco Haszing
24b116419d
Merge pull request #96 from remcohaszing/fix-publish
Fix publishing
2021-08-27 08:22:30 +02:00
Remco Haszing
307ae10623
Fix publishing
Add the `actions/checkout` action before publishing.
2021-08-26 17:27:58 +02:00
Remco Haszing
28928ca314
3.1.0 2021-08-26 17:24:30 +02:00
Remco Haszing
888ac94808
Merge pull request #94 from remcohaszing/breadcrumbs
Add editor breadcrumbs to demo
2021-08-26 17:23:48 +02:00
Remco Haszing
67d9aecfb6
Add editor breadcrumbs to demo
This uses some untyped and undocumented monaco APIs.

Closes #41
2021-08-25 20:05:49 +02:00
Remco Haszing
b79134d080
Merge pull request #93 from remcohaszing/support-json-links
Resolve JSON pointers as links
2021-08-25 20:02:31 +02:00
Remco Haszing
cf4b843ce5
Merge branch 'main' into support-json-links 2021-08-25 19:23:42 +02:00
Remco Haszing
74803276b6
Merge pull request #91 from remcohaszing/webpack-to-demo
Rename webpack example to demo
2021-08-25 18:53:05 +02:00
Remco Haszing
020c123830
Merge pull request #89 from remcohaszing/automate-publishing
Automate publishing to npm
2021-08-25 18:42:04 +02:00
Remco Haszing
c99e1c3db6
Merge pull request #90 from remcohaszing/no-unnecessary-promises
Use type-fest Promisable for worker return types
2021-08-25 18:41:14 +02:00
Remco Haszing
0da9f2cdfd
Resolve JSON pointers as links 2021-08-25 17:39:53 +02:00
Remco Haszing
109332e5e7
Rename webpack example to demo
It has grown significantly. I plan to add more minimal demos for Webpack
and probably some other bundlers.
2021-08-23 17:28:13 +02:00
Remco Haszing
a95fdc4463
Use type-fest Promisable for worker return types
Monaco turns the synchronous return values into promises anyway.
2021-08-23 17:19:36 +02:00
Remco Haszing
d1c499b224
Automate publishing to npm
Also the `lint` job has been split into `eslint` and `prettier`.

Closes #6
2021-08-23 17:15:07 +02:00
Remco Haszing
13a21cba5d
Merge pull request #88 from remcohaszing/update-yaml-language-server
Update yaml-language-server to 0.22.0
2021-08-23 17:03:25 +02:00
Remco Haszing
1f476ad558
Bump js-yaml
This needs to be in sync with `yaml-language-server`.
2021-08-23 16:18:45 +02:00
Remco Haszing
2228054e58
Update yaml-language-server to 0.22.0 2021-08-21 23:19:37 +02:00
Remco Haszing
ecd189685e
Merge pull request #86 from remcohaszing/example-typescript
Show problems panel in example
2021-08-21 21:34:24 +02:00
Remco Haszing
6860281373
Merge pull request #84 from remcohaszing/async-await
Convert promise chains to async/await
2021-08-21 21:33:56 +02:00
Remco Haszing
8b0e02a4a6
Merge pull request #87 from remcohaszing/remove-do-resolve
Remove doResolve from yaml worker
2021-08-21 21:33:41 +02:00
Remco Haszing
8f6cb81147
Remove doResolve from yaml worker
It’s unused. It’s also not available in the latest version of
yaml-language-server.
2021-08-21 13:20:57 +02:00
Remco Haszing
3774841f7c
Show problems panel in example
The example was also converted to TypeScript.
2021-08-19 22:40:58 +02:00
Remco Haszing
5d059ce47c
Merge pull request #85 from remcohaszing/update-monaco
Update monaco-editor to 0.27.0
2021-08-19 18:47:46 +02:00
Remco Haszing
fff16c993e
Update monaco-editor to 0.27.0
This is only used for development. Everything still works.
2021-08-19 18:03:12 +02:00
Remco Haszing
ba395c9d23
Convert promise chains to async/await 2021-08-19 17:55:46 +02:00
Remco Haszing
57e820ed0c
Merge pull request #82 from remcohaszing/classes-to-factories
Convert classes to factory functions
2021-08-19 17:46:47 +02:00
Remco Haszing
40a38e2d2d
Merge pull request #83 from remcohaszing/remove-unused-filler
Remove os filler
2021-08-19 17:46:37 +02:00
Remco Haszing
40243d4e83
Remove os filler
It’s unused
2021-08-19 17:21:38 +02:00
Remco Haszing
8fa3ca4252
Convert classes to factory functions
TypeScript is better at inferring types when using simple functions and
objects instead of classes. As a result many type annotations have now
been removed without impacting type safety.

Some other benefits are this can be minified better and private fields
are now truly private variables.
2021-08-19 17:06:42 +02:00
Remco Haszing
bdfa1ef4e7
Merge pull request #80 from remcohaszing/tsconfig-fixes
Do some tsconfig cleanups
2021-08-19 08:50:55 +02:00
Remco Haszing
d4c6747667
Merge pull request #79 from remcohaszing/github-actions-tsc
Run type checks in GitHub workflow
2021-08-19 08:50:37 +02:00
Remco Haszing
df88461b0c
Merge pull request #78 from remcohaszing/remove-commented-code
Remove commented code
2021-08-19 08:50:21 +02:00
Remco Haszing
d7e5aa7744
Merge pull request #77 from remcohaszing/remove-document-range-formatting-edit-provider
Remove DocumentRangeFormattingEditProvider
2021-08-19 08:50:02 +02:00
Remco Haszing
d4ddc80b51
Merge pull request #81 from remcohaszing/fix-mistyped-enums
Fix mismatched enum types
2021-08-19 08:49:47 +02:00
Remco Haszing
fd9efe8060
Do some tsconfig cleanups
- `alwaysStrict` is unnecessary, because ESM is always strict.
- `noEmit` is enabled, because TypeScript isn’t used to bundle the code.
- `outDir` was removed, because TypeScrtips isn’t used to bundle the
  code.
- `exclude` was removed, because it’s not necessary.
2021-08-18 21:51:29 +02:00
Remco Haszing
62998a0b38
Run type checks in GitHub workflow 2021-08-18 21:47:53 +02:00
Remco Haszing
dd64c96d59
Fix mismatched enum types
These enums were annotated as numbers, but they could be more specific.
2021-08-18 21:46:06 +02:00
Remco Haszing
3dc04e2150
Remove commented code 2021-08-18 16:04:56 +02:00
Remco Haszing
cdef13351a
Remove unused format option 2021-08-18 15:56:45 +02:00
Remco Haszing
288c34cd37
Remove DocumentRangeFormattingEditProvider
The YAML language service doesn’t support formatting ranges.

In practice this means the “Format Selection” option which does the same
as “Format Document” is no longer available in the menu that’s opened
when pressing F1.
2021-08-18 15:47:50 +02:00
Remco Haszing
26b0d6ea96
Merge pull request #74 from remcohaszing/esbuild
Build project using esbuild
2021-08-15 21:23:51 +02:00
Remco Haszing
612604e254
Merge pull request #76 from remcohaszing/fix-readme-inconsistency
Fix consistency in readme
2021-08-15 13:16:38 +02:00
Remco Haszing
970179a272
Merge pull request #75 from remcohaszing/keywords
Add keywords in package.json
2021-08-15 12:56:15 +02:00
Remco Haszing
b533a0af0a
Fix consistency in readme
All GitHub usernames were prefixed with an `@` sign, except one.
2021-08-15 12:53:49 +02:00
Remco Haszing
0d107449ad
Add keywords in package.json
This helps people find this package.
2021-08-15 12:46:36 +02:00
Remco Haszing
95fd123191
Build project using esbuild
This is much more flexible than `monaco-plugin-helpers`. Because of
this, it’s possible to use Prettier as an external dependency, so users
can ignore it in their own build process of they choose not to support
formatting.

Instead of rewriting YAML language service imports in the build tool, I
decided to just import them from where they need to be imported in the
source code.

Closes #63
2021-08-15 12:37:13 +02:00
Remco Haszing
c2e6af4198
3.0.1 2021-08-10 09:57:35 +02:00
Remco Haszing
f16e46331e
Merge pull request #71 from remcohaszing/update-example-value
Add a more advanced example value
2021-08-09 22:37:28 +02:00
fleonus
41d2b2e0c9
Update examples/webpack/src/index.js 2021-08-09 22:31:30 +02:00
Remco Haszing
b42b0b6af4
Update examples/webpack/src/index.js
Co-authored-by: fleonus <hkapoor@gitlab.com>
2021-08-09 22:30:08 +02:00
Remco Haszing
2912c4b287
Merge pull request #72 from remcohaszing/fix-editor-loading-background
Set the editor background while loading
2021-08-09 22:28:01 +02:00
Remco Haszing
f5fc412497
Merge pull request #70 from remcohaszing/demo-metadata
Update metadata
2021-08-09 21:42:47 +02:00
Remco Haszing
0d46780695
Set the editor background while loading
The colors match the editor background color that’s displayed when the
editor is loaded.
2021-08-09 21:41:46 +02:00
Remco Haszing
260f0da919
Add a more advanced example value 2021-08-09 21:32:40 +02:00
Remco Haszing
11030e5599
Update metadata
- Add links to https://monaco-editor.js.org
- Add netlify badge to the readme
- Add YAML icon to the demo
2021-08-09 20:49:00 +02:00
Remco Haszing
249771b770
Merge pull request #69 from remcohaszing/optimize-example
Optimize the example
2021-08-09 08:29:41 +02:00
Remco Haszing
72d77fdc33
Optimize the example 2021-08-07 13:40:56 +02:00
Remco Haszing
ee45815857
Merge pull request #68 from remcohaszing/update-example
Update the example
2021-08-07 13:14:33 +02:00
Remco Haszing
4bbdb7e5b1
Update the example
It looks somewhat nice now.
2021-08-07 10:50:50 +02:00
Remco Haszing
92b103ee8d
Fix command for netlify 2021-08-07 09:33:29 +02:00
Remco Haszing
b6195b1563
Add .nvmrc 2021-08-07 09:31:34 +02:00
Remco Haszing
9962474f4d
Configure netlify 2021-08-07 09:28:19 +02:00
Remco Haszing
cff2665b7c
Merge pull request #67 from remcohaszing/service-worker-to-web-worker
Service worker to web worker
2021-08-05 19:08:54 +02:00
Remco Haszing
3094ebef91
Merge pull request #65 from remcohaszing/webpack-5
Update dependencies
2021-08-05 18:44:19 +02:00
Remco Haszing
6271f31cd3
Merge pull request #66 from remcohaszing/remove-vscode-settings
Remove .vscode folder
2021-08-05 18:44:03 +02:00
Remco Haszing
e4c13afe52
Change service worker to web worker in readme
They are different things. Monaco uses web workers.
2021-08-05 18:42:54 +02:00
Remco Haszing
e95737f7a2
Remove .vscode folder
Contributors should be able to use their own preferences.
2021-08-05 18:37:23 +02:00
Remco Haszing
13c46f5de6
Update dependencies
Most notably update to Webpack 5. Webpack 5 supports web workers without
the need of a loader, so the `webpack-worker-loader` example has been
removed.
2021-08-05 18:33:58 +02:00
Remco Haszing
c1310d88ff
Merge pull request #64 from remcohaszing/update-metadata
Update documentation
2021-07-31 16:51:20 +02:00
Remco Haszing
2ea154af85
Update documentation
- Update repository links
- Restructure the readme
- Add contributing document
- Update credits
2021-07-31 16:15:45 +02:00
Remco Haszing
090302534a
3.0.0 2021-07-18 15:01:19 +02:00
Remco Haszing
bd831b1e03
Merge pull request #61 from remcohaszing/expose-set-diagnostics-options
Expose setDiagnosticsOptions in monaco-yaml
2021-07-18 15:01:04 +02:00
Remco Haszing
7174aff026
Expose setDiagnosticsOptions in monaco-yaml
This removes the need to explain certain statements and imports need to
happen in a specific order. Users can now just use:

```ts
import { setDiagnosticsOptions } from 'monaco-yaml';

setDiagnosticsOptions({});
```
2021-07-18 14:58:42 +02:00
Remco Haszing
9436e1f034
Merge pull request #60 from remcohaszing/enhance-types
Add missing diagnostics options in types
2021-07-18 14:44:40 +02:00
Remco Haszing
7a6fcf0c64
Add missing diagnostics options in types
Also JSON schemas have been typed to be more specific using
`@types/json-schema`.
2021-07-18 14:20:41 +02:00
Remco Haszing
ce58d4b6d7
Merge pull request #59 from remcohaszing/simplify-webpack-example-structures
Use a more minimal webpack config for examples
2021-07-18 13:35:58 +02:00
Remco Haszing
249de5dc34
Use a more minimal webpack config for examples 2021-07-18 13:29:54 +02:00
Remco Haszing
b276fd26d1
Merge pull request #58 from remcohaszing/eslint
Introduce ESLint
2021-07-17 17:18:23 +02:00
Remco Haszing
ac7b6fe307
Introduce ESLint
The ESLint preset `eslint-config-remcohaszing` is used.
2021-07-17 17:12:17 +02:00
Remco Haszing
9a107bf7cc
Merge pull request #57 from remcohaszing/bump-dependencies
Bump dependencies
2021-07-17 14:24:41 +02:00
Remco Haszing
f327e73f66
Bump dependencies 2021-07-17 14:20:08 +02:00
Remco Haszing
872423db4b
Merge pull request #46 from remcohaszing/remove-react
Remove react
2021-07-17 13:45:18 +02:00
Remco Haszing
668b53af11
Remove React from examples
`react-monaco-editor` has a dependency on `monaco-editor@*`. This makes it
annoying to manage the exact version of `monaco-editor` that’s being used.
2021-07-17 13:41:43 +02:00
Remco Haszing
296968c33f
Merge pull request #56 from remcohaszing/remove-umd
Remove UMD support
2021-07-17 13:24:21 +02:00
Remco Haszing
67e2accd3b
Remove UMD support
It was already broken.

Also the npm ecosystem is moving towards ESM only. This package should be a
part of that.
2021-07-17 13:22:05 +02:00
Remco Haszing
bb3d8bd941
Merge pull request #49 from remcohaszing/npm
Convert from yarn to npm
2021-07-17 13:08:55 +02:00
Remco Haszing
c12db2ef5b
Merge pull request #48 from remcohaszing/monaco-imports
Replace monaco namespace with monaco-editor imports
2021-07-17 12:46:06 +02:00
Remco Haszing
ec4de1f50c
Convert from yarn to npm
Npm 7 also supports workspaces, but doesn’t require the workspace root to be
private. This means the examples can be workspaces within the project, so the
entire project can be handled as one mono repository with a single lock file and
`node_modules` directory.

Also the readme has been updated with usage instructions.
2021-04-28 17:47:00 +02:00
Remco Haszing
52c457a196
Use monaco-editor/esm/vs/editor/editor.api
This doesn’t enforce users to pull in all of monaco-editor.
2021-04-22 20:00:34 +02:00
Remco Haszing
5a0de63544
Synchronize yarn lockfiles 2021-04-14 20:09:42 +02:00
Remco Haszing
c4a95e2dd5
Replace monaco namespace with monaco-editor imports
This is a preparation for `monaco-editor@^0.22.0`. In this version the global
`monaco` object was removed for ESM users.

A choice was made to use `monaco-editor` imports, because this probably has
best compatibility for most users. If users want to use `monaco-editor-core`,
they will have to create an alias in their own build process.
2021-04-13 21:18:18 +02:00
Remco Haszing
0e0555455c
Replace Thenable with PromiseLike
`Thenable` is a deprecated alias of the TypeScript builtin `PromiseLike`.
2021-04-13 21:18:18 +02:00
Himanshu Kapoor
4e00c72636
Merge pull request #47 from remcohaszing/fix-dependencies
Fix dependencies
2021-04-13 21:07:09 +02:00
Remco Haszing
09e2418046
Fix js-yaml dependency 2021-04-13 20:17:12 +02:00
Remco Haszing
5fd08c73ed
Update prettier to match yaml-language-server
Since both yaml-language-server and prettier are included in the bundle, their
versions should match for best compatibility. Also code has been formatted using
the updated prettier.
2021-04-13 20:17:12 +02:00
Remco Haszing
3762a98af0
Fix dependencies
This package includes `yaml-language-server` in its build. This means it’s not a
runtime dependency, but it belongs in `devDependencies`.

The runtime bundle does depend on the dependencies specified in `resolveSkip` in
`scripts/bundle-esm.js`. These packages have been added as direct dependencies
instead.
2021-04-13 20:17:12 +02:00
Himanshu Kapoor
3da78b4f01
Merge pull request #45 from remcohaszing/fixes-and-cleanups
Fixes and cleanups
2021-04-13 19:07:01 +02:00
Remco Haszing
1b173c35a9
Move build script into prepare
This is needed for the examples to work.
2021-03-30 21:30:02 +02:00
Remco Haszing
9f10ccc9f9
Gitignore built packages 2021-03-25 18:01:10 +01:00
Remco Haszing
c8d9e1cc58
Upgrade TypeScript 2021-03-25 18:00:50 +01:00
Remco Haszing
04907bd623
Apply prettier on all committed files 2021-03-25 17:59:58 +01:00
Remco Haszing
97106b71c9
Add GitHub workflow
2 jobs have been specified:

- `pack` makes sure the package can be built.
- `lint` checks the code using Prettier.
2021-03-25 17:55:23 +01:00
Remco Haszing
f4130f38a3
Move yarn prepare script to prepack
No need to rebuild the package on every `yarn install`, but it should be built
before packing.
2021-03-25 17:52:58 +01:00
Remco Haszing
1c532f6815
Update husky and lint-staged 2021-03-25 17:40:43 +01:00
Remco Haszing
26317d314a
Replace .npmignore with package.json files
This is inclusive instead of exclusive, which is more manageable.
2021-03-25 17:40:24 +01:00
Remco Haszing
a5a49756be
Remove unused dependencies
Jest, eslint, and typescript-tslint-plugin were installed, but never used. Node
types were used for timers, but this is incorrect, as this code is supposed to
run in the browser.
2021-03-25 17:40:16 +01:00
Remco Haszing
7f49a21a56
Revert "Fix types for languages.yaml namespaces"
This reverts commit e784f842c3.
2021-03-25 17:07:47 +01:00
Yazan Aabed
8d3e1626f3
Merge pull request #38 from remcohaszing/fix-languages.yaml-types
Fix types for languages.yaml namespaces
2020-12-15 14:12:45 +01:00
Remco Haszing
e784f842c3
Fix types for languages.yaml namespaces
`monaco-editor` no longer uses a global `monaco` namespace.
2020-12-09 10:07:15 +01:00
74 changed files with 10467 additions and 17330 deletions

View file

@ -3,12 +3,12 @@ root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
max_line_length = 100
trim_trailing_whitespace = true
[*.md]
max_line_length = off
trim_trailing_whitespace = false
[COMMIT_EDITMSG]
max_line_length = 72

19
.eslintrc.yaml Normal file
View file

@ -0,0 +1,19 @@
extends:
- remcohaszing
- remcohaszing/typechecking
rules:
no-restricted-globals: off
'@typescript-eslint/no-misused-promises': off
'@typescript-eslint/no-shadow': off
'@typescript-eslint/no-unnecessary-condition': off
import/extensions: off
import/no-extraneous-dependencies: off
import/no-unresolved: off
jsdoc/require-jsdoc: off
node/no-extraneous-import: off
node/no-unsupported-features/es-syntax: off
node/no-unsupported-features/node-builtins: off

66
.github/workflows/ci.yaml vendored Normal file
View file

@ -0,0 +1,66 @@
name: ci
on:
pull_request:
push:
branches: [main]
tags: ['*']
jobs:
eslint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with: { node-version: 16 }
- run: npm ci
- run: npx eslint .
examples:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with: { node-version: 16 }
- run: npm ci
- run: npm run prepack
- run: npm run build --workspaces
pack:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with: { node-version: 16 }
- run: npm ci
- run: npm pack
prettier:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with: { node-version: 16 }
- run: npm ci
- run: npx prettier --check .
tsc:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with: { node-version: 16 }
- run: npm ci
- run: npx tsc
# release:
# runs-on: ubuntu-latest
# needs: [eslint, pack, prettier, tsc]
# if: startsWith(github.ref, 'refs/tags/')
# steps:
# - uses: actions/checkout@v2
# - uses: actions/setup-node@v2
# with: { node-version: 16 }
# - run: npm ci
# - run: npm publish
# env:
# NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

9
.gitignore vendored
View file

@ -1,4 +1,7 @@
/node_modules/
/out/
/lib/
dist/
node_modules/
/index.js
/yaml.worker.js
*.log
*.map
*.tgz

3
.husky/pre-commit Executable file
View file

@ -0,0 +1,3 @@
#!/usr/bin/env sh
npx lint-staged

View file

@ -1,12 +0,0 @@
/.vscode/
/out/
/scripts/
/examples/
/patches/
/src/
/test/
/.gitignore
/.npmignore
/examples
/test-demo.png
/.editorconfig

1
.npmrc Normal file
View file

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

1
.nvmrc Normal file
View file

@ -0,0 +1 @@
16

View file

@ -1 +1,3 @@
/lib/esm/_deps/
dist/
/index.js
/yaml.worker.js

3
.prettierrc.yaml Normal file
View file

@ -0,0 +1,3 @@
proseWrap: always
singleQuote: true
trailingComma: all

18
.vscode/launch.json vendored
View file

@ -1,18 +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": [
{
"type": "node",
"name": "vscode-jest-tests",
"request": "launch",
"args": ["--runInBand"],
"cwd": "${workspaceFolder}",
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"program": "${workspaceFolder}/node_modules/jest/bin/jest"
}
]
}

11
.vscode/settings.json vendored
View file

@ -1,11 +0,0 @@
// Place your settings in this file to overwrite default and user settings.
{
"files.trimTrailingWhitespace": true,
"search.exclude": {
"**/node_modules": true,
"**/lib": true,
"**/out": true
},
"javascript.preferences.quoteStyle": "single",
"typescript.preferences.quoteStyle": "single"
}

36
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,36 @@
# Contributing
## Prerequisites
The following are required to start working on this project:
- [Git](https://git-scm.com)
- [NodeJS](https://nodejs.org) 16 or higher
- [npm](https://github.com/npm/cli) 8.1.2 or higher
## Getting started
To get started with contributing, clone the repository and install its dependencies.
```sh
git clone https://github.com/remcohaszing/monaco-yaml
cd monaco-yaml
npm ci
```
## Building
To build the repository, run:
```sh
npm run prepack
```
## Running
To test it, run one of the
[examples](https://github.com/remcohaszing/monaco-yaml/tree/main/examples).
```sh
npm --workspace demo start
```

View file

@ -1,21 +1,18 @@
The MIT License (MIT)
Copyright (c) Microsoft Corporation
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.
The MIT License (MIT)
Copyright (c) Microsoft Corporation
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.

229
README.md
View file

@ -1,34 +1,219 @@
# Monaco YAML
YAML language plugin for the Monaco Editor. It provides the following features when editing YAML files:
* Code completion, based on JSON schemas or by looking at similar objects in the same file
* Hovers, based on JSON schemas
* Validation: Syntax errors and schema validation
* Formatting
* Document Symbols
* Syntax highlighting
* Automatically load remote schema files (by enabling DiagnosticsOptions.enableSchemaRequest)
[![ci workflow](https://github.com/remcohaszing/monaco-yaml/actions/workflows/ci.yaml/badge.svg)](https://github.com/remcohaszing/monaco-yaml/actions/workflows/ci.yaml)
[![npm version](https://img.shields.io/npm/v/monaco-yaml)](https://www.npmjs.com/package/monaco-yaml)
[![prettier code style](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://prettier.io)
[![demo](https://img.shields.io/badge/demo-monaco--yaml.js.org-61ffcf.svg)](https://monaco-yaml.js.org)
[![netlify status](https://api.netlify.com/api/v1/badges/20b08937-99d0-4882-b9a3-d5f09ddd29b7/deploy-status)](https://app.netlify.com/sites/monaco-yaml/deploys)
Schemas can also be provided by configuration. See [here](https://github.com/Microsoft/monaco-json/blob/master/src/monaco.d.ts)
for the API that the JSON plugin offers to configure the JSON language support.
YAML language plugin for the Monaco Editor. It provides the following features when editing YAML
files:
## Installing
- Code completion, based on JSON schemas or by looking at similar objects in the same file
- Hovers, based on JSON schemas
- Validation: Syntax errors and schema validation
- Formatting using Prettier
- Document Symbols
- Automatically load remote schema files (by enabling DiagnosticsOptions.enableSchemaRequest)
- Links from JSON references.
- Links and hover effects from YAML anchors.
`yarn add monaco-yaml`
Both vs loader and ESM are supported.
See `examples` directory for esm and umd examples.
Schemas can also be provided by configuration. See
[here](https://github.com/remcohaszing/monaco-yaml/blob/main/index.d.ts) for the API that the plugin
offers to configure the YAML language support.
## Development
## Installation
* `git clone https://github.com/pengx17/monaco-yaml`
* `cd monaco-yaml`
* `yarn`
```sh
npm install monaco-yaml
```
A running example:
![demo-image](test-demo.png)
## Usage
Import `monaco-yaml` and configure it before an editor instance is created.
```typescript
import { editor, Uri } from 'monaco-editor';
import { setDiagnosticsOptions } from 'monaco-yaml';
// The uri is used for the schema file match.
const modelUri = Uri.parse('a://b/foo.yaml');
setDiagnosticsOptions({
enableSchemaRequest: true,
hover: true,
completion: true,
validate: true,
format: true,
schemas: [
{
// Id of the first schema
uri: 'http://myserver/foo-schema.json',
// Associate with our model
fileMatch: [String(modelUri)],
schema: {
type: 'object',
properties: {
p1: {
enum: ['v1', 'v2'],
},
p2: {
// Reference the second schema
$ref: 'http://myserver/bar-schema.json',
},
},
},
},
{
// Id of the first schema
uri: 'http://myserver/bar-schema.json',
schema: {
type: 'object',
properties: {
q1: {
enum: ['x1', 'x2'],
},
},
},
},
],
});
editor.create(document.createElement('editor'), {
// Monaco-yaml features should just work if the editor language is set to 'yaml'.
language: 'yaml',
model: editor.createModel('p1: \n', 'yaml', modelUri),
});
```
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/yaml.worker', import.meta.url));
default:
throw new Error(`Unknown label ${label}`);
}
},
};
```
## Examples
A demo is available on [monaco-yaml.js.org](https://monaco-yaml.js.org).
A running example: ![demo-image](test-demo.png)
Some usage examples can be found in the
[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
Please see our [contributing guidelines](CONTRIBUTING.md)
## Credits
- https://github.com/redhat-developer/yaml-language-server
Originally [@kpdecker](https://github.com/kpdecker) forked this repository from
[`monaco-json`](https://github.com/microsoft/monaco-json) by
[@microsoft](https://github.com/microsoft) and rewrote it to work with
[`yaml-language-server`](https://github.com/redhat-developer/yaml-language-server) instead. Later
the repository maintenance was taken over by [@pengx17](https://github.com/pengx17). Eventually the
repository was tranferred to the account of [@remcohaszing](https://github.com/remcohaszing), who is
currently maintaining this repository with the help of [@fleon](https://github.com/fleon) and
[@yazaabed](https://github.com/yazaabed).
The heavy processing is done in
[`yaml-language-server`](https://github.com/redhat-developer/yaml-language-server), best known for
being the backbone for [`vscode-yaml`](https://github.com/redhat-developer/vscode-yaml). This
repository provides a thin layer to add functionality provided by `yaml-language-server` into
`monaco-editor`.
## License
[MIT](https://github.com/pengx17/monaco-yaml/blob/master/LICENSE.md)
[MIT](https://github.com/remcohaszing/monaco-yaml/blob/main/LICENSE.md)

58
build.js Executable file
View file

@ -0,0 +1,58 @@
const { build } = require('esbuild');
const { dependencies, peerDependencies } = require('./package.json');
build({
entryPoints: ['src/index.ts', 'src/yaml.worker.ts'],
bundle: true,
external: Object.keys({ ...dependencies, ...peerDependencies }),
logLevel: 'info',
outdir: '.',
sourcemap: true,
format: 'esm',
target: ['es2019'],
plugins: [
{
name: 'alias',
setup({ onResolve }) {
// The file monaco-yaml/lib/esm/schemaSelectionHandlers.js imports code from the language
// server part that we dont want.
onResolve({ filter: /\/schemaSelectionHandlers$/ }, () => ({
path: require.resolve('./src/fillers/schemaSelectionHandlers.ts'),
}));
// The yaml language service only imports re-exports of vscode-languageserver-types from
// vscode-languageserver.
onResolve({ filter: /^vscode-languageserver(\/node|-protocol)?$/ }, () => ({
path: 'vscode-languageserver-types',
external: true,
}));
// The yaml language service uses path. We can stub it using path-browserify.
onResolve({ filter: /^path$/ }, () => ({
path: 'path-browserify',
external: true,
}));
// The main prettier entry point contains all of Prettier.
// The standalone bundle is smaller and works fine for us.
onResolve({ filter: /^prettier/ }, ({ path }) => ({
path: path === 'prettier' ? 'prettier/standalone.js' : `${path}.js`,
external: true,
}));
// This tiny filler implementation serves all our needs.
onResolve({ filter: /vscode-nls/ }, () => ({
path: require.resolve('./src/fillers/vscode-nls.ts'),
}));
// The language server dependencies tend to write both ESM and UMD output alongside each
// other, then use UMD for imports. We prefer ESM.
onResolve({ filter: /\/umd\// }, (args) => ({
path: require.resolve(args.path.replace(/\/umd\//, '/esm/'), {
paths: [args.resolveDir],
}),
}));
},
},
],
}).catch((error) => {
// eslint-disable-next-line no-console
console.error(error);
process.exit(1);
});

31
examples/demo/README.md Normal file
View file

@ -0,0 +1,31 @@
# Demo
This demo is deployed to [monaco-yaml.js.org](https://monaco-yaml.js.org). It shows how
`monaco-editor` and `monaco-yaml` can be used with
[Webpack 5](https://webpack.js.org/concepts/entry-points).
## Prerequisites
- [NodeJS](https://nodejs.org) 16 or higher
- [npm](https://github.com/npm/cli) 8.1.2 or higher
## Setup
To run the project locally, clone the repository and set it up:
```sh
git clone https://github.com/remcohaszing/monaco-yaml
cd monaco-yaml
npm ci
npm run prepack
```
## Running
To start it, simply run:
```sh
npm --workspace demo start
```
The demo will open in your browser.

View file

@ -0,0 +1,24 @@
{
"name": "demo",
"version": "1.0.0",
"private": true,
"scripts": {
"start": "webpack serve --open --mode development",
"build": "webpack --mode production"
},
"dependencies": {
"@fortawesome/fontawesome-free": "^6.0.0",
"@schemastore/schema-catalog": "^0.0.5",
"css-loader": "^6.0.0",
"css-minimizer-webpack-plugin": "^3.0.0",
"html-webpack-plugin": "^5.0.0",
"mini-css-extract-plugin": "^2.0.0",
"monaco-editor": "^0.31.0",
"monaco-yaml": "file:../..",
"ts-loader": "^9.0.0",
"typescript": "^4.0.0",
"webpack": "^5.0.0",
"webpack-cli": "^4.0.0",
"webpack-dev-server": "^4.0.0"
}
}

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 512 470.647">
<style>
@media (prefers-color-scheme: dark) {
.char {
fill: #ffffff;
}
}
</style>
<polygon class="char" points="512 422.735 395.638 422.735 395.638 250.125 347.442 250.125 347.442 469.647 512 469.647 512 422.737 512 422.735" />
<polygon class="char" points="87.701 250.177 87.701 470.647 135.004 470.647 135.004 318.569 184.509 420.789 221.743 420.789 272.939 314.976 272.939 470.602 318.318 470.602 318.318 250.177 256.358 250.177 201.381 349.883 149.021 250.177 87.701 250.177 87.701 250.177" />
<path fill="#cb171e" d="M330.294,195.39H228.433l-20.717,50.024H162.61L257.99,20.465h46.137l91.51,224.949h-48.2L330.293,195.39Zm-16.92-44.911-31.226-82.55-34.837,82.55h66.063Z" transform="translate(0 -19.939)" />
<polygon class="char" points="235.793 0 143.978 137.674 143.978 224.949 87.702 224.949 87.702 137.674 0 0 63.25 0 119.018 88.646 175.243 0 235.793 0 235.793 0" />
</svg>

After

Width:  |  Height:  |  Size: 1 KiB

122
examples/demo/src/index.css Normal file
View file

@ -0,0 +1,122 @@
:root {
--background-color: hsl(0, 0%, 96%);
--editor-background: hsl(60, 100%, 100%);
--foreground-color: hsl(0, 0%, 0%);
--primary-color: hsl(189, 100%, 63%);
--shadow-color: hsla(0, 0%, 27%, 0.239);
--warning-color: hsl(49, 100%, 40%);
}
@media (prefers-color-scheme: dark) {
:root {
--background-color: hsl(0, 0%, 23%);
--editor-background: hsl(0, 0%, 12%);
--foreground-color: hsl(0, 0%, 100%);
--shadow-color: hsl(0, 0%, 43%);
--warning-color: hsl(49, 100%, 40%);
}
}
body {
background: var(--background-color);
display: flex;
flex-flow: column;
font-family: sans-serif;
height: 100vh;
margin: 0;
}
h1 {
margin: 0 1rem;
}
nav {
align-items: center;
background-color: var(--primary-color);
box-shadow: 0px 5px 5px var(--shadow-color);
display: flex;
flex: 0 0 auto;
height: 3rem;
justify-content: space-between;
}
.nav-icon {
text-decoration: none;
}
.nav-icon > img {
height: 2rem;
margin-right: 1rem;
vertical-align: middle;
}
.editor-wrapper {
background: var(--editor-background);
box-shadow: 0 0 10px var(--shadow-color);
display: flex;
flex: 1 1 auto;
flex-flow: column;
margin: 1.5rem;
}
#schema-selection {
background-color: var(--editor-background);
border: none;
border-bottom: 1px solid var(--shadow-color);
color: var(--foreground-color);
width: 100%;
}
#breadcrumbs {
border-bottom: 1px solid var(--shadow-color);
color: var(--foreground-color);
flex: 0 0 1rem;
}
.breadcrumb {
cursor: pointer;
}
#breadcrumbs::before,
.breadcrumb:not(:last-child)::after {
content: '';
margin: 0 0.2rem;
}
.breadcrumb.array::before {
content: '[]';
}
.breadcrumb.object::before {
content: '{}';
}
#editor {
flex: 1 1 auto;
}
#problems {
border-top: 1px solid var(--shadow-color);
flex: 0 0 20vh;
color: var(--foreground-color);
overflow-y: scroll;
}
.problem {
align-items: center;
cursor: pointer;
display: flex;
padding: 0.25rem;
}
.problem:hover {
background-color: var(--shadow-color);
}
.problem-text {
margin-left: 0.5rem;
}
.problem .codicon-warning {
color: var(--warning-color);
}

View file

@ -0,0 +1,37 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="<%= require('./icon.svg') %>" />
<title>Monaco YAML</title>
</head>
<body>
<nav>
<h1>Monaco YAML</h1>
<div>
<a href="https://npmjs.com/package/monaco-yaml" class="nav-icon">
<img
alt="npm icon"
src="<%= require('@fortawesome/fontawesome-free/svgs/brands/npm.svg') %>"
/>
</a>
<a href="https://github.com/remcohaszing/monaco-yaml" class="nav-icon">
<img
alt="GitHub icon"
src="<%= require('@fortawesome/fontawesome-free/svgs/brands/github.svg') %>"
/>
</a>
</div>
</nav>
<div class="editor-wrapper">
<div>
<select id="schema-selection">
<option value="monaco-yaml.yaml">Monaco YAML example</option>
</select>
</div>
<div id="breadcrumbs"></div>
<div id="editor"></div>
<div id="problems"></div>
</div>
</body>
</html>

230
examples/demo/src/index.ts Normal file
View file

@ -0,0 +1,230 @@
import './index.css';
import { JSONSchemaForSchemaStoreOrgCatalogFiles } from '@schemastore/schema-catalog';
import { CancellationToken } from 'monaco-editor/esm/vs/base/common/cancellation';
import { getDocumentSymbols } from 'monaco-editor/esm/vs/editor/contrib/documentSymbols/documentSymbols';
import {
editor,
Environment,
languages,
Position,
Range,
Uri,
} from 'monaco-editor/esm/vs/editor/editor.api';
import { SchemasSettings, setDiagnosticsOptions } from 'monaco-yaml';
// NOTE: This will give you all editor featues. If you would prefer to limit to only the editor
// features you want to use, import them each individually. See this example: (https://github.com/microsoft/monaco-editor-samples/blob/main/browser-esm-webpack-small/index.js#L1-L91)
import 'monaco-editor';
import defaultSchemaUri from './schema.json';
declare global {
interface Window {
MonacoEnvironment: Environment;
}
}
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 'yaml':
return new Worker(new URL('monaco-yaml/yaml.worker', import.meta.url));
default:
throw new Error(`Unknown label ${label}`);
}
},
};
const defaultSchema: SchemasSettings = {
uri: defaultSchemaUri,
fileMatch: ['monaco-yaml.yaml'],
};
setDiagnosticsOptions({
schemas: [defaultSchema],
});
const value = `
# Property descriptions are displayed when hovering over properties using your cursor
property: This property has a JSON schema description
# Titles work too!
titledProperty: Titles work too!
# Even markdown descriptions work
markdown: hover me to get a markdown based description 😮
# Enums can be autocompleted by placing the cursor after the colon and pressing Ctrl+Space
enum:
# Unused anchors will be reported
unused anchor: &unused anchor
# Of course numbers are supported!
number: 12
# As well as booleans!
boolean: true
# And strings
string: I am a string
# This property is using the JSON schema recursively
reference:
boolean: Not a boolean
# Also works in arrays
array:
- string: 12
enum: Mewtwo
reference:
reference:
boolean: true
# JSON referenses can be clicked for navigation
pointer:
$ref: '#/array'
# This anchor can be referenced
anchorRef: &anchor can be clicked as well
# Press control while hovering over the anchor
anchorPointer: *anchor
formatting: Formatting is supported too! Under the hood this is powered by Prettier. Just press Ctrl+Shift+I or right click and press Format to format this document.
`.replace(/:$/m, ': ');
const ed = editor.create(document.getElementById('editor'), {
automaticLayout: true,
model: editor.createModel(value, 'yaml', Uri.parse('monaco-yaml.yaml')),
theme: window.matchMedia('(prefers-color-scheme: dark)').matches ? 'vs-dark' : 'vs-light',
});
const select = document.getElementById('schema-selection') as HTMLSelectElement;
fetch('https://www.schemastore.org/api/json/catalog.json').then(async (response) => {
if (!response.ok) {
return;
}
const catalog = (await response.json()) as JSONSchemaForSchemaStoreOrgCatalogFiles;
const schemas = [defaultSchema];
catalog.schemas.sort((a, b) => a.name.localeCompare(b.name));
for (const { fileMatch, name, url } of catalog.schemas) {
const match =
typeof name === 'string' && fileMatch?.find((filename) => /\.ya?ml$/i.test(filename));
if (!match) {
continue;
}
const option = document.createElement('option');
option.value = match;
option.textContent = name;
select.append(option);
schemas.push({
fileMatch: [match],
uri: url,
});
}
setDiagnosticsOptions({
validate: true,
enableSchemaRequest: true,
format: true,
hover: true,
completion: true,
schemas,
});
});
select.addEventListener('change', () => {
const oldModel = ed.getModel();
const newModel = editor.createModel(oldModel.getValue(), 'yaml', Uri.parse(select.value));
ed.setModel(newModel);
oldModel.dispose();
});
function* iterateSymbols(
symbols: languages.DocumentSymbol[],
position: Position,
): Iterable<languages.DocumentSymbol> {
for (const symbol of symbols) {
if (Range.containsPosition(symbol.range, position)) {
yield symbol;
yield* iterateSymbols(symbol.children, position);
}
}
}
ed.onDidChangeCursorPosition(async (event) => {
const breadcrumbs = document.getElementById('breadcrumbs');
const symbols = await getDocumentSymbols(ed.getModel(), false, CancellationToken.None);
while (breadcrumbs.lastChild) {
breadcrumbs.lastChild.remove();
}
for (const symbol of iterateSymbols(symbols, event.position)) {
const breadcrumb = document.createElement('span');
breadcrumb.setAttribute('role', 'button');
breadcrumb.classList.add('breadcrumb');
breadcrumb.textContent = symbol.name;
breadcrumb.title = symbol.detail;
if (symbol.kind === languages.SymbolKind.Array) {
breadcrumb.classList.add('array');
} else if (symbol.kind === languages.SymbolKind.Module) {
breadcrumb.classList.add('object');
}
breadcrumb.addEventListener('click', () => {
ed.setPosition({
lineNumber: symbol.range.startLineNumber,
column: symbol.range.startColumn,
});
ed.focus();
});
breadcrumbs.append(breadcrumb);
}
});
editor.onDidChangeMarkers(([resource]) => {
const problems = document.getElementById('problems');
const markers = editor.getModelMarkers({ resource });
while (problems.lastChild) {
problems.lastChild.remove();
}
for (const marker of markers) {
const wrapper = document.createElement('div');
wrapper.setAttribute('role', 'button');
const codicon = document.createElement('div');
const text = document.createElement('div');
wrapper.classList.add('problem');
codicon.classList.add('codicon', 'codicon-warning');
text.classList.add('problem-text');
text.textContent = marker.message;
wrapper.append(codicon, text);
wrapper.addEventListener('click', () => {
ed.setPosition({ lineNumber: marker.startLineNumber, column: marker.startColumn });
ed.focus();
});
problems.append(wrapper);
}
});

View file

@ -0,0 +1,41 @@
{
"type": "object",
"properties": {
"property": {
"description": "I have a description"
},
"titledProperty": {
"title": "I have a title",
"description": "I also have a description"
},
"markdown": {
"markdownDescription": "Even **markdown** _descriptions_ `are` ~~not~~ supported!"
},
"enum": {
"description": "Pick your starter",
"enum": ["Bulbasaur", "Squirtle", "Charmander", "Pikachu"]
},
"number": {
"description": "Numbers work!",
"minimum": 42,
"maximum": 1337
},
"boolean": {
"description": "Are boolean supported?",
"type": "boolean"
},
"string": {
"type": "string"
},
"reference": {
"description": "JSON schemas can be referenced, even recursively",
"$ref": "#"
},
"array": {
"description": "It also works in arrays",
"items": {
"$ref": "#"
}
}
}
}

29
examples/demo/src/types.d.ts vendored Normal file
View file

@ -0,0 +1,29 @@
declare module 'monaco-editor/esm/vs/base/common/cancellation' {
export enum CancellationToken {
None,
}
}
declare module 'monaco-editor/esm/vs/editor/contrib/documentSymbols/documentSymbols' {
import { ITextModel, languages } from 'monaco-editor';
import { CancellationToken } from 'monaco-editor/esm/vs/base/common/cancellation';
export function getDocumentSymbols(
model: ITextModel,
flat: boolean,
token: CancellationToken,
): Promise<languages.DocumentSymbol[]>;
}
declare module 'monaco-editor/esm/vs/editor/editor.worker.js' {
import { worker } from 'monaco-editor/esm/vs/editor/editor.api';
export function initialize(
fn: (ctx: worker.IWorkerContext, createData: unknown) => unknown,
): void;
}
declare module '*.json' {
declare const uri: string;
export default uri;
}

View file

@ -0,0 +1,39 @@
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const HtmlWebPackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
output: {
filename: '[contenthash].js',
},
devtool: 'source-map',
resolve: {
extensions: ['.mjs', '.js', '.ts'],
},
module: {
rules: [
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
{
// Monaco editor uses .ttf icons.
test: /\.(svg|ttf)$/,
type: 'asset/resource',
},
{
test: /schema\.json$/,
type: 'asset/resource',
},
{
test: /\.ts$/,
loader: 'ts-loader',
options: { transpileOnly: true },
},
],
},
optimization: {
minimizer: ['...', new CssMinimizerPlugin()],
},
plugins: [new HtmlWebPackPlugin(), new MiniCssExtractPlugin({ filename: '[contenthash].css' })],
};

View file

@ -0,0 +1,35 @@
# Monaco Editor Webpack Loader Plugin Example
This demo demonstrates how bundle `monaco-editor` and `monaco-yaml` with
[monaco-editor-webpack-plugin](https://github.com/microsoft/monaco-editor/tree/main/webpack-plugin).
The build output is
[esm library](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules). Example is
based on
[link](https://github.com/microsoft/monaco-editor/tree/main/samples/browser-esm-webpack-monaco-plugin).
To start it, simply run:
## Prerequisites
- [NodeJS](https://nodejs.org) 16 or higher
- [npm](https://github.com/npm/cli) 8.1.2 or higher
## Setup
To run the project locally, clone the repository and set it up:
```sh
git clone https://github.com/remcohaszing/monaco-yaml
cd monaco-yaml
npm ci
npm run prepack
```
## Running
To start it, simply run:
```sh
npm --workspace monaco-editor-webpack-plugin-example start
```
The demo will open in your browser.

View file

@ -0,0 +1,4 @@
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js';
export { setDiagnosticsOptions } from 'monaco-yaml';
export default monaco;

View file

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Monaco Editor Webpack Plugin Example</title>
<style>
.editor {
width: 800px;
height: 600px;
border: 1px solid #ccc;
}
</style>
</head>
<body>
<div class="editor"></div>
<script src="index.js" type="module"></script>
</body>
</html>

View file

@ -0,0 +1,37 @@
const value = `
number: 0xfe
boolean: true
`;
async function create() {
// Dynamic import is possible
const { default: monaco } = await import('./main.js');
// Define schema first
monaco.languages.yaml.yamlDefaults.setDiagnosticsOptions({
schemas: [
{
fileMatch: ['*'],
uri: 'my-schema.json',
schema: {
type: 'object',
properties: {
number: {
description: 'number property',
type: 'number',
},
},
},
},
],
});
// Create editor
monaco.editor.create(document.querySelector('.editor'), {
language: 'yaml',
tabSize: 2,
value,
});
}
create();

View file

@ -0,0 +1,20 @@
{
"name": "monaco-editor-webpack-plugin-example",
"version": "1.0.0",
"private": true,
"type": "module",
"scripts": {
"start": "webpack serve --open --mode development",
"build": "webpack --mode production"
},
"dependencies": {
"css-loader": "^6.0.0",
"monaco-editor": "^0.31.0",
"monaco-editor-webpack-plugin": "^7.0.0",
"monaco-yaml": "file:../..",
"style-loader": "^3.0.0",
"webpack": "^5.0.0",
"webpack-cli": "^4.0.0",
"webpack-dev-server": "^4.0.0"
}
}

View file

@ -0,0 +1,49 @@
import MonacoWebpackPlugin from 'monaco-editor-webpack-plugin';
export default {
entry: './editor.js',
output: {
filename: '[name].js',
library: {
type: 'module',
},
clean: true,
},
target: 'es2020',
experiments: {
outputModule: true,
},
devtool: 'source-map',
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.ttf$/,
type: 'asset',
},
],
},
plugins: [
new MonacoWebpackPlugin({
languages: [],
customLanguages: [
{
label: 'yaml',
entry: ['monaco-yaml', 'vs/basic-languages/yaml/yaml.contribution'],
worker: {
id: 'monaco-yaml/yamlWorker',
entry: 'monaco-yaml/yaml.worker',
},
},
],
}),
],
devServer: {
static: {
directory: './',
},
},
};

View file

@ -1,3 +0,0 @@
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}

View file

@ -1,2 +0,0 @@
dist/
node_modules/

View file

@ -1,9 +0,0 @@
# Demo: React + Weback + Worker Loader + Babel
To run:
```
yarn && yarn start
```
The demo will open in your browser. See (index.jsx)[index.jsx#L34-L36] for the schema loaded.

View file

@ -1,10 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>React Example</title>
</head>
<body>
<div id="react"></div>
</body>
</html>

View file

@ -1,80 +0,0 @@
import React, { useEffect, useState } from 'react';
import ReactDOM from 'react-dom';
import MonacoEditor from 'react-monaco-editor';
import 'monaco-yaml/lib/esm/monaco.contribution';
import { languages } from 'monaco-editor/esm/vs/editor/editor.api';
// NOTE: This will give you all editor featues. If you would prefer to limit to only the editor
// features you want to use, import them each individually. See this example: (https://github.com/microsoft/monaco-editor-samples/blob/master/browser-esm-webpack-small/index.js#L1-L91)
import 'monaco-editor';
// NOTE: using loader syntax becuase Yaml worker imports editor.worker directly and that
// import shouldn't go through loader syntax.
import EditorWorker from 'worker-loader!monaco-editor/esm/vs/editor/editor.worker';
import YamlWorker from 'worker-loader!monaco-yaml/lib/esm/yaml.worker';
window.MonacoEnvironment = {
getWorker(workerId, label) {
if (label === 'yaml') {
return new YamlWorker();
}
return new EditorWorker();
},
};
const { yaml } = languages || {};
const Editor = () => {
const [value, setValue] = useState('p1: ');
useEffect(() => {
yaml &&
yaml.yamlDefaults.setDiagnosticsOptions({
validate: true,
enableSchemaRequest: true,
hover: true,
completion: true,
schemas: [
{
uri: 'http://myserver/foo-schema.json', // id of the first schema
fileMatch: ['*'], // associate with our model
schema: {
id: 'http://myserver/foo-schema.json', // id of the first schema
type: 'object',
properties: {
p1: {
enum: ['v1', 'v2'],
},
p2: {
$ref: 'http://myserver/bar-schema.json', // reference the second schema
},
},
},
},
{
uri: 'http://myserver/bar-schema.json', // id of the first schema
schema: {
id: 'http://myserver/bar-schema.json', // id of the first schema
type: 'object',
properties: {
q1: {
enum: ['x1', 'x2'],
},
},
},
},
],
});
}, []);
return (
<MonacoEditor
width="800"
height="600"
language="yaml"
value={value}
onChange={setValue}
/>
);
};
ReactDOM.render(<Editor />, document.getElementById('react'));

View file

@ -1,31 +0,0 @@
{
"name": "react-webpack-worker-loader-example",
"version": "1.0.0",
"description": "",
"private": true,
"main": "index.js",
"scripts": {
"start": "webpack-dev-server --open --mode development",
"build": "webpack --mode production"
},
"author": "",
"devDependencies": {
"@babel/core": "^7.8.4",
"@babel/preset-env": "^7.8.4",
"@babel/preset-react": "^7.8.3",
"babel-loader": "^8.0.6",
"css-loader": "^3.4.2",
"file-loader": "^5.1.0",
"html-webpack-plugin": "^3.2.0",
"monaco-editor": "^0.20.0",
"monaco-yaml": "file:../..",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-monaco-editor": "^0.34.0",
"style-loader": "^1.1.3",
"webpack": "^4.41.6",
"webpack-cli": "^3.3.11",
"webpack-dev-server": "^3.10.3",
"worker-loader": "^2.0.0"
}
}

View file

@ -1,41 +0,0 @@
const HtmlWebPackPlugin = require('html-webpack-plugin');
const path = require('path');
module.exports = {
entry: {
main: './index.jsx',
},
output: {
globalObject: 'this',
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.ttf$/,
loader: 'file-loader',
},
],
},
plugins: [
new HtmlWebPackPlugin({
template: './index.html',
}),
],
node: {
fs: 'empty',
module: 'empty',
},
};

File diff suppressed because it is too large Load diff

View file

@ -1,3 +0,0 @@
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}

View file

@ -1,2 +0,0 @@
dist/
node_modules/

View file

@ -1,9 +0,0 @@
# Demo: React + Weback + Babel
To run:
```
yarn && yarn start
```
The demo will open in your browser. See (index.jsx)[index.jsx#L34-L36] for the schema loaded.

View file

@ -1,10 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>React Example</title>
</head>
<body>
<div id="react"></div>
</body>
</html>

View file

@ -1,75 +0,0 @@
import React, { useEffect, useState } from 'react';
import ReactDOM from 'react-dom';
import MonacoEditor from 'react-monaco-editor';
import 'monaco-yaml/lib/esm/monaco.contribution';
import { languages } from 'monaco-editor/esm/vs/editor/editor.api';
// NOTE: This will give you all editor featues. If you would prefer to limit to only the editor
// features you want to use, import them each individually. See this example: (https://github.com/microsoft/monaco-editor-samples/blob/master/browser-esm-webpack-small/index.js#L1-L91)
import 'monaco-editor';
window.MonacoEnvironment = {
getWorkerUrl(moduleId, label) {
if (label === 'yaml') {
return './yaml.worker.bundle.js';
}
return './editor.worker.bundle.js';
},
};
const { yaml } = languages || {};
const Editor = () => {
const [value, setValue] = useState('p1: ');
useEffect(() => {
yaml &&
yaml.yamlDefaults.setDiagnosticsOptions({
validate: true,
enableSchemaRequest: true,
hover: true,
completion: true,
schemas: [
{
uri: 'http://myserver/foo-schema.json', // id of the first schema
fileMatch: ['*'], // associate with our model
schema: {
id: 'http://myserver/foo-schema.json', // id of the first schema
type: 'object',
properties: {
p1: {
enum: ['v1', 'v2'],
},
p2: {
$ref: 'http://myserver/bar-schema.json', // reference the second schema
},
},
},
},
{
uri: 'http://myserver/bar-schema.json', // id of the first schema
schema: {
id: 'http://myserver/bar-schema.json', // id of the first schema
type: 'object',
properties: {
q1: {
enum: ['x1', 'x2'],
},
},
},
},
],
});
}, []);
return (
<MonacoEditor
width="800"
height="600"
language="yaml"
value={value}
onChange={setValue}
/>
);
};
ReactDOM.render(<Editor />, document.getElementById('react'));

View file

@ -1,30 +0,0 @@
{
"name": "react-webpack-example",
"version": "1.0.0",
"description": "",
"private": true,
"main": "index.js",
"scripts": {
"start": "webpack-dev-server --open --mode development",
"build": "webpack --mode production"
},
"author": "",
"devDependencies": {
"@babel/core": "^7.8.4",
"@babel/preset-env": "^7.8.4",
"@babel/preset-react": "^7.8.3",
"babel-loader": "^8.0.6",
"css-loader": "^3.4.2",
"file-loader": "^5.1.0",
"html-webpack-plugin": "^3.2.0",
"monaco-editor": "^0.20.0",
"monaco-yaml": "file:../..",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-monaco-editor": "^0.34.0",
"style-loader": "^1.1.3",
"webpack": "^4.41.6",
"webpack-cli": "^3.3.11",
"webpack-dev-server": "^3.10.3"
}
}

View file

@ -1,43 +0,0 @@
const HtmlWebPackPlugin = require('html-webpack-plugin');
const path = require('path');
module.exports = {
entry: {
main: './index.jsx',
'editor.worker': 'monaco-editor/esm/vs/editor/editor.worker.js',
'yaml.worker': 'monaco-yaml/lib/esm/yaml.worker.js',
},
output: {
globalObject: 'this',
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.ttf$/,
loader: 'file-loader',
},
],
},
plugins: [
new HtmlWebPackPlugin({
template: './index.html',
}),
],
node: {
fs: 'empty',
module: 'empty',
},
};

File diff suppressed because it is too large Load diff

View file

@ -1,162 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<link
rel="stylesheet"
data-name="vs/editor/editor.main"
href="../node_modules/monaco-editor-core/dev/vs/editor/editor.main.css"
/>
</head>
<body>
<h2>Monaco Editor YAML test page</h2>
<code id="path"></code>
<div
id="container"
style="width:800px;height:600px;border:1px solid grey"
></div>
<style>
.x-highlight-range {
background-color: lightblue;
}
</style>
<script>
// Loading basic-languages to get the YAML language definition
var paths = {
'vs/basic-languages': '../node_modules/monaco-languages/release/dev',
'vs/language/yaml': '../lib/dev',
vs: '../node_modules/monaco-editor-core/dev/vs',
prettier: '../node_modules/prettier',
};
if (document.location.protocol === 'http:') {
// Add support for running local http server
let testIndex = document.location.pathname.indexOf('/test/');
if (testIndex !== -1) {
let prefix = document.location.pathname.substr(0, testIndex);
paths['vs/language/yaml'] = prefix + '/lib/dev';
}
}
var require = {
paths: paths,
};
</script>
<script src="../node_modules/monaco-editor-core/dev/vs/loader.js"></script>
<script src="../node_modules/monaco-editor-core/dev/vs/editor/editor.main.nls.js"></script>
<script src="../node_modules/monaco-editor-core/dev/vs/editor/editor.main.js"></script>
<script>
require([
'vs/basic-languages/monaco.contribution',
'vs/language/yaml/monaco.contribution',
'prettier/standalone',
'prettier/parser-yaml',
], function() {
const yaml = `p1: `;
const modelUri = monaco.Uri.parse('a://b/foo.json');
const editor = monaco.editor.create(
document.getElementById('container'),
{
language: 'yaml',
showFoldingControls: 'always',
model: monaco.editor.createModel(yaml, 'yaml', modelUri),
}
);
monaco.languages.yaml.yamlDefaults.setDiagnosticsOptions({
enableSchemaRequest: true,
hover: true,
completion: true,
validate: true,
format: true,
schemas: [
{
uri: 'http://myserver/foo-schema.json', // id of the first schema
fileMatch: [modelUri.toString()], // associate with our model
schema: {
type: 'object',
properties: {
p1: {
enum: ['v1', 'v2'],
},
p2: {
$ref: 'http://myserver/bar-schema.json', // reference the second schema
},
},
},
},
{
uri: 'http://myserver/bar-schema.json', // id of the first schema
schema: {
type: 'object',
properties: {
q1: {
enum: ['x1', 'x2'],
},
},
},
},
],
});
require(['vs/editor/contrib/quickOpen/quickOpen'], async quickOpen => {
const NEVER_CANCEL_TOKEN = {
isCancellationRequested: false,
onCancellationRequested: () => Event.NONE,
};
let oldDecorations = [];
async function _getSymbolForPosition(model, position) {
const symbols = await quickOpen.getDocumentSymbols(
model,
false,
NEVER_CANCEL_TOKEN
);
function _recur(symbol) {
let target = symbol;
if (symbol && symbol.children && symbol.children.length) {
target =
_recur(
symbol.children.find(child =>
child.range.containsPosition(position)
)
) || symbol;
}
return target;
}
return _recur({ children: symbols });
}
editor.onDidChangeCursorSelection(async ({ selection }) => {
const model = editor.getModel();
const position = selection.getPosition();
const symbol = await _getSymbolForPosition(model, position);
console.log(`${symbol.name}: ${symbol.range}`);
if (symbol && symbol.range) {
const decoration = {
range: symbol.range,
options: {
isWholeLine: false,
className: 'x-highlight-range',
},
};
oldDecorations = editor.deltaDecorations(
oldDecorations,
decoration ? [decoration] : []
);
}
});
});
});
</script>
</body>
</html>

View file

@ -0,0 +1,29 @@
# Vite Example
This minimal example shows how `monaco-yaml` can be used with [Vite](https://vitejs.dev).
## Prerequisites
- [NodeJS](https://nodejs.org) 16 or higher
- [npm](https://github.com/npm/cli) 8.1.2 or higher
## Setup
To run the project locally, clone the repository and set it up:
```sh
git clone https://github.com/remcohaszing/monaco-yaml
cd monaco-yaml
npm ci
npm run prepack
```
## Running
To start it, simply run:
```sh
npm --workspace vite-example start
```
The demo will be available on http://localhost:3000.

View file

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Monaco YAML</title>
</head>
<body>
<div id="editor" style="width: 800px; height: 600px;"></div>
<script type="module" src="/index.js"></script>
</body>
</html>

View file

@ -0,0 +1,67 @@
import { editor, Uri } from 'monaco-editor';
import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker';
import { setDiagnosticsOptions } from 'monaco-yaml';
import YamlWorker from 'monaco-yaml/yaml.worker?worker';
window.MonacoEnvironment = {
getWorker(moduleId, label) {
switch (label) {
case 'editorWorkerService':
return new EditorWorker();
case 'yaml':
return new YamlWorker();
default:
throw new Error(`Unknown label ${label}`);
}
},
};
// The uri is used for the schema file match.
const modelUri = Uri.parse('a://b/foo.yaml');
setDiagnosticsOptions({
enableSchemaRequest: true,
hover: true,
completion: true,
validate: true,
format: true,
schemas: [
{
// Id of the first schema
uri: 'http://myserver/foo-schema.json',
// Associate with our model
fileMatch: [String(modelUri)],
schema: {
type: 'object',
properties: {
p1: {
enum: ['v1', 'v2'],
},
p2: {
// Reference the second schema
$ref: 'http://myserver/bar-schema.json',
},
},
},
},
{
// Id of the first schema
uri: 'http://myserver/bar-schema.json',
schema: {
type: 'object',
properties: {
q1: {
enum: ['x1', 'x2'],
},
},
},
},
],
});
const value = 'p1: \np2: \n';
editor.create(document.getElementById('editor'), {
automaticLayout: true,
model: editor.createModel(value, 'yaml', modelUri),
});

View file

@ -0,0 +1,14 @@
{
"name": "vite-example",
"version": "1.0.0",
"private": true,
"scripts": {
"start": "vite",
"build": "vite build"
},
"dependencies": {
"monaco-editor": "^0.31.0",
"monaco-yaml": "file:../..",
"vite": "^2.0.0"
}
}

112
index.d.ts vendored Normal file
View file

@ -0,0 +1,112 @@
import { JSONSchema4, JSONSchema6, JSONSchema7 } from 'json-schema';
import { IEvent, languages } from 'monaco-editor/esm/vs/editor/editor.api';
export interface SchemasSettings {
/**
* A `Uri` file match which will trigger the schema validation. This may be a glob or an exact
* path.
*
* @example '.gitlab-ci.yml'
* @example 'file://**\/.github/actions/*.yaml'
*/
fileMatch: string[];
/**
* The JSON schema which will be used for validation. If not specified, it will be downloaded from
* `uri`.
*/
schema?: JSONSchema4 | JSONSchema6 | JSONSchema7;
/**
* The source URI of the JSON schema. The JSON schema will be downloaded from here if no schema
* was supplied. It will also be displayed as the source in hover tooltips.
*/
uri: string;
}
declare module 'monaco-editor/esm/vs/editor/editor.api' {
namespace languages.yaml {
export interface DiagnosticsOptions {
/**
* If set, enable schema based autocompletion.
*
* @default true
*/
readonly completion?: boolean;
/**
* A list of custom tags.
*
* @default []
*/
readonly customTags?: string[];
/**
* If set, the schema service would load schema content on-demand with 'fetch' if available
*
* @default false
*/
readonly enableSchemaRequest?: boolean;
/**
* If true, formatting using Prettier is enabled. Setting this to `false` does **not** exclude
* Prettier from the bundle.
*
* @default true
*/
readonly format?: boolean;
/**
* If set, enable hover typs based the JSON schema.
*
* @default true
*/
readonly hover?: boolean;
/**
* If true, a different diffing algorithm is used to generate error messages.
*
* @default false
*/
readonly isKubernetes?: boolean;
/**
* A list of known schemas and/or associations of schemas to file names.
*
* @default []
*/
readonly schemas?: SchemasSettings[];
/**
* If set, the validator will be enabled and perform syntax validation as well as schema
* based validation.
*
* @default true
*/
readonly validate?: boolean;
/**
* The YAML version to use for parsing.
*
* @default '1.2'
*/
readonly yamlVersion?: '1.1' | '1.2';
}
export interface LanguageServiceDefaults {
readonly onDidChange: IEvent<LanguageServiceDefaults>;
readonly languageId: string;
readonly diagnosticsOptions: DiagnosticsOptions;
setDiagnosticsOptions: (options: DiagnosticsOptions) => void;
}
export const yamlDefaults: LanguageServiceDefaults;
}
}
/**
* Configure `monaco-yaml` diagnostics options.
*
* @param options - The options to set.
*/
export function setDiagnosticsOptions(options?: languages.yaml.DiagnosticsOptions): void;

3
netlify.toml Normal file
View file

@ -0,0 +1,3 @@
[build]
publish = 'examples/demo/dist/'
command = 'npm ci && npm run prepack && npm --workspace demo run build'

8500
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,91 +1,71 @@
{
"name": "monaco-yaml",
"version": "2.5.0",
"version": "4.0.0-alpha.1",
"description": "YAML plugin for the Monaco Editor",
"homepage": "https://monaco-yaml.js.org",
"scripts": {
"watch": "tsc -p ./src --watch",
"compile": "rimraf ./out && yarn compile:umd && yarn compile:esm",
"compile:umd": "tsc -p ./tsconfig.json",
"compile:esm": "tsc -p ./tsconfig.esm.json",
"bundle": "rimraf ./lib && yarn bundle:umd && yarn bundle:esm && mcopy ./src/monaco.d.ts ./lib/monaco.d.ts",
"bundle:umd": "node ./scripts/bundle-umd",
"bundle:esm": "node ./scripts/bundle-esm",
"build": "yarn compile && yarn bundle",
"prepare": "yarn build",
"lint": "prettier \"{src,test}/**/*.{json,scss,html,ts}\" --write",
"test": "jest --verbose"
},
"main": "./lib/esm/monaco.contribution.js",
"module": "./lib/esm/monaco.contribution.js",
"typings": "./lib/monaco.d.ts",
"directories": {
"lib": "./lib"
"prepack": "node build.js",
"prepare": "husky install"
},
"typings": "./index.d.ts",
"files": [
"index.js",
"index.d.ts",
"yaml.worker.js"
],
"workspaces": [
"examples/*"
],
"author": "Kevin Decker <kpdecker@gmail.com> (http://incaseofstairs.com)",
"maintainers": [
"kpdecker",
"pengx17"
"Remco Haszing <remcohaszing@gmail.com> (https://github.com/remcohaszing)"
],
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/pengx17/monaco-yaml"
"url": "https://github.com/remcohaszing/monaco-yaml"
},
"bugs": {
"url": "https://github.com/pengx17/monaco-yaml/issues"
"url": "https://github.com/remcohaszing/monaco-yaml/issues"
},
"keywords": [
"editor",
"frontend",
"front-end",
"monaco",
"monaco-editor",
"yaml"
],
"dependencies": {
"yaml-language-server": "^0.11.1"
"@types/json-schema": "^7.0.0",
"jsonc-parser": "^3.0.0",
"path-browserify": "^1.0.0",
"prettier": "2.0.5",
"vscode-languageserver-textdocument": "^1.0.0",
"vscode-languageserver-types": "^3.0.0",
"yaml": "2.0.0-10"
},
"peerDependencies": {
"monaco-editor": ">=0.30"
},
"devDependencies": {
"@types/jest": "^23.3.10",
"@types/node": "^12.12.6",
"husky": "^1.2.1",
"jest": "^23.6.0",
"lint-staged": "^10.1.2",
"monaco-editor": "^0.21.2",
"monaco-editor-core": "^0.21.2",
"monaco-languages": "^2.1.1",
"monaco-plugin-helpers": "^1.0.3",
"prettier": "^1.19.1",
"requirejs": "^2.3.6",
"rimraf": "^2.6.2",
"ts-jest": "^23.10.5",
"typescript": "^3.8.3",
"typescript-tslint-plugin": "^0.5.5",
"eslint": "^6.8.0",
"uglify-es": "^3.3.9"
},
"prettier": {
"singleQuote": true,
"trailingComma": "es5",
"semi": true
"@typescript-eslint/eslint-plugin": "^5.0.0",
"esbuild": "^0.14.0",
"eslint": "^7.0.0",
"eslint-config-remcohaszing": "^3.0.0",
"husky": "^7.0.0",
"lint-staged": "^12.0.0",
"monaco-editor": "^0.31.0",
"type-fest": "^2.0.0",
"typescript": "^4.0.0",
"yaml-language-server": "^1.0.0"
},
"lint-staged": {
"src/*.{json,scss,html,ts,js,jsx}|scripts/*.js": [
"*.{css,json,md,html,yaml}": [
"prettier --write"
]
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"jest": {
"globals": {
"ts-jest": {
"tsConfig": "./test/tsconfig.json"
}
},
"moduleFileExtensions": [
"js",
"ts"
],
"transform": {
"^.+\\.(ts|tsx)$": "ts-jest"
},
"testMatch": [
"**/test/*.test.+(ts|js)"
"*.{js,ts}": [
"eslint"
]
}
}

View file

@ -1,70 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const path = require('path');
const helpers = require('monaco-plugin-helpers');
const REPO_ROOT = path.join(__dirname, '../');
helpers.packageESM({
repoRoot: REPO_ROOT,
esmSource: 'out/esm',
esmDestination: 'lib/esm',
entryPoints: ['monaco.contribution.js', 'yamlMode.js', 'yaml.worker.js'],
resolveAlias: {
'vscode-nls': path.join(REPO_ROOT, 'out/esm/fillers/vscode-nls.js'),
'vscode-json-languageservice/lib/umd/services/jsonValidation': path.join(
REPO_ROOT,
'node_modules/vscode-json-languageservice/lib/esm/services/jsonValidation.js'
),
'vscode-json-languageservice': path.join(
REPO_ROOT,
'node_modules/vscode-json-languageservice/lib/esm/jsonLanguageService.js'
),
'vscode-json-languageservice/lib/umd/services/jsonHover': path.join(
REPO_ROOT,
'node_modules/vscode-json-languageservice/lib/esm/services/jsonHover.js'
),
'vscode-json-languageservice/lib/umd/services/jsonDocumentSymbols': path.join(
REPO_ROOT,
'node_modules/vscode-json-languageservice/lib/esm/services/jsonDocumentSymbols.js'
),
'vscode-json-languageservice/lib/umd/services/jsonSchemaService': path.join(
REPO_ROOT,
'node_modules/vscode-json-languageservice/lib/esm/services/jsonSchemaService.js'
),
'vscode-json-languageservice/lib/umd/services/jsonCompletion': path.join(
REPO_ROOT,
'node_modules/vscode-json-languageservice/lib/esm/services/jsonCompletion.js'
),
'vscode-json-languageservice/lib/umd/services/jsonDefinition': path.join(
REPO_ROOT,
'node_modules/vscode-json-languageservice/lib/esm/services/jsonDefinition.js'
),
'yaml-language-server': path.join(
REPO_ROOT,
'node_modules/yaml-language-server/lib/esm/languageservice/yamlLanguageService.js'
),
prettier: path.join(REPO_ROOT, 'node_modules/prettier/standalone.js'),
'prettier/parser-yaml': path.join(
REPO_ROOT,
'node_modules/prettier/parser-yaml.js'
),
},
resolveSkip: [
'monaco-editor',
'monaco-editor-core',
'js-yaml',
'yaml-ast-parser-custom-tags',
],
destinationFolderSimplification: {
node_modules: '_deps',
'jsonc-parser/lib/esm': 'jsonc-parser',
'vscode-languageserver-types/lib/esm': 'vscode-languageserver-types',
'vscode-uri/lib/esm': 'vscode-uri',
},
});

View file

@ -1,75 +0,0 @@
const requirejs = require('requirejs');
const path = require('path');
const fs = require('fs');
const uglifyES = require('uglify-es');
const helpers = require('monaco-plugin-helpers');
const REPO_ROOT = path.resolve(__dirname, '..');
const sha1 = helpers.getGitVersion(REPO_ROOT);
const semver = require('../package.json').version;
const headerVersion = semver + '(' + sha1 + ')';
const BUNDLED_FILE_HEADER = [
'/*!-----------------------------------------------------------------------------',
' * Copyright (c) Microsoft Corporation. All rights reserved.',
' * monaco-yaml version: ' + headerVersion,
' * Released under the MIT license',
' * https://github.com/kpdecker/monaco-yaml/blob/master/LICENSE.md',
' *-----------------------------------------------------------------------------*/',
'',
].join('\n');
bundleOne('monaco.contribution');
bundleOne('yamlMode');
bundleOne('yamlWorker');
function bundleOne(moduleId, exclude) {
requirejs.optimize(
{
baseUrl: 'out/amd/',
name: 'vs/language/yaml/' + moduleId,
out: 'lib/dev/' + moduleId + '.js',
exclude: exclude,
paths: {
'vs/language/yaml': REPO_ROOT + '/out/amd',
},
optimize: 'none',
packages: [
{
name: 'vscode-languageserver-types',
location: path.join(
REPO_ROOT,
'node_modules/vscode-languageserver-types/lib/umd'
),
main: 'main',
},
{
name: 'yaml-language-server',
location: path.join(
REPO_ROOT,
'node_modules/yaml-language-server/out/server/src'
),
main: 'index',
},
],
},
function() {
const devFilePath = path.join(REPO_ROOT, 'lib/dev/' + moduleId + '.js');
const minFilePath = path.join(REPO_ROOT, 'lib/min/' + moduleId + '.js');
const fileContents = fs.readFileSync(devFilePath).toString();
console.log();
console.log(`Minifying ${devFilePath}...`);
const result = uglifyES.minify(fileContents, {
output: {
comments: 'some',
},
});
console.log(`Done.`);
try {
fs.mkdirSync(path.join(REPO_ROOT, 'lib/min'));
} catch (err) {}
fs.writeFileSync(minFilePath, BUNDLED_FILE_HEADER + result.code);
}
);
}

1
src/constants.ts Normal file
View file

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

View file

@ -1 +0,0 @@
export const EOL = '\n';

View file

@ -0,0 +1,5 @@
/**
* This is a stub for `monaco-yaml/lib/esm/schemaSelectionHandlers.js`.
*/
// eslint-disable-next-line @typescript-eslint/no-empty-function
export function JSONSchemaSelection(): void {}

View file

@ -1,8 +1,3 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export interface Options {
locale?: string;
cacheLanguageResolution?: boolean;
@ -11,38 +6,30 @@ export interface LocalizeInfo {
key: string;
comment: string[];
}
export interface LocalizeFunc {
(info: LocalizeInfo, message: string, ...args: any[]): string;
(key: string, message: string, ...args: any[]): string;
}
export type LocalizeFunc = (
info: LocalizeInfo | string,
message: string,
...args: unknown[]
) => string;
export type LoadFunc = (file?: string) => LocalizeFunc;
function format(message: string, args: any[]): string {
let result: string;
if (args.length === 0) {
result = message;
} else {
result = message.replace(/\{(\d+)\}/g, (match, rest) => {
const index = rest[0];
return typeof args[index] !== 'undefined' ? args[index] : match;
});
}
return result;
function format(message: string, args: string[]): string {
return args.length === 0
? message
: message.replace(/{(\d+)}/g, (match, rest: number[]) => {
const [index] = rest;
return typeof args[index] === 'undefined' ? match : args[index];
});
}
function localize(
key: string | LocalizeInfo,
message: string,
...args: any[]
): string {
function localize(key: LocalizeInfo | string, message: string, ...args: string[]): string {
return format(message, args);
}
export function loadMessageBundle(file?: string): LocalizeFunc {
export function loadMessageBundle(): LocalizeFunc {
return localize;
}
export function config(opt?: Options | string): LoadFunc {
export function config(): LoadFunc {
return loadMessageBundle;
}

78
src/index.ts Normal file
View file

@ -0,0 +1,78 @@
import { Emitter, languages } from 'monaco-editor/esm/vs/editor/editor.api.js';
import { languageId } from './constants';
import { setupMode } from './yamlMode';
// --- YAML configuration and defaults ---------
const diagnosticDefault: languages.yaml.DiagnosticsOptions = {
completion: true,
customTags: [],
enableSchemaRequest: false,
format: true,
isKubernetes: false,
hover: true,
schemas: [],
validate: true,
yamlVersion: '1.2',
};
export function createLanguageServiceDefaults(
initialDiagnosticsOptions: languages.yaml.DiagnosticsOptions,
): languages.yaml.LanguageServiceDefaults {
const onDidChange = new Emitter<languages.yaml.LanguageServiceDefaults>();
let diagnosticsOptions = initialDiagnosticsOptions;
const languageServiceDefaults: languages.yaml.LanguageServiceDefaults = {
get onDidChange() {
return onDidChange.event;
},
get languageId() {
return languageId;
},
get diagnosticsOptions() {
return diagnosticsOptions;
},
setDiagnosticsOptions(options) {
diagnosticsOptions = { ...diagnosticDefault, ...options };
onDidChange.fire(languageServiceDefaults);
},
};
return languageServiceDefaults;
}
const yamlDefaults = createLanguageServiceDefaults(diagnosticDefault);
// Export API
function createAPI(): typeof languages.yaml {
return {
yamlDefaults,
};
}
languages.yaml = createAPI();
// --- Registration to monaco editor ---
languages.register({
id: languageId,
extensions: ['.yaml', '.yml'],
aliases: ['YAML', 'yaml', 'YML', 'yml'],
mimetypes: ['application/x-yaml'],
});
languages.onLanguage('yaml', () => {
setupMode(yamlDefaults);
});
/**
* Configure `monaco-yaml` diagnostics options.
*
* @param options - The options to set.
*/
export function setDiagnosticsOptions(options: languages.yaml.DiagnosticsOptions = {}): void {
languages.yaml.yamlDefaults.setDiagnosticsOptions(options);
}

View file

@ -1,149 +1,49 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import {
editor,
IDisposable,
languages,
MarkerSeverity,
MarkerTag,
Position,
Range,
Uri,
} from 'monaco-editor/esm/vs/editor/editor.api.js';
import * as ls from 'vscode-languageserver-types';
import { CustomFormatterOptions } from 'yaml-language-server/lib/esm/languageservice/yamlLanguageService.js';
import { LanguageServiceDefaultsImpl } from './monaco.contribution';
import { languageId } from './constants';
import { YAMLWorker } from './yamlWorker';
import * as ls from 'vscode-languageserver-types';
import Uri = monaco.Uri;
import Position = monaco.Position;
import Range = monaco.Range;
import IRange = monaco.IRange;
import Thenable = monaco.Thenable;
import CancellationToken = monaco.CancellationToken;
import IDisposable = monaco.IDisposable;
import { CustomFormatterOptions } from 'yaml-language-server';
export type WorkerAccessor = (...more: Uri[]) => Thenable<YAMLWorker>;
export type WorkerAccessor = (...more: Uri[]) => PromiseLike<YAMLWorker>;
// --- diagnostics --- ---
export class DiagnosticsAdapter {
private _disposables: IDisposable[] = [];
private _listener: { [uri: string]: IDisposable } = Object.create(null);
constructor(
private _languageId: string,
private _worker: WorkerAccessor,
defaults: LanguageServiceDefaultsImpl
) {
const onModelAdd = (model: monaco.editor.IModel): void => {
const modeId = model.getModeId();
if (modeId !== this._languageId) {
return;
}
let handle: NodeJS.Timer;
this._listener[model.uri.toString()] = model.onDidChangeContent(() => {
clearTimeout(handle);
handle = setTimeout(() => this._doValidate(model.uri, modeId), 500);
});
this._doValidate(model.uri, modeId);
};
const onModelRemoved = (model: monaco.editor.IModel): void => {
monaco.editor.setModelMarkers(model, this._languageId, []);
const uriStr = model.uri.toString();
const listener = this._listener[uriStr];
if (listener) {
listener.dispose();
delete this._listener[uriStr];
}
};
this._disposables.push(monaco.editor.onDidCreateModel(onModelAdd));
this._disposables.push(
monaco.editor.onWillDisposeModel(model => {
onModelRemoved(model);
this._resetSchema(model.uri);
})
);
this._disposables.push(
monaco.editor.onDidChangeModelLanguage(event => {
onModelRemoved(event.model);
onModelAdd(event.model);
this._resetSchema(event.model.uri);
})
);
this._disposables.push(
defaults.onDidChange(_ => {
monaco.editor.getModels().forEach(model => {
if (model.getModeId() === this._languageId) {
onModelRemoved(model);
onModelAdd(model);
}
});
})
);
this._disposables.push({
dispose: () => {
monaco.editor.getModels().forEach(onModelRemoved);
for (const key in this._listener) {
this._listener[key].dispose();
}
},
});
monaco.editor.getModels().forEach(onModelAdd);
}
public dispose(): void {
this._disposables.forEach(d => d && d.dispose());
this._disposables = [];
}
private _resetSchema(resource: Uri): void {
this._worker().then(worker => {
worker.resetSchema(resource.toString());
});
}
private _doValidate(resource: Uri, languageId: string): void {
this._worker(resource)
.then(worker => {
return worker.doValidation(resource.toString()).then(diagnostics => {
const markers = diagnostics.map(d => toDiagnostics(resource, d));
const model = monaco.editor.getModel(resource);
if (model.getModeId() === languageId) {
monaco.editor.setModelMarkers(model, languageId, markers);
}
});
})
.then(undefined, err => {
console.error(err);
});
}
}
function toSeverity(lsSeverity: number): monaco.MarkerSeverity {
function toSeverity(lsSeverity: ls.DiagnosticSeverity): MarkerSeverity {
switch (lsSeverity) {
case ls.DiagnosticSeverity.Error:
return monaco.MarkerSeverity.Error;
return MarkerSeverity.Error;
case ls.DiagnosticSeverity.Warning:
return monaco.MarkerSeverity.Warning;
return MarkerSeverity.Warning;
case ls.DiagnosticSeverity.Information:
return monaco.MarkerSeverity.Info;
return MarkerSeverity.Info;
case ls.DiagnosticSeverity.Hint:
return monaco.MarkerSeverity.Hint;
return MarkerSeverity.Hint;
default:
return monaco.MarkerSeverity.Info;
return MarkerSeverity.Info;
}
}
function toDiagnostics(
resource: Uri,
diag: ls.Diagnostic
): monaco.editor.IMarkerData {
const code =
typeof diag.code === 'number' ? String(diag.code) : (diag.code as string);
function toMarkerDataTag(tag: ls.DiagnosticTag): MarkerTag {
switch (tag) {
case ls.DiagnosticTag.Deprecated:
return MarkerTag.Deprecated;
case ls.DiagnosticTag.Unnecessary:
return MarkerTag.Unnecessary;
default:
}
}
function toDiagnostics(diag: ls.Diagnostic): editor.IMarkerData {
return {
severity: toSeverity(diag.severity),
startLineNumber: diag.range.start.line + 1,
@ -151,48 +51,109 @@ function toDiagnostics(
endLineNumber: diag.range.end.line + 1,
endColumn: diag.range.end.character + 1,
message: diag.message,
code,
code: String(diag.code),
source: diag.source,
tags: diag.tags?.map(toMarkerDataTag),
};
}
export function createDiagnosticsAdapter(
getWorker: WorkerAccessor,
defaults: languages.yaml.LanguageServiceDefaults,
): void {
const listeners = new Map<string, IDisposable>();
const resetSchema = async (resource: Uri): Promise<void> => {
const worker = await getWorker();
worker.resetSchema(String(resource));
};
const doValidate = async (resource: Uri): Promise<void> => {
const worker = await getWorker(resource);
const diagnostics = await worker.doValidation(String(resource));
const markers = diagnostics.map(toDiagnostics);
const model = editor.getModel(resource);
// Return value from getModel can be null if model not found
// (e.g. if user navigates away from editor)
if (model && model.getLanguageId() === languageId) {
editor.setModelMarkers(model, languageId, markers);
}
};
const onModelAdd = (model: editor.IModel): void => {
if (model.getLanguageId() !== languageId) {
return;
}
let handle: ReturnType<typeof setTimeout>;
listeners.set(
String(model.uri),
model.onDidChangeContent(() => {
clearTimeout(handle);
handle = setTimeout(() => doValidate(model.uri), 500);
}),
);
doValidate(model.uri);
};
const onModelRemoved = (model: editor.IModel): void => {
editor.setModelMarkers(model, languageId, []);
const uriStr = String(model.uri);
const listener = listeners.get(uriStr);
if (listener) {
listener.dispose();
listeners.delete(uriStr);
}
};
editor.onDidCreateModel(onModelAdd);
editor.onWillDisposeModel((model) => {
onModelRemoved(model);
resetSchema(model.uri);
});
editor.onDidChangeModelLanguage((event) => {
onModelRemoved(event.model);
onModelAdd(event.model);
resetSchema(event.model.uri);
});
defaults.onDidChange(() => {
for (const model of editor.getModels()) {
if (model.getLanguageId() === languageId) {
onModelRemoved(model);
onModelAdd(model);
}
}
});
for (const model of editor.getModels()) {
onModelAdd(model);
}
}
// --- completion ------
function fromPosition(position: Position): ls.Position {
if (!position) {
return void 0;
return;
}
return { character: position.column - 1, line: position.lineNumber - 1 };
}
function fromRange(range: IRange): ls.Range {
if (!range) {
return void 0;
}
return {
start: {
line: range.startLineNumber - 1,
character: range.startColumn - 1,
},
end: { line: range.endLineNumber - 1, character: range.endColumn - 1 },
};
}
function toRange(range: ls.Range): Range {
if (!range) {
return void 0;
return;
}
return new Range(
range.start.line + 1,
range.start.character + 1,
range.end.line + 1,
range.end.character + 1
range.end.character + 1,
);
}
function toCompletionItemKind(
kind: number
): monaco.languages.CompletionItemKind {
const mItemKind = monaco.languages.CompletionItemKind;
function toCompletionItemKind(kind: ls.CompletionItemKind): languages.CompletionItemKind {
const mItemKind = languages.CompletionItemKind;
switch (kind) {
case ls.CompletionItemKind.Text:
@ -231,59 +192,14 @@ function toCompletionItemKind(
return mItemKind.File;
case ls.CompletionItemKind.Reference:
return mItemKind.Reference;
default:
return mItemKind.Property;
}
return mItemKind.Property;
}
function fromCompletionItemKind(
kind: monaco.languages.CompletionItemKind
): ls.CompletionItemKind {
const mItemKind = monaco.languages.CompletionItemKind;
switch (kind) {
case mItemKind.Text:
return ls.CompletionItemKind.Text;
case mItemKind.Method:
return ls.CompletionItemKind.Method;
case mItemKind.Function:
return ls.CompletionItemKind.Function;
case mItemKind.Constructor:
return ls.CompletionItemKind.Constructor;
case mItemKind.Field:
return ls.CompletionItemKind.Field;
case mItemKind.Variable:
return ls.CompletionItemKind.Variable;
case mItemKind.Class:
return ls.CompletionItemKind.Class;
case mItemKind.Interface:
return ls.CompletionItemKind.Interface;
case mItemKind.Module:
return ls.CompletionItemKind.Module;
case mItemKind.Property:
return ls.CompletionItemKind.Property;
case mItemKind.Unit:
return ls.CompletionItemKind.Unit;
case mItemKind.Value:
return ls.CompletionItemKind.Value;
case mItemKind.Enum:
return ls.CompletionItemKind.Enum;
case mItemKind.Keyword:
return ls.CompletionItemKind.Keyword;
case mItemKind.Snippet:
return ls.CompletionItemKind.Snippet;
case mItemKind.Color:
return ls.CompletionItemKind.Color;
case mItemKind.File:
return ls.CompletionItemKind.File;
case mItemKind.Reference:
return ls.CompletionItemKind.Reference;
}
return ls.CompletionItemKind.Property;
}
function toTextEdit(textEdit: ls.TextEdit): monaco.editor.ISingleEditOperation {
function toTextEdit(textEdit: ls.TextEdit): editor.ISingleEditOperation {
if (!textEdit) {
return void 0;
return;
}
return {
range: toRange(textEdit.range),
@ -291,150 +207,107 @@ function toTextEdit(textEdit: ls.TextEdit): monaco.editor.ISingleEditOperation {
};
}
export class CompletionAdapter
implements monaco.languages.CompletionItemProvider {
constructor(private _worker: WorkerAccessor) {}
export function createCompletionItemProvider(
getWorker: WorkerAccessor,
): languages.CompletionItemProvider {
return {
triggerCharacters: [' ', ':'],
public get triggerCharacters(): string[] {
return [' ', ':'];
}
async provideCompletionItems(model, position) {
const resource = model.uri;
public provideCompletionItems(
model: monaco.editor.IReadOnlyModel,
position: Position,
context: monaco.languages.CompletionContext,
token: CancellationToken
): Thenable<monaco.languages.CompletionList> {
const resource = model.uri;
const worker = await getWorker(resource);
const info = await worker.doComplete(String(resource), fromPosition(position));
if (!info) {
return;
}
return this._worker(resource)
.then(worker => {
return worker.doComplete(resource.toString(), fromPosition(position));
})
.then(info => {
if (!info) {
return;
}
const wordInfo = model.getWordUntilPosition(position);
const wordRange = new Range(
position.lineNumber,
wordInfo.startColumn,
position.lineNumber,
wordInfo.endColumn,
);
const wordInfo = model.getWordUntilPosition(position);
const wordRange = new Range(
position.lineNumber,
wordInfo.startColumn,
position.lineNumber,
wordInfo.endColumn
);
const items: monaco.languages.CompletionItem[] = info.items.map(
entry => {
const item: monaco.languages.CompletionItem = {
label: entry.label,
insertText: entry.insertText || entry.label,
sortText: entry.sortText,
filterText: entry.filterText,
documentation: entry.documentation,
detail: entry.detail,
kind: toCompletionItemKind(entry.kind),
range: wordRange,
};
if (entry.textEdit) {
item.range = toRange(entry.textEdit.range);
item.insertText = entry.textEdit.newText;
}
if (entry.additionalTextEdits) {
item.additionalTextEdits = entry.additionalTextEdits.map(
toTextEdit
);
}
if (entry.insertTextFormat === ls.InsertTextFormat.Snippet) {
item.insertTextRules =
monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet;
}
return item;
}
);
return {
isIncomplete: info.isIncomplete,
suggestions: items,
const items = info.items.map((entry) => {
const item: languages.CompletionItem = {
label: entry.label,
insertText: entry.insertText || entry.label,
sortText: entry.sortText,
filterText: entry.filterText,
documentation: entry.documentation,
detail: entry.detail,
kind: toCompletionItemKind(entry.kind),
range: wordRange,
};
if (entry.textEdit) {
item.range = toRange(
'range' in entry.textEdit ? entry.textEdit.range : entry.textEdit.replace,
);
item.insertText = entry.textEdit.newText;
}
if (entry.additionalTextEdits) {
item.additionalTextEdits = entry.additionalTextEdits.map(toTextEdit);
}
if (entry.insertTextFormat === ls.InsertTextFormat.Snippet) {
item.insertTextRules = languages.CompletionItemInsertTextRule.InsertAsSnippet;
}
return item;
});
}
}
function isMarkupContent(thing: any): thing is ls.MarkupContent {
return (
thing &&
typeof thing === 'object' &&
typeof (thing as ls.MarkupContent).kind === 'string'
);
}
function toMarkdownString(
entry: ls.MarkupContent | ls.MarkedString
): monaco.IMarkdownString {
if (typeof entry === 'string') {
return {
value: entry,
};
}
if (isMarkupContent(entry)) {
if (entry.kind === 'plaintext') {
return {
value: entry.value.replace(/[\\`*_{}[\]()#+\-.!]/g, '\\$&'),
incomplete: info.isIncomplete,
suggestions: items,
};
}
return {
value: entry.value,
};
}
return { value: '```' + entry.language + '\n' + entry.value + '\n```\n' };
},
};
}
function toMarkedStringArray(
contents: ls.MarkupContent | ls.MarkedString | ls.MarkedString[]
): monaco.IMarkdownString[] {
if (!contents) {
return void 0;
}
if (Array.isArray(contents)) {
return contents.map(toMarkdownString);
}
return [toMarkdownString(contents)];
// --- definition ------
export function createDefinitionProvider(getWorker: WorkerAccessor): languages.DefinitionProvider {
return {
async provideDefinition(model, position) {
const resource = model.uri;
const worker = await getWorker(resource);
const definitions = await worker.doDefinition(String(resource), fromPosition(position));
return definitions?.map((definition) => ({
originSelectionRange: definition.originSelectionRange,
range: toRange(definition.targetRange),
targetSelectionRange: definition.targetSelectionRange,
uri: Uri.parse(definition.targetUri),
}));
},
};
}
// --- hover ------
export class HoverAdapter implements monaco.languages.HoverProvider {
constructor(private _worker: WorkerAccessor) {}
export function createHoverProvider(getWorker: WorkerAccessor): languages.HoverProvider {
return {
async provideHover(model, position) {
const resource = model.uri;
public provideHover(
model: monaco.editor.IReadOnlyModel,
position: Position,
token: CancellationToken
): Thenable<monaco.languages.Hover> {
const resource = model.uri;
return this._worker(resource)
.then(worker => {
return worker.doHover(resource.toString(), fromPosition(position));
})
.then(info => {
if (!info) {
return;
}
return {
range: toRange(info.range),
contents: toMarkedStringArray(info.contents),
} as monaco.languages.Hover;
});
}
const worker = await getWorker(resource);
const info = await worker.doHover(String(resource), fromPosition(position));
if (!info) {
return;
}
return {
range: toRange(info.range),
contents: [{ value: (info.contents as ls.MarkupContent).value }],
};
},
};
}
// --- document symbols ------
function toSymbolKind(kind: ls.SymbolKind): monaco.languages.SymbolKind {
const mKind = monaco.languages.SymbolKind;
function toSymbolKind(kind: ls.SymbolKind): languages.SymbolKind {
const mKind = languages.SymbolKind;
switch (kind) {
case ls.SymbolKind.File:
@ -473,48 +346,43 @@ function toSymbolKind(kind: ls.SymbolKind): monaco.languages.SymbolKind {
return mKind.Boolean;
case ls.SymbolKind.Array:
return mKind.Array;
}
return mKind.Function;
}
export class DocumentSymbolAdapter
implements monaco.languages.DocumentSymbolProvider {
constructor(private _worker: WorkerAccessor) {}
public provideDocumentSymbols(
model: monaco.editor.IReadOnlyModel,
token: CancellationToken
): Thenable<monaco.languages.DocumentSymbol[]> {
const resource = model.uri;
return this._worker(resource)
.then(worker => worker.findDocumentSymbols(resource.toString()))
.then(items => {
if (!items) {
return;
}
return items.map(item => toDocumentSymbol(item));
});
default:
return mKind.Function;
}
}
function toDocumentSymbol(
item: ls.DocumentSymbol
): monaco.languages.DocumentSymbol {
function toDocumentSymbol(item: ls.DocumentSymbol): languages.DocumentSymbol {
return {
detail: '',
detail: item.detail || '',
range: toRange(item.range),
name: item.name,
kind: toSymbolKind(item.kind),
selectionRange: toRange(item.selectionRange),
children: item.children.map(child => toDocumentSymbol(child)),
children: item.children.map(toDocumentSymbol),
tags: [],
};
}
export function createDocumentSymbolProvider(
getWorker: WorkerAccessor,
): languages.DocumentSymbolProvider {
return {
async provideDocumentSymbols(model) {
const resource = model.uri;
const worker = await getWorker(resource);
const items = await worker.findDocumentSymbols(String(resource));
if (!items) {
return;
}
return items.map(toDocumentSymbol);
},
};
}
function fromFormattingOptions(
options: monaco.languages.FormattingOptions
): ls.FormattingOptions & CustomFormatterOptions {
options: languages.FormattingOptions,
): CustomFormatterOptions & ls.FormattingOptions {
return {
tabSize: options.tabSize,
insertSpaces: options.insertSpaces,
@ -522,115 +390,42 @@ function fromFormattingOptions(
};
}
export class DocumentFormattingEditProvider
implements monaco.languages.DocumentFormattingEditProvider {
constructor(private _worker: WorkerAccessor) {}
export function createDocumentFormattingEditProvider(
getWorker: WorkerAccessor,
): languages.DocumentFormattingEditProvider {
return {
async provideDocumentFormattingEdits(model, options) {
const resource = model.uri;
public provideDocumentFormattingEdits(
model: monaco.editor.IReadOnlyModel,
options: monaco.languages.FormattingOptions,
token: CancellationToken
): Thenable<monaco.editor.ISingleEditOperation[]> {
const resource = model.uri;
return this._worker(resource).then(worker => {
return worker
.format(resource.toString(), null, fromFormattingOptions(options))
.then(edits => {
if (!edits || edits.length === 0) {
return;
}
return edits.map(toTextEdit);
});
});
}
const worker = await getWorker(resource);
const edits = await worker.format(String(resource), fromFormattingOptions(options));
if (!edits || edits.length === 0) {
return;
}
return edits.map(toTextEdit);
},
};
}
export class DocumentRangeFormattingEditProvider
implements monaco.languages.DocumentRangeFormattingEditProvider {
constructor(private _worker: WorkerAccessor) {}
public provideDocumentRangeFormattingEdits(
model: monaco.editor.IReadOnlyModel,
range: Range,
options: monaco.languages.FormattingOptions,
token: CancellationToken
): Thenable<monaco.editor.ISingleEditOperation[]> {
const resource = model.uri;
return this._worker(resource).then(worker => {
return worker
.format(
resource.toString(),
fromRange(range),
fromFormattingOptions(options)
)
.then(edits => {
if (!edits || edits.length === 0) {
return;
}
return edits.map(toTextEdit);
});
});
}
function toLink(link: ls.DocumentLink): languages.ILink {
return {
range: toRange(link.range),
tooltip: link.tooltip,
url: link.target,
};
}
// export class DocumentColorAdapter
// implements monaco.languages.DocumentColorProvider {
// constructor(private _worker: WorkerAccessor) {}
export function createLinkProvider(getWorker: WorkerAccessor): languages.LinkProvider {
return {
async provideLinks(model) {
const resource = model.uri;
// public provideDocumentColors(
// model: monaco.editor.IReadOnlyModel,
// token: CancellationToken
// ): Thenable<monaco.languages.IColorInformation[]> {
// const resource = model.uri;
const worker = await getWorker(resource);
const links = await worker.findLinks(String(resource));
// return this._worker(resource)
// .then(worker => worker.findDocumentColors(resource.toString()))
// .then(infos => {
// if (!infos) {
// return;
// }
// return infos.map(item => ({
// color: item.color,
// range: toRange(item.range),
// }));
// });
// }
// public provideColorPresentations(
// model: monaco.editor.IReadOnlyModel,
// info: monaco.languages.IColorInformation,
// token: CancellationToken
// ): Thenable<monaco.languages.IColorPresentation[]> {
// const resource = model.uri;
// return this._worker(resource)
// .then(worker =>
// worker.getColorPresentations(
// resource.toString(),
// info.color,
// fromRange(info.range)
// )
// )
// .then(presentations => {
// if (!presentations) {
// return;
// }
// return presentations.map(presentation => {
// const item: monaco.languages.IColorPresentation = {
// label: presentation.label,
// };
// if (presentation.textEdit) {
// item.textEdit = toTextEdit(presentation.textEdit);
// }
// if (presentation.additionalTextEdits) {
// item.additionalTextEdits = presentation.additionalTextEdits.map(
// toTextEdit
// );
// }
// return item;
// });
// });
// }
// }
return {
links: links.map(toLink),
};
},
};
}

View file

@ -1,82 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { setupMode } from './yamlMode';
import Emitter = monaco.Emitter;
import IEvent = monaco.IEvent;
declare var require: <T>(
moduleId: [string],
callback: (module: T) => void
) => void;
// --- YAML configuration and defaults ---------
export class LanguageServiceDefaultsImpl
implements monaco.languages.yaml.LanguageServiceDefaults {
private _onDidChange = new Emitter<
monaco.languages.yaml.LanguageServiceDefaults
>();
private _diagnosticsOptions: monaco.languages.yaml.DiagnosticsOptions;
private _languageId: string;
constructor(
languageId: string,
diagnosticsOptions: monaco.languages.yaml.DiagnosticsOptions
) {
this._languageId = languageId;
this.setDiagnosticsOptions(diagnosticsOptions);
}
get onDidChange(): IEvent<monaco.languages.yaml.LanguageServiceDefaults> {
return this._onDidChange.event;
}
get languageId(): string {
return this._languageId;
}
get diagnosticsOptions(): monaco.languages.yaml.DiagnosticsOptions {
return this._diagnosticsOptions;
}
public setDiagnosticsOptions(
options: monaco.languages.yaml.DiagnosticsOptions
): void {
this._diagnosticsOptions = options || Object.create(null);
this._onDidChange.fire(this);
}
}
const diagnosticDefault: monaco.languages.yaml.DiagnosticsOptions = {
validate: true,
schemas: [],
enableSchemaRequest: false,
};
const yamlDefaults = new LanguageServiceDefaultsImpl('yaml', diagnosticDefault);
// Export API
function createAPI(): typeof monaco.languages.yaml {
return {
yamlDefaults,
};
}
monaco.languages.yaml = createAPI();
// --- Registration to monaco editor ---
monaco.languages.register({
id: 'yaml',
extensions: ['.yaml', '.yml'],
aliases: ['YAML', 'yaml', 'YML', 'yml'],
mimetypes: ['application/x-yaml'],
});
monaco.languages.onLanguage('yaml', () => {
setupMode(yamlDefaults);
});

54
src/monaco.d.ts vendored
View file

@ -1,54 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
declare namespace monaco.languages.yaml {
export interface DiagnosticsOptions {
/**
* If set, the validator will be enabled and perform syntax validation as well as schema based validation.
*/
readonly validate?: boolean;
/**
* A list of known schemas and/or associations of schemas to file names.
*/
readonly schemas?: Array<{
/**
* The URI of the schema, which is also the identifier of the schema.
*/
readonly uri: string;
/**
* A list of file names that are associated to the schema. The '*' wildcard can be used. For example '*.schema.json', 'package.json'
*/
readonly fileMatch?: string[];
/**
* The schema for the given URI.
*/
readonly schema?: any;
}>;
/**
* If set, the schema service would load schema content on-demand with 'fetch' if available
*/
readonly enableSchemaRequest?: boolean;
/**
* If specified, this prefix will be added to all on demand schema requests
*/
readonly prefix?: string;
/**
* Whether or not kubernetes yaml is supported
*/
readonly isKubernetes?: boolean;
readonly format?: boolean;
}
export interface LanguageServiceDefaults {
readonly onDidChange: IEvent<LanguageServiceDefaults>;
readonly diagnosticsOptions: DiagnosticsOptions;
setDiagnosticsOptions(options: DiagnosticsOptions): void;
}
export const yamlDefaults: LanguageServiceDefaults;
}

View file

@ -1,5 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/// <reference path='../../node_modules/monaco-editor-core/monaco.d.ts'/>

View file

@ -1,96 +1,67 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { editor, languages } from 'monaco-editor/esm/vs/editor/editor.api.js';
import { LanguageServiceDefaultsImpl } from './monaco.contribution';
import { WorkerAccessor } from './languageFeatures';
import { YAMLWorker } from './yamlWorker';
import IDisposable = monaco.IDisposable;
import Uri = monaco.Uri;
// 2min
const STOP_WHEN_IDLE_FOR = 2 * 60 * 1000;
const STOP_WHEN_IDLE_FOR = 2 * 60 * 1000; // 2min
export function createWorkerManager(
defaults: languages.yaml.LanguageServiceDefaults,
): WorkerAccessor {
let worker: editor.MonacoWebWorker<YAMLWorker>;
let client: Promise<YAMLWorker>;
let lastUsedTime = 0;
export class WorkerManager {
private _defaults: LanguageServiceDefaultsImpl;
private _idleCheckInterval: NodeJS.Timer;
private _lastUsedTime: number;
private _configChangeListener: IDisposable;
private _worker: monaco.editor.MonacoWebWorker<YAMLWorker>;
private _client: Promise<YAMLWorker>;
constructor(defaults: LanguageServiceDefaultsImpl) {
this._defaults = defaults;
this._worker = null;
this._idleCheckInterval = setInterval(() => this._checkIfIdle(), 30 * 1000);
this._lastUsedTime = 0;
this._configChangeListener = this._defaults.onDidChange(() =>
this._stopWorker()
);
}
public dispose(): void {
clearInterval(this._idleCheckInterval);
this._configChangeListener.dispose();
this._stopWorker();
}
public getLanguageServiceWorker(...resources: Uri[]): Promise<YAMLWorker> {
let _client: YAMLWorker;
return this._getClient()
.then(client => {
_client = client;
})
.then(_ => {
return this._worker.withSyncedResources(resources);
})
.then(_ => _client);
}
private _stopWorker(): void {
if (this._worker) {
this._worker.dispose();
this._worker = null;
const stopWorker = (): void => {
if (worker) {
worker.dispose();
worker = undefined;
}
this._client = null;
}
client = undefined;
};
private _checkIfIdle(): void {
if (!this._worker) {
setInterval(() => {
if (!worker) {
return;
}
const timePassedSinceLastUsed = Date.now() - this._lastUsedTime;
const timePassedSinceLastUsed = Date.now() - lastUsedTime;
if (timePassedSinceLastUsed > STOP_WHEN_IDLE_FOR) {
this._stopWorker();
stopWorker();
}
}
}, 30 * 1000);
private _getClient(): Promise<YAMLWorker> {
this._lastUsedTime = Date.now();
// This is necessary to have updated language options take effect (e.g. schema changes)
defaults.onDidChange(() => stopWorker());
if (!this._client) {
this._worker = monaco.editor.createWebWorker<YAMLWorker>({
// module that exports the create() method and returns a `YAMLWorker` instance
const getClient = (): Promise<YAMLWorker> => {
lastUsedTime = Date.now();
if (!client) {
worker = editor.createWebWorker<YAMLWorker>({
// Module that exports the create() method and returns a `YAMLWorker` instance
moduleId: 'vs/language/yaml/yamlWorker',
label: this._defaults.languageId,
label: defaults.languageId,
// passed in to the create() method
// Passed in to the create() method
createData: {
languageSettings: this._defaults.diagnosticsOptions,
languageId: this._defaults.languageId,
enableSchemaRequest: this._defaults.diagnosticsOptions
.enableSchemaRequest,
prefix: this._defaults.diagnosticsOptions.prefix,
isKubernetes: this._defaults.diagnosticsOptions.isKubernetes,
languageSettings: defaults.diagnosticsOptions,
enableSchemaRequest: defaults.diagnosticsOptions.enableSchemaRequest,
isKubernetes: defaults.diagnosticsOptions.isKubernetes,
customTags: defaults.diagnosticsOptions.customTags,
},
});
this._client = this._worker.getProxy();
client = worker.getProxy();
}
return this._client;
}
return client;
};
return async (...resources) => {
const client = await getClient();
await worker.withSyncedResources(resources);
return client;
};
}

View file

@ -1,15 +1,7 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { initialize } from 'monaco-editor/esm/vs/editor/editor.worker.js';
import * as worker from 'monaco-editor/esm/vs/editor/editor.worker';
import { YAMLWorker } from './yamlWorker';
import { createYAMLWorker, ICreateData } from './yamlWorker';
self.onmessage = () => {
// ignore the first message
worker.initialize((ctx, createData) => {
return new YAMLWorker(ctx, createData);
});
initialize((ctx, createData: ICreateData) => Object.create(createYAMLWorker(ctx, createData)));
};

View file

@ -1,73 +1,18 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { languages } from 'monaco-editor/esm/vs/editor/editor.api.js';
import * as languageFeatures from './languageFeatures';
import { LanguageServiceDefaultsImpl } from './monaco.contribution';
import { WorkerManager } from './workerManager';
import { YAMLWorker } from './yamlWorker';
import { languageId } from './constants';
import {
createCompletionItemProvider,
createDefinitionProvider,
createDiagnosticsAdapter,
createDocumentFormattingEditProvider,
createDocumentSymbolProvider,
createHoverProvider,
createLinkProvider,
} from './languageFeatures';
import { createWorkerManager } from './workerManager';
import Uri = monaco.Uri;
import IDisposable = monaco.IDisposable;
export function setupMode(defaults: LanguageServiceDefaultsImpl): void {
const disposables: IDisposable[] = [];
const client = new WorkerManager(defaults);
disposables.push(client);
const worker: languageFeatures.WorkerAccessor = (
...uris: Uri[]
): Promise<YAMLWorker> => {
return client.getLanguageServiceWorker(...uris);
};
const languageId = defaults.languageId;
disposables.push(
monaco.languages.registerCompletionItemProvider(
languageId,
new languageFeatures.CompletionAdapter(worker)
)
);
disposables.push(
monaco.languages.registerHoverProvider(
languageId,
new languageFeatures.HoverAdapter(worker)
)
);
disposables.push(
monaco.languages.registerDocumentSymbolProvider(
languageId,
new languageFeatures.DocumentSymbolAdapter(worker)
)
);
disposables.push(
monaco.languages.registerDocumentFormattingEditProvider(
languageId,
new languageFeatures.DocumentFormattingEditProvider(worker)
)
);
disposables.push(
monaco.languages.registerDocumentRangeFormattingEditProvider(
languageId,
new languageFeatures.DocumentRangeFormattingEditProvider(worker)
)
);
disposables.push(
new languageFeatures.DiagnosticsAdapter(languageId, worker, defaults)
);
disposables.push(
monaco.languages.setLanguageConfiguration(languageId, richEditConfiguration)
);
// Color adapter should be necessary most of the time:
// disposables.push(monaco.languages.registerColorProvider(languageId, new languageFeatures.DocumentColorAdapter(worker)));
}
const richEditConfiguration: monaco.languages.LanguageConfiguration = {
const richEditConfiguration: languages.LanguageConfiguration = {
comments: {
lineComment: '#',
},
@ -94,7 +39,23 @@ const richEditConfiguration: monaco.languages.LanguageConfiguration = {
onEnterRules: [
{
beforeText: /:\s*$/,
action: { indentAction: monaco.languages.IndentAction.Indent },
action: { indentAction: languages.IndentAction.Indent },
},
],
};
export function setupMode(defaults: languages.yaml.LanguageServiceDefaults): void {
const worker = createWorkerManager(defaults);
languages.registerCompletionItemProvider(languageId, createCompletionItemProvider(worker));
languages.registerHoverProvider(languageId, createHoverProvider(worker));
languages.registerDefinitionProvider(languageId, createDefinitionProvider(worker));
languages.registerDocumentSymbolProvider(languageId, createDocumentSymbolProvider(worker));
languages.registerDocumentFormattingEditProvider(
languageId,
createDocumentFormattingEditProvider(worker),
);
languages.registerLinkProvider(languageId, createLinkProvider(worker));
createDiagnosticsAdapter(worker, defaults);
languages.setLanguageConfiguration(languageId, richEditConfiguration);
}

View file

@ -1,127 +1,111 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Red Hat, Inc. All rights reserved.
* Copyright (c) Adam Voss. All rights reserved.
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import Thenable = monaco.Thenable;
import IWorkerContext = monaco.worker.IWorkerContext;
import { worker } from 'monaco-editor/esm/vs/editor/editor.api.js';
import { Promisable } from 'type-fest';
import { TextDocument } from 'vscode-languageserver-textdocument';
import * as ls from 'vscode-languageserver-types';
import * as yamlService from 'yaml-language-server';
import {
CustomFormatterOptions,
getLanguageService,
LanguageSettings,
} from 'yaml-language-server/lib/esm/languageservice/yamlLanguageService.js';
let defaultSchemaRequestService;
if (typeof fetch !== 'undefined') {
defaultSchemaRequestService = function(url) {
return fetch(url).then(response => response.text());
};
import { languageId } from './constants';
async function schemaRequestService(uri: string): Promise<string> {
const response = await fetch(uri);
if (response.ok) {
return response.text();
}
throw new Error(`Schema request failed for ${uri}`);
}
export class YAMLWorker {
private _ctx: IWorkerContext;
private _languageService: yamlService.LanguageService;
private _languageSettings: yamlService.LanguageSettings;
private _languageId: string;
private _isKubernetes: boolean;
export interface YAMLWorker {
doValidation: (uri: string) => Promisable<ls.Diagnostic[]>;
constructor(ctx: IWorkerContext, createData: ICreateData) {
const prefix = createData.prefix || '';
const service = (url: string) =>
defaultSchemaRequestService(`${prefix}${url}`);
this._ctx = ctx;
this._languageSettings = createData.languageSettings;
this._languageId = createData.languageId;
this._languageService = yamlService.getLanguageService(
createData.enableSchemaRequest && service,
null,
[]
);
this._isKubernetes = createData.isKubernetes || false;
this._languageService.configure({
...this._languageSettings,
hover: true,
isKubernetes: this._isKubernetes,
});
}
doComplete: (uri: string, position: ls.Position) => Promisable<ls.CompletionList>;
public doValidation(uri: string): Thenable<ls.Diagnostic[]> {
const document = this._getTextDocument(uri);
if (document) {
return this._languageService.doValidation(document, this._isKubernetes);
}
return Promise.resolve([]);
}
doDefinition: (uri: string, position: ls.Position) => Promisable<ls.LocationLink[]>;
public doComplete(
uri: string,
position: ls.Position
): Thenable<ls.CompletionList> {
const document = this._getTextDocument(uri);
return this._languageService.doComplete(
document,
position,
this._isKubernetes
);
}
doHover: (uri: string, position: ls.Position) => Promisable<ls.Hover>;
public doResolve(item: ls.CompletionItem): Thenable<ls.CompletionItem> {
return this._languageService.doResolve(item);
}
format: (uri: string, options: CustomFormatterOptions) => Promisable<ls.TextEdit[]>;
public doHover(uri: string, position: ls.Position): Thenable<ls.Hover> {
const document = this._getTextDocument(uri);
return this._languageService.doHover(document, position);
}
resetSchema: (uri: string) => Promisable<boolean>;
public format(
uri: string,
range: ls.Range,
options: yamlService.CustomFormatterOptions
): Thenable<ls.TextEdit[]> {
const document = this._getTextDocument(uri);
const textEdits = this._languageService.doFormat(document, options);
return Promise.resolve(textEdits);
}
findDocumentSymbols: (uri: string) => Promisable<ls.DocumentSymbol[]>;
public resetSchema(uri: string): Thenable<boolean> {
return Promise.resolve(this._languageService.resetSchema(uri));
}
findLinks: (uri: string) => Promisable<ls.DocumentLink[]>;
}
public findDocumentSymbols(uri: string): Thenable<ls.DocumentSymbol[]> {
const document = this._getTextDocument(uri);
const symbols = this._languageService.findDocumentSymbols2(document);
return Promise.resolve(symbols);
}
export function createYAMLWorker(
ctx: worker.IWorkerContext,
{ enableSchemaRequest, languageSettings }: ICreateData,
): YAMLWorker {
const languageService = getLanguageService(
enableSchemaRequest ? schemaRequestService : null,
null,
null,
null,
null,
);
languageService.configure(languageSettings);
private _getTextDocument(uri: string): ls.TextDocument {
const models = this._ctx.getMirrorModels();
const getTextDocument = (uri: string): TextDocument => {
const models = ctx.getMirrorModels();
for (const model of models) {
if (model.uri.toString() === uri) {
return ls.TextDocument.create(
uri,
this._languageId,
model.version,
model.getValue()
);
if (String(model.uri) === uri) {
return TextDocument.create(uri, languageId, model.version, model.getValue());
}
}
return null;
}
};
return {
doValidation(uri) {
const document = getTextDocument(uri);
if (document) {
return languageService.doValidation(document, languageSettings.isKubernetes);
}
return [];
},
doComplete(uri, position) {
const document = getTextDocument(uri);
return languageService.doComplete(document, position, languageSettings.isKubernetes);
},
doDefinition(uri, position) {
const document = getTextDocument(uri);
return languageService.doDefinition(document, { position, textDocument: { uri } });
},
doHover(uri, position) {
const document = getTextDocument(uri);
return languageService.doHover(document, position);
},
format(uri, options) {
const document = getTextDocument(uri);
return languageService.doFormat(document, options);
},
resetSchema(uri) {
return languageService.resetSchema(uri);
},
findDocumentSymbols(uri) {
const document = getTextDocument(uri);
return languageService.findDocumentSymbols2(document, {});
},
findLinks(uri) {
const document = getTextDocument(uri);
return languageService.findLinks(document);
},
};
}
export interface ICreateData {
languageId: string;
languageSettings: yamlService.LanguageSettings;
languageSettings: LanguageSettings;
enableSchemaRequest: boolean;
prefix?: string;
isKubernetes?: boolean;
}
export function create(
ctx: IWorkerContext,
createData: ICreateData
): YAMLWorker {
return new YAMLWorker(ctx, createData);
}

View file

@ -1,20 +0,0 @@
{
"compilerOptions": {
"alwaysStrict": true,
"declaration": true,
"forceConsistentCasingInFileNames": true,
"downlevelIteration": true,
"module": "esnext",
"moduleResolution": "node",
"lib": ["dom", "es2016"],
"outDir": "./out/esm",
"sourceMap": true,
"target": "es6",
"plugins": [
{
"name": "typescript-tslint-plugin"
}
]
},
"exclude": ["node_modules", "out", "lib", "test"]
}

View file

@ -2,16 +2,14 @@
"compilerOptions": {
"declaration": true,
"forceConsistentCasingInFileNames": true,
"module": "umd",
"downlevelIteration": true,
"lib": ["dom", "dom.iterable", "es2017"],
"module": "esnext",
"moduleResolution": "node",
"lib": ["dom", "es2016"],
"outDir": "./out/amd",
"noEmit": true,
"skipLibCheck": true,
"sourceMap": true,
"target": "es6",
"plugins": [
{
"name": "typescript-tslint-plugin"
}
]
},
"exclude": ["node_modules", "out", "lib", "test"]
"types": []
}
}

4742
yarn.lock

File diff suppressed because it is too large Load diff