From 891d68310c1832f93c88f628fc23a9ba57d1ad4d Mon Sep 17 00:00:00 2001 From: Rikki Schulte Date: Sun, 11 Jun 2023 12:24:19 +0200 Subject: [PATCH] fix cache & validation --- .changeset/rotten-buckets-promise.md | 12 + .../package.json | 3 +- .../src/GraphQLCache.ts | 237 ++++++++++-------- .../src/Logger.ts | 1 - .../src/MessageProcessor.ts | 88 +++++-- .../src/startServer.ts | 4 +- .../graphql-language-service/src/types.ts | 6 +- yarn.lock | 163 ++++++++++-- 8 files changed, 361 insertions(+), 153 deletions(-) create mode 100644 .changeset/rotten-buckets-promise.md diff --git a/.changeset/rotten-buckets-promise.md b/.changeset/rotten-buckets-promise.md new file mode 100644 index 00000000000..7f5650cb108 --- /dev/null +++ b/.changeset/rotten-buckets-promise.md @@ -0,0 +1,12 @@ +--- +'graphql-language-service-server': minor +'graphql-language-service-cli': patch +'vscode-graphql': patch +--- + +**Fix:** Disable `getSchema()` results cacheing in the LSP server for now. Schema changes from file and/or network schema should be reflected in other files after they are saved or edit. + +If this leads to excessive introspection schema fetching for URL `schema` configs, we will add an lru schema cache with configurable invalidation timeout. Hopefully `cache-control` headers take care of this problem transparently. + + + diff --git a/packages/graphql-language-service-server/package.json b/packages/graphql-language-service-server/package.json index b8cac7c0dd7..ba7041500f5 100644 --- a/packages/graphql-language-service-server/package.json +++ b/packages/graphql-language-service-server/package.json @@ -43,7 +43,7 @@ "@vue/compiler-sfc": "^3.2.41", "dotenv": "8.2.0", "fast-glob": "^3.2.7", - "glob": "^7.2.0", + "glob": "^10.2.3", "graphql-config": "4.3.0", "graphql-language-service": "^5.1.5", "mkdirp": "^1.0.4", @@ -51,6 +51,7 @@ "nullthrows": "^1.0.0", "vscode-jsonrpc": "^8.0.1", "vscode-languageserver": "^8.0.1", + "vscode-languageserver-textdocument": "1.0.8", "vscode-languageserver-types": "^3.17.2", "vscode-uri": "^3.0.2" }, diff --git a/packages/graphql-language-service-server/src/GraphQLCache.ts b/packages/graphql-language-service-server/src/GraphQLCache.ts index 3541176eea6..9e88406b63f 100644 --- a/packages/graphql-language-service-server/src/GraphQLCache.ts +++ b/packages/graphql-language-service-server/src/GraphQLCache.ts @@ -24,8 +24,8 @@ import type { } from 'graphql-language-service'; import type { Logger } from 'vscode-languageserver'; -import * as fs from 'node:fs'; -import { readFile } from 'node:fs/promises'; +// import * as fs from 'node:fs'; +import { readFile, stat } from 'node:fs/promises'; import { GraphQLSchema, Kind, extendSchema, parse, visit } from 'graphql'; import nullthrows from 'nullthrows'; @@ -39,9 +39,10 @@ import type { UnnormalizedTypeDefPointer } from '@graphql-tools/load'; import { parseDocument } from './parseDocument'; import stringToHash from './stringToHash'; -import glob from 'glob'; +import { glob } from 'glob'; import { LoadConfigOptions } from './types'; import { URI } from 'vscode-uri'; +import { resolve } from 'node:path'; // Maximum files to read when processing GraphQL files. const MAX_READS = 200; @@ -57,7 +58,8 @@ export async function getGraphQLCache({ loadConfigOptions: LoadConfigOptions; config?: GraphQLConfig; }): Promise { - const graphQLConfig = config || (await loadConfig(loadConfigOptions)); + logger.error(`loadConfig: ${JSON.stringify(loadConfigOptions, null, 2)}`); + const graphQLConfig = config || (await loadConfig({})); return new GraphQLCache({ configDir: loadConfigOptions.rootDir as string, config: graphQLConfig as GraphQLConfig, @@ -193,16 +195,13 @@ export class GraphQLCache implements GraphQLCacheInterface { ): Promise> => { // This function may be called from other classes. // If then, check the cache first. - const rootDir = projectConfig.dirpath; const cacheKey = this._cacheKeyForProject(projectConfig); if (this._fragmentDefinitionsCache.has(cacheKey)) { return this._fragmentDefinitionsCache.get(cacheKey) || new Map(); } - const list = await this._readFilesFromInputDirs(rootDir, projectConfig); - const { fragmentDefinitions, graphQLFileMap } = - await this.readAllGraphQLFiles(list); + await this.readAllGraphQLFiles(projectConfig); this._fragmentDefinitionsCache.set(cacheKey, fragmentDefinitions); this._graphQLFileListCache.set(cacheKey, graphQLFileMap); @@ -304,14 +303,13 @@ export class GraphQLCache implements GraphQLCacheInterface { ): Promise> => { // This function may be called from other classes. // If then, check the cache first. - const rootDir = projectConfig.dirpath; const cacheKey = this._cacheKeyForProject(projectConfig); if (this._typeDefinitionsCache.has(cacheKey)) { return this._typeDefinitionsCache.get(cacheKey) || new Map(); } - const list = await this._readFilesFromInputDirs(rootDir, projectConfig); const { objectTypeDefinitions, graphQLFileMap } = - await this.readAllGraphQLFiles(list); + await this.readAllGraphQLFiles(projectConfig); + this._typeDefinitionsCache.set(cacheKey, objectTypeDefinitions); this._graphQLFileListCache.set(cacheKey, graphQLFileMap); @@ -319,66 +317,68 @@ export class GraphQLCache implements GraphQLCacheInterface { }; _readFilesFromInputDirs = ( - rootDir: string, - projectConfig: GraphQLProjectConfig, + _rootDir: string, + _projectConfig: GraphQLProjectConfig, ): Promise> => { - let pattern: string; - const patterns = this._getSchemaAndDocumentFilePatterns(projectConfig); - - // See https://github.com/graphql/graphql-language-service/issues/221 - // for details on why special handling is required here for the - // documents.length === 1 case. - if (patterns.length === 1) { - // @ts-ignore - pattern = patterns[0]; - } else { - pattern = `{${patterns.join(',')}}`; - } - - return new Promise((resolve, reject) => { - const globResult = new glob.Glob( - pattern, - { - cwd: rootDir, - stat: true, - absolute: false, - ignore: [ - 'generated/relay', - '**/__flow__/**', - '**/__generated__/**', - '**/__github__/**', - '**/__mocks__/**', - '**/node_modules/**', - '**/__flowtests__/**', - ], - }, - error => { - if (error) { - reject(error); - } - }, - ); - globResult.on('end', () => { - resolve( - Object.keys(globResult.statCache) - .filter( - filePath => typeof globResult.statCache[filePath] === 'object', - ) - .filter(filePath => projectConfig.match(filePath)) - .map(filePath => { - // @TODO - // so we have to force this here - // because glob's DefinitelyTyped doesn't use fs.Stats here though - // the docs indicate that is what's there :shrug: - const cacheEntry = globResult.statCache[filePath] as fs.Stats; - return { - filePath: URI.file(filePath).toString(), - mtime: Math.trunc(cacheEntry.mtime.getTime() / 1000), - size: cacheEntry.size, - }; - }), - ); - }); + // let pattern: string; + // const patterns = this._getSchemaAndDocumentFilePatterns(projectConfig); + + // // See https://github.com/graphql/graphql-language-service/issues/221 + // // for details on why special handling is required here for the + // // documents.length === 1 case. + // if (patterns.length === 1) { + // // @ts-ignore + // pattern = patterns[0]; + // } else { + // pattern = `{${patterns.join(',')}}`; + // } + + return new Promise((res, _reject) => { + // const globResult = new glob.Glob( + // pattern, + // { + // cwd: rootDir, + // stat: true, + // absolute: false, + // ignore: [ + // 'generated/relay', + // '**/__flow__/**', + // '**/__generated__/**', + // '**/__github__/**', + // '**/__mocks__/**', + // '**/node_modules/**', + // '**/__flowtests__/**', + // ], + // }, + // error => { + // if (error) { + // reject(error); + // } + // }, + // ); + this._logger.error('glob result'); + // globResult.on('end', () => { + res([]); + // resolve( + // Object.keys(globResult.statCache) + // .filter( + // filePath => typeof globResult.statCache[filePath] === 'object', + // ) + // .filter(filePath => projectConfig.match(filePath)) + // .map(filePath => { + // // @TODO + // // so we have to force this here + // // because glob's DefinitelyTyped doesn't use fs.Stats here though + // // the docs indicate that is what's there :shrug: + // const cacheEntry = globResult.statCache[filePath] as fs.Stats; + // return { + // filePath: URI.file(filePath).toString(), + // mtime: Math.trunc(cacheEntry.mtime.getTime() / 1000), + // size: cacheEntry.size, + // }; + // }), + // ); + // }); }); }; @@ -425,11 +425,11 @@ export class GraphQLCache implements GraphQLCacheInterface { } async updateFragmentDefinition( - rootDir: Uri, + cacheKey: string, filePath: Uri, contents: Array, ): Promise { - const cache = this._fragmentDefinitionsCache.get(rootDir); + const cache = this._fragmentDefinitionsCache.get(cacheKey); const asts = contents.map(({ query }) => { try { return { @@ -465,10 +465,11 @@ export class GraphQLCache implements GraphQLCacheInterface { } async updateFragmentDefinitionCache( - rootDir: Uri, filePath: Uri, exists: boolean, ): Promise { + const projectConfig = this._graphQLConfig.getProjectForFile(filePath); + const cacheKey = this._cacheKeyForProject(projectConfig); const fileAndContent = exists ? await this.promiseToReadGraphQLFile(filePath) : null; @@ -477,13 +478,13 @@ export class GraphQLCache implements GraphQLCacheInterface { // previously. // For delete, remove the entry from the set. if (!exists) { - const cache = this._fragmentDefinitionsCache.get(rootDir); + const cache = this._fragmentDefinitionsCache.get(cacheKey); if (cache) { cache.delete(filePath); } } else if (fileAndContent?.queries) { await this.updateFragmentDefinition( - rootDir, + cacheKey, filePath, fileAndContent.queries, ); @@ -491,11 +492,11 @@ export class GraphQLCache implements GraphQLCacheInterface { } async updateObjectTypeDefinition( - rootDir: Uri, + cacheKey: string, filePath: Uri, contents: Array, ): Promise { - const cache = this._typeDefinitionsCache.get(rootDir); + const cache = this._typeDefinitionsCache.get(cacheKey); const asts = contents.map(({ query }) => { try { return { @@ -531,10 +532,11 @@ export class GraphQLCache implements GraphQLCacheInterface { } async updateObjectTypeDefinitionCache( - rootDir: Uri, filePath: Uri, exists: boolean, ): Promise { + const projectConfig = this._graphQLConfig.getProjectForFile(filePath); + const cacheKey = this._cacheKeyForProject(projectConfig); const fileAndContent = exists ? await this.promiseToReadGraphQLFile(filePath) : null; @@ -543,13 +545,13 @@ export class GraphQLCache implements GraphQLCacheInterface { // previously. // For delete, remove the entry from the set. if (!exists) { - const cache = this._typeDefinitionsCache.get(rootDir); + const cache = this._typeDefinitionsCache.get(cacheKey); if (cache) { cache.delete(filePath); } } else if (fileAndContent?.queries) { await this.updateObjectTypeDefinition( - rootDir, + cacheKey, filePath, fileAndContent.queries, ); @@ -620,7 +622,7 @@ export class GraphQLCache implements GraphQLCacheInterface { getSchema = async ( appName?: string, - queryHasExtensions?: boolean | null, + _queryHasExtensions?: boolean | null, ): Promise => { const projectConfig = this._graphQLConfig.getProject(appName); @@ -629,27 +631,25 @@ export class GraphQLCache implements GraphQLCacheInterface { } const schemaPath = projectConfig.schema as string; - const schemaKey = this._getSchemaCacheKeyForProject(projectConfig); + const schemaKey = this._cacheKeyForProject(projectConfig); - let schemaCacheKey = null; + // let schemaCacheKey = null; let schema = null; - if (schemaPath && schemaKey) { - schemaCacheKey = schemaKey as string; + // schemaCacheKey = schemaKey as string; - // Maybe use cache - if (this._schemaMap.has(schemaCacheKey)) { - schema = this._schemaMap.get(schemaCacheKey); - if (schema) { - return queryHasExtensions - ? this._extendSchema(schema, schemaPath, schemaCacheKey) - : schema; - } - } + // Maybe use cache + // if (this._schemaMap.has(schemaCacheKey)) { + // schema = this._schemaMap.get(schemaCacheKey); + // if (schema) { + // return queryHasExtensions + // ? this._extendSchema(schema, schemaPath, schemaCacheKey) + // : schema; + // } + // } - // Read from disk - schema = await projectConfig.getSchema(); - } + // Read from disk or network + schema = await projectConfig.getSchema(); const customDirectives = projectConfig?.extensions?.customDirectives; if (customDirectives && schema) { @@ -662,12 +662,12 @@ export class GraphQLCache implements GraphQLCacheInterface { } if (this._graphQLFileListCache.has(this._configDir)) { - schema = this._extendSchema(schema, schemaPath, schemaCacheKey); + schema = this._extendSchema(schema, schemaPath, schemaKey); } - if (schemaCacheKey) { - this._schemaMap.set(schemaCacheKey, schema); - } + // if (schemaCacheKey) { + // this._schemaMap.set(schemaCacheKey, schema); + // } return schema; }; @@ -695,25 +695,39 @@ export class GraphQLCache implements GraphQLCacheInterface { * and create fragmentDefinitions and GraphQL files cache. */ readAllGraphQLFiles = async ( - list: Array, + projectConfig: GraphQLProjectConfig, ): Promise<{ objectTypeDefinitions: Map; fragmentDefinitions: Map; graphQLFileMap: Map; }> => { + const list = await glob( + this._getSchemaAndDocumentFilePatterns(projectConfig), + { + // stat: true, + ignore: 'node_modules/**', + // withFileTypes: true, + }, + ); const queue = list.slice(); // copy const responses: GraphQLFileInfo[] = []; while (queue.length) { const chunk = queue.splice(0, MAX_READS); - const promises = chunk.map(async fileInfo => { + const promises = chunk.map(async filePath => { try { - const response = await this.promiseToReadGraphQLFile( - fileInfo.filePath, - ); + const resolvedPath = resolve(filePath); + this._logger.error(resolvedPath); + const stats = await stat(resolvedPath); + + if (!filePath || !stats) { + return; + } + const response = await this.promiseToReadGraphQLFile(resolvedPath); responses.push({ ...response, - mtime: fileInfo.mtime, - size: fileInfo.size, + filePath: resolvedPath, + mtime: stats.mtimeMs, + size: stats.size, }); } catch (error: any) { // eslint-disable-next-line no-console @@ -727,7 +741,7 @@ export class GraphQLCache implements GraphQLCacheInterface { * queue. */ if (error.code === 'EMFILE' || error.code === 'ENFILE') { - queue.push(fileInfo); + queue.push(filePath); } } }); @@ -754,6 +768,7 @@ export class GraphQLCache implements GraphQLCacheInterface { for (const response of responses) { const { filePath, content, asts, mtime, size } = response; + this._logger.error(asts?.length.toString()); if (asts) { for (const ast of asts) { @@ -799,7 +814,9 @@ export class GraphQLCache implements GraphQLCacheInterface { promiseToReadGraphQLFile = async ( filePath: Uri, ): Promise => { - const content = await readFile(URI.parse(filePath).fsPath, 'utf8'); + const actualPath = URI.parse(filePath).fsPath; + this._logger.error(`actual path ${actualPath}`); + const content = await readFile(actualPath, 'utf8'); const asts: DocumentNode[] = []; let queries: CachedContent[] = []; diff --git a/packages/graphql-language-service-server/src/Logger.ts b/packages/graphql-language-service-server/src/Logger.ts index ccc58defa81..02da6123cde 100644 --- a/packages/graphql-language-service-server/src/Logger.ts +++ b/packages/graphql-language-service-server/src/Logger.ts @@ -6,7 +6,6 @@ * LICENSE file in the root directory of this source tree. * */ - import { Logger as VSCodeLogger } from 'vscode-jsonrpc'; import { Connection } from 'vscode-languageserver'; diff --git a/packages/graphql-language-service-server/src/MessageProcessor.ts b/packages/graphql-language-service-server/src/MessageProcessor.ts index c44eb28efce..919df5bc7c1 100644 --- a/packages/graphql-language-service-server/src/MessageProcessor.ts +++ b/packages/graphql-language-service-server/src/MessageProcessor.ts @@ -124,6 +124,7 @@ export class MessageProcessor { connection: Connection; }) { this._connection = connection; + this._logger = logger; this._graphQLConfig = config; this._parser = (text, uri) => { @@ -205,10 +206,10 @@ export class MessageProcessor { } async _updateGraphQLConfig() { - const settings = await this._connection.workspace.getConfiguration({ + const settings = await this.connection.workspace.getConfiguration({ section: 'graphql-config', }); - const vscodeSettings = await this._connection.workspace.getConfiguration({ + const vscodeSettings = await this.connection.workspace.getConfiguration({ section: 'vscode-graphql', }); if (settings?.dotEnvPath) { @@ -235,17 +236,21 @@ export class MessageProcessor { logger: this._logger, }); + this._languageService = new GraphQLLanguageService( this._graphQLCache, this._logger, ); - if (this._graphQLConfig || this._graphQLCache?.getGraphQLConfig) { - const config = - this._graphQLConfig ?? this._graphQLCache.getGraphQLConfig(); - await this._cacheAllProjectFiles(config); + if (this._graphQLConfig || this._graphQLCache?._graphQLConfig) { + this._graphQLConfig ??= this._graphQLCache._graphQLConfig; + await this._cacheAllProjectFiles(this._graphQLConfig) + } this._isInitialized = true; + await this._validateTextDocuments() + } catch (err) { + this._logConfigError('config error!!') this._handleConfigError({ err }); } } @@ -383,6 +388,7 @@ export class MessageProcessor { } }), ); + await this._validateTextDocuments(); } this._logger.log( @@ -665,6 +671,7 @@ export class MessageProcessor { const text = readFileSync(URI.parse(uri).fsPath, 'utf-8'); const contents = this._parser(text, uri); + await this._invalidateCache({ uri, version: 0 }, uri, contents); await this._updateFragmentDefinition(uri, contents); await this._updateObjectTypeDefinition(uri, contents); @@ -690,6 +697,8 @@ export class MessageProcessor { }), ) ).reduce((left, right) => left.concat(right), diagnostics); + + await this._validateTextDocuments(); } this._logger.log( @@ -704,12 +713,10 @@ export class MessageProcessor { } if (change.type === FileChangeTypeKind.Deleted) { await this._graphQLCache.updateFragmentDefinitionCache( - this._graphQLCache.getGraphQLConfig().dirpath, change.uri, false, ); await this._graphQLCache.updateObjectTypeDefinitionCache( - this._graphQLCache.getGraphQLConfig().dirpath, change.uri, false, ); @@ -870,10 +877,10 @@ export class MessageProcessor { // await this._cacheAllProjectFiles(config); if (params.query !== '') { - const documents = this._getTextDocuments(); + const docs = this._getTextDocuments(); const symbols: SymbolInformation[] = []; await Promise.all( - documents.map(async ([uri]) => { + docs.map(async ([uri]) => { const cachedDocument = this._getCachedDocument(uri); if (!cachedDocument) { return []; @@ -897,6 +904,37 @@ export class MessageProcessor { return Array.from(this._textDocumentCache); } + async _validateTextDocuments() { + await Promise.all( + this._getTextDocuments().map(async ([docPath, doc]) => { + await this._invalidateCache( + { uri: docPath, version: doc.version }, + docPath, + doc.contents, + ); + + doc.contents.map(async ({ query, range }) => { + const results = await this._languageService.getDiagnostics( + query, + docPath, + this._isRelayCompatMode(query), + ); + if (results && results.length > 0) { + await this.connection.sendDiagnostics({ + uri: docPath, + diagnostics: processDiagnosticsMessage(results, query, range), + }); + } else { + await this.connection.sendDiagnostics({ + uri: docPath, + diagnostics: [], + }); + } + }); + }), + ); + } + async _cacheSchemaText(uri: string, text: string, version: number) { try { const contents = this._parser(text, uri); @@ -1080,9 +1118,9 @@ export class MessageProcessor { */ async _cacheDocumentFilesforProject(project: GraphQLProjectConfig) { try { - const documents = await project.getDocuments(); + const docs = await project.getDocuments(); return Promise.all( - documents.map(async document => { + docs.map(async document => { if (!document.location || !document.rawSDL) { return; } @@ -1123,7 +1161,9 @@ export class MessageProcessor { Object.keys(config.projects).map(async projectName => { const project = config.getProject(projectName); await this._cacheSchemaFilesForProject(project); - await this._cacheDocumentFilesforProject(project); + // const docs = await project.getDocuments() + this._logger.error(`no docs found in ${JSON.stringify(config)}`) + // await this._cacheDocumentFilesforProject(project); }), ); } @@ -1138,18 +1178,32 @@ export class MessageProcessor { uri: Uri, contents: CachedContent[], ): Promise { - const rootDir = this._graphQLCache.getGraphQLConfig().dirpath; + const project = this._graphQLCache._graphQLConfig?.getProjectForFile(uri); + if (project) { + const cacheKey = this._graphQLCache._cacheKeyForProject(project); - await this._graphQLCache.updateFragmentDefinition(rootDir, uri, contents); + await this._graphQLCache.updateFragmentDefinition( + cacheKey, + uri, + contents, + ); + } } async _updateObjectTypeDefinition( uri: Uri, contents: CachedContent[], ): Promise { - const rootDir = this._graphQLCache.getGraphQLConfig().dirpath; + const project = this._graphQLCache._graphQLConfig?.getProjectForFile(uri); + if (project) { + const cacheKey = this._graphQLCache._cacheKeyForProject(project); - await this._graphQLCache.updateObjectTypeDefinition(rootDir, uri, contents); + await this._graphQLCache.updateObjectTypeDefinition( + cacheKey, + uri, + contents, + ); + } } _getCachedDocument(uri: string): CachedDocumentType | null { diff --git a/packages/graphql-language-service-server/src/startServer.ts b/packages/graphql-language-service-server/src/startServer.ts index 0f9cf102f0d..8bcfb025e90 100644 --- a/packages/graphql-language-service-server/src/startServer.ts +++ b/packages/graphql-language-service-server/src/startServer.ts @@ -48,6 +48,7 @@ import { } from './parseDocument'; import { LoadConfigOptions } from './types'; + export interface ServerOptions { /** * port for the LSP server to run on. required if using method socket @@ -266,6 +267,7 @@ async function addHandlers({ tmpDir, loadConfigOptions, }: HandlerOptions): Promise { + const messageProcessor = new MessageProcessor({ logger, config, @@ -275,7 +277,7 @@ async function addHandlers({ graphqlFileExtensions || DEFAULT_SUPPORTED_GRAPHQL_EXTENSIONS, tmpDir, loadConfigOptions, - connection, + connection }); connection.onNotification( diff --git a/packages/graphql-language-service/src/types.ts b/packages/graphql-language-service/src/types.ts index 893e413dcd8..56f26a4abf5 100644 --- a/packages/graphql-language-service/src/types.ts +++ b/packages/graphql-language-service/src/types.ts @@ -68,13 +68,12 @@ export interface GraphQLCache { ) => Promise>; updateObjectTypeDefinition: ( - rootDir: Uri, + cacheKey: string, filePath: Uri, contents: CachedContent[], ) => Promise; updateObjectTypeDefinitionCache: ( - rootDir: Uri, filePath: Uri, exists: boolean, ) => Promise; @@ -94,13 +93,12 @@ export interface GraphQLCache { ) => Promise>; updateFragmentDefinition: ( - rootDir: Uri, + cacheKey: string, filePath: Uri, contents: CachedContent[], ) => Promise; updateFragmentDefinitionCache: ( - rootDir: Uri, filePath: Uri, exists: boolean, ) => Promise; diff --git a/yarn.lock b/yarn.lock index 14a2ae5d623..45ede3f1dac 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2847,6 +2847,18 @@ resolved "https://registry.yarnpkg.com/@iarna/toml/-/toml-2.2.5.tgz#b32366c89b43c6f8cefbdefac778b9c828e3ba8c" integrity sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg== +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + dependencies: + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" + "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" @@ -3415,6 +3427,11 @@ tslib "^2.4.0" webcrypto-core "^1.7.4" +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + "@pkgr/utils@^2.3.1": version "2.3.1" resolved "https://registry.yarnpkg.com/@pkgr/utils/-/utils-2.3.1.tgz#0a9b06ffddee364d6642b3cd562ca76f55b34a03" @@ -5041,6 +5058,11 @@ ansi-regex@^5.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== +ansi-regex@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" + integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== + ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" @@ -5065,6 +5087,11 @@ ansi-styles@^5.0.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== +ansi-styles@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + ansi-wrap@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" @@ -7421,6 +7448,11 @@ duplexer@^0.1.1, duplexer@~0.1.1: resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -7469,6 +7501,11 @@ emoji-regex@^8.0.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + emojis-list@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" @@ -9083,6 +9120,14 @@ for-own@^0.1.4: dependencies: for-in "^1.0.1" +foreground-child@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d" + integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg== + dependencies: + cross-spawn "^7.0.0" + signal-exit "^4.0.1" + forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" @@ -9449,6 +9494,17 @@ glob@7.2.0, glob@^7.0.6, glob@^7.2.0: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^10.2.3: + version "10.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.2.3.tgz#aa6765963fe6c5936d5c2e00943e7af06302a1a7" + integrity sha512-Kb4rfmBVE3eQTAimgmeqc2LwSnN0wIOkkUL6HmxEFxNJ4fHghYHVbFba/HcGcRjE6s9KoMNK3rSOwkL4PioZjg== + dependencies: + foreground-child "^3.1.0" + jackspeak "^2.0.3" + minimatch "^9.0.0" + minipass "^5.0.0" + path-scurry "^1.7.0" + glob@^7.0.0, glob@^7.0.5, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: version "7.1.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" @@ -10818,6 +10874,15 @@ iterall@^1.2.1, iterall@^1.3.0: resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.3.0.tgz#afcb08492e2915cbd8a0884eb93a8c94d0d72fea" integrity sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg== +jackspeak@^2.0.3: + version "2.2.0" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.2.0.tgz#497cbaedc902ec3f31d5d61be804d2364ff9ddad" + integrity sha512-r5XBrqIJfwRIjRt/Xr5fv9Wh09qyhHfKnYddDlpM+ibRR20qrYActpCAgU6U+d53EOEjzkvxPMVHSlgR7leXrQ== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + jest-changed-files@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-24.9.0.tgz#08d8c15eb79a7fa3fc98269bc14b451ee82f8039" @@ -11900,6 +11965,11 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +lru-cache@^9.1.1: + version "9.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-9.1.1.tgz#c58a93de58630b688de39ad04ef02ef26f1902f1" + integrity sha512-65/Jky17UwSb0BuB9V+MyDpsOtXKmYwzhyl+cOa9XUiI4uV2Ouy/2voFP3+al0BjZbJgMBD8FojMpAf+Z+qn4A== + lunr@^2.3.9: version "2.3.9" resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.9.tgz#18b123142832337dd6e964df1a5a7707b25d35e1" @@ -12270,6 +12340,13 @@ minimatch@^3.0.3, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" +minimatch@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.0.tgz#bfc8e88a1c40ffd40c172ddac3decb8451503b56" + integrity sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w== + dependencies: + brace-expansion "^2.0.1" + minimist-options@4.1.0, minimist-options@^4.0.2: version "4.1.0" resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" @@ -12284,6 +12361,11 @@ minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5, minimist@^1. resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18" integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g== +minipass@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" + integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== + mixme@^0.5.1: version "0.5.4" resolved "https://registry.yarnpkg.com/mixme/-/mixme-0.5.4.tgz#8cb3bd0cd32a513c161bf1ca99d143f0bcf2eff3" @@ -13110,6 +13192,14 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +path-scurry@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.8.0.tgz#809e09690c63817c76d0183f19a5b21b530ff7d2" + integrity sha512-IjTrKseM404/UAWA8bBbL3Qp6O2wXkanuIE3seCxBH7ctRuvH1QRawy1N3nVDHGkdeZsjOsSe/8AQBL/VQCy2g== + dependencies: + lru-cache "^9.1.1" + minipass "^5.0.0" + path-to-regexp@0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" @@ -15101,6 +15191,11 @@ signal-exit@^3.0.5: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.6.tgz#24e630c4b0f03fea446a2bd299e62b4a6ca8d0af" integrity sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ== +signal-exit@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.0.2.tgz#ff55bb1d9ff2114c13b400688fa544ac63c36967" + integrity sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q== + simple-concat@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" @@ -15403,6 +15498,15 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + string-width@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" @@ -15438,14 +15542,14 @@ string-width@^4.1.0, string-width@^4.2.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.0" -string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== +string-width@^5.0.1, string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" string.prototype.matchall@^4.0.8: version "4.0.8" @@ -15534,6 +15638,13 @@ stringify-object@^3.3.0: is-obj "^1.0.1" is-regexp "^1.0.0" +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" @@ -15562,12 +15673,12 @@ strip-ansi@^6.0.0: dependencies: ansi-regex "^5.0.0" -strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== +strip-ansi@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2" + integrity sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw== dependencies: - ansi-regex "^5.0.1" + ansi-regex "^6.0.1" strip-bom-buffer@^0.1.1: version "0.1.1" @@ -16643,6 +16754,11 @@ vscode-languageserver-protocol@3.17.2: vscode-jsonrpc "8.0.2" vscode-languageserver-types "3.17.2" +vscode-languageserver-textdocument@1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.8.tgz#9eae94509cbd945ea44bca8dcfe4bb0c15bb3ac0" + integrity sha512-1bonkGqQs5/fxGT5UchTgjGVnfysL0O8v1AYMBjqTbWQTFn721zaPGDYFkOKtfDgFiSgXM3KwaG3FMGfW4Ed9Q== + vscode-languageserver-types@3.17.1, vscode-languageserver-types@^3.17.1: version "3.17.1" resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.1.tgz#c2d87fa7784f8cac389deb3ff1e2d9a7bef07e16" @@ -17056,6 +17172,15 @@ workerpool@6.2.1: resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-3.0.1.tgz#288a04d87eda5c286e060dfe8f135ce8d007f8ba" @@ -17082,14 +17207,14 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== +wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" wrappy@1: version "1.0.2"