From cc813f01fa1c881d603d3bf3a3eab790e4c884b0 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Sat, 30 Aug 2025 02:02:23 +0300 Subject: [PATCH 01/71] feat(Compilers): add basic support for ripple --- src/livecodes/languages/languages.ts | 2 ++ src/livecodes/languages/ripple/index.ts | 1 + src/livecodes/languages/ripple/lang-ripple.ts | 31 +++++++++++++++++++ .../languages/ripple/ripple-runtime.ts | 9 ++++++ src/livecodes/result/result-page.ts | 6 ++-- src/livecodes/vendors.ts | 2 ++ src/sdk/models.ts | 1 + 7 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 src/livecodes/languages/ripple/index.ts create mode 100644 src/livecodes/languages/ripple/lang-ripple.ts create mode 100644 src/livecodes/languages/ripple/ripple-runtime.ts diff --git a/src/livecodes/languages/languages.ts b/src/livecodes/languages/languages.ts index 9f318652af..1adcb54bad 100644 --- a/src/livecodes/languages/languages.ts +++ b/src/livecodes/languages/languages.ts @@ -59,6 +59,7 @@ import { reason } from './reason'; import { rescript } from './rescript'; import { richtext } from './richtext'; import { riot } from './riot'; +import { ripple } from './ripple'; import { ruby } from './ruby'; import { rubyWasm } from './ruby-wasm'; import { scheme } from './scheme'; @@ -128,6 +129,7 @@ export const languages: LanguageSpecs[] = [ solidTsx, riot, malina, + ripple, coffeescript, livescript, civet, diff --git a/src/livecodes/languages/ripple/index.ts b/src/livecodes/languages/ripple/index.ts new file mode 100644 index 0000000000..ace98a13ca --- /dev/null +++ b/src/livecodes/languages/ripple/index.ts @@ -0,0 +1 @@ +export * from './lang-ripple'; diff --git a/src/livecodes/languages/ripple/lang-ripple.ts b/src/livecodes/languages/ripple/lang-ripple.ts new file mode 100644 index 0000000000..3f30bb9b43 --- /dev/null +++ b/src/livecodes/languages/ripple/lang-ripple.ts @@ -0,0 +1,31 @@ +import type { LanguageSpecs } from '../../models'; +import { rippleUrl } from '../../vendors'; +import { parserPlugins } from '../prettier'; + +export const ripple: LanguageSpecs = { + name: 'ripple', + title: 'Ripple', + info: false, + parser: { + name: 'babel-ts', + pluginUrls: [parserPlugins.babel, parserPlugins.html], + }, + compiler: { + factory: async () => { + // TODO: convert to UMD + const { compile } = await import(rippleUrl); + return async (code) => { + if (!code.trim()) return ''; + const { js, css } = await compile(code, './src/App.ripple'); + const cssCode = + css === '' + ? '' + : `\n\nconst styles = document.createElement('style');\nstyles.innerHTML = ${JSON.stringify(css)};\ndocument.head.appendChild(styles);\n`; + return `${js.code}${cssCode}`; + }; + }, + }, + extensions: ['ripple'], + editor: 'script', + editorLanguage: 'typescript', +}; diff --git a/src/livecodes/languages/ripple/ripple-runtime.ts b/src/livecodes/languages/ripple/ripple-runtime.ts new file mode 100644 index 0000000000..d7d8d898b6 --- /dev/null +++ b/src/livecodes/languages/ripple/ripple-runtime.ts @@ -0,0 +1,9 @@ +export const rippleRuntime = ` +import { mount } from 'ripple'; +import { App } from "./script"; +(() => { + mount(App, { + target: document.querySelector("#livecodes-app") || document.body.appendChild(document.createElement('div')), + }); +})(); +`; diff --git a/src/livecodes/result/result-page.ts b/src/livecodes/result/result-page.ts index 1610161a45..c5c6f189d4 100644 --- a/src/livecodes/result/result-page.ts +++ b/src/livecodes/result/result-page.ts @@ -11,6 +11,7 @@ import { import { cssPresets, getLanguageCompiler, getLanguageExtension } from '../languages'; import { reactRuntime } from '../languages/jsx/react-runtime'; import { reactNativeRuntime } from '../languages/react-native/react-native-runtime'; +import { rippleRuntime } from '../languages/ripple/ripple-runtime'; import { solidRuntime } from '../languages/solid/solid-runtime'; import { hasCustomJsxRuntime } from '../languages/typescript'; import type { Cache, CompileInfo, Config, EditorId, Language } from '../models'; @@ -210,6 +211,7 @@ export const createResultPage = async ({ 'react-native-tsx': reactNativeRuntime, solid: solidRuntime, 'solid.tsx': solidRuntime, + ripple: rippleRuntime, }; const jsxRuntime = jsxRuntimes[code.script.language] || ''; const reactImport = @@ -219,7 +221,7 @@ export const createResultPage = async ({ const shouldInsertJsxRuntime = Object.keys(jsxRuntimes).includes(code.script.language) && !config.customSettings[code.script.language]?.disableAutoRender && - hasDefaultExport(code.script.compiled) && + (hasDefaultExport(code.script.compiled) || code.script.language === 'ripple') && // FIXME: ripple default export !hasCustomJsxRuntime(code.script.content || '', config) && !importFromScript; const hasPreact = getImports(code.script.compiled).find((mod) => mod === 'preact'); @@ -439,7 +441,7 @@ export const createResultPage = async ({ } } - // React JSX runtime + // JSX runtime if (shouldInsertJsxRuntime) { const jsxRuntimeScript = dom.createElement('script'); jsxRuntimeScript.type = 'module'; diff --git a/src/livecodes/vendors.ts b/src/livecodes/vendors.ts index 3ee6afdcfc..570e046b59 100644 --- a/src/livecodes/vendors.ts +++ b/src/livecodes/vendors.ts @@ -389,6 +389,8 @@ export const resetCssUrl = /* @__PURE__ */ getUrl('reset-css@5.0.1/reset.css'); export const riotBaseUrl = /* @__PURE__ */ getUrl('riot@9.2.2/'); +export const rippleUrl = /* @__PURE__ */ getModuleUrl('ripple@0.2.3/compiler'); + export const rubyWasmBaseUrl = /* @__PURE__ */ getUrl('@ruby/3.3-wasm-wasi@2.6.2/dist/'); export const rubyWasmScriptUrl = /* @__PURE__ */ getUrl( diff --git a/src/sdk/models.ts b/src/sdk/models.ts index e6bd21a015..16bf986a7a 100644 --- a/src/sdk/models.ts +++ b/src/sdk/models.ts @@ -968,6 +968,7 @@ export type Language = | 'riotjs' | 'malina' | 'malinajs' + | 'ripple' | 'xht' | 'coffeescript' | 'coffee' From bb8c04f9fbc22b90ba6ff2200192bcb6b39d3dd6 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Sun, 31 Aug 2025 02:47:04 +0300 Subject: [PATCH 02/71] upgrade ripple, use default export --- src/livecodes/languages/ripple/ripple-runtime.ts | 2 +- src/livecodes/result/result-page.ts | 2 +- src/livecodes/vendors.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/livecodes/languages/ripple/ripple-runtime.ts b/src/livecodes/languages/ripple/ripple-runtime.ts index d7d8d898b6..80653677e6 100644 --- a/src/livecodes/languages/ripple/ripple-runtime.ts +++ b/src/livecodes/languages/ripple/ripple-runtime.ts @@ -1,6 +1,6 @@ export const rippleRuntime = ` import { mount } from 'ripple'; -import { App } from "./script"; +import App from "./script"; (() => { mount(App, { target: document.querySelector("#livecodes-app") || document.body.appendChild(document.createElement('div')), diff --git a/src/livecodes/result/result-page.ts b/src/livecodes/result/result-page.ts index c5c6f189d4..9a13c0f140 100644 --- a/src/livecodes/result/result-page.ts +++ b/src/livecodes/result/result-page.ts @@ -221,7 +221,7 @@ export const createResultPage = async ({ const shouldInsertJsxRuntime = Object.keys(jsxRuntimes).includes(code.script.language) && !config.customSettings[code.script.language]?.disableAutoRender && - (hasDefaultExport(code.script.compiled) || code.script.language === 'ripple') && // FIXME: ripple default export + hasDefaultExport(code.script.compiled) && !hasCustomJsxRuntime(code.script.content || '', config) && !importFromScript; const hasPreact = getImports(code.script.compiled).find((mod) => mod === 'preact'); diff --git a/src/livecodes/vendors.ts b/src/livecodes/vendors.ts index 570e046b59..b0207c7aee 100644 --- a/src/livecodes/vendors.ts +++ b/src/livecodes/vendors.ts @@ -389,7 +389,7 @@ export const resetCssUrl = /* @__PURE__ */ getUrl('reset-css@5.0.1/reset.css'); export const riotBaseUrl = /* @__PURE__ */ getUrl('riot@9.2.2/'); -export const rippleUrl = /* @__PURE__ */ getModuleUrl('ripple@0.2.3/compiler'); +export const rippleUrl = /* @__PURE__ */ getModuleUrl('ripple@0.2.5/compiler'); export const rubyWasmBaseUrl = /* @__PURE__ */ getUrl('@ruby/3.3-wasm-wasi@2.6.2/dist/'); From f0c18a7bce84392e8e92a85664ae0647d5d47932 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Sun, 31 Aug 2025 22:01:23 +0300 Subject: [PATCH 03/71] add syntax highlighting for ripple in monaco --- scripts/build.js | 1 + .../monaco/languages/monaco-lang-ripple.ts | 6856 +++++++++++++++++ src/livecodes/editor/monaco/monaco.ts | 50 + src/livecodes/languages/ripple/lang-ripple.ts | 1 - src/livecodes/vendors.ts | 10 +- 5 files changed, 6916 insertions(+), 2 deletions(-) create mode 100644 src/livecodes/editor/monaco/languages/monaco-lang-ripple.ts diff --git a/scripts/build.js b/scripts/build.js index 13058760d2..2b9d0550a5 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -160,6 +160,7 @@ const esmBuild = () => 'editor/monaco/languages/monaco-lang-astro.ts', 'editor/monaco/languages/monaco-lang-clio.ts', 'editor/monaco/languages/monaco-lang-imba.ts', + 'editor/monaco/languages/monaco-lang-ripple.ts', // 'editor/monaco/languages/monaco-lang-sql.ts', 'editor/monaco/languages/monaco-lang-wat.ts', 'editor/codemirror/codemirror.ts', diff --git a/src/livecodes/editor/monaco/languages/monaco-lang-ripple.ts b/src/livecodes/editor/monaco/languages/monaco-lang-ripple.ts new file mode 100644 index 0000000000..392d2620d0 --- /dev/null +++ b/src/livecodes/editor/monaco/languages/monaco-lang-ripple.ts @@ -0,0 +1,6856 @@ +// from https://github.com/trueadm/ripple/blob/main/packages/ripple-vscode-plugin/syntaxes/ripple.tmLanguage.json +// and https://github.com/trueadm/ripple/blob/main/packages/ripple-vscode-plugin/language-configuration.json +export default { + syntax: { + information_for_contributors: [ + 'This file has been converted from https://github.com/microsoft/TypeScript-TmLanguage/blob/master/TypeScriptReact.tmLanguage', + 'If you want to provide a fix or improvement, please create a pull request against the original repository.', + 'Once accepted there, we are happy to receive an update request.', + ], + version: + 'https://github.com/microsoft/TypeScript-TmLanguage/commit/48f608692aa6d6ad7bd65b478187906c798234a8', + name: 'Ripple', + scopeName: 'source.ripple', + patterns: [ + { + include: '#directives', + }, + { + include: '#statements', + }, + { + include: '#shebang', + }, + ], + repository: { + shebang: { + name: 'comment.line.shebang.js', + match: '\\A(#!).*(?=$)', + captures: { + '1': { + name: 'punctuation.definition.comment.js', + }, + }, + }, + statements: { + patterns: [ + { + include: '#declaration', + }, + { + include: '#control-statement', + }, + { + include: '#after-operator-block-as-object-literal', + }, + { + include: '#decl-block', + }, + { + include: '#label', + }, + { + include: '#expression', + }, + { + include: '#punctuation-semicolon', + }, + { + include: '#string', + }, + { + include: '#comment', + }, + ], + }, + 'component-statements': { + patterns: [ + { + include: '#jsx', + }, + { + include: '#declaration', + }, + { + include: '#component-control-statement', + }, + { + include: '#component-decl-block', + }, + { + include: '#label', + }, + { + include: '#expression', + }, + { + include: '#punctuation-semicolon', + }, + { + include: '#string', + }, + { + include: '#comment', + }, + ], + }, + declaration: { + patterns: [ + { + include: '#decorator', + }, + { + include: '#var-expr', + }, + { + include: '#component-declaration', + }, + { + include: '#fragment-declaration', + }, + { + include: '#function-declaration', + }, + { + include: '#class-declaration', + }, + { + include: '#interface-declaration', + }, + { + include: '#enum-declaration', + }, + { + include: '#namespace-declaration', + }, + { + include: '#type-alias-declaration', + }, + { + include: '#import-equals-declaration', + }, + { + include: '#import-declaration', + }, + { + include: '#export-declaration', + }, + { + name: 'storage.modifier.js', + match: + '(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\\'\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(?\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\\'\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))', + beginCaptures: { + '1': { + name: 'meta.definition.variable.js entity.name.function.js', + }, + '2': { + name: 'keyword.operator.definiteassignment.js', + }, + }, + end: '(?=$|^|[;,=}]|((?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\\'\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(?\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\\'\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))', + beginCaptures: { + '1': { + name: 'meta.definition.variable.js variable.other.constant.js entity.name.function.js', + }, + }, + end: '(?=$|^|[;,=}]|((?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\\'\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(?\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\\'\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))', + captures: { + '1': { + name: 'storage.modifier.js', + }, + '2': { + name: 'keyword.operator.rest.js', + }, + '3': { + name: 'entity.name.function.js variable.language.this.js', + }, + '4': { + name: 'entity.name.function.js', + }, + '5': { + name: 'keyword.operator.optional.js', + }, + }, + }, + { + match: + '(?x)(?:(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\\'\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(?\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\\'\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))', + captures: { + '1': { + name: 'meta.definition.property.js entity.name.function.js', + }, + '2': { + name: 'keyword.operator.optional.js', + }, + '3': { + name: 'keyword.operator.definiteassignment.js', + }, + }, + }, + { + name: 'meta.definition.property.js variable.object.property.js', + match: '\\#?[_$[:alpha:]][_$[:alnum:]]*', + }, + { + name: 'keyword.operator.optional.js', + match: '\\?', + }, + { + name: 'keyword.operator.definiteassignment.js', + match: '\\!', + }, + ], + }, + 'variable-initializer': { + patterns: [ + { + begin: '(?\\s*$)', + beginCaptures: { + '1': { + name: 'keyword.operator.assignment.js', + }, + }, + end: '(?=$|^|[,);}\\]]|((?]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])', + beginCaptures: { + '1': { + name: 'storage.modifier.js', + }, + '2': { + name: 'storage.modifier.js', + }, + '3': { + name: 'storage.modifier.js', + }, + '4': { + name: 'storage.modifier.async.js', + }, + '5': { + name: 'keyword.operator.new.js', + }, + '6': { + name: 'keyword.generator.asterisk.js', + }, + }, + end: '(?=\\}|;|,|$)|(?<=\\})', + patterns: [ + { + include: '#method-declaration-name', + }, + { + include: '#function-body', + }, + ], + }, + { + name: 'meta.method.declaration.js', + begin: + '(?x)(?]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])', + beginCaptures: { + '1': { + name: 'storage.modifier.js', + }, + '2': { + name: 'storage.modifier.js', + }, + '3': { + name: 'storage.modifier.js', + }, + '4': { + name: 'storage.modifier.async.js', + }, + '5': { + name: 'storage.type.property.js', + }, + '6': { + name: 'keyword.generator.asterisk.js', + }, + }, + end: '(?=\\}|;|,|$)|(?<=\\})', + patterns: [ + { + include: '#method-declaration-name', + }, + { + include: '#function-body', + }, + ], + }, + ], + }, + 'object-literal-method-declaration': { + name: 'meta.method.declaration.js', + begin: + '(?x)(?]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])', + beginCaptures: { + '1': { + name: 'storage.modifier.async.js', + }, + '2': { + name: 'storage.type.property.js', + }, + '3': { + name: 'keyword.generator.asterisk.js', + }, + }, + end: '(?=\\}|;|,)|(?<=\\})', + patterns: [ + { + include: '#method-declaration-name', + }, + { + include: '#function-body', + }, + { + begin: + '(?x)(?]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])', + beginCaptures: { + '1': { + name: 'storage.modifier.async.js', + }, + '2': { + name: 'storage.type.property.js', + }, + '3': { + name: 'keyword.generator.asterisk.js', + }, + }, + end: '(?=\\(|\\<)', + patterns: [ + { + include: '#method-declaration-name', + }, + ], + }, + ], + }, + 'method-declaration-name': { + begin: + '(?x)(?=((\\b(?)', + captures: { + '1': { + name: 'storage.modifier.async.js', + }, + '2': { + name: 'variable.parameter.js', + }, + }, + }, + { + name: 'meta.arrow.js', + begin: + '(?x) (?:\n (? is on new line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\\'\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n )\n)', + beginCaptures: { + '1': { + name: 'storage.modifier.async.js', + }, + }, + end: '(?==>|\\{|(^\\s*(export|function|class|interface|let|var|(?:\\busing(?=\\s+(?!in\\b|of\\b(?!\\s*(?:of\\b|=)))[_$[:alpha:]])\\b)|(?:\\bawait\\s+(?:\\busing(?=\\s+(?!in\\b|of\\b(?!\\s*(?:of\\b|=)))[_$[:alpha:]])\\b)\\b)|const|import|enum|namespace|module|type|abstract|declare)\\s+))', + patterns: [ + { + include: '#comment', + }, + { + include: '#type-parameters', + }, + { + include: '#function-parameters', + }, + { + include: '#arrow-return-type', + }, + { + include: '#possibly-arrow-return-type', + }, + ], + }, + { + name: 'meta.arrow.js', + begin: '=>', + beginCaptures: { + '0': { + name: 'storage.type.function.arrow.js', + }, + }, + end: '((?<=\\}|\\S)(?)|((?!\\{)(?=\\S)))(?!\\/[\\/\\*])', + patterns: [ + { + include: '#single-line-comment-consuming-line-ending', + }, + { + include: '#decl-block', + }, + { + include: '#expression', + }, + ], + }, + ], + }, + 'indexer-declaration': { + name: 'meta.indexer.declaration.js', + begin: + '(?:(?]|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^yield|[^\\._$[:alnum:]]yield|^throw|[^\\._$[:alnum:]]throw|^in|[^\\._$[:alnum:]]in|^of|[^\\._$[:alnum:]]of|^typeof|[^\\._$[:alnum:]]typeof|&&|\\|\\||\\*)\\s*(\\{)', + beginCaptures: { + '1': { + name: 'punctuation.definition.block.js', + }, + }, + end: '\\}', + endCaptures: { + '0': { + name: 'punctuation.definition.block.js', + }, + }, + patterns: [ + { + include: '#object-member', + }, + ], + }, + 'object-literal': { + name: 'meta.objectliteral.js', + begin: '\\{', + beginCaptures: { + '0': { + name: 'punctuation.definition.block.js', + }, + }, + end: '\\}', + endCaptures: { + '0': { + name: 'punctuation.definition.block.js', + }, + }, + patterns: [ + { + include: '#object-member', + }, + ], + }, + 'object-member': { + patterns: [ + { + include: '#comment', + }, + { + include: '#object-literal-method-declaration', + }, + { + name: 'meta.object.member.js meta.object-literal.key.js', + begin: '(?=\\[)', + end: '(?=:)|((?<=[\\]])(?=\\s*[\\(\\<]))', + patterns: [ + { + include: '#comment', + }, + { + include: '#array-literal', + }, + ], + }, + { + name: 'meta.object.member.js meta.object-literal.key.js', + begin: '(?=[\\\'\\"\\`])', + end: '(?=:)|((?<=[\\\'\\"\\`])(?=((\\s*[\\(\\<,}])|(\\s+(as|satisifies)\\s+))))', + patterns: [ + { + include: '#comment', + }, + { + include: '#string', + }, + ], + }, + { + name: 'meta.object.member.js meta.object-literal.key.js', + begin: + '(?x)(?=(\\b(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\\'\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))', + captures: { + '0': { + name: 'meta.object-literal.key.js', + }, + '1': { + name: 'entity.name.function.js', + }, + }, + }, + { + name: 'meta.object.member.js', + match: + '(?:[_$[:alpha:]][_$[:alnum:]]*)\\s*(?=(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*:)', + captures: { + '0': { + name: 'meta.object-literal.key.js', + }, + }, + }, + { + name: 'meta.object.member.js', + begin: '\\.\\.\\.', + beginCaptures: { + '0': { + name: 'keyword.operator.spread.js', + }, + }, + end: '(?=,|\\})', + patterns: [ + { + include: '#expression', + }, + ], + }, + { + name: 'meta.object.member.js', + match: '([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=,|\\}|$|\\/\\/|\\/\\*)', + captures: { + '1': { + name: 'variable.other.readwrite.js', + }, + }, + }, + { + name: 'meta.object.member.js', + match: '(?]|\\|\\||\\&\\&|\\!\\=\\=|$|^|((?]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)\\(\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))', + beginCaptures: { + '1': { + name: 'storage.modifier.async.js', + }, + }, + end: '(?<=\\))', + patterns: [ + { + include: '#type-parameters', + }, + { + begin: '\\(', + beginCaptures: { + '0': { + name: 'meta.brace.round.js', + }, + }, + end: '\\)', + endCaptures: { + '0': { + name: 'meta.brace.round.js', + }, + }, + patterns: [ + { + include: '#expression-inside-possibly-arrow-parens', + }, + ], + }, + ], + }, + { + begin: + '(?<=:)\\s*(async)?\\s*(\\()(?=\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))', + beginCaptures: { + '1': { + name: 'storage.modifier.async.js', + }, + '2': { + name: 'meta.brace.round.js', + }, + }, + end: '\\)', + endCaptures: { + '0': { + name: 'meta.brace.round.js', + }, + }, + patterns: [ + { + include: '#expression-inside-possibly-arrow-parens', + }, + ], + }, + { + begin: '(?<=:)\\s*(async)?\\s*(?=\\<\\s*$)', + beginCaptures: { + '1': { + name: 'storage.modifier.async.js', + }, + }, + end: '(?<=\\>)', + patterns: [ + { + include: '#type-parameters', + }, + ], + }, + { + begin: + '(?<=\\>)\\s*(\\()(?=\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))', + beginCaptures: { + '1': { + name: 'meta.brace.round.js', + }, + }, + end: '\\)', + endCaptures: { + '0': { + name: 'meta.brace.round.js', + }, + }, + patterns: [ + { + include: '#expression-inside-possibly-arrow-parens', + }, + ], + }, + { + include: '#possibly-arrow-return-type', + }, + { + include: '#expression', + }, + ], + }, + { + include: '#punctuation-comma', + }, + { + include: '#decl-block', + }, + ], + }, + 'ternary-expression': { + begin: '(?!\\?\\.\\s*[^[:digit:]])(\\?)(?!\\?)', + beginCaptures: { + '1': { + name: 'keyword.operator.ternary.js', + }, + }, + end: '\\s*(:)', + endCaptures: { + '1': { + name: 'keyword.operator.ternary.js', + }, + }, + patterns: [ + { + include: '#expression', + }, + ], + }, + 'function-call': { + patterns: [ + { + begin: + '(?=(((([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))|(?<=[\\)]))\\s*(?:(\\?\\.\\s*)|(\\!))?((<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\())', + end: '(?<=\\))(?!(((([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))|(?<=[\\)]))\\s*(?:(\\?\\.\\s*)|(\\!))?((<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\())', + patterns: [ + { + name: 'meta.function-call.js', + begin: + '(?=(([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))', + end: '(?=\\s*(?:(\\?\\.\\s*)|(\\!))?((<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\())', + patterns: [ + { + include: '#function-call-target', + }, + ], + }, + { + include: '#comment', + }, + { + include: '#function-call-optionals', + }, + { + include: '#type-arguments', + }, + { + include: '#paren-expression', + }, + ], + }, + { + begin: + '(?=(((([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))|(?<=[\\)]))(<\\s*[\\{\\[\\(]\\s*$))', + end: '(?<=\\>)(?!(((([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))|(?<=[\\)]))(<\\s*[\\{\\[\\(]\\s*$))', + patterns: [ + { + name: 'meta.function-call.js', + begin: + '(?=(([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))', + end: '(?=(<\\s*[\\{\\[\\(]\\s*$))', + patterns: [ + { + include: '#function-call-target', + }, + ], + }, + { + include: '#comment', + }, + { + include: '#function-call-optionals', + }, + { + include: '#type-arguments', + }, + ], + }, + ], + }, + 'function-call-target': { + patterns: [ + { + include: '#support-function-call-identifiers', + }, + { + name: 'entity.name.function.js', + match: '(\\#?[_$[:alpha:]][_$[:alnum:]]*)', + }, + ], + }, + 'function-call-optionals': { + patterns: [ + { + name: 'meta.function-call.js punctuation.accessor.optional.js', + match: '\\?\\.', + }, + { + name: 'meta.function-call.js keyword.operator.definiteassignment.js', + match: '\\!', + }, + ], + }, + 'support-function-call-identifiers': { + patterns: [ + { + include: '#literal', + }, + { + include: '#support-objects', + }, + { + include: '#object-identifiers', + }, + { + include: '#punctuation-accessor', + }, + { + name: 'keyword.operator.expression.import.js', + match: + '(?:(?]|\\|\\||\\&\\&|\\!\\=\\=|$|((?]|\\|\\||\\&\\&|\\!\\=\\=|$|(===|!==|==|!=)|(([\\&\\~\\^\\|]\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s+instanceof(?![_$[:alnum:]])(?:(?=\\.\\.\\.)|(?!\\.)))|((?]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\(\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))', + beginCaptures: { + '1': { + name: 'storage.modifier.async.js', + }, + }, + end: '(?<=\\))', + patterns: [ + { + include: '#paren-expression-possibly-arrow-with-typeparameters', + }, + ], + }, + { + begin: + '(?<=[(=,]|=>|^return|[^\\._$[:alnum:]]return)\\s*(async)?(?=\\s*((((<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\()|(<)|((<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)))\\s*$)', + beginCaptures: { + '1': { + name: 'storage.modifier.async.js', + }, + }, + end: '(?<=\\))', + patterns: [ + { + include: '#paren-expression-possibly-arrow-with-typeparameters', + }, + ], + }, + { + include: '#possibly-arrow-return-type', + }, + ], + }, + 'paren-expression-possibly-arrow-with-typeparameters': { + patterns: [ + { + include: '#type-parameters', + }, + { + begin: '\\(', + beginCaptures: { + '0': { + name: 'meta.brace.round.js', + }, + }, + end: '\\)', + endCaptures: { + '0': { + name: 'meta.brace.round.js', + }, + }, + patterns: [ + { + include: '#expression-inside-possibly-arrow-parens', + }, + ], + }, + ], + }, + 'expression-inside-possibly-arrow-parens': { + patterns: [ + { + include: '#expressionWithoutIdentifiers', + }, + { + include: '#comment', + }, + { + include: '#string', + }, + { + include: '#decorator', + }, + { + include: '#destructuring-parameter', + }, + { + match: + '(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\\'\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(?\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\\'\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))', + captures: { + '1': { + name: 'storage.modifier.js', + }, + '2': { + name: 'keyword.operator.rest.js', + }, + '3': { + name: 'entity.name.function.js variable.language.this.js', + }, + '4': { + name: 'entity.name.function.js', + }, + '5': { + name: 'keyword.operator.optional.js', + }, + }, + }, + { + match: + '(?x)(?:(?]|\\|\\||\\&\\&|\\!\\=\\=|$|((?>=|>>>=|\\|=', + }, + { + name: 'keyword.operator.bitwise.shift.js', + match: '<<|>>>|>>', + }, + { + name: 'keyword.operator.comparison.js', + match: '===|!==|==|!=', + }, + { + name: 'keyword.operator.relational.js operator.relational.ripple-force entity.name.operator.relational.ripple', + match: '<=|>=|<>|<|>', + }, + { + match: '(?<=[_$[:alnum:]])(\\!)\\s*(?:(/=)|(?:(/)(?![/*])))', + captures: { + '1': { + name: 'keyword.operator.logical.js', + }, + '2': { + name: 'keyword.operator.assignment.compound.js', + }, + '3': { + name: 'keyword.operator.arithmetic.js', + }, + }, + }, + { + name: 'keyword.operator.logical.js', + match: '\\!|&&|\\|\\||\\?\\?', + }, + { + name: 'keyword.operator.bitwise.js', + match: '\\&|~|\\^|\\|', + }, + { + name: 'keyword.operator.assignment.js', + match: '\\=', + }, + { + name: 'keyword.operator.decrement.js', + match: '--', + }, + { + name: 'keyword.operator.increment.js', + match: '\\+\\+', + }, + { + name: 'keyword.operator.arithmetic.js', + match: '%|\\*|/|-|\\+', + }, + { + begin: + '(?<=[_$[:alnum:])\\]])\\s*(?=(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)+(?:(/=)|(?:(/)(?![/*]))))', + end: '(?:(/=)|(?:(/)(?!\\*([^\\*]|(\\*[^\\/]))*\\*\\/)))', + endCaptures: { + '1': { + name: 'keyword.operator.assignment.compound.js', + }, + '2': { + name: 'keyword.operator.arithmetic.js', + }, + }, + patterns: [ + { + include: '#comment', + }, + ], + }, + { + match: '(?<=[_$[:alnum:])\\]])\\s*(?:(/=)|(?:(/)(?![/*])))', + captures: { + '1': { + name: 'keyword.operator.assignment.compound.js', + }, + '2': { + name: 'keyword.operator.arithmetic.js', + }, + }, + }, + ], + }, + 'typeof-operator': { + begin: + '(?:&|{\\?]|(extends\\s+)|$|;|^\\s*$|(?:^\\s*(?:abstract|async|(?:\\bawait\\s+(?:\\busing(?=\\s+(?!in\\b|of\\b(?!\\s*(?:of\\b|=)))[_$[:alpha:]])\\b)\\b)|break|case|catch|class|const|continue|declare|do|else|enum|export|finally|function|for|goto|if|import|interface|let|module|namespace|switch|return|throw|try|type|(?:\\busing(?=\\s+(?!in\\b|of\\b(?!\\s*(?:of\\b|=)))[_$[:alpha:]])\\b)|var|while)\\b))', + patterns: [ + { + include: '#type-arguments', + }, + { + include: '#expression', + }, + ], + }, + literal: { + patterns: [ + { + include: '#numeric-literal', + }, + { + include: '#boolean-literal', + }, + { + include: '#null-literal', + }, + { + include: '#undefined-literal', + }, + { + include: '#numericConstant-literal', + }, + { + include: '#array-literal', + }, + { + include: '#this-literal', + }, + { + include: '#super-literal', + }, + ], + }, + 'array-literal': { + name: 'meta.array.literal.js', + begin: '\\s*(\\[)', + beginCaptures: { + '1': { + name: 'meta.brace.square.js', + }, + }, + end: '\\]', + endCaptures: { + '0': { + name: 'meta.brace.square.js', + }, + }, + patterns: [ + { + include: '#expression', + }, + { + include: '#punctuation-comma', + }, + ], + }, + 'numeric-literal': { + patterns: [ + { + name: 'constant.numeric.hex.js', + match: '\\b(?]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\\())\n |\n (?:(EPSILON|MAX_SAFE_INTEGER|MAX_VALUE|MIN_SAFE_INTEGER|MIN_VALUE|NEGATIVE_INFINITY|POSITIVE_INFINITY)\\b(?!\\$)))', + captures: { + '1': { + name: 'punctuation.accessor.js', + }, + '2': { + name: 'punctuation.accessor.optional.js', + }, + '3': { + name: 'support.variable.property.js', + }, + '4': { + name: 'support.constant.js', + }, + }, + }, + { + match: + '(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\\'\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))', + captures: { + '1': { + name: 'punctuation.accessor.js', + }, + '2': { + name: 'punctuation.accessor.optional.js', + }, + '3': { + name: 'entity.name.function.js', + }, + }, + }, + { + match: + '(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))\\s*(\\#?[[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])', + captures: { + '1': { + name: 'punctuation.accessor.js', + }, + '2': { + name: 'punctuation.accessor.optional.js', + }, + '3': { + name: 'variable.other.constant.property.js', + }, + }, + }, + { + match: '(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*)', + captures: { + '1': { + name: 'punctuation.accessor.js', + }, + '2': { + name: 'punctuation.accessor.optional.js', + }, + '3': { + name: 'variable.other.property.js', + }, + }, + }, + { + name: 'variable.other.constant.js', + match: '([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])', + }, + { + name: 'variable.other.readwrite.js', + match: '[_$[:alpha:]][_$[:alnum:]]*', + }, + ], + }, + 'object-identifiers': { + patterns: [ + { + name: 'support.class.js', + match: '([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\\??\\.\\s*prototype\\b(?!\\$))', + }, + { + match: + '(?x)(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))\\s*(?:\n (\\#?[[:upper:]][_$[:digit:][:upper:]]*) |\n (\\#?[_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*)', + captures: { + '1': { + name: 'punctuation.accessor.js', + }, + '2': { + name: 'punctuation.accessor.optional.js', + }, + '3': { + name: 'variable.other.constant.object.property.js', + }, + '4': { + name: 'variable.other.object.property.js', + }, + }, + }, + { + match: + '(?x)(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*)', + captures: { + '1': { + name: 'variable.other.constant.object.js', + }, + '2': { + name: 'variable.other.object.js', + }, + }, + }, + ], + }, + 'type-annotation': { + patterns: [ + { + name: 'meta.type.annotation.js', + begin: '(:)(?=\\s*\\S)', + beginCaptures: { + '1': { + name: 'keyword.operator.type.annotation.js', + }, + }, + end: '(?])|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))', + patterns: [ + { + include: '#type', + }, + ], + }, + { + name: 'meta.type.annotation.js', + begin: '(:)', + beginCaptures: { + '1': { + name: 'keyword.operator.type.annotation.js', + }, + }, + end: '(?])|(?=^\\s*$)|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))', + patterns: [ + { + include: '#type', + }, + ], + }, + ], + }, + 'parameter-type-annotation': { + patterns: [ + { + name: 'meta.type.annotation.js', + begin: '(:)', + beginCaptures: { + '1': { + name: 'keyword.operator.type.annotation.js', + }, + }, + end: '(?=[,)])|(?==[^>])', + patterns: [ + { + include: '#type', + }, + ], + }, + ], + }, + 'return-type': { + patterns: [ + { + name: 'meta.return.type.js', + begin: '(?<=\\))\\s*(:)(?=\\s*\\S)', + beginCaptures: { + '1': { + name: 'keyword.operator.type.annotation.js', + }, + }, + end: '(?|\\{|(^\\s*(export|function|class|interface|let|var|(?:\\busing(?=\\s+(?!in\\b|of\\b(?!\\s*(?:of\\b|=)))[_$[:alpha:]])\\b)|(?:\\bawait\\s+(?:\\busing(?=\\s+(?!in\\b|of\\b(?!\\s*(?:of\\b|=)))[_$[:alpha:]])\\b)\\b)|const|import|enum|namespace|module|type|abstract|declare)\\s+))', + patterns: [ + { + include: '#arrow-return-type-body', + }, + ], + }, + 'possibly-arrow-return-type': { + begin: + '(?<=\\)|^)\\s*(:)(?=\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*=>)', + beginCaptures: { + '1': { + name: 'meta.arrow.js meta.return.type.arrow.js keyword.operator.type.annotation.js', + }, + }, + end: '(?==>|\\{|(^\\s*(export|function|class|interface|let|var|(?:\\busing(?=\\s+(?!in\\b|of\\b(?!\\s*(?:of\\b|=)))[_$[:alpha:]])\\b)|(?:\\bawait\\s+(?:\\busing(?=\\s+(?!in\\b|of\\b(?!\\s*(?:of\\b|=)))[_$[:alpha:]])\\b)\\b)|const|import|enum|namespace|module|type|abstract|declare)\\s+))', + contentName: 'meta.arrow.js meta.return.type.arrow.js', + patterns: [ + { + include: '#arrow-return-type-body', + }, + ], + }, + 'arrow-return-type-body': { + patterns: [ + { + begin: '(?<=[:])(?=\\s*\\{)', + end: '(?<=\\})', + patterns: [ + { + include: '#type-object', + }, + ], + }, + { + include: '#type-predicate-operator', + }, + { + include: '#type', + }, + ], + }, + 'type-parameters': { + name: 'meta.type.parameters.js', + begin: '(<)', + beginCaptures: { + '1': { + name: 'punctuation.definition.typeparameters.begin.js', + }, + }, + end: '(>)', + endCaptures: { + '1': { + name: 'punctuation.definition.typeparameters.end.js', + }, + }, + patterns: [ + { + include: '#comment', + }, + { + name: 'storage.modifier.js', + match: + '(?)', + }, + ], + }, + 'type-arguments': { + name: 'meta.type.parameters.js', + begin: '\\<', + beginCaptures: { + '0': { + name: 'punctuation.definition.typeparameters.begin.js', + }, + }, + end: '\\>', + endCaptures: { + '0': { + name: 'punctuation.definition.typeparameters.end.js', + }, + }, + patterns: [ + { + include: '#type-arguments-body', + }, + ], + }, + 'type-arguments-body': { + patterns: [ + { + match: + '(?)\n ))\n ))\n)) |\n(:\\s*(?\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))))', + captures: { + '1': { + name: 'storage.modifier.js', + }, + '2': { + name: 'keyword.operator.rest.js', + }, + '3': { + name: 'entity.name.function.js variable.language.this.js', + }, + '4': { + name: 'entity.name.function.js', + }, + '5': { + name: 'keyword.operator.optional.js', + }, + }, + }, + { + match: + '(?x)(?:(?)', + patterns: [ + { + include: '#comment', + }, + { + include: '#type-parameters', + }, + ], + }, + { + name: 'meta.type.constructor.js', + begin: + '(?)\n ))\n )\n )\n)', + end: '(?<=\\))', + patterns: [ + { + include: '#function-parameters', + }, + ], + }, + ], + }, + 'type-function-return-type': { + patterns: [ + { + name: 'meta.type.function.return.js', + begin: '(=>)(?=\\s*\\S)', + beginCaptures: { + '1': { + name: 'storage.type.function.arrow.js', + }, + }, + end: '(?)(?:\\?]|//|$)', + patterns: [ + { + include: '#type-function-return-type-core', + }, + ], + }, + { + name: 'meta.type.function.return.js', + begin: '=>', + beginCaptures: { + '0': { + name: 'storage.type.function.arrow.js', + }, + }, + end: '(?)(?]|//|^\\s*$)|((?<=\\S)(?=\\s*$)))', + patterns: [ + { + include: '#type-function-return-type-core', + }, + ], + }, + ], + }, + 'type-function-return-type-core': { + patterns: [ + { + include: '#comment', + }, + { + begin: '(?<==>)(?=\\s*\\{)', + end: '(?<=\\})', + patterns: [ + { + include: '#type-object', + }, + ], + }, + { + include: '#type-predicate-operator', + }, + { + include: '#type', + }, + ], + }, + 'type-operators': { + patterns: [ + { + include: '#typeof-operator', + }, + { + include: '#type-infer', + }, + { + begin: '([&|])(?=\\s*\\{)', + beginCaptures: { + '0': { + name: 'keyword.operator.type.js', + }, + }, + end: '(?<=\\})', + patterns: [ + { + include: '#type-object', + }, + ], + }, + { + begin: '[&|]', + beginCaptures: { + '0': { + name: 'keyword.operator.type.js', + }, + }, + end: '(?=\\S)', + }, + { + name: 'keyword.operator.expression.keyof.js', + match: + '(?)', + endCaptures: { + '1': { + name: 'meta.type.parameters.js punctuation.definition.typeparameters.end.js', + }, + }, + contentName: 'meta.type.parameters.js', + patterns: [ + { + include: '#type-arguments-body', + }, + ], + }, + { + begin: '([_$[:alpha:]][_$[:alnum:]]*)\\s*(<)', + beginCaptures: { + '1': { + name: 'entity.name.type.js', + }, + '2': { + name: 'meta.type.parameters.js punctuation.definition.typeparameters.begin.js', + }, + }, + end: '(>)', + endCaptures: { + '1': { + name: 'meta.type.parameters.js punctuation.definition.typeparameters.end.js', + }, + }, + contentName: 'meta.type.parameters.js', + patterns: [ + { + include: '#type-arguments-body', + }, + ], + }, + { + match: '([_$[:alpha:]][_$[:alnum:]]*)\\s*(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))', + captures: { + '1': { + name: 'entity.name.type.module.js', + }, + '2': { + name: 'punctuation.accessor.js', + }, + '3': { + name: 'punctuation.accessor.optional.js', + }, + }, + }, + { + name: 'entity.name.type.js', + match: '[_$[:alpha:]][_$[:alnum:]]*', + }, + ], + }, + 'punctuation-comma': { + name: 'punctuation.separator.comma.js', + match: ',', + }, + 'punctuation-semicolon': { + name: 'punctuation.terminator.statement.js', + match: ';', + }, + 'punctuation-accessor': { + match: '(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))', + captures: { + '1': { + name: 'punctuation.accessor.js', + }, + '2': { + name: 'punctuation.accessor.optional.js', + }, + }, + }, + string: { + patterns: [ + { + include: '#qstring-single', + }, + { + include: '#qstring-double', + }, + { + include: '#template', + }, + ], + }, + 'qstring-double': { + name: 'string.quoted.double.js', + begin: '"', + beginCaptures: { + '0': { + name: 'punctuation.definition.string.begin.js', + }, + }, + end: '(")|((?:[^\\\\\\n])$)', + endCaptures: { + '1': { + name: 'punctuation.definition.string.end.js', + }, + '2': { + name: 'invalid.illegal.newline.js', + }, + }, + patterns: [ + { + include: '#string-character-escape', + }, + ], + }, + 'qstring-single': { + name: 'string.quoted.single.js', + begin: "'", + beginCaptures: { + '0': { + name: 'punctuation.definition.string.begin.js', + }, + }, + end: "(\\')|((?:[^\\\\\\n])$)", + endCaptures: { + '1': { + name: 'punctuation.definition.string.end.js', + }, + '2': { + name: 'invalid.illegal.newline.js', + }, + }, + patterns: [ + { + include: '#string-character-escape', + }, + ], + }, + 'string-character-escape': { + name: 'constant.character.escape.js', + match: + '\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|u\\{[0-9A-Fa-f]+\\}|[0-2][0-7]{0,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.|$)', + }, + template: { + patterns: [ + { + include: '#template-call', + }, + { + contentName: 'string.template.js', + begin: '([_$[:alpha:]][_$[:alnum:]]*)?(`)', + beginCaptures: { + '1': { + name: 'entity.name.function.tagged-template.js', + }, + '2': { + name: 'string.template.js punctuation.definition.string.template.begin.js', + }, + }, + end: '`', + endCaptures: { + '0': { + name: 'string.template.js punctuation.definition.string.template.end.js', + }, + }, + patterns: [ + { + include: '#template-substitution-element', + }, + { + include: '#string-character-escape', + }, + ], + }, + ], + }, + 'template-call': { + patterns: [ + { + begin: + '(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)(<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?`)', + end: '(?=`)', + patterns: [ + { + begin: + '(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))', + end: '(?=(<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?`)', + patterns: [ + { + include: '#support-function-call-identifiers', + }, + { + name: 'entity.name.function.tagged-template.js', + match: '([_$[:alpha:]][_$[:alnum:]]*)', + }, + ], + }, + { + include: '#type-arguments', + }, + ], + }, + { + begin: + '([_$[:alpha:]][_$[:alnum:]]*)?\\s*(?=(<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)`)', + beginCaptures: { + '1': { + name: 'entity.name.function.tagged-template.js', + }, + }, + end: '(?=`)', + patterns: [ + { + include: '#type-arguments', + }, + ], + }, + ], + }, + 'template-substitution-element': { + name: 'meta.template.expression.js', + begin: '\\$\\{', + beginCaptures: { + '0': { + name: 'punctuation.definition.template-expression.begin.js', + }, + }, + end: '\\}', + endCaptures: { + '0': { + name: 'punctuation.definition.template-expression.end.js', + }, + }, + patterns: [ + { + include: '#expression', + }, + ], + contentName: 'meta.embedded.line.js', + }, + 'type-string': { + patterns: [ + { + include: '#qstring-single', + }, + { + include: '#qstring-double', + }, + { + include: '#template-type', + }, + ], + }, + 'template-type': { + patterns: [ + { + include: '#template-call', + }, + { + contentName: 'string.template.js', + begin: '([_$[:alpha:]][_$[:alnum:]]*)?(`)', + beginCaptures: { + '1': { + name: 'entity.name.function.tagged-template.js', + }, + '2': { + name: 'string.template.js punctuation.definition.string.template.begin.js', + }, + }, + end: '`', + endCaptures: { + '0': { + name: 'string.template.js punctuation.definition.string.template.end.js', + }, + }, + patterns: [ + { + include: '#template-type-substitution-element', + }, + { + include: '#string-character-escape', + }, + ], + }, + ], + }, + 'template-type-substitution-element': { + name: 'meta.template.expression.js', + begin: '\\$\\{', + beginCaptures: { + '0': { + name: 'punctuation.definition.template-expression.begin.js', + }, + }, + end: '\\}', + endCaptures: { + '0': { + name: 'punctuation.definition.template-expression.end.js', + }, + }, + patterns: [ + { + include: '#type', + }, + ], + contentName: 'meta.embedded.line.js', + }, + regex: { + patterns: [ + { + name: 'string.regexp.js', + begin: + '(?|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[\\()]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\]|\\(([^\\)\\\\]|\\\\.)+\\))+\\/([dgimsuvy]+|(?![\\/\\*])|(?=\\/\\*))(?!\\s*[a-zA-Z0-9_$]))', + beginCaptures: { + '1': { + name: 'punctuation.definition.string.begin.js', + }, + }, + end: '(/)([dgimsuvy]*)', + endCaptures: { + '1': { + name: 'punctuation.definition.string.end.js', + }, + '2': { + name: 'keyword.other.js', + }, + }, + patterns: [ + { + include: '#regexp', + }, + ], + }, + { + name: 'string.regexp.js', + begin: + '((?', + captures: { + '0': { + name: 'keyword.other.back-reference.regexp', + }, + '1': { + name: 'variable.other.regexp', + }, + }, + }, + { + name: 'keyword.operator.quantifier.regexp', + match: '[?+*]|\\{(\\d+,\\d+|\\d+,|,\\d+|\\d+)\\}\\??', + }, + { + name: 'keyword.operator.or.regexp', + match: '\\|', + }, + { + name: 'meta.group.assertion.regexp', + begin: '(\\()((\\?=)|(\\?!)|(\\?<=)|(\\?))?', + beginCaptures: { + '0': { + name: 'punctuation.definition.group.regexp', + }, + '1': { + name: 'punctuation.definition.group.no-capture.regexp', + }, + '2': { + name: 'variable.other.regexp', + }, + }, + end: '\\)', + endCaptures: { + '0': { + name: 'punctuation.definition.group.regexp', + }, + }, + patterns: [ + { + include: '#regexp', + }, + ], + }, + { + name: 'constant.other.character-class.set.regexp', + begin: '(\\[)(\\^)?', + beginCaptures: { + '1': { + name: 'punctuation.definition.character-class.regexp', + }, + '2': { + name: 'keyword.operator.negation.regexp', + }, + }, + end: '(\\])', + endCaptures: { + '1': { + name: 'punctuation.definition.character-class.regexp', + }, + }, + patterns: [ + { + name: 'constant.other.character-class.range.regexp', + match: + '(?:.|(\\\\(?:[0-7]{3}|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}))|(\\\\c[A-Z])|(\\\\.))\\-(?:[^\\]\\\\]|(\\\\(?:[0-7]{3}|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}))|(\\\\c[A-Z])|(\\\\.))', + captures: { + '1': { + name: 'constant.character.numeric.regexp', + }, + '2': { + name: 'constant.character.control.regexp', + }, + '3': { + name: 'constant.character.escape.backslash.regexp', + }, + '4': { + name: 'constant.character.numeric.regexp', + }, + '5': { + name: 'constant.character.control.regexp', + }, + '6': { + name: 'constant.character.escape.backslash.regexp', + }, + }, + }, + { + include: '#regex-character-class', + }, + ], + }, + { + include: '#regex-character-class', + }, + ], + }, + 'regex-character-class': { + patterns: [ + { + name: 'constant.other.character-class.regexp', + match: '\\\\[wWsSdDtrnvf]|\\.', + }, + { + name: 'constant.character.numeric.regexp', + match: '\\\\([0-7]{3}|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4})', + }, + { + name: 'constant.character.control.regexp', + match: '\\\\c[A-Z]', + }, + { + name: 'constant.character.escape.backslash.regexp', + match: '\\\\.', + }, + ], + }, + comment: { + patterns: [ + { + name: 'comment.block.documentation.js', + begin: '/\\*\\*(?!/)', + beginCaptures: { + '0': { + name: 'punctuation.definition.comment.js', + }, + }, + end: '\\*/', + endCaptures: { + '0': { + name: 'punctuation.definition.comment.js', + }, + }, + patterns: [ + { + include: '#docblock', + }, + ], + }, + { + name: 'comment.block.js', + begin: '(/\\*)(?:\\s*((@)internal)(?=\\s|(\\*/)))?', + beginCaptures: { + '1': { + name: 'punctuation.definition.comment.js', + }, + '2': { + name: 'storage.type.internaldeclaration.js', + }, + '3': { + name: 'punctuation.decorator.internaldeclaration.js', + }, + }, + end: '\\*/', + endCaptures: { + '0': { + name: 'punctuation.definition.comment.js', + }, + }, + }, + { + begin: '(^[ \\t]+)?((//)(?:\\s*((@)internal)(?=\\s|$))?)', + beginCaptures: { + '1': { + name: 'punctuation.whitespace.comment.leading.js', + }, + '2': { + name: 'comment.line.double-slash.js', + }, + '3': { + name: 'punctuation.definition.comment.js', + }, + '4': { + name: 'storage.type.internaldeclaration.js', + }, + '5': { + name: 'punctuation.decorator.internaldeclaration.js', + }, + }, + end: '(?=$)', + contentName: 'comment.line.double-slash.js', + }, + ], + }, + 'single-line-comment-consuming-line-ending': { + begin: '(^[ \\t]+)?((//)(?:\\s*((@)internal)(?=\\s|$))?)', + beginCaptures: { + '1': { + name: 'punctuation.whitespace.comment.leading.js', + }, + '2': { + name: 'comment.line.double-slash.js', + }, + '3': { + name: 'punctuation.definition.comment.js', + }, + '4': { + name: 'storage.type.internaldeclaration.js', + }, + '5': { + name: 'punctuation.decorator.internaldeclaration.js', + }, + }, + end: '(?=^)', + contentName: 'comment.line.double-slash.js', + }, + directives: { + name: 'comment.line.triple-slash.directive.js', + begin: + '^(///)\\s*(?=<(reference|amd-dependency|amd-module)(\\s+(path|types|no-default-lib|lib|name|resolution-mode)\\s*=\\s*((\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`)))+\\s*/>\\s*$)', + beginCaptures: { + '1': { + name: 'punctuation.definition.comment.js', + }, + }, + end: '(?=$)', + patterns: [ + { + name: 'meta.tag.js', + begin: '(<)(reference|amd-dependency|amd-module)', + beginCaptures: { + '1': { + name: 'punctuation.definition.tag.directive.js', + }, + '2': { + name: 'entity.name.tag.directive.js', + }, + }, + end: '/>', + endCaptures: { + '0': { + name: 'punctuation.definition.tag.directive.js', + }, + }, + patterns: [ + { + name: 'entity.other.attribute-name.directive.js', + match: 'path|types|no-default-lib|lib|name|resolution-mode', + }, + { + name: 'keyword.operator.assignment.js', + match: '=', + }, + { + include: '#string', + }, + ], + }, + ], + }, + docblock: { + patterns: [ + { + match: '(?x)\n((@)(?:access|api))\n\\s+\n(private|protected|public)\n\\b', + captures: { + '1': { + name: 'storage.type.class.jsdoc', + }, + '2': { + name: 'punctuation.definition.block.tag.jsdoc', + }, + '3': { + name: 'constant.language.access-type.jsdoc', + }, + }, + }, + { + match: + '(?x)\n((@)author)\n\\s+\n(\n [^@\\s<>*/]\n (?:[^@<>*/]|\\*[^/])*\n)\n(?:\n \\s*\n (<)\n ([^>\\s]+)\n (>)\n)?', + captures: { + '1': { + name: 'storage.type.class.jsdoc', + }, + '2': { + name: 'punctuation.definition.block.tag.jsdoc', + }, + '3': { + name: 'entity.name.type.instance.jsdoc', + }, + '4': { + name: 'punctuation.definition.bracket.angle.begin.jsdoc', + }, + '5': { + name: 'constant.other.email.link.underline.jsdoc', + }, + '6': { + name: 'punctuation.definition.bracket.angle.end.jsdoc', + }, + }, + }, + { + match: + '(?x)\n((@)borrows) \\s+\n((?:[^@\\s*/]|\\*[^/])+) # \n\\s+ (as) \\s+ # as\n((?:[^@\\s*/]|\\*[^/])+) # ', + captures: { + '1': { + name: 'storage.type.class.jsdoc', + }, + '2': { + name: 'punctuation.definition.block.tag.jsdoc', + }, + '3': { + name: 'entity.name.type.instance.jsdoc', + }, + '4': { + name: 'keyword.operator.control.jsdoc', + }, + '5': { + name: 'entity.name.type.instance.jsdoc', + }, + }, + }, + { + name: 'meta.example.jsdoc', + begin: '((@)example)\\s+', + end: '(?=@|\\*/)', + beginCaptures: { + '1': { + name: 'storage.type.class.jsdoc', + }, + '2': { + name: 'punctuation.definition.block.tag.jsdoc', + }, + }, + patterns: [ + { + match: '^\\s\\*\\s+', + }, + { + contentName: 'constant.other.description.jsdoc', + begin: '\\G(<)caption(>)', + beginCaptures: { + '0': { + name: 'entity.name.tag.inline.jsdoc', + }, + '1': { + name: 'punctuation.definition.bracket.angle.begin.jsdoc', + }, + '2': { + name: 'punctuation.definition.bracket.angle.end.jsdoc', + }, + }, + end: '()|(?=\\*/)', + endCaptures: { + '0': { + name: 'entity.name.tag.inline.jsdoc', + }, + '1': { + name: 'punctuation.definition.bracket.angle.begin.jsdoc', + }, + '2': { + name: 'punctuation.definition.bracket.angle.end.jsdoc', + }, + }, + }, + { + match: '[^\\s@*](?:[^*]|\\*[^/])*', + captures: { + '0': { + name: 'source.embedded.js', + }, + }, + }, + ], + }, + { + match: + '(?x) ((@)kind) \\s+ (class|constant|event|external|file|function|member|mixin|module|namespace|typedef) \\b', + captures: { + '1': { + name: 'storage.type.class.jsdoc', + }, + '2': { + name: 'punctuation.definition.block.tag.jsdoc', + }, + '3': { + name: 'constant.language.symbol-type.jsdoc', + }, + }, + }, + { + match: + '(?x)\n((@)see)\n\\s+\n(?:\n # URL\n (\n (?=https?://)\n (?:[^\\s*]|\\*[^/])+\n )\n |\n # JSDoc namepath\n (\n (?!\n # Avoid matching bare URIs (also acceptable as links)\n https?://\n |\n # Avoid matching {@inline tags}; we match those below\n (?:\\[[^\\[\\]]*\\])? # Possible description [preceding]{@tag}\n {@(?:link|linkcode|linkplain|tutorial)\\b\n )\n # Matched namepath\n (?:[^@\\s*/]|\\*[^/])+\n )\n)', + captures: { + '1': { + name: 'storage.type.class.jsdoc', + }, + '2': { + name: 'punctuation.definition.block.tag.jsdoc', + }, + '3': { + name: 'variable.other.link.underline.jsdoc', + }, + '4': { + name: 'entity.name.type.instance.jsdoc', + }, + }, + }, + { + match: + '(?x)\n((@)template)\n\\s+\n# One or more valid identifiers\n(\n [A-Za-z_$] # First character: non-numeric word character\n [\\w$.\\[\\]]* # Rest of identifier\n (?: # Possible list of additional identifiers\n \\s* , \\s*\n [A-Za-z_$]\n [\\w$.\\[\\]]*\n )*\n)', + captures: { + '1': { + name: 'storage.type.class.jsdoc', + }, + '2': { + name: 'punctuation.definition.block.tag.jsdoc', + }, + '3': { + name: 'variable.other.jsdoc', + }, + }, + }, + { + begin: '(?x)((@)template)\\s+(?={)', + beginCaptures: { + '1': { + name: 'storage.type.class.jsdoc', + }, + '2': { + name: 'punctuation.definition.block.tag.jsdoc', + }, + }, + end: '(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])', + patterns: [ + { + include: '#jsdoctype', + }, + { + name: 'variable.other.jsdoc', + match: '([A-Za-z_$][\\w$.\\[\\]]*)', + }, + ], + }, + { + match: + '(?x)\n(\n (@)\n (?:arg|argument|const|constant|member|namespace|param|var)\n)\n\\s+\n(\n [A-Za-z_$]\n [\\w$.\\[\\]]*\n)', + captures: { + '1': { + name: 'storage.type.class.jsdoc', + }, + '2': { + name: 'punctuation.definition.block.tag.jsdoc', + }, + '3': { + name: 'variable.other.jsdoc', + }, + }, + }, + { + begin: '((@)typedef)\\s+(?={)', + beginCaptures: { + '1': { + name: 'storage.type.class.jsdoc', + }, + '2': { + name: 'punctuation.definition.block.tag.jsdoc', + }, + }, + end: '(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])', + patterns: [ + { + include: '#jsdoctype', + }, + { + name: 'entity.name.type.instance.jsdoc', + match: '(?:[^@\\s*/]|\\*[^/])+', + }, + ], + }, + { + begin: + '((@)(?:arg|argument|const|constant|member|namespace|param|prop|property|var))\\s+(?={)', + beginCaptures: { + '1': { + name: 'storage.type.class.jsdoc', + }, + '2': { + name: 'punctuation.definition.block.tag.jsdoc', + }, + }, + end: '(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])', + patterns: [ + { + include: '#jsdoctype', + }, + { + name: 'variable.other.jsdoc', + match: '([A-Za-z_$][\\w$.\\[\\]]*)', + }, + { + name: 'variable.other.jsdoc', + match: + '(?x)\n(\\[)\\s*\n[\\w$]+\n(?:\n (?:\\[\\])? # Foo[ ].bar properties within an array\n \\. # Foo.Bar namespaced parameter\n [\\w$]+\n)*\n(?:\n \\s*\n (=) # [foo=bar] Default parameter value\n \\s*\n (\n # The inner regexes are to stop the match early at */ and to not stop at escaped quotes\n (?>\n "(?:(?:\\*(?!/))|(?:\\\\(?!"))|[^*\\\\])*?" | # [foo="bar"] Double-quoted\n \'(?:(?:\\*(?!/))|(?:\\\\(?!\'))|[^*\\\\])*?\' | # [foo=\'bar\'] Single-quoted\n \\[ (?:(?:\\*(?!/))|[^*])*? \\] | # [foo=[1,2]] Array literal\n (?:(?:\\*(?!/))|\\s(?!\\s*\\])|\\[.*?(?:\\]|(?=\\*/))|[^*\\s\\[\\]])* # Everything else\n )*\n )\n)?\n\\s*(?:(\\])((?:[^*\\s]|\\*[^\\s/])+)?|(?=\\*/))', + captures: { + '1': { + name: 'punctuation.definition.optional-value.begin.bracket.square.jsdoc', + }, + '2': { + name: 'keyword.operator.assignment.jsdoc', + }, + '3': { + name: 'source.embedded.js', + }, + '4': { + name: 'punctuation.definition.optional-value.end.bracket.square.jsdoc', + }, + '5': { + name: 'invalid.illegal.syntax.jsdoc', + }, + }, + }, + ], + }, + { + begin: + '(?x)\n(\n (@)\n (?:define|enum|exception|export|extends|lends|implements|modifies\n |namespace|private|protected|returns?|satisfies|suppress|this|throws|type\n |yields?)\n)\n\\s+(?={)', + beginCaptures: { + '1': { + name: 'storage.type.class.jsdoc', + }, + '2': { + name: 'punctuation.definition.block.tag.jsdoc', + }, + }, + end: '(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])', + patterns: [ + { + include: '#jsdoctype', + }, + ], + }, + { + match: + '(?x)\n(\n (@)\n (?:alias|augments|callback|constructs|emits|event|fires|exports?\n |extends|external|function|func|host|lends|listens|interface|memberof!?\n |method|module|mixes|mixin|name|requires|see|this|typedef|uses)\n)\n\\s+\n(\n (?:\n [^{}@\\s*] | \\*[^/]\n )+\n)', + captures: { + '1': { + name: 'storage.type.class.jsdoc', + }, + '2': { + name: 'punctuation.definition.block.tag.jsdoc', + }, + '3': { + name: 'entity.name.type.instance.jsdoc', + }, + }, + }, + { + contentName: 'variable.other.jsdoc', + begin: "((@)(?:default(?:value)?|license|version))\\s+(([''\"]))", + beginCaptures: { + '1': { + name: 'storage.type.class.jsdoc', + }, + '2': { + name: 'punctuation.definition.block.tag.jsdoc', + }, + '3': { + name: 'variable.other.jsdoc', + }, + '4': { + name: 'punctuation.definition.string.begin.jsdoc', + }, + }, + end: '(\\3)|(?=$|\\*/)', + endCaptures: { + '0': { + name: 'variable.other.jsdoc', + }, + '1': { + name: 'punctuation.definition.string.end.jsdoc', + }, + }, + }, + { + match: '((@)(?:default(?:value)?|license|tutorial|variation|version))\\s+([^\\s*]+)', + captures: { + '1': { + name: 'storage.type.class.jsdoc', + }, + '2': { + name: 'punctuation.definition.block.tag.jsdoc', + }, + '3': { + name: 'variable.other.jsdoc', + }, + }, + }, + { + name: 'storage.type.class.jsdoc', + match: + '(?x) (@) (?:abstract|access|alias|api|arg|argument|async|attribute|augments|author|beta|borrows|bubbles |callback|chainable|class|classdesc|code|config|const|constant|constructor|constructs|copyright |default|defaultvalue|define|deprecated|desc|description|dict|emits|enum|event|example|exception |exports?|extends|extension(?:_?for)?|external|externs|file|fileoverview|final|fires|for|func |function|generator|global|hideconstructor|host|ignore|implements|implicitCast|inherit[Dd]oc |inner|instance|interface|internal|kind|lends|license|listens|main|member|memberof!?|method |mixes|mixins?|modifies|module|name|namespace|noalias|nocollapse|nocompile|nosideeffects |override|overview|package|param|polymer(?:Behavior)?|preserve|private|prop|property|protected |public|read[Oo]nly|record|require[ds]|returns?|see|since|static|struct|submodule|summary |suppress|template|this|throws|todo|tutorial|type|typedef|unrestricted|uses|var|variation |version|virtual|writeOnce|yields?) \\b', + captures: { + '1': { + name: 'punctuation.definition.block.tag.jsdoc', + }, + }, + }, + { + include: '#inline-tags', + }, + { + match: '((@)(?:[_$[:alpha:]][_$[:alnum:]]*))(?=\\s+)', + captures: { + '1': { + name: 'storage.type.class.jsdoc', + }, + '2': { + name: 'punctuation.definition.block.tag.jsdoc', + }, + }, + }, + ], + }, + brackets: { + patterns: [ + { + begin: '{', + end: '}|(?=\\*/)', + patterns: [ + { + include: '#brackets', + }, + ], + }, + { + begin: '\\[', + end: '\\]|(?=\\*/)', + patterns: [ + { + include: '#brackets', + }, + ], + }, + ], + }, + 'inline-tags': { + patterns: [ + { + name: 'constant.other.description.jsdoc', + match: '(\\[)[^\\]]+(\\])(?={@(?:link|linkcode|linkplain|tutorial))', + captures: { + '1': { + name: 'punctuation.definition.bracket.square.begin.jsdoc', + }, + '2': { + name: 'punctuation.definition.bracket.square.end.jsdoc', + }, + }, + }, + { + name: 'entity.name.type.instance.jsdoc', + begin: '({)((@)(?:link(?:code|plain)?|tutorial))\\s*', + beginCaptures: { + '1': { + name: 'punctuation.definition.bracket.curly.begin.jsdoc', + }, + '2': { + name: 'storage.type.class.jsdoc', + }, + '3': { + name: 'punctuation.definition.inline.tag.jsdoc', + }, + }, + end: '}|(?=\\*/)', + endCaptures: { + '0': { + name: 'punctuation.definition.bracket.curly.end.jsdoc', + }, + }, + patterns: [ + { + match: '\\G((?=https?://)(?:[^|}\\s*]|\\*[/])+)(\\|)?', + captures: { + '1': { + name: 'variable.other.link.underline.jsdoc', + }, + '2': { + name: 'punctuation.separator.pipe.jsdoc', + }, + }, + }, + { + match: '\\G((?:[^{}@\\s|*]|\\*[^/])+)(\\|)?', + captures: { + '1': { + name: 'variable.other.description.jsdoc', + }, + '2': { + name: 'punctuation.separator.pipe.jsdoc', + }, + }, + }, + ], + }, + ], + }, + jsdoctype: { + patterns: [ + { + contentName: 'entity.name.type.instance.jsdoc', + begin: '\\G({)', + beginCaptures: { + '0': { + name: 'entity.name.type.instance.jsdoc', + }, + '1': { + name: 'punctuation.definition.bracket.curly.begin.jsdoc', + }, + }, + end: '((}))\\s*|(?=\\*/)', + endCaptures: { + '1': { + name: 'entity.name.type.instance.jsdoc', + }, + '2': { + name: 'punctuation.definition.bracket.curly.end.jsdoc', + }, + }, + patterns: [ + { + include: '#brackets', + }, + ], + }, + ], + }, + jsx: { + patterns: [ + { + include: '#jsx-tag-style', + }, + { + include: '#jsx-tag-without-attributes', + }, + { + include: '#jsx-tag', + }, + ], + }, + 'jsx-tag-without-attributes-in-expression': { + begin: + '(?:*]|&&|\\|\\||\\?|\\*\\/|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^yield|[^\\._$[:alnum:]]yield|^)\\s*(?=(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))', + end: '(?!(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))', + patterns: [ + { + include: '#jsx-tag-without-attributes', + }, + ], + }, + 'jsx-tag-without-attributes': { + name: 'meta.tag.without-attributes.js', + begin: + '(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?)', + end: '()', + beginCaptures: { + '1': { + name: 'punctuation.definition.tag.begin.js', + }, + '2': { + name: 'entity.name.tag.namespace.js', + }, + '3': { + name: 'punctuation.separator.namespace.js', + }, + '4': { + name: 'entity.name.tag.js', + }, + '5': { + name: 'support.class.component.js', + }, + '6': { + name: 'punctuation.definition.tag.end.js', + }, + }, + endCaptures: { + '1': { + name: 'punctuation.definition.tag.begin.js', + }, + '2': { + name: 'entity.name.tag.namespace.js', + }, + '3': { + name: 'punctuation.separator.namespace.js', + }, + '4': { + name: 'entity.name.tag.js', + }, + '5': { + name: 'support.class.component.js', + }, + '6': { + name: 'punctuation.definition.tag.end.js', + }, + }, + contentName: 'meta.jsx.children.js', + patterns: [ + { + include: '#jsx-children', + }, + ], + }, + 'jsx-tag-in-expression': { + begin: + '(?x)\n (?:*]|&&|\\|\\||\\?|\\*\\/|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^yield|[^\\._$[:alnum:]]yield|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))', + end: '(?!(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))', + patterns: [ + { + include: '#jsx-tag', + }, + ], + }, + 'jsx-tag-style': { + name: 'style.tag.js', + begin: '(<)\\s*(style)\\b(?![^>]*/>)(?=[^>]*>)', + beginCaptures: { + '1': { + name: 'punctuation.definition.tag.begin.js', + }, + '2': { + name: 'entity.name.tag.js', + }, + }, + end: '()', + endCaptures: { + '1': { + name: 'punctuation.definition.tag.begin.js', + }, + '2': { + name: 'entity.name.tag.js', + }, + '3': { + name: 'punctuation.definition.tag.end.js', + }, + }, + patterns: [ + { + begin: '(>)', + beginCaptures: { + '1': { + name: 'punctuation.definition.tag.end.js', + }, + }, + end: '(?=)', + contentName: 'source.css', + patterns: [ + { + include: 'source.css', + }, + ], + }, + { + begin: '(?<=]*/>)', + end: '(?=>)', + patterns: [ + { + include: '#jsx-tag-attributes', + }, + ], + }, + ], + }, + 'jsx-tag': { + name: 'meta.tag.js', + begin: + '(?=(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))', + end: '(/>)|(?:())', + endCaptures: { + '1': { + name: 'punctuation.definition.tag.end.js', + }, + '2': { + name: 'punctuation.definition.tag.begin.js', + }, + '3': { + name: 'entity.name.tag.namespace.js', + }, + '4': { + name: 'punctuation.separator.namespace.js', + }, + '5': { + name: 'entity.name.tag.js', + }, + '6': { + name: 'support.class.component.js', + }, + '7': { + name: 'punctuation.definition.tag.end.js', + }, + }, + patterns: [ + { + begin: + '(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?)', + beginCaptures: { + '1': { + name: 'punctuation.definition.tag.begin.js', + }, + '2': { + name: 'entity.name.tag.namespace.js', + }, + '3': { + name: 'punctuation.separator.namespace.js', + }, + '4': { + name: 'entity.name.tag.js', + }, + '5': { + name: 'support.class.component.js', + }, + }, + end: '(?=[/]?>)', + patterns: [ + { + include: '#comment', + }, + { + include: '#type-arguments', + }, + { + include: '#jsx-tag-attributes', + }, + ], + }, + { + begin: '(>)', + beginCaptures: { + '1': { + name: 'punctuation.definition.tag.end.js', + }, + }, + end: '(?=)', + patterns: [ + { + include: '#comment', + }, + { + include: '#jsx-tag-attribute-name', + }, + { + include: '#jsx-tag-attribute-assignment', + }, + { + include: '#jsx-string-double-quoted', + }, + { + include: '#jsx-string-single-quoted', + }, + { + include: '#jsx-evaluated-code', + }, + { + include: '#jsx-tag-attributes-illegal', + }, + ], + }, + 'jsx-tag-attribute-name': { + match: + '(?x)\n \\s*\n (?:([_$[:alpha:]][-_$[:alnum:].]*)(:))?\n ([_$[:alpha:]][-_$[:alnum:]]*)\n (?=\\s|=|/?>|/\\*|//)', + captures: { + '1': { + name: 'entity.other.attribute-name.namespace.js', + }, + '2': { + name: 'punctuation.separator.namespace.js', + }, + '3': { + name: 'entity.other.attribute-name.js', + }, + }, + }, + 'jsx-tag-attribute-assignment': { + name: 'keyword.operator.assignment.js', + match: '=(?=\\s*(?:\'|"|{|/\\*|//|\\n))', + }, + 'jsx-string-double-quoted': { + name: 'string.quoted.double.js', + begin: '"', + end: '"', + beginCaptures: { + '0': { + name: 'punctuation.definition.string.begin.js', + }, + }, + endCaptures: { + '0': { + name: 'punctuation.definition.string.end.js', + }, + }, + patterns: [ + { + include: '#jsx-entities', + }, + ], + }, + 'jsx-string-single-quoted': { + name: 'string.quoted.single.js', + begin: "'", + end: "'", + beginCaptures: { + '0': { + name: 'punctuation.definition.string.begin.js', + }, + }, + endCaptures: { + '0': { + name: 'punctuation.definition.string.end.js', + }, + }, + patterns: [ + { + include: '#jsx-entities', + }, + ], + }, + 'jsx-tag-attributes-illegal': { + name: 'invalid.illegal.attribute.js', + match: '\\S+', + }, + }, + }, + + config: { + // Note that this file should stay in sync with 'typescript-language-basics/language-configuration.json' + // onEnterRules cause errors - currently disabled + comments: { + lineComment: '//', + blockComment: ['/*', '*/'], + }, + brackets: [ + ['${', '}'], + ['{', '}'], + ['[', ']'], + ['(', ')'], + ], + autoClosingPairs: [ + { + open: '{', + close: '}', + }, + { + open: '[', + close: ']', + }, + { + open: '(', + close: ')', + }, + { + open: "'", + close: "'", + notIn: ['string', 'comment'], + }, + { + open: '"', + close: '"', + notIn: ['string'], + }, + { + open: '`', + close: '`', + notIn: ['string', 'comment'], + }, + { + open: '/**', + close: ' */', + notIn: ['string'], + }, + ], + surroundingPairs: [ + ['{', '}'], + ['[', ']'], + ['(', ')'], + ["'", "'"], + ['"', '"'], + ['`', '`'], + ['<', '>'], + ], + autoCloseBefore: ';:.,=}])>` \n\t', + folding: { + markers: { + start: '^\\s*//\\s*#?region\\b', + end: '^\\s*//\\s*#?endregion\\b', + }, + }, + wordPattern: { + pattern: + '(-?\\d*\\.\\d\\w*)|([^\\`\\~\\@\\!\\%\\^\\&\\*\\(\\)\\-\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\\'\\"\\,\\.\\<\\>/\\?\\s]+)', + }, + indentationRules: { + decreaseIndentPattern: { + pattern: '^\\s*[\\}\\]\\)].*$', + }, + increaseIndentPattern: { + pattern: '^.*(\\{[^}]*|\\([^)]*|\\[[^\\]]*)$', + }, + // e.g. * ...| or */| or *-----*/| + unIndentedLinePattern: { + pattern: + '^(\\t|[ ])*[ ]\\*[^/]*\\*/\\s*$|^(\\t|[ ])*[ ]\\*/\\s*$|^(\\t|[ ])*[ ]\\*([ ]([^\\*]|\\*(?!/))*)?$', + }, + indentNextLinePattern: { + pattern: '^((.*=>\\s*)|((.*[^\\w]+|\\s*)(if|while|for)\\s*\\(.*\\)\\s*))$', + }, + }, + // onEnterRules: [ + // { + // // e.g. /** | */ + // beforeText: { + // pattern: '^\\s*/\\*\\*(?!/)([^\\*]|\\*(?!/))*$', + // }, + // afterText: { + // pattern: '^\\s*\\*/$', + // }, + // action: { + // indent: 'indentOutdent', + // appendText: ' * ', + // }, + // }, + // { + // // e.g. /** ...| + // beforeText: { + // pattern: '^\\s*/\\*\\*(?!/)([^\\*]|\\*(?!/))*$', + // }, + // action: { + // indent: 'none', + // appendText: ' * ', + // }, + // }, + // { + // // e.g. * ...| + // beforeText: { + // pattern: '^(\\t|[ ])*[ ]\\*([ ]([^\\*]|\\*(?!/))*)?$', + // }, + // previousLineText: { + // pattern: '(?=^(\\s*(/\\*\\*|\\*)).*)(?=(?!(\\s*\\*/)))', + // }, + // action: { + // indent: 'none', + // appendText: '* ', + // }, + // }, + // { + // // e.g. */| + // beforeText: { + // pattern: '^(\\t|[ ])*[ ]\\*/\\s*$', + // }, + // action: { + // indent: 'none', + // removeText: 1, + // }, + // }, + // { + // // e.g. *-----*/| + // beforeText: { + // pattern: '^(\\t|[ ])*[ ]\\*[^/]*\\*/\\s*$', + // }, + // action: { + // indent: 'none', + // removeText: 1, + // }, + // }, + // { + // beforeText: { + // pattern: '^\\s*(\\bcase\\s.+:|\\bdefault:)$', + // }, + // afterText: { + // pattern: '^(?!\\s*(\\bcase\\b|\\bdefault\\b))', + // }, + // action: { + // indent: 'indent', + // }, + // }, + // { + // // Decrease indentation after single line if/else if/else, for, or while + // previousLineText: '^\\s*(((else ?)?if|for|while)\\s*\\(.*\\)\\s*|else\\s*)$', + // // But make sure line doesn't have braces or is not another if statement + // beforeText: '^\\s+([^{i\\s]|i(?!f\\b))', + // action: { + // indent: 'outdent', + // }, + // }, + // // Indent when pressing enter from inside () + // { + // beforeText: '^.*\\([^\\)]*$', + // afterText: '^\\s*\\).*$', + // action: { + // indent: 'indentOutdent', + // appendText: '\t', + // }, + // }, + // // Indent when pressing enter from inside {} + // { + // beforeText: '^.*\\{[^\\}]*$', + // afterText: '^\\s*\\}.*$', + // action: { + // indent: 'indentOutdent', + // appendText: '\t', + // }, + // }, + // // Indent when pressing enter from inside [] + // { + // beforeText: '^.*\\[[^\\]]*$', + // afterText: '^\\s*\\].*$', + // action: { + // indent: 'indentOutdent', + // appendText: '\t', + // }, + // }, + // // Add // when pressing enter from inside line comment + // { + // beforeText: { + // pattern: '(? astro: baseUrl + '{{hash:monaco-lang-astro.js}}', clio: baseUrl + '{{hash:monaco-lang-clio.js}}', imba: baseUrl + '{{hash:monaco-lang-imba.js}}', + ripple: baseUrl + '{{hash:monaco-lang-ripple.js}}', // sql: baseUrl + '{{hash:monaco-lang-sql.js}}', // TODO: add autocomplete wat: baseUrl + '{{hash:monaco-lang-wat.js}}', }; @@ -260,6 +265,7 @@ export const createEditor = async (options: EditorOptions): Promise interface CustomLanguageDefinition { config?: Monaco.languages.LanguageConfiguration; tokens?: Monaco.languages.IMonarchLanguage; + syntax?: Record; } const addVueSupport = async () => { @@ -274,6 +280,46 @@ export const createEditor = async (options: EditorOptions): Promise setTheme(currentTheme, currentEditorTheme); }; + async function registerFromTextMate({ + name, + scopeName, + syntax, + }: { + name: string; + scopeName: string; + syntax: string; + }) { + await addVueSupport(); // a workaround for TextMate syntax + + const { loadWASM } = await import(onigasmUrl); + const { Registry } = await import(monacoTextmateUrl); + const { wireTmGrammars } = await import(monacoEditorTextmateUrl); + + await loadWASM(onigasmWasmUrl); + + const registry = new Registry({ + getGrammarDefinition: async (_scopeName: string) => { + return { + format: 'json', + content: syntax, + }; + }, + }); + + const grammars = new Map(); + grammars.set(name, scopeName); + monaco.languages.register({ id: name }); + await wireTmGrammars(monaco, registry, grammars, editor); + } + + const addRippleSupport = async (syntax: CustomLanguageDefinition['syntax']) => { + await registerFromTextMate({ + name: 'ripple', + scopeName: 'source.ripple', + syntax: JSON.stringify(syntax, null, 2).replace('"name": "Ripple"', '"name": "ripple"'), + }); + }; + const loadMonacoLanguage = async (lang: Language) => { if (monacoMapLanguage(lang) === 'vue') { await addVueSupport(); @@ -289,6 +335,10 @@ export const createEditor = async (options: EditorOptions): Promise if (mod.tokens) { monaco.languages.setMonarchTokensProvider(lang, mod.tokens); } + if (lang === 'ripple') { + await addRippleSupport(mod.syntax); + return; + } } }; diff --git a/src/livecodes/languages/ripple/lang-ripple.ts b/src/livecodes/languages/ripple/lang-ripple.ts index 3f30bb9b43..8afe23152f 100644 --- a/src/livecodes/languages/ripple/lang-ripple.ts +++ b/src/livecodes/languages/ripple/lang-ripple.ts @@ -27,5 +27,4 @@ export const ripple: LanguageSpecs = { }, extensions: ['ripple'], editor: 'script', - editorLanguage: 'typescript', }; diff --git a/src/livecodes/vendors.ts b/src/livecodes/vendors.ts index b0207c7aee..0945e7f014 100644 --- a/src/livecodes/vendors.ts +++ b/src/livecodes/vendors.ts @@ -295,8 +295,12 @@ export const mjmlUrl = /* @__PURE__ */ getUrl('mjml-browser@4.15.3/lib/index.js' export const monacoBaseUrl = /* @__PURE__ */ getUrl('@live-codes/monaco-editor@0.3.0/'); +export const monacoEditorTextmateUrl = /* @__PURE__ */ getModuleUrl('monaco-editor-textmate@4.0.0'); + export const monacoEmacsUrl = /* @__PURE__ */ getUrl('monaco-emacs@0.3.0/dist/monaco-emacs.js'); +export const monacoTextmateUrl = /* @__PURE__ */ getModuleUrl('monaco-textmate@3.0.1'); + export const monacoThemesBaseUrl = /* @__PURE__ */ getUrl('monaco-themes@0.4.4/themes/'); export const monacoVimUrl = /* @__PURE__ */ getUrl('monaco-vim@0.4.1/dist/monaco-vim.js'); @@ -315,6 +319,10 @@ export const normalizeCssUrl = /* @__PURE__ */ getUrl('normalize.css@8.0.1/norma export const nunjucksBaseUrl = /* @__PURE__ */ getUrl('nunjucks@3.2.4/browser/'); +export const onigasmUrl = /* @__PURE__ */ getModuleUrl('onigasm@2.2.5'); + +export const onigasmWasmUrl = /* @__PURE__ */ getUrl('onigasm@2.2.5/lib/onigasm.wasm'); + export const opalBaseUrl = /* @__PURE__ */ getUrl('https://cdn.opalrb.com/opal/1.8.2/'); export const parinferUrl = /* @__PURE__ */ getUrl('parinfer@3.13.1/parinfer.js'); @@ -389,7 +397,7 @@ export const resetCssUrl = /* @__PURE__ */ getUrl('reset-css@5.0.1/reset.css'); export const riotBaseUrl = /* @__PURE__ */ getUrl('riot@9.2.2/'); -export const rippleUrl = /* @__PURE__ */ getModuleUrl('ripple@0.2.5/compiler'); +export const rippleUrl = /* @__PURE__ */ getModuleUrl('ripple@0.2.6/compiler'); export const rubyWasmBaseUrl = /* @__PURE__ */ getUrl('@ruby/3.3-wasm-wasi@2.6.2/dist/'); From 16eeddb0b45945e03c12c950914f20f594181e0d Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Mon, 1 Sep 2025 03:39:01 +0300 Subject: [PATCH 04/71] add support for CSS in Ripple components --- .../monaco/languages/monaco-lang-ripple.ts | 1841 +++++++++++++++++ src/livecodes/editor/monaco/monaco.ts | 51 +- 2 files changed, 1871 insertions(+), 21 deletions(-) diff --git a/src/livecodes/editor/monaco/languages/monaco-lang-ripple.ts b/src/livecodes/editor/monaco/languages/monaco-lang-ripple.ts index 392d2620d0..30aca96d4f 100644 --- a/src/livecodes/editor/monaco/languages/monaco-lang-ripple.ts +++ b/src/livecodes/editor/monaco/languages/monaco-lang-ripple.ts @@ -1,5 +1,6 @@ // from https://github.com/trueadm/ripple/blob/main/packages/ripple-vscode-plugin/syntaxes/ripple.tmLanguage.json // and https://github.com/trueadm/ripple/blob/main/packages/ripple-vscode-plugin/language-configuration.json +// and 'https://cdn.jsdelivr.net/gh/zikaari/monaco-textmate-languages@master/grammars/css/css.tmLanguage.json' export default { syntax: { information_for_contributors: [ @@ -6853,4 +6854,1844 @@ export default { // }, // ], }, + + cssSyntax: { + information_for_contributors: [ + 'This file has been converted from https://github.com/atom/language-css/blob/master/grammars/css.cson', + 'If you want to provide a fix or improvement, please create a pull request against the original repository.', + 'Once accepted there, we are happy to receive an update request.', + ], + version: 'https://github.com/atom/language-css/commit/2bc1e294e2440ad91197263cd9f95dc4b00bab2f', + name: 'CSS', + scopeName: 'source.css', + patterns: [ + { + include: '#comment-block', + }, + { + include: '#escapes', + }, + { + include: '#combinators', + }, + { + include: '#selector', + }, + { + include: '#at-rules', + }, + { + include: '#rule-list', + }, + ], + repository: { + 'at-rules': { + patterns: [ + { + begin: '\\A(?:\\xEF\\xBB\\xBF)?(?i:(?=\\s*@charset\\b))', + end: ';|(?=$)', + endCaptures: { + '0': { + name: 'punctuation.terminator.rule.css', + }, + }, + name: 'meta.at-rule.charset.css', + patterns: [ + { + captures: { + '1': { + name: 'invalid.illegal.not-lowercase.charset.css', + }, + '2': { + name: 'invalid.illegal.leading-whitespace.charset.css', + }, + '3': { + name: 'invalid.illegal.no-whitespace.charset.css', + }, + '4': { + name: 'invalid.illegal.whitespace.charset.css', + }, + '5': { + name: 'invalid.illegal.not-double-quoted.charset.css', + }, + '6': { + name: 'invalid.illegal.unclosed-string.charset.css', + }, + '7': { + name: 'invalid.illegal.unexpected-characters.charset.css', + }, + }, + match: + '(?x) # Possible errors:\n\\G\n((?!@charset)@\\w+) # Not lowercase (@charset is case-sensitive)\n|\n\\G(\\s+) # Preceding whitespace\n|\n(@charset\\S[^;]*) # No whitespace after @charset\n|\n(?<=@charset) # Before quoted charset name\n(\\x20{2,}|\\t+) # More than one space used, or a tab\n|\n(?<=@charset\\x20) # Beginning of charset name\n([^";]+) # Not double-quoted\n|\n("[^"]+$) # Unclosed quote\n|\n(?<=") # After charset name\n([^;]+) # Unexpected junk instead of semicolon', + }, + { + captures: { + '1': { + name: 'keyword.control.at-rule.charset.css', + }, + '2': { + name: 'punctuation.definition.keyword.css', + }, + }, + match: '((@)charset)(?=\\s)', + }, + { + begin: '"', + beginCaptures: { + '0': { + name: 'punctuation.definition.string.begin.css', + }, + }, + end: '"|$', + endCaptures: { + '0': { + name: 'punctuation.definition.string.end.css', + }, + }, + name: 'string.quoted.double.css', + patterns: [ + { + begin: '(?:\\G|^)(?=(?:[^"])+$)', + end: '$', + name: 'invalid.illegal.unclosed.string.css', + }, + ], + }, + ], + }, + { + begin: '(?i)((@)import)(?:\\s+|$|(?=[\'"]|/\\*))', + beginCaptures: { + '1': { + name: 'keyword.control.at-rule.import.css', + }, + '2': { + name: 'punctuation.definition.keyword.css', + }, + }, + end: ';', + endCaptures: { + '0': { + name: 'punctuation.terminator.rule.css', + }, + }, + name: 'meta.at-rule.import.css', + patterns: [ + { + begin: '\\G\\s*(?=/\\*)', + end: '(?<=\\*/)\\s*', + patterns: [ + { + include: '#comment-block', + }, + ], + }, + { + include: '#string', + }, + { + include: '#url', + }, + { + include: '#media-query-list', + }, + ], + }, + { + begin: '(?i)((@)font-face)(?=\\s*|{|/\\*|$)', + beginCaptures: { + '1': { + name: 'keyword.control.at-rule.font-face.css', + }, + '2': { + name: 'punctuation.definition.keyword.css', + }, + }, + end: '(?!\\G)', + name: 'meta.at-rule.font-face.css', + patterns: [ + { + include: '#comment-block', + }, + { + include: '#escapes', + }, + { + include: '#rule-list', + }, + ], + }, + { + begin: '(?i)(@)page(?=[\\s:{]|/\\*|$)', + captures: { + '0': { + name: 'keyword.control.at-rule.page.css', + }, + '1': { + name: 'punctuation.definition.keyword.css', + }, + }, + end: '(?=\\s*($|[:{;]))', + name: 'meta.at-rule.page.css', + patterns: [ + { + include: '#rule-list', + }, + ], + }, + { + begin: '(?i)(?=@media(\\s|\\(|/\\*|$))', + end: '(?<=})(?!\\G)', + patterns: [ + { + begin: '(?i)\\G(@)media', + beginCaptures: { + '0': { + name: 'keyword.control.at-rule.media.css', + }, + '1': { + name: 'punctuation.definition.keyword.css', + }, + }, + end: '(?=\\s*[{;])', + name: 'meta.at-rule.media.header.css', + patterns: [ + { + include: '#media-query-list', + }, + ], + }, + { + begin: '{', + beginCaptures: { + '0': { + name: 'punctuation.section.media.begin.bracket.curly.css', + }, + }, + end: '}', + endCaptures: { + '0': { + name: 'punctuation.section.media.end.bracket.curly.css', + }, + }, + name: 'meta.at-rule.media.body.css', + patterns: [ + { + include: '$self', + }, + ], + }, + ], + }, + { + begin: '(?i)(?=@counter-style([\\s\'"{;]|/\\*|$))', + end: '(?<=})(?!\\G)', + patterns: [ + { + begin: '(?i)\\G(@)counter-style', + beginCaptures: { + '0': { + name: 'keyword.control.at-rule.counter-style.css', + }, + '1': { + name: 'punctuation.definition.keyword.css', + }, + }, + end: '(?=\\s*{)', + name: 'meta.at-rule.counter-style.header.css', + patterns: [ + { + include: '#comment-block', + }, + { + include: '#escapes', + }, + { + captures: { + '0': { + patterns: [ + { + include: '#escapes', + }, + ], + }, + }, + match: + '(?x)\n(?:[-a-zA-Z_] | [^\\x00-\\x7F]) # First letter\n(?:[-a-zA-Z0-9_] | [^\\x00-\\x7F] # Remainder of identifier\n |\\\\(?:[0-9a-fA-F]{1,6}|.)\n)*', + name: 'variable.parameter.style-name.css', + }, + ], + }, + { + begin: '{', + beginCaptures: { + '0': { + name: 'punctuation.section.property-list.begin.bracket.curly.css', + }, + }, + end: '}', + endCaptures: { + '0': { + name: 'punctuation.section.property-list.end.bracket.curly.css', + }, + }, + name: 'meta.at-rule.counter-style.body.css', + patterns: [ + { + include: '#comment-block', + }, + { + include: '#escapes', + }, + { + include: '#rule-list-innards', + }, + ], + }, + ], + }, + { + begin: '(?i)(?=@document([\\s\'"{;]|/\\*|$))', + end: '(?<=})(?!\\G)', + patterns: [ + { + begin: '(?i)\\G(@)document', + beginCaptures: { + '0': { + name: 'keyword.control.at-rule.document.css', + }, + '1': { + name: 'punctuation.definition.keyword.css', + }, + }, + end: '(?=\\s*[{;])', + name: 'meta.at-rule.document.header.css', + patterns: [ + { + begin: '(?i)(?>>', + name: 'invalid.deprecated.combinator.css', + }, + { + match: '>>|>|\\+|~', + name: 'keyword.operator.combinator.css', + }, + ], + }, + commas: { + match: ',', + name: 'punctuation.separator.list.comma.css', + }, + 'comment-block': { + begin: '/\\*', + beginCaptures: { + '0': { + name: 'punctuation.definition.comment.begin.css', + }, + }, + end: '\\*/', + endCaptures: { + '0': { + name: 'punctuation.definition.comment.end.css', + }, + }, + name: 'comment.block.css', + }, + escapes: { + patterns: [ + { + match: '\\\\[0-9a-fA-F]{1,6}', + name: 'constant.character.escape.codepoint.css', + }, + { + begin: '\\\\$\\s*', + end: '^(?<:=]|\\)|/\\*) # Terminates cleanly', + }, + 'media-feature-keywords': { + match: + '(?xi)\n(?<=^|\\s|:|\\*/)\n(?: portrait # Orientation\n | landscape\n | progressive # Scan types\n | interlace\n | fullscreen # Display modes\n | standalone\n | minimal-ui\n | browser\n)\n(?=\\s|\\)|$)', + name: 'support.constant.property-value.css', + }, + 'media-query': { + begin: '\\G', + end: '(?=\\s*[{;])', + patterns: [ + { + include: '#comment-block', + }, + { + include: '#escapes', + }, + { + include: '#media-types', + }, + { + match: '(?i)(?<=\\s|^|,|\\*/)(only|not)(?=\\s|{|/\\*|$)', + name: 'keyword.operator.logical.$1.media.css', + }, + { + match: '(?i)(?<=\\s|^|\\*/|\\))and(?=\\s|/\\*|$)', + name: 'keyword.operator.logical.and.media.css', + }, + { + match: ',(?:(?:\\s*,)+|(?=\\s*[;){]))', + name: 'invalid.illegal.comma.css', + }, + { + include: '#commas', + }, + { + begin: '\\(', + beginCaptures: { + '0': { + name: 'punctuation.definition.parameters.begin.bracket.round.css', + }, + }, + end: '\\)', + endCaptures: { + '0': { + name: 'punctuation.definition.parameters.end.bracket.round.css', + }, + }, + patterns: [ + { + include: '#media-features', + }, + { + include: '#media-feature-keywords', + }, + { + match: ':', + name: 'punctuation.separator.key-value.css', + }, + { + match: '>=|<=|=|<|>', + name: 'keyword.operator.comparison.css', + }, + { + captures: { + '1': { + name: 'constant.numeric.css', + }, + '2': { + name: 'keyword.operator.arithmetic.css', + }, + '3': { + name: 'constant.numeric.css', + }, + }, + match: '(\\d+)\\s*(/)\\s*(\\d+)', + name: 'meta.ratio.css', + }, + { + include: '#numeric-values', + }, + { + include: '#comment-block', + }, + ], + }, + ], + }, + 'media-query-list': { + begin: '(?=\\s*[^{;])', + end: '(?=\\s*[{;])', + patterns: [ + { + include: '#media-query', + }, + ], + }, + 'media-types': { + captures: { + '1': { + name: 'support.constant.media.css', + }, + '2': { + name: 'invalid.deprecated.constant.media.css', + }, + }, + match: + '(?xi)\n(?<=^|\\s|,|\\*/)\n(?:\n # Valid media types\n (all|print|screen|speech)\n |\n # Deprecated in Media Queries 4: http://dev.w3.org/csswg/mediaqueries/#media-types\n (aural|braille|embossed|handheld|projection|tty|tv)\n)\n(?=$|[{,\\s;]|/\\*)', + }, + 'numeric-values': { + patterns: [ + { + captures: { + '1': { + name: 'punctuation.definition.constant.css', + }, + }, + match: '(#)(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})\\b', + name: 'constant.other.color.rgb-value.hex.css', + }, + { + captures: { + '1': { + name: 'keyword.other.unit.percentage.css', + }, + '2': { + name: 'keyword.other.unit.${2:/downcase}.css', + }, + }, + match: + '(?xi) (?+~|] # - Followed by another selector\n | /\\* # - Followed by a block comment\n )\n |\n # Name contains unescaped ASCII symbol\n (?: # Check for acceptable preceding characters\n [-a-zA-Z_0-9]|[^\\x00-\\x7F] # - Valid selector character\n | \\\\(?:[0-9a-fA-F]{1,6}|.) # - Escape sequence\n )*\n (?: # Invalid punctuation\n [!"\'%&(*;+~|] # - Another selector\n | /\\* # - A block comment\n)', + name: 'entity.other.attribute-name.class.css', + }, + { + captures: { + '1': { + name: 'punctuation.definition.entity.css', + }, + '2': { + patterns: [ + { + include: '#escapes', + }, + ], + }, + }, + match: + '(?x)\n(\\#)\n(\n -?\n (?![0-9])\n (?:[-a-zA-Z0-9_]|[^\\x00-\\x7F]|\\\\(?:[0-9a-fA-F]{1,6}|.))+\n)\n(?=$|[\\s,.\\#)\\[:{>+~|]|/\\*)', + name: 'entity.other.attribute-name.id.css', + }, + { + begin: '\\[', + beginCaptures: { + '0': { + name: 'punctuation.definition.entity.begin.bracket.square.css', + }, + }, + end: '\\]', + endCaptures: { + '0': { + name: 'punctuation.definition.entity.end.bracket.square.css', + }, + }, + name: 'meta.attribute-selector.css', + patterns: [ + { + include: '#comment-block', + }, + { + include: '#string', + }, + { + captures: { + '1': { + name: 'storage.modifier.ignore-case.css', + }, + }, + match: '(?<=["\'\\s]|^|\\*/)\\s*([iI])\\s*(?=[\\s\\]]|/\\*|$)', + }, + { + captures: { + '1': { + name: 'string.unquoted.attribute-value.css', + patterns: [ + { + include: '#escapes', + }, + ], + }, + }, + match: '(?x)(?<==)\\s*((?!/\\*)(?:[^\\\\"\'\\s\\]]|\\\\.)+)', + }, + { + include: '#escapes', + }, + { + match: '[~|^$*]?=', + name: 'keyword.operator.pattern.css', + }, + { + match: '\\|', + name: 'punctuation.separator.css', + }, + { + captures: { + '1': { + name: 'entity.other.namespace-prefix.css', + patterns: [ + { + include: '#escapes', + }, + ], + }, + }, + match: + "(?x)\n# Qualified namespace prefix\n( -?(?!\\d)(?:[\\w-]|[^\\x00-\\x7F]|\\\\(?:[0-9a-fA-F]{1,6}|.))+\n| \\*\n)\n# Lookahead to ensure there's a valid identifier ahead\n(?=\n \\| (?!\\s|=|$|\\])\n (?: -?(?!\\d)\n | [\\\\\\w-]\n | [^\\x00-\\x7F]\n )\n)", + }, + { + captures: { + '1': { + name: 'entity.other.attribute-name.css', + patterns: [ + { + include: '#escapes', + }, + ], + }, + }, + match: + '(?x)\n(-?(?!\\d)(?>[\\w-]|[^\\x00-\\x7F]|\\\\(?:[0-9a-fA-F]{1,6}|.))+)\n\\s*\n(?=[~|^\\]$*=]|/\\*)', + }, + ], + }, + { + include: '#pseudo-classes', + }, + { + include: '#pseudo-elements', + }, + { + include: '#functional-pseudo-classes', + }, + { + match: + '(?x) (?\\s,.\\#|){:\\[]|/\\*|$)', + name: 'entity.name.tag.css', + }, + 'unicode-range': { + captures: { + '0': { + name: 'constant.other.unicode-range.css', + }, + '1': { + name: 'punctuation.separator.dash.unicode-range.css', + }, + }, + match: '(? interface CustomLanguageDefinition { config?: Monaco.languages.LanguageConfiguration; tokens?: Monaco.languages.IMonarchLanguage; - syntax?: Record; } const addVueSupport = async () => { @@ -280,15 +279,13 @@ export const createEditor = async (options: EditorOptions): Promise setTheme(currentTheme, currentEditorTheme); }; - async function registerFromTextMate({ - name, - scopeName, - syntax, - }: { - name: string; - scopeName: string; - syntax: string; - }) { + async function registerFromTextMate( + langs: Array<{ + name: string; + scopeName: string; + syntax: string; + }>, + ) { await addVueSupport(); // a workaround for TextMate syntax const { loadWASM } = await import(onigasmUrl); @@ -298,26 +295,38 @@ export const createEditor = async (options: EditorOptions): Promise await loadWASM(onigasmWasmUrl); const registry = new Registry({ - getGrammarDefinition: async (_scopeName: string) => { + getGrammarDefinition: async (scopeName: string) => { return { format: 'json', - content: syntax, + content: langs.find((l) => l.scopeName === scopeName)?.syntax ?? '', }; }, }); const grammars = new Map(); - grammars.set(name, scopeName); - monaco.languages.register({ id: name }); + for (const { name, scopeName } of langs) { + grammars.set(name, scopeName); + monaco.languages.register({ id: name }); + } await wireTmGrammars(monaco, registry, grammars, editor); } - const addRippleSupport = async (syntax: CustomLanguageDefinition['syntax']) => { - await registerFromTextMate({ - name: 'ripple', - scopeName: 'source.ripple', - syntax: JSON.stringify(syntax, null, 2).replace('"name": "Ripple"', '"name": "ripple"'), - }); + const addRippleSupport = async (syntaxes: { + ripple: Record; + css: Record; + }) => { + await registerFromTextMate([ + { + name: 'ripple', + scopeName: 'source.ripple', + syntax: JSON.stringify(syntaxes.ripple), + }, + { + name: 'CSS', + scopeName: 'source.css', + syntax: JSON.stringify(syntaxes.css), + }, + ]); }; const loadMonacoLanguage = async (lang: Language) => { @@ -336,7 +345,7 @@ export const createEditor = async (options: EditorOptions): Promise monaco.languages.setMonarchTokensProvider(lang, mod.tokens); } if (lang === 'ripple') { - await addRippleSupport(mod.syntax); + await addRippleSupport({ ripple: (mod as any).syntax, css: (mod as any).cssSyntax }); return; } } From 085b3a30c42c72176700e97d25a7a3016c688671 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Mon, 1 Sep 2025 05:15:44 +0300 Subject: [PATCH 05/71] fix typos in ripple syntax file --- .../editor/monaco/languages/monaco-lang-ripple.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/livecodes/editor/monaco/languages/monaco-lang-ripple.ts b/src/livecodes/editor/monaco/languages/monaco-lang-ripple.ts index 30aca96d4f..b6cfdc30cc 100644 --- a/src/livecodes/editor/monaco/languages/monaco-lang-ripple.ts +++ b/src/livecodes/editor/monaco/languages/monaco-lang-ripple.ts @@ -1157,7 +1157,7 @@ export default { ], }, { - name: 'meta.paramter.array-binding-pattern.js', + name: 'meta.parameter.array-binding-pattern.js', begin: '(?]|\\|\\||\\&\\&|\\!\\=\\=|$|^|((?]|\\|\\||\\&\\&|\\!\\=\\=|$|^|((? Date: Mon, 1 Sep 2025 05:17:30 +0300 Subject: [PATCH 06/71] temporarily use latest published ripple version --- src/livecodes/vendors.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/livecodes/vendors.ts b/src/livecodes/vendors.ts index 0945e7f014..322d05d4c4 100644 --- a/src/livecodes/vendors.ts +++ b/src/livecodes/vendors.ts @@ -397,7 +397,7 @@ export const resetCssUrl = /* @__PURE__ */ getUrl('reset-css@5.0.1/reset.css'); export const riotBaseUrl = /* @__PURE__ */ getUrl('riot@9.2.2/'); -export const rippleUrl = /* @__PURE__ */ getModuleUrl('ripple@0.2.6/compiler'); +export const rippleUrl = /* @__PURE__ */ getModuleUrl('ripple/compiler'); // TODO: pin version export const rubyWasmBaseUrl = /* @__PURE__ */ getUrl('@ruby/3.3-wasm-wasi@2.6.2/dist/'); From b7a457cd7df4c8622deef0b9330fcee7c4013d68 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Mon, 1 Sep 2025 05:20:59 +0300 Subject: [PATCH 07/71] prepare for ripple formatter --- src/livecodes/languages/prettier.ts | 1 + src/livecodes/languages/ripple/lang-ripple.ts | 10 +++++----- src/sdk/models.ts | 1 + 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/livecodes/languages/prettier.ts b/src/livecodes/languages/prettier.ts index 41777117da..6639d84c21 100644 --- a/src/livecodes/languages/prettier.ts +++ b/src/livecodes/languages/prettier.ts @@ -11,4 +11,5 @@ export const parserPlugins = { php: prettierPhpUrl, pug: vendorsBaseUrl + 'prettier/parser-pug.js', java: vendorsBaseUrl + 'prettier/parser-java.js', + // ripple: vendorsBaseUrl + 'prettier/parser-ripple.js', }; diff --git a/src/livecodes/languages/ripple/lang-ripple.ts b/src/livecodes/languages/ripple/lang-ripple.ts index 8afe23152f..a33ada87c2 100644 --- a/src/livecodes/languages/ripple/lang-ripple.ts +++ b/src/livecodes/languages/ripple/lang-ripple.ts @@ -1,15 +1,15 @@ import type { LanguageSpecs } from '../../models'; import { rippleUrl } from '../../vendors'; -import { parserPlugins } from '../prettier'; +// import { parserPlugins } from '../prettier'; export const ripple: LanguageSpecs = { name: 'ripple', title: 'Ripple', info: false, - parser: { - name: 'babel-ts', - pluginUrls: [parserPlugins.babel, parserPlugins.html], - }, + // parser: { + // name: 'ripple', + // pluginUrls: [parserPlugins.ripple], + // }, compiler: { factory: async () => { // TODO: convert to UMD diff --git a/src/sdk/models.ts b/src/sdk/models.ts index 16bf986a7a..fb40a15e00 100644 --- a/src/sdk/models.ts +++ b/src/sdk/models.ts @@ -1243,6 +1243,7 @@ export type ParserName = | 'babel-ts' | 'babel-flow' | 'glimmer' + | 'ripple' | 'html' | 'markdown' | 'css' From 1dd4f750140c346343a402a9f226fcf6fe9a0cd9 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Mon, 1 Sep 2025 05:25:39 +0300 Subject: [PATCH 08/71] minor fixes --- eslint.config.mjs | 1 + src/livecodes/editor/monaco/monaco.ts | 10 ++++------ typos.toml | 1 + 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index aab8c872fb..bdb275ecf3 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -32,6 +32,7 @@ export default [ '**/.jest', '**/.storybook', 'functions/vendors', + 'src/livecodes/editor/monaco/languages/monaco-lang-ripple.ts', ], }, ...fixupConfigRules( diff --git a/src/livecodes/editor/monaco/monaco.ts b/src/livecodes/editor/monaco/monaco.ts index b3eb0bcd0c..99ca505f3b 100644 --- a/src/livecodes/editor/monaco/monaco.ts +++ b/src/livecodes/editor/monaco/monaco.ts @@ -295,12 +295,10 @@ export const createEditor = async (options: EditorOptions): Promise await loadWASM(onigasmWasmUrl); const registry = new Registry({ - getGrammarDefinition: async (scopeName: string) => { - return { - format: 'json', - content: langs.find((l) => l.scopeName === scopeName)?.syntax ?? '', - }; - }, + getGrammarDefinition: async (scopeName: string) => ({ + format: 'json', + content: langs.find((l) => l.scopeName === scopeName)?.syntax ?? '', + }), }); const grammars = new Map(); diff --git a/typos.toml b/typos.toml index 629bd22d2b..b71e8ea5b4 100644 --- a/typos.toml +++ b/typos.toml @@ -8,6 +8,7 @@ extend-exclude = [ "src/livecodes/services/google-fonts.ts", # Font name "src/livecodes/templates/starter/blockly-starter.ts", # Random string id "functions/vendors/*.js", # Built files + "src/livecodes/editor/monaco/languages/monaco-lang-ripple.ts" ] [default] From 3324ef97d1acdda5bbc566c37e7d59bf207775bd Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Mon, 1 Sep 2025 13:20:42 +0300 Subject: [PATCH 09/71] add prettier-plugin-ripple --- src/livecodes/languages/prettier.ts | 4 ++-- src/livecodes/languages/ripple/lang-ripple.ts | 10 +++++----- src/livecodes/vendors.ts | 4 ++++ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/livecodes/languages/prettier.ts b/src/livecodes/languages/prettier.ts index 6639d84c21..cd6d55457f 100644 --- a/src/livecodes/languages/prettier.ts +++ b/src/livecodes/languages/prettier.ts @@ -1,4 +1,4 @@ -import { prettierBaseUrl, prettierPhpUrl, vendorsBaseUrl } from '../vendors'; +import { prettierBaseUrl, prettierPhpUrl, prettierRippleUrl, vendorsBaseUrl } from '../vendors'; export const prettierUrl = prettierBaseUrl + 'standalone.js'; export const parserPlugins = { @@ -11,5 +11,5 @@ export const parserPlugins = { php: prettierPhpUrl, pug: vendorsBaseUrl + 'prettier/parser-pug.js', java: vendorsBaseUrl + 'prettier/parser-java.js', - // ripple: vendorsBaseUrl + 'prettier/parser-ripple.js', + ripple: prettierRippleUrl, }; diff --git a/src/livecodes/languages/ripple/lang-ripple.ts b/src/livecodes/languages/ripple/lang-ripple.ts index a33ada87c2..dab54bc9fa 100644 --- a/src/livecodes/languages/ripple/lang-ripple.ts +++ b/src/livecodes/languages/ripple/lang-ripple.ts @@ -1,15 +1,15 @@ import type { LanguageSpecs } from '../../models'; import { rippleUrl } from '../../vendors'; -// import { parserPlugins } from '../prettier'; +import { parserPlugins } from '../prettier'; export const ripple: LanguageSpecs = { name: 'ripple', title: 'Ripple', info: false, - // parser: { - // name: 'ripple', - // pluginUrls: [parserPlugins.ripple], - // }, + parser: { + name: 'ripple', + pluginUrls: [parserPlugins.ripple], + }, compiler: { factory: async () => { // TODO: convert to UMD diff --git a/src/livecodes/vendors.ts b/src/livecodes/vendors.ts index 322d05d4c4..903bbcbfea 100644 --- a/src/livecodes/vendors.ts +++ b/src/livecodes/vendors.ts @@ -343,6 +343,10 @@ export const postcssImportUrlUrl = /* @__PURE__ */ getUrl( export const prettierBaseUrl = /* @__PURE__ */ getUrl('prettier@3.3.2/'); +export const prettierRippleUrl = /* @__PURE__ */ getUrl( + '@hatemhosny/prettier-plugin-ripple@0.0.2/build/parser-ripple.js', +); + export const prettierPhpUrl = /* @__PURE__ */ getUrl('@prettier/plugin-php@0.22.2/standalone.js'); export const prismBaseUrl = /* @__PURE__ */ getUrl('prismjs@1.29.0/components/'); From a6c6cce91d0ffecdfcb0a0f154b3fb4fd1984988 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Mon, 1 Sep 2025 22:17:42 +0300 Subject: [PATCH 10/71] update ripple formatter --- src/livecodes/vendors.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/livecodes/vendors.ts b/src/livecodes/vendors.ts index 903bbcbfea..2d65cc92bb 100644 --- a/src/livecodes/vendors.ts +++ b/src/livecodes/vendors.ts @@ -344,7 +344,7 @@ export const postcssImportUrlUrl = /* @__PURE__ */ getUrl( export const prettierBaseUrl = /* @__PURE__ */ getUrl('prettier@3.3.2/'); export const prettierRippleUrl = /* @__PURE__ */ getUrl( - '@hatemhosny/prettier-plugin-ripple@0.0.2/build/parser-ripple.js', + '@hatemhosny/prettier-plugin-ripple@0.0.3/build/parser-ripple.js', ); export const prettierPhpUrl = /* @__PURE__ */ getUrl('@prettier/plugin-php@0.22.2/standalone.js'); @@ -401,7 +401,7 @@ export const resetCssUrl = /* @__PURE__ */ getUrl('reset-css@5.0.1/reset.css'); export const riotBaseUrl = /* @__PURE__ */ getUrl('riot@9.2.2/'); -export const rippleUrl = /* @__PURE__ */ getModuleUrl('ripple/compiler'); // TODO: pin version +export const rippleUrl = /* @__PURE__ */ getModuleUrl('ripple@0.2.7/compiler'); // TODO: pin version export const rubyWasmBaseUrl = /* @__PURE__ */ getUrl('@ruby/3.3-wasm-wasi@2.6.2/dist/'); From 4a8b37df9f6dd8adc762506148d730a0285d20d8 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Tue, 2 Sep 2025 22:36:42 +0300 Subject: [PATCH 11/71] add ripple basic syntax highlight for codemirror and codejar --- src/livecodes/editor/monaco/monaco.ts | 8 +++++--- src/livecodes/languages/ripple/lang-ripple.ts | 1 + src/livecodes/vendors.ts | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/livecodes/editor/monaco/monaco.ts b/src/livecodes/editor/monaco/monaco.ts index 99ca505f3b..9e32ab8c16 100644 --- a/src/livecodes/editor/monaco/monaco.ts +++ b/src/livecodes/editor/monaco/monaco.ts @@ -94,9 +94,11 @@ export const createEditor = async (options: EditorOptions): Promise ? 'csharp' : language.startsWith('vue') ? 'vue' - : ['svelte', 'malina', 'riot'].includes(language) - ? ('razor' as Language) // avoid mixing code between markup & script editors when formatting - : mapLanguage(language); + : language === 'ripple' + ? 'ripple' + : ['svelte', 'malina', 'riot'].includes(language) + ? ('razor' as Language) // avoid mixing code between markup & script editors when formatting + : mapLanguage(language); try { (window as any).monaco = (window as any).monaco || (await loadMonaco()).monaco; diff --git a/src/livecodes/languages/ripple/lang-ripple.ts b/src/livecodes/languages/ripple/lang-ripple.ts index dab54bc9fa..7ac5abff72 100644 --- a/src/livecodes/languages/ripple/lang-ripple.ts +++ b/src/livecodes/languages/ripple/lang-ripple.ts @@ -27,4 +27,5 @@ export const ripple: LanguageSpecs = { }, extensions: ['ripple'], editor: 'script', + editorLanguage: 'jsx', }; diff --git a/src/livecodes/vendors.ts b/src/livecodes/vendors.ts index 2d65cc92bb..0c9b6d6683 100644 --- a/src/livecodes/vendors.ts +++ b/src/livecodes/vendors.ts @@ -344,7 +344,7 @@ export const postcssImportUrlUrl = /* @__PURE__ */ getUrl( export const prettierBaseUrl = /* @__PURE__ */ getUrl('prettier@3.3.2/'); export const prettierRippleUrl = /* @__PURE__ */ getUrl( - '@hatemhosny/prettier-plugin-ripple@0.0.3/build/parser-ripple.js', + '@hatemhosny/prettier-plugin-ripple@0.0.5/build/parser-ripple.js', ); export const prettierPhpUrl = /* @__PURE__ */ getUrl('@prettier/plugin-php@0.22.2/standalone.js'); @@ -401,7 +401,7 @@ export const resetCssUrl = /* @__PURE__ */ getUrl('reset-css@5.0.1/reset.css'); export const riotBaseUrl = /* @__PURE__ */ getUrl('riot@9.2.2/'); -export const rippleUrl = /* @__PURE__ */ getModuleUrl('ripple@0.2.7/compiler'); // TODO: pin version +export const rippleUrl = /* @__PURE__ */ getModuleUrl('ripple@0.2.12/compiler'); // TODO: pin version export const rubyWasmBaseUrl = /* @__PURE__ */ getUrl('@ruby/3.3-wasm-wasi@2.6.2/dist/'); From 2c881771aa2b38118035b52e56e77790b6593134 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Tue, 2 Sep 2025 23:07:51 +0300 Subject: [PATCH 12/71] use a workaround till ripple formatter is fixed --- src/livecodes/formatter/format.worker.ts | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/livecodes/formatter/format.worker.ts b/src/livecodes/formatter/format.worker.ts index a6769c2bd9..0ee86a7d49 100644 --- a/src/livecodes/formatter/format.worker.ts +++ b/src/livecodes/formatter/format.worker.ts @@ -116,14 +116,20 @@ const format = async ( singleQuote: formatterConfig.singleQuote ?? defaultConfig.singleQuote, trailingComma: formatterConfig.trailingComma === false ? 'none' : 'all', }; - return ( - (await (self as any).prettier.formatWithCursor(value, { - parser: parser?.name, - plugins: prettierPlugins, - cursorOffset, - ...options, - })) || unFormatted - ); + const formatted = await (self as any).prettier.formatWithCursor(value, { + parser: parser?.name, + plugins: prettierPlugins, + cursorOffset, + ...options, + }); + + // TODO: remove when ripple plugin is fixed + if (formatted && language === 'ripple') { + formatted.formatted = formatted.formatted.replace(/,?\[object Object\],?/g, ''); + if (formatted.cursorOffset < 1) formatted.cursorOffset = 1; + } + + return formatted || unFormatted; } if (getFormatter(language) != null) { const formatFn = loadFormatter(language); From 6d65af0128dda059b210724a0f3a1d80a13efeab Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Tue, 2 Sep 2025 23:17:56 +0300 Subject: [PATCH 13/71] revert formatting workaround --- src/livecodes/formatter/format.worker.ts | 22 ++++++++-------------- src/livecodes/vendors.ts | 2 +- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/livecodes/formatter/format.worker.ts b/src/livecodes/formatter/format.worker.ts index 0ee86a7d49..a6769c2bd9 100644 --- a/src/livecodes/formatter/format.worker.ts +++ b/src/livecodes/formatter/format.worker.ts @@ -116,20 +116,14 @@ const format = async ( singleQuote: formatterConfig.singleQuote ?? defaultConfig.singleQuote, trailingComma: formatterConfig.trailingComma === false ? 'none' : 'all', }; - const formatted = await (self as any).prettier.formatWithCursor(value, { - parser: parser?.name, - plugins: prettierPlugins, - cursorOffset, - ...options, - }); - - // TODO: remove when ripple plugin is fixed - if (formatted && language === 'ripple') { - formatted.formatted = formatted.formatted.replace(/,?\[object Object\],?/g, ''); - if (formatted.cursorOffset < 1) formatted.cursorOffset = 1; - } - - return formatted || unFormatted; + return ( + (await (self as any).prettier.formatWithCursor(value, { + parser: parser?.name, + plugins: prettierPlugins, + cursorOffset, + ...options, + })) || unFormatted + ); } if (getFormatter(language) != null) { const formatFn = loadFormatter(language); diff --git a/src/livecodes/vendors.ts b/src/livecodes/vendors.ts index 0c9b6d6683..923d3e4eae 100644 --- a/src/livecodes/vendors.ts +++ b/src/livecodes/vendors.ts @@ -344,7 +344,7 @@ export const postcssImportUrlUrl = /* @__PURE__ */ getUrl( export const prettierBaseUrl = /* @__PURE__ */ getUrl('prettier@3.3.2/'); export const prettierRippleUrl = /* @__PURE__ */ getUrl( - '@hatemhosny/prettier-plugin-ripple@0.0.5/build/parser-ripple.js', + '@hatemhosny/prettier-plugin-ripple@0.0.6/build/parser-ripple.js', ); export const prettierPhpUrl = /* @__PURE__ */ getUrl('@prettier/plugin-php@0.22.2/standalone.js'); From 813cbdd3ff4faeff5df842a7a8a5441b6fc29b61 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Wed, 3 Sep 2025 01:20:16 +0300 Subject: [PATCH 14/71] add postFormat to parsers --- src/livecodes/formatter/format.worker.ts | 18 ++++++++++-------- src/livecodes/languages/ripple/lang-ripple.ts | 4 ++++ src/livecodes/vendors.ts | 2 +- src/sdk/models.ts | 4 ++++ 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/livecodes/formatter/format.worker.ts b/src/livecodes/formatter/format.worker.ts index a6769c2bd9..d15e04adb5 100644 --- a/src/livecodes/formatter/format.worker.ts +++ b/src/livecodes/formatter/format.worker.ts @@ -116,14 +116,16 @@ const format = async ( singleQuote: formatterConfig.singleQuote ?? defaultConfig.singleQuote, trailingComma: formatterConfig.trailingComma === false ? 'none' : 'all', }; - return ( - (await (self as any).prettier.formatWithCursor(value, { - parser: parser?.name, - plugins: prettierPlugins, - cursorOffset, - ...options, - })) || unFormatted - ); + let formatted = await (self as any).prettier.formatWithCursor(value, { + parser: parser?.name, + plugins: prettierPlugins, + cursorOffset, + ...options, + }); + if (typeof parser?.postFormat === 'function') { + formatted = await parser.postFormat(formatted); + } + return formatted || unFormatted; } if (getFormatter(language) != null) { const formatFn = loadFormatter(language); diff --git a/src/livecodes/languages/ripple/lang-ripple.ts b/src/livecodes/languages/ripple/lang-ripple.ts index 7ac5abff72..d59a7a4fd7 100644 --- a/src/livecodes/languages/ripple/lang-ripple.ts +++ b/src/livecodes/languages/ripple/lang-ripple.ts @@ -9,6 +9,10 @@ export const ripple: LanguageSpecs = { parser: { name: 'ripple', pluginUrls: [parserPlugins.ripple], + postFormat: async (parsed: { formatted: string; cursorOffset: number }) => ({ + formatted: parsed.formatted.replace(/,?\[object Object\],?/g, ''), + cursorOffset: parsed.cursorOffset, + }), }, compiler: { factory: async () => { diff --git a/src/livecodes/vendors.ts b/src/livecodes/vendors.ts index 923d3e4eae..0c9b6d6683 100644 --- a/src/livecodes/vendors.ts +++ b/src/livecodes/vendors.ts @@ -344,7 +344,7 @@ export const postcssImportUrlUrl = /* @__PURE__ */ getUrl( export const prettierBaseUrl = /* @__PURE__ */ getUrl('prettier@3.3.2/'); export const prettierRippleUrl = /* @__PURE__ */ getUrl( - '@hatemhosny/prettier-plugin-ripple@0.0.6/build/parser-ripple.js', + '@hatemhosny/prettier-plugin-ripple@0.0.5/build/parser-ripple.js', ); export const prettierPhpUrl = /* @__PURE__ */ getUrl('@prettier/plugin-php@0.22.2/standalone.js'); diff --git a/src/sdk/models.ts b/src/sdk/models.ts index fb40a15e00..40f8abe05d 100644 --- a/src/sdk/models.ts +++ b/src/sdk/models.ts @@ -1257,6 +1257,10 @@ export interface Parser { name: ParserName; plugins?: any[]; pluginUrls: string[]; + postFormat?: (parsed: { + formatted: string; + cursorOffset: number; + }) => Promise<{ formatted: string; cursorOffset: number }>; } export type FormatFn = ( value: string, From db6a6703a37a601a8290c54bdffb4f1b55a7e873 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Wed, 3 Sep 2025 01:24:12 +0300 Subject: [PATCH 15/71] edit --- src/livecodes/languages/ripple/lang-ripple.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/livecodes/languages/ripple/lang-ripple.ts b/src/livecodes/languages/ripple/lang-ripple.ts index d59a7a4fd7..2b38132bc6 100644 --- a/src/livecodes/languages/ripple/lang-ripple.ts +++ b/src/livecodes/languages/ripple/lang-ripple.ts @@ -9,10 +9,14 @@ export const ripple: LanguageSpecs = { parser: { name: 'ripple', pluginUrls: [parserPlugins.ripple], - postFormat: async (parsed: { formatted: string; cursorOffset: number }) => ({ - formatted: parsed.formatted.replace(/,?\[object Object\],?/g, ''), - cursorOffset: parsed.cursorOffset, - }), + postFormat: async (parsed: { formatted: string; cursorOffset: number }) => { + let formatted = parsed.formatted.replace(/,?\[object Object\],?/g, ''); + if (!formatted.endsWith('\n')) formatted += '\n'; + return { + formatted, + cursorOffset: parsed.cursorOffset, + }; + }, }, compiler: { factory: async () => { From 24df4245924f026da83e88c04e58137f714681ee Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Wed, 3 Sep 2025 01:27:48 +0300 Subject: [PATCH 16/71] add a todo comment --- src/livecodes/languages/ripple/lang-ripple.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/livecodes/languages/ripple/lang-ripple.ts b/src/livecodes/languages/ripple/lang-ripple.ts index 2b38132bc6..78a538945f 100644 --- a/src/livecodes/languages/ripple/lang-ripple.ts +++ b/src/livecodes/languages/ripple/lang-ripple.ts @@ -9,6 +9,7 @@ export const ripple: LanguageSpecs = { parser: { name: 'ripple', pluginUrls: [parserPlugins.ripple], + // TODO: remove this after fixing the prettier plugin postFormat: async (parsed: { formatted: string; cursorOffset: number }) => { let formatted = parsed.formatted.replace(/,?\[object Object\],?/g, ''); if (!formatted.endsWith('\n')) formatted += '\n'; From f3702a7561b22700a75652e52f85b52fe736d309 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Thu, 4 Sep 2025 04:19:41 +0300 Subject: [PATCH 17/71] update ripple formatter and remove workaround --- src/livecodes/languages/ripple/lang-ripple.ts | 9 --------- src/livecodes/vendors.ts | 2 +- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/src/livecodes/languages/ripple/lang-ripple.ts b/src/livecodes/languages/ripple/lang-ripple.ts index 78a538945f..7ac5abff72 100644 --- a/src/livecodes/languages/ripple/lang-ripple.ts +++ b/src/livecodes/languages/ripple/lang-ripple.ts @@ -9,15 +9,6 @@ export const ripple: LanguageSpecs = { parser: { name: 'ripple', pluginUrls: [parserPlugins.ripple], - // TODO: remove this after fixing the prettier plugin - postFormat: async (parsed: { formatted: string; cursorOffset: number }) => { - let formatted = parsed.formatted.replace(/,?\[object Object\],?/g, ''); - if (!formatted.endsWith('\n')) formatted += '\n'; - return { - formatted, - cursorOffset: parsed.cursorOffset, - }; - }, }, compiler: { factory: async () => { diff --git a/src/livecodes/vendors.ts b/src/livecodes/vendors.ts index 0c9b6d6683..6ae1b372bc 100644 --- a/src/livecodes/vendors.ts +++ b/src/livecodes/vendors.ts @@ -344,7 +344,7 @@ export const postcssImportUrlUrl = /* @__PURE__ */ getUrl( export const prettierBaseUrl = /* @__PURE__ */ getUrl('prettier@3.3.2/'); export const prettierRippleUrl = /* @__PURE__ */ getUrl( - '@hatemhosny/prettier-plugin-ripple@0.0.5/build/parser-ripple.js', + '@hatemhosny/prettier-plugin-ripple@0.0.7/build/parser-ripple.js', ); export const prettierPhpUrl = /* @__PURE__ */ getUrl('@prettier/plugin-php@0.22.2/standalone.js'); From 28387b9d9b1a669e2e1a59245a6fc51cb641ab35 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Fri, 5 Sep 2025 00:13:17 +0300 Subject: [PATCH 18/71] allow changing ripple compiler version --- scripts/build.js | 1 + .../languages/ripple/lang-ripple-compiler.ts | 46 +++++++++++++++++++ src/livecodes/languages/ripple/lang-ripple.ts | 16 ++----- src/livecodes/vendors.ts | 2 - 4 files changed, 50 insertions(+), 15 deletions(-) create mode 100644 src/livecodes/languages/ripple/lang-ripple-compiler.ts diff --git a/scripts/build.js b/scripts/build.js index 2b9d0550a5..e668ebe84e 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -237,6 +237,7 @@ const iifeBuild = () => 'languages/python-wasm/lang-python-wasm-script.ts', 'languages/rescript/lang-rescript-formatter.ts', 'languages/riot/lang-riot-compiler.ts', + 'languages/ripple/lang-ripple-compiler.ts', 'languages/ruby-wasm/lang-ruby-wasm-script.ts', 'languages/scss/lang-scss-compiler.ts', 'languages/solid/lang-solid-compiler.ts', diff --git a/src/livecodes/languages/ripple/lang-ripple-compiler.ts b/src/livecodes/languages/ripple/lang-ripple-compiler.ts new file mode 100644 index 0000000000..440617ab13 --- /dev/null +++ b/src/livecodes/languages/ripple/lang-ripple-compiler.ts @@ -0,0 +1,46 @@ +import type { CompilerFunction, Config } from '../../models'; +import { modulesService } from '../../services/modules'; + +(self as any).createRippleCompiler = async (initialConfig: Config): Promise => { + let version = initialConfig.customSettings.ripple?.version || 'latest'; + let compile: (code: string, filename: string) => Promise<{ js: { code: string }; css: string }>; + + const updateCompiler = async (currentVersion: string) => { + if (typeof compile === 'function' && currentVersion === version) return; + const mod = await import( + /* @__PURE__ */ modulesService.getModuleUrl(`ripple@${currentVersion}/compiler`) + ); + compile = mod.compile; + version = currentVersion; + }; + + return async (code, { config }) => { + if (!code.trim()) return ''; + + const newVersion = config.customSettings.ripple?.version || version; + await updateCompiler(newVersion); + + const { js, css } = await compile(code, './App.ripple'); + + const cssCode = + css === '' + ? '' + : `\n +const styles = document.createElement('style'); +styles.innerHTML = ${JSON.stringify(css)}; +document.head.appendChild(styles); +`; + + const moduleUrl = /* @__PURE__ */ modulesService.getModuleUrl(`ripple@${version}`); + return { + code: `${js.code}${cssCode}`, + info: { + imports: { + ripple: moduleUrl, + 'ripple/internal': `${moduleUrl}/internal`, + 'ripple/internal/client': `${moduleUrl}/internal/client`, + }, + }, + }; + }; +}; diff --git a/src/livecodes/languages/ripple/lang-ripple.ts b/src/livecodes/languages/ripple/lang-ripple.ts index 7ac5abff72..9aacc74937 100644 --- a/src/livecodes/languages/ripple/lang-ripple.ts +++ b/src/livecodes/languages/ripple/lang-ripple.ts @@ -1,5 +1,4 @@ import type { LanguageSpecs } from '../../models'; -import { rippleUrl } from '../../vendors'; import { parserPlugins } from '../prettier'; export const ripple: LanguageSpecs = { @@ -11,18 +10,9 @@ export const ripple: LanguageSpecs = { pluginUrls: [parserPlugins.ripple], }, compiler: { - factory: async () => { - // TODO: convert to UMD - const { compile } = await import(rippleUrl); - return async (code) => { - if (!code.trim()) return ''; - const { js, css } = await compile(code, './src/App.ripple'); - const cssCode = - css === '' - ? '' - : `\n\nconst styles = document.createElement('style');\nstyles.innerHTML = ${JSON.stringify(css)};\ndocument.head.appendChild(styles);\n`; - return `${js.code}${cssCode}`; - }; + factory: (config, baseUrl) => { + (self as any).importScripts(baseUrl + '{{hash:lang-ripple-compiler.js}}'); + return (self as any).createRippleCompiler(config); }, }, extensions: ['ripple'], diff --git a/src/livecodes/vendors.ts b/src/livecodes/vendors.ts index 6ae1b372bc..c44a9dbda4 100644 --- a/src/livecodes/vendors.ts +++ b/src/livecodes/vendors.ts @@ -401,8 +401,6 @@ export const resetCssUrl = /* @__PURE__ */ getUrl('reset-css@5.0.1/reset.css'); export const riotBaseUrl = /* @__PURE__ */ getUrl('riot@9.2.2/'); -export const rippleUrl = /* @__PURE__ */ getModuleUrl('ripple@0.2.12/compiler'); // TODO: pin version - export const rubyWasmBaseUrl = /* @__PURE__ */ getUrl('@ruby/3.3-wasm-wasi@2.6.2/dist/'); export const rubyWasmScriptUrl = /* @__PURE__ */ getUrl( From 20f8def115a88fd5520672d4b32537c75ff3bd6c Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Fri, 5 Sep 2025 04:44:18 +0300 Subject: [PATCH 19/71] add ripple starter template --- src/livecodes/assets/templates/ripple-0.png | Bin 0 -> 4040 bytes .../i18n/locales/en/translation.lokalise.json | 4 ++ src/livecodes/i18n/locales/en/translation.ts | 1 + src/livecodes/templates/starter/index.ts | 2 + .../templates/starter/ripple-starter.ts | 46 ++++++++++++++++++ src/sdk/models.ts | 1 + 6 files changed, 54 insertions(+) create mode 100644 src/livecodes/assets/templates/ripple-0.png create mode 100644 src/livecodes/templates/starter/ripple-starter.ts diff --git a/src/livecodes/assets/templates/ripple-0.png b/src/livecodes/assets/templates/ripple-0.png new file mode 100644 index 0000000000000000000000000000000000000000..5b30ea52ad417ca0f4d6360f18d770992de46277 GIT binary patch literal 4040 zcmai1cQhMN+ox(3Q7cv|Rija{SCm*mjM}jkQEgL7h1M);2B}R|&Cr@vl&GS1#OSa` zYgE*%)@Va(e(CxCd(U~#`^UY{dG2%1xzD}l+}}vFG)Hor6FNsnN5^4oq;E}&INEs5 z!bF?jEx`P9?GNS-Z&u^Xt$D0=sGZrXWn9V?_kR$yOl$&Y3N#x}_g zsX=^{l=V6(;iW-3-5D;UgqLVH#Kl-0mZ&;$=nMj=xA6AYTH_OB=GNSshdW2N+S7y1 zEa{x6Z_NgLgqJ4<*_?iHf7<%BmD=dC+N|D;_>QT6FoSoym;{M?vl zVzjxUx;1%p)OtrsR;r8YJ%y!yRzca@OBV?(+r(8>dCj&tN)_H)2>j{GQb|cjOzb-# zRxeU^zXv;ys1?Op1yiqlEb4gFpne-Gd6}7%1>r(* zad8m2+B#}Ad19{T`wi+;%bhPx91%(@e+`8LU`eg58hQwXyq`{_crSUWi@Bw9u7^QI zMaATyzfJGuz*rJmaejV&ZMvR;65m@KwvYR|L8%H(^G88kpO-b+9beyjL_%}<`ubun zh@?~?nM5yL(%ZRcd&ykX!Xw9?1K;DJnKi{0l2Hg3TU=U7_8#16Zf+JJ5+_$J96+j~ zoeSW1q5FCmqdNa8DLq|u)H2yk%Wj(Go}8TK&L5*|`F}*>IZSmLZhaW9bzs2v+_DrZ zUg!zmnao>~_h=@bL1U+RlXT~UmsG^X+2e|eYQ0qWfw<&#LBYf+w{XW`ZVL;G2`>>S zAaAVP;$9nUFKF#~KBi*BN79;Pg+e_Cb!}$%V*?>f#zqO`fKntO#4^oGg}IWLefZNm zzOu+d_muwl>*7y>(-uG?>I?%zueuwjgoFe{M!M(6)fgV+;QDOO+y&Rc#F9H>Wo4(l ztE+CkU$)wCSy`xbh!R63<>IB!ZxC+F7mTT~VO+B%j1i}!4zaj5)-owOV-~{c`L6}D znNDM@R^nr?Q81J5IqB)?Sy)*O9ULllgIJIlqlCq1$2YR9JdzQQW@iJcNDj~OrS11O zhv`j$a_6ax@N2odjAdp;qM8YgY1Nmb8ZFP7Gpd-x1Z|9S!9(wpV>mT0-Zd0IQ>o^8 zCw@EhdT$7eBd_$QRXZ0QaA-%8?=hU)8#Latvu zu>vgAjL`wgmpJ^+aZ>hZ^vYySkHNP0{mCp6TAnvGUprF7G)IP9_KjC+-vxryFYs({ z@0)aS07>eId>gN{amZ~J5)>rcR%?j}DjW5J4ZA7wtX`Mqvzwg7H$6RJ&P1=cK%Xxx zavr=;0MFZqC8oe1^J1^0)<|=69CNKfO3FXou}@h@;PrKK-D#(;lv!`qmOEDY(z$cz zNM_B^-Fg!g7%F;uyE%x%ly>V(!q{N$m^v&>)t(45*VhkQrh2%P(VC?X864SjaV3gtVJ+RFnB;#FMem2kDvRjz zta;3Yb}osflkcqp%=d46&5<0(>^ zL~gYzrf@pFbiE9E#vQvB>(7rS5E4>SxDRh=9sN4|GZq_^{q>h%(j1t^4 z_bSgaGIl$wrwe?DWBVJtI>%}hxT4}pHFyGx;24IcM!tWVoZD~)Ja5mm^7iW&@NNF9#41F;Br9D2Sf>jBLGkN}rV@+~L!rRR@ELYoC^|TqSo< zkR zdAZ(qF7&AFX7#k1DO@m1=#4ZK5JNb3#nvWh(+JVG!;^H;H(|7OX2u-(btM2?7vh$@l-q<^;Mfri$>A32k+Ax6Zj%;u*~ zm9MI}iMWgm>&haRWxl%L0Y&O51vbt%S$^-Hrq-?k;tf)mo(vKimUi!Z>}ai-QB*7E zaf4Y*QqqYCV}_=L>2!VTHZUE(9IiQDBTW+s-Cu@GiPK;p8D3HIE-qJT6;hkaO#?yY zoETYE^~`;D>@34M$y#1s_n-E^P=76eqkjA6l%9AfVaQB5 z8jW$uM^Ev4c2g>tvsMaKyi>9?4ag}Mc%$?ePY&~{frtMp_o;p(lozl7NhA>lkYP#T zt|z# z0>WU2MS=8f3StI;#w(kAE&>f z43W1aI&k6<%*xF^e|NVGR-d}|htY)9jkPatQhl!WIe@Mfn;9z~U=LFYstmx_TkiLz zi7K!FSnXscyD7s1+0u*-Zxy*n+_G9WZCqe&-glS8NY`wt(b%oNQj~?4wvbK+Y1#tZzip z2+=rg{}1*@sDhm?lR^x0seNtX_FmJ+usWEy?wkjX6KpUVpKNU?)ri4%_%~jt3{Lf% z@X&$+5{CgKocY3RXMM6py01eW zAcjmiU!NeTw&F4eZ_~1i^tpn17I9E{IlJgwxIx+f3#=k3jZZ>nvVX51BH==czHib6 zoQQW5%`a$_AaDT8yrxl`Kcv)Ti1Ci@u$*>mp{sp)(WcVPLH?(z;qh5{+pk$!S-XUn zTuIGSZrP!qD_*uG;&WsvyDy|6vQmaVW->qb%v|1ua@ZZERcNVz_CQQ}cOD!Jl+Az? zErfs4{0BSB`PQBFpFXP}3x=0vi(cB4*ZF(_P%TtIDeCO8l;j>;roqoJ#zj@!UdFS%_vghV=?)Lig^1Xu04F^q;QEwSE@XZlVs) z*9tczeg*?^#=}3FKjhh@H+vDs+FWT{^rj$ETRK5LA@W+k+{UG9`Grmt@6D?j9f#n5 z+$J=@uEjHTfMCHaZV~DioSS?bh&nWE)?rl`+=w_>_Y{}#(Xq{j^LWxU$Hk~&nd3z8 z!&t|L)dV1-l?M1}Ld$%ad3ku_Ol|Ts|LH|@MMd9_1Ko;P)D)_;c)RN0_xCstfY6eT zce`uEO;F(lIFk~eMMi)sKk=%Ca;Wsg6Wg2B)zy|LmsnT0m_gi#)uv0f56k@w!aQ5c zzFzjYgy|FX@qxIfrzeYZ{cdtu?LzzY%f5>?MEmMRT=aZ_M$qChr`9;%Cx^*Ty2Eb6 z*Z<;GvDmiiL{;H_*TtLsYk85#v$B+hih&MB0s$Y15UFf&TCmhGC3Q^;1B?X!n;rch dZk6tYu~W=+?8O+CX1?j@j1A27U+K9={~xCjifI4< literal 0 HcmV?d00001 diff --git a/src/livecodes/i18n/locales/en/translation.lokalise.json b/src/livecodes/i18n/locales/en/translation.lokalise.json index d6d83d19e2..4221722691 100644 --- a/src/livecodes/i18n/locales/en/translation.lokalise.json +++ b/src/livecodes/i18n/locales/en/translation.lokalise.json @@ -2744,6 +2744,10 @@ "notes": "", "translation": "Riot.js Starter" }, + "templates.starter.ripple": { + "notes": "", + "translation": "Ripple Starter" + }, "templates.starter.ruby": { "notes": "", "translation": "Ruby Starter" diff --git a/src/livecodes/i18n/locales/en/translation.ts b/src/livecodes/i18n/locales/en/translation.ts index 7346431e9b..a3246661af 100644 --- a/src/livecodes/i18n/locales/en/translation.ts +++ b/src/livecodes/i18n/locales/en/translation.ts @@ -1032,6 +1032,7 @@ const translation = { reason: 'Reason Starter', rescript: 'ReScript Starter', riot: 'Riot.js Starter', + ripple: 'Ripple Starter', ruby: 'Ruby Starter', 'ruby-wasm': 'Ruby (Wasm) Starter', scheme: 'Scheme Starter', diff --git a/src/livecodes/templates/starter/index.ts b/src/livecodes/templates/starter/index.ts index 1075d26834..032067f703 100644 --- a/src/livecodes/templates/starter/index.ts +++ b/src/livecodes/templates/starter/index.ts @@ -52,6 +52,7 @@ import { reactStarter } from './react-starter'; import { reasonStarter } from './reason-starter'; import { rescriptStarter } from './rescript-starter'; import { riotStarter } from './riot-starter'; +import { rippleStarter } from './ripple-starter'; import { rubyStarter } from './ruby-starter'; import { rubyWasmStarter } from './ruby-wasm-starter'; import { schemeStarter } from './scheme-starter'; @@ -79,6 +80,7 @@ export const starterTemplates = [ preactStarter, svelteStarter, solidStarter, + rippleStarter, litStarter, stencilStarter, mdxStarter, diff --git a/src/livecodes/templates/starter/ripple-starter.ts b/src/livecodes/templates/starter/ripple-starter.ts new file mode 100644 index 0000000000..07f5124b90 --- /dev/null +++ b/src/livecodes/templates/starter/ripple-starter.ts @@ -0,0 +1,46 @@ +import type { Template } from '../../models'; + +export const rippleStarter: Template = { + name: 'ripple', + title: window.deps.translateString('templates.starter.ripple', 'Ripple Starter'), + thumbnail: 'assets/templates/ripple-0.png', + activeEditor: 'script', + markup: { + language: 'html', + content: '', + }, + style: { + language: 'css', + content: '', + }, + script: { + language: 'ripple', + content: ` +component Counter(props: { $name: string }) { +
+

{\`Hello, \${props.\$name}!\`}

+ + + let \$count = 0; +

{\`You clicked \${\$count} times.\`}

+ +
+ + +} + +export default component App() { + +} +`.trimStart(), + }, +}; diff --git a/src/sdk/models.ts b/src/sdk/models.ts index 40f8abe05d..c465302332 100644 --- a/src/sdk/models.ts +++ b/src/sdk/models.ts @@ -1391,6 +1391,7 @@ export type TemplateName = | 'preact' | 'svelte' | 'solid' + | 'ripple' | 'lit' | 'stencil' | 'mdx' From 20a473d0e2a90774bd9a364dc83becaf84453577 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Fri, 5 Sep 2025 18:43:27 +0300 Subject: [PATCH 20/71] compile styles in ripple components --- src/livecodes/languages/ripple/lang-ripple-compiler.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/livecodes/languages/ripple/lang-ripple-compiler.ts b/src/livecodes/languages/ripple/lang-ripple-compiler.ts index 440617ab13..07c16f507a 100644 --- a/src/livecodes/languages/ripple/lang-ripple-compiler.ts +++ b/src/livecodes/languages/ripple/lang-ripple-compiler.ts @@ -1,6 +1,9 @@ +import { compileBlocks } from '../../compiler'; import type { CompilerFunction, Config } from '../../models'; import { modulesService } from '../../services/modules'; +// TODO: recursively compile imported Ripple components + (self as any).createRippleCompiler = async (initialConfig: Config): Promise => { let version = initialConfig.customSettings.ripple?.version || 'latest'; let compile: (code: string, filename: string) => Promise<{ js: { code: string }; css: string }>; @@ -20,6 +23,8 @@ import { modulesService } from '../../services/modules'; const newVersion = config.customSettings.ripple?.version || version; await updateCompiler(newVersion); + code = await compileBlocks(code, 'style', config); + const { js, css } = await compile(code, './App.ripple'); const cssCode = From ffffb1a60defcda3328c289738247f417256a3de Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Fri, 5 Sep 2025 18:43:48 +0300 Subject: [PATCH 21/71] add docs for ripple support --- docs/docs/languages/ripple.mdx | 401 ++++++++++++++++++ docs/src/components/LanguageSliders.tsx | 1 + docs/src/components/TemplateList.tsx | 1 + src/livecodes/UI/command-menu-actions.ts | 1 + src/livecodes/templates/starter/index.ts | 2 +- .../templates/starter/ripple-starter.ts | 2 +- 6 files changed, 406 insertions(+), 2 deletions(-) create mode 100644 docs/docs/languages/ripple.mdx diff --git a/docs/docs/languages/ripple.mdx b/docs/docs/languages/ripple.mdx new file mode 100644 index 0000000000..93bfe5315a --- /dev/null +++ b/docs/docs/languages/ripple.mdx @@ -0,0 +1,401 @@ +--- +toc_max_heading_level: 4 +--- + +# Ripple + +[Ripple](https://www.ripplejs.com/) is a TypeScript UI framework that takes the best parts of React, Solid and Svelte and combines them into one package. + +## Usage + +Ripple components can be used in LiveCodes as documented in the [Ripple docs](https://github.com/trueadm/ripple). See below for usage. + +### Demo + +import LiveCodes from '../../src/components/LiveCodes.tsx'; +import RunInLiveCodes from '../../src/components/RunInLiveCodes.tsx'; + +export const demo = { + activeEditor: 'script', + script: { + language: 'ripple', + content: ` export default component Counter() { + let \$count = 0; + let \$doubled = \$count * 2; + +
+

{'Counter'}

+

{\`Count: \${\$count}\`}

+

{\`Doubled: \${\$doubled}\`}

+ + + +
+ + + }`, + }, +} + + + +### Auto-rendering + +A component is mounted and rendered automatically as a Ripple component (without having to [manually mount](#manual-mount) it) if the following conditions are met: + +- The component is exported as the default export. +- No [imports from `"./script"`](#exports) in markup editor. +- Auto-rendering is not [disabled](#disabling-auto-rendering). + +### Root Element + +To mount the application instance to a specific DOM element use `"livecodes-app"` as the element `id` in the HTML. Otherwise, if that element is not found, a new `div` element is added to `document.body` and is used to mount the instance. + +Example: + +export const customRoot = { + markup: { + language: 'html', + content: `

Custom Root Element

+
+
...other page content
+`, + }, + script: { + language: 'ripple', + content: `export default component App() { + let \$name = 'Ripple'; +
{\`I'm a \${\$name} component\`}
+ +} +`, + }, +}; + + + + +### Manual Mount + +Exports from Ripple code can be imported in [markup editor](../features/projects.mdx#markup-editor) from `"./script"` and used to mount the application instance manually. +See [Exports](#exports) for details. + +Example: + +export const manualMount = { + markup: { + language: 'html', + content: `

Manual Mount

+
+
...other page content
+ + +`, + }, + script: { + language: 'ripple', + content: `export component App(props: { name: string }) { +
{\`I'm a \${props.name} component\`}
+ +} +`, + }, +}; + + + +### Disabling Auto-rendering + +To disable [auto-rendering](#auto-rendering), set the [custom settings](#custom-settings) `disableAutoRender` property to `true`. + +```json title="Custom Settings" +{ + "ripple": { + "disableAutoRender": true + } +} +``` + +### Module Imports + +npm modules can be imported as described in the section about [module resolution](../features/module-resolution.mdx), including bare module imports and importing from different CDNs. Stylesheets imported in the `script` block are added as `` tags in the page `head`. + +Module imports can be customized using import maps as described in [module resolution](../features/module-resolution.mdx#custom-module-resolution) documentations. + +Example: + +export const importsDemo = { + ripple: `import { effect } from "ripple"; +import confetti from "canvas-confetti"; + +export default component App() { +
+ let $count = 0; + + effect(() => { + if ($count === 2) confetti(); + }); + + + + if ($count > 1) { +
{'Greater than 1!'}
+ } +
+ + +} +`, +}; + + + + +{/* +### Importing External Components + +External Svelte components can be imported. The import URL has to be an absolute URL ending with `.svelte` extension. Any bare or relative imports in the imported files are resolved and compiled recursively. + +Example: + +```html + + + +``` + */} + +### Exports + +Values exported from [script editor](../features/projects.mdx#script-editor) (default or named) can be imported in the [markup editor](../features/projects.mdx#markup-editor) by importing from `"./script"` (with no extension). + +This can be useful, for example, for [manually mounting](#manual-mount) components in the markup editor. + +:::info note + +When values are imported from `"./script"`, [auto-rendering](#auto-rendering) is disabled, because it is assumed that you want to take control over component rendering. + +::: + +### Styles + +CSS can be applied to the component using various ways: + +#### Component Styles + +Styles in a `style` tag in a Ripple component are applied to that component only. + +CSS processors (e.g. SCSS, Stylus) can be used by specifying a `lang` attribute for the `style` tag. + +Example: + +export const styleTag = { + ripple: `export default component App() { +

{'Hello World!'}

+ + +} +` +} + + + + +#### Style Editor + +Styles added in the [style editor](../features/projects.mdx#style-editor) are applied globally to the [result page](../features/result.mdx). This can use different **languages/processors** supported in LiveCodes including CSS, SCSS, Less, Stylus, ..etc. See [style documentation](../features/css.mdx) for more details. + +And of course, styles and stylesheets added in [markup editor](../features/projects.mdx#markup-editor) are also applied globally. + +#### Importing Stylesheets + +Stylesheets imported in [script editor](../features/projects.mdx#script-editor) are added as `` tags in the page `head`. +The stylesheet URL can be an absolute URL or a path in the npm package. The URL has to end with `".css"`. + +example: + +export const stylesDemo = { + ripple: `import "bootstrap/dist/css/bootstrap.css";\n\nexport default component App() {\n

{'Hello World!'}

\n}\n`, +}; + + + +#### CSS Modules + +CSS modules are supported and are [documented separately](./cssmodules.mdx). Make sure to enable CSS modules (from style editor menu or in [`processors`](../configuration/configuration-object.mdx#processors) property of [configuration object](../configuration/configuration-object.mdx)). + +Demo: + +export const cssModulesDemo = { + activeEditor: 'script', + style: { language: 'css', content: `.title {\n color: green;\n font-family: sans-serif;\n}\n` }, + script: { + language: 'ripple', + content: `import classes from './style.module.css';\n\nexport default component() {\n

\n {'Hello, CSS Modules!'}\n

\n}\n`, + }, + processors: ['cssmodules'], +}; + + + +#### CSS Frameworks + +[CSS Frameworks](../features/css.mdx#css-processors) supported in LiveCodes (e.g. [Tailwind CSS](./tailwindcss.mdx), [UnoCSS](./unocss.mdx), [WindiCSS](./windicss.mdx)) can detect class names added in Ripple components. +Make sure that the required utility is enabled (from style editor menu or in `processors` property of [configuration object](../configuration/configuration-object.mdx#processors)). + +Example: + +export const tailwindDemo = { + activeEditor: 'script', + script: { + language: 'ripple', + content: `export default component Counter() { + let $count = 0; + +
+

{'Ripple + Tailwind CSS'}

+
+ + {$count} + +
+ +
+} +`, + }, + processors: ['tailwindcss'], +}; + + + +## Language Info + +### Name + +`ripple` + +### Extensions + +`.ripple` + +### Editor + +`script` + +## Compiler + +The official [Ripple compiler](https://github.com/trueadm/ripple). + +### Version + +`ripple`: v0.2.15 + +## Code Formatting + +Using [Prettier](https://prettier.io/). + +## Custom Settings + +[Custom settings](../advanced/custom-settings.mdx) can be added to the property `ripple`. +These include: + +- `"disableAutoRender"` - [disables auto-rendering](#disabling-auto-rendering) (default: `false`). +- `"version"` - specifies the version of Ripple compiler (default: `"latest"`). + +Example: + +```json title="Custom Settings" +{ + "ripple": { + "version": "0.2.15" + } +} +``` + +Please note that custom settings should be valid JSON (i.e. functions are not allowed). + +## Starter Template + +https://livecodes.io/?template=ripple + + + +## Links + +- [Ripple](https://ripplejs.com/) +- [Ripple documentations](https://github.com/trueadm/ripple) diff --git a/docs/src/components/LanguageSliders.tsx b/docs/src/components/LanguageSliders.tsx index e1daff5ac6..9c51edf216 100644 --- a/docs/src/components/LanguageSliders.tsx +++ b/docs/src/components/LanguageSliders.tsx @@ -69,6 +69,7 @@ export default function Sliders() { { name: 'solid.tsx', title: 'Solid (TS)' }, { name: 'riot', title: 'Riot.js' }, { name: 'malina', title: 'Malina.js' }, + { name: 'ripple', title: 'Ripple' }, { name: 'coffeescript', title: 'CoffeeScript' }, { name: 'livescript', title: 'LiveScript' }, { name: 'civet', title: 'Civet' }, diff --git a/docs/src/components/TemplateList.tsx b/docs/src/components/TemplateList.tsx index 126f377f72..e38688d7b8 100644 --- a/docs/src/components/TemplateList.tsx +++ b/docs/src/components/TemplateList.tsx @@ -23,6 +23,7 @@ const templates = [ { name: 'astro', title: 'Astro Starter', thumbnail: 'astro.svg' }, { name: 'riot', title: 'Riot.js Starter', thumbnail: 'riot.svg' }, { name: 'malina', title: 'Malina.js Starter', thumbnail: 'malina.svg' }, + { name: 'ripple', title: 'Ripple Starter', thumbnail: 'malina.svg' }, { name: 'jquery', title: 'jQuery Starter', thumbnail: 'jquery.svg' }, { name: 'backbone', title: 'Backbone Starter', thumbnail: 'backbone.svg' }, { name: 'knockout', title: 'Knockout Starter', thumbnail: 'knockout.svg' }, diff --git a/src/livecodes/UI/command-menu-actions.ts b/src/livecodes/UI/command-menu-actions.ts index d42de5ca55..fbed0aeb33 100644 --- a/src/livecodes/UI/command-menu-actions.ts +++ b/src/livecodes/UI/command-menu-actions.ts @@ -266,6 +266,7 @@ export const getCommandMenuActions = ({ 'preact', 'svelte', 'solid', + 'ripple', 'lit', 'stencil', 'mdx', diff --git a/src/livecodes/templates/starter/index.ts b/src/livecodes/templates/starter/index.ts index 032067f703..e6d68ed7fb 100644 --- a/src/livecodes/templates/starter/index.ts +++ b/src/livecodes/templates/starter/index.ts @@ -80,7 +80,6 @@ export const starterTemplates = [ preactStarter, svelteStarter, solidStarter, - rippleStarter, litStarter, stencilStarter, mdxStarter, @@ -91,6 +90,7 @@ export const starterTemplates = [ astroStarter, riotStarter, malinaStarter, + rippleStarter, jqueryStarter, backboneStarter, knockoutStarter, diff --git a/src/livecodes/templates/starter/ripple-starter.ts b/src/livecodes/templates/starter/ripple-starter.ts index 07f5124b90..a74074c592 100644 --- a/src/livecodes/templates/starter/ripple-starter.ts +++ b/src/livecodes/templates/starter/ripple-starter.ts @@ -33,7 +33,7 @@ component Counter(props: { $name: string }) { font: 1em sans-serif; } .logo { - width: 150px; + width: 100px; } } From dfe070296804ee4292f8d87d12eb37ed5980ef77 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Fri, 5 Sep 2025 18:52:52 +0300 Subject: [PATCH 22/71] fix --- src/livecodes/languages/ripple/lang-ripple-compiler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/livecodes/languages/ripple/lang-ripple-compiler.ts b/src/livecodes/languages/ripple/lang-ripple-compiler.ts index 07c16f507a..43a31a8347 100644 --- a/src/livecodes/languages/ripple/lang-ripple-compiler.ts +++ b/src/livecodes/languages/ripple/lang-ripple-compiler.ts @@ -1,4 +1,4 @@ -import { compileBlocks } from '../../compiler'; +import { compileBlocks } from '../../compiler/compile-blocks'; import type { CompilerFunction, Config } from '../../models'; import { modulesService } from '../../services/modules'; From abd3e58263040db37936b9d18ca16937f27da64d Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Sat, 6 Sep 2025 20:42:36 +0300 Subject: [PATCH 23/71] allow importing external ripple components --- src/livecodes/compiler/import-map.ts | 10 ++- .../languages/ripple/lang-ripple-compiler.ts | 75 +++++++++++++++---- 2 files changed, 68 insertions(+), 17 deletions(-) diff --git a/src/livecodes/compiler/import-map.ts b/src/livecodes/compiler/import-map.ts index a915cd0040..ae70efb17c 100644 --- a/src/livecodes/compiler/import-map.ts +++ b/src/livecodes/compiler/import-map.ts @@ -144,6 +144,14 @@ export const isScriptImport = (mod: string) => mod.toLowerCase().endsWith('.vue') || mod.toLowerCase().endsWith('.svelte'))); +const isStyleImport = (mod: string) => + mod.toLowerCase().startsWith('./style') || + mod.toLowerCase().endsWith('.css') || + mod.toLowerCase().endsWith('.scss') || + mod.toLowerCase().endsWith('.sass') || + mod.toLowerCase().endsWith('.less') || + mod.toLowerCase().endsWith('.styl'); + const modulesCache: Record = {}; const fetchModule = async (mod: string) => { if (modulesCache[mod]) { @@ -176,7 +184,7 @@ export const replaceSFCImports = async ( const isExtensionless = (mod: string) => mod.startsWith('.') && !mod.split('/')[mod.split('/').length - 1].includes('.'); const sfcImports = getImports(code).filter( - (mod) => isSfc(mod) || isExtensionless(mod) || mod.startsWith('.'), + (mod) => !isStyleImport(mod) && (isSfc(mod) || isExtensionless(mod) || mod.startsWith('.')), ); const projectImportMap = { ...config.imports, diff --git a/src/livecodes/languages/ripple/lang-ripple-compiler.ts b/src/livecodes/languages/ripple/lang-ripple-compiler.ts index 43a31a8347..b51fe59c29 100644 --- a/src/livecodes/languages/ripple/lang-ripple-compiler.ts +++ b/src/livecodes/languages/ripple/lang-ripple-compiler.ts @@ -1,11 +1,22 @@ +import { createImportMap, getCompileResult, replaceSFCImports } from '../../compiler'; import { compileBlocks } from '../../compiler/compile-blocks'; import type { CompilerFunction, Config } from '../../models'; import { modulesService } from '../../services/modules'; +import { getLanguageByAlias } from '../utils'; -// TODO: recursively compile imported Ripple components +const getLatestVersion = async () => { + const pkg = await fetch('https://data.jsdelivr.com/v1/packages/npm/ripple') + .then((res) => res.json()) + .catch(() => ({})); + return pkg.tags?.latest || 'latest'; +}; (self as any).createRippleCompiler = async (initialConfig: Config): Promise => { - let version = initialConfig.customSettings.ripple?.version || 'latest'; + const MAIN_FILE = '__LiveCodes_App__.ripple'; + let importedContent = ''; + let imports: Record = {}; + + let version: string = initialConfig.customSettings.ripple?.version || (await getLatestVersion()); let compile: (code: string, filename: string) => Promise<{ js: { code: string }; css: string }>; const updateCompiler = async (currentVersion: string) => { @@ -17,35 +28,67 @@ import { modulesService } from '../../services/modules'; version = currentVersion; }; - return async (code, { config }) => { - if (!code.trim()) return ''; + const compileRipple = async ( + code: string, + { config, filename }: { config: Config; filename: string }, + ) => { + if (filename === MAIN_FILE) { + importedContent = ''; + imports = {}; + } + if (!code.trim()) return getCompileResult(''); const newVersion = config.customSettings.ripple?.version || version; await updateCompiler(newVersion); - code = await compileBlocks(code, 'style', config); + const isRipple = (mod: string) => + mod.toLowerCase().endsWith('.ripple') || mod.toLowerCase().startsWith('data:text/ripple'); - const { js, css } = await compile(code, './App.ripple'); + const fullCode = await replaceSFCImports(code, { + config, + filename, + getLanguageByAlias, + isSfc: isRipple, + compileSFC: async ( + code: string, + { config, filename }: { config: Config; filename: string }, + ) => { + const compiled = (await compileRipple(code, { config, filename })).code; + importedContent += `\n${filename}\n\n${code}\n`; + return compiled; + }, + }); + const processedCode = await compileBlocks(fullCode, 'style', config); + const { js, css } = await compile(processedCode, filename); const cssCode = css === '' ? '' - : `\n + : ` const styles = document.createElement('style'); styles.innerHTML = ${JSON.stringify(css)}; document.head.appendChild(styles); `; - const moduleUrl = /* @__PURE__ */ modulesService.getModuleUrl(`ripple@${version}`); + if (filename === MAIN_FILE) { + const moduleUrl = /* @__PURE__ */ modulesService.getModuleUrl(`ripple@${version}`); + imports = { + ...createImportMap(importedContent, config), + ripple: moduleUrl, + 'ripple/internal': `${moduleUrl}/internal`, + 'ripple/internal/client': `${moduleUrl}/internal/client`, + }; + } + return { - code: `${js.code}${cssCode}`, - info: { - imports: { - ripple: moduleUrl, - 'ripple/internal': `${moduleUrl}/internal`, - 'ripple/internal/client': `${moduleUrl}/internal/client`, - }, - }, + code: `${js.code}\n${cssCode}`, + info: { importedContent, imports }, }; }; + + return (code, { config }) => + compileRipple(code, { + config, + filename: MAIN_FILE, + }); }; From dbfe2e154085f0711545622d877a330e5a32c6b3 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Sat, 6 Sep 2025 20:42:55 +0300 Subject: [PATCH 24/71] edit ripple docs --- docs/docs/languages/ripple.mdx | 70 +++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 22 deletions(-) diff --git a/docs/docs/languages/ripple.mdx b/docs/docs/languages/ripple.mdx index 93bfe5315a..62e5df4610 100644 --- a/docs/docs/languages/ripple.mdx +++ b/docs/docs/languages/ripple.mdx @@ -6,11 +6,9 @@ toc_max_heading_level: 4 [Ripple](https://www.ripplejs.com/) is a TypeScript UI framework that takes the best parts of React, Solid and Svelte and combines them into one package. -## Usage - Ripple components can be used in LiveCodes as documented in the [Ripple docs](https://github.com/trueadm/ripple). See below for usage. -### Demo +## Demo import LiveCodes from '../../src/components/LiveCodes.tsx'; import RunInLiveCodes from '../../src/components/RunInLiveCodes.tsx'; @@ -57,6 +55,9 @@ export const demo = { + +## Mounting + ### Auto-rendering A component is mounted and rendered automatically as a Ripple component (without having to [manually mount](#manual-mount) it) if the following conditions are met: @@ -68,6 +69,7 @@ A component is mounted and rendered automatically as a Ripple component (without ### Root Element To mount the application instance to a specific DOM element use `"livecodes-app"` as the element `id` in the HTML. Otherwise, if that element is not found, a new `div` element is added to `document.body` and is used to mount the instance. +In case you need more control, you can [manually mount](#manual-mount) the instance. Example: @@ -152,9 +154,11 @@ To disable [auto-rendering](#auto-rendering), set the [custom settings](#custom- } ``` -### Module Imports +## Importing Modules -npm modules can be imported as described in the section about [module resolution](../features/module-resolution.mdx), including bare module imports and importing from different CDNs. Stylesheets imported in the `script` block are added as `` tags in the page `head`. +### NPM Modules + +npm modules can be imported as described in the section about [module resolution](../features/module-resolution.mdx), including bare module imports and importing from different CDNs. Stylesheets imported in the `script` block are added as `` tags in the page `head` (see [below](#importing-stylesheets)). Module imports can be customized using import maps as described in [module resolution](../features/module-resolution.mdx#custom-module-resolution) documentations. @@ -192,22 +196,44 @@ export default component App() { +### External Components -{/* -### Importing External Components +External Ripple components can be imported. +The import URL can be either: +- An absolute URL ending with `.ripple` extension. +- A [bare module import](../features/module-resolution.mdx#bare-module-imports) for a published npm module with full path to the component with extension. +- A [data URL](../features/data-urls.mdx) starting with `data:text/ripple`. -External Svelte components can be imported. The import URL has to be an absolute URL ending with `.svelte` extension. Any bare or relative imports in the imported files are resolved and compiled recursively. +Any bare or relative imports in the imported files are resolved and compiled recursively. +If a processor is enabled (e.g. Tailwind CSS), classes in the imported files are detected and used in the generated CSS (see [CSS Frameworks](#css-frameworks) section below). -Example: +Example: ([source](https://github.com/hatemhosny/ripple-tailwind-counter-demo)) -```html - +export const externalComponents = { + activeEditor: 'script', + script: { + language: 'ripple', + content: `// import from npm modules +import Counter from 'ripple-tailwind-counter-demo/src/Counter.ripple'; +// alternatively use absolute URLs +// import Counter from 'https://raw.githubusercontent.com/hatemhosny/ripple-tailwind-counter-demo/refs/heads/main/src/Counter.ripple'; - -``` - */} + +export default component App() { + let $name = "World"; + + setTimeout(() => { + $name = "Ripple + Tailwind!"; + }, 2000); + + +} +`, + }, + processors: ['tailwindcss'], +} + + ### Exports @@ -221,11 +247,11 @@ When values are imported from `"./script"`, [auto-rendering](#auto-rendering) is ::: -### Styles +## Styles CSS can be applied to the component using various ways: -#### Component Styles +### Component Styles Styles in a `style` tag in a Ripple component are applied to that component only. @@ -255,13 +281,13 @@ export const styleTag = { > -#### Style Editor +### Style Editor Styles added in the [style editor](../features/projects.mdx#style-editor) are applied globally to the [result page](../features/result.mdx). This can use different **languages/processors** supported in LiveCodes including CSS, SCSS, Less, Stylus, ..etc. See [style documentation](../features/css.mdx) for more details. And of course, styles and stylesheets added in [markup editor](../features/projects.mdx#markup-editor) are also applied globally. -#### Importing Stylesheets +### Importing Stylesheets Stylesheets imported in [script editor](../features/projects.mdx#script-editor) are added as `` tags in the page `head`. The stylesheet URL can be an absolute URL or a path in the npm package. The URL has to end with `".css"`. @@ -279,7 +305,7 @@ export const stylesDemo = { formatCode={false} > -#### CSS Modules +### CSS Modules CSS modules are supported and are [documented separately](./cssmodules.mdx). Make sure to enable CSS modules (from style editor menu or in [`processors`](../configuration/configuration-object.mdx#processors) property of [configuration object](../configuration/configuration-object.mdx)). @@ -297,7 +323,7 @@ export const cssModulesDemo = { -#### CSS Frameworks +### CSS Frameworks [CSS Frameworks](../features/css.mdx#css-processors) supported in LiveCodes (e.g. [Tailwind CSS](./tailwindcss.mdx), [UnoCSS](./unocss.mdx), [WindiCSS](./windicss.mdx)) can detect class names added in Ripple components. Make sure that the required utility is enabled (from style editor menu or in `processors` property of [configuration object](../configuration/configuration-object.mdx#processors)). From e62a259d416b4eebfabc41c63aec93cc3d23d44c Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Sat, 6 Sep 2025 21:22:08 +0300 Subject: [PATCH 25/71] upgrade ripple formatter --- src/livecodes/languages/ripple/lang-ripple-compiler.ts | 3 ++- src/livecodes/vendors.ts | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/livecodes/languages/ripple/lang-ripple-compiler.ts b/src/livecodes/languages/ripple/lang-ripple-compiler.ts index b51fe59c29..c3f7a85b0c 100644 --- a/src/livecodes/languages/ripple/lang-ripple-compiler.ts +++ b/src/livecodes/languages/ripple/lang-ripple-compiler.ts @@ -1,5 +1,6 @@ -import { createImportMap, getCompileResult, replaceSFCImports } from '../../compiler'; import { compileBlocks } from '../../compiler/compile-blocks'; +import { createImportMap, replaceSFCImports } from '../../compiler/import-map'; +import { getCompileResult } from '../../compiler/utils'; import type { CompilerFunction, Config } from '../../models'; import { modulesService } from '../../services/modules'; import { getLanguageByAlias } from '../utils'; diff --git a/src/livecodes/vendors.ts b/src/livecodes/vendors.ts index c44a9dbda4..df06b73a82 100644 --- a/src/livecodes/vendors.ts +++ b/src/livecodes/vendors.ts @@ -344,7 +344,7 @@ export const postcssImportUrlUrl = /* @__PURE__ */ getUrl( export const prettierBaseUrl = /* @__PURE__ */ getUrl('prettier@3.3.2/'); export const prettierRippleUrl = /* @__PURE__ */ getUrl( - '@hatemhosny/prettier-plugin-ripple@0.0.7/build/parser-ripple.js', + '@hatemhosny/prettier-plugin-ripple@0.0.8/build/parser-ripple.js', ); export const prettierPhpUrl = /* @__PURE__ */ getUrl('@prettier/plugin-php@0.22.2/standalone.js'); From 28592cd2e95d82b2538f39881507931a03277b67 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Sat, 6 Sep 2025 21:32:32 +0300 Subject: [PATCH 26/71] feat(Compilers): add basic support for ripple --- src/livecodes/languages/languages.ts | 2 ++ src/livecodes/languages/ripple/index.ts | 1 + src/livecodes/languages/ripple/lang-ripple.ts | 31 +++++++++++++++++++ .../languages/ripple/ripple-runtime.ts | 9 ++++++ src/livecodes/result/result-page.ts | 6 ++-- src/livecodes/vendors.ts | 2 ++ src/sdk/models.ts | 1 + 7 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 src/livecodes/languages/ripple/index.ts create mode 100644 src/livecodes/languages/ripple/lang-ripple.ts create mode 100644 src/livecodes/languages/ripple/ripple-runtime.ts diff --git a/src/livecodes/languages/languages.ts b/src/livecodes/languages/languages.ts index 9f318652af..1adcb54bad 100644 --- a/src/livecodes/languages/languages.ts +++ b/src/livecodes/languages/languages.ts @@ -59,6 +59,7 @@ import { reason } from './reason'; import { rescript } from './rescript'; import { richtext } from './richtext'; import { riot } from './riot'; +import { ripple } from './ripple'; import { ruby } from './ruby'; import { rubyWasm } from './ruby-wasm'; import { scheme } from './scheme'; @@ -128,6 +129,7 @@ export const languages: LanguageSpecs[] = [ solidTsx, riot, malina, + ripple, coffeescript, livescript, civet, diff --git a/src/livecodes/languages/ripple/index.ts b/src/livecodes/languages/ripple/index.ts new file mode 100644 index 0000000000..ace98a13ca --- /dev/null +++ b/src/livecodes/languages/ripple/index.ts @@ -0,0 +1 @@ +export * from './lang-ripple'; diff --git a/src/livecodes/languages/ripple/lang-ripple.ts b/src/livecodes/languages/ripple/lang-ripple.ts new file mode 100644 index 0000000000..3f30bb9b43 --- /dev/null +++ b/src/livecodes/languages/ripple/lang-ripple.ts @@ -0,0 +1,31 @@ +import type { LanguageSpecs } from '../../models'; +import { rippleUrl } from '../../vendors'; +import { parserPlugins } from '../prettier'; + +export const ripple: LanguageSpecs = { + name: 'ripple', + title: 'Ripple', + info: false, + parser: { + name: 'babel-ts', + pluginUrls: [parserPlugins.babel, parserPlugins.html], + }, + compiler: { + factory: async () => { + // TODO: convert to UMD + const { compile } = await import(rippleUrl); + return async (code) => { + if (!code.trim()) return ''; + const { js, css } = await compile(code, './src/App.ripple'); + const cssCode = + css === '' + ? '' + : `\n\nconst styles = document.createElement('style');\nstyles.innerHTML = ${JSON.stringify(css)};\ndocument.head.appendChild(styles);\n`; + return `${js.code}${cssCode}`; + }; + }, + }, + extensions: ['ripple'], + editor: 'script', + editorLanguage: 'typescript', +}; diff --git a/src/livecodes/languages/ripple/ripple-runtime.ts b/src/livecodes/languages/ripple/ripple-runtime.ts new file mode 100644 index 0000000000..d7d8d898b6 --- /dev/null +++ b/src/livecodes/languages/ripple/ripple-runtime.ts @@ -0,0 +1,9 @@ +export const rippleRuntime = ` +import { mount } from 'ripple'; +import { App } from "./script"; +(() => { + mount(App, { + target: document.querySelector("#livecodes-app") || document.body.appendChild(document.createElement('div')), + }); +})(); +`; diff --git a/src/livecodes/result/result-page.ts b/src/livecodes/result/result-page.ts index 1610161a45..c5c6f189d4 100644 --- a/src/livecodes/result/result-page.ts +++ b/src/livecodes/result/result-page.ts @@ -11,6 +11,7 @@ import { import { cssPresets, getLanguageCompiler, getLanguageExtension } from '../languages'; import { reactRuntime } from '../languages/jsx/react-runtime'; import { reactNativeRuntime } from '../languages/react-native/react-native-runtime'; +import { rippleRuntime } from '../languages/ripple/ripple-runtime'; import { solidRuntime } from '../languages/solid/solid-runtime'; import { hasCustomJsxRuntime } from '../languages/typescript'; import type { Cache, CompileInfo, Config, EditorId, Language } from '../models'; @@ -210,6 +211,7 @@ export const createResultPage = async ({ 'react-native-tsx': reactNativeRuntime, solid: solidRuntime, 'solid.tsx': solidRuntime, + ripple: rippleRuntime, }; const jsxRuntime = jsxRuntimes[code.script.language] || ''; const reactImport = @@ -219,7 +221,7 @@ export const createResultPage = async ({ const shouldInsertJsxRuntime = Object.keys(jsxRuntimes).includes(code.script.language) && !config.customSettings[code.script.language]?.disableAutoRender && - hasDefaultExport(code.script.compiled) && + (hasDefaultExport(code.script.compiled) || code.script.language === 'ripple') && // FIXME: ripple default export !hasCustomJsxRuntime(code.script.content || '', config) && !importFromScript; const hasPreact = getImports(code.script.compiled).find((mod) => mod === 'preact'); @@ -439,7 +441,7 @@ export const createResultPage = async ({ } } - // React JSX runtime + // JSX runtime if (shouldInsertJsxRuntime) { const jsxRuntimeScript = dom.createElement('script'); jsxRuntimeScript.type = 'module'; diff --git a/src/livecodes/vendors.ts b/src/livecodes/vendors.ts index 3ee6afdcfc..570e046b59 100644 --- a/src/livecodes/vendors.ts +++ b/src/livecodes/vendors.ts @@ -389,6 +389,8 @@ export const resetCssUrl = /* @__PURE__ */ getUrl('reset-css@5.0.1/reset.css'); export const riotBaseUrl = /* @__PURE__ */ getUrl('riot@9.2.2/'); +export const rippleUrl = /* @__PURE__ */ getModuleUrl('ripple@0.2.3/compiler'); + export const rubyWasmBaseUrl = /* @__PURE__ */ getUrl('@ruby/3.3-wasm-wasi@2.6.2/dist/'); export const rubyWasmScriptUrl = /* @__PURE__ */ getUrl( diff --git a/src/sdk/models.ts b/src/sdk/models.ts index e6bd21a015..16bf986a7a 100644 --- a/src/sdk/models.ts +++ b/src/sdk/models.ts @@ -968,6 +968,7 @@ export type Language = | 'riotjs' | 'malina' | 'malinajs' + | 'ripple' | 'xht' | 'coffeescript' | 'coffee' From ffbdbfc666a2a004c56cc7b9d91bd635f67621a6 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Sat, 6 Sep 2025 21:32:32 +0300 Subject: [PATCH 27/71] upgrade ripple, use default export --- src/livecodes/languages/ripple/ripple-runtime.ts | 2 +- src/livecodes/result/result-page.ts | 2 +- src/livecodes/vendors.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/livecodes/languages/ripple/ripple-runtime.ts b/src/livecodes/languages/ripple/ripple-runtime.ts index d7d8d898b6..80653677e6 100644 --- a/src/livecodes/languages/ripple/ripple-runtime.ts +++ b/src/livecodes/languages/ripple/ripple-runtime.ts @@ -1,6 +1,6 @@ export const rippleRuntime = ` import { mount } from 'ripple'; -import { App } from "./script"; +import App from "./script"; (() => { mount(App, { target: document.querySelector("#livecodes-app") || document.body.appendChild(document.createElement('div')), diff --git a/src/livecodes/result/result-page.ts b/src/livecodes/result/result-page.ts index c5c6f189d4..9a13c0f140 100644 --- a/src/livecodes/result/result-page.ts +++ b/src/livecodes/result/result-page.ts @@ -221,7 +221,7 @@ export const createResultPage = async ({ const shouldInsertJsxRuntime = Object.keys(jsxRuntimes).includes(code.script.language) && !config.customSettings[code.script.language]?.disableAutoRender && - (hasDefaultExport(code.script.compiled) || code.script.language === 'ripple') && // FIXME: ripple default export + hasDefaultExport(code.script.compiled) && !hasCustomJsxRuntime(code.script.content || '', config) && !importFromScript; const hasPreact = getImports(code.script.compiled).find((mod) => mod === 'preact'); diff --git a/src/livecodes/vendors.ts b/src/livecodes/vendors.ts index 570e046b59..b0207c7aee 100644 --- a/src/livecodes/vendors.ts +++ b/src/livecodes/vendors.ts @@ -389,7 +389,7 @@ export const resetCssUrl = /* @__PURE__ */ getUrl('reset-css@5.0.1/reset.css'); export const riotBaseUrl = /* @__PURE__ */ getUrl('riot@9.2.2/'); -export const rippleUrl = /* @__PURE__ */ getModuleUrl('ripple@0.2.3/compiler'); +export const rippleUrl = /* @__PURE__ */ getModuleUrl('ripple@0.2.5/compiler'); export const rubyWasmBaseUrl = /* @__PURE__ */ getUrl('@ruby/3.3-wasm-wasi@2.6.2/dist/'); From f9c3b4738121f2a3995c936cc52f4850dea80b19 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Sat, 6 Sep 2025 21:32:32 +0300 Subject: [PATCH 28/71] add syntax highlighting for ripple in monaco --- scripts/build.js | 1 + .../monaco/languages/monaco-lang-ripple.ts | 6856 +++++++++++++++++ src/livecodes/editor/monaco/monaco.ts | 50 + src/livecodes/languages/ripple/lang-ripple.ts | 1 - src/livecodes/vendors.ts | 10 +- 5 files changed, 6916 insertions(+), 2 deletions(-) create mode 100644 src/livecodes/editor/monaco/languages/monaco-lang-ripple.ts diff --git a/scripts/build.js b/scripts/build.js index 13058760d2..2b9d0550a5 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -160,6 +160,7 @@ const esmBuild = () => 'editor/monaco/languages/monaco-lang-astro.ts', 'editor/monaco/languages/monaco-lang-clio.ts', 'editor/monaco/languages/monaco-lang-imba.ts', + 'editor/monaco/languages/monaco-lang-ripple.ts', // 'editor/monaco/languages/monaco-lang-sql.ts', 'editor/monaco/languages/monaco-lang-wat.ts', 'editor/codemirror/codemirror.ts', diff --git a/src/livecodes/editor/monaco/languages/monaco-lang-ripple.ts b/src/livecodes/editor/monaco/languages/monaco-lang-ripple.ts new file mode 100644 index 0000000000..392d2620d0 --- /dev/null +++ b/src/livecodes/editor/monaco/languages/monaco-lang-ripple.ts @@ -0,0 +1,6856 @@ +// from https://github.com/trueadm/ripple/blob/main/packages/ripple-vscode-plugin/syntaxes/ripple.tmLanguage.json +// and https://github.com/trueadm/ripple/blob/main/packages/ripple-vscode-plugin/language-configuration.json +export default { + syntax: { + information_for_contributors: [ + 'This file has been converted from https://github.com/microsoft/TypeScript-TmLanguage/blob/master/TypeScriptReact.tmLanguage', + 'If you want to provide a fix or improvement, please create a pull request against the original repository.', + 'Once accepted there, we are happy to receive an update request.', + ], + version: + 'https://github.com/microsoft/TypeScript-TmLanguage/commit/48f608692aa6d6ad7bd65b478187906c798234a8', + name: 'Ripple', + scopeName: 'source.ripple', + patterns: [ + { + include: '#directives', + }, + { + include: '#statements', + }, + { + include: '#shebang', + }, + ], + repository: { + shebang: { + name: 'comment.line.shebang.js', + match: '\\A(#!).*(?=$)', + captures: { + '1': { + name: 'punctuation.definition.comment.js', + }, + }, + }, + statements: { + patterns: [ + { + include: '#declaration', + }, + { + include: '#control-statement', + }, + { + include: '#after-operator-block-as-object-literal', + }, + { + include: '#decl-block', + }, + { + include: '#label', + }, + { + include: '#expression', + }, + { + include: '#punctuation-semicolon', + }, + { + include: '#string', + }, + { + include: '#comment', + }, + ], + }, + 'component-statements': { + patterns: [ + { + include: '#jsx', + }, + { + include: '#declaration', + }, + { + include: '#component-control-statement', + }, + { + include: '#component-decl-block', + }, + { + include: '#label', + }, + { + include: '#expression', + }, + { + include: '#punctuation-semicolon', + }, + { + include: '#string', + }, + { + include: '#comment', + }, + ], + }, + declaration: { + patterns: [ + { + include: '#decorator', + }, + { + include: '#var-expr', + }, + { + include: '#component-declaration', + }, + { + include: '#fragment-declaration', + }, + { + include: '#function-declaration', + }, + { + include: '#class-declaration', + }, + { + include: '#interface-declaration', + }, + { + include: '#enum-declaration', + }, + { + include: '#namespace-declaration', + }, + { + include: '#type-alias-declaration', + }, + { + include: '#import-equals-declaration', + }, + { + include: '#import-declaration', + }, + { + include: '#export-declaration', + }, + { + name: 'storage.modifier.js', + match: + '(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\\'\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(?\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\\'\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))', + beginCaptures: { + '1': { + name: 'meta.definition.variable.js entity.name.function.js', + }, + '2': { + name: 'keyword.operator.definiteassignment.js', + }, + }, + end: '(?=$|^|[;,=}]|((?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\\'\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(?\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\\'\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))', + beginCaptures: { + '1': { + name: 'meta.definition.variable.js variable.other.constant.js entity.name.function.js', + }, + }, + end: '(?=$|^|[;,=}]|((?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\\'\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(?\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\\'\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))', + captures: { + '1': { + name: 'storage.modifier.js', + }, + '2': { + name: 'keyword.operator.rest.js', + }, + '3': { + name: 'entity.name.function.js variable.language.this.js', + }, + '4': { + name: 'entity.name.function.js', + }, + '5': { + name: 'keyword.operator.optional.js', + }, + }, + }, + { + match: + '(?x)(?:(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\\'\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(?\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\\'\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))', + captures: { + '1': { + name: 'meta.definition.property.js entity.name.function.js', + }, + '2': { + name: 'keyword.operator.optional.js', + }, + '3': { + name: 'keyword.operator.definiteassignment.js', + }, + }, + }, + { + name: 'meta.definition.property.js variable.object.property.js', + match: '\\#?[_$[:alpha:]][_$[:alnum:]]*', + }, + { + name: 'keyword.operator.optional.js', + match: '\\?', + }, + { + name: 'keyword.operator.definiteassignment.js', + match: '\\!', + }, + ], + }, + 'variable-initializer': { + patterns: [ + { + begin: '(?\\s*$)', + beginCaptures: { + '1': { + name: 'keyword.operator.assignment.js', + }, + }, + end: '(?=$|^|[,);}\\]]|((?]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])', + beginCaptures: { + '1': { + name: 'storage.modifier.js', + }, + '2': { + name: 'storage.modifier.js', + }, + '3': { + name: 'storage.modifier.js', + }, + '4': { + name: 'storage.modifier.async.js', + }, + '5': { + name: 'keyword.operator.new.js', + }, + '6': { + name: 'keyword.generator.asterisk.js', + }, + }, + end: '(?=\\}|;|,|$)|(?<=\\})', + patterns: [ + { + include: '#method-declaration-name', + }, + { + include: '#function-body', + }, + ], + }, + { + name: 'meta.method.declaration.js', + begin: + '(?x)(?]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])', + beginCaptures: { + '1': { + name: 'storage.modifier.js', + }, + '2': { + name: 'storage.modifier.js', + }, + '3': { + name: 'storage.modifier.js', + }, + '4': { + name: 'storage.modifier.async.js', + }, + '5': { + name: 'storage.type.property.js', + }, + '6': { + name: 'keyword.generator.asterisk.js', + }, + }, + end: '(?=\\}|;|,|$)|(?<=\\})', + patterns: [ + { + include: '#method-declaration-name', + }, + { + include: '#function-body', + }, + ], + }, + ], + }, + 'object-literal-method-declaration': { + name: 'meta.method.declaration.js', + begin: + '(?x)(?]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])', + beginCaptures: { + '1': { + name: 'storage.modifier.async.js', + }, + '2': { + name: 'storage.type.property.js', + }, + '3': { + name: 'keyword.generator.asterisk.js', + }, + }, + end: '(?=\\}|;|,)|(?<=\\})', + patterns: [ + { + include: '#method-declaration-name', + }, + { + include: '#function-body', + }, + { + begin: + '(?x)(?]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])', + beginCaptures: { + '1': { + name: 'storage.modifier.async.js', + }, + '2': { + name: 'storage.type.property.js', + }, + '3': { + name: 'keyword.generator.asterisk.js', + }, + }, + end: '(?=\\(|\\<)', + patterns: [ + { + include: '#method-declaration-name', + }, + ], + }, + ], + }, + 'method-declaration-name': { + begin: + '(?x)(?=((\\b(?)', + captures: { + '1': { + name: 'storage.modifier.async.js', + }, + '2': { + name: 'variable.parameter.js', + }, + }, + }, + { + name: 'meta.arrow.js', + begin: + '(?x) (?:\n (? is on new line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\\'\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n )\n)', + beginCaptures: { + '1': { + name: 'storage.modifier.async.js', + }, + }, + end: '(?==>|\\{|(^\\s*(export|function|class|interface|let|var|(?:\\busing(?=\\s+(?!in\\b|of\\b(?!\\s*(?:of\\b|=)))[_$[:alpha:]])\\b)|(?:\\bawait\\s+(?:\\busing(?=\\s+(?!in\\b|of\\b(?!\\s*(?:of\\b|=)))[_$[:alpha:]])\\b)\\b)|const|import|enum|namespace|module|type|abstract|declare)\\s+))', + patterns: [ + { + include: '#comment', + }, + { + include: '#type-parameters', + }, + { + include: '#function-parameters', + }, + { + include: '#arrow-return-type', + }, + { + include: '#possibly-arrow-return-type', + }, + ], + }, + { + name: 'meta.arrow.js', + begin: '=>', + beginCaptures: { + '0': { + name: 'storage.type.function.arrow.js', + }, + }, + end: '((?<=\\}|\\S)(?)|((?!\\{)(?=\\S)))(?!\\/[\\/\\*])', + patterns: [ + { + include: '#single-line-comment-consuming-line-ending', + }, + { + include: '#decl-block', + }, + { + include: '#expression', + }, + ], + }, + ], + }, + 'indexer-declaration': { + name: 'meta.indexer.declaration.js', + begin: + '(?:(?]|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^yield|[^\\._$[:alnum:]]yield|^throw|[^\\._$[:alnum:]]throw|^in|[^\\._$[:alnum:]]in|^of|[^\\._$[:alnum:]]of|^typeof|[^\\._$[:alnum:]]typeof|&&|\\|\\||\\*)\\s*(\\{)', + beginCaptures: { + '1': { + name: 'punctuation.definition.block.js', + }, + }, + end: '\\}', + endCaptures: { + '0': { + name: 'punctuation.definition.block.js', + }, + }, + patterns: [ + { + include: '#object-member', + }, + ], + }, + 'object-literal': { + name: 'meta.objectliteral.js', + begin: '\\{', + beginCaptures: { + '0': { + name: 'punctuation.definition.block.js', + }, + }, + end: '\\}', + endCaptures: { + '0': { + name: 'punctuation.definition.block.js', + }, + }, + patterns: [ + { + include: '#object-member', + }, + ], + }, + 'object-member': { + patterns: [ + { + include: '#comment', + }, + { + include: '#object-literal-method-declaration', + }, + { + name: 'meta.object.member.js meta.object-literal.key.js', + begin: '(?=\\[)', + end: '(?=:)|((?<=[\\]])(?=\\s*[\\(\\<]))', + patterns: [ + { + include: '#comment', + }, + { + include: '#array-literal', + }, + ], + }, + { + name: 'meta.object.member.js meta.object-literal.key.js', + begin: '(?=[\\\'\\"\\`])', + end: '(?=:)|((?<=[\\\'\\"\\`])(?=((\\s*[\\(\\<,}])|(\\s+(as|satisifies)\\s+))))', + patterns: [ + { + include: '#comment', + }, + { + include: '#string', + }, + ], + }, + { + name: 'meta.object.member.js meta.object-literal.key.js', + begin: + '(?x)(?=(\\b(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\\'\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))', + captures: { + '0': { + name: 'meta.object-literal.key.js', + }, + '1': { + name: 'entity.name.function.js', + }, + }, + }, + { + name: 'meta.object.member.js', + match: + '(?:[_$[:alpha:]][_$[:alnum:]]*)\\s*(?=(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*:)', + captures: { + '0': { + name: 'meta.object-literal.key.js', + }, + }, + }, + { + name: 'meta.object.member.js', + begin: '\\.\\.\\.', + beginCaptures: { + '0': { + name: 'keyword.operator.spread.js', + }, + }, + end: '(?=,|\\})', + patterns: [ + { + include: '#expression', + }, + ], + }, + { + name: 'meta.object.member.js', + match: '([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=,|\\}|$|\\/\\/|\\/\\*)', + captures: { + '1': { + name: 'variable.other.readwrite.js', + }, + }, + }, + { + name: 'meta.object.member.js', + match: '(?]|\\|\\||\\&\\&|\\!\\=\\=|$|^|((?]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)\\(\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))', + beginCaptures: { + '1': { + name: 'storage.modifier.async.js', + }, + }, + end: '(?<=\\))', + patterns: [ + { + include: '#type-parameters', + }, + { + begin: '\\(', + beginCaptures: { + '0': { + name: 'meta.brace.round.js', + }, + }, + end: '\\)', + endCaptures: { + '0': { + name: 'meta.brace.round.js', + }, + }, + patterns: [ + { + include: '#expression-inside-possibly-arrow-parens', + }, + ], + }, + ], + }, + { + begin: + '(?<=:)\\s*(async)?\\s*(\\()(?=\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))', + beginCaptures: { + '1': { + name: 'storage.modifier.async.js', + }, + '2': { + name: 'meta.brace.round.js', + }, + }, + end: '\\)', + endCaptures: { + '0': { + name: 'meta.brace.round.js', + }, + }, + patterns: [ + { + include: '#expression-inside-possibly-arrow-parens', + }, + ], + }, + { + begin: '(?<=:)\\s*(async)?\\s*(?=\\<\\s*$)', + beginCaptures: { + '1': { + name: 'storage.modifier.async.js', + }, + }, + end: '(?<=\\>)', + patterns: [ + { + include: '#type-parameters', + }, + ], + }, + { + begin: + '(?<=\\>)\\s*(\\()(?=\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))', + beginCaptures: { + '1': { + name: 'meta.brace.round.js', + }, + }, + end: '\\)', + endCaptures: { + '0': { + name: 'meta.brace.round.js', + }, + }, + patterns: [ + { + include: '#expression-inside-possibly-arrow-parens', + }, + ], + }, + { + include: '#possibly-arrow-return-type', + }, + { + include: '#expression', + }, + ], + }, + { + include: '#punctuation-comma', + }, + { + include: '#decl-block', + }, + ], + }, + 'ternary-expression': { + begin: '(?!\\?\\.\\s*[^[:digit:]])(\\?)(?!\\?)', + beginCaptures: { + '1': { + name: 'keyword.operator.ternary.js', + }, + }, + end: '\\s*(:)', + endCaptures: { + '1': { + name: 'keyword.operator.ternary.js', + }, + }, + patterns: [ + { + include: '#expression', + }, + ], + }, + 'function-call': { + patterns: [ + { + begin: + '(?=(((([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))|(?<=[\\)]))\\s*(?:(\\?\\.\\s*)|(\\!))?((<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\())', + end: '(?<=\\))(?!(((([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))|(?<=[\\)]))\\s*(?:(\\?\\.\\s*)|(\\!))?((<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\())', + patterns: [ + { + name: 'meta.function-call.js', + begin: + '(?=(([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))', + end: '(?=\\s*(?:(\\?\\.\\s*)|(\\!))?((<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\())', + patterns: [ + { + include: '#function-call-target', + }, + ], + }, + { + include: '#comment', + }, + { + include: '#function-call-optionals', + }, + { + include: '#type-arguments', + }, + { + include: '#paren-expression', + }, + ], + }, + { + begin: + '(?=(((([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))|(?<=[\\)]))(<\\s*[\\{\\[\\(]\\s*$))', + end: '(?<=\\>)(?!(((([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))|(?<=[\\)]))(<\\s*[\\{\\[\\(]\\s*$))', + patterns: [ + { + name: 'meta.function-call.js', + begin: + '(?=(([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))', + end: '(?=(<\\s*[\\{\\[\\(]\\s*$))', + patterns: [ + { + include: '#function-call-target', + }, + ], + }, + { + include: '#comment', + }, + { + include: '#function-call-optionals', + }, + { + include: '#type-arguments', + }, + ], + }, + ], + }, + 'function-call-target': { + patterns: [ + { + include: '#support-function-call-identifiers', + }, + { + name: 'entity.name.function.js', + match: '(\\#?[_$[:alpha:]][_$[:alnum:]]*)', + }, + ], + }, + 'function-call-optionals': { + patterns: [ + { + name: 'meta.function-call.js punctuation.accessor.optional.js', + match: '\\?\\.', + }, + { + name: 'meta.function-call.js keyword.operator.definiteassignment.js', + match: '\\!', + }, + ], + }, + 'support-function-call-identifiers': { + patterns: [ + { + include: '#literal', + }, + { + include: '#support-objects', + }, + { + include: '#object-identifiers', + }, + { + include: '#punctuation-accessor', + }, + { + name: 'keyword.operator.expression.import.js', + match: + '(?:(?]|\\|\\||\\&\\&|\\!\\=\\=|$|((?]|\\|\\||\\&\\&|\\!\\=\\=|$|(===|!==|==|!=)|(([\\&\\~\\^\\|]\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s+instanceof(?![_$[:alnum:]])(?:(?=\\.\\.\\.)|(?!\\.)))|((?]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\(\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))', + beginCaptures: { + '1': { + name: 'storage.modifier.async.js', + }, + }, + end: '(?<=\\))', + patterns: [ + { + include: '#paren-expression-possibly-arrow-with-typeparameters', + }, + ], + }, + { + begin: + '(?<=[(=,]|=>|^return|[^\\._$[:alnum:]]return)\\s*(async)?(?=\\s*((((<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\()|(<)|((<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)))\\s*$)', + beginCaptures: { + '1': { + name: 'storage.modifier.async.js', + }, + }, + end: '(?<=\\))', + patterns: [ + { + include: '#paren-expression-possibly-arrow-with-typeparameters', + }, + ], + }, + { + include: '#possibly-arrow-return-type', + }, + ], + }, + 'paren-expression-possibly-arrow-with-typeparameters': { + patterns: [ + { + include: '#type-parameters', + }, + { + begin: '\\(', + beginCaptures: { + '0': { + name: 'meta.brace.round.js', + }, + }, + end: '\\)', + endCaptures: { + '0': { + name: 'meta.brace.round.js', + }, + }, + patterns: [ + { + include: '#expression-inside-possibly-arrow-parens', + }, + ], + }, + ], + }, + 'expression-inside-possibly-arrow-parens': { + patterns: [ + { + include: '#expressionWithoutIdentifiers', + }, + { + include: '#comment', + }, + { + include: '#string', + }, + { + include: '#decorator', + }, + { + include: '#destructuring-parameter', + }, + { + match: + '(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\\'\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(?\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\\'\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))', + captures: { + '1': { + name: 'storage.modifier.js', + }, + '2': { + name: 'keyword.operator.rest.js', + }, + '3': { + name: 'entity.name.function.js variable.language.this.js', + }, + '4': { + name: 'entity.name.function.js', + }, + '5': { + name: 'keyword.operator.optional.js', + }, + }, + }, + { + match: + '(?x)(?:(?]|\\|\\||\\&\\&|\\!\\=\\=|$|((?>=|>>>=|\\|=', + }, + { + name: 'keyword.operator.bitwise.shift.js', + match: '<<|>>>|>>', + }, + { + name: 'keyword.operator.comparison.js', + match: '===|!==|==|!=', + }, + { + name: 'keyword.operator.relational.js operator.relational.ripple-force entity.name.operator.relational.ripple', + match: '<=|>=|<>|<|>', + }, + { + match: '(?<=[_$[:alnum:]])(\\!)\\s*(?:(/=)|(?:(/)(?![/*])))', + captures: { + '1': { + name: 'keyword.operator.logical.js', + }, + '2': { + name: 'keyword.operator.assignment.compound.js', + }, + '3': { + name: 'keyword.operator.arithmetic.js', + }, + }, + }, + { + name: 'keyword.operator.logical.js', + match: '\\!|&&|\\|\\||\\?\\?', + }, + { + name: 'keyword.operator.bitwise.js', + match: '\\&|~|\\^|\\|', + }, + { + name: 'keyword.operator.assignment.js', + match: '\\=', + }, + { + name: 'keyword.operator.decrement.js', + match: '--', + }, + { + name: 'keyword.operator.increment.js', + match: '\\+\\+', + }, + { + name: 'keyword.operator.arithmetic.js', + match: '%|\\*|/|-|\\+', + }, + { + begin: + '(?<=[_$[:alnum:])\\]])\\s*(?=(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)+(?:(/=)|(?:(/)(?![/*]))))', + end: '(?:(/=)|(?:(/)(?!\\*([^\\*]|(\\*[^\\/]))*\\*\\/)))', + endCaptures: { + '1': { + name: 'keyword.operator.assignment.compound.js', + }, + '2': { + name: 'keyword.operator.arithmetic.js', + }, + }, + patterns: [ + { + include: '#comment', + }, + ], + }, + { + match: '(?<=[_$[:alnum:])\\]])\\s*(?:(/=)|(?:(/)(?![/*])))', + captures: { + '1': { + name: 'keyword.operator.assignment.compound.js', + }, + '2': { + name: 'keyword.operator.arithmetic.js', + }, + }, + }, + ], + }, + 'typeof-operator': { + begin: + '(?:&|{\\?]|(extends\\s+)|$|;|^\\s*$|(?:^\\s*(?:abstract|async|(?:\\bawait\\s+(?:\\busing(?=\\s+(?!in\\b|of\\b(?!\\s*(?:of\\b|=)))[_$[:alpha:]])\\b)\\b)|break|case|catch|class|const|continue|declare|do|else|enum|export|finally|function|for|goto|if|import|interface|let|module|namespace|switch|return|throw|try|type|(?:\\busing(?=\\s+(?!in\\b|of\\b(?!\\s*(?:of\\b|=)))[_$[:alpha:]])\\b)|var|while)\\b))', + patterns: [ + { + include: '#type-arguments', + }, + { + include: '#expression', + }, + ], + }, + literal: { + patterns: [ + { + include: '#numeric-literal', + }, + { + include: '#boolean-literal', + }, + { + include: '#null-literal', + }, + { + include: '#undefined-literal', + }, + { + include: '#numericConstant-literal', + }, + { + include: '#array-literal', + }, + { + include: '#this-literal', + }, + { + include: '#super-literal', + }, + ], + }, + 'array-literal': { + name: 'meta.array.literal.js', + begin: '\\s*(\\[)', + beginCaptures: { + '1': { + name: 'meta.brace.square.js', + }, + }, + end: '\\]', + endCaptures: { + '0': { + name: 'meta.brace.square.js', + }, + }, + patterns: [ + { + include: '#expression', + }, + { + include: '#punctuation-comma', + }, + ], + }, + 'numeric-literal': { + patterns: [ + { + name: 'constant.numeric.hex.js', + match: '\\b(?]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\\())\n |\n (?:(EPSILON|MAX_SAFE_INTEGER|MAX_VALUE|MIN_SAFE_INTEGER|MIN_VALUE|NEGATIVE_INFINITY|POSITIVE_INFINITY)\\b(?!\\$)))', + captures: { + '1': { + name: 'punctuation.accessor.js', + }, + '2': { + name: 'punctuation.accessor.optional.js', + }, + '3': { + name: 'support.variable.property.js', + }, + '4': { + name: 'support.constant.js', + }, + }, + }, + { + match: + '(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*(((const\\s+)?[_$[:alpha:]])|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\\'\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))', + captures: { + '1': { + name: 'punctuation.accessor.js', + }, + '2': { + name: 'punctuation.accessor.optional.js', + }, + '3': { + name: 'entity.name.function.js', + }, + }, + }, + { + match: + '(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))\\s*(\\#?[[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])', + captures: { + '1': { + name: 'punctuation.accessor.js', + }, + '2': { + name: 'punctuation.accessor.optional.js', + }, + '3': { + name: 'variable.other.constant.property.js', + }, + }, + }, + { + match: '(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*)', + captures: { + '1': { + name: 'punctuation.accessor.js', + }, + '2': { + name: 'punctuation.accessor.optional.js', + }, + '3': { + name: 'variable.other.property.js', + }, + }, + }, + { + name: 'variable.other.constant.js', + match: '([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])', + }, + { + name: 'variable.other.readwrite.js', + match: '[_$[:alpha:]][_$[:alnum:]]*', + }, + ], + }, + 'object-identifiers': { + patterns: [ + { + name: 'support.class.js', + match: '([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\\??\\.\\s*prototype\\b(?!\\$))', + }, + { + match: + '(?x)(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))\\s*(?:\n (\\#?[[:upper:]][_$[:digit:][:upper:]]*) |\n (\\#?[_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*)', + captures: { + '1': { + name: 'punctuation.accessor.js', + }, + '2': { + name: 'punctuation.accessor.optional.js', + }, + '3': { + name: 'variable.other.constant.object.property.js', + }, + '4': { + name: 'variable.other.object.property.js', + }, + }, + }, + { + match: + '(?x)(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*)', + captures: { + '1': { + name: 'variable.other.constant.object.js', + }, + '2': { + name: 'variable.other.object.js', + }, + }, + }, + ], + }, + 'type-annotation': { + patterns: [ + { + name: 'meta.type.annotation.js', + begin: '(:)(?=\\s*\\S)', + beginCaptures: { + '1': { + name: 'keyword.operator.type.annotation.js', + }, + }, + end: '(?])|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))', + patterns: [ + { + include: '#type', + }, + ], + }, + { + name: 'meta.type.annotation.js', + begin: '(:)', + beginCaptures: { + '1': { + name: 'keyword.operator.type.annotation.js', + }, + }, + end: '(?])|(?=^\\s*$)|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))', + patterns: [ + { + include: '#type', + }, + ], + }, + ], + }, + 'parameter-type-annotation': { + patterns: [ + { + name: 'meta.type.annotation.js', + begin: '(:)', + beginCaptures: { + '1': { + name: 'keyword.operator.type.annotation.js', + }, + }, + end: '(?=[,)])|(?==[^>])', + patterns: [ + { + include: '#type', + }, + ], + }, + ], + }, + 'return-type': { + patterns: [ + { + name: 'meta.return.type.js', + begin: '(?<=\\))\\s*(:)(?=\\s*\\S)', + beginCaptures: { + '1': { + name: 'keyword.operator.type.annotation.js', + }, + }, + end: '(?|\\{|(^\\s*(export|function|class|interface|let|var|(?:\\busing(?=\\s+(?!in\\b|of\\b(?!\\s*(?:of\\b|=)))[_$[:alpha:]])\\b)|(?:\\bawait\\s+(?:\\busing(?=\\s+(?!in\\b|of\\b(?!\\s*(?:of\\b|=)))[_$[:alpha:]])\\b)\\b)|const|import|enum|namespace|module|type|abstract|declare)\\s+))', + patterns: [ + { + include: '#arrow-return-type-body', + }, + ], + }, + 'possibly-arrow-return-type': { + begin: + '(?<=\\)|^)\\s*(:)(?=\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*=>)', + beginCaptures: { + '1': { + name: 'meta.arrow.js meta.return.type.arrow.js keyword.operator.type.annotation.js', + }, + }, + end: '(?==>|\\{|(^\\s*(export|function|class|interface|let|var|(?:\\busing(?=\\s+(?!in\\b|of\\b(?!\\s*(?:of\\b|=)))[_$[:alpha:]])\\b)|(?:\\bawait\\s+(?:\\busing(?=\\s+(?!in\\b|of\\b(?!\\s*(?:of\\b|=)))[_$[:alpha:]])\\b)\\b)|const|import|enum|namespace|module|type|abstract|declare)\\s+))', + contentName: 'meta.arrow.js meta.return.type.arrow.js', + patterns: [ + { + include: '#arrow-return-type-body', + }, + ], + }, + 'arrow-return-type-body': { + patterns: [ + { + begin: '(?<=[:])(?=\\s*\\{)', + end: '(?<=\\})', + patterns: [ + { + include: '#type-object', + }, + ], + }, + { + include: '#type-predicate-operator', + }, + { + include: '#type', + }, + ], + }, + 'type-parameters': { + name: 'meta.type.parameters.js', + begin: '(<)', + beginCaptures: { + '1': { + name: 'punctuation.definition.typeparameters.begin.js', + }, + }, + end: '(>)', + endCaptures: { + '1': { + name: 'punctuation.definition.typeparameters.end.js', + }, + }, + patterns: [ + { + include: '#comment', + }, + { + name: 'storage.modifier.js', + match: + '(?)', + }, + ], + }, + 'type-arguments': { + name: 'meta.type.parameters.js', + begin: '\\<', + beginCaptures: { + '0': { + name: 'punctuation.definition.typeparameters.begin.js', + }, + }, + end: '\\>', + endCaptures: { + '0': { + name: 'punctuation.definition.typeparameters.end.js', + }, + }, + patterns: [ + { + include: '#type-arguments-body', + }, + ], + }, + 'type-arguments-body': { + patterns: [ + { + match: + '(?)\n ))\n ))\n)) |\n(:\\s*(?\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))))', + captures: { + '1': { + name: 'storage.modifier.js', + }, + '2': { + name: 'keyword.operator.rest.js', + }, + '3': { + name: 'entity.name.function.js variable.language.this.js', + }, + '4': { + name: 'entity.name.function.js', + }, + '5': { + name: 'keyword.operator.optional.js', + }, + }, + }, + { + match: + '(?x)(?:(?)', + patterns: [ + { + include: '#comment', + }, + { + include: '#type-parameters', + }, + ], + }, + { + name: 'meta.type.constructor.js', + begin: + '(?)\n ))\n )\n )\n)', + end: '(?<=\\))', + patterns: [ + { + include: '#function-parameters', + }, + ], + }, + ], + }, + 'type-function-return-type': { + patterns: [ + { + name: 'meta.type.function.return.js', + begin: '(=>)(?=\\s*\\S)', + beginCaptures: { + '1': { + name: 'storage.type.function.arrow.js', + }, + }, + end: '(?)(?:\\?]|//|$)', + patterns: [ + { + include: '#type-function-return-type-core', + }, + ], + }, + { + name: 'meta.type.function.return.js', + begin: '=>', + beginCaptures: { + '0': { + name: 'storage.type.function.arrow.js', + }, + }, + end: '(?)(?]|//|^\\s*$)|((?<=\\S)(?=\\s*$)))', + patterns: [ + { + include: '#type-function-return-type-core', + }, + ], + }, + ], + }, + 'type-function-return-type-core': { + patterns: [ + { + include: '#comment', + }, + { + begin: '(?<==>)(?=\\s*\\{)', + end: '(?<=\\})', + patterns: [ + { + include: '#type-object', + }, + ], + }, + { + include: '#type-predicate-operator', + }, + { + include: '#type', + }, + ], + }, + 'type-operators': { + patterns: [ + { + include: '#typeof-operator', + }, + { + include: '#type-infer', + }, + { + begin: '([&|])(?=\\s*\\{)', + beginCaptures: { + '0': { + name: 'keyword.operator.type.js', + }, + }, + end: '(?<=\\})', + patterns: [ + { + include: '#type-object', + }, + ], + }, + { + begin: '[&|]', + beginCaptures: { + '0': { + name: 'keyword.operator.type.js', + }, + }, + end: '(?=\\S)', + }, + { + name: 'keyword.operator.expression.keyof.js', + match: + '(?)', + endCaptures: { + '1': { + name: 'meta.type.parameters.js punctuation.definition.typeparameters.end.js', + }, + }, + contentName: 'meta.type.parameters.js', + patterns: [ + { + include: '#type-arguments-body', + }, + ], + }, + { + begin: '([_$[:alpha:]][_$[:alnum:]]*)\\s*(<)', + beginCaptures: { + '1': { + name: 'entity.name.type.js', + }, + '2': { + name: 'meta.type.parameters.js punctuation.definition.typeparameters.begin.js', + }, + }, + end: '(>)', + endCaptures: { + '1': { + name: 'meta.type.parameters.js punctuation.definition.typeparameters.end.js', + }, + }, + contentName: 'meta.type.parameters.js', + patterns: [ + { + include: '#type-arguments-body', + }, + ], + }, + { + match: '([_$[:alpha:]][_$[:alnum:]]*)\\s*(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))', + captures: { + '1': { + name: 'entity.name.type.module.js', + }, + '2': { + name: 'punctuation.accessor.js', + }, + '3': { + name: 'punctuation.accessor.optional.js', + }, + }, + }, + { + name: 'entity.name.type.js', + match: '[_$[:alpha:]][_$[:alnum:]]*', + }, + ], + }, + 'punctuation-comma': { + name: 'punctuation.separator.comma.js', + match: ',', + }, + 'punctuation-semicolon': { + name: 'punctuation.terminator.statement.js', + match: ';', + }, + 'punctuation-accessor': { + match: '(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))', + captures: { + '1': { + name: 'punctuation.accessor.js', + }, + '2': { + name: 'punctuation.accessor.optional.js', + }, + }, + }, + string: { + patterns: [ + { + include: '#qstring-single', + }, + { + include: '#qstring-double', + }, + { + include: '#template', + }, + ], + }, + 'qstring-double': { + name: 'string.quoted.double.js', + begin: '"', + beginCaptures: { + '0': { + name: 'punctuation.definition.string.begin.js', + }, + }, + end: '(")|((?:[^\\\\\\n])$)', + endCaptures: { + '1': { + name: 'punctuation.definition.string.end.js', + }, + '2': { + name: 'invalid.illegal.newline.js', + }, + }, + patterns: [ + { + include: '#string-character-escape', + }, + ], + }, + 'qstring-single': { + name: 'string.quoted.single.js', + begin: "'", + beginCaptures: { + '0': { + name: 'punctuation.definition.string.begin.js', + }, + }, + end: "(\\')|((?:[^\\\\\\n])$)", + endCaptures: { + '1': { + name: 'punctuation.definition.string.end.js', + }, + '2': { + name: 'invalid.illegal.newline.js', + }, + }, + patterns: [ + { + include: '#string-character-escape', + }, + ], + }, + 'string-character-escape': { + name: 'constant.character.escape.js', + match: + '\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|u\\{[0-9A-Fa-f]+\\}|[0-2][0-7]{0,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.|$)', + }, + template: { + patterns: [ + { + include: '#template-call', + }, + { + contentName: 'string.template.js', + begin: '([_$[:alpha:]][_$[:alnum:]]*)?(`)', + beginCaptures: { + '1': { + name: 'entity.name.function.tagged-template.js', + }, + '2': { + name: 'string.template.js punctuation.definition.string.template.begin.js', + }, + }, + end: '`', + endCaptures: { + '0': { + name: 'string.template.js punctuation.definition.string.template.end.js', + }, + }, + patterns: [ + { + include: '#template-substitution-element', + }, + { + include: '#string-character-escape', + }, + ], + }, + ], + }, + 'template-call': { + patterns: [ + { + begin: + '(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)(<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?`)', + end: '(?=`)', + patterns: [ + { + begin: + '(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))', + end: '(?=(<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?`)', + patterns: [ + { + include: '#support-function-call-identifiers', + }, + { + name: 'entity.name.function.tagged-template.js', + match: '([_$[:alpha:]][_$[:alnum:]]*)', + }, + ], + }, + { + include: '#type-arguments', + }, + ], + }, + { + begin: + '([_$[:alpha:]][_$[:alnum:]]*)?\\s*(?=(<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)`)', + beginCaptures: { + '1': { + name: 'entity.name.function.tagged-template.js', + }, + }, + end: '(?=`)', + patterns: [ + { + include: '#type-arguments', + }, + ], + }, + ], + }, + 'template-substitution-element': { + name: 'meta.template.expression.js', + begin: '\\$\\{', + beginCaptures: { + '0': { + name: 'punctuation.definition.template-expression.begin.js', + }, + }, + end: '\\}', + endCaptures: { + '0': { + name: 'punctuation.definition.template-expression.end.js', + }, + }, + patterns: [ + { + include: '#expression', + }, + ], + contentName: 'meta.embedded.line.js', + }, + 'type-string': { + patterns: [ + { + include: '#qstring-single', + }, + { + include: '#qstring-double', + }, + { + include: '#template-type', + }, + ], + }, + 'template-type': { + patterns: [ + { + include: '#template-call', + }, + { + contentName: 'string.template.js', + begin: '([_$[:alpha:]][_$[:alnum:]]*)?(`)', + beginCaptures: { + '1': { + name: 'entity.name.function.tagged-template.js', + }, + '2': { + name: 'string.template.js punctuation.definition.string.template.begin.js', + }, + }, + end: '`', + endCaptures: { + '0': { + name: 'string.template.js punctuation.definition.string.template.end.js', + }, + }, + patterns: [ + { + include: '#template-type-substitution-element', + }, + { + include: '#string-character-escape', + }, + ], + }, + ], + }, + 'template-type-substitution-element': { + name: 'meta.template.expression.js', + begin: '\\$\\{', + beginCaptures: { + '0': { + name: 'punctuation.definition.template-expression.begin.js', + }, + }, + end: '\\}', + endCaptures: { + '0': { + name: 'punctuation.definition.template-expression.end.js', + }, + }, + patterns: [ + { + include: '#type', + }, + ], + contentName: 'meta.embedded.line.js', + }, + regex: { + patterns: [ + { + name: 'string.regexp.js', + begin: + '(?|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[\\()]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\]|\\(([^\\)\\\\]|\\\\.)+\\))+\\/([dgimsuvy]+|(?![\\/\\*])|(?=\\/\\*))(?!\\s*[a-zA-Z0-9_$]))', + beginCaptures: { + '1': { + name: 'punctuation.definition.string.begin.js', + }, + }, + end: '(/)([dgimsuvy]*)', + endCaptures: { + '1': { + name: 'punctuation.definition.string.end.js', + }, + '2': { + name: 'keyword.other.js', + }, + }, + patterns: [ + { + include: '#regexp', + }, + ], + }, + { + name: 'string.regexp.js', + begin: + '((?', + captures: { + '0': { + name: 'keyword.other.back-reference.regexp', + }, + '1': { + name: 'variable.other.regexp', + }, + }, + }, + { + name: 'keyword.operator.quantifier.regexp', + match: '[?+*]|\\{(\\d+,\\d+|\\d+,|,\\d+|\\d+)\\}\\??', + }, + { + name: 'keyword.operator.or.regexp', + match: '\\|', + }, + { + name: 'meta.group.assertion.regexp', + begin: '(\\()((\\?=)|(\\?!)|(\\?<=)|(\\?))?', + beginCaptures: { + '0': { + name: 'punctuation.definition.group.regexp', + }, + '1': { + name: 'punctuation.definition.group.no-capture.regexp', + }, + '2': { + name: 'variable.other.regexp', + }, + }, + end: '\\)', + endCaptures: { + '0': { + name: 'punctuation.definition.group.regexp', + }, + }, + patterns: [ + { + include: '#regexp', + }, + ], + }, + { + name: 'constant.other.character-class.set.regexp', + begin: '(\\[)(\\^)?', + beginCaptures: { + '1': { + name: 'punctuation.definition.character-class.regexp', + }, + '2': { + name: 'keyword.operator.negation.regexp', + }, + }, + end: '(\\])', + endCaptures: { + '1': { + name: 'punctuation.definition.character-class.regexp', + }, + }, + patterns: [ + { + name: 'constant.other.character-class.range.regexp', + match: + '(?:.|(\\\\(?:[0-7]{3}|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}))|(\\\\c[A-Z])|(\\\\.))\\-(?:[^\\]\\\\]|(\\\\(?:[0-7]{3}|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}))|(\\\\c[A-Z])|(\\\\.))', + captures: { + '1': { + name: 'constant.character.numeric.regexp', + }, + '2': { + name: 'constant.character.control.regexp', + }, + '3': { + name: 'constant.character.escape.backslash.regexp', + }, + '4': { + name: 'constant.character.numeric.regexp', + }, + '5': { + name: 'constant.character.control.regexp', + }, + '6': { + name: 'constant.character.escape.backslash.regexp', + }, + }, + }, + { + include: '#regex-character-class', + }, + ], + }, + { + include: '#regex-character-class', + }, + ], + }, + 'regex-character-class': { + patterns: [ + { + name: 'constant.other.character-class.regexp', + match: '\\\\[wWsSdDtrnvf]|\\.', + }, + { + name: 'constant.character.numeric.regexp', + match: '\\\\([0-7]{3}|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4})', + }, + { + name: 'constant.character.control.regexp', + match: '\\\\c[A-Z]', + }, + { + name: 'constant.character.escape.backslash.regexp', + match: '\\\\.', + }, + ], + }, + comment: { + patterns: [ + { + name: 'comment.block.documentation.js', + begin: '/\\*\\*(?!/)', + beginCaptures: { + '0': { + name: 'punctuation.definition.comment.js', + }, + }, + end: '\\*/', + endCaptures: { + '0': { + name: 'punctuation.definition.comment.js', + }, + }, + patterns: [ + { + include: '#docblock', + }, + ], + }, + { + name: 'comment.block.js', + begin: '(/\\*)(?:\\s*((@)internal)(?=\\s|(\\*/)))?', + beginCaptures: { + '1': { + name: 'punctuation.definition.comment.js', + }, + '2': { + name: 'storage.type.internaldeclaration.js', + }, + '3': { + name: 'punctuation.decorator.internaldeclaration.js', + }, + }, + end: '\\*/', + endCaptures: { + '0': { + name: 'punctuation.definition.comment.js', + }, + }, + }, + { + begin: '(^[ \\t]+)?((//)(?:\\s*((@)internal)(?=\\s|$))?)', + beginCaptures: { + '1': { + name: 'punctuation.whitespace.comment.leading.js', + }, + '2': { + name: 'comment.line.double-slash.js', + }, + '3': { + name: 'punctuation.definition.comment.js', + }, + '4': { + name: 'storage.type.internaldeclaration.js', + }, + '5': { + name: 'punctuation.decorator.internaldeclaration.js', + }, + }, + end: '(?=$)', + contentName: 'comment.line.double-slash.js', + }, + ], + }, + 'single-line-comment-consuming-line-ending': { + begin: '(^[ \\t]+)?((//)(?:\\s*((@)internal)(?=\\s|$))?)', + beginCaptures: { + '1': { + name: 'punctuation.whitespace.comment.leading.js', + }, + '2': { + name: 'comment.line.double-slash.js', + }, + '3': { + name: 'punctuation.definition.comment.js', + }, + '4': { + name: 'storage.type.internaldeclaration.js', + }, + '5': { + name: 'punctuation.decorator.internaldeclaration.js', + }, + }, + end: '(?=^)', + contentName: 'comment.line.double-slash.js', + }, + directives: { + name: 'comment.line.triple-slash.directive.js', + begin: + '^(///)\\s*(?=<(reference|amd-dependency|amd-module)(\\s+(path|types|no-default-lib|lib|name|resolution-mode)\\s*=\\s*((\\\'([^\\\'\\\\]|\\\\.)*\\\')|(\\"([^\\"\\\\]|\\\\.)*\\")|(\\`([^\\`\\\\]|\\\\.)*\\`)))+\\s*/>\\s*$)', + beginCaptures: { + '1': { + name: 'punctuation.definition.comment.js', + }, + }, + end: '(?=$)', + patterns: [ + { + name: 'meta.tag.js', + begin: '(<)(reference|amd-dependency|amd-module)', + beginCaptures: { + '1': { + name: 'punctuation.definition.tag.directive.js', + }, + '2': { + name: 'entity.name.tag.directive.js', + }, + }, + end: '/>', + endCaptures: { + '0': { + name: 'punctuation.definition.tag.directive.js', + }, + }, + patterns: [ + { + name: 'entity.other.attribute-name.directive.js', + match: 'path|types|no-default-lib|lib|name|resolution-mode', + }, + { + name: 'keyword.operator.assignment.js', + match: '=', + }, + { + include: '#string', + }, + ], + }, + ], + }, + docblock: { + patterns: [ + { + match: '(?x)\n((@)(?:access|api))\n\\s+\n(private|protected|public)\n\\b', + captures: { + '1': { + name: 'storage.type.class.jsdoc', + }, + '2': { + name: 'punctuation.definition.block.tag.jsdoc', + }, + '3': { + name: 'constant.language.access-type.jsdoc', + }, + }, + }, + { + match: + '(?x)\n((@)author)\n\\s+\n(\n [^@\\s<>*/]\n (?:[^@<>*/]|\\*[^/])*\n)\n(?:\n \\s*\n (<)\n ([^>\\s]+)\n (>)\n)?', + captures: { + '1': { + name: 'storage.type.class.jsdoc', + }, + '2': { + name: 'punctuation.definition.block.tag.jsdoc', + }, + '3': { + name: 'entity.name.type.instance.jsdoc', + }, + '4': { + name: 'punctuation.definition.bracket.angle.begin.jsdoc', + }, + '5': { + name: 'constant.other.email.link.underline.jsdoc', + }, + '6': { + name: 'punctuation.definition.bracket.angle.end.jsdoc', + }, + }, + }, + { + match: + '(?x)\n((@)borrows) \\s+\n((?:[^@\\s*/]|\\*[^/])+) # \n\\s+ (as) \\s+ # as\n((?:[^@\\s*/]|\\*[^/])+) # ', + captures: { + '1': { + name: 'storage.type.class.jsdoc', + }, + '2': { + name: 'punctuation.definition.block.tag.jsdoc', + }, + '3': { + name: 'entity.name.type.instance.jsdoc', + }, + '4': { + name: 'keyword.operator.control.jsdoc', + }, + '5': { + name: 'entity.name.type.instance.jsdoc', + }, + }, + }, + { + name: 'meta.example.jsdoc', + begin: '((@)example)\\s+', + end: '(?=@|\\*/)', + beginCaptures: { + '1': { + name: 'storage.type.class.jsdoc', + }, + '2': { + name: 'punctuation.definition.block.tag.jsdoc', + }, + }, + patterns: [ + { + match: '^\\s\\*\\s+', + }, + { + contentName: 'constant.other.description.jsdoc', + begin: '\\G(<)caption(>)', + beginCaptures: { + '0': { + name: 'entity.name.tag.inline.jsdoc', + }, + '1': { + name: 'punctuation.definition.bracket.angle.begin.jsdoc', + }, + '2': { + name: 'punctuation.definition.bracket.angle.end.jsdoc', + }, + }, + end: '()|(?=\\*/)', + endCaptures: { + '0': { + name: 'entity.name.tag.inline.jsdoc', + }, + '1': { + name: 'punctuation.definition.bracket.angle.begin.jsdoc', + }, + '2': { + name: 'punctuation.definition.bracket.angle.end.jsdoc', + }, + }, + }, + { + match: '[^\\s@*](?:[^*]|\\*[^/])*', + captures: { + '0': { + name: 'source.embedded.js', + }, + }, + }, + ], + }, + { + match: + '(?x) ((@)kind) \\s+ (class|constant|event|external|file|function|member|mixin|module|namespace|typedef) \\b', + captures: { + '1': { + name: 'storage.type.class.jsdoc', + }, + '2': { + name: 'punctuation.definition.block.tag.jsdoc', + }, + '3': { + name: 'constant.language.symbol-type.jsdoc', + }, + }, + }, + { + match: + '(?x)\n((@)see)\n\\s+\n(?:\n # URL\n (\n (?=https?://)\n (?:[^\\s*]|\\*[^/])+\n )\n |\n # JSDoc namepath\n (\n (?!\n # Avoid matching bare URIs (also acceptable as links)\n https?://\n |\n # Avoid matching {@inline tags}; we match those below\n (?:\\[[^\\[\\]]*\\])? # Possible description [preceding]{@tag}\n {@(?:link|linkcode|linkplain|tutorial)\\b\n )\n # Matched namepath\n (?:[^@\\s*/]|\\*[^/])+\n )\n)', + captures: { + '1': { + name: 'storage.type.class.jsdoc', + }, + '2': { + name: 'punctuation.definition.block.tag.jsdoc', + }, + '3': { + name: 'variable.other.link.underline.jsdoc', + }, + '4': { + name: 'entity.name.type.instance.jsdoc', + }, + }, + }, + { + match: + '(?x)\n((@)template)\n\\s+\n# One or more valid identifiers\n(\n [A-Za-z_$] # First character: non-numeric word character\n [\\w$.\\[\\]]* # Rest of identifier\n (?: # Possible list of additional identifiers\n \\s* , \\s*\n [A-Za-z_$]\n [\\w$.\\[\\]]*\n )*\n)', + captures: { + '1': { + name: 'storage.type.class.jsdoc', + }, + '2': { + name: 'punctuation.definition.block.tag.jsdoc', + }, + '3': { + name: 'variable.other.jsdoc', + }, + }, + }, + { + begin: '(?x)((@)template)\\s+(?={)', + beginCaptures: { + '1': { + name: 'storage.type.class.jsdoc', + }, + '2': { + name: 'punctuation.definition.block.tag.jsdoc', + }, + }, + end: '(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])', + patterns: [ + { + include: '#jsdoctype', + }, + { + name: 'variable.other.jsdoc', + match: '([A-Za-z_$][\\w$.\\[\\]]*)', + }, + ], + }, + { + match: + '(?x)\n(\n (@)\n (?:arg|argument|const|constant|member|namespace|param|var)\n)\n\\s+\n(\n [A-Za-z_$]\n [\\w$.\\[\\]]*\n)', + captures: { + '1': { + name: 'storage.type.class.jsdoc', + }, + '2': { + name: 'punctuation.definition.block.tag.jsdoc', + }, + '3': { + name: 'variable.other.jsdoc', + }, + }, + }, + { + begin: '((@)typedef)\\s+(?={)', + beginCaptures: { + '1': { + name: 'storage.type.class.jsdoc', + }, + '2': { + name: 'punctuation.definition.block.tag.jsdoc', + }, + }, + end: '(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])', + patterns: [ + { + include: '#jsdoctype', + }, + { + name: 'entity.name.type.instance.jsdoc', + match: '(?:[^@\\s*/]|\\*[^/])+', + }, + ], + }, + { + begin: + '((@)(?:arg|argument|const|constant|member|namespace|param|prop|property|var))\\s+(?={)', + beginCaptures: { + '1': { + name: 'storage.type.class.jsdoc', + }, + '2': { + name: 'punctuation.definition.block.tag.jsdoc', + }, + }, + end: '(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])', + patterns: [ + { + include: '#jsdoctype', + }, + { + name: 'variable.other.jsdoc', + match: '([A-Za-z_$][\\w$.\\[\\]]*)', + }, + { + name: 'variable.other.jsdoc', + match: + '(?x)\n(\\[)\\s*\n[\\w$]+\n(?:\n (?:\\[\\])? # Foo[ ].bar properties within an array\n \\. # Foo.Bar namespaced parameter\n [\\w$]+\n)*\n(?:\n \\s*\n (=) # [foo=bar] Default parameter value\n \\s*\n (\n # The inner regexes are to stop the match early at */ and to not stop at escaped quotes\n (?>\n "(?:(?:\\*(?!/))|(?:\\\\(?!"))|[^*\\\\])*?" | # [foo="bar"] Double-quoted\n \'(?:(?:\\*(?!/))|(?:\\\\(?!\'))|[^*\\\\])*?\' | # [foo=\'bar\'] Single-quoted\n \\[ (?:(?:\\*(?!/))|[^*])*? \\] | # [foo=[1,2]] Array literal\n (?:(?:\\*(?!/))|\\s(?!\\s*\\])|\\[.*?(?:\\]|(?=\\*/))|[^*\\s\\[\\]])* # Everything else\n )*\n )\n)?\n\\s*(?:(\\])((?:[^*\\s]|\\*[^\\s/])+)?|(?=\\*/))', + captures: { + '1': { + name: 'punctuation.definition.optional-value.begin.bracket.square.jsdoc', + }, + '2': { + name: 'keyword.operator.assignment.jsdoc', + }, + '3': { + name: 'source.embedded.js', + }, + '4': { + name: 'punctuation.definition.optional-value.end.bracket.square.jsdoc', + }, + '5': { + name: 'invalid.illegal.syntax.jsdoc', + }, + }, + }, + ], + }, + { + begin: + '(?x)\n(\n (@)\n (?:define|enum|exception|export|extends|lends|implements|modifies\n |namespace|private|protected|returns?|satisfies|suppress|this|throws|type\n |yields?)\n)\n\\s+(?={)', + beginCaptures: { + '1': { + name: 'storage.type.class.jsdoc', + }, + '2': { + name: 'punctuation.definition.block.tag.jsdoc', + }, + }, + end: '(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])', + patterns: [ + { + include: '#jsdoctype', + }, + ], + }, + { + match: + '(?x)\n(\n (@)\n (?:alias|augments|callback|constructs|emits|event|fires|exports?\n |extends|external|function|func|host|lends|listens|interface|memberof!?\n |method|module|mixes|mixin|name|requires|see|this|typedef|uses)\n)\n\\s+\n(\n (?:\n [^{}@\\s*] | \\*[^/]\n )+\n)', + captures: { + '1': { + name: 'storage.type.class.jsdoc', + }, + '2': { + name: 'punctuation.definition.block.tag.jsdoc', + }, + '3': { + name: 'entity.name.type.instance.jsdoc', + }, + }, + }, + { + contentName: 'variable.other.jsdoc', + begin: "((@)(?:default(?:value)?|license|version))\\s+(([''\"]))", + beginCaptures: { + '1': { + name: 'storage.type.class.jsdoc', + }, + '2': { + name: 'punctuation.definition.block.tag.jsdoc', + }, + '3': { + name: 'variable.other.jsdoc', + }, + '4': { + name: 'punctuation.definition.string.begin.jsdoc', + }, + }, + end: '(\\3)|(?=$|\\*/)', + endCaptures: { + '0': { + name: 'variable.other.jsdoc', + }, + '1': { + name: 'punctuation.definition.string.end.jsdoc', + }, + }, + }, + { + match: '((@)(?:default(?:value)?|license|tutorial|variation|version))\\s+([^\\s*]+)', + captures: { + '1': { + name: 'storage.type.class.jsdoc', + }, + '2': { + name: 'punctuation.definition.block.tag.jsdoc', + }, + '3': { + name: 'variable.other.jsdoc', + }, + }, + }, + { + name: 'storage.type.class.jsdoc', + match: + '(?x) (@) (?:abstract|access|alias|api|arg|argument|async|attribute|augments|author|beta|borrows|bubbles |callback|chainable|class|classdesc|code|config|const|constant|constructor|constructs|copyright |default|defaultvalue|define|deprecated|desc|description|dict|emits|enum|event|example|exception |exports?|extends|extension(?:_?for)?|external|externs|file|fileoverview|final|fires|for|func |function|generator|global|hideconstructor|host|ignore|implements|implicitCast|inherit[Dd]oc |inner|instance|interface|internal|kind|lends|license|listens|main|member|memberof!?|method |mixes|mixins?|modifies|module|name|namespace|noalias|nocollapse|nocompile|nosideeffects |override|overview|package|param|polymer(?:Behavior)?|preserve|private|prop|property|protected |public|read[Oo]nly|record|require[ds]|returns?|see|since|static|struct|submodule|summary |suppress|template|this|throws|todo|tutorial|type|typedef|unrestricted|uses|var|variation |version|virtual|writeOnce|yields?) \\b', + captures: { + '1': { + name: 'punctuation.definition.block.tag.jsdoc', + }, + }, + }, + { + include: '#inline-tags', + }, + { + match: '((@)(?:[_$[:alpha:]][_$[:alnum:]]*))(?=\\s+)', + captures: { + '1': { + name: 'storage.type.class.jsdoc', + }, + '2': { + name: 'punctuation.definition.block.tag.jsdoc', + }, + }, + }, + ], + }, + brackets: { + patterns: [ + { + begin: '{', + end: '}|(?=\\*/)', + patterns: [ + { + include: '#brackets', + }, + ], + }, + { + begin: '\\[', + end: '\\]|(?=\\*/)', + patterns: [ + { + include: '#brackets', + }, + ], + }, + ], + }, + 'inline-tags': { + patterns: [ + { + name: 'constant.other.description.jsdoc', + match: '(\\[)[^\\]]+(\\])(?={@(?:link|linkcode|linkplain|tutorial))', + captures: { + '1': { + name: 'punctuation.definition.bracket.square.begin.jsdoc', + }, + '2': { + name: 'punctuation.definition.bracket.square.end.jsdoc', + }, + }, + }, + { + name: 'entity.name.type.instance.jsdoc', + begin: '({)((@)(?:link(?:code|plain)?|tutorial))\\s*', + beginCaptures: { + '1': { + name: 'punctuation.definition.bracket.curly.begin.jsdoc', + }, + '2': { + name: 'storage.type.class.jsdoc', + }, + '3': { + name: 'punctuation.definition.inline.tag.jsdoc', + }, + }, + end: '}|(?=\\*/)', + endCaptures: { + '0': { + name: 'punctuation.definition.bracket.curly.end.jsdoc', + }, + }, + patterns: [ + { + match: '\\G((?=https?://)(?:[^|}\\s*]|\\*[/])+)(\\|)?', + captures: { + '1': { + name: 'variable.other.link.underline.jsdoc', + }, + '2': { + name: 'punctuation.separator.pipe.jsdoc', + }, + }, + }, + { + match: '\\G((?:[^{}@\\s|*]|\\*[^/])+)(\\|)?', + captures: { + '1': { + name: 'variable.other.description.jsdoc', + }, + '2': { + name: 'punctuation.separator.pipe.jsdoc', + }, + }, + }, + ], + }, + ], + }, + jsdoctype: { + patterns: [ + { + contentName: 'entity.name.type.instance.jsdoc', + begin: '\\G({)', + beginCaptures: { + '0': { + name: 'entity.name.type.instance.jsdoc', + }, + '1': { + name: 'punctuation.definition.bracket.curly.begin.jsdoc', + }, + }, + end: '((}))\\s*|(?=\\*/)', + endCaptures: { + '1': { + name: 'entity.name.type.instance.jsdoc', + }, + '2': { + name: 'punctuation.definition.bracket.curly.end.jsdoc', + }, + }, + patterns: [ + { + include: '#brackets', + }, + ], + }, + ], + }, + jsx: { + patterns: [ + { + include: '#jsx-tag-style', + }, + { + include: '#jsx-tag-without-attributes', + }, + { + include: '#jsx-tag', + }, + ], + }, + 'jsx-tag-without-attributes-in-expression': { + begin: + '(?:*]|&&|\\|\\||\\?|\\*\\/|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^yield|[^\\._$[:alnum:]]yield|^)\\s*(?=(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))', + end: '(?!(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))', + patterns: [ + { + include: '#jsx-tag-without-attributes', + }, + ], + }, + 'jsx-tag-without-attributes': { + name: 'meta.tag.without-attributes.js', + begin: + '(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?)', + end: '()', + beginCaptures: { + '1': { + name: 'punctuation.definition.tag.begin.js', + }, + '2': { + name: 'entity.name.tag.namespace.js', + }, + '3': { + name: 'punctuation.separator.namespace.js', + }, + '4': { + name: 'entity.name.tag.js', + }, + '5': { + name: 'support.class.component.js', + }, + '6': { + name: 'punctuation.definition.tag.end.js', + }, + }, + endCaptures: { + '1': { + name: 'punctuation.definition.tag.begin.js', + }, + '2': { + name: 'entity.name.tag.namespace.js', + }, + '3': { + name: 'punctuation.separator.namespace.js', + }, + '4': { + name: 'entity.name.tag.js', + }, + '5': { + name: 'support.class.component.js', + }, + '6': { + name: 'punctuation.definition.tag.end.js', + }, + }, + contentName: 'meta.jsx.children.js', + patterns: [ + { + include: '#jsx-children', + }, + ], + }, + 'jsx-tag-in-expression': { + begin: + '(?x)\n (?:*]|&&|\\|\\||\\?|\\*\\/|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^yield|[^\\._$[:alnum:]]yield|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))', + end: '(?!(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))', + patterns: [ + { + include: '#jsx-tag', + }, + ], + }, + 'jsx-tag-style': { + name: 'style.tag.js', + begin: '(<)\\s*(style)\\b(?![^>]*/>)(?=[^>]*>)', + beginCaptures: { + '1': { + name: 'punctuation.definition.tag.begin.js', + }, + '2': { + name: 'entity.name.tag.js', + }, + }, + end: '()', + endCaptures: { + '1': { + name: 'punctuation.definition.tag.begin.js', + }, + '2': { + name: 'entity.name.tag.js', + }, + '3': { + name: 'punctuation.definition.tag.end.js', + }, + }, + patterns: [ + { + begin: '(>)', + beginCaptures: { + '1': { + name: 'punctuation.definition.tag.end.js', + }, + }, + end: '(?=)', + contentName: 'source.css', + patterns: [ + { + include: 'source.css', + }, + ], + }, + { + begin: '(?<=]*/>)', + end: '(?=>)', + patterns: [ + { + include: '#jsx-tag-attributes', + }, + ], + }, + ], + }, + 'jsx-tag': { + name: 'meta.tag.js', + begin: + '(?=(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))', + end: '(/>)|(?:())', + endCaptures: { + '1': { + name: 'punctuation.definition.tag.end.js', + }, + '2': { + name: 'punctuation.definition.tag.begin.js', + }, + '3': { + name: 'entity.name.tag.namespace.js', + }, + '4': { + name: 'punctuation.separator.namespace.js', + }, + '5': { + name: 'entity.name.tag.js', + }, + '6': { + name: 'support.class.component.js', + }, + '7': { + name: 'punctuation.definition.tag.end.js', + }, + }, + patterns: [ + { + begin: + '(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?)', + beginCaptures: { + '1': { + name: 'punctuation.definition.tag.begin.js', + }, + '2': { + name: 'entity.name.tag.namespace.js', + }, + '3': { + name: 'punctuation.separator.namespace.js', + }, + '4': { + name: 'entity.name.tag.js', + }, + '5': { + name: 'support.class.component.js', + }, + }, + end: '(?=[/]?>)', + patterns: [ + { + include: '#comment', + }, + { + include: '#type-arguments', + }, + { + include: '#jsx-tag-attributes', + }, + ], + }, + { + begin: '(>)', + beginCaptures: { + '1': { + name: 'punctuation.definition.tag.end.js', + }, + }, + end: '(?=)', + patterns: [ + { + include: '#comment', + }, + { + include: '#jsx-tag-attribute-name', + }, + { + include: '#jsx-tag-attribute-assignment', + }, + { + include: '#jsx-string-double-quoted', + }, + { + include: '#jsx-string-single-quoted', + }, + { + include: '#jsx-evaluated-code', + }, + { + include: '#jsx-tag-attributes-illegal', + }, + ], + }, + 'jsx-tag-attribute-name': { + match: + '(?x)\n \\s*\n (?:([_$[:alpha:]][-_$[:alnum:].]*)(:))?\n ([_$[:alpha:]][-_$[:alnum:]]*)\n (?=\\s|=|/?>|/\\*|//)', + captures: { + '1': { + name: 'entity.other.attribute-name.namespace.js', + }, + '2': { + name: 'punctuation.separator.namespace.js', + }, + '3': { + name: 'entity.other.attribute-name.js', + }, + }, + }, + 'jsx-tag-attribute-assignment': { + name: 'keyword.operator.assignment.js', + match: '=(?=\\s*(?:\'|"|{|/\\*|//|\\n))', + }, + 'jsx-string-double-quoted': { + name: 'string.quoted.double.js', + begin: '"', + end: '"', + beginCaptures: { + '0': { + name: 'punctuation.definition.string.begin.js', + }, + }, + endCaptures: { + '0': { + name: 'punctuation.definition.string.end.js', + }, + }, + patterns: [ + { + include: '#jsx-entities', + }, + ], + }, + 'jsx-string-single-quoted': { + name: 'string.quoted.single.js', + begin: "'", + end: "'", + beginCaptures: { + '0': { + name: 'punctuation.definition.string.begin.js', + }, + }, + endCaptures: { + '0': { + name: 'punctuation.definition.string.end.js', + }, + }, + patterns: [ + { + include: '#jsx-entities', + }, + ], + }, + 'jsx-tag-attributes-illegal': { + name: 'invalid.illegal.attribute.js', + match: '\\S+', + }, + }, + }, + + config: { + // Note that this file should stay in sync with 'typescript-language-basics/language-configuration.json' + // onEnterRules cause errors - currently disabled + comments: { + lineComment: '//', + blockComment: ['/*', '*/'], + }, + brackets: [ + ['${', '}'], + ['{', '}'], + ['[', ']'], + ['(', ')'], + ], + autoClosingPairs: [ + { + open: '{', + close: '}', + }, + { + open: '[', + close: ']', + }, + { + open: '(', + close: ')', + }, + { + open: "'", + close: "'", + notIn: ['string', 'comment'], + }, + { + open: '"', + close: '"', + notIn: ['string'], + }, + { + open: '`', + close: '`', + notIn: ['string', 'comment'], + }, + { + open: '/**', + close: ' */', + notIn: ['string'], + }, + ], + surroundingPairs: [ + ['{', '}'], + ['[', ']'], + ['(', ')'], + ["'", "'"], + ['"', '"'], + ['`', '`'], + ['<', '>'], + ], + autoCloseBefore: ';:.,=}])>` \n\t', + folding: { + markers: { + start: '^\\s*//\\s*#?region\\b', + end: '^\\s*//\\s*#?endregion\\b', + }, + }, + wordPattern: { + pattern: + '(-?\\d*\\.\\d\\w*)|([^\\`\\~\\@\\!\\%\\^\\&\\*\\(\\)\\-\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\\'\\"\\,\\.\\<\\>/\\?\\s]+)', + }, + indentationRules: { + decreaseIndentPattern: { + pattern: '^\\s*[\\}\\]\\)].*$', + }, + increaseIndentPattern: { + pattern: '^.*(\\{[^}]*|\\([^)]*|\\[[^\\]]*)$', + }, + // e.g. * ...| or */| or *-----*/| + unIndentedLinePattern: { + pattern: + '^(\\t|[ ])*[ ]\\*[^/]*\\*/\\s*$|^(\\t|[ ])*[ ]\\*/\\s*$|^(\\t|[ ])*[ ]\\*([ ]([^\\*]|\\*(?!/))*)?$', + }, + indentNextLinePattern: { + pattern: '^((.*=>\\s*)|((.*[^\\w]+|\\s*)(if|while|for)\\s*\\(.*\\)\\s*))$', + }, + }, + // onEnterRules: [ + // { + // // e.g. /** | */ + // beforeText: { + // pattern: '^\\s*/\\*\\*(?!/)([^\\*]|\\*(?!/))*$', + // }, + // afterText: { + // pattern: '^\\s*\\*/$', + // }, + // action: { + // indent: 'indentOutdent', + // appendText: ' * ', + // }, + // }, + // { + // // e.g. /** ...| + // beforeText: { + // pattern: '^\\s*/\\*\\*(?!/)([^\\*]|\\*(?!/))*$', + // }, + // action: { + // indent: 'none', + // appendText: ' * ', + // }, + // }, + // { + // // e.g. * ...| + // beforeText: { + // pattern: '^(\\t|[ ])*[ ]\\*([ ]([^\\*]|\\*(?!/))*)?$', + // }, + // previousLineText: { + // pattern: '(?=^(\\s*(/\\*\\*|\\*)).*)(?=(?!(\\s*\\*/)))', + // }, + // action: { + // indent: 'none', + // appendText: '* ', + // }, + // }, + // { + // // e.g. */| + // beforeText: { + // pattern: '^(\\t|[ ])*[ ]\\*/\\s*$', + // }, + // action: { + // indent: 'none', + // removeText: 1, + // }, + // }, + // { + // // e.g. *-----*/| + // beforeText: { + // pattern: '^(\\t|[ ])*[ ]\\*[^/]*\\*/\\s*$', + // }, + // action: { + // indent: 'none', + // removeText: 1, + // }, + // }, + // { + // beforeText: { + // pattern: '^\\s*(\\bcase\\s.+:|\\bdefault:)$', + // }, + // afterText: { + // pattern: '^(?!\\s*(\\bcase\\b|\\bdefault\\b))', + // }, + // action: { + // indent: 'indent', + // }, + // }, + // { + // // Decrease indentation after single line if/else if/else, for, or while + // previousLineText: '^\\s*(((else ?)?if|for|while)\\s*\\(.*\\)\\s*|else\\s*)$', + // // But make sure line doesn't have braces or is not another if statement + // beforeText: '^\\s+([^{i\\s]|i(?!f\\b))', + // action: { + // indent: 'outdent', + // }, + // }, + // // Indent when pressing enter from inside () + // { + // beforeText: '^.*\\([^\\)]*$', + // afterText: '^\\s*\\).*$', + // action: { + // indent: 'indentOutdent', + // appendText: '\t', + // }, + // }, + // // Indent when pressing enter from inside {} + // { + // beforeText: '^.*\\{[^\\}]*$', + // afterText: '^\\s*\\}.*$', + // action: { + // indent: 'indentOutdent', + // appendText: '\t', + // }, + // }, + // // Indent when pressing enter from inside [] + // { + // beforeText: '^.*\\[[^\\]]*$', + // afterText: '^\\s*\\].*$', + // action: { + // indent: 'indentOutdent', + // appendText: '\t', + // }, + // }, + // // Add // when pressing enter from inside line comment + // { + // beforeText: { + // pattern: '(? astro: baseUrl + '{{hash:monaco-lang-astro.js}}', clio: baseUrl + '{{hash:monaco-lang-clio.js}}', imba: baseUrl + '{{hash:monaco-lang-imba.js}}', + ripple: baseUrl + '{{hash:monaco-lang-ripple.js}}', // sql: baseUrl + '{{hash:monaco-lang-sql.js}}', // TODO: add autocomplete wat: baseUrl + '{{hash:monaco-lang-wat.js}}', }; @@ -260,6 +265,7 @@ export const createEditor = async (options: EditorOptions): Promise interface CustomLanguageDefinition { config?: Monaco.languages.LanguageConfiguration; tokens?: Monaco.languages.IMonarchLanguage; + syntax?: Record; } const addVueSupport = async () => { @@ -274,6 +280,46 @@ export const createEditor = async (options: EditorOptions): Promise setTheme(currentTheme, currentEditorTheme); }; + async function registerFromTextMate({ + name, + scopeName, + syntax, + }: { + name: string; + scopeName: string; + syntax: string; + }) { + await addVueSupport(); // a workaround for TextMate syntax + + const { loadWASM } = await import(onigasmUrl); + const { Registry } = await import(monacoTextmateUrl); + const { wireTmGrammars } = await import(monacoEditorTextmateUrl); + + await loadWASM(onigasmWasmUrl); + + const registry = new Registry({ + getGrammarDefinition: async (_scopeName: string) => { + return { + format: 'json', + content: syntax, + }; + }, + }); + + const grammars = new Map(); + grammars.set(name, scopeName); + monaco.languages.register({ id: name }); + await wireTmGrammars(monaco, registry, grammars, editor); + } + + const addRippleSupport = async (syntax: CustomLanguageDefinition['syntax']) => { + await registerFromTextMate({ + name: 'ripple', + scopeName: 'source.ripple', + syntax: JSON.stringify(syntax, null, 2).replace('"name": "Ripple"', '"name": "ripple"'), + }); + }; + const loadMonacoLanguage = async (lang: Language) => { if (monacoMapLanguage(lang) === 'vue') { await addVueSupport(); @@ -289,6 +335,10 @@ export const createEditor = async (options: EditorOptions): Promise if (mod.tokens) { monaco.languages.setMonarchTokensProvider(lang, mod.tokens); } + if (lang === 'ripple') { + await addRippleSupport(mod.syntax); + return; + } } }; diff --git a/src/livecodes/languages/ripple/lang-ripple.ts b/src/livecodes/languages/ripple/lang-ripple.ts index 3f30bb9b43..8afe23152f 100644 --- a/src/livecodes/languages/ripple/lang-ripple.ts +++ b/src/livecodes/languages/ripple/lang-ripple.ts @@ -27,5 +27,4 @@ export const ripple: LanguageSpecs = { }, extensions: ['ripple'], editor: 'script', - editorLanguage: 'typescript', }; diff --git a/src/livecodes/vendors.ts b/src/livecodes/vendors.ts index b0207c7aee..0945e7f014 100644 --- a/src/livecodes/vendors.ts +++ b/src/livecodes/vendors.ts @@ -295,8 +295,12 @@ export const mjmlUrl = /* @__PURE__ */ getUrl('mjml-browser@4.15.3/lib/index.js' export const monacoBaseUrl = /* @__PURE__ */ getUrl('@live-codes/monaco-editor@0.3.0/'); +export const monacoEditorTextmateUrl = /* @__PURE__ */ getModuleUrl('monaco-editor-textmate@4.0.0'); + export const monacoEmacsUrl = /* @__PURE__ */ getUrl('monaco-emacs@0.3.0/dist/monaco-emacs.js'); +export const monacoTextmateUrl = /* @__PURE__ */ getModuleUrl('monaco-textmate@3.0.1'); + export const monacoThemesBaseUrl = /* @__PURE__ */ getUrl('monaco-themes@0.4.4/themes/'); export const monacoVimUrl = /* @__PURE__ */ getUrl('monaco-vim@0.4.1/dist/monaco-vim.js'); @@ -315,6 +319,10 @@ export const normalizeCssUrl = /* @__PURE__ */ getUrl('normalize.css@8.0.1/norma export const nunjucksBaseUrl = /* @__PURE__ */ getUrl('nunjucks@3.2.4/browser/'); +export const onigasmUrl = /* @__PURE__ */ getModuleUrl('onigasm@2.2.5'); + +export const onigasmWasmUrl = /* @__PURE__ */ getUrl('onigasm@2.2.5/lib/onigasm.wasm'); + export const opalBaseUrl = /* @__PURE__ */ getUrl('https://cdn.opalrb.com/opal/1.8.2/'); export const parinferUrl = /* @__PURE__ */ getUrl('parinfer@3.13.1/parinfer.js'); @@ -389,7 +397,7 @@ export const resetCssUrl = /* @__PURE__ */ getUrl('reset-css@5.0.1/reset.css'); export const riotBaseUrl = /* @__PURE__ */ getUrl('riot@9.2.2/'); -export const rippleUrl = /* @__PURE__ */ getModuleUrl('ripple@0.2.5/compiler'); +export const rippleUrl = /* @__PURE__ */ getModuleUrl('ripple@0.2.6/compiler'); export const rubyWasmBaseUrl = /* @__PURE__ */ getUrl('@ruby/3.3-wasm-wasi@2.6.2/dist/'); From ce7fea3fd72fd2ebc3d8d4d6cc9f155af1e52d52 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Sat, 6 Sep 2025 21:32:32 +0300 Subject: [PATCH 29/71] add support for CSS in Ripple components --- .../monaco/languages/monaco-lang-ripple.ts | 1841 +++++++++++++++++ src/livecodes/editor/monaco/monaco.ts | 51 +- 2 files changed, 1871 insertions(+), 21 deletions(-) diff --git a/src/livecodes/editor/monaco/languages/monaco-lang-ripple.ts b/src/livecodes/editor/monaco/languages/monaco-lang-ripple.ts index 392d2620d0..30aca96d4f 100644 --- a/src/livecodes/editor/monaco/languages/monaco-lang-ripple.ts +++ b/src/livecodes/editor/monaco/languages/monaco-lang-ripple.ts @@ -1,5 +1,6 @@ // from https://github.com/trueadm/ripple/blob/main/packages/ripple-vscode-plugin/syntaxes/ripple.tmLanguage.json // and https://github.com/trueadm/ripple/blob/main/packages/ripple-vscode-plugin/language-configuration.json +// and 'https://cdn.jsdelivr.net/gh/zikaari/monaco-textmate-languages@master/grammars/css/css.tmLanguage.json' export default { syntax: { information_for_contributors: [ @@ -6853,4 +6854,1844 @@ export default { // }, // ], }, + + cssSyntax: { + information_for_contributors: [ + 'This file has been converted from https://github.com/atom/language-css/blob/master/grammars/css.cson', + 'If you want to provide a fix or improvement, please create a pull request against the original repository.', + 'Once accepted there, we are happy to receive an update request.', + ], + version: 'https://github.com/atom/language-css/commit/2bc1e294e2440ad91197263cd9f95dc4b00bab2f', + name: 'CSS', + scopeName: 'source.css', + patterns: [ + { + include: '#comment-block', + }, + { + include: '#escapes', + }, + { + include: '#combinators', + }, + { + include: '#selector', + }, + { + include: '#at-rules', + }, + { + include: '#rule-list', + }, + ], + repository: { + 'at-rules': { + patterns: [ + { + begin: '\\A(?:\\xEF\\xBB\\xBF)?(?i:(?=\\s*@charset\\b))', + end: ';|(?=$)', + endCaptures: { + '0': { + name: 'punctuation.terminator.rule.css', + }, + }, + name: 'meta.at-rule.charset.css', + patterns: [ + { + captures: { + '1': { + name: 'invalid.illegal.not-lowercase.charset.css', + }, + '2': { + name: 'invalid.illegal.leading-whitespace.charset.css', + }, + '3': { + name: 'invalid.illegal.no-whitespace.charset.css', + }, + '4': { + name: 'invalid.illegal.whitespace.charset.css', + }, + '5': { + name: 'invalid.illegal.not-double-quoted.charset.css', + }, + '6': { + name: 'invalid.illegal.unclosed-string.charset.css', + }, + '7': { + name: 'invalid.illegal.unexpected-characters.charset.css', + }, + }, + match: + '(?x) # Possible errors:\n\\G\n((?!@charset)@\\w+) # Not lowercase (@charset is case-sensitive)\n|\n\\G(\\s+) # Preceding whitespace\n|\n(@charset\\S[^;]*) # No whitespace after @charset\n|\n(?<=@charset) # Before quoted charset name\n(\\x20{2,}|\\t+) # More than one space used, or a tab\n|\n(?<=@charset\\x20) # Beginning of charset name\n([^";]+) # Not double-quoted\n|\n("[^"]+$) # Unclosed quote\n|\n(?<=") # After charset name\n([^;]+) # Unexpected junk instead of semicolon', + }, + { + captures: { + '1': { + name: 'keyword.control.at-rule.charset.css', + }, + '2': { + name: 'punctuation.definition.keyword.css', + }, + }, + match: '((@)charset)(?=\\s)', + }, + { + begin: '"', + beginCaptures: { + '0': { + name: 'punctuation.definition.string.begin.css', + }, + }, + end: '"|$', + endCaptures: { + '0': { + name: 'punctuation.definition.string.end.css', + }, + }, + name: 'string.quoted.double.css', + patterns: [ + { + begin: '(?:\\G|^)(?=(?:[^"])+$)', + end: '$', + name: 'invalid.illegal.unclosed.string.css', + }, + ], + }, + ], + }, + { + begin: '(?i)((@)import)(?:\\s+|$|(?=[\'"]|/\\*))', + beginCaptures: { + '1': { + name: 'keyword.control.at-rule.import.css', + }, + '2': { + name: 'punctuation.definition.keyword.css', + }, + }, + end: ';', + endCaptures: { + '0': { + name: 'punctuation.terminator.rule.css', + }, + }, + name: 'meta.at-rule.import.css', + patterns: [ + { + begin: '\\G\\s*(?=/\\*)', + end: '(?<=\\*/)\\s*', + patterns: [ + { + include: '#comment-block', + }, + ], + }, + { + include: '#string', + }, + { + include: '#url', + }, + { + include: '#media-query-list', + }, + ], + }, + { + begin: '(?i)((@)font-face)(?=\\s*|{|/\\*|$)', + beginCaptures: { + '1': { + name: 'keyword.control.at-rule.font-face.css', + }, + '2': { + name: 'punctuation.definition.keyword.css', + }, + }, + end: '(?!\\G)', + name: 'meta.at-rule.font-face.css', + patterns: [ + { + include: '#comment-block', + }, + { + include: '#escapes', + }, + { + include: '#rule-list', + }, + ], + }, + { + begin: '(?i)(@)page(?=[\\s:{]|/\\*|$)', + captures: { + '0': { + name: 'keyword.control.at-rule.page.css', + }, + '1': { + name: 'punctuation.definition.keyword.css', + }, + }, + end: '(?=\\s*($|[:{;]))', + name: 'meta.at-rule.page.css', + patterns: [ + { + include: '#rule-list', + }, + ], + }, + { + begin: '(?i)(?=@media(\\s|\\(|/\\*|$))', + end: '(?<=})(?!\\G)', + patterns: [ + { + begin: '(?i)\\G(@)media', + beginCaptures: { + '0': { + name: 'keyword.control.at-rule.media.css', + }, + '1': { + name: 'punctuation.definition.keyword.css', + }, + }, + end: '(?=\\s*[{;])', + name: 'meta.at-rule.media.header.css', + patterns: [ + { + include: '#media-query-list', + }, + ], + }, + { + begin: '{', + beginCaptures: { + '0': { + name: 'punctuation.section.media.begin.bracket.curly.css', + }, + }, + end: '}', + endCaptures: { + '0': { + name: 'punctuation.section.media.end.bracket.curly.css', + }, + }, + name: 'meta.at-rule.media.body.css', + patterns: [ + { + include: '$self', + }, + ], + }, + ], + }, + { + begin: '(?i)(?=@counter-style([\\s\'"{;]|/\\*|$))', + end: '(?<=})(?!\\G)', + patterns: [ + { + begin: '(?i)\\G(@)counter-style', + beginCaptures: { + '0': { + name: 'keyword.control.at-rule.counter-style.css', + }, + '1': { + name: 'punctuation.definition.keyword.css', + }, + }, + end: '(?=\\s*{)', + name: 'meta.at-rule.counter-style.header.css', + patterns: [ + { + include: '#comment-block', + }, + { + include: '#escapes', + }, + { + captures: { + '0': { + patterns: [ + { + include: '#escapes', + }, + ], + }, + }, + match: + '(?x)\n(?:[-a-zA-Z_] | [^\\x00-\\x7F]) # First letter\n(?:[-a-zA-Z0-9_] | [^\\x00-\\x7F] # Remainder of identifier\n |\\\\(?:[0-9a-fA-F]{1,6}|.)\n)*', + name: 'variable.parameter.style-name.css', + }, + ], + }, + { + begin: '{', + beginCaptures: { + '0': { + name: 'punctuation.section.property-list.begin.bracket.curly.css', + }, + }, + end: '}', + endCaptures: { + '0': { + name: 'punctuation.section.property-list.end.bracket.curly.css', + }, + }, + name: 'meta.at-rule.counter-style.body.css', + patterns: [ + { + include: '#comment-block', + }, + { + include: '#escapes', + }, + { + include: '#rule-list-innards', + }, + ], + }, + ], + }, + { + begin: '(?i)(?=@document([\\s\'"{;]|/\\*|$))', + end: '(?<=})(?!\\G)', + patterns: [ + { + begin: '(?i)\\G(@)document', + beginCaptures: { + '0': { + name: 'keyword.control.at-rule.document.css', + }, + '1': { + name: 'punctuation.definition.keyword.css', + }, + }, + end: '(?=\\s*[{;])', + name: 'meta.at-rule.document.header.css', + patterns: [ + { + begin: '(?i)(?>>', + name: 'invalid.deprecated.combinator.css', + }, + { + match: '>>|>|\\+|~', + name: 'keyword.operator.combinator.css', + }, + ], + }, + commas: { + match: ',', + name: 'punctuation.separator.list.comma.css', + }, + 'comment-block': { + begin: '/\\*', + beginCaptures: { + '0': { + name: 'punctuation.definition.comment.begin.css', + }, + }, + end: '\\*/', + endCaptures: { + '0': { + name: 'punctuation.definition.comment.end.css', + }, + }, + name: 'comment.block.css', + }, + escapes: { + patterns: [ + { + match: '\\\\[0-9a-fA-F]{1,6}', + name: 'constant.character.escape.codepoint.css', + }, + { + begin: '\\\\$\\s*', + end: '^(?<:=]|\\)|/\\*) # Terminates cleanly', + }, + 'media-feature-keywords': { + match: + '(?xi)\n(?<=^|\\s|:|\\*/)\n(?: portrait # Orientation\n | landscape\n | progressive # Scan types\n | interlace\n | fullscreen # Display modes\n | standalone\n | minimal-ui\n | browser\n)\n(?=\\s|\\)|$)', + name: 'support.constant.property-value.css', + }, + 'media-query': { + begin: '\\G', + end: '(?=\\s*[{;])', + patterns: [ + { + include: '#comment-block', + }, + { + include: '#escapes', + }, + { + include: '#media-types', + }, + { + match: '(?i)(?<=\\s|^|,|\\*/)(only|not)(?=\\s|{|/\\*|$)', + name: 'keyword.operator.logical.$1.media.css', + }, + { + match: '(?i)(?<=\\s|^|\\*/|\\))and(?=\\s|/\\*|$)', + name: 'keyword.operator.logical.and.media.css', + }, + { + match: ',(?:(?:\\s*,)+|(?=\\s*[;){]))', + name: 'invalid.illegal.comma.css', + }, + { + include: '#commas', + }, + { + begin: '\\(', + beginCaptures: { + '0': { + name: 'punctuation.definition.parameters.begin.bracket.round.css', + }, + }, + end: '\\)', + endCaptures: { + '0': { + name: 'punctuation.definition.parameters.end.bracket.round.css', + }, + }, + patterns: [ + { + include: '#media-features', + }, + { + include: '#media-feature-keywords', + }, + { + match: ':', + name: 'punctuation.separator.key-value.css', + }, + { + match: '>=|<=|=|<|>', + name: 'keyword.operator.comparison.css', + }, + { + captures: { + '1': { + name: 'constant.numeric.css', + }, + '2': { + name: 'keyword.operator.arithmetic.css', + }, + '3': { + name: 'constant.numeric.css', + }, + }, + match: '(\\d+)\\s*(/)\\s*(\\d+)', + name: 'meta.ratio.css', + }, + { + include: '#numeric-values', + }, + { + include: '#comment-block', + }, + ], + }, + ], + }, + 'media-query-list': { + begin: '(?=\\s*[^{;])', + end: '(?=\\s*[{;])', + patterns: [ + { + include: '#media-query', + }, + ], + }, + 'media-types': { + captures: { + '1': { + name: 'support.constant.media.css', + }, + '2': { + name: 'invalid.deprecated.constant.media.css', + }, + }, + match: + '(?xi)\n(?<=^|\\s|,|\\*/)\n(?:\n # Valid media types\n (all|print|screen|speech)\n |\n # Deprecated in Media Queries 4: http://dev.w3.org/csswg/mediaqueries/#media-types\n (aural|braille|embossed|handheld|projection|tty|tv)\n)\n(?=$|[{,\\s;]|/\\*)', + }, + 'numeric-values': { + patterns: [ + { + captures: { + '1': { + name: 'punctuation.definition.constant.css', + }, + }, + match: '(#)(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})\\b', + name: 'constant.other.color.rgb-value.hex.css', + }, + { + captures: { + '1': { + name: 'keyword.other.unit.percentage.css', + }, + '2': { + name: 'keyword.other.unit.${2:/downcase}.css', + }, + }, + match: + '(?xi) (?+~|] # - Followed by another selector\n | /\\* # - Followed by a block comment\n )\n |\n # Name contains unescaped ASCII symbol\n (?: # Check for acceptable preceding characters\n [-a-zA-Z_0-9]|[^\\x00-\\x7F] # - Valid selector character\n | \\\\(?:[0-9a-fA-F]{1,6}|.) # - Escape sequence\n )*\n (?: # Invalid punctuation\n [!"\'%&(*;+~|] # - Another selector\n | /\\* # - A block comment\n)', + name: 'entity.other.attribute-name.class.css', + }, + { + captures: { + '1': { + name: 'punctuation.definition.entity.css', + }, + '2': { + patterns: [ + { + include: '#escapes', + }, + ], + }, + }, + match: + '(?x)\n(\\#)\n(\n -?\n (?![0-9])\n (?:[-a-zA-Z0-9_]|[^\\x00-\\x7F]|\\\\(?:[0-9a-fA-F]{1,6}|.))+\n)\n(?=$|[\\s,.\\#)\\[:{>+~|]|/\\*)', + name: 'entity.other.attribute-name.id.css', + }, + { + begin: '\\[', + beginCaptures: { + '0': { + name: 'punctuation.definition.entity.begin.bracket.square.css', + }, + }, + end: '\\]', + endCaptures: { + '0': { + name: 'punctuation.definition.entity.end.bracket.square.css', + }, + }, + name: 'meta.attribute-selector.css', + patterns: [ + { + include: '#comment-block', + }, + { + include: '#string', + }, + { + captures: { + '1': { + name: 'storage.modifier.ignore-case.css', + }, + }, + match: '(?<=["\'\\s]|^|\\*/)\\s*([iI])\\s*(?=[\\s\\]]|/\\*|$)', + }, + { + captures: { + '1': { + name: 'string.unquoted.attribute-value.css', + patterns: [ + { + include: '#escapes', + }, + ], + }, + }, + match: '(?x)(?<==)\\s*((?!/\\*)(?:[^\\\\"\'\\s\\]]|\\\\.)+)', + }, + { + include: '#escapes', + }, + { + match: '[~|^$*]?=', + name: 'keyword.operator.pattern.css', + }, + { + match: '\\|', + name: 'punctuation.separator.css', + }, + { + captures: { + '1': { + name: 'entity.other.namespace-prefix.css', + patterns: [ + { + include: '#escapes', + }, + ], + }, + }, + match: + "(?x)\n# Qualified namespace prefix\n( -?(?!\\d)(?:[\\w-]|[^\\x00-\\x7F]|\\\\(?:[0-9a-fA-F]{1,6}|.))+\n| \\*\n)\n# Lookahead to ensure there's a valid identifier ahead\n(?=\n \\| (?!\\s|=|$|\\])\n (?: -?(?!\\d)\n | [\\\\\\w-]\n | [^\\x00-\\x7F]\n )\n)", + }, + { + captures: { + '1': { + name: 'entity.other.attribute-name.css', + patterns: [ + { + include: '#escapes', + }, + ], + }, + }, + match: + '(?x)\n(-?(?!\\d)(?>[\\w-]|[^\\x00-\\x7F]|\\\\(?:[0-9a-fA-F]{1,6}|.))+)\n\\s*\n(?=[~|^\\]$*=]|/\\*)', + }, + ], + }, + { + include: '#pseudo-classes', + }, + { + include: '#pseudo-elements', + }, + { + include: '#functional-pseudo-classes', + }, + { + match: + '(?x) (?\\s,.\\#|){:\\[]|/\\*|$)', + name: 'entity.name.tag.css', + }, + 'unicode-range': { + captures: { + '0': { + name: 'constant.other.unicode-range.css', + }, + '1': { + name: 'punctuation.separator.dash.unicode-range.css', + }, + }, + match: '(? interface CustomLanguageDefinition { config?: Monaco.languages.LanguageConfiguration; tokens?: Monaco.languages.IMonarchLanguage; - syntax?: Record; } const addVueSupport = async () => { @@ -280,15 +279,13 @@ export const createEditor = async (options: EditorOptions): Promise setTheme(currentTheme, currentEditorTheme); }; - async function registerFromTextMate({ - name, - scopeName, - syntax, - }: { - name: string; - scopeName: string; - syntax: string; - }) { + async function registerFromTextMate( + langs: Array<{ + name: string; + scopeName: string; + syntax: string; + }>, + ) { await addVueSupport(); // a workaround for TextMate syntax const { loadWASM } = await import(onigasmUrl); @@ -298,26 +295,38 @@ export const createEditor = async (options: EditorOptions): Promise await loadWASM(onigasmWasmUrl); const registry = new Registry({ - getGrammarDefinition: async (_scopeName: string) => { + getGrammarDefinition: async (scopeName: string) => { return { format: 'json', - content: syntax, + content: langs.find((l) => l.scopeName === scopeName)?.syntax ?? '', }; }, }); const grammars = new Map(); - grammars.set(name, scopeName); - monaco.languages.register({ id: name }); + for (const { name, scopeName } of langs) { + grammars.set(name, scopeName); + monaco.languages.register({ id: name }); + } await wireTmGrammars(monaco, registry, grammars, editor); } - const addRippleSupport = async (syntax: CustomLanguageDefinition['syntax']) => { - await registerFromTextMate({ - name: 'ripple', - scopeName: 'source.ripple', - syntax: JSON.stringify(syntax, null, 2).replace('"name": "Ripple"', '"name": "ripple"'), - }); + const addRippleSupport = async (syntaxes: { + ripple: Record; + css: Record; + }) => { + await registerFromTextMate([ + { + name: 'ripple', + scopeName: 'source.ripple', + syntax: JSON.stringify(syntaxes.ripple), + }, + { + name: 'CSS', + scopeName: 'source.css', + syntax: JSON.stringify(syntaxes.css), + }, + ]); }; const loadMonacoLanguage = async (lang: Language) => { @@ -336,7 +345,7 @@ export const createEditor = async (options: EditorOptions): Promise monaco.languages.setMonarchTokensProvider(lang, mod.tokens); } if (lang === 'ripple') { - await addRippleSupport(mod.syntax); + await addRippleSupport({ ripple: (mod as any).syntax, css: (mod as any).cssSyntax }); return; } } From e2d6ceab8d44b841d3bb77e37a446334d7452db1 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Sat, 6 Sep 2025 21:32:33 +0300 Subject: [PATCH 30/71] fix typos in ripple syntax file --- .../editor/monaco/languages/monaco-lang-ripple.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/livecodes/editor/monaco/languages/monaco-lang-ripple.ts b/src/livecodes/editor/monaco/languages/monaco-lang-ripple.ts index 30aca96d4f..b6cfdc30cc 100644 --- a/src/livecodes/editor/monaco/languages/monaco-lang-ripple.ts +++ b/src/livecodes/editor/monaco/languages/monaco-lang-ripple.ts @@ -1157,7 +1157,7 @@ export default { ], }, { - name: 'meta.paramter.array-binding-pattern.js', + name: 'meta.parameter.array-binding-pattern.js', begin: '(?]|\\|\\||\\&\\&|\\!\\=\\=|$|^|((?]|\\|\\||\\&\\&|\\!\\=\\=|$|^|((? Date: Sat, 6 Sep 2025 21:32:33 +0300 Subject: [PATCH 31/71] temporarily use latest published ripple version --- src/livecodes/vendors.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/livecodes/vendors.ts b/src/livecodes/vendors.ts index 0945e7f014..322d05d4c4 100644 --- a/src/livecodes/vendors.ts +++ b/src/livecodes/vendors.ts @@ -397,7 +397,7 @@ export const resetCssUrl = /* @__PURE__ */ getUrl('reset-css@5.0.1/reset.css'); export const riotBaseUrl = /* @__PURE__ */ getUrl('riot@9.2.2/'); -export const rippleUrl = /* @__PURE__ */ getModuleUrl('ripple@0.2.6/compiler'); +export const rippleUrl = /* @__PURE__ */ getModuleUrl('ripple/compiler'); // TODO: pin version export const rubyWasmBaseUrl = /* @__PURE__ */ getUrl('@ruby/3.3-wasm-wasi@2.6.2/dist/'); From 05d6552a552b9cda6c936fc98126f8e878e5ef21 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Sat, 6 Sep 2025 21:32:33 +0300 Subject: [PATCH 32/71] prepare for ripple formatter --- src/livecodes/languages/prettier.ts | 1 + src/livecodes/languages/ripple/lang-ripple.ts | 10 +++++----- src/sdk/models.ts | 1 + 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/livecodes/languages/prettier.ts b/src/livecodes/languages/prettier.ts index 41777117da..6639d84c21 100644 --- a/src/livecodes/languages/prettier.ts +++ b/src/livecodes/languages/prettier.ts @@ -11,4 +11,5 @@ export const parserPlugins = { php: prettierPhpUrl, pug: vendorsBaseUrl + 'prettier/parser-pug.js', java: vendorsBaseUrl + 'prettier/parser-java.js', + // ripple: vendorsBaseUrl + 'prettier/parser-ripple.js', }; diff --git a/src/livecodes/languages/ripple/lang-ripple.ts b/src/livecodes/languages/ripple/lang-ripple.ts index 8afe23152f..a33ada87c2 100644 --- a/src/livecodes/languages/ripple/lang-ripple.ts +++ b/src/livecodes/languages/ripple/lang-ripple.ts @@ -1,15 +1,15 @@ import type { LanguageSpecs } from '../../models'; import { rippleUrl } from '../../vendors'; -import { parserPlugins } from '../prettier'; +// import { parserPlugins } from '../prettier'; export const ripple: LanguageSpecs = { name: 'ripple', title: 'Ripple', info: false, - parser: { - name: 'babel-ts', - pluginUrls: [parserPlugins.babel, parserPlugins.html], - }, + // parser: { + // name: 'ripple', + // pluginUrls: [parserPlugins.ripple], + // }, compiler: { factory: async () => { // TODO: convert to UMD diff --git a/src/sdk/models.ts b/src/sdk/models.ts index 16bf986a7a..fb40a15e00 100644 --- a/src/sdk/models.ts +++ b/src/sdk/models.ts @@ -1243,6 +1243,7 @@ export type ParserName = | 'babel-ts' | 'babel-flow' | 'glimmer' + | 'ripple' | 'html' | 'markdown' | 'css' From b2cf421f2fe15a7660a8eec1c2af3b0782bb7cbb Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Sat, 6 Sep 2025 21:32:33 +0300 Subject: [PATCH 33/71] minor fixes --- eslint.config.mjs | 1 + src/livecodes/editor/monaco/monaco.ts | 10 ++++------ typos.toml | 1 + 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index aab8c872fb..bdb275ecf3 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -32,6 +32,7 @@ export default [ '**/.jest', '**/.storybook', 'functions/vendors', + 'src/livecodes/editor/monaco/languages/monaco-lang-ripple.ts', ], }, ...fixupConfigRules( diff --git a/src/livecodes/editor/monaco/monaco.ts b/src/livecodes/editor/monaco/monaco.ts index b3eb0bcd0c..99ca505f3b 100644 --- a/src/livecodes/editor/monaco/monaco.ts +++ b/src/livecodes/editor/monaco/monaco.ts @@ -295,12 +295,10 @@ export const createEditor = async (options: EditorOptions): Promise await loadWASM(onigasmWasmUrl); const registry = new Registry({ - getGrammarDefinition: async (scopeName: string) => { - return { - format: 'json', - content: langs.find((l) => l.scopeName === scopeName)?.syntax ?? '', - }; - }, + getGrammarDefinition: async (scopeName: string) => ({ + format: 'json', + content: langs.find((l) => l.scopeName === scopeName)?.syntax ?? '', + }), }); const grammars = new Map(); diff --git a/typos.toml b/typos.toml index 629bd22d2b..b71e8ea5b4 100644 --- a/typos.toml +++ b/typos.toml @@ -8,6 +8,7 @@ extend-exclude = [ "src/livecodes/services/google-fonts.ts", # Font name "src/livecodes/templates/starter/blockly-starter.ts", # Random string id "functions/vendors/*.js", # Built files + "src/livecodes/editor/monaco/languages/monaco-lang-ripple.ts" ] [default] From b3240741556fc789d6c203f6f74ad68fc02d7625 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Sat, 6 Sep 2025 21:32:33 +0300 Subject: [PATCH 34/71] add prettier-plugin-ripple --- src/livecodes/languages/prettier.ts | 4 ++-- src/livecodes/languages/ripple/lang-ripple.ts | 10 +++++----- src/livecodes/vendors.ts | 4 ++++ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/livecodes/languages/prettier.ts b/src/livecodes/languages/prettier.ts index 6639d84c21..cd6d55457f 100644 --- a/src/livecodes/languages/prettier.ts +++ b/src/livecodes/languages/prettier.ts @@ -1,4 +1,4 @@ -import { prettierBaseUrl, prettierPhpUrl, vendorsBaseUrl } from '../vendors'; +import { prettierBaseUrl, prettierPhpUrl, prettierRippleUrl, vendorsBaseUrl } from '../vendors'; export const prettierUrl = prettierBaseUrl + 'standalone.js'; export const parserPlugins = { @@ -11,5 +11,5 @@ export const parserPlugins = { php: prettierPhpUrl, pug: vendorsBaseUrl + 'prettier/parser-pug.js', java: vendorsBaseUrl + 'prettier/parser-java.js', - // ripple: vendorsBaseUrl + 'prettier/parser-ripple.js', + ripple: prettierRippleUrl, }; diff --git a/src/livecodes/languages/ripple/lang-ripple.ts b/src/livecodes/languages/ripple/lang-ripple.ts index a33ada87c2..dab54bc9fa 100644 --- a/src/livecodes/languages/ripple/lang-ripple.ts +++ b/src/livecodes/languages/ripple/lang-ripple.ts @@ -1,15 +1,15 @@ import type { LanguageSpecs } from '../../models'; import { rippleUrl } from '../../vendors'; -// import { parserPlugins } from '../prettier'; +import { parserPlugins } from '../prettier'; export const ripple: LanguageSpecs = { name: 'ripple', title: 'Ripple', info: false, - // parser: { - // name: 'ripple', - // pluginUrls: [parserPlugins.ripple], - // }, + parser: { + name: 'ripple', + pluginUrls: [parserPlugins.ripple], + }, compiler: { factory: async () => { // TODO: convert to UMD diff --git a/src/livecodes/vendors.ts b/src/livecodes/vendors.ts index 322d05d4c4..903bbcbfea 100644 --- a/src/livecodes/vendors.ts +++ b/src/livecodes/vendors.ts @@ -343,6 +343,10 @@ export const postcssImportUrlUrl = /* @__PURE__ */ getUrl( export const prettierBaseUrl = /* @__PURE__ */ getUrl('prettier@3.3.2/'); +export const prettierRippleUrl = /* @__PURE__ */ getUrl( + '@hatemhosny/prettier-plugin-ripple@0.0.2/build/parser-ripple.js', +); + export const prettierPhpUrl = /* @__PURE__ */ getUrl('@prettier/plugin-php@0.22.2/standalone.js'); export const prismBaseUrl = /* @__PURE__ */ getUrl('prismjs@1.29.0/components/'); From 224bdac29144078f450057a70d7b5ceb5bef7bab Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Sat, 6 Sep 2025 21:32:33 +0300 Subject: [PATCH 35/71] update ripple formatter --- src/livecodes/vendors.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/livecodes/vendors.ts b/src/livecodes/vendors.ts index 903bbcbfea..2d65cc92bb 100644 --- a/src/livecodes/vendors.ts +++ b/src/livecodes/vendors.ts @@ -344,7 +344,7 @@ export const postcssImportUrlUrl = /* @__PURE__ */ getUrl( export const prettierBaseUrl = /* @__PURE__ */ getUrl('prettier@3.3.2/'); export const prettierRippleUrl = /* @__PURE__ */ getUrl( - '@hatemhosny/prettier-plugin-ripple@0.0.2/build/parser-ripple.js', + '@hatemhosny/prettier-plugin-ripple@0.0.3/build/parser-ripple.js', ); export const prettierPhpUrl = /* @__PURE__ */ getUrl('@prettier/plugin-php@0.22.2/standalone.js'); @@ -401,7 +401,7 @@ export const resetCssUrl = /* @__PURE__ */ getUrl('reset-css@5.0.1/reset.css'); export const riotBaseUrl = /* @__PURE__ */ getUrl('riot@9.2.2/'); -export const rippleUrl = /* @__PURE__ */ getModuleUrl('ripple/compiler'); // TODO: pin version +export const rippleUrl = /* @__PURE__ */ getModuleUrl('ripple@0.2.7/compiler'); // TODO: pin version export const rubyWasmBaseUrl = /* @__PURE__ */ getUrl('@ruby/3.3-wasm-wasi@2.6.2/dist/'); From bea5b56d0d0efd0ee2ed98190d11426621b0f757 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Sat, 6 Sep 2025 21:32:33 +0300 Subject: [PATCH 36/71] add ripple basic syntax highlight for codemirror and codejar --- src/livecodes/editor/monaco/monaco.ts | 8 +++++--- src/livecodes/languages/ripple/lang-ripple.ts | 1 + src/livecodes/vendors.ts | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/livecodes/editor/monaco/monaco.ts b/src/livecodes/editor/monaco/monaco.ts index 99ca505f3b..9e32ab8c16 100644 --- a/src/livecodes/editor/monaco/monaco.ts +++ b/src/livecodes/editor/monaco/monaco.ts @@ -94,9 +94,11 @@ export const createEditor = async (options: EditorOptions): Promise ? 'csharp' : language.startsWith('vue') ? 'vue' - : ['svelte', 'malina', 'riot'].includes(language) - ? ('razor' as Language) // avoid mixing code between markup & script editors when formatting - : mapLanguage(language); + : language === 'ripple' + ? 'ripple' + : ['svelte', 'malina', 'riot'].includes(language) + ? ('razor' as Language) // avoid mixing code between markup & script editors when formatting + : mapLanguage(language); try { (window as any).monaco = (window as any).monaco || (await loadMonaco()).monaco; diff --git a/src/livecodes/languages/ripple/lang-ripple.ts b/src/livecodes/languages/ripple/lang-ripple.ts index dab54bc9fa..7ac5abff72 100644 --- a/src/livecodes/languages/ripple/lang-ripple.ts +++ b/src/livecodes/languages/ripple/lang-ripple.ts @@ -27,4 +27,5 @@ export const ripple: LanguageSpecs = { }, extensions: ['ripple'], editor: 'script', + editorLanguage: 'jsx', }; diff --git a/src/livecodes/vendors.ts b/src/livecodes/vendors.ts index 2d65cc92bb..0c9b6d6683 100644 --- a/src/livecodes/vendors.ts +++ b/src/livecodes/vendors.ts @@ -344,7 +344,7 @@ export const postcssImportUrlUrl = /* @__PURE__ */ getUrl( export const prettierBaseUrl = /* @__PURE__ */ getUrl('prettier@3.3.2/'); export const prettierRippleUrl = /* @__PURE__ */ getUrl( - '@hatemhosny/prettier-plugin-ripple@0.0.3/build/parser-ripple.js', + '@hatemhosny/prettier-plugin-ripple@0.0.5/build/parser-ripple.js', ); export const prettierPhpUrl = /* @__PURE__ */ getUrl('@prettier/plugin-php@0.22.2/standalone.js'); @@ -401,7 +401,7 @@ export const resetCssUrl = /* @__PURE__ */ getUrl('reset-css@5.0.1/reset.css'); export const riotBaseUrl = /* @__PURE__ */ getUrl('riot@9.2.2/'); -export const rippleUrl = /* @__PURE__ */ getModuleUrl('ripple@0.2.7/compiler'); // TODO: pin version +export const rippleUrl = /* @__PURE__ */ getModuleUrl('ripple@0.2.12/compiler'); // TODO: pin version export const rubyWasmBaseUrl = /* @__PURE__ */ getUrl('@ruby/3.3-wasm-wasi@2.6.2/dist/'); From ec6838b8b6950f382943a01d471e662a41167a75 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Sat, 6 Sep 2025 21:32:33 +0300 Subject: [PATCH 37/71] use a workaround till ripple formatter is fixed --- src/livecodes/formatter/format.worker.ts | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/livecodes/formatter/format.worker.ts b/src/livecodes/formatter/format.worker.ts index a6769c2bd9..0ee86a7d49 100644 --- a/src/livecodes/formatter/format.worker.ts +++ b/src/livecodes/formatter/format.worker.ts @@ -116,14 +116,20 @@ const format = async ( singleQuote: formatterConfig.singleQuote ?? defaultConfig.singleQuote, trailingComma: formatterConfig.trailingComma === false ? 'none' : 'all', }; - return ( - (await (self as any).prettier.formatWithCursor(value, { - parser: parser?.name, - plugins: prettierPlugins, - cursorOffset, - ...options, - })) || unFormatted - ); + const formatted = await (self as any).prettier.formatWithCursor(value, { + parser: parser?.name, + plugins: prettierPlugins, + cursorOffset, + ...options, + }); + + // TODO: remove when ripple plugin is fixed + if (formatted && language === 'ripple') { + formatted.formatted = formatted.formatted.replace(/,?\[object Object\],?/g, ''); + if (formatted.cursorOffset < 1) formatted.cursorOffset = 1; + } + + return formatted || unFormatted; } if (getFormatter(language) != null) { const formatFn = loadFormatter(language); From fc56a4133e9cda89b04b4cf4a471530e4067cd26 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Sat, 6 Sep 2025 21:32:33 +0300 Subject: [PATCH 38/71] revert formatting workaround --- src/livecodes/formatter/format.worker.ts | 22 ++++++++-------------- src/livecodes/vendors.ts | 2 +- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/livecodes/formatter/format.worker.ts b/src/livecodes/formatter/format.worker.ts index 0ee86a7d49..a6769c2bd9 100644 --- a/src/livecodes/formatter/format.worker.ts +++ b/src/livecodes/formatter/format.worker.ts @@ -116,20 +116,14 @@ const format = async ( singleQuote: formatterConfig.singleQuote ?? defaultConfig.singleQuote, trailingComma: formatterConfig.trailingComma === false ? 'none' : 'all', }; - const formatted = await (self as any).prettier.formatWithCursor(value, { - parser: parser?.name, - plugins: prettierPlugins, - cursorOffset, - ...options, - }); - - // TODO: remove when ripple plugin is fixed - if (formatted && language === 'ripple') { - formatted.formatted = formatted.formatted.replace(/,?\[object Object\],?/g, ''); - if (formatted.cursorOffset < 1) formatted.cursorOffset = 1; - } - - return formatted || unFormatted; + return ( + (await (self as any).prettier.formatWithCursor(value, { + parser: parser?.name, + plugins: prettierPlugins, + cursorOffset, + ...options, + })) || unFormatted + ); } if (getFormatter(language) != null) { const formatFn = loadFormatter(language); diff --git a/src/livecodes/vendors.ts b/src/livecodes/vendors.ts index 0c9b6d6683..923d3e4eae 100644 --- a/src/livecodes/vendors.ts +++ b/src/livecodes/vendors.ts @@ -344,7 +344,7 @@ export const postcssImportUrlUrl = /* @__PURE__ */ getUrl( export const prettierBaseUrl = /* @__PURE__ */ getUrl('prettier@3.3.2/'); export const prettierRippleUrl = /* @__PURE__ */ getUrl( - '@hatemhosny/prettier-plugin-ripple@0.0.5/build/parser-ripple.js', + '@hatemhosny/prettier-plugin-ripple@0.0.6/build/parser-ripple.js', ); export const prettierPhpUrl = /* @__PURE__ */ getUrl('@prettier/plugin-php@0.22.2/standalone.js'); From 00683e9d7569bbab41c5937c0894b769acea30a0 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Sat, 6 Sep 2025 21:32:33 +0300 Subject: [PATCH 39/71] add postFormat to parsers --- src/livecodes/formatter/format.worker.ts | 18 ++++++++++-------- src/livecodes/languages/ripple/lang-ripple.ts | 4 ++++ src/livecodes/vendors.ts | 2 +- src/sdk/models.ts | 4 ++++ 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/livecodes/formatter/format.worker.ts b/src/livecodes/formatter/format.worker.ts index a6769c2bd9..d15e04adb5 100644 --- a/src/livecodes/formatter/format.worker.ts +++ b/src/livecodes/formatter/format.worker.ts @@ -116,14 +116,16 @@ const format = async ( singleQuote: formatterConfig.singleQuote ?? defaultConfig.singleQuote, trailingComma: formatterConfig.trailingComma === false ? 'none' : 'all', }; - return ( - (await (self as any).prettier.formatWithCursor(value, { - parser: parser?.name, - plugins: prettierPlugins, - cursorOffset, - ...options, - })) || unFormatted - ); + let formatted = await (self as any).prettier.formatWithCursor(value, { + parser: parser?.name, + plugins: prettierPlugins, + cursorOffset, + ...options, + }); + if (typeof parser?.postFormat === 'function') { + formatted = await parser.postFormat(formatted); + } + return formatted || unFormatted; } if (getFormatter(language) != null) { const formatFn = loadFormatter(language); diff --git a/src/livecodes/languages/ripple/lang-ripple.ts b/src/livecodes/languages/ripple/lang-ripple.ts index 7ac5abff72..d59a7a4fd7 100644 --- a/src/livecodes/languages/ripple/lang-ripple.ts +++ b/src/livecodes/languages/ripple/lang-ripple.ts @@ -9,6 +9,10 @@ export const ripple: LanguageSpecs = { parser: { name: 'ripple', pluginUrls: [parserPlugins.ripple], + postFormat: async (parsed: { formatted: string; cursorOffset: number }) => ({ + formatted: parsed.formatted.replace(/,?\[object Object\],?/g, ''), + cursorOffset: parsed.cursorOffset, + }), }, compiler: { factory: async () => { diff --git a/src/livecodes/vendors.ts b/src/livecodes/vendors.ts index 923d3e4eae..0c9b6d6683 100644 --- a/src/livecodes/vendors.ts +++ b/src/livecodes/vendors.ts @@ -344,7 +344,7 @@ export const postcssImportUrlUrl = /* @__PURE__ */ getUrl( export const prettierBaseUrl = /* @__PURE__ */ getUrl('prettier@3.3.2/'); export const prettierRippleUrl = /* @__PURE__ */ getUrl( - '@hatemhosny/prettier-plugin-ripple@0.0.6/build/parser-ripple.js', + '@hatemhosny/prettier-plugin-ripple@0.0.5/build/parser-ripple.js', ); export const prettierPhpUrl = /* @__PURE__ */ getUrl('@prettier/plugin-php@0.22.2/standalone.js'); diff --git a/src/sdk/models.ts b/src/sdk/models.ts index fb40a15e00..40f8abe05d 100644 --- a/src/sdk/models.ts +++ b/src/sdk/models.ts @@ -1257,6 +1257,10 @@ export interface Parser { name: ParserName; plugins?: any[]; pluginUrls: string[]; + postFormat?: (parsed: { + formatted: string; + cursorOffset: number; + }) => Promise<{ formatted: string; cursorOffset: number }>; } export type FormatFn = ( value: string, From a8ee0a957391c46650e920ac97be05c30fbca283 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Sat, 6 Sep 2025 21:32:34 +0300 Subject: [PATCH 40/71] edit --- src/livecodes/languages/ripple/lang-ripple.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/livecodes/languages/ripple/lang-ripple.ts b/src/livecodes/languages/ripple/lang-ripple.ts index d59a7a4fd7..2b38132bc6 100644 --- a/src/livecodes/languages/ripple/lang-ripple.ts +++ b/src/livecodes/languages/ripple/lang-ripple.ts @@ -9,10 +9,14 @@ export const ripple: LanguageSpecs = { parser: { name: 'ripple', pluginUrls: [parserPlugins.ripple], - postFormat: async (parsed: { formatted: string; cursorOffset: number }) => ({ - formatted: parsed.formatted.replace(/,?\[object Object\],?/g, ''), - cursorOffset: parsed.cursorOffset, - }), + postFormat: async (parsed: { formatted: string; cursorOffset: number }) => { + let formatted = parsed.formatted.replace(/,?\[object Object\],?/g, ''); + if (!formatted.endsWith('\n')) formatted += '\n'; + return { + formatted, + cursorOffset: parsed.cursorOffset, + }; + }, }, compiler: { factory: async () => { From 6d5f6d367d3b01aa1951d9087ba5402babdc31f8 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Sat, 6 Sep 2025 21:32:34 +0300 Subject: [PATCH 41/71] add a todo comment --- src/livecodes/languages/ripple/lang-ripple.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/livecodes/languages/ripple/lang-ripple.ts b/src/livecodes/languages/ripple/lang-ripple.ts index 2b38132bc6..78a538945f 100644 --- a/src/livecodes/languages/ripple/lang-ripple.ts +++ b/src/livecodes/languages/ripple/lang-ripple.ts @@ -9,6 +9,7 @@ export const ripple: LanguageSpecs = { parser: { name: 'ripple', pluginUrls: [parserPlugins.ripple], + // TODO: remove this after fixing the prettier plugin postFormat: async (parsed: { formatted: string; cursorOffset: number }) => { let formatted = parsed.formatted.replace(/,?\[object Object\],?/g, ''); if (!formatted.endsWith('\n')) formatted += '\n'; From 765861f7930dd0f0e2a83eabf3138feff4b6ca4c Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Sat, 6 Sep 2025 21:32:34 +0300 Subject: [PATCH 42/71] update ripple formatter and remove workaround --- src/livecodes/languages/ripple/lang-ripple.ts | 9 --------- src/livecodes/vendors.ts | 2 +- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/src/livecodes/languages/ripple/lang-ripple.ts b/src/livecodes/languages/ripple/lang-ripple.ts index 78a538945f..7ac5abff72 100644 --- a/src/livecodes/languages/ripple/lang-ripple.ts +++ b/src/livecodes/languages/ripple/lang-ripple.ts @@ -9,15 +9,6 @@ export const ripple: LanguageSpecs = { parser: { name: 'ripple', pluginUrls: [parserPlugins.ripple], - // TODO: remove this after fixing the prettier plugin - postFormat: async (parsed: { formatted: string; cursorOffset: number }) => { - let formatted = parsed.formatted.replace(/,?\[object Object\],?/g, ''); - if (!formatted.endsWith('\n')) formatted += '\n'; - return { - formatted, - cursorOffset: parsed.cursorOffset, - }; - }, }, compiler: { factory: async () => { diff --git a/src/livecodes/vendors.ts b/src/livecodes/vendors.ts index 0c9b6d6683..6ae1b372bc 100644 --- a/src/livecodes/vendors.ts +++ b/src/livecodes/vendors.ts @@ -344,7 +344,7 @@ export const postcssImportUrlUrl = /* @__PURE__ */ getUrl( export const prettierBaseUrl = /* @__PURE__ */ getUrl('prettier@3.3.2/'); export const prettierRippleUrl = /* @__PURE__ */ getUrl( - '@hatemhosny/prettier-plugin-ripple@0.0.5/build/parser-ripple.js', + '@hatemhosny/prettier-plugin-ripple@0.0.7/build/parser-ripple.js', ); export const prettierPhpUrl = /* @__PURE__ */ getUrl('@prettier/plugin-php@0.22.2/standalone.js'); From 0c1e45f540d83bc2115d00b8bda05e8533f2e7d2 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Sat, 6 Sep 2025 21:32:34 +0300 Subject: [PATCH 43/71] allow changing ripple compiler version --- scripts/build.js | 1 + .../languages/ripple/lang-ripple-compiler.ts | 46 +++++++++++++++++++ src/livecodes/languages/ripple/lang-ripple.ts | 16 ++----- src/livecodes/vendors.ts | 2 - 4 files changed, 50 insertions(+), 15 deletions(-) create mode 100644 src/livecodes/languages/ripple/lang-ripple-compiler.ts diff --git a/scripts/build.js b/scripts/build.js index 2b9d0550a5..e668ebe84e 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -237,6 +237,7 @@ const iifeBuild = () => 'languages/python-wasm/lang-python-wasm-script.ts', 'languages/rescript/lang-rescript-formatter.ts', 'languages/riot/lang-riot-compiler.ts', + 'languages/ripple/lang-ripple-compiler.ts', 'languages/ruby-wasm/lang-ruby-wasm-script.ts', 'languages/scss/lang-scss-compiler.ts', 'languages/solid/lang-solid-compiler.ts', diff --git a/src/livecodes/languages/ripple/lang-ripple-compiler.ts b/src/livecodes/languages/ripple/lang-ripple-compiler.ts new file mode 100644 index 0000000000..440617ab13 --- /dev/null +++ b/src/livecodes/languages/ripple/lang-ripple-compiler.ts @@ -0,0 +1,46 @@ +import type { CompilerFunction, Config } from '../../models'; +import { modulesService } from '../../services/modules'; + +(self as any).createRippleCompiler = async (initialConfig: Config): Promise => { + let version = initialConfig.customSettings.ripple?.version || 'latest'; + let compile: (code: string, filename: string) => Promise<{ js: { code: string }; css: string }>; + + const updateCompiler = async (currentVersion: string) => { + if (typeof compile === 'function' && currentVersion === version) return; + const mod = await import( + /* @__PURE__ */ modulesService.getModuleUrl(`ripple@${currentVersion}/compiler`) + ); + compile = mod.compile; + version = currentVersion; + }; + + return async (code, { config }) => { + if (!code.trim()) return ''; + + const newVersion = config.customSettings.ripple?.version || version; + await updateCompiler(newVersion); + + const { js, css } = await compile(code, './App.ripple'); + + const cssCode = + css === '' + ? '' + : `\n +const styles = document.createElement('style'); +styles.innerHTML = ${JSON.stringify(css)}; +document.head.appendChild(styles); +`; + + const moduleUrl = /* @__PURE__ */ modulesService.getModuleUrl(`ripple@${version}`); + return { + code: `${js.code}${cssCode}`, + info: { + imports: { + ripple: moduleUrl, + 'ripple/internal': `${moduleUrl}/internal`, + 'ripple/internal/client': `${moduleUrl}/internal/client`, + }, + }, + }; + }; +}; diff --git a/src/livecodes/languages/ripple/lang-ripple.ts b/src/livecodes/languages/ripple/lang-ripple.ts index 7ac5abff72..9aacc74937 100644 --- a/src/livecodes/languages/ripple/lang-ripple.ts +++ b/src/livecodes/languages/ripple/lang-ripple.ts @@ -1,5 +1,4 @@ import type { LanguageSpecs } from '../../models'; -import { rippleUrl } from '../../vendors'; import { parserPlugins } from '../prettier'; export const ripple: LanguageSpecs = { @@ -11,18 +10,9 @@ export const ripple: LanguageSpecs = { pluginUrls: [parserPlugins.ripple], }, compiler: { - factory: async () => { - // TODO: convert to UMD - const { compile } = await import(rippleUrl); - return async (code) => { - if (!code.trim()) return ''; - const { js, css } = await compile(code, './src/App.ripple'); - const cssCode = - css === '' - ? '' - : `\n\nconst styles = document.createElement('style');\nstyles.innerHTML = ${JSON.stringify(css)};\ndocument.head.appendChild(styles);\n`; - return `${js.code}${cssCode}`; - }; + factory: (config, baseUrl) => { + (self as any).importScripts(baseUrl + '{{hash:lang-ripple-compiler.js}}'); + return (self as any).createRippleCompiler(config); }, }, extensions: ['ripple'], diff --git a/src/livecodes/vendors.ts b/src/livecodes/vendors.ts index 6ae1b372bc..c44a9dbda4 100644 --- a/src/livecodes/vendors.ts +++ b/src/livecodes/vendors.ts @@ -401,8 +401,6 @@ export const resetCssUrl = /* @__PURE__ */ getUrl('reset-css@5.0.1/reset.css'); export const riotBaseUrl = /* @__PURE__ */ getUrl('riot@9.2.2/'); -export const rippleUrl = /* @__PURE__ */ getModuleUrl('ripple@0.2.12/compiler'); // TODO: pin version - export const rubyWasmBaseUrl = /* @__PURE__ */ getUrl('@ruby/3.3-wasm-wasi@2.6.2/dist/'); export const rubyWasmScriptUrl = /* @__PURE__ */ getUrl( From bba104db3904a6b4d73fc93315d6ec0e66c73a8c Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Sat, 6 Sep 2025 21:32:34 +0300 Subject: [PATCH 44/71] add ripple starter template --- src/livecodes/assets/templates/ripple-0.png | Bin 0 -> 4040 bytes .../i18n/locales/en/translation.lokalise.json | 4 ++ src/livecodes/i18n/locales/en/translation.ts | 1 + src/livecodes/templates/starter/index.ts | 2 + .../templates/starter/ripple-starter.ts | 46 ++++++++++++++++++ src/sdk/models.ts | 1 + 6 files changed, 54 insertions(+) create mode 100644 src/livecodes/assets/templates/ripple-0.png create mode 100644 src/livecodes/templates/starter/ripple-starter.ts diff --git a/src/livecodes/assets/templates/ripple-0.png b/src/livecodes/assets/templates/ripple-0.png new file mode 100644 index 0000000000000000000000000000000000000000..5b30ea52ad417ca0f4d6360f18d770992de46277 GIT binary patch literal 4040 zcmai1cQhMN+ox(3Q7cv|Rija{SCm*mjM}jkQEgL7h1M);2B}R|&Cr@vl&GS1#OSa` zYgE*%)@Va(e(CxCd(U~#`^UY{dG2%1xzD}l+}}vFG)Hor6FNsnN5^4oq;E}&INEs5 z!bF?jEx`P9?GNS-Z&u^Xt$D0=sGZrXWn9V?_kR$yOl$&Y3N#x}_g zsX=^{l=V6(;iW-3-5D;UgqLVH#Kl-0mZ&;$=nMj=xA6AYTH_OB=GNSshdW2N+S7y1 zEa{x6Z_NgLgqJ4<*_?iHf7<%BmD=dC+N|D;_>QT6FoSoym;{M?vl zVzjxUx;1%p)OtrsR;r8YJ%y!yRzca@OBV?(+r(8>dCj&tN)_H)2>j{GQb|cjOzb-# zRxeU^zXv;ys1?Op1yiqlEb4gFpne-Gd6}7%1>r(* zad8m2+B#}Ad19{T`wi+;%bhPx91%(@e+`8LU`eg58hQwXyq`{_crSUWi@Bw9u7^QI zMaATyzfJGuz*rJmaejV&ZMvR;65m@KwvYR|L8%H(^G88kpO-b+9beyjL_%}<`ubun zh@?~?nM5yL(%ZRcd&ykX!Xw9?1K;DJnKi{0l2Hg3TU=U7_8#16Zf+JJ5+_$J96+j~ zoeSW1q5FCmqdNa8DLq|u)H2yk%Wj(Go}8TK&L5*|`F}*>IZSmLZhaW9bzs2v+_DrZ zUg!zmnao>~_h=@bL1U+RlXT~UmsG^X+2e|eYQ0qWfw<&#LBYf+w{XW`ZVL;G2`>>S zAaAVP;$9nUFKF#~KBi*BN79;Pg+e_Cb!}$%V*?>f#zqO`fKntO#4^oGg}IWLefZNm zzOu+d_muwl>*7y>(-uG?>I?%zueuwjgoFe{M!M(6)fgV+;QDOO+y&Rc#F9H>Wo4(l ztE+CkU$)wCSy`xbh!R63<>IB!ZxC+F7mTT~VO+B%j1i}!4zaj5)-owOV-~{c`L6}D znNDM@R^nr?Q81J5IqB)?Sy)*O9ULllgIJIlqlCq1$2YR9JdzQQW@iJcNDj~OrS11O zhv`j$a_6ax@N2odjAdp;qM8YgY1Nmb8ZFP7Gpd-x1Z|9S!9(wpV>mT0-Zd0IQ>o^8 zCw@EhdT$7eBd_$QRXZ0QaA-%8?=hU)8#Latvu zu>vgAjL`wgmpJ^+aZ>hZ^vYySkHNP0{mCp6TAnvGUprF7G)IP9_KjC+-vxryFYs({ z@0)aS07>eId>gN{amZ~J5)>rcR%?j}DjW5J4ZA7wtX`Mqvzwg7H$6RJ&P1=cK%Xxx zavr=;0MFZqC8oe1^J1^0)<|=69CNKfO3FXou}@h@;PrKK-D#(;lv!`qmOEDY(z$cz zNM_B^-Fg!g7%F;uyE%x%ly>V(!q{N$m^v&>)t(45*VhkQrh2%P(VC?X864SjaV3gtVJ+RFnB;#FMem2kDvRjz zta;3Yb}osflkcqp%=d46&5<0(>^ zL~gYzrf@pFbiE9E#vQvB>(7rS5E4>SxDRh=9sN4|GZq_^{q>h%(j1t^4 z_bSgaGIl$wrwe?DWBVJtI>%}hxT4}pHFyGx;24IcM!tWVoZD~)Ja5mm^7iW&@NNF9#41F;Br9D2Sf>jBLGkN}rV@+~L!rRR@ELYoC^|TqSo< zkR zdAZ(qF7&AFX7#k1DO@m1=#4ZK5JNb3#nvWh(+JVG!;^H;H(|7OX2u-(btM2?7vh$@l-q<^;Mfri$>A32k+Ax6Zj%;u*~ zm9MI}iMWgm>&haRWxl%L0Y&O51vbt%S$^-Hrq-?k;tf)mo(vKimUi!Z>}ai-QB*7E zaf4Y*QqqYCV}_=L>2!VTHZUE(9IiQDBTW+s-Cu@GiPK;p8D3HIE-qJT6;hkaO#?yY zoETYE^~`;D>@34M$y#1s_n-E^P=76eqkjA6l%9AfVaQB5 z8jW$uM^Ev4c2g>tvsMaKyi>9?4ag}Mc%$?ePY&~{frtMp_o;p(lozl7NhA>lkYP#T zt|z# z0>WU2MS=8f3StI;#w(kAE&>f z43W1aI&k6<%*xF^e|NVGR-d}|htY)9jkPatQhl!WIe@Mfn;9z~U=LFYstmx_TkiLz zi7K!FSnXscyD7s1+0u*-Zxy*n+_G9WZCqe&-glS8NY`wt(b%oNQj~?4wvbK+Y1#tZzip z2+=rg{}1*@sDhm?lR^x0seNtX_FmJ+usWEy?wkjX6KpUVpKNU?)ri4%_%~jt3{Lf% z@X&$+5{CgKocY3RXMM6py01eW zAcjmiU!NeTw&F4eZ_~1i^tpn17I9E{IlJgwxIx+f3#=k3jZZ>nvVX51BH==czHib6 zoQQW5%`a$_AaDT8yrxl`Kcv)Ti1Ci@u$*>mp{sp)(WcVPLH?(z;qh5{+pk$!S-XUn zTuIGSZrP!qD_*uG;&WsvyDy|6vQmaVW->qb%v|1ua@ZZERcNVz_CQQ}cOD!Jl+Az? zErfs4{0BSB`PQBFpFXP}3x=0vi(cB4*ZF(_P%TtIDeCO8l;j>;roqoJ#zj@!UdFS%_vghV=?)Lig^1Xu04F^q;QEwSE@XZlVs) z*9tczeg*?^#=}3FKjhh@H+vDs+FWT{^rj$ETRK5LA@W+k+{UG9`Grmt@6D?j9f#n5 z+$J=@uEjHTfMCHaZV~DioSS?bh&nWE)?rl`+=w_>_Y{}#(Xq{j^LWxU$Hk~&nd3z8 z!&t|L)dV1-l?M1}Ld$%ad3ku_Ol|Ts|LH|@MMd9_1Ko;P)D)_;c)RN0_xCstfY6eT zce`uEO;F(lIFk~eMMi)sKk=%Ca;Wsg6Wg2B)zy|LmsnT0m_gi#)uv0f56k@w!aQ5c zzFzjYgy|FX@qxIfrzeYZ{cdtu?LzzY%f5>?MEmMRT=aZ_M$qChr`9;%Cx^*Ty2Eb6 z*Z<;GvDmiiL{;H_*TtLsYk85#v$B+hih&MB0s$Y15UFf&TCmhGC3Q^;1B?X!n;rch dZk6tYu~W=+?8O+CX1?j@j1A27U+K9={~xCjifI4< literal 0 HcmV?d00001 diff --git a/src/livecodes/i18n/locales/en/translation.lokalise.json b/src/livecodes/i18n/locales/en/translation.lokalise.json index d6d83d19e2..4221722691 100644 --- a/src/livecodes/i18n/locales/en/translation.lokalise.json +++ b/src/livecodes/i18n/locales/en/translation.lokalise.json @@ -2744,6 +2744,10 @@ "notes": "", "translation": "Riot.js Starter" }, + "templates.starter.ripple": { + "notes": "", + "translation": "Ripple Starter" + }, "templates.starter.ruby": { "notes": "", "translation": "Ruby Starter" diff --git a/src/livecodes/i18n/locales/en/translation.ts b/src/livecodes/i18n/locales/en/translation.ts index 7346431e9b..a3246661af 100644 --- a/src/livecodes/i18n/locales/en/translation.ts +++ b/src/livecodes/i18n/locales/en/translation.ts @@ -1032,6 +1032,7 @@ const translation = { reason: 'Reason Starter', rescript: 'ReScript Starter', riot: 'Riot.js Starter', + ripple: 'Ripple Starter', ruby: 'Ruby Starter', 'ruby-wasm': 'Ruby (Wasm) Starter', scheme: 'Scheme Starter', diff --git a/src/livecodes/templates/starter/index.ts b/src/livecodes/templates/starter/index.ts index 1075d26834..032067f703 100644 --- a/src/livecodes/templates/starter/index.ts +++ b/src/livecodes/templates/starter/index.ts @@ -52,6 +52,7 @@ import { reactStarter } from './react-starter'; import { reasonStarter } from './reason-starter'; import { rescriptStarter } from './rescript-starter'; import { riotStarter } from './riot-starter'; +import { rippleStarter } from './ripple-starter'; import { rubyStarter } from './ruby-starter'; import { rubyWasmStarter } from './ruby-wasm-starter'; import { schemeStarter } from './scheme-starter'; @@ -79,6 +80,7 @@ export const starterTemplates = [ preactStarter, svelteStarter, solidStarter, + rippleStarter, litStarter, stencilStarter, mdxStarter, diff --git a/src/livecodes/templates/starter/ripple-starter.ts b/src/livecodes/templates/starter/ripple-starter.ts new file mode 100644 index 0000000000..07f5124b90 --- /dev/null +++ b/src/livecodes/templates/starter/ripple-starter.ts @@ -0,0 +1,46 @@ +import type { Template } from '../../models'; + +export const rippleStarter: Template = { + name: 'ripple', + title: window.deps.translateString('templates.starter.ripple', 'Ripple Starter'), + thumbnail: 'assets/templates/ripple-0.png', + activeEditor: 'script', + markup: { + language: 'html', + content: '', + }, + style: { + language: 'css', + content: '', + }, + script: { + language: 'ripple', + content: ` +component Counter(props: { $name: string }) { +
+

{\`Hello, \${props.\$name}!\`}

+ + + let \$count = 0; +

{\`You clicked \${\$count} times.\`}

+ +
+ + +} + +export default component App() { + +} +`.trimStart(), + }, +}; diff --git a/src/sdk/models.ts b/src/sdk/models.ts index 40f8abe05d..c465302332 100644 --- a/src/sdk/models.ts +++ b/src/sdk/models.ts @@ -1391,6 +1391,7 @@ export type TemplateName = | 'preact' | 'svelte' | 'solid' + | 'ripple' | 'lit' | 'stencil' | 'mdx' From 7881b061313a6db6c3a12484369c7ecf3b64cf0c Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Sat, 6 Sep 2025 21:32:34 +0300 Subject: [PATCH 45/71] compile styles in ripple components --- src/livecodes/languages/ripple/lang-ripple-compiler.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/livecodes/languages/ripple/lang-ripple-compiler.ts b/src/livecodes/languages/ripple/lang-ripple-compiler.ts index 440617ab13..07c16f507a 100644 --- a/src/livecodes/languages/ripple/lang-ripple-compiler.ts +++ b/src/livecodes/languages/ripple/lang-ripple-compiler.ts @@ -1,6 +1,9 @@ +import { compileBlocks } from '../../compiler'; import type { CompilerFunction, Config } from '../../models'; import { modulesService } from '../../services/modules'; +// TODO: recursively compile imported Ripple components + (self as any).createRippleCompiler = async (initialConfig: Config): Promise => { let version = initialConfig.customSettings.ripple?.version || 'latest'; let compile: (code: string, filename: string) => Promise<{ js: { code: string }; css: string }>; @@ -20,6 +23,8 @@ import { modulesService } from '../../services/modules'; const newVersion = config.customSettings.ripple?.version || version; await updateCompiler(newVersion); + code = await compileBlocks(code, 'style', config); + const { js, css } = await compile(code, './App.ripple'); const cssCode = From 0887ab8d3fd9fe7087929d2e3e0d606c8ef7e744 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Sat, 6 Sep 2025 21:32:34 +0300 Subject: [PATCH 46/71] add docs for ripple support --- docs/docs/languages/ripple.mdx | 401 ++++++++++++++++++ docs/src/components/LanguageSliders.tsx | 1 + docs/src/components/TemplateList.tsx | 1 + src/livecodes/UI/command-menu-actions.ts | 1 + src/livecodes/templates/starter/index.ts | 2 +- .../templates/starter/ripple-starter.ts | 2 +- 6 files changed, 406 insertions(+), 2 deletions(-) create mode 100644 docs/docs/languages/ripple.mdx diff --git a/docs/docs/languages/ripple.mdx b/docs/docs/languages/ripple.mdx new file mode 100644 index 0000000000..93bfe5315a --- /dev/null +++ b/docs/docs/languages/ripple.mdx @@ -0,0 +1,401 @@ +--- +toc_max_heading_level: 4 +--- + +# Ripple + +[Ripple](https://www.ripplejs.com/) is a TypeScript UI framework that takes the best parts of React, Solid and Svelte and combines them into one package. + +## Usage + +Ripple components can be used in LiveCodes as documented in the [Ripple docs](https://github.com/trueadm/ripple). See below for usage. + +### Demo + +import LiveCodes from '../../src/components/LiveCodes.tsx'; +import RunInLiveCodes from '../../src/components/RunInLiveCodes.tsx'; + +export const demo = { + activeEditor: 'script', + script: { + language: 'ripple', + content: ` export default component Counter() { + let \$count = 0; + let \$doubled = \$count * 2; + +
+

{'Counter'}

+

{\`Count: \${\$count}\`}

+

{\`Doubled: \${\$doubled}\`}

+ + + +
+ + + }`, + }, +} + + + +### Auto-rendering + +A component is mounted and rendered automatically as a Ripple component (without having to [manually mount](#manual-mount) it) if the following conditions are met: + +- The component is exported as the default export. +- No [imports from `"./script"`](#exports) in markup editor. +- Auto-rendering is not [disabled](#disabling-auto-rendering). + +### Root Element + +To mount the application instance to a specific DOM element use `"livecodes-app"` as the element `id` in the HTML. Otherwise, if that element is not found, a new `div` element is added to `document.body` and is used to mount the instance. + +Example: + +export const customRoot = { + markup: { + language: 'html', + content: `

Custom Root Element

+
+
...other page content
+`, + }, + script: { + language: 'ripple', + content: `export default component App() { + let \$name = 'Ripple'; +
{\`I'm a \${\$name} component\`}
+ +} +`, + }, +}; + + + + +### Manual Mount + +Exports from Ripple code can be imported in [markup editor](../features/projects.mdx#markup-editor) from `"./script"` and used to mount the application instance manually. +See [Exports](#exports) for details. + +Example: + +export const manualMount = { + markup: { + language: 'html', + content: `

Manual Mount

+
+
...other page content
+ + +`, + }, + script: { + language: 'ripple', + content: `export component App(props: { name: string }) { +
{\`I'm a \${props.name} component\`}
+ +} +`, + }, +}; + + + +### Disabling Auto-rendering + +To disable [auto-rendering](#auto-rendering), set the [custom settings](#custom-settings) `disableAutoRender` property to `true`. + +```json title="Custom Settings" +{ + "ripple": { + "disableAutoRender": true + } +} +``` + +### Module Imports + +npm modules can be imported as described in the section about [module resolution](../features/module-resolution.mdx), including bare module imports and importing from different CDNs. Stylesheets imported in the `script` block are added as `` tags in the page `head`. + +Module imports can be customized using import maps as described in [module resolution](../features/module-resolution.mdx#custom-module-resolution) documentations. + +Example: + +export const importsDemo = { + ripple: `import { effect } from "ripple"; +import confetti from "canvas-confetti"; + +export default component App() { +
+ let $count = 0; + + effect(() => { + if ($count === 2) confetti(); + }); + + + + if ($count > 1) { +
{'Greater than 1!'}
+ } +
+ + +} +`, +}; + + + + +{/* +### Importing External Components + +External Svelte components can be imported. The import URL has to be an absolute URL ending with `.svelte` extension. Any bare or relative imports in the imported files are resolved and compiled recursively. + +Example: + +```html + + + +``` + */} + +### Exports + +Values exported from [script editor](../features/projects.mdx#script-editor) (default or named) can be imported in the [markup editor](../features/projects.mdx#markup-editor) by importing from `"./script"` (with no extension). + +This can be useful, for example, for [manually mounting](#manual-mount) components in the markup editor. + +:::info note + +When values are imported from `"./script"`, [auto-rendering](#auto-rendering) is disabled, because it is assumed that you want to take control over component rendering. + +::: + +### Styles + +CSS can be applied to the component using various ways: + +#### Component Styles + +Styles in a `style` tag in a Ripple component are applied to that component only. + +CSS processors (e.g. SCSS, Stylus) can be used by specifying a `lang` attribute for the `style` tag. + +Example: + +export const styleTag = { + ripple: `export default component App() { +

{'Hello World!'}

+ + +} +` +} + + + + +#### Style Editor + +Styles added in the [style editor](../features/projects.mdx#style-editor) are applied globally to the [result page](../features/result.mdx). This can use different **languages/processors** supported in LiveCodes including CSS, SCSS, Less, Stylus, ..etc. See [style documentation](../features/css.mdx) for more details. + +And of course, styles and stylesheets added in [markup editor](../features/projects.mdx#markup-editor) are also applied globally. + +#### Importing Stylesheets + +Stylesheets imported in [script editor](../features/projects.mdx#script-editor) are added as `` tags in the page `head`. +The stylesheet URL can be an absolute URL or a path in the npm package. The URL has to end with `".css"`. + +example: + +export const stylesDemo = { + ripple: `import "bootstrap/dist/css/bootstrap.css";\n\nexport default component App() {\n

{'Hello World!'}

\n}\n`, +}; + + + +#### CSS Modules + +CSS modules are supported and are [documented separately](./cssmodules.mdx). Make sure to enable CSS modules (from style editor menu or in [`processors`](../configuration/configuration-object.mdx#processors) property of [configuration object](../configuration/configuration-object.mdx)). + +Demo: + +export const cssModulesDemo = { + activeEditor: 'script', + style: { language: 'css', content: `.title {\n color: green;\n font-family: sans-serif;\n}\n` }, + script: { + language: 'ripple', + content: `import classes from './style.module.css';\n\nexport default component() {\n

\n {'Hello, CSS Modules!'}\n

\n}\n`, + }, + processors: ['cssmodules'], +}; + + + +#### CSS Frameworks + +[CSS Frameworks](../features/css.mdx#css-processors) supported in LiveCodes (e.g. [Tailwind CSS](./tailwindcss.mdx), [UnoCSS](./unocss.mdx), [WindiCSS](./windicss.mdx)) can detect class names added in Ripple components. +Make sure that the required utility is enabled (from style editor menu or in `processors` property of [configuration object](../configuration/configuration-object.mdx#processors)). + +Example: + +export const tailwindDemo = { + activeEditor: 'script', + script: { + language: 'ripple', + content: `export default component Counter() { + let $count = 0; + +
+

{'Ripple + Tailwind CSS'}

+
+ + {$count} + +
+ +
+} +`, + }, + processors: ['tailwindcss'], +}; + + + +## Language Info + +### Name + +`ripple` + +### Extensions + +`.ripple` + +### Editor + +`script` + +## Compiler + +The official [Ripple compiler](https://github.com/trueadm/ripple). + +### Version + +`ripple`: v0.2.15 + +## Code Formatting + +Using [Prettier](https://prettier.io/). + +## Custom Settings + +[Custom settings](../advanced/custom-settings.mdx) can be added to the property `ripple`. +These include: + +- `"disableAutoRender"` - [disables auto-rendering](#disabling-auto-rendering) (default: `false`). +- `"version"` - specifies the version of Ripple compiler (default: `"latest"`). + +Example: + +```json title="Custom Settings" +{ + "ripple": { + "version": "0.2.15" + } +} +``` + +Please note that custom settings should be valid JSON (i.e. functions are not allowed). + +## Starter Template + +https://livecodes.io/?template=ripple + + + +## Links + +- [Ripple](https://ripplejs.com/) +- [Ripple documentations](https://github.com/trueadm/ripple) diff --git a/docs/src/components/LanguageSliders.tsx b/docs/src/components/LanguageSliders.tsx index e1daff5ac6..9c51edf216 100644 --- a/docs/src/components/LanguageSliders.tsx +++ b/docs/src/components/LanguageSliders.tsx @@ -69,6 +69,7 @@ export default function Sliders() { { name: 'solid.tsx', title: 'Solid (TS)' }, { name: 'riot', title: 'Riot.js' }, { name: 'malina', title: 'Malina.js' }, + { name: 'ripple', title: 'Ripple' }, { name: 'coffeescript', title: 'CoffeeScript' }, { name: 'livescript', title: 'LiveScript' }, { name: 'civet', title: 'Civet' }, diff --git a/docs/src/components/TemplateList.tsx b/docs/src/components/TemplateList.tsx index 126f377f72..e38688d7b8 100644 --- a/docs/src/components/TemplateList.tsx +++ b/docs/src/components/TemplateList.tsx @@ -23,6 +23,7 @@ const templates = [ { name: 'astro', title: 'Astro Starter', thumbnail: 'astro.svg' }, { name: 'riot', title: 'Riot.js Starter', thumbnail: 'riot.svg' }, { name: 'malina', title: 'Malina.js Starter', thumbnail: 'malina.svg' }, + { name: 'ripple', title: 'Ripple Starter', thumbnail: 'malina.svg' }, { name: 'jquery', title: 'jQuery Starter', thumbnail: 'jquery.svg' }, { name: 'backbone', title: 'Backbone Starter', thumbnail: 'backbone.svg' }, { name: 'knockout', title: 'Knockout Starter', thumbnail: 'knockout.svg' }, diff --git a/src/livecodes/UI/command-menu-actions.ts b/src/livecodes/UI/command-menu-actions.ts index d42de5ca55..fbed0aeb33 100644 --- a/src/livecodes/UI/command-menu-actions.ts +++ b/src/livecodes/UI/command-menu-actions.ts @@ -266,6 +266,7 @@ export const getCommandMenuActions = ({ 'preact', 'svelte', 'solid', + 'ripple', 'lit', 'stencil', 'mdx', diff --git a/src/livecodes/templates/starter/index.ts b/src/livecodes/templates/starter/index.ts index 032067f703..e6d68ed7fb 100644 --- a/src/livecodes/templates/starter/index.ts +++ b/src/livecodes/templates/starter/index.ts @@ -80,7 +80,6 @@ export const starterTemplates = [ preactStarter, svelteStarter, solidStarter, - rippleStarter, litStarter, stencilStarter, mdxStarter, @@ -91,6 +90,7 @@ export const starterTemplates = [ astroStarter, riotStarter, malinaStarter, + rippleStarter, jqueryStarter, backboneStarter, knockoutStarter, diff --git a/src/livecodes/templates/starter/ripple-starter.ts b/src/livecodes/templates/starter/ripple-starter.ts index 07f5124b90..a74074c592 100644 --- a/src/livecodes/templates/starter/ripple-starter.ts +++ b/src/livecodes/templates/starter/ripple-starter.ts @@ -33,7 +33,7 @@ component Counter(props: { $name: string }) { font: 1em sans-serif; } .logo { - width: 150px; + width: 100px; } } From defbe25e9b293b2491a1cc688bdf3fc23e8d33ea Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Sat, 6 Sep 2025 21:32:34 +0300 Subject: [PATCH 47/71] fix --- src/livecodes/languages/ripple/lang-ripple-compiler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/livecodes/languages/ripple/lang-ripple-compiler.ts b/src/livecodes/languages/ripple/lang-ripple-compiler.ts index 07c16f507a..43a31a8347 100644 --- a/src/livecodes/languages/ripple/lang-ripple-compiler.ts +++ b/src/livecodes/languages/ripple/lang-ripple-compiler.ts @@ -1,4 +1,4 @@ -import { compileBlocks } from '../../compiler'; +import { compileBlocks } from '../../compiler/compile-blocks'; import type { CompilerFunction, Config } from '../../models'; import { modulesService } from '../../services/modules'; From d420059c393b594681c8b7da5cfcb2094f50cb27 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Sat, 6 Sep 2025 21:32:34 +0300 Subject: [PATCH 48/71] allow importing external ripple components --- src/livecodes/compiler/import-map.ts | 10 ++- .../languages/ripple/lang-ripple-compiler.ts | 75 +++++++++++++++---- 2 files changed, 68 insertions(+), 17 deletions(-) diff --git a/src/livecodes/compiler/import-map.ts b/src/livecodes/compiler/import-map.ts index a915cd0040..ae70efb17c 100644 --- a/src/livecodes/compiler/import-map.ts +++ b/src/livecodes/compiler/import-map.ts @@ -144,6 +144,14 @@ export const isScriptImport = (mod: string) => mod.toLowerCase().endsWith('.vue') || mod.toLowerCase().endsWith('.svelte'))); +const isStyleImport = (mod: string) => + mod.toLowerCase().startsWith('./style') || + mod.toLowerCase().endsWith('.css') || + mod.toLowerCase().endsWith('.scss') || + mod.toLowerCase().endsWith('.sass') || + mod.toLowerCase().endsWith('.less') || + mod.toLowerCase().endsWith('.styl'); + const modulesCache: Record = {}; const fetchModule = async (mod: string) => { if (modulesCache[mod]) { @@ -176,7 +184,7 @@ export const replaceSFCImports = async ( const isExtensionless = (mod: string) => mod.startsWith('.') && !mod.split('/')[mod.split('/').length - 1].includes('.'); const sfcImports = getImports(code).filter( - (mod) => isSfc(mod) || isExtensionless(mod) || mod.startsWith('.'), + (mod) => !isStyleImport(mod) && (isSfc(mod) || isExtensionless(mod) || mod.startsWith('.')), ); const projectImportMap = { ...config.imports, diff --git a/src/livecodes/languages/ripple/lang-ripple-compiler.ts b/src/livecodes/languages/ripple/lang-ripple-compiler.ts index 43a31a8347..b51fe59c29 100644 --- a/src/livecodes/languages/ripple/lang-ripple-compiler.ts +++ b/src/livecodes/languages/ripple/lang-ripple-compiler.ts @@ -1,11 +1,22 @@ +import { createImportMap, getCompileResult, replaceSFCImports } from '../../compiler'; import { compileBlocks } from '../../compiler/compile-blocks'; import type { CompilerFunction, Config } from '../../models'; import { modulesService } from '../../services/modules'; +import { getLanguageByAlias } from '../utils'; -// TODO: recursively compile imported Ripple components +const getLatestVersion = async () => { + const pkg = await fetch('https://data.jsdelivr.com/v1/packages/npm/ripple') + .then((res) => res.json()) + .catch(() => ({})); + return pkg.tags?.latest || 'latest'; +}; (self as any).createRippleCompiler = async (initialConfig: Config): Promise => { - let version = initialConfig.customSettings.ripple?.version || 'latest'; + const MAIN_FILE = '__LiveCodes_App__.ripple'; + let importedContent = ''; + let imports: Record = {}; + + let version: string = initialConfig.customSettings.ripple?.version || (await getLatestVersion()); let compile: (code: string, filename: string) => Promise<{ js: { code: string }; css: string }>; const updateCompiler = async (currentVersion: string) => { @@ -17,35 +28,67 @@ import { modulesService } from '../../services/modules'; version = currentVersion; }; - return async (code, { config }) => { - if (!code.trim()) return ''; + const compileRipple = async ( + code: string, + { config, filename }: { config: Config; filename: string }, + ) => { + if (filename === MAIN_FILE) { + importedContent = ''; + imports = {}; + } + if (!code.trim()) return getCompileResult(''); const newVersion = config.customSettings.ripple?.version || version; await updateCompiler(newVersion); - code = await compileBlocks(code, 'style', config); + const isRipple = (mod: string) => + mod.toLowerCase().endsWith('.ripple') || mod.toLowerCase().startsWith('data:text/ripple'); - const { js, css } = await compile(code, './App.ripple'); + const fullCode = await replaceSFCImports(code, { + config, + filename, + getLanguageByAlias, + isSfc: isRipple, + compileSFC: async ( + code: string, + { config, filename }: { config: Config; filename: string }, + ) => { + const compiled = (await compileRipple(code, { config, filename })).code; + importedContent += `\n${filename}\n\n${code}\n`; + return compiled; + }, + }); + const processedCode = await compileBlocks(fullCode, 'style', config); + const { js, css } = await compile(processedCode, filename); const cssCode = css === '' ? '' - : `\n + : ` const styles = document.createElement('style'); styles.innerHTML = ${JSON.stringify(css)}; document.head.appendChild(styles); `; - const moduleUrl = /* @__PURE__ */ modulesService.getModuleUrl(`ripple@${version}`); + if (filename === MAIN_FILE) { + const moduleUrl = /* @__PURE__ */ modulesService.getModuleUrl(`ripple@${version}`); + imports = { + ...createImportMap(importedContent, config), + ripple: moduleUrl, + 'ripple/internal': `${moduleUrl}/internal`, + 'ripple/internal/client': `${moduleUrl}/internal/client`, + }; + } + return { - code: `${js.code}${cssCode}`, - info: { - imports: { - ripple: moduleUrl, - 'ripple/internal': `${moduleUrl}/internal`, - 'ripple/internal/client': `${moduleUrl}/internal/client`, - }, - }, + code: `${js.code}\n${cssCode}`, + info: { importedContent, imports }, }; }; + + return (code, { config }) => + compileRipple(code, { + config, + filename: MAIN_FILE, + }); }; From 56805b0c1461c6ef87e25bdd63d62cd333e8b534 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Sat, 6 Sep 2025 21:32:34 +0300 Subject: [PATCH 49/71] edit ripple docs --- docs/docs/languages/ripple.mdx | 70 +++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 22 deletions(-) diff --git a/docs/docs/languages/ripple.mdx b/docs/docs/languages/ripple.mdx index 93bfe5315a..62e5df4610 100644 --- a/docs/docs/languages/ripple.mdx +++ b/docs/docs/languages/ripple.mdx @@ -6,11 +6,9 @@ toc_max_heading_level: 4 [Ripple](https://www.ripplejs.com/) is a TypeScript UI framework that takes the best parts of React, Solid and Svelte and combines them into one package. -## Usage - Ripple components can be used in LiveCodes as documented in the [Ripple docs](https://github.com/trueadm/ripple). See below for usage. -### Demo +## Demo import LiveCodes from '../../src/components/LiveCodes.tsx'; import RunInLiveCodes from '../../src/components/RunInLiveCodes.tsx'; @@ -57,6 +55,9 @@ export const demo = { + +## Mounting + ### Auto-rendering A component is mounted and rendered automatically as a Ripple component (without having to [manually mount](#manual-mount) it) if the following conditions are met: @@ -68,6 +69,7 @@ A component is mounted and rendered automatically as a Ripple component (without ### Root Element To mount the application instance to a specific DOM element use `"livecodes-app"` as the element `id` in the HTML. Otherwise, if that element is not found, a new `div` element is added to `document.body` and is used to mount the instance. +In case you need more control, you can [manually mount](#manual-mount) the instance. Example: @@ -152,9 +154,11 @@ To disable [auto-rendering](#auto-rendering), set the [custom settings](#custom- } ``` -### Module Imports +## Importing Modules -npm modules can be imported as described in the section about [module resolution](../features/module-resolution.mdx), including bare module imports and importing from different CDNs. Stylesheets imported in the `script` block are added as `` tags in the page `head`. +### NPM Modules + +npm modules can be imported as described in the section about [module resolution](../features/module-resolution.mdx), including bare module imports and importing from different CDNs. Stylesheets imported in the `script` block are added as `` tags in the page `head` (see [below](#importing-stylesheets)). Module imports can be customized using import maps as described in [module resolution](../features/module-resolution.mdx#custom-module-resolution) documentations. @@ -192,22 +196,44 @@ export default component App() { +### External Components -{/* -### Importing External Components +External Ripple components can be imported. +The import URL can be either: +- An absolute URL ending with `.ripple` extension. +- A [bare module import](../features/module-resolution.mdx#bare-module-imports) for a published npm module with full path to the component with extension. +- A [data URL](../features/data-urls.mdx) starting with `data:text/ripple`. -External Svelte components can be imported. The import URL has to be an absolute URL ending with `.svelte` extension. Any bare or relative imports in the imported files are resolved and compiled recursively. +Any bare or relative imports in the imported files are resolved and compiled recursively. +If a processor is enabled (e.g. Tailwind CSS), classes in the imported files are detected and used in the generated CSS (see [CSS Frameworks](#css-frameworks) section below). -Example: +Example: ([source](https://github.com/hatemhosny/ripple-tailwind-counter-demo)) -```html - +export const externalComponents = { + activeEditor: 'script', + script: { + language: 'ripple', + content: `// import from npm modules +import Counter from 'ripple-tailwind-counter-demo/src/Counter.ripple'; +// alternatively use absolute URLs +// import Counter from 'https://raw.githubusercontent.com/hatemhosny/ripple-tailwind-counter-demo/refs/heads/main/src/Counter.ripple'; - -``` - */} + +export default component App() { + let $name = "World"; + + setTimeout(() => { + $name = "Ripple + Tailwind!"; + }, 2000); + + +} +`, + }, + processors: ['tailwindcss'], +} + + ### Exports @@ -221,11 +247,11 @@ When values are imported from `"./script"`, [auto-rendering](#auto-rendering) is ::: -### Styles +## Styles CSS can be applied to the component using various ways: -#### Component Styles +### Component Styles Styles in a `style` tag in a Ripple component are applied to that component only. @@ -255,13 +281,13 @@ export const styleTag = { > -#### Style Editor +### Style Editor Styles added in the [style editor](../features/projects.mdx#style-editor) are applied globally to the [result page](../features/result.mdx). This can use different **languages/processors** supported in LiveCodes including CSS, SCSS, Less, Stylus, ..etc. See [style documentation](../features/css.mdx) for more details. And of course, styles and stylesheets added in [markup editor](../features/projects.mdx#markup-editor) are also applied globally. -#### Importing Stylesheets +### Importing Stylesheets Stylesheets imported in [script editor](../features/projects.mdx#script-editor) are added as `` tags in the page `head`. The stylesheet URL can be an absolute URL or a path in the npm package. The URL has to end with `".css"`. @@ -279,7 +305,7 @@ export const stylesDemo = { formatCode={false} > -#### CSS Modules +### CSS Modules CSS modules are supported and are [documented separately](./cssmodules.mdx). Make sure to enable CSS modules (from style editor menu or in [`processors`](../configuration/configuration-object.mdx#processors) property of [configuration object](../configuration/configuration-object.mdx)). @@ -297,7 +323,7 @@ export const cssModulesDemo = { -#### CSS Frameworks +### CSS Frameworks [CSS Frameworks](../features/css.mdx#css-processors) supported in LiveCodes (e.g. [Tailwind CSS](./tailwindcss.mdx), [UnoCSS](./unocss.mdx), [WindiCSS](./windicss.mdx)) can detect class names added in Ripple components. Make sure that the required utility is enabled (from style editor menu or in `processors` property of [configuration object](../configuration/configuration-object.mdx#processors)). From 6848574f524fdde71915e524326332cb90fc9875 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Sat, 6 Sep 2025 21:32:34 +0300 Subject: [PATCH 50/71] upgrade ripple formatter --- src/livecodes/languages/ripple/lang-ripple-compiler.ts | 3 ++- src/livecodes/vendors.ts | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/livecodes/languages/ripple/lang-ripple-compiler.ts b/src/livecodes/languages/ripple/lang-ripple-compiler.ts index b51fe59c29..c3f7a85b0c 100644 --- a/src/livecodes/languages/ripple/lang-ripple-compiler.ts +++ b/src/livecodes/languages/ripple/lang-ripple-compiler.ts @@ -1,5 +1,6 @@ -import { createImportMap, getCompileResult, replaceSFCImports } from '../../compiler'; import { compileBlocks } from '../../compiler/compile-blocks'; +import { createImportMap, replaceSFCImports } from '../../compiler/import-map'; +import { getCompileResult } from '../../compiler/utils'; import type { CompilerFunction, Config } from '../../models'; import { modulesService } from '../../services/modules'; import { getLanguageByAlias } from '../utils'; diff --git a/src/livecodes/vendors.ts b/src/livecodes/vendors.ts index c44a9dbda4..df06b73a82 100644 --- a/src/livecodes/vendors.ts +++ b/src/livecodes/vendors.ts @@ -344,7 +344,7 @@ export const postcssImportUrlUrl = /* @__PURE__ */ getUrl( export const prettierBaseUrl = /* @__PURE__ */ getUrl('prettier@3.3.2/'); export const prettierRippleUrl = /* @__PURE__ */ getUrl( - '@hatemhosny/prettier-plugin-ripple@0.0.7/build/parser-ripple.js', + '@hatemhosny/prettier-plugin-ripple@0.0.8/build/parser-ripple.js', ); export const prettierPhpUrl = /* @__PURE__ */ getUrl('@prettier/plugin-php@0.22.2/standalone.js'); From a57b44a290b2d6d7ca240d5a4d232198e9b4e1b0 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Sun, 7 Sep 2025 00:42:45 +0300 Subject: [PATCH 51/71] use esm plugin for prettier --- src/livecodes/formatter/format.worker.ts | 47 ++++++++++++++---------- src/livecodes/vendors.ts | 4 +- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/src/livecodes/formatter/format.worker.ts b/src/livecodes/formatter/format.worker.ts index d15e04adb5..bdb59f60ba 100644 --- a/src/livecodes/formatter/format.worker.ts +++ b/src/livecodes/formatter/format.worker.ts @@ -46,7 +46,7 @@ const load = (languages: Language[]) => { } }; -function loadParser(language: Language): Parser | undefined { +async function loadParser(language: Language): Promise { if (!(self as any).prettier) { loadPrettier(); } @@ -60,26 +60,33 @@ function loadParser(language: Language): Parser | undefined { if (!(self as any).prettierPlugins) { (self as any).prettierPlugins = {}; } - parser.plugins = parser.pluginUrls - .map((pluginUrl) => { - if (plugins[pluginUrl]) return true; - try { - importScripts(pluginUrl); - plugins[pluginUrl] = true; - if (!prettierPlugins.pug && (self as any).pluginPug) { - prettierPlugins.pug = (self as any).pluginPug; + parser.plugins = ( + await Promise.all( + parser.pluginUrls.map(async (pluginUrl) => { + if (plugins[pluginUrl]) return true; + if (language === 'ripple') { + const p = await import(pluginUrl); + prettierPlugins[language] = p; + return true; } - if (!prettierPlugins.java && (self as any).pluginJava?.default) { - prettierPlugins.java = (self as any).pluginJava.default; + try { + importScripts(pluginUrl); + plugins[pluginUrl] = true; + if (!prettierPlugins.pug && (self as any).pluginPug) { + prettierPlugins.pug = (self as any).pluginPug; + } + if (!prettierPlugins.java && (self as any).pluginJava?.default) { + prettierPlugins.java = (self as any).pluginJava.default; + } + return true; + } catch { + // eslint-disable-next-line no-console + console.warn('Failed to load formatter for: ' + language); + return false; } - return true; - } catch (err) { - // eslint-disable-next-line no-console - console.warn('Failed to load formatter for: ' + language); - return false; - } - }) - .filter(Boolean); + }), + ) + ).filter(Boolean); if (parser.plugins.length > 0) { parsers[language] = parser; @@ -108,7 +115,7 @@ const format = async ( const unFormatted = { formatted: value, cursorOffset }; if (getParser(language) != null) { - const parser = loadParser(language); + const parser = await loadParser(language); const options = { useTabs: formatterConfig.useTabs ?? defaultConfig.useTabs, tabWidth: formatterConfig.tabSize ?? defaultConfig.tabSize, diff --git a/src/livecodes/vendors.ts b/src/livecodes/vendors.ts index df06b73a82..ed60d715f2 100644 --- a/src/livecodes/vendors.ts +++ b/src/livecodes/vendors.ts @@ -343,9 +343,7 @@ export const postcssImportUrlUrl = /* @__PURE__ */ getUrl( export const prettierBaseUrl = /* @__PURE__ */ getUrl('prettier@3.3.2/'); -export const prettierRippleUrl = /* @__PURE__ */ getUrl( - '@hatemhosny/prettier-plugin-ripple@0.0.8/build/parser-ripple.js', -); +export const prettierRippleUrl = /* @__PURE__ */ getModuleUrl('prettier-plugin-ripple@0.2.25'); export const prettierPhpUrl = /* @__PURE__ */ getUrl('@prettier/plugin-php@0.22.2/standalone.js'); From b10c3c32e3ba7f36d9eaa0f715f1839b395c19b1 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Tue, 9 Sep 2025 17:49:46 +0300 Subject: [PATCH 52/71] allow loading ripple compiler & formatter from pkg.pr.new --- scripts/build.js | 1 + src/livecodes/formatter/format.worker.ts | 12 ++++---- src/livecodes/formatter/formatter.ts | 6 ++-- src/livecodes/formatter/get-formatter.ts | 8 +++--- src/livecodes/formatter/models.ts | 7 +++-- src/livecodes/languages/prettier.ts | 3 +- .../languages/ripple/lang-ripple-compiler.ts | 22 +++++++-------- .../languages/ripple/lang-ripple-formatter.ts | 28 +++++++++++++++++++ src/livecodes/languages/ripple/lang-ripple.ts | 9 +++--- src/livecodes/services/pkgInfo.ts | 8 ++++++ src/livecodes/vendors.ts | 2 ++ src/sdk/models.ts | 3 +- 12 files changed, 76 insertions(+), 33 deletions(-) create mode 100644 src/livecodes/languages/ripple/lang-ripple-formatter.ts diff --git a/scripts/build.js b/scripts/build.js index e668ebe84e..b179b6b368 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -238,6 +238,7 @@ const iifeBuild = () => 'languages/rescript/lang-rescript-formatter.ts', 'languages/riot/lang-riot-compiler.ts', 'languages/ripple/lang-ripple-compiler.ts', + 'languages/ripple/lang-ripple-formatter.ts', 'languages/ruby-wasm/lang-ruby-wasm-script.ts', 'languages/scss/lang-scss-compiler.ts', 'languages/solid/lang-solid-compiler.ts', diff --git a/src/livecodes/formatter/format.worker.ts b/src/livecodes/formatter/format.worker.ts index bdb59f60ba..99aaa06d56 100644 --- a/src/livecodes/formatter/format.worker.ts +++ b/src/livecodes/formatter/format.worker.ts @@ -1,6 +1,6 @@ import { defaultConfig } from '../config/default-config'; import { languages, parserPlugins, prettierUrl } from '../languages'; -import type { FormatFn, FormatterConfig, Language, Parser } from '../models'; +import type { Config, FormatFn, FormatterConfig, Language, Parser } from '../models'; import type { FormatterMessage, FormatterMessageEvent } from './models'; const worker: Worker = self as any; @@ -9,6 +9,7 @@ declare const prettierPlugins: { [key: string]: { parsers: any } }; declare const importScripts: (...args: string[]) => void; let baseUrl: string; +let initialConfig: Config; const parsers: { [key: string]: Parser } = {}; const plugins: { [key: string]: any } = {}; const formatters: { [key: string]: FormatFn } = {}; @@ -94,7 +95,7 @@ async function loadParser(language: Language): Promise { return parser; } -const loadFormatter = (language: Language): FormatFn | undefined => { +const loadFormatter = async (language: Language): Promise => { if (language in formatters) { return formatters[language]; } @@ -102,7 +103,7 @@ const loadFormatter = (language: Language): FormatFn | undefined => { const formatter = getFormatter(language); if (!formatter) return; - formatters[language] = formatter.factory(baseUrl, language); + formatters[language] = await formatter.factory(baseUrl, language, initialConfig); return formatters[language]; }; @@ -135,7 +136,7 @@ const format = async ( return formatted || unFormatted; } if (getFormatter(language) != null) { - const formatFn = loadFormatter(language); + const formatFn = await loadFormatter(language); const result = await formatFn?.(value, cursorOffset); return result || unFormatted; } @@ -148,7 +149,8 @@ worker.addEventListener( const message = event.data; if (message.type === 'init') { - baseUrl = message.baseUrl; + baseUrl = message.payload.baseUrl; + initialConfig = message.payload.config; } if (message.type === 'load') { diff --git a/src/livecodes/formatter/formatter.ts b/src/livecodes/formatter/formatter.ts index 82e0441558..f9a24737c8 100644 --- a/src/livecodes/formatter/formatter.ts +++ b/src/livecodes/formatter/formatter.ts @@ -1,14 +1,14 @@ -import type { FormatFn, Language } from '../models'; +import type { Config, FormatFn, Language } from '../models'; import { getAppCDN } from '../services/modules'; import type { Formatter, FormatterMessage, FormatterMessageEvent } from './models'; -export const createFormatter = (baseUrl: string): Formatter => { +export const createFormatter = (baseUrl: string, config: Config): Formatter => { let worker: Worker | undefined; const initWorker = () => { if (worker) return; worker = new Worker(baseUrl + '{{hash:format.worker.js}}' + '?appCDN=' + getAppCDN()); - const configMessage: FormatterMessage = { type: 'init', baseUrl }; + const configMessage: FormatterMessage = { type: 'init', payload: { baseUrl, config } }; worker.postMessage(configMessage); }; diff --git a/src/livecodes/formatter/get-formatter.ts b/src/livecodes/formatter/get-formatter.ts index cdec830d79..31e587a10b 100644 --- a/src/livecodes/formatter/get-formatter.ts +++ b/src/livecodes/formatter/get-formatter.ts @@ -8,13 +8,13 @@ export const getFormatter = (config: Config, baseUrl: string, lazy: boolean): Fo if (readonly || mode === 'codeblock' || mode === 'result') { return createFakeFormatter(); } else if (lazy) { - return createLazyFormatter(baseUrl); + return createLazyFormatter(baseUrl, config); } else { - return createFormatter(baseUrl); + return createFormatter(baseUrl, config); } }; -const createLazyFormatter = (baseUrl: string) => { +const createLazyFormatter = (baseUrl: string, config: Config) => { const fakeFormatter = createFakeFormatter(); let formatter = fakeFormatter; @@ -34,7 +34,7 @@ const createLazyFormatter = (baseUrl: string) => { }; const loadFormatter = function () { - formatter = createFormatter(baseUrl); + formatter = createFormatter(baseUrl, config); lazyFormatter.load = formatter.load; lazyFormatter.getFormatFn = formatter.getFormatFn; lazyFormatter.destroy = formatter.destroy; diff --git a/src/livecodes/formatter/models.ts b/src/livecodes/formatter/models.ts index a384b00fd8..0fc780083a 100644 --- a/src/livecodes/formatter/models.ts +++ b/src/livecodes/formatter/models.ts @@ -1,4 +1,4 @@ -import type { FormatFn, FormatterConfig, Language } from '../models'; +import type { Config, FormatFn, FormatterConfig, Language } from '../models'; export interface Formatter { load: (languages: Language[]) => Promise; @@ -21,7 +21,10 @@ export type FormatterMessage = export interface InitMessage { type: 'init'; - baseUrl: string; + payload: { + baseUrl: string; + config: Config; + }; } export interface LoadMessage { diff --git a/src/livecodes/languages/prettier.ts b/src/livecodes/languages/prettier.ts index cd6d55457f..41777117da 100644 --- a/src/livecodes/languages/prettier.ts +++ b/src/livecodes/languages/prettier.ts @@ -1,4 +1,4 @@ -import { prettierBaseUrl, prettierPhpUrl, prettierRippleUrl, vendorsBaseUrl } from '../vendors'; +import { prettierBaseUrl, prettierPhpUrl, vendorsBaseUrl } from '../vendors'; export const prettierUrl = prettierBaseUrl + 'standalone.js'; export const parserPlugins = { @@ -11,5 +11,4 @@ export const parserPlugins = { php: prettierPhpUrl, pug: vendorsBaseUrl + 'prettier/parser-pug.js', java: vendorsBaseUrl + 'prettier/parser-java.js', - ripple: prettierRippleUrl, }; diff --git a/src/livecodes/languages/ripple/lang-ripple-compiler.ts b/src/livecodes/languages/ripple/lang-ripple-compiler.ts index c3f7a85b0c..c5a9432858 100644 --- a/src/livecodes/languages/ripple/lang-ripple-compiler.ts +++ b/src/livecodes/languages/ripple/lang-ripple-compiler.ts @@ -3,28 +3,26 @@ import { createImportMap, replaceSFCImports } from '../../compiler/import-map'; import { getCompileResult } from '../../compiler/utils'; import type { CompilerFunction, Config } from '../../models'; import { modulesService } from '../../services/modules'; +import { pkgInfoService } from '../../services/pkgInfo'; import { getLanguageByAlias } from '../utils'; -const getLatestVersion = async () => { - const pkg = await fetch('https://data.jsdelivr.com/v1/packages/npm/ripple') - .then((res) => res.json()) - .catch(() => ({})); - return pkg.tags?.latest || 'latest'; -}; - (self as any).createRippleCompiler = async (initialConfig: Config): Promise => { const MAIN_FILE = '__LiveCodes_App__.ripple'; let importedContent = ''; let imports: Record = {}; - let version: string = initialConfig.customSettings.ripple?.version || (await getLatestVersion()); + let version: string = + initialConfig.customSettings.ripple?.version || + (await pkgInfoService.getPkgLatestVersion('ripple')); let compile: (code: string, filename: string) => Promise<{ js: { code: string }; css: string }>; const updateCompiler = async (currentVersion: string) => { if (typeof compile === 'function' && currentVersion === version) return; - const mod = await import( - /* @__PURE__ */ modulesService.getModuleUrl(`ripple@${currentVersion}/compiler`) - ); + const modName = + currentVersion.startsWith('pr:ripple@') || currentVersion.startsWith('pkg.pr.new:ripple@') + ? `${currentVersion}/compiler` // 'pr:ripple@f8bdb34' + : `ripple@${currentVersion}/compiler`; // '0.2.25' + const mod = await import(modulesService.getModuleUrl(modName)); compile = mod.compile; version = currentVersion; }; @@ -72,7 +70,7 @@ document.head.appendChild(styles); `; if (filename === MAIN_FILE) { - const moduleUrl = /* @__PURE__ */ modulesService.getModuleUrl(`ripple@${version}`); + const moduleUrl = modulesService.getModuleUrl(`ripple@${version}`); imports = { ...createImportMap(importedContent, config), ripple: moduleUrl, diff --git a/src/livecodes/languages/ripple/lang-ripple-formatter.ts b/src/livecodes/languages/ripple/lang-ripple-formatter.ts new file mode 100644 index 0000000000..da981c954c --- /dev/null +++ b/src/livecodes/languages/ripple/lang-ripple-formatter.ts @@ -0,0 +1,28 @@ +import { defaultConfig } from '../../config/default-config'; +import type { Config, FormatFn } from '../../models'; +import { modulesService } from '../../services/modules'; +import { pkgInfoService } from '../../services/pkgInfo'; +import { prettierEsmUrl, prettierRippleUrl } from '../../vendors'; + +(self as any).createRippleFormatter = async (initialConfig: Config): Promise => { + const version = + initialConfig.customSettings.ripple?.version || + (await pkgInfoService.getPkgLatestVersion('ripple')); + const pluginUrl = + version.startsWith('pr:ripple@') || version.startsWith('pkg.pr.new:ripple@') + ? modulesService.getModuleUrl(version.replace('ripple', 'prettier-plugin-ripple')) + : prettierRippleUrl; + + const [prettier, ripplePlugin] = await Promise.all([import(prettierEsmUrl), import(pluginUrl)]); + return async (code, cursorOffset, formatterConfig) => + prettier.formatWithCursor(code, { + parser: 'ripple', + plugins: [ripplePlugin], + cursorOffset, + useTabs: formatterConfig?.useTabs ?? defaultConfig.useTabs, + tabWidth: formatterConfig?.tabSize ?? defaultConfig.tabSize, + semi: formatterConfig?.semicolons ?? defaultConfig.semicolons, + singleQuote: formatterConfig?.singleQuote ?? defaultConfig.singleQuote, + trailingComma: formatterConfig?.trailingComma === false ? 'none' : 'all', + }); +}; diff --git a/src/livecodes/languages/ripple/lang-ripple.ts b/src/livecodes/languages/ripple/lang-ripple.ts index 9aacc74937..76c59d5742 100644 --- a/src/livecodes/languages/ripple/lang-ripple.ts +++ b/src/livecodes/languages/ripple/lang-ripple.ts @@ -1,13 +1,14 @@ import type { LanguageSpecs } from '../../models'; -import { parserPlugins } from '../prettier'; export const ripple: LanguageSpecs = { name: 'ripple', title: 'Ripple', info: false, - parser: { - name: 'ripple', - pluginUrls: [parserPlugins.ripple], + formatter: { + factory: async (baseUrl, _language, config) => { + (self as any).importScripts(baseUrl + '{{hash:lang-ripple-formatter.js}}'); + return (self as any).createRippleFormatter(config); + }, }, compiler: { factory: (config, baseUrl) => { diff --git a/src/livecodes/services/pkgInfo.ts b/src/livecodes/services/pkgInfo.ts index 5096143cb3..41b36f493c 100644 --- a/src/livecodes/services/pkgInfo.ts +++ b/src/livecodes/services/pkgInfo.ts @@ -217,9 +217,17 @@ const getPkgDefaultFiles = async ( }; }; +const getPkgLatestVersion = async (pkgName: string): Promise => { + const pkg = await fetch(`${apiEndpoint}/packages/npm/${pkgName}`, { headers: jsDelivrHeaders }) + .then((res) => res.json()) + .catch(() => ({})); + return pkg.tags?.latest || 'latest'; +}; + export const pkgInfoService: CDNService = { search, getPkgInfo, getPkgFiles, getPkgDefaultFiles, + getPkgLatestVersion, }; diff --git a/src/livecodes/vendors.ts b/src/livecodes/vendors.ts index ed60d715f2..9bb7df689a 100644 --- a/src/livecodes/vendors.ts +++ b/src/livecodes/vendors.ts @@ -343,6 +343,8 @@ export const postcssImportUrlUrl = /* @__PURE__ */ getUrl( export const prettierBaseUrl = /* @__PURE__ */ getUrl('prettier@3.3.2/'); +export const prettierEsmUrl = /* @__PURE__ */ getModuleUrl('prettier@3.3.2/standalone'); + export const prettierRippleUrl = /* @__PURE__ */ getModuleUrl('prettier-plugin-ripple@0.2.25'); export const prettierPhpUrl = /* @__PURE__ */ getUrl('@prettier/plugin-php@0.22.2/standalone.js'); diff --git a/src/sdk/models.ts b/src/sdk/models.ts index c465302332..4e22a0ae23 100644 --- a/src/sdk/models.ts +++ b/src/sdk/models.ts @@ -1269,7 +1269,7 @@ export type FormatFn = ( ) => Promise<{ formatted: string; cursorOffset: number }>; export interface LanguageFormatter { - factory: (baseUrl: string, language: Language) => FormatFn; + factory: (baseUrl: string, language: Language, config: Config) => FormatFn | Promise; } export type CssPresetId = '' | 'normalize.css' | 'reset-css'; @@ -2077,6 +2077,7 @@ export interface CDNService { getPkgInfo: (pkgName: string) => Promise; getPkgFiles: (pkgName: string) => Promise<{ default?: string; files: string[] } | APIError>; getPkgDefaultFiles: (pkgName: string) => Promise<{ js?: string; css?: string } | APIError>; + getPkgLatestVersion: (pkgName: string) => Promise; } export interface WorkerMessageEvent extends MessageEvent { From 544dea066f62a2fbd1597f900ce01dfc3059ad44 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Sat, 13 Sep 2025 02:11:48 +0300 Subject: [PATCH 53/71] fixes --- docs/src/components/TemplateList.tsx | 2 +- src/livecodes/languages/ripple/lang-ripple-formatter.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/components/TemplateList.tsx b/docs/src/components/TemplateList.tsx index e38688d7b8..68d2fcf3e3 100644 --- a/docs/src/components/TemplateList.tsx +++ b/docs/src/components/TemplateList.tsx @@ -23,7 +23,7 @@ const templates = [ { name: 'astro', title: 'Astro Starter', thumbnail: 'astro.svg' }, { name: 'riot', title: 'Riot.js Starter', thumbnail: 'riot.svg' }, { name: 'malina', title: 'Malina.js Starter', thumbnail: 'malina.svg' }, - { name: 'ripple', title: 'Ripple Starter', thumbnail: 'malina.svg' }, + { name: 'ripple', title: 'Ripple Starter', thumbnail: 'ripple-0.png' }, { name: 'jquery', title: 'jQuery Starter', thumbnail: 'jquery.svg' }, { name: 'backbone', title: 'Backbone Starter', thumbnail: 'backbone.svg' }, { name: 'knockout', title: 'Knockout Starter', thumbnail: 'knockout.svg' }, diff --git a/src/livecodes/languages/ripple/lang-ripple-formatter.ts b/src/livecodes/languages/ripple/lang-ripple-formatter.ts index da981c954c..9e76c9e5c4 100644 --- a/src/livecodes/languages/ripple/lang-ripple-formatter.ts +++ b/src/livecodes/languages/ripple/lang-ripple-formatter.ts @@ -6,7 +6,7 @@ import { prettierEsmUrl, prettierRippleUrl } from '../../vendors'; (self as any).createRippleFormatter = async (initialConfig: Config): Promise => { const version = - initialConfig.customSettings.ripple?.version || + initialConfig.customSettings?.ripple?.version || (await pkgInfoService.getPkgLatestVersion('ripple')); const pluginUrl = version.startsWith('pr:ripple@') || version.startsWith('pkg.pr.new:ripple@') From 6885b11e35553fea41275c871fa859cf3f09c281 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Sat, 13 Sep 2025 19:39:22 +0300 Subject: [PATCH 54/71] use filename `Component.ripple` --- docs/docs/languages/ripple.mdx | 4 ++-- src/livecodes/languages/ripple/lang-ripple-compiler.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/docs/languages/ripple.mdx b/docs/docs/languages/ripple.mdx index 62e5df4610..536020cbb4 100644 --- a/docs/docs/languages/ripple.mdx +++ b/docs/docs/languages/ripple.mdx @@ -102,7 +102,7 @@ export const customRoot = { ### Manual Mount -Exports from Ripple code can be imported in [markup editor](../features/projects.mdx#markup-editor) from `"./script"` and used to mount the application instance manually. +Exports from Ripple code can be imported in [markup editor](../features/projects.mdx#markup-editor) from `"./Component.ripple"` and used to mount the application instance manually. See [Exports](#exports) for details. Example: @@ -116,7 +116,7 @@ export const manualMount = {