diff --git a/__mocks__/vscode.js b/__mocks__/vscode.js new file mode 100644 index 00000000..5e23aea0 --- /dev/null +++ b/__mocks__/vscode.js @@ -0,0 +1,55 @@ +// __mocks__/vscode.js + +const vscode = { + languages: { + createDiagnosticCollection: jest.fn().mockImplementation(() => { + const diagnosticsMap = new Map(); + return { + clear: jest.fn(() => diagnosticsMap.clear()), + dispose: jest.fn(), + get: jest.fn(uri => diagnosticsMap.get(uri.toString())), + set: jest.fn((uri, diagnostics) => diagnosticsMap.set(uri.toString(), diagnostics)), + delete: jest.fn(uri => diagnosticsMap.delete(uri.toString())), + forEach: jest.fn(callback => diagnosticsMap.forEach(callback)), + }; + }), + }, + Uri: { + parse: jest.fn().mockImplementation((str) => ({ + toString: () => str, + })), + }, + workspace: { + openTextDocument: jest.fn().mockImplementation((uri) => ({ + getText: jest.fn(() => ''), + uri: uri, + positionAt: jest.fn().mockImplementation((index) => { + return new vscode.Position(Math.floor(index / 100), index % 100); + }), + })), + fs: { + writeFile: jest.fn(), + } + }, + Range: jest.fn().mockImplementation((start, end) => ({ + start: start, + end: end + })), + Position: jest.fn().mockImplementation((line, character) => ({ + line: line, + character: character + })), + Diagnostic: jest.fn().mockImplementation((range, message, severity) => ({ + range: range, + message: message, + severity: severity + })), + DiagnosticSeverity: { + Error: 0, + Warning: 1, + Information: 2, + Hint: 3 + } +}; + +module.exports = vscode; \ No newline at end of file diff --git a/docs/search/analyzer.md b/docs/search/analyzer.md new file mode 100644 index 00000000..a9dee9b7 --- /dev/null +++ b/docs/search/analyzer.md @@ -0,0 +1,7 @@ +Use the **analyzer** property to modify the behavior of a match query or a match phrase query. + +Set the **analyzer** property to the name of the analyzer you want to use on the contents of the match property or match_phrase property. + +The specified analyzer only applies to the content of your Search request. It does not apply to the contents of documents in the Search index. However, the analyzer set on your Search request and in your Search index should match. + +→ [Additional Query Object Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#additional-query-properties) \ No newline at end of file diff --git a/docs/search/bool.md b/docs/search/bool.md new file mode 100644 index 00000000..fb735fad --- /dev/null +++ b/docs/search/bool.md @@ -0,0 +1,7 @@ +Use the **bool** property to query a field that contains a boolean value. + +Use the field property and set the **bool** property to true or false to run a search. + +The Search Service does not use any analyzers on the contents of your query. + +→ [Non-Analytics Query Documentation]("https://docs.couchbase.com/server/current/search/search-request-params.html#non-analytic-queries") \ No newline at end of file diff --git a/docs/search/boost.md b/docs/search/boost.md new file mode 100644 index 00000000..440f2cdf --- /dev/null +++ b/docs/search/boost.md @@ -0,0 +1,5 @@ +If you use multiple clauses in a query, you can use the **boost** property to assign the relative importance to a clause. + +Clauses with a higher value in the **boost** property score higher and appear earlier in search results. + +→ [Additional Query Object Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#additional-query-properties) \ No newline at end of file diff --git a/docs/search/bottom_right.md b/docs/search/bottom_right.md new file mode 100644 index 00000000..6af33a3f --- /dev/null +++ b/docs/search/bottom_right.md @@ -0,0 +1,11 @@ +Set the geo location value to use as the bottom-right corner point of the rectangle search area. + +If you use **bottom_right** as an object, you must set two values: + +→ **lon**: The longitude of the geo location to use as the bottom-right corner of the rectangle. + +→ **lat**: The latitude of the geo location to use as the bottom-right corner of the rectangle. + +If you use **bottom_right** as an array, your array must contain a longitude value followed by a latitude value. For example, [-2.235143, 53.482358], where -2.235143 is the longitude. + +→ [Rectangle-Based Geopoint Query Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#geopoint-queries-rectangle) \ No newline at end of file diff --git a/docs/search/cidr.md b/docs/search/cidr.md new file mode 100644 index 00000000..cd627d51 --- /dev/null +++ b/docs/search/cidr.md @@ -0,0 +1,5 @@ +Enter an IP address range or single IP address, in IPv4 or IPv6 CIDR notation. + +The Search Service returns documents with IP addresses that fall inside the specified range or match the specified IP address. + +→ [IP Address Range Query Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#ip-address-range-queries) \ No newline at end of file diff --git a/docs/search/collections.md b/docs/search/collections.md new file mode 100644 index 00000000..e15d5592 --- /dev/null +++ b/docs/search/collections.md @@ -0,0 +1,3 @@ +Contains an array of strings that specify the collections where you want to run the query. + +→ [Search Request Json Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html) \ No newline at end of file diff --git a/docs/search/conjuncts.md b/docs/search/conjuncts.md new file mode 100644 index 00000000..f5744643 --- /dev/null +++ b/docs/search/conjuncts.md @@ -0,0 +1,9 @@ +Use the **conjuncts** array to specify multiple child queries in a single query object. + +You can use the **conjuncts** array inside a must object or directly inside a query object. + +If you use the **conjuncts** array, every query object in the array must have a match in a document to include the document in search results. + +You can create objects in a **conjuncts** array to describe any of the available query types. + +→ [Compound Query Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#boolean-queries) \ No newline at end of file diff --git a/docs/search/consistency.md b/docs/search/consistency.md new file mode 100644 index 00000000..2ee1f1de --- /dev/null +++ b/docs/search/consistency.md @@ -0,0 +1,5 @@ +Use the **consistency** object to control the consistency behavior for a Search index + +It contains a **vectors** object, the **level** and **results** properties. + +→ [Consistency Object Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#consistency) \ No newline at end of file diff --git a/docs/search/coordinates.md b/docs/search/coordinates.md new file mode 100644 index 00000000..b0ab0191 --- /dev/null +++ b/docs/search/coordinates.md @@ -0,0 +1,72 @@ +An array of coordinate floating point values that define the GeoJSON shape. + +The Search Service uses the first value in the coordinates array as the longitude value. + +#### Point Query +For a **Point** query, set the **coordinates** array to a single array with a longitude and latitude value + +#### LineString Query +For a **LineString** query, the **coordinates** array can contain multiple coordinate point arrays. + +#### Polygon Query + +An array that contains an outer array, and arrays of 2 coordinate floating point values that define the GeoJSON Polygon shape. + +The Search Service uses the first value in any nested **coordinates** array as the longitude value for the coordinate. + +The Search Service also follows strict GeoJSON syntax, and expects exterior coordinates in a polygon to be in counterclockwise order. + +#### MultiPoint Query +An array that contains arrays of 2 coordinate floating point values that define the GeoJSON MultiPoint shape. + +#### MultiLineString Query + +An array that contains nested arrays, each with their own nested arrays of 2 coordinate floating point values. + +For example, the following coordinates array defines 2 LineStrings with start and end points: +"coordinates": [ +[ +[1.954764, 50.962097], [3.029578, 49.868547] +], +[ +[3.029578, 49.868547], [-0.387444, 48.545836] +] +] +The innermost arrays define the individual points for a LineString in the MultiLineString shape. + +#### MultiPolygon Query +An array that contains arrays that describe a GeoJSON Polygon shape. + +Each inner array that describes a Polygon can contain multiple arrays with 2 coordinate floating point values. These innermost arrays describe the coordinates of the Polygon. + +The Search Service also follows strict GeoJSON syntax, and expects exterior coordinates in a polygon to be in counterclockwise order + +#### GeometryCollection Query + +An array or array of arrays that describes a GeoJSON shape. + +The exact structure of the arrays depends on the shape: + +→ Point +→ LineString +→ Polygon +→ MultiPoint +→ MultiLineString +→ MultiPolygon + +For any array that contains only floating point values, the Search Service uses the first value as the longitude. + +The Search Service also follows strict GeoJSON syntax, and expects exterior coordinates in a polygon to be in counterclockwise order. + +#### Circle Query +An array of coordinate floating point values that define the center point of the Circle. + +Set the **coordinates** array to a single array with a longitude and latitude value. + +#### Envelope Query + +An array of 2 different arrays that contain coordinate floating point values. + +The first **coordinates** nested array contains the minimum longitude and maximum latitude, or the top-left corner of the rectangle. + +The second nested array contains the maximum longitude and minimum latitude, or the bottom-right corner. \ No newline at end of file diff --git a/docs/search/ctl.md b/docs/search/ctl.md new file mode 100644 index 00000000..0afa444f --- /dev/null +++ b/docs/search/ctl.md @@ -0,0 +1,5 @@ +Use the **ctl** object to make sure that the Search Service runs your Search query against the latest version of the documents in your database. + +The **ctl** object and its properties cause the Search Service to run your query against the latest version of a document written to a vBucket. The Search Service uses a consistency vector to synchronize the last document write to a vBucket from the Data Service with the Search index. + +→ [Ctl Object Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#ctl) \ No newline at end of file diff --git a/docs/search/disjuncts.md b/docs/search/disjuncts.md new file mode 100644 index 00000000..46df2697 --- /dev/null +++ b/docs/search/disjuncts.md @@ -0,0 +1,9 @@ +Use the **disjuncts** array to specify multiple child queries in a single query object. + +You can use the **disjuncts** array inside a must_not object, should object, or directly inside a query object. + +Use a min property to set the number of query objects from the **disjuncts** array that must have a match in a document. If a document does not match the min number of query objects, the Search Service does not include the document in search results. + +You can create objects in a **disjuncts** array to describe any of the available query types. + +→ [Compound Query Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#boolean-queries) \ No newline at end of file diff --git a/docs/search/distance.md b/docs/search/distance.md new file mode 100644 index 00000000..59c0783e --- /dev/null +++ b/docs/search/distance.md @@ -0,0 +1,16 @@ +The radius where the Search Service should search for matching geo location values. + +Enter the radius as a single string, with a numeric value and a unit value. For example, 100.5mi. + +You can use the following distance units: + +→ **mm:** Millimeters +→ **cm:** Centimeters +→ **in:** Inches +→ **yd:** Yards +→ **ft:** Feet +→ **m:** Meters +→ **km:** Kilometers +→ **mi:** Miles + +→ [Distance/Radius-Based Geopoint Query Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#geopoint-queries-distance) \ No newline at end of file diff --git a/docs/search/end.md b/docs/search/end.md new file mode 100644 index 00000000..1a454df1 --- /dev/null +++ b/docs/search/end.md @@ -0,0 +1,7 @@ +Set the end date of the date range that you want to search for. + +You can specify only an **end** value or only a **start** value on your date range. + +By default, **end** is exclusive to the range. + +→ [Date Range Query Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#date-range-queries) \ No newline at end of file diff --git a/docs/search/explain.md b/docs/search/explain.md new file mode 100644 index 00000000..e7670e97 --- /dev/null +++ b/docs/search/explain.md @@ -0,0 +1,5 @@ +To create an explanation for a search result's score in search results, set **explain** to true. + +To turn off explanations for search result scoring, set **explain** to false. + +→ [Search Request Json Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html) \ No newline at end of file diff --git a/docs/search/facets.md b/docs/search/facets.md new file mode 100644 index 00000000..df5ba2c5 --- /dev/null +++ b/docs/search/facets.md @@ -0,0 +1,9 @@ +Contains **{facet-name}** objects to define each facet you want to return with search results. + +The Search Service supports the following facet types: + +→ **Term Facet**: Counts the documents that have the same value for a specified field. + +→ **Numeric Range Facet**: Counts the documents with numeric field values that are greater than or less than a specified range or ranges. + +→ **Date Range Facet**: Counts the documents with date field values that are earlier or later than a specified range or ranges. \ No newline at end of file diff --git a/docs/search/field.md b/docs/search/field.md new file mode 100644 index 00000000..69a27d0d --- /dev/null +++ b/docs/search/field.md @@ -0,0 +1,3 @@ +Specify a specific field name, using dot notation, where the Search Service should search for a match to your search query. + +→ [Additional Query Object Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#additional-query-properties) \ No newline at end of file diff --git a/docs/search/fields.md b/docs/search/fields.md new file mode 100644 index 00000000..46634e2b --- /dev/null +++ b/docs/search/fields.md @@ -0,0 +1,5 @@ +An array of strings to specify each indexed field you want to return in search results. + +You must add a field and its contents to a Search index to view it in search results or add it to the **fields** array. + +→ [Search Request Json Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html) \ No newline at end of file diff --git a/docs/search/fuzziness.md b/docs/search/fuzziness.md new file mode 100644 index 00000000..64bd11d1 --- /dev/null +++ b/docs/search/fuzziness.md @@ -0,0 +1,9 @@ +Use the **fuzziness** property to run a fuzzy query. + +The **fuzziness** property uses your specified edit distance to match terms based on their similarity, rather than exact matches. + +You can set **fuzziness** to a maximum value of 2. + +Use the **fuzziness** property with the term property for a term query or the match property for a match query. + +→ [Additional Query Object Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#additional-query-properties) \ No newline at end of file diff --git a/docs/search/geometries.md b/docs/search/geometries.md new file mode 100644 index 00000000..f5556304 --- /dev/null +++ b/docs/search/geometries.md @@ -0,0 +1,12 @@ +Contains objects to define each GeoJSON shape in the GeometryCollection. + +Each object in the **geometries** array has a **type** property and a coordinates property. + +Set the type property inside the object to the specific shape type you want to define: + +→ Point +→ LineString +→ Polygon +→ MultiPoint +→ MultiLineString +→ MultiPolygon \ No newline at end of file diff --git a/docs/search/geometry.md b/docs/search/geometry.md new file mode 100644 index 00000000..9ede0b5d --- /dev/null +++ b/docs/search/geometry.md @@ -0,0 +1,3 @@ +Contains the **shape** property and **relation** property. + +Defines the GeoJSON shape and how the Search Service should find a match in documents. \ No newline at end of file diff --git a/docs/search/highlight.md b/docs/search/highlight.md new file mode 100644 index 00000000..09386fd2 --- /dev/null +++ b/docs/search/highlight.md @@ -0,0 +1,10 @@ +Use the **highlight** object to control how the Search Service highlights matches in search results. + +```json +"highlight": { + "style": "html", + "fields": ["textField"] +}, +``` + +→ [Highlight Object Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#highlight) \ No newline at end of file diff --git a/docs/search/includeLocations.md b/docs/search/includeLocations.md new file mode 100644 index 00000000..88730c08 --- /dev/null +++ b/docs/search/includeLocations.md @@ -0,0 +1,5 @@ +To return the position of each occurrence of a search term inside a document, set **includeLocations** to true. + +**Note**: You must have *Include Term Vectors* enabled or the **include_term_vectors** property set to true on a field to use **includeLocations**. For more information about how to enable term vectors, see Child Field Options or Search Index JSON Properties. + +→ [Search Request Json Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html) \ No newline at end of file diff --git a/docs/search/inclusive_end.md b/docs/search/inclusive_end.md new file mode 100644 index 00000000..20563257 --- /dev/null +++ b/docs/search/inclusive_end.md @@ -0,0 +1,7 @@ +Set whether the Search Service should return documents that contain the exact **end** value. + +If you set **inclusive_end** to false, only dates earlier than end count as a match to your Search query. + +If you do not set the **inclusive_end** value, by default, **end** is exclusive to the range. + +→ [Date Range Query Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#date-range-queries) \ No newline at end of file diff --git a/docs/search/inclusive_max.md b/docs/search/inclusive_max.md new file mode 100644 index 00000000..59e7bf4f --- /dev/null +++ b/docs/search/inclusive_max.md @@ -0,0 +1,7 @@ +Set whether the Search Service should return documents that contain the exact **max** value. + +If you set **inclusive_max** to false, only values less than **max** count as a match to your Search query. + +If you do not set the **inclusive_max** value, by default, **max** is exclusive to the range. + +→ [Numeric Range Query Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#numeric-range-queries) \ No newline at end of file diff --git a/docs/search/inclusive_min.md b/docs/search/inclusive_min.md new file mode 100644 index 00000000..51200adc --- /dev/null +++ b/docs/search/inclusive_min.md @@ -0,0 +1,7 @@ +Set whether the Search Service should return documents that contain the exact **min** value. + +If you set **inclusive_min** to false, only values greater than min count as a match to your Search query. + +If you do not set the **inclusive_min** value, by default, **min** is inclusive to the range. + +→ [Numeric Range Query Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#numeric-range-queries) \ No newline at end of file diff --git a/docs/search/inclusive_start.md b/docs/search/inclusive_start.md new file mode 100644 index 00000000..24f61036 --- /dev/null +++ b/docs/search/inclusive_start.md @@ -0,0 +1,7 @@ +Set whether the Search Service should return documents that contain the exact **start** value. + +If you set **inclusive_start** to false, only dates later than start count as a match to your Search query. + +If you do not set the **inclusive_start** value, by default, **start** is inclusive to the range. + +→ [Date Range Query Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#date-range-queries) \ No newline at end of file diff --git a/docs/search/k.md b/docs/search/k.md new file mode 100644 index 00000000..0283cba6 --- /dev/null +++ b/docs/search/k.md @@ -0,0 +1,7 @@ +Enter the total number of results that you want to return from your Vector Search query. + +The Search Service returns the **k** closest vectors to the vector given in vector. + +**NOTE:** The **size** or **limit** property overrides any value set in **k**. + +→ [Knn Object Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#knn-object) \ No newline at end of file diff --git a/docs/search/knn.md b/docs/search/knn.md new file mode 100644 index 00000000..2114fa4b --- /dev/null +++ b/docs/search/knn.md @@ -0,0 +1,6 @@ +Each object inside the knn array in a Search query describes a Vector Search query. +Add the knn array with at least one object to run a Vector Search query + +**NOTE:** To run a Vector Search query, you must still include a **query** object with your Search request. To return only results from your Vector Search query, you can set the query object to a **match_none** query. To run a hybrid query that uses regular Search Service parameters together with Vector Search to return results + +→ [Knn Object Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#knn-object) \ No newline at end of file diff --git a/docs/search/lat.md b/docs/search/lat.md new file mode 100644 index 00000000..89594cf2 --- /dev/null +++ b/docs/search/lat.md @@ -0,0 +1 @@ +The latitude of the geo location \ No newline at end of file diff --git a/docs/search/level.md b/docs/search/level.md new file mode 100644 index 00000000..b955268c --- /dev/null +++ b/docs/search/level.md @@ -0,0 +1,7 @@ +Set the consistency to bounded or unbounded consistency: + +→ **at_plus**: The Search query executes but requires that the Search index matches the timestamp of the last document update. You must provide a **vectors** object + +→ **not_bounded**: The Search query executes without a consistency requirement. **not_bounded** is faster than **at_plus**, as it doesn't rely on a **vectors** object or wait for the Search index to match the Data Service index. + +→ [Consistency Object Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#consistency) \ No newline at end of file diff --git a/docs/search/limit.md b/docs/search/limit.md new file mode 100644 index 00000000..818f1808 --- /dev/null +++ b/docs/search/limit.md @@ -0,0 +1,5 @@ +Set the total number of results to return for a single page of search results. + +If you provide both the **size** and **limit** properties, the Search Service uses the **size** value. + +→ [Search Request Json Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html) \ No newline at end of file diff --git a/docs/search/location.md b/docs/search/location.md new file mode 100644 index 00000000..7bd86d4e --- /dev/null +++ b/docs/search/location.md @@ -0,0 +1,11 @@ +Set the geo location value to use as the center of the search radius for your query. + +If you use **location** as an object, you must set two values: + +→ **lon**: The longitude of the geo location to use as the center of the search radius. + +→ **lat**: The latitude of the geo location to use as the center of the search radius. + +If you use **location** as an array, your array must contain a longitude value followed by a latitude value. For example, [-2.235143, 53.482358], where -2.235143 is the longitude. + +→ [Distance/Radius-Based Geopoint Query Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#geopoint-queries-distance) \ No newline at end of file diff --git a/docs/search/lon.md b/docs/search/lon.md new file mode 100644 index 00000000..6fc0a534 --- /dev/null +++ b/docs/search/lon.md @@ -0,0 +1 @@ +The longitude of the geo location \ No newline at end of file diff --git a/docs/search/match.md b/docs/search/match.md new file mode 100644 index 00000000..ce9d4cdc --- /dev/null +++ b/docs/search/match.md @@ -0,0 +1,9 @@ +Use the **match** property to run a match query. The Search Service searches for an exact match to the specified term inside the Search index's default field. + +You can set a specific field to search with the field property. + +You can change the matching behavior by using the fuzziness property. + +You cannot include spaces inside the string you provide to the **match** property without specifying the operator property, which tells the Search Service how to interpret the string. + +→ [Analytics Query Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#analytic-queries) \ No newline at end of file diff --git a/docs/search/match_all.md b/docs/search/match_all.md new file mode 100644 index 00000000..6655b017 --- /dev/null +++ b/docs/search/match_all.md @@ -0,0 +1,3 @@ +Use the **match_all** object as the only property in your **query** object to return all documents from the Search index in search results. + +→ [Special Queries Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#special-queries) \ No newline at end of file diff --git a/docs/search/match_none.md b/docs/search/match_none.md new file mode 100644 index 00000000..9a465574 --- /dev/null +++ b/docs/search/match_none.md @@ -0,0 +1,5 @@ +Use the **match_none** object as the only property in your **query** object to return no documents from the Search index in search results. + +If you're using the knn object, the **match_none** object returns only matches to the Vector Search query inside the knn object. + +→ [Special Queries Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#special-queries) \ No newline at end of file diff --git a/docs/search/match_phrase.md b/docs/search/match_phrase.md new file mode 100644 index 00000000..99df16b3 --- /dev/null +++ b/docs/search/match_phrase.md @@ -0,0 +1,9 @@ +Use the **match_phrase** property to run a match phrase query. The Search Service searches for exact matches to the phrase you specify. + +Unlike a **match** query string, a **match_phrase** query string can contain spaces without using the operator property. + +To use a match phrase query: +→ You must specify a field to search with the field property or the {field-name} syntax in your search query. +→ You must have Include Term Vectors enabled or the include_term_vectors property set to true on the field you want to search. + +→ [Analytics Query Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#analytic-queries) \ No newline at end of file diff --git a/docs/search/max.md b/docs/search/max.md new file mode 100644 index 00000000..f65e4139 --- /dev/null +++ b/docs/search/max.md @@ -0,0 +1,7 @@ +Set the maximum value of the range that you want to search for. + +You can specify only a **min** value or only a **max** value on your range. + +By default, **max** is exclusive to the range. + +→ [Numeric Range Query Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#numeric-range-queries) \ No newline at end of file diff --git a/docs/search/min.md b/docs/search/min.md new file mode 100644 index 00000000..d6afa93a --- /dev/null +++ b/docs/search/min.md @@ -0,0 +1,7 @@ +Set the minimum value of the range that you want to search for. + +You can specify only a **min** value or only a max value on your range. + +By default, **min** is inclusive to the range. + +→ [Numeric Range Query Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#numeric-range-queries) \ No newline at end of file diff --git a/docs/search/must.md b/docs/search/must.md new file mode 100644 index 00000000..414ed719 --- /dev/null +++ b/docs/search/must.md @@ -0,0 +1,7 @@ +Use a **must** object to create a boolean query. + +A **must** object must contain a conjuncts array. The array lists all the queries that must have a match in a document to include the document in search results. + +For example, a query could have a **must** object with 2 queries in a conjuncts array. The Search Service must find a match for both those queries in a document to include it in search results. + +→ [Boolean Query Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#boolean-queries) \ No newline at end of file diff --git a/docs/search/must_not.md b/docs/search/must_not.md new file mode 100644 index 00000000..684edbd3 --- /dev/null +++ b/docs/search/must_not.md @@ -0,0 +1,7 @@ +Use a **must_not** object to create a boolean query. + +A **must_not** object must contain a disjuncts array. The array lists all the queries that must have a match in a document to include the document in search results. + +For example, a query could have a **must_not** object with 3 queries in a disjuncts array. The Search Service must not find a match for any of the 3 queries in a document to include it in search results. + +→ [Boolean Query Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#boolean-queries) \ No newline at end of file diff --git a/docs/search/offset.md b/docs/search/offset.md new file mode 100644 index 00000000..8e354c4f --- /dev/null +++ b/docs/search/offset.md @@ -0,0 +1,7 @@ +Set an offset value to change where pagination starts for search results, based on the Search query's Sort Object. + +For example, if you set a **size** value of 5 and a **from** value of 10, the Search query returns results 11 through 15 on a page. + +If you provide both the **from** and **offset** properties, the Search Service uses the **from** value. + +→ [Search Request Json Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html) \ No newline at end of file diff --git a/docs/search/operator.md b/docs/search/operator.md new file mode 100644 index 00000000..21ddf90b --- /dev/null +++ b/docs/search/operator.md @@ -0,0 +1,11 @@ +Use the **operator** property to modify the behavior of a match query: + +→ **"and"**: Any spaces between terms in the match property are interpreted as the AND operator. Documents must match all of the terms in the query. + +→ **"or"**: Any spaces between terms in the match property are interpreted as the OR operator. Documents must match at least one of the terms in the query. + +For example, if you set a **match** property to the value "good great" and the **operator** property to "and", the Search Service only returns matches for documents that contain good and great. + +If you set the **operator** property to "or", a document only needs to contain one of the terms from the **match** property: good or great. + +→ [Additional Query Object Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#additional-query-properties) \ No newline at end of file diff --git a/docs/search/polygon_points.md b/docs/search/polygon_points.md new file mode 100644 index 00000000..3e188613 --- /dev/null +++ b/docs/search/polygon_points.md @@ -0,0 +1,9 @@ +Set an array of latitude and longitude string values to use as the points in your polygon search area. + +For example, an array of [ "37.79393211306212,-122.44234633404847", "37.77995881733997,-122.43977141339417", "37.788031092020155,-122.42925715405579"] is interpreted as 3 separate polygon points and creates a 3-sided polygon. + +For **polygon_points**, the first value in the string is the latitude, and the second is the longitude. + +You can set the last value in the array to the same value as the first latitude and longitude to explicitly close your polygon. Otherwise, the Search Service infers the polygon's closure. + +→ [Polygon-Based Geopoint Query Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#geopoint-queries-polygon) \ No newline at end of file diff --git a/docs/search/prefix.md b/docs/search/prefix.md new file mode 100644 index 00000000..e7b86fc7 --- /dev/null +++ b/docs/search/prefix.md @@ -0,0 +1,9 @@ +Use the **prefix** property to run a prefix query. + +Set the property to a string to return matches for any term that starts with that string in search results. + +For example, you could set the **prefix** property to "inter" to return matches for "interview", "internal", "interesting", and so on. + +If you use the prefix property, the Search Service does not use any analyzers on the contents of your query text. + +→ [Non-Analytics Query Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#non-analytic-queries) \ No newline at end of file diff --git a/docs/search/prefix_lang.md b/docs/search/prefix_lang.md new file mode 100644 index 00000000..8d6c13db --- /dev/null +++ b/docs/search/prefix_lang.md @@ -0,0 +1,5 @@ +Use the **prefix_length** property to modify the behavior of a match query. + +The **prefix_length** changes a match query to a prefix match query. The Search Service matches terms based on the query and the result sharing a prefix of the specified length. + +→ [Additional Query Object Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#additional-query-properties) \ No newline at end of file diff --git a/docs/search/query.md b/docs/search/query.md new file mode 100644 index 00000000..6f2442bc --- /dev/null +++ b/docs/search/query.md @@ -0,0 +1,5 @@ +Use the **query** object to set the specific details of your Search query. + +Use the properties in the **query** object to control search result rankings, add multiple subqueries, and more. + +→ [Query Object Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#query-object) \ No newline at end of file diff --git a/docs/search/query_string.md b/docs/search/query_string.md new file mode 100644 index 00000000..07ca8e16 --- /dev/null +++ b/docs/search/query_string.md @@ -0,0 +1,11 @@ +Query String queries let you express more complex queries with a special syntax. You can reduce the properties you need to specify for a Search query with Query String syntax. + +If you do not add any additional Query String syntax to a query, the Search Service interprets the query as a match query. + +- **^** : If you use multiple clauses in a query, you can use the ^ operator to assign the relative importance to a clause. +- **>, >=, < and ≤** : You can run two types of range queries with the later than (>), later than or equal to (>=), earlier than (<), and earlier than or equal to (≤) operators: +- **\\** : Use a backslash character (\\) to escape characters in a Query String query. +- **{field-name}** : Set the field in a document where the Search Service should search for your query by adding a field name and a colon to the start of a search term. Use dot notation for the field name. For example, `parentField.childField`. +- **+** and **-** : Use the + and - operators before a clause in a Query String query to run a boolean query. The + operator adds the clause to the MUST list of a boolean query. The - operator adds the clause to the MUST_NOT list of a boolean query. + +→ [Query String Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#query-string-query-syntax) \ No newline at end of file diff --git a/docs/search/radius.md b/docs/search/radius.md new file mode 100644 index 00000000..491ed22d --- /dev/null +++ b/docs/search/radius.md @@ -0,0 +1,16 @@ +Set the radius of the Circle. + +Enter the radius as a single string, with a numeric value and a unit value. For example, 100.5mi. + +You can use the following distance units: + +→ **mm:** Millimeters +→ **cm:** Centimeters +→ **in:** Inches +→ **yd:** Yards +→ **ft:** Feet +→ **m:** Meters +→ **km:** Kilometers +→ **mi:** Miles + +→ [Circle GeoJSON Query Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#geojson-queries-circle) \ No newline at end of file diff --git a/docs/search/regexp.md b/docs/search/regexp.md new file mode 100644 index 00000000..93fb33af --- /dev/null +++ b/docs/search/regexp.md @@ -0,0 +1,7 @@ +Use the **regexp** property to run a regular expression query. + +Set the property to a regular expression to return matches for that regular expression in search results. + +If you use the **regexp** property, the Search Service does not use any analyzers on the contents of your query text. + +→ [Non-Analytics Query Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#non-analytic-queries) \ No newline at end of file diff --git a/docs/search/relation.md b/docs/search/relation.md new file mode 100644 index 00000000..a1eac293 --- /dev/null +++ b/docs/search/relation.md @@ -0,0 +1,9 @@ +Set how the Search Service should return a match for a GeoJSON Point search. + +Your selected **relation** type determines which shapes return a match for your query. + +You can use the following string values in the **relation** property: **intersects**, **contains** and **within** + +These values have different meanings according to the shape. Please check docs for more. + +→ [Point GeoJSON Query Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#geojson-queries-point) \ No newline at end of file diff --git a/docs/search/results.md b/docs/search/results.md new file mode 100644 index 00000000..345a179a --- /dev/null +++ b/docs/search/results.md @@ -0,0 +1,5 @@ +To display an error instead of partial results if any index partitions are unavailable on a node, set **results** to **complete**. + +To return partial results from a query if a node is unreachable, remove the **results** property. + +→ [Consistency Object Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#consistency) \ No newline at end of file diff --git a/docs/search/score.md b/docs/search/score.md new file mode 100644 index 00000000..d975f91b --- /dev/null +++ b/docs/search/score.md @@ -0,0 +1,5 @@ +To turn off document relevancy scoring in search results, set **score** to none. + +To turn on document relevancy scoring in search results, remove the **score** property. + +→ [Search Request Json Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html) \ No newline at end of file diff --git a/docs/search/search_after.md b/docs/search/search_after.md new file mode 100644 index 00000000..60540e87 --- /dev/null +++ b/docs/search/search_after.md @@ -0,0 +1,13 @@ +Use **search_after** with **from**/**offset** and sort to control pagination in search results. + +Give a value for each string or JSON object in the **sort** array to the **search_after** array. The Search Service starts search result pagination after the document with those values. + +You must provide the values in the same order that they appear in the **sort** array. + +For example, if you had a set of 10 documents to sort based on _id values of 1-10, with **from** set to 2 and **search_after** set to 8, documents 9-10 appear on the same page. + +--- + +**Note**: If you use **search_after** in a search request, you can't use **search_before**. Both properties are included in the example code to show the correct syntax. + +→ [Search Request Json Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html) \ No newline at end of file diff --git a/docs/search/search_before.md b/docs/search/search_before.md new file mode 100644 index 00000000..c3e80e84 --- /dev/null +++ b/docs/search/search_before.md @@ -0,0 +1,13 @@ +Use **search_before** with **from**/**offset** and sort to control pagination in search results. + +Give a value for each string or JSON object in the **sort** array to the **search_before** array. The Search Service starts search result pagination before the document with those values. + +You must provide the values in the same order that they appear in the **sort** array. + +For example, if you had a set of 10 documents to sort based on _id values of 1-10, with **from** set to 2 and **search_before** set to 8, documents 2-6 appear on the same page. + +--- + +**Note**: If you use **search_before** in a search request, you can't use **search_after**. Both properties are included in the example code to show the correct syntax. + +→ [Search Request Json Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html) \ No newline at end of file diff --git a/docs/search/shape.md b/docs/search/shape.md new file mode 100644 index 00000000..53762658 --- /dev/null +++ b/docs/search/shape.md @@ -0,0 +1,3 @@ +Contains the **type** property and **coordinates** property. + +Defines the specific GeoJSON shape to use in the query. \ No newline at end of file diff --git a/docs/search/should.md b/docs/search/should.md new file mode 100644 index 00000000..6d00286c --- /dev/null +++ b/docs/search/should.md @@ -0,0 +1,7 @@ +Use a **should** object to create a boolean query. + +A **should** object must contain a disjuncts array. The array lists all the queries that must have a match in a document to score the document higher in search results. + +A document can be included in search results if it does not match the query or queries in a **should** object. The document scores higher in search results if it does match the query. + +→ [Boolean Query Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#boolean-queries) \ No newline at end of file diff --git a/docs/search/sort.md b/docs/search/sort.md new file mode 100644 index 00000000..0a3d9738 --- /dev/null +++ b/docs/search/sort.md @@ -0,0 +1,11 @@ +Contains an array of strings or JSON objects to set how to sort search results. + +The strings can be: + +→ **{field_name}**: Specify the name of a field to use to sort the search results. + +→ **_id**: Use the document's identifier to sort the search results. + +→ **_score**: Use the document's score from the Search query to sort the search results. + +→ [Sort Object Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#sort) \ No newline at end of file diff --git a/docs/search/start.md b/docs/search/start.md new file mode 100644 index 00000000..5ba58f0c --- /dev/null +++ b/docs/search/start.md @@ -0,0 +1,7 @@ +Set the start date of the date range that you want to search for. + +You can specify only a **start** value or only an **end** value on your date range. + +By default, **start** is inclusive to the range. + +→ [Date Range Query Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#date-range-queries) \ No newline at end of file diff --git a/docs/search/style.md b/docs/search/style.md new file mode 100644 index 00000000..2b076263 --- /dev/null +++ b/docs/search/style.md @@ -0,0 +1,7 @@ +Sets how the Search Service highlights a match from a search query: + +→ **ansi**: The Search Service highlights matches with a yellow background (\u001b[43m). + +→ **html**: The Search Service surrounds matches with and HTML tags. + +→ [Highlight Object Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#highlight) \ No newline at end of file diff --git a/docs/search/term.md b/docs/search/term.md new file mode 100644 index 00000000..51a52242 --- /dev/null +++ b/docs/search/term.md @@ -0,0 +1,9 @@ +Use the **term** property to run a term query. + +The Search Service searches for an exact match for the text you provide in the **term** property. + +You can change the matching behavior by using the fuzziness property. + +If you use the **term** property, the Search Service does not use any analyzers on the contents of your query text. + +→ [Non-Analytics Query Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#non-analytic-queries) \ No newline at end of file diff --git a/docs/search/terms.md b/docs/search/terms.md new file mode 100644 index 00000000..526f3087 --- /dev/null +++ b/docs/search/terms.md @@ -0,0 +1,11 @@ +Use the **terms** array to run a phrase query. The Search Service searches for the strings you provide in the **terms** array in the specified order. + +Unlike the match_phrase property, the **terms** array does not use any analyzers on the contents of your query text. + +For example, set the **terms** array to ["nice", "view"]. The Search Service looks for any occurrences of nice in a document that are followed by an occurrence of view. + +To use a phrase query: +→ You must set the field property in your search query. +→ You must have Include Term Vectors enabled or the include_term_vectors property set to true on the field you want to search. + +→ [Non-Analytics Query Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#non-analytic-queries) \ No newline at end of file diff --git a/docs/search/timeout.md b/docs/search/timeout.md new file mode 100644 index 00000000..73ad4c8e --- /dev/null +++ b/docs/search/timeout.md @@ -0,0 +1,3 @@ +Set the maximum time, in milliseconds, that a Search query can execute on a Search index partition. + +If the query time exceeds the **timeout**, the Search Service cancels the query. The query might return partial results if any index partitions responded before the timeout. \ No newline at end of file diff --git a/docs/search/top_left.md b/docs/search/top_left.md new file mode 100644 index 00000000..9827e272 --- /dev/null +++ b/docs/search/top_left.md @@ -0,0 +1,11 @@ +Set the geo location value to use as the top-left corner point of the rectangle search area. + +If you use **top_left** as an object, you must set two values: + +→ **lon**: The longitude of the geo location to use as the top-left corner of the rectangle. + +→ **lat**: The latitude of the geo location to use as the top-left corner of the rectangle. + +If you use **top_left** as an array, your array must contain a longitude value followed by a latitude value. For example, [-2.235143, 53.482358], where -2.235143 is the longitude. + +→ [Rectangle-Based Geopoint Query Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#geopoint-queries-rectangle) \ No newline at end of file diff --git a/docs/search/type_facet.md b/docs/search/type_facet.md new file mode 100644 index 00000000..1c80c2ec --- /dev/null +++ b/docs/search/type_facet.md @@ -0,0 +1,7 @@ +Set the data type of the field specified in field: + +→ **string**: The field contains a string. + +→ **date**: The field contains date/time data. + +→ **number**: The field contains a number or geographic data, like a latitude or longitude value. \ No newline at end of file diff --git a/docs/search/type_shape.md b/docs/search/type_shape.md new file mode 100644 index 00000000..0fc570aa --- /dev/null +++ b/docs/search/type_shape.md @@ -0,0 +1,21 @@ +**type** defines the shape of the GeoJson Query + +The allowed values are the following: + +→ **"Point"**: Use a GeoJSON Point query to search for a single latitude and longitude coordinate that intersects or is contained inside a GeoJSON shape in your documents + +→ **"LineString"**: Use a GeoJSON LineString query to search for a line of coordinates that intersects or is contained inside a GeoJSON shape in your documents + +→ **"Polygon"**: Use a GeoJSON Polygon query to search for a defined area that intersects, is contained inside, or surrounds a GeoJSON shape in your documents + +→ **"MultiPoint"**: Use a GeoJSON MultiPoint query to search for multiple coordinate points that intersect or are contained inside a GeoJSON shape in your documents + +→ **"MultiLineString"**: Use a GeoJSON MultiLineString query to search for multiple LineStrings that intersect or are contained inside a GeoJSON shape in your documents + +→ **"MultiPolygon"**: Use a GeoJSON MultiPolygon query to search for a group of defined Polygons that intersect, are contained inside, or surround a GeoJSON shape in your documents + +→ **"GeometryCollection"**: Use a GeoJSON GeometryCollection query to search for a group of defined Points, LineStrings, or Polygons that intersect, are contained inside, or surround a GeoJSON shape in your documents + +→ **"Circle"**: Use a GeoJSON Circle query to search in a radius around a single latitude and longitude coordinate + +→ **"Envelope"**: Use a GeoJSON Envelope query to search in a bounded rectangle, based on a pair of coordinates that define the minimum and maximum longitude and latitude: \ No newline at end of file diff --git a/docs/search/vector.md b/docs/search/vector.md new file mode 100644 index 00000000..f56ced5e --- /dev/null +++ b/docs/search/vector.md @@ -0,0 +1,7 @@ +Enter the vector that you want to compare to the vector data in **field**. + +The Search Service uses the similarity metric defined in the Search index definition to return the **k** closest vectors from the Search index. + +**NOTE:** The vector in your Search query must match the dimension of the vectors stored in your Search index. If the dimensions do not match, your Search query does not return any results. For more information about the dimension value, see the dims property or the Dimension option in the UI. + +→ [Knn Object Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#knn-object) \ No newline at end of file diff --git a/docs/search/vectors.md b/docs/search/vectors.md new file mode 100644 index 00000000..9a7353de --- /dev/null +++ b/docs/search/vectors.md @@ -0,0 +1,3 @@ +An object that contains a **{search-index-name}** object for each Search index in the query. + +→ [Vectors Object Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#vectors) \ No newline at end of file diff --git a/docs/search/wildcard.md b/docs/search/wildcard.md new file mode 100644 index 00000000..2764e0b9 --- /dev/null +++ b/docs/search/wildcard.md @@ -0,0 +1,15 @@ +Use the **wildcard** property to run a wildcard query. + +Set the property to a regular expression that includes a wildcard character in the middle or end of a search term: + +→ Use **?** to allow a match to any single character. + +→ Use **\*** to allow a match to zero or many characters. + +For example, you could set the **wildcard** property to "inter*" to return matches for "interview", "interject", "internal", and so on. + +You cannot place the wildcard character at the start of the search term. + +If you use the **wildcard** property, the Search Service does not use any analyzers on the contents of your query text. + +→ [Non-Analytics Query Documentation](https://docs.couchbase.com/server/current/search/search-request-params.html#non-analytic-queries) \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 1612d773..7ecaad19 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,6 +32,7 @@ "dayjs": "^1.11.9", "decompress": "^4.2.1", "gitly": "^2.5.2", + "jsonc-parser": "^3.2.1", "monaco-editor": "^0.43.0", "mongodb": "^6.4.0", "prop-types": "^15.7.2", @@ -47,23 +48,25 @@ "react-tooltip": "^5.26.0", "shelljs": "^0.8.5", "stream-json": "^1.8.0", - "uuid": "^9.0.1" + "uuid": "^9.0.1", + "vscode-json-languageservice": "^5.3.11" }, "devDependencies": { "@babel/parser": "^7.22.7", "@babel/preset-env": "^7.23.5", "@babel/preset-react": "^7.23.3", + "@electron/rebuild": "^3.6.0", "@types/glob": "^7.2.0", "@types/jest": "^29.5.12", "@types/mocha": "^10.0.6", - "@types/node": "^20.12.2", + "@types/node": "^20.14.2", "@types/react": "^18.2.6", "@types/react-dom": "^18.2.4", "@types/uuid": "^9.0.6", "@types/vscode": "^1.63.1", "@typescript-eslint/eslint-plugin": "^7.5.0", "@typescript-eslint/parser": "^7.5.0", - "@vscode/test-electron": "^2.3.9", + "@vscode/test-electron": "^2.4.0", "babel-loader": "^9.1.3", "class-transformer": "^0.5.1", "cmake-js": "^6.3.2", @@ -84,7 +87,7 @@ "terser-webpack-plugin": "^5.3.10", "ts-jest": "^29.1.2", "ts-loader": "^9.5.1", - "typescript": "^5.4.3", + "typescript": "^5.4.5", "webpack": "^5.91.0", "webpack-cli": "^5.1.4" }, @@ -1929,6 +1932,332 @@ "node": ">=10.0.0" } }, + "node_modules/@electron/rebuild": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@electron/rebuild/-/rebuild-3.6.0.tgz", + "integrity": "sha512-zF4x3QupRU3uNGaP5X1wjpmcjfw1H87kyqZ00Tc3HvriV+4gmOGuvQjGNkrJuXdsApssdNyVwLsy+TaeTGGcVw==", + "dev": true, + "dependencies": { + "@malept/cross-spawn-promise": "^2.0.0", + "chalk": "^4.0.0", + "debug": "^4.1.1", + "detect-libc": "^2.0.1", + "fs-extra": "^10.0.0", + "got": "^11.7.0", + "node-abi": "^3.45.0", + "node-api-version": "^0.2.0", + "node-gyp": "^9.0.0", + "ora": "^5.1.0", + "read-binary-file-arch": "^1.0.6", + "semver": "^7.3.5", + "tar": "^6.0.5", + "yargs": "^17.0.1" + }, + "bin": { + "electron-rebuild": "lib/cli.js" + }, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/@electron/rebuild/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@electron/rebuild/node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/@electron/rebuild/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@electron/rebuild/node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@electron/rebuild/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@electron/rebuild/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@electron/rebuild/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@electron/rebuild/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@electron/rebuild/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@electron/rebuild/node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@electron/rebuild/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/rebuild/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@electron/rebuild/node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@electron/rebuild/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@electron/rebuild/node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@electron/rebuild/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@electron/rebuild/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@electron/rebuild/node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@electron/rebuild/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@electron/rebuild/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@electron/rebuild/node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@electron/rebuild/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@electron/rebuild/node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@electron/rebuild/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -2067,6 +2396,12 @@ "react": ">=16.3" } }, + "node_modules/@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "dev": true + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -2929,8 +3264,30 @@ "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@malept/cross-spawn-promise": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-2.0.0.tgz", + "integrity": "sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/malept" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund" + } + ], + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "engines": { + "node": ">= 12.13.0" } }, "node_modules/@monaco-editor/loader": { @@ -3000,6 +3357,45 @@ "node": ">= 8" } }, + "node_modules/@npmcli/fs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", + "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", + "dev": true, + "dependencies": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/fs/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/move-file": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", + "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", + "deprecated": "This functionality has been moved to @npmcli/fs", + "dev": true, + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, "node_modules/@popperjs/core": { "version": "2.11.8", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", @@ -3023,6 +3419,18 @@ "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", "dev": true }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, "node_modules/@sinonjs/commons": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", @@ -3041,13 +3449,25 @@ "@sinonjs/commons": "^3.0.0" } }, + "node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "dev": true, + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", "dev": true, "engines": { - "node": ">= 6" + "node": ">= 10" } }, "node_modules/@types/babel__core": { @@ -3091,6 +3511,18 @@ "@babel/types": "^7.20.7" } }, + "node_modules/@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "dev": true, + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, "node_modules/@types/debug": { "version": "4.1.12", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", @@ -3167,6 +3599,12 @@ "@types/unist": "*" } }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", + "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", + "dev": true + }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", @@ -3207,6 +3645,15 @@ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, + "node_modules/@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/mdast": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.3.tgz", @@ -3233,9 +3680,9 @@ "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" }, "node_modules/@types/node": { - "version": "20.12.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.2.tgz", - "integrity": "sha512-zQ0NYO87hyN6Xrclcqp7f8ZbXNbRfoGWNcMvHTPQp9UUrwI0mI7XBz+cu7/W6/VClYo2g63B0cjull/srU7LgQ==", + "version": "20.14.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.2.tgz", + "integrity": "sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q==", "dependencies": { "undici-types": "~5.26.4" } @@ -3263,6 +3710,15 @@ "@types/react": "*" } }, + "node_modules/@types/responselike": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", + "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/semver": { "version": "7.5.8", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", @@ -3661,41 +4117,32 @@ "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" }, + "node_modules/@vscode/l10n": { + "version": "0.0.18", + "resolved": "https://registry.npmjs.org/@vscode/l10n/-/l10n-0.0.18.tgz", + "integrity": "sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ==" + }, "node_modules/@vscode/test-electron": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.3.9.tgz", - "integrity": "sha512-z3eiChaCQXMqBnk2aHHSEkobmC2VRalFQN0ApOAtydL172zXGxTwGrRtviT5HnUB+Q+G3vtEYFtuQkYqBzYgMA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.4.0.tgz", + "integrity": "sha512-yojuDFEjohx6Jb+x949JRNtSn6Wk2FAh4MldLE3ck9cfvCqzwxF32QsNy1T9Oe4oT+ZfFcg0uPUCajJzOmPlTA==", "dev": true, "dependencies": { - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.4", "jszip": "^3.10.1", - "semver": "^7.5.2" + "ora": "^7.0.1", + "semver": "^7.6.2" }, "engines": { "node": ">=16" } }, - "node_modules/@vscode/test-electron/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@vscode/test-electron/node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, "bin": { "semver": "bin/semver.js" }, @@ -3703,12 +4150,6 @@ "node": ">=10" } }, - "node_modules/@vscode/test-electron/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/@webassemblyjs/ast": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", @@ -3911,6 +4352,12 @@ "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", "dev": true }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, "node_modules/acorn": { "version": "8.11.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", @@ -3951,15 +4398,40 @@ } }, "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", "dev": true, "dependencies": { - "debug": "4" + "debug": "^4.3.4" }, "engines": { - "node": ">= 6.0.0" + "node": ">= 14" + } + }, + "node_modules/agentkeepalive": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", + "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", + "dev": true, + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, "node_modules/ajv": { @@ -4511,6 +4983,55 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/bl": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz", + "integrity": "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==", + "dev": true, + "dependencies": { + "buffer": "^6.0.3", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -4667,22 +5188,175 @@ "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", "dev": true, "engines": { - "node": ">=0.10" + "node": ">=0.10" + } + }, + "node_modules/buffer-shims": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", + "integrity": "sha512-Zy8ZXMyxIT6RMTeY7OP/bDndfj6bwCan7SS98CEndS6deHwWPpseeHlwarNcBim+etXnF9HBc1non5JgDaJU1g==", + "dev": true + }, + "node_modules/buffers": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", + "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", + "dev": true, + "engines": { + "node": ">=0.2.0" + } + }, + "node_modules/cacache": { + "version": "16.1.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz", + "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", + "infer-owner": "^1.0.4", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/cacache/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/cacache/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/cacache/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cacache/node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cacache/node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacache/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "dev": true, + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/cacheable-request": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", + "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", + "dev": true, + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/buffer-shims": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", - "integrity": "sha512-Zy8ZXMyxIT6RMTeY7OP/bDndfj6bwCan7SS98CEndS6deHwWPpseeHlwarNcBim+etXnF9HBc1non5JgDaJU1g==", - "dev": true - }, - "node_modules/buffers": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", - "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", + "node_modules/cacheable-request/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, "engines": { - "node": ">=0.2.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/call-bind": { @@ -4898,6 +5572,42 @@ "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==" }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", + "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "dev": true, + "dependencies": { + "restore-cursor": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/cliui": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", @@ -4956,6 +5666,15 @@ "node": ">=0.10.0" } }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, "node_modules/clone-deep": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", @@ -4970,6 +5689,18 @@ "node": ">=6" } }, + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "dev": true, + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/clsx": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", @@ -5875,6 +6606,33 @@ "node": ">=4" } }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/decompress-tar": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", @@ -5983,6 +6741,27 @@ "node": ">=0.10.0" } }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -6038,6 +6817,15 @@ "node": ">=6" } }, + "node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -6110,6 +6898,12 @@ "readable-stream": "^2.0.2" } }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, "node_modules/electron-to-chromium": { "version": "1.4.722", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.722.tgz", @@ -6142,6 +6936,16 @@ "node": ">= 4" } }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, "node_modules/end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -6163,6 +6967,15 @@ "node": ">=10.13.0" } }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/envinfo": { "version": "7.11.1", "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.11.1.tgz", @@ -6175,6 +6988,12 @@ "node": ">=4" } }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -6725,6 +7544,12 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", + "dev": true + }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -7018,22 +7843,6 @@ "node": ">= 8" } }, - "node_modules/fs-minipass/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fs-minipass/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -7349,6 +8158,31 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/got": { + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "dev": true, + "dependencies": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=10.19.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -7598,31 +8432,49 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true + }, "node_modules/http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", "dev": true, "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" + "agent-base": "^7.1.0", + "debug": "^4.3.4" }, "engines": { - "node": ">= 6" + "node": ">= 14" + } + }, + "node_modules/http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dev": true, + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "engines": { + "node": ">=10.19.0" } }, "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", "dev": true, "dependencies": { - "agent-base": "6", + "agent-base": "^7.0.2", "debug": "4" }, "engines": { - "node": ">= 6" + "node": ">= 14" } }, "node_modules/human-signals": { @@ -7634,6 +8486,28 @@ "node": ">=10.17.0" } }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dev": true, + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/icss-utils": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", @@ -7794,6 +8668,21 @@ "node": ">=0.8.19" } }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -7854,8 +8743,7 @@ "version": "9.0.5", "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", - "optional": true, - "peer": true, + "devOptional": true, "dependencies": { "jsbn": "1.1.0", "sprintf-js": "^1.1.3" @@ -7868,8 +8756,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "optional": true, - "peer": true + "devOptional": true }, "node_modules/is-alphabetical": { "version": "2.0.1", @@ -8064,12 +8951,30 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-iojs": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-iojs/-/is-iojs-1.1.0.tgz", "integrity": "sha512-tLn1j3wYSL6DkvEI+V/j0pKohpa5jk+ER74v6S4SgCXnjS0WA+DoZbwZBrrhgwksMvtuwndyGeG5F8YMsoBzSA==", "dev": true }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true + }, "node_modules/is-natural-number": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", @@ -10208,8 +11113,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", - "optional": true, - "peer": true + "devOptional": true }, "node_modules/jsesc": { "version": "2.5.2", @@ -10265,6 +11169,11 @@ "node": ">=6" } }, + "node_modules/jsonc-parser": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", + "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==" + }, "node_modules/jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", @@ -10583,6 +11492,15 @@ "loose-envify": "cli.js" } }, + "node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/lowlight": { "version": "1.20.0", "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.20.0.tgz", @@ -10602,34 +11520,109 @@ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, "dependencies": { - "yallist": "^3.0.2" + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/make-dir/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "engines": { + "node": ">=4" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/make-fetch-happen": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", + "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^16.1.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^2.0.3", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^9.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" } }, - "node_modules/make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "node_modules/make-fetch-happen/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, "dependencies": { - "pify": "^3.0.0" + "agent-base": "6", + "debug": "4" }, "engines": { - "node": ">=4" + "node": ">= 6" } }, - "node_modules/make-dir/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "node_modules/make-fetch-happen/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, "engines": { - "node": ">=4" + "node": ">=12" } }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, "node_modules/makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", @@ -11308,6 +12301,15 @@ "node": ">=6" } }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -11327,29 +12329,99 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dependencies": { - "minipass": "^3.0.0", "yallist": "^4.0.0" }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, "engines": { "node": ">= 8" } }, - "node_modules/minizlib/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "node_modules/minipass-fetch": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", + "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", + "dev": true, "dependencies": { - "yallist": "^4.0.0" + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" }, "engines": { "node": ">=8" } }, + "node_modules/minipass/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/minizlib/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -11712,23 +12784,225 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/neo-async": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node_modules/node-abi": { + "version": "3.65.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.65.0.tgz", + "integrity": "sha512-ThjYBfoDNr08AWx6hGaRbfPwxKV9kVzAzOzlLKbk2CuqXE2xnCh+cbAGnwM3t8Lq4v9rUB7VfondlkBckcJrVA==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-abi/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-api-headers": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/node-api-headers/-/node-api-headers-1.1.0.tgz", + "integrity": "sha512-ucQW+SbYCUPfprvmzBsnjT034IGRB2XK8rRc78BgjNKhTdFKgAwAmgW704bKIBmcYW48it0Gkjpkd39Azrwquw==" + }, + "node_modules/node-api-version": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/node-api-version/-/node-api-version-0.2.0.tgz", + "integrity": "sha512-fthTTsi8CxaBXMaBAD7ST2uylwvsnYxh2PfaScwpMhos6KlSFajXQPcM4ogNE1q2s3Lbz9GCGqeIHC+C6OZnKg==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + } + }, + "node_modules/node-api-version/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-gyp": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.4.1.tgz", + "integrity": "sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ==", + "dev": true, + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^10.0.3", + "nopt": "^6.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^12.13 || ^14.13 || >=16" + } + }, + "node_modules/node-gyp/node_modules/are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "deprecated": "This package is no longer supported.", + "dev": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/node-gyp/node_modules/gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "deprecated": "This package is no longer supported.", + "dev": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/node-gyp/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/node-gyp/node_modules/npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "deprecated": "This package is no longer supported.", + "dev": true, + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/node-gyp/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/node-gyp/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-gyp/node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-gyp/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/node-gyp/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, - "node_modules/node-api-headers": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/node-api-headers/-/node-api-headers-1.1.0.tgz", - "integrity": "sha512-ucQW+SbYCUPfprvmzBsnjT034IGRB2XK8rRc78BgjNKhTdFKgAwAmgW704bKIBmcYW48it0Gkjpkd39Azrwquw==" - }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -11760,6 +13034,21 @@ "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", "dev": true }, + "node_modules/nopt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", + "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", + "dev": true, + "dependencies": { + "abbrev": "^1.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, "node_modules/normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -11790,6 +13079,18 @@ "node": ">=0.10.0" } }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/npm-run-all": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", @@ -11986,6 +13287,119 @@ "node": ">= 0.8.0" } }, + "node_modules/ora": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-7.0.1.tgz", + "integrity": "sha512-0TUxTiFJWv+JnjWm4o9yvuskpEJLXTcng8MJuKd+SzAzp2o+OP3HWqNhB4OdJRt1Vsd9/mR0oyaEYlOnL7XIRw==", + "dev": true, + "dependencies": { + "chalk": "^5.3.0", + "cli-cursor": "^4.0.0", + "cli-spinners": "^2.9.0", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^1.3.0", + "log-symbols": "^5.1.0", + "stdin-discarder": "^0.1.0", + "string-width": "^6.1.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ora/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ora/node_modules/emoji-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "dev": true + }, + "node_modules/ora/node_modules/is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/log-symbols": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-5.1.0.tgz", + "integrity": "sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==", + "dev": true, + "dependencies": { + "chalk": "^5.0.0", + "is-unicode-supported": "^1.1.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/string-width": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-6.1.0.tgz", + "integrity": "sha512-k01swCJAgQmuADB0YIc+7TuatfNvTBVOoaUWJjTB9R4VJzR5vNWzf5t42ESVZFPS8xTySF7CAdV4t/aaIm3UnQ==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^10.2.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/os-locale": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", @@ -11998,6 +13412,15 @@ "node": ">=0.10.0" } }, + "node_modules/p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -12028,6 +13451,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -12501,6 +13939,25 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "dev": true + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -12538,6 +13995,16 @@ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -12582,6 +14049,18 @@ } ] }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -12781,6 +14260,18 @@ "react-dom": ">=16.14.0" } }, + "node_modules/read-binary-file-arch": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/read-binary-file-arch/-/read-binary-file-arch-1.0.6.tgz", + "integrity": "sha512-BNg9EN3DD3GsDXX7Aa8O4p92sryjkmzYYgmgTAc6CA4uGLEDzFfxOxugu21akOxpcXHiEgsYkC6nPsQvLLLmEg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "bin": { + "read-binary-file-arch": "cli.js" + } + }, "node_modules/read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", @@ -13137,6 +14628,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true + }, "node_modules/resolve-cwd": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", @@ -13176,6 +14673,43 @@ "node": ">=10" } }, + "node_modules/responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "dev": true, + "dependencies": { + "lowercase-keys": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", + "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -13270,6 +14804,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "optional": true + }, "node_modules/sass": { "version": "1.72.0", "resolved": "https://registry.npmjs.org/sass/-/sass-1.72.0.tgz", @@ -13578,8 +15119,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "optional": true, - "peer": true, + "devOptional": true, "engines": { "node": ">= 6.0.0", "npm": ">= 3.0.0" @@ -13589,8 +15129,7 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.1.tgz", "integrity": "sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ==", - "optional": true, - "peer": true, + "devOptional": true, "dependencies": { "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" @@ -13600,6 +15139,32 @@ "npm": ">= 3.0.0" } }, + "node_modules/socks-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", + "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "dev": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/socks-proxy-agent/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -13689,6 +15254,18 @@ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, + "node_modules/ssri": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", + "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", + "dev": true, + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, "node_modules/stack-utils": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", @@ -13715,6 +15292,21 @@ "resolved": "https://registry.npmjs.org/state-local/-/state-local-1.0.7.tgz", "integrity": "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==" }, + "node_modules/stdin-discarder": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.1.0.tgz", + "integrity": "sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ==", + "dev": true, + "dependencies": { + "bl": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/stream-chain": { "version": "2.2.5", "resolved": "https://registry.npmjs.org/stream-chain/-/stream-chain-2.2.5.tgz", @@ -14579,9 +16171,9 @@ } }, "node_modules/typescript": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.3.tgz", - "integrity": "sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==", + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -14678,6 +16270,30 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/unique-filename": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", + "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", + "dev": true, + "dependencies": { + "unique-slug": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/unique-slug": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz", + "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, "node_modules/unist-util-is": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", @@ -14926,6 +16542,33 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/vscode-json-languageservice": { + "version": "5.3.11", + "resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-5.3.11.tgz", + "integrity": "sha512-WYS72Ymria3dn8ZbjtBbt5K71m05wY1Q6hpXV5JxUT0q75Ts0ljLmnZJAVpx8DjPgYbFD+Z8KHpWh2laKLUCtQ==", + "dependencies": { + "@vscode/l10n": "^0.0.18", + "jsonc-parser": "^3.2.1", + "vscode-languageserver-textdocument": "^1.0.11", + "vscode-languageserver-types": "^3.17.5", + "vscode-uri": "^3.0.8" + } + }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.11.tgz", + "integrity": "sha512-X+8T3GoiwTVlJbicx/sIAF+yuJAqz8VvwJyoMVhwEMoEKE/fkDmrqUgDMyBECcM2A2frVZIUj5HI/ErRXCfOeA==" + }, + "node_modules/vscode-languageserver-types": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==" + }, + "node_modules/vscode-uri": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz", + "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==" + }, "node_modules/walker": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", @@ -14956,6 +16599,15 @@ "node": ">=10.13.0" } }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", diff --git a/package.json b/package.json index 3039ec6a..55db319e 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,8 @@ "compile:views": "webpack --mode development", "watch:extension": "tsc -watch -p ./", "watch:views": "webpack --watch --mode development", - "test": "node ./out/test/runTest.js && jest", + "test": "node ./out/test/runTest.js", + "test:file": "node ./out/test/runTest.js", "format": "prettier 'src/**/*.ts' --write", "lint": "eslint src --ext ts --fix", "pretest": "npm run compile:extension" @@ -55,17 +56,18 @@ "@babel/parser": "^7.22.7", "@babel/preset-env": "^7.23.5", "@babel/preset-react": "^7.23.3", + "@electron/rebuild": "^3.6.0", "@types/glob": "^7.2.0", "@types/jest": "^29.5.12", "@types/mocha": "^10.0.6", - "@types/node": "^20.12.2", + "@types/node": "^20.14.2", "@types/react": "^18.2.6", "@types/react-dom": "^18.2.4", "@types/uuid": "^9.0.6", "@types/vscode": "^1.63.1", "@typescript-eslint/eslint-plugin": "^7.5.0", "@typescript-eslint/parser": "^7.5.0", - "@vscode/test-electron": "^2.3.9", + "@vscode/test-electron": "^2.4.0", "babel-loader": "^9.1.3", "class-transformer": "^0.5.1", "cmake-js": "^6.3.2", @@ -86,7 +88,7 @@ "terser-webpack-plugin": "^5.3.10", "ts-jest": "^29.1.2", "ts-loader": "^9.5.1", - "typescript": "^5.4.3", + "typescript": "^5.4.5", "webpack": "^5.91.0", "webpack-cli": "^5.1.4" }, @@ -114,6 +116,7 @@ "dayjs": "^1.11.9", "decompress": "^4.2.1", "gitly": "^2.5.2", + "jsonc-parser": "^3.2.1", "monaco-editor": "^0.43.0", "mongodb": "^6.4.0", "prop-types": "^15.7.2", @@ -129,7 +132,8 @@ "react-tooltip": "^5.26.0", "shelljs": "^0.8.5", "stream-json": "^1.8.0", - "uuid": "^9.0.1" + "uuid": "^9.0.1", + "vscode-json-languageservice": "^5.3.11" }, "activationEvents": [ "onFileSystem:couchbase", @@ -358,17 +362,24 @@ ], "configuration": "./language/language-configuration.json" }, - { - "id":"searchQuery", + "id": "json", "extensions": [ ".cbs.json" ], "aliases": [ "SEARCH" ], - "configuration": "./language/language-configuration.json" - + "configurationDefaults": { + "[json]": { + "editor.quickSuggestions": { + "strings": false, + "comments": false, + "other": false + }, + "editor.suggestOnTriggerCharacters": false + } + } } ], "grammars": [ @@ -732,7 +743,7 @@ "command": "vscode-couchbase.runSearch", "key": "ctrl+shift+e", "mac": "cmd+shift+e", - "when": "(editorLangId == cbs.json || resourceFilename =~ /.cbs.json$/) && !isKVCluster" + "when": "editorLangId == json && resourceFilename =~ /\\.cbs\\.json$/ && !isKVCluster && isSearchEnabled" } ], "menus": { @@ -746,7 +757,7 @@ { "command": "vscode-couchbase.runSearch", "category": "Couchbase", - "when": "(editorLangId == cbs.json || resourceFilename =~ /.cbs.json$/) && !isKVCluster", + "when": "editorLangId == json && resourceFilename =~ /\\.cbs\\.json$/ && !isKVCluster && isSearchEnabled", "group": "navigation@1" }, { @@ -761,7 +772,7 @@ "command": "vscode-couchbase.searchContext", "category": "Couchbase", "group": "navigation@2", - "when": "(editorLangId == cbs.json || resourceFilename =~ /.cbs.json$/) && !isKVCluster" + "when": "editorLangId == json && resourceFilename =~ /\\.cbs\\.json$/ && !isKVCluster" }, { "title": "Show Favorite Queries", @@ -814,7 +825,7 @@ }, { "command": "vscode-couchbase.runSearch", - "when": "(editorLangId == .cbs.json || resourceFilename =~ /.cbs.json$/) && !isKVCluster", + "when": "editorLangId == json && resourceFilename =~ /\\.cbs\\.json$/ && !isKVCluster && isSearchEnabled", "group": "navigation@1" } ], @@ -1023,7 +1034,7 @@ }, { "command": "vscode-couchbase.openSearchWorkbench", - "when": "view == couchbase && viewItem == searchIndex && !isKVCluster", + "when": "view == couchbase && viewItem == searchIndex && !isKVCluster && isSearchEnabled", "group": "workbench@1" }, { @@ -1254,4 +1265,4 @@ } ] } -} \ No newline at end of file +} diff --git a/src/commands/fts/SearchWorkbench/contributor/autoComplete.ts b/src/commands/fts/SearchWorkbench/contributor/autoComplete.ts new file mode 100644 index 00000000..cb5db227 --- /dev/null +++ b/src/commands/fts/SearchWorkbench/contributor/autoComplete.ts @@ -0,0 +1,11 @@ +import * as jsonc from 'jsonc-parser'; +import * as vscode from 'vscode'; + +export interface CBSContributor { + + accept(key: string | null): boolean; + + contributeKey(parentKey: string | null, node: jsonc.Node, suggestion: string[], result: vscode.CompletionItem[], existingKeys:string[]): any; + + contributeValue(attributeKey: string | null, node: jsonc.Node, suggestion: string[], fields:string[]): any; +} diff --git a/src/commands/fts/SearchWorkbench/contributor/autoCompleteVisitor.ts b/src/commands/fts/SearchWorkbench/contributor/autoCompleteVisitor.ts new file mode 100644 index 00000000..3d78b027 --- /dev/null +++ b/src/commands/fts/SearchWorkbench/contributor/autoCompleteVisitor.ts @@ -0,0 +1,292 @@ +import * as vscode from 'vscode'; +import * as jsonc from 'jsonc-parser'; +import { CBSContributor } from './autoComplete'; +import { booleanCbsContributor } from './booleanCbsContributor'; +import { consistencyCbsContributor } from './consistencyCbsContributor'; +import { geometryCbsContributor } from './geometryCbsContributor'; +import { highlightCbsContributor } from './highlightCbsContributor'; +import { knnCbsContributor } from './knnCbsContributor'; +import { locationCbsContributor } from './locationCbsContributor'; +import { fieldsContributor } from './fieldsContributor'; +import { queryCbsContributor } from './queryCbsContributor'; +import { cbsTemplate } from './cbsTemplates'; +import { ctlCbsContributor } from './ctlCbsContributor'; +import { shapeCbsContributor } from './shapeCbsContributor'; +import { SearchWorkbench } from '../searchWorkbench'; +import { logger } from '../../../../logger/logger'; + + + +export class AutocompleteVisitor { + public topLevelKeywords: string[] = ["query", "knn", "ctl", "size", "limit", "from", "offset", "highlight", "fields", "facets", "explain", "sort", "includeLocations", "score", "search_after", "search_before", "collections"]; + private contributors: CBSContributor[] = [new booleanCbsContributor(), new consistencyCbsContributor(), new geometryCbsContributor(), new highlightCbsContributor(), new knnCbsContributor(), new locationCbsContributor(), new queryCbsContributor(), new ctlCbsContributor(), new shapeCbsContributor()]; + + async getAutoCompleteContributor(document: vscode.TextDocument, position: vscode.Position, searchWorkBench?: SearchWorkbench): Promise { + const text = document.getText(); + // const rootNode = jsonc.parseTree(text); + const queryContext = searchWorkBench?.editorToContext.get(document.uri.toString()); + const tempJsonString = this.addTemporaryQuotes(text, position); + const rootNode = jsonc.parseTree(tempJsonString); + + + if (!rootNode) { + return []; + } + const node = jsonc.findNodeAtOffset(rootNode, document.offsetAt(position)); + + if (!node) { + return []; + } + if(!this.isWithinObject(node)){ + return []; + } + const isKey = this.isKey(document, position); + let attributeName: string | null = null; + if (!isKey) { + attributeName = this.getAttributeName(rootNode, node); + } + + const suggestions: string[] = []; + const result: vscode.CompletionItem[] = []; + const existingKeys: string[] = []; + + await this.fetchKeys(node, existingKeys) + const isWithinQuotes = this.isWithinQuotes(document, position); + if (this.isTopLevelProperty(rootNode, node)) { + + if (!isKey) { + if (attributeName == 'score') { + suggestions.push('none'); + } + } else { + suggestions.push(...this.topLevelKeywords.filter(keyword => !existingKeys.includes(keyword))); + + + if (!existingKeys.includes('highlight')) { + result.push(cbsTemplate.getHighlightTemplate()); + } + if (!existingKeys.includes('knn')) { + result.push(cbsTemplate.getKNNTemplate()) + } + } + + } else { + let type = this.getNodeType(node, rootNode); + for (const contributor of this.contributors) { + if (contributor.accept(type)) { + if (isKey) { + const existingKeys2 = existingKeys.filter(item => item !== ''); + contributor.contributeKey(type, node, suggestions, result, existingKeys2); + } + else { + let fields: string[] = [] + if (attributeName == "field" && queryContext?.bucketName && queryContext?.indexName) { + fields = await fieldsContributor.getFieldNames(queryContext?.bucketName, queryContext?.indexName) + } + contributor.contributeValue(attributeName, node, suggestions, fields) + } + } + }; + + + + } + for (const suggestion of suggestions) { + if (!existingKeys.includes(suggestion)) { + let itemLabel = suggestion; + if (!isWithinQuotes) { + itemLabel = `"${suggestion}"`; + } + + const completionItem = new vscode.CompletionItem(itemLabel, vscode.CompletionItemKind.Text); + result.push(completionItem); + } + }; + return result; + } + + addTemporaryQuotes(jsonString: string, position: vscode.Position): string { + const lines = jsonString.split('\n'); + const line = lines[position.line]; + + const regex = /("(\w+)")\s*:\s*,/; + + if (regex.test(line)) { + return lines.map((l, i) => + i === position.line ? l.replace(regex, '$1: "",') : l + ).join('\n'); + } + + return jsonString; + } + + isTopLevelProperty(rootNode: jsonc.Node, currentNode: jsonc.Node) { + if (currentNode === rootNode) { + return true + } + if (currentNode.type === 'string') { + if (currentNode.parent && currentNode.parent.parent) { + const propertyNode = currentNode.parent.parent + return propertyNode === rootNode + } + } + if (currentNode.type === 'property' && currentNode.parent) { + return currentNode.parent === rootNode; + } + + return false; + } + + async fetchKeys(node: jsonc.Node, existingKeys: string[]): Promise { + if (node.type === 'object') { + for (const prop of node.children || []) { + if (prop.type === 'property') { + const keyNode = prop.children?.[0]; + if (keyNode && keyNode.type === 'string') { + existingKeys.push(keyNode.value as string); + } + } + } + } else if (node.type === 'string') { + if (node.parent?.type === 'property' && node.parent.parent?.type === 'object') { + const objectNode = node.parent.parent; + for (const prop of objectNode.children || []) { + if (prop.type === 'property') { + const keyNode = prop.children?.[0]; + if (keyNode && keyNode.type === 'string' && keyNode.value !== '') { + existingKeys.push(keyNode.value as string); + } + } + } + } + } + } + + + + getNodeType(node: jsonc.Node | undefined, rootNode: jsonc.Node): string | null { + let currentNode = node ; + if (!currentNode) { + logger.debug("Error fetching Node type, Node is undefined") + return null; + } + + + let lastPropertyName = undefined; + let count = 0; + + while (currentNode) { + if (currentNode.type === 'property') { + if (currentNode.parent) { + count = count + 1; + lastPropertyName = jsonc.findNodeAtOffset(rootNode, currentNode.offset)?.value; + if (count == 2) { + break; + } + } + } else if (currentNode.type === 'array' && currentNode.parent && currentNode.parent.type === 'property') { + lastPropertyName = jsonc.findNodeAtOffset(rootNode, currentNode.parent.offset)?.value; + break; + } else if ( currentNode.type === 'object' && currentNode.parent && currentNode.parent.type === 'property'){ + lastPropertyName = jsonc.findNodeAtOffset(rootNode,currentNode.parent.offset)?.value + break; + } + currentNode = currentNode.parent; + } + + if (lastPropertyName) { + return lastPropertyName; + } else { + return null; + } + } + + isKey(document: vscode.TextDocument, position: vscode.Position): boolean { + const lineText = document.lineAt(position.line).text.substring(0, position.character); + + if (/^\s*[\{,]\s*$/.test(lineText)) { + return true; + } + + let depth = 0; + for (let i = position.character - 1; i >= 0; i--) { + const char = lineText[i]; + switch (char) { + case ':': + if (depth === 0) return false; + break; + case '{': + case '[': + depth++; + break; + case '}': + case ']': + depth--; + break; + } + } + + return true; + } + + + + + getAttributeName(rootNode: jsonc.Node, currentNode: jsonc.Node) { + if (!rootNode) { + return null + } + if (currentNode && currentNode.parent?.type === "object") { + return jsonc.findNodeAtOffset(rootNode, currentNode.offset)?.value; + } + if (currentNode && currentNode.parent && currentNode.parent?.type === "property") { + const propertyNode = currentNode.parent; + return jsonc.findNodeAtOffset(rootNode, propertyNode.offset)?.value; + } + + return null; + } + + isWithinQuotes(document: vscode.TextDocument, position: vscode.Position): boolean { + const lineText = document.lineAt(position.line).text; + const charPos = position.character; + + let quoteOpen = false; + let quoteClose = false; + + for (let i = charPos - 1; i >= 0; i--) { + if (lineText[i] === '"' && (i === 0 || lineText[i - 1] !== '\\')) { + quoteOpen = true; + break; + } + } + + for (let i = charPos; i < lineText.length; i++) { + if (lineText[i] === '"' && (i === 0 || lineText[i - 1] !== '\\')) { + quoteClose = true; + break; + } + } + + return quoteOpen && quoteClose; + } + + isWithinObject(currentNode: jsonc.Node): boolean{ + while (currentNode) { + if (currentNode.type === 'array') { + let objectWithinArray: jsonc.Node | undefined = currentNode; + while (objectWithinArray && objectWithinArray.type !== 'object') { + objectWithinArray = objectWithinArray.parent; + } + return objectWithinArray !== undefined && objectWithinArray.parent === currentNode; + } else if (currentNode.type === 'object') { + return true; + } + if(currentNode.parent){ + currentNode = currentNode.parent; + } + } + + return true; + } +} diff --git a/src/commands/fts/SearchWorkbench/contributor/booleanCbsContributor.ts b/src/commands/fts/SearchWorkbench/contributor/booleanCbsContributor.ts new file mode 100644 index 00000000..0d4038b0 --- /dev/null +++ b/src/commands/fts/SearchWorkbench/contributor/booleanCbsContributor.ts @@ -0,0 +1,23 @@ +import { Node } from 'jsonc-parser' +import { CBSContributor } from './autoComplete' + +export class booleanCbsContributor implements CBSContributor { + + accept(key: string | null): boolean { + return key === "must" || key === "must_not" || key === "should"; + } + + contributeKey(parentKey: string, node: Node, suggestion: string[]) { + if (parentKey === "must") { + suggestion.push("conjuncts") + } else if (parentKey == "must_not" || parentKey == "should") { + suggestion.push("disjuncts") + } + + } + + contributeValue(attributeKey: string, node: Node, suggestion: string[]) { + + } + +} \ No newline at end of file diff --git a/src/commands/fts/SearchWorkbench/contributor/cbsTemplateDef.ts b/src/commands/fts/SearchWorkbench/contributor/cbsTemplateDef.ts new file mode 100644 index 00000000..143e49d2 --- /dev/null +++ b/src/commands/fts/SearchWorkbench/contributor/cbsTemplateDef.ts @@ -0,0 +1,11 @@ +export class cbsTemplateDef { + key: string; + desc: string; + attrs: string[]; + + constructor(key: string, desc: string, attrs: string[]) { + this.key = key; + this.desc = desc; + this.attrs = attrs; + } +} diff --git a/src/commands/fts/SearchWorkbench/contributor/cbsTemplates.ts b/src/commands/fts/SearchWorkbench/contributor/cbsTemplates.ts new file mode 100644 index 00000000..4bf7d765 --- /dev/null +++ b/src/commands/fts/SearchWorkbench/contributor/cbsTemplates.ts @@ -0,0 +1,279 @@ +import * as vscode from 'vscode'; + +export class cbsTemplate { + + static getQueryTemplate(existingKeys: string[]): vscode.CompletionItem { + const QUERY = 'query'; + const snippetCompletion = new vscode.CompletionItem(QUERY, vscode.CompletionItemKind.Module); + snippetCompletion.detail = "Query string query syntax"; + + let snippetText = ''; + + if (!existingKeys.includes("query")) { + snippetText += '\t"query": "$1"\n'; + } + + snippetText = snippetText.replace(/,\n\}/g, '\n}'); + + snippetCompletion.insertText = new vscode.SnippetString(snippetText); + + return snippetCompletion; + } + + + static getHighlightTemplate(): vscode.CompletionItem { + + const snippetCompletion = new vscode.CompletionItem("Highlight Options", vscode.CompletionItemKind.Module); + snippetCompletion.detail = "Highlight Options"; + + let snippetText = `"highlight": {\n\t"style": "$1",\n\t"fields": [$2]\n}`; + + + snippetCompletion.insertText = new vscode.SnippetString(snippetText); + + return snippetCompletion; + } + + static getEmptyTemplate(name: string, desc: string): vscode.CompletionItem { + const emptyTemplate = new vscode.CompletionItem(name, vscode.CompletionItemKind.Module); + emptyTemplate.detail = desc; + emptyTemplate.documentation = new vscode.MarkdownString(`Inserts an empty JSON object for \`${name}\``); + + let snippetText = `"${name}": {}`; + + emptyTemplate.insertText = new vscode.SnippetString(snippetText); + + // emptyTemplate.command = { title: 'Format Document', command: 'editor.action.formatDocument' }; + + return emptyTemplate; + } + + static getGeoTemplate(key: string, desc: string, type: string, existingKeys: string[]): vscode.CompletionItem { + const geoCompletion = new vscode.CompletionItem(key, vscode.CompletionItemKind.Module); + geoCompletion.detail = desc; + let snippetText = ''; + + let cursorPosition = 1; + + if (!existingKeys.includes("field")) { + snippetText += `"field": "\${${cursorPosition++}}",\n`; + } + + if (!existingKeys.includes("geometry")) { + snippetText += '"geometry": {\n'; + snippetText += '"shape": {\n'; + snippetText += `"type": "${type}",\n`; + + if (type === "GeometryCollection") { + snippetText += `"geometries": [\${${cursorPosition++}}]\n`; + } else { + snippetText += `"coordinates": [\${${cursorPosition++}}]\n`; + } + + if (type === "Circle") { + snippetText += `, "radius": "\${${cursorPosition++}}"\n`; + } + + snippetText += '},\n'; + snippetText += `"relation": "\${${cursorPosition++}}"\n`; + snippetText += '}'; + } + + snippetText = snippetText.replace(/,\n}/g, '\n}'); + + geoCompletion.insertText = new vscode.SnippetString(snippetText); + + return geoCompletion; + } + + + + static getKNNTemplate(): vscode.CompletionItem { + const snippetCompletion = new vscode.CompletionItem("knn", vscode.CompletionItemKind.Module); + snippetCompletion.detail = "Knn filter"; + let snippetText = '"knn": [{\n\t"k": $1,\n\t"field": "$2",\n\t"vector": [$3]\n}]'; + + snippetCompletion.insertText = new vscode.SnippetString(snippetText); + + return snippetCompletion; + } + + static getConjunctsTemplate(existingKeys: string[]): vscode.CompletionItem { + const CONJUNCTS_QUERY = 'conjuncts'; + const snippetCompletion = new vscode.CompletionItem(CONJUNCTS_QUERY, vscode.CompletionItemKind.Module); + snippetCompletion.detail = "Query conjunction"; + + let snippetText = ''; + + if (!existingKeys.includes("conjuncts")) { + snippetText += '\t"conjuncts": [\n\t\t{\n\t\t\t$1\n\t\t}\n\t]\n'; + } + + snippetText = snippetText.replace(/,\n\}/g, '\n}'); + + snippetCompletion.insertText = new vscode.SnippetString(snippetText); + + return snippetCompletion; + } + + static getDisjunctsTemplate(existingKeys: string[]): vscode.CompletionItem { + const DISJUNCTS_QUERY = 'disjuncts'; + const snippetCompletion = new vscode.CompletionItem(DISJUNCTS_QUERY, vscode.CompletionItemKind.Module); + snippetCompletion.detail = "Query disjunction"; + + let snippetText = ''; + + if (!existingKeys.includes("disjuncts")) { + snippetText += '\t"disjuncts": [\n\t\t{\n\t\t\t$1\n\t\t}\n\t]\n'; + } + + snippetText = snippetText.replace(/,\n\}/g, '\n}'); + + snippetCompletion.insertText = new vscode.SnippetString(snippetText); + + return snippetCompletion; + } + + static getMustTemplate(): vscode.CompletionItem { + const snippetCompletion = new vscode.CompletionItem('must'); + snippetCompletion.detail = "Must boolean query template"; + snippetCompletion.kind = vscode.CompletionItemKind.Module; + + let snippetText = ''; + + snippetText += '"must": {\n\t"conjuncts": [\n\t\t{$1}\n\t]\n}'; + + snippetCompletion.insertText = new vscode.SnippetString(snippetText); + + return snippetCompletion; + } + + static getShouldTemplate(): vscode.CompletionItem { + const snippetCompletion = new vscode.CompletionItem('should'); + snippetCompletion.detail = "Should boolean query template"; + snippetCompletion.kind = vscode.CompletionItemKind.Module; + + let snippetText = ''; + snippetText += '"should": {\n\t"disjuncts": [\n\t\t{$1}\n\t]\n}'; + + snippetCompletion.insertText = new vscode.SnippetString(snippetText); + + return snippetCompletion; + } + + static getMustNotTemplate(): vscode.CompletionItem { + const snippetCompletion = new vscode.CompletionItem('must_not'); + snippetCompletion.detail = "MustNot boolean query template"; + snippetCompletion.kind = vscode.CompletionItemKind.Module; + + let snippetText = ''; + + snippetText += '"must_not": {\n\t"disjuncts": [\n\t\t{$1}\n\t]\n}'; + + snippetCompletion.insertText = new vscode.SnippetString(snippetText); + + return snippetCompletion; + } + + static createGenericTemplate(key: string, description: string, attributes: string[]): vscode.CompletionItem { + const snippetCompletion = new vscode.CompletionItem(key); + snippetCompletion.detail = description; + snippetCompletion.kind = vscode.CompletionItemKind.Module; + + let snippetText = ''; + + attributes.forEach((attr, index) => { + snippetText += `\t"${attr}": $${index + 1}`; + if (index < attributes.length - 1) { + snippetText += ",\n"; + } + }); + + + snippetCompletion.insertText = new vscode.SnippetString(snippetText); + + return snippetCompletion; + } + + + static getRectangleTemplate(existingKeys: string[]): vscode.CompletionItem { + const RECTANGLE_QUERY = 'rectangle_query'; + const snippetCompletion = new vscode.CompletionItem(RECTANGLE_QUERY, vscode.CompletionItemKind.Module); + snippetCompletion.detail = "Rectangle-Based Geopoint Query"; + + let snippetText = ''; + + if (!existingKeys.includes("field")) { + snippetText += '\t"field": "$1",\n'; + } + + if (!existingKeys.includes("top_left")) { + snippetText += `\t"top_left": {\n\t\t"lon": "$2",\n\t\t"lat": "$3"\n\t},\n`; + } + + if (!existingKeys.includes("bottom_right")) { + snippetText += `\t"bottom_right": {\n\t\t"lon": "$4",\n\t\t"lat": "$5"\n\t}\n`; + } + + snippetText = snippetText.replace(/,\n}$/g, '\n}'); + + snippetCompletion.insertText = new vscode.SnippetString(snippetText); + + return snippetCompletion; + } + + static getRadiusTemplate(existingKeys: string[]): vscode.CompletionItem { + const RADIUS_QUERY = 'radius_query'; + const snippetCompletion = new vscode.CompletionItem(RADIUS_QUERY, vscode.CompletionItemKind.Module); + snippetCompletion.detail = "Distance/Radius-Based Geopoint Query"; + + let snippetText = ''; + + if (!existingKeys.includes("field")) { + snippetText += '\t"field": "$1",\n'; + } + + if (!existingKeys.includes("distance")) { + snippetText += '\t"distance": "$2",\n'; + } + + if (!existingKeys.includes("location")) { + snippetText += `\t"location": {\n\t\t"lon": "$3",\n\t\t"lat": "$4"\n\t}\n`; + } + + snippetText = snippetText.replace(/,\n\}/g, '\n}'); + + snippetCompletion.insertText = new vscode.SnippetString(snippetText); + + return snippetCompletion; + } + + static getVectorTemplate(existingKeys: string[]): vscode.CompletionItem { + const snippetCompletion = new vscode.CompletionItem('vector_query'); + snippetCompletion.detail = "Vector search filter"; + snippetCompletion.kind = vscode.CompletionItemKind.Module; + + let snippetText = ''; + + if (!existingKeys.includes("field")) { + snippetText += '"field": "$1",\n'; + } + if (!existingKeys.includes("k")) { + snippetText += '"k": $2,\n'; + } + if (!existingKeys.includes("vector")) { + snippetText += '"vector": [$3]\n'; + } + + snippetText = snippetText.replace(/,\n$/, '\n'); + + snippetCompletion.insertText = new vscode.SnippetString(snippetText); + // snippetCompletion.command = { + // title: "Format Document", + // command: "editor.action.formatDocument" + // }; + + return snippetCompletion; + } + +} \ No newline at end of file diff --git a/src/commands/fts/SearchWorkbench/contributor/consistencyCbsContributor.ts b/src/commands/fts/SearchWorkbench/contributor/consistencyCbsContributor.ts new file mode 100644 index 00000000..e0eb901c --- /dev/null +++ b/src/commands/fts/SearchWorkbench/contributor/consistencyCbsContributor.ts @@ -0,0 +1,27 @@ +import { Node } from 'jsonc-parser' +import { CBSContributor } from './autoComplete' +import * as vscode from 'vscode'; + +export class consistencyCbsContributor implements CBSContributor { + public static keys: string[] = ["vectors", "level", "results"]; + + accept(key: string | null): boolean { + return key === "consistency"; + } + + contributeKey(parentKey: string, node: Node, suggestion: string[], result: vscode.CompletionItem[], existingKeys: string[]) { + suggestion.push(...consistencyCbsContributor.keys) + + } + + contributeValue(attributeKey: string, node: Node, suggestion: string[], fields:string[]) { + if (attributeKey == "level") { + suggestion.push("at_plus", "not_bounded") + } + else if (attributeKey == "results") { + suggestion.push("complete") + } + + } + +} \ No newline at end of file diff --git a/src/commands/fts/SearchWorkbench/contributor/ctlCbsContributor.ts b/src/commands/fts/SearchWorkbench/contributor/ctlCbsContributor.ts new file mode 100644 index 00000000..6c5ae789 --- /dev/null +++ b/src/commands/fts/SearchWorkbench/contributor/ctlCbsContributor.ts @@ -0,0 +1,21 @@ +import { Node } from 'jsonc-parser' +import { CBSContributor } from './autoComplete' +import * as vscode from 'vscode'; + +export class ctlCbsContributor implements CBSContributor { + public static keys: string[] = ["timeout", "consistency"]; + + accept(key: string | null): boolean { + return key === "ctl"; + } + + contributeKey(parentKey: string, node: Node, suggestion: string[], result: vscode.CompletionItem[], existingKeys: string[]) { + suggestion.push(...ctlCbsContributor.keys); + + } + + contributeValue(attributeKey: string, node: Node, suggestion: string[], fields:string[]) { + + } + +} \ No newline at end of file diff --git a/src/commands/fts/SearchWorkbench/contributor/fieldsContributor.ts b/src/commands/fts/SearchWorkbench/contributor/fieldsContributor.ts new file mode 100644 index 00000000..b8b09681 --- /dev/null +++ b/src/commands/fts/SearchWorkbench/contributor/fieldsContributor.ts @@ -0,0 +1,88 @@ +import { CacheService, IBucketCache } from "../../../../util/cacheService/cacheService"; +import { getActiveConnection } from "../../../../util/connections"; +import { CouchbaseRestAPI } from "../../../../util/apis/CouchbaseRestAPI"; +import { SearchIndexParser } from "../indexParser/indexParser"; +import { logger } from "../../../../logger/logger"; + + +export class fieldsContributor { + + static async getFieldNames(bucketName: string, indexName: string): Promise { + const cache = new CacheService() + const suggestions: string[] = [] + const connection = getActiveConnection(); + if (!connection) { + return []; + } + const api = new CouchbaseRestAPI(connection); + + cache.loadCache(connection); + const bucketCache = cache.getCache(bucketName); + const result = await api.fetchSearchIndexDefinition(indexName); + if (!bucketCache) { + return [] + } + const index = result?.indexDef + if (index) { + try { + const fields = SearchIndexParser.extractPropertiesMap(index); + fields.set(SearchIndexParser.getDefaultField(index), ''); + + const isDynamic = SearchIndexParser.isIndexDynamic(index); + if (isDynamic) { + const cols = SearchIndexParser.listCollections(index); + for (const prop of cols) { + if (!SearchIndexParser.isCollectionDynamicallyIndexed(index, prop)) { + continue; + } + + if (prop.includes('.')) { + const parts = prop.split('.'); + const additionalFields = this.extractFieldsFromCollection(bucketCache, parts[0], parts[1]); + if (additionalFields && typeof additionalFields[0] === 'object' && additionalFields[0] !== null) { + const entries = Object.entries(additionalFields[0] as { [key: string]: any }); + + entries.map(property => { + const key = property[0]; + const value = property[1]; + + if (typeof value === 'object' && value !== null && 'type' in value) { + const type = value.type; + if (type !== 'array') { + if (type === 'object') { + Object.entries(value.value).forEach(([subKey, _]) => { + const fullKey = `${key}.${subKey}`; + fields.set(fullKey, '') + }); + + } + fields.set(key, value) + } + + } + }); + } + } + } + } + suggestions.push(...fields.keys()); + return suggestions; + } catch (e) { + logger.debug(`An error occurred while trying to extract fields from index: ${indexName}` + e); + } + } + return []; + } + + + static extractFieldsFromCollection(bucketCache: IBucketCache, scopeName: string, collectionName: string): any { + const scope = bucketCache.scopes.get(scopeName); + if (scope) { + const collection = scope.collections.get(collectionName); + return collection?.schema?.patterns + } + return + } +} + + diff --git a/src/commands/fts/SearchWorkbench/contributor/geometryCbsContributor.ts b/src/commands/fts/SearchWorkbench/contributor/geometryCbsContributor.ts new file mode 100644 index 00000000..fc77fa7b --- /dev/null +++ b/src/commands/fts/SearchWorkbench/contributor/geometryCbsContributor.ts @@ -0,0 +1,24 @@ +import { Node } from 'jsonc-parser' +import { CBSContributor } from './autoComplete' +import * as vscode from 'vscode'; + +export class geometryCbsContributor implements CBSContributor { + public static keys: string[] = ["shape", "relation"]; + + accept(key: string | null): boolean { + return key === "geometry"; + } + + contributeKey(parentKey: string, node: Node, suggestion: string[], result: vscode.CompletionItem[], existingKeys: string[]) { + suggestion.push(...geometryCbsContributor.keys) + + } + + contributeValue(attributeKey: string, node: Node, suggestion: string[], fields:string[]) { + if (attributeKey == "relation") { + suggestion.push("intersects", "contains", "within") + } + + } + +} \ No newline at end of file diff --git a/src/commands/fts/SearchWorkbench/contributor/highlightCbsContributor.ts b/src/commands/fts/SearchWorkbench/contributor/highlightCbsContributor.ts new file mode 100644 index 00000000..8b10f23f --- /dev/null +++ b/src/commands/fts/SearchWorkbench/contributor/highlightCbsContributor.ts @@ -0,0 +1,24 @@ +import { Node } from 'jsonc-parser' +import { CBSContributor } from './autoComplete' +import * as vscode from 'vscode'; + +export class highlightCbsContributor implements CBSContributor { + public static keys: string[] = ["style", "fields"]; + + accept(key: string | null): boolean { + return key === "highlight"; + } + + contributeKey(parentKey: string, node: Node, suggestion: string[], result: vscode.CompletionItem[], existingKeys: string[]) { + suggestion.push(...highlightCbsContributor.keys) + + } + + contributeValue(attributeKey: string, node: Node, suggestion: string[]) { + if (attributeKey == "style") { + suggestion.push("ansi", "html") + } + + } + +} \ No newline at end of file diff --git a/src/commands/fts/SearchWorkbench/contributor/knnCbsContributor.ts b/src/commands/fts/SearchWorkbench/contributor/knnCbsContributor.ts new file mode 100644 index 00000000..1de87c96 --- /dev/null +++ b/src/commands/fts/SearchWorkbench/contributor/knnCbsContributor.ts @@ -0,0 +1,26 @@ +import { Node } from 'jsonc-parser' +import { CBSContributor } from './autoComplete' +import * as vscode from 'vscode'; +import { cbsTemplate } from './cbsTemplates'; + +export class knnCbsContributor implements CBSContributor { + public static keys: string[] = ["k", "field", "vector", "boost"]; + + accept(key: string | null): boolean { + return key === "knn"; + } + + contributeKey(parentKey: string, node: Node, suggestion: string[], result: vscode.CompletionItem[], existingKeys: string[] ) { + suggestion.push(...knnCbsContributor.keys) + result.push(cbsTemplate.getVectorTemplate(existingKeys)) + + } + + contributeValue(attributeKey: string, node: Node, suggestion: string[], fields:string[]) { + if (attributeKey == "field") { + suggestion.push(...fields); + } + + } + +} \ No newline at end of file diff --git a/src/commands/fts/SearchWorkbench/contributor/locationCbsContributor.ts b/src/commands/fts/SearchWorkbench/contributor/locationCbsContributor.ts new file mode 100644 index 00000000..e4f650bc --- /dev/null +++ b/src/commands/fts/SearchWorkbench/contributor/locationCbsContributor.ts @@ -0,0 +1,21 @@ +import { Node } from 'jsonc-parser' +import { CBSContributor } from './autoComplete' +import * as vscode from 'vscode'; + +export class locationCbsContributor implements CBSContributor { + public static keys: string[] = ["lat", "lon"]; + + accept(key: string | null): boolean { + return key === "location" || key === "top_left" || key === "bottom_right"; + } + + contributeKey(parentKey: string, node: Node, suggestion: string[], result: vscode.CompletionItem[], existingKeys: string[]) { + suggestion.push(...locationCbsContributor.keys) + + } + + contributeValue(attributeKey: string, node: Node, suggestion: string[], fields: string[]) { + + } + +} \ No newline at end of file diff --git a/src/commands/fts/SearchWorkbench/contributor/queryCbsContributor.ts b/src/commands/fts/SearchWorkbench/contributor/queryCbsContributor.ts new file mode 100644 index 00000000..e70e1a2e --- /dev/null +++ b/src/commands/fts/SearchWorkbench/contributor/queryCbsContributor.ts @@ -0,0 +1,253 @@ +import { Node } from "jsonc-parser"; +import { CompletionItem } from "vscode"; +import { CBSContributor } from "./autoComplete"; +import { cbsTemplate } from "./cbsTemplates"; +import { cbsTemplateDef } from "./cbsTemplateDef"; +import * as vscode from 'vscode'; + +export class queryCbsContributor implements CBSContributor { + + public static allQueryKeys: Set = new Set(); + private boolQueries = ["must", "must_not", "should"]; + private compound = ["disjuncts", "conjuncts"]; + private query = ["boost", "conjuncts"]; + private match = ["match", "analyzer", "operator", "boost", "fuzziness", "prefix_length", "field"]; + private matchPhrase = ["match_phrase", "analyzer", "operator", "boost", "fuzziness", "prefix_length", "field"]; + private bool = ["bool", "boost", "field"]; + private prefix = ["prefix", "boost", "field"]; + private regexp = ["regexp", "boost", "field"]; + private terms = ["terms", "boost", "field"]; + private cidr = ["cidr", "boost", "field"]; + private wildcard = ["wildcard", "boost", "field"]; + private term = ["term", "boost", "field", "fuzziness"]; + private polygon = ["polygon_points", "boost", "field"]; + private numeric = ["min", "max", "inclusive_min", "inclusive_max", "field", "boost"]; + private date = ["start", "end", "inclusive_start", "inclusive_end", "field", "boost"]; + private radius = ["location", "distance", "field", "boost"]; + private rectangle = ["top_left", "bottom_right", "field", "boost"]; + private geometry = ["geometry", "field", "boost"]; + private special = ["match_all", "match_none"]; + + + constructor() { + this.addAllKeys(); + } + + private addAllKeys(): void { + + ["query", + ...this.boolQueries, + ...this.compound, + ...this.query, + ...this.match, + ...this.matchPhrase, + ...this.bool, + ...this.prefix, + ...this.regexp, + ...this.terms, + ...this.cidr, + ...this.wildcard, + ...this.term, + ...this.polygon, + ...this.numeric, + ...this.date, + ...this.radius, + ...this.rectangle, + ...this.geometry, + ...this.special].forEach(key => { + queryCbsContributor.allQueryKeys.add(key); + }); + } + + accept(key: string | null): boolean { + return key === "query" || key === "disjuncts" || key === "conjuncts"; + } + + contributeKey(parentKey: string | null, node: Node, suggestion: string[], result: CompletionItem[], existingKeys: string[]) { + + if (existingKeys.length === 0) { + queryCbsContributor.allQueryKeys.forEach(key => suggestion.push(key)); + } + + if (this.boolQueries.some(query => existingKeys.includes(query))) { + this.boolQueries.filter(query => !existingKeys.includes(query)).forEach(query => { + suggestion.push(query); + }); + this.addBooleanTemplates(existingKeys, result); + } else if (!existingKeys.includes("query") && !this.compound.some(comp => existingKeys.includes(comp))) { + + if (!existingKeys.includes("field")) { + suggestion.push("field"); + } + + if (existingKeys.length === 0) { + result.push(cbsTemplate.getQueryTemplate(existingKeys)); + suggestion.push("query"); + this.addBooleanTemplates(existingKeys, result); + result.push(cbsTemplate.getConjunctsTemplate(existingKeys)); + result.push(cbsTemplate.getDisjunctsTemplate(existingKeys)); + result.push(cbsTemplate.getEmptyTemplate("match_all", "match_all template")) + result.push(cbsTemplate.getEmptyTemplate("match_none", "match_all template")) + } + + const boolContributors = this.getBoolContributors(existingKeys, result); + const cidrContributors = this.getCidrContributors(existingKeys, result); + const prefixContributors = this.getPrefixContributors(existingKeys, result) + const regexexpContributors = this.getRegexpContributors(existingKeys, result) + const termContributors = this.getTermContributors(existingKeys, result) + const termsContributors = this.getTermsContributors(existingKeys, result) + const rectangleContributors = this.getRectangleContributors(existingKeys, result) + const polygonContributors = this.getPolygonContributors(existingKeys, result) + const radiusContributors = this.getRadiusContributors(existingKeys, result) + const wildCardContributors = this.getWildCardContributors(existingKeys, result) + const numericContributors = this.getNumericContributors(existingKeys, result) + const dateContributors = this.getDateContributors(existingKeys, result) + const matchQuery = this.getMatchContributors(existingKeys, result) + const matchPhraseQuery = this.getMatchPhraseContributors(existingKeys, result) + this.addGeometryContributors(existingKeys, result) + const allContributors = [...boolContributors, ...cidrContributors, ...prefixContributors, ...regexexpContributors, ...termContributors, ...termsContributors, ...rectangleContributors, ...polygonContributors, ...radiusContributors, ...wildCardContributors, ...numericContributors, ...dateContributors, ...matchQuery, ...matchPhraseQuery]; + + allContributors.forEach(contributor => { + if (!suggestion.includes(contributor)) { + suggestion.push(contributor); + } + }); + + + } + } + + addBooleanTemplates(existingKeys: string[], result: CompletionItem[]) { + if (!existingKeys.includes("must")) { + result.push(cbsTemplate.getMustTemplate()) + } + if (!existingKeys.includes("must_not")) { + result.push(cbsTemplate.getMustNotTemplate()) + } + if (!existingKeys.includes("should")) { + result.push(cbsTemplate.getShouldTemplate()) + } + + } + + addGeometryContributors(existingKeys: string[], result: CompletionItem[]) { + if (existingKeys.every(key => this.geometry.includes(key))) { + result.push(cbsTemplate.getGeoTemplate("point_geo_query", "Point GeoJSON Query", "Point", existingKeys)) + result.push(cbsTemplate.getGeoTemplate("linestring_geo_query", "LineString GeoJSON Query", "Point", existingKeys)) + result.push(cbsTemplate.getGeoTemplate("polygon_geo_query", "Polygon GeoJSON Query", "Polygon", existingKeys)) + result.push(cbsTemplate.getGeoTemplate("multi_point_geo_query", "MultiPoint GeoJSON Query", "MultiPoint", existingKeys)) + result.push(cbsTemplate.getGeoTemplate("multi_linestring_geo_query", "MultiLineString GeoJSON Query", "MultiLineString", existingKeys)) + result.push(cbsTemplate.getGeoTemplate("multi_polygon_geo_query", "MultiPolygon GeoJSON Query", "MultiPolygon", existingKeys)) + result.push(cbsTemplate.getGeoTemplate("envelope_geo_query", "Envelope GeoJSON Query", "Envelope", existingKeys)) + result.push(cbsTemplate.getGeoTemplate("circle_geo_query", "Circle GeoJSON Query", "Circle", existingKeys)) + result.push(cbsTemplate.getGeoTemplate("geometry_col_geo_query", "Geometry Collection GeoJSON Query", "GeometryCollection", existingKeys)) + } + } + + getPolygonContributors(existingKeys: string[], result: CompletionItem[]): string[] { + const template = this.getSingleTemplate("polygon_points_query", "Polygon Based Geopoint queries", this.polygon); + return this.genericContributor(this.polygon, existingKeys, result, [template]); + } + + getRectangleContributors(existingKeys: string[], result: CompletionItem[]): string[] { + if (existingKeys.every(key => this.rectangle.includes(key))) { + result.push(cbsTemplate.getRectangleTemplate(existingKeys)) + } + return this.genericContributor(this.rectangle, existingKeys, result, []) + } + + getRadiusContributors(existingKeys: string[], result: CompletionItem[]): string[] { + if (existingKeys.every(key => this.radius.includes(key))) { + result.push(cbsTemplate.getRadiusTemplate(existingKeys)) + } + return this.genericContributor(this.radius, existingKeys, result, []) + } + + getBoolContributors(existingKeys: string[], result: CompletionItem[]): string[] { + const template = this.getSingleTemplate("bool_query", "Boolean query", this.bool); + return this.genericContributor(this.bool, existingKeys, result, [template]); + } + + getCidrContributors(existingKeys: string[], result: CompletionItem[]): string[] { + const template = this.getSingleTemplate("cidr_query", "CIDR query", this.cidr); + return this.genericContributor(this.cidr, existingKeys, result, [template]); + } + + + getPrefixContributors(existingKeys: string[], result: CompletionItem[]): string[] { + const template = this.getSingleTemplate("prefix_query", "Prefix query", this.prefix); + return this.genericContributor(this.prefix, existingKeys, result, [template]); + } + + getRegexpContributors(existingKeys: string[], result: CompletionItem[]): string[] { + const template = this.getSingleTemplate("regex_query", "Regex query", this.regexp); + return this.genericContributor(this.regexp, existingKeys, result, [template]); + } + + getTermContributors(existingKeys: string[], result: CompletionItem[]): string[] { + const template = this.getSingleTemplate("term_query", "Term query", this.term); + return this.genericContributor(this.term, existingKeys, result, [template]); + } + + getTermsContributors(existingKeys: string[], result: CompletionItem[]): string[] { + const template = this.getSingleTemplate("terms_query", "Terms query", this.terms); + return this.genericContributor(this.terms, existingKeys, result, [template]); + } + + getWildCardContributors(existingKeys: string[], result: CompletionItem[]): string[] { + const template = this.getSingleTemplate("wildcard_query", "Wildcard query", this.wildcard); + return this.genericContributor(this.wildcard, existingKeys, result, [template]); + } + + getNumericContributors(existingKeys: string[], result: CompletionItem[]): string[] { + const numericRangeTemplate = this.getSingleTemplate("numeric_range", "Simple numeric range search", ["field", "min", "max"]); + const numericRangeAllTemplate = this.getSingleTemplate("numeric_range_all", "Data numeric search with all attributes", this.numeric) + return this.genericContributor(this.numeric, existingKeys, result, [numericRangeTemplate, numericRangeAllTemplate]); + } + + getDateContributors(existingKeys: string[], result: CompletionItem[]): string[] { + const dateRangeTemplate = this.getSingleTemplate("date_range", "Simple data range search", ["field", "start", "end"]); + const dateRangeAllTemplate = this.getSingleTemplate("date_range_all", "Data range search with all attributes", this.date) + return this.genericContributor(this.date, existingKeys, result, [dateRangeTemplate, dateRangeAllTemplate]); + } + + getMatchContributors(existingKeys: string[], result: CompletionItem[]): string[] { + const matchQueryTemplate = this.getSingleTemplate("match_query", "Simple match query search", ["field", "match"]); + const matchQueryAllTemplate = this.getSingleTemplate("match_query_all", "Match query search with all attributes", this.match) + return this.genericContributor(this.match, existingKeys, result, [matchQueryTemplate, matchQueryAllTemplate]); + } + + getMatchPhraseContributors(existingKeys: string[], result: CompletionItem[]): string[] { + const matchPhraseQueryTemplate = this.getSingleTemplate("match_phrase_query", "Simple match phrase query search", ["field", "match_phrase"]); + const matchPhraseQueryAllTemplate = this.getSingleTemplate("match_phrase_query_all", "Match phrase query search with all attributes", this.matchPhrase) + return this.genericContributor(this.matchPhrase, existingKeys, result, [matchPhraseQueryTemplate, matchPhraseQueryAllTemplate]); + } + + genericContributor(keys: string[], existingKeys: string[], result: vscode.CompletionItem[], templateDefs: cbsTemplateDef[]): string[] { + if (existingKeys.every(key => keys.includes(key))) { + templateDefs.forEach(def => { + def.attrs = def.attrs.filter(attr => !existingKeys.includes(attr) && attr !== 'boost'); + result.push(cbsTemplate.createGenericTemplate(def.key, def.desc, def.attrs)) + }); + return keys; + } else { + return []; + } + } + + private getSingleTemplate(key: string, desc: string, fields: string[]): cbsTemplateDef { + return new cbsTemplateDef(key, desc, fields); + } + + contributeValue(attributeKey: string | null, node: Node, suggestion: string[], fields: string[]) { + + if (attributeKey == "operator") { + suggestion.push("or", "and"); + } + else if (attributeKey == "field") { + suggestion.push(...fields); + } + + } + +} \ No newline at end of file diff --git a/src/commands/fts/SearchWorkbench/contributor/shapeCbsContributor.ts b/src/commands/fts/SearchWorkbench/contributor/shapeCbsContributor.ts new file mode 100644 index 00000000..52b2615d --- /dev/null +++ b/src/commands/fts/SearchWorkbench/contributor/shapeCbsContributor.ts @@ -0,0 +1,76 @@ +import { Node } from "jsonc-parser"; +import { CompletionItem } from "vscode"; +import { CBSContributor } from "./autoComplete"; + +export class shapeCbsContributor implements CBSContributor { + + accept(key: string | null): boolean { + return key === "shape" + } + + contributeKey(parentKey: string | null, node: Node, suggestion: string[], result: CompletionItem[], existingKeys: string[]) { + let type: string = ""; + if (node.type === 'string') { + if (node.parent && node.parent.parent) { + node = node.parent.parent + } + } + if (!node.children) { + return + } + for (const propertyNode of node.children) { + if (propertyNode.type === 'property' && propertyNode.children) { + let keyNode = null; + let valueNode = null; + + for (const childNode of propertyNode.children) { + if (childNode.type === 'string' && childNode.value === 'type') { + keyNode = childNode; + } else if (childNode.type === 'string') { + valueNode = childNode; + } + + if (keyNode && valueNode) { + type = valueNode.value; + } + } + } + } + + if (type === "Circle") { + suggestion.push("coordinates") + suggestion.push("type") + suggestion.push("radius") + } else if (type === "GeometryCollection") { + suggestion.push("type") + suggestion.push("geometries") + } else if (type === "") { + suggestion.push("coordinates") + suggestion.push("type") + suggestion.push("radius") + suggestion.push("geometries") + } else { + suggestion.push("coordinates") + suggestion.push("type") + } + + + } + + contributeValue(attributeKey: string | null, node: Node, suggestion: string[], fields: string[]) { + if (attributeKey === "type") { + suggestion.push("Point"); + suggestion.push("LineString"); + suggestion.push("Polygon"); + suggestion.push("MultiPoint"); + suggestion.push("MultiLineString"); + suggestion.push("MultiPolygon"); + suggestion.push("GeometryCollection"); + suggestion.push("Circle"); + suggestion.push("Envelope"); + } + + } + + +} \ No newline at end of file diff --git a/src/commands/fts/SearchWorkbench/documentation/documentationProvider.ts b/src/commands/fts/SearchWorkbench/documentation/documentationProvider.ts new file mode 100644 index 00000000..c1db1a33 --- /dev/null +++ b/src/commands/fts/SearchWorkbench/documentation/documentationProvider.ts @@ -0,0 +1,279 @@ +import * as vscode from 'vscode'; +import * as jsonc from 'jsonc-parser'; +import * as fs from 'fs'; +import * as path from 'path'; +import { logger } from '../../../../logger/logger'; + + + +export class CbsJsonHoverProvider implements vscode.HoverProvider { + private context: vscode.ExtensionContext; + + constructor(context: vscode.ExtensionContext) { + this.context = context; + } + + provideHover(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): vscode.ProviderResult { + if (!this.isCbsJsonFile(document)) { + return null; + } + + const offset = document.offsetAt(position); + const text = document.getText(); + const rootNode = jsonc.parseTree(text); + if (!rootNode){ + return + } + let node = jsonc.findNodeAtOffset(rootNode, offset); + node = node?.parent + + if (node && node.type === 'property' && node.children && node.children[0].type === 'string') { + + const key = node.children[0].value; + const parentNode = jsonc.findNodeAtOffset(rootNode, node.parent!.offset); + const type = this.getParentType(parentNode); + + const documentation = this.getDocumentationForKey(key, type); + if (documentation) { + return new vscode.Hover(documentation); + } + } + + return null; + } + + private isCbsJsonFile(document: vscode.TextDocument): boolean { + return document.fileName.endsWith('.cbs.json'); + } + + private getParentType(node: jsonc.Node | undefined): string | null { + if (!node || !node.parent) return null; + if (node.parent.type === 'property') { + return node.parent.children![0].value; + } + return null; + } + + + private getDocumentationForKey(key: string, type: string | null): vscode.MarkdownString | null { + let filePath: string; + + switch (key) { + case "query": + filePath = type === null ? "/docs/search/query.md" : "/docs/search/query_string.md"; + break; + case "must": + filePath = "/docs/search/must.md"; + break; + case "must_not": + filePath = "/docs/search/must_not.md"; + break; + case "should": + filePath = "/docs/search/should.md"; + break; + case "conjuncts": + filePath = "/docs/search/conjuncts.md"; + break; + case "disjuncts": + filePath = "/docs/search/disjuncts.md"; + break; + case "match": + filePath = "/docs/search/match.md"; + break; + case "match_phrase": + filePath = "/docs/search/match_phrase.md"; + break; + case "bool": + filePath = "/docs/search/bool.md"; + break; + case "prefix": + filePath = "/docs/search/prefix.md"; + break; + case "regexp": + filePath = "/docs/search/regexp.md"; + break; + case "term": + filePath = "/docs/search/term.md"; + break; + case "terms": + filePath = "/docs/search/terms.md"; + break; + case "wildcard": + filePath = "/docs/search/wildcard.md"; + break; + case "min": + filePath = "/docs/search/min.md"; + break; + case "max": + filePath = "/docs/search/max.md"; + break; + case "inclusive_max": + filePath = "/docs/search/inclusive_max.md"; + break; + case "inclusive_min": + filePath = "/docs/search/inclusive_min.md"; + break; + case "start": + filePath = "/docs/search/start.md"; + break; + case "end": + filePath = "/docs/search/end.md"; + break; + case "inclusive_start": + filePath = "/docs/search/inclusive_start.md"; + break; + case "inclusive_end": + filePath = "/docs/search/inclusive_end.md"; + break; + case "cidr": + filePath = "/docs/search/cidr.md"; + break; + case "knn": + filePath = "/docs/search/knn.md"; + break; + case "k": + filePath = "/docs/search/k.md"; + break; + case "vector": + filePath = "/docs/search/vector.md"; + break; + case "distance": + filePath = "/docs/search/distance.md"; + break; + case "location": + filePath = "/docs/search/location.md"; + break; + case "lat": + filePath = "/docs/search/lat.md"; + break; + case "lon": + filePath = "/docs/search/lon.md"; + break; + case "top_left": + filePath = "/docs/search/top_left.md"; + break; + case "bottom_right": + filePath = "/docs/search/bottom_right.md"; + break; + case "polygon_points": + filePath = "/docs/search/polygon_points.md"; + break; + case "geometry": + filePath = "/docs/search/geometry.md"; + break; + case "shape": + filePath = "/docs/search/shape.md"; + break; + case "type": + filePath = type === "shape" ? "/docs/search/type_shape.md" : "/docs/search/type_facet.md"; + break; + case "coordinates": + filePath = "/docs/search/coordinates.md"; + break; + case "relation": + filePath = "/docs/search/relation.md"; + break; + case "geometries": + filePath = "/docs/search/geometries.md"; + break; + case "radius": + filePath = "/docs/search/radius.md"; + break; + case "match_all": + filePath = "/docs/search/match_all.md"; + break; + case "match_none": + filePath = "/docs/search/match_none.md"; + break; + case "analyzer": + filePath = "/docs/search/analyzer.md"; + break; + case "boost": + filePath = "/docs/search/boost.md"; + break; + case "field": + filePath = "/docs/search/field.md"; + break; + case "fuzziness": + filePath = "/docs/search/fuzziness.md"; + break; + case "operator": + filePath = "/docs/search/operator.md"; + break; + case "prefix_length": + filePath = "/docs/search/prefix_length.md"; + break; + case "size": + case "limit": + filePath = "/docs/search/limit.md"; + break; + case "from": + case "offset": + filePath = "/docs/search/offset.md"; + break; + case "fields": + filePath = "/docs/search/fields.md"; + break; + case "facets": + filePath = "/docs/search/facets.md"; + break; + case "explain": + filePath = "/docs/search/explain.md"; + break; + case "sort": + filePath = "/docs/search/sort.md"; + break; + case "includeLocations": + filePath = "/docs/search/includeLocations.md"; + break; + case "score": + filePath = "/docs/search/score.md"; + break; + case "search_after": + filePath = "/docs/search/search_after.md"; + break; + case "search_before": + filePath = "/docs/search/search_before.md"; + break; + case "collections": + filePath = "/docs/search/collections.md"; + break; + case "ctl": + filePath = "/docs/search/ctl.md"; + break; + case "timeout": + filePath = "/docs/search/timeout.md"; + break; + case "consistency": + filePath = "/docs/search/consistency.md"; + break; + case "vectors": + filePath = "/docs/search/vectors.md"; + break; + case "level": + filePath = "/docs/search/level.md"; + break; + case "results": + filePath = "/docs/search/results.md"; + break; + case "highlight": + filePath = "/docs/search/highlight.md"; + break; + case "style": + filePath = "/docs/search/style.md"; + break; + default: + return new vscode.MarkdownString("No documentation available for this key."); + } + try { + const fullPath = path.join(this.context.extensionPath, filePath); + const content = fs.readFileSync(fullPath, 'utf8'); + return new vscode.MarkdownString(content); + } catch (error) { + logger.error(`Error reading documentation file: ${error}`); + // Return empty for no documentation + return new vscode.MarkdownString(""); + } + } + +} \ No newline at end of file diff --git a/src/commands/fts/SearchWorkbench/indexParser/indexParser.ts b/src/commands/fts/SearchWorkbench/indexParser/indexParser.ts new file mode 100644 index 00000000..f901c91d --- /dev/null +++ b/src/commands/fts/SearchWorkbench/indexParser/indexParser.ts @@ -0,0 +1,62 @@ +export class SearchIndexParser { + static extractPropertiesMap(index: any): Map { + const rootNode = index; + const propertiesMap = new Map(); + const typesNode = rootNode?.params?.mapping?.types; + + if (typesNode && typeof typesNode === 'object') { + for (const [_, typeValue] of Object.entries(typesNode)) { + if (typeValue && typeof typeValue === 'object' && 'properties' in typeValue) { + const propertiesNode = (typeValue as any).properties; + this.extractProperties(propertiesNode, '', propertiesMap); + } + } + } + return propertiesMap; + } + + private static extractProperties(node: any, parentKey: string, propertiesMap: Map) { + if (node && typeof node === 'object') { + for (const [key, value] of Object.entries(node)) { + if (typeof value === 'object' && value) { + if ('properties' in value) { + const newParentKey = parentKey ? `${parentKey}.${key}` : key; + this.extractProperties(value.properties, newParentKey, propertiesMap); + } else if ('fields' in value) { + for (const fieldNode of (value.fields as any[])) { + const type = fieldNode.type?.toString() || ''; + const fieldName = fieldNode.name?.toString() || key; + const finalKey = parentKey ? `${parentKey}.${fieldName}` : fieldName; + propertiesMap.set(finalKey, type); + } + } else if ('type' in value) { + const type = value.type?.toString() || ''; + const finalKey = parentKey ? `${parentKey}.${key}` : key; + propertiesMap.set(finalKey, type); + } + } + } + } + } + + static isIndexDynamic(index: any): boolean { + const rootNode = index; + return rootNode?.params?.mapping?.index_dynamic || false; + } + + static isCollectionDynamicallyIndexed(index: any, collection: string): boolean { + const rootNode = index; + return rootNode?.params?.mapping?.types?.[collection]?.dynamic || false; + } + + static getDefaultField(index: any): string { + const rootNode = index; + return rootNode?.params?.mapping?.default_field || ''; + } + + static listCollections(index: any): string[] { + const rootNode = index; + const typesNode = rootNode?.params?.mapping?.types; + return typesNode ? Object.keys(typesNode) : []; + } +} \ No newline at end of file diff --git a/src/commands/fts/SearchWorkbench/openSearchIndex.ts b/src/commands/fts/SearchWorkbench/openSearchIndex.ts index 37c042ab..546ca4da 100644 --- a/src/commands/fts/SearchWorkbench/openSearchIndex.ts +++ b/src/commands/fts/SearchWorkbench/openSearchIndex.ts @@ -33,6 +33,7 @@ export const openSearchIndex = async (searchIndexNode: SearchIndexNode, clusterC { create: true, overwrite: true } ); } catch (error) { + logger.error("Failed to open Index definition, as it is not a valid JSON"); vscode.window.showInformationMessage("Unable to open Index definition: It is not a valid JSON ", { modal: true }); return false; } diff --git a/src/commands/fts/SearchWorkbench/searchWorkbench.ts b/src/commands/fts/SearchWorkbench/searchWorkbench.ts index 18506303..66d4b214 100644 --- a/src/commands/fts/SearchWorkbench/searchWorkbench.ts +++ b/src/commands/fts/SearchWorkbench/searchWorkbench.ts @@ -1,6 +1,5 @@ import * as vscode from 'vscode'; import { getActiveConnection } from '../../../util/connections'; -import UntitledSqlppDocumentService from './controller'; import { WorkbenchWebviewProvider } from '../../../workbench/workbenchWebviewProvider'; import { CouchbaseError, QueryOptions, QueryProfileMode, QueryStatus } from "couchbase"; import { ISearchQueryContext } from '../../../types/ISearchQueryContext'; @@ -8,6 +7,7 @@ import { CouchbaseRestAPI } from '../../../util/apis/CouchbaseRestAPI'; import { MemFS } from "../../../util/fileSystemProvider"; import UntitledSearchJsonDocumentService from './controller'; import SearchIndexNode from '../../../model/SearchIndexNode'; +import { logger } from '../../../logger/logger'; export class SearchWorkbench { private _untitledSearchJsonDocumentService: UntitledSearchJsonDocumentService; @@ -33,7 +33,7 @@ export class SearchWorkbench { // Get the active text editor const activeTextEditor = vscode.window.activeTextEditor; - if (activeTextEditor && activeTextEditor.document.languageId === "searchQuery") { + if (activeTextEditor && activeTextEditor.document.languageId === "json" && activeTextEditor.document.fileName.endsWith(".cbs.json")) { activeTextEditor.document.save(); const indexQueryPayload = activeTextEditor.selection.isEmpty ? activeTextEditor.document.getText() : activeTextEditor.document.getText(activeTextEditor.selection); @@ -48,10 +48,11 @@ export class SearchWorkbench { const explainPlan = JSON.stringify(""); const couchbbaseRestAPI = new CouchbaseRestAPI(connection); const searchQueryResult = await couchbbaseRestAPI.runSearchIndexes(queryContext?.indexName, indexQueryPayload); - workbenchWebviewProvider.setSearchQueryResult( + workbenchWebviewProvider.setQueryResult( JSON.stringify(searchQueryResult?.hits), {}, - explainPlan + explainPlan, + true ); } catch (err) { const errorArray = []; @@ -85,7 +86,8 @@ export class SearchWorkbench { workbenchWebviewProvider.setQueryResult( JSON.stringify(errorArray), queryStatusProps, - null + null, + true ); } @@ -96,7 +98,7 @@ export class SearchWorkbench { try { return this._untitledSearchJsonDocumentService.newQuery(searchIndexNode, memFs); } catch (error) { - console.log("Error in openSearchWorkbench:", error); + logger.error("Error while opening Search WorkBench:" + error); throw error; } } diff --git a/src/commands/fts/SearchWorkbench/test/queryTypeObject.test.ts b/src/commands/fts/SearchWorkbench/test/queryTypeObject.test.ts index e27946ba..59e90c74 100644 --- a/src/commands/fts/SearchWorkbench/test/queryTypeObject.test.ts +++ b/src/commands/fts/SearchWorkbench/test/queryTypeObject.test.ts @@ -194,7 +194,7 @@ describe("Query Type Object Tests", () => { await getDiagnosticsForJson(json); const uri = vscode.Uri.parse('untitled:test.json'); const diagnostics = diagnosticsCollection.get(uri) ?? []; - expect(diagnostics.some(diagnostic => diagnostic.message.includes(ValidationHelper.getUnexpectedAttributeMessageForQuery("min", "match")))).toBeTruthy(); + expect(diagnostics.some(diagnostic => diagnostic.message.includes(ValidationHelper.getUnexpectedAttributeMessageForQuery("match", "numeric range")))).toBeTruthy(); }); test("Valid Match Phrase", async () => { diff --git a/src/commands/fts/SearchWorkbench/validators/geometryObjectValidator.ts b/src/commands/fts/SearchWorkbench/validators/geometryObjectValidator.ts index eecf6e4c..397af1ee 100644 --- a/src/commands/fts/SearchWorkbench/validators/geometryObjectValidator.ts +++ b/src/commands/fts/SearchWorkbench/validators/geometryObjectValidator.ts @@ -49,22 +49,30 @@ export class GeometryObjectValidator implements SearchObjectValidator { private validateRelation(propertyValue: any, property: JsonProperty, diagnosticsList: vscode.Diagnostic[], document: vscode.TextDocument): void { if (!["intersects", "contains", "within"].includes(propertyValue.value)) { const positionMap = ValidationHelper.getPositionMap(document); - diagnosticsList.push(new vscode.Diagnostic( + const newDiagnostic = new vscode.Diagnostic( positionMap.get("relation") || new vscode.Range(0, 0, 0, 1), ValidationHelper.getRelationErrorMessage(), vscode.DiagnosticSeverity.Error - )); + ); + + if (!ValidationHelper.diagnosticExists(diagnosticsList, newDiagnostic)) { + diagnosticsList.push(newDiagnostic); + } } } - private checkMissingFields(requiredFields: string[], currentAttributes: string[], diagnosticsList: vscode.Diagnostic[], document: vscode.TextDocument,positionMap:any): void { + private checkMissingFields(requiredFields: string[], currentAttributes: string[], diagnosticsList: vscode.Diagnostic[], document: vscode.TextDocument, positionMap: any): void { requiredFields.forEach(field => { if (!currentAttributes.includes(field)) { - diagnosticsList.push(new vscode.Diagnostic( + const newDiagnostic = new vscode.Diagnostic( positionMap.get("geometry") || new vscode.Range(0, 0, 0, 1), ValidationHelper.missingRequiredAttributeQuery(field, "geometry"), vscode.DiagnosticSeverity.Error - )); + ); + + if (!ValidationHelper.diagnosticExists(diagnosticsList, newDiagnostic)) { + diagnosticsList.push(newDiagnostic); + } } }); } diff --git a/src/commands/fts/SearchWorkbench/validators/queryTypeObjectValidator.ts b/src/commands/fts/SearchWorkbench/validators/queryTypeObjectValidator.ts index a003a4ef..bf655995 100644 --- a/src/commands/fts/SearchWorkbench/validators/queryTypeObjectValidator.ts +++ b/src/commands/fts/SearchWorkbench/validators/queryTypeObjectValidator.ts @@ -23,29 +23,40 @@ export class QueryTypeObjectValidator implements SearchObjectValidator { const isCompound = this.validateCompound(jsonObject, properties, diagnosticsList, document); if (!containsMatchAllNone && !isCompound && !isBooleanQuery && !properties.includes("geometry")) { + let newDiagnostic: vscode.Diagnostic; + if (isFieldMissing && !containsQuery) { - diagnosticsList.push(new vscode.Diagnostic( + newDiagnostic = new vscode.Diagnostic( ValidationHelper.getPositionMap(document).get(key) || new vscode.Range(0, 0, 0, 1), QueryTypeObjectValidator.getMissingFieldOrQueryMessage(), vscode.DiagnosticSeverity.Error - )); + ); + if (!ValidationHelper.diagnosticExists(diagnosticsList, newDiagnostic)) { + diagnosticsList.push(newDiagnostic); + } } else if (!isFieldMissing && !containsQuery) { if (jsonObject.children.length === 1) { - diagnosticsList.push(new vscode.Diagnostic( + newDiagnostic = new vscode.Diagnostic( ValidationHelper.getPositionMap(document).get(key) || new vscode.Range(0, 0, 0, 1), QueryTypeObjectValidator.getMissingFieldOperationMessage(), vscode.DiagnosticSeverity.Error - )); + ); + if (!ValidationHelper.diagnosticExists(diagnosticsList, newDiagnostic)) { + diagnosticsList.push(newDiagnostic); + } } else { this.validateQueryType(jsonObject, diagnosticsList, document); } } else { if (jsonObject.children.length > 1) { - diagnosticsList.push(new vscode.Diagnostic( + newDiagnostic = new vscode.Diagnostic( ValidationHelper.getPositionMap(document).get(key) || new vscode.Range(0, 0, 0, 1), QueryTypeObjectValidator.getInvalidFieldWithQueryMessage(), vscode.DiagnosticSeverity.Error - )); + ); + if (!ValidationHelper.diagnosticExists(diagnosticsList, newDiagnostic)) { + diagnosticsList.push(newDiagnostic); + } } } } @@ -62,11 +73,15 @@ export class QueryTypeObjectValidator implements SearchObjectValidator { if (hasCompound) { jsonObject.children.forEach(child => { if (!(child instanceof JsonProperty) || !allowedCompoundAttrs.includes((child as JsonProperty).key)) { - diagnosticsList.push(new vscode.Diagnostic( + const newDiagnostic = new vscode.Diagnostic( ValidationHelper.getPositionMap(document).get((child as JsonProperty).key) || new vscode.Range(0, 0, 0, 1), QueryTypeObjectValidator.getFieldNotAllowedOnCompound(), vscode.DiagnosticSeverity.Error - )); + ); + + if (!ValidationHelper.diagnosticExists(diagnosticsList, newDiagnostic)) { + diagnosticsList.push(newDiagnostic); + } } }); } @@ -91,15 +106,12 @@ export class QueryTypeObjectValidator implements SearchObjectValidator { } private containsQuery(jsonObject: JsonObject): boolean { - // Check if jsonObject has any children if (!jsonObject.children || jsonObject.children.length === 0) { return false; } for (const child of jsonObject.children) { - // Check if the child is a JsonProperty if (child instanceof JsonProperty) { - // Check if the key of the JsonProperty is "query" if (child.key === "query") { return true; } @@ -110,16 +122,16 @@ export class QueryTypeObjectValidator implements SearchObjectValidator { } private validateQueryType(jsonObject: JsonObject, diagnosticsList: vscode.Diagnostic[], document: vscode.TextDocument): void { - jsonObject.children.forEach(child => { + for (let i = 0; i < jsonObject.children.length; i++) { + const child = jsonObject.children[i]; if (!(child instanceof JsonProperty)) { - return; + continue; } const property = child as JsonProperty; const propertyKey = property.key; - switch (propertyKey) { case "match": this.validateMatch(jsonObject, diagnosticsList, document); @@ -162,11 +174,15 @@ export class QueryTypeObjectValidator implements SearchObjectValidator { this.validateTermRange(jsonObject, diagnosticsList, document); return; } else { - diagnosticsList.push(new vscode.Diagnostic( + const newDiagnostic = new vscode.Diagnostic( ValidationHelper.getPositionMap(document).get(propertyKey) || new vscode.Range(0, 0, 0, 1), QueryTypeObjectValidator.invalidQueryFormatMessage(), vscode.DiagnosticSeverity.Error - )); + ); + + if (!ValidationHelper.diagnosticExists(diagnosticsList, newDiagnostic)) { + diagnosticsList.push(newDiagnostic); + } return; } case "inclusive_start": @@ -188,8 +204,16 @@ export class QueryTypeObjectValidator implements SearchObjectValidator { } - }); - + } + const newDiagnostic = new vscode.Diagnostic( + ValidationHelper.getPositionMap(document).get("query") || new vscode.Range(0, 0, 0, 1), + QueryTypeObjectValidator.invalidQueryFormatMessage(), + vscode.DiagnosticSeverity.Error + ); + + if (!ValidationHelper.diagnosticExists(diagnosticsList, newDiagnostic)) { + diagnosticsList.push(newDiagnostic); + } } @@ -207,11 +231,15 @@ export class QueryTypeObjectValidator implements SearchObjectValidator { currentAttributes.push(propertyKey); if (!allowedFields.includes(propertyKey)) { - diagnosticsList.push(new vscode.Diagnostic( + const newDiagnostic = new vscode.Diagnostic( ValidationHelper.getPositionMap(document).get(propertyKey) || new vscode.Range(0, 0, 0, 1), ValidationHelper.getUnexpectedAttributeMessageForQuery(propertyKey, target), vscode.DiagnosticSeverity.Error - )); + ); + + if (!ValidationHelper.diagnosticExists(diagnosticsList, newDiagnostic)) { + diagnosticsList.push(newDiagnostic); + } } else { counter.set(propertyKey, (counter.get(propertyKey) || 0) + 1); } @@ -221,11 +249,15 @@ export class QueryTypeObjectValidator implements SearchObjectValidator { const missingFields = requiredFields.filter(field => !currentAttributes.includes(field)); if (currentAttributes.length > 0 && missingFields.length > 0) { - diagnosticsList.push(new vscode.Diagnostic( + const newDiagnostic = new vscode.Diagnostic( ValidationHelper.getPositionMap(document).get(target) || new vscode.Range(0, 0, 0, 1), ValidationHelper.missingRequiredAttributeQuery(missingFields.join(", "), target), vscode.DiagnosticSeverity.Error - )); + ); + + if (!ValidationHelper.diagnosticExists(diagnosticsList, newDiagnostic)) { + diagnosticsList.push(newDiagnostic); + } } } @@ -260,11 +292,15 @@ export class QueryTypeObjectValidator implements SearchObjectValidator { validateGenericRange(jsonObject: JsonObject, diagnosticsList: vscode.Diagnostic[], document: vscode.TextDocument): void { const properties = jsonObject.children.map(child => (child as JsonProperty).key); if (!properties.includes("min") && !properties.includes("max")) { - diagnosticsList.push(new vscode.Diagnostic( + const newDiagnostic = new vscode.Diagnostic( ValidationHelper.getPositionMap(document).get("min") || new vscode.Range(0, 0, 0, 1), QueryTypeObjectValidator.minOrMaxRequiredMessage(), vscode.DiagnosticSeverity.Error - )); + ); + + if (!ValidationHelper.diagnosticExists(diagnosticsList, newDiagnostic)) { + diagnosticsList.push(newDiagnostic); + } } } @@ -289,11 +325,15 @@ export class QueryTypeObjectValidator implements SearchObjectValidator { const properties = jsonObject.children.map(child => (child as JsonProperty).key); if (!properties.includes("start") && !properties.includes("end")) { - diagnosticsList.push(new vscode.Diagnostic( + const newDiagnostic = new vscode.Diagnostic( ValidationHelper.getPositionMap(document).get("start") || new vscode.Range(0, 0, 0, 1), QueryTypeObjectValidator.startOrEndRequiredMessage(), vscode.DiagnosticSeverity.Error - )); + ); + + if (!ValidationHelper.diagnosticExists(diagnosticsList, newDiagnostic)) { + diagnosticsList.push(newDiagnostic); + } } } @@ -319,11 +359,15 @@ export class QueryTypeObjectValidator implements SearchObjectValidator { } }); if (matchValue !== null && (matchValue as string).includes(" ") && !isOperatorPresent) { - diagnosticsList.push(new vscode.Diagnostic( + const newDiagnostic = new vscode.Diagnostic( ValidationHelper.getPositionMap(document).get("match") || new vscode.Range(0, 0, 0, 1), QueryTypeObjectValidator.matchWithSpaceMessage(), vscode.DiagnosticSeverity.Error - )); + ); + + if (!ValidationHelper.diagnosticExists(diagnosticsList, newDiagnostic)) { + diagnosticsList.push(newDiagnostic); + } } } @@ -345,11 +389,15 @@ export class QueryTypeObjectValidator implements SearchObjectValidator { private validateOperatorValue(diagnosticsList: vscode.Diagnostic[], property: JsonProperty, document: vscode.TextDocument): void { if (property.value.value !== "or" && property.value.value !== "and") { - diagnosticsList.push(new vscode.Diagnostic( + const newDiagnostic = new vscode.Diagnostic( ValidationHelper.getPositionMap(document).get(property.key) || new vscode.Range(0, 0, 0, 1), QueryTypeObjectValidator.invalidOperatorMessage(), vscode.DiagnosticSeverity.Error - )); + ); + + if (!ValidationHelper.diagnosticExists(diagnosticsList, newDiagnostic)) { + diagnosticsList.push(newDiagnostic); + } } } static matchWithSpaceMessage(): string { diff --git a/src/commands/fts/SearchWorkbench/validators/shapeObjectValidator.ts b/src/commands/fts/SearchWorkbench/validators/shapeObjectValidator.ts index 9b547eb0..84e6a6e7 100644 --- a/src/commands/fts/SearchWorkbench/validators/shapeObjectValidator.ts +++ b/src/commands/fts/SearchWorkbench/validators/shapeObjectValidator.ts @@ -1,6 +1,6 @@ import * as vscode from 'vscode'; import { SearchObjectValidator } from './searchValidator'; -import { JsonArray, JsonObject,JsonProperty } from './JsonNodes'; +import { JsonArray, JsonObject, JsonProperty } from './JsonNodes'; import { ValidationHelper } from './validationHelper'; @@ -11,7 +11,7 @@ export class ShapeObjectValidator implements SearchObjectValidator { validate(jsonObject: JsonObject, diagnosticsList: vscode.Diagnostic[], document: vscode.TextDocument, key: string): void { const target = "shape"; - const requiredFields = ['type']; + let requiredFields = ['type']; const counter: Map = new Map(); const currentAttributes: string[] = []; const positionMap = ValidationHelper.getPositionMap(document); @@ -33,11 +33,15 @@ export class ShapeObjectValidator implements SearchObjectValidator { } if (!["type", "coordinates", "geometries", "radius"].includes(propertyKey)) { - diagnosticsList.push(new vscode.Diagnostic( + const newDiagnostic = new vscode.Diagnostic( positionMap.get(propertyKey) || new vscode.Range(0, 0, 0, 1), `Unexpected attribute '${propertyKey}' for query '${target}'`, vscode.DiagnosticSeverity.Error - )); + ); + + if (!ValidationHelper.diagnosticExists(diagnosticsList, newDiagnostic)) { + diagnosticsList.push(newDiagnostic); + } } else { counter.set(propertyKey, (counter.get(propertyKey) || 0) + 1); @@ -49,14 +53,18 @@ export class ShapeObjectValidator implements SearchObjectValidator { // this.validateMultipleOccurrences(counter, jsonObject, diagnosticsList, positionMap); }); - + requiredFields = requiredFields.filter(item => !currentAttributes.includes(item)); requiredFields.forEach(field => { - if (!currentAttributes.includes(field)) { - diagnosticsList.push(new vscode.Diagnostic( + if (!currentAttributes.includes(field) && currentAttributes.length !== 0 && requiredFields.length !== 0) { + const newDiagnostic = new vscode.Diagnostic( positionMap.get(key) || new vscode.Range(0, 0, 0, 1), ValidationHelper.missingRequiredAttributeQuery(field, key), vscode.DiagnosticSeverity.Error - )); + ); + + if (!ValidationHelper.diagnosticExists(diagnosticsList, newDiagnostic)) { + diagnosticsList.push(newDiagnostic); + } } }); @@ -65,11 +73,13 @@ export class ShapeObjectValidator implements SearchObjectValidator { } else if (typeValue === "GeometryCollection") { this.validateGeometryCollection(currentAttributes, diagnosticsList, positionMap, key); } else { - this.validateCoordinates(typeValue, currentAttributes, coordinates, diagnosticsList, positionMap); + if (typeValue) { + this.validateCoordinates(typeValue, currentAttributes, coordinates, diagnosticsList, positionMap); + } } if (typeValue && coordinates != null && (["LineString", "Polygon", "MultiLineString", "MultiPolygon", "Envelope", "MultiPoint"].includes(typeValue))) { - this.validateCoordinatesStructure(coordinates,typeValue,diagnosticsList,document,key) + this.validateCoordinatesStructure(coordinates, typeValue, diagnosticsList, document, key) } } @@ -79,64 +89,88 @@ export class ShapeObjectValidator implements SearchObjectValidator { "Point", "Circle", "Envelope", "LineString", "MultiPoint", "MultiLineString", "MultiPolygon", "GeometryCollection", "Polygon" ]; - + if (!validTypes.includes(typeValue)) { - diagnosticsList.push(new vscode.Diagnostic( + const newDiagnostic = new vscode.Diagnostic( positionMap.get(property.key) || new vscode.Range(0, 0, 0, 1), `Invalid type '${typeValue}'`, vscode.DiagnosticSeverity.Error - )); + ); + + if (!ValidationHelper.diagnosticExists(diagnosticsList, newDiagnostic)) { + diagnosticsList.push(newDiagnostic); + } } } } - private validateCoordinatesStructure(coordinates: JsonArray, type: string, diagnosticsList: vscode.Diagnostic[], document: vscode.TextDocument, key:string): void { + private validateCoordinatesStructure(coordinates: JsonArray, type: string, diagnosticsList: vscode.Diagnostic[], document: vscode.TextDocument, key: string): void { if (type && coordinates instanceof JsonArray) { - if (!coordinates.children.every(child => child instanceof JsonArray)) { - const positionMap = ValidationHelper.getPositionMap(document); - diagnosticsList.push(new vscode.Diagnostic( - positionMap.get(key) || new vscode.Range(0, 0, 0, 1), - `'${type}' in '${key}' requires 'coordinates' to be an array of arrays.`, - vscode.DiagnosticSeverity.Error - )); + if (!coordinates.children.every(child => child instanceof JsonArray)) { + const positionMap = ValidationHelper.getPositionMap(document); + const newDiagnostic = new vscode.Diagnostic( + positionMap.get(key) || new vscode.Range(0, 0, 0, 1), + `'${type}' in '${key}' requires 'coordinates' to be an array of arrays.`, + vscode.DiagnosticSeverity.Error + ); + + if (!ValidationHelper.diagnosticExists(diagnosticsList, newDiagnostic)) { + diagnosticsList.push(newDiagnostic); + } + } } } - } private validateCircle(currentAttributes: string[], diagnosticsList: vscode.Diagnostic[], positionMap: any, key: string): void { if (!currentAttributes.includes("radius")) { - diagnosticsList.push(new vscode.Diagnostic( + const newDiagnostic = new vscode.Diagnostic( positionMap.get(key) || new vscode.Range(0, 0, 0, 1), ValidationHelper.missingRequiredAttributeQuery("radius", key), vscode.DiagnosticSeverity.Error - )); + ); + + if (!ValidationHelper.diagnosticExists(diagnosticsList, newDiagnostic)) { + diagnosticsList.push(newDiagnostic); + } } if (!currentAttributes.includes("coordinates")) { - diagnosticsList.push(new vscode.Diagnostic( + const newDiagnostic = new vscode.Diagnostic( positionMap.get(key) || new vscode.Range(0, 0, 0, 1), ValidationHelper.missingRequiredAttributeQuery("coordinates", key), vscode.DiagnosticSeverity.Error - )); + ); + + if (!ValidationHelper.diagnosticExists(diagnosticsList, newDiagnostic)) { + diagnosticsList.push(newDiagnostic); + } } } private validateGeometryCollection(currentAttributes: string[], diagnosticsList: vscode.Diagnostic[], positionMap: any, key: string): void { if (!currentAttributes.includes("geometries")) { - diagnosticsList.push(new vscode.Diagnostic( + const newDiagnostic = new vscode.Diagnostic( positionMap.get(key) || new vscode.Range(0, 0, 0, 1), ValidationHelper.missingRequiredAttributeQuery("geometries", key), vscode.DiagnosticSeverity.Error - )); + ); + + if (!ValidationHelper.diagnosticExists(diagnosticsList, newDiagnostic)) { + diagnosticsList.push(newDiagnostic); + } } } private validateCoordinates(typeValue: string | null, currentAttributes: string[], coordinates: JsonProperty | null, diagnosticsList: vscode.Diagnostic[], positionMap: any): void { if (!currentAttributes.includes("coordinates")) { - diagnosticsList.push(new vscode.Diagnostic( + const newDiagnostic = new vscode.Diagnostic( positionMap.get("type") || new vscode.Range(0, 0, 0, 1), ValidationHelper.missingRequiredAttributeQuery("coordinates", "shape"), vscode.DiagnosticSeverity.Error - )); + ); + + if (!ValidationHelper.diagnosticExists(diagnosticsList, newDiagnostic)) { + diagnosticsList.push(newDiagnostic); + } } } diff --git a/src/commands/fts/SearchWorkbench/validators/validationUtil.ts b/src/commands/fts/SearchWorkbench/validators/validationUtil.ts index 55e491d0..fb4fd4df 100644 --- a/src/commands/fts/SearchWorkbench/validators/validationUtil.ts +++ b/src/commands/fts/SearchWorkbench/validators/validationUtil.ts @@ -13,6 +13,7 @@ import { GeometryObjectValidator } from './geometryObjectValidator' import { ShapeObjectValidator } from './shapeObjectValidator' import { JsonObject, JsonArray, JsonProperty, JsonNode } from './JsonNodes'; import { ValidationHelper } from './validationHelper'; +import { logger } from '../../../../logger/logger'; @@ -104,6 +105,7 @@ export function validateDocument(document: vscode.TextDocument | undefined, diag visitJsonObject(jsonObject, diagnosticsList, document); } catch (error) { + logger.error("Invalid Json Error: "+ error) diagnosticsList.push(new vscode.Diagnostic(new vscode.Range(0, 0, 0, 1), `Invalid JSON: ${error}`,vscode.DiagnosticSeverity.Error)); } @@ -229,7 +231,6 @@ function validateProperty(property: JsonProperty, contextKey:string, diagnostics function isTopLevel(property: JsonProperty): boolean { - // Checks if the property's parent is either null or the root JsonObject return !property.parent || property.parent.parent === null; } diff --git a/src/extension.ts b/src/extension.ts index 40eb49e5..50f248fc 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -81,6 +81,8 @@ import SearchIndexNode from "./model/SearchIndexNode"; import { openSearchIndex } from "./commands/fts/SearchWorkbench/openSearchIndex"; import { handleSearchContextStatusbar } from "./handlers/handleSearchQueryContextStatusBar"; import { validateDocument } from "./commands/fts/SearchWorkbench/validators/validationUtil"; +import { AutocompleteVisitor } from "./commands/fts/SearchWorkbench/contributor/autoCompleteVisitor"; +import { CbsJsonHoverProvider } from "./commands/fts/SearchWorkbench/documentation/documentationProvider"; export function activate(context: vscode.ExtensionContext) { Global.setState(context.globalState); @@ -108,11 +110,52 @@ export function activate(context: vscode.ExtensionContext) { context.subscriptions.push(diagnosticCollection); context.subscriptions.push(vscode.workspace.onDidChangeTextDocument(event => { - if (event.document === vscode.window.activeTextEditor?.document && event.document.languageId == "searchQuery") { + if (event.document === vscode.window.activeTextEditor?.document && event.document.languageId == "json" && vscode.window.activeTextEditor?.document.fileName.endsWith(".cbs.json")) { validateDocument(event.document, diagnosticCollection); } })); +const hoverProvider = new CbsJsonHoverProvider(context); +context.subscriptions.push( + vscode.languages.registerHoverProvider({ language: 'json', pattern: '**/*.cbs.json' }, hoverProvider) +); + +const provider = vscode.languages.registerCompletionItemProvider( + { language: 'json', pattern: '**/*.cbs.json' }, + { + async provideCompletionItems(document, position, token, context) { + const autoComplete = new AutocompleteVisitor(); + const suggestions = await autoComplete.getAutoCompleteContributor(document, position, currentSearchWorkbench); + if (suggestions.length === 0) { + return [new vscode.CompletionItem('', vscode.CompletionItemKind.Text)].map(item => { + item.sortText = '\u0000'; + item.preselect = true; + item.keepWhitespace = true; + item.insertText = ''; + item.range = new vscode.Range(position, position); + return item; + }); + } + return suggestions; + } + }, + '\"' +); + + + +context.subscriptions.push(provider); + +const disposable = vscode.window.onDidChangeTextEditorSelection(async (e) => { + if (e.kind === vscode.TextEditorSelectionChangeKind.Command) { + const activeEditor = vscode.window.activeTextEditor; + if (activeEditor && activeEditor.document.fileName.endsWith('.cbs.json')) { + await vscode.commands.executeCommand('editor.action.formatDocument'); + } + } +}); + +context.subscriptions.push(disposable); const subscriptions = context.subscriptions; @@ -208,8 +251,8 @@ context.subscriptions.push(vscode.workspace.onDidChangeTextDocument(event => { editor && editor.document.languageId === "json" && editor.document.uri.scheme === "couchbase" && - // TODO: Find better way to identify index def files - !editor.document.uri.path.includes("Search") + !editor.document.uri.path.endsWith("cbs.json") && + !editor.document.uri.path.includes("/Search/") ) { await handleActiveEditorChange(editor, uriToCasMap, memFs); } @@ -221,7 +264,9 @@ context.subscriptions.push(vscode.workspace.onDidChangeTextDocument(event => { async (document: vscode.TextDocument) => { if ( document && document.languageId === "json" && - document.uri.scheme === "couchbase" + document.uri.scheme === "couchbase" && + !document.uri.path.endsWith("cbs.json") && + !document.uri.path.includes("/Search/") ) { await handleOnSaveTextDocument(document, uriToCasMap, memFs, cacheService); clusterConnectionTreeProvider.refresh(); @@ -725,7 +770,7 @@ context.subscriptions.push(vscode.workspace.onDidChangeTextDocument(event => { searchWorkbench.openSearchWorkbench(searchIndexNode, memFs); const editorChangeSubscription = vscode.window.onDidChangeActiveTextEditor(async (editor) => { - if (editor && editor.document.languageId === "searchQuery") { + if (editor && editor.document.languageId === "json" && editor.document.fileName.endsWith(".cbs.json")) { await handleSearchContextStatusbar(editor, searchIndexNode, searchWorkbench, globalStatusBarItem); } }); diff --git a/src/handlers/handleSearchQueryContextStatusBar.ts b/src/handlers/handleSearchQueryContextStatusBar.ts index 478e6eb6..3825abd2 100644 --- a/src/handlers/handleSearchQueryContextStatusBar.ts +++ b/src/handlers/handleSearchQueryContextStatusBar.ts @@ -4,7 +4,7 @@ import { showSearchContextStatusbar } from '../util/queryContextUtils'; import SearchIndexNode from '../model/SearchIndexNode'; export const handleSearchContextStatusbar = async (editor: vscode.TextEditor | undefined,searchNode:SearchIndexNode, workbench:SearchWorkbench, globalStatusBarItem: vscode.StatusBarItem) => { - if( editor && editor.document.languageId === "searchQuery"){ + if( editor && editor.document.languageId === "json" && editor.document.fileName.endsWith(".cbs.json")){ // Case 1: Show Status bar showSearchContextStatusbar(editor,searchNode, workbench, globalStatusBarItem); } else { diff --git a/src/model/ScopeNode.ts b/src/model/ScopeNode.ts index 51bebee4..9b8baff8 100644 --- a/src/model/ScopeNode.ts +++ b/src/model/ScopeNode.ts @@ -20,6 +20,7 @@ import { getActiveConnection } from "../util/connections"; import { CacheService } from "../../src/util/cacheService/cacheService"; import { SearchDirectory } from "./SearchDirectory"; import { CollectionDirectory } from "./CollectionDirectory"; +import { hasSearchService } from "../util/common"; export class ScopeNode implements INode { @@ -74,6 +75,7 @@ export class ScopeNode implements INode { const childrenDirectoriesList: INode[] = []; // Search Directory + if (hasSearchService(connection?.services)){ childrenDirectoriesList.push( new SearchDirectory( this, @@ -82,6 +84,7 @@ export class ScopeNode implements INode { this.scopeName ) ); + } // Collections Directory const collectionDirectory = new CollectionDirectory( diff --git a/src/pages/queryContext/queryContext.ts b/src/pages/queryContext/queryContext.ts index 30b5051c..6908729f 100644 --- a/src/pages/queryContext/queryContext.ts +++ b/src/pages/queryContext/queryContext.ts @@ -106,7 +106,7 @@ export async function fetchSearchContext(searchIndexNode: SearchIndexNode, workb } try { const activeEditor = vscode.window.activeTextEditor; - if (!(activeEditor && activeEditor.document.languageId === "searchQuery")) { + if (!(activeEditor && activeEditor.document.languageId === "json" && activeEditor.document.fileName.endsWith(".cbs.json"))) { vscode.window.showErrorMessage("Please ensure that the workbench is open/active"); return; } diff --git a/src/reactViews/app/bootstrap.tsx b/src/reactViews/app/bootstrap.tsx index 539c58ff..0f82eee4 100644 --- a/src/reactViews/app/bootstrap.tsx +++ b/src/reactViews/app/bootstrap.tsx @@ -24,6 +24,8 @@ export const App: React.FC = () => { const [explainPlan, setExplainPlan] = React.useState(null); const [theme, setTheme] = React.useState("vs-dark"); const [currentTab, setCurrentTab] = React.useState(QueryTabs.JSON); // TODO: initial value should be chart + const [isSearch, setIsSearch] = React.useState(false); + window.addEventListener('message', event => { const message = event.data; // The JSON data our extension sent @@ -31,7 +33,10 @@ export const App: React.FC = () => { case 'queryResult': setQueryResult(JSON.parse(message.result)); setQueryStatus(message.queryStatus); + setIsSearch(message.isSearch); + if (!message.isSearch) { setExplainPlan(JSON.parse(message.explainPlan)); + } message.isDarkTheme ? setTheme("vs-dark") : setTheme("vs-light"); break; case 'theme': @@ -42,7 +47,7 @@ export const App: React.FC = () => { return (
- + item.key === QueryTabs.JSON) : TAB_BAR_ITEMS} value={currentTab} onChange={setCurrentTab} />
{currentTab === QueryTabs.JSON && { theme={theme} language="json" />} - {currentTab === QueryTabs.Table && } - {currentTab === QueryTabs.PLAN && } + {!isSearch && currentTab === QueryTabs.Table && } + {!isSearch && currentTab === QueryTabs.PLAN && }
); diff --git a/src/test/contributor/cbsCtlCodeCompletion.test.ts b/src/test/contributor/cbsCtlCodeCompletion.test.ts new file mode 100644 index 00000000..c62b3de2 --- /dev/null +++ b/src/test/contributor/cbsCtlCodeCompletion.test.ts @@ -0,0 +1,149 @@ +import * as assert from 'assert'; +import * as vscode from 'vscode'; +import * as path from 'path'; +import * as os from 'os'; +import * as fs from 'fs'; +import { AutocompleteVisitor } from '../../commands/fts/SearchWorkbench/contributor/autoCompleteVisitor'; +import { consistencyCbsContributor } from '../../commands/fts/SearchWorkbench/contributor/consistencyCbsContributor'; +import { ctlCbsContributor } from '../../commands/fts/SearchWorkbench/contributor/ctlCbsContributor'; + + + + +suite('CBSCtlCodeCompletion Test Suite', () => { + let autocompleteVisitor: AutocompleteVisitor; + let tempDir: string; + + setup(async () => { + autocompleteVisitor = new AutocompleteVisitor(); + tempDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'vscode-test-')); + }); + + teardown(async () => { + await fs.promises.rm(tempDir, { recursive: true, force: true }); + }); + + const getCompletions = async (content: string): Promise => { + const tempFile = path.join(tempDir, 'test.json'); + await fs.promises.writeFile(tempFile, content); + + const uri = vscode.Uri.file(tempFile); + const document = await vscode.workspace.openTextDocument(uri); + + const caretIndex = content.indexOf(''); + const position = document.positionAt(caretIndex); + + const completionItems = await autocompleteVisitor.getAutoCompleteContributor(document, position); + return completionItems.map(item => item.label as string); + }; + + test('completion for ctl', async () => { + const content = `{ + "ctl": {""} + }`; + const completionResults = await getCompletions(content); + + assert.notStrictEqual(completionResults, null, "No completions found"); + for (const keyword of ctlCbsContributor.keys) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + + test('dont suggest keyword already exists', async () => { + const content = `{ + "ctl": { "timeout": 10000, + ""} + }`; + const completionResults = await getCompletions(content); + + assert.notStrictEqual(completionResults, null, "No completions found"); + const expected = ["consistency"]; + for (const keyword of expected) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + + test('completion consistency', async () => { + const content = `{ + "ctl": { + "timeout": 10000, + "consistency": { + "" + } + } + }`; + const completionResults = await getCompletions(content); + + assert.notStrictEqual(completionResults, null, "No completions found"); + for (const keyword of consistencyCbsContributor.keys) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + + test('completion consistency existing values', async () => { + const content = `{ + "ctl": { + "timeout": 10000, + "consistency": { + "level": "at_plus", + "" + } + } + }`; + const completionResults = await getCompletions(content); + + assert.notStrictEqual(completionResults, null, "No completions found"); + for (const keyword of ["vectors", "results"]) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + + test('suggest level values', async () => { + const content = `{ + "ctl": { + "timeout": 10000, + "consistency": { + "vectors": { + "searchIndexName": { + "607/205096593892159": 2, + "640/298739127912798": 4 + } + }, + "level": "", + "results": "complete" + } + } + }`; + const completionResults = await getCompletions(content); + + assert.notStrictEqual(completionResults, null, "No completions found"); + const expected = ["at_plus", "not_bounded"]; + for (const keyword of expected) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + + test('suggest results values', async () => { + const content = `{ + "ctl": { + "timeout": 10000, + "consistency": { + "vectors": { + "searchIndexName": { + "607/205096593892159": 2, + "640/298739127912798": 4 + } + }, + "results": "" + } + } + }`; + const completionResults = await getCompletions(content); + + assert.notStrictEqual(completionResults, null, "No completions found"); + const expected = ["complete"]; + for (const keyword of expected) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); +}); \ No newline at end of file diff --git a/src/test/contributor/cbsGeometryCodeCompletion.test.ts b/src/test/contributor/cbsGeometryCodeCompletion.test.ts new file mode 100644 index 00000000..e1fbdf9f --- /dev/null +++ b/src/test/contributor/cbsGeometryCodeCompletion.test.ts @@ -0,0 +1,70 @@ +import * as assert from 'assert'; +import * as vscode from 'vscode'; +import * as path from 'path'; +import * as os from 'os'; +import * as fs from 'fs'; +import { AutocompleteVisitor } from '../../commands/fts/SearchWorkbench/contributor/autoCompleteVisitor'; +import { geometryCbsContributor } from '../../commands/fts/SearchWorkbench/contributor/geometryCbsContributor'; + +suite('CBSGeometryCodeCompletion Test Suite', () => { + let autocompleteVisitor: AutocompleteVisitor; + let tempDir: string; + + setup(async () => { + autocompleteVisitor = new AutocompleteVisitor(); + tempDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'vscode-test-')); + }); + + teardown(async () => { + await fs.promises.rm(tempDir, { recursive: true, force: true }); + }); + + const getCompletions = async (content: string): Promise => { + const tempFile = path.join(tempDir, 'test.json'); + await fs.promises.writeFile(tempFile, content); + + const uri = vscode.Uri.file(tempFile); + const document = await vscode.workspace.openTextDocument(uri); + + const caretIndex = content.indexOf(''); + const position = document.positionAt(caretIndex); + + const completionItems = await autocompleteVisitor.getAutoCompleteContributor(document, position); + return completionItems.map(item => item.label as string); + }; + + test('completion for geometry', async () => { + const content = `{ + "query": { + "field": "geojson", + "geometry": { + "" + } + } + }`; + const completionResults = await getCompletions(content); + + assert.notStrictEqual(completionResults, null, "No completions found"); + for (const keyword of geometryCbsContributor.keys) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + + test('completion for geometry relation', async () => { + const content = `{ + "query": { + "field": "geojson", + "geometry": { + "relation": "" + } + } + }`; + const completionResults = await getCompletions(content); + + assert.notStrictEqual(completionResults, null, "No completions found"); + const expected = ["intersects", "within"]; + for (const keyword of expected) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + }); \ No newline at end of file diff --git a/src/test/contributor/cbsHighlightCodeCompletion.test.ts b/src/test/contributor/cbsHighlightCodeCompletion.test.ts new file mode 100644 index 00000000..fc4a4e6c --- /dev/null +++ b/src/test/contributor/cbsHighlightCodeCompletion.test.ts @@ -0,0 +1,77 @@ +import * as assert from 'assert'; +import * as vscode from 'vscode'; +import * as path from 'path'; +import * as os from 'os'; +import * as fs from 'fs'; +import { AutocompleteVisitor } from '../../commands/fts/SearchWorkbench/contributor/autoCompleteVisitor'; +import { highlightCbsContributor } from '../../commands/fts/SearchWorkbench/contributor/highlightCbsContributor'; + + +suite('CBSHighlightCodeCompletion Test Suite', () => { + let autocompleteVisitor: AutocompleteVisitor; + let tempDir: string; + + setup(async () => { + autocompleteVisitor = new AutocompleteVisitor(); + tempDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'vscode-test-')); + }); + + teardown(async () => { + await fs.promises.rm(tempDir, { recursive: true, force: true }); + }); + + const getCompletions = async (content: string): Promise => { + const tempFile = path.join(tempDir, 'test.json'); + await fs.promises.writeFile(tempFile, content); + + const uri = vscode.Uri.file(tempFile); + const document = await vscode.workspace.openTextDocument(uri); + + const caretIndex = content.indexOf(''); + const position = document.positionAt(caretIndex); + + const completionItems = await autocompleteVisitor.getAutoCompleteContributor(document, position); + return completionItems.map(item => item.label as string); + }; + + test('completion for highlight', async () => { + const content = `{ + "highlight": {""} + }`; + const completionResults = await getCompletions(content); + + assert.notStrictEqual(completionResults, null, "No completions found"); + for (const keyword of highlightCbsContributor.keys) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + + test('dont suggest keyword already exists', async () => { + const content = `{ + "highlight": { "fields": ["textField"], + ""} + }`; + const completionResults = await getCompletions(content); + + assert.notStrictEqual(completionResults, null, "No completions found"); + const expected = ["style"]; + for (const keyword of expected) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + + test('suggest style values', async () => { + const content = `{ + "highlight": { "fields": ["textField"], + "style": "" + } + }`; + const completionResults = await getCompletions(content); + + assert.notStrictEqual(completionResults, null, "No completions found"); + const expected = ["html", "ansi"]; + for (const keyword of expected) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + }); \ No newline at end of file diff --git a/src/test/contributor/cbsKnnCodeCompletion.test.ts b/src/test/contributor/cbsKnnCodeCompletion.test.ts new file mode 100644 index 00000000..1c820a8f --- /dev/null +++ b/src/test/contributor/cbsKnnCodeCompletion.test.ts @@ -0,0 +1,62 @@ +import * as assert from 'assert'; +import * as vscode from 'vscode'; +import * as path from 'path'; +import * as os from 'os'; +import * as fs from 'fs'; +import { AutocompleteVisitor } from '../../commands/fts/SearchWorkbench/contributor/autoCompleteVisitor'; +import { knnCbsContributor } from '../../commands/fts/SearchWorkbench/contributor/knnCbsContributor'; + + +suite('CBSKnnCodeCompletion Test Suite', () => { + let autocompleteVisitor: AutocompleteVisitor; + let tempDir: string; + + setup(async () => { + autocompleteVisitor = new AutocompleteVisitor(); + tempDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'vscode-test-')); + }); + + teardown(async () => { + await fs.promises.rm(tempDir, { recursive: true, force: true }); + }); + + const getCompletions = async (content: string): Promise => { + const tempFile = path.join(tempDir, 'test.json'); + await fs.promises.writeFile(tempFile, content); + + const uri = vscode.Uri.file(tempFile); + const document = await vscode.workspace.openTextDocument(uri); + + const caretIndex = content.indexOf(''); + const position = document.positionAt(caretIndex); + + const completionItems = await autocompleteVisitor.getAutoCompleteContributor(document, position); + return completionItems.map(item => item.label as string); + }; + + test('empty json completion', async () => { + const content = `{ "knn": { "" } }`; + const completionResults = await getCompletions(content); + + assert.notStrictEqual(completionResults, null, "No completions found"); + for (const keyword of knnCbsContributor.keys) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + + test('dont suggest keyword already exists', async () => { + const content = `{ + "knn": { + "field": "vector_field", + "" + } + }`; + const completionResults = await getCompletions(content); + + assert.notStrictEqual(completionResults, null, "No completions found"); + const expected = ["k", "vector"]; + for (const keyword of expected) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + }); \ No newline at end of file diff --git a/src/test/contributor/cbsQueryCodeCompletion.test.ts b/src/test/contributor/cbsQueryCodeCompletion.test.ts new file mode 100644 index 00000000..1acb5112 --- /dev/null +++ b/src/test/contributor/cbsQueryCodeCompletion.test.ts @@ -0,0 +1,446 @@ +import * as assert from 'assert'; +import * as vscode from 'vscode'; +import * as path from 'path'; +import * as os from 'os'; +import * as fs from 'fs'; +import { AutocompleteVisitor } from '../../commands/fts/SearchWorkbench/contributor/autoCompleteVisitor'; +import { queryCbsContributor } from '../../commands/fts/SearchWorkbench/contributor/queryCbsContributor'; +import { locationCbsContributor } from '../../commands/fts/SearchWorkbench/contributor/locationCbsContributor'; + +suite('CBSQueryCodeCompletion Test Suite', () => { + let autocompleteVisitor: AutocompleteVisitor; + let tempDir: string; + + setup(async () => { + autocompleteVisitor = new AutocompleteVisitor(); + tempDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'vscode-test-')); + }); + + teardown(async () => { + await fs.promises.rm(tempDir, { recursive: true, force: true }); + }); + + const getCompletions = async (content: string): Promise => { + const tempFile = path.join(tempDir, 'test.json'); + await fs.promises.writeFile(tempFile, content); + + const uri = vscode.Uri.file(tempFile); + const document = await vscode.workspace.openTextDocument(uri); + + const caretIndex = content.indexOf(''); + const position = document.positionAt(caretIndex); + const completionItems = await autocompleteVisitor.getAutoCompleteContributor(document, position); + return completionItems.map(item => item.label as string); + }; + + test('query completion', async () => { + const content = `{ + "query": { + "" + } + }`; + const completionResults = await getCompletions(content); + + assert.notStrictEqual(completionResults, null, "No completions found"); + for (const keyword of queryCbsContributor.allQueryKeys) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + + test('query completion conjuncts', async () => { + const content = `{ + "query": { + "conjuncts":[ + { + "" + } + ] + } + }`; + const completionResults = await getCompletions(content); + + assert.notStrictEqual(completionResults, null, "No completions found"); + for (const keyword of queryCbsContributor.allQueryKeys) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + + test('query completion disjuncts', async () => { + const content = `{ + "query": { + "disjuncts":[ + { + "" + } + ] + } + }`; + const completionResults = await getCompletions(content); + + assert.notStrictEqual(completionResults, null, "No completions found"); + for (const keyword of queryCbsContributor.allQueryKeys) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + + test('query completion disjuncts no recommendation', async () => { + const content = `{ + "query": { + "disjuncts":[ + "" + ] + } + }`; + const completionResults = await getCompletions(content); + assert.strictEqual(completionResults.length, 0); + }); + + test('query completion conjuncts no recommendation', async () => { + const content = `{ + "query": { + "conjuncts":[ + "" + ] + } + }`; + const completionResults = await getCompletions(content); + assert.strictEqual(completionResults.length, 0); + }); + + test('query completion empty', async () => { + const content = `{ + "query": { + "query": "", + + } + }`; + const completionResults = await getCompletions(content); + assert.strictEqual(completionResults.length, 0); + }); + + test('match', async () => { + const content = `{ + "query": { + "match":"", + "" + } + }`; + const completionResults = await getCompletions(content); + const expected = ["field", "analyzer", "operator", "boost", "fuzziness", "prefix_length"]; + for (const keyword of expected) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + + test('operator', async () => { + const content = `{ + "query": { + "operator": "or", + "" + } + }`; + const completionResults = await getCompletions(content); + const expected = ["field", "analyzer", "boost", "fuzziness", "prefix_length"]; + for (const keyword of expected) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + + test('bool', async () => { + const content = `{ + "query": { + "bool": true + "" + } + }`; + const completionResults = await getCompletions(content); + const expected = ["field", "boost"]; + for (const keyword of expected) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + + test('prefix', async () => { + const content = `{ + "query": { + "prefix": "" + "" + } + }`; + const completionResults = await getCompletions(content); + const expected = ["field", "boost"]; + for (const keyword of expected) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + + test('regex', async () => { + const content = `{ + "query": { + "regexp": "" + "" + } + }`; + const completionResults = await getCompletions(content); + const expected = ["field", "boost"]; + for (const keyword of expected) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + + test('term', async () => { + const content = `{ + "query": { + "term": "" + "" + } + }`; + const completionResults = await getCompletions(content); + const expected = ["field", "boost", "fuzziness"]; + for (const keyword of expected) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + + test('terms', async () => { + const content = `{ + "query": { + "terms": [] + "" + } + }`; + const completionResults = await getCompletions(content); + const expected = ["field", "boost"]; + for (const keyword of expected) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + + test('wildcard', async () => { + const content = `{ + "query": { + "wildcard": "*" + "" + } + }`; + const completionResults = await getCompletions(content); + const expected = ["field", "boost"]; + for (const keyword of expected) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + + test('numeric min', async () => { + const content = `{ + "query": { + "min": 3, + "" + } + }`; + const completionResults = await getCompletions(content); + const expected = ["max", "inclusive_min", "inclusive_max", "field", "boost"]; + for (const keyword of expected) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + + test('numeric min max', async () => { + const content = `{ + "query": { + "min": 3, + "min": 10, + "" + } + }`; + const completionResults = await getCompletions(content); + const expected = ["inclusive_min", "inclusive_max", "field", "boost"]; + for (const keyword of expected) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + + test('date start', async () => { + const content = `{ + "query": { + "start": "2001-10-09T10:20:30-08:00", + "" + } + }`; + const completionResults = await getCompletions(content); + const expected = ["end", "inclusive_start", "inclusive_end", "field", "boost"]; + for (const keyword of expected) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + + test('date start inclusive end', async () => { + const content = `{ + "query": { + "start": "2001-10-09T10:20:30-08:00", + "inclusive_end": false, + "" + } + }`; + const completionResults = await getCompletions(content); + const expected = ["end", "inclusive_start", "field", "boost"]; + for (const keyword of expected) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + + test('date inclusive end', async () => { + const content = `{ + "query": { + "inclusive_start": false, + "" + } + }`; + const completionResults = await getCompletions(content); + const expected = ["start", "end", "inclusive_end", "field", "boost"]; + for (const keyword of expected) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + + test('distance', async () => { + const content = `{ + "query": { + "location": { + "lon": -2.235143, + "lat": 53.482358 + }, + "" + } + }`; + const completionResults = await getCompletions(content); + const expected = ["distance", "field", "boost"]; + for (const keyword of expected) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + + test('rectangle', async () => { + const content = `{ + "query": { + "top_left": [-2.235143, 53.482358], + "" + } + }`; + const completionResults = await getCompletions(content); + const expected = ["bottom_right", "field", "boost"]; + for (const keyword of expected) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + + test('polygon', async () => { + const content = `{ + "query": { + "polygon_points": [ + "37.79393211306212,-122.44234633404847", + "37.77995881733997,-122.43977141339417", + "37.788031092020155,-122.42925715405579", + "37.79026946582319,-122.41149020154114", + "37.79571192027403,-122.40735054016113", + "37.79393211306212,-122.44234633404847" + ], + "" + } + }`; + const completionResults = await getCompletions(content); + const expected = ["field", "boost"]; + for (const keyword of expected) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + + test('must', async () => { + const content = `{ + "query":{ + "must":{ + "" + } + } + }`; + const completionResults = await getCompletions(content); + assert.notStrictEqual(completionResults, null, "No completions found"); + assert.ok(completionResults.includes("conjuncts"), "Expected completion 'conjuncts' not found"); + }); + + test('must not', async () => { + const content = `{ + "query":{ + "must_not":{ + "" + } + } + }`; + const completionResults = await getCompletions(content); + assert.notStrictEqual(completionResults, null, "No completions found"); + assert.ok(completionResults.includes("disjuncts"), "Expected completion 'disjuncts' not found"); + }); + + test('should', async () => { + const content = `{ + "query":{ + "disjuncts":{ + "" + } + } + }`; + const completionResults = await getCompletions(content); + assert.notStrictEqual(completionResults, null, "No completions found"); + assert.ok(completionResults.includes("disjuncts"), "Expected completion 'disjuncts' not found"); + }); + + test('top left', async () => { + const content = `{ + "query": { + "top_left": {""}, + "bottom_right": { + "lon": 28.955043, + "lat": 40.991862 + }, + "field": "geo" + } + }`; + const completionResults = await getCompletions(content); + assert.notStrictEqual(completionResults, null, "No completions found"); + for (const keyword of locationCbsContributor.keys) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + + test('bottom right', async () => { + const content = `{ + "query": { + "top_left": [-2.235143, 53.482358], + "bottom_right": { + "lon": 28.955043, + "" + }, + "field": "geo" + } + }`; + const completionResults = await getCompletions(content); + assert.notStrictEqual(completionResults, null, "No completions found"); + assert.ok(completionResults.includes("lat"), "Expected completion 'lat' not found"); + }); + + test('location', async () => { + const content = `{ + "query": { + "location": { + "" + }, + "distance": "100mi", + "field": "geo" + } + }`; + const completionResults = await getCompletions(content); + assert.notStrictEqual(completionResults, null, "No completions found"); + for (const keyword of locationCbsContributor.keys) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + }); \ No newline at end of file diff --git a/src/test/contributor/cbsRootCodeCompletion.test.ts b/src/test/contributor/cbsRootCodeCompletion.test.ts new file mode 100644 index 00000000..be2a2a65 --- /dev/null +++ b/src/test/contributor/cbsRootCodeCompletion.test.ts @@ -0,0 +1,77 @@ +import * as assert from 'assert'; +import * as vscode from 'vscode'; +import * as path from 'path'; +import * as os from 'os'; +import * as fs from 'fs'; +import { AutocompleteVisitor } from '../../commands/fts/SearchWorkbench/contributor/autoCompleteVisitor'; + +suite('CBSRootCodeCompletion Test Suite', () => { + let autocompleteVisitor: AutocompleteVisitor; + let tempDir: string; + + setup(async () => { + autocompleteVisitor = new AutocompleteVisitor(); + tempDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'vscode-test-')); + }); + + teardown(async () => { + await fs.promises.rm(tempDir, { recursive: true, force: true }); + }); + + const getCompletions = async (content: string): Promise => { + const tempFile = path.join(tempDir, 'test.json'); + await fs.promises.writeFile(tempFile, content); + + const uri = vscode.Uri.file(tempFile); + const document = await vscode.workspace.openTextDocument(uri); + + const caretIndex = content.indexOf(''); + const position = document.positionAt(caretIndex); + + const completionItems = await autocompleteVisitor.getAutoCompleteContributor(document, position); + return completionItems.map(item => item.label as string); + }; + + test('empty json completion', async () => { + const content = `{}`; + const completionResults = await getCompletions(content); + + assert.notStrictEqual(completionResults, null, "No completions found"); + const expected = autocompleteVisitor.topLevelKeywords.map(e => `"${e}"`); + for (const keyword of expected) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + + test('dont suggest keyword already exists', async () => { + const content = `{ + "query": {}, + + }`; + const completionResults = await getCompletions(content); + + assert.notStrictEqual(completionResults, null, "No completions found"); + const expected = autocompleteVisitor.topLevelKeywords + .filter(e => e !== "query") + .map(e => `"${e}"`); + for (const keyword of expected) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + + + + test('score completion', async () => { + const content = `{ + "query": { + "query": "your_query_here" + }, + "fields": ["*"], + "score": "" + }`; + const completionResults = await getCompletions(content); + + assert.notStrictEqual(completionResults, null, "No completions found"); + assert.ok(completionResults.includes("none"), "Expected completion 'none' not found"); + }); + }); \ No newline at end of file diff --git a/src/test/contributor/cbsShapeCodeCompletion.test.ts b/src/test/contributor/cbsShapeCodeCompletion.test.ts new file mode 100644 index 00000000..64f12e9d --- /dev/null +++ b/src/test/contributor/cbsShapeCodeCompletion.test.ts @@ -0,0 +1,118 @@ +import * as assert from 'assert'; +import * as vscode from 'vscode'; +import * as path from 'path'; +import * as os from 'os'; +import * as fs from 'fs'; +import { AutocompleteVisitor } from '../../commands/fts/SearchWorkbench/contributor/autoCompleteVisitor'; + +suite('CBSShapeCodeCompletion Test Suite', () => { + let autocompleteVisitor: AutocompleteVisitor; + let tempDir: string; + + setup(async () => { + autocompleteVisitor = new AutocompleteVisitor(); + tempDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'vscode-test-')); + }); + + teardown(async () => { + await fs.promises.rm(tempDir, { recursive: true, force: true }); + }); + + const getCompletions = async (content: string): Promise => { + const tempFile = path.join(tempDir, 'test.json'); + await fs.promises.writeFile(tempFile, content); + + const uri = vscode.Uri.file(tempFile); + const document = await vscode.workspace.openTextDocument(uri); + + const caretIndex = content.indexOf(''); + const position = document.positionAt(caretIndex); + + const completionItems = await autocompleteVisitor.getAutoCompleteContributor(document, position); + return completionItems.map(item => item.label as string); + }; + + test('completion for shape', async () => { + const content = `{ + "query": { + "field": "geojson", + "geometry": { + "shape": { + "" + }, + "relation": "intersects" + } + } + }`; + const completionResults = await getCompletions(content); + + assert.notStrictEqual(completionResults, null, "No completions found"); + const expected = ["coordinates", "type", "radius", "geometries"]; + for (const keyword of expected) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + + test('completion for circle', async () => { + const content = `{ + "query": { + "field": "geojson", + "geometry": { + "shape": { + "type": "Circle", + "" + }, + "relation": "intersects" + } + } + }`; + const completionResults = await getCompletions(content); + + assert.notStrictEqual(completionResults, null, "No completions found"); + assert.strictEqual(completionResults.length, 2); + const expected = ["coordinates", "radius"]; + for (const keyword of expected) { + assert.ok(completionResults.includes(keyword), `Expected completion '${keyword}' not found`); + } + }); + + test('completion for geometry collection', async () => { + const content = `{ + "query": { + "field": "geojson", + "geometry": { + "shape": { + "type": "GeometryCollection", + "" + }, + "relation": "intersects" + } + } + }`; + const completionResults = await getCompletions(content); + + assert.notStrictEqual(completionResults, null, "No completions found"); + assert.strictEqual(completionResults.length, 1); + assert.ok(completionResults.includes("geometries"), "Expected completion 'geometries' not found"); + }); + + test('completion for polygon', async () => { + const content = `{ + "query": { + "field": "geojson", + "geometry": { + "shape": { + "type": "Polygon", + "" + }, + "relation": "intersects" + } + } + }`; + const completionResults = await getCompletions(content); + + assert.notStrictEqual(completionResults, null, "No completions found"); + assert.strictEqual(completionResults.length, 1); + assert.ok(completionResults.includes("coordinates"), "Expected completion 'coordinates' not found"); + }); + }); \ No newline at end of file diff --git a/src/test/runTest.ts b/src/test/runTest.ts index d9dfb906..b8033fe5 100644 --- a/src/test/runTest.ts +++ b/src/test/runTest.ts @@ -14,24 +14,35 @@ * limitations under the License. */ -import * as path from "path"; - -import { runTests } from "@vscode/test-electron"; +import * as path from 'path'; +import * as fs from 'fs'; +import { runTests } from '@vscode/test-electron'; async function main() { try { - // The folder containing the Extension Manifest package.json - // Passed to `--extensionDevelopmentPath` - const extensionDevelopmentPath = path.resolve(__dirname, "../../"); + const extensionDevelopmentPath = path.resolve(__dirname, '../'); + const extensionTestsPath = path.resolve(__dirname, './suite/index'); + + // Cleanup step + const userDataPath = path.resolve(__dirname, '../../.vscode-test/user-data'); + if (fs.existsSync(userDataPath)) { + fs.rmdirSync(userDataPath, { recursive: true }); + } - // The path to test runner - // Passed to --extensionTestsPath - const extensionTestsPath = path.resolve(__dirname, "./suite/index"); + // Get the test file from command line arguments + const testFile = process.argv[2]; + if (testFile) { + process.env.VSCODE_TEST_FILE = testFile; + } // Download VS Code, unzip it and run the integration test - await runTests({ extensionDevelopmentPath, extensionTestsPath }); - } catch (err: any) { - console.error("Failed to run tests"); + await runTests({ + extensionDevelopmentPath, + extensionTestsPath, + launchArgs: testFile ? ['--disable-extensions', '--extensionTestsPath=' + extensionTestsPath, '--testFile=' + testFile] : undefined + }); + } catch (err) { + console.error('Failed to run tests', err); process.exit(1); } } diff --git a/src/test/suite/index.ts b/src/test/suite/index.ts index fdffa874..07e7e753 100644 --- a/src/test/suite/index.ts +++ b/src/test/suite/index.ts @@ -16,7 +16,8 @@ import * as path from "path"; import Mocha from "mocha"; -import glob from "glob"; +import util from 'util'; +const glob = util.promisify(require('glob')); export function run(): Promise { // Create the mocha test @@ -25,17 +26,23 @@ export function run(): Promise { color: true, }); - const testsRoot = path.resolve(__dirname, ".."); + const testsRoot = path.resolve(__dirname, '..'); - return new Promise((c, e) => { - glob("**/**.test.js", { cwd: testsRoot }, (err, files) => { - if (err) { - return e(err); - } - - // Add files to the test suite - files.forEach((f) => mocha.addFile(path.resolve(testsRoot, f))); + return new Promise(async (c, e) => { + const testFile = process.env.VSCODE_TEST_FILE; + if (testFile) { + // If a specific test file is specified, only add that file + mocha.addFile(path.resolve(testsRoot, testFile)); + } else { + try { + const files = await glob("contributor/*.test.js", { cwd: testsRoot }); + files.forEach((f: string) => mocha.addFile(path.resolve(testsRoot, f))); + } catch (err) { + console.error("Error during glob operation:", err); + return; + } + } try { // Run the mocha test mocha.run((failures) => { @@ -50,5 +57,4 @@ export function run(): Promise { e(err); } }); - }); } diff --git a/src/util/cacheService/cacheService.ts b/src/util/cacheService/cacheService.ts index 38f0a54f..95321974 100644 --- a/src/util/cacheService/cacheService.ts +++ b/src/util/cacheService/cacheService.ts @@ -51,16 +51,25 @@ export class CacheService { const type = propertyValue.type; if (type === 'object') { const children = this.schemaTreeTraversal(propertyValue.properties); - currentNodes[property[0]] = children; + currentNodes[property[0]] = { + type: 'object', + value: children + }; } else if (type === 'array') { try { const items = propertyValue.items; const itemType = items.type; if (itemType === 'object') { const children = this.schemaTreeTraversal(items.properties); - currentNodes[property[0]] = children; + currentNodes[property[0]] = { + type: 'array', + value: children + }; } else { - currentNodes[property[0]] = `array of ${itemType}`; + currentNodes[property[0]] = { + type: 'array', + value: `array of ${itemType}` + };; } } catch (error) { logger.error(`Error processing array type for ${property[0]}: ${error}`); @@ -70,7 +79,10 @@ export class CacheService { try { let currentType: string = type.toString(); currentType = currentType.replace(',', " | "); - currentNodes[property[0]] = currentType; + currentNodes[property[0]] = { + type: currentType, + value: currentType + }; } catch (e) { logger.error("Type can't be stringified: " + e); } @@ -582,6 +594,10 @@ export class CacheService { // return vscode.globalState.update(BUCKETS_STATE_KEY, finalJson); } + public getCache(bucketName:string){ + return this.bucketsData.get(bucketName) + } + public async loadCache(connection: IConnection): Promise { const storedDataJson = Global.state.get(`vscode-couchbase.iq.bucketsCache.${connection.connectionIdentifier}`); if (!storedDataJson) { diff --git a/src/util/common.ts b/src/util/common.ts index 34a17fa8..51a15cef 100644 --- a/src/util/common.ts +++ b/src/util/common.ts @@ -58,4 +58,11 @@ export const hasQueryService = (services: string[] | undefined) => { return false; } return services.includes('n1ql'); +}; + +export const hasSearchService = (services: string[] | undefined) => { + if (!services) { + return false; + } + return services.includes('fts'); }; \ No newline at end of file diff --git a/src/util/connections.ts b/src/util/connections.ts index cd12df49..cac487e9 100644 --- a/src/util/connections.ts +++ b/src/util/connections.ts @@ -24,7 +24,7 @@ import ClusterConnectionTreeProvider from "../tree/ClusterConnectionTreeProvider import { logger } from "../logger/logger"; import { getServices } from "./OverviewClusterUtils/ClusterOverviewGeneralTab"; import { CouchbaseRestAPI } from "./apis/CouchbaseRestAPI"; -import { hasQueryService } from "./common"; +import { hasQueryService, hasSearchService } from "./common"; import { SecretService } from "./secretService"; export function getConnectionId(connection: IConnection) { @@ -197,6 +197,7 @@ export async function useConnection(connection: IConnection): Promise { connection.services = getServices(serviceOverview!); // Set the isKVCluster context vscode.commands.executeCommand('setContext', 'isKVCluster', !hasQueryService(connection.services)); + vscode.commands.executeCommand('setContext', 'isSearchEnabled', hasSearchService(connection.services)); status = true; vscode.window.showInformationMessage("Connection established successfully!"); logger.info(`Connection established successfully with ${connection.connectionIdentifier}`); diff --git a/src/workbench/queryWorkbench.ts b/src/workbench/queryWorkbench.ts index e11f18a4..c5296001 100644 --- a/src/workbench/queryWorkbench.ts +++ b/src/workbench/queryWorkbench.ts @@ -85,7 +85,8 @@ export class QueryWorkbench { workbenchWebviewProvider.setQueryResult( JSON.stringify(result?.rows), queryStatusProps, - explainPlan + explainPlan, + false ); await saveQuery({ query: query, id: getUUID() }); queryHistoryTreeProvider.refresh(); @@ -126,7 +127,8 @@ export class QueryWorkbench { workbenchWebviewProvider.setQueryResult( JSON.stringify(errorArray), queryStatusProps, - null + null, + false ); } } diff --git a/src/workbench/workbenchWebviewProvider.ts b/src/workbench/workbenchWebviewProvider.ts index f2eea89e..e99bb912 100644 --- a/src/workbench/workbenchWebviewProvider.ts +++ b/src/workbench/workbenchWebviewProvider.ts @@ -18,7 +18,8 @@ type IQueryStatusProps = { type IQueryResultProps = { queryResult: string; queryStatus: IQueryStatusProps; - plan: string | null + plan: string | null; + isSearch: boolean }; export class WorkbenchWebviewProvider implements vscode.WebviewViewProvider { public _view?: vscode.WebviewView; @@ -49,7 +50,7 @@ export class WorkbenchWebviewProvider implements vscode.WebviewViewProvider { this._view?.webview.postMessage({ command: "theme", isDarkTheme }); this._view?.onDidChangeVisibility(() => { if (Memory.state.get(Constants.QUERY_RESULT)) { - this.sendQueryResult(JSON.stringify([{ "status": "Loading last executed result" }]), { queryStatus: QueryStatus.Running }, null); + this.sendQueryResult(JSON.stringify([{ "status": "Loading last executed result" }]), { queryStatus: QueryStatus.Running }, null,); const previousResult = Memory.state.get(Constants.QUERY_RESULT); if (previousResult) { this.sendQueryResult(previousResult.queryResult, previousResult.queryStatus, previousResult.plan); @@ -58,21 +59,16 @@ export class WorkbenchWebviewProvider implements vscode.WebviewViewProvider { }); } - async sendQueryResult(queryResult: string, queryStatus: IQueryStatusProps, plan: string | null) { + async sendQueryResult(queryResult: string, queryStatus: IQueryStatusProps, plan: string | null, isSearch?: boolean) { const isDarkTheme: boolean = vscode.window.activeColorTheme.kind === vscode.ColorThemeKind.Dark; - await this._view?.webview.postMessage({ command: "queryResult", result: queryResult, queryStatus: queryStatus, explainPlan: plan, isDarkTheme }); - Memory.state.update(Constants.QUERY_RESULT, { queryResult, queryStatus, plan }); + await this._view?.webview.postMessage({ command: "queryResult", result: queryResult, queryStatus: queryStatus, explainPlan: plan, isDarkTheme, isSearch:isSearch }); + Memory.state.update(Constants.QUERY_RESULT, { queryResult, queryStatus, plan, isSearch }); } - async setQueryResult(queryResult: string, queryStatus: IQueryStatusProps, plan: string | null) { + async setQueryResult(queryResult: string, queryStatus: any, plan: string | null, isSearch: boolean) { this._view?.show(); this._queryResult = queryResult; - await this.sendQueryResult(queryResult, queryStatus, plan); + await this.sendQueryResult(queryResult, queryStatus, plan, isSearch); } - async setSearchQueryResult(queryResult: string, queryStatus: any, plan: string | null) { - this._view?.show(); - this._queryResult = queryResult; - await this.sendQueryResult(queryResult, queryStatus, plan); - } } \ No newline at end of file