diff --git a/packages/cli/src/services/frontend.service.ts b/packages/cli/src/services/frontend.service.ts index eb5e3648465e1..f371edd935be0 100644 --- a/packages/cli/src/services/frontend.service.ts +++ b/packages/cli/src/services/frontend.service.ts @@ -32,6 +32,8 @@ import { Logger } from '@/Logger'; import { UrlService } from './url.service'; import { InternalHooks } from '@/InternalHooks'; import { isApiEnabled } from '@/PublicApi'; +import glob from 'fast-glob'; +import { readFile, writeFile } from 'node:fs/promises'; @Service() export class FrontendService { @@ -52,6 +54,7 @@ export class FrontendService { ) { loadNodesAndCredentials.addPostProcessor(async () => await this.generateTypes()); void this.generateTypes(); + void this.generateTypedefs(); this.initSettings(); @@ -368,4 +371,32 @@ export class FrontendService { } } } + + async generateTypedefs() { + const typedefsDir = path.join(this.instanceSettings.staticCacheDir, 'typedefs'); + + await mkdir(typedefsDir, { recursive: true }); + + // @TODO: Filter out irrelevant typedefs + + const paths = await glob('../../../node_modules/typescript/lib/*.d.ts'); + const names = paths.map((p) => path.basename(p)); + + await writeFile(path.resolve(typedefsDir, 'keys.json'), JSON.stringify(names)); + + const writeStream = createWriteStream(path.resolve(typedefsDir, 'map.json')); + + writeStream.write('{'); + + const content = await Promise.all( + paths.map( + async (_path, i) => `"${names[i]}":${JSON.stringify(await readFile(_path, 'utf8'))}`, + ), + ); + + writeStream.write(content.join(',')); + + writeStream.write('}'); + writeStream.end(); + } } diff --git a/packages/editor-ui/package.json b/packages/editor-ui/package.json index c09da5de7b906..d1bddbcb9a72e 100644 --- a/packages/editor-ui/package.json +++ b/packages/editor-ui/package.json @@ -43,8 +43,10 @@ "@jsplumb/util": "^5.13.2", "@lezer/common": "^1.0.4", "@n8n/chat": "workspace:*", + "@n8n/codemirror-lang": "workspace:*", "@n8n/codemirror-lang-sql": "^1.0.2", "@n8n/permissions": "workspace:*", + "@typescript/vfs": "^1.5.3", "@vue-flow/background": "^1.3.0", "@vue-flow/controls": "^1.1.1", "@vue-flow/core": "^1.33.5", @@ -55,7 +57,6 @@ "axios": "1.6.7", "chart.js": "^4.4.0", "codemirror-lang-html-n8n": "^1.0.0", - "@n8n/codemirror-lang": "workspace:*", "dateformat": "^3.0.3", "email-providers": "^2.0.1", "esprima-next": "5.8.4", @@ -64,6 +65,7 @@ "flatted": "^3.2.4", "humanize-duration": "^3.27.2", "jsonpath": "^1.1.1", + "localforage": "^1.10.0", "lodash-es": "^4.17.21", "luxon": "^3.3.0", "n8n-design-system": "workspace:*", @@ -73,6 +75,7 @@ "qrcode.vue": "^3.3.4", "stream-browserify": "^3.0.0", "timeago.js": "^4.0.2", + "typescript": "*", "uuid": "^8.3.2", "v3-infinite-loading": "^1.2.2", "vue": "^3.4.21", diff --git a/packages/editor-ui/src/api/typedefs.ts b/packages/editor-ui/src/api/typedefs.ts new file mode 100644 index 0000000000000..2a905be2c1e18 --- /dev/null +++ b/packages/editor-ui/src/api/typedefs.ts @@ -0,0 +1,16 @@ +import axios from 'axios'; +import { useRootStore } from '@/stores/root.store'; + +export async function fetchTypedefsIndex() { + const response = await axios.get(useRootStore().baseUrl + 'typedefs/keys.json'); + + return response.data; +} + +export async function fetchTypedefsMap() { + const response = await axios.get>( + useRootStore().baseUrl + 'typedefs/map.json', + ); + + return response.data; +} diff --git a/packages/editor-ui/src/components/ParameterInput.vue b/packages/editor-ui/src/components/ParameterInput.vue index 58300ee47bb7a..ec868986f222b 100644 --- a/packages/editor-ui/src/components/ParameterInput.vue +++ b/packages/editor-ui/src/components/ParameterInput.vue @@ -127,7 +127,13 @@ @update:model-value="expressionUpdated" > - + + +
+ + + diff --git a/packages/editor-ui/src/components/TypeScriptEditor/icons.ts b/packages/editor-ui/src/components/TypeScriptEditor/icons.ts new file mode 100644 index 0000000000000..0ccc0160f2d2d --- /dev/null +++ b/packages/editor-ui/src/components/TypeScriptEditor/icons.ts @@ -0,0 +1,37 @@ +// https://code.visualstudio.com/docs/editor/intellisense#_types-of-completions + +const toCssUrl = (svg: string) => { + const encodedSvg = svg.replace(//g, '%3E'); + + return `url(\"data:image/svg+xml,${encodedSvg}\")`; +}; + +// @TODO: Optimize all SVGs + +export const classSymbol = toCssUrl( + "", +); + +export const constantSymbol = toCssUrl( + "", +); + +export const fieldSymbol = toCssUrl( + "", +); + +export const variableSymbol = toCssUrl( + "", +); + +export const keywordSymbol = toCssUrl( + "", +); + +export const methodSymbol = toCssUrl( + "", +); + +export const snippetSymbol = toCssUrl( + "", +); diff --git a/packages/editor-ui/src/components/TypeScriptEditor/themes.ts b/packages/editor-ui/src/components/TypeScriptEditor/themes.ts new file mode 100644 index 0000000000000..4a5064965f0c8 --- /dev/null +++ b/packages/editor-ui/src/components/TypeScriptEditor/themes.ts @@ -0,0 +1,124 @@ +import type { Extension } from '@codemirror/state'; +import { EditorView } from '@codemirror/view'; +import * as icons from './icons'; + +export const editorTheme: Extension = [ + EditorView.theme({ + '&': { + fontFamily: 'var(--font-family-monospace)', + fontSize: 'var(--font-size-s)', + background: '#fff', + }, + '.cm-foldPlaceholder': { + background: 'transparent', + border: 'none', + }, + '.cm-tooltip': { + maxWidth: '800px', + display: 'flex', + flexDirection: 'column', + }, + '.cm-tooltip-section': { + order: '1', + }, + '.cm-tooltip-lint': { + order: '2', + }, + '.cm-tooltip-section:not(:first-child)': { + borderTop: 'none', + }, + '.cm-tooltip-below': { + marginTop: '5px', + }, + '.cm-tooltip.cm-tooltip-autocomplete > ul': { + minWidth: '250px', + }, + '.cm-tooltip.cm-tooltip-autocomplete > ul > li': { + display: 'flex', + alignItems: 'center', + padding: '2px', + }, + '.cm-completionMatchedText': { + textDecoration: 'none', + fontWeight: 600, + color: '#00B4D4', + }, + '.cm-completionDetail': { + fontStyle: 'initial', + color: '#ABABAB', + marginLeft: '2rem', + }, + '.cm-completionIcon': { + padding: '0', + marginRight: '4px', + width: '16px', + height: '16px', + backgroundRepeat: 'no-repeat', + backgroundImage: icons.snippetSymbol, + '&:after': { + content: "' '", + }, + '&.cm-completionIcon-function, &.cm-completionIcon-method': { + backgroundImage: icons.methodSymbol, + '&:after': { + content: "' '", + }, + }, + '&.cm-completionIcon-property, &.cm-completionIcon-getter': { + backgroundImage: icons.fieldSymbol, + '&:after': { + content: "' '", + }, + }, + '&.cm-completionIcon-enum, &.cm-completionIcon-enum-member, &.cm-completionIcon-string': { + backgroundImage: icons.constantSymbol, + '&:after': { + content: "' '", + }, + }, + '&.cm-completionIcon-var, &.cm-completionIcon-let, &.cm-completionIcon-const': { + backgroundImage: icons.variableSymbol, + '&:after': { + content: "' '", + }, + }, + '&.cm-completionIcon-keyword': { + backgroundImage: icons.keywordSymbol, + '&:after': { + content: "' '", + }, + }, + '&.cm-completionIcon-class, &.cm-completionIcon-interface, &.cm-completionIcon-alias': { + backgroundImage: icons.classSymbol, + '&:after': { + content: "' '", + }, + }, + }, + + '.cm-scroller': { overflow: 'auto' }, + '.cm-gutters': { background: '#fff' }, + '.cm-gutterElement': { color: '#cbd5e1' }, + '.cm-foldMarker': { + color: '#94a3b8', + }, + '.cm-activeLine, .cm-activeLineGutter': { + background: '#f1f5f9', + }, + '.cm-tooltip-autocomplete': { + background: '#e2e8f0', + }, + '.cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected]': { + background: '#cbd5e1', + color: '#1e293b', + }, + '.cm-diagnostic, .cm-quickinfo-tooltip': { + background: '#e2e8f0', + border: '1px solid #cbd5e1', + color: '#1e293b', + marginLeft: '0px', + padding: '0.5rem', + }, + '.cm-line': { color: '#1e293b' }, + }), +]; diff --git a/packages/editor-ui/src/plugins/codemirror/typescript-extension/constants.ts b/packages/editor-ui/src/plugins/codemirror/typescript-extension/constants.ts new file mode 100644 index 0000000000000..06af2dc761b96 --- /dev/null +++ b/packages/editor-ui/src/plugins/codemirror/typescript-extension/constants.ts @@ -0,0 +1 @@ +export const INDEX_TS = 'index.ts'; diff --git a/packages/editor-ui/src/plugins/codemirror/typescript-extension/typescript-completions.ts b/packages/editor-ui/src/plugins/codemirror/typescript-extension/typescript-completions.ts new file mode 100644 index 0000000000000..cc6fedbd86f1a --- /dev/null +++ b/packages/editor-ui/src/plugins/codemirror/typescript-extension/typescript-completions.ts @@ -0,0 +1,23 @@ +import { completeFromList } from '@codemirror/autocomplete'; +import type { CompletionContext } from '@codemirror/autocomplete'; +import { tsProjectField } from './typescript-project-field'; + +export const tsCompletions = async (context: CompletionContext) => { + const { state, pos } = context; + const completions = await state.field(tsProjectField).getCompletions(pos); + + if (!completions) return null; + + const options = completions.entries.map((c) => ({ + type: c.kind, + label: c.name, + boost: 1 / parseInt(c.sortText), + // @TODO: Add entry details + })); + + if (state.sliceDoc(pos - 1, pos) === '.') { + return { from: pos, options }; + } + + return await completeFromList(options)(context); +}; diff --git a/packages/editor-ui/src/plugins/codemirror/typescript-extension/typescript-diagnostics.ts b/packages/editor-ui/src/plugins/codemirror/typescript-extension/typescript-diagnostics.ts new file mode 100644 index 0000000000000..804f2cf3584fe --- /dev/null +++ b/packages/editor-ui/src/plugins/codemirror/typescript-extension/typescript-diagnostics.ts @@ -0,0 +1,42 @@ +// @TODO: Fix lint exceptions + +import type { Diagnostic } from '@codemirror/lint'; +import type { EditorState } from '@codemirror/state'; +import { tsProjectField } from './typescript-project-field'; +import type ts from 'typescript'; + +export const tsDiagnostics = async (state: EditorState): Promise => { + const rawDiagnostics = await state.field(tsProjectField).getDiagnostics(); + + return rawDiagnostics.map((diagnostic) => { + if (diagnostic.relatedInformation) { + diagnostic.relatedInformation.forEach((r) => { + // eslint-disable-next-line @typescript-eslint/restrict-plus-operands, @typescript-eslint/no-base-to-string + diagnostic.messageText += '\n\n' + r.file?.fileName + ': ' + r.messageText; + }); + } + + return { + from: diagnostic.start, + to: diagnostic.start + diagnostic.length, + severity: toSeverity(diagnostic), + // eslint-disable-next-line @typescript-eslint/no-base-to-string + message: diagnostic.messageText.toString(), + }; + }); +}; + +const TS_SEVERITY = { + warning: 0, + error: 1, +} as const; + +function toSeverity(diagnostic: ts.Diagnostic) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison + return diagnostic.category === TS_SEVERITY.error + ? 'error' + : // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison + diagnostic.category === TS_SEVERITY.warning + ? 'warning' + : 'info'; +} diff --git a/packages/editor-ui/src/plugins/codemirror/typescript-extension/typescript-extension.ts b/packages/editor-ui/src/plugins/codemirror/typescript-extension/typescript-extension.ts new file mode 100644 index 0000000000000..a3e2d20c2180f --- /dev/null +++ b/packages/editor-ui/src/plugins/codemirror/typescript-extension/typescript-extension.ts @@ -0,0 +1,26 @@ +import { autocompletion } from '@codemirror/autocomplete'; +import { javascriptLanguage } from '@codemirror/lang-javascript'; +import { LanguageSupport } from '@codemirror/language'; +import { linter } from '@codemirror/lint'; +import type { Extension } from '@codemirror/state'; +import { EditorView, hoverTooltip } from '@codemirror/view'; + +import { tsProjectField, updateIndexTs } from './typescript-project-field'; +import { tsCompletions } from './typescript-completions'; +import { tsDiagnostics } from './typescript-diagnostics'; +import { tsQuickInfo } from './typescript-quickinfo'; + +export function typescript(): Extension { + return [ + tsProjectField, + autocompletion(), + new LanguageSupport(javascriptLanguage, [ + javascriptLanguage.data.of({ autocomplete: tsCompletions }), + ]), + linter(async ({ state }) => await tsDiagnostics(state)), + hoverTooltip(async ({ state }, pos) => await tsQuickInfo(state, pos)), + EditorView.updateListener.of(({ view, docChanged }) => { + if (docChanged) updateIndexTs(view); + }), + ]; +} diff --git a/packages/editor-ui/src/plugins/codemirror/typescript-extension/typescript-project-field.ts b/packages/editor-ui/src/plugins/codemirror/typescript-extension/typescript-project-field.ts new file mode 100644 index 0000000000000..92d5f6eec6516 --- /dev/null +++ b/packages/editor-ui/src/plugins/codemirror/typescript-extension/typescript-project-field.ts @@ -0,0 +1,22 @@ +import { StateField } from '@codemirror/state'; +import { TypeScriptProject } from './typescript-project'; +import { INDEX_TS } from './constants'; +import { throttle } from 'lodash-es'; +import type { EditorView } from '@codemirror/view'; + +export const tsProjectField = StateField.define({ + create(state) { + return new TypeScriptProject(state.sliceDoc()); + }, + + update(newTsProject) { + return newTsProject; // required but unneeded + }, +}); + +export const updateIndexTs = throttle((view: EditorView) => { + void view.state + .field(tsProjectField) + .getVirtualEnv() + .then((venv) => venv.updateFile(INDEX_TS, view.state.sliceDoc(0) || ' ')); +}, 100); diff --git a/packages/editor-ui/src/plugins/codemirror/typescript-extension/typescript-project.ts b/packages/editor-ui/src/plugins/codemirror/typescript-extension/typescript-project.ts new file mode 100644 index 0000000000000..5ccddaa49ca3b --- /dev/null +++ b/packages/editor-ui/src/plugins/codemirror/typescript-extension/typescript-project.ts @@ -0,0 +1,160 @@ +// @TODO: Fix lint exceptions +import type { VirtualTypeScriptEnvironment } from '@typescript/vfs'; +import { createSystem, createVirtualTypeScriptEnvironment } from '@typescript/vfs'; + +import typescript from 'typescript'; +import localForage from 'localforage'; +import { fetchTypedefsIndex, fetchTypedefsMap } from '@/api/typedefs'; +import { INDEX_TS } from './constants'; +import { ApplicationError } from 'n8n-workflow'; + +// @TODO: Implication - TS adds ~900 kB (minified and gzipped) to bundle size +// @TODO: Implication - We now support types, so erase them before execution + +export class TypeScriptProject { + private readonly vfs = new Map(); + + private readonly store = localForage; + + private state: 'lazy' | 'mid-init' | 'ready'; + + private initPromise?: Promise; + + private virtualEnv?: VirtualTypeScriptEnvironment; + + private readonly indexTs = INDEX_TS; + + constructor(indexTsContent: string) { + this.vfs.set(this.indexTs, indexTsContent || ' '); + this.state = 'lazy'; + this.initPromise = undefined; + } + + private async init() { + this.state = 'mid-init'; + + // @TODO: Prevent creation of `local-forage-detect-blob-support` + this.store.config({ + driver: this.store.INDEXEDDB, + name: 'n8n', + storeName: 'typedefs', + }); + + await this.loadTypedefs(); + + this.virtualEnv = createVirtualTypeScriptEnvironment( + createSystem(this.vfs), + [this.indexTs], + typescript, + { + target: typescript.ScriptTarget.ESNext, + noImplicitAny: false, + // @TODO: Decide on tsconfig + }, + ); + + this.state = 'ready'; + } + + // @TODO: Connect to StateField disposal + dispose() { + this.assertVirtualEnv(this.virtualEnv); + + this.virtualEnv.languageService.dispose(); + + this.state = 'lazy'; + this.initPromise = undefined; + this.virtualEnv = undefined; + } + + async getVirtualEnv() { + if (this.state === 'lazy') { + this.initPromise = this.init(); + await this.initPromise; + // this.assertVirtualEnv(this.virtualEnv); // @TODO: Why does this fail? + + return this.virtualEnv!; + } + + if (this.state === 'mid-init') { + await this.initPromise; + // this.assertVirtualEnv(this.virtualEnv); + + return this.virtualEnv!; + } + + // this.assertVirtualEnv(this.virtualEnv); + return this.virtualEnv!; + } + + private assertVirtualEnv( + virtualEnv?: VirtualTypeScriptEnvironment, + ): asserts virtualEnv is VirtualTypeScriptEnvironment { + if (virtualEnv !== undefined) { + throw new ApplicationError('Expected virtual env to be initialized'); + } + } + + private async loadTypedefs() { + const isCacheEmpty = (await this.store.getItem('cache_ready')) !== 'true'; + + if (isCacheEmpty) { + await this.store.clear(); + + const typedefs = await fetchTypedefsMap(); // ~3 MB + const entries = Object.entries(typedefs); + + entries.push(['cache_ready', 'true']); + entries.forEach(([name, content]) => this.vfs.set('/' + name, content)); + + await Promise.all( + entries.map(async ([name, content]) => await this.store.setItem(name, content)), + ); + + return; + } + + const filenames = await fetchTypedefsIndex(); // ~2 KB + + const cache = await Promise.all( + filenames.map(async (f) => await this.store.getItem(f)), + ); + + this.assertCache(cache); + + filenames.forEach((f, i) => this.vfs.set('/' + f, cache[i])); + } + + assertCache(cache: Array): asserts cache is string[] { + if (cache.some((i) => i === null)) { + throw new ApplicationError('Some typedefs are missing from cache'); + } + } + + async getDiagnostics() { + const { languageService } = await this.getVirtualEnv(); + + function isDisplayable( + d: typescript.Diagnostic, + ): d is typescript.Diagnostic & { start: number; length: number } { + return d.start !== undefined && d.length !== undefined; + } + + return [ + ...languageService.getSemanticDiagnostics(this.indexTs), + ...languageService.getSyntacticDiagnostics(this.indexTs), + ].filter(isDisplayable); + } + + async getCompletions(position: number) { + const { languageService } = await this.getVirtualEnv(); + + return languageService.getCompletionsAtPosition(this.indexTs, position, {}); + } + + async getQuickInfo(position: number) { + const { languageService } = await this.getVirtualEnv(); + + return languageService.getQuickInfoAtPosition(this.indexTs, position); + } +} diff --git a/packages/editor-ui/src/plugins/codemirror/typescript-extension/typescript-quickinfo.ts b/packages/editor-ui/src/plugins/codemirror/typescript-extension/typescript-quickinfo.ts new file mode 100644 index 0000000000000..bde61da52dfa7 --- /dev/null +++ b/packages/editor-ui/src/plugins/codemirror/typescript-extension/typescript-quickinfo.ts @@ -0,0 +1,57 @@ +import type { EditorState } from '@codemirror/state'; +import { tsProjectField } from './typescript-project-field'; + +export const tsQuickInfo = async (state: EditorState, pos: number) => { + const rawQuickInfo = await state.field(tsProjectField).getQuickInfo(pos); + + if (!rawQuickInfo) return null; + + return { + pos, + create() { + const container = document.createElement('div'); + const domTop = document.createElement('div'); + + domTop.setAttribute('class', 'cm-quickinfo-tooltip'); + + if (rawQuickInfo.displayParts) { + domTop.innerHTML = rawQuickInfo.displayParts.map((p) => p.text).join(''); + } + + container.appendChild(domTop); + + // @TODO: Clean this up + + // eslint-disable-next-line @typescript-eslint/prefer-optional-chain + if (rawQuickInfo.documentation && rawQuickInfo.documentation[0]) { + const domBottom = document.createElement('div'); + domBottom.setAttribute('class', 'cm-quickinfo-tooltip'); + + domBottom.textContent = rawQuickInfo.documentation[0].text; + if (rawQuickInfo.tags?.length) { + for (const tag of rawQuickInfo.tags) { + if (tag.name === 'param') { + if (tag.text) { + for (const line of tag.text) { + if (line.kind === 'parameterName') { + domBottom.innerHTML += `

@param ${line.text}`; + } else if (line.kind === 'space') { + // skip + } else { + domBottom.innerHTML += `
${line.text}`; + } + } + } + } + } + } + + container.appendChild(domBottom); + } + + return { + dom: container, + }; + }, + }; +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c4f3c38bf649a..0d892e1c51118 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1165,6 +1165,9 @@ importers: '@n8n/permissions': specifier: workspace:* version: link:../@n8n/permissions + '@typescript/vfs': + specifier: ^1.5.3 + version: 1.5.3(typescript@5.5.2) '@vue-flow/background': specifier: ^1.3.0 version: 1.3.0(@vue-flow/core@1.33.5(vue@3.4.21(typescript@5.5.2)))(vue@3.4.21(typescript@5.5.2)) @@ -1219,6 +1222,9 @@ importers: jsonpath: specifier: ^1.1.1 version: 1.1.1 + localforage: + specifier: ^1.10.0 + version: 1.10.0 lodash-es: specifier: ^4.17.21 version: 4.17.21 @@ -1246,6 +1252,9 @@ importers: timeago.js: specifier: ^4.0.2 version: 4.0.2 + typescript: + specifier: ^5.5.2 + version: 5.5.2 uuid: specifier: ^8.3.2 version: 8.3.2 @@ -5907,6 +5916,11 @@ packages: resolution: {integrity: sha512-c6EIQRHhcpl6+tO8EMR+kjkkV+ugUNXOmeASA1rlzkd8EPIriavpWoiEz1HR/VLhbVIdhqnV6E7JZm00cBDx2A==} engines: {node: ^16.0.0 || >=18.0.0} + '@typescript/vfs@1.5.3': + resolution: {integrity: sha512-OSZ/o3wwD5VPZVdGGsXWk7sRGRtwrGnqA4zwmb33FTs7Wxmad0QTkQCbaNyqWA8hL09TCwAthdp8yjFA5G1lvw==} + peerDependencies: + typescript: ^5.5.2 + '@ungap/structured-clone@1.2.0': resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} @@ -13776,7 +13790,7 @@ snapshots: '@acuminous/bitsyntax@0.1.2': dependencies: buffer-more-ints: 1.0.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) safe-buffer: 5.1.2 transitivePeerDependencies: - supports-color @@ -14847,7 +14861,7 @@ snapshots: '@babel/traverse': 7.22.8 '@babel/types': 7.23.6 convert-source-map: 1.9.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 7.6.0 @@ -14867,7 +14881,7 @@ snapshots: '@babel/traverse': 7.24.0 '@babel/types': 7.24.0 convert-source-map: 2.0.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 7.6.0 @@ -14887,7 +14901,7 @@ snapshots: '@babel/traverse': 7.24.6 '@babel/types': 7.24.6 convert-source-map: 2.0.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 7.6.0 @@ -14997,7 +15011,7 @@ snapshots: '@babel/core': 7.24.6 '@babel/helper-compilation-targets': 7.24.6 '@babel/helper-plugin-utils': 7.24.6 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) lodash.debounce: 4.0.8 resolve: 1.22.8 transitivePeerDependencies: @@ -15008,7 +15022,7 @@ snapshots: '@babel/core': 7.24.6 '@babel/helper-compilation-targets': 7.24.6 '@babel/helper-plugin-utils': 7.24.6 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) lodash.debounce: 4.0.8 resolve: 1.22.8 transitivePeerDependencies: @@ -15930,7 +15944,7 @@ snapshots: '@babel/helper-split-export-declaration': 7.22.6 '@babel/parser': 7.24.0 '@babel/types': 7.24.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -15945,7 +15959,7 @@ snapshots: '@babel/helper-split-export-declaration': 7.22.6 '@babel/parser': 7.24.0 '@babel/types': 7.24.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -15960,7 +15974,7 @@ snapshots: '@babel/helper-split-export-declaration': 7.24.6 '@babel/parser': 7.24.6 '@babel/types': 7.24.6 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -16242,7 +16256,7 @@ snapshots: '@eslint/eslintrc@2.1.4': dependencies: ajv: 6.12.6 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) espree: 9.6.1 globals: 13.20.0 ignore: 5.2.4 @@ -16382,7 +16396,7 @@ snapshots: '@humanwhocodes/config-array@0.11.14': dependencies: '@humanwhocodes/object-schema': 2.0.2 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -16699,7 +16713,7 @@ snapshots: '@kwsites/file-exists@1.1.1': dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -19690,7 +19704,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 7.2.0(typescript@5.5.2) '@typescript-eslint/utils': 7.2.0(eslint@8.57.0)(typescript@5.5.2) - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) eslint: 8.57.0 ts-api-utils: 1.0.1(typescript@5.5.2) optionalDependencies: @@ -19706,7 +19720,7 @@ snapshots: dependencies: '@typescript-eslint/types': 6.7.5 '@typescript-eslint/visitor-keys': 6.7.5 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 semver: 7.6.0 @@ -19720,7 +19734,7 @@ snapshots: dependencies: '@typescript-eslint/types': 7.2.0 '@typescript-eslint/visitor-keys': 7.2.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 @@ -19769,6 +19783,13 @@ snapshots: '@typescript-eslint/types': 7.2.0 eslint-visitor-keys: 3.4.3 + '@typescript/vfs@1.5.3(typescript@5.5.2)': + dependencies: + debug: 4.3.5(supports-color@8.1.1) + typescript: 5.5.2 + transitivePeerDependencies: + - supports-color + '@ungap/structured-clone@1.2.0': {} '@vitejs/plugin-vue@5.0.4(vite@5.2.12(@types/node@18.16.16)(sass@1.64.1)(terser@5.16.1))(vue@3.4.21(typescript@5.5.2))': @@ -20202,19 +20223,19 @@ snapshots: agent-base@6.0.2: dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) transitivePeerDependencies: - supports-color agent-base@7.1.0: dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) transitivePeerDependencies: - supports-color agentkeepalive@4.2.1: dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) depd: 1.1.2 humanize-ms: 1.2.1 transitivePeerDependencies: @@ -21734,7 +21755,7 @@ snapshots: detect-port@1.5.1: dependencies: address: 1.2.2 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -22114,7 +22135,7 @@ snapshots: esbuild-register@3.5.0(esbuild@0.20.2): dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) esbuild: 0.20.2 transitivePeerDependencies: - supports-color @@ -23370,7 +23391,7 @@ snapshots: dependencies: '@tootallnate/once': 1.1.2 agent-base: 6.0.2 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) transitivePeerDependencies: - supports-color optional: true @@ -23379,14 +23400,14 @@ snapshots: dependencies: '@tootallnate/once': 2.0.0 agent-base: 6.0.2 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) transitivePeerDependencies: - supports-color http-proxy-agent@7.0.0: dependencies: agent-base: 7.1.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -23401,14 +23422,14 @@ snapshots: https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) transitivePeerDependencies: - supports-color https-proxy-agent@7.0.2: dependencies: agent-base: 7.1.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -23794,7 +23815,7 @@ snapshots: istanbul-lib-source-maps@4.0.1: dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) istanbul-lib-coverage: 3.2.2 source-map: 0.6.1 transitivePeerDependencies: @@ -25176,7 +25197,7 @@ snapshots: mqtt-packet@9.0.0: dependencies: bl: 6.0.12 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) process-nextick-args: 2.0.1 transitivePeerDependencies: - supports-color @@ -25470,7 +25491,7 @@ snapshots: number-allocator@1.0.14: dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) js-sdsl: 4.3.0 transitivePeerDependencies: - supports-color @@ -26830,7 +26851,7 @@ snapshots: retry-request@5.0.2: dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) extend: 3.0.2 transitivePeerDependencies: - supports-color @@ -27205,7 +27226,7 @@ snapshots: simple-websocket@9.1.0: dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) queue-microtask: 1.2.3 randombytes: 2.1.0 readable-stream: 3.6.0 @@ -27288,7 +27309,7 @@ snapshots: socks-proxy-agent@6.2.1: dependencies: agent-base: 6.0.2 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) socks: 2.7.1 transitivePeerDependencies: - supports-color