diff --git a/.azure-pipelines/publish-nightly.yml b/.azure-pipelines/publish-nightly.yml index 4a757c36..e5c622eb 100644 --- a/.azure-pipelines/publish-nightly.yml +++ b/.azure-pipelines/publish-nightly.yml @@ -23,6 +23,16 @@ resources: ref: main endpoint: Monaco +parameters: + - name: vscodeRef + displayName: The VS Code commit id. + type: string + default: 'main' + - name: prereleaseVersion + displayName: The prerelease version. + type: string + default: 'dev-${today}' + extends: template: azure-pipelines/npm-package/pipeline.yml@templates parameters: @@ -31,10 +41,17 @@ extends: workingDirectory: $(Build.SourcesDirectory)/dependencies/vscode/out-monaco-editor-core testPlatforms: [] buildSteps: + - script: sudo apt install -y libkrb5-dev + displayName: Install libkrb5-dev + - script: npm ci displayName: Install NPM dependencies - script: yarn ts-node ./scripts/ci/monaco-editor-core-prepare nightly + env: + VSCODE_REF: ${{ parameters.vscodeRef }} + PRERELEASE_VERSION: ${{ parameters.prereleaseVersion }} + retryCountOnTaskFailure: 5 displayName: Setup, Build & Test monaco-editor-core tag: next @@ -50,6 +67,10 @@ extends: displayName: Install NPM dependencies - script: yarn ts-node ./scripts/ci/monaco-editor-prepare nightly + env: + VSCODE_REF: ${{ parameters.vscodeRef }} + PRERELEASE_VERSION: ${{ parameters.prereleaseVersion }} + retryCountOnTaskFailure: 5 displayName: Setup, Build & Test monaco-editor tag: next diff --git a/.azure-pipelines/publish-stable.yml b/.azure-pipelines/publish-stable.yml index d8cb4813..f2aac055 100644 --- a/.azure-pipelines/publish-stable.yml +++ b/.azure-pipelines/publish-stable.yml @@ -37,6 +37,9 @@ extends: workingDirectory: $(Build.SourcesDirectory)/dependencies/vscode/out-monaco-editor-core testPlatforms: [] buildSteps: + - script: sudo apt install -y libkrb5-dev + displayName: Install libkrb5-dev + - script: npm ci displayName: Install NPM dependencies @@ -68,9 +71,11 @@ extends: buildSteps: - script: npm ci displayName: Install NPM dependencies + workingDirectory: $(Build.SourcesDirectory)/webpack-plugin - script: npm run compile displayName: Build plugin + workingDirectory: $(Build.SourcesDirectory)/webpack-plugin tag: latest ghCreateTag: false diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cfb85827..c315421d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: uses: actions/cache@v2 with: path: '**/node_modules' - key: ${{ runner.os }}-cacheNodeModules2-${{ hashFiles('**/package-lock.json') }} + key: ${{ runner.os }}-cacheNodeModules2-${{ hashFiles('**/package-lock.json', '**/package.json') }} restore-keys: ${{ runner.os }}-cacheNodeModules2- - name: execute `npm ci` (1) diff --git a/.github/workflows/publish/computeState.js b/.github/workflows/publish/computeState.js deleted file mode 100644 index 6eb18167..00000000 --- a/.github/workflows/publish/computeState.js +++ /dev/null @@ -1,103 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -//@ts-check - -const fs = require('fs'); -const cp = require('child_process'); -const packageJson = require('../../../package.json'); - -if (process.argv.length !== 4) { - console.error(`usage: node computeState.js <"workflow_dispatch"|"schedule"> <"true"|"false">`); - process.exit(1); -} - -const EVENT_NAME = /** @type {'workflow_dispatch'|'schedule'} */ (process.argv[2]); -const STR_NIGHTLY = /** @type {'true'|'false'|''} */ (process.argv[3]); - -if (!/^((workflow_dispatch)|(schedule))$/.test(EVENT_NAME)) { - console.error(`usage: node computeState.js <"workflow_dispatch"|"schedule"> <"true"|"false">`); - process.exit(2); -} - -if (!/^((true)|(false)|())$/.test(STR_NIGHTLY)) { - console.error(`usage: node computeState.js <"workflow_dispatch"|"schedule"> <"true"|"false">`); - process.exit(3); -} - -const NIGHTLY = EVENT_NAME === 'schedule' || STR_NIGHTLY === 'true'; - -const distTag = NIGHTLY ? 'next' : 'latest'; - -const latestMonacoEditorVersion = npmGetLatestVersion('monaco-editor'); -const version = (() => { - if (NIGHTLY) { - const pieces = latestMonacoEditorVersion.split('.'); - const minor = parseInt(pieces[1], 10); - const date = new Date(); - const yyyy = date.getUTCFullYear(); - const mm = String(date.getUTCMonth() + 1).padStart(2, '0'); - const dd = String(date.getUTCDate()).padStart(2, '0'); - return `0.${minor + 1}.0-dev.${yyyy}${mm}${dd}`; - } else { - return packageJson.version; - } -})(); - -const vscodeBranch = (() => { - if (NIGHTLY) { - return 'main'; - } else { - return packageJson.vscode; - } -})(); - -const skipMonacoEditorCore = (() => { - return /** @type {'true'|'false'} */ (String(npmExists('monaco-editor-core', version))); -})(); - -const skipMonacoEditor = (() => { - return /** @type {'true'|'false'} */ (String(npmExists('monaco-editor', version))); -})(); - -console.log(` -::set-output name=dist_tag::${distTag} -::set-output name=version::${version} -::set-output name=vscode_branch::${vscodeBranch} -::set-output name=skip_monaco_editor_core::${skipMonacoEditorCore} -::set-output name=skip_monaco_editor::${skipMonacoEditor} -`); - -/** - * @param {string} packageName - * @returns {string} - */ -function npmGetLatestVersion(packageName) { - const output = cp.execSync(`npm show ${packageName} version`).toString(); - const version = output.split(/\r\n|\r|\n/g)[0]; - if (!/^0\.(\d+)\.(\d+)$/.test(version)) { - console.error(`version ${version} does not match 0.x.y`); - process.exit(1); - } - return version; -} - -/** - * @param {string} packageName - * @param {string} version - * @returns {boolean} - */ -function npmExists(packageName, version) { - try { - const output = cp.execSync(`npm show ${packageName}@${version} version`).toString(); - const result = output.split(/\r\n|\r|\n/g)[0]; - if (result.trim().length === 0) { - return false; - } - return true; - } catch (err) { - return false; - } -} diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml index 7508da49..1ff6c69a 100644 --- a/.github/workflows/website.yml +++ b/.github/workflows/website.yml @@ -1,23 +1,34 @@ name: Publish Website on: - push: - tags: - - 'v*' - # enable users to manually trigger with workflow_dispatch + schedule: + - cron: 0 23 * * * workflow_dispatch: {} +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: 'pages' + cancel-in-progress: false + jobs: - publish-website: - name: Publish Website + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest steps: - - uses: actions/checkout@dc323e67f16fb5f7663d20ff7941f27f5809e9b6 # pin@v2 - + - name: Checkout + uses: actions/checkout@v3 - uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 # pin@v2 with: node-version: 16 - - name: Cache node modules id: cacheNodeModules uses: actions/cache@v2 @@ -25,11 +36,9 @@ jobs: path: '**/node_modules' key: ${{ runner.os }}-cacheNodeModules2-${{ hashFiles('**/package-lock.json') }} restore-keys: ${{ runner.os }}-cacheNodeModules2- - - name: execute `npm ci` (1) if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }} run: npm ci - - name: Build run: npm run build-monaco-editor @@ -45,8 +54,13 @@ jobs: working-directory: website run: yarn run build - - name: Upload website to github pages - uses: peaceiris/actions-gh-pages@bd8c6b06eba6b3d25d72b7a1767993c0aeee42e7 # pin@v3 + - name: Setup Pages + uses: actions/configure-pages@v3 + - name: Upload artifact + uses: actions/upload-pages-artifact@v1 with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./website/dist + # Upload entire repository + path: './website/dist' + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v2 diff --git a/.vscode/launch.json b/.vscode/launch.json index 2d19c833..44c09c98 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -15,6 +15,12 @@ "order": 1 } }, + { + "name": "Website", + "type": "chrome", + "request": "launch", + "url": "http://localhost:8080/" + }, { // Clone VS Code and make sure the task "Launch Http Server" runs. // Then the editor is build from sources. diff --git a/CHANGELOG.md b/CHANGELOG.md index b4a60415..194148df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,65 @@ # Monaco Editor Changelog +## [0.42.0] + +- Uses new diff editor widget by default. Use `experimental.useVersion2: false` to use the old widget. The old widget will be replaced in the next update. +- Diff editor uses inline mode by default when width is too small. Use the config option `useInlineViewWhenSpaceIsLimited` to control this behavior. +- Fixes broken language features when a model is created before the editor. + +## [0.41.0] + +- `IDiffEditor.diffReviewNext` was renamed to `IDiffEditor.accessibleDiffViewerNext`. +- `IDiffEditor.diffReviewPrev` was renamed to `IDiffEditor.accessibleDiffViewerPrev`. +- Introduces `InlineCompletionsProvider.yieldsToGroupIds` to allows inline completion providers to yield to other providers. +- Bugfixes + +Contributions to `monaco-editor`: + +- [@claylibrarymarket](https://github.com/claylibrarymarket): Fix Twig's plain text class expression [PR #4063](https://github.com/microsoft/monaco-editor/pull/4063) +- [@FossPrime (Ray Foss)](https://github.com/FossPrime): Use new GitHub pages workflow [PR #4000](https://github.com/microsoft/monaco-editor/pull/4000) +- [@leandrocp (Leandro Pereira)](https://github.com/leandrocp): Elixir - Add support for multi-letter uppercase sigils [PR #4041](https://github.com/microsoft/monaco-editor/pull/4041) +- [@philippleidig (PhilippLe)](https://github.com/philippleidig): Add TwinCAT file support for structured text (st) language [PR #3315](https://github.com/microsoft/monaco-editor/pull/3315) +- [@remcohaszing (Remco Haszing)](https://github.com/remcohaszing) + - Add mdx language [PR #3096](https://github.com/microsoft/monaco-editor/pull/3096) + - Export custom TypeScript worker variables [PR #3488](https://github.com/microsoft/monaco-editor/pull/3488) + - Document some basic concepts [PR #4087](https://github.com/microsoft/monaco-editor/pull/4087) + +## [0.40.0] + +- Support for Glyph Margin Widgets +- Removes `getDiffLineInformationForOriginal` and `getDiffLineInformationForModified` from `IDiffEditor` +- `createTrustedTypesPolicy` is optional now +- New option `IModelDecorationOptions.shouldFillLineOnLineBreak` +- New option `EditorOptions.readOnlyMessage` + +## [0.39.0] + +- New method `Environment.createTrustedTypesPolicy` to override trusted types handling. +- Bugfixes + +Contributions to `monaco-editor`: + +- [@dlitsman (Dmitry Litsman)](https://github.com/dlitsman): Extend the "Rendering Glyphs In The Margin" example to include a transparent color note. [PR #3945](https://github.com/microsoft/monaco-editor/pull/3945) +- [@dneto0 (David Neto)](https://github.com/dneto0): Avoid a hack in the WGSL lexer [PR #3887](https://github.com/microsoft/monaco-editor/pull/3887) +- [@spahnke (Sebastian Pahnke)](https://github.com/spahnke) + - [JS, TS] Add Monarch support for private identifiers [PR #3919](https://github.com/microsoft/monaco-editor/pull/3919) + - [JS] Add static keyword [PR #3922](https://github.com/microsoft/monaco-editor/pull/3922) +- [@titouanmathis (Titouan Mathis)](https://github.com/titouanmathis): [Webpack Plugin] Fix CJS being injected in ESM files [PR #3933](https://github.com/microsoft/monaco-editor/pull/3933) + +## [0.38.0] + +- `diffAlgorithm` values changed: `smart` -> `legacy`, `experimental` -> `advanced` +- New `registerEditorOpener` API +- New property `IViewZone.showInHiddenAreas` to show view zones in hidden areas +- New properties `InlineCompletions.suppressSuggestions` and `InlineCompletions.enableForwardStability` +- Bugfixes + +Contributions to `monaco-editor`: + +- [@dneto0 (David Neto)](https://github.com/dneto0): Add WebGPU Shading Language tokenizer, with tests [PR #3884](https://github.com/microsoft/monaco-editor/pull/3884) +- [@kisstkondoros (Tamas Kiss)](https://github.com/kisstkondoros): Fix reference error in convert method of OutlineAdapter [PR #3924](https://github.com/microsoft/monaco-editor/pull/3924) +- [@tamayika](https://github.com/tamayika): Change moduleResolution to node16 and adopt TS 5.0 [PR #3860](https://github.com/microsoft/monaco-editor/pull/3860) + ## [0.37.1] - Fixes Inline Completions feature diff --git a/MAINTAINING.md b/MAINTAINING.md index 9b71b787..deb5aee9 100644 --- a/MAINTAINING.md +++ b/MAINTAINING.md @@ -2,29 +2,26 @@ (For maintainers only) -- [P1 Inbox Queue](https://github.com/microsoft/monaco-editor/issues?q=is%3Aissue+is%3Aopen+-label%3Afeature-request+-label%3Aquestion+-label%3Aupstream+-label%3A%22help+wanted%22+-label%3A%22info-needed%22+-label%3A%22as-designed%22+-label%3Abug+-label%3A*question+) -- [Inbox Queue](https://github.com/microsoft/monaco-editor/issues?q=is%3Aissue+is%3Aopen+no%3Aassignee+-label%3Afeature-request+-label%3Aquestion+-label%3Aupstream+-label%3A%22help+wanted%22+-label%3A%22info-needed%22+-label%3A%22as-designed%22+) +Make sure every unassigned issue is labeled properly: -## Updating TypeScript +- [Inbox Queue](https://github.com/microsoft/monaco-editor/issues?q=is%3Aissue+is%3Aopen+no%3Aassignee+-label%3Afeature-request+-label%3Aupstream+-label%3A%22info-needed%22++-label%3Abug+) -- change typescript's version in `package.json`. -- execute `npm install .` -- execute `npm run import-typescript` -- adopt new APIs +## Publishing a stable build monaco-editor build -## Shipping a new monaco-editor npm module +- Make sure there exists a nightly build from the VS Code commit the stable build should be built from +- [Compare Last Stable With Nightly](https://microsoft.github.io/monaco-editor/playground.html?source=v0.40.0-dev.20230704#XQAAAAJWBgAAAAAAAABBqQkHQ5NjdMjwa-jY7SIQ9S7DNlzs5W-mwj0fe1ZCDRFc9ws9XQE0SJE1jc2VKxhaLFIw9vEWSxW3yscw_SM66BuzMt6m3zM8Thvb-XSMR_Da8IdBq3FOgly-7-xuaHSi_yUg58ZO9Mr-RKT7GyHzHoU8B9N7P-uTzmCdhT2Vv-4gNRbWSMQCUPrfmzFCkSH_WR2Vc8LGx2m0uRSFiJu82B1mS0RM-eriU9PTOqAgBrlPUMTU44VrHyVOqgs5BFrUuUHwGDzUHxeNuUk-kg2u70awQLQ83wD4o2EbSefqfIWkk2Yi0mnUS903tLA4V17MD_6OHIRArunMPL6E14ZCW0_Aql21F62Fmz--i_pNbqBIpSlBbZl6LzA1HzNsoDH7i2rn1qAw55L1MjwOU4QQMCJfffmJznAbGoZWkXK91OPYlOGNHNGG-MPUFsY5JSjLfvCWOvXypW9ZVkBZMo1qUbtE135CLqbaBiw52f3eOPBTru3IL_wT__ciAFI5NDiVOeN8V9zqkzbwiFNeQyZcjxmrDLjYTPJpao0dG61Um0w4FpVud8p77bjoAdEfG8JNO97W4cawj0HvMfvcZS81P7IsijZqA7KyVsdq79iCJQuMO31aS86cM4GTNT0TvdI7p62uiEmm9X6ZjF8oSLxW87Vt0oYAZ5wBePqdN6FwNO6BWACt2Ep9i5Q6h-mOy7_JWOiPTOH0Zz3v6SaNhjxJwZAqNG3FqvRTgLg-au-pfa8PD0No3U15UyWeqrVXSthGFghLJ16ppEwFCqFfQ6Vr0leZtSZXyk41-t5ZKMG-KQjzq1XE2PnuyOz60nV4GaYvGlMHrXz-XrEqb2kwNf_pBee0) + - Update [package.json](./package.json) + - set `version` to next stable + - set `vscodeRef` to _vscodeCommitId_ + - update `devDependencies.monaco-editor-core` to _version_ + - Run `npm install` to update lockfile + - Update [CHANGELOG.md](./CHANGELOG.md) + - API Changes / Breaking Changes / New and noteworthy + - Thank you ([use this tool](https://tools.code.visualstudio.com/acknowledgement)) + - Commit + - [Trigger build](https://dev.azure.com/monacotools/Monaco/_build?definitionId=416) -- update `package.json` and bump `"version"` as necessary -- update `package.json` and edit `"vscode"` to point to the vscode repo commit that should be shipped at `monaco-editor-core` (both `monaco-editor-core` and `monaco-editor` will be published under the same version defined in `package.json`). -- write entry in `CHANGELOG.md` - - API Changes / Breaking Changes / New and noteworthy - - Thank you ([use this tool](https://vscode-tools.azurewebsites.net/acknowledgement/)) -- trigger a build using [`Publish to npm`](https://github.com/microsoft/monaco-editor/actions/workflows/publish.yml) and type false when asked "is nightly?" -- if the publish succeeded, run `git tag 0.x.y` and `git push origin 0.x.y` -- edit `package.json` and update the `"monaco-editor-core"` dev dependency. -- run `npm install` - -#### 8. Publish new webpack plugin +#### Publish new webpack plugin - **TBD** - https://github.com/microsoft/monaco-editor/tree/main/webpack-plugin @@ -41,3 +38,10 @@ - use `npm version major` - publish using `npm publish` - remember to push tags upstream + +## Updating TypeScript + +- change typescript's version in `package.json`. +- execute `npm install .` +- execute `npm run import-typescript` +- adopt new APIs diff --git a/README.md b/README.md index 297e8cf9..eee79f77 100644 --- a/README.md +++ b/README.md @@ -31,13 +31,39 @@ You will get: It is recommended to develop against the `dev` version, and in production to use the `min` version. +## Concepts + +Monaco editor is best known for being the text editor that powers VS Code. However, it's a bit more nuanced. Some basic understanding about the underlying concepts is needed to use Monaco editor effectively. + +### Models + +Models are at the heart of Monaco editor. It's what you interact with when managing content. A model represents a file that has been opened. This could represent a file that exists on a file system, but it doesn't have to. For example, the model holds the text content, determines the language of the content, and tracks the edit history of the content. + +### URIs + +Each model is identified by a URI. This is why it's not possible for two models to have the same URI. Ideally when you represent content in Monaco editor, you should think of a virtual file system that matches the files your users are editing. For example, you could use `file:///` as a base path. If a model is created without a URI, its URI will be `inmemory://model/1`. The number increases as more models are created. + +### Editors + +An editor is a user facing view of the model. This is what gets attached to the DOM and what your users see visually. Typical editor operations are displaying a model, managing the view state, or executing actions or commands. + +### Providers + +Providers provide smart editor features. For example, this includes completion and hover information. It is not the same as, but often maps to [language server protocol](https://microsoft.github.io/language-server-protocol) features. + +Providers work on models. Some smart features depends on the file URI. For example, for TypeScript to resolve imports, or for JSON IntelliSense to determine which JSON schema to apply to which model. So it's important to choose proper model URIs. + +### Disposables + +Many Monaco related objects often implement the `.dispose()` method. This method is intended to perform cleanups when a resource is no longer needed. For example, calling `model.dispose()` will unregister it, freeing up the URI for a new model. Editors should be disposed to free up resources and remove their model listeners. + ## Documentation - Learn how to integrate the editor with these [complete samples](./samples/). - [Integrate the AMD version](./docs/integrate-amd.md). - [Integrate the ESM version](./docs/integrate-esm.md) - Learn how to use the editor API and try out your own customizations in the [playground](https://microsoft.github.io/monaco-editor/playground.html). -- Explore the [API docs](https://microsoft.github.io/monaco-editor/docs.html) or read them straight from [`monaco.d.ts`](https://github.com/microsoft/monaco-editor/blob/main/website/typedoc/monaco.d.ts). +- Explore the [API docs](https://microsoft.github.io/monaco-editor/docs.html) or read them straight from [`monaco.d.ts`](https://microsoft.github.io/monaco-editor/node_modules/monaco-editor/monaco.d.ts). - Read [this guide](https://github.com/microsoft/monaco-editor/wiki/Accessibility-Guide-for-Integrators) to ensure the editor is accessible to all your users! - Create a Monarch tokenizer for a new programming language [in the Monarch playground](https://microsoft.github.io/monaco-editor/monarch.html). - Ask questions on [StackOverflow](https://stackoverflow.com/questions/tagged/monaco-editor)! Search open and closed issues, there are a lot of tips in there! diff --git a/build/importTypescript.ts b/build/importTypescript.ts index c2e67267..84b7edc8 100644 --- a/build/importTypescript.ts +++ b/build/importTypescript.ts @@ -37,6 +37,16 @@ export const typescriptVersion = "${typeScriptDependencyVersion}";\n` let tsServices = fs.readFileSync(path.join(TYPESCRIPT_LIB_SOURCE, 'typescript.js')).toString(); + tsServices = tsServices + .replace( + 'const path = matchedStar ? subst.replace("*", matchedStar) : subst;', + 'const path = matchedStar ? subst.replace("*", matchedStar) : subst; // CodeQL [SM02383] This is a false positive, the code is from the TypeScript compiler' + ) + .replace( + 'return key.replace("*", matchedStar);', + 'return key.replace("*", matchedStar); // CodeQL [SM02383] This is a false positive, the code is from the TypeScript compiler' + ); + // The output from this build will only be accessible via ESM; rather than removing // references to require/module, define them as dummy variables that bundlers will ignore. // The TS code can figure out that it's not running under Node even with these defined. diff --git a/build/simpleserver.ts b/build/simpleserver.ts index 76224554..bdfe8e51 100644 --- a/build/simpleserver.ts +++ b/build/simpleserver.ts @@ -10,8 +10,6 @@ import yaserver = require('yaserver'); import { REPO_ROOT } from './utils'; import { ensureDir } from './fs'; -const WEBSITE_GENERATED_PATH = path.join(REPO_ROOT, 'website/playground/new-samples'); - generateTestSamplesTask(); const SERVER_ROOT = path.normalize(path.join(REPO_ROOT, '../')); @@ -53,106 +51,6 @@ function generateTestSamplesTask() { const destination = path.join(REPO_ROOT, 'test/manual/generated/all-samples.js'); ensureDir(path.dirname(destination)); fs.writeFileSync(destination, prefix + JSON.stringify(samples, null, '\t') + suffix); - - /** @type {{ chapter: string; name: string; id: string; path: string; }[]} */ - const PLAY_SAMPLES = require(path.join(WEBSITE_GENERATED_PATH, 'all.js')).PLAY_SAMPLES; - /** @type {{ path: string; name: string; }[]} */ - const locations = []; - for (let i = 0; i < PLAY_SAMPLES.length; i++) { - const sample = PLAY_SAMPLES[i]; - const sampleId = sample.id; - const samplePath = path.join(WEBSITE_GENERATED_PATH, sample.path); - - const html = fs.readFileSync(path.join(samplePath, 'sample.html')); - const js = fs.readFileSync(path.join(samplePath, 'sample.js')); - const css = fs.readFileSync(path.join(samplePath, 'sample.css')); - - const result = [ - '', - '', - '', - '', - ' ', - ' ', - '', - '', - '', - '[<< BACK]
', - 'THIS IS A GENERATED FILE VIA `npm run simpleserver`', - '', - '
', - '', - '
', - '
', - '', - '', - html, - '', - '', - '
', - '
', - '', - '', - '', - '', - '' - ]; - - const destination = path.join( - REPO_ROOT, - 'test/manual/generated/playground/' + sampleId + '.html' - ); - ensureDir(path.dirname(destination)); - fs.writeFileSync(destination, result.join('\n')); - locations.push({ - path: sampleId + '.html', - name: sample.chapter + ' > ' + sample.name - }); - } - - const index = [ - '', - '', - '', - '', - ' ', - '', - '', - '[<< BACK]
', - 'THIS IS A GENERATED FILE VIA `npm run simpleserver`

', - locations - .map(function (location) { - return ( - '' + - location.name + - '' - ); - }) - .join('
\n'), - '', - '', - '' - ]; - fs.writeFileSync( - path.join(REPO_ROOT, 'test/manual/generated/playground/index.html'), - index.join('\n') - ); } function createSimpleServer(rootDir: string, port: number) { diff --git a/package-lock.json b/package-lock.json index 081ac824..ae809d5d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "monaco-editor", - "version": "0.37.0", + "version": "0.43.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "monaco-editor", - "version": "0.37.0", + "version": "0.43.0", "hasInstallScript": true, "license": "MIT", "devDependencies": { @@ -25,7 +25,7 @@ "jsdom": "^19.0.0", "jsonc-parser": "^3.0.0", "mocha": "^9.2.0", - "monaco-editor-core": "^0.37.0-dev.20230403", + "monaco-editor-core": "0.42.0-rc1", "parcel": "^2.7.0", "pin-github-action": "^1.8.0", "playwright": "^1.32.2", @@ -37,7 +37,7 @@ "terser": "^5.14.2", "ts-node": "^10.6.0", "typescript": "^5.0.2", - "vite": "^3.1.8", + "vite": "^3.2.7", "vscode-css-languageservice": "5.4.1", "vscode-html-languageservice": "4.2.4", "vscode-json-languageservice": "4.2.1", @@ -49,9 +49,9 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", + "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", "dev": true, "dependencies": { "@babel/highlight": "^7.18.6" @@ -978,6 +978,74 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/@parcel/optimizer-htmlnano/node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/@parcel/optimizer-htmlnano/node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@parcel/optimizer-htmlnano/node_modules/csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "dev": true, + "dependencies": { + "css-tree": "^1.1.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@parcel/optimizer-htmlnano/node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", + "dev": true + }, + "node_modules/@parcel/optimizer-htmlnano/node_modules/svgo": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", + "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "dev": true, + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/@parcel/optimizer-image": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/@parcel/optimizer-image/-/optimizer-image-2.8.1.tgz", @@ -1019,6 +1087,74 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/@parcel/optimizer-svgo/node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/@parcel/optimizer-svgo/node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@parcel/optimizer-svgo/node_modules/csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "dev": true, + "dependencies": { + "css-tree": "^1.1.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@parcel/optimizer-svgo/node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", + "dev": true + }, + "node_modules/@parcel/optimizer-svgo/node_modules/svgo": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", + "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "dev": true, + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/@parcel/optimizer-terser": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/@parcel/optimizer-terser/-/optimizer-terser-2.8.1.tgz", @@ -1826,12 +1962,6 @@ "integrity": "sha512-93+VvleD3mXwlLI/xASjw0FzKcwzl3OdTCzm1LaRfqgS21gfFtK3zDXM5Op9TeeMsJVOaJ2VRDpT9q4Y3d0AvA==", "dev": true }, - "node_modules/@types/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", - "dev": true - }, "node_modules/@types/shelljs": { "version": "0.8.11", "resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.11.tgz", @@ -2559,6 +2689,15 @@ "node": ">= 0.8" } }, + "node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -2575,19 +2714,21 @@ } }, "node_modules/cosmiconfig": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.1.3.tgz", + "integrity": "sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==", "dev": true, "dependencies": { - "@types/parse-json": "^4.0.0", "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" + "path-type": "^4.0.0" }, "engines": { - "node": ">=10" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" } }, "node_modules/create-require": { @@ -2637,32 +2778,99 @@ } }, "node_modules/css-select": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", - "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "boolbase": "^1.0.0", - "css-what": "^6.0.1", - "domhandler": "^4.3.1", - "domutils": "^2.8.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", "nth-check": "^2.0.1" }, "funding": { "url": "https://github.com/sponsors/fb55" } }, - "node_modules/css-tree": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", - "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "node_modules/css-select/node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/css-select/node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "domelementtype": "^2.3.0" }, "engines": { - "node": ">=8.0.0" + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/css-select/node_modules/domutils": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", + "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.1" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/css-select/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" } }, "node_modules/css-what": { @@ -2690,17 +2898,44 @@ } }, "node_modules/csso": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", - "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { - "css-tree": "^1.1.2" + "css-tree": "~2.2.0" }, "engines": { - "node": ">=8.0.0" + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" } }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "dev": true, + "optional": true, + "peer": true + }, "node_modules/cssom": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", @@ -4114,22 +4349,22 @@ } }, "node_modules/htmlnano": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/htmlnano/-/htmlnano-2.0.3.tgz", - "integrity": "sha512-S4PGGj9RbdgW8LhbILNK7W9JhmYP8zmDY7KDV/8eCiJBQJlbmltp5I0gv8c5ntLljfdxxfmJ+UJVSqyH4mb41A==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/htmlnano/-/htmlnano-2.0.4.tgz", + "integrity": "sha512-WGCkyGFwjKW1GeCBsPYacMvaMnZtFJ0zIRnC2NCddkA+IOEhTqskXrS7lep+3yYZw/nQ3dW1UAX4yA/GJyR8BA==", "dev": true, "dependencies": { - "cosmiconfig": "^7.0.1", + "cosmiconfig": "^8.0.0", "posthtml": "^0.16.5", "timsort": "^0.3.0" }, "peerDependencies": { - "cssnano": "^5.0.11", + "cssnano": "^6.0.0", "postcss": "^8.3.11", "purgecss": "^5.0.0", "relateurl": "^0.2.7", "srcset": "4.0.0", - "svgo": "^2.8.0", + "svgo": "^3.0.2", "terser": "^5.10.0", "uncss": "^0.17.3" }, @@ -4930,10 +5165,12 @@ } }, "node_modules/mdn-data": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", - "dev": true + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "dev": true, + "optional": true, + "peer": true }, "node_modules/merge-stream": { "version": "2.0.0", @@ -5089,9 +5326,9 @@ "dev": true }, "node_modules/monaco-editor-core": { - "version": "0.37.0-dev.20230403", - "resolved": "https://registry.npmjs.org/monaco-editor-core/-/monaco-editor-core-0.37.0-dev.20230403.tgz", - "integrity": "sha512-p77v5G3WNBSSCLY8ORkNkP5XmAOQj7QwxkyzyILj+sWFbw3/1B9SIead0QS368FHV7JKCZ8/LR5T5ccBUZJlJg==", + "version": "0.42.0-rc1", + "resolved": "https://registry.npmjs.org/monaco-editor-core/-/monaco-editor-core-0.42.0-rc1.tgz", + "integrity": "sha512-Y3MCaVVKAb+JTy80uL0FxgzOWRMeIa6VJb7T4yPBI6eFSin4Rnx7WDc2L0BRr+jS6GPH74i2xpL4EDoIAWDZmQ==", "dev": true }, "node_modules/mri": { @@ -5431,15 +5668,6 @@ "url": "https://opencollective.com/parcel" } }, - "node_modules/parcel/node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -5570,15 +5798,6 @@ "node": "^12.20.0 || >=14" } }, - "node_modules/pin-github-action/node_modules/yaml": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.1.tgz", - "integrity": "sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==", - "dev": true, - "engines": { - "node": ">= 14" - } - }, "node_modules/playwright": { "version": "1.32.2", "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.32.2.tgz", @@ -5954,6 +6173,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true + }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -6347,33 +6572,29 @@ } }, "node_modules/svgo": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", - "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.0.2.tgz", + "integrity": "sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "@trysound/sax": "0.2.0", "commander": "^7.2.0", - "css-select": "^4.1.3", - "css-tree": "^1.1.3", - "csso": "^4.2.0", - "picocolors": "^1.0.0", - "stable": "^0.1.8" + "css-select": "^5.1.0", + "css-tree": "^2.2.1", + "csso": "^5.0.5", + "picocolors": "^1.0.0" }, "bin": { "svgo": "bin/svgo" }, "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/svgo/node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "dev": true, - "engines": { - "node": ">= 10" + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" } }, "node_modules/symbol-tree": { @@ -6480,14 +6701,15 @@ } }, "node_modules/tough-cookie": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", - "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", "dev": true, "dependencies": { "psl": "^1.1.33", "punycode": "^2.1.1", - "universalify": "^0.1.2" + "universalify": "^0.2.0", + "url-parse": "^1.5.3" }, "engines": { "node": ">=6" @@ -6636,9 +6858,9 @@ "dev": true }, "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", "dev": true, "engines": { "node": ">= 4.0.0" @@ -6685,6 +6907,16 @@ "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", "dev": true }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -6713,9 +6945,9 @@ "dev": true }, "node_modules/vite": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.5.tgz", - "integrity": "sha512-4mVEpXpSOgrssFZAOmGIr85wPHKvaDAcXqxVxVRZhljkJOMZi1ibLibzjLHzJvcok8BMguLc7g1W6W/GqZbLdQ==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.7.tgz", + "integrity": "sha512-29pdXjk49xAP0QBr0xXqu2s5jiQIXNvE/xwd0vUizYT2Hzqe4BksNNoWllFVXJf4eLZ+UlVQmXfB4lWrc+t18g==", "dev": true, "dependencies": { "esbuild": "^0.15.9", @@ -7125,12 +7357,12 @@ "dev": true }, "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz", + "integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==", "dev": true, "engines": { - "node": ">= 6" + "node": ">= 14" } }, "node_modules/yargs": { @@ -7208,9 +7440,9 @@ }, "dependencies": { "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", + "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", "dev": true, "requires": { "@babel/highlight": "^7.18.6" @@ -7858,6 +8090,61 @@ "nullthrows": "^1.1.1", "posthtml": "^0.16.5", "svgo": "^2.4.0" + }, + "dependencies": { + "css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + } + }, + "css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "dev": true, + "requires": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + } + }, + "csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "dev": true, + "requires": { + "css-tree": "^1.1.2" + } + }, + "mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", + "dev": true + }, + "svgo": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", + "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "dev": true, + "requires": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" + } + } } }, "@parcel/optimizer-image": { @@ -7883,6 +8170,61 @@ "@parcel/plugin": "2.8.1", "@parcel/utils": "2.8.1", "svgo": "^2.4.0" + }, + "dependencies": { + "css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + } + }, + "css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "dev": true, + "requires": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + } + }, + "csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "dev": true, + "requires": { + "css-tree": "^1.1.2" + } + }, + "mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", + "dev": true + }, + "svgo": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", + "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "dev": true, + "requires": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" + } + } } }, "@parcel/optimizer-terser": { @@ -8440,12 +8782,6 @@ "integrity": "sha512-93+VvleD3mXwlLI/xASjw0FzKcwzl3OdTCzm1LaRfqgS21gfFtK3zDXM5Op9TeeMsJVOaJ2VRDpT9q4Y3d0AvA==", "dev": true }, - "@types/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", - "dev": true - }, "@types/shelljs": { "version": "0.8.11", "resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.11.tgz", @@ -9035,6 +9371,12 @@ "delayed-stream": "~1.0.0" } }, + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -9048,16 +9390,15 @@ "dev": true }, "cosmiconfig": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.1.3.tgz", + "integrity": "sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==", "dev": true, "requires": { - "@types/parse-json": "^4.0.0", "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" + "path-type": "^4.0.0" } }, "create-require": { @@ -9094,26 +9435,77 @@ } }, "css-select": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", - "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", "dev": true, + "optional": true, + "peer": true, "requires": { "boolbase": "^1.0.0", - "css-what": "^6.0.1", - "domhandler": "^4.3.1", - "domutils": "^2.8.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", "nth-check": "^2.0.1" + }, + "dependencies": { + "dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + } + }, + "domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "domelementtype": "^2.3.0" + } + }, + "domutils": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", + "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.1" + } + }, + "entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "optional": true, + "peer": true + } } }, "css-tree": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", - "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", "dev": true, + "optional": true, + "peer": true, "requires": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" } }, "css-what": { @@ -9129,12 +9521,36 @@ "dev": true }, "csso": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", - "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", "dev": true, + "optional": true, + "peer": true, "requires": { - "css-tree": "^1.1.2" + "css-tree": "~2.2.0" + }, + "dependencies": { + "css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + } + }, + "mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "dev": true, + "optional": true, + "peer": true + } } }, "cssom": { @@ -9977,12 +10393,12 @@ } }, "htmlnano": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/htmlnano/-/htmlnano-2.0.3.tgz", - "integrity": "sha512-S4PGGj9RbdgW8LhbILNK7W9JhmYP8zmDY7KDV/8eCiJBQJlbmltp5I0gv8c5ntLljfdxxfmJ+UJVSqyH4mb41A==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/htmlnano/-/htmlnano-2.0.4.tgz", + "integrity": "sha512-WGCkyGFwjKW1GeCBsPYacMvaMnZtFJ0zIRnC2NCddkA+IOEhTqskXrS7lep+3yYZw/nQ3dW1UAX4yA/GJyR8BA==", "dev": true, "requires": { - "cosmiconfig": "^7.0.1", + "cosmiconfig": "^8.0.0", "posthtml": "^0.16.5", "timsort": "^0.3.0" } @@ -10496,10 +10912,12 @@ } }, "mdn-data": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", - "dev": true + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "dev": true, + "optional": true, + "peer": true }, "merge-stream": { "version": "2.0.0", @@ -10619,9 +11037,9 @@ } }, "monaco-editor-core": { - "version": "0.37.0-dev.20230403", - "resolved": "https://registry.npmjs.org/monaco-editor-core/-/monaco-editor-core-0.37.0-dev.20230403.tgz", - "integrity": "sha512-p77v5G3WNBSSCLY8ORkNkP5XmAOQj7QwxkyzyILj+sWFbw3/1B9SIead0QS368FHV7JKCZ8/LR5T5ccBUZJlJg==", + "version": "0.42.0-rc1", + "resolved": "https://registry.npmjs.org/monaco-editor-core/-/monaco-editor-core-0.42.0-rc1.tgz", + "integrity": "sha512-Y3MCaVVKAb+JTy80uL0FxgzOWRMeIa6VJb7T4yPBI6eFSin4Rnx7WDc2L0BRr+jS6GPH74i2xpL4EDoIAWDZmQ==", "dev": true }, "mri": { @@ -10873,14 +11291,6 @@ "commander": "^7.0.0", "get-port": "^4.2.0", "v8-compile-cache": "^2.0.0" - }, - "dependencies": { - "commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "dev": true - } } }, "parent-module": { @@ -10976,12 +11386,6 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", "dev": true - }, - "yaml": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.1.tgz", - "integrity": "sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==", - "dev": true } } }, @@ -11247,6 +11651,12 @@ "side-channel": "^1.0.4" } }, + "querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true + }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -11518,26 +11928,19 @@ "dev": true }, "svgo": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", - "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.0.2.tgz", + "integrity": "sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ==", "dev": true, + "optional": true, + "peer": true, "requires": { "@trysound/sax": "0.2.0", "commander": "^7.2.0", - "css-select": "^4.1.3", - "css-tree": "^1.1.3", - "csso": "^4.2.0", - "picocolors": "^1.0.0", - "stable": "^0.1.8" - }, - "dependencies": { - "commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "dev": true - } + "css-select": "^5.1.0", + "css-tree": "^2.2.1", + "csso": "^5.0.5", + "picocolors": "^1.0.0" } }, "symbol-tree": { @@ -11607,14 +12010,15 @@ } }, "tough-cookie": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", - "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", "dev": true, "requires": { "psl": "^1.1.33", "punycode": "^2.1.1", - "universalify": "^0.1.2" + "universalify": "^0.2.0", + "url-parse": "^1.5.3" } }, "tr46": { @@ -11710,9 +12114,9 @@ "dev": true }, "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", "dev": true }, "update-browserslist-db": { @@ -11740,6 +12144,16 @@ "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", "dev": true }, + "url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -11765,9 +12179,9 @@ "dev": true }, "vite": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.5.tgz", - "integrity": "sha512-4mVEpXpSOgrssFZAOmGIr85wPHKvaDAcXqxVxVRZhljkJOMZi1ibLibzjLHzJvcok8BMguLc7g1W6W/GqZbLdQ==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.7.tgz", + "integrity": "sha512-29pdXjk49xAP0QBr0xXqu2s5jiQIXNvE/xwd0vUizYT2Hzqe4BksNNoWllFVXJf4eLZ+UlVQmXfB4lWrc+t18g==", "dev": true, "requires": { "esbuild": "^0.15.9", @@ -12056,9 +12470,9 @@ "dev": true }, "yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz", + "integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==", "dev": true }, "yargs": { diff --git a/package.json b/package.json index 68fb1602..15ab30f9 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "monaco-editor", - "version": "0.37.1", - "vscodeRef": "8f74fbfd1f2d8f6268a42df131726b218aafe511", + "version": "0.43.0", + "vscodeRef": "16e9205452dd417e32f164325b589b94892846b4", "private": true, "description": "A browser based code editor", "homepage": "https://github.com/microsoft/monaco-editor", @@ -52,7 +52,7 @@ "jsdom": "^19.0.0", "jsonc-parser": "^3.0.0", "mocha": "^9.2.0", - "monaco-editor-core": "^0.37.0-dev.20230403", + "monaco-editor-core": "0.42.0-rc1", "parcel": "^2.7.0", "pin-github-action": "^1.8.0", "playwright": "^1.32.2", @@ -64,7 +64,7 @@ "terser": "^5.14.2", "ts-node": "^10.6.0", "typescript": "^5.0.2", - "vite": "^3.1.8", + "vite": "^3.2.7", "vscode-css-languageservice": "5.4.1", "vscode-html-languageservice": "4.2.4", "vscode-json-languageservice": "4.2.1", diff --git a/samples/browser-esm-vite-react/package-lock.json b/samples/browser-esm-vite-react/package-lock.json index 66a08f5f..22e369d4 100644 --- a/samples/browser-esm-vite-react/package-lock.json +++ b/samples/browser-esm-vite-react/package-lock.json @@ -13,7 +13,7 @@ "react": "^17.0.2", "react-dom": "^17.0.2", "typescript": "^5.0.2", - "vite": "^2.9.13" + "vite": "^2.9.16" } }, "node_modules/@ampproject/remapping": { @@ -1372,15 +1372,15 @@ } }, "node_modules/vite": { - "version": "2.9.13", - "resolved": "https://registry.npmjs.org/vite/-/vite-2.9.13.tgz", - "integrity": "sha512-AsOBAaT0AD7Mhe8DuK+/kE4aWYFMx/i0ZNi98hJclxb4e0OhQcZYUrvLjIaQ8e59Ui7txcvKMiJC1yftqpQoDw==", + "version": "2.9.16", + "resolved": "https://registry.npmjs.org/vite/-/vite-2.9.16.tgz", + "integrity": "sha512-X+6q8KPyeuBvTQV8AVSnKDvXoBMnTx8zxh54sOwmmuOdxkjMmEJXH2UEchA+vTMps1xw9vL64uwJOWryULg7nA==", "dev": true, "dependencies": { "esbuild": "^0.14.27", "postcss": "^8.4.13", "resolve": "^1.22.0", - "rollup": "^2.59.0" + "rollup": ">=2.59.0 <2.78.0" }, "bin": { "vite": "bin/vite.js" @@ -2298,16 +2298,16 @@ "dev": true }, "vite": { - "version": "2.9.13", - "resolved": "https://registry.npmjs.org/vite/-/vite-2.9.13.tgz", - "integrity": "sha512-AsOBAaT0AD7Mhe8DuK+/kE4aWYFMx/i0ZNi98hJclxb4e0OhQcZYUrvLjIaQ8e59Ui7txcvKMiJC1yftqpQoDw==", + "version": "2.9.16", + "resolved": "https://registry.npmjs.org/vite/-/vite-2.9.16.tgz", + "integrity": "sha512-X+6q8KPyeuBvTQV8AVSnKDvXoBMnTx8zxh54sOwmmuOdxkjMmEJXH2UEchA+vTMps1xw9vL64uwJOWryULg7nA==", "dev": true, "requires": { "esbuild": "^0.14.27", "fsevents": "~2.3.2", "postcss": "^8.4.13", "resolve": "^1.22.0", - "rollup": "^2.59.0" + "rollup": ">=2.59.0 <2.78.0" } } } diff --git a/samples/browser-esm-vite-react/package.json b/samples/browser-esm-vite-react/package.json index a760b02a..07ff5a1b 100644 --- a/samples/browser-esm-vite-react/package.json +++ b/samples/browser-esm-vite-react/package.json @@ -15,6 +15,6 @@ "@types/react-dom": "^17.0.11", "@vitejs/plugin-react": "^1.1.4", "typescript": "^5.0.2", - "vite": "^2.9.13" + "vite": "^2.9.16" } } diff --git a/scripts/ci/env.ts b/scripts/ci/env.ts new file mode 100644 index 00000000..fc43a709 --- /dev/null +++ b/scripts/ci/env.ts @@ -0,0 +1,15 @@ +interface Env { + VSCODE_REF: string; + PRERELEASE_VERSION: string; +} + +export function getNightlyEnv(): Env { + const env: Env = process.env as any; + if (!env.PRERELEASE_VERSION) { + throw new Error(`Missing PRERELEASE_VERSION in process.env`); + } + if (!env.VSCODE_REF) { + throw new Error(`Missing VSCODE_REF in process.env`); + } + return env; +} diff --git a/scripts/ci/monaco-editor-core-prepare.ts b/scripts/ci/monaco-editor-core-prepare.ts index ea70c44b..eef4371e 100644 --- a/scripts/ci/monaco-editor-core-prepare.ts +++ b/scripts/ci/monaco-editor-core-prepare.ts @@ -1,6 +1,7 @@ import { mkdir, rm } from 'fs/promises'; import { join, resolve } from 'path'; import { PackageJson, group, gitShallowClone, run, writeJsonFile, getNightlyVersion } from '../lib'; +import { getNightlyEnv } from './env'; const selfPath = __dirname; const rootPath = join(selfPath, '..', '..'); @@ -21,8 +22,11 @@ async function prepareMonacoEditorCoreReleaseStableOrNightly() { version = monacoEditorPackageJson.version; ref = monacoEditorPackageJson.vscodeRef; } else if (arg === 'nightly') { - version = getNightlyVersion(monacoEditorPackageJson.version); - ref = 'main'; + version = getNightlyVersion( + monacoEditorPackageJson.version, + getNightlyEnv().PRERELEASE_VERSION + ); + ref = getNightlyEnv().VSCODE_REF; } else { throw new Error('Invalid argument'); } diff --git a/scripts/ci/monaco-editor-prepare.ts b/scripts/ci/monaco-editor-prepare.ts index 2791ec84..b5e2c326 100644 --- a/scripts/ci/monaco-editor-prepare.ts +++ b/scripts/ci/monaco-editor-prepare.ts @@ -1,6 +1,7 @@ import { readFile } from 'fs/promises'; import { join, resolve } from 'path'; import { PackageJson, getNightlyVersion, group, run, writeJsonFile, gitCommitId } from '../lib'; +import { getNightlyEnv } from './env'; const selfPath = __dirname; const rootPath = join(selfPath, '..', '..'); @@ -23,7 +24,10 @@ async function prepareMonacoEditorReleaseStableOrNightly() { if (arg === 'stable') { version = monacoEditorPackageJson.version; } else if (arg === 'nightly') { - version = getNightlyVersion(monacoEditorPackageJson.version); + version = getNightlyVersion( + monacoEditorPackageJson.version, + getNightlyEnv().PRERELEASE_VERSION + ); } else { throw new Error('Invalid argument'); } diff --git a/scripts/lib/index.ts b/scripts/lib/index.ts index 4db4cfe2..9f1c8b71 100644 --- a/scripts/lib/index.ts +++ b/scripts/lib/index.ts @@ -73,14 +73,17 @@ export async function writeJsonFile(filePath: string, jsonData: unknown): Promis await writeFile(filePath, JSON.stringify(jsonData, null, '\t') + '\n'); } -export function getNightlyVersion(version: string): string { +export function getNightlyVersion(version: string, prerelease: string): string { const pieces = version.split('.'); const minor = parseInt(pieces[1], 10); const date = new Date(); const yyyy = date.getUTCFullYear(); const mm = String(date.getUTCMonth() + 1).padStart(2, '0'); const dd = String(date.getUTCDate()).padStart(2, '0'); - return `0.${minor + 1}.0-dev.${yyyy}${mm}${dd}`; + + prerelease = prerelease.replace('${today}', `${yyyy}${mm}${dd}`); + + return `0.${minor + 1}.0-${prerelease}`; } export interface PackageJson { diff --git a/src/basic-languages/elixir/elixir.test.ts b/src/basic-languages/elixir/elixir.test.ts index fe68c922..25c06294 100644 --- a/src/basic-languages/elixir/elixir.test.ts +++ b/src/basic-languages/elixir/elixir.test.ts @@ -303,6 +303,17 @@ testTokenization('elixir', [ ] } ], + // Sigils (multi-letter uppercase) + [ + { + line: '~DX/foo/', + tokens: [ + { startIndex: 0, type: 'sigil.delimiter.elixir' }, + { startIndex: 4, type: 'sigil.elixir' }, + { startIndex: 7, type: 'sigil.delimiter.elixir' } + ] + } + ], // Sigils (no interpolation) [ { @@ -314,6 +325,17 @@ testTokenization('elixir', [ ] } ], + // Sigils (multi-letter uppercase no interpolation) + [ + { + line: '~WW/foo#{1}/', + tokens: [ + { startIndex: 0, type: 'sigil.delimiter.elixir' }, + { startIndex: 4, type: 'sigil.elixir' }, + { startIndex: 11, type: 'sigil.delimiter.elixir' } + ] + } + ], // Sigils (modifiers) [ { @@ -325,6 +347,17 @@ testTokenization('elixir', [ ] } ], + // Sigils (multi-letter uppercase with modifiers) + [ + { + line: '~DX/custom/az09', + tokens: [ + { startIndex: 0, type: 'sigil.delimiter.elixir' }, + { startIndex: 4, type: 'sigil.elixir' }, + { startIndex: 10, type: 'sigil.delimiter.elixir' } + ] + } + ], // Module attributes [ { diff --git a/src/basic-languages/elixir/elixir.ts b/src/basic-languages/elixir/elixir.ts index 078d1030..bb98e976 100644 --- a/src/basic-languages/elixir/elixir.ts +++ b/src/basic-languages/elixir/elixir.ts @@ -333,7 +333,8 @@ export const language = { // See https://elixir-lang.org/getting-started/sigils.html // Sigils allow for typing values using their textual representation. - // All sigils start with ~ followed by a letter indicating sigil type + // All sigils start with ~ followed by a letter or + // multi-letter uppercase starting at Elixir v1.15.0, indicating sigil type // and then a delimiter pair enclosing the textual representation. // Optional modifiers are allowed after the closing delimiter. // For instance a regular expressions can be written as: @@ -353,16 +354,16 @@ export const language = { sigils: [ [/~[a-z]@sigilStartDelimiter/, { token: '@rematch', next: '@sigil.interpol' }], - [/~[A-Z]@sigilStartDelimiter/, { token: '@rematch', next: '@sigil.noInterpol' }] + [/~([A-Z]+)@sigilStartDelimiter/, { token: '@rematch', next: '@sigil.noInterpol' }] ], sigil: [ - [/~([a-zA-Z])\{/, { token: '@rematch', switchTo: '@sigilStart.$S2.$1.{.}' }], - [/~([a-zA-Z])\[/, { token: '@rematch', switchTo: '@sigilStart.$S2.$1.[.]' }], - [/~([a-zA-Z])\(/, { token: '@rematch', switchTo: '@sigilStart.$S2.$1.(.)' }], - [/~([a-zA-Z])\' }], + [/~([a-z]|[A-Z]+)\{/, { token: '@rematch', switchTo: '@sigilStart.$S2.$1.{.}' }], + [/~([a-z]|[A-Z]+)\[/, { token: '@rematch', switchTo: '@sigilStart.$S2.$1.[.]' }], + [/~([a-z]|[A-Z]+)\(/, { token: '@rematch', switchTo: '@sigilStart.$S2.$1.(.)' }], + [/~([a-z]|[A-Z]+)\' }], [ - /~([a-zA-Z])(@sigilSymmetricDelimiter)/, + /~([a-z]|[A-Z]+)(@sigilSymmetricDelimiter)/, { token: '@rematch', switchTo: '@sigilStart.$S2.$1.$2.$2' } ] ], @@ -475,7 +476,7 @@ export const language = { // Fallback to the generic sigil by default 'sigilStart.interpol': [ [ - /~([a-zA-Z])@sigilStartDelimiter/, + /~([a-z]|[A-Z]+)@sigilStartDelimiter/, { token: 'sigil.delimiter', switchTo: '@sigilContinue.$S2.$S3.$S4.$S5' @@ -498,7 +499,7 @@ export const language = { 'sigilStart.noInterpol': [ [ - /~([a-zA-Z])@sigilStartDelimiter/, + /~([a-z]|[A-Z]+)@sigilStartDelimiter/, { token: 'sigil.delimiter', switchTo: '@sigilContinue.$S2.$S3.$S4.$S5' diff --git a/src/basic-languages/javascript/javascript.test.ts b/src/basic-languages/javascript/javascript.test.ts index a3566422..88da829f 100644 --- a/src/basic-languages/javascript/javascript.test.ts +++ b/src/basic-languages/javascript/javascript.test.ts @@ -39,6 +39,65 @@ testTokenization('javascript', [ } ], + // identifiers + [ + { + line: 'foo;', + tokens: [ + { startIndex: 0, type: 'identifier.js' }, + { startIndex: 3, type: 'delimiter.js' } + ] + } + ], + + [ + { + line: 'foo() { return 1; }', + tokens: [ + { startIndex: 0, type: 'identifier.js' }, + { startIndex: 3, type: 'delimiter.parenthesis.js' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'delimiter.bracket.js' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'keyword.js' }, + { startIndex: 14, type: '' }, + { startIndex: 15, type: 'number.js' }, + { startIndex: 16, type: 'delimiter.js' }, + { startIndex: 17, type: '' }, + { startIndex: 18, type: 'delimiter.bracket.js' } + ] + } + ], + + [ + { + line: '#foo;', + tokens: [ + { startIndex: 0, type: 'identifier.js' }, + { startIndex: 4, type: 'delimiter.js' } + ] + } + ], + + [ + { + line: '#foo() { return 1; }', + tokens: [ + { startIndex: 0, type: 'identifier.js' }, + { startIndex: 4, type: 'delimiter.parenthesis.js' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'delimiter.bracket.js' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'keyword.js' }, + { startIndex: 15, type: '' }, + { startIndex: 16, type: 'number.js' }, + { startIndex: 17, type: 'delimiter.js' }, + { startIndex: 18, type: '' }, + { startIndex: 19, type: 'delimiter.bracket.js' } + ] + } + ], + // Comments - single line [ { diff --git a/src/basic-languages/javascript/javascript.ts b/src/basic-languages/javascript/javascript.ts index 5ad3bd67..3af6b4f8 100644 --- a/src/basic-languages/javascript/javascript.ts +++ b/src/basic-languages/javascript/javascript.ts @@ -43,6 +43,7 @@ export const language = { 'null', 'return', 'set', + 'static', 'super', 'switch', 'symbol', diff --git a/src/basic-languages/mdx/mdx.contribution.ts b/src/basic-languages/mdx/mdx.contribution.ts new file mode 100644 index 00000000..c435bfcf --- /dev/null +++ b/src/basic-languages/mdx/mdx.contribution.ts @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { registerLanguage } from '../_.contribution'; + +declare var AMD: any; +declare var require: any; + +registerLanguage({ + id: 'mdx', + extensions: ['.mdx'], + aliases: ['MDX', 'mdx'], + loader: () => { + if (AMD) { + return new Promise((resolve, reject) => { + require(['vs/basic-languages/mdx/mdx'], resolve, reject); + }); + } else { + return import('./mdx'); + } + } +}); diff --git a/src/basic-languages/mdx/mdx.test.ts b/src/basic-languages/mdx/mdx.test.ts new file mode 100644 index 00000000..99ef43cc --- /dev/null +++ b/src/basic-languages/mdx/mdx.test.ts @@ -0,0 +1,171 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { testTokenization } from '../test/testRunner'; + +testTokenization( + ['mdx', 'yaml'], + [ + // headers + [ + { + line: '# header 1', + tokens: [{ startIndex: 0, type: 'keyword.mdx' }] + }, + { + line: '## header 2', + tokens: [{ startIndex: 0, type: 'keyword.mdx' }] + }, + { + line: '### header 3', + tokens: [{ startIndex: 0, type: 'keyword.mdx' }] + }, + { + line: '#### header 4', + tokens: [{ startIndex: 0, type: 'keyword.mdx' }] + }, + { + line: '##### header 5', + tokens: [{ startIndex: 0, type: 'keyword.mdx' }] + }, + { + line: '###### header 6', + tokens: [{ startIndex: 0, type: 'keyword.mdx' }] + } + ], + + // Lists + [ + { + line: '- apple', + tokens: [ + { startIndex: 0, type: 'keyword.mdx' }, + { startIndex: 1, type: 'white.mdx' }, + { startIndex: 2, type: '' } + ] + }, + { + line: '* pear', + tokens: [ + { startIndex: 0, type: 'keyword.mdx' }, + { startIndex: 1, type: 'white.mdx' }, + { startIndex: 2, type: '' } + ] + }, + { + line: '+ pineapple', + tokens: [ + { startIndex: 0, type: 'keyword.mdx' }, + { startIndex: 1, type: 'white.mdx' }, + { startIndex: 2, type: '' } + ] + }, + { + line: '1. orange', + tokens: [ + { startIndex: 0, type: 'number.mdx' }, + { startIndex: 2, type: 'white.mdx' }, + { startIndex: 3, type: '' } + ] + } + ], + + // Frontmatter + [ + { + line: '---', + tokens: [{ startIndex: 0, type: 'meta.content.mdx' }] + }, + { + line: 'frontmatter: yaml', + tokens: [ + { startIndex: 0, type: 'type.yaml' }, + { startIndex: 11, type: 'operators.yaml' }, + { startIndex: 12, type: 'white.yaml' }, + { startIndex: 13, type: 'string.yaml' } + ] + }, + { + line: '---', + tokens: [{ startIndex: 0, type: 'meta.content.mdx' }] + } + ], + + // links + [ + { + line: '[MDX](https://mdxjs.com)', + tokens: [ + { startIndex: 0, type: '' }, + { startIndex: 1, type: 'type.identifier.mdx' }, + { startIndex: 4, type: '' }, + { startIndex: 6, type: 'string.link.mdx' }, + { startIndex: 23, type: '' } + ] + }, + { + line: '[monaco][monaco]', + tokens: [ + { startIndex: 0, type: '' }, + { startIndex: 1, type: 'type.identifier.mdx' }, + { startIndex: 7, type: '' }, + { startIndex: 9, type: 'type.identifier.mdx' }, + { startIndex: 15, type: '' } + ] + }, + { + line: '[monaco][]', + tokens: [ + { startIndex: 0, type: '' }, + { startIndex: 1, type: 'type.identifier.mdx' }, + { startIndex: 9, type: '' } + ] + }, + { + line: '[monaco]', + tokens: [ + { startIndex: 0, type: '' }, + { startIndex: 1, type: 'type.identifier.mdx' }, + { startIndex: 7, type: '' } + ] + }, + { + line: '[monaco]: https://github.com/microsoft/monaco-editor', + tokens: [ + { startIndex: 0, type: '' }, + { startIndex: 1, type: 'type.identifier.mdx' }, + { startIndex: 7, type: '' }, + { startIndex: 10, type: 'string.link.mdx' } + ] + } + ], + + // JSX + [ + { + line: '
**child**
', + tokens: [ + { startIndex: 0, type: 'type.identifier.mdx' }, + // This is incorrect. MDX children that start on the same line are JSX, not markdown + { startIndex: 5, type: 'strong.mdx' }, + { startIndex: 14, type: 'type.identifier.mdx' } + ] + }, + { + line: '{console.log("This is JavaScript")}', + tokens: [ + { startIndex: 0, type: 'delimiter.bracket.mdx' }, + { startIndex: 1, type: 'identifier.js' }, + { startIndex: 8, type: 'delimiter.js' }, + { startIndex: 9, type: 'identifier.js' }, + { startIndex: 12, type: 'delimiter.parenthesis.js' }, + { startIndex: 13, type: 'string.js' }, + { startIndex: 33, type: 'delimiter.parenthesis.js' }, + { startIndex: 34, type: 'delimiter.bracket.mdx' } + ] + } + ] + ] +); diff --git a/src/basic-languages/mdx/mdx.ts b/src/basic-languages/mdx/mdx.ts new file mode 100644 index 00000000..dfbc01e8 --- /dev/null +++ b/src/basic-languages/mdx/mdx.ts @@ -0,0 +1,163 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { languages } from '../../fillers/monaco-editor-core'; + +export const conf: languages.LanguageConfiguration = { + comments: { + blockComment: ['{/*', '*/}'] + }, + brackets: [['{', '}']], + autoClosingPairs: [ + { open: '"', close: '"' }, + { open: "'", close: "'" }, + { open: 'β€œ', close: '”' }, + { open: 'β€˜', close: '’' }, + { open: '`', close: '`' }, + { open: '{', close: '}' }, + { open: '(', close: ')' }, + { open: '_', close: '_' }, + { open: '**', close: '**' }, + { open: '<', close: '>' } + ], + onEnterRules: [ + { + beforeText: /^\s*- .+/, + action: { indentAction: languages.IndentAction.None, appendText: '- ' } + }, + { + beforeText: /^\s*\+ .+/, + action: { indentAction: languages.IndentAction.None, appendText: '+ ' } + }, + { + beforeText: /^\s*\* .+/, + action: { indentAction: languages.IndentAction.None, appendText: '* ' } + }, + { + beforeText: /^> /, + action: { indentAction: languages.IndentAction.None, appendText: '> ' } + }, + { + beforeText: /<\w+/, + action: { indentAction: languages.IndentAction.Indent } + }, + { + beforeText: /\s+>\s*$/, + action: { indentAction: languages.IndentAction.Indent } + }, + { + beforeText: /<\/\w+>/, + action: { indentAction: languages.IndentAction.Outdent } + }, + ...Array.from({ length: 100 }, (_, index) => ({ + beforeText: new RegExp(`^${index}\\. .+`), + action: { indentAction: languages.IndentAction.None, appendText: `${index + 1}. ` } + })) + ] +}; + +export const language = { + defaultToken: '', + tokenPostfix: '.mdx', + control: /[!#()*+.[\\\]_`{}\-]/, + escapes: /\\@control/, + + tokenizer: { + root: [ + [/^---$/, { token: 'meta.content', next: '@frontmatter', nextEmbedded: 'yaml' }], + [/^\s*import/, { token: 'keyword', next: '@import', nextEmbedded: 'js' }], + [/^\s*export/, { token: 'keyword', next: '@export', nextEmbedded: 'js' }], + [/<\w+/, { token: 'type.identifier', next: '@jsx' }], + [/<\/?\w+>/, 'type.identifier'], + [ + /^(\s*)(>*\s*)(#{1,6}\s)/, + [{ token: 'white' }, { token: 'comment' }, { token: 'keyword', next: '@header' }] + ], + [/^(\s*)(>*\s*)([*+-])(\s+)/, ['white', 'comment', 'keyword', 'white']], + [/^(\s*)(>*\s*)(\d{1,9}\.)(\s+)/, ['white', 'comment', 'number', 'white']], + [/^(\s*)(>*\s*)(\d{1,9}\.)(\s+)/, ['white', 'comment', 'number', 'white']], + [/^(\s*)(>*\s*)(-{3,}|\*{3,}|_{3,})$/, ['white', 'comment', 'keyword']], + [/`{3,}(\s.*)?$/, { token: 'string', next: '@codeblock_backtick' }], + [/~{3,}(\s.*)?$/, { token: 'string', next: '@codeblock_tilde' }], + [ + /`{3,}(\S+).*$/, + { token: 'string', next: '@codeblock_highlight_backtick', nextEmbedded: '$1' } + ], + [ + /~{3,}(\S+).*$/, + { token: 'string', next: '@codeblock_highlight_tilde', nextEmbedded: '$1' } + ], + [/^(\s*)(-{4,})$/, ['white', 'comment']], + [/^(\s*)(>+)/, ['white', 'comment']], + { include: 'content' } + ], + content: [ + [ + /(\[)(.+)(]\()(.+)(\s+".*")(\))/, + ['', 'string.link', '', 'type.identifier', 'string.link', ''] + ], + [/(\[)(.+)(]\()(.+)(\))/, ['', 'type.identifier', '', 'string.link', '']], + [/(\[)(.+)(]\[)(.+)(])/, ['', 'type.identifier', '', 'type.identifier', '']], + [/(\[)(.+)(]:\s+)(\S*)/, ['', 'type.identifier', '', 'string.link']], + [/(\[)(.+)(])/, ['', 'type.identifier', '']], + [/`.*`/, 'variable.source'], + [/_/, { token: 'emphasis', next: '@emphasis_underscore' }], + [/\*(?!\*)/, { token: 'emphasis', next: '@emphasis_asterisk' }], + [/\*\*/, { token: 'strong', next: '@strong' }], + [/{/, { token: 'delimiter.bracket', next: '@expression', nextEmbedded: 'js' }] + ], + import: [[/'\s*(;|$)/, { token: 'string', next: '@pop', nextEmbedded: '@pop' }]], + expression: [ + [/{/, { token: 'delimiter.bracket', next: '@expression' }], + [/}/, { token: 'delimiter.bracket', next: '@pop', nextEmbedded: '@pop' }] + ], + export: [[/^\s*$/, { token: 'delimiter.bracket', next: '@pop', nextEmbedded: '@pop' }]], + jsx: [ + [/\s+/, ''], + [/(\w+)(=)("(?:[^"\\]|\\.)*")/, ['attribute.name', 'operator', 'string']], + [/(\w+)(=)('(?:[^'\\]|\\.)*')/, ['attribute.name', 'operator', 'string']], + [/(\w+(?=\s|>|={|$))/, ['attribute.name']], + [/={/, { token: 'delimiter.bracket', next: '@expression', nextEmbedded: 'js' }], + [/>/, { token: 'type.identifier', next: '@pop' }] + ], + header: [ + [/.$/, { token: 'keyword', next: '@pop' }], + { include: 'content' }, + [/./, { token: 'keyword' }] + ], + strong: [ + [/\*\*/, { token: 'strong', next: '@pop' }], + { include: 'content' }, + [/./, { token: 'strong' }] + ], + emphasis_underscore: [ + [/_/, { token: 'emphasis', next: '@pop' }], + { include: 'content' }, + [/./, { token: 'emphasis' }] + ], + emphasis_asterisk: [ + [/\*(?!\*)/, { token: 'emphasis', next: '@pop' }], + { include: 'content' }, + [/./, { token: 'emphasis' }] + ], + frontmatter: [[/^---$/, { token: 'meta.content', nextEmbedded: '@pop', next: '@pop' }]], + codeblock_highlight_backtick: [ + [/\s*`{3,}\s*$/, { token: 'string', next: '@pop', nextEmbedded: '@pop' }], + [/.*$/, 'variable.source'] + ], + codeblock_highlight_tilde: [ + [/\s*~{3,}\s*$/, { token: 'string', next: '@pop', nextEmbedded: '@pop' }], + [/.*$/, 'variable.source'] + ], + codeblock_backtick: [ + [/\s*`{3,}\s*$/, { token: 'string', next: '@pop' }], + [/.*$/, 'variable.source'] + ], + codeblock_tilde: [ + [/\s*~{3,}\s*$/, { token: 'string', next: '@pop' }], + [/.*$/, 'variable.source'] + ] + } +}; diff --git a/src/basic-languages/monaco.contribution.ts b/src/basic-languages/monaco.contribution.ts index 74531ece..b6c07a54 100644 --- a/src/basic-languages/monaco.contribution.ts +++ b/src/basic-languages/monaco.contribution.ts @@ -39,6 +39,7 @@ import './lua/lua.contribution'; import './liquid/liquid.contribution'; import './m3/m3.contribution'; import './markdown/markdown.contribution'; +import './mdx/mdx.contribution'; import './mips/mips.contribution'; import './msdax/msdax.contribution'; import './mysql/mysql.contribution'; diff --git a/src/basic-languages/st/st.contribution.ts b/src/basic-languages/st/st.contribution.ts index e94b9b67..b6811c7a 100644 --- a/src/basic-languages/st/st.contribution.ts +++ b/src/basic-languages/st/st.contribution.ts @@ -10,7 +10,7 @@ declare var require: any; registerLanguage({ id: 'st', - extensions: ['.st', '.iecst', '.iecplc', '.lc3lib'], + extensions: ['.st', '.iecst', '.iecplc', '.lc3lib', '.TcPOU', '.TcDUT', '.TcGVL', '.TcIO'], aliases: ['StructuredText', 'scl', 'stl'], loader: () => { if (AMD) { diff --git a/src/basic-languages/st/st.ts b/src/basic-languages/st/st.ts index fe76f2f1..4ddfdfb7 100644 --- a/src/basic-languages/st/st.ts +++ b/src/basic-languages/st/st.ts @@ -172,7 +172,8 @@ export const language = { 'vendor', 'common_source', 'from', - 'extends' + 'extends', + 'implements' ], constant: ['false', 'true', 'null'], diff --git a/src/basic-languages/twig/twig.test.ts b/src/basic-languages/twig/twig.test.ts index a957eec7..179323b1 100644 --- a/src/basic-languages/twig/twig.test.ts +++ b/src/basic-languages/twig/twig.test.ts @@ -734,6 +734,15 @@ testTokenization( tokens: [{ startIndex: 0, type: 'comment.twig' }] } ], + [ + { + line: 'test {# Hello World! #}', + tokens: [ + { startIndex: 0, type: '' }, + { startIndex: 5, type: 'comment.twig' } + ] + } + ], [ { line: '{#Hello World!#}', @@ -860,6 +869,19 @@ testTokenization( ] } ], + [ + { + line: 'test {{ foo }}', + tokens: [ + { startIndex: 0, type: '' }, + { startIndex: 5, type: 'delimiter.twig' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'variable.twig' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'delimiter.twig' } + ] + } + ], [ { line: '{{ foo(42) }}', @@ -962,6 +984,17 @@ testTokenization( ] } ], + [ + { + line: 'test {% %}', + tokens: [ + { startIndex: 0, type: '' }, + { startIndex: 5, type: 'delimiter.twig' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'delimiter.twig' } + ] + } + ], [ { line: '{% for item in navigation %}', diff --git a/src/basic-languages/twig/twig.ts b/src/basic-languages/twig/twig.ts index 30a05eb7..2dc7c42c 100644 --- a/src/basic-languages/twig/twig.ts +++ b/src/basic-languages/twig/twig.ts @@ -104,7 +104,7 @@ export const language = { [/(<)((?:[\w\-]+:)?[\w\-]+)/, ['delimiter.html', { token: 'tag.html', next: '@otherTag' }]], [/(<\/)((?:[\w\-]+:)?[\w\-]+)/, ['delimiter.html', { token: 'tag.html', next: '@otherTag' }]], [/{ predeclared_intrinsics, operators, - symbols: /[!%&*+\-\.\/:;<=>^|_~]+/, + symbols: /[!%&*+\-\.\/:;<=>^|_~,]+/, tokenizer: { root: [ @@ -402,8 +402,6 @@ export const language = { { include: '@commentOrSpace' }, { include: '@numbers' }, - [/;:\./, 'delimiter'], - [/,/, 'delimiter'], // Hack: Should be in previous rule [/[{}()\[\]]/, '@brackets'], ['@', 'annotation', '@attribute'], [ diff --git a/src/language/typescript/languageFeatures.ts b/src/language/typescript/languageFeatures.ts index 28e58dda..ca111417 100644 --- a/src/language/typescript/languageFeatures.ts +++ b/src/language/typescript/languageFeatures.ts @@ -890,7 +890,7 @@ export class OutlineAdapter extends Adapter implements languages.DocumentSymbolP range: this._textSpanToRange(model, item.spans[0]), selectionRange: this._textSpanToRange(model, item.spans[0]), tags: [], - children: item.childItems?.map((child) => convert(child, result.name)), + children: item.childItems?.map((child) => convert(child, item.text)), containerName: containerLabel }; return result; diff --git a/src/language/typescript/lib/typescriptServices.js b/src/language/typescript/lib/typescriptServices.js index c878528b..4a26445e 100644 --- a/src/language/typescript/lib/typescriptServices.js +++ b/src/language/typescript/lib/typescriptServices.js @@ -40937,7 +40937,7 @@ ${lanes.join("\n")} trace(state.host, Diagnostics.Module_name_0_matched_pattern_1, moduleName, matchedPatternText); } const resolved = forEach(paths[matchedPatternText], (subst) => { - const path = matchedStar ? subst.replace("*", matchedStar) : subst; + const path = matchedStar ? subst.replace("*", matchedStar) : subst; // CodeQL [SM02383] This is a false positive, the code is from the TypeScript compiler const candidate = normalizePath(combinePaths(baseDirectory, path)); if (state.traceEnabled) { trace(state.host, Diagnostics.Trying_substitution_0_candidate_module_location_Colon_1, subst, path); @@ -44626,7 +44626,7 @@ ${lanes.join("\n")} for (const { ending, value } of candidates) { if (value.length >= prefix.length + suffix.length && startsWith(value, prefix) && endsWith(value, suffix) && validateEnding({ ending, value })) { const matchedStar = value.substring(prefix.length, value.length - suffix.length); - return key.replace("*", matchedStar); + return key.replace("*", matchedStar); // CodeQL [SM02383] This is a false positive, the code is from the TypeScript compiler } } } else if (some(candidates, (c) => c.ending !== 0 /* Minimal */ && pattern === c.value) || some(candidates, (c) => c.ending === 0 /* Minimal */ && pattern === c.value && validateEnding(c))) { diff --git a/src/language/typescript/ts.worker.ts b/src/language/typescript/ts.worker.ts index f03e32d1..d654d679 100644 --- a/src/language/typescript/ts.worker.ts +++ b/src/language/typescript/ts.worker.ts @@ -3,15 +3,17 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as edworker from 'monaco-editor-core/esm/vs/editor/editor.worker'; -import { ICreateData, create } from './tsWorker'; +import { initialize } from 'monaco-editor-core/esm/vs/editor/editor.worker'; +import * as ts from './lib/typescriptServices'; +import { ICreateData, TypeScriptWorker, create } from './tsWorker'; import { worker } from '../../fillers/monaco-editor-core'; +import { libFileMap } from './lib/lib'; self.onmessage = () => { // ignore the first message - edworker.initialize((ctx: worker.IWorkerContext, createData: ICreateData) => { + initialize((ctx: worker.IWorkerContext, createData: ICreateData) => { return create(ctx, createData); }); }; -export { create } from './tsWorker'; +export { TypeScriptWorker, create, initialize, libFileMap, ts }; diff --git a/test/manual/dev-setup.js b/test/manual/dev-setup.js index 9cfe13db..8eefd586 100644 --- a/test/manual/dev-setup.js +++ b/test/manual/dev-setup.js @@ -6,8 +6,8 @@ 'npm/dev': 'node_modules/monaco-editor-core/dev/vs', 'npm/min': 'node_modules/monaco-editor-core/min/vs', built: '/vscode/out-monaco-editor-core/min/vs', - releaseDev: 'release/dev/vs', - releaseMin: 'release/min/vs' + releaseDev: 'out/monaco-editor/dev/vs', + releaseMin: 'out/monaco-editor/min/vs' }; const pluginPaths = { src: 'out/amd', @@ -35,11 +35,11 @@ div.style.padding = '5px 20px 5px 5px'; div.style.zIndex = '1000'; - div.innerHTML = - '
  • ' + - renderLoadingOptions(true) + - (isRelease ? '' : `
  • ${renderLoadingOptions(false)}`) + - '
'; + div.innerHTML = // CodeQL [SM03712] This code is not deployed and serves as local test code. No risk of malicious input. + '
  • ' + // CodeQL [SM03712] This code is not deployed and serves as local test code. No risk of malicious input. + renderLoadingOptions(true) + // CodeQL [SM03712] This code is not deployed and serves as local test code. No risk of malicious input. + (isRelease ? '' : `
  • ${renderLoadingOptions(false)}`) + // CodeQL [SM03712] This code is not deployed and serves as local test code. No risk of malicious input. + '
'; // CodeQL [SM03712] This code is not deployed and serves as local test code. No risk of malicious input. document.body.appendChild(div); @@ -47,7 +47,7 @@ for (let i = 0; i < aElements.length; i++) { let aElement = aElements[i]; if (aElement.className === 'loading-opts') { - aElement.href += window.location.search; + aElement.href += window.location.search; // CodeQL [SM01507] This code is not deployed and serves as local test code. No risk of malicious input. } } })(); diff --git a/test/manual/index.js b/test/manual/index.js index f18a3d5e..b1942b89 100644 --- a/test/manual/index.js +++ b/test/manual/index.js @@ -1,4 +1,4 @@ -/// +/// define(['require', './samples'], function (require, SAMPLES) { const domutils = require('vs/base/browser/dom'); @@ -20,16 +20,10 @@ define(['require', './samples'], function (require, SAMPLES) { renderWhitespace: true }); - editor.addCommand( - { - ctrlCmd: true, - key: 'F9' - }, - function (ctx, args) { - alert('Command Running!!'); - console.log(ctx); - } - ); + editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.F9, function (ctx, args) { + alert('Command Running!!'); + console.log(ctx); + }); editor.addAction({ id: 'my-unique-id', diff --git a/webpack-plugin/package-lock.json b/webpack-plugin/package-lock.json index a2fca095..32b06e28 100644 --- a/webpack-plugin/package-lock.json +++ b/webpack-plugin/package-lock.json @@ -1,12 +1,12 @@ { "name": "monaco-editor-webpack-plugin", - "version": "7.0.1", + "version": "7.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "monaco-editor-webpack-plugin", - "version": "7.0.1", + "version": "7.1.0", "license": "MIT", "dependencies": { "loader-utils": "^2.0.2" diff --git a/webpack-plugin/package.json b/webpack-plugin/package.json index 114d315c..145dfc8b 100644 --- a/webpack-plugin/package.json +++ b/webpack-plugin/package.json @@ -1,6 +1,6 @@ { "name": "monaco-editor-webpack-plugin", - "version": "7.0.1", + "version": "7.1.0", "description": "A webpack plugin for the Monaco Editor", "main": "out/index.js", "typings": "./out/index.d.ts", diff --git a/webpack-plugin/src/loaders/include.ts b/webpack-plugin/src/loaders/include.ts index f8705471..4bebcce9 100644 --- a/webpack-plugin/src/loaders/include.ts +++ b/webpack-plugin/src/loaders/include.ts @@ -30,8 +30,12 @@ export const pitch: PitchLoaderDefinitionFunction = function pit ...(globals ? Object.keys(globals).map((key) => `self[${JSON.stringify(key)}] = ${globals[key]};`) : []), - ...pre.map((include: any) => `require(${stringifyRequest(include)});`), - `module.exports = require(${stringifyRequest(`!!${remainingRequest}`)});`, - ...post.map((include: any) => `require(${stringifyRequest(include)});`) + ...pre.map((include: any) => `import ${stringifyRequest(include)};`), + ` +import * as monaco from ${stringifyRequest(`!!${remainingRequest}`)}; +export * from ${stringifyRequest(`!!${remainingRequest}`)}; +export default monaco; + `, + ...post.map((include: any) => `import ${stringifyRequest(include)};`) ].join('\n'); }; diff --git a/website/index/samples/sample.mdx.txt b/website/index/samples/sample.mdx.txt new file mode 100644 index 00000000..295a0c28 --- /dev/null +++ b/website/index/samples/sample.mdx.txt @@ -0,0 +1,92 @@ +--- +frontmatter: data +yaml: true +--- + +[link](https://example.com) + +~~~ +aasd +asd +asd +~~~ + +# Hello MDX {1+2} + +import { MyComponent } from './MyComponent' + +This is **bold {'foo' + 1} text** + +This is _emphasis {'foo' + 1} text_ + +This is *emphasis {'foo' + 1} text too* + + This is an indented *code* block + +export function foo() { + console.log('asd', 1) + if(true) { + return 'yep' + } + return 'nope' +} + + +This is regular content + +- this is a list + +* this is also a list + ++ me too! + +1. pizza +2. fries +3. ice cream + +---- + +_________ + +***\ +~~~css +body { + color: red; +} +~~~ + +> - this is a list +> +> * this is also a list +> +> + me too! +> +> 1. pizza +> 2. fries +> 3. ice cream +> +> --- +> +> _________ +> +> *** +> +> ```css +> body { +> color: red; +> } +> ``` + +> This is a blockquote +> +>> This is a nested {'blockquote'} + +{'foo' + 1 + 2 + {} + 12} + +{/* this is a comment */} + + + + This is **also** markdown. + + diff --git a/website/package.json b/website/package.json index f86bd77e..657513c6 100644 --- a/website/package.json +++ b/website/package.json @@ -24,7 +24,7 @@ "mini-css-extract-plugin": "^2.6.1", "mobx": "^5.15.4", "mobx-react": "^6.2.2", - "monaco-editor": "^0.35.0", + "monaco-editor": "^0.42.0-dev-20230906", "react": "^17.0.2", "react-bootstrap": "^2.4.0", "react-dom": "^17.0.2", diff --git a/website/src/monaco-loader.ts b/website/src/monaco-loader.ts index 2c771a0c..898b08d7 100644 --- a/website/src/monaco-loader.ts +++ b/website/src/monaco-loader.ts @@ -84,7 +84,7 @@ function loadScript(path: string): Promise { script.onload = () => res(); script.async = true; script.type = "text/javascript"; - script.src = path; + script.src = path; // CodeQL [SM01507] This is safe because the runner (that allows for dynamic paths) runs in an isolated iframe. The hosting website uses a static path configuration. // CodeQL [SM03712] This is safe because the runner (that allows for dynamic paths) runs in an isolated iframe. The hosting website uses a static path configuration. document.head.appendChild(script); }); } diff --git a/website/src/runner/index.ts b/website/src/runner/index.ts index 8bc551be..aaedd7e5 100644 --- a/website/src/runner/index.ts +++ b/website/src/runner/index.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { loadMonaco } from "../monaco-loader"; -import { IMessage, IPreviewState } from "../shared"; +import { IMessageFromRunner, IMessageToRunner, IPreviewState } from "../shared"; import "./style.scss"; window.addEventListener("message", (event) => { @@ -14,14 +14,14 @@ window.addEventListener("message", (event) => { console.error("not in sandbox"); return; } - const e = event.data as IMessage | { kind: undefined }; + const e = event.data as IMessageToRunner | { kind: undefined }; if (e.kind === "initialize") { initialize(e.state); } else if (e.kind === "update-css") { const style = document.getElementById( "custom-style" ) as HTMLStyleElement; - style.innerHTML = e.css; + style.innerHTML = e.css; // CodeQL [SM03712] This is safe because the runner runs in an isolated iframe. } }); @@ -46,13 +46,15 @@ async function initialize(state: IPreviewState) { const style = document.createElement("style"); style.id = "custom-style"; - style.innerHTML = state.css; + style.innerHTML = state.css; // CodeQL [SM03712] This is safe because the runner runs in an isolated iframe. This feature is essential to the functionality of the playground. // CodeQL [SM02688] This is safe because the runner runs in an isolated iframe. This feature is essential to the functionality of the playground. document.body.appendChild(style); document.body.innerHTML += state.html; + const js = massageJs(state.js); + try { - eval(state.js); + eval(js); // CodeQL [SM01632] This is safe because the runner runs in an isolated iframe. This feature is essential to the functionality of the playground. // CodeQL [SM02688] This is safe because the runner runs in an isolated iframe. This feature is essential to the functionality of the playground. } catch (err) { const pre = document.createElement("pre"); pre.appendChild( @@ -61,3 +63,42 @@ async function initialize(state: IPreviewState) { document.body.insertBefore(pre, document.body.firstChild); } } + +function sendMessageToParent(message: IMessageFromRunner) { + window.parent.postMessage(message, "*"); +} + +(globalThis as any).$sendMessageToParent = sendMessageToParent; + +(globalThis as any).$bindModelToCodeStr = function bindModel( + model: any, + codeStringName: string +) { + model.onDidChangeContent(() => { + const value = model.getValue(); + sendMessageToParent({ + kind: "update-code-string", + codeStringName, + value, + }); + }); +}; + +function massageJs(js: string) { + /* + Alternate experimental syntax: // bind to code string: `editor.getModel()` -> codeString + + const bindToCodeStringRegexp = /\/\/ bind to code string: `(.*?)` -> (.*?)(\n|$)/g; + js = js.replaceAll(bindToCodeStringRegexp, (match, p1, p2) => { + return `globalThis.bindModelToCodeStr(${p1}, ${JSON.stringify(p2)})\n`; + }); + */ + + const setFromRegexp = /\/*\Wset from `(.*?)`:\W*\//g; + for (const m of js.matchAll(setFromRegexp)) { + const p1 = m[1]; + const target = JSON.stringify("set from `" + p1 + "`"); + js += `\n try { globalThis.$bindModelToCodeStr(${p1}, ${target}); } catch (e) { console.error(e); }`; + } + return js; +} diff --git a/website/src/shared.ts b/website/src/shared.ts index 71036e39..0165733f 100644 --- a/website/src/shared.ts +++ b/website/src/shared.ts @@ -5,7 +5,7 @@ import { IMonacoSetup } from "./monaco-loader"; -export type IMessage = +export type IMessageToRunner = | { kind: "initialize"; state: IPreviewState; @@ -15,6 +15,16 @@ export type IMessage = css: string; }; +export type IMessageFromRunner = + | { + kind: "update-code-string"; + codeStringName: string; + value: string; + } + | { + kind: "reload"; + }; + export interface IPlaygroundProject { js: string; css: string; @@ -22,6 +32,6 @@ export interface IPlaygroundProject { } export interface IPreviewState extends IPlaygroundProject { - key: number; + reloadKey: number; monacoSetup: IMonacoSetup; } diff --git a/website/src/website/components/Loader.tsx b/website/src/website/components/Loader.tsx new file mode 100644 index 00000000..236aa75c --- /dev/null +++ b/website/src/website/components/Loader.tsx @@ -0,0 +1,40 @@ +import * as React from "react"; +export class Loader extends React.Component< + { children: (value: T) => React.ReactChild; loader: () => Promise }, + { value: T | undefined; hasValue: boolean } +> { + constructor(props: any) { + super(props); + this.state = { value: undefined, hasValue: false }; + if (!this.state.value) { + this.props.loader().then((value) => { + this.setState({ + hasValue: true, + value, + }); + }); + } + } + + render() { + if (!this.state.hasValue) { + return null; + } + return this.props.children(this.state.value!); + } +} + +/** + * Decorates a component so that it only gets mounted when monaco is loaded. + */ +export function withLoader( + loader: () => Promise +): ( + Component: React.FunctionComponent | React.ComponentClass +) => any { + return (Component) => { + return (props: any) => ( + {() => } + ); + }; +} diff --git a/website/src/website/components/monaco/MonacoEditor.tsx b/website/src/website/components/monaco/MonacoEditor.tsx index bd8d47af..57e47761 100644 --- a/website/src/website/components/monaco/MonacoEditor.tsx +++ b/website/src/website/components/monaco/MonacoEditor.tsx @@ -249,6 +249,7 @@ export class MonacoDiffEditor extends React.Component< minimap: { enabled: false }, automaticLayout: false, theme: this.props.theme, + originalEditable: true, }); this.editor.setModel({ original: this.props.originalModel, diff --git a/website/src/website/components/monaco/MonacoLoader.tsx b/website/src/website/components/monaco/MonacoLoader.tsx index 44665417..61ea1c46 100644 --- a/website/src/website/components/monaco/MonacoLoader.tsx +++ b/website/src/website/components/monaco/MonacoLoader.tsx @@ -26,6 +26,7 @@ export class MonacoLoader extends React.Component< return this.props.children(this.state.monaco); } } + /** * Decorates a component so that it only gets mounted when monaco is loaded. */ diff --git a/website/src/website/data/home-samples/sample.mdx.txt b/website/src/website/data/home-samples/sample.mdx.txt new file mode 100644 index 00000000..0e2479f9 --- /dev/null +++ b/website/src/website/data/home-samples/sample.mdx.txt @@ -0,0 +1,91 @@ +--- +title: Hello! +--- + +import {Chart} from './chart.js' +import population from './population.js' +import {External} from './some/place.js' + +export const year = 2018 +export const pi = 3.14 + +export function SomeComponent(props) { + const name = (props || {}).name || 'world' + + return
+

Hi, {name}!

+ +

and some more things

+
+} + +export function Local(props) { + return +} + +# Last year’s snowfall + +In {year}, the snowfall was above average. +It was followed by a warm spring which caused +flood conditions in many of the nearby rivers. + + + +
+ > Some notable things in a block quote! +
+ +# Heading (rank 1) +## Heading 2 +### 3 +#### 4 +##### 5 +###### 6 + +> Block quote + +* Unordered +* List + +1. Ordered +2. List + +A paragraph, introducing a thematic break: + +--- + +```js +// Get an element. +const element = document.querySelectorAll('#hi') + +// Add a class. +element.classList.add('asd') +``` + +a [link](https://example.com), an ![image](./image.png), some *emphasis*, +something **strong**, and finally a little `code()`. + +} +/> + +Two 🍰 is: {Math.PI * 2} + +{(function () { + const guess = Math.random() + + if (guess > 0.66) { + return Look at us. + } + + if (guess > 0.33) { + return Who would have guessed?! + } + + return Not me. +})()} + +{/* A comment! */} diff --git a/website/src/website/data/playground-samples/creating-the-diffeditor/hello-diff-world/sample.js b/website/src/website/data/playground-samples/creating-the-diffeditor/hello-diff-world/sample.js index 83089074..84d8ba80 100644 --- a/website/src/website/data/playground-samples/creating-the-diffeditor/hello-diff-world/sample.js +++ b/website/src/website/data/playground-samples/creating-the-diffeditor/hello-diff-world/sample.js @@ -1,8 +1,18 @@ -var originalModel = monaco.editor.createModel("heLLo world!", "text/plain"); -var modifiedModel = monaco.editor.createModel("hello orlando!", "text/plain"); +const originalModel = monaco.editor.createModel( + /* set from `originalModel`: */ `hello world`, + "text/plain" +); +const modifiedModel = monaco.editor.createModel( + /* set from `modifiedModel`: */ `Hello World!`, + "text/plain" +); -var diffEditor = monaco.editor.createDiffEditor( - document.getElementById("container") +const diffEditor = monaco.editor.createDiffEditor( + document.getElementById("container"), + { + originalEditable: true, + automaticLayout: true, + } ); diffEditor.setModel({ original: originalModel, diff --git a/website/src/website/data/playground-samples/creating-the-editor/hello-world/sample.js b/website/src/website/data/playground-samples/creating-the-editor/hello-world/sample.js index c68ae059..7beb8e40 100644 --- a/website/src/website/data/playground-samples/creating-the-editor/hello-world/sample.js +++ b/website/src/website/data/playground-samples/creating-the-editor/hello-world/sample.js @@ -1,10 +1,10 @@ -const text = `function hello() { +const value = /* set from `myEditor.getModel()`: */ `function hello() { alert('Hello world!'); }`; // Hover on each property to see its docs! -monaco.editor.create(document.getElementById("container"), { - value: text, +const myEditor = monaco.editor.create(document.getElementById("container"), { + value, language: "javascript", automaticLayout: true, }); diff --git a/website/src/website/data/playground-samples/interacting-with-the-editor/rendering-glyphs-in-the-margin/sample.css b/website/src/website/data/playground-samples/interacting-with-the-editor/rendering-glyphs-in-the-margin/sample.css index 6aa88f43..92c07cbc 100644 --- a/website/src/website/data/playground-samples/interacting-with-the-editor/rendering-glyphs-in-the-margin/sample.css +++ b/website/src/website/data/playground-samples/interacting-with-the-editor/rendering-glyphs-in-the-margin/sample.css @@ -2,5 +2,6 @@ background: red; } .myContentClass { - background: lightblue; + /* Make sure to use transparent colors for the selection to work */ + background: rgba(173, 216, 230, 0.5); } diff --git a/website/src/website/pages/home/Home.tsx b/website/src/website/pages/home/Home.tsx index 9e77ebf3..759a06b2 100644 --- a/website/src/website/pages/home/Home.tsx +++ b/website/src/website/pages/home/Home.tsx @@ -172,10 +172,9 @@ class EditorDemo extends React.Component {

IntelliSense, Validation

- Paragraph of text beneath the heading to explain - the heading. We'll add onto it with another - sentence and probably just keep going until we - run out of words. + Get completions and errors directly in the + browser for supported languages. Or write your + own completion providers in JavaScript.

@@ -184,10 +183,9 @@ class EditorDemo extends React.Component {

Basic Syntax Colorization

- Paragraph of text beneath the heading to explain - the heading. We'll add onto it with another - sentence and probably just keep going until we - run out of words. + Colorize code using our pre-built syntax + highlighting, or configure your own custom + colorization.

@@ -217,6 +215,7 @@ class EditorDemo extends React.Component { value={this.currentSample.value || "loading..."} language={this.currentLanguage?.id} theme={this.currentTheme.id} + onDidValueChange={() => {}} /> diff --git a/website/src/website/pages/playground/BisectModel.ts b/website/src/website/pages/playground/BisectModel.ts new file mode 100644 index 00000000..a2f400d9 --- /dev/null +++ b/website/src/website/pages/playground/BisectModel.ts @@ -0,0 +1,161 @@ +import { action, ObservableMap } from "mobx"; +import { + getNpmVersions, + getNpmVersionsSync, + getVsCodeCommitId, +} from "./getNpmVersionsSync"; +import { PlaygroundModel } from "./PlaygroundModel"; +import { findLastIndex } from "./utils"; + +export class BisectModel { + private readonly map = new ObservableMap(); + + constructor(private readonly model: PlaygroundModel) {} + + public getState(version: string): boolean | undefined { + return this.map.get(version); + } + + public get isActive() { + return [...this.map.values()].some((e) => e !== undefined); + } + + public reset(): void { + this.map.clear(); + } + + public async toggleState(version: string, state: boolean): Promise { + const currentState = this.getState(version); + await this.setState( + version, + currentState === state ? undefined : state + ); + } + + @action + public async setState( + version: string, + state: boolean | undefined + ): Promise { + if (state === undefined) { + this.map.delete(version); + } else { + this.map.set(version, state); + } + + const nextVersion = await this.getNextVersion(); + if (!nextVersion) { + return; + } + this.model.settings.setSettings({ + ...this.model.settings.settings, + npmVersion: nextVersion, + }); + } + + private get versions() { + return getNpmVersionsSync(undefined); + } + + private get indexOfLastBadVersion() { + return findLastIndex(this.versions, (v) => this.map.get(v) === false); + } + private get indexOfFirstGoodVersion() { + return this.versions.findIndex((v) => this.map.get(v) === true); + } + + public get steps() { + const indexOfFirstGoodVersion = this.indexOfFirstGoodVersion; + const indexOfLastBadVersion = this.indexOfLastBadVersion; + + if (indexOfFirstGoodVersion === -1 && indexOfLastBadVersion === -1) { + return -1; + } + if (indexOfFirstGoodVersion === -1) { + return Math.ceil( + Math.log2(this.versions.length - indexOfLastBadVersion) + ); + } else if (indexOfLastBadVersion === -1) { + return Math.ceil(Math.log2(indexOfFirstGoodVersion + 1)); + } else { + return Math.ceil( + Math.log2(indexOfFirstGoodVersion - indexOfLastBadVersion) + ); + } + } + + public get isFinished() { + if ( + this.indexOfFirstGoodVersion !== -1 && + this.indexOfLastBadVersion + 1 === this.indexOfFirstGoodVersion + ) { + return true; + } + return false; + } + + public async openGithub() { + const versions = await getNpmVersions(); + const indexOfFirstGoodVersion = + this.indexOfFirstGoodVersion === -1 + ? versions.length - 1 + : this.indexOfFirstGoodVersion; + const indexOfLastBadVersion = + this.indexOfLastBadVersion === -1 ? 0 : this.indexOfLastBadVersion; + const goodCommitId = await getVsCodeCommitId( + versions[indexOfFirstGoodVersion] + ); + const badCommitId = await getVsCodeCommitId( + versions[indexOfLastBadVersion] + ); + window.open( + `https://github.com/microsoft/vscode/compare/${goodCommitId}...${badCommitId}`, + "_blank" + ); + } + + private async getNextVersion(): Promise { + const versions = await getNpmVersions(); + + const indexOfFirstGoodVersion = this.indexOfFirstGoodVersion; + const indexOfLastBadVersion = this.indexOfLastBadVersion; + + if ( + indexOfFirstGoodVersion !== -1 && + indexOfLastBadVersion + 1 === indexOfFirstGoodVersion + ) { + // Finished + return; + } + + if (indexOfLastBadVersion === -1 && indexOfFirstGoodVersion === -1) { + return versions[0]; + } + if (indexOfLastBadVersion === -1) { + // try first (newest) version that hasn't been tested + const indexOfFirstUntestedVersion = versions.findIndex( + (v) => this.map.get(v) === undefined + ); + if (indexOfFirstUntestedVersion === -1) { + return undefined; + } + return versions[indexOfFirstUntestedVersion]; + } + + if (indexOfFirstGoodVersion === -1) { + /*// exponential back off, might be good for recent regressions, but ruins step counter + const candidate = Math.min( + indexOfLastBadVersion * 2 + 1, + versions.length - 1 + );*/ + const candidate = Math.floor( + (indexOfLastBadVersion + versions.length) / 2 + ); + return versions[candidate]; + } + + return versions[ + Math.floor((indexOfLastBadVersion + indexOfFirstGoodVersion) / 2) + ]; + } +} diff --git a/website/src/website/pages/playground/LocationModel.ts b/website/src/website/pages/playground/LocationModel.ts new file mode 100644 index 00000000..abc96ad1 --- /dev/null +++ b/website/src/website/pages/playground/LocationModel.ts @@ -0,0 +1,211 @@ +import { action, observable } from "mobx"; +import { IPlaygroundProject } from "../../../shared"; +import { monacoEditorVersion } from "../../monacoEditorVersion"; +import { LzmaCompressor } from "../../utils/lzmaCompressor"; +import { + HistoryController, + IHistoryModel, + ILocation, +} from "../../utils/ObservableHistory"; +import { debouncedComputed, Disposable } from "../../utils/utils"; +import { getPlaygroundExamples, PlaygroundExample } from "./playgroundExamples"; +import { Source } from "./Source"; +import { PlaygroundModel } from "./PlaygroundModel"; +import { projectEquals } from "./utils"; + +export class LocationModel implements IHistoryModel { + public readonly dispose = Disposable.fn(); + + private readonly compressor = new LzmaCompressor(); + + private cachedState: + | { state: IPlaygroundProject; hash: string } + | undefined = undefined; + + @observable private _sourceOverride: Source | undefined; + get sourceOverride(): Source | undefined { + return this._sourceOverride; + } + + @observable private _compareWith: Source | undefined; + get compareWith(): Source | undefined { + return this._compareWith; + } + + /** + * This is used to control replace/push state. + * Replace is used if the history id does not change. + */ + @observable historyId: number = 0; + + constructor(private readonly model: PlaygroundModel) { + this.dispose.track( + new HistoryController((initialLocation) => { + this.updateLocation(initialLocation); + return this; + }) + ); + } + + get location(): ILocation { + const source = this._sourceOverride || this.sourceFromSettings; + return { + hashValue: this.computedHashValue.value || this.cachedState?.hash, + searchParams: { + source: source?.sourceToString(), + sourceLanguages: source?.sourceLanguagesToString(), + compareWith: this._compareWith?.sourceToString(), + }, + }; + } + + @action + updateLocation(currentLocation: ILocation): void { + const hashValue = currentLocation.hashValue; + const sourceStr = currentLocation.searchParams.source; + const sourceLanguages = currentLocation.searchParams.sourceLanguages; + const source = + sourceStr || sourceLanguages + ? Source.parse(sourceStr, sourceLanguages) + : undefined; + + if (this.sourceFromSettings?.equals(source)) { + this._sourceOverride = undefined; + } else { + this._sourceOverride = source; + } + + const compareWithStr = currentLocation.searchParams.compareWith; + const compareWith = compareWithStr + ? Source.parse(compareWithStr, undefined) + : undefined; + this._compareWith = compareWith; + + function findExample(hashValue: string): PlaygroundExample | undefined { + if (hashValue.startsWith("example-")) { + hashValue = hashValue.substring("example-".length); + } + return getPlaygroundExamples() + .flatMap((e) => e.examples) + .find((e) => e.id === hashValue); + } + + let example: PlaygroundExample | undefined; + + if (!hashValue) { + this.model.selectedExample = getPlaygroundExamples()[0].examples[0]; + } else if ((example = findExample(hashValue))) { + this.model.selectedExample = example; + } else { + let p: IPlaygroundProject | undefined = undefined; + if (this.cachedState?.hash === hashValue) { + p = this.cachedState.state; + } + if (!p) { + try { + p = + this.compressor.decodeData( + hashValue + ); + } catch (e) { + console.log("Could not deserialize from hash value", e); + } + } + if (p) { + this.cachedState = { state: p, hash: hashValue }; + this.model.setState(p); + } + } + } + + private readonly computedHashValue = debouncedComputed( + 500, + () => ({ + state: this.model.playgroundProject, + selectedExampleProject: this.model.selectedExampleProject, + }), + ({ state, selectedExampleProject }) => { + if ( + selectedExampleProject && + projectEquals(state, selectedExampleProject.project) + ) { + return "example-" + selectedExampleProject.example.id; + } + if ( + this.cachedState && + projectEquals(this.cachedState.state, state) + ) { + return this.cachedState.hash; + } + return this.compressor.encodeData(state); + } + ); + + private get sourceFromSettings(): Source | undefined { + const settings = this.model.settings.settings; + if (settings.monacoSource === "npm") { + return new Source(settings.npmVersion, undefined, undefined); + } else if ( + settings.monacoSource === "independent" && + ((settings.coreSource === "url" && + (settings.languagesSource === "latest" || + settings.languagesSource === "url")) || + (settings.coreSource === "latest" && + settings.languagesSource === "url")) + ) { + return new Source( + undefined, + settings.coreSource === "url" ? settings.coreUrl : undefined, + settings.languagesSource === "latest" + ? undefined + : settings.languagesUrl + ); + } else if (settings.monacoSource === "latest") { + return new Source(monacoEditorVersion, undefined, undefined); + } + return undefined; + } + + @action + exitCompare(): void { + this._compareWith = undefined; + this.historyId++; + } + + @action + disableSourceOverride(): void { + this._sourceOverride = undefined; + this.historyId++; + } + + @action + compareWithLatestDev(): void { + this._compareWith = Source.useLatestDev(); + this.historyId++; + } + + @action + saveCompareWith(): void { + if (this._compareWith) { + this.model.settings.setSettings({ + ...this.model.settings.settings, + ...this._compareWith.toPartialSettings(), + }); + this.historyId++; + this._compareWith = undefined; + this._sourceOverride = undefined; + } + } + + @action + saveSourceOverride(): void { + if (this._sourceOverride) { + this.model.settings.setSettings({ + ...this.model.settings.settings, + ...this._sourceOverride.toPartialSettings(), + }); + this.historyId++; + this._sourceOverride = undefined; + } + } +} diff --git a/website/src/website/pages/playground/PlaygroundModel.ts b/website/src/website/pages/playground/PlaygroundModel.ts index d94a9988..46ea286c 100644 --- a/website/src/website/pages/playground/PlaygroundModel.ts +++ b/website/src/website/pages/playground/PlaygroundModel.ts @@ -8,7 +8,6 @@ import { autorun, computed, observable, - ObservableMap, reaction, runInAction, } from "mobx"; @@ -18,22 +17,10 @@ import { waitForLoadedMonaco, } from "../../../monaco-loader"; import { IPlaygroundProject, IPreviewState } from "../../../shared"; -import { monacoEditorVersion } from "../../monacoEditorVersion"; import { Debouncer } from "../../utils/Debouncer"; -import { LzmaCompressor } from "../../utils/lzmaCompressor"; -import { - HistoryController, - IHistoryModel, - ILocation, -} from "../../utils/ObservableHistory"; import { ObservablePromise } from "../../utils/ObservablePromise"; -import { debouncedComputed, Disposable } from "../../utils/utils"; -import { - getNpmVersions, - getNpmVersionsSync, - getVsCodeCommitId, -} from "./getNpmVersionsSync"; -import { getPlaygroundExamples, PlaygroundExample } from "./playgroundExamples"; +import { Disposable } from "../../utils/utils"; +import { PlaygroundExample } from "./playgroundExamples"; import { getDefaultSettings, JsonString, @@ -41,6 +28,8 @@ import { SettingsModel, toLoaderConfig, } from "./SettingsModel"; +import { BisectModel } from "./BisectModel"; +import { LocationModel } from "./LocationModel"; export class PlaygroundModel { public readonly dispose = Disposable.fn(); @@ -58,16 +47,18 @@ export class PlaygroundModel { @observable public reloadKey = 0; - public readonly serializer = new StateUrlSerializer(this); + public readonly historyModel = new LocationModel(this); public reload(): void { this.reloadKey++; } - private readonly _previewHandlers = new Set(); + public get previewShouldBeFullScreen(): boolean { + return this.settings.previewFullScreen; + } private _wasEverNonFullScreen = false; - public get wasEverNonFullScreen() { + public get wasEverNonFullScreen(): boolean { if (this._wasEverNonFullScreen) { return true; } @@ -79,7 +70,7 @@ export class PlaygroundModel { @computed.struct get monacoSetup(): IMonacoSetup { - const sourceOverride = this.serializer.sourceOverride; + const sourceOverride = this.historyModel.sourceOverride; if (sourceOverride) { return toLoaderConfig({ ...getDefaultSettings(), @@ -105,10 +96,33 @@ export class PlaygroundModel { return { ...this.playgroundProject, monacoSetup: this.monacoSetup, - key: this.reloadKey, + reloadKey: this.reloadKey, }; } + @observable.ref + private _previewState: IPreviewState | undefined = undefined; + + public readonly getPreviewState = (): IPreviewState | undefined => { + return this._previewState; + }; + + public readonly getCompareWithPreviewState = (): + | IPreviewState + | undefined => { + const previewState = this.getPreviewState(); + if (!previewState) { + return undefined; + } + return { + ...previewState, + monacoSetup: toLoaderConfig({ + ...getDefaultSettings(), + ...this.historyModel.compareWith!.toPartialSettings(), + }), + }; + }; + @observable public settingsDialogModel: SettingsDialogModel | undefined = undefined; @@ -134,43 +148,50 @@ export class PlaygroundModel { example: value, project: p, }; + this.reloadKey++; this.setState(p); }); }); } } - private readonly debouncer = new Debouncer(250); + private readonly debouncer = new Debouncer(700); @observable public isDirty = false; constructor() { - let lastState = this.state; + let lastState: IPreviewState | undefined = undefined; this.dispose.track({ dispose: reaction( () => ({ state: this.state }), - ({ state }) => { + () => { + const state = this.state; if (!this.settings.autoReload) { if ( - JSON.stringify(state.monacoSetup) === - JSON.stringify(lastState.monacoSetup) && - state.key === lastState.key + (!lastState || + JSON.stringify(state.monacoSetup) === + JSON.stringify(lastState.monacoSetup)) && + state.reloadKey === (lastState?.reloadKey ?? 0) ) { this.isDirty = true; return; } } - this.debouncer.run(() => { + const updatePreviewState = () => { this.isDirty = false; - lastState = state; - for (const handler of this._previewHandlers) { - handler.handlePreview(state); - } - }); + this._previewState = state; + lastState = this._previewState; + }; + + if (state.reloadKey !== lastState?.reloadKey) { + updatePreviewState(); + } else { + this.debouncer.run(updatePreviewState); + } }, - { name: "update preview" } + { name: "update preview", fireImmediately: true } ), }); @@ -178,6 +199,17 @@ export class PlaygroundModel { let disposable: Disposable | undefined = undefined; waitForLoadedMonaco().then((m) => { + this.dispose.track( + monaco.editor.addEditorAction({ + id: "reload", + label: "Reload", + run: (editor, ...args) => { + this.reload(); + }, + keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter], + }) + ); + const options = monaco.languages.typescript.javascriptDefaults.getCompilerOptions(); monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions( @@ -222,6 +254,28 @@ export class PlaygroundModel { }); } + setCodeString(codeStringName: string, value: string) { + function escapeRegexpChars(str: string) { + return str.replace(/[-[\]/{}()*+?.\\^$|]/g, "\\$&"); + } + + const regexp = new RegExp( + "(\\b" + + escapeRegexpChars(codeStringName) + + ":[^\\w`]*`)([^`\\\\\\n]|\\n|\\\\\\\\|\\\\\\`|\\\\\\$)*`" + ); + const js = this.js; + const str = value + .replaceAll("\\", "\\\\") + .replaceAll("$", "\\$$$$") + .replaceAll("`", "\\`"); + const newJs = js.replace(regexp, "$1" + str + "`"); + const autoReload = this.settings.autoReload; + this.settings.autoReload = false; + this.js = newJs; + this.settings.autoReload = autoReload; + } + public showSettingsDialog(): void { this.settingsDialogModel = new SettingsDialogModel( this.settings.settings @@ -245,21 +299,13 @@ export class PlaygroundModel { this.css = state.css; } - public setPreviewHandler(handler: IPreviewHandler): monaco.IDisposable { - this._previewHandlers.add(handler); - handler.handlePreview(this.state); - return { - dispose: () => { - this._previewHandlers.delete(handler); - }, - }; - } - public readonly bisectModel = new BisectModel(this); -} -export interface IPreviewHandler { - handlePreview(state: IPreviewState): void; + @action + compareWithLatestDev(): void { + this.settings.previewFullScreen = true; + this.historyModel.compareWithLatestDev(); + } } export class SettingsDialogModel { @@ -277,419 +323,3 @@ export class SettingsDialogModel { this.settings = Object.assign({}, settings); } } - -function projectEquals( - project1: IPlaygroundProject, - project2: IPlaygroundProject -): boolean { - return ( - project1.css === project2.css && - project1.html === project2.html && - project1.js === project2.js - ); -} - -class StateUrlSerializer implements IHistoryModel { - public readonly dispose = Disposable.fn(); - - private readonly compressor = new LzmaCompressor(); - - private cachedState: - | { state: IPlaygroundProject; hash: string } - | undefined = undefined; - - private readonly computedHashValue = debouncedComputed( - 500, - () => ({ - state: this.model.playgroundProject, - selectedExampleProject: this.model.selectedExampleProject, - }), - ({ state, selectedExampleProject }) => { - if ( - selectedExampleProject && - projectEquals(state, selectedExampleProject.project) - ) { - return "example-" + selectedExampleProject.example.id; - } - if ( - this.cachedState && - projectEquals(this.cachedState.state, state) - ) { - return this.cachedState.hash; - } - return this.compressor.encodeData(state); - } - ); - - private get sourceFromSettings(): Source | undefined { - const settings = this.model.settings.settings; - if (settings.monacoSource === "npm") { - return new Source(settings.npmVersion, undefined, undefined); - } else if ( - settings.monacoSource === "independent" && - ((settings.coreSource === "url" && - (settings.languagesSource === "latest" || - settings.languagesSource === "url")) || - (settings.coreSource === "latest" && - settings.languagesSource === "url")) - ) { - return new Source( - undefined, - settings.coreSource === "url" ? settings.coreUrl : undefined, - settings.languagesSource === "latest" - ? undefined - : settings.languagesUrl - ); - } else if (settings.monacoSource === "latest") { - return new Source(monacoEditorVersion, undefined, undefined); - } - return undefined; - } - - @observable - private _sourceOverride: Source | undefined; - - get sourceOverride(): Source | undefined { - return this._sourceOverride; - } - - @action - disableSourceOverride(): void { - this._sourceOverride = undefined; - this.historyId++; - } - - @action - saveSourceOverride(): void { - if (this._sourceOverride) { - this.model.settings.setSettings({ - ...this.model.settings.settings, - ...this._sourceOverride.toPartialSettings(), - }); - this.historyId++; - this._sourceOverride = undefined; - } - } - - /** - * This is used to control replace/push state. - * Replace is used if the history id does not change. - */ - @observable historyId: number = 0; - - get location(): ILocation { - const source = this._sourceOverride || this.sourceFromSettings; - return { - hashValue: this.computedHashValue.value || this.cachedState?.hash, - searchParams: { - source: source?.sourceToString(), - sourceLanguages: source?.sourceLanguagesToString(), - }, - }; - } - - @action - updateLocation(currentLocation: ILocation): void { - const hashValue = currentLocation.hashValue; - const sourceStr = currentLocation.searchParams.source; - const sourceLanguages = currentLocation.searchParams.sourceLanguages; - const source = - sourceStr || sourceLanguages - ? Source.parse(sourceStr, sourceLanguages) - : undefined; - - if (this.sourceFromSettings?.equals(source)) { - this._sourceOverride = undefined; - } else { - this._sourceOverride = source; - } - - if (!hashValue) { - this.model.selectedExample = getPlaygroundExamples()[0].examples[0]; - } else if (hashValue.startsWith("example-")) { - const exampleName = hashValue.substring("example-".length); - const example = getPlaygroundExamples() - .flatMap((e) => e.examples) - .find((e) => e.id === exampleName); - if (example) { - this.model.selectedExample = example; - } - } else { - let p: IPlaygroundProject | undefined = undefined; - if (this.cachedState?.hash === hashValue) { - p = this.cachedState.state; - } - if (!p) { - try { - p = - this.compressor.decodeData( - hashValue - ); - } catch (e) { - console.log("Could not deserialize from hash value", e); - } - } - if (p) { - this.cachedState = { state: p, hash: hashValue }; - this.model.setState(p); - } - } - } - - private readonly historyController = this.dispose.track( - new HistoryController((initialLocation) => { - this.updateLocation(initialLocation); - return this; - }) - ); - - constructor(private readonly model: PlaygroundModel) {} -} - -class BisectModel { - private readonly map = new ObservableMap(); - - constructor(private readonly model: PlaygroundModel) {} - - public getState(version: string): boolean | undefined { - return this.map.get(version); - } - - public get isActive() { - return [...this.map.values()].some((e) => e !== undefined); - } - - public reset(): void { - this.map.clear(); - } - - public async toggleState(version: string, state: boolean): Promise { - const currentState = this.getState(version); - await this.setState( - version, - currentState === state ? undefined : state - ); - } - - @action - public async setState( - version: string, - state: boolean | undefined - ): Promise { - if (state === undefined) { - this.map.delete(version); - } else { - this.map.set(version, state); - } - - const nextVersion = await this.getNextVersion(); - if (!nextVersion) { - return; - } - this.model.settings.setSettings({ - ...this.model.settings.settings, - npmVersion: nextVersion, - }); - } - - private get versions() { - return getNpmVersionsSync(undefined); - } - - private get indexOfLastBadVersion() { - return findLastIndex(this.versions, (v) => this.map.get(v) === false); - } - private get indexOfFirstGoodVersion() { - return this.versions.findIndex((v) => this.map.get(v) === true); - } - - public get steps() { - const indexOfFirstGoodVersion = this.indexOfFirstGoodVersion; - const indexOfLastBadVersion = this.indexOfLastBadVersion; - - if (indexOfFirstGoodVersion === -1 && indexOfLastBadVersion === -1) { - return -1; - } - if (indexOfFirstGoodVersion === -1) { - return Math.ceil( - Math.log2(this.versions.length - indexOfLastBadVersion) - ); - } else if (indexOfLastBadVersion === -1) { - return Math.ceil(Math.log2(indexOfFirstGoodVersion + 1)); - } else { - return Math.ceil( - Math.log2(indexOfFirstGoodVersion - indexOfLastBadVersion) - ); - } - } - - public get isFinished() { - if ( - this.indexOfFirstGoodVersion !== -1 && - this.indexOfLastBadVersion + 1 === this.indexOfFirstGoodVersion - ) { - return true; - } - return false; - } - - public async openGithub() { - const versions = await getNpmVersions(); - const indexOfFirstGoodVersion = - this.indexOfFirstGoodVersion === -1 - ? versions.length - 1 - : this.indexOfFirstGoodVersion; - const indexOfLastBadVersion = - this.indexOfLastBadVersion === -1 ? 0 : this.indexOfLastBadVersion; - const goodCommitId = await getVsCodeCommitId( - versions[indexOfFirstGoodVersion] - ); - const badCommitId = await getVsCodeCommitId( - versions[indexOfLastBadVersion] - ); - window.open( - `https://github.com/microsoft/vscode/compare/${goodCommitId}...${badCommitId}`, - "_blank" - ); - } - - private async getNextVersion(): Promise { - const versions = await getNpmVersions(); - - const indexOfFirstGoodVersion = this.indexOfFirstGoodVersion; - const indexOfLastBadVersion = this.indexOfLastBadVersion; - - if ( - indexOfFirstGoodVersion !== -1 && - indexOfLastBadVersion + 1 === indexOfFirstGoodVersion - ) { - // Finished - return; - } - - if (indexOfLastBadVersion === -1 && indexOfFirstGoodVersion === -1) { - return versions[0]; - } - if (indexOfLastBadVersion === -1) { - // try first (newest) version that hasn't been tested - const indexOfFirstUntestedVersion = versions.findIndex( - (v) => this.map.get(v) === undefined - ); - if (indexOfFirstUntestedVersion === -1) { - return undefined; - } - return versions[indexOfFirstUntestedVersion]; - } - - if (indexOfFirstGoodVersion === -1) { - /*// exponential back off, might be good for recent regressions, but ruins step counter - const candidate = Math.min( - indexOfLastBadVersion * 2 + 1, - versions.length - 1 - );*/ - const candidate = Math.floor( - (indexOfLastBadVersion + versions.length) / 2 - ); - return versions[candidate]; - } - - return versions[ - Math.floor((indexOfLastBadVersion + indexOfFirstGoodVersion) / 2) - ]; - } -} - -function findLastIndex( - array: T[], - predicate: (value: T) => boolean -): number { - for (let i = array.length - 1; i >= 0; i--) { - if (predicate(array[i])) { - return i; - } - } - return -1; -} - -class Source { - public static parse( - sourceStr: string | undefined, - sourceLanguagesStr: string | undefined - ): Source { - if (sourceStr && sourceStr.startsWith("v")) { - return new Source( - sourceStr.substring(1), - undefined, - sourceLanguagesStr - ); - } - return new Source(undefined, sourceStr, sourceLanguagesStr); - } - - public equals(other: Source | undefined): boolean { - if (!other) { - return false; - } - return other.toString() === this.toString(); - } - - constructor( - public readonly version: string | undefined, - public readonly url: string | undefined, - public readonly sourceLanguagesStr: string | undefined - ) { - if ( - version === undefined && - url === undefined && - sourceLanguagesStr === undefined - ) { - throw new Error("one parameter must be defined"); - } - } - - sourceToString(): string | undefined { - if (this.url) { - return this.url; - } - if (this.version) { - return `v${this.version}`; - } - return undefined; - } - - sourceLanguagesToString(): string | undefined { - return this.sourceLanguagesStr; - } - - toString() { - return `${this.sourceToString()};${this.sourceLanguagesToString()}`; - } - - public toPartialSettings(): Partial { - const languagesSettings: Partial = { - languagesSource: - this.sourceLanguagesStr === undefined ? "latest" : "url", - languagesUrl: this.sourceLanguagesStr, - }; - - if (this.version) { - return { - monacoSource: "npm", - npmVersion: this.version, - }; - } else if (this.url) { - return { - monacoSource: "independent", - coreSource: "url", - coreUrl: this.url, - ...languagesSettings, - }; - } else { - return { - monacoSource: "independent", - coreSource: "latest", - ...languagesSettings, - }; - } - } -} diff --git a/website/src/website/pages/playground/PlaygroundPage.tsx b/website/src/website/pages/playground/PlaygroundPage.tsx index 49a06f82..fccfa6f1 100644 --- a/website/src/website/pages/playground/PlaygroundPage.tsx +++ b/website/src/website/pages/playground/PlaygroundPage.tsx @@ -3,7 +3,19 @@ import * as React from "react"; import { hotComponent } from "../../utils/hotComponent"; import { PlaygroundModel } from "./PlaygroundModel"; import { PlaygroundPageContent } from "./PlaygroundPageContent"; +import { withLoader } from "../../components/Loader"; +import { getNpmVersions } from "./getNpmVersionsSync"; +@withLoader(async () => { + const search = new URLSearchParams(window.location.search); + if ( + search.get("source") === "latest-dev" || + search.get("compareWith") === "latest-dev" + ) { + // So that the source class can resolve that value + await getNpmVersions(); + } +}) @hotComponent(module) @observer export class PlaygroundPage extends React.Component { diff --git a/website/src/website/pages/playground/PlaygroundPageContent.tsx b/website/src/website/pages/playground/PlaygroundPageContent.tsx index e93c0d4a..4681b0fb 100644 --- a/website/src/website/pages/playground/PlaygroundPageContent.tsx +++ b/website/src/website/pages/playground/PlaygroundPageContent.tsx @@ -1,24 +1,25 @@ import { autorun } from "mobx"; import { observer } from "mobx-react"; import * as React from "react"; +import { ButtonGroup, FormCheck } from "react-bootstrap"; import { getLoadedMonaco } from "../../../monaco-loader"; -import { IPlaygroundProject, IPreviewState } from "../../../shared"; import { Page } from "../../components/Page"; import { Select } from "../../components/Select"; +import { Button, Col, Row, Stack } from "../../components/bootstrap"; import { MonacoEditor, MonacoEditorHeight, } from "../../components/monaco/MonacoEditor"; import { withLoadedMonaco } from "../../components/monaco/MonacoLoader"; +import { monacoEditorVersion } from "../../monacoEditorVersion"; import { hotComponent } from "../../utils/hotComponent"; import { IReference, ref } from "../../utils/ref"; -import { getNpmVersionsSync } from "./getNpmVersionsSync"; -import { getPlaygroundExamples, PlaygroundExample } from "./playgroundExamples"; import { PlaygroundModel } from "./PlaygroundModel"; import { Preview } from "./Preview"; import { SettingsDialog } from "./SettingsDialog"; -import { Button, Col, Row, Stack } from "../../components/bootstrap"; -import { ButtonGroup, FormCheck } from "react-bootstrap"; +import { getNpmVersionsSync } from "./getNpmVersionsSync"; +import { PlaygroundExample, getPlaygroundExamples } from "./playgroundExamples"; +import { getDefaultSettings, toLoaderConfig } from "./SettingsModel"; @hotComponent(module) @observer @@ -41,7 +42,7 @@ export class PlaygroundPageContent extends React.Component< )} - + - {model.settings.previewFullScreen || ( + {model.previewShouldBeFullScreen || ( - (model.settings.autoReload = - e.target.checked) - } + onChange={(e) => { + model.settings.autoReload = + e.target.checked; + if ( + e.target.checked && + model.isDirty + ) { + model.reload(); + } + }} /> )} + + + + ) : ( + <> + + + - - ) : ( - <> - - - + + + } + > + + + + )} @@ -252,13 +329,15 @@ export class VersionSelector extends React.Component<{