From f45030414e15e20cb2b8a75e941895a49b7aeaed Mon Sep 17 00:00:00 2001 From: Mark Carrington Date: Mon, 4 Sep 2023 19:36:37 +0100 Subject: [PATCH 01/81] Initial basic CTE implementation --- MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs | 135 ++++++++++++++++++ .../MarkMpn.Sql4Cds.Engine.Tests.csproj | 1 + .../ExecutionPlan/SelectNode.cs | 5 +- .../ExecutionPlanBuilder.cs | 40 +++++- MarkMpn.Sql4Cds.Tests/AutocompleteTests.cs | 14 ++ 5 files changed, 189 insertions(+), 6 deletions(-) create mode 100644 MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs diff --git a/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs b/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs new file mode 100644 index 00000000..c79e2e12 --- /dev/null +++ b/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs @@ -0,0 +1,135 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.SqlTypes; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.Remoting.Contexts; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Web.Services.Description; +using System.Xml.Serialization; +using FakeXrmEasy; +using FakeXrmEasy.Extensions; +using MarkMpn.Sql4Cds.Engine.ExecutionPlan; +using Microsoft.SqlServer.TransactSql.ScriptDom; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.Xrm.Sdk; +using Microsoft.Xrm.Sdk.Metadata; +using Microsoft.Xrm.Sdk.Metadata.Query; +using Microsoft.Xrm.Sdk.Query; +using Microsoft.Xrm.Tooling.Connector; + +namespace MarkMpn.Sql4Cds.Engine.Tests +{ + [TestClass] + public class CteTests : FakeXrmEasyTestsBase, IQueryExecutionOptions + { + private List _supportedJoins = new List + { + JoinOperator.Inner, + JoinOperator.LeftOuter + }; + + CancellationToken IQueryExecutionOptions.CancellationToken => CancellationToken.None; + + bool IQueryExecutionOptions.BlockUpdateWithoutWhere => false; + + bool IQueryExecutionOptions.BlockDeleteWithoutWhere => false; + + bool IQueryExecutionOptions.UseBulkDelete => false; + + int IQueryExecutionOptions.BatchSize => 1; + + bool IQueryExecutionOptions.UseTDSEndpoint => false; + + int IQueryExecutionOptions.MaxDegreeOfParallelism => 10; + + bool IQueryExecutionOptions.ColumnComparisonAvailable => true; + + bool IQueryExecutionOptions.UseLocalTimeZone => true; + + List IQueryExecutionOptions.JoinOperatorsAvailable => _supportedJoins; + + bool IQueryExecutionOptions.BypassCustomPlugins => false; + + void IQueryExecutionOptions.ConfirmInsert(ConfirmDmlStatementEventArgs e) + { + } + + void IQueryExecutionOptions.ConfirmDelete(ConfirmDmlStatementEventArgs e) + { + } + + void IQueryExecutionOptions.ConfirmUpdate(ConfirmDmlStatementEventArgs e) + { + } + + bool IQueryExecutionOptions.ContinueRetrieve(int count) + { + return true; + } + + void IQueryExecutionOptions.Progress(double? progress, string message) + { + } + + string IQueryExecutionOptions.PrimaryDataSource => "local"; + + Guid IQueryExecutionOptions.UserId => Guid.NewGuid(); + + bool IQueryExecutionOptions.QuotedIdentifiers => true; + + public ColumnOrdering ColumnOrdering => ColumnOrdering.Alphabetical; + + [TestMethod] + public void SimpleSelect() + { + var planBuilder = new ExecutionPlanBuilder(_localDataSource.Values, this); + + var query = @" + WITH cte AS (SELECT accountid, name FROM account) + SELECT * FROM cte"; + + var plans = planBuilder.Build(query, null, out _); + + Assert.AreEqual(1, plans.Length); + + var select = AssertNode(plans[0]); + var fetch = AssertNode(select.Source); + AssertFetchXml(fetch, @" + + + + + + "); + } + + private T AssertNode(IExecutionPlanNode node) where T : IExecutionPlanNode + { + Assert.IsInstanceOfType(node, typeof(T)); + return (T)node; + } + + private void AssertFetchXml(FetchXmlScan node, string fetchXml) + { + try + { + var serializer = new XmlSerializer(typeof(FetchXml.FetchType)); + using (var reader = new StringReader(fetchXml)) + { + var fetch = (FetchXml.FetchType)serializer.Deserialize(reader); + PropertyEqualityAssert.Equals(fetch, node.FetchXml); + } + } + catch (AssertFailedException ex) + { + Assert.Fail($"Expected:\r\n{fetchXml}\r\n\r\nActual:\r\n{node.FetchXmlString}\r\n\r\n{ex.Message}"); + } + } + } +} diff --git a/MarkMpn.Sql4Cds.Engine.Tests/MarkMpn.Sql4Cds.Engine.Tests.csproj b/MarkMpn.Sql4Cds.Engine.Tests/MarkMpn.Sql4Cds.Engine.Tests.csproj index 3a4fa1a8..7190c955 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/MarkMpn.Sql4Cds.Engine.Tests.csproj +++ b/MarkMpn.Sql4Cds.Engine.Tests/MarkMpn.Sql4Cds.Engine.Tests.csproj @@ -78,6 +78,7 @@ + diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/SelectNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/SelectNode.cs index 1e5fed68..e00c252d 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/SelectNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/SelectNode.cs @@ -117,11 +117,12 @@ internal static void FoldFetchXmlColumns(IDataExecutionPlanNode source, List _cteSubplans; public ExecutionPlanBuilder(IEnumerable dataSources, IQueryExecutionOptions options) { @@ -166,7 +167,38 @@ private void ConvertStatement(TSqlStatement statement, ExecutionPlanOptimizer op var originalSql = statement.ToSql(); IRootExecutionPlanNodeInternal[] plans; - var hints = statement is StatementWithCtesAndXmlNamespaces stmtWithCtes ? stmtWithCtes.OptimizerHints : null; + IList hints = null; + _cteSubplans = new Dictionary(StringComparer.OrdinalIgnoreCase); + + if (statement is StatementWithCtesAndXmlNamespaces stmtWithCtes) + { + hints = stmtWithCtes.OptimizerHints; + + if (stmtWithCtes.WithCtesAndXmlNamespaces != null) + { + foreach (var cte in stmtWithCtes.WithCtesAndXmlNamespaces.CommonTableExpressions) + { + if (_cteSubplans.ContainsKey(cte.ExpressionName.Value)) + throw new NotSupportedQueryFragmentException($"A CTE with the name '{cte.ExpressionName.Value}' has already been declared.", cte.ExpressionName); + + // If the CTE isn't recursive then we can just convert it to a subquery + var plan = ConvertSelectStatement(cte.QueryExpression, hints, null, null, _nodeContext); + + // Apply column aliases + if (cte.Columns.Count > 0) + { + // TODO: What if a different number of columns? + + plan.ExpandWildcardColumns(_nodeContext); + + for (var i = 0; i < cte.Columns.Count; i++) + plan.ColumnSet[i].OutputColumn = cte.Columns[i].Value; + } + + _cteSubplans.Add(cte.ExpressionName.Value, new AliasNode(plan, cte.ExpressionName, _nodeContext)); + } + } + } if (statement is SelectStatement select) plans = new[] { ConvertSelectStatement(select) }; @@ -1658,9 +1690,6 @@ private IRootExecutionPlanNodeInternal ConvertSelectStatement(SelectStatement se if (select.On != null) throw new NotSupportedQueryFragmentException("Unsupported ON clause", select.On); - if (select.WithCtesAndXmlNamespaces != null) - throw new NotSupportedQueryFragmentException("Unsupported CTE clause", select.WithCtesAndXmlNamespaces); - var variableAssignments = new List(); SelectElement firstNonSetSelectElement = null; @@ -3471,6 +3500,9 @@ private IDataExecutionPlanNodeInternal ConvertTableReference(TableReference refe { if (reference is NamedTableReference table) { + if (table.SchemaObject.Identifiers.Count == 1 && _cteSubplans.TryGetValue(table.SchemaObject.BaseIdentifier.Value, out var cteSubplan)) + return cteSubplan; + var dataSource = SelectDataSource(table.SchemaObject); var entityName = table.SchemaObject.BaseIdentifier.Value; diff --git a/MarkMpn.Sql4Cds.Tests/AutocompleteTests.cs b/MarkMpn.Sql4Cds.Tests/AutocompleteTests.cs index 08d78322..81fa4c11 100644 --- a/MarkMpn.Sql4Cds.Tests/AutocompleteTests.cs +++ b/MarkMpn.Sql4Cds.Tests/AutocompleteTests.cs @@ -390,5 +390,19 @@ DECLARE @x varchar CollectionAssert.IsSubsetOf(new[] { "@i", "@x", "@@ROWCOUNT", "@@IDENTITY", "@@SERVERNAME", "@@VERSION" }, suggestions); } + + [TestMethod] + public void SuggestVariablesWithoutFrom() + { + var sql = @" + DECLARE @i int + DECLARE @x varchar + + SELECT "; + + var suggestions = _autocomplete.GetSuggestions(sql, sql.Length - 1).Select(s => s.Text).ToList(); + + CollectionAssert.IsSubsetOf(new[] { "@i", "@x", "@@ROWCOUNT", "@@IDENTITY", "@@SERVERNAME", "@@VERSION" }, suggestions); + } } } From c07a8cc5d9b6ea877bca46e069707f2a1d0fc34e Mon Sep 17 00:00:00 2001 From: Mark Carrington Date: Tue, 5 Sep 2023 19:03:03 +0100 Subject: [PATCH 02/81] Allow using TDS Endpoint for non-recursive CTEs --- .../ExecutionPlanBuilder.cs | 5 +- .../MarkMpn.Sql4Cds.Engine.projitems | 2 + .../Visitors/CteValidatorVisitor.cs | 144 ++++++++++++++++++ .../ReplaceCtesWithSubqueriesVisitor.cs | 109 +++++++++++++ .../TDSEndpointCompatibilityVisitor.cs | 120 +++++++++++++-- 5 files changed, 370 insertions(+), 10 deletions(-) create mode 100644 MarkMpn.Sql4Cds.Engine/Visitors/CteValidatorVisitor.cs create mode 100644 MarkMpn.Sql4Cds.Engine/Visitors/ReplaceCtesWithSubqueriesVisitor.cs diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs index 73102aaa..3f6256dd 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs @@ -98,7 +98,7 @@ public IRootExecutionPlanNode[] Build(string sql, IDictionary + @@ -139,6 +140,7 @@ + diff --git a/MarkMpn.Sql4Cds.Engine/Visitors/CteValidatorVisitor.cs b/MarkMpn.Sql4Cds.Engine/Visitors/CteValidatorVisitor.cs new file mode 100644 index 00000000..2eb5131d --- /dev/null +++ b/MarkMpn.Sql4Cds.Engine/Visitors/CteValidatorVisitor.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.SqlServer.TransactSql.ScriptDom; + +namespace MarkMpn.Sql4Cds.Engine.Visitors +{ + /// + /// Checks the properties of a CTE to ensure it is valid + /// + /// + /// https://learn.microsoft.com/en-us/sql/t-sql/queries/with-common-table-expression-transact-sql?view=sql-server-ver16 + /// + class CteValidatorVisitor : TSqlFragmentVisitor + { + private int _cteReferenceCount; + private FunctionCall _scalarAggregate; + private ScalarSubquery _subquery; + private QualifiedJoin _outerJoin; + + public string Name { get; private set; } + + public bool IsRecursive { get; private set; } + + public override void Visit(CommonTableExpression node) + { + Name = node.ExpressionName.Value; + + base.Visit(node); + } + + public override void Visit(FromClause node) + { + _cteReferenceCount = 0; + + base.Visit(node); + + // The FROM clause of a recursive member must refer only one time to the CTE expression_name. + if (_cteReferenceCount > 1) + throw new NotSupportedQueryFragmentException("Recursive CTEs can only be referenced once", node); + } + + public override void Visit(NamedTableReference node) + { + if (node.SchemaObject.Identifiers.Count == 1 && + node.SchemaObject.BaseIdentifier.Value.Equals(Name, StringComparison.OrdinalIgnoreCase)) + { + IsRecursive = true; + _cteReferenceCount++; + + // The following items aren't allowed in the CTE_query_definition of a recursive member: + // A hint applied to a recursive reference to a CTE inside a CTE_query_definition. + if (node.TableHints.Count > 0) + throw new NotSupportedQueryFragmentException("Table hints are not supported in CTEs", node.TableHints[0]); + } + + base.Visit(node); + } + + public override void Visit(QualifiedJoin node) + { + base.Visit(node); + + if (node.QualifiedJoinType != QualifiedJoinType.Inner) + _outerJoin = node; + } + + public override void ExplicitVisit(BinaryQueryExpression node) + { + base.ExplicitVisit(node); + + // UNION ALL is the only set operator allowed between the last anchor member and first recursive member, and when combining multiple recursive members. + if (IsRecursive && (node.BinaryQueryExpressionType != BinaryQueryExpressionType.Union || !node.All)) + throw new NotSupportedQueryFragmentException("Recursive CTEs must have a UNION ALL between the anchor and recursive parts", node); + } + + public override void Visit(QuerySpecification node) + { + _scalarAggregate = null; + _subquery = null; + _outerJoin = null; + + base.Visit(node); + + // The following clauses can't be used in the CTE_query_definition: + // ORDER BY (except when a TOP clause is specified) + if (node.OrderByClause != null && node.TopRowFilter == null) + throw new NotSupportedQueryFragmentException("ORDER BY is not supported in CTEs", node.OrderByClause); + + // FOR BROWSE + if (node.ForClause is BrowseForClause) + throw new NotSupportedQueryFragmentException("FOR BROWSE is not supported in CTEs", node.ForClause); + + if (IsRecursive) + { + // The following items aren't allowed in the CTE_query_definition of a recursive member: + // SELECT DISTINCT + if (node.UniqueRowFilter == UniqueRowFilter.Distinct) + throw new NotSupportedQueryFragmentException("DISTINCT is not supported in CTEs", node); + + // GROUP BY + if (node.GroupByClause != null) + throw new NotSupportedQueryFragmentException("GROUP BY is not supported in CTEs", node.GroupByClause); + + // TODO: PIVOT + + // HAVING + if (node.HavingClause != null) + throw new NotSupportedQueryFragmentException("HAVING is not supported in CTEs", node.HavingClause); + + // Scalar aggregation + if (_scalarAggregate != null) + throw new NotSupportedQueryFragmentException("Scalar aggregation is not supported in CTEs", _scalarAggregate); + + // TOP + if (node.TopRowFilter != null) + throw new NotSupportedQueryFragmentException("TOP is not supported in CTEs", node.TopRowFilter); + + // LEFT, RIGHT, OUTER JOIN (INNER JOIN is allowed) + if (_outerJoin != null) + throw new NotSupportedQueryFragmentException("Outer joins are not supported in CTEs", _outerJoin); + + // Subqueries + if (_subquery != null) + throw new NotSupportedQueryFragmentException("Subqueries are not supported in CTEs", _subquery); + } + } + + public override void Visit(SelectStatement node) + { + base.Visit(node); + + // The following clauses can't be used in the CTE_query_definition: + // INTO + if (node.Into != null) + throw new NotSupportedQueryFragmentException("INTO is not supported in CTEs", node.Into); + + // OPTION clause with query hints + if (node.OptimizerHints.Count > 0) + throw new NotSupportedQueryFragmentException("Optimizer hints are not supported in CTEs", node.OptimizerHints[0]); + + } + } +} diff --git a/MarkMpn.Sql4Cds.Engine/Visitors/ReplaceCtesWithSubqueriesVisitor.cs b/MarkMpn.Sql4Cds.Engine/Visitors/ReplaceCtesWithSubqueriesVisitor.cs new file mode 100644 index 00000000..ff55c91c --- /dev/null +++ b/MarkMpn.Sql4Cds.Engine/Visitors/ReplaceCtesWithSubqueriesVisitor.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.SqlServer.TransactSql.ScriptDom; + +namespace MarkMpn.Sql4Cds.Engine.Visitors +{ + /// + /// Finds references to non-recursive CTEs and replaces them with subqueries + /// + class ReplaceCtesWithSubqueriesVisitor : TSqlFragmentVisitor + { + private Dictionary _cteQueries; + + public ReplaceCtesWithSubqueriesVisitor() + { + _cteQueries = new Dictionary(StringComparer.OrdinalIgnoreCase); + } + + public override void Visit(CommonTableExpression node) + { + base.Visit(node); + + _cteQueries[node.ExpressionName.Value] = node; + } + + public override void Visit(SelectStatement node) + { + // Visit the CTEs first + if (node.WithCtesAndXmlNamespaces != null) + node.WithCtesAndXmlNamespaces.Accept(this); + + base.Visit(node); + + // Should have visited the CTEs now, so remove them from the query + node.WithCtesAndXmlNamespaces = null; + } + + public override void Visit(FromClause node) + { + base.Visit(node); + + for (var i = 0; i < node.TableReferences.Count; i++) + { + if (node.TableReferences[i] is NamedTableReference ntr && + TryGetCteDefinition(ntr, out var subquery)) + { + node.TableReferences[i] = subquery; + } + } + } + + public override void Visit(QualifiedJoin node) + { + base.Visit(node); + + if (node.FirstTableReference is NamedTableReference table1 && + TryGetCteDefinition(table1, out var subquery1)) + { + node.FirstTableReference = subquery1; + } + + if (node.SecondTableReference is NamedTableReference table2 && + TryGetCteDefinition(table2, out var subquery2)) + { + node.SecondTableReference = subquery2; + } + } + + public override void Visit(UnqualifiedJoin node) + { + base.Visit(node); + + if (node.FirstTableReference is NamedTableReference table1 && + TryGetCteDefinition(table1, out var subquery1)) + { + node.FirstTableReference = subquery1; + } + + if (node.SecondTableReference is NamedTableReference table2 && + TryGetCteDefinition(table2, out var subquery2)) + { + node.SecondTableReference = subquery2; + } + } + + private bool TryGetCteDefinition(NamedTableReference table, out QueryDerivedTable subquery) + { + subquery = null; + + if (table.SchemaObject.Identifiers.Count > 1) + return false; + + if (!_cteQueries.TryGetValue(table.SchemaObject.BaseIdentifier.Value, out var cte)) + return false; + + subquery = new QueryDerivedTable + { + Alias = table.Alias ?? cte.ExpressionName, + QueryExpression = cte.QueryExpression + }; + + foreach (var col in cte.Columns) + subquery.Columns.Add(col); + + return true; + } + } +} diff --git a/MarkMpn.Sql4Cds.Engine/Visitors/TDSEndpointCompatibilityVisitor.cs b/MarkMpn.Sql4Cds.Engine/Visitors/TDSEndpointCompatibilityVisitor.cs index 051267b4..77488f7f 100644 --- a/MarkMpn.Sql4Cds.Engine/Visitors/TDSEndpointCompatibilityVisitor.cs +++ b/MarkMpn.Sql4Cds.Engine/Visitors/TDSEndpointCompatibilityVisitor.cs @@ -19,6 +19,7 @@ class TDSEndpointCompatibilityVisitor : TSqlFragmentVisitor private readonly IAttributeMetadataCache _metadata; private readonly Dictionary _tableNames; private readonly HashSet _supportedTables; + private readonly Dictionary _ctes; private bool? _isEntireBatch; private TSqlFragment _root; @@ -35,6 +36,7 @@ public TDSEndpointCompatibilityVisitor(IDbConnection con, IAttributeMetadataCach _con = con; _metadata = metadata; _tableNames = new Dictionary(StringComparer.OrdinalIgnoreCase); + _ctes = new Dictionary(StringComparer.OrdinalIgnoreCase); _isEntireBatch = isEntireBatch; if (outerTableNames != null) @@ -68,6 +70,8 @@ public TDSEndpointCompatibilityVisitor(IDbConnection con, IAttributeMetadataCach public bool IsCompatible { get; private set; } + public bool RequiresCteRewrite { get; private set; } + public override void Visit(TSqlFragment node) { if (_root == null) @@ -93,9 +97,10 @@ public override void Visit(NamedTableReference node) return; } - if (_supportedTables != null && !_supportedTables.Contains(node.SchemaObject.BaseIdentifier.Value)) + if (_supportedTables != null && !_supportedTables.Contains(node.SchemaObject.BaseIdentifier.Value) && + (node.SchemaObject.Identifiers.Count != 1 || !_ctes.ContainsKey(node.SchemaObject.BaseIdentifier.Value))) { - // Table does not exist in TDS endpoint + // Table does not exist in TDS endpoint and is not defined as a CTE IsCompatible = false; return; } @@ -121,15 +126,34 @@ public override void Visit(ColumnReferenceExpression node) // Table name not specified. Try to find it in the list of current tables foreach (var table in _tableNames.Values) { - var attribute = TryGetEntity(table)?.Attributes?.SingleOrDefault(a => a.LogicalName.Equals(columnName)); - - if (!AttributeIsSupported(attribute)) + if (GetCTECols(table, out var cols)) + { + if (!cols.Contains(columnName)) + { + IsCompatible = false; + return; + } + } + else { - IsCompatible = false; - return; + var attribute = TryGetEntity(table)?.Attributes?.SingleOrDefault(a => a.LogicalName.Equals(columnName)); + + if (!AttributeIsSupported(attribute)) + { + IsCompatible = false; + return; + } } } } + else if (GetCTECols(node.MultiPartIdentifier[0].Value, out var cols)) + { + if (!cols.Contains(columnName)) + { + IsCompatible = false; + return; + } + } else { var attribute = TryGetEntity(node.MultiPartIdentifier[0].Value)?.Attributes?.SingleOrDefault(a => a.LogicalName.Equals(columnName)); @@ -145,6 +169,51 @@ public override void Visit(ColumnReferenceExpression node) base.Visit(node); } + private bool GetCTECols(string cteName, out HashSet cols) + { + cols = null; + + if (!_ctes.TryGetValue(cteName, out var cte)) + return false; + + cols = new HashSet(StringComparer.OrdinalIgnoreCase); + + if (cte.Columns.Count > 0) + { + foreach (var col in cte.Columns) + cols.Add(col.Value); + } + else + { + var query = cte.QueryExpression; + + while (query is BinaryQueryExpression bin) + query = bin.FirstQueryExpression; + + if (!(query is QuerySpecification spec)) + return false; + + // Can't easily work out the column names that will be produced by a SELECT * within a CTE + if (spec.SelectElements.OfType().Any()) + return false; + + foreach (var col in spec.SelectElements.OfType()) + { + if (!(col is SelectScalarExpression sse)) + return false; + + if (sse.ColumnName != null) + cols.Add(sse.ColumnName.Value); + else if (sse.Expression is ColumnReferenceExpression cre) + cols.Add(cre.MultiPartIdentifier.Identifiers.Last().Value); + else + return false; + } + } + + return true; + } + private EntityMetadata TryGetEntity(string logicalname) { if (_tableNames.TryGetValue(logicalname, out var tableName)) @@ -230,6 +299,9 @@ public override void Visit(ScalarSubquery node) if (!subVisitor.IsCompatible) IsCompatible = false; + if (subVisitor.RequiresCteRewrite) + RequiresCteRewrite = true; + return; } @@ -247,27 +319,39 @@ public override void Visit(QueryDerivedTable node) if (!subVisitor.IsCompatible) IsCompatible = false; + if (subVisitor.RequiresCteRewrite) + RequiresCteRewrite = true; + return; } base.Visit(node); } - public override void Visit(SelectStatement node) + public override void ExplicitVisit(SelectStatement node) { // Name resolution needs to be scoped to the query, so create a new sub-visitor if (IsCompatible && _root != node) { var subVisitor = new TDSEndpointCompatibilityVisitor(_con, _metadata, _isEntireBatch, supportedTables: _supportedTables); + subVisitor._root = node; + + // Visit CTEs first + if (node.WithCtesAndXmlNamespaces != null) + node.WithCtesAndXmlNamespaces.Accept(subVisitor); + node.Accept(subVisitor); if (!subVisitor.IsCompatible) IsCompatible = false; + if (subVisitor.RequiresCteRewrite) + RequiresCteRewrite = true; + return; } - base.Visit(node); + base.ExplicitVisit(node); } public override void Visit(QuerySpecification node) @@ -318,5 +402,23 @@ public override void Visit(DistinctPredicate node) // Can't use IS [NOT] DISTINCT FROM IsCompatible = false; } + + public override void Visit(CommonTableExpression node) + { + var cteValidator = new CteValidatorVisitor(); + node.Accept(cteValidator); + + if (cteValidator.IsRecursive) + { + IsCompatible = false; + } + else + { + // TDS Endpoint doesn't support CTEs but we can rewrite non-recursive ones as subqueries + RequiresCteRewrite = true; + } + + _ctes[node.ExpressionName.Value] = node; + } } } From 91373210bba48b20fecef9050c9b70fb231e28a1 Mon Sep 17 00:00:00 2001 From: Mark Carrington Date: Tue, 5 Sep 2023 21:58:34 +0100 Subject: [PATCH 03/81] More simple tests --- MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs | 67 +++++++++++++++++++ .../ExecutionPlan/AliasNode.cs | 12 +++- .../ExecutionPlanBuilder.cs | 13 +++- 3 files changed, 88 insertions(+), 4 deletions(-) diff --git a/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs b/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs index c79e2e12..ac48da0a 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs +++ b/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs @@ -109,6 +109,73 @@ WITH cte AS (SELECT accountid, name FROM account) "); } + [TestMethod] + public void MergeFilters() + { + var planBuilder = new ExecutionPlanBuilder(_localDataSource.Values, this); + + var query = @" + WITH cte AS (SELECT contactid, firstname, lastname FROM contact WHERE firstname = 'Mark') + SELECT * FROM cte WHERE lastname = 'Carrington'"; + + var plans = planBuilder.Build(query, null, out _); + + Assert.AreEqual(1, plans.Length); + + var select = AssertNode(plans[0]); + var fetch = AssertNode(select.Source); + AssertFetchXml(fetch, @" + + + + + + + + + + + "); + } + + [TestMethod] + public void MultipleReferencesWithAliases() + { + var planBuilder = new ExecutionPlanBuilder(_localDataSource.Values, this); + + var query = @" + WITH cte AS (SELECT contactid, firstname, lastname FROM contact WHERE firstname = 'Mark') + SELECT * FROM cte a INNER JOIN cte b ON a.lastname = b.lastname"; + + var plans = planBuilder.Build(query, null, out _); + + Assert.AreEqual(1, plans.Length); + + var select = AssertNode(plans[0]); + var fetch = AssertNode(select.Source); + AssertFetchXml(fetch, @" + + + + + + + + + + + + + + + + + + + + "); + } + private T AssertNode(IExecutionPlanNode node) where T : IExecutionPlanNode { Assert.IsInstanceOfType(node, typeof(T)); diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/AliasNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/AliasNode.cs index a1a6364d..3a5f1185 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/AliasNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/AliasNode.cs @@ -291,7 +291,17 @@ public override object Clone() }; clone.Source.Parent = clone; - clone.ColumnSet.AddRange(ColumnSet); + + foreach (var col in ColumnSet) + { + clone.ColumnSet.Add(new SelectColumn + { + AllColumns = col.AllColumns, + OutputColumn = col.OutputColumn, + SourceColumn = col.SourceColumn, + SourceExpression = col.SourceExpression, + }); + } return clone; } diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs index 3f6256dd..e1a468f5 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs @@ -20,7 +20,7 @@ class ExecutionPlanBuilder { private ExpressionCompilationContext _staticContext; private NodeCompilationContext _nodeContext; - private Dictionary _cteSubplans; + private Dictionary _cteSubplans; public ExecutionPlanBuilder(IEnumerable dataSources, IQueryExecutionOptions options) { @@ -168,7 +168,7 @@ private void ConvertStatement(TSqlStatement statement, ExecutionPlanOptimizer op IRootExecutionPlanNodeInternal[] plans; IList hints = null; - _cteSubplans = new Dictionary(StringComparer.OrdinalIgnoreCase); + _cteSubplans = new Dictionary(StringComparer.OrdinalIgnoreCase); if (statement is StatementWithCtesAndXmlNamespaces stmtWithCtes) { @@ -3504,7 +3504,14 @@ private IDataExecutionPlanNodeInternal ConvertTableReference(TableReference refe if (reference is NamedTableReference table) { if (table.SchemaObject.Identifiers.Count == 1 && _cteSubplans.TryGetValue(table.SchemaObject.BaseIdentifier.Value, out var cteSubplan)) - return cteSubplan; + { + var aliasNode = (AliasNode)cteSubplan.Clone(); + + if (table.Alias != null) + aliasNode.Alias = table.Alias.Value; + + return aliasNode; + } var dataSource = SelectDataSource(table.SchemaObject); var entityName = table.SchemaObject.BaseIdentifier.Value; From b58822986ea77001174e6124173b67832ca2983e Mon Sep 17 00:00:00 2001 From: Mark Carrington Date: Tue, 5 Sep 2023 22:08:08 +0100 Subject: [PATCH 04/81] Fixed UNION with wildcard columns --- MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs | 35 +++++++++++++++++++ .../ExecutionPlan/ConcatenateNode.cs | 1 + .../ExecutionPlanBuilder.cs | 4 +++ 3 files changed, 40 insertions(+) diff --git a/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs b/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs index ac48da0a..5729deb9 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs +++ b/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs @@ -176,6 +176,41 @@ WITH cte AS (SELECT contactid, firstname, lastname FROM contact WHERE firstname "); } + [TestMethod] + public void MultipleReferencesInUnionAll() + { + var planBuilder = new ExecutionPlanBuilder(_localDataSource.Values, this); + + var query = @" + WITH cte AS (SELECT contactid, firstname, lastname FROM contact WHERE firstname = 'Mark') + SELECT * FROM cte UNION ALL SELECT cte.* FROM cte"; + + var plans = planBuilder.Build(query, null, out _); + + Assert.AreEqual(1, plans.Length); + + var select = AssertNode(plans[0]); + var concat = AssertNode(select.Source); + var fetch1 = AssertNode(concat.Sources[0]); + var fetch2 = AssertNode(concat.Sources[1]); + Assert.AreNotEqual(fetch1, fetch2); + + foreach (var fetch in new[] { fetch1, fetch2 }) + { + AssertFetchXml(fetch, @" + + + + + + + + + + "); + } + } + private T AssertNode(IExecutionPlanNode node) where T : IExecutionPlanNode { Assert.IsInstanceOfType(node, typeof(T)); diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/ConcatenateNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/ConcatenateNode.cs index 6e2419d7..6e017bbb 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/ConcatenateNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/ConcatenateNode.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Microsoft.SqlServer.TransactSql.ScriptDom; using Microsoft.Xrm.Sdk; +using Microsoft.Xrm.Sdk.Query; namespace MarkMpn.Sql4Cds.Engine.ExecutionPlan { diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs index e1a468f5..1e28a235 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs @@ -1818,6 +1818,8 @@ private SelectNode ConvertBinaryQuery(BinaryQueryExpression binary, IList Date: Tue, 5 Sep 2023 22:30:04 +0100 Subject: [PATCH 05/81] Updated error messages to match SQL Server --- MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs | 154 ++++++++++++++++++ .../Visitors/CteValidatorVisitor.cs | 35 ++-- 2 files changed, 176 insertions(+), 13 deletions(-) diff --git a/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs b/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs index 5729deb9..212f17c1 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs +++ b/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs @@ -211,6 +211,160 @@ WITH cte AS (SELECT contactid, firstname, lastname FROM contact WHERE firstname } } + [TestMethod] + [ExpectedException(typeof(NotSupportedQueryFragmentException))] + public void MultipleRecursiveReferences() + { + var planBuilder = new ExecutionPlanBuilder(_localDataSource.Values, this); + + var query = @" + WITH cte AS ( + SELECT contactid, firstname, lastname FROM contact WHERE firstname = 'Mark' + UNION ALL + SELECT cte.* FROM cte a INNER JOIN cte b ON a.lastname = b.lastname + ) + SELECT * FROM cte"; + + planBuilder.Build(query, null, out _); + } + + [TestMethod] + [ExpectedException(typeof(NotSupportedQueryFragmentException))] + public void HintsOnRecursiveReference() + { + var planBuilder = new ExecutionPlanBuilder(_localDataSource.Values, this); + + var query = @" + WITH cte AS ( + SELECT contactid, firstname, lastname FROM contact WHERE firstname = 'Mark' + UNION ALL + SELECT cte.* FROM cte WITH (NOLOCK) + ) + SELECT * FROM cte"; + + planBuilder.Build(query, null, out _); + } + + [TestMethod] + [ExpectedException(typeof(NotSupportedQueryFragmentException))] + public void RecursionWithoutUnionAll() + { + var planBuilder = new ExecutionPlanBuilder(_localDataSource.Values, this); + + var query = @" + WITH cte AS ( + SELECT contactid, firstname, lastname FROM contact WHERE firstname = 'Mark' + UNION + SELECT cte.* FROM cte + ) + SELECT * FROM cte"; + + planBuilder.Build(query, null, out _); + } + + [TestMethod] + [ExpectedException(typeof(NotSupportedQueryFragmentException))] + public void OrderByWithoutTop() + { + var planBuilder = new ExecutionPlanBuilder(_localDataSource.Values, this); + + var query = @" + WITH cte AS ( + SELECT contactid, firstname, lastname FROM contact WHERE firstname = 'Mark' + UNION ALL + SELECT cte.* FROM cte + ORDER BY firstname + ) + SELECT * FROM cte"; + + planBuilder.Build(query, null, out _); + } + + [TestMethod] + [ExpectedException(typeof(NotSupportedQueryFragmentException))] + public void GroupByOnRecursiveReference() + { + var planBuilder = new ExecutionPlanBuilder(_localDataSource.Values, this); + + var query = @" + WITH cte AS ( + SELECT contactid, firstname, lastname FROM contact WHERE firstname = 'Mark' + UNION ALL + SELECT cte.* FROM cte GROUP BY contactid, firstname, lastname + ) + SELECT * FROM cte"; + + planBuilder.Build(query, null, out _); + } + + [TestMethod] + [ExpectedException(typeof(NotSupportedQueryFragmentException))] + public void AggregateOnRecursiveReference() + { + var planBuilder = new ExecutionPlanBuilder(_localDataSource.Values, this); + + var query = @" + WITH cte AS ( + SELECT contactid, firstname, lastname FROM contact WHERE firstname = 'Mark' + UNION ALL + SELECT MIN(contactid), MIN(firstname), MIN(lastname) FROM cte + ) + SELECT * FROM cte"; + + planBuilder.Build(query, null, out _); + } + + [TestMethod] + [ExpectedException(typeof(NotSupportedQueryFragmentException))] + public void TopOnRecursiveReference() + { + var planBuilder = new ExecutionPlanBuilder(_localDataSource.Values, this); + + var query = @" + WITH cte AS ( + SELECT contactid, firstname, lastname FROM contact WHERE firstname = 'Mark' + UNION ALL + SELECT TOP 10 cte.* FROM cte + ) + SELECT * FROM cte"; + + planBuilder.Build(query, null, out _); + } + + [TestMethod] + [ExpectedException(typeof(NotSupportedQueryFragmentException))] + public void OuterJoinOnRecursiveReference() + { + var planBuilder = new ExecutionPlanBuilder(_localDataSource.Values, this); + + var query = @" + WITH cte AS ( + SELECT contactid, firstname, lastname FROM contact WHERE firstname = 'Mark' + UNION ALL + SELECT cte.* FROM contact LEFT OUTER JOIN cte ON contact.lastname = cte.lastname + ) + SELECT * FROM cte"; + + planBuilder.Build(query, null, out _); + } + + [TestMethod] + [ExpectedException(typeof(NotSupportedQueryFragmentException))] + public void SubqueryOnRecursiveReference() + { + var planBuilder = new ExecutionPlanBuilder(_localDataSource.Values, this); + + var query = @" + WITH cte AS ( + SELECT contactid, firstname, lastname FROM contact WHERE firstname = 'Mark' + UNION ALL + SELECT contactid, firstname, lastname FROM contact WHERE lastname IN (SELECT lastname FROM cte) + ) + SELECT * FROM cte"; + + planBuilder.Build(query, null, out _); + } + private T AssertNode(IExecutionPlanNode node) where T : IExecutionPlanNode { Assert.IsInstanceOfType(node, typeof(T)); diff --git a/MarkMpn.Sql4Cds.Engine/Visitors/CteValidatorVisitor.cs b/MarkMpn.Sql4Cds.Engine/Visitors/CteValidatorVisitor.cs index 2eb5131d..19378ce5 100644 --- a/MarkMpn.Sql4Cds.Engine/Visitors/CteValidatorVisitor.cs +++ b/MarkMpn.Sql4Cds.Engine/Visitors/CteValidatorVisitor.cs @@ -37,7 +37,7 @@ public override void Visit(FromClause node) // The FROM clause of a recursive member must refer only one time to the CTE expression_name. if (_cteReferenceCount > 1) - throw new NotSupportedQueryFragmentException("Recursive CTEs can only be referenced once", node); + throw new NotSupportedQueryFragmentException($"Recursive member of a common table expression '{Name}' has multiple recursive references.", node); } public override void Visit(NamedTableReference node) @@ -51,7 +51,7 @@ public override void Visit(NamedTableReference node) // The following items aren't allowed in the CTE_query_definition of a recursive member: // A hint applied to a recursive reference to a CTE inside a CTE_query_definition. if (node.TableHints.Count > 0) - throw new NotSupportedQueryFragmentException("Table hints are not supported in CTEs", node.TableHints[0]); + throw new NotSupportedQueryFragmentException($"Hints are not allowed on recursive common table expression (CTE) references. Consider removing hint from recursive CTE reference '{node.SchemaObject.ToSql()}'.", node.TableHints[0]); } base.Visit(node); @@ -71,7 +71,7 @@ public override void ExplicitVisit(BinaryQueryExpression node) // UNION ALL is the only set operator allowed between the last anchor member and first recursive member, and when combining multiple recursive members. if (IsRecursive && (node.BinaryQueryExpressionType != BinaryQueryExpressionType.Union || !node.All)) - throw new NotSupportedQueryFragmentException("Recursive CTEs must have a UNION ALL between the anchor and recursive parts", node); + throw new NotSupportedQueryFragmentException($"Recursive common table expression '{Name}' does not contain a top-level UNION ALL operator", node); } public override void Visit(QuerySpecification node) @@ -85,44 +85,44 @@ public override void Visit(QuerySpecification node) // The following clauses can't be used in the CTE_query_definition: // ORDER BY (except when a TOP clause is specified) if (node.OrderByClause != null && node.TopRowFilter == null) - throw new NotSupportedQueryFragmentException("ORDER BY is not supported in CTEs", node.OrderByClause); + throw new NotSupportedQueryFragmentException("The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP, OFFSET or FOR XML is also specified", node.OrderByClause); // FOR BROWSE if (node.ForClause is BrowseForClause) - throw new NotSupportedQueryFragmentException("FOR BROWSE is not supported in CTEs", node.ForClause); + throw new NotSupportedQueryFragmentException("The FOR BROWSE clause is no longer supported in views", node.ForClause); if (IsRecursive) { // The following items aren't allowed in the CTE_query_definition of a recursive member: // SELECT DISTINCT if (node.UniqueRowFilter == UniqueRowFilter.Distinct) - throw new NotSupportedQueryFragmentException("DISTINCT is not supported in CTEs", node); + throw new NotSupportedQueryFragmentException($"DISTINCT operator is not allowed in the recursive part of a recursive common table expression '{Name}'.", node); // GROUP BY if (node.GroupByClause != null) - throw new NotSupportedQueryFragmentException("GROUP BY is not supported in CTEs", node.GroupByClause); + throw new NotSupportedQueryFragmentException($"GROUP BY, HAVING, or aggregate functions are not allowed in the recursive part of a recursive common table expression '{Name}'", node.GroupByClause); // TODO: PIVOT // HAVING if (node.HavingClause != null) - throw new NotSupportedQueryFragmentException("HAVING is not supported in CTEs", node.HavingClause); + throw new NotSupportedQueryFragmentException($"GROUP BY, HAVING, or aggregate functions are not allowed in the recursive part of a recursive common table expression '{Name}'", node.HavingClause); // Scalar aggregation if (_scalarAggregate != null) - throw new NotSupportedQueryFragmentException("Scalar aggregation is not supported in CTEs", _scalarAggregate); + throw new NotSupportedQueryFragmentException($"GROUP BY, HAVING, or aggregate functions are not allowed in the recursive part of a recursive common table expression '{Name}'", _scalarAggregate); // TOP - if (node.TopRowFilter != null) - throw new NotSupportedQueryFragmentException("TOP is not supported in CTEs", node.TopRowFilter); + if (node.TopRowFilter != null || node.OffsetClause != null) + throw new NotSupportedQueryFragmentException($"The TOP or OFFSET operator is not allowed in the recursive part of a recursive common table expression '{Name}'", (TSqlFragment)node.TopRowFilter ?? node.OffsetClause); // LEFT, RIGHT, OUTER JOIN (INNER JOIN is allowed) if (_outerJoin != null) - throw new NotSupportedQueryFragmentException("Outer joins are not supported in CTEs", _outerJoin); + throw new NotSupportedQueryFragmentException($"Outer join is not allowed in the recursive part of a recursive common table expression '{Name}'", _outerJoin); // Subqueries if (_subquery != null) - throw new NotSupportedQueryFragmentException("Subqueries are not supported in CTEs", _subquery); + throw new NotSupportedQueryFragmentException("Recursive references are not allowed in subqueries", _subquery); } } @@ -138,7 +138,16 @@ public override void Visit(SelectStatement node) // OPTION clause with query hints if (node.OptimizerHints.Count > 0) throw new NotSupportedQueryFragmentException("Optimizer hints are not supported in CTEs", node.OptimizerHints[0]); + } + + public override void ExplicitVisit(ScalarSubquery node) + { + var count = _cteReferenceCount; + + base.ExplicitVisit(node); + if (_cteReferenceCount > count) + _subquery = node; } } } From fb67a7e91dedad52eaeac6e5eea50fb21a613f87 Mon Sep 17 00:00:00 2001 From: Mark Carrington Date: Wed, 6 Sep 2023 08:23:18 +0100 Subject: [PATCH 06/81] Validate CTEs before trying to convert them --- MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs | 2 +- .../ExecutionPlanBuilder.cs | 30 ++++++++++++------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs b/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs index 212f17c1..e826ffbe 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs +++ b/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs @@ -263,7 +263,7 @@ SELECT cte.* FROM cte } [TestMethod] - [ExpectedException(typeof(NotSupportedQueryFragmentException))] + [ExpectedException(typeof(QueryParseException))] public void OrderByWithoutTop() { var planBuilder = new ExecutionPlanBuilder(_localDataSource.Values, this); diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs index 1e28a235..41a87ce8 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs @@ -181,21 +181,31 @@ private void ConvertStatement(TSqlStatement statement, ExecutionPlanOptimizer op if (_cteSubplans.ContainsKey(cte.ExpressionName.Value)) throw new NotSupportedQueryFragmentException($"A CTE with the name '{cte.ExpressionName.Value}' has already been declared.", cte.ExpressionName); - // If the CTE isn't recursive then we can just convert it to a subquery - var plan = ConvertSelectStatement(cte.QueryExpression, hints, null, null, _nodeContext); + var cteValidator = new CteValidatorVisitor(); + cte.Accept(cteValidator); - // Apply column aliases - if (cte.Columns.Count > 0) + if (!cteValidator.IsRecursive) { - // TODO: What if a different number of columns? + // If the CTE isn't recursive then we can just convert it to a subquery + var plan = ConvertSelectStatement(cte.QueryExpression, hints, null, null, _nodeContext); - plan.ExpandWildcardColumns(_nodeContext); + // Apply column aliases + if (cte.Columns.Count > 0) + { + // TODO: What if a different number of columns? - for (var i = 0; i < cte.Columns.Count; i++) - plan.ColumnSet[i].OutputColumn = cte.Columns[i].Value; - } + plan.ExpandWildcardColumns(_nodeContext); + + for (var i = 0; i < cte.Columns.Count; i++) + plan.ColumnSet[i].OutputColumn = cte.Columns[i].Value; + } - _cteSubplans.Add(cte.ExpressionName.Value, new AliasNode(plan, cte.ExpressionName, _nodeContext)); + _cteSubplans.Add(cte.ExpressionName.Value, new AliasNode(plan, cte.ExpressionName, _nodeContext)); + } + else + { + throw new NotSupportedQueryFragmentException("Recursive CTEs are not yet supported", cte); + } } } } From 9e4616a710cfce6bbd3bf84db66432f6695b9dd2 Mon Sep 17 00:00:00 2001 From: Mark Carrington Date: Wed, 6 Sep 2023 08:31:17 +0100 Subject: [PATCH 07/81] Tests for column aliases --- MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs | 39 +++++++++++++++++++ .../ExecutionPlanBuilder.cs | 8 +++- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs b/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs index e826ffbe..05f094f4 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs +++ b/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs @@ -109,6 +109,30 @@ WITH cte AS (SELECT accountid, name FROM account) "); } + [TestMethod] + public void ColumnAliases() + { + var planBuilder = new ExecutionPlanBuilder(_localDataSource.Values, this); + + var query = @" + WITH cte (id, n) AS (SELECT accountid, name FROM account) + SELECT * FROM cte"; + + var plans = planBuilder.Build(query, null, out _); + + Assert.AreEqual(1, plans.Length); + + var select = AssertNode(plans[0]); + var fetch = AssertNode(select.Source); + AssertFetchXml(fetch, @" + + + + + + "); + } + [TestMethod] public void MergeFilters() { @@ -365,6 +389,21 @@ UNION ALL planBuilder.Build(query, null, out _); } + [TestMethod] + [ExpectedException(typeof(NotSupportedQueryFragmentException))] + public void IncorrectColumnCount() + { + var planBuilder = new ExecutionPlanBuilder(_localDataSource.Values, this); + + var query = @" + WITH cte (id, fname) AS ( + SELECT contactid, firstname, lastname FROM contact WHERE firstname = 'Mark' + ) + SELECT * FROM cte"; + + planBuilder.Build(query, null, out _); + } + private T AssertNode(IExecutionPlanNode node) where T : IExecutionPlanNode { Assert.IsInstanceOfType(node, typeof(T)); diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs index 41a87ce8..8b29aa77 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs @@ -192,10 +192,14 @@ private void ConvertStatement(TSqlStatement statement, ExecutionPlanOptimizer op // Apply column aliases if (cte.Columns.Count > 0) { - // TODO: What if a different number of columns? - plan.ExpandWildcardColumns(_nodeContext); + if (cte.Columns.Count < plan.ColumnSet.Count) + throw new NotSupportedQueryFragmentException($"'{cteValidator.Name}' has more columns than were specified in the column list.", cte); + + if (cte.Columns.Count > plan.ColumnSet.Count) + throw new NotSupportedQueryFragmentException($"'{cteValidator.Name}' has fewer columns than were specified in the column list.", cte); + for (var i = 0; i < cte.Columns.Count; i++) plan.ColumnSet[i].OutputColumn = cte.Columns[i].Value; } From 8e31b544e5296134c86409105593f4a228287607 Mon Sep 17 00:00:00 2001 From: Mark Carrington Date: Thu, 7 Sep 2023 08:36:54 +0100 Subject: [PATCH 08/81] Added tests for calculated columns within CTE --- MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs | 53 +++++++++++++++++++ .../ExecutionPlanBuilder.cs | 6 +++ 2 files changed, 59 insertions(+) diff --git a/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs b/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs index 05f094f4..7e260dc8 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs +++ b/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs @@ -404,6 +404,59 @@ WITH cte (id, fname) AS ( planBuilder.Build(query, null, out _); } + [TestMethod] + [ExpectedException(typeof(NotSupportedQueryFragmentException))] + public void AnonymousColumn() + { + var planBuilder = new ExecutionPlanBuilder(_localDataSource.Values, this); + + var query = @" + WITH cte AS ( + SELECT contactid, firstname + '', lastname FROM contact WHERE firstname = 'Mark' + ) + SELECT * FROM cte"; + + planBuilder.Build(query, null, out _); + } + + [TestMethod] + public void AliasedAnonymousColumn() + { + var planBuilder = new ExecutionPlanBuilder(_localDataSource.Values, this); + + var query = @" + WITH cte (id, fname, lname) AS ( + SELECT contactid, firstname + '', lastname FROM contact WHERE firstname = 'Mark' + ) + SELECT * FROM cte"; + + var plans = planBuilder.Build(query, null, out _); + + Assert.AreEqual(1, plans.Length); + + var select = AssertNode(plans[0]); + Assert.AreEqual("id", select.ColumnSet[0].OutputColumn); + Assert.AreEqual("contact.contactid", select.ColumnSet[0].SourceColumn); + Assert.AreEqual("fname", select.ColumnSet[1].OutputColumn); + Assert.AreEqual("Expr1", select.ColumnSet[1].SourceColumn); + Assert.AreEqual("lname", select.ColumnSet[2].OutputColumn); + Assert.AreEqual("contact.lastname", select.ColumnSet[2].SourceColumn); + var compute = AssertNode(select.Source); + Assert.AreEqual("firstname + ''", compute.Columns["Expr1"].ToSql()); + var fetch = AssertNode(compute.Source); + AssertFetchXml(fetch, @" + + + + + + + + + + "); + } + private T AssertNode(IExecutionPlanNode node) where T : IExecutionPlanNode { Assert.IsInstanceOfType(node, typeof(T)); diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs index 8b29aa77..171e52fe 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs @@ -204,6 +204,12 @@ private void ConvertStatement(TSqlStatement statement, ExecutionPlanOptimizer op plan.ColumnSet[i].OutputColumn = cte.Columns[i].Value; } + for (var i = 0; i < plan.ColumnSet.Count; i++) + { + if (plan.ColumnSet[i].OutputColumn == null) + throw new NotSupportedQueryFragmentException($"No column name was specified for column {i+1} of '{cteValidator.Name}'", cte); + } + _cteSubplans.Add(cte.ExpressionName.Value, new AliasNode(plan, cte.ExpressionName, _nodeContext)); } else From 180694dc93a09295b781d9d506e511250adcd682 Mon Sep 17 00:00:00 2001 From: Mark Carrington Date: Fri, 8 Sep 2023 08:09:33 +0100 Subject: [PATCH 09/81] Build basic structure of recursive CTE plan --- MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs | 62 ++++++++ .../ExecutionPlanBuilder.cs | 133 +++++++++++++++--- .../Visitors/CteValidatorVisitor.cs | 29 +++- 3 files changed, 202 insertions(+), 22 deletions(-) diff --git a/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs b/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs index 7e260dc8..8622a8d5 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs +++ b/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs @@ -133,6 +133,39 @@ WITH cte (id, n) AS (SELECT accountid, name FROM account) "); } + [TestMethod] + public void MultipleAnchorQueries() + { + var planBuilder = new ExecutionPlanBuilder(_localDataSource.Values, this); + + var query = @" + WITH cte (id, n) AS (SELECT accountid, name FROM account UNION ALL select contactid, fullname FROM contact) + SELECT * FROM cte"; + + var plans = planBuilder.Build(query, null, out _); + + Assert.AreEqual(1, plans.Length); + + var select = AssertNode(plans[0]); + var concat = AssertNode(select.Source); + var account = AssertNode(concat.Sources[0]); + AssertFetchXml(account, @" + + + + + + "); + var contact = AssertNode(concat.Sources[1]); + AssertFetchXml(contact, @" + + + + + + "); + } + [TestMethod] public void MergeFilters() { @@ -457,6 +490,35 @@ WITH cte (id, fname, lname) AS ( "); } + [TestMethod] + public void SimpleRecursion() + { + var planBuilder = new ExecutionPlanBuilder(_localDataSource.Values, this); + + var query = @" + WITH cte AS ( + SELECT contactid, firstname, lastname FROM contact WHERE firstname = 'Mark' + UNION ALL + SELECT c.contactid, c.firstname, c.lastname FROM contact c INNER JOIN cte ON c.parentcustomerid = cte.contactid + ) + SELECT * FROM cte"; + + var plans = planBuilder.Build(query, null, out _); + + Assert.AreEqual(1, plans.Length); + + var select = AssertNode(plans[0]); + var spoolProducer = AssertNode(select.Source); + var concat = AssertNode(spoolProducer.Source); + var depth0 = AssertNode(concat.Sources[0]); + var anchor = AssertNode(depth0.Source); + var assert = AssertNode(concat.Sources[1]); + var nestedLoop = AssertNode(assert.Source); + var depthPlus1 = AssertNode(nestedLoop.LeftSource); + var spoolConsumer = AssertNode(depthPlus1); + var children = AssertNode(nestedLoop.RightSource); + } + private T AssertNode(IExecutionPlanNode node) where T : IExecutionPlanNode { Assert.IsInstanceOfType(node, typeof(T)); diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs index 171e52fe..e0498efc 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs @@ -184,38 +184,129 @@ private void ConvertStatement(TSqlStatement statement, ExecutionPlanOptimizer op var cteValidator = new CteValidatorVisitor(); cte.Accept(cteValidator); - if (!cteValidator.IsRecursive) + // Start by converting the anchor query to a subquery + var plan = ConvertSelectStatement(cteValidator.AnchorQuery, hints, null, null, _nodeContext); + + // Apply column aliases + if (cte.Columns.Count > 0) + { + plan.ExpandWildcardColumns(_nodeContext); + + if (cte.Columns.Count < plan.ColumnSet.Count) + throw new NotSupportedQueryFragmentException($"'{cteValidator.Name}' has more columns than were specified in the column list.", cte); + + if (cte.Columns.Count > plan.ColumnSet.Count) + throw new NotSupportedQueryFragmentException($"'{cteValidator.Name}' has fewer columns than were specified in the column list.", cte); + + for (var i = 0; i < cte.Columns.Count; i++) + plan.ColumnSet[i].OutputColumn = cte.Columns[i].Value; + } + + for (var i = 0; i < plan.ColumnSet.Count; i++) + { + if (plan.ColumnSet[i].OutputColumn == null) + throw new NotSupportedQueryFragmentException($"No column name was specified for column {i+1} of '{cteValidator.Name}'", cte); + } + + var anchorQuery = new AliasNode(plan, cte.ExpressionName, _nodeContext); + + if (cteValidator.RecursiveQueries.Count > 0) { - // If the CTE isn't recursive then we can just convert it to a subquery - var plan = ConvertSelectStatement(cte.QueryExpression, hints, null, null, _nodeContext); + var ctePlan = anchorQuery.Source; - // Apply column aliases - if (cte.Columns.Count > 0) + // Add a ComputeScalar node to add the initial recursion depth (0) + var recursionDepthField = _nodeContext.GetExpressionName(); + var initialRecursionDepthComputeScalar = new ComputeScalarNode { - plan.ExpandWildcardColumns(_nodeContext); + Source = ctePlan, + Columns = + { + [recursionDepthField] = new IntegerLiteral { Value = "0" } + } + }; - if (cte.Columns.Count < plan.ColumnSet.Count) - throw new NotSupportedQueryFragmentException($"'{cteValidator.Name}' has more columns than were specified in the column list.", cte); + // Add a ConcatenateNode to combine the anchor results with the recursion results + var recurseConcat = new ConcatenateNode + { + Sources = { initialRecursionDepthComputeScalar }, + }; - if (cte.Columns.Count > plan.ColumnSet.Count) - throw new NotSupportedQueryFragmentException($"'{cteValidator.Name}' has fewer columns than were specified in the column list.", cte); + foreach (var col in anchorQuery.ColumnSet) + { + var concatCol = new ConcatenateColumn + { + SourceColumns = { col.SourceColumn }, + OutputColumn = col.OutputColumn + }; - for (var i = 0; i < cte.Columns.Count; i++) - plan.ColumnSet[i].OutputColumn = cte.Columns[i].Value; + recurseConcat.ColumnSet.Add(concatCol); } - for (var i = 0; i < plan.ColumnSet.Count; i++) + recurseConcat.ColumnSet.Add(new ConcatenateColumn { - if (plan.ColumnSet[i].OutputColumn == null) - throw new NotSupportedQueryFragmentException($"No column name was specified for column {i+1} of '{cteValidator.Name}'", cte); - } + SourceColumns = { recursionDepthField }, + OutputColumn = recursionDepthField + }); - _cteSubplans.Add(cte.ExpressionName.Value, new AliasNode(plan, cte.ExpressionName, _nodeContext)); - } - else - { - throw new NotSupportedQueryFragmentException("Recursive CTEs are not yet supported", cte); + // Add an IndexSpool node in stack mode to enable the recursion + var recurseIndexStack = new IndexSpoolNode + { + Source = recurseConcat, + // TODO: WithStack = true + }; + + // Pull the same records into the recursive loop + var recurseTableSpool = new TableSpoolNode + { + // TODO: Producer = recurseIndexStack + }; + + // Increment the depth + var incrementedDepthField = _nodeContext.GetExpressionName(); + var incrementRecursionDepthComputeScalar = new ComputeScalarNode + { + Source = recurseTableSpool, + Columns = + { + [incrementedDepthField] = new BinaryExpression + { + FirstExpression = recursionDepthField.ToColumnReference(), + BinaryExpressionType = BinaryExpressionType.Add, + SecondExpression = new IntegerLiteral { Value = "1" } + } + } + }; + + // Use a nested loop to pass through the records to the recusive queries + var recurseLoop = new NestedLoopNode + { + LeftSource = incrementRecursionDepthComputeScalar, + // TODO: Capture all CTE fields in the outer references + JoinType = QualifiedJoinType.Inner, + }; + + // Ensure we don't get stuck in an infinite loop + var assert = new AssertNode + { + Source = recurseLoop, + Assertion = e => + { + var depth = e.GetAttributeValue(incrementedDepthField); + return depth.Value < 100; + }, + ErrorMessage = "Recursion depth exceeded" + }; + + // Combine the recursion results into the main results + recurseConcat.Sources.Add(assert); + + // TODO: Update the sources for each field in the concat node + recurseConcat.ColumnSet.Last().SourceColumns.Add(incrementedDepthField); + + anchorQuery.Source = incrementRecursionDepthComputeScalar; } + + _cteSubplans.Add(cte.ExpressionName.Value, new AliasNode(plan, cte.ExpressionName, _nodeContext)); } } } diff --git a/MarkMpn.Sql4Cds.Engine/Visitors/CteValidatorVisitor.cs b/MarkMpn.Sql4Cds.Engine/Visitors/CteValidatorVisitor.cs index 19378ce5..10ab5a61 100644 --- a/MarkMpn.Sql4Cds.Engine/Visitors/CteValidatorVisitor.cs +++ b/MarkMpn.Sql4Cds.Engine/Visitors/CteValidatorVisitor.cs @@ -11,7 +11,7 @@ namespace MarkMpn.Sql4Cds.Engine.Visitors /// /// https://learn.microsoft.com/en-us/sql/t-sql/queries/with-common-table-expression-transact-sql?view=sql-server-ver16 /// - class CteValidatorVisitor : TSqlFragmentVisitor + class CteValidatorVisitor : TSqlConcreteFragmentVisitor { private int _cteReferenceCount; private FunctionCall _scalarAggregate; @@ -22,6 +22,10 @@ class CteValidatorVisitor : TSqlFragmentVisitor public bool IsRecursive { get; private set; } + public QueryExpression AnchorQuery { get; private set; } + + public List RecursiveQueries { get; } = new List(); + public override void Visit(CommonTableExpression node) { Name = node.ExpressionName.Value; @@ -69,11 +73,34 @@ public override void ExplicitVisit(BinaryQueryExpression node) { base.ExplicitVisit(node); + if (!IsRecursive) + AnchorQuery = node; + // UNION ALL is the only set operator allowed between the last anchor member and first recursive member, and when combining multiple recursive members. if (IsRecursive && (node.BinaryQueryExpressionType != BinaryQueryExpressionType.Union || !node.All)) throw new NotSupportedQueryFragmentException($"Recursive common table expression '{Name}' does not contain a top-level UNION ALL operator", node); } + public override void ExplicitVisit(QuerySpecification node) + { + base.ExplicitVisit(node); + + if (!IsRecursive) + AnchorQuery = node; + else + RecursiveQueries.Add(node); + } + + public override void ExplicitVisit(QueryParenthesisExpression node) + { + base.ExplicitVisit(node); + + if (!IsRecursive) + AnchorQuery = node; + else + RecursiveQueries.Add(node); + } + public override void Visit(QuerySpecification node) { _scalarAggregate = null; From 95226dd7c9c86b1bc48fc7445dd81844e57cf7be Mon Sep 17 00:00:00 2001 From: Mark Carrington Date: Sun, 10 Sep 2023 09:19:29 +0100 Subject: [PATCH 10/81] Use MAXRECURSION hint --- .../ExecutionPlanBuilder.cs | 55 +++++++++++++++---- 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs index 011dc965..6ce77050 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs @@ -285,20 +285,55 @@ private void ConvertStatement(TSqlStatement statement, ExecutionPlanOptimizer op JoinType = QualifiedJoinType.Inner, }; + if (cteValidator.RecursiveQueries.Count > 1) + { + // Combine the results of each recursive query with a concat node + var concat = new ConcatenateNode(); + recurseLoop.RightSource = concat; + + foreach (var qry in cteValidator.RecursiveQueries) + concat.Sources.Add(ConvertRecursiveCTEQuery(qry)); + } + else + { + recurseLoop.RightSource = ConvertRecursiveCTEQuery(cteValidator.RecursiveQueries[0]); + } + // Ensure we don't get stuck in an infinite loop - var assert = new AssertNode + var maxRecursion = stmtWithCtes.OptimizerHints + .OfType() + .Where(hint => hint.HintKind == OptimizerHintKind.MaxRecursion) + .FirstOrDefault() + ?.Value + ?.Value + ?? "100"; + + if (!Int32.TryParse(maxRecursion, out var max) || max < 0) + throw new NotSupportedQueryFragmentException("Invalid MAXRECURSION hint", stmtWithCtes.OptimizerHints + .OfType() + .Where(hint => hint.HintKind == OptimizerHintKind.MaxRecursion) + .First()); + + if (max > 0) { - Source = recurseLoop, - Assertion = e => + var assert = new AssertNode { - var depth = e.GetAttributeValue(incrementedDepthField); - return depth.Value < 100; - }, - ErrorMessage = "Recursion depth exceeded" - }; + Source = recurseLoop, + Assertion = e => + { + var depth = e.GetAttributeValue(incrementedDepthField); + return depth.Value < max; + }, + ErrorMessage = "Recursion depth exceeded" + }; - // Combine the recursion results into the main results - recurseConcat.Sources.Add(assert); + // Combine the recursion results into the main results + recurseConcat.Sources.Add(assert); + } + else + { + recurseConcat.Sources.Add(recurseLoop); + } // TODO: Update the sources for each field in the concat node recurseConcat.ColumnSet.Last().SourceColumns.Add(incrementedDepthField); From 2fe11e92fb9245782f3b20f330f6e1da3ce215f3 Mon Sep 17 00:00:00 2001 From: Mark Carrington Date: Sun, 10 Sep 2023 21:58:52 +0100 Subject: [PATCH 11/81] Progress --- .../ExecutionPlanBuilder.cs | 59 ++++++- .../MarkMpn.Sql4Cds.Engine.projitems | 1 + .../Visitors/CteValidatorVisitor.cs | 45 +++-- ...emoveRecursiveCTETableReferencesVisitor.cs | 164 ++++++++++++++++++ 4 files changed, 251 insertions(+), 18 deletions(-) create mode 100644 MarkMpn.Sql4Cds.Engine/Visitors/RemoveRecursiveCTETableReferencesVisitor.cs diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs index 6ce77050..cabd6989 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs @@ -209,6 +209,7 @@ private void ConvertStatement(TSqlStatement statement, ExecutionPlanOptimizer op } var anchorQuery = new AliasNode(plan, cte.ExpressionName, _nodeContext); + _cteSubplans.Add(cte.ExpressionName.Value, anchorQuery); if (cteValidator.RecursiveQueries.Count > 0) { @@ -281,10 +282,16 @@ private void ConvertStatement(TSqlStatement statement, ExecutionPlanOptimizer op var recurseLoop = new NestedLoopNode { LeftSource = incrementRecursionDepthComputeScalar, - // TODO: Capture all CTE fields in the outer references JoinType = QualifiedJoinType.Inner, + OuterReferences = new Dictionary(StringComparer.OrdinalIgnoreCase) }; + // Capture all CTE fields in the outer references + var anchorSchema = anchorQuery.GetSchema(_nodeContext); + + foreach (var col in anchorSchema.Schema) + recurseLoop.OuterReferences[col.Key] = "@" + _nodeContext.GetExpressionName(); + if (cteValidator.RecursiveQueries.Count > 1) { // Combine the results of each recursive query with a concat node @@ -292,11 +299,39 @@ private void ConvertStatement(TSqlStatement statement, ExecutionPlanOptimizer op recurseLoop.RightSource = concat; foreach (var qry in cteValidator.RecursiveQueries) - concat.Sources.Add(ConvertRecursiveCTEQuery(qry)); + { + var rightSource = ConvertRecursiveCTEQuery(qry, anchorSchema, cteValidator, recurseLoop.OuterReferences); + concat.Sources.Add(rightSource.Source); + + if (concat.Sources.Count == 1) + { + for (var i = 0; i < rightSource.ColumnSet.Count; i++) + { + var col = rightSource.ColumnSet[i]; + var expr = _nodeContext.GetExpressionName(); + concat.ColumnSet.Add(new ConcatenateColumn { OutputColumn = expr }); + recurseLoop.DefinedValues.Add(expr, expr); + recurseConcat.ColumnSet[i].SourceColumns.Add(expr); + } + } + + for (var i = 0; i < rightSource.ColumnSet.Count; i++) + concat.ColumnSet[i].SourceColumns.Add(rightSource.ColumnSet[i].SourceColumn); + } } else { - recurseLoop.RightSource = ConvertRecursiveCTEQuery(cteValidator.RecursiveQueries[0]); + var rightSource = ConvertRecursiveCTEQuery(cteValidator.RecursiveQueries[0], anchorSchema, cteValidator, recurseLoop.OuterReferences); + recurseLoop.RightSource = rightSource.Source; + + for (var i = 0; i < rightSource.ColumnSet.Count; i++) + { + var col = rightSource.ColumnSet[i]; + var expr = _nodeContext.GetExpressionName(); + + recurseLoop.DefinedValues.Add(expr, col.SourceColumn); + recurseConcat.ColumnSet[i].SourceColumns.Add(expr); + } } // Ensure we don't get stuck in an infinite loop @@ -335,13 +370,10 @@ private void ConvertStatement(TSqlStatement statement, ExecutionPlanOptimizer op recurseConcat.Sources.Add(recurseLoop); } - // TODO: Update the sources for each field in the concat node recurseConcat.ColumnSet.Last().SourceColumns.Add(incrementedDepthField); anchorQuery.Source = incrementRecursionDepthComputeScalar; } - - _cteSubplans.Add(cte.ExpressionName.Value, new AliasNode(plan, cte.ExpressionName, _nodeContext)); } } } @@ -402,6 +434,21 @@ private void ConvertStatement(TSqlStatement statement, ExecutionPlanOptimizer op } } + private SelectNode ConvertRecursiveCTEQuery(QueryExpression queryExpression, INodeSchema anchorSchema, CteValidatorVisitor cteValidator, Dictionary outerReferences) + { + // Convert the query using the anchor query as a subquery to check for ambiguous column names + ConvertSelectStatement(queryExpression, null, null, null, _nodeContext); + + // Remove recursive references from the FROM clause, moving join predicates to the WHERE clause + // If the recursive reference was in an unqualified join, replace it with (SELECT @Expr1, @Expr2) AS cte (field1, field2) + // Otherwise, remove it entirely and replace column references with variables + var cteReplacer = new RemoveRecursiveCTETableReferencesVisitor(cteValidator.Name, anchorSchema.Schema.Keys.ToArray(), outerReferences); + queryExpression.Accept(cteReplacer); + + // Convert the modified query. + return ConvertSelectStatement(queryExpression, null, anchorSchema, outerReferences, _nodeContext); + } + private IRootExecutionPlanNodeInternal[] ConvertExecuteStatement(ExecuteStatement execute) { var nodes = new List(); diff --git a/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.projitems b/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.projitems index 3b3db435..ab0d4ccd 100644 --- a/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.projitems +++ b/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.projitems @@ -140,6 +140,7 @@ + diff --git a/MarkMpn.Sql4Cds.Engine/Visitors/CteValidatorVisitor.cs b/MarkMpn.Sql4Cds.Engine/Visitors/CteValidatorVisitor.cs index 10ab5a61..a022596f 100644 --- a/MarkMpn.Sql4Cds.Engine/Visitors/CteValidatorVisitor.cs +++ b/MarkMpn.Sql4Cds.Engine/Visitors/CteValidatorVisitor.cs @@ -81,16 +81,6 @@ public override void ExplicitVisit(BinaryQueryExpression node) throw new NotSupportedQueryFragmentException($"Recursive common table expression '{Name}' does not contain a top-level UNION ALL operator", node); } - public override void ExplicitVisit(QuerySpecification node) - { - base.ExplicitVisit(node); - - if (!IsRecursive) - AnchorQuery = node; - else - RecursiveQueries.Add(node); - } - public override void ExplicitVisit(QueryParenthesisExpression node) { base.ExplicitVisit(node); @@ -101,13 +91,13 @@ public override void ExplicitVisit(QueryParenthesisExpression node) RecursiveQueries.Add(node); } - public override void Visit(QuerySpecification node) + public override void ExplicitVisit(QuerySpecification node) { _scalarAggregate = null; _subquery = null; _outerJoin = null; - base.Visit(node); + base.ExplicitVisit(node); // The following clauses can't be used in the CTE_query_definition: // ORDER BY (except when a TOP clause is specified) @@ -151,6 +141,11 @@ public override void Visit(QuerySpecification node) if (_subquery != null) throw new NotSupportedQueryFragmentException("Recursive references are not allowed in subqueries", _subquery); } + + if (!IsRecursive) + AnchorQuery = node; + else + RecursiveQueries.Add(node); } public override void Visit(SelectStatement node) @@ -176,5 +171,31 @@ public override void ExplicitVisit(ScalarSubquery node) if (_cteReferenceCount > count) _subquery = node; } + + public override void Visit(FunctionCall node) + { + base.Visit(node); + + switch (node.FunctionName.Value.ToLowerInvariant()) + { + case "approx_count_distinct": + case "avg": + case "checksum_agg": + case "count": + case "count_big": + case "grouping": + case "grouping_id": + case "max": + case "min": + case "stdev": + case "stdevp": + case "string_agg": + case "sum": + case "var": + case "varp": + _scalarAggregate = node; + break; + } + } } } diff --git a/MarkMpn.Sql4Cds.Engine/Visitors/RemoveRecursiveCTETableReferencesVisitor.cs b/MarkMpn.Sql4Cds.Engine/Visitors/RemoveRecursiveCTETableReferencesVisitor.cs new file mode 100644 index 00000000..06ab4e5f --- /dev/null +++ b/MarkMpn.Sql4Cds.Engine/Visitors/RemoveRecursiveCTETableReferencesVisitor.cs @@ -0,0 +1,164 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.SqlServer.TransactSql.ScriptDom; + +namespace MarkMpn.Sql4Cds.Engine.Visitors +{ + /// + /// Finds recursive references in a CTE definition and removes them, moving join predicates to the WHERE clause + /// + class RemoveRecursiveCTETableReferencesVisitor : TSqlConcreteFragmentVisitor + { + private readonly string _name; + private readonly string[] _columnNames; + private readonly Dictionary _outerReferences; + private BooleanExpression _joinPredicate; + private int _inUnqualifiedJoin; + + public RemoveRecursiveCTETableReferencesVisitor(string name, string[] columnNames, Dictionary outerReferences) + { + _name = name; + _columnNames = columnNames; + _outerReferences = outerReferences; + } + + private bool IsRecursiveReference(TableReference tableReference) + { + if (!(tableReference is NamedTableReference namedTable)) + return false; + + if (namedTable.SchemaObject.Identifiers.Count != 1) + return false; + + return namedTable.SchemaObject.BaseIdentifier.Value.Equals(_name, StringComparison.OrdinalIgnoreCase); + } + + private InlineDerivedTable CreateInlineDerivedTable() + { + var table = new InlineDerivedTable + { + Alias = new Identifier { Value = _name }, + RowValues = { new RowValue() } + }; + + foreach (var col in _columnNames) + { + table.Columns.Add(new Identifier { Value = col }); + table.RowValues[0].ColumnValues.Add(new VariableReference { Name = _outerReferences[col] }); + } + + return table; + } + + private bool RemoveRecursiveJoin(TableReference tableReference, out TableReference removed) + { + removed = null; + + if (!(tableReference is JoinTableReference join)) + return false; + + if (IsRecursiveReference(join.FirstTableReference)) + { + if (_inUnqualifiedJoin > 0) + { + join.FirstTableReference = CreateInlineDerivedTable(); + return false; + } + + _joinPredicate = (join as QualifiedJoin)?.SearchCondition; + removed = join.SecondTableReference; + return true; + } + + if (IsRecursiveReference(join.SecondTableReference)) + { + if (_inUnqualifiedJoin > 0) + { + join.SecondTableReference = CreateInlineDerivedTable(); + return false; + } + + _joinPredicate = (join as QualifiedJoin)?.SearchCondition; + removed = join.FirstTableReference; + return true; + } + + return false; + } + + public override void Visit(FromClause node) + { + base.Visit(node); + + for (var i = 0; i < node.TableReferences.Count; i++) + { + if (IsRecursiveReference(node.TableReferences[i])) + { + if (_inUnqualifiedJoin > 0) + node.TableReferences[i] = CreateInlineDerivedTable(); + else + node.TableReferences.RemoveAt(i); + } + else if (RemoveRecursiveJoin(node.TableReferences[i], out var removed)) + { + node.TableReferences[i] = removed; + } + } + } + + public override void Visit(QualifiedJoin node) + { + base.Visit(node); + + if (RemoveRecursiveJoin(node.FirstTableReference, out var removed)) + node.FirstTableReference = removed; + + if (RemoveRecursiveJoin(node.SecondTableReference, out removed)) + node.SecondTableReference = removed; + } + + public override void Visit(UnqualifiedJoin node) + { + base.Visit(node); + + if (RemoveRecursiveJoin(node.FirstTableReference, out var removed)) + node.FirstTableReference = removed; + } + + public override void ExplicitVisit(UnqualifiedJoin node) + { + node.FirstTableReference.Accept(this); + + _inUnqualifiedJoin++; + + if (RemoveRecursiveJoin(node.SecondTableReference, out var removed)) + node.SecondTableReference = removed; + + node.SecondTableReference.Accept(this); + _inUnqualifiedJoin--; + } + + public override void ExplicitVisit(QuerySpecification node) + { + base.ExplicitVisit(node); + + if (_joinPredicate != null) + { + if (node.WhereClause == null) + { + node.WhereClause = new WhereClause { SearchCondition = _joinPredicate }; + } + else + { + node.WhereClause.SearchCondition = new BooleanBinaryExpression + { + FirstExpression = node.WhereClause.SearchCondition, + BinaryExpressionType = BooleanBinaryExpressionType.And, + SecondExpression = _joinPredicate + }; + } + } + } + } +} From e43617f7a5a311cce281b88456879e5a05ea1081 Mon Sep 17 00:00:00 2001 From: Mark Carrington Date: Mon, 11 Sep 2023 20:57:48 +0100 Subject: [PATCH 12/81] Clone spool producer/consumer nodes --- .../ExecutionPlan/ISpoolProducerNode.cs | 24 ++++++++ .../ExecutionPlan/IndexSpoolNode.cs | 60 +++++++++++++++---- .../ExecutionPlan/TableSpoolNode.cs | 52 +++++++++++++--- .../ExecutionPlanBuilder.cs | 16 ++--- .../MarkMpn.Sql4Cds.Engine.projitems | 1 + ...emoveRecursiveCTETableReferencesVisitor.cs | 15 +++++ 6 files changed, 143 insertions(+), 25 deletions(-) create mode 100644 MarkMpn.Sql4Cds.Engine/ExecutionPlan/ISpoolProducerNode.cs diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/ISpoolProducerNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/ISpoolProducerNode.cs new file mode 100644 index 00000000..b18ba77d --- /dev/null +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/ISpoolProducerNode.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.Xrm.Sdk; + +namespace MarkMpn.Sql4Cds.Engine.ExecutionPlan +{ + /// + /// Provides an interface for nodes that spool data internally + /// + interface ISpoolProducerNode : IDataExecutionPlanNodeInternal + { + /// + /// Accesses the spooled data + /// + /// The sequence of data that has been spooled + IEnumerable GetWorkTable(); + + /// + /// Returns the last cloned version of this node + /// + ISpoolProducerNode LastClone { get; } + } +} diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/IndexSpoolNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/IndexSpoolNode.cs index 9180bf67..ebe0bb15 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/IndexSpoolNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/IndexSpoolNode.cs @@ -13,11 +13,12 @@ namespace MarkMpn.Sql4Cds.Engine.ExecutionPlan /// /// Stores data in a hashtable for fast lookups /// - class IndexSpoolNode : BaseDataNode, ISingleSourceExecutionPlanNode + class IndexSpoolNode : BaseDataNode, ISingleSourceExecutionPlanNode, ISpoolProducerNode { private IDictionary> _hashTable; private Func _keySelector; private Func _seekSelector; + private Stack _stack; public IndexSpoolNode() { } @@ -28,18 +29,29 @@ public IndexSpoolNode() { } /// The column in the data source to create an index on /// [Category("Index Spool")] - [Description("The column in the data source to create an index on")] [DisplayName("Key Column")] + [Description("The column in the data source to create an index on")] public string KeyColumn { get; set; } /// /// The name of the parameter to use for seeking in the index /// [Category("Index Spool")] - [Description("The name of the parameter to use for seeking in the index")] [DisplayName("Seek Value")] + [Description("The name of the parameter to use for seeking in the index")] public string SeekValue { get; set; } + /// + /// Stores the records in a stack to support recursive CTEs + /// + [Category("Index Spool")] + [DisplayName("With Stack")] + [Description("Stores the records in a stack to support recursive CTEs")] + public bool WithStack { get; set; } + + [Browsable(false)] + public ISpoolProducerNode LastClone { get; private set; } + public override void AddRequiredColumns(NodeCompilationContext context, IList requiredColumns) { requiredColumns.Add(KeyColumn); @@ -61,15 +73,18 @@ public override IDataExecutionPlanNodeInternal FoldQuery(NodeCompilationContext { Source = Source.FoldQuery(context, hints); - // Index and seek values must be the same type - var indexType = Source.GetSchema(context).Schema[KeyColumn].Type; - var seekType = context.ParameterTypes[SeekValue]; + if (KeyColumn != null && SeekValue != null) + { + // Index and seek values must be the same type + var indexType = Source.GetSchema(context).Schema[KeyColumn].Type; + var seekType = context.ParameterTypes[SeekValue]; - if (!SqlTypeConverter.CanMakeConsistentTypes(indexType, seekType, context.PrimaryDataSource, out var consistentType)) - throw new QueryExecutionException($"No type conversion available for {indexType.ToSql()} and {seekType.ToSql()}"); + if (!SqlTypeConverter.CanMakeConsistentTypes(indexType, seekType, context.PrimaryDataSource, out var consistentType)) + throw new QueryExecutionException($"No type conversion available for {indexType.ToSql()} and {seekType.ToSql()}"); - _keySelector = SqlTypeConverter.GetConversion(indexType, consistentType); - _seekSelector = SqlTypeConverter.GetConversion(seekType, consistentType); + _keySelector = SqlTypeConverter.GetConversion(indexType, consistentType); + _seekSelector = SqlTypeConverter.GetConversion(seekType, consistentType); + } return this; } @@ -86,6 +101,9 @@ public override IEnumerable GetSources() protected override IEnumerable ExecuteInternal(NodeExecutionContext context) { + if (WithStack) + return ExecuteInternalWithStack(context); + // Build an internal hash table of the source indexed by the key column if (_hashTable == null) { @@ -102,6 +120,23 @@ protected override IEnumerable ExecuteInternal(NodeExecutionContext cont return matches; } + private IEnumerable ExecuteInternalWithStack(NodeExecutionContext context) + { + _stack = new Stack(); + + foreach (var entity in Source.Execute(context)) + { + _stack.Push(entity); + yield return entity; + } + } + + public IEnumerable GetWorkTable() + { + while (_stack.Count > 0) + yield return _stack.Pop(); + } + public override string ToString() { return "Index Spool\r\n(Eager Spool)"; @@ -111,14 +146,17 @@ public override object Clone() { var clone = new IndexSpoolNode { - Source = (IDataExecutionPlanNodeInternal)Source.Clone(), KeyColumn = KeyColumn, SeekValue = SeekValue, _keySelector = _keySelector, _seekSelector = _seekSelector }; + LastClone = clone; + + clone.Source = (IDataExecutionPlanNodeInternal)Source.Clone(); clone.Source.Parent = clone; + return clone; } } diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/TableSpoolNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/TableSpoolNode.cs index 611772c8..47fbb544 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/TableSpoolNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/TableSpoolNode.cs @@ -13,7 +13,7 @@ namespace MarkMpn.Sql4Cds.Engine.ExecutionPlan /// /// Provides a rewindable cache of a data source /// - class TableSpoolNode : BaseDataNode, ISingleSourceExecutionPlanNode + class TableSpoolNode : BaseDataNode, ISingleSourceExecutionPlanNode, ISpoolProducerNode { class CachedList : IEnumerable { @@ -83,6 +83,8 @@ IEnumerator IEnumerable.GetEnumerator() } } + public TableSpoolNode() { } + private Entity[] _eagerSpool; private CachedList _lazyCache; @@ -96,6 +98,23 @@ IEnumerator IEnumerable.GetEnumerator() [DisplayName("Spool Type")] public SpoolType SpoolType { get; set; } + /// + /// Indicates if this spool is in place only for performance reasons + /// + internal bool IsPerformanceSpool { get; set; } + + /// + /// The node that produces data that this node should repeat + /// + /// + /// If this property is set, the node operates in Consumer mode. + /// + [Browsable(false)] + public ISpoolProducerNode Producer { get; set; } + + [Browsable(false)] + public ISpoolProducerNode LastClone { get; private set; } + internal int GetCount(NodeExecutionContext context) { if (_eagerSpool == null) @@ -124,19 +143,23 @@ protected override IEnumerable ExecuteInternal(NodeExecutionContext cont public override IEnumerable GetSources() { - yield return Source; + if (Source != null) + yield return Source; } public override INodeSchema GetSchema(NodeCompilationContext context) { - return Source.GetSchema(context); + return (Source ?? Producer).GetSchema(context); } public override IDataExecutionPlanNodeInternal FoldQuery(NodeCompilationContext context, IList hints) { + if (Source == null) + return this; + Source = Source.FoldQuery(context, hints); - if (hints != null && hints.Any(hint => hint.HintKind == OptimizerHintKind.NoPerformanceSpool)) + if (IsPerformanceSpool && hints != null && hints.Any(hint => hint.HintKind == OptimizerHintKind.NoPerformanceSpool)) return Source; Source.Parent = this; @@ -145,14 +168,22 @@ public override IDataExecutionPlanNodeInternal FoldQuery(NodeCompilationContext public override void AddRequiredColumns(NodeCompilationContext context, IList requiredColumns) { - Source.AddRequiredColumns(context, requiredColumns); + Source?.AddRequiredColumns(context, requiredColumns); } protected override RowCountEstimate EstimateRowsOutInternal(NodeCompilationContext context) { + if (Source == null) + return new RowCountEstimate(1); + return Source.EstimateRowsOut(context); } + public IEnumerable GetWorkTable() + { + return (IEnumerable)_eagerSpool ?? _lazyCache; + } + public override string ToString() { return $"Table Spool\r\n({SpoolType} Spool)"; @@ -162,11 +193,18 @@ public override object Clone() { var clone = new TableSpoolNode { - Source = (IDataExecutionPlanNodeInternal)Source.Clone(), + Producer = Producer?.LastClone, SpoolType = SpoolType }; - clone.Source.Parent = clone; + LastClone = clone; + + if (Source != null) + { + clone.Source = (IDataExecutionPlanNodeInternal)Source.Clone(); + clone.Source.Parent = clone; + } + return clone; } } diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs index cabd6989..be322359 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs @@ -253,13 +253,13 @@ private void ConvertStatement(TSqlStatement statement, ExecutionPlanOptimizer op var recurseIndexStack = new IndexSpoolNode { Source = recurseConcat, - // TODO: WithStack = true + WithStack = true }; // Pull the same records into the recursive loop var recurseTableSpool = new TableSpoolNode { - // TODO: Producer = recurseIndexStack + Producer = recurseIndexStack }; // Increment the depth @@ -372,7 +372,7 @@ private void ConvertStatement(TSqlStatement statement, ExecutionPlanOptimizer op recurseConcat.ColumnSet.Last().SourceColumns.Add(incrementedDepthField); - anchorQuery.Source = incrementRecursionDepthComputeScalar; + anchorQuery.Source = recurseIndexStack; } } } @@ -446,7 +446,8 @@ private SelectNode ConvertRecursiveCTEQuery(QueryExpression queryExpression, INo queryExpression.Accept(cteReplacer); // Convert the modified query. - return ConvertSelectStatement(queryExpression, null, anchorSchema, outerReferences, _nodeContext); + var childContext = new NodeCompilationContext(_nodeContext, outerReferences.ToDictionary(kvp => kvp.Value, kvp => anchorSchema.Schema[kvp.Key].Type, StringComparer.OrdinalIgnoreCase)); + return ConvertSelectStatement(queryExpression, null, null, null, childContext); } private IRootExecutionPlanNodeInternal[] ConvertExecuteStatement(ExecuteStatement execute) @@ -3322,7 +3323,7 @@ private ColumnReferenceExpression ConvertScalarSubqueries(TSqlFragment expressio { if (EstimateRowsOut(node, context) > 1) { - var spool = new TableSpoolNode { Source = loopRightSource, SpoolType = SpoolType.Lazy }; + var spool = new TableSpoolNode { Source = loopRightSource, SpoolType = SpoolType.Lazy, IsPerformanceSpool = true }; loopRightSource = spool; } } @@ -3600,7 +3601,8 @@ private void InsertCorrelatedSubquerySpool(ISingleSourceExecutionPlanNode node, var spool = new TableSpoolNode { Source = lastCorrelatedStep.Source, - SpoolType = SpoolType.Lazy + SpoolType = SpoolType.Lazy, + IsPerformanceSpool = true }; lastCorrelatedStep.Source = spool; @@ -3951,7 +3953,7 @@ private IDataExecutionPlanNodeInternal ConvertTableReference(TableReference refe else { // Spool the inner table so the results can be reused by the nested loop - rhs = new TableSpoolNode { Source = rhs, SpoolType = SpoolType.Eager }; + rhs = new TableSpoolNode { Source = rhs, SpoolType = SpoolType.Eager, IsPerformanceSpool = true }; joinNode = new NestedLoopNode { diff --git a/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.projitems b/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.projitems index ab0d4ccd..44ecb297 100644 --- a/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.projitems +++ b/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.projitems @@ -27,6 +27,7 @@ + diff --git a/MarkMpn.Sql4Cds.Engine/Visitors/RemoveRecursiveCTETableReferencesVisitor.cs b/MarkMpn.Sql4Cds.Engine/Visitors/RemoveRecursiveCTETableReferencesVisitor.cs index 06ab4e5f..342b27c3 100644 --- a/MarkMpn.Sql4Cds.Engine/Visitors/RemoveRecursiveCTETableReferencesVisitor.cs +++ b/MarkMpn.Sql4Cds.Engine/Visitors/RemoveRecursiveCTETableReferencesVisitor.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Text; +using MarkMpn.Sql4Cds.Engine.ExecutionPlan; using Microsoft.SqlServer.TransactSql.ScriptDom; namespace MarkMpn.Sql4Cds.Engine.Visitors @@ -15,6 +17,7 @@ class RemoveRecursiveCTETableReferencesVisitor : TSqlConcreteFragmentVisitor private readonly Dictionary _outerReferences; private BooleanExpression _joinPredicate; private int _inUnqualifiedJoin; + private bool _usingInlineDerivedTable; public RemoveRecursiveCTETableReferencesVisitor(string name, string[] columnNames, Dictionary outerReferences) { @@ -36,6 +39,8 @@ private bool IsRecursiveReference(TableReference tableReference) private InlineDerivedTable CreateInlineDerivedTable() { + _usingInlineDerivedTable = true; + var table = new InlineDerivedTable { Alias = new Identifier { Value = _name }, @@ -159,6 +164,16 @@ public override void ExplicitVisit(QuerySpecification node) }; } } + + if (!_usingInlineDerivedTable) + { + // Replace references to the recursive CTE columns with variables + var rewrites = _outerReferences + .SelectMany(kvp => new[] { kvp, new KeyValuePair(kvp.Key.Split('.')[1], kvp.Value) }) + .ToDictionary(kvp => (ScalarExpression)kvp.Key.ToColumnReference(), kvp => (ScalarExpression)new VariableReference { Name = kvp.Value }); + + node.Accept(new RewriteVisitor(rewrites)); + } } } } From d2e072f7e6c3b18241b47ea2f20c986701f44616 Mon Sep 17 00:00:00 2001 From: Mark Carrington Date: Mon, 18 Sep 2023 07:58:41 +0100 Subject: [PATCH 13/81] Recursion progress --- MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs | 60 ++++++++++++- .../ExecutionPlanBuilder.cs | 8 +- .../TSqlFragmentExtensions.cs | 86 ++++++++++++++++++- ...emoveRecursiveCTETableReferencesVisitor.cs | 2 +- 4 files changed, 149 insertions(+), 7 deletions(-) diff --git a/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs b/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs index 8622a8d5..fdd47156 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs +++ b/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs @@ -512,11 +512,69 @@ UNION ALL var concat = AssertNode(spoolProducer.Source); var depth0 = AssertNode(concat.Sources[0]); var anchor = AssertNode(depth0.Source); + + AssertFetchXml(anchor, @" + + + + + + + + + + "); + var assert = AssertNode(concat.Sources[1]); var nestedLoop = AssertNode(assert.Source); var depthPlus1 = AssertNode(nestedLoop.LeftSource); - var spoolConsumer = AssertNode(depthPlus1); + var spoolConsumer = AssertNode(depthPlus1.Source); var children = AssertNode(nestedLoop.RightSource); + + AssertFetchXml(children, @" + + + + + + + + + + "); + } + + [TestMethod] + public void FactorialCalc() + { + using (var con = new Sql4CdsConnection(_localDataSource)) + using (var cmd = con.CreateCommand()) + { + cmd.CommandText = @" + WITH Factorial (N, Factorial) AS ( + SELECT 1, 1 + UNION ALL + SELECT N + 1, (N + 1) * Factorial FROM Factorial WHERE N < 5) + SELECT N, Factorial FROM Factorial"; + + using (var reader = cmd.ExecuteReader()) + { + var n = 1; + var factorial = 1; + + while (n <= 5) + { + Assert.IsTrue(reader.Read()); + Assert.AreEqual(n, reader.GetInt32(0)); + Assert.AreEqual(factorial, reader.GetInt32(1)); + + n++; + factorial *= n; + } + + Assert.IsFalse(reader.Read()); + } + } } private T AssertNode(IExecutionPlanNode node) where T : IExecutionPlanNode diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs index 9a82a025..a9cf153a 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs @@ -290,7 +290,7 @@ private void ConvertStatement(TSqlStatement statement, ExecutionPlanOptimizer op var anchorSchema = anchorQuery.GetSchema(_nodeContext); foreach (var col in anchorSchema.Schema) - recurseLoop.OuterReferences[col.Key] = "@" + _nodeContext.GetExpressionName(); + recurseLoop.OuterReferences[col.Key.SplitMultiPartIdentifier().Last()] = "@" + _nodeContext.GetExpressionName(); if (cteValidator.RecursiveQueries.Count > 1) { @@ -437,7 +437,7 @@ private void ConvertStatement(TSqlStatement statement, ExecutionPlanOptimizer op private SelectNode ConvertRecursiveCTEQuery(QueryExpression queryExpression, INodeSchema anchorSchema, CteValidatorVisitor cteValidator, Dictionary outerReferences) { // Convert the query using the anchor query as a subquery to check for ambiguous column names - ConvertSelectStatement(queryExpression, null, null, null, _nodeContext); + ConvertSelectStatement(queryExpression.Clone(), null, null, null, _nodeContext); // Remove recursive references from the FROM clause, moving join predicates to the WHERE clause // If the recursive reference was in an unqualified join, replace it with (SELECT @Expr1, @Expr2) AS cte (field1, field2) @@ -446,7 +446,7 @@ private SelectNode ConvertRecursiveCTEQuery(QueryExpression queryExpression, INo queryExpression.Accept(cteReplacer); // Convert the modified query. - var childContext = new NodeCompilationContext(_nodeContext, outerReferences.ToDictionary(kvp => kvp.Value, kvp => anchorSchema.Schema[kvp.Key].Type, StringComparer.OrdinalIgnoreCase)); + var childContext = new NodeCompilationContext(_nodeContext, outerReferences.ToDictionary(kvp => kvp.Value, kvp => anchorSchema.Schema[cteValidator.Name.EscapeIdentifier() + "." + kvp.Key].Type, StringComparer.OrdinalIgnoreCase)); return ConvertSelectStatement(queryExpression, null, null, null, childContext); } @@ -2081,7 +2081,7 @@ private SelectNode ConvertSelectQuerySpec(QuerySpecification querySpec, IList() } } : ConvertFromClause(querySpec.FromClause, hints, querySpec, outerSchema, outerReferences, context); + var node = querySpec.FromClause == null || querySpec.FromClause.TableReferences.Count == 0 ? new ConstantScanNode { Values = { new Dictionary() } } : ConvertFromClause(querySpec.FromClause, hints, querySpec, outerSchema, outerReferences, context); var logicalSchema = node.GetSchema(context); node = ConvertInSubqueries(node, hints, querySpec, context, outerSchema, outerReferences); diff --git a/MarkMpn.Sql4Cds.Engine/TSqlFragmentExtensions.cs b/MarkMpn.Sql4Cds.Engine/TSqlFragmentExtensions.cs index 20e6c7d3..87875986 100644 --- a/MarkMpn.Sql4Cds.Engine/TSqlFragmentExtensions.cs +++ b/MarkMpn.Sql4Cds.Engine/TSqlFragmentExtensions.cs @@ -455,7 +455,91 @@ public static T Clone(this T fragment) where T : TSqlFragment }; } - throw new NotSupportedQueryFragmentException("Unhandled expression type", fragment); + if (fragment is QuerySpecification querySpec) + { + var clone = new QuerySpecification + { + ForClause = querySpec.ForClause?.Clone(), + FromClause = querySpec.FromClause?.Clone(), + GroupByClause = querySpec.GroupByClause?.Clone(), + HavingClause = querySpec.HavingClause?.Clone(), + OffsetClause = querySpec.OffsetClause?.Clone(), + OrderByClause = querySpec.OrderByClause?.Clone(), + TopRowFilter = querySpec.TopRowFilter?.Clone(), + UniqueRowFilter = querySpec.UniqueRowFilter, + WhereClause = querySpec.WhereClause?.Clone(), + WindowClause = querySpec.WindowClause?.Clone() + }; + + foreach (var selectElement in querySpec.SelectElements) + clone.SelectElements.Add(selectElement.Clone()); + + return (T)(object)clone; + } + + if (fragment is FromClause from) + { + var clone = new FromClause(); + + foreach (var predict in from.PredictTableReference) + clone.PredictTableReference.Add(predict.Clone()); + + foreach (var table in from.TableReferences) + clone.TableReferences.Add(table.Clone()); + + return (T)(object)clone; + } + + if (fragment is NamedTableReference tableRef) + { + var clone = new NamedTableReference + { + Alias = tableRef.Alias?.Clone(), + ForPath = tableRef.ForPath, + SchemaObject = tableRef.SchemaObject.Clone(), + TableSampleClause = tableRef.TableSampleClause?.Clone(), + TemporalClause = tableRef.TemporalClause?.Clone(), + }; + + foreach (var hint in tableRef.TableHints) + clone.TableHints.Add(hint.Clone()); + + return (T)(object)clone; + } + + if (fragment is GroupByClause groupBy) + { + var clone = new GroupByClause + { + All = groupBy.All, + GroupByOption = groupBy.GroupByOption + }; + + foreach (var groupBySpec in groupBy.GroupingSpecifications) + clone.GroupingSpecifications.Add(groupBySpec.Clone()); + + return (T)(object)clone; + } + + if (fragment is WhereClause where) + { + return (T)(object)new WhereClause + { + Cursor = where.Cursor?.Clone(), + SearchCondition = where.SearchCondition?.Clone() + }; + } + + if (fragment is SelectScalarExpression selectScalarExpression) + { + return (T)(object)new SelectScalarExpression + { + ColumnName = selectScalarExpression.ColumnName?.Clone(), + Expression = selectScalarExpression.Expression?.Clone() + }; + } + + throw new NotSupportedQueryFragmentException("Unhandled expression type " + fragment.GetType().Name, fragment); } } } diff --git a/MarkMpn.Sql4Cds.Engine/Visitors/RemoveRecursiveCTETableReferencesVisitor.cs b/MarkMpn.Sql4Cds.Engine/Visitors/RemoveRecursiveCTETableReferencesVisitor.cs index 342b27c3..7e1a763e 100644 --- a/MarkMpn.Sql4Cds.Engine/Visitors/RemoveRecursiveCTETableReferencesVisitor.cs +++ b/MarkMpn.Sql4Cds.Engine/Visitors/RemoveRecursiveCTETableReferencesVisitor.cs @@ -169,7 +169,7 @@ public override void ExplicitVisit(QuerySpecification node) { // Replace references to the recursive CTE columns with variables var rewrites = _outerReferences - .SelectMany(kvp => new[] { kvp, new KeyValuePair(kvp.Key.Split('.')[1], kvp.Value) }) + .SelectMany(kvp => new[] { kvp, new KeyValuePair(_name.EscapeIdentifier() + "." + kvp.Key, kvp.Value) }) .ToDictionary(kvp => (ScalarExpression)kvp.Key.ToColumnReference(), kvp => (ScalarExpression)new VariableReference { Name = kvp.Value }); node.Accept(new RewriteVisitor(rewrites)); From 55acc58147ea46d4f121706a86767c08ef98a203 Mon Sep 17 00:00:00 2001 From: Mark Carrington Date: Wed, 27 Sep 2023 08:01:15 +0100 Subject: [PATCH 14/81] Allow cloning joins --- MarkMpn.Sql4Cds.Engine/TSqlFragmentExtensions.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/MarkMpn.Sql4Cds.Engine/TSqlFragmentExtensions.cs b/MarkMpn.Sql4Cds.Engine/TSqlFragmentExtensions.cs index 87875986..bfa88ec6 100644 --- a/MarkMpn.Sql4Cds.Engine/TSqlFragmentExtensions.cs +++ b/MarkMpn.Sql4Cds.Engine/TSqlFragmentExtensions.cs @@ -507,6 +507,18 @@ public static T Clone(this T fragment) where T : TSqlFragment return (T)(object)clone; } + if (fragment is QualifiedJoin qualifiedJoin) + { + return (T)(object)new QualifiedJoin + { + FirstTableReference = qualifiedJoin.FirstTableReference.Clone(), + JoinHint = qualifiedJoin.JoinHint, + QualifiedJoinType = qualifiedJoin.QualifiedJoinType, + SearchCondition = qualifiedJoin.SearchCondition?.Clone(), + SecondTableReference = qualifiedJoin.SecondTableReference.Clone() + }; + } + if (fragment is GroupByClause groupBy) { var clone = new GroupByClause From 07021a7ab1d0f028ad5de44a7eccf614adc78b33 Mon Sep 17 00:00:00 2001 From: Mark Carrington Date: Wed, 27 Sep 2023 08:01:35 +0100 Subject: [PATCH 15/81] Keep aliases case insensitive --- MarkMpn.Sql4Cds.Engine/ExecutionPlan/AliasNode.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/AliasNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/AliasNode.cs index e0eae65a..a2e21ded 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/AliasNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/AliasNode.cs @@ -192,7 +192,7 @@ public override INodeSchema GetSchema(NodeCompilationContext context) // Map the base names to the alias names var sourceSchema = Source.GetSchema(context); var schema = new ColumnList(); - var aliases = new Dictionary>(); + var aliases = new Dictionary>(StringComparer.OrdinalIgnoreCase); var primaryKey = (string)null; var mappings = new Dictionary(StringComparer.OrdinalIgnoreCase); var escapedAlias = Alias.EscapeIdentifier(); From efec67cadd95cd56a335743d21ef263d5b4dd2c2 Mon Sep 17 00:00:00 2001 From: Mark Carrington Date: Wed, 27 Sep 2023 08:02:05 +0100 Subject: [PATCH 16/81] Preserve WithStack property while cloning --- MarkMpn.Sql4Cds.Engine/ExecutionPlan/IndexSpoolNode.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/IndexSpoolNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/IndexSpoolNode.cs index ebe0bb15..7301b70f 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/IndexSpoolNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/IndexSpoolNode.cs @@ -139,6 +139,9 @@ public IEnumerable GetWorkTable() public override string ToString() { + if (WithStack) + return "Index Spool\r\n(Lazy Spool)"; + return "Index Spool\r\n(Eager Spool)"; } @@ -149,7 +152,8 @@ public override object Clone() KeyColumn = KeyColumn, SeekValue = SeekValue, _keySelector = _keySelector, - _seekSelector = _seekSelector + _seekSelector = _seekSelector, + WithStack = WithStack, }; LastClone = clone; From 165577d9ca290698d8e6333dc13d03f69aa23a1e Mon Sep 17 00:00:00 2001 From: Mark Carrington Date: Wed, 27 Sep 2023 08:02:31 +0100 Subject: [PATCH 17/81] Use producer node as source --- MarkMpn.Sql4Cds.Engine/ExecutionPlan/TableSpoolNode.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/TableSpoolNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/TableSpoolNode.cs index 47fbb544..631fd0c6 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/TableSpoolNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/TableSpoolNode.cs @@ -125,6 +125,9 @@ internal int GetCount(NodeExecutionContext context) protected override IEnumerable ExecuteInternal(NodeExecutionContext context) { + if (Producer != null) + return Producer.GetWorkTable(); + if (SpoolType == SpoolType.Eager) { if (_eagerSpool == null) From 203ac337bbd2e8832dcc5e96a7ed3422048743d9 Mon Sep 17 00:00:00 2001 From: Mark Carrington Date: Wed, 27 Sep 2023 08:03:00 +0100 Subject: [PATCH 18/81] Fixed column renaming --- MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs index a9cf153a..7a3c7060 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs @@ -213,7 +213,9 @@ private void ConvertStatement(TSqlStatement statement, ExecutionPlanOptimizer op if (cteValidator.RecursiveQueries.Count > 0) { + anchorQuery = (AliasNode)anchorQuery.Clone(); var ctePlan = anchorQuery.Source; + var anchorSchema = anchorQuery.GetSchema(_nodeContext); // Add a ComputeScalar node to add the initial recursion depth (0) var recursionDepthField = _nodeContext.GetExpressionName(); @@ -241,6 +243,8 @@ private void ConvertStatement(TSqlStatement statement, ExecutionPlanOptimizer op }; recurseConcat.ColumnSet.Add(concatCol); + + col.SourceColumn = col.OutputColumn; } recurseConcat.ColumnSet.Add(new ConcatenateColumn @@ -259,7 +263,8 @@ private void ConvertStatement(TSqlStatement statement, ExecutionPlanOptimizer op // Pull the same records into the recursive loop var recurseTableSpool = new TableSpoolNode { - Producer = recurseIndexStack + Producer = recurseIndexStack, + SpoolType = SpoolType.Lazy }; // Increment the depth @@ -287,8 +292,6 @@ private void ConvertStatement(TSqlStatement statement, ExecutionPlanOptimizer op }; // Capture all CTE fields in the outer references - var anchorSchema = anchorQuery.GetSchema(_nodeContext); - foreach (var col in anchorSchema.Schema) recurseLoop.OuterReferences[col.Key.SplitMultiPartIdentifier().Last()] = "@" + _nodeContext.GetExpressionName(); @@ -373,6 +376,7 @@ private void ConvertStatement(TSqlStatement statement, ExecutionPlanOptimizer op recurseConcat.ColumnSet.Last().SourceColumns.Add(incrementedDepthField); anchorQuery.Source = recurseIndexStack; + _cteSubplans[cte.ExpressionName.Value] = anchorQuery; } } } From 38fa3f13b96dd1621699b7999c259b15c04fe584 Mon Sep 17 00:00:00 2001 From: Mark Carrington Date: Wed, 27 Sep 2023 08:03:15 +0100 Subject: [PATCH 19/81] Extended tests --- MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs | 39 ++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs b/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs index fdd47156..61e585cf 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs +++ b/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs @@ -508,6 +508,9 @@ UNION ALL Assert.AreEqual(1, plans.Length); var select = AssertNode(plans[0]); + Assert.AreEqual("contactid", select.ColumnSet[0].OutputColumn); + Assert.AreEqual("firstname", select.ColumnSet[1].OutputColumn); + Assert.AreEqual("lastname", select.ColumnSet[2].OutputColumn); var spoolProducer = AssertNode(select.Source); var concat = AssertNode(spoolProducer.Source); var depth0 = AssertNode(concat.Sources[0]); @@ -577,6 +580,42 @@ UNION ALL } } + [TestMethod] + public void FactorialCalcFiltered() + { + + using (var con = new Sql4CdsConnection(_localDataSource)) + using (var cmd = con.CreateCommand()) + { + cmd.CommandText = @" + WITH Factorial (N, Factorial) AS ( + SELECT 1, 1 + UNION ALL + SELECT N + 1, (N + 1) * Factorial FROM Factorial WHERE N < 5) + SELECT Factorial FROM Factorial WHERE N = 3"; + + Assert.AreEqual(6, cmd.ExecuteScalar()); + } + } + + [TestMethod] + public void FactorialCalcFilteredCaseInsensitive() + { + using (var con = new Sql4CdsConnection(_localDataSource)) + using (var cmd = con.CreateCommand()) + { + cmd.CommandText = @" + with factorial (N, Factorial) as ( + select 1, 1 + union all + select N + 1, (N + 1) * factorial from factorial where n < 10 + ) + select factorial from factorial where n = 3"; + + Assert.AreEqual(6, cmd.ExecuteScalar()); + } + } + private T AssertNode(IExecutionPlanNode node) where T : IExecutionPlanNode { Assert.IsInstanceOfType(node, typeof(T)); From 9520643c5cbe1e443ae62c356c21fab2cb27f1c7 Mon Sep 17 00:00:00 2001 From: Mark Carrington Date: Mon, 2 Oct 2023 17:41:39 -0700 Subject: [PATCH 20/81] Fixed nested loop left outer join with no records returned from inner source --- MarkMpn.Sql4Cds.Engine/ExecutionPlan/NestedLoopNode.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/NestedLoopNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/NestedLoopNode.cs index 08734d5a..c28072d8 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/NestedLoopNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/NestedLoopNode.cs @@ -114,7 +114,17 @@ protected override IEnumerable ExecuteInternal(NodeExecutionContext cont } if (!hasRight && JoinType == QualifiedJoinType.LeftOuter) + { + if (rightSchema == null) + { + rightSchema = RightSource.GetSchema(rightCompilationContext); + mergedSchema = GetSchema(context, true); + joinCondition = JoinCondition?.Compile(new ExpressionCompilationContext(context, mergedSchema, null)); + joinConditionContext = joinCondition == null ? null : new ExpressionExecutionContext(context); + } + yield return Merge(left, leftSchema, null, rightSchema); + } } } From beff09381b9d7757d03e597d5485876e019dee00 Mon Sep 17 00:00:00 2001 From: Mark Carrington Date: Wed, 18 Oct 2023 08:06:03 +0100 Subject: [PATCH 21/81] Spool large recursive queries --- MarkMpn.Sql4Cds.Controls/ExecutionPlanView.cs | 7 +- MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs | 16 ++- .../ExecutionPlan/AdaptiveIndexSpoolNode.cs | 110 ++++++++++++++++++ .../ExecutionPlan/FetchXmlScan.cs | 30 ++++- .../ExecutionPlan/IndexSpoolNode.cs | 2 - .../MarkMpn.Sql4Cds.Engine.projitems | 1 + 6 files changed, 157 insertions(+), 9 deletions(-) create mode 100644 MarkMpn.Sql4Cds.Engine/ExecutionPlan/AdaptiveIndexSpoolNode.cs diff --git a/MarkMpn.Sql4Cds.Controls/ExecutionPlanView.cs b/MarkMpn.Sql4Cds.Controls/ExecutionPlanView.cs index b72cecd1..e3f054b0 100644 --- a/MarkMpn.Sql4Cds.Controls/ExecutionPlanView.cs +++ b/MarkMpn.Sql4Cds.Controls/ExecutionPlanView.cs @@ -141,7 +141,12 @@ protected override void OnPaint(PaintEventArgs e) if (iconRect.IntersectsWith(clipRect)) { - using (var stream = GetType().Assembly.GetManifestResourceStream(GetType(), "Images." + kvp.Key.GetType().Name + ".ico")) + var imageName = kvp.Key.GetType().Name; + + if (imageName == "AdaptiveIndexSpoolNode") + imageName = "IndexSpoolNode"; + + using (var stream = GetType().Assembly.GetManifestResourceStream(GetType(), "Images." + imageName + ".ico")) { Image image; diff --git a/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs b/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs index 61e585cf..4297e47c 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs +++ b/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs @@ -532,9 +532,11 @@ UNION ALL var nestedLoop = AssertNode(assert.Source); var depthPlus1 = AssertNode(nestedLoop.LeftSource); var spoolConsumer = AssertNode(depthPlus1.Source); - var children = AssertNode(nestedLoop.RightSource); + var adaptiveSpool = AssertNode(nestedLoop.RightSource); + var childrenFiltered = AssertNode(adaptiveSpool.UnspooledSource); + var childrenUnfiltered = AssertNode(adaptiveSpool.SpooledSource); - AssertFetchXml(children, @" + AssertFetchXml(childrenFiltered, @" @@ -545,6 +547,16 @@ UNION ALL "); + + AssertFetchXml(childrenUnfiltered, @" + + + + + + + + "); } [TestMethod] diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/AdaptiveIndexSpoolNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/AdaptiveIndexSpoolNode.cs new file mode 100644 index 00000000..df2689ba --- /dev/null +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/AdaptiveIndexSpoolNode.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text; +using Microsoft.SqlServer.TransactSql.ScriptDom; +using Microsoft.Xrm.Sdk; + +namespace MarkMpn.Sql4Cds.Engine.ExecutionPlan +{ + class AdaptiveIndexSpoolNode : BaseDataNode + { + private IndexSpoolNode _indexSpool; + + public AdaptiveIndexSpoolNode() + { + _indexSpool = new IndexSpoolNode(); + } + + [Browsable(false)] + public IDataExecutionPlanNodeInternal SpooledSource + { + get => _indexSpool.Source; + set => _indexSpool.Source = value; + } + + [Browsable(false)] + public IDataExecutionPlanNodeInternal UnspooledSource { get; set; } + + /// + /// The column in the data source to create an index on + /// + [Category("Index Spool")] + [DisplayName("Key Column")] + [Description("The column in the data source to create an index on")] + public string KeyColumn + { + get => _indexSpool.KeyColumn; + set => _indexSpool.KeyColumn = value; + } + + /// + /// The name of the parameter to use for seeking in the index + /// + [Category("Index Spool")] + [DisplayName("Seek Value")] + [Description("The name of the parameter to use for seeking in the index")] + public string SeekValue + { + get => _indexSpool.SeekValue; + set => _indexSpool.SeekValue = value; + } + + public override void AddRequiredColumns(NodeCompilationContext context, IList requiredColumns) + { + UnspooledSource.AddRequiredColumns(context, requiredColumns); + _indexSpool.AddRequiredColumns(context, requiredColumns); + } + + public override IDataExecutionPlanNodeInternal FoldQuery(NodeCompilationContext context, IList hints) + { + _indexSpool.FoldQuery(context, hints); + UnspooledSource = UnspooledSource.FoldQuery(context, hints); + return this; + } + + public override INodeSchema GetSchema(NodeCompilationContext context) + { + return UnspooledSource.GetSchema(context); + } + + public override IEnumerable GetSources() + { + return new[] { UnspooledSource, SpooledSource }; + } + + protected override RowCountEstimate EstimateRowsOutInternal(NodeCompilationContext context) + { + return _indexSpool.EstimateRowsOut(context); + } + + protected override IEnumerable ExecuteInternal(NodeExecutionContext context) + { + IDataExecutionPlanNodeInternal source; + + if (ExecutionCount < 10) + source = UnspooledSource; + else + source = _indexSpool; + + foreach (var result in source.Execute(context)) + yield return result; + } + + public override string ToString() + { + return "Index Spool\r\n(Adaptive)"; + } + + public override object Clone() + { + return new AdaptiveIndexSpoolNode + { + _indexSpool = (IndexSpoolNode)_indexSpool.Clone(), + UnspooledSource = (IDataExecutionPlanNodeInternal)UnspooledSource.Clone(), + KeyColumn = KeyColumn, + SeekValue = SeekValue + }; + } + } +} diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FetchXmlScan.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FetchXmlScan.cs index ebc85a30..3ff0f7b0 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FetchXmlScan.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FetchXmlScan.cs @@ -1249,14 +1249,15 @@ public override IDataExecutionPlanNodeInternal FoldQuery(NodeCompilationContext if (FoldFilterToIndexSpool(context, out var indexSpool)) { + NormalizeFilters(); Parent = indexSpool; - return indexSpool; + return indexSpool.FoldQuery(context, hints); } return this; } - private bool FoldFilterToIndexSpool(NodeCompilationContext context, out IndexSpoolNode indexSpool) + private bool FoldFilterToIndexSpool(NodeCompilationContext context, out IDataExecutionPlanNodeInternal indexSpool) { if (Entity.Items == null) { @@ -1288,11 +1289,11 @@ private bool FoldFilterToIndexSpool(NodeCompilationContext context, out IndexSpo { var loop = parent as NestedLoopNode; - if (loop != null && prev == loop.RightSource) + if (loop != null && prev == loop.RightSource && loop.OuterReferences.Any(kvp => kvp.Value.Equals(variableCondition.value, StringComparison.OrdinalIgnoreCase))) { var rowCount = loop.LeftSource.EstimateRowsOut(context); - if (rowCount.Value >= 100 && loop.OuterReferences.Any(kvp => kvp.Value.Equals(variableCondition.value, StringComparison.OrdinalIgnoreCase))) + if (rowCount.Value >= 100) { indexSpool = new IndexSpoolNode { @@ -1301,6 +1302,27 @@ private bool FoldFilterToIndexSpool(NodeCompilationContext context, out IndexSpo SeekValue = variableCondition.value }; + foreach (var filter in Entity.Items.OfType()) + filter.Items = filter.Items.Except(new[] { variableCondition }).ToArray(); + + return true; + } + else if (loop.LeftSource is ComputeScalarNode leftComputeScalar && + leftComputeScalar.Source is TableSpoolNode leftSpool && + leftSpool.Producer != null) + { + // In the recursive part of a CTE. We might only be being called for one record at a time, but that might happen + // lots of times. Add an adaptive spool in to avoid excessive calls + var clone = (FetchXmlScan)Clone(); + + indexSpool = new AdaptiveIndexSpoolNode + { + UnspooledSource = clone, + SpooledSource = this, + KeyColumn = (variableCondition.entityname ?? Alias) + "." + variableCondition.attribute, + SeekValue = variableCondition.value + }; + foreach (var filter in Entity.Items.OfType()) filter.Items = filter.Items.Except(new[] { variableCondition }).ToArray(); diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/IndexSpoolNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/IndexSpoolNode.cs index 7301b70f..6f26e3d1 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/IndexSpoolNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/IndexSpoolNode.cs @@ -20,8 +20,6 @@ class IndexSpoolNode : BaseDataNode, ISingleSourceExecutionPlanNode, ISpoolProdu private Func _seekSelector; private Stack _stack; - public IndexSpoolNode() { } - [Browsable(false)] public IDataExecutionPlanNodeInternal Source { get; set; } diff --git a/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.projitems b/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.projitems index 1648bfb8..36ff8fa9 100644 --- a/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.projitems +++ b/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.projitems @@ -27,6 +27,7 @@ + From 41a0e3e9f84f5aaea07706ec69cbf565610a2919 Mon Sep 17 00:00:00 2001 From: Mark Carrington Date: Fri, 20 Oct 2023 08:56:32 +0100 Subject: [PATCH 22/81] Initial work on folding CTEs to FetchXML --- .../ExecutionPlan/IndexSpoolNode.cs | 200 +++++++++++++++++- 1 file changed, 199 insertions(+), 1 deletion(-) diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/IndexSpoolNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/IndexSpoolNode.cs index 6f26e3d1..86e77b17 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/IndexSpoolNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/IndexSpoolNode.cs @@ -5,8 +5,10 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using MarkMpn.Sql4Cds.Engine.FetchXml; using Microsoft.SqlServer.TransactSql.ScriptDom; using Microsoft.Xrm.Sdk; +using Microsoft.Xrm.Sdk.Metadata; namespace MarkMpn.Sql4Cds.Engine.ExecutionPlan { @@ -52,7 +54,8 @@ class IndexSpoolNode : BaseDataNode, ISingleSourceExecutionPlanNode, ISpoolProdu public override void AddRequiredColumns(NodeCompilationContext context, IList requiredColumns) { - requiredColumns.Add(KeyColumn); + if (KeyColumn != null) + requiredColumns.Add(KeyColumn); Source.AddRequiredColumns(context, requiredColumns); } @@ -61,6 +64,9 @@ protected override RowCountEstimate EstimateRowsOutInternal(NodeCompilationConte { var rows = Source.EstimateRowsOut(context); + if (KeyColumn == null) + return rows; + if (rows is RowCountEstimateDefiniteRange range && range.Maximum == 1) return range; @@ -84,9 +90,201 @@ public override IDataExecutionPlanNodeInternal FoldQuery(NodeCompilationContext _seekSelector = SqlTypeConverter.GetConversion(seekType, consistentType); } + if (WithStack) + return FoldCTEToFetchXml(context, hints); + return this; } + private IDataExecutionPlanNodeInternal FoldCTEToFetchXml(NodeCompilationContext context, IList hints) + { + // We can use above/below FetchXML conditions for common CTE patterns + // https://learn.microsoft.com/en-us/power-apps/developer/data-platform/query-hierarchical-data + // This always uses the default max recursion depth of 100, so don't use it if we have any other hint + var maxRecursion = hints + .OfType() + .Where(hint => hint.HintKind == OptimizerHintKind.MaxRecursion) + .FirstOrDefault() + ?.Value + ?.Value + ?? "100"; + + if (maxRecursion != "100") + return this; + + // Check we have the required execution plan pattern: + // + // Index Spool ━━ Concatenate ━━ Compute Scalar ━━ FetchXML Query + // ┕ Assert ━━ Nested Loop ━━ Compute Scalar ━━ Table Spool + // ┕ Index Spool ━━ FetchXML Query + // ┕ FetchXML Query + + var concat = Source as ConcatenateNode; + if (concat == null || concat.Sources.Count != 2) + return this; + + var initialDepthCompute = concat.Sources[0] as ComputeScalarNode; + if (initialDepthCompute == null) + return this; + + var anchorFetchXml = initialDepthCompute.Source as FetchXmlScan; + if (anchorFetchXml == null) + return this; + + var depthAssert = concat.Sources[1] as AssertNode; + if (depthAssert == null) + return this; + + var recurseLoop = depthAssert.Source as NestedLoopNode; + if (recurseLoop == null) + return this; + + var incrementDepthCompute = recurseLoop.LeftSource as ComputeScalarNode; + if (incrementDepthCompute == null) + return this; + + var recurseSpoolConsumer = incrementDepthCompute.Source as TableSpoolNode; + if (recurseSpoolConsumer == null || recurseSpoolConsumer.Source != null) + return this; + + var adaptiveSpool = recurseLoop.RightSource as AdaptiveIndexSpoolNode; + if (adaptiveSpool == null) + return this; + + var unspooledRecursiveFetchXml = adaptiveSpool.UnspooledSource as FetchXmlScan; + if (unspooledRecursiveFetchXml == null) + return this; + + var spooledRecursiveFetchXml = adaptiveSpool.SpooledSource as FetchXmlScan; + if (spooledRecursiveFetchXml == null) + return this; + + // We can only use the hierarchical FetchXML filters if the recursion is within the same entity and is using only the + // hierarchical relationship for filtering + if (anchorFetchXml.DataSource != spooledRecursiveFetchXml.DataSource || + anchorFetchXml.Entity.name != spooledRecursiveFetchXml.Entity.name) + return this; + + // TODO: Check for any other filters or link-entities + + // TODO: Check all columns are consistent + + // TODO: Check there are no extra calculated columns + + var metadata = context.DataSources[anchorFetchXml.DataSource].Metadata[anchorFetchXml.Entity.name]; + var hierarchicalRelationship = metadata.OneToManyRelationships.SingleOrDefault(r => r.IsHierarchical == true); + + if (hierarchicalRelationship == null || + hierarchicalRelationship.ReferencingEntity != hierarchicalRelationship.ReferencedEntity) + return this; + + var anchorKey = adaptiveSpool.SeekValue; // Will be the variable name defined by the recursion loop + anchorKey = recurseLoop.OuterReferences.Single(kvp => kvp.Value == anchorKey).Key; // Will now be the column name defined by the concatenate node + anchorKey = concat.ColumnSet.Single(col => col.OutputColumn == anchorKey).SourceColumns[0]; // Will now be the column from the anchor FetchXML + var anchorCol = anchorKey.ToColumnReference(); + if (anchorCol.MultiPartIdentifier.Count != 2 || + anchorCol.MultiPartIdentifier.Identifiers[0].Value != anchorFetchXml.Alias) + return this; + var anchorAttr = anchorCol.MultiPartIdentifier[1].Value; + + var recurseCol = adaptiveSpool.KeyColumn.ToColumnReference(); + if (recurseCol.MultiPartIdentifier.Count != 2 || + recurseCol.MultiPartIdentifier.Identifiers[0].Value != spooledRecursiveFetchXml.Alias) + return this; + var recurseAttr = recurseCol.MultiPartIdentifier[1].Value; + + var isUnder = anchorAttr == hierarchicalRelationship.ReferencedAttribute && recurseAttr == hierarchicalRelationship.ReferencingAttribute; + var isAbove = anchorAttr == hierarchicalRelationship.ReferencingAttribute && recurseAttr == hierarchicalRelationship.ReferencedAttribute; + + if (!isUnder && !isAbove) + return this; + + // The depth counter is no longer generated or used, so remove it from the concat column list + var depthField = initialDepthCompute.Columns.Single().Key; + var depthFieldConcatColumn = concat.ColumnSet.Single(c => c.SourceColumns[0] == depthField); + concat.ColumnSet.Remove(depthFieldConcatColumn); + + // We can replace the whole CTE with a single eq-or-above or eq-or-under FetchXML if the anchor + // query filters on a single primary key + var at = GetPrimaryKeyFilter(anchorFetchXml, metadata); + + if (at != null) + { + at.@operator = isUnder ? @operator.eqorunder : @operator.eqorabove; + + // We might have some column renamings applied, so update them too + var alias = Parent as AliasNode; + + if (alias == null) + { + foreach (var col in concat.ColumnSet) + anchorFetchXml.ColumnMappings.Add(new SelectColumn { SourceColumn = col.SourceColumns[0], OutputColumn = col.OutputColumn }); + } + else + { + foreach (var col in alias.ColumnSet) + { + var concatCol = concat.ColumnSet.Single(c => c.OutputColumn == col.SourceColumn); + col.SourceColumn = concatCol.SourceColumns[0]; + } + } + + return anchorFetchXml; + } + + // We can replace the recursive part with a nested loop calling an above or under FetchXML if the anchor + // query is a more complex filter. We don't want to recurse into the results of this second FetchXML though as the recursion + // has already happened server-side, so the execution plan should become: + // + // Concatenate ━━ Index Spool ━━ FetchXML Query + // ┕ Nested Loop ━━ Table Spool + // ┕ FetchXML Query + + var recurseCondition = (condition) unspooledRecursiveFetchXml.Entity.Items.OfType().Single().Items.Single(); + recurseCondition.attribute = metadata.PrimaryIdAttribute; + recurseCondition.@operator = isUnder ? @operator.under : @operator.above; + + concat.Sources[0] = this; + Parent = concat; + Source = anchorFetchXml; + anchorFetchXml.Parent = this; + concat.Sources[1] = recurseLoop; + recurseLoop.Parent = concat; + recurseLoop.LeftSource = recurseSpoolConsumer; + recurseSpoolConsumer.Parent = recurseLoop; + recurseLoop.RightSource = unspooledRecursiveFetchXml; + unspooledRecursiveFetchXml.Parent = recurseLoop; + + // The spooled data will now be using the original names from the anchor FetchXML node rather than the renamed + // versions from the Concatenate node, so rewrite the outer references + var outerReferences = new Dictionary(StringComparer.OrdinalIgnoreCase); + + foreach (var outerRef in recurseLoop.OuterReferences) + { + var concatCol = concat.ColumnSet.Single(c => c.OutputColumn == outerRef.Key); + outerReferences[concatCol.SourceColumns[0]] = outerRef.Value; + } + + recurseLoop.OuterReferences = outerReferences; + + return concat; + } + + private condition GetPrimaryKeyFilter(FetchXmlScan anchorFetchXml, EntityMetadata metadata) + { + if (anchorFetchXml.Entity.Items == null) + return null; + var anchorFilters = anchorFetchXml.Entity.Items.OfType().ToArray(); + if (anchorFilters.Length != 1) + return null; + if (anchorFilters[0].Items == null || anchorFilters[0].Items.Length != 1 || !(anchorFilters[0].Items[0] is condition anchorCondition)) + return null; + if (anchorCondition.attribute != metadata.PrimaryIdAttribute || anchorCondition.@operator != @operator.eq) + return null; + + return anchorCondition; + } + public override INodeSchema GetSchema(NodeCompilationContext context) { return Source.GetSchema(context); From a74a25bab56c7d47728067930c6e730a74e16c32 Mon Sep 17 00:00:00 2001 From: Mark Carrington Date: Sun, 22 Oct 2023 17:11:59 +0100 Subject: [PATCH 23/81] Improved folding CTE to FetchXML --- .../FakeXrmEasyTestsBase.cs | 17 +++++++++++ .../ExecutionPlan/AliasNode.cs | 1 + .../ExecutionPlan/IndexSpoolNode.cs | 30 ++++++++++++++++--- 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/MarkMpn.Sql4Cds.Engine.Tests/FakeXrmEasyTestsBase.cs b/MarkMpn.Sql4Cds.Engine.Tests/FakeXrmEasyTestsBase.cs index e02f760e..4f8c59a4 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/FakeXrmEasyTestsBase.cs +++ b/MarkMpn.Sql4Cds.Engine.Tests/FakeXrmEasyTestsBase.cs @@ -117,6 +117,9 @@ public FakeXrmEasyTestsBase() SetColumnNumber(_context); SetColumnNumber(_context2); + + SetRelationships(_context); + SetRelationships(_context2); } private void SetPrimaryNameAttributes(XrmFakedContext context) @@ -243,5 +246,19 @@ private void SetColumnNumber(XrmFakedContext context) context.SetEntityMetadata(entity); } } + + private void SetRelationships(XrmFakedContext context) + { + foreach (var entity in context.CreateMetadataQuery()) + { + if (entity.OneToManyRelationships == null) + typeof(EntityMetadata).GetProperty(nameof(EntityMetadata.OneToManyRelationships)).SetValue(entity, Array.Empty()); + + if (entity.ManyToOneRelationships == null) + typeof(EntityMetadata).GetProperty(nameof(EntityMetadata.ManyToOneRelationships)).SetValue(entity, Array.Empty()); + + context.SetEntityMetadata(entity); + } + } } } diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/AliasNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/AliasNode.cs index a2e21ded..b3262711 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/AliasNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/AliasNode.cs @@ -165,6 +165,7 @@ internal void FoldToFetchXML(FetchXmlScan fetchXml) // Add the mappings to the FetchXML to produce the columns with the expected names, and hide all other possible columns var originalAlias = fetchXml.Alias.EscapeIdentifier(); fetchXml.Alias = Alias; + fetchXml.ColumnMappings.Clear(); var escapedAlias = Alias.EscapeIdentifier(); diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/IndexSpoolNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/IndexSpoolNode.cs index 86e77b17..2f684067 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/IndexSpoolNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/IndexSpoolNode.cs @@ -165,11 +165,34 @@ private IDataExecutionPlanNodeInternal FoldCTEToFetchXml(NodeCompilationContext anchorFetchXml.Entity.name != spooledRecursiveFetchXml.Entity.name) return this; - // TODO: Check for any other filters or link-entities + // Check for any other filters or link-entities + if (spooledRecursiveFetchXml.Entity.GetLinkEntities().Any() || + spooledRecursiveFetchXml.Entity.Items != null && spooledRecursiveFetchXml.Entity.Items.OfType().Any()) + return this; + + // Check there are no extra calculated columns + if (initialDepthCompute.Columns.Count != 1 || incrementDepthCompute.Columns.Count != 1) + return this; + + // Check all columns are consistent + var depthField = initialDepthCompute.Columns.Single().Key; - // TODO: Check all columns are consistent + for (var i = 0; i < concat.ColumnSet.Count; i++) + { + if (concat.ColumnSet[i].SourceColumns[0] == depthField) + continue; + + var anchorAttribute = concat.ColumnSet[i].SourceColumns[0]; + var recurseAttribute = concat.ColumnSet[i].SourceColumns[1]; + recurseAttribute = recurseLoop.DefinedValues[recurseAttribute]; - // TODO: Check there are no extra calculated columns + // Ignore any differences in the aliases used for the anchor and recursive parts + anchorAttribute = anchorAttribute.ToColumnReference().MultiPartIdentifier.Identifiers.Last().Value; + recurseAttribute = recurseAttribute.ToColumnReference().MultiPartIdentifier.Identifiers.Last().Value; + + if (anchorAttribute != recurseAttribute) + return this; + } var metadata = context.DataSources[anchorFetchXml.DataSource].Metadata[anchorFetchXml.Entity.name]; var hierarchicalRelationship = metadata.OneToManyRelationships.SingleOrDefault(r => r.IsHierarchical == true); @@ -200,7 +223,6 @@ private IDataExecutionPlanNodeInternal FoldCTEToFetchXml(NodeCompilationContext return this; // The depth counter is no longer generated or used, so remove it from the concat column list - var depthField = initialDepthCompute.Columns.Single().Key; var depthFieldConcatColumn = concat.ColumnSet.Single(c => c.SourceColumns[0] == depthField); concat.ColumnSet.Remove(depthFieldConcatColumn); From 06dac7b36046e82a0490dff5f295f0051ffc12dd Mon Sep 17 00:00:00 2001 From: Mark Carrington Date: Sun, 22 Oct 2023 17:12:21 +0100 Subject: [PATCH 24/81] Allow rewriting CTEs used in subqueries --- .../TDSEndpointCompatibilityVisitor.cs | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/MarkMpn.Sql4Cds.Engine/Visitors/TDSEndpointCompatibilityVisitor.cs b/MarkMpn.Sql4Cds.Engine/Visitors/TDSEndpointCompatibilityVisitor.cs index 66623d98..96b29cfe 100644 --- a/MarkMpn.Sql4Cds.Engine/Visitors/TDSEndpointCompatibilityVisitor.cs +++ b/MarkMpn.Sql4Cds.Engine/Visitors/TDSEndpointCompatibilityVisitor.cs @@ -31,12 +31,13 @@ class TDSEndpointCompatibilityVisitor : TSqlFragmentVisitor /// Indicates if this query is the entire SQL batch, or a single statement within it /// A mapping of table aliases to table names available from the outer query /// A pre-calculated list of supported tables - public TDSEndpointCompatibilityVisitor(IDbConnection con, IAttributeMetadataCache metadata, bool? isEntireBatch = null, Dictionary outerTableNames = null, HashSet supportedTables = null) + /// A mapping of CTE names to their definitions from the outer query + public TDSEndpointCompatibilityVisitor(IDbConnection con, IAttributeMetadataCache metadata, bool? isEntireBatch = null, Dictionary outerTableNames = null, HashSet supportedTables = null, Dictionary ctes = null) { _con = con; _metadata = metadata; _tableNames = new Dictionary(StringComparer.OrdinalIgnoreCase); - _ctes = new Dictionary(StringComparer.OrdinalIgnoreCase); + _ctes = ctes ?? new Dictionary(StringComparer.OrdinalIgnoreCase); _isEntireBatch = isEntireBatch; if (outerTableNames != null) @@ -126,15 +127,7 @@ public override void Visit(ColumnReferenceExpression node) // Table name not specified. Try to find it in the list of current tables foreach (var table in _tableNames.Values) { - if (GetCTECols(table, out var cols)) - { - if (!cols.Contains(columnName)) - { - IsCompatible = false; - return; - } - } - else + if (!GetCTECols(table, out _)) { var attribute = TryGetEntity(table)?.Attributes?.SingleOrDefault(a => a.LogicalName.Equals(columnName)); @@ -296,7 +289,7 @@ public override void Visit(ScalarSubquery node) // Name resolution needs to be scoped to the query, so create a new sub-visitor if (IsCompatible && _root != node) { - var subVisitor = new TDSEndpointCompatibilityVisitor(_con, _metadata, _isEntireBatch, _tableNames, _supportedTables); + var subVisitor = new TDSEndpointCompatibilityVisitor(_con, _metadata, _isEntireBatch, _tableNames, _supportedTables, _ctes); node.Accept(subVisitor); if (!subVisitor.IsCompatible) @@ -316,7 +309,7 @@ public override void Visit(QueryDerivedTable node) // Name resolution needs to be scoped to the query, so create a new sub-visitor if (IsCompatible && _root != node) { - var subVisitor = new TDSEndpointCompatibilityVisitor(_con, _metadata, _isEntireBatch, supportedTables: _supportedTables); + var subVisitor = new TDSEndpointCompatibilityVisitor(_con, _metadata, _isEntireBatch, supportedTables: _supportedTables, ctes: _ctes); node.Accept(subVisitor); if (!subVisitor.IsCompatible) @@ -336,7 +329,7 @@ public override void ExplicitVisit(SelectStatement node) // Name resolution needs to be scoped to the query, so create a new sub-visitor if (IsCompatible && _root != node) { - var subVisitor = new TDSEndpointCompatibilityVisitor(_con, _metadata, _isEntireBatch, supportedTables: _supportedTables); + var subVisitor = new TDSEndpointCompatibilityVisitor(_con, _metadata, _isEntireBatch, supportedTables: _supportedTables, ctes: _ctes); subVisitor._root = node; // Visit CTEs first From 9f4349b70606e09f816550e0cb73407523190f9b Mon Sep 17 00:00:00 2001 From: Mark Carrington Date: Tue, 24 Oct 2023 17:09:00 +0100 Subject: [PATCH 25/81] Check for multi-currency issues when aggregating non-base currency fields --- .../ExecutionPlan/AssertNode.cs | 16 ++++- .../ExecutionPlan/HashMatchAggregateNode.cs | 65 ++++++++++++++++++- 2 files changed, 78 insertions(+), 3 deletions(-) diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/AssertNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/AssertNode.cs index 9125ce29..980bdf2b 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/AssertNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/AssertNode.cs @@ -14,6 +14,11 @@ namespace MarkMpn.Sql4Cds.Engine.ExecutionPlan /// class AssertNode : BaseDataNode, ISingleSourceExecutionPlanNode { + public AssertNode() + { + ExceptionConstructor = msg => new ApplicationException(msg); + } + /// /// The data source for the assertion /// @@ -34,12 +39,18 @@ class AssertNode : BaseDataNode, ISingleSourceExecutionPlanNode [DisplayName("Error Message")] public string ErrorMessage { get; set; } + /// + /// The type of exception to throw when the returns false + /// + [Browsable(false)] + public Func ExceptionConstructor { get; set; } + protected override IEnumerable ExecuteInternal(NodeExecutionContext context) { foreach (var entity in Source.Execute(context)) { if (!Assertion(entity)) - throw new ApplicationException(ErrorMessage); + throw ExceptionConstructor(ErrorMessage); yield return entity; } @@ -78,7 +89,8 @@ public override object Clone() { Source = (IDataExecutionPlanNodeInternal)Source.Clone(), Assertion = Assertion, - ErrorMessage = ErrorMessage + ErrorMessage = ErrorMessage, + ExceptionConstructor = ExceptionConstructor }; clone.Source.Parent = clone; diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/HashMatchAggregateNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/HashMatchAggregateNode.cs index e9caab2f..f1fe0f28 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/HashMatchAggregateNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/HashMatchAggregateNode.cs @@ -21,6 +21,13 @@ namespace MarkMpn.Sql4Cds.Engine.ExecutionPlan /// class HashMatchAggregateNode : BaseAggregateNode { + class MultiCurrencyAggregateException : ApplicationException + { + public MultiCurrencyAggregateException(string message) : base(message) + { + } + } + private bool _folded; protected override IEnumerable ExecuteInternal(NodeExecutionContext context) @@ -124,6 +131,7 @@ Source is FetchXmlScan fetch && // Check if all the aggregates & groupings can be done in FetchXML. Can only convert them if they can ALL // be handled - if any one needs to be calculated manually, we need to calculate them all. var canUseFetchXmlAggregate = true; + var addMultiCurrencyCheck = false; // Also track if we can partition the query for larger source data sets. We can't partition DISTINCT aggregates, // and need to transform AVG(field) to SUM(field) / COUNT(field) @@ -467,6 +475,10 @@ Source is FetchXmlScan fetch && if ((attr is LookupAttributeMetadata || attr is UniqueIdentifierAttributeMetadata || attr?.IsPrimaryId == true) && (aggregateType == FetchXml.AggregateType.min || aggregateType == FetchXml.AggregateType.max)) canUseFetchXmlAggregate = false; + // Can't do do aggregation on money values in multi-currency orgs + if (attr is MoneyAttributeMetadata money && money.IsBaseCurrency == false) + addMultiCurrencyCheck = true; + var attribute = fetchXml.AddAttribute(colName, a => a.aggregate == aggregateType && a.alias == agg.Key && a.distinct == distinct, metadata, out _, out _); if (attribute.name != attr?.LogicalName) @@ -497,6 +509,57 @@ Source is FetchXmlScan fetch && IDataExecutionPlanNodeInternal firstTry = fetchXml; + if (addMultiCurrencyCheck) + { + var currencyCheckFetchXml = new FetchXmlScan + { + DataSource = fetchXml.DataSource, + Alias = context.GetExpressionName(), + FetchXml = new FetchXml.FetchType + { + top = "2", + Items = new object[] + { + new FetchEntityType + { + name = "transactioncurrency", + Items = new object[] + { + new FetchAttributeType + { + name = "transactioncurrencyid" + } + } + } + } + } + }; + var currencyCount = new StreamAggregateNode + { + Source = currencyCheckFetchXml, + Aggregates = + { + [context.GetExpressionName()] = new Aggregate + { + AggregateType = AggregateType.CountStar + } + } + }; + var singleCurrencyAssert = new AssertNode + { + Source = currencyCount, + Assertion = e => ((SqlInt32)e[currencyCount.Aggregates.Single().Key]).Value == 1, + ErrorMessage = "Multiple currencies found - aggregating non-base currency values is not supported in FetchXML", + ExceptionConstructor = msg => new MultiCurrencyAggregateException(msg) + }; + firstTry = new NestedLoopNode + { + LeftSource = singleCurrencyAssert, + RightSource = firstTry, + JoinType = QualifiedJoinType.Inner + }; + } + // If the main aggregate query fails due to having over 50K records, check if we can retry with partitioning. We // need a createdon field to be available for this to work. if (canPartition) @@ -630,7 +693,7 @@ Source is FetchXmlScan fetch && { TrySource = firstTry, CatchSource = nonFetchXmlAggregate, - ExceptionFilter = ex => (ex is QueryExecutionException qee && (qee.InnerException is PartitionedAggregateNode.PartitionOverflowException || qee.InnerException is FetchXmlScan.InvalidPagingException)) || (GetOrganizationServiceFault(ex, out var fault) && (IsAggregateQueryRetryable(fault) || IsCompositeAddressPluginBug(fault))) + ExceptionFilter = ex => (ex is QueryExecutionException qee && (qee.InnerException is PartitionedAggregateNode.PartitionOverflowException || qee.InnerException is FetchXmlScan.InvalidPagingException || qee.InnerException is MultiCurrencyAggregateException)) || (GetOrganizationServiceFault(ex, out var fault) && (IsAggregateQueryRetryable(fault) || IsCompositeAddressPluginBug(fault))) }; firstTry.Parent = tryCatch; From 9ae6aa7a41cd2fa6f415c146a2d8b533085c22e4 Mon Sep 17 00:00:00 2001 From: Mark Carrington Date: Wed, 25 Oct 2023 14:42:03 +0100 Subject: [PATCH 26/81] Allow using columns from outer queries in joins Fixes #376 --- MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs index 3e1b89b6..c55069e0 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs @@ -3840,6 +3840,9 @@ private IDataExecutionPlanNodeInternal ConvertTableReference(TableReference refe var rhsSchema = rhs.GetSchema(context); var fixedValueColumns = GetFixedValueColumnsFromWhereClause(query, lhsSchema, rhsSchema); + // Capture any references to data from an outer query + CaptureOuterReferences(outerSchema, null, join.SearchCondition, context, outerReferences); + var joinConditionVisitor = new JoinConditionVisitor(lhsSchema, rhsSchema, fixedValueColumns); join.SearchCondition.Accept(joinConditionVisitor); From 17c2a73ed91816318195d7bfc500dbbfa8ec3379 Mon Sep 17 00:00:00 2001 From: Mark Carrington Date: Wed, 25 Oct 2023 14:42:36 +0100 Subject: [PATCH 27/81] Use standard Index Spool icon for custom Adaptive Index Spool node --- .../QueryExecution/QueryExecutionHandler.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MarkMpn.Sql4Cds.LanguageServer/QueryExecution/QueryExecutionHandler.cs b/MarkMpn.Sql4Cds.LanguageServer/QueryExecution/QueryExecutionHandler.cs index 5d2abdaa..2a74444f 100644 --- a/MarkMpn.Sql4Cds.LanguageServer/QueryExecution/QueryExecutionHandler.cs +++ b/MarkMpn.Sql4Cds.LanguageServer/QueryExecution/QueryExecutionHandler.cs @@ -676,6 +676,8 @@ private ExecutionPlanNode ConvertExecutionPlanNode(IExecutionPlanNode node, Time converted.Type = "languageConstructCatchAll"; else if (converted.Type == "xmlWriter") converted.Type = "udx"; + else if (converted.Type == "adaptiveIndexSpool") + converted.Type = "indexSpool"; // Get the filtered list of properties var typeDescriptor = new ExecutionPlanNodeTypeDescriptor(node, !executed, _ => null); From 10aa0fbb57e14435e8666ad9c1bd23c59450b489 Mon Sep 17 00:00:00 2001 From: Mark Carrington Date: Wed, 25 Oct 2023 14:42:54 +0100 Subject: [PATCH 28/81] Support disconnect message from object explorer --- .../Contracts/CloseSessionParams.cs | 14 +++++++ .../Contracts/CloseSessionRequest.cs | 15 ++++++++ .../Contracts/CloseSessionResponse.cs | 21 +++++++++++ .../SessionDisconnectedNotification.cs | 37 +++++++++++++++++++ .../ObjectExplorer/ObjectExplorerHandler.cs | 19 ++++++++++ 5 files changed, 106 insertions(+) create mode 100644 MarkMpn.Sql4Cds.LanguageServer/ObjectExplorer/Contracts/CloseSessionParams.cs create mode 100644 MarkMpn.Sql4Cds.LanguageServer/ObjectExplorer/Contracts/CloseSessionRequest.cs create mode 100644 MarkMpn.Sql4Cds.LanguageServer/ObjectExplorer/Contracts/CloseSessionResponse.cs create mode 100644 MarkMpn.Sql4Cds.LanguageServer/ObjectExplorer/Contracts/SessionDisconnectedNotification.cs diff --git a/MarkMpn.Sql4Cds.LanguageServer/ObjectExplorer/Contracts/CloseSessionParams.cs b/MarkMpn.Sql4Cds.LanguageServer/ObjectExplorer/Contracts/CloseSessionParams.cs new file mode 100644 index 00000000..611cb280 --- /dev/null +++ b/MarkMpn.Sql4Cds.LanguageServer/ObjectExplorer/Contracts/CloseSessionParams.cs @@ -0,0 +1,14 @@ +namespace MarkMpn.Sql4Cds.LanguageServer.ObjectExplorer.Contracts +{ + /// + /// Parameters to the . + /// + public class CloseSessionParams + { + /// + /// The Id returned from a . This + /// is used to disambiguate between different trees. + /// + public string SessionId { get; set; } + } +} diff --git a/MarkMpn.Sql4Cds.LanguageServer/ObjectExplorer/Contracts/CloseSessionRequest.cs b/MarkMpn.Sql4Cds.LanguageServer/ObjectExplorer/Contracts/CloseSessionRequest.cs new file mode 100644 index 00000000..cbdea1ed --- /dev/null +++ b/MarkMpn.Sql4Cds.LanguageServer/ObjectExplorer/Contracts/CloseSessionRequest.cs @@ -0,0 +1,15 @@ +using MarkMpn.Sql4Cds.LanguageServer.Connection.Contracts; +using Microsoft.VisualStudio.LanguageServer.Protocol; + +namespace MarkMpn.Sql4Cds.LanguageServer.ObjectExplorer.Contracts +{ + /// + /// Closes an Object Explorer tree session for a specific connection. + /// + public class CloseSessionRequest + { + public const string MessageName = "objectexplorer/closesession"; + + public static readonly LspRequest Type = new LspRequest(MessageName); + } +} diff --git a/MarkMpn.Sql4Cds.LanguageServer/ObjectExplorer/Contracts/CloseSessionResponse.cs b/MarkMpn.Sql4Cds.LanguageServer/ObjectExplorer/Contracts/CloseSessionResponse.cs new file mode 100644 index 00000000..2464e72c --- /dev/null +++ b/MarkMpn.Sql4Cds.LanguageServer/ObjectExplorer/Contracts/CloseSessionResponse.cs @@ -0,0 +1,21 @@ +namespace MarkMpn.Sql4Cds.LanguageServer.ObjectExplorer.Contracts +{ + /// + /// Information returned from a . + /// Contains success information, a to be used when + /// requesting closing an existing session. + /// + public class CloseSessionResponse + { + /// + /// Boolean indicating if the session was closed successfully + /// + public bool Success { get; set; } + + /// + /// Unique ID to use when sending any requests for objects in the + /// tree under the node + /// + public string SessionId { get; set; } + } +} diff --git a/MarkMpn.Sql4Cds.LanguageServer/ObjectExplorer/Contracts/SessionDisconnectedNotification.cs b/MarkMpn.Sql4Cds.LanguageServer/ObjectExplorer/Contracts/SessionDisconnectedNotification.cs new file mode 100644 index 00000000..d1ba63e0 --- /dev/null +++ b/MarkMpn.Sql4Cds.LanguageServer/ObjectExplorer/Contracts/SessionDisconnectedNotification.cs @@ -0,0 +1,37 @@ +using Microsoft.VisualStudio.LanguageServer.Protocol; + +namespace MarkMpn.Sql4Cds.LanguageServer.ObjectExplorer.Contracts +{ + /// + /// Information returned when a session is disconnected. + /// Contains success information and a + /// + public class SessionDisconnectedParameters + { + /// + /// Boolean indicating if the connection was successful + /// + public bool Success { get; set; } + + /// + /// Unique ID to use when sending any requests for objects in the + /// tree under the node + /// + public string SessionId { get; set; } + + /// + /// Error message returned from the engine for a object explorer session failure reason, if any. + /// + public string ErrorMessage { get; set; } + } + + /// + /// Session disconnected notification + /// + public class SessionDisconnectedNotification + { + public const string MessageName = "objectexplorer/sessiondisconnected"; + + public static readonly LspNotification Type = new LspNotification(MessageName); + } +} diff --git a/MarkMpn.Sql4Cds.LanguageServer/ObjectExplorer/ObjectExplorerHandler.cs b/MarkMpn.Sql4Cds.LanguageServer/ObjectExplorer/ObjectExplorerHandler.cs index e3ef7c42..d27b8067 100644 --- a/MarkMpn.Sql4Cds.LanguageServer/ObjectExplorer/ObjectExplorerHandler.cs +++ b/MarkMpn.Sql4Cds.LanguageServer/ObjectExplorer/ObjectExplorerHandler.cs @@ -29,6 +29,7 @@ public void Initialize(JsonRpc lsp) lsp.AddHandler(CreateSessionRequest.Type, HandleCreateSession); lsp.AddHandler(ExpandRequest.Type, HandleExpand); lsp.AddHandler(RefreshRequest.Type, HandleRefresh); + lsp.AddHandler(CloseSessionRequest.Type, HandleCloseSession); } public CreateSessionResponse HandleCreateSession(ConnectionDetails request) @@ -61,6 +62,24 @@ public CreateSessionResponse HandleCreateSession(ConnectionDetails request) return new CreateSessionResponse { SessionId = session.SessionId }; } + public CloseSessionResponse HandleCloseSession(CloseSessionParams request) + { + _connectionManager.Disconnect(request.SessionId); + + _ = _lsp.NotifyAsync(SessionDisconnectedNotification.Type, new SessionDisconnectedParameters + { + SessionId = request.SessionId, + Success = true, + ErrorMessage = null + }); + + return new CloseSessionResponse + { + SessionId = request.SessionId, + Success = true + }; + } + public bool HandleExpand(ExpandParams request) { var session = _connectionManager.GetConnection(request.SessionId); From 9aaad16664c008472e523bf8bf425be9d7e8db31 Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Fri, 27 Oct 2023 11:46:52 +0100 Subject: [PATCH 29/81] Added missing files to NuGet package Fixes #377 --- MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.FetchXml.nuspec | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.FetchXml.nuspec b/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.FetchXml.nuspec index f02a69da..cddda3d3 100644 --- a/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.FetchXml.nuspec +++ b/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.FetchXml.nuspec @@ -18,8 +18,10 @@ + + From 1a1c177ba37ade809a01cb1d91c9a804b51f18f1 Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Fri, 27 Oct 2023 11:47:21 +0100 Subject: [PATCH 30/81] Improved FetchXML to SQL conversion for hierarchical filters --- .../FakeXrmEasyTestsBase.cs | 34 ++++ .../FetchXml2SqlTests.cs | 122 ++++++++++++- .../Metadata/Account.cs | 7 + MarkMpn.Sql4Cds.Engine/FetchXml2Sql.cs | 162 +++++++++--------- 4 files changed, 247 insertions(+), 78 deletions(-) diff --git a/MarkMpn.Sql4Cds.Engine.FetchXml.Tests/FakeXrmEasyTestsBase.cs b/MarkMpn.Sql4Cds.Engine.FetchXml.Tests/FakeXrmEasyTestsBase.cs index 1f34ee35..3355415b 100644 --- a/MarkMpn.Sql4Cds.Engine.FetchXml.Tests/FakeXrmEasyTestsBase.cs +++ b/MarkMpn.Sql4Cds.Engine.FetchXml.Tests/FakeXrmEasyTestsBase.cs @@ -8,6 +8,7 @@ using FakeXrmEasy.FakeMessageExecutors; using Microsoft.Crm.Sdk.Messages; using Microsoft.Xrm.Sdk; +using Microsoft.Xrm.Sdk.Metadata; namespace MarkMpn.Sql4Cds.Engine.FetchXml.Tests { @@ -23,6 +24,39 @@ public FakeXrmEasyTestsBase() _context.AddFakeMessageExecutor(new WhoAmIHandler()); _service = _context.GetOrganizationService(); + + SetRelationships(_context); + } + + private void SetRelationships(XrmFakedContext context) + { + foreach (var entity in context.CreateMetadataQuery()) + { + if (entity.OneToManyRelationships == null) + typeof(EntityMetadata).GetProperty(nameof(EntityMetadata.OneToManyRelationships)).SetValue(entity, Array.Empty()); + + if (entity.ManyToOneRelationships == null) + typeof(EntityMetadata).GetProperty(nameof(EntityMetadata.ManyToOneRelationships)).SetValue(entity, Array.Empty()); + + if (entity.LogicalName == "account") + { + // Add parentaccountid relationship + var relationship = new OneToManyRelationshipMetadata + { + SchemaName = "account_parentaccount", + ReferencedEntity = "account", + ReferencedAttribute = "accountid", + ReferencingEntity = "account", + ReferencingAttribute = "parentaccountid", + IsHierarchical = true + }; + + typeof(EntityMetadata).GetProperty(nameof(EntityMetadata.OneToManyRelationships)).SetValue(entity, entity.OneToManyRelationships.Concat(new[] { relationship }).ToArray()); + typeof(EntityMetadata).GetProperty(nameof(EntityMetadata.ManyToOneRelationships)).SetValue(entity, entity.ManyToOneRelationships.Concat(new[] { relationship }).ToArray()); + } + + context.SetEntityMetadata(entity); + } } } diff --git a/MarkMpn.Sql4Cds.Engine.FetchXml.Tests/FetchXml2SqlTests.cs b/MarkMpn.Sql4Cds.Engine.FetchXml.Tests/FetchXml2SqlTests.cs index 2ff00c19..21cdd4ae 100644 --- a/MarkMpn.Sql4Cds.Engine.FetchXml.Tests/FetchXml2SqlTests.cs +++ b/MarkMpn.Sql4Cds.Engine.FetchXml.Tests/FetchXml2SqlTests.cs @@ -431,9 +431,129 @@ public void ArchiveJoins() Assert.AreEqual("SELECT contact.firstname, contact.lastname, account.name FROM archive.contact INNER JOIN archive.account ON contact.parentcustomerid = account.accountid", NormalizeWhitespace(converted)); } + [TestMethod] + public void Under() + { + var metadata = new AttributeMetadataCache(_service); + var fetch = @" + + + + + + + "; + + var converted = FetchXml2Sql.Convert(_service, metadata, fetch, new FetchXml2SqlOptions { ConvertFetchXmlOperatorsTo = FetchXmlOperatorConversion.SqlCalculations }, out _); + + Assert.AreEqual(NormalizeWhitespace(@" + WITH account_hierarchical(accountid) AS ( + SELECT accountid FROM account WHERE parentaccountid = 'e2218046-f778-42f6-a8a7-772d0653349b' + UNION ALL + SELECT account.accountid FROM account INNER JOIN account_hierarchical ON account.parentaccountid = account_hierarchical.accountid + ) + SELECT * FROM account WHERE accountid IN ( SELECT accountid FROM account_hierarchical )"), NormalizeWhitespace(converted)); + } + + [TestMethod] + public void EqOrUnder() + { + var metadata = new AttributeMetadataCache(_service); + var fetch = @" + + + + + + + "; + + var converted = FetchXml2Sql.Convert(_service, metadata, fetch, new FetchXml2SqlOptions { ConvertFetchXmlOperatorsTo = FetchXmlOperatorConversion.SqlCalculations }, out _); + + Assert.AreEqual(NormalizeWhitespace(@" + WITH account_hierarchical(accountid) AS ( + SELECT accountid FROM account WHERE accountid = 'e2218046-f778-42f6-a8a7-772d0653349b' + UNION ALL + SELECT account.accountid FROM account INNER JOIN account_hierarchical ON account.parentaccountid = account_hierarchical.accountid + ) + SELECT * FROM account WHERE accountid IN ( SELECT accountid FROM account_hierarchical )"), NormalizeWhitespace(converted)); + } + + [TestMethod] + public void NotUnder() + { + var metadata = new AttributeMetadataCache(_service); + var fetch = @" + + + + + + + "; + + var converted = FetchXml2Sql.Convert(_service, metadata, fetch, new FetchXml2SqlOptions { ConvertFetchXmlOperatorsTo = FetchXmlOperatorConversion.SqlCalculations }, out _); + + Assert.AreEqual(NormalizeWhitespace(@" + WITH account_hierarchical(accountid) AS ( + SELECT accountid FROM account WHERE accountid = 'e2218046-f778-42f6-a8a7-772d0653349b' + UNION ALL + SELECT account.accountid FROM account INNER JOIN account_hierarchical ON account.parentaccountid = account_hierarchical.accountid + ) + SELECT * FROM account WHERE (accountid IS NULL OR accountid NOT IN ( SELECT accountid FROM account_hierarchical ))"), NormalizeWhitespace(converted)); + } + + [TestMethod] + public void Above() + { + var metadata = new AttributeMetadataCache(_service); + var fetch = @" + + + + + + + "; + + var converted = FetchXml2Sql.Convert(_service, metadata, fetch, new FetchXml2SqlOptions { ConvertFetchXmlOperatorsTo = FetchXmlOperatorConversion.SqlCalculations }, out _); + + Assert.AreEqual(NormalizeWhitespace(@" + WITH account_hierarchical(accountid, parentaccountid) AS ( + SELECT account.accountid, account.parentaccountid FROM account INNER JOIN account AS anchor ON account.accountid = anchor.parentaccountid WHERE anchor.accountid = 'e2218046-f778-42f6-a8a7-772d0653349b' + UNION ALL + SELECT account.accountid, account.parentaccountid FROM account INNER JOIN account_hierarchical ON account.accountid = account_hierarchical.parentaccountid + ) + SELECT * FROM account WHERE accountid IN ( SELECT accountid FROM account_hierarchical )"), NormalizeWhitespace(converted)); + } + + [TestMethod] + public void EqOrAbove() + { + var metadata = new AttributeMetadataCache(_service); + var fetch = @" + + + + + + + "; + + var converted = FetchXml2Sql.Convert(_service, metadata, fetch, new FetchXml2SqlOptions { ConvertFetchXmlOperatorsTo = FetchXmlOperatorConversion.SqlCalculations }, out _); + + Assert.AreEqual(NormalizeWhitespace(@" + WITH account_hierarchical(accountid, parentaccountid) AS ( + SELECT accountid, parentaccountid FROM account WHERE accountid = 'e2218046-f778-42f6-a8a7-772d0653349b' + UNION ALL + SELECT account.accountid, account.parentaccountid FROM account INNER JOIN account_hierarchical ON account.accountid = account_hierarchical.parentaccountid + ) + SELECT * FROM account WHERE accountid IN ( SELECT accountid FROM account_hierarchical )"), NormalizeWhitespace(converted)); + } + private static string NormalizeWhitespace(string s) { - return Regex.Replace(s, "\\s+", " "); + return Regex.Replace(s, "\\s+", " ").Trim(); } } } diff --git a/MarkMpn.Sql4Cds.Engine.FetchXml.Tests/Metadata/Account.cs b/MarkMpn.Sql4Cds.Engine.FetchXml.Tests/Metadata/Account.cs index 0a9856ec..67b245ff 100644 --- a/MarkMpn.Sql4Cds.Engine.FetchXml.Tests/Metadata/Account.cs +++ b/MarkMpn.Sql4Cds.Engine.FetchXml.Tests/Metadata/Account.cs @@ -29,5 +29,12 @@ class Account [AttributeLogicalName("primarycontactid")] [RelationshipSchemaName("account_primarycontact")] public Contact PrimaryContact { get; set; } + + [AttributeLogicalName("parentaccountid")] + public EntityReference ParentAccountId { get; set; } + + [AttributeLogicalName("parentaccountid")] + [RelationshipSchemaName("account_parentaccount")] + public Account ParentAccount { get; set; } } } diff --git a/MarkMpn.Sql4Cds.Engine/FetchXml2Sql.cs b/MarkMpn.Sql4Cds.Engine/FetchXml2Sql.cs index 73be4b6b..66777927 100644 --- a/MarkMpn.Sql4Cds.Engine/FetchXml2Sql.cs +++ b/MarkMpn.Sql4Cds.Engine/FetchXml2Sql.cs @@ -1674,7 +1674,7 @@ private static BooleanExpression GetCondition(IOrganizationService org, IAttribu case @operator.eqorunder: case @operator.notunder: { - var cte = GetUnderCte(meta, new Guid(condition.value), ctes); + var cte = GetUnderCte(meta, new Guid(condition.value), ctes, condition.@operator == @operator.under); var inPred = new InPredicate { Expression = field, @@ -1692,7 +1692,6 @@ private static BooleanExpression GetCondition(IOrganizationService org, IAttribu { Identifiers = { - new Identifier { Value = cte.ExpressionName.Value }, new Identifier { Value = meta.PrimaryIdAttribute } } } @@ -1714,25 +1713,6 @@ private static BooleanExpression GetCondition(IOrganizationService org, IAttribu } } } - }, - WhereClause = condition.@operator != @operator.under ? null : new WhereClause - { - SearchCondition = new BooleanComparisonExpression - { - FirstExpression = new ColumnReferenceExpression - { - MultiPartIdentifier = new MultiPartIdentifier - { - Identifiers = - { - new Identifier { Value = cte.ExpressionName.Value }, - new Identifier { Value = "Level" } - } - } - }, - ComparisonType = BooleanComparisonType.NotEqualToBrackets, - SecondExpression = new IntegerLiteral { Value = "0" } - } } } } @@ -1756,7 +1736,7 @@ private static BooleanExpression GetCondition(IOrganizationService org, IAttribu case @operator.above: case @operator.eqorabove: { - var cte = GetAboveCte(meta, new Guid(condition.value), ctes); + var cte = GetAboveCte(meta, new Guid(condition.value), ctes, condition.@operator == @operator.above); var inPred = new InPredicate { Expression = field, @@ -1774,7 +1754,6 @@ private static BooleanExpression GetCondition(IOrganizationService org, IAttribu { Identifiers = { - new Identifier { Value = cte.ExpressionName.Value }, new Identifier { Value = meta.PrimaryIdAttribute } } } @@ -1796,25 +1775,6 @@ private static BooleanExpression GetCondition(IOrganizationService org, IAttribu } } } - }, - WhereClause = condition.@operator != @operator.above ? null : new WhereClause - { - SearchCondition = new BooleanComparisonExpression - { - FirstExpression = new ColumnReferenceExpression - { - MultiPartIdentifier = new MultiPartIdentifier - { - Identifiers = - { - new Identifier { Value = cte.ExpressionName.Value }, - new Identifier { Value = "Level" } - } - } - }, - ComparisonType = BooleanComparisonType.NotEqualToBrackets, - SecondExpression = new IntegerLiteral { Value = "0" } - } } } } @@ -1999,19 +1959,20 @@ private static FunctionCall DatePart(string datePart, ScalarExpression date) /// The metadata of the entity to recurse in /// The unique identifier of the starting record to recurse down from /// The details of all the CTEs already in the query + /// Indicates if the starting record should be excluded from the results /// The CTE that represents the required query /// /// Generates a CTE like: /// - /// account_hierarchical([Level], AccountId, ParentAccountId) AS + /// account_hierarchical(AccountId) AS /// ( - /// SELECT 0, accountid, parentaccountid FROM account WHERE accountid = 'guid' + /// SELECT accountid FROM account WHERE accountid = 'guid' /// UNION ALL - /// SELECT Level + 1, account.accountid, account.parentaccountid FROM account INNER JOIN account_hierarchical ON account.parentaccountid = account_hierarchical.accountid + /// SELECT account.accountid FROM account INNER JOIN account_hierarchical ON account.parentaccountid = account_hierarchical.accountid /// - private static CommonTableExpression GetUnderCte(EntityMetadata meta, Guid guid, IDictionary ctes) + private static CommonTableExpression GetUnderCte(EntityMetadata meta, Guid guid, IDictionary ctes, bool excludeAnchor) { - return GetCte(meta, guid, false, ctes); + return GetCte(meta, guid, false, ctes, excludeAnchor); } /// @@ -2020,19 +1981,20 @@ private static CommonTableExpression GetUnderCte(EntityMetadata meta, Guid guid, /// The metadata of the entity to recurse in /// The unique identifier of the starting record to recurse down from /// The details of all the CTEs already in the query + /// Indicates if the starting record should be excluded from the results /// The CTE that represents the required query /// /// Generates a CTE like: /// - /// account_hierarchical([Level], AccountId, ParentAccountId) AS + /// account_hierarchical(AccountId, ParentAccountId) AS /// ( - /// SELECT 0, accountid, parentaccountid FROM account WHERE accountid = 'guid' + /// SELECT accountid, parentaccountid FROM account WHERE accountid = 'guid' /// UNION ALL - /// SELECT Level + 1, account.accountid, account.parentaccountid FROM account INNER JOIN account_hierarchical ON account.accountid = account_hierarchical.parentaccountid + /// SELECT account.accountid, account.parentaccountid FROM account INNER JOIN account_hierarchical ON account.accountid = account_hierarchical.parentaccountid /// - private static CommonTableExpression GetAboveCte(EntityMetadata meta, Guid guid, IDictionary ctes) + private static CommonTableExpression GetAboveCte(EntityMetadata meta, Guid guid, IDictionary ctes, bool excludeAnchor) { - return GetCte(meta, guid, true, ctes); + return GetCte(meta, guid, true, ctes, excludeAnchor); } /// @@ -2043,7 +2005,7 @@ private static CommonTableExpression GetAboveCte(EntityMetadata meta, Guid guid, /// Indicates if the CTE should find records above the selected record (true) or below (false) /// The details of all the CTEs already in the query /// The CTE that represents the required query - private static CommonTableExpression GetCte(EntityMetadata meta, Guid guid, bool above, IDictionary ctes) + private static CommonTableExpression GetCte(EntityMetadata meta, Guid guid, bool above, IDictionary ctes, bool excludeAnchor) { if (meta == null) throw new DisconnectedException(); @@ -2070,7 +2032,6 @@ private static CommonTableExpression GetCte(EntityMetadata meta, Guid guid, bool ExpressionName = new Identifier { Value = name }, Columns = { - new Identifier { Value = "Level" }, new Identifier { Value = meta.PrimaryIdAttribute }, new Identifier { Value = parentLookupAttribute } }, @@ -2080,10 +2041,6 @@ private static CommonTableExpression GetCte(EntityMetadata meta, Guid guid, bool { SelectElements = { - new SelectScalarExpression - { - Expression = new IntegerLiteral { Value = "0" } - }, new SelectScalarExpression { Expression = new ColumnReferenceExpression @@ -2137,7 +2094,7 @@ private static CommonTableExpression GetCte(EntityMetadata meta, Guid guid, bool { Identifiers = { - new Identifier { Value = meta.PrimaryIdAttribute } + new Identifier { Value = excludeAnchor && !above ? parentLookupAttribute : meta.PrimaryIdAttribute } } } }, @@ -2152,24 +2109,6 @@ private static CommonTableExpression GetCte(EntityMetadata meta, Guid guid, bool { SelectElements = { - new SelectScalarExpression - { - Expression = new BinaryExpression - { - FirstExpression = new ColumnReferenceExpression - { - MultiPartIdentifier = new MultiPartIdentifier - { - Identifiers = - { - new Identifier { Value = "Level" } - } - } - }, - BinaryExpressionType = BinaryExpressionType.Add, - SecondExpression = new IntegerLiteral { Value = "1" } - } - }, new SelectScalarExpression { Expression = new ColumnReferenceExpression @@ -2259,6 +2198,75 @@ private static CommonTableExpression GetCte(EntityMetadata meta, Guid guid, bool } }; + if (excludeAnchor && above) + { + // Need to include a join in the anchor query to find the records above the source record but not including that record + var query = (BinaryQueryExpression)cte.QueryExpression; + var anchorQuery = (QuerySpecification)query.FirstQueryExpression; + var filter = (BooleanComparisonExpression)anchorQuery.WhereClause.SearchCondition; + var field = (ColumnReferenceExpression)filter.FirstExpression; + + anchorQuery.FromClause.TableReferences[0] = new QualifiedJoin + { + FirstTableReference = anchorQuery.FromClause.TableReferences[0], + QualifiedJoinType = QualifiedJoinType.Inner, + SecondTableReference = new NamedTableReference + { + SchemaObject = new SchemaObjectName + { + Identifiers = + { + new Identifier { Value = meta.LogicalName } + } + }, + Alias = new Identifier { Value = "anchor" } + }, + SearchCondition = new BooleanComparisonExpression + { + FirstExpression = new ColumnReferenceExpression + { + MultiPartIdentifier = new MultiPartIdentifier + { + Identifiers = + { + new Identifier { Value = meta.LogicalName }, + new Identifier { Value = meta.PrimaryIdAttribute } + } + } + }, + ComparisonType = BooleanComparisonType.Equals, + SecondExpression = new ColumnReferenceExpression + { + MultiPartIdentifier = new MultiPartIdentifier + { + Identifiers = + { + new Identifier { Value = "anchor" }, + new Identifier { Value = parentLookupAttribute } + } + } + } + } + }; + + ((ColumnReferenceExpression)((SelectScalarExpression)anchorQuery.SelectElements[0]).Expression).MultiPartIdentifier.Identifiers.Insert(0, new Identifier { Value = meta.LogicalName }); + ((ColumnReferenceExpression)((SelectScalarExpression)anchorQuery.SelectElements[1]).Expression).MultiPartIdentifier.Identifiers.Insert(0, new Identifier { Value = meta.LogicalName }); + field.MultiPartIdentifier.Identifiers.Insert(0, new Identifier { Value = "anchor" }); + } + + if (!above) + { + // Don't need the parent attribute in the CTE for "under" queries + cte.Columns.RemoveAt(1); + + var query = (BinaryQueryExpression)cte.QueryExpression; + var anchorQuery = (QuerySpecification)query.FirstQueryExpression; + var recursiveQuery = (QuerySpecification)query.SecondQueryExpression; + + anchorQuery.SelectElements.RemoveAt(1); + recursiveQuery.SelectElements.RemoveAt(1); + } + ctes.Add(name, cte); return cte; From 7dee5fb804199610ef7d47484ce20db3b3e4f0c7 Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Sun, 29 Oct 2023 19:56:32 +0000 Subject: [PATCH 31/81] Fixed test --- MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs index c55069e0..79ae8ff4 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs @@ -3841,7 +3841,9 @@ private IDataExecutionPlanNodeInternal ConvertTableReference(TableReference refe var fixedValueColumns = GetFixedValueColumnsFromWhereClause(query, lhsSchema, rhsSchema); // Capture any references to data from an outer query - CaptureOuterReferences(outerSchema, null, join.SearchCondition, context, outerReferences); + // Use a temporary NestedLoopNode to include the full schema available within this query so far to ensure columns are + // used from this query in preference to the outer query. + CaptureOuterReferences(outerSchema, new NestedLoopNode { LeftSource = lhs, RightSource = rhs }, join.SearchCondition, context, outerReferences); var joinConditionVisitor = new JoinConditionVisitor(lhsSchema, rhsSchema, fixedValueColumns); join.SearchCondition.Accept(joinConditionVisitor); From add2b619c76c7234d90956b5ba97f97940f8e7d3 Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Mon, 30 Oct 2023 08:28:16 +0000 Subject: [PATCH 32/81] Added tests for folding CTEs to hierarchical FetchXML conditions --- MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs | 125 +++++++++++++++++- .../ExecutionPlanTests.cs | 2 + .../FakeXrmEasyTestsBase.cs | 19 +++ .../Metadata/Account.cs | 7 + .../Sql2FetchXmlTests.cs | 4 + 5 files changed, 156 insertions(+), 1 deletion(-) diff --git a/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs b/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs index 4297e47c..3d8cee34 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs +++ b/MarkMpn.Sql4Cds.Engine.Tests/CteTests.cs @@ -595,7 +595,6 @@ UNION ALL [TestMethod] public void FactorialCalcFiltered() { - using (var con = new Sql4CdsConnection(_localDataSource)) using (var cmd = con.CreateCommand()) { @@ -628,6 +627,130 @@ union all } } + [TestMethod] + public void Under() + { + var planBuilder = new ExecutionPlanBuilder(_localDataSource.Values, this); + + var query = @" + WITH account_hierarchical(accountid) AS ( + SELECT accountid FROM account WHERE parentaccountid = 'e2218046-f778-42f6-a8a7-772d0653349b' + UNION ALL + SELECT account.accountid FROM account INNER JOIN account_hierarchical ON account.parentaccountid = account_hierarchical.accountid + ) + SELECT * FROM account WHERE accountid IN ( SELECT accountid FROM account_hierarchical )"; + + var plans = planBuilder.Build(query, null, out _); + + Assert.AreEqual(1, plans.Length); + + var select = AssertNode(plans[0]); + var fetch = AssertNode(select.Source); + + AssertFetchXml(fetch, @" + + + + + + + + "); + } + + [TestMethod] + public void EqOrUnder() + { + var planBuilder = new ExecutionPlanBuilder(_localDataSource.Values, this); + + var query = @" + WITH account_hierarchical(accountid) AS ( + SELECT accountid FROM account WHERE accountid = 'e2218046-f778-42f6-a8a7-772d0653349b' + UNION ALL + SELECT account.accountid FROM account INNER JOIN account_hierarchical ON account.parentaccountid = account_hierarchical.accountid + ) + SELECT * FROM account WHERE accountid IN ( SELECT accountid FROM account_hierarchical )"; + + var plans = planBuilder.Build(query, null, out _); + + Assert.AreEqual(1, plans.Length); + + var select = AssertNode(plans[0]); + var fetch = AssertNode(select.Source); + + AssertFetchXml(fetch, @" + + + + + + + + "); + } + + [TestMethod] + public void Above() + { + var planBuilder = new ExecutionPlanBuilder(_localDataSource.Values, this); + + var query = @" + WITH account_hierarchical(accountid, parentaccountid) AS ( + SELECT account.accountid, account.parentaccountid FROM account INNER JOIN account AS anchor ON account.accountid = anchor.parentaccountid WHERE anchor.accountid = 'e2218046-f778-42f6-a8a7-772d0653349b' + UNION ALL + SELECT account.accountid, account.parentaccountid FROM account INNER JOIN account_hierarchical ON account.accountid = account_hierarchical.parentaccountid + ) + SELECT * FROM account WHERE accountid IN ( SELECT accountid FROM account_hierarchical )"; + + var plans = planBuilder.Build(query, null, out _); + + Assert.AreEqual(1, plans.Length); + + var select = AssertNode(plans[0]); + var fetch = AssertNode(select.Source); + + AssertFetchXml(fetch, @" + + + + + + + + "); + } + + [TestMethod] + public void EqOrAbove() + { + var planBuilder = new ExecutionPlanBuilder(_localDataSource.Values, this); + + var query = @" + WITH account_hierarchical(accountid, parentaccountid) AS ( + SELECT accountid, parentaccountid FROM account WHERE accountid = 'e2218046-f778-42f6-a8a7-772d0653349b' + UNION ALL + SELECT account.accountid, account.parentaccountid FROM account INNER JOIN account_hierarchical ON account.accountid = account_hierarchical.parentaccountid + ) + SELECT * FROM account WHERE accountid IN ( SELECT accountid FROM account_hierarchical )"; + + var plans = planBuilder.Build(query, null, out _); + + Assert.AreEqual(1, plans.Length); + + var select = AssertNode(plans[0]); + var fetch = AssertNode(select.Source); + + AssertFetchXml(fetch, @" + + + + + + + + "); + } + private T AssertNode(IExecutionPlanNode node) where T : IExecutionPlanNode { Assert.IsInstanceOfType(node, typeof(T)); diff --git a/MarkMpn.Sql4Cds.Engine.Tests/ExecutionPlanTests.cs b/MarkMpn.Sql4Cds.Engine.Tests/ExecutionPlanTests.cs index d08dfa6c..0c0a2787 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/ExecutionPlanTests.cs +++ b/MarkMpn.Sql4Cds.Engine.Tests/ExecutionPlanTests.cs @@ -128,6 +128,8 @@ public void SimpleSelectStar() "ownerid", "owneridname", "owneridtype", + "parentaccountid", + "parentaccountidname", "primarycontactid", "primarycontactidname", "turnover" diff --git a/MarkMpn.Sql4Cds.Engine.Tests/FakeXrmEasyTestsBase.cs b/MarkMpn.Sql4Cds.Engine.Tests/FakeXrmEasyTestsBase.cs index 4f8c59a4..20155e14 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/FakeXrmEasyTestsBase.cs +++ b/MarkMpn.Sql4Cds.Engine.Tests/FakeXrmEasyTestsBase.cs @@ -162,6 +162,8 @@ private void SetLookupTargets(XrmFakedContext context) typeof(EntityMetadata).GetProperty(nameof(EntityMetadata.ObjectTypeCode)).SetValue(entity, 1); var primaryContactId = (LookupAttributeMetadata)entity.Attributes.Single(a => a.LogicalName == "primarycontactid"); primaryContactId.Targets = new[] { "contact" }; + var parentAccountId = (LookupAttributeMetadata)entity.Attributes.Single(a => a.LogicalName == "parentaccountid"); + parentAccountId.Targets = new[] { "account" }; context.SetEntityMetadata(entity); } @@ -257,6 +259,23 @@ private void SetRelationships(XrmFakedContext context) if (entity.ManyToOneRelationships == null) typeof(EntityMetadata).GetProperty(nameof(EntityMetadata.ManyToOneRelationships)).SetValue(entity, Array.Empty()); + if (entity.LogicalName == "account") + { + // Add parentaccountid relationship + var relationship = new OneToManyRelationshipMetadata + { + SchemaName = "account_parentaccount", + ReferencedEntity = "account", + ReferencedAttribute = "accountid", + ReferencingEntity = "account", + ReferencingAttribute = "parentaccountid", + IsHierarchical = true + }; + + typeof(EntityMetadata).GetProperty(nameof(EntityMetadata.OneToManyRelationships)).SetValue(entity, entity.OneToManyRelationships.Concat(new[] { relationship }).ToArray()); + typeof(EntityMetadata).GetProperty(nameof(EntityMetadata.ManyToOneRelationships)).SetValue(entity, entity.ManyToOneRelationships.Concat(new[] { relationship }).ToArray()); + } + context.SetEntityMetadata(entity); } } diff --git a/MarkMpn.Sql4Cds.Engine.Tests/Metadata/Account.cs b/MarkMpn.Sql4Cds.Engine.Tests/Metadata/Account.cs index 291fbcf0..40bae6df 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/Metadata/Account.cs +++ b/MarkMpn.Sql4Cds.Engine.Tests/Metadata/Account.cs @@ -48,5 +48,12 @@ class Account [AttributeLogicalName("owneridname")] public string OwnerIdName { get; } + + [AttributeLogicalName("parentaccountid")] + [RelationshipSchemaName("account_parent")] + public Account ParentAccount { get; set; } + + [AttributeLogicalName("parentaccountid")] + public EntityReference ParentAccountId { get; set; } } } diff --git a/MarkMpn.Sql4Cds.Engine.Tests/Sql2FetchXmlTests.cs b/MarkMpn.Sql4Cds.Engine.Tests/Sql2FetchXmlTests.cs index 001d9bf0..16f2d783 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/Sql2FetchXmlTests.cs +++ b/MarkMpn.Sql4Cds.Engine.Tests/Sql2FetchXmlTests.cs @@ -126,6 +126,8 @@ public void SelectStar() "ownerid", "owneridname", "owneridtype", + "parentaccountid", + "parentaccountidname", "primarycontactid", "primarycontactidname", "turnover" @@ -157,6 +159,8 @@ public void SelectStarAndField() "ownerid", "owneridname", "owneridtype", + "parentaccountid", + "parentaccountidname", "primarycontactid", "primarycontactidname", "turnover", From 6de3297c7f979c4b6adb08f5726848882f570112 Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Mon, 30 Oct 2023 20:09:53 +0000 Subject: [PATCH 33/81] Handle time zone mismatch for starting bulk delete jobs Fixes #380 --- MarkMpn.Sql4Cds.Engine/ExecutionPlan/BulkDeleteJobNode.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BulkDeleteJobNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BulkDeleteJobNode.cs index 0e10cf80..ff147d47 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BulkDeleteJobNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BulkDeleteJobNode.cs @@ -62,7 +62,7 @@ public string Execute(NodeExecutionContext context, out int recordsAffected) { JobName = $"SQL 4 CDS {GetDisplayName(0, meta)} Bulk Delete Job", QuerySet = new[] { query }, - StartDateTime = DateTime.Now, + StartDateTime = DateTime.UtcNow, RecurrencePattern = String.Empty, SendEmailNotification = false, ToRecipients = Array.Empty(), From 023777581000cef403ffc123af08985e1073c0c0 Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Tue, 31 Oct 2023 21:01:50 +0000 Subject: [PATCH 34/81] Fixed row count estimate overflow --- MarkMpn.Sql4Cds.Engine/ExecutionPlan/BaseAggregateNode.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BaseAggregateNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BaseAggregateNode.cs index bc1a930d..89f190a9 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BaseAggregateNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BaseAggregateNode.cs @@ -387,7 +387,11 @@ protected override RowCountEstimate EstimateRowsOutInternal(NodeCompilationConte if (GroupBy.Count == 0) return RowCountEstimateDefiniteRange.ExactlyOne; - var rows = Source.EstimateRowsOut(context).Value * 4 / 10; + var sourceRows = Source.EstimateRowsOut(context).Value; + var rows = sourceRows * 4 / 10; + + if (rows < 0) + rows = sourceRows / 10 * 4; return new RowCountEstimate(rows); } From 45f89f1bc83762f38be79d531971c62122cf5ffe Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Tue, 31 Oct 2023 21:02:13 +0000 Subject: [PATCH 35/81] Fold "under" and "above" filters to FetchXML --- .../ExecutionPlan/IndexSpoolNode.cs | 68 ++++++++++++++++++- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/IndexSpoolNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/IndexSpoolNode.cs index 2f684067..90e6a8f0 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/IndexSpoolNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/IndexSpoolNode.cs @@ -205,9 +205,37 @@ private IDataExecutionPlanNodeInternal FoldCTEToFetchXml(NodeCompilationContext anchorKey = recurseLoop.OuterReferences.Single(kvp => kvp.Value == anchorKey).Key; // Will now be the column name defined by the concatenate node anchorKey = concat.ColumnSet.Single(col => col.OutputColumn == anchorKey).SourceColumns[0]; // Will now be the column from the anchor FetchXML var anchorCol = anchorKey.ToColumnReference(); + var anchorIsUnder = false; + var anchorIsAbove = false; + FetchLinkEntityType anchorLink = null; + + // The anchor query will normally have the target table as the root entity, but could be a related entity if + // we want to use the "above" condition instead of "eq-or-above" if (anchorCol.MultiPartIdentifier.Count != 2 || anchorCol.MultiPartIdentifier.Identifiers[0].Value != anchorFetchXml.Alias) - return this; + { + anchorLink = anchorFetchXml.Entity.Items + .OfType() + .Where(link => link.alias == anchorCol.MultiPartIdentifier.Identifiers[0].Value) + .SingleOrDefault(); + + if (anchorLink == null) + return this; + + if (anchorLink.name != anchorFetchXml.Entity.name) + return this; + + if (anchorLink.from == hierarchicalRelationship.ReferencedAttribute && + anchorLink.to == hierarchicalRelationship.ReferencingAttribute) + { + anchorIsAbove = true; + } + else + { + return this; + } + } + var anchorAttr = anchorCol.MultiPartIdentifier[1].Value; var recurseCol = adaptiveSpool.KeyColumn.ToColumnReference(); @@ -230,10 +258,36 @@ private IDataExecutionPlanNodeInternal FoldCTEToFetchXml(NodeCompilationContext // query filters on a single primary key var at = GetPrimaryKeyFilter(anchorFetchXml, metadata); + // Also check for a filter on the hierarchy lookup attribute to convert to "under". + if (at == null && isUnder) + { + at = GetForeignKeyFilter(anchorFetchXml, hierarchicalRelationship); + + if (at != null) + anchorIsUnder = true; + } + if (at != null) { at.@operator = isUnder ? @operator.eqorunder : @operator.eqorabove; + if (at.@operator == @operator.eqorabove && anchorIsAbove) + { + // If we're using a link entity in the anchor query to find only records above the target record, + // not at-or-above, we can remove the link now. We'll have been using that link for the output values, + // so switch the alias of the top-level entity too + anchorFetchXml.Entity.Items = anchorFetchXml.Entity.Items.Except(new[] { anchorLink }).ToArray(); + at.@operator = @operator.above; + anchorFetchXml.Alias = anchorLink.alias; + } + else if (at.@operator == @operator.eqorunder && anchorIsUnder) + { + // If we're using a filter on the foreign key to represent an "under" condition, switch the filter to + // be on the primary key attribute instead. + at.@operator = @operator.under; + at.attribute = metadata.PrimaryIdAttribute; + } + // We might have some column renamings applied, so update them too var alias = Parent as AliasNode; @@ -292,7 +346,17 @@ private IDataExecutionPlanNodeInternal FoldCTEToFetchXml(NodeCompilationContext return concat; } + private condition GetForeignKeyFilter(FetchXmlScan anchorFetchXml, OneToManyRelationshipMetadata hierarchicalRelationship) + { + return GetFilter(anchorFetchXml, hierarchicalRelationship.ReferencingAttribute); + } + private condition GetPrimaryKeyFilter(FetchXmlScan anchorFetchXml, EntityMetadata metadata) + { + return GetFilter(anchorFetchXml, metadata.PrimaryIdAttribute); + } + + private condition GetFilter(FetchXmlScan anchorFetchXml, string attribute) { if (anchorFetchXml.Entity.Items == null) return null; @@ -301,7 +365,7 @@ private condition GetPrimaryKeyFilter(FetchXmlScan anchorFetchXml, EntityMetadat return null; if (anchorFilters[0].Items == null || anchorFilters[0].Items.Length != 1 || !(anchorFilters[0].Items[0] is condition anchorCondition)) return null; - if (anchorCondition.attribute != metadata.PrimaryIdAttribute || anchorCondition.@operator != @operator.eq) + if (anchorCondition.attribute != attribute || anchorCondition.@operator != @operator.eq) return null; return anchorCondition; From 1ca1381f4a5471307220619ac4eba99a3f6234c2 Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Wed, 1 Nov 2023 21:23:58 +0000 Subject: [PATCH 36/81] Do not re-fold filter source immediately --- MarkMpn.Sql4Cds.Engine/ExecutionPlan/FilterNode.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FilterNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FilterNode.cs index 7b11aefd..9efd8926 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FilterNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FilterNode.cs @@ -1157,7 +1157,7 @@ private bool FoldFiltersToDataSources(NodeCompilationContext context, IList (ScalarExpression)(escapedAlias + "." + col.OutputColumn).ToColumnReference(), col => col.SourceColumn)) }; - alias.Source = aliasFilterNode.FoldQuery(context, hints); + alias.Source = aliasFilterNode; foldedFilters = true; } From 17704723d430e61fcc46cc0d7f657a177dd7335b Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Thu, 2 Nov 2023 19:55:46 +0000 Subject: [PATCH 37/81] Reduce custom sorts on merge joins --- .../ExecutionPlan/MergeJoinNode.cs | 75 +++++++++---------- 1 file changed, 34 insertions(+), 41 deletions(-) diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/MergeJoinNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/MergeJoinNode.cs index d4fdb871..b4daeeff 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/MergeJoinNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/MergeJoinNode.cs @@ -217,6 +217,23 @@ public override IDataExecutionPlanNodeInternal FoldQuery(NodeCompilationContext if (folded != this) return folded; + var hashJoin = new HashJoinNode + { + LeftSource = LeftSource, + RightSource = RightSource, + LeftAttribute = LeftAttribute, + RightAttribute = RightAttribute, + JoinType = JoinType, + AdditionalJoinCriteria = AdditionalJoinCriteria, + SemiJoin = SemiJoin + }; + + foreach (var kvp in DefinedValues) + hashJoin.DefinedValues.Add(kvp); + + hashJoin.LeftSource.Parent = hashJoin; + hashJoin.RightSource.Parent = hashJoin; + // Can't use a merge join if the join key types have different sort orders if (LeftAttribute != null && RightAttribute != null) { @@ -229,26 +246,7 @@ public override IDataExecutionPlanNodeInternal FoldQuery(NodeCompilationContext var rightType = rightSchema.Schema[rightColumn].Type; if (!IsConsistentSortTypes(leftType, rightType)) - { - var hashJoin = new HashJoinNode - { - LeftSource = LeftSource, - RightSource = RightSource, - LeftAttribute = LeftAttribute, - RightAttribute = RightAttribute, - JoinType = JoinType, - AdditionalJoinCriteria = AdditionalJoinCriteria, - SemiJoin = SemiJoin - }; - - foreach (var kvp in DefinedValues) - hashJoin.DefinedValues.Add(kvp); - - hashJoin.LeftSource.Parent = hashJoin; - hashJoin.RightSource.Parent = hashJoin; - - return hashJoin; - } + return hashJoin.FoldQuery(context, hints); } // This is a many-to-many join if the left attribute is not unique @@ -301,27 +299,22 @@ public override IDataExecutionPlanNodeInternal FoldQuery(NodeCompilationContext // If we couldn't fold the sorts, it's probably faster to use a hash join instead if we only want partial results var leftSort = LeftSource as SortNode; var rightSort = RightSource as SortNode; - if (Parent is TopNode && (leftSort != null || rightSort != null)) - { - var hashJoin = new HashJoinNode - { - LeftSource = leftSort?.Source ?? LeftSource, - RightSource = rightSort?.Source ?? RightSource, - LeftAttribute = LeftAttribute, - RightAttribute = RightAttribute, - JoinType = JoinType, - AdditionalJoinCriteria = AdditionalJoinCriteria, - SemiJoin = SemiJoin - }; - - foreach (var kvp in DefinedValues) - hashJoin.DefinedValues.Add(kvp); - - hashJoin.LeftSource.Parent = hashJoin; - hashJoin.RightSource.Parent = hashJoin; - - return hashJoin; - } + + if (leftSort == null && rightSort == null) + return this; + + hashJoin.LeftSource = leftSort?.Source ?? LeftSource; + hashJoin.RightSource = rightSort?.Source ?? RightSource; + + + var foldedHashJoin = hashJoin.FoldQuery(context, hints); + + if (Parent is TopNode || + leftSort != null && rightSort != null) + return foldedHashJoin; + + LeftSource.Parent = this; + RightSource.Parent = this; return this; } From 604586c1b917c5cee17914d53fff0c8e7567c2b1 Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Thu, 2 Nov 2023 19:56:13 +0000 Subject: [PATCH 38/81] Switch FetchXML sort to custom sorting after adding joins that require custom paging --- .../ExecutionPlan/FoldableJoinNode.cs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FoldableJoinNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FoldableJoinNode.cs index 00620632..96c21080 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FoldableJoinNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FoldableJoinNode.cs @@ -371,7 +371,7 @@ private bool FoldFetchXmlJoin(NodeCompilationContext context, IList Date: Thu, 2 Nov 2023 19:57:07 +0000 Subject: [PATCH 39/81] Avoid folding filters to tables in subqueries if the same alias exists in the outer query --- .../ExecutionPlanTests.cs | 47 ++++++++++++ .../ExecutionPlan/BaseDataNode.cs | 17 +++-- .../ExecutionPlan/FetchXmlScan.cs | 10 ++- .../ExecutionPlan/FilterNode.cs | 72 +++++++++++++++++-- 4 files changed, 132 insertions(+), 14 deletions(-) diff --git a/MarkMpn.Sql4Cds.Engine.Tests/ExecutionPlanTests.cs b/MarkMpn.Sql4Cds.Engine.Tests/ExecutionPlanTests.cs index 0c0a2787..c5b6fcf2 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/ExecutionPlanTests.cs +++ b/MarkMpn.Sql4Cds.Engine.Tests/ExecutionPlanTests.cs @@ -6426,5 +6426,52 @@ WHERE contactid IN (SELECT DISTINCT primarycontactid FROM account WHERE name = _supportedJoins.Remove(JoinOperator.Any); } } + + [TestMethod] + public void FoldFilterToCorrectTableAlias() + { + // The same table alias can be used in the main query and in a query-derived table. Ensure filters are + // folded to the correct one. + + var planBuilder = new ExecutionPlanBuilder(_localDataSource.Values, this); + + var query = @" +SELECT * +FROM (SELECT name FROM account AS a INNER JOIN contact AS c ON a.primarycontactid = c.contactid) AS q +INNER JOIN contact AS c ON q.name = c.fullname +WHERE c.firstname = 'Mark'"; + + var plans = planBuilder.Build(query, null, out _); + + Assert.AreEqual(1, plans.Length); + + var select = AssertNode(plans[0]); + var join = AssertNode(select.Source); + var leftFetch = AssertNode(join.LeftSource); + var rightFetch = AssertNode(join.RightSource); + + AssertFetchXml(leftFetch, @" + + + + + + + + + "); + + AssertFetchXml(rightFetch, @" + + + + + + + + + + "); + } } } diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BaseDataNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BaseDataNode.cs index 7b87b638..dfa22b96 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BaseDataNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BaseDataNode.cs @@ -190,14 +190,15 @@ public void MergeStatsFrom(BaseDataNode other) /// The SQL criteria to attempt to translate to FetchXML /// The schema of the node that the criteria apply to /// The prefix of the table that the can be translated for, or null if any tables can be referenced + /// The prefixes of any tables that the cannot be translated for /// The logical name of the root entity that the FetchXML query is targetting /// The alias of the root entity that the FetchXML query is targetting /// The child items of the root entity in the FetchXML query /// The FetchXML version of the that is generated by this method /// true if the can be translated to FetchXML, or false otherwise - protected bool TranslateFetchXMLCriteria(NodeCompilationContext context, IAttributeMetadataCache metadata, BooleanExpression criteria, INodeSchema schema, string allowedPrefix, string targetEntityName, string targetEntityAlias, object[] items, out filter filter) + protected bool TranslateFetchXMLCriteria(NodeCompilationContext context, IAttributeMetadataCache metadata, BooleanExpression criteria, INodeSchema schema, string allowedPrefix, HashSet barredPrefixes, string targetEntityName, string targetEntityAlias, object[] items, out filter filter) { - if (!TranslateFetchXMLCriteria(context, metadata, criteria, schema, allowedPrefix, targetEntityName, targetEntityAlias, items, out var condition, out filter)) + if (!TranslateFetchXMLCriteria(context, metadata, criteria, schema, allowedPrefix, barredPrefixes, targetEntityName, targetEntityAlias, items, out var condition, out filter)) return false; if (condition != null) @@ -214,22 +215,23 @@ protected bool TranslateFetchXMLCriteria(NodeCompilationContext context, IAttrib /// The SQL criteria to attempt to translate to FetchXML /// The schema of the node that the criteria apply to /// The prefix of the table that the can be translated for, or null if any tables can be referenced + /// The prefixes of any tables that the cannot be translated for /// The logical name of the root entity that the FetchXML query is targetting /// The alias of the root entity that the FetchXML query is targetting /// The child items of the root entity in the FetchXML query /// The FetchXML version of the that is generated by this method when it covers multiple conditions /// The FetchXML version of the that is generated by this method when it is for a single condition only /// true if the can be translated to FetchXML, or false otherwise - private bool TranslateFetchXMLCriteria(NodeCompilationContext context, IAttributeMetadataCache metadata, BooleanExpression criteria, INodeSchema schema, string allowedPrefix, string targetEntityName, string targetEntityAlias, object[] items, out condition condition, out filter filter) + private bool TranslateFetchXMLCriteria(NodeCompilationContext context, IAttributeMetadataCache metadata, BooleanExpression criteria, INodeSchema schema, string allowedPrefix, HashSet barredPrefixes, string targetEntityName, string targetEntityAlias, object[] items, out condition condition, out filter filter) { condition = null; filter = null; if (criteria is BooleanBinaryExpression binary) { - if (!TranslateFetchXMLCriteria(context, metadata, binary.FirstExpression, schema, allowedPrefix, targetEntityName, targetEntityAlias, items, out var lhsCondition, out var lhsFilter)) + if (!TranslateFetchXMLCriteria(context, metadata, binary.FirstExpression, schema, allowedPrefix, barredPrefixes, targetEntityName, targetEntityAlias, items, out var lhsCondition, out var lhsFilter)) return false; - if (!TranslateFetchXMLCriteria(context, metadata, binary.SecondExpression, schema, allowedPrefix, targetEntityName, targetEntityAlias, items, out var rhsCondition, out var rhsFilter)) + if (!TranslateFetchXMLCriteria(context, metadata, binary.SecondExpression, schema, allowedPrefix, barredPrefixes, targetEntityName, targetEntityAlias, items, out var rhsCondition, out var rhsFilter)) return false; filter = new filter @@ -246,7 +248,7 @@ private bool TranslateFetchXMLCriteria(NodeCompilationContext context, IAttribut if (criteria is BooleanParenthesisExpression paren) { - return TranslateFetchXMLCriteria(context, metadata, paren.Expression, schema, allowedPrefix, targetEntityName, targetEntityAlias, items, out condition, out filter); + return TranslateFetchXMLCriteria(context, metadata, paren.Expression, schema, allowedPrefix, barredPrefixes, targetEntityName, targetEntityAlias, items, out condition, out filter); } if (criteria is DistinctPredicate distinct) @@ -469,6 +471,9 @@ private bool TranslateFetchXMLCriteria(NodeCompilationContext context, IAttribut if (allowedPrefix != null && !allowedPrefix.Equals(entityAlias)) return false; + if (barredPrefixes != null && barredPrefixes.Contains(entityAlias)) + return false; + var entityName = AliasToEntityName(targetEntityAlias, targetEntityName, items, entityAlias); if (IsInvalidAuditFilter(targetEntityName, entityName, items)) diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FetchXmlScan.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FetchXmlScan.cs index 3ff0f7b0..1738b130 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FetchXmlScan.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FetchXmlScan.cs @@ -1704,14 +1704,18 @@ public override void AddRequiredColumns(NodeCompilationContext context, IList map.OutputColumn == normalizedCol); + var mapping = ColumnMappings.SingleOrDefault(map => map.OutputColumn == normalizedCol || map.OutputColumn == parts[0] && map.AllColumns); - if (mapping != null) + if (mapping != null && mapping.AllColumns) + normalizedCol = (mapping.SourceColumn ?? parts[0]).EscapeIdentifier() + "." + parts[1].EscapeIdentifier(); + else if (mapping != null) normalizedCol = mapping.SourceColumn; + else if (HiddenAliases.Contains(parts[0], StringComparer.OrdinalIgnoreCase)) + continue; var attr = AddAttribute(normalizedCol, null, dataSource.Metadata, out _, out var linkEntity); - if (mapping != null && attr != null) + if (mapping != null && !mapping.AllColumns && attr != null) { if (attr.name != parts[1] && IsValidAlias(parts[1])) attr.alias = parts[1]; diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FilterNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FilterNode.cs index 9efd8926..feacd14c 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FilterNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FilterNode.cs @@ -1089,6 +1089,10 @@ private bool FoldFiltersToDataSources(NodeCompilationContext context, IList> GetIgnoreAliasesByNode() + { + var fetchXmlSources = GetFoldableSources(Source) + .OfType() + .ToList(); + + // Build a full list of where we see each alias + var nodesByAlias = new Dictionary>(StringComparer.OrdinalIgnoreCase); + + foreach (var fetchXml in fetchXmlSources) + { + foreach (var alias in GetAliases(fetchXml)) + { + if (!nodesByAlias.TryGetValue(alias, out var nodes)) + { + nodes = new List(); + nodesByAlias.Add(alias, nodes); + } + + nodes.Add(fetchXml); + } + } + + var ignoreAliases = fetchXmlSources + .ToDictionary(f => f, f => new HashSet(StringComparer.OrdinalIgnoreCase)); + + // Aliases should be ignored if they appear as visible in another node, or they are hidden in all nodes + foreach (var alias in nodesByAlias) + { + if (alias.Value.Count < 2) + continue; + + var hiddenNodes = alias.Value + .Where(n => n.HiddenAliases.Contains(alias.Key, StringComparer.OrdinalIgnoreCase)) + .ToList(); + + var visibleNodes = alias.Value + .Except(hiddenNodes) + .ToList(); + + foreach (var node in alias.Value) + { + if (visibleNodes.Count == 0 || visibleNodes.Any(n => n != node)) + ignoreAliases[node].Add(alias.Key); + } + } + + return ignoreAliases; + } + + private IEnumerable GetAliases(FetchXmlScan fetchXml) + { + yield return fetchXml.Alias; + + foreach (var linkEntity in fetchXml.Entity.GetLinkEntities()) + yield return linkEntity.alias; + } + private BooleanExpression ReplaceColumnNames(BooleanExpression filter, Dictionary replacements) { filter = filter.Clone(); @@ -1350,9 +1412,9 @@ public override void AddRequiredColumns(NodeCompilationContext context, IList barredPrefixes, string targetEntityName, string targetEntityAlias, object[] items, out filter filter) { - if (TranslateFetchXMLCriteria(context, metadata, criteria, schema, allowedPrefix, targetEntityName, targetEntityAlias, items, out filter)) + if (TranslateFetchXMLCriteria(context, metadata, criteria, schema, allowedPrefix, barredPrefixes, targetEntityName, targetEntityAlias, items, out filter)) return null; if (!(criteria is BooleanBinaryExpression bin)) @@ -1361,8 +1423,8 @@ private BooleanExpression ExtractFetchXMLFilters(NodeCompilationContext context, if (bin.BinaryExpressionType != BooleanBinaryExpressionType.And) return criteria; - bin.FirstExpression = ExtractFetchXMLFilters(context, metadata, bin.FirstExpression, schema, allowedPrefix, targetEntityName, targetEntityAlias, items, out var lhsFilter); - bin.SecondExpression = ExtractFetchXMLFilters(context, metadata, bin.SecondExpression, schema, allowedPrefix, targetEntityName, targetEntityAlias, items, out var rhsFilter); + bin.FirstExpression = ExtractFetchXMLFilters(context, metadata, bin.FirstExpression, schema, allowedPrefix, barredPrefixes, targetEntityName, targetEntityAlias, items, out var lhsFilter); + bin.SecondExpression = ExtractFetchXMLFilters(context, metadata, bin.SecondExpression, schema, allowedPrefix, barredPrefixes, targetEntityName, targetEntityAlias, items, out var rhsFilter); filter = (lhsFilter != null && rhsFilter != null) ? new filter { Items = new object[] { lhsFilter, rhsFilter } } : lhsFilter ?? rhsFilter; From 624e42332302a497baf7bdf8eb6140968f0ff727 Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Fri, 3 Nov 2023 08:34:46 +0000 Subject: [PATCH 40/81] Show plugin log more reliably --- MarkMpn.Sql4Cds.XTB/SqlQueryControl.cs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/MarkMpn.Sql4Cds.XTB/SqlQueryControl.cs b/MarkMpn.Sql4Cds.XTB/SqlQueryControl.cs index 5daf414a..b2980c64 100644 --- a/MarkMpn.Sql4Cds.XTB/SqlQueryControl.cs +++ b/MarkMpn.Sql4Cds.XTB/SqlQueryControl.cs @@ -829,19 +829,25 @@ private string GetErrorMessage(Exception error) if (fault.Message != error.Message) msg += "\r\n" + fault.Message; + if (fault.ErrorDetails.TryGetValue("Plugin.ExceptionFromPluginExecute", out var plugin)) + msg += "\r\nError from plugin: " + plugin; + + if (!String.IsNullOrEmpty(fault.TraceText)) + msg += "\r\nTrace log: " + fault.TraceText; + while (fault.InnerFault != null) { if (fault.InnerFault.Message != fault.Message) msg += "\r\n" + fault.InnerFault.Message; fault = fault.InnerFault; - } - if (fault.ErrorDetails.TryGetValue("Plugin.ExceptionFromPluginExecute", out var plugin)) - msg += "\r\nError from plugin: " + plugin; + if (fault.ErrorDetails.TryGetValue("Plugin.ExceptionFromPluginExecute", out plugin)) + msg += "\r\nError from plugin: " + plugin; - if (!String.IsNullOrEmpty(fault.TraceText)) - msg += "\r\nTrace log: " + fault.TraceText; + if (!String.IsNullOrEmpty(fault.TraceText)) + msg += "\r\nTrace log: " + fault.TraceText; + } } return msg; From 749b9e55fa64fb1da3047795da22abb7df64b257 Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Fri, 3 Nov 2023 08:55:56 +0000 Subject: [PATCH 41/81] Do not fold NOT IN queries using an inner join to a left outer join Fixes #382 --- MarkMpn.Sql4Cds.Engine/ExecutionPlan/FilterNode.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FilterNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FilterNode.cs index feacd14c..efc1c887 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FilterNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FilterNode.cs @@ -893,6 +893,11 @@ private bool FoldInExistsToFetchXml(NodeCompilationContext context, IList l.linktype == "inner")) + break; + // Replace the filter on the defined value name with a filter on the primary key column nullFilter.Expression = (rightFetch.Alias + "." + context.DataSources[rightFetch.DataSource].Metadata[rightFetch.Entity.name].PrimaryIdAttribute).ToColumnReference(); From 1ed3d60ae5da4d128aa35da2224fc855395bc2cf Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Mon, 6 Nov 2023 08:53:58 +0000 Subject: [PATCH 42/81] Fixed error showing execution plan with calculated columns --- MarkMpn.Sql4Cds.Engine/ExecutionPlanNodeTypeDescriptor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlanNodeTypeDescriptor.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlanNodeTypeDescriptor.cs index ec61670c..33347c8f 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlanNodeTypeDescriptor.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlanNodeTypeDescriptor.cs @@ -304,7 +304,7 @@ private static string GetPropertyName(System.Collections.IList list, object item .SingleOrDefault(p => p.GetCustomAttribute() != null); if (dictionaryKeyProperty != null) - return dictionaryKeyProperty.GetValue(item).ToString(); + return dictionaryKeyProperty.GetValue(item)?.ToString() ?? " "; return index.ToString().PadLeft((int)Math.Ceiling(Math.Log10(list.Count)), '0'); } From cab37bdc46ea60e044134a1db9b9ce1dfdbf69a3 Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Mon, 6 Nov 2023 08:54:45 +0000 Subject: [PATCH 43/81] Show plugin error details in Azure Data Studio messages --- .../QueryExecution/QueryExecutionHandler.cs | 55 +++++++++++++++++-- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/MarkMpn.Sql4Cds.LanguageServer/QueryExecution/QueryExecutionHandler.cs b/MarkMpn.Sql4Cds.LanguageServer/QueryExecution/QueryExecutionHandler.cs index 2a74444f..e4dfd862 100644 --- a/MarkMpn.Sql4Cds.LanguageServer/QueryExecution/QueryExecutionHandler.cs +++ b/MarkMpn.Sql4Cds.LanguageServer/QueryExecution/QueryExecutionHandler.cs @@ -6,6 +6,7 @@ using System.Globalization; using System.Linq; using System.Net; +using System.ServiceModel; using System.Text; using System.Text.RegularExpressions; using System.Threading; @@ -18,11 +19,9 @@ using MarkMpn.Sql4Cds.LanguageServer.Workspace; using Microsoft.SqlTools.ServiceLayer.ExecutionPlan.Contracts; using Microsoft.VisualStudio.LanguageServer.Protocol; +using Microsoft.Xrm.Sdk; using Microsoft.Xrm.Sdk.Metadata; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using StreamJsonRpc; -using static Microsoft.ApplicationInsights.MetricDimensionNames.TelemetryContext; namespace MarkMpn.Sql4Cds.LanguageServer.QueryExecution { @@ -400,7 +399,7 @@ private async Task Execute(Connection.Session session, ExecuteRequestParamsBase { BatchId = batchSummary.Id, Time = DateTime.UtcNow.ToString("o"), - Message = ex.Message, + Message = GetErrorMessage(ex), IsError = true } }); @@ -507,6 +506,54 @@ private async Task Execute(Connection.Session session, ExecuteRequestParamsBase }); } + private string GetErrorMessage(Exception error) + { + string msg; + + if (error is AggregateException aggregateException) + msg = String.Join("\r\n", aggregateException.InnerExceptions.Select(ex => GetErrorMessage(ex))); + else + msg = error.Message; + + while (error.InnerException != null) + { + if (error.InnerException.Message != error.Message) + msg += "\r\n" + error.InnerException.Message; + + error = error.InnerException; + } + + if (error is FaultException faultEx) + { + var fault = faultEx.Detail; + + if (fault.Message != error.Message) + msg += "\r\n" + fault.Message; + + if (fault.ErrorDetails.TryGetValue("Plugin.ExceptionFromPluginExecute", out var plugin)) + msg += "\r\nError from plugin: " + plugin; + + if (!String.IsNullOrEmpty(fault.TraceText)) + msg += "\r\nTrace log: " + fault.TraceText; + + while (fault.InnerFault != null) + { + if (fault.InnerFault.Message != fault.Message) + msg += "\r\n" + fault.InnerFault.Message; + + fault = fault.InnerFault; + + if (fault.ErrorDetails.TryGetValue("Plugin.ExceptionFromPluginExecute", out plugin)) + msg += "\r\nError from plugin: " + plugin; + + if (!String.IsNullOrEmpty(fault.TraceText)) + msg += "\r\nTrace log: " + fault.TraceText; + } + } + + return msg; + } + private string GetDisplayName(int count, EntityMetadata meta) { if (count == 1) From d4c8592ffd91693d97e5cc3b73a0e41f0b8fb0eb Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Mon, 6 Nov 2023 16:08:50 +0000 Subject: [PATCH 44/81] Remove data source from list when final use is disconnected --- .../Connection/ConnectionManager.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/MarkMpn.Sql4Cds.LanguageServer/Connection/ConnectionManager.cs b/MarkMpn.Sql4Cds.LanguageServer/Connection/ConnectionManager.cs index 33c01857..45dd83b6 100644 --- a/MarkMpn.Sql4Cds.LanguageServer/Connection/ConnectionManager.cs +++ b/MarkMpn.Sql4Cds.LanguageServer/Connection/ConnectionManager.cs @@ -49,7 +49,10 @@ public Session Connect(ConnectionDetails connection, string ownerUri) public void Disconnect(string ownerUri) { - _connectedDataSource.TryRemove(ownerUri, out _); + if (_connectedDataSource.TryRemove(ownerUri, out var dataSourceName) && + !_connectedDataSource.Any(kvp => kvp.Value == dataSourceName)) + _dataSources.TryRemove(dataSourceName, out _); + _connections.TryRemove(ownerUri, out _); } From a6b0237c6678b940731d1709529e81d0f5edd50b Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Tue, 7 Nov 2023 17:54:25 +0000 Subject: [PATCH 45/81] Clearer progress messages for multi-threaded DML operations --- .../ExecutionPlan/BaseDmlNode.cs | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BaseDmlNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BaseDmlNode.cs index 152d211b..cfd4fc9e 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BaseDmlNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BaseDmlNode.cs @@ -544,6 +544,8 @@ protected string ExecuteDmlOperation(DataSource dataSource, IQueryExecutionOptio { var inProgressCount = 0; var count = 0; + var errorCount = 0; + var threadCount = 0; #if NETCOREAPP var svc = dataSource.Connection as ServiceClient; @@ -580,6 +582,7 @@ protected string ExecuteDmlOperation(DataSource dataSource, IQueryExecutionOptio if (!useAffinityCookie && service is CrmServiceClient crmService) crmService.EnableAffinityCookie = false; #endif + Interlocked.Increment(ref threadCount); return new { Service = service, EMR = default(ExecuteMultipleRequest) }; }, @@ -600,7 +603,11 @@ protected string ExecuteDmlOperation(DataSource dataSource, IQueryExecutionOptio { var newCount = Interlocked.Increment(ref inProgressCount); var progress = (double)newCount / entities.Count; - options.Progress(progress, $"{operationNames.InProgressUppercase} {newCount:N0} of {entities.Count:N0} {GetDisplayName(0, meta)} ({progress:P0})..."); + + if (threadCount < 2) + options.Progress(progress, $"{operationNames.InProgressUppercase} {newCount:N0} of {entities.Count:N0} {GetDisplayName(0, meta)} ({progress:P0})..."); + else + options.Progress(progress, $"{operationNames.InProgressUppercase} {newCount - threadCount + 1:N0}-{newCount:N0} of {entities.Count:N0} {GetDisplayName(0, meta)} ({progress:P0}, {threadCount:N0} threads)..."); try { @@ -643,7 +650,7 @@ protected string ExecuteDmlOperation(DataSource dataSource, IQueryExecutionOptio if (threadLocalState.EMR.Requests.Count == BatchSize) { - ProcessBatch(threadLocalState.EMR, ref count, ref inProgressCount, entities, operationNames, meta, options, dataSource, threadLocalState.Service, responseHandler, ref fault); + ProcessBatch(threadLocalState.EMR, threadCount, ref count, ref inProgressCount, ref errorCount, entities, operationNames, meta, options, dataSource, threadLocalState.Service, responseHandler, ref fault); threadLocalState = new { threadLocalState.Service, EMR = default(ExecuteMultipleRequest) }; } @@ -654,7 +661,9 @@ protected string ExecuteDmlOperation(DataSource dataSource, IQueryExecutionOptio (threadLocalState) => { if (threadLocalState.EMR != null) - ProcessBatch(threadLocalState.EMR, ref count, ref inProgressCount, entities, operationNames, meta, options, dataSource, threadLocalState.Service, responseHandler, ref fault); + ProcessBatch(threadLocalState.EMR, threadCount, ref count, ref inProgressCount, ref errorCount, entities, operationNames, meta, options, dataSource, threadLocalState.Service, responseHandler, ref fault); + + Interlocked.Decrement(ref threadCount); if (threadLocalState.Service != dataSource.Connection && threadLocalState.Service is IDisposable disposableClient) disposableClient.Dispose(); @@ -694,11 +703,12 @@ protected class BulkApiErrorDetail public int StatusCode { get; set; } } - private void ProcessBatch(ExecuteMultipleRequest req, ref int count, ref int inProgressCount, List entities, OperationNames operationNames, EntityMetadata meta, IQueryExecutionOptions options, DataSource dataSource, IOrganizationService org, Action responseHandler, ref OrganizationServiceFault fault) + private void ProcessBatch(ExecuteMultipleRequest req, int threadCount, ref int count, ref int inProgressCount, ref int errorCount, List entities, OperationNames operationNames, EntityMetadata meta, IQueryExecutionOptions options, DataSource dataSource, IOrganizationService org, Action responseHandler, ref OrganizationServiceFault fault) { var newCount = Interlocked.Add(ref inProgressCount, req.Requests.Count); var progress = (double)newCount / entities.Count; - options.Progress(progress, $"{operationNames.InProgressUppercase} {GetDisplayName(0, meta)} {newCount + 1 - req.Requests.Count:N0} - {newCount:N0} of {entities.Count:N0}..."); + var threadCountMessage = threadCount < 2 ? "" : $" ({threadCount:N0} threads)"; + options.Progress(progress, $"{operationNames.InProgressUppercase} {GetDisplayName(0, meta)} {count + errorCount + 1:N0} - {newCount:N0} of {entities.Count:N0}{threadCountMessage}..."); var resp = ExecuteMultiple(dataSource, org, meta, req); if (responseHandler != null) @@ -715,6 +725,7 @@ private void ProcessBatch(ExecuteMultipleRequest req, ref int count, ref int inP .ToList(); Interlocked.Add(ref count, req.Requests.Count - errorResponses.Count); + Interlocked.Add(ref errorCount, errorResponses.Count); var error = errorResponses.FirstOrDefault(item => FilterErrors(item.Fault)); From ee540f9ef19eb99ad91826689c48d77343092698 Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Fri, 10 Nov 2023 08:22:06 +0000 Subject: [PATCH 46/81] Refactored outputting log messages from DML nodes --- .../Ado/Sql4CdsDataReader.cs | 10 ++++---- .../ExecutionPlan/AssignVariablesNode.cs | 3 +-- .../ExecutionPlan/BaseDmlNode.cs | 25 ++++++++++--------- .../ExecutionPlan/BulkDeleteJobNode.cs | 4 +-- .../ExecutionPlan/DeclareVariablesNode.cs | 3 +-- .../ExecutionPlan/DeleteNode.cs | 10 ++++---- .../ExecutionPlan/ExecuteAsNode.cs | 4 +-- .../ExecutionPlan/ExecuteMessageNode.cs | 4 +-- .../ExecutionPlan/FetchXmlScan.cs | 2 +- .../ExecutionPlan/FilterNode.cs | 2 +- .../IDmlQueryExecutionPlanNode.cs | 3 +-- .../ExecutionPlan/InsertNode.cs | 5 ++-- .../ExecutionPlan/NestedLoopNode.cs | 2 +- .../ExecutionPlan/PartitionedAggregateNode.cs | 2 +- .../ExecutionPlan/PrintNode.cs | 8 +++--- .../ExecutionPlan/RevertNode.cs | 4 +-- .../ExecutionPlan/UpdateNode.cs | 12 ++++----- .../ExecutionPlan/WaitForNode.cs | 3 +-- MarkMpn.Sql4Cds.Engine/NodeContext.cs | 14 ++++++++--- 19 files changed, 61 insertions(+), 59 deletions(-) diff --git a/MarkMpn.Sql4Cds.Engine/Ado/Sql4CdsDataReader.cs b/MarkMpn.Sql4Cds.Engine/Ado/Sql4CdsDataReader.cs index c5b5bc47..1155a8eb 100644 --- a/MarkMpn.Sql4Cds.Engine/Ado/Sql4CdsDataReader.cs +++ b/MarkMpn.Sql4Cds.Engine/Ado/Sql4CdsDataReader.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Linq.Expressions; using System.Text; +using System.Xml; using MarkMpn.Sql4Cds.Engine.ExecutionPlan; using Microsoft.SqlServer.TransactSql.ScriptDom; using Microsoft.Xrm.Sdk; @@ -62,13 +63,15 @@ public Sql4CdsDataReader(Sql4CdsCommand command, IQueryExecutionOptions options, private bool Execute(Dictionary parameterTypes, Dictionary parameterValues) { - var context = new NodeExecutionContext(_connection.DataSources, _options, parameterTypes, parameterValues); + IRootExecutionPlanNode logNode = null; + var context = new NodeExecutionContext(_connection.DataSources, _options, parameterTypes, parameterValues, msg => _connection.OnInfoMessage(logNode, msg)); try { while (_instructionPointer < _command.Plan.Length && !_options.CancellationToken.IsCancellationRequested) { var node = _command.Plan[_instructionPointer]; + logNode = node; if (node is IDataReaderExecutionPlanNode dataSetNode) { @@ -90,10 +93,7 @@ private bool Execute(Dictionary parameterTypes, Dicti else if (node is IDmlQueryExecutionPlanNode dmlNode) { dmlNode = (IDmlQueryExecutionPlanNode)dmlNode.Clone(); - var msg = dmlNode.Execute(context, out var recordsAffected); - - if (!String.IsNullOrEmpty(msg)) - _connection.OnInfoMessage(dmlNode, msg); + dmlNode.Execute(context, out var recordsAffected); _command.OnStatementCompleted(dmlNode, recordsAffected); diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/AssignVariablesNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/AssignVariablesNode.cs index 9aea2a30..3b726b9d 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/AssignVariablesNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/AssignVariablesNode.cs @@ -40,7 +40,7 @@ class AssignVariablesNode : BaseDmlNode [Browsable(false)] public override bool ContinueOnError { get; set; } - public override string Execute(NodeExecutionContext context, out int recordsAffected) + public override void Execute(NodeExecutionContext context, out int recordsAffected) { _executionCount++; @@ -63,7 +63,6 @@ public override string Execute(NodeExecutionContext context, out int recordsAffe } recordsAffected = -1; - return null; } /// diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BaseDmlNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BaseDmlNode.cs index cfd4fc9e..d5271303 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BaseDmlNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BaseDmlNode.cs @@ -129,8 +129,7 @@ public void Dispose() /// /// The context in which the node is being executed /// The number of records that were affected by the query - /// A log message to display - public abstract string Execute(NodeExecutionContext context, out int recordsAffected); + public abstract void Execute(NodeExecutionContext context, out int recordsAffected); /// /// Indicates if some errors returned by the server can be silently ignored @@ -539,8 +538,8 @@ protected class OperationNames /// The metadata of the entity that will be affected /// A function to generate a DML request from a data source entity /// The constant strings to use in log messages - /// The final log message - protected string ExecuteDmlOperation(DataSource dataSource, IQueryExecutionOptions options, List entities, EntityMetadata meta, Func requestGenerator, OperationNames operationNames, out int recordsAffected, IDictionary parameterValues, Action responseHandler = null) + /// A callback function to be executed when a log message is generated + protected void ExecuteDmlOperation(DataSource dataSource, IQueryExecutionOptions options, List entities, EntityMetadata meta, Func requestGenerator, OperationNames operationNames, NodeExecutionContext context, out int recordsAffected, Action responseHandler = null) { var inProgressCount = 0; var count = 0; @@ -618,13 +617,15 @@ protected string ExecuteDmlOperation(DataSource dataSource, IQueryExecutionOptio } catch (FaultException ex) { - if (FilterErrors(ex.Detail)) + if (FilterErrors(context, request, ex.Detail)) { if (ContinueOnError) fault = fault ?? ex.Detail; else throw; } + + Interlocked.Increment(ref errorCount); } } else @@ -650,7 +651,7 @@ protected string ExecuteDmlOperation(DataSource dataSource, IQueryExecutionOptio if (threadLocalState.EMR.Requests.Count == BatchSize) { - ProcessBatch(threadLocalState.EMR, threadCount, ref count, ref inProgressCount, ref errorCount, entities, operationNames, meta, options, dataSource, threadLocalState.Service, responseHandler, ref fault); + ProcessBatch(threadLocalState.EMR, threadCount, ref count, ref inProgressCount, ref errorCount, entities, operationNames, meta, options, dataSource, threadLocalState.Service, context, responseHandler, ref fault); threadLocalState = new { threadLocalState.Service, EMR = default(ExecuteMultipleRequest) }; } @@ -661,7 +662,7 @@ protected string ExecuteDmlOperation(DataSource dataSource, IQueryExecutionOptio (threadLocalState) => { if (threadLocalState.EMR != null) - ProcessBatch(threadLocalState.EMR, threadCount, ref count, ref inProgressCount, ref errorCount, entities, operationNames, meta, options, dataSource, threadLocalState.Service, responseHandler, ref fault); + ProcessBatch(threadLocalState.EMR, threadCount, ref count, ref inProgressCount, ref errorCount, entities, operationNames, meta, options, dataSource, threadLocalState.Service, context, responseHandler, ref fault); Interlocked.Decrement(ref threadCount); @@ -692,8 +693,8 @@ protected string ExecuteDmlOperation(DataSource dataSource, IQueryExecutionOptio } recordsAffected = count; - parameterValues["@@ROWCOUNT"] = (SqlInt32)count; - return $"{count:N0} {GetDisplayName(count, meta)} {operationNames.CompletedLowercase}"; + context.ParameterValues["@@ROWCOUNT"] = (SqlInt32)count; + context.Log($"{count:N0} {GetDisplayName(count, meta)} {operationNames.CompletedLowercase}"); } protected class BulkApiErrorDetail @@ -703,7 +704,7 @@ protected class BulkApiErrorDetail public int StatusCode { get; set; } } - private void ProcessBatch(ExecuteMultipleRequest req, int threadCount, ref int count, ref int inProgressCount, ref int errorCount, List entities, OperationNames operationNames, EntityMetadata meta, IQueryExecutionOptions options, DataSource dataSource, IOrganizationService org, Action responseHandler, ref OrganizationServiceFault fault) + private void ProcessBatch(ExecuteMultipleRequest req, int threadCount, ref int count, ref int inProgressCount, ref int errorCount, List entities, OperationNames operationNames, EntityMetadata meta, IQueryExecutionOptions options, DataSource dataSource, IOrganizationService org, NodeExecutionContext context, Action responseHandler, ref OrganizationServiceFault fault) { var newCount = Interlocked.Add(ref inProgressCount, req.Requests.Count); var progress = (double)newCount / entities.Count; @@ -727,7 +728,7 @@ private void ProcessBatch(ExecuteMultipleRequest req, int threadCount, ref int c Interlocked.Add(ref count, req.Requests.Count - errorResponses.Count); Interlocked.Add(ref errorCount, errorResponses.Count); - var error = errorResponses.FirstOrDefault(item => FilterErrors(item.Fault)); + var error = errorResponses.FirstOrDefault(item => FilterErrors(context, req.Requests[item.RequestIndex], item.Fault)); if (error != null) { @@ -738,7 +739,7 @@ private void ProcessBatch(ExecuteMultipleRequest req, int threadCount, ref int c } } - protected virtual bool FilterErrors(OrganizationServiceFault fault) + protected virtual bool FilterErrors(NodeExecutionContext context, OrganizationRequest request, OrganizationServiceFault fault) { return true; } diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BulkDeleteJobNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BulkDeleteJobNode.cs index ff147d47..a46a6917 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BulkDeleteJobNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BulkDeleteJobNode.cs @@ -43,7 +43,7 @@ public override void AddRequiredColumns(NodeCompilationContext context, IList hints) diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/DeleteNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/DeleteNode.cs index 17980768..9c30c85b 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/DeleteNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/DeleteNode.cs @@ -106,7 +106,7 @@ protected override void RenameSourceColumns(IDictionary columnRe SecondaryIdSource = secondaryIdSourceRenamed; } - public override string Execute(NodeExecutionContext context, out int recordsAffected) + public override void Execute(NodeExecutionContext context, out int recordsAffected) { _executionCount++; @@ -172,7 +172,7 @@ public override string Execute(NodeExecutionContext context, out int recordsAffe using (_timer.Run()) { - return ExecuteDmlOperation( + ExecuteDmlOperation( dataSource, context.Options, entities, @@ -184,8 +184,8 @@ public override string Execute(NodeExecutionContext context, out int recordsAffe InProgressLowercase = "deleting", CompletedLowercase = "deleted" }, - out recordsAffected, - context.ParameterValues); + context, + out recordsAffected); } } catch (QueryExecutionException ex) @@ -250,7 +250,7 @@ private OrganizationRequest CreateDeleteRequest(EntityMetadata meta, Entity enti return req; } - protected override bool FilterErrors(OrganizationServiceFault fault) + protected override bool FilterErrors(NodeExecutionContext context, OrganizationRequest request, OrganizationServiceFault fault) { // Ignore errors trying to delete records that don't exist - record may have been deleted by another // process in parallel. diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/ExecuteAsNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/ExecuteAsNode.cs index 9eebea94..0c99b53c 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/ExecuteAsNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/ExecuteAsNode.cs @@ -51,7 +51,7 @@ public override void AddRequiredColumns(NodeCompilationContext context, IList hints) diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FetchXmlScan.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FetchXmlScan.cs index 1738b130..59c69c25 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FetchXmlScan.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FetchXmlScan.cs @@ -1185,7 +1185,7 @@ private void AddSchemaAttribute(DataSource dataSource, ColumnList schema, Dictio if (attrMetadata is LookupAttributeMetadata lookup) { - AddSchemaAttribute(schema, aliases, fullName + "name", attrMetadata.LogicalName + "name", DataTypeHelpers.NVarChar(lookup.Targets == null || lookup.Targets.Length == 0 ? 100 : lookup.Targets.Select(e => ((StringAttributeMetadata)dataSource.Metadata[e].Attributes.SingleOrDefault(a => a.LogicalName == dataSource.Metadata[e].PrimaryNameAttribute))?.MaxLength ?? 100).Max(), dataSource.DefaultCollation, CollationLabel.Implicit), notNull); + AddSchemaAttribute(schema, aliases, fullName + "name", attrMetadata.LogicalName + "name", DataTypeHelpers.NVarChar(lookup.Targets == null || lookup.Targets.Length == 0 ? 100 : lookup.Targets.Select(e => (dataSource.Metadata[e].Attributes.SingleOrDefault(a => a.LogicalName == dataSource.Metadata[e].PrimaryNameAttribute) as StringAttributeMetadata)?.MaxLength ?? 100).Max(), dataSource.DefaultCollation, CollationLabel.Implicit), notNull); if (lookup.Targets?.Length != 1 && lookup.AttributeType != AttributeTypeCode.PartyList) AddSchemaAttribute(schema, aliases, fullName + "type", attrMetadata.LogicalName + "type", DataTypeHelpers.NVarChar(MetadataExtensions.EntityLogicalNameMaxLength, dataSource.DefaultCollation, CollationLabel.Implicit), notNull); diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FilterNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FilterNode.cs index efc1c887..976e39f5 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FilterNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FilterNode.cs @@ -1511,7 +1511,7 @@ protected bool TranslateMetadataCriteria(NodeCompilationContext context, Boolean relationshipFilter = null; var expressionCompilationContext = new ExpressionCompilationContext(context, null, null); - var expressionExecutionContext = new ExpressionExecutionContext(new NodeExecutionContext(context.DataSources, context.Options, context.ParameterTypes, null)); + var expressionExecutionContext = new ExpressionExecutionContext(new NodeExecutionContext(context.DataSources, context.Options, context.ParameterTypes, null, null)); if (criteria is BooleanBinaryExpression binary) { diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/IDmlQueryExecutionPlanNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/IDmlQueryExecutionPlanNode.cs index d865ab29..8e254b73 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/IDmlQueryExecutionPlanNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/IDmlQueryExecutionPlanNode.cs @@ -18,7 +18,6 @@ internal interface IDmlQueryExecutionPlanNode : IRootExecutionPlanNodeInternal /// /// The context in which the node is being executed /// The number of records that were affected by the query - /// A status message for the results of the query - string Execute(NodeExecutionContext context, out int recordsAffected); + void Execute(NodeExecutionContext context, out int recordsAffected); } } diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/InsertNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/InsertNode.cs index 914232f4..e4cfc7c8 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/InsertNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/InsertNode.cs @@ -65,6 +65,7 @@ public override void AddRequiredColumns(NodeCompilationContext context, IList) ((r) => SetIdentity(r, context.ParameterValues)) ); } diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/NestedLoopNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/NestedLoopNode.cs index c28072d8..1e58d7c2 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/NestedLoopNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/NestedLoopNode.cs @@ -81,7 +81,7 @@ protected override IEnumerable ExecuteInternal(NodeExecutionContext cont var hasRight = false; - foreach (var right in RightSource.Execute(new NodeExecutionContext(context.DataSources, context.Options, innerParameterTypes, innerParameters))) + foreach (var right in RightSource.Execute(new NodeExecutionContext(context.DataSources, context.Options, innerParameterTypes, innerParameters, context.Log))) { if (rightSchema == null) { diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/PartitionedAggregateNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/PartitionedAggregateNode.cs index fa9857e4..5c82120c 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/PartitionedAggregateNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/PartitionedAggregateNode.cs @@ -202,7 +202,7 @@ protected override IEnumerable ExecuteInternal(NodeExecutionContext cont partitionParameterValues[kvp.Key] = kvp.Value; } - var partitionContext = new NodeExecutionContext(context.DataSources, context.Options, context.ParameterTypes, partitionParameterValues); + var partitionContext = new NodeExecutionContext(context.DataSources, context.Options, context.ParameterTypes, partitionParameterValues, context.Log); return new { Context = partitionContext, Fetch = fetch }; }, diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/PrintNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/PrintNode.cs index 6b7f3c50..45eebaf2 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/PrintNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/PrintNode.cs @@ -47,7 +47,7 @@ public object Clone() }; } - public string Execute(NodeExecutionContext context, out int recordsAffected) + public void Execute(NodeExecutionContext context, out int recordsAffected) { _executionCount++; recordsAffected = -1; @@ -56,10 +56,8 @@ public string Execute(NodeExecutionContext context, out int recordsAffected) { var value = (SqlString)_expression(new ExpressionExecutionContext(context)); - if (value.IsNull) - return null; - - return value.Value; + if (!value.IsNull) + context.Log(value.Value); } } diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/RevertNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/RevertNode.cs index 5029ccb1..aa5b6a66 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/RevertNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/RevertNode.cs @@ -52,7 +52,7 @@ public override void AddRequiredColumns(NodeCompilationContext context, IList columnRe } } - protected override bool FilterErrors(OrganizationServiceFault fault) + protected override bool FilterErrors(NodeExecutionContext context, OrganizationRequest request, OrganizationServiceFault fault) { - // Ignore errors trying to delete records that don't exist - record may have been deleted by another + // Ignore errors trying to update records that don't exist - record may have been deleted by another // process in parallel. return fault.ErrorCode != -2147220969 && fault.ErrorCode != -2147185406 && fault.ErrorCode != -2147220969 && fault.ErrorCode != 404; } diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/WaitForNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/WaitForNode.cs index f6bcb962..6f297c6e 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/WaitForNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/WaitForNode.cs @@ -55,7 +55,7 @@ public override void AddRequiredColumns(NodeCompilationContext context, IListThe options that the query is being executed with /// The names and types of the parameters that are available to the query /// The current value of each parameter + /// A callback function to log messages public NodeExecutionContext( IDictionary dataSources, IQueryExecutionOptions options, IDictionary parameterTypes, - IDictionary parameterValues) + IDictionary parameterValues, + Action log) : base(dataSources, options, parameterTypes) { ParameterValues = parameterValues; + Log = log ?? (msg => { }); } /// /// Returns the current value of each parameter /// public IDictionary ParameterValues { get; } + + public Action Log { get; } } /// @@ -179,8 +184,9 @@ public ExpressionExecutionContext( IQueryExecutionOptions options, IDictionary parameterTypes, IDictionary parameterValues, + Action log, Entity entity) - : base(dataSources, options, parameterTypes, parameterValues) + : base(dataSources, options, parameterTypes, parameterValues, log) { Entity = entity; } @@ -195,7 +201,7 @@ public ExpressionExecutionContext( /// representing each row as it is processed. /// public ExpressionExecutionContext(NodeExecutionContext nodeContext) - : base(nodeContext.DataSources, nodeContext.Options, nodeContext.ParameterTypes, nodeContext.ParameterValues) + : base(nodeContext.DataSources, nodeContext.Options, nodeContext.ParameterTypes, nodeContext.ParameterValues, nodeContext.Log) { Entity = null; } @@ -213,7 +219,7 @@ public ExpressionExecutionContext(NodeExecutionContext nodeContext) /// representing each row as it is processed. /// public ExpressionExecutionContext(ExpressionCompilationContext compilationContext) - : base(compilationContext.DataSources, compilationContext.Options, compilationContext.ParameterTypes, null) + : base(compilationContext.DataSources, compilationContext.Options, compilationContext.ParameterTypes, null, null) { Entity = null; } From 49d06946964939a9bd818660541b3d155ceee195 Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Fri, 10 Nov 2023 08:23:06 +0000 Subject: [PATCH 47/81] Added IGNORE_DUP_KEY query hint for insert commands --- .../ExecutionPlanNodeTests.cs | 40 ++++++------ .../ExecutionPlanTests.cs | 41 ++++++++---- .../Sql2FetchXmlTests.cs | 62 +++++++++--------- .../ExecutionPlan/InsertNode.cs | 65 ++++++++++++++++++- .../OptimizerHintValidatingVisitor.cs | 3 + 5 files changed, 146 insertions(+), 65 deletions(-) diff --git a/MarkMpn.Sql4Cds.Engine.Tests/ExecutionPlanNodeTests.cs b/MarkMpn.Sql4Cds.Engine.Tests/ExecutionPlanNodeTests.cs index 992c5902..3db165ef 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/ExecutionPlanNodeTests.cs +++ b/MarkMpn.Sql4Cds.Engine.Tests/ExecutionPlanNodeTests.cs @@ -37,7 +37,7 @@ public void ConstantScanTest() Alias = "test" }; - var results = node.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null)).ToArray(); + var results = node.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null, null)).ToArray(); Assert.AreEqual(1, results.Length); Assert.AreEqual("Mark", ((SqlString)results[0]["test.firstname"]).Value); @@ -84,7 +84,7 @@ public void FilterNodeTest() } }; - var results = node.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null)).ToArray(); + var results = node.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null, null)).ToArray(); Assert.AreEqual(1, results.Length); Assert.AreEqual("Mark", ((SqlString)results[0]["test.firstname"]).Value); @@ -161,7 +161,7 @@ public void MergeJoinInnerTest() JoinType = QualifiedJoinType.Inner }; - var results = node.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null)).ToArray(); + var results = node.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null, null)).ToArray(); Assert.AreEqual(2, results.Length); Assert.AreEqual("Mark", ((SqlString)results[0]["f.firstname"]).Value); @@ -241,7 +241,7 @@ public void MergeJoinLeftOuterTest() JoinType = QualifiedJoinType.LeftOuter }; - var results = node.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null)).ToArray(); + var results = node.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null, null)).ToArray(); Assert.AreEqual(3, results.Length); Assert.AreEqual("Mark", ((SqlString)results[0]["f.firstname"]).Value); @@ -323,7 +323,7 @@ public void MergeJoinRightOuterTest() JoinType = QualifiedJoinType.RightOuter }; - var results = node.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null)).ToArray(); + var results = node.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null, null)).ToArray(); Assert.AreEqual(3, results.Length); Assert.AreEqual("Mark", ((SqlString)results[0]["f.firstname"]).Value); @@ -362,7 +362,7 @@ public void AssertionTest() ErrorMessage = "Only Mark is allowed" }; - var results = node.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null)).GetEnumerator(); + var results = node.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null, null)).GetEnumerator(); Assert.IsTrue(results.MoveNext()); Assert.AreEqual("Mark", results.Current.GetAttributeValue("test.name").Value); @@ -420,7 +420,7 @@ public void ComputeScalarTest() } }; - var results = node.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null)) + var results = node.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null, null)) .Select(e => e.GetAttributeValue("mul").Value) .ToArray(); @@ -462,7 +462,7 @@ public void DistinctTest() } }; - var results = node.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null)) + var results = node.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null, null)) .Select(e => e.GetAttributeValue("test.value1").Value) .ToArray(); @@ -504,7 +504,7 @@ public void DistinctCaseInsensitiveTest() } }; - var results = node.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null)) + var results = node.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null, null)) .Select(e => e.GetAttributeValue("test.value1").Value) .ToArray(); @@ -562,7 +562,7 @@ public void SortNodeTest() } }; - var results = node.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null)) + var results = node.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null, null)) .Select(e => e.GetAttributeValue("test.expectedorder").Value) .ToArray(); @@ -627,7 +627,7 @@ public void SortNodePresortedTest() } }; - var results = node.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null)) + var results = node.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null, null)) .Select(e => e.GetAttributeValue("test.expectedorder").Value) .ToArray(); @@ -659,11 +659,11 @@ public void TableSpoolTest() var spool = new TableSpoolNode { Source = source }; - var results1 = spool.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null)) + var results1 = spool.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null, null)) .Select(e => e.GetAttributeValue("test.value1").Value) .ToArray(); - var results2 = spool.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null)) + var results2 = spool.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null, null)) .Select(e => e.GetAttributeValue("test.value1").Value) .ToArray(); @@ -708,7 +708,7 @@ public void CaseInsenstiveHashMatchAggregateNodeTest() } }; - var results = spool.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null)) + var results = spool.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null, null)) .Select(e => new { Name = e.GetAttributeValue("src.value1").Value, Count = e.GetAttributeValue("count").Value }) .ToArray(); @@ -749,7 +749,7 @@ public void SqlTransformSingleResult() public void AggregateInitialTest() { var aggregate = CreateAggregateTest(); - var result = aggregate.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null)).Single(); + var result = aggregate.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null, null)).Single(); Assert.AreEqual(SqlInt32.Null, result["min"]); Assert.AreEqual(SqlInt32.Null, result["max"]); @@ -767,7 +767,7 @@ public void AggregateInitialTest() public void AggregateSingleValueTest() { var aggregate = CreateAggregateTest(1); - var result = aggregate.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null)).Single(); + var result = aggregate.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null, null)).Single(); Assert.AreEqual((SqlInt32)1, result["min"]); Assert.AreEqual((SqlInt32)1, result["max"]); @@ -785,7 +785,7 @@ public void AggregateSingleValueTest() public void AggregateTwoEqualValuesTest() { var aggregate = CreateAggregateTest(1, 1); - var result = aggregate.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null)).Single(); + var result = aggregate.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null, null)).Single(); Assert.AreEqual((SqlInt32)1, result["min"]); Assert.AreEqual((SqlInt32)1, result["max"]); @@ -803,7 +803,7 @@ public void AggregateTwoEqualValuesTest() public void AggregateMultipleValuesTest() { var aggregate = CreateAggregateTest(1, 3, 1, 1); - var result = aggregate.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null)).Single(); + var result = aggregate.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null, null)).Single(); Assert.AreEqual((SqlInt32)1, result["min"]); Assert.AreEqual((SqlInt32)3, result["max"]); @@ -962,7 +962,7 @@ public void NestedLoopJoinInnerTest() } }; - var results = node.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null)).ToArray(); + var results = node.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null, null)).ToArray(); Assert.AreEqual(2, results.Length); Assert.AreEqual("Mark", ((SqlString)results[0]["f.firstname"]).Value); @@ -1034,7 +1034,7 @@ public void NestedLoopJoinLeftOuterTest() } }; - var results = node.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null)).ToArray(); + var results = node.Execute(new NodeExecutionContext(_localDataSource, new StubOptions(), null, null, null)).ToArray(); Assert.AreEqual(3, results.Length); Assert.AreEqual("Mark", ((SqlString)results[0]["f.firstname"]).Value); diff --git a/MarkMpn.Sql4Cds.Engine.Tests/ExecutionPlanTests.cs b/MarkMpn.Sql4Cds.Engine.Tests/ExecutionPlanTests.cs index c5b6fcf2..8bed3114 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/ExecutionPlanTests.cs +++ b/MarkMpn.Sql4Cds.Engine.Tests/ExecutionPlanTests.cs @@ -3273,7 +3273,7 @@ GROUP BY firstname }, }; - var result = select.Execute(new NodeExecutionContext(_localDataSource, this, new Dictionary(), new Dictionary()), CommandBehavior.Default); + var result = select.Execute(new NodeExecutionContext(_localDataSource, this, new Dictionary(), new Dictionary(), null), CommandBehavior.Default); var dataTable = new DataTable(); dataTable.Load(result); @@ -3722,7 +3722,7 @@ DECLARE @test int { if (plan is IDataReaderExecutionPlanNode selectQuery) { - var results = selectQuery.Execute(new NodeExecutionContext(_dataSources, this, parameterTypes, parameterValues), CommandBehavior.Default); + var results = selectQuery.Execute(new NodeExecutionContext(_dataSources, this, parameterTypes, parameterValues, null), CommandBehavior.Default); var dataTable = new DataTable(); dataTable.Load(results); @@ -3732,7 +3732,7 @@ DECLARE @test int } else if (plan is IDmlQueryExecutionPlanNode dmlQuery) { - dmlQuery.Execute(new NodeExecutionContext(_dataSources, this, parameterTypes, parameterValues), out _); + dmlQuery.Execute(new NodeExecutionContext(_dataSources, this, parameterTypes, parameterValues, null), out _); } } } @@ -3776,7 +3776,7 @@ public void SetVariableInDeclaration() { if (plan is IDataReaderExecutionPlanNode selectQuery) { - var results = selectQuery.Execute(new NodeExecutionContext(_dataSources, this, parameterTypes, parameterValues), CommandBehavior.Default); + var results = selectQuery.Execute(new NodeExecutionContext(_dataSources, this, parameterTypes, parameterValues, null), CommandBehavior.Default); var dataTable = new DataTable(); dataTable.Load(results); @@ -3786,7 +3786,7 @@ public void SetVariableInDeclaration() } else if (plan is IDmlQueryExecutionPlanNode dmlQuery) { - dmlQuery.Execute(new NodeExecutionContext(_dataSources, this, parameterTypes, parameterValues), out _); + dmlQuery.Execute(new NodeExecutionContext(_dataSources, this, parameterTypes, parameterValues, null), out _); } } } @@ -3834,7 +3834,7 @@ DECLARE @test varchar(3) { if (plan is IDataReaderExecutionPlanNode selectQuery) { - var results = selectQuery.Execute(new NodeExecutionContext(_localDataSource, this, parameterTypes, parameterValues), CommandBehavior.Default); + var results = selectQuery.Execute(new NodeExecutionContext(_localDataSource, this, parameterTypes, parameterValues, null), CommandBehavior.Default); var dataTable = new DataTable(); dataTable.Load(results); @@ -3844,7 +3844,7 @@ DECLARE @test varchar(3) } else if (plan is IDmlQueryExecutionPlanNode dmlQuery) { - dmlQuery.Execute(new NodeExecutionContext(_localDataSource, this, parameterTypes, parameterValues), out _); + dmlQuery.Execute(new NodeExecutionContext(_localDataSource, this, parameterTypes, parameterValues, null), out _); } } } @@ -3868,7 +3868,7 @@ DECLARE @test varchar(3) { if (plan is IDataReaderExecutionPlanNode selectQuery) { - var results = selectQuery.Execute(new NodeExecutionContext(_localDataSource, this, parameterTypes, parameterValues), CommandBehavior.Default); + var results = selectQuery.Execute(new NodeExecutionContext(_localDataSource, this, parameterTypes, parameterValues, null), CommandBehavior.Default); var dataTable = new DataTable(); dataTable.Load(results); @@ -3878,7 +3878,7 @@ DECLARE @test varchar(3) } else if (plan is IDmlQueryExecutionPlanNode dmlQuery) { - dmlQuery.Execute(new NodeExecutionContext(_localDataSource, this, parameterTypes, parameterValues), out _); + dmlQuery.Execute(new NodeExecutionContext(_localDataSource, this, parameterTypes, parameterValues, null), out _); } } } @@ -3960,7 +3960,7 @@ DECLARE @test varchar(3) { if (plan is IDataReaderExecutionPlanNode selectQuery) { - var results = selectQuery.Execute(new NodeExecutionContext(_localDataSource, this, parameterTypes, parameterValues), CommandBehavior.Default); + var results = selectQuery.Execute(new NodeExecutionContext(_localDataSource, this, parameterTypes, parameterValues, null), CommandBehavior.Default); var dataTable = new DataTable(); dataTable.Load(results); @@ -3970,7 +3970,7 @@ DECLARE @test varchar(3) } else if (plan is IDmlQueryExecutionPlanNode dmlQuery) { - dmlQuery.Execute(new NodeExecutionContext(_localDataSource, this, parameterTypes, parameterValues), out _); + dmlQuery.Execute(new NodeExecutionContext(_localDataSource, this, parameterTypes, parameterValues, null), out _); } } } @@ -3994,7 +3994,7 @@ DECLARE @test varchar { if (plan is IDataReaderExecutionPlanNode selectQuery) { - var results = selectQuery.Execute(new NodeExecutionContext(_localDataSource, this, parameterTypes, parameterValues), CommandBehavior.Default); + var results = selectQuery.Execute(new NodeExecutionContext(_localDataSource, this, parameterTypes, parameterValues, null), CommandBehavior.Default); var dataTable = new DataTable(); dataTable.Load(results); @@ -4004,7 +4004,7 @@ DECLARE @test varchar } else if (plan is IDmlQueryExecutionPlanNode dmlQuery) { - dmlQuery.Execute(new NodeExecutionContext(_localDataSource, this, parameterTypes, parameterValues), out _); + dmlQuery.Execute(new NodeExecutionContext(_localDataSource, this, parameterTypes, parameterValues, null), out _); } } } @@ -6473,5 +6473,20 @@ public void FoldFilterToCorrectTableAlias() "); } + + [TestMethod] + public void IgnoreDupKeyHint() + { + var planBuilder = new ExecutionPlanBuilder(_localDataSource.Values, this); + + var query = @"INSERT INTO account (accountid, name) VALUES ('{CD503427-E785-40D8-AD0E-FBDF4918D298}', 'Data8') OPTION (USE HINT ('IGNORE_DUP_KEY'))"; + + var plans = planBuilder.Build(query, null, out _); + + Assert.AreEqual(1, plans.Length); + + var insert = AssertNode(plans[0]); + Assert.IsTrue(insert.IgnoreDuplicateKey); + } } } diff --git a/MarkMpn.Sql4Cds.Engine.Tests/Sql2FetchXmlTests.cs b/MarkMpn.Sql4Cds.Engine.Tests/Sql2FetchXmlTests.cs index 16f2d783..f00071ac 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/Sql2FetchXmlTests.cs +++ b/MarkMpn.Sql4Cds.Engine.Tests/Sql2FetchXmlTests.cs @@ -706,7 +706,7 @@ public void SelectArithmetic() } }; - var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary()), CommandBehavior.Default); + var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary(), null), CommandBehavior.Default); var dataTable = new DataTable(); dataTable.Load(dataReader); @@ -754,7 +754,7 @@ public void WhereComparingTwoFields() } }; - var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary()), CommandBehavior.Default); + var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary(), null), CommandBehavior.Default); var dataTable = new DataTable(); dataTable.Load(dataReader); @@ -798,7 +798,7 @@ public void WhereComparingExpression() } }; - var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary()), CommandBehavior.Default); + var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary(), null), CommandBehavior.Default); var dataTable = new DataTable(); dataTable.Load(dataReader); @@ -839,7 +839,7 @@ public void BackToFrontLikeExpression() } }; - var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary()), CommandBehavior.Default); + var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary(), null), CommandBehavior.Default); var dataTable = new DataTable(); dataTable.Load(dataReader); @@ -874,7 +874,7 @@ public void UpdateFieldToField() } }; - ((UpdateNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary()), out _); + ((UpdateNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary(), null), out _); Assert.AreEqual("Carrington", _context.Data["contact"][guid]["firstname"]); } @@ -906,7 +906,7 @@ public void UpdateFieldToExpression() } }; - ((UpdateNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary()), out _); + ((UpdateNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary(), null), out _); Assert.AreEqual("Hello Carrington", _context.Data["contact"][guid]["firstname"]); } @@ -942,7 +942,7 @@ public void UpdateReplace() } }; - ((UpdateNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary()), out _); + ((UpdateNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary(), null), out _); Assert.AreEqual("--CDS--", _context.Data["contact"][guid]["firstname"]); } @@ -973,7 +973,7 @@ public void StringFunctions() } }; - var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary()), CommandBehavior.Default); + var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary(), null), CommandBehavior.Default); var dataTable = new DataTable(); dataTable.Load(dataReader); @@ -1013,7 +1013,7 @@ public void SelectExpression() } }; - var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary()), CommandBehavior.Default); + var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary(), null), CommandBehavior.Default); var dataTable = new DataTable(); dataTable.Load(dataReader); @@ -1063,7 +1063,7 @@ public void SelectExpressionNullValues() } }; - var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary()), CommandBehavior.Default); + var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary(), null), CommandBehavior.Default); var dataTable = new DataTable(); dataTable.Load(dataReader); @@ -1108,7 +1108,7 @@ public void OrderByExpression() } }; - var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary()), CommandBehavior.Default); + var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary(), null), CommandBehavior.Default); var dataTable = new DataTable(); dataTable.Load(dataReader); @@ -1153,7 +1153,7 @@ public void OrderByAliasedField() } }; - var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary()), CommandBehavior.Default); + var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary(), null), CommandBehavior.Default); var dataTable = new DataTable(); dataTable.Load(dataReader); @@ -1197,7 +1197,7 @@ public void OrderByCalculatedField() } }; - var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary()), CommandBehavior.Default); + var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary(), null), CommandBehavior.Default); var dataTable = new DataTable(); dataTable.Load(dataReader); @@ -1241,7 +1241,7 @@ public void OrderByCalculatedFieldByIndex() } }; - var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary()), CommandBehavior.Default); + var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary(), null), CommandBehavior.Default); var dataTable = new DataTable(); dataTable.Load(dataReader); @@ -1283,7 +1283,7 @@ public void DateCalculations() } }; - var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary()), CommandBehavior.Default); + var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary(), null), CommandBehavior.Default); var dataTable = new DataTable(); dataTable.Load(dataReader); @@ -1368,7 +1368,7 @@ public void CustomFilterAggregateHavingProjectionSortAndTop() } }; - var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary()), CommandBehavior.Default); + var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary(), null), CommandBehavior.Default); var dataTable = new DataTable(); dataTable.Load(dataReader); @@ -1431,7 +1431,7 @@ public void FilterCaseInsensitive() } }; - var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary()), CommandBehavior.Default); + var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary(), null), CommandBehavior.Default); var dataTable = new DataTable(); dataTable.Load(dataReader); @@ -1488,7 +1488,7 @@ public void GroupCaseInsensitive() } }; - var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary()), CommandBehavior.Default); + var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary(), null), CommandBehavior.Default); var dataTable = new DataTable(); dataTable.Load(dataReader); @@ -1541,7 +1541,7 @@ public void AggregateExpressionsWithoutGrouping() } }; - var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary()), CommandBehavior.Default); + var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary(), null), CommandBehavior.Default); var dataTable = new DataTable(); dataTable.Load(dataReader); @@ -1596,7 +1596,7 @@ public void AggregateQueryProducesAlternative() } }; - var dataReader = alternativeQuery.Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary()), CommandBehavior.Default); + var dataReader = alternativeQuery.Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary(), null), CommandBehavior.Default); var dataTable = new DataTable(); dataTable.Load(dataReader); @@ -1650,7 +1650,7 @@ public void GuidEntityReferenceInequality() } }; - var dataReader = select.Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary()), CommandBehavior.Default); + var dataReader = select.Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary(), null), CommandBehavior.Default); var dataTable = new DataTable(); dataTable.Load(dataReader); @@ -1701,7 +1701,7 @@ public void UpdateGuidToEntityReference() } }; - update.Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary()), out _); + update.Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary(), null), out _); Assert.AreEqual(new EntityReference("contact", contact1), _context.Data["account"][account1].GetAttributeValue("primarycontactid")); Assert.AreEqual(new EntityReference("contact", contact2), _context.Data["account"][account2].GetAttributeValue("primarycontactid")); @@ -1975,7 +1975,7 @@ public void ImplicitTypeConversion() } }; - var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary()), CommandBehavior.Default); + var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary(), null), CommandBehavior.Default); var dataTable = new DataTable(); dataTable.Load(dataReader); @@ -2008,7 +2008,7 @@ public void ImplicitTypeConversionComparison() } }; - var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary()), CommandBehavior.Default); + var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary(), null), CommandBehavior.Default); var dataTable = new DataTable(); dataTable.Load(dataReader); @@ -2033,7 +2033,7 @@ public void GlobalOptionSet() Assert.AreEqual("name = 'test'", filterNode.Filter.ToSql()); var optionsetNode = (GlobalOptionSetQueryNode)filterNode.Source; - var dataReader = selectNode.Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary()), CommandBehavior.Default); + var dataReader = selectNode.Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary(), null), CommandBehavior.Default); var dataTable = new DataTable(); dataTable.Load(dataReader); @@ -2055,7 +2055,7 @@ public void EntityDetails() var sortNode = (SortNode)selectNode.Source; var metadataNode = (MetadataQueryNode)sortNode.Source; - var dataReader = selectNode.Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary()), CommandBehavior.Default); + var dataReader = selectNode.Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary(), null), CommandBehavior.Default); var dataTable = new DataTable(); dataTable.Load(dataReader); @@ -2074,7 +2074,7 @@ public void AttributeDetails() var planBuilder = new ExecutionPlanBuilder(_localDataSource.Values, this); var queries = planBuilder.Build(query, null, out _); - var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary()), CommandBehavior.Default); + var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary(), null), CommandBehavior.Default); var dataTable = new DataTable(); dataTable.Load(dataReader); @@ -2130,7 +2130,7 @@ public void OptionSetNameSelect() CollectionAssert.AreEqual(new[] { "new_optionsetvalue", "new_optionsetvaluename" }, select.ColumnSet.Select(c => c.OutputColumn).ToList()); - var dataReader = select.Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary()), CommandBehavior.Default); + var dataReader = select.Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary(), null), CommandBehavior.Default); var dataTable = new DataTable(); dataTable.Load(dataReader); @@ -2454,7 +2454,7 @@ public void CharIndex() } }; - var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary()), CommandBehavior.Default); + var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary(), null), CommandBehavior.Default); var dataTable = new DataTable(); dataTable.Load(dataReader); @@ -2484,7 +2484,7 @@ public void CastDateTimeToDate() } }; - var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary()), CommandBehavior.Default); + var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary(), null), CommandBehavior.Default); var dataTable = new DataTable(); dataTable.Load(dataReader); @@ -2522,7 +2522,7 @@ public void GroupByPrimaryFunction() } }; - var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary()), CommandBehavior.Default); + var dataReader = ((SelectNode)queries[0]).Execute(new NodeExecutionContext(GetDataSources(_context), this, new Dictionary(), new Dictionary(), null), CommandBehavior.Default); var dataTable = new DataTable(); dataTable.Load(dataReader); diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/InsertNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/InsertNode.cs index e4cfc7c8..d51c1e43 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/InsertNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/InsertNode.cs @@ -5,6 +5,7 @@ using System.ServiceModel; using System.Threading; using System.Threading.Tasks; +using System.Xml; using Microsoft.Crm.Sdk.Messages; using Microsoft.SqlServer.TransactSql.ScriptDom; using Microsoft.Xrm.Sdk; @@ -53,6 +54,11 @@ class InsertNode : BaseDmlNode [Category("Insert")] public override bool ContinueOnError { get; set; } + [Category("Insert")] + [DisplayName("Ignore Duplicate Key")] + [Description("Ignores any duplicate key errors encountered. Errors will be logged but the query will complete.")] + public bool IgnoreDuplicateKey { get; set; } + public override void AddRequiredColumns(NodeCompilationContext context, IList requiredColumns) { foreach (var col in ColumnMappings.Values) @@ -64,7 +70,26 @@ public override void AddRequiredColumns(NodeCompilationContext context, IList hints) + { + IgnoreDuplicateKey = GetIgnoreDuplicateKey(context, hints); + + return base.FoldQuery(context, hints); + } + + private bool GetIgnoreDuplicateKey(NodeCompilationContext context, IList queryHints) + { + if (queryHints == null) + return false; + + var ignoreDupKey = queryHints + .OfType() + .Where(hint => hint.Hints.Any(s => s.Value.Equals("IGNORE_DUP_KEY", StringComparison.OrdinalIgnoreCase))) + .Any(); + + return ignoreDupKey; + } + public override void Execute(NodeExecutionContext context, out int recordsAffected) { _executionCount++; @@ -200,6 +225,43 @@ private OrganizationRequest CreateInsertRequest(EntityMetadata meta, Entity enti return new CreateRequest { Target = insert }; } + protected override bool FilterErrors(NodeExecutionContext context, OrganizationRequest request, OrganizationServiceFault fault) + { + if (IgnoreDuplicateKey) + { + if (fault.ErrorCode == -2147220937 || fault.ErrorCode == -2147088238 || fault.ErrorCode == 409) + { + var logMessage = "Ignoring duplicate key error"; + + if (fault.ErrorCode == -2147088238) + { + // Duplicate alternate key. The duplicated values are available in the fault details + if (fault.ErrorDetails.TryGetValue("DuplicateAttributes", out var value) && + value is string duplicateAttributes) + { + var xml = new XmlDocument(); + xml.LoadXml(duplicateAttributes); + + logMessage += $". The duplicate values were ({String.Join(", ", xml.SelectNodes("/DuplicateAttributes/*").OfType().Select(attr => attr.InnerText))})"; + } + } + else + { + // Duplicate primary key. + if (request is AssociateRequest associate) + logMessage += $". The duplicate values were ({associate.Target.Id}, {associate.RelatedEntities[0].Id})"; + else if (request is CreateRequest create) + logMessage += $". The duplicate values were ({create.Target.Id})"; + } + + context.Log(logMessage); + return false; + } + } + + return true; + } + private void SetIdentity(OrganizationResponse response, IDictionary parameterValues) { var create = (CreateResponse)response; @@ -314,6 +376,7 @@ public override object Clone() Length = Length, LogicalName = LogicalName, MaxDOP = MaxDOP, + IgnoreDuplicateKey = IgnoreDuplicateKey, Source = (IExecutionPlanNodeInternal)Source.Clone(), Sql = Sql }; diff --git a/MarkMpn.Sql4Cds.Engine/Visitors/OptimizerHintValidatingVisitor.cs b/MarkMpn.Sql4Cds.Engine/Visitors/OptimizerHintValidatingVisitor.cs index 7645421a..a27698ac 100644 --- a/MarkMpn.Sql4Cds.Engine/Visitors/OptimizerHintValidatingVisitor.cs +++ b/MarkMpn.Sql4Cds.Engine/Visitors/OptimizerHintValidatingVisitor.cs @@ -57,6 +57,9 @@ class OptimizerHintValidatingVisitor : TSqlFragmentVisitor // Custom hint to use legacy specialized update messages - https://learn.microsoft.com/en-us/power-apps/developer/data-platform/org-service/entity-operations-update-delete?tabs=late#legacy-update-messages "USE_LEGACY_UPDATE_MESSAGES", + + // Ignore duplicate keys on insert, equivalent to IGNORE_DUP_KEY option on creation of index + "IGNORE_DUP_KEY", }; private static readonly HashSet _removableSql4CdsQueryHints = new HashSet(StringComparer.OrdinalIgnoreCase) From 18f7f91777ecd5d9ed678a93d0b61ed620e1811a Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Fri, 10 Nov 2023 08:23:38 +0000 Subject: [PATCH 48/81] Avoid additional RetrieveVersionRequest where possible --- MarkMpn.Sql4Cds.Engine/TableSizeCache.cs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/MarkMpn.Sql4Cds.Engine/TableSizeCache.cs b/MarkMpn.Sql4Cds.Engine/TableSizeCache.cs index 700971c6..f4a9b4dc 100644 --- a/MarkMpn.Sql4Cds.Engine/TableSizeCache.cs +++ b/MarkMpn.Sql4Cds.Engine/TableSizeCache.cs @@ -8,6 +8,11 @@ using Microsoft.Crm.Sdk.Messages; using Microsoft.Xrm.Sdk; using Microsoft.Xrm.Sdk.Query; +#if NETCOREAPP +using Microsoft.PowerPlatform.Dataverse.Client; +#else +using Microsoft.Xrm.Tooling.Connector; +#endif namespace MarkMpn.Sql4Cds.Engine { @@ -24,7 +29,17 @@ public TableSizeCache(IOrganizationService org, IAttributeMetadataCache metadata _org = org; _metadata = metadata; - _version = new Version(((RetrieveVersionResponse)_org.Execute(new RetrieveVersionRequest())).Version); +#if NETCOREAPP + if (org is ServiceClient svc) + _version = svc.ConnectedOrgVersion; + else +#else + if (org is CrmServiceClient svc) + _version = svc.ConnectedOrgVersion; + else +#endif + + _version = new Version(((RetrieveVersionResponse)_org.Execute(new RetrieveVersionRequest())).Version); } private bool UseRetrieveTotalRecordCountRequest => _version.Major >= 9; From 583d9870b1f762905d633a181abb82b8dc07a596 Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Fri, 10 Nov 2023 08:23:57 +0000 Subject: [PATCH 49/81] Apply naming convention --- .../QueryExecution/QueryExecutionHandler.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MarkMpn.Sql4Cds.LanguageServer/QueryExecution/QueryExecutionHandler.cs b/MarkMpn.Sql4Cds.LanguageServer/QueryExecution/QueryExecutionHandler.cs index e4dfd862..692f4ec3 100644 --- a/MarkMpn.Sql4Cds.LanguageServer/QueryExecution/QueryExecutionHandler.cs +++ b/MarkMpn.Sql4Cds.LanguageServer/QueryExecution/QueryExecutionHandler.cs @@ -100,7 +100,7 @@ public ExecuteRequestResult HandleExecuteDocumentSelection(ExecuteDocumentSelect qry += '\n'; } - await Execute(session, request, qry, request.QuerySelection); + await ExecuteAsync(session, request, qry, request.QuerySelection); }); return new ExecuteRequestResult(); @@ -123,13 +123,13 @@ private ExecuteRequestResult HandleExecuteString(ExecuteStringParams request) _ = Task.Run(async () => { var lines = request.Query.Split('\n'); - await Execute(session, request, request.Query, new SelectionData { StartLine =0, StartColumn = 0, EndLine = lines.Length - 1, EndColumn = lines[lines.Length - 1].Length }); + await ExecuteAsync(session, request, request.Query, new SelectionData { StartLine =0, StartColumn = 0, EndLine = lines.Length - 1, EndColumn = lines[lines.Length - 1].Length }); }); return new ExecuteRequestResult(); } - private async Task Execute(Connection.Session session, ExecuteRequestParamsBase request, string qry, SelectionData selection) + private async Task ExecuteAsync(Connection.Session session, ExecuteRequestParamsBase request, string qry, SelectionData selection) { // query/batchStart (BatchEventParams) // query/message (MessagePArams) From 915ee7c5cd5ae155d31a75ed0cbb541306a790c5 Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Fri, 10 Nov 2023 08:57:01 +0000 Subject: [PATCH 50/81] Add log message indicating IGNORE_DUP_KEY is implicit for listmember inserts --- .../ExecutionPlanTests.cs | 2 +- MarkMpn.Sql4Cds.Engine/Ado/Sql4CdsCommand.cs | 2 ++ .../ExecutionPlan/InsertNode.cs | 13 ++++++++++++ .../ExecutionPlan/NestedLoopNode.cs | 10 +++++----- .../ExecutionPlanBuilder.cs | 19 +++++++++++------- .../ExecutionPlanOptimizer.cs | 7 +++++-- MarkMpn.Sql4Cds.Engine/MetaMetadataCache.cs | 4 ++-- MarkMpn.Sql4Cds.Engine/NodeContext.cs | 20 ++++++++++++------- MarkMpn.Sql4Cds.XTB/SqlQueryControl.cs | 2 +- 9 files changed, 54 insertions(+), 25 deletions(-) diff --git a/MarkMpn.Sql4Cds.Engine.Tests/ExecutionPlanTests.cs b/MarkMpn.Sql4Cds.Engine.Tests/ExecutionPlanTests.cs index 8bed3114..5a6a3d24 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/ExecutionPlanTests.cs +++ b/MarkMpn.Sql4Cds.Engine.Tests/ExecutionPlanTests.cs @@ -1997,7 +1997,7 @@ SELECT TOP 10 var filter = AssertNode(top.Source); var constant = AssertNode(filter.Source); - var schema = constant.GetSchema(new NodeCompilationContext(_dataSources, this, null)); + var schema = constant.GetSchema(new NodeCompilationContext(_dataSources, this, null, null)); Assert.AreEqual(typeof(SqlInt32), schema.Schema["a.ID"].Type.ToNetType(out _)); Assert.AreEqual(typeof(SqlString), schema.Schema["a.name"].Type.ToNetType(out _)); } diff --git a/MarkMpn.Sql4Cds.Engine/Ado/Sql4CdsCommand.cs b/MarkMpn.Sql4Cds.Engine/Ado/Sql4CdsCommand.cs index d3fc7dc8..e04571c7 100644 --- a/MarkMpn.Sql4Cds.Engine/Ado/Sql4CdsCommand.cs +++ b/MarkMpn.Sql4Cds.Engine/Ado/Sql4CdsCommand.cs @@ -42,6 +42,7 @@ public Sql4CdsCommand(Sql4CdsConnection connection, string commandText) DbParameterCollection = new Sql4CdsParameterCollection(); _planBuilder = new ExecutionPlanBuilder(_connection.DataSources.Values, _connection.Options); + _planBuilder.Log = msg => _connection.OnInfoMessage(null, msg); } /// @@ -116,6 +117,7 @@ protected override DbConnection DbConnection _connection = con; _planBuilder = new ExecutionPlanBuilder(_connection.DataSources.Values, _connection.Options); + _planBuilder.Log = msg => _connection.OnInfoMessage(null, msg); Plan = null; UseTDSEndpointDirectly = false; } diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/InsertNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/InsertNode.cs index d51c1e43..de62f24b 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/InsertNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/InsertNode.cs @@ -78,6 +78,19 @@ public override IRootExecutionPlanNodeInternal[] FoldQuery(NodeCompilationContex } private bool GetIgnoreDuplicateKey(NodeCompilationContext context, IList queryHints) + { + var ignoreDupKey = GetIgnoreDuplicateKeyHint(queryHints); + + if (!ignoreDupKey && LogicalName == "listmember") + { + ignoreDupKey = true; + context.Log("Duplicate entries will be silently ignored for listmember inserts"); + } + + return ignoreDupKey; + } + + private bool GetIgnoreDuplicateKeyHint(IList queryHints) { if (queryHints == null) return false; diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/NestedLoopNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/NestedLoopNode.cs index 1e58d7c2..9d9c4d4a 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/NestedLoopNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/NestedLoopNode.cs @@ -60,7 +60,7 @@ protected override IEnumerable ExecuteInternal(NodeExecutionContext cont innerParameterTypes[kvp.Value] = leftSchema.Schema[kvp.Key].Type; } - rightCompilationContext = new NodeCompilationContext(context.DataSources, context.Options, innerParameterTypes); + rightCompilationContext = new NodeCompilationContext(context.DataSources, context.Options, innerParameterTypes, context.Log); } var innerParameters = context.ParameterValues; @@ -179,7 +179,7 @@ public override IDataExecutionPlanNodeInternal FoldQuery(NodeCompilationContext LeftSource.Parent = this; var innerParameterTypes = GetInnerParameterTypes(leftSchema, context.ParameterTypes); - var innerContext = new NodeCompilationContext(context.DataSources, context.Options, innerParameterTypes); + var innerContext = new NodeCompilationContext(context.DataSources, context.Options, innerParameterTypes, context.Log); RightSource = RightSource.FoldQuery(innerContext, hints); RightSource.Parent = this; @@ -268,7 +268,7 @@ public override void AddRequiredColumns(NodeCompilationContext context, IList rightSchema.ContainsColumn(col, out _)) @@ -284,7 +284,7 @@ protected override INodeSchema GetRightSchema(NodeCompilationContext context) { var leftSchema = LeftSource.GetSchema(context); var innerParameterTypes = GetInnerParameterTypes(leftSchema, context.ParameterTypes); - var innerContext = new NodeCompilationContext(context.DataSources, context.Options, innerParameterTypes); + var innerContext = new NodeCompilationContext(context.DataSources, context.Options, innerParameterTypes, context.Log); return RightSource.GetSchema(innerContext); } @@ -294,7 +294,7 @@ protected override RowCountEstimate EstimateRowsOutInternal(NodeCompilationConte ParseEstimate(leftEstimate, out var leftMin, out var leftMax, out var leftIsRange); var leftSchema = LeftSource.GetSchema(context); var innerParameterTypes = GetInnerParameterTypes(leftSchema, context.ParameterTypes); - var innerContext = new NodeCompilationContext(context.DataSources, context.Options, innerParameterTypes); + var innerContext = new NodeCompilationContext(context.DataSources, context.Options, innerParameterTypes, context.Log); var rightEstimate = RightSource.EstimateRowsOut(innerContext); ParseEstimate(rightEstimate, out var rightMin, out var rightMax, out var rightIsRange); diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs index 79ae8ff4..b8bb44f8 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs @@ -48,6 +48,11 @@ public ExecutionPlanBuilder(IEnumerable dataSources, IQueryExecution /// public bool EstimatedPlanOnly { get; set; } + /// + /// A callback function to log messages + /// + public Action Log { get; set; } + private DataSource PrimaryDataSource => DataSources[Options.PrimaryDataSource]; /// @@ -63,7 +68,7 @@ public IRootExecutionPlanNode[] Build(string sql, IDictionary(StringComparer.OrdinalIgnoreCase); _staticContext = new ExpressionCompilationContext(DataSources, Options, parameterTypes, null, null); - _nodeContext = new NodeCompilationContext(DataSources, Options, parameterTypes); + _nodeContext = new NodeCompilationContext(DataSources, Options, parameterTypes, Log); if (parameters != null) { @@ -125,7 +130,7 @@ public IRootExecutionPlanNode[] Build(string sql, IDictionary(); var innerQuery = ConvertSelectStatement(existsSubquery.Subquery.QueryExpression, hints, schema, references, innerContext); - var innerSchema = innerQuery.Source.GetSchema(new NodeCompilationContext(DataSources, Options, parameters)); + var innerSchema = innerQuery.Source.GetSchema(new NodeCompilationContext(DataSources, Options, parameters, Log)); var innerSchemaPrimaryKey = innerSchema.PrimaryKey; // Create the join @@ -3447,8 +3452,8 @@ private bool UseMergeJoin(IDataExecutionPlanNodeInternal node, IDataExecutionPla if (outerKey == null) return false; - var outerSchema = node.GetSchema(new NodeCompilationContext(DataSources, Options, null)); - var innerSchema = subNode.GetSchema(new NodeCompilationContext(DataSources, Options, null)); + var outerSchema = node.GetSchema(new NodeCompilationContext(DataSources, Options, null, Log)); + var innerSchema = subNode.GetSchema(new NodeCompilationContext(DataSources, Options, null, Log)); if (!outerSchema.ContainsColumn(outerKey, out outerKey) || !innerSchema.ContainsColumn(innerKey, out innerKey)) @@ -3521,7 +3526,7 @@ private bool UseMergeJoin(IDataExecutionPlanNodeInternal node, IDataExecutionPla if (semiJoin) { // Regenerate the schema after changing the alias - innerSchema = subNode.GetSchema(new NodeCompilationContext(DataSources, Options, null)); + innerSchema = subNode.GetSchema(new NodeCompilationContext(DataSources, Options, null, Log)); if (innerSchema.PrimaryKey != rightAttribute.GetColumnName() && !(merge.RightSource is DistinctNode)) { diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlanOptimizer.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlanOptimizer.cs index 9807afbe..1b8f787b 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlanOptimizer.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlanOptimizer.cs @@ -17,12 +17,13 @@ namespace MarkMpn.Sql4Cds.Engine /// class ExecutionPlanOptimizer { - public ExecutionPlanOptimizer(IDictionary dataSources, IQueryExecutionOptions options, IDictionary parameterTypes, bool compileConditions) + public ExecutionPlanOptimizer(IDictionary dataSources, IQueryExecutionOptions options, IDictionary parameterTypes, bool compileConditions, Action log) { DataSources = dataSources; Options = options; ParameterTypes = parameterTypes; CompileConditions = compileConditions; + Log = log; } public IDictionary DataSources { get; } @@ -33,6 +34,8 @@ public ExecutionPlanOptimizer(IDictionary dataSources, IQuer public bool CompileConditions { get; } + public Action Log { get; } + /// /// Optimizes an execution plan /// @@ -49,7 +52,7 @@ public IRootExecutionPlanNodeInternal[] Optimize(IRootExecutionPlanNodeInternal hints.Add(new ConditionalNode.DoNotCompileConditionsHint()); } - var context = new NodeCompilationContext(DataSources, Options, ParameterTypes); + var context = new NodeCompilationContext(DataSources, Options, ParameterTypes, Log); // Move any additional operators down to the FetchXml var bypassOptimization = hints != null && hints.OfType().Any(list => list.Hints.Any(h => h.Value.Equals("DEBUG_BYPASS_OPTIMIZATION", StringComparison.OrdinalIgnoreCase))); diff --git a/MarkMpn.Sql4Cds.Engine/MetaMetadataCache.cs b/MarkMpn.Sql4Cds.Engine/MetaMetadataCache.cs index 59740d3d..2b6f6a12 100644 --- a/MarkMpn.Sql4Cds.Engine/MetaMetadataCache.cs +++ b/MarkMpn.Sql4Cds.Engine/MetaMetadataCache.cs @@ -92,7 +92,7 @@ static MetaMetadataCache() metadataNode.ManyToOneRelationshipAlias = "relationship_n_1"; metadataNode.ManyToManyRelationshipAlias = "relationship_n_n"; - var metadataSchema = metadataNode.GetSchema(new NodeCompilationContext(null, new StubOptions(), null)); + var metadataSchema = metadataNode.GetSchema(new NodeCompilationContext(null, new StubOptions(), null, null)); _customMetadata["metadata." + metadataNode.EntityAlias] = SchemaToMetadata(metadataSchema, metadataNode.EntityAlias); _customMetadata["metadata." + metadataNode.AttributeAlias] = SchemaToMetadata(metadataSchema, metadataNode.AttributeAlias); @@ -103,7 +103,7 @@ static MetaMetadataCache() var optionsetNode = new GlobalOptionSetQueryNode(); optionsetNode.Alias = "globaloptionset"; - var optionsetSchema = optionsetNode.GetSchema(new NodeCompilationContext(null, new StubOptions(), null)); + var optionsetSchema = optionsetNode.GetSchema(new NodeCompilationContext(null, new StubOptions(), null, null)); _customMetadata["metadata." + optionsetNode.Alias] = SchemaToMetadata(optionsetSchema, optionsetNode.Alias); } diff --git a/MarkMpn.Sql4Cds.Engine/NodeContext.cs b/MarkMpn.Sql4Cds.Engine/NodeContext.cs index b0ece541..1ed06b2d 100644 --- a/MarkMpn.Sql4Cds.Engine/NodeContext.cs +++ b/MarkMpn.Sql4Cds.Engine/NodeContext.cs @@ -21,14 +21,17 @@ class NodeCompilationContext /// The data sources that are available to the query /// The options that the query will be executed with /// The names and types of the parameters that are available to the query + /// A callback function to log messages public NodeCompilationContext( IDictionary dataSources, IQueryExecutionOptions options, - IDictionary parameterTypes) + IDictionary parameterTypes, + Action log) { DataSources = dataSources; Options = options; ParameterTypes = parameterTypes; + Log = log ?? (msg => { }); } /// @@ -43,6 +46,7 @@ public NodeCompilationContext( DataSources = parentContext.DataSources; Options = parentContext.Options; ParameterTypes = parameterTypes; + Log = parentContext.Log; _parentContext = parentContext; } @@ -66,6 +70,11 @@ public NodeCompilationContext( /// public DataSource PrimaryDataSource => DataSources[Options.PrimaryDataSource]; + /// + /// A callback function to log messages + /// + public Action Log { get; } + /// /// Generates a unique name for an expression /// @@ -98,18 +107,15 @@ public NodeExecutionContext( IDictionary parameterTypes, IDictionary parameterValues, Action log) - : base(dataSources, options, parameterTypes) + : base(dataSources, options, parameterTypes, log) { ParameterValues = parameterValues; - Log = log ?? (msg => { }); } /// /// Returns the current value of each parameter /// public IDictionary ParameterValues { get; } - - public Action Log { get; } } /// @@ -131,7 +137,7 @@ public ExpressionCompilationContext( IDictionary parameterTypes, INodeSchema schema, INodeSchema nonAggregateSchema) - : base(dataSources, options, parameterTypes) + : base(dataSources, options, parameterTypes, null) { Schema = schema; NonAggregateSchema = nonAggregateSchema; @@ -147,7 +153,7 @@ public ExpressionCompilationContext( NodeCompilationContext nodeContext, INodeSchema schema, INodeSchema nonAggregateSchema) - : base(nodeContext.DataSources, nodeContext.Options, nodeContext.ParameterTypes) + : base(nodeContext.DataSources, nodeContext.Options, nodeContext.ParameterTypes, nodeContext.Log) { Schema = schema; NonAggregateSchema = nonAggregateSchema; diff --git a/MarkMpn.Sql4Cds.XTB/SqlQueryControl.cs b/MarkMpn.Sql4Cds.XTB/SqlQueryControl.cs index b2980c64..1c22c782 100644 --- a/MarkMpn.Sql4Cds.XTB/SqlQueryControl.cs +++ b/MarkMpn.Sql4Cds.XTB/SqlQueryControl.cs @@ -1212,7 +1212,7 @@ private void ShowResult(IRootExecutionPlanNode query, ExecuteParams args, DataTa } else if (msg != null) { - AddMessage(query.Index, query.Length, msg, false); + AddMessage(query?.Index ?? -1, query?.Length ?? 0, msg, false); } else if (args.IncludeFetchXml) { From 00d3d728fa2f99c2c5eaef0ca96fa31ea7e99f0d Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Sat, 11 Nov 2023 17:10:51 +0000 Subject: [PATCH 51/81] Added OPENJSON support using default schema #340 --- .../AdoProviderTests.cs | 93 ++++++ .../ExecutionPlan/OpenJsonNode.cs | 275 +++++++++++++++++ .../ExecutionPlanBuilder.cs | 42 +++ MarkMpn.Sql4Cds.Engine/ExpressionFunctions.cs | 26 +- MarkMpn.Sql4Cds.Engine/JsonPath.cs | 287 ++++++++++++++++++ 5 files changed, 705 insertions(+), 18 deletions(-) create mode 100644 MarkMpn.Sql4Cds.Engine/ExecutionPlan/OpenJsonNode.cs create mode 100644 MarkMpn.Sql4Cds.Engine/JsonPath.cs diff --git a/MarkMpn.Sql4Cds.Engine.Tests/AdoProviderTests.cs b/MarkMpn.Sql4Cds.Engine.Tests/AdoProviderTests.cs index bad282d1..dd5d110b 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/AdoProviderTests.cs +++ b/MarkMpn.Sql4Cds.Engine.Tests/AdoProviderTests.cs @@ -1514,5 +1514,98 @@ public void ComplexFetchXmlAlias() } } } + + [TestMethod] + public void OpenJsonDefaultSchema() + { + using (var con = new Sql4CdsConnection(_localDataSource)) + using (var cmd = con.CreateCommand()) + { + cmd.CommandText = @" +DECLARE @json NVARCHAR(MAX) + +SET @json='{""name"":""John"",""surname"":""Doe"",""age"":45,""skills"":[""SQL"",""C#"",""MVC""]}'; + +SELECT * +FROM OPENJSON(@json);"; + + using (var reader = cmd.ExecuteReader()) + { + Assert.AreEqual("key", reader.GetName(0)); + Assert.AreEqual("value", reader.GetName(1)); + Assert.AreEqual("type", reader.GetName(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("name", reader.GetString(0)); + Assert.AreEqual("John", reader.GetString(1)); + Assert.AreEqual(1, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("surname", reader.GetString(0)); + Assert.AreEqual("Doe", reader.GetString(1)); + Assert.AreEqual(1, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("age", reader.GetString(0)); + Assert.AreEqual("45", reader.GetString(1)); + Assert.AreEqual(2, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("skills", reader.GetString(0)); + Assert.AreEqual("[\r\n \"SQL\",\r\n \"C#\",\r\n \"MVC\"\r\n]", reader.GetString(1)); + Assert.AreEqual(4, reader.GetInt32(2)); + + Assert.IsFalse(reader.Read()); + } + } + } + + [TestMethod] + public void OpenJsonDefaultSchemaWithPath() + { + using (var con = new Sql4CdsConnection(_localDataSource)) + using (var cmd = con.CreateCommand()) + { + cmd.CommandText = @" +DECLARE @json NVARCHAR(4000) = N'{ + ""path"": { + ""to"":{ + ""sub-object"":[""en-GB"", ""en-UK"",""de-AT"",""es-AR"",""sr-Cyrl""] + } + } + }'; + +SELECT [key], value +FROM OPENJSON(@json,'$.path.to.""sub-object""')"; + + using (var reader = cmd.ExecuteReader()) + { + Assert.AreEqual("key", reader.GetName(0)); + Assert.AreEqual("value", reader.GetName(1)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("0", reader.GetString(0)); + Assert.AreEqual("en-GB", reader.GetString(1)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("1", reader.GetString(0)); + Assert.AreEqual("en-UK", reader.GetString(1)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("2", reader.GetString(0)); + Assert.AreEqual("de-AT", reader.GetString(1)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("3", reader.GetString(0)); + Assert.AreEqual("es-AR", reader.GetString(1)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("4", reader.GetString(0)); + Assert.AreEqual("sr-Cyrl", reader.GetString(1)); + + Assert.IsFalse(reader.Read()); + } + } + } } } diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/OpenJsonNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/OpenJsonNode.cs new file mode 100644 index 00000000..757bb13a --- /dev/null +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/OpenJsonNode.cs @@ -0,0 +1,275 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data.SqlTypes; +using System.Linq; +using System.Text; +using Microsoft.SqlServer.TransactSql.ScriptDom; +using Microsoft.Xrm.Sdk; +using Newtonsoft.Json.Linq; + +namespace MarkMpn.Sql4Cds.Engine.ExecutionPlan +{ + class OpenJsonNode : BaseDataNode + { + private Func _jsonExpression; + private Func _pathExpression; + private Collation _jsonCollation; + + private static readonly Collation _keyCollation; + + static OpenJsonNode() + { + _keyCollation = new Collation(null, 1033, SqlCompareOptions.BinarySort2, null); + } + + private OpenJsonNode() + { + } + + public OpenJsonNode(OpenJsonTableReference tvf) + { + Alias = tvf.Alias?.Value; + Json = tvf.Variable.Clone(); + Path = tvf.RowPattern?.Clone(); + + // TODO: Check expressions are string types and add conversions if not + } + + /// + /// The alias for the data source + /// + [Category("Open JSON")] + [Description("The alias for the data source")] + public string Alias { get; set; } + + /// + /// The expression that provides the JSON to parse + /// + [Category("Open JSON")] + [Description("The expression that provides the JSON to parse")] + public ScalarExpression Json { get; set; } + + /// + /// The expression that defines the JSON path to the object or array to parse + /// + [Category("Open JSON")] + [Description("The expression that defines the JSON path to the object or array to parse")] + public ScalarExpression Path { get; set; } + + public override void AddRequiredColumns(NodeCompilationContext context, IList requiredColumns) + { + } + + public override IDataExecutionPlanNodeInternal FoldQuery(NodeCompilationContext context, IList hints) + { + var ecc = new ExpressionCompilationContext(context, null, null); + _jsonExpression = Json.Compile(ecc); + _pathExpression = Path?.Compile(ecc); + + Json.GetType(ecc, out var jsonType); + _jsonCollation = (jsonType as SqlDataTypeReferenceWithCollation)?.Collation ?? context.PrimaryDataSource.DefaultCollation; + + return this; + } + + public override INodeSchema GetSchema(NodeCompilationContext context) + { + var columns = new ColumnList(); + var aliases = new Dictionary>(StringComparer.OrdinalIgnoreCase); + + columns.Add(PrefixWithAlias("key", aliases), new ColumnDefinition(DataTypeHelpers.NVarChar(4000, _keyCollation, CollationLabel.Implicit), false, false)); + columns.Add(PrefixWithAlias("value", aliases), new ColumnDefinition(DataTypeHelpers.NVarChar(Int32.MaxValue, _jsonCollation, CollationLabel.Implicit), true, false)); + columns.Add(PrefixWithAlias("type", aliases), new ColumnDefinition(DataTypeHelpers.Int, false, false)); + + var schema = new NodeSchema( + columns, + aliases, + columns.First().Key, + null + ); + + return schema; + } + + private string PrefixWithAlias(string name, IDictionary> aliases) + { + name = name.EscapeIdentifier(); + + if (Alias == null) + return name; + + var fullName = Alias.EscapeIdentifier() + "." + name; + + if (aliases != null) + { + if (!aliases.TryGetValue(name, out var alias)) + { + alias = new List(); + aliases[name] = alias; + } + + ((List)alias).Add(fullName); + } + + return fullName; + } + + public override IEnumerable GetSources() + { + return Array.Empty(); + } + + protected override RowCountEstimate EstimateRowsOutInternal(NodeCompilationContext context) + { + return new RowCountEstimate(10); + } + + protected override IEnumerable ExecuteInternal(NodeExecutionContext context) + { + var eec = new ExpressionExecutionContext(context); + + var json = (SqlString) _jsonExpression(eec); + + if (json.IsNull || json.Value.Length == 0) + yield break; + + string path; + + if (_pathExpression != null) + { + var pathValue = (SqlString)_pathExpression(eec); + + if (pathValue.IsNull) + yield break; + + path = pathValue.Value; + } + else + { + path = "$"; + } + + JsonPath jpath; + JToken jsonDoc; + JToken jtoken; + + try + { + jpath = new JsonPath(path); + jsonDoc = JToken.Parse(json.Value); + jtoken = jpath.Evaluate(jsonDoc); + } + catch (Newtonsoft.Json.JsonException ex) + { + throw new QueryExecutionException(ex.Message, ex); + } + + if (jtoken == null) + { + if (jpath.Mode == JsonPathMode.Lax) + yield break; + else + throw new QueryExecutionException("Property does not exist"); + } + + var keyCol = PrefixWithAlias("key", null); + var valueCol = PrefixWithAlias("value", null); + var typeCol = PrefixWithAlias("type", null); + + if (jtoken.Type == JTokenType.Object) + { + foreach (var prop in ((JObject)jtoken).Properties()) + { + var key = _keyCollation.ToSqlString(prop.Name); + var value = GetValue(prop.Value); + var type = GetType(prop.Value); + + yield return new Entity + { + [keyCol] = key, + [valueCol] = value, + [typeCol] = type + }; + } + } + else if (jtoken.Type == JTokenType.Array) + { + for (var i = 0; i < ((JArray)jtoken).Count; i++) + { + var subToken = ((JArray)jtoken)[i]; + var key = _keyCollation.ToSqlString(i.ToString()); + var value = GetValue(subToken); + var type = GetType(subToken); + + yield return new Entity + { + [keyCol] = key, + [valueCol] = value, + [typeCol] = type + }; + } + } + else + { + if (jpath.Mode == JsonPathMode.Lax) + yield break; + else + throw new QueryExecutionException("Not an object or array"); + } + } + + private SqlString GetValue(JToken token) + { + string str; + + if (token is JContainer) + str = token.ToString(); + else + str = token.Value(); + + return _jsonCollation.ToSqlString(str); + } + + private SqlInt32 GetType(JToken token) + { + switch (token.Type) + { + case JTokenType.Null: + return 0; + + case JTokenType.String: + return 1; + + case JTokenType.Integer: + case JTokenType.Float: + return 2; + + case JTokenType.Boolean: + return 3; + + case JTokenType.Array: + return 4; + + case JTokenType.Object: + return 5; + + default: + throw new QueryExecutionException($"Unexpected token type: {token.Type}"); + } + } + + public override object Clone() + { + return new OpenJsonNode + { + Alias = Alias, + Json = Json.Clone(), + Path = Path.Clone(), + _jsonExpression = _jsonExpression, + _pathExpression = _pathExpression, + _jsonCollation = _jsonCollation + }; + } + } +} diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs index b8bb44f8..3796c6e0 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs @@ -4100,6 +4100,48 @@ private IDataExecutionPlanNodeInternal ConvertTableReference(TableReference refe return loop; } + if (reference is OpenJsonTableReference openJson) + { + // Capture any references to data from an outer query + CaptureOuterReferences(outerSchema, null, openJson, context, outerReferences); + + // Convert any scalar subqueries in the parameters to its own execution plan, and capture the references from those plans + // as parameters to be passed to the function + IDataExecutionPlanNodeInternal source = new ConstantScanNode { Values = { new Dictionary() } }; + var computeScalar = new ComputeScalarNode { Source = source }; + + ConvertScalarSubqueries(openJson.Variable, hints, ref source, computeScalar, context, openJson); + + if (openJson.RowPattern != null) + ConvertScalarSubqueries(openJson.RowPattern, hints, ref source, computeScalar, context, openJson); + + if (source is ConstantScanNode) + source = null; + else if (computeScalar.Columns.Count > 0) + source = computeScalar; + + var scalarSubquerySchema = source?.GetSchema(context); + var scalarSubqueryReferences = new Dictionary(); + CaptureOuterReferences(scalarSubquerySchema, null, openJson, context, scalarSubqueryReferences); + + var execute = new OpenJsonNode(openJson); + + if (source == null) + return execute; + + // If we've got any subquery parameters we need to use a loop to pass them to the function + var loop = new NestedLoopNode + { + LeftSource = source, + RightSource = execute, + JoinType = QualifiedJoinType.Inner, + OuterReferences = scalarSubqueryReferences, + OutputLeftSchema = false, + }; + + return loop; + } + throw new NotSupportedQueryFragmentException("Unhandled table reference", reference); } diff --git a/MarkMpn.Sql4Cds.Engine/ExpressionFunctions.cs b/MarkMpn.Sql4Cds.Engine/ExpressionFunctions.cs index 610b7266..b7210305 100644 --- a/MarkMpn.Sql4Cds.Engine/ExpressionFunctions.cs +++ b/MarkMpn.Sql4Cds.Engine/ExpressionFunctions.cs @@ -58,21 +58,16 @@ public static SqlString Json_Value(SqlString json, SqlString jpath) return SqlString.Null; var path = jpath.Value; - var lax = !path.StartsWith("strict ", StringComparison.OrdinalIgnoreCase); - - if (path.StartsWith("strict ", StringComparison.OrdinalIgnoreCase)) - path = path.Substring(7); - else if (path.StartsWith("lax ", StringComparison.OrdinalIgnoreCase)) - path = path.Substring(4); - + try { + var jsonPath = new JsonPath(path); var jsonDoc = JToken.Parse(json.Value); - var jtoken = jsonDoc.SelectToken(path); + var jtoken = jsonPath.Evaluate(jsonDoc); if (jtoken == null) { - if (lax) + if (jsonPath.Mode == JsonPathMode.Lax) return SqlString.Null; else throw new QueryExecutionException("Property does not exist"); @@ -80,7 +75,7 @@ public static SqlString Json_Value(SqlString json, SqlString jpath) if (jtoken.Type == JTokenType.Object || jtoken.Type == JTokenType.Array) { - if (lax) + if (jsonPath.Mode == JsonPathMode.Lax) return SqlString.Null; else throw new QueryExecutionException("Not a scalar value"); @@ -93,7 +88,7 @@ public static SqlString Json_Value(SqlString json, SqlString jpath) if (value.Length > 4000) { - if (lax) + if (jsonPath.Mode == JsonPathMode.Lax) return SqlString.Null; else throw new QueryExecutionException("Value too long"); @@ -120,16 +115,11 @@ public static SqlBoolean Json_Path_Exists(SqlString json, SqlString jpath) var path = jpath.Value; - if (path.StartsWith("strict ", StringComparison.OrdinalIgnoreCase)) - path = path.Substring(7); - else if (path.StartsWith("lax ", StringComparison.OrdinalIgnoreCase)) - path = path.Substring(4); - try { - + var jsonPath = new JsonPath(path); var jsonDoc = JToken.Parse(json.Value); - var jtoken = jsonDoc.SelectToken(path); + var jtoken = jsonPath.Evaluate(jsonDoc); return jtoken != null; } diff --git a/MarkMpn.Sql4Cds.Engine/JsonPath.cs b/MarkMpn.Sql4Cds.Engine/JsonPath.cs new file mode 100644 index 00000000..a8e1b5d1 --- /dev/null +++ b/MarkMpn.Sql4Cds.Engine/JsonPath.cs @@ -0,0 +1,287 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json.Linq; + +namespace MarkMpn.Sql4Cds.Engine +{ + /// + /// Handles navigating JSON documents using a JSON Path expression + /// + /// + /// The JSON Path syntax supported by SQL Server is subtely different to that implemented by + /// JSON.NET, so to keep compatibility with the various T-SQL samples we need to use this class + /// instead of the built-in method. + /// https://learn.microsoft.com/en-us/sql/relational-databases/json/json-path-expressions-sql-server?view=sql-server-ver16 + /// + class JsonPath + { + private readonly JsonPathPart[] _parts; + private readonly JsonPathMode _mode; + + public JsonPath(string expression) + { + _parts = Parse(expression, out _mode); + } + + /// + /// Returns the mode the path should be evaluated in + /// + public JsonPathMode Mode { get; } + + /// + /// Finds the token matching the path + /// + /// The token to start matching from + /// The token matching the path, or null if no match is found + public JToken Evaluate(JToken token) + { + foreach (var part in _parts) + { + token = part.Match(token); + + if (token == null) + return null; + } + + return token; + } + + private static JsonPathPart[] Parse(string expression, out JsonPathMode mode) + { + mode = JsonPathMode.Lax; + + if (expression.StartsWith("lax ")) + { + expression = expression.Substring(4); + } + else if (expression.StartsWith("strict ")) + { + expression = expression.Substring(7); + mode = JsonPathMode.Strict; + } + + var parts = new List(); + + for (var i = 0; i < expression.Length; i++) + { + if (i == 0 && expression[i] == '$') + { + parts.Add(new ContextJsonPathPart()); + } + else if (expression[i] == '.') + { + // Start of a property key + i++; + + if (i == expression.Length) + throw new Newtonsoft.Json.JsonException($"Invalid JSON path - missing property name after '.' at end of '{expression}'"); + + if (expression[i] == '"') + { + // Start of a quoted property key + i++; + var start = i; + + while (i < expression.Length) + { + if (expression[i] == '\\') + i += 2; + else if (expression[i] == '"') + break; + else + i++; + } + + if (i < expression.Length && expression[i] == '"') + { + var propertyName = expression.Substring(start, i - start).Replace("\\\"", "\"").Replace("\\\\", "\\"); + parts.Add(new PropertyJsonPathPart(propertyName)); + } + } + else if (expression[i] >= 'a' && expression[i] <= 'z' || + expression[i] >= 'A' && expression[i] <= 'Z') + { + // Start of an unquoted property key + var end = expression.IndexOfAny(new[] { '.', '[' }, i); + + if (end == -1) + end = expression.Length; + + var propertyName = expression.Substring(i, end - i); + + if (propertyName == "sql:identity()") + { + if (end == expression.Length) + parts.Add(new ArrayIndexJsonPathPart()); + else + throw new Newtonsoft.Json.JsonException($"Invalid JSON path - sql:identity() function must be the final token of the path'"); + } + + parts.Add(new PropertyJsonPathPart(propertyName)); + i = end - 1; + } + else + { + // Error + throw new Newtonsoft.Json.JsonException($"Invalid JSON path - invalid property name at index {i} of '{expression}'"); + } + } + else if (expression[i] == '[') + { + // Start of an array indexer + var end = expression.IndexOf(']', i); + + if (end == -1) + throw new Newtonsoft.Json.JsonException($"Invalid JSON path - missing closing bracket for indexer at index {i} of '{expression}'"); + + var indexStr = expression.Substring(i + 1, end - i - 1); + + if (!UInt32.TryParse(indexStr, out var index)) + throw new Newtonsoft.Json.JsonException($"Invalid JSON path - invalid indexer at index {i} of '{expression}'"); + + parts.Add(new ArrayElementJsonPathPart(index)); + i = end; + } + else + { + // Error + throw new Newtonsoft.Json.JsonException($"Invalid JSON path - invalid token at index {i} of '{expression}'"); + } + } + + return parts.ToArray(); + } + + public override string ToString() + { + return _mode.ToString().ToLowerInvariant() + " " + String.Join("", _parts.Select(p => p.ToString())); + } + + /// + /// Represents a single token within the path + /// + abstract class JsonPathPart + { + /// + /// Extracts the required child token from the current context token + /// + /// The current context token + /// The child token that is matched by this part of the path + public abstract JToken Match(JToken token); + } + + /// + /// Handles the $ sign representing the context item + /// + class ContextJsonPathPart : JsonPathPart + { + public override JToken Match(JToken token) + { + return token; + } + + public override string ToString() + { + return "$"; + } + } + + /// + /// Handles a property (key) name + /// + class PropertyJsonPathPart : JsonPathPart + { + /// + /// Creates a new + /// + /// The key of the property to extract + public PropertyJsonPathPart(string propertyName) + { + PropertyName = propertyName; + } + + /// + /// Returns the key of the property to extract + /// + public string PropertyName { get; } + + public override JToken Match(JToken token) + { + if (!(token is JObject obj)) + return null; + + var prop = obj.Property(PropertyName); + return prop?.Value; + } + + public override string ToString() + { + if ((PropertyName[0] >= 'a' && PropertyName[0] <= 'z' || PropertyName[0] >= 'A' && PropertyName[0] <= 'Z') + && PropertyName.All(ch => ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch >= '0' && ch <= '9')) + return "." + PropertyName; + + return ".\"" + PropertyName.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\""; + } + } + + /// + /// Handles an array element indexer + /// + class ArrayElementJsonPathPart : JsonPathPart + { + /// + /// Creates a new + /// + /// The index of the array to extract + public ArrayElementJsonPathPart(uint index) + { + Index = (int)index; + } + + /// + /// The index of the array to extract + /// + public int Index { get; } + + public override JToken Match(JToken token) + { + if (!(token is JArray arr) || arr.Count <= Index) + return null; + + return arr[Index]; + } + + public override string ToString() + { + return $"[{Index}]"; + } + } + + /// + /// Handles the sql:identity() function to return the index of an element within it's containing array + /// + class ArrayIndexJsonPathPart : JsonPathPart + { + public override JToken Match(JToken token) + { + if (!(token.Parent is JArray arr)) + return null; + + var index = arr.IndexOf(token); + return new JValue(index); + } + + public override string ToString() + { + return ".sql:identity()"; + } + } + } + + enum JsonPathMode + { + Lax, + Strict + } +} From ccf8cecf83c9256f4b02b78c195163adbc01b456 Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Mon, 13 Nov 2023 08:08:42 +0000 Subject: [PATCH 52/81] Added OPENJSON support using explicit schema --- .../ExecutionPlan/OpenJsonNode.cs | 193 +++++++++++++++--- .../ExecutionPlanBuilder.cs | 2 +- 2 files changed, 169 insertions(+), 26 deletions(-) diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/OpenJsonNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/OpenJsonNode.cs index 757bb13a..ecc0edc0 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/OpenJsonNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/OpenJsonNode.cs @@ -15,6 +15,7 @@ class OpenJsonNode : BaseDataNode private Func _jsonExpression; private Func _pathExpression; private Collation _jsonCollation; + private List> _conversions; private static readonly Collation _keyCollation; @@ -27,13 +28,25 @@ private OpenJsonNode() { } - public OpenJsonNode(OpenJsonTableReference tvf) + public OpenJsonNode(OpenJsonTableReference tvf, NodeCompilationContext context) { Alias = tvf.Alias?.Value; Json = tvf.Variable.Clone(); Path = tvf.RowPattern?.Clone(); + Schema = tvf.SchemaDeclarationItems; // TODO: Check expressions are string types and add conversions if not + + // Validate the schema definition + if (Schema != null) + { + var schema = GetSchema(context); + + var sourceType = DataTypeHelpers.NVarChar(Int32.MaxValue, Collation.USEnglish, CollationLabel.Implicit); + _conversions = schema.Schema + .Select(col => SqlTypeConverter.GetConversion(sourceType, col.Value.Type)) + .ToList(); + } } /// @@ -57,6 +70,12 @@ public OpenJsonNode(OpenJsonTableReference tvf) [Description("The expression that defines the JSON path to the object or array to parse")] public ScalarExpression Path { get; set; } + /// + /// The types of values to be returned + /// + [Browsable(false)] + public IList Schema { get; set; } + public override void AddRequiredColumns(NodeCompilationContext context, IList requiredColumns) { } @@ -78,14 +97,60 @@ public override INodeSchema GetSchema(NodeCompilationContext context) var columns = new ColumnList(); var aliases = new Dictionary>(StringComparer.OrdinalIgnoreCase); - columns.Add(PrefixWithAlias("key", aliases), new ColumnDefinition(DataTypeHelpers.NVarChar(4000, _keyCollation, CollationLabel.Implicit), false, false)); - columns.Add(PrefixWithAlias("value", aliases), new ColumnDefinition(DataTypeHelpers.NVarChar(Int32.MaxValue, _jsonCollation, CollationLabel.Implicit), true, false)); - columns.Add(PrefixWithAlias("type", aliases), new ColumnDefinition(DataTypeHelpers.Int, false, false)); + if (Schema == null) + { + columns.Add(PrefixWithAlias("key", aliases), new ColumnDefinition(DataTypeHelpers.NVarChar(4000, _keyCollation, CollationLabel.Implicit), false, false)); + columns.Add(PrefixWithAlias("value", aliases), new ColumnDefinition(DataTypeHelpers.NVarChar(Int32.MaxValue, _jsonCollation, CollationLabel.Implicit), true, false)); + columns.Add(PrefixWithAlias("type", aliases), new ColumnDefinition(DataTypeHelpers.Int, false, false)); + } + else + { + var columnNames = new HashSet(StringComparer.OrdinalIgnoreCase); + + foreach (var col in Schema) + { + if (!columnNames.Add(col.ColumnDefinition.ColumnIdentifier.Value)) + throw new NotSupportedQueryFragmentException("Duplicate column name", col.ColumnDefinition.ColumnIdentifier); + + var type = col.ColumnDefinition.DataType; + + if (type is SqlDataTypeReference sqlType && sqlType.SqlDataTypeOption.IsStringType()) + { + var collation = context.PrimaryDataSource.DefaultCollation; + + if (col.ColumnDefinition.Collation != null && !Collation.TryParse(col.ColumnDefinition.Collation.Value, out collation)) + throw new NotSupportedQueryFragmentException("Invalid collation", col.ColumnDefinition.Collation); + + type = new SqlDataTypeReferenceWithCollation + { + SqlDataTypeOption = sqlType.SqlDataTypeOption, + Collation = collation, + CollationLabel = col.ColumnDefinition.Collation == null ? CollationLabel.CoercibleDefault : CollationLabel.Implicit + }; + + foreach (var param in sqlType.Parameters) + ((SqlDataTypeReferenceWithCollation)type).Parameters.Add(param); + } + + if (col.AsJson) + { + if (!(type is SqlDataTypeReference nvarcharType) || + nvarcharType.SqlDataTypeOption != SqlDataTypeOption.NVarChar || + nvarcharType.Parameters.Count != 1 || + !(nvarcharType.Parameters[0] is MaxLiteral)) + { + throw new NotSupportedQueryFragmentException("AS JSON column must be of NVARCHAR(max) type", col.ColumnDefinition.DataType); + } + } + + columns.Add(PrefixWithAlias(col.ColumnDefinition.ColumnIdentifier.Value, aliases), new ColumnDefinition(type, true, false)); + } + } var schema = new NodeSchema( columns, aliases, - columns.First().Key, + null, null ); @@ -173,41 +238,66 @@ protected override IEnumerable ExecuteInternal(NodeExecutionContext cont throw new QueryExecutionException("Property does not exist"); } + var schema = GetSchema(context); var keyCol = PrefixWithAlias("key", null); var valueCol = PrefixWithAlias("value", null); var typeCol = PrefixWithAlias("type", null); + JsonPath[] mappings = null; + + if (Schema != null) + { + mappings = Schema + .Select(col => col.Mapping as StringLiteral) + .Select(mapping => mapping == null ? null : new JsonPath(mapping.Value)) + .ToArray(); + } + if (jtoken.Type == JTokenType.Object) { foreach (var prop in ((JObject)jtoken).Properties()) { - var key = _keyCollation.ToSqlString(prop.Name); - var value = GetValue(prop.Value); - var type = GetType(prop.Value); - - yield return new Entity + if (Schema == null) { - [keyCol] = key, - [valueCol] = value, - [typeCol] = type - }; + var key = _keyCollation.ToSqlString(prop.Name); + var value = GetValue(prop.Value); + var type = GetType(prop.Value); + + yield return new Entity + { + [keyCol] = key, + [valueCol] = value, + [typeCol] = type + }; + } + else + { + yield return TokenToEntity(prop.Value, schema, mappings); + } } } else if (jtoken.Type == JTokenType.Array) { for (var i = 0; i < ((JArray)jtoken).Count; i++) { - var subToken = ((JArray)jtoken)[i]; - var key = _keyCollation.ToSqlString(i.ToString()); - var value = GetValue(subToken); - var type = GetType(subToken); - - yield return new Entity + if (Schema == null) { - [keyCol] = key, - [valueCol] = value, - [typeCol] = type - }; + var subToken = ((JArray)jtoken)[i]; + var key = _keyCollation.ToSqlString(i.ToString()); + var value = GetValue(subToken); + var type = GetType(subToken); + + yield return new Entity + { + [keyCol] = key, + [valueCol] = value, + [typeCol] = type + }; + } + else + { + yield return TokenToEntity(((JArray)jtoken)[i], schema, mappings); + } } } else @@ -219,6 +309,57 @@ protected override IEnumerable ExecuteInternal(NodeExecutionContext cont } } + private Entity TokenToEntity(JToken token, INodeSchema schema, JsonPath[] mappings) + { + var result = new Entity(); + + for (var i = 0; i < schema.Schema.Count; i++) + { + var mapping = mappings[i]; + JToken value; + + if (mapping != null) + value = mapping.Evaluate(token); + else if (token is JObject obj) + value = obj.Property(Schema[i].ColumnDefinition.ColumnIdentifier.Value)?.Value; + else + value = null; + + string stringValue; + + if (Schema[i].AsJson) + { + if (value is JArray || value is JObject) + stringValue = value.ToString(); + else if (mapping == null || mapping.Mode == JsonPathMode.Lax) + stringValue = null; + else + throw new QueryExecutionException(""); + } + else + { + if (value is JArray || value is JObject) + { + if (mapping == null || mapping.Mode == JsonPathMode.Lax) + stringValue = null; + else + throw new QueryExecutionException(""); + } + else + { + stringValue = value.Value(); + } + } + + var sqlStringValue = Collation.USEnglish.ToSqlString(stringValue); + var sqlValue = _conversions[i](sqlStringValue); + + result[PrefixWithAlias(Schema[i].ColumnDefinition.ColumnIdentifier.Value, null)] = sqlValue; + } + + return result; + } + private SqlString GetValue(JToken token) { string str; @@ -266,9 +407,11 @@ public override object Clone() Alias = Alias, Json = Json.Clone(), Path = Path.Clone(), + Schema = Schema, _jsonExpression = _jsonExpression, _pathExpression = _pathExpression, - _jsonCollation = _jsonCollation + _jsonCollation = _jsonCollation, + _conversions = _conversions, }; } } diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs index 3796c6e0..7b32d7b5 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs @@ -4124,7 +4124,7 @@ private IDataExecutionPlanNodeInternal ConvertTableReference(TableReference refe var scalarSubqueryReferences = new Dictionary(); CaptureOuterReferences(scalarSubquerySchema, null, openJson, context, scalarSubqueryReferences); - var execute = new OpenJsonNode(openJson); + var execute = new OpenJsonNode(openJson, context); if (source == null) return execute; From 3f87b0591e75516ea0077dad00b28e0976fda10d Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Wed, 15 Nov 2023 08:08:49 +0000 Subject: [PATCH 53/81] Use System.Text.Json instead of Newtonsoft --- .../AdoProviderTests.cs | 75 ++++++ MarkMpn.Sql4Cds.Engine.Tests/JsonPathTests.cs | 226 ++++++++++++++++++ .../MarkMpn.Sql4Cds.Engine.Tests.csproj | 7 + MarkMpn.Sql4Cds.Engine.Tests/app.config | 2 +- .../ExecutionPlan/OpenJsonNode.cs | 124 ++++++---- MarkMpn.Sql4Cds.Engine/ExpressionFunctions.cs | 14 +- MarkMpn.Sql4Cds.Engine/JsonPath.cs | 93 ++++--- 7 files changed, 433 insertions(+), 108 deletions(-) create mode 100644 MarkMpn.Sql4Cds.Engine.Tests/JsonPathTests.cs diff --git a/MarkMpn.Sql4Cds.Engine.Tests/AdoProviderTests.cs b/MarkMpn.Sql4Cds.Engine.Tests/AdoProviderTests.cs index dd5d110b..cc598067 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/AdoProviderTests.cs +++ b/MarkMpn.Sql4Cds.Engine.Tests/AdoProviderTests.cs @@ -1607,5 +1607,80 @@ DECLARE @json NVARCHAR(4000) = N'{ } } } + + [TestMethod] + public void OpenJsonExplicitSchema() + { + using (var con = new Sql4CdsConnection(_localDataSource)) + using (var cmd = con.CreateCommand()) + { + cmd.CommandText = @" +DECLARE @json NVARCHAR(MAX) = N'[ + { + ""Order"": { + ""Number"":""SO43659"", + ""Date"":""2011-05-31T00:00:00"" + }, + ""AccountNumber"":""AW29825"", + ""Item"": { + ""Price"":2024.9940, + ""Quantity"":1 + } + }, + { + ""Order"": { + ""Number"":""SO43661"", + ""Date"":""2011-06-01T00:00:00"" + }, + ""AccountNumber"":""AW73565"", + ""Item"": { + ""Price"":2024.9940, + ""Quantity"":3 + } + } +]' + +SELECT * +FROM OPENJSON ( @json ) +WITH ( + Number VARCHAR(200) '$.Order.Number', + Date DATETIME '$.Order.Date', + Customer VARCHAR(200) '$.AccountNumber', + Quantity INT '$.Item.Quantity', + [Order] NVARCHAR(MAX) AS JSON + )"; + + using (var reader = cmd.ExecuteReader()) + { + Assert.AreEqual("Number", reader.GetName(0)); + Assert.AreEqual("Date", reader.GetName(1)); + Assert.AreEqual("Customer", reader.GetName(2)); + Assert.AreEqual("Quantity", reader.GetName(3)); + Assert.AreEqual("Order", reader.GetName(4)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("SO43659", reader.GetString(0)); + Assert.AreEqual(new DateTime(2011, 5, 31), reader.GetDateTime(1)); + Assert.AreEqual("AW29825", reader.GetString(2)); + Assert.AreEqual(1, reader.GetInt32(3)); + Assert.AreEqual(@"{ + ""Number"": ""SO43659"", + ""Date"": ""2011-05-31T00:00:00"" +}", reader.GetString(4)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("SO43661", reader.GetString(0)); + Assert.AreEqual(new DateTime(2011, 6, 1), reader.GetDateTime(1)); + Assert.AreEqual("AW73565", reader.GetString(2)); + Assert.AreEqual(3, reader.GetInt32(3)); + Assert.AreEqual(@"{ + ""Number"": ""SO43661"", + ""Date"": ""2011-06-01T00:00:00"" +}", reader.GetString(4)); + + Assert.IsFalse(reader.Read()); + } + } + } } } diff --git a/MarkMpn.Sql4Cds.Engine.Tests/JsonPathTests.cs b/MarkMpn.Sql4Cds.Engine.Tests/JsonPathTests.cs new file mode 100644 index 00000000..bd67eab9 --- /dev/null +++ b/MarkMpn.Sql4Cds.Engine.Tests/JsonPathTests.cs @@ -0,0 +1,226 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace MarkMpn.Sql4Cds.Engine.Tests +{ + [TestClass] + public class JsonPathTests + { + [TestMethod] + public void DollarOnly() + { + var path = new JsonPath("$"); + + var json = JsonDocument.Parse(@" +{ + ""path"": { + ""to"": { + ""sub-object"": ""hello world"" + } + } +}"); + + var value = path.Evaluate(json.RootElement); + Assert.AreEqual(value, json.RootElement); + } + + [TestMethod] + public void QuotedPropertyName() + { + var path = new JsonPath("$.path.to.\"sub-object\""); + + var json = JsonDocument.Parse(@" +{ + ""path"": { + ""to"": { + ""sub-object"": ""hello world"" + } + } +}"); + + var value = path.Evaluate(json.RootElement); + Assert.AreEqual("hello world", value.Value.GetString()); + } + + [TestMethod] + public void DuplicatePathsReturnsFirstMatch() + { + var path = new JsonPath("$.person.name"); + + var json = JsonDocument.Parse(@" +{ + ""person"": { + ""name"": ""Mark"", + ""name"": ""Carrington"" + } +}"); + + var value = path.Evaluate(json.RootElement); + Assert.AreEqual("Mark", value.Value.GetString()); + } + + [TestMethod] + public void DefaultModeLax() + { + var path = new JsonPath("$.path.to.\"sub-object\""); + Assert.AreEqual(JsonPathMode.Lax, path.Mode); + } + + [TestMethod] + public void ExplicitModeLax() + { + var path = new JsonPath("lax $.path.to.\"sub-object\""); + Assert.AreEqual(JsonPathMode.Lax, path.Mode); + } + + [TestMethod] + public void ExplicitModeStrict() + { + var path = new JsonPath("strict $.path.to.\"sub-object\""); + Assert.AreEqual(JsonPathMode.Lax, path.Mode); + } + + [TestMethod] + [ExpectedException(typeof(JsonException))] + public void FailsOnUnknownMode() + { + new JsonPath("laxtrict $.path.to.\"sub-object\""); + } + + [TestMethod] + [ExpectedException(typeof(JsonException))] + public void FailsOnExtraQuotes() + { + new JsonPath("laxtrict $.path.to.\"\"sub-object\"\""); + } + + [TestMethod] + [ExpectedException(typeof(JsonException))] + public void FailsOnMissingLeadingDollar() + { + new JsonPath("path.to.\"sub-object\""); + } + + [TestMethod] + [ExpectedException(typeof(JsonException))] + public void FailsOnDoublePeriod() + { + new JsonPath("$.path..to.\"sub-object\""); + } + + [TestMethod] + [ExpectedException(typeof(JsonException))] + public void FailsOnTrailingPeriod() + { + new JsonPath("$.path.to.\"sub-object\"."); + } + + [TestMethod] + public void ArrayIndexer() + { + var path = new JsonPath("$.path.to.\"sub-object\"[1]"); + + var json = JsonDocument.Parse(@" +{ + ""path"": { + ""to"": { + ""sub-object"": [ ""hello"", ""world"" ] + } + } +}"); + + var value = path.Evaluate(json.RootElement); + Assert.AreEqual("world", value.Value.GetString()); + } + + [TestMethod] + [ExpectedException(typeof(JsonException))] + public void FailsOnNegativeIndexer() + { + new JsonPath("$.path.to.\"sub-object\"[-1]"); + } + + [TestMethod] + [ExpectedException(typeof(JsonException))] + public void FailsOnAlphaIndexer() + { + new JsonPath("$.path.to.\"sub-object\"[x]"); + } + + [TestMethod] + [ExpectedException(typeof(JsonException))] + public void FailsOnMissingCloseBracket() + { + new JsonPath("$.path.to.\"sub-object\"[1"); + } + + [TestMethod] + [ExpectedException(typeof(JsonException))] + public void FailsOnMissingOpeningBracket() + { + new JsonPath("$.path.to1]"); + } + + [TestMethod] + public void NestedArrayIndexer() + { + var path = new JsonPath("$.path.to.\"sub-object\"[1][0]"); + + var json = JsonDocument.Parse(@" +{ + ""path"": { + ""to"": { + ""sub-object"": [ [ ""hel"", ""lo"" ], [ ""wor"", ""ld"" ] ] + } + } +}"); + + var value = path.Evaluate(json.RootElement); + Assert.AreEqual("wor", value.Value.GetString()); + } + + [TestMethod] + [ExpectedException(typeof(JsonException))] + public void FailsOnDollarNotAtStart() + { + new JsonPath("$.path.$.to"); + } + + [TestMethod] + [ExpectedException(typeof(JsonException))] + public void FailsOnUnquotedDollar() + { + new JsonPath("$.path$"); + } + + [TestMethod] + [ExpectedException(typeof(JsonException))] + public void FailsOnLeadingNumber() + { + new JsonPath("$.1path"); + } + + [TestMethod] + public void TrailingNumber() + { + var path = new JsonPath("$.path1.to2.\"sub-object\""); + + var json = JsonDocument.Parse(@" +{ + ""path1"": { + ""to2"": { + ""sub-object"": ""hello world"" + } + } +}"); + + var value = path.Evaluate(json.RootElement); + Assert.AreEqual("hello world", value.Value.GetString()); + } + } +} diff --git a/MarkMpn.Sql4Cds.Engine.Tests/MarkMpn.Sql4Cds.Engine.Tests.csproj b/MarkMpn.Sql4Cds.Engine.Tests/MarkMpn.Sql4Cds.Engine.Tests.csproj index 7190c955..b654cc8a 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/MarkMpn.Sql4Cds.Engine.Tests.csproj +++ b/MarkMpn.Sql4Cds.Engine.Tests/MarkMpn.Sql4Cds.Engine.Tests.csproj @@ -82,6 +82,7 @@ + @@ -124,6 +125,12 @@ 3.0.2 + + 6.0.0 + + + 6.0.7 + diff --git a/MarkMpn.Sql4Cds.Engine.Tests/app.config b/MarkMpn.Sql4Cds.Engine.Tests/app.config index 1de11e40..8a0f6cf2 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/app.config +++ b/MarkMpn.Sql4Cds.Engine.Tests/app.config @@ -16,7 +16,7 @@ - + diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/OpenJsonNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/OpenJsonNode.cs index ecc0edc0..3626cc7b 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/OpenJsonNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/OpenJsonNode.cs @@ -4,9 +4,9 @@ using System.Data.SqlTypes; using System.Linq; using System.Text; +using System.Text.Json; using Microsoft.SqlServer.TransactSql.ScriptDom; using Microsoft.Xrm.Sdk; -using Newtonsoft.Json.Linq; namespace MarkMpn.Sql4Cds.Engine.ExecutionPlan { @@ -33,15 +33,21 @@ public OpenJsonNode(OpenJsonTableReference tvf, NodeCompilationContext context) Alias = tvf.Alias?.Value; Json = tvf.Variable.Clone(); Path = tvf.RowPattern?.Clone(); - Schema = tvf.SchemaDeclarationItems; + Schema = tvf.SchemaDeclarationItems.Count == 0 ? null : tvf.SchemaDeclarationItems; - // TODO: Check expressions are string types and add conversions if not + // Check expressions are string types and add conversions if not + var ecc = new ExpressionCompilationContext(context, null, null); + if (Json.GetType(ecc, out _) != typeof(SqlString)) + Json = new ConvertCall { Parameter = Json, DataType = DataTypeHelpers.NVarChar(Int32.MaxValue, context.PrimaryDataSource.DefaultCollation, CollationLabel.CoercibleDefault) }; + if (Path != null && Path.GetType(ecc, out _) != typeof(SqlString)) + Path = new ConvertCall { Parameter = Path, DataType = DataTypeHelpers.NVarChar(Int32.MaxValue, context.PrimaryDataSource.DefaultCollation, CollationLabel.CoercibleDefault) }; // Validate the schema definition if (Schema != null) { var schema = GetSchema(context); + // Set up the conversion functions to convert the string values extracted from the JSON to the type defined in the schema var sourceType = DataTypeHelpers.NVarChar(Int32.MaxValue, Collation.USEnglish, CollationLabel.Implicit); _conversions = schema.Schema .Select(col => SqlTypeConverter.GetConversion(sourceType, col.Value.Type)) @@ -105,13 +111,8 @@ public override INodeSchema GetSchema(NodeCompilationContext context) } else { - var columnNames = new HashSet(StringComparer.OrdinalIgnoreCase); - foreach (var col in Schema) { - if (!columnNames.Add(col.ColumnDefinition.ColumnIdentifier.Value)) - throw new NotSupportedQueryFragmentException("Duplicate column name", col.ColumnDefinition.ColumnIdentifier); - var type = col.ColumnDefinition.DataType; if (type is SqlDataTypeReference sqlType && sqlType.SqlDataTypeOption.IsStringType()) @@ -139,7 +140,7 @@ public override INodeSchema GetSchema(NodeCompilationContext context) nvarcharType.Parameters.Count != 1 || !(nvarcharType.Parameters[0] is MaxLiteral)) { - throw new NotSupportedQueryFragmentException("AS JSON column must be of NVARCHAR(max) type", col.ColumnDefinition.DataType); + throw new NotSupportedQueryFragmentException("AS JSON option can be specified only for column of nvarchar(max) type in WITH clause", col.ColumnDefinition.DataType); } } @@ -216,16 +217,16 @@ protected override IEnumerable ExecuteInternal(NodeExecutionContext cont } JsonPath jpath; - JToken jsonDoc; - JToken jtoken; + JsonElement jsonDoc; + JsonElement? jtoken; try { jpath = new JsonPath(path); - jsonDoc = JToken.Parse(json.Value); + jsonDoc = JsonDocument.Parse(json.Value).RootElement; jtoken = jpath.Evaluate(jsonDoc); } - catch (Newtonsoft.Json.JsonException ex) + catch (JsonException ex) { throw new QueryExecutionException(ex.Message, ex); } @@ -253,14 +254,14 @@ protected override IEnumerable ExecuteInternal(NodeExecutionContext cont .ToArray(); } - if (jtoken.Type == JTokenType.Object) + if (jtoken.Value.ValueKind == JsonValueKind.Object) { - foreach (var prop in ((JObject)jtoken).Properties()) + foreach (var prop in jtoken.Value.EnumerateObject()) { if (Schema == null) { var key = _keyCollation.ToSqlString(prop.Name); - var value = GetValue(prop.Value); + var value = _jsonCollation.ToSqlString(GetValue(prop.Value)); var type = GetType(prop.Value); yield return new Entity @@ -276,16 +277,17 @@ protected override IEnumerable ExecuteInternal(NodeExecutionContext cont } } } - else if (jtoken.Type == JTokenType.Array) + else if (jtoken.Value.ValueKind == JsonValueKind.Array) { - for (var i = 0; i < ((JArray)jtoken).Count; i++) + var i = 0; + + foreach (var item in jtoken.Value.EnumerateArray()) { if (Schema == null) { - var subToken = ((JArray)jtoken)[i]; var key = _keyCollation.ToSqlString(i.ToString()); - var value = GetValue(subToken); - var type = GetType(subToken); + var value = _jsonCollation.ToSqlString(GetValue(item)); + var type = GetType(item); yield return new Entity { @@ -296,8 +298,10 @@ protected override IEnumerable ExecuteInternal(NodeExecutionContext cont } else { - yield return TokenToEntity(((JArray)jtoken)[i], schema, mappings); + yield return TokenToEntity(item, schema, mappings); } + + i++; } } else @@ -309,45 +313,56 @@ protected override IEnumerable ExecuteInternal(NodeExecutionContext cont } } - private Entity TokenToEntity(JToken token, INodeSchema schema, JsonPath[] mappings) + private Entity TokenToEntity(JsonElement token, INodeSchema schema, JsonPath[] mappings) { var result = new Entity(); for (var i = 0; i < schema.Schema.Count; i++) { var mapping = mappings[i]; - JToken value; + JsonElement? value; if (mapping != null) + { value = mapping.Evaluate(token); - else if (token is JObject obj) - value = obj.Property(Schema[i].ColumnDefinition.ColumnIdentifier.Value)?.Value; + } + else if (token.ValueKind == JsonValueKind.Object) + { + if (token.TryGetProperty(Schema[i].ColumnDefinition.ColumnIdentifier.Value, out var prop)) + value = prop; + else + value = null; + } else + { value = null; + } string stringValue; if (Schema[i].AsJson) { - if (value is JArray || value is JObject) - stringValue = value.ToString(); + if (value?.ValueKind == JsonValueKind.Array || value?.ValueKind == JsonValueKind.Object) + stringValue = value.Value.ToString(); else if (mapping == null || mapping.Mode == JsonPathMode.Lax) stringValue = null; else - throw new QueryExecutionException(""); + throw new QueryExecutionException("Object or array cannot be found in the specified JSON path"); } else { - if (value is JArray || value is JObject) + if (value?.ValueKind == JsonValueKind.Array || value?.ValueKind == JsonValueKind.Object || value == null) { if (mapping == null || mapping.Mode == JsonPathMode.Lax) stringValue = null; + else if (value == null) + throw new QueryExecutionException("Property cannot be found on the specified JSON path"); else - throw new QueryExecutionException(""); + throw new QueryExecutionException("Object or array cannot be found in the specified JSON path"); } else { - stringValue = value.Value(); + stringValue = GetValue(value.Value); } } @@ -360,43 +375,54 @@ private Entity TokenToEntity(JToken token, INodeSchema schema, JsonPath[] mappin return result; } - private SqlString GetValue(JToken token) + private string GetValue(JsonElement token) { - string str; + switch (token.ValueKind) + { + case JsonValueKind.Object: + case JsonValueKind.Array: + return token.ToString(); - if (token is JContainer) - str = token.ToString(); - else - str = token.Value(); + case JsonValueKind.String: + return token.GetString(); - return _jsonCollation.ToSqlString(str); + case JsonValueKind.Number: + return token.GetDecimal().ToString(); + + case JsonValueKind.True: + case JsonValueKind.False: + return token.GetBoolean() ? "true" : "false"; + + default: + return null; + } } - private SqlInt32 GetType(JToken token) + private SqlInt32 GetType(JsonElement token) { - switch (token.Type) + switch (token.ValueKind) { - case JTokenType.Null: + case JsonValueKind.Null: return 0; - case JTokenType.String: + case JsonValueKind.String: return 1; - case JTokenType.Integer: - case JTokenType.Float: + case JsonValueKind.Number: return 2; - case JTokenType.Boolean: + case JsonValueKind.True: + case JsonValueKind.False: return 3; - case JTokenType.Array: + case JsonValueKind.Array: return 4; - case JTokenType.Object: + case JsonValueKind.Object: return 5; default: - throw new QueryExecutionException($"Unexpected token type: {token.Type}"); + throw new QueryExecutionException($"Unexpected token type: {token.ValueKind}"); } } diff --git a/MarkMpn.Sql4Cds.Engine/ExpressionFunctions.cs b/MarkMpn.Sql4Cds.Engine/ExpressionFunctions.cs index b7210305..c1716f46 100644 --- a/MarkMpn.Sql4Cds.Engine/ExpressionFunctions.cs +++ b/MarkMpn.Sql4Cds.Engine/ExpressionFunctions.cs @@ -3,7 +3,6 @@ using Microsoft.SqlServer.TransactSql.ScriptDom; using Microsoft.VisualBasic; using Microsoft.Xrm.Sdk; -using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Data.SqlTypes; @@ -18,6 +17,7 @@ using System.Xml.XPath; using Wmhelp.XPath2; using Wmhelp.XPath2.Value; +using System.Text.Json; #if NETCOREAPP using Microsoft.PowerPlatform.Dataverse.Client; #else @@ -62,8 +62,8 @@ public static SqlString Json_Value(SqlString json, SqlString jpath) try { var jsonPath = new JsonPath(path); - var jsonDoc = JToken.Parse(json.Value); - var jtoken = jsonPath.Evaluate(jsonDoc); + var jsonDoc = JsonDocument.Parse(json.Value); + var jtoken = jsonPath.Evaluate(jsonDoc.RootElement); if (jtoken == null) { @@ -73,7 +73,7 @@ public static SqlString Json_Value(SqlString json, SqlString jpath) throw new QueryExecutionException("Property does not exist"); } - if (jtoken.Type == JTokenType.Object || jtoken.Type == JTokenType.Array) + if (jtoken.Value.ValueKind == JsonValueKind.Object || jtoken.Value.ValueKind == JsonValueKind.Array) { if (jsonPath.Mode == JsonPathMode.Lax) return SqlString.Null; @@ -81,7 +81,7 @@ public static SqlString Json_Value(SqlString json, SqlString jpath) throw new QueryExecutionException("Not a scalar value"); } - var value = jtoken.Value(); + var value = jtoken.Value.GetString(); if (value == null) return SqlString.Null; @@ -118,8 +118,8 @@ public static SqlBoolean Json_Path_Exists(SqlString json, SqlString jpath) try { var jsonPath = new JsonPath(path); - var jsonDoc = JToken.Parse(json.Value); - var jtoken = jsonPath.Evaluate(jsonDoc); + var jsonDoc = JsonDocument.Parse(json.Value); + var jtoken = jsonPath.Evaluate(jsonDoc.RootElement); return jtoken != null; } diff --git a/MarkMpn.Sql4Cds.Engine/JsonPath.cs b/MarkMpn.Sql4Cds.Engine/JsonPath.cs index a8e1b5d1..7bc9a236 100644 --- a/MarkMpn.Sql4Cds.Engine/JsonPath.cs +++ b/MarkMpn.Sql4Cds.Engine/JsonPath.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; -using Newtonsoft.Json.Linq; +using System.Text.Json; namespace MarkMpn.Sql4Cds.Engine { @@ -34,14 +34,16 @@ public JsonPath(string expression) /// /// The token to start matching from /// The token matching the path, or null if no match is found - public JToken Evaluate(JToken token) + public JsonElement? Evaluate(JsonElement token) { foreach (var part in _parts) { - token = part.Match(token); + var match = part.Match(token); - if (token == null) + if (match == null) return null; + + token = match.Value; } return token; @@ -69,13 +71,13 @@ private static JsonPathPart[] Parse(string expression, out JsonPathMode mode) { parts.Add(new ContextJsonPathPart()); } - else if (expression[i] == '.') + else if (i > 0 && expression[i] == '.') { // Start of a property key i++; if (i == expression.Length) - throw new Newtonsoft.Json.JsonException($"Invalid JSON path - missing property name after '.' at end of '{expression}'"); + throw new JsonException($"Invalid JSON path - missing property name after '.' at end of '{expression}'"); if (expression[i] == '"') { @@ -103,28 +105,32 @@ private static JsonPathPart[] Parse(string expression, out JsonPathMode mode) expression[i] >= 'A' && expression[i] <= 'Z') { // Start of an unquoted property key - var end = expression.IndexOfAny(new[] { '.', '[' }, i); - - if (end == -1) - end = expression.Length; - - var propertyName = expression.Substring(i, end - i); + var start = i; - if (propertyName == "sql:identity()") + while (i < expression.Length) { - if (end == expression.Length) - parts.Add(new ArrayIndexJsonPathPart()); + if (expression[i] >= 'a' && expression[i] <= 'z' || + expression[i] >= 'A' && expression[i] <= 'Z' || + expression[i] >= '0' && expression[i] <= '9') + { + i++; + } else - throw new Newtonsoft.Json.JsonException($"Invalid JSON path - sql:identity() function must be the final token of the path'"); + { + break; + } } + var propertyName = expression.Substring(start, i - start); parts.Add(new PropertyJsonPathPart(propertyName)); - i = end - 1; + + if (i < expression.Length) + i--; } else { // Error - throw new Newtonsoft.Json.JsonException($"Invalid JSON path - invalid property name at index {i} of '{expression}'"); + throw new JsonException($"Invalid JSON path - invalid property name at index {i} of '{expression}'"); } } else if (expression[i] == '[') @@ -133,20 +139,20 @@ private static JsonPathPart[] Parse(string expression, out JsonPathMode mode) var end = expression.IndexOf(']', i); if (end == -1) - throw new Newtonsoft.Json.JsonException($"Invalid JSON path - missing closing bracket for indexer at index {i} of '{expression}'"); + throw new JsonException($"Invalid JSON path - missing closing bracket for indexer at index {i} of '{expression}'"); var indexStr = expression.Substring(i + 1, end - i - 1); if (!UInt32.TryParse(indexStr, out var index)) - throw new Newtonsoft.Json.JsonException($"Invalid JSON path - invalid indexer at index {i} of '{expression}'"); + throw new JsonException($"Invalid JSON path - invalid indexer at index {i} of '{expression}'"); parts.Add(new ArrayElementJsonPathPart(index)); - i = end; + i = end ; } else { // Error - throw new Newtonsoft.Json.JsonException($"Invalid JSON path - invalid token at index {i} of '{expression}'"); + throw new JsonException($"JSON path is not properly formatted. Unexpected character '{expression[i]}' is found at position {i}"); } } @@ -168,7 +174,7 @@ abstract class JsonPathPart /// /// The current context token /// The child token that is matched by this part of the path - public abstract JToken Match(JToken token); + public abstract JsonElement? Match(JsonElement token); } /// @@ -176,7 +182,7 @@ abstract class JsonPathPart /// class ContextJsonPathPart : JsonPathPart { - public override JToken Match(JToken token) + public override JsonElement? Match(JsonElement token) { return token; } @@ -206,13 +212,18 @@ public PropertyJsonPathPart(string propertyName) /// public string PropertyName { get; } - public override JToken Match(JToken token) + public override JsonElement? Match(JsonElement token) { - if (!(token is JObject obj)) + if (token.ValueKind != JsonValueKind.Object) return null; - var prop = obj.Property(PropertyName); - return prop?.Value; + foreach (var prop in token.EnumerateObject()) + { + if (prop.NameEquals(PropertyName)) + return prop.Value; + } + + return null; } public override string ToString() @@ -244,12 +255,12 @@ public ArrayElementJsonPathPart(uint index) /// public int Index { get; } - public override JToken Match(JToken token) + public override JsonElement? Match(JsonElement token) { - if (!(token is JArray arr) || arr.Count <= Index) + if (token.ValueKind != JsonValueKind.Array || token.GetArrayLength() < Index) return null; - return arr[Index]; + return token[Index]; } public override string ToString() @@ -257,26 +268,6 @@ public override string ToString() return $"[{Index}]"; } } - - /// - /// Handles the sql:identity() function to return the index of an element within it's containing array - /// - class ArrayIndexJsonPathPart : JsonPathPart - { - public override JToken Match(JToken token) - { - if (!(token.Parent is JArray arr)) - return null; - - var index = arr.IndexOf(token); - return new JValue(index); - } - - public override string ToString() - { - return ".sql:identity()"; - } - } } enum JsonPathMode From 4c077cac7ee1253d3d66042fb3de93d773d4e951 Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Wed, 15 Nov 2023 08:13:59 +0000 Subject: [PATCH 54/81] Updated expected whitespace --- .../AdoProviderTests.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/MarkMpn.Sql4Cds.Engine.Tests/AdoProviderTests.cs b/MarkMpn.Sql4Cds.Engine.Tests/AdoProviderTests.cs index cc598067..3d43beb2 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/AdoProviderTests.cs +++ b/MarkMpn.Sql4Cds.Engine.Tests/AdoProviderTests.cs @@ -1552,7 +1552,7 @@ DECLARE @json NVARCHAR(MAX) Assert.IsTrue(reader.Read()); Assert.AreEqual("skills", reader.GetString(0)); - Assert.AreEqual("[\r\n \"SQL\",\r\n \"C#\",\r\n \"MVC\"\r\n]", reader.GetString(1)); + Assert.AreEqual("[\"SQL\",\"C#\",\"MVC\"]", reader.GetString(1)); Assert.AreEqual(4, reader.GetInt32(2)); Assert.IsFalse(reader.Read()); @@ -1663,20 +1663,20 @@ [Order] NVARCHAR(MAX) AS JSON Assert.AreEqual(new DateTime(2011, 5, 31), reader.GetDateTime(1)); Assert.AreEqual("AW29825", reader.GetString(2)); Assert.AreEqual(1, reader.GetInt32(3)); - Assert.AreEqual(@"{ - ""Number"": ""SO43659"", - ""Date"": ""2011-05-31T00:00:00"" -}", reader.GetString(4)); + Assert.AreEqual(@"{ + ""Number"":""SO43659"", + ""Date"":""2011-05-31T00:00:00"" + }", reader.GetString(4)); Assert.IsTrue(reader.Read()); Assert.AreEqual("SO43661", reader.GetString(0)); Assert.AreEqual(new DateTime(2011, 6, 1), reader.GetDateTime(1)); Assert.AreEqual("AW73565", reader.GetString(2)); Assert.AreEqual(3, reader.GetInt32(3)); - Assert.AreEqual(@"{ - ""Number"": ""SO43661"", - ""Date"": ""2011-06-01T00:00:00"" -}", reader.GetString(4)); + Assert.AreEqual(@"{ + ""Number"":""SO43661"", + ""Date"":""2011-06-01T00:00:00"" + }", reader.GetString(4)); Assert.IsFalse(reader.Read()); } From c7c5b8104d1ed956129b1d6d35c24fe7e187931e Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Wed, 15 Nov 2023 08:29:54 +0000 Subject: [PATCH 55/81] Handle subquery alias as source for defined values in join --- .../AdoProviderTests.cs | 117 ++++++++++++++++++ .../ExecutionPlan/BaseJoinNode.cs | 17 ++- .../ExecutionPlan/FoldableJoinNode.cs | 10 +- .../ExecutionPlan/NestedLoopNode.cs | 3 + 4 files changed, 144 insertions(+), 3 deletions(-) diff --git a/MarkMpn.Sql4Cds.Engine.Tests/AdoProviderTests.cs b/MarkMpn.Sql4Cds.Engine.Tests/AdoProviderTests.cs index 3d43beb2..a407002a 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/AdoProviderTests.cs +++ b/MarkMpn.Sql4Cds.Engine.Tests/AdoProviderTests.cs @@ -1608,6 +1608,77 @@ DECLARE @json NVARCHAR(4000) = N'{ } } + [TestMethod] + public void OpenJsonDefaultSchemaDataTypes() + { + using (var con = new Sql4CdsConnection(_localDataSource)) + using (var cmd = con.CreateCommand()) + { + cmd.CommandText = @" +DECLARE @json NVARCHAR(2048) = N'{ + ""String_value"": ""John"", + ""DoublePrecisionFloatingPoint_value"": 45, + ""DoublePrecisionFloatingPoint_value"": 2.3456, + ""BooleanTrue_value"": true, + ""BooleanFalse_value"": false, + ""Null_value"": null, + ""Array_value"": [""a"",""r"",""r"",""a"",""y""], + ""Object_value"": {""obj"":""ect""} +}'; + +SELECT * FROM OpenJson(@json);"; + + using (var reader = cmd.ExecuteReader()) + { + Assert.AreEqual("key", reader.GetName(0)); + Assert.AreEqual("value", reader.GetName(1)); + Assert.AreEqual("type", reader.GetName(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("String_value", reader.GetString(0)); + Assert.AreEqual("John", reader.GetString(1)); + Assert.AreEqual(1, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("DoublePrecisionFloatingPoint_value", reader.GetString(0)); + Assert.AreEqual("45", reader.GetString(1)); + Assert.AreEqual(2, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("DoublePrecisionFloatingPoint_value", reader.GetString(0)); + Assert.AreEqual("2.3456", reader.GetString(1)); + Assert.AreEqual(2, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("BooleanTrue_value", reader.GetString(0)); + Assert.AreEqual("true", reader.GetString(1)); + Assert.AreEqual(3, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("BooleanFalse_value", reader.GetString(0)); + Assert.AreEqual("false", reader.GetString(1)); + Assert.AreEqual(3, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("Null_value", reader.GetString(0)); + Assert.IsTrue(reader.IsDBNull(1)); + Assert.AreEqual(0, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("Array_value", reader.GetString(0)); + Assert.AreEqual("[\"a\",\"r\",\"r\",\"a\",\"y\"]", reader.GetString(1)); + Assert.AreEqual(4, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("Object_value", reader.GetString(0)); + Assert.AreEqual("{\"obj\":\"ect\"}", reader.GetString(1)); + Assert.AreEqual(5, reader.GetInt32(2)); + + Assert.IsFalse(reader.Read()); + } + } + } + [TestMethod] public void OpenJsonExplicitSchema() { @@ -1682,5 +1753,51 @@ [Order] NVARCHAR(MAX) AS JSON } } } + + [TestMethod] + public void MergeJson() + { + using (var con = new Sql4CdsConnection(_localDataSource)) + using (var cmd = con.CreateCommand()) + { + cmd.CommandText = @" +DECLARE @json1 NVARCHAR(MAX),@json2 NVARCHAR(MAX) + +SET @json1=N'{""name"": ""John"", ""surname"":""Doe""}' + +SET @json2=N'{""name"": ""John"", ""age"":45}' + +SELECT * +FROM OPENJSON(@json1) +UNION ALL +SELECT * +FROM OPENJSON(@json2) +WHERE [key] NOT IN (SELECT [key] FROM OPENJSON(@json1))"; + + using (var reader = cmd.ExecuteReader()) + { + Assert.AreEqual("key", reader.GetName(0)); + Assert.AreEqual("value", reader.GetName(1)); + Assert.AreEqual("type", reader.GetName(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("name", reader.GetString(0)); + Assert.AreEqual("John", reader.GetString(1)); + Assert.AreEqual(1, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("surname", reader.GetString(0)); + Assert.AreEqual("Doe", reader.GetString(1)); + Assert.AreEqual(1, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("age", reader.GetString(0)); + Assert.AreEqual("45", reader.GetString(1)); + Assert.AreEqual(2, reader.GetInt32(2)); + + Assert.IsFalse(reader.Read()); + } + } + } } } diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BaseJoinNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BaseJoinNode.cs index 2a9afed2..5c85ec19 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BaseJoinNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BaseJoinNode.cs @@ -112,6 +112,18 @@ protected Entity Merge(Entity leftEntity, INodeSchema leftSchema, Entity rightEn return merged; } + protected void FoldDefinedValues(INodeSchema rightSchema) + { + foreach (var kvp in DefinedValues.ToList()) + { + if (!rightSchema.ContainsColumn(kvp.Value, out var innerColumn)) + throw new NotSupportedQueryFragmentException($"Unknown defined column '{kvp.Value}'"); + + if (innerColumn != kvp.Value) + DefinedValues[kvp.Key] = innerColumn; + } + } + public override IEnumerable GetSources() { yield return LeftSource; @@ -172,7 +184,10 @@ protected virtual INodeSchema GetSchema(NodeCompilationContext context, bool inc } foreach (var definedValue in DefinedValues) - schema[definedValue.Key] = innerSchema.Schema[definedValue.Value]; + { + innerSchema.ContainsColumn(definedValue.Value, out var innerColumn); + schema[definedValue.Key] = innerSchema.Schema[innerColumn]; + } _lastLeftSchema = outerSchema; _lastRightSchema = innerSchema; diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FoldableJoinNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FoldableJoinNode.cs index 96c21080..11a3894b 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FoldableJoinNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FoldableJoinNode.cs @@ -56,11 +56,14 @@ public override IDataExecutionPlanNodeInternal FoldQuery(NodeCompilationContext RightSource = RightSource.FoldQuery(context, hints); RightSource.Parent = this; + var leftSchema = LeftSource.GetSchema(context); + var rightSchema = RightSource.GetSchema(context); + + FoldDefinedValues(rightSchema); + if (SemiJoin) return this; - var leftSchema = LeftSource.GetSchema(context); - var rightSchema = RightSource.GetSchema(context); var leftFilter = JoinType == QualifiedJoinType.Inner || JoinType == QualifiedJoinType.LeftOuter ? LeftSource as FilterNode : null; var rightFilter = JoinType == QualifiedJoinType.Inner || JoinType == QualifiedJoinType.RightOuter ? RightSource as FilterNode : null; var leftFetch = (leftFilter?.Source ?? LeftSource) as FetchXmlScan; @@ -685,9 +688,12 @@ public override void AddRequiredColumns(NodeCompilationContext context, IList leftSchema.ContainsColumn(col, out _)) + .Distinct() .ToList(); var rightColumns = requiredColumns .Where(col => rightSchema.ContainsColumn(col, out _)) + .Concat(DefinedValues.Values) + .Distinct() .ToList(); if (LeftAttribute != null) diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/NestedLoopNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/NestedLoopNode.cs index 9d9c4d4a..ef8bb6be 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/NestedLoopNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/NestedLoopNode.cs @@ -180,9 +180,12 @@ public override IDataExecutionPlanNodeInternal FoldQuery(NodeCompilationContext var innerParameterTypes = GetInnerParameterTypes(leftSchema, context.ParameterTypes); var innerContext = new NodeCompilationContext(context.DataSources, context.Options, innerParameterTypes, context.Log); + var rightSchema = RightSource.GetSchema(innerContext); RightSource = RightSource.FoldQuery(innerContext, hints); RightSource.Parent = this; + FoldDefinedValues(rightSchema); + if (LeftSource is ConstantScanNode constant && constant.Schema.Count == 0 && constant.Values.Count == 1 && From 588d0b19a9ee91ff704c6f80584dd7dbe342bb64 Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Wed, 15 Nov 2023 08:44:08 +0000 Subject: [PATCH 56/81] Fixed use of OPENJSON in CROSS APPLY --- .../AdoProviderTests.cs | 90 +++++++++++++++++++ .../Visitors/RewriteVisitorBase.cs | 7 ++ 2 files changed, 97 insertions(+) diff --git a/MarkMpn.Sql4Cds.Engine.Tests/AdoProviderTests.cs b/MarkMpn.Sql4Cds.Engine.Tests/AdoProviderTests.cs index a407002a..999408a0 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/AdoProviderTests.cs +++ b/MarkMpn.Sql4Cds.Engine.Tests/AdoProviderTests.cs @@ -1799,5 +1799,95 @@ FROM OPENJSON(@json2) } } } + + [TestMethod] + public void NestedJson() + { + using (var con = new Sql4CdsConnection(_localDataSource)) + using (var cmd = con.CreateCommand()) + { + cmd.CommandText = @" +--simple cross apply example +DECLARE @JSON NVARCHAR(MAX) = N'[ +{ +""OrderNumber"":""SO43659"", +""OrderDate"":""2011-05-31T00:00:00"", +""AccountNumber"":""AW29825"", +""ItemPrice"":2024.9940, +""ItemQuantity"":1 +}, +{ +""OrderNumber"":""SO43661"", +""OrderDate"":""2011-06-01T00:00:00"", +""AccountNumber"":""AW73565"", +""ItemPrice"":2024.9940, +""ItemQuantity"":3 +} +]' + +SELECT root.[key] AS [Order],TheValues.[key], TheValues.[value] +FROM OPENJSON ( @JSON ) AS root +CROSS APPLY OPENJSON ( root.value) AS TheValues"; + + using (var reader = cmd.ExecuteReader()) + { + Assert.AreEqual("Order", reader.GetName(0)); + Assert.AreEqual("key", reader.GetName(1)); + Assert.AreEqual("value", reader.GetName(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("0", reader.GetString(0)); + Assert.AreEqual("OrderNumber", reader.GetString(1)); + Assert.AreEqual("SO43659", reader.GetString(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("0", reader.GetString(0)); + Assert.AreEqual("OrderDate", reader.GetString(1)); + Assert.AreEqual("2011-05-31T00:00:00", reader.GetString(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("0", reader.GetString(0)); + Assert.AreEqual("AccountNumber", reader.GetString(1)); + Assert.AreEqual("AW29825", reader.GetString(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("0", reader.GetString(0)); + Assert.AreEqual("ItemPrice", reader.GetString(1)); + Assert.AreEqual("2024.9940", reader.GetString(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("0", reader.GetString(0)); + Assert.AreEqual("ItemQuantity", reader.GetString(1)); + Assert.AreEqual("1", reader.GetString(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("1", reader.GetString(0)); + Assert.AreEqual("OrderNumber", reader.GetString(1)); + Assert.AreEqual("SO43661", reader.GetString(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("1", reader.GetString(0)); + Assert.AreEqual("OrderDate", reader.GetString(1)); + Assert.AreEqual("2011-06-01T00:00:00", reader.GetString(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("1", reader.GetString(0)); + Assert.AreEqual("AccountNumber", reader.GetString(1)); + Assert.AreEqual("AW73565", reader.GetString(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("1", reader.GetString(0)); + Assert.AreEqual("ItemPrice", reader.GetString(1)); + Assert.AreEqual("2024.9940", reader.GetString(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("1", reader.GetString(0)); + Assert.AreEqual("ItemQuantity", reader.GetString(1)); + Assert.AreEqual("3", reader.GetString(2)); + + Assert.IsFalse(reader.Read()); + } + } + } } } diff --git a/MarkMpn.Sql4Cds.Engine/Visitors/RewriteVisitorBase.cs b/MarkMpn.Sql4Cds.Engine/Visitors/RewriteVisitorBase.cs index b1990b2d..c0259916 100644 --- a/MarkMpn.Sql4Cds.Engine/Visitors/RewriteVisitorBase.cs +++ b/MarkMpn.Sql4Cds.Engine/Visitors/RewriteVisitorBase.cs @@ -227,5 +227,12 @@ public override void ExplicitVisit(SchemaObjectFunctionTableReference node) } } } + + public override void ExplicitVisit(OpenJsonTableReference node) + { + base.ExplicitVisit(node); + ReplaceExpression(node, n => n.Variable); + ReplaceExpression(node, n => n.RowPattern); + } } } From 3894c6be8936fae4534ce20c4160c13336560c7c Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Wed, 15 Nov 2023 20:29:29 +0000 Subject: [PATCH 57/81] Handle setting polymorphic lookup fields using TDS Endpoint --- .../ExecutionPlan/BaseDmlNode.cs | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BaseDmlNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BaseDmlNode.cs index d5271303..c5880b01 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BaseDmlNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BaseDmlNode.cs @@ -439,10 +439,22 @@ protected Dictionary> CompileColumnMappings(DataSou { var sourceTargetColumnName = mappings[destAttributeName + "type"]; var sourceTargetType = schema.Schema[sourceTargetColumnName].Type; - var stringType = DataTypeHelpers.NVarChar(MetadataExtensions.EntityLogicalNameMaxLength, dataSource.DefaultCollation, CollationLabel.Implicit); + targetExpr = Expression.Property(entityParam, typeof(Entity).GetCustomAttribute().MemberName, Expression.Constant(sourceTargetColumnName)); - targetExpr = SqlTypeConverter.Convert(targetExpr, sourceTargetType, stringType); - targetExpr = SqlTypeConverter.Convert(targetExpr, typeof(string)); + targetExpr = Expression.Convert(targetExpr, sourceTargetType.ToNetType(out _)); + + if (targetExpr.Type == typeof(SqlInt32)) + { + // Using TDS Endpoint, ___type fields are returned as ObjectTypeCode values, not logical names + targetExpr = Expr.Call(() => ObjectTypeCodeToLogicalName(Expr.Arg(), Expr.Arg()), targetExpr, Expression.Constant(dataSource.Metadata)); + } + else + { + // Normally we want to specify the target type as a logical name + var stringType = DataTypeHelpers.NVarChar(MetadataExtensions.EntityLogicalNameMaxLength, dataSource.DefaultCollation, CollationLabel.Implicit); + targetExpr = SqlTypeConverter.Convert(targetExpr, sourceTargetType, stringType); + targetExpr = SqlTypeConverter.Convert(targetExpr, typeof(string)); + } } convertedExpr = SqlTypeConverter.Convert(expr, sourceSqlType, DataTypeHelpers.UniqueIdentifier); @@ -508,6 +520,14 @@ protected Dictionary> CompileColumnMappings(DataSou return attributeAccessors; } + private static string ObjectTypeCodeToLogicalName(SqlInt32 otc, IAttributeMetadataCache attributeMetadataCache) + { + if (otc.IsNull) + throw new QueryExecutionException("Cannot convert null ObjectTypeCode to EntityReference"); + + return attributeMetadataCache[otc.Value].LogicalName; + } + /// /// Provides values to include in log messages /// From 7c52cb2b3d91bd16278bd054f9262e9fe129d543 Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Wed, 15 Nov 2023 20:31:33 +0000 Subject: [PATCH 58/81] Offer literal value suggestions for entityname attributes --- .../Autocomplete/Autocomplete.cs | 53 +++++++++++++++++-- MarkMpn.Sql4Cds.XTB/Autocomplete.cs | 52 ++++++++++++++++-- 2 files changed, 99 insertions(+), 6 deletions(-) diff --git a/MarkMpn.Sql4Cds.LanguageServer/Autocomplete/Autocomplete.cs b/MarkMpn.Sql4Cds.LanguageServer/Autocomplete/Autocomplete.cs index 76253508..e322d61c 100644 --- a/MarkMpn.Sql4Cds.LanguageServer/Autocomplete/Autocomplete.cs +++ b/MarkMpn.Sql4Cds.LanguageServer/Autocomplete/Autocomplete.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Reflection; using System.Text; +using Data8.PowerPlatform.Dataverse.Client.Wsdl; using MarkMpn.Sql4Cds.Engine; using Microsoft.Crm.Sdk.Messages; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -568,13 +569,15 @@ public IEnumerable GetSuggestions(string text, int pos) { // Check if there are any applicable filter operator functions that match the type of the current attribute var identifiers = prevPrevWord.Split('.'); + var instance = default(AutocompleteDataSource); + var entity = default(EntityMetadata); var attribute = default(AttributeMetadata); if (identifiers.Length == 2) { if (tables.TryGetValue(identifiers[0], out var tableName)) { - if (TryParseTableName(tableName, out var instanceName, out _, out tableName) && _dataSources.TryGetValue(instanceName, out var instance) && instance.Metadata.TryGetMinimalData(tableName, out var entity)) + if (TryParseTableName(tableName, out var instanceName, out _, out tableName) && _dataSources.TryGetValue(instanceName, out instance) && instance.Metadata.TryGetMinimalData(tableName, out entity)) { attribute = entity.Attributes.SingleOrDefault(a => a.LogicalName.Equals(identifiers[1], StringComparison.OrdinalIgnoreCase)); } @@ -584,7 +587,7 @@ public IEnumerable GetSuggestions(string text, int pos) { foreach (var table in tables.Values) { - if (TryParseTableName(table, out var instanceName, out _, out var tableName) && _dataSources.TryGetValue(instanceName, out var instance) && instance.Metadata.TryGetMinimalData(tableName, out var entity)) + if (TryParseTableName(table, out var instanceName, out _, out var tableName) && _dataSources.TryGetValue(instanceName, out instance) && instance.Metadata.TryGetMinimalData(tableName, out entity)) { var tableAttribute = entity.Attributes.SingleOrDefault(a => a.LogicalName.Equals(identifiers[0], StringComparison.OrdinalIgnoreCase)); @@ -623,8 +626,25 @@ public IEnumerable GetSuggestions(string text, int pos) items.AddRange(typeof(FetchXmlConditionMethods).GetMethods(BindingFlags.Public | BindingFlags.Static).Where(m => m.GetParameters()[0].ParameterType == expectedType).Select(m => new FunctionAutocompleteItem(m, currentLength))); } - if (attribute is EnumAttributeMetadata enumAttr) + if (attribute is EntityNameAttributeMetadata entityNameAttr) + { + var lookupAttr = entity.Attributes.SingleOrDefault(a => a.LogicalName == entityNameAttr.AttributeOf) as LookupAttributeMetadata; + + if (lookupAttr?.Targets == null || lookupAttr.Targets.Length == 0) + { + // Could be any entity name, show them all + items.AddRange(instance.Entities.Select(e => new EntityNameAutocompleteItem(e, currentLength))); + } + else + { + // Can only be one of the allowed entity types + items.AddRange(instance.Entities.Where(e => lookupAttr.Targets.Contains(e.LogicalName)).Select(e => new EntityNameAutocompleteItem(e, currentLength))); + } + } + else if (attribute is EnumAttributeMetadata enumAttr) + { items.AddRange(enumAttr.OptionSet.Options.Select(o => new OptionSetAutocompleteItem(o, currentLength))); + } } } @@ -1800,6 +1820,33 @@ public override string ToolTipText } } + class EntityNameAutocompleteItem : SqlAutocompleteItem + { + private readonly EntityMetadata _entity; + + public EntityNameAutocompleteItem(EntityMetadata entity, int replaceLength) : base(entity.LogicalName, replaceLength, CompletionItemKind.Text) + { + _entity = entity; + } + + public override string ToolTipTitle + { + get => _entity.DisplayName?.UserLocalizedLabel?.Label ?? _entity.LogicalName; + set => base.ToolTipTitle = value; + } + + public override string ToolTipText + { + get => _entity.Description?.UserLocalizedLabel?.Label; + set => base.ToolTipText = value; + } + + public override string GetTextForReplace() + { + return "'" + _entity.LogicalName + "'"; + } + } + class CollationAutocompleteItem : SqlAutocompleteItem { private readonly Collation _collation; diff --git a/MarkMpn.Sql4Cds.XTB/Autocomplete.cs b/MarkMpn.Sql4Cds.XTB/Autocomplete.cs index 492e40ff..1de56c50 100644 --- a/MarkMpn.Sql4Cds.XTB/Autocomplete.cs +++ b/MarkMpn.Sql4Cds.XTB/Autocomplete.cs @@ -568,13 +568,15 @@ public IEnumerable GetSuggestions(string text, int pos) { // Check if there are any applicable filter operator functions that match the type of the current attribute var identifiers = prevPrevWord.Split('.'); + var instance = default(AutocompleteDataSource); + var entity = default(EntityMetadata); var attribute = default(AttributeMetadata); if (identifiers.Length == 2) { if (tables.TryGetValue(identifiers[0], out var tableName)) { - if (TryParseTableName(tableName, out var instanceName, out _, out tableName) && _dataSources.TryGetValue(instanceName, out var instance) && instance.Metadata.TryGetMinimalData(tableName, out var entity)) + if (TryParseTableName(tableName, out var instanceName, out _, out tableName) && _dataSources.TryGetValue(instanceName, out instance) && instance.Metadata.TryGetMinimalData(tableName, out entity)) { attribute = entity.Attributes.SingleOrDefault(a => a.LogicalName.Equals(identifiers[1], StringComparison.OrdinalIgnoreCase)); } @@ -584,7 +586,7 @@ public IEnumerable GetSuggestions(string text, int pos) { foreach (var table in tables.Values) { - if (TryParseTableName(table, out var instanceName, out _, out var tableName) && _dataSources.TryGetValue(instanceName, out var instance) && instance.Metadata.TryGetMinimalData(tableName, out var entity)) + if (TryParseTableName(table, out var instanceName, out _, out var tableName) && _dataSources.TryGetValue(instanceName, out instance) && instance.Metadata.TryGetMinimalData(tableName, out entity)) { var tableAttribute = entity.Attributes.SingleOrDefault(a => a.LogicalName.Equals(identifiers[0], StringComparison.OrdinalIgnoreCase)); @@ -623,8 +625,25 @@ public IEnumerable GetSuggestions(string text, int pos) items.AddRange(typeof(FetchXmlConditionMethods).GetMethods(BindingFlags.Public | BindingFlags.Static).Where(m => m.GetParameters()[0].ParameterType == expectedType).Select(m => new FunctionAutocompleteItem(m, currentLength))); } - if (attribute is EnumAttributeMetadata enumAttr) + if (attribute is EntityNameAttributeMetadata entityNameAttr) + { + var lookupAttr = entity.Attributes.SingleOrDefault(a => a.LogicalName == entityNameAttr.AttributeOf) as LookupAttributeMetadata; + + if (lookupAttr?.Targets == null || lookupAttr.Targets.Length == 0) + { + // Could be any entity name, show them all + items.AddRange(instance.Entities.Select(e => new EntityNameAutocompleteItem(e, currentLength))); + } + else + { + // Can only be one of the allowed entity types + items.AddRange(instance.Entities.Where(e => lookupAttr.Targets.Contains(e.LogicalName)).Select(e => new EntityNameAutocompleteItem(e, currentLength))); + } + } + else if (attribute is EnumAttributeMetadata enumAttr) + { items.AddRange(enumAttr.OptionSet.Options.Select(o => new OptionSetAutocompleteItem(o, currentLength))); + } } } @@ -1782,6 +1801,33 @@ public override string ToolTipText } } + class EntityNameAutocompleteItem : SqlAutocompleteItem + { + private readonly EntityMetadata _entity; + + public EntityNameAutocompleteItem(EntityMetadata entity, int replaceLength) : base(entity.LogicalName, replaceLength, 11) + { + _entity = entity; + } + + public override string ToolTipTitle + { + get => _entity.DisplayName?.UserLocalizedLabel?.Label ?? _entity.LogicalName; + set => base.ToolTipTitle = value; + } + + public override string ToolTipText + { + get => _entity.Description?.UserLocalizedLabel?.Label; + set => base.ToolTipText = value; + } + + public override string GetTextForReplace() + { + return "'" + _entity.LogicalName + "'"; + } + } + class CollationAutocompleteItem : SqlAutocompleteItem { private readonly Collation _collation; From f3bd7f6d88be7332d69da9d3155280e6e1c6c5af Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Wed, 15 Nov 2023 20:33:24 +0000 Subject: [PATCH 59/81] Fixed column name escaping --- MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs index 7b32d7b5..27ce3e3e 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs @@ -298,7 +298,7 @@ private void ConvertStatement(TSqlStatement statement, ExecutionPlanOptimizer op // Capture all CTE fields in the outer references foreach (var col in anchorSchema.Schema) - recurseLoop.OuterReferences[col.Key.SplitMultiPartIdentifier().Last()] = "@" + _nodeContext.GetExpressionName(); + recurseLoop.OuterReferences[col.Key.SplitMultiPartIdentifier().Last().EscapeIdentifier()] = "@" + _nodeContext.GetExpressionName(); if (cteValidator.RecursiveQueries.Count > 1) { From 2535ab68a003892c71b7451b3c90c0979c5ae70a Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Wed, 15 Nov 2023 20:33:52 +0000 Subject: [PATCH 60/81] Fixed use of SELECT * within CTEs --- MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs index 27ce3e3e..33cf43e4 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs @@ -455,8 +455,10 @@ private SelectNode ConvertRecursiveCTEQuery(QueryExpression queryExpression, INo queryExpression.Accept(cteReplacer); // Convert the modified query. - var childContext = new NodeCompilationContext(_nodeContext, outerReferences.ToDictionary(kvp => kvp.Value, kvp => anchorSchema.Schema[cteValidator.Name.EscapeIdentifier() + "." + kvp.Key].Type, StringComparer.OrdinalIgnoreCase)); - return ConvertSelectStatement(queryExpression, null, null, null, childContext); + var childContext = new NodeCompilationContext(_nodeContext, outerReferences.ToDictionary(kvp => kvp.Value, kvp => anchorSchema.Schema[cteValidator.Name.EscapeIdentifier() + "." + kvp.Key.EscapeIdentifier()].Type, StringComparer.OrdinalIgnoreCase)); + var converted = ConvertSelectStatement(queryExpression, null, null, null, childContext); + converted.ExpandWildcardColumns(childContext); + return converted; } private IRootExecutionPlanNodeInternal[] ConvertExecuteStatement(ExecuteStatement execute) From 0056a42581495230f9780c31a27c10269dd29a9a Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Wed, 15 Nov 2023 20:34:46 +0000 Subject: [PATCH 61/81] Added filter StartupExpression for more efficient filtering of CROSS APPLY queries --- .../AdoProviderTests.cs | 118 ++++++++++++++++++ .../ExecutionPlan/FilterNode.cs | 24 ++++ 2 files changed, 142 insertions(+) diff --git a/MarkMpn.Sql4Cds.Engine.Tests/AdoProviderTests.cs b/MarkMpn.Sql4Cds.Engine.Tests/AdoProviderTests.cs index 999408a0..d203be81 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/AdoProviderTests.cs +++ b/MarkMpn.Sql4Cds.Engine.Tests/AdoProviderTests.cs @@ -1889,5 +1889,123 @@ FROM OPENJSON ( @JSON ) AS root } } } + + [TestMethod] + public void RecursiveCTEJson() + { + using (var con = new Sql4CdsConnection(_localDataSource)) + using (var cmd = con.CreateCommand()) + { + cmd.CommandText = @" +DECLARE @JSON NVARCHAR(MAX) = N'[ +{ +""OrderNumber"":""SO43659"", +""OrderDate"":""2011-05-31T00:00:00"", +""AccountNumber"":""AW29825"", +""ItemPrice"":2024.9940, +""ItemQuantity"":1 +}, +{ +""OrderNumber"":""SO43661"", +""OrderDate"":""2011-06-01T00:00:00"", +""AccountNumber"":""AW73565"", +""ItemPrice"":2024.9940, +""ItemQuantity"":3 +} +]'; + + +with cte ([key], value, type) as ( + select '$[' + [key] + ']', value, type from OPENJSON(@json) + + union all + + select cte.[key] + case when cte.type = 4 then '[' + childvalues.[key] + ']' else '.' + childvalues.[key] end, childvalues.value, childvalues.type from cte cross apply OPENJSON(cte.value) as childvalues WHERE cte.type in (4, 5) +) + +SELECT * from CTE"; + + using (var reader = cmd.ExecuteReader()) + { + Assert.AreEqual("key", reader.GetName(0)); + Assert.AreEqual("value", reader.GetName(1)); + Assert.AreEqual("type", reader.GetName(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("$[0]", reader.GetString(0)); + Assert.AreEqual(@"{ +""OrderNumber"":""SO43659"", +""OrderDate"":""2011-05-31T00:00:00"", +""AccountNumber"":""AW29825"", +""ItemPrice"":2024.9940, +""ItemQuantity"":1 +}", reader.GetString(1)); + Assert.AreEqual(5, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("$[1]", reader.GetString(0)); + Assert.AreEqual(@"{ +""OrderNumber"":""SO43661"", +""OrderDate"":""2011-06-01T00:00:00"", +""AccountNumber"":""AW73565"", +""ItemPrice"":2024.9940, +""ItemQuantity"":3 +}", reader.GetString(1)); + Assert.AreEqual(5, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("$[1].OrderNumber", reader.GetString(0)); + Assert.AreEqual("SO43661", reader.GetString(1)); + Assert.AreEqual(1, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("$[1].OrderDate", reader.GetString(0)); + Assert.AreEqual("2011-06-01T00:00:00", reader.GetString(1)); + Assert.AreEqual(1, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("$[1].AccountNumber", reader.GetString(0)); + Assert.AreEqual("AW73565", reader.GetString(1)); + Assert.AreEqual(1, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("$[1].ItemPrice", reader.GetString(0)); + Assert.AreEqual("2024.9940", reader.GetString(1)); + Assert.AreEqual(2, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("$[1].ItemQuantity", reader.GetString(0)); + Assert.AreEqual("3", reader.GetString(1)); + Assert.AreEqual(2, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("$[0].OrderNumber", reader.GetString(0)); + Assert.AreEqual("SO43659", reader.GetString(1)); + Assert.AreEqual(1, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("$[0].OrderDate", reader.GetString(0)); + Assert.AreEqual("2011-05-31T00:00:00", reader.GetString(1)); + Assert.AreEqual(1, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("$[0].AccountNumber", reader.GetString(0)); + Assert.AreEqual("AW29825", reader.GetString(1)); + Assert.AreEqual(1, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("$[0].ItemPrice", reader.GetString(0)); + Assert.AreEqual("2024.9940", reader.GetString(1)); + Assert.AreEqual(2, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("$[0].ItemQuantity", reader.GetString(0)); + Assert.AreEqual("1", reader.GetString(1)); + Assert.AreEqual(2, reader.GetInt32(2)); + + Assert.IsFalse(reader.Read()); + } + } + } } } diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FilterNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FilterNode.cs index 976e39f5..2737a2e9 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FilterNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/FilterNode.cs @@ -27,6 +27,14 @@ class FilterNode : BaseDataNode, ISingleSourceExecutionPlanNode [Description("The filter to apply")] public BooleanExpression Filter { get; set; } + /// + /// Indicates if the filter should be evaluated during startup only + /// + [Category("Filter")] + [DisplayName("Startup Expression")] + [Description("Indicates if the filter shold be evaluated during startup only")] + public bool StartupExpression { get; set; } + /// /// The data source to select from /// @@ -40,6 +48,9 @@ protected override IEnumerable ExecuteInternal(NodeExecutionContext cont var filter = Filter.Compile(expressionCompilationContext); var expressionContext = new ExpressionExecutionContext(context); + if (StartupExpression && !filter(expressionContext)) + yield break; + foreach (var entity in Source.Execute(context)) { expressionContext.Entity = entity; @@ -164,9 +175,21 @@ public override IDataExecutionPlanNodeInternal FoldQuery(NodeCompilationContext if (FoldScalarSubqueries(context, out var nestedLoop)) return nestedLoop.FoldQuery(context, hints); + // Check if we can apply the filter during startup instead of per-record + StartupExpression = CheckStartupExpression(); + return this; } + private bool CheckStartupExpression() + { + // We only need to apply the filter expression to individual rows if it references any fields + if (Filter.GetColumns().Any()) + return false; + + return true; + } + private BooleanExpression FoldNotIsNullToIsNotNull(BooleanExpression filter) { var visitor = new RefactorNotIsNullVisitor(filter); @@ -1836,6 +1859,7 @@ public override object Clone() var clone = new FilterNode { Filter = Filter, + StartupExpression = StartupExpression, Source = (IDataExecutionPlanNodeInternal)Source.Clone() }; From a336ee4cfef3ca625100dcd36de38f625dbac7f8 Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Fri, 17 Nov 2023 08:52:28 +0000 Subject: [PATCH 62/81] Added JSON_QUERY and ISJSON methods --- .../AdoProviderTests.cs | 504 ----------------- .../JsonFunctionTests.cs | 183 +++++++ MarkMpn.Sql4Cds.Engine.Tests/JsonPathTests.cs | 2 +- .../MarkMpn.Sql4Cds.Engine.Tests.csproj | 2 + MarkMpn.Sql4Cds.Engine.Tests/OpenJsonTests.cs | 506 ++++++++++++++++++ .../ExecutionPlan/ExpressionExtensions.cs | 91 ++-- MarkMpn.Sql4Cds.Engine/ExpressionFunctions.cs | 137 ++++- MarkMpn.Sql4Cds.Engine/JsonPath.cs | 2 +- .../Autocomplete/FunctionMetadata.cs | 6 + MarkMpn.Sql4Cds.XTB/FunctionMetadata.cs | 6 + 10 files changed, 882 insertions(+), 557 deletions(-) create mode 100644 MarkMpn.Sql4Cds.Engine.Tests/JsonFunctionTests.cs create mode 100644 MarkMpn.Sql4Cds.Engine.Tests/OpenJsonTests.cs diff --git a/MarkMpn.Sql4Cds.Engine.Tests/AdoProviderTests.cs b/MarkMpn.Sql4Cds.Engine.Tests/AdoProviderTests.cs index d203be81..1125608b 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/AdoProviderTests.cs +++ b/MarkMpn.Sql4Cds.Engine.Tests/AdoProviderTests.cs @@ -1324,17 +1324,6 @@ public void StringAgg() } } - [TestMethod] - public void JsonValueNull() - { - using (var con = new Sql4CdsConnection(_localDataSource)) - using (var cmd = con.CreateCommand()) - { - cmd.CommandText = "SELECT JSON_VALUE('{ \"changedAttributes\": [ { \"logicalName\": \"column1\", \"oldValue\": null, \"newValue\": \"\" } ] }', '$.changedAttributes[0].oldValue')"; - Assert.AreEqual(DBNull.Value, cmd.ExecuteScalar()); - } - } - [TestMethod] public void VariantType() { @@ -1514,498 +1503,5 @@ public void ComplexFetchXmlAlias() } } } - - [TestMethod] - public void OpenJsonDefaultSchema() - { - using (var con = new Sql4CdsConnection(_localDataSource)) - using (var cmd = con.CreateCommand()) - { - cmd.CommandText = @" -DECLARE @json NVARCHAR(MAX) - -SET @json='{""name"":""John"",""surname"":""Doe"",""age"":45,""skills"":[""SQL"",""C#"",""MVC""]}'; - -SELECT * -FROM OPENJSON(@json);"; - - using (var reader = cmd.ExecuteReader()) - { - Assert.AreEqual("key", reader.GetName(0)); - Assert.AreEqual("value", reader.GetName(1)); - Assert.AreEqual("type", reader.GetName(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("name", reader.GetString(0)); - Assert.AreEqual("John", reader.GetString(1)); - Assert.AreEqual(1, reader.GetInt32(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("surname", reader.GetString(0)); - Assert.AreEqual("Doe", reader.GetString(1)); - Assert.AreEqual(1, reader.GetInt32(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("age", reader.GetString(0)); - Assert.AreEqual("45", reader.GetString(1)); - Assert.AreEqual(2, reader.GetInt32(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("skills", reader.GetString(0)); - Assert.AreEqual("[\"SQL\",\"C#\",\"MVC\"]", reader.GetString(1)); - Assert.AreEqual(4, reader.GetInt32(2)); - - Assert.IsFalse(reader.Read()); - } - } - } - - [TestMethod] - public void OpenJsonDefaultSchemaWithPath() - { - using (var con = new Sql4CdsConnection(_localDataSource)) - using (var cmd = con.CreateCommand()) - { - cmd.CommandText = @" -DECLARE @json NVARCHAR(4000) = N'{ - ""path"": { - ""to"":{ - ""sub-object"":[""en-GB"", ""en-UK"",""de-AT"",""es-AR"",""sr-Cyrl""] - } - } - }'; - -SELECT [key], value -FROM OPENJSON(@json,'$.path.to.""sub-object""')"; - - using (var reader = cmd.ExecuteReader()) - { - Assert.AreEqual("key", reader.GetName(0)); - Assert.AreEqual("value", reader.GetName(1)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("0", reader.GetString(0)); - Assert.AreEqual("en-GB", reader.GetString(1)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("1", reader.GetString(0)); - Assert.AreEqual("en-UK", reader.GetString(1)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("2", reader.GetString(0)); - Assert.AreEqual("de-AT", reader.GetString(1)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("3", reader.GetString(0)); - Assert.AreEqual("es-AR", reader.GetString(1)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("4", reader.GetString(0)); - Assert.AreEqual("sr-Cyrl", reader.GetString(1)); - - Assert.IsFalse(reader.Read()); - } - } - } - - [TestMethod] - public void OpenJsonDefaultSchemaDataTypes() - { - using (var con = new Sql4CdsConnection(_localDataSource)) - using (var cmd = con.CreateCommand()) - { - cmd.CommandText = @" -DECLARE @json NVARCHAR(2048) = N'{ - ""String_value"": ""John"", - ""DoublePrecisionFloatingPoint_value"": 45, - ""DoublePrecisionFloatingPoint_value"": 2.3456, - ""BooleanTrue_value"": true, - ""BooleanFalse_value"": false, - ""Null_value"": null, - ""Array_value"": [""a"",""r"",""r"",""a"",""y""], - ""Object_value"": {""obj"":""ect""} -}'; - -SELECT * FROM OpenJson(@json);"; - - using (var reader = cmd.ExecuteReader()) - { - Assert.AreEqual("key", reader.GetName(0)); - Assert.AreEqual("value", reader.GetName(1)); - Assert.AreEqual("type", reader.GetName(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("String_value", reader.GetString(0)); - Assert.AreEqual("John", reader.GetString(1)); - Assert.AreEqual(1, reader.GetInt32(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("DoublePrecisionFloatingPoint_value", reader.GetString(0)); - Assert.AreEqual("45", reader.GetString(1)); - Assert.AreEqual(2, reader.GetInt32(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("DoublePrecisionFloatingPoint_value", reader.GetString(0)); - Assert.AreEqual("2.3456", reader.GetString(1)); - Assert.AreEqual(2, reader.GetInt32(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("BooleanTrue_value", reader.GetString(0)); - Assert.AreEqual("true", reader.GetString(1)); - Assert.AreEqual(3, reader.GetInt32(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("BooleanFalse_value", reader.GetString(0)); - Assert.AreEqual("false", reader.GetString(1)); - Assert.AreEqual(3, reader.GetInt32(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("Null_value", reader.GetString(0)); - Assert.IsTrue(reader.IsDBNull(1)); - Assert.AreEqual(0, reader.GetInt32(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("Array_value", reader.GetString(0)); - Assert.AreEqual("[\"a\",\"r\",\"r\",\"a\",\"y\"]", reader.GetString(1)); - Assert.AreEqual(4, reader.GetInt32(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("Object_value", reader.GetString(0)); - Assert.AreEqual("{\"obj\":\"ect\"}", reader.GetString(1)); - Assert.AreEqual(5, reader.GetInt32(2)); - - Assert.IsFalse(reader.Read()); - } - } - } - - [TestMethod] - public void OpenJsonExplicitSchema() - { - using (var con = new Sql4CdsConnection(_localDataSource)) - using (var cmd = con.CreateCommand()) - { - cmd.CommandText = @" -DECLARE @json NVARCHAR(MAX) = N'[ - { - ""Order"": { - ""Number"":""SO43659"", - ""Date"":""2011-05-31T00:00:00"" - }, - ""AccountNumber"":""AW29825"", - ""Item"": { - ""Price"":2024.9940, - ""Quantity"":1 - } - }, - { - ""Order"": { - ""Number"":""SO43661"", - ""Date"":""2011-06-01T00:00:00"" - }, - ""AccountNumber"":""AW73565"", - ""Item"": { - ""Price"":2024.9940, - ""Quantity"":3 - } - } -]' - -SELECT * -FROM OPENJSON ( @json ) -WITH ( - Number VARCHAR(200) '$.Order.Number', - Date DATETIME '$.Order.Date', - Customer VARCHAR(200) '$.AccountNumber', - Quantity INT '$.Item.Quantity', - [Order] NVARCHAR(MAX) AS JSON - )"; - - using (var reader = cmd.ExecuteReader()) - { - Assert.AreEqual("Number", reader.GetName(0)); - Assert.AreEqual("Date", reader.GetName(1)); - Assert.AreEqual("Customer", reader.GetName(2)); - Assert.AreEqual("Quantity", reader.GetName(3)); - Assert.AreEqual("Order", reader.GetName(4)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("SO43659", reader.GetString(0)); - Assert.AreEqual(new DateTime(2011, 5, 31), reader.GetDateTime(1)); - Assert.AreEqual("AW29825", reader.GetString(2)); - Assert.AreEqual(1, reader.GetInt32(3)); - Assert.AreEqual(@"{ - ""Number"":""SO43659"", - ""Date"":""2011-05-31T00:00:00"" - }", reader.GetString(4)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("SO43661", reader.GetString(0)); - Assert.AreEqual(new DateTime(2011, 6, 1), reader.GetDateTime(1)); - Assert.AreEqual("AW73565", reader.GetString(2)); - Assert.AreEqual(3, reader.GetInt32(3)); - Assert.AreEqual(@"{ - ""Number"":""SO43661"", - ""Date"":""2011-06-01T00:00:00"" - }", reader.GetString(4)); - - Assert.IsFalse(reader.Read()); - } - } - } - - [TestMethod] - public void MergeJson() - { - using (var con = new Sql4CdsConnection(_localDataSource)) - using (var cmd = con.CreateCommand()) - { - cmd.CommandText = @" -DECLARE @json1 NVARCHAR(MAX),@json2 NVARCHAR(MAX) - -SET @json1=N'{""name"": ""John"", ""surname"":""Doe""}' - -SET @json2=N'{""name"": ""John"", ""age"":45}' - -SELECT * -FROM OPENJSON(@json1) -UNION ALL -SELECT * -FROM OPENJSON(@json2) -WHERE [key] NOT IN (SELECT [key] FROM OPENJSON(@json1))"; - - using (var reader = cmd.ExecuteReader()) - { - Assert.AreEqual("key", reader.GetName(0)); - Assert.AreEqual("value", reader.GetName(1)); - Assert.AreEqual("type", reader.GetName(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("name", reader.GetString(0)); - Assert.AreEqual("John", reader.GetString(1)); - Assert.AreEqual(1, reader.GetInt32(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("surname", reader.GetString(0)); - Assert.AreEqual("Doe", reader.GetString(1)); - Assert.AreEqual(1, reader.GetInt32(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("age", reader.GetString(0)); - Assert.AreEqual("45", reader.GetString(1)); - Assert.AreEqual(2, reader.GetInt32(2)); - - Assert.IsFalse(reader.Read()); - } - } - } - - [TestMethod] - public void NestedJson() - { - using (var con = new Sql4CdsConnection(_localDataSource)) - using (var cmd = con.CreateCommand()) - { - cmd.CommandText = @" ---simple cross apply example -DECLARE @JSON NVARCHAR(MAX) = N'[ -{ -""OrderNumber"":""SO43659"", -""OrderDate"":""2011-05-31T00:00:00"", -""AccountNumber"":""AW29825"", -""ItemPrice"":2024.9940, -""ItemQuantity"":1 -}, -{ -""OrderNumber"":""SO43661"", -""OrderDate"":""2011-06-01T00:00:00"", -""AccountNumber"":""AW73565"", -""ItemPrice"":2024.9940, -""ItemQuantity"":3 -} -]' - -SELECT root.[key] AS [Order],TheValues.[key], TheValues.[value] -FROM OPENJSON ( @JSON ) AS root -CROSS APPLY OPENJSON ( root.value) AS TheValues"; - - using (var reader = cmd.ExecuteReader()) - { - Assert.AreEqual("Order", reader.GetName(0)); - Assert.AreEqual("key", reader.GetName(1)); - Assert.AreEqual("value", reader.GetName(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("0", reader.GetString(0)); - Assert.AreEqual("OrderNumber", reader.GetString(1)); - Assert.AreEqual("SO43659", reader.GetString(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("0", reader.GetString(0)); - Assert.AreEqual("OrderDate", reader.GetString(1)); - Assert.AreEqual("2011-05-31T00:00:00", reader.GetString(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("0", reader.GetString(0)); - Assert.AreEqual("AccountNumber", reader.GetString(1)); - Assert.AreEqual("AW29825", reader.GetString(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("0", reader.GetString(0)); - Assert.AreEqual("ItemPrice", reader.GetString(1)); - Assert.AreEqual("2024.9940", reader.GetString(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("0", reader.GetString(0)); - Assert.AreEqual("ItemQuantity", reader.GetString(1)); - Assert.AreEqual("1", reader.GetString(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("1", reader.GetString(0)); - Assert.AreEqual("OrderNumber", reader.GetString(1)); - Assert.AreEqual("SO43661", reader.GetString(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("1", reader.GetString(0)); - Assert.AreEqual("OrderDate", reader.GetString(1)); - Assert.AreEqual("2011-06-01T00:00:00", reader.GetString(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("1", reader.GetString(0)); - Assert.AreEqual("AccountNumber", reader.GetString(1)); - Assert.AreEqual("AW73565", reader.GetString(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("1", reader.GetString(0)); - Assert.AreEqual("ItemPrice", reader.GetString(1)); - Assert.AreEqual("2024.9940", reader.GetString(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("1", reader.GetString(0)); - Assert.AreEqual("ItemQuantity", reader.GetString(1)); - Assert.AreEqual("3", reader.GetString(2)); - - Assert.IsFalse(reader.Read()); - } - } - } - - [TestMethod] - public void RecursiveCTEJson() - { - using (var con = new Sql4CdsConnection(_localDataSource)) - using (var cmd = con.CreateCommand()) - { - cmd.CommandText = @" -DECLARE @JSON NVARCHAR(MAX) = N'[ -{ -""OrderNumber"":""SO43659"", -""OrderDate"":""2011-05-31T00:00:00"", -""AccountNumber"":""AW29825"", -""ItemPrice"":2024.9940, -""ItemQuantity"":1 -}, -{ -""OrderNumber"":""SO43661"", -""OrderDate"":""2011-06-01T00:00:00"", -""AccountNumber"":""AW73565"", -""ItemPrice"":2024.9940, -""ItemQuantity"":3 -} -]'; - - -with cte ([key], value, type) as ( - select '$[' + [key] + ']', value, type from OPENJSON(@json) - - union all - - select cte.[key] + case when cte.type = 4 then '[' + childvalues.[key] + ']' else '.' + childvalues.[key] end, childvalues.value, childvalues.type from cte cross apply OPENJSON(cte.value) as childvalues WHERE cte.type in (4, 5) -) - -SELECT * from CTE"; - - using (var reader = cmd.ExecuteReader()) - { - Assert.AreEqual("key", reader.GetName(0)); - Assert.AreEqual("value", reader.GetName(1)); - Assert.AreEqual("type", reader.GetName(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("$[0]", reader.GetString(0)); - Assert.AreEqual(@"{ -""OrderNumber"":""SO43659"", -""OrderDate"":""2011-05-31T00:00:00"", -""AccountNumber"":""AW29825"", -""ItemPrice"":2024.9940, -""ItemQuantity"":1 -}", reader.GetString(1)); - Assert.AreEqual(5, reader.GetInt32(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("$[1]", reader.GetString(0)); - Assert.AreEqual(@"{ -""OrderNumber"":""SO43661"", -""OrderDate"":""2011-06-01T00:00:00"", -""AccountNumber"":""AW73565"", -""ItemPrice"":2024.9940, -""ItemQuantity"":3 -}", reader.GetString(1)); - Assert.AreEqual(5, reader.GetInt32(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("$[1].OrderNumber", reader.GetString(0)); - Assert.AreEqual("SO43661", reader.GetString(1)); - Assert.AreEqual(1, reader.GetInt32(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("$[1].OrderDate", reader.GetString(0)); - Assert.AreEqual("2011-06-01T00:00:00", reader.GetString(1)); - Assert.AreEqual(1, reader.GetInt32(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("$[1].AccountNumber", reader.GetString(0)); - Assert.AreEqual("AW73565", reader.GetString(1)); - Assert.AreEqual(1, reader.GetInt32(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("$[1].ItemPrice", reader.GetString(0)); - Assert.AreEqual("2024.9940", reader.GetString(1)); - Assert.AreEqual(2, reader.GetInt32(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("$[1].ItemQuantity", reader.GetString(0)); - Assert.AreEqual("3", reader.GetString(1)); - Assert.AreEqual(2, reader.GetInt32(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("$[0].OrderNumber", reader.GetString(0)); - Assert.AreEqual("SO43659", reader.GetString(1)); - Assert.AreEqual(1, reader.GetInt32(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("$[0].OrderDate", reader.GetString(0)); - Assert.AreEqual("2011-05-31T00:00:00", reader.GetString(1)); - Assert.AreEqual(1, reader.GetInt32(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("$[0].AccountNumber", reader.GetString(0)); - Assert.AreEqual("AW29825", reader.GetString(1)); - Assert.AreEqual(1, reader.GetInt32(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("$[0].ItemPrice", reader.GetString(0)); - Assert.AreEqual("2024.9940", reader.GetString(1)); - Assert.AreEqual(2, reader.GetInt32(2)); - - Assert.IsTrue(reader.Read()); - Assert.AreEqual("$[0].ItemQuantity", reader.GetString(0)); - Assert.AreEqual("1", reader.GetString(1)); - Assert.AreEqual(2, reader.GetInt32(2)); - - Assert.IsFalse(reader.Read()); - } - } - } } } diff --git a/MarkMpn.Sql4Cds.Engine.Tests/JsonFunctionTests.cs b/MarkMpn.Sql4Cds.Engine.Tests/JsonFunctionTests.cs new file mode 100644 index 00000000..8ac2dc21 --- /dev/null +++ b/MarkMpn.Sql4Cds.Engine.Tests/JsonFunctionTests.cs @@ -0,0 +1,183 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MarkMpn.Sql4Cds.Engine.ExecutionPlan; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace MarkMpn.Sql4Cds.Engine.Tests +{ + [TestClass] + public class JsonFunctionTests : FakeXrmEasyTestsBase + { + [TestMethod] + [DataRow("lax $", null, false)] + [DataRow("strict $", null, true)] + [DataRow("lax $.info.type", "1", false)] + [DataRow("strict $.info.type", "1", false)] + [DataRow("lax $.info.address.town", "Bristol", false)] + [DataRow("strict $.info.address.town", "Bristol", false)] + [DataRow("lax $.info.\"address\"", null, false)] + [DataRow("strict $.info.\"address\"", null, true)] + [DataRow("lax $.info.tags", null, false)] + [DataRow("strict $.info.tags", null, true)] + [DataRow("lax $.info.type[0]", null, false)] + [DataRow("strict $.info.type[0]", null, true)] + [DataRow("lax $.info.none", null, false)] + [DataRow("strict $.info.none", null, true)] + public void JsonValue(string path, string expectedValue, bool expectedError) + { + using (var con = new Sql4CdsConnection(_localDataSource)) + using (var cmd = con.CreateCommand()) + { + cmd.CommandText = @" +DECLARE @jsonInfo NVARCHAR(MAX) + +SET @jsonInfo=N'{ + ""info"":{ + ""type"":1, + ""address"":{ + ""town"":""Bristol"", + ""county"":""Avon"", + ""country"":""England"" + }, + ""tags"":[""Sport"", ""Water polo""] + }, + ""type"":""Basic"" + }' + +SELECT JSON_VALUE(@jsonInfo, @path)"; + + var param = cmd.CreateParameter(); + param.ParameterName = "@path"; + param.Value = path; + cmd.Parameters.Add(param); + + if (expectedError) + { + Assert.ThrowsException(() => cmd.ExecuteScalar()); + } + else + { + if (expectedValue == null) + Assert.AreEqual(DBNull.Value, cmd.ExecuteScalar()); + else + Assert.AreEqual(expectedValue, cmd.ExecuteScalar()); + } + } + } + + [TestMethod] + public void JsonValueNull() + { + using (var con = new Sql4CdsConnection(_localDataSource)) + using (var cmd = con.CreateCommand()) + { + cmd.CommandText = "SELECT JSON_VALUE('{ \"changedAttributes\": [ { \"logicalName\": \"column1\", \"oldValue\": null, \"newValue\": \"\" } ] }', '$.changedAttributes[0].oldValue')"; + Assert.AreEqual(DBNull.Value, cmd.ExecuteScalar()); + } + } + + [TestMethod] + [DataRow("lax $", null, true, false)] + [DataRow("strict $", null, true, false)] + [DataRow("lax $.info.type", null, false, false)] + [DataRow("strict $.info.type", null, false, true)] + [DataRow("lax $.info.address.town", null, false, false)] + [DataRow("strict $.info.address.town", null, false, true)] + [DataRow("lax $.info.\"address\"", @"{ + ""town"": ""Cheltenham"", + ""county"": ""Gloucestershire"", + ""country"": ""England"" + }", false, false)] + [DataRow("strict $.info.\"address\"", @"{ + ""town"": ""Cheltenham"", + ""county"": ""Gloucestershire"", + ""country"": ""England"" + }", false, false)] + [DataRow("lax $.info.tags", "[\"Sport\", \"Water polo\"]", false, false)] + [DataRow("strict $.info.tags", "[\"Sport\", \"Water polo\"]", false, false)] + [DataRow("lax $.info.type[0]", null, false, false)] + [DataRow("strict $.info.type[0]", null, false, true)] + [DataRow("lax $.info.none", null, false, false)] + [DataRow("strict $.info.none", null, false, true)] + public void JsonQuery(string path, string expectedValue, bool expectedFullValue, bool expectedError) + { + using (var con = new Sql4CdsConnection(_localDataSource)) + using (var cmd = con.CreateCommand()) + { + cmd.CommandText = "SELECT JSON_QUERY(@json, @path)"; + + var jsonParam = cmd.CreateParameter(); + jsonParam.ParameterName = "@json"; + jsonParam.Value = @"{ + ""info"": { + ""type"": 1, + ""address"": { + ""town"": ""Cheltenham"", + ""county"": ""Gloucestershire"", + ""country"": ""England"" + }, + ""tags"": [""Sport"", ""Water polo""] + }, + ""type"": ""Basic"" +}"; + cmd.Parameters.Add(jsonParam); + + var pathParam = cmd.CreateParameter(); + pathParam.ParameterName = "@path"; + pathParam.Value = path; + cmd.Parameters.Add(pathParam); + + if (expectedFullValue) + expectedValue = (string)jsonParam.Value; + + if (expectedError) + { + Assert.ThrowsException(() => cmd.ExecuteScalar()); + } + else + { + if (expectedValue == null) + Assert.AreEqual(DBNull.Value, cmd.ExecuteScalar()); + else + Assert.AreEqual(expectedValue, cmd.ExecuteScalar()); + } + } + } + + [TestMethod] + public void IsJsonTrue() + { + using (var con = new Sql4CdsConnection(_localDataSource)) + using (var cmd = con.CreateCommand()) + { + cmd.CommandText = "SELECT ISJSON('true', VALUE)"; + Assert.AreEqual(true, cmd.ExecuteScalar()); + } + } + + [TestMethod] + public void IsJsonUnquotedString() + { + using (var con = new Sql4CdsConnection(_localDataSource)) + using (var cmd = con.CreateCommand()) + { + cmd.CommandText = "SELECT ISJSON('test string', VALUE)"; + Assert.AreEqual(false, cmd.ExecuteScalar()); + } + } + + [TestMethod] + public void IsJsonQuotedString() + { + using (var con = new Sql4CdsConnection(_localDataSource)) + using (var cmd = con.CreateCommand()) + { + cmd.CommandText = "SELECT ISJSON('\"test string\"', SCALAR)"; + Assert.AreEqual(true, cmd.ExecuteScalar()); + } + } + } +} diff --git a/MarkMpn.Sql4Cds.Engine.Tests/JsonPathTests.cs b/MarkMpn.Sql4Cds.Engine.Tests/JsonPathTests.cs index bd67eab9..cb3610e5 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/JsonPathTests.cs +++ b/MarkMpn.Sql4Cds.Engine.Tests/JsonPathTests.cs @@ -82,7 +82,7 @@ public void ExplicitModeLax() public void ExplicitModeStrict() { var path = new JsonPath("strict $.path.to.\"sub-object\""); - Assert.AreEqual(JsonPathMode.Lax, path.Mode); + Assert.AreEqual(JsonPathMode.Strict, path.Mode); } [TestMethod] diff --git a/MarkMpn.Sql4Cds.Engine.Tests/MarkMpn.Sql4Cds.Engine.Tests.csproj b/MarkMpn.Sql4Cds.Engine.Tests/MarkMpn.Sql4Cds.Engine.Tests.csproj index b654cc8a..601079fc 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/MarkMpn.Sql4Cds.Engine.Tests.csproj +++ b/MarkMpn.Sql4Cds.Engine.Tests/MarkMpn.Sql4Cds.Engine.Tests.csproj @@ -82,6 +82,7 @@ + @@ -89,6 +90,7 @@ + diff --git a/MarkMpn.Sql4Cds.Engine.Tests/OpenJsonTests.cs b/MarkMpn.Sql4Cds.Engine.Tests/OpenJsonTests.cs new file mode 100644 index 00000000..99bd3681 --- /dev/null +++ b/MarkMpn.Sql4Cds.Engine.Tests/OpenJsonTests.cs @@ -0,0 +1,506 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace MarkMpn.Sql4Cds.Engine.Tests +{ + [TestClass] + public class OpenJsonTests : FakeXrmEasyTestsBase + { + [TestMethod] + public void OpenJsonDefaultSchema() + { + using (var con = new Sql4CdsConnection(_localDataSource)) + using (var cmd = con.CreateCommand()) + { + cmd.CommandText = @" +DECLARE @json NVARCHAR(MAX) + +SET @json='{""name"":""John"",""surname"":""Doe"",""age"":45,""skills"":[""SQL"",""C#"",""MVC""]}'; + +SELECT * +FROM OPENJSON(@json);"; + + using (var reader = cmd.ExecuteReader()) + { + Assert.AreEqual("key", reader.GetName(0)); + Assert.AreEqual("value", reader.GetName(1)); + Assert.AreEqual("type", reader.GetName(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("name", reader.GetString(0)); + Assert.AreEqual("John", reader.GetString(1)); + Assert.AreEqual(1, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("surname", reader.GetString(0)); + Assert.AreEqual("Doe", reader.GetString(1)); + Assert.AreEqual(1, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("age", reader.GetString(0)); + Assert.AreEqual("45", reader.GetString(1)); + Assert.AreEqual(2, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("skills", reader.GetString(0)); + Assert.AreEqual("[\"SQL\",\"C#\",\"MVC\"]", reader.GetString(1)); + Assert.AreEqual(4, reader.GetInt32(2)); + + Assert.IsFalse(reader.Read()); + } + } + } + + [TestMethod] + public void OpenJsonDefaultSchemaWithPath() + { + using (var con = new Sql4CdsConnection(_localDataSource)) + using (var cmd = con.CreateCommand()) + { + cmd.CommandText = @" +DECLARE @json NVARCHAR(4000) = N'{ + ""path"": { + ""to"":{ + ""sub-object"":[""en-GB"", ""en-UK"",""de-AT"",""es-AR"",""sr-Cyrl""] + } + } + }'; + +SELECT [key], value +FROM OPENJSON(@json,'$.path.to.""sub-object""')"; + + using (var reader = cmd.ExecuteReader()) + { + Assert.AreEqual("key", reader.GetName(0)); + Assert.AreEqual("value", reader.GetName(1)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("0", reader.GetString(0)); + Assert.AreEqual("en-GB", reader.GetString(1)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("1", reader.GetString(0)); + Assert.AreEqual("en-UK", reader.GetString(1)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("2", reader.GetString(0)); + Assert.AreEqual("de-AT", reader.GetString(1)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("3", reader.GetString(0)); + Assert.AreEqual("es-AR", reader.GetString(1)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("4", reader.GetString(0)); + Assert.AreEqual("sr-Cyrl", reader.GetString(1)); + + Assert.IsFalse(reader.Read()); + } + } + } + + [TestMethod] + public void OpenJsonDefaultSchemaDataTypes() + { + using (var con = new Sql4CdsConnection(_localDataSource)) + using (var cmd = con.CreateCommand()) + { + cmd.CommandText = @" +DECLARE @json NVARCHAR(2048) = N'{ + ""String_value"": ""John"", + ""DoublePrecisionFloatingPoint_value"": 45, + ""DoublePrecisionFloatingPoint_value"": 2.3456, + ""BooleanTrue_value"": true, + ""BooleanFalse_value"": false, + ""Null_value"": null, + ""Array_value"": [""a"",""r"",""r"",""a"",""y""], + ""Object_value"": {""obj"":""ect""} +}'; + +SELECT * FROM OpenJson(@json);"; + + using (var reader = cmd.ExecuteReader()) + { + Assert.AreEqual("key", reader.GetName(0)); + Assert.AreEqual("value", reader.GetName(1)); + Assert.AreEqual("type", reader.GetName(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("String_value", reader.GetString(0)); + Assert.AreEqual("John", reader.GetString(1)); + Assert.AreEqual(1, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("DoublePrecisionFloatingPoint_value", reader.GetString(0)); + Assert.AreEqual("45", reader.GetString(1)); + Assert.AreEqual(2, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("DoublePrecisionFloatingPoint_value", reader.GetString(0)); + Assert.AreEqual("2.3456", reader.GetString(1)); + Assert.AreEqual(2, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("BooleanTrue_value", reader.GetString(0)); + Assert.AreEqual("true", reader.GetString(1)); + Assert.AreEqual(3, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("BooleanFalse_value", reader.GetString(0)); + Assert.AreEqual("false", reader.GetString(1)); + Assert.AreEqual(3, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("Null_value", reader.GetString(0)); + Assert.IsTrue(reader.IsDBNull(1)); + Assert.AreEqual(0, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("Array_value", reader.GetString(0)); + Assert.AreEqual("[\"a\",\"r\",\"r\",\"a\",\"y\"]", reader.GetString(1)); + Assert.AreEqual(4, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("Object_value", reader.GetString(0)); + Assert.AreEqual("{\"obj\":\"ect\"}", reader.GetString(1)); + Assert.AreEqual(5, reader.GetInt32(2)); + + Assert.IsFalse(reader.Read()); + } + } + } + + [TestMethod] + public void OpenJsonExplicitSchema() + { + using (var con = new Sql4CdsConnection(_localDataSource)) + using (var cmd = con.CreateCommand()) + { + cmd.CommandText = @" +DECLARE @json NVARCHAR(MAX) = N'[ + { + ""Order"": { + ""Number"":""SO43659"", + ""Date"":""2011-05-31T00:00:00"" + }, + ""AccountNumber"":""AW29825"", + ""Item"": { + ""Price"":2024.9940, + ""Quantity"":1 + } + }, + { + ""Order"": { + ""Number"":""SO43661"", + ""Date"":""2011-06-01T00:00:00"" + }, + ""AccountNumber"":""AW73565"", + ""Item"": { + ""Price"":2024.9940, + ""Quantity"":3 + } + } +]' + +SELECT * +FROM OPENJSON ( @json ) +WITH ( + Number VARCHAR(200) '$.Order.Number', + Date DATETIME '$.Order.Date', + Customer VARCHAR(200) '$.AccountNumber', + Quantity INT '$.Item.Quantity', + [Order] NVARCHAR(MAX) AS JSON + )"; + + using (var reader = cmd.ExecuteReader()) + { + Assert.AreEqual("Number", reader.GetName(0)); + Assert.AreEqual("Date", reader.GetName(1)); + Assert.AreEqual("Customer", reader.GetName(2)); + Assert.AreEqual("Quantity", reader.GetName(3)); + Assert.AreEqual("Order", reader.GetName(4)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("SO43659", reader.GetString(0)); + Assert.AreEqual(new DateTime(2011, 5, 31), reader.GetDateTime(1)); + Assert.AreEqual("AW29825", reader.GetString(2)); + Assert.AreEqual(1, reader.GetInt32(3)); + Assert.AreEqual(@"{ + ""Number"":""SO43659"", + ""Date"":""2011-05-31T00:00:00"" + }", reader.GetString(4)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("SO43661", reader.GetString(0)); + Assert.AreEqual(new DateTime(2011, 6, 1), reader.GetDateTime(1)); + Assert.AreEqual("AW73565", reader.GetString(2)); + Assert.AreEqual(3, reader.GetInt32(3)); + Assert.AreEqual(@"{ + ""Number"":""SO43661"", + ""Date"":""2011-06-01T00:00:00"" + }", reader.GetString(4)); + + Assert.IsFalse(reader.Read()); + } + } + } + + [TestMethod] + public void MergeJson() + { + using (var con = new Sql4CdsConnection(_localDataSource)) + using (var cmd = con.CreateCommand()) + { + cmd.CommandText = @" +DECLARE @json1 NVARCHAR(MAX),@json2 NVARCHAR(MAX) + +SET @json1=N'{""name"": ""John"", ""surname"":""Doe""}' + +SET @json2=N'{""name"": ""John"", ""age"":45}' + +SELECT * +FROM OPENJSON(@json1) +UNION ALL +SELECT * +FROM OPENJSON(@json2) +WHERE [key] NOT IN (SELECT [key] FROM OPENJSON(@json1))"; + + using (var reader = cmd.ExecuteReader()) + { + Assert.AreEqual("key", reader.GetName(0)); + Assert.AreEqual("value", reader.GetName(1)); + Assert.AreEqual("type", reader.GetName(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("name", reader.GetString(0)); + Assert.AreEqual("John", reader.GetString(1)); + Assert.AreEqual(1, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("surname", reader.GetString(0)); + Assert.AreEqual("Doe", reader.GetString(1)); + Assert.AreEqual(1, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("age", reader.GetString(0)); + Assert.AreEqual("45", reader.GetString(1)); + Assert.AreEqual(2, reader.GetInt32(2)); + + Assert.IsFalse(reader.Read()); + } + } + } + + [TestMethod] + public void NestedJson() + { + using (var con = new Sql4CdsConnection(_localDataSource)) + using (var cmd = con.CreateCommand()) + { + cmd.CommandText = @" +--simple cross apply example +DECLARE @JSON NVARCHAR(MAX) = N'[ +{ +""OrderNumber"":""SO43659"", +""OrderDate"":""2011-05-31T00:00:00"", +""AccountNumber"":""AW29825"", +""ItemPrice"":2024.9940, +""ItemQuantity"":1 +}, +{ +""OrderNumber"":""SO43661"", +""OrderDate"":""2011-06-01T00:00:00"", +""AccountNumber"":""AW73565"", +""ItemPrice"":2024.9940, +""ItemQuantity"":3 +} +]' + +SELECT root.[key] AS [Order],TheValues.[key], TheValues.[value] +FROM OPENJSON ( @JSON ) AS root +CROSS APPLY OPENJSON ( root.value) AS TheValues"; + + using (var reader = cmd.ExecuteReader()) + { + Assert.AreEqual("Order", reader.GetName(0)); + Assert.AreEqual("key", reader.GetName(1)); + Assert.AreEqual("value", reader.GetName(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("0", reader.GetString(0)); + Assert.AreEqual("OrderNumber", reader.GetString(1)); + Assert.AreEqual("SO43659", reader.GetString(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("0", reader.GetString(0)); + Assert.AreEqual("OrderDate", reader.GetString(1)); + Assert.AreEqual("2011-05-31T00:00:00", reader.GetString(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("0", reader.GetString(0)); + Assert.AreEqual("AccountNumber", reader.GetString(1)); + Assert.AreEqual("AW29825", reader.GetString(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("0", reader.GetString(0)); + Assert.AreEqual("ItemPrice", reader.GetString(1)); + Assert.AreEqual("2024.9940", reader.GetString(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("0", reader.GetString(0)); + Assert.AreEqual("ItemQuantity", reader.GetString(1)); + Assert.AreEqual("1", reader.GetString(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("1", reader.GetString(0)); + Assert.AreEqual("OrderNumber", reader.GetString(1)); + Assert.AreEqual("SO43661", reader.GetString(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("1", reader.GetString(0)); + Assert.AreEqual("OrderDate", reader.GetString(1)); + Assert.AreEqual("2011-06-01T00:00:00", reader.GetString(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("1", reader.GetString(0)); + Assert.AreEqual("AccountNumber", reader.GetString(1)); + Assert.AreEqual("AW73565", reader.GetString(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("1", reader.GetString(0)); + Assert.AreEqual("ItemPrice", reader.GetString(1)); + Assert.AreEqual("2024.9940", reader.GetString(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("1", reader.GetString(0)); + Assert.AreEqual("ItemQuantity", reader.GetString(1)); + Assert.AreEqual("3", reader.GetString(2)); + + Assert.IsFalse(reader.Read()); + } + } + } + + [TestMethod] + public void RecursiveCTEJson() + { + using (var con = new Sql4CdsConnection(_localDataSource)) + using (var cmd = con.CreateCommand()) + { + cmd.CommandText = @" +DECLARE @JSON NVARCHAR(MAX) = N'[ +{ +""OrderNumber"":""SO43659"", +""OrderDate"":""2011-05-31T00:00:00"", +""AccountNumber"":""AW29825"", +""ItemPrice"":2024.9940, +""ItemQuantity"":1 +}, +{ +""OrderNumber"":""SO43661"", +""OrderDate"":""2011-06-01T00:00:00"", +""AccountNumber"":""AW73565"", +""ItemPrice"":2024.9940, +""ItemQuantity"":3 +} +]'; + + +with cte ([key], value, type) as ( + select '$[' + [key] + ']', value, type from OPENJSON(@json) + + union all + + select cte.[key] + case when cte.type = 4 then '[' + childvalues.[key] + ']' else '.' + childvalues.[key] end, childvalues.value, childvalues.type from cte cross apply OPENJSON(cte.value) as childvalues WHERE cte.type in (4, 5) +) + +SELECT * from CTE"; + + using (var reader = cmd.ExecuteReader()) + { + Assert.AreEqual("key", reader.GetName(0)); + Assert.AreEqual("value", reader.GetName(1)); + Assert.AreEqual("type", reader.GetName(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("$[0]", reader.GetString(0)); + Assert.AreEqual(@"{ +""OrderNumber"":""SO43659"", +""OrderDate"":""2011-05-31T00:00:00"", +""AccountNumber"":""AW29825"", +""ItemPrice"":2024.9940, +""ItemQuantity"":1 +}", reader.GetString(1)); + Assert.AreEqual(5, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("$[1]", reader.GetString(0)); + Assert.AreEqual(@"{ +""OrderNumber"":""SO43661"", +""OrderDate"":""2011-06-01T00:00:00"", +""AccountNumber"":""AW73565"", +""ItemPrice"":2024.9940, +""ItemQuantity"":3 +}", reader.GetString(1)); + Assert.AreEqual(5, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("$[1].OrderNumber", reader.GetString(0)); + Assert.AreEqual("SO43661", reader.GetString(1)); + Assert.AreEqual(1, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("$[1].OrderDate", reader.GetString(0)); + Assert.AreEqual("2011-06-01T00:00:00", reader.GetString(1)); + Assert.AreEqual(1, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("$[1].AccountNumber", reader.GetString(0)); + Assert.AreEqual("AW73565", reader.GetString(1)); + Assert.AreEqual(1, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("$[1].ItemPrice", reader.GetString(0)); + Assert.AreEqual("2024.9940", reader.GetString(1)); + Assert.AreEqual(2, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("$[1].ItemQuantity", reader.GetString(0)); + Assert.AreEqual("3", reader.GetString(1)); + Assert.AreEqual(2, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("$[0].OrderNumber", reader.GetString(0)); + Assert.AreEqual("SO43659", reader.GetString(1)); + Assert.AreEqual(1, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("$[0].OrderDate", reader.GetString(0)); + Assert.AreEqual("2011-05-31T00:00:00", reader.GetString(1)); + Assert.AreEqual(1, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("$[0].AccountNumber", reader.GetString(0)); + Assert.AreEqual("AW29825", reader.GetString(1)); + Assert.AreEqual(1, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("$[0].ItemPrice", reader.GetString(0)); + Assert.AreEqual("2024.9940", reader.GetString(1)); + Assert.AreEqual(2, reader.GetInt32(2)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("$[0].ItemQuantity", reader.GetString(0)); + Assert.AreEqual("1", reader.GetString(1)); + Assert.AreEqual(2, reader.GetInt32(2)); + + Assert.IsFalse(reader.Read()); + } + } + } + } +} diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/ExpressionExtensions.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/ExpressionExtensions.cs index 7998ff50..85a0e4c9 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/ExpressionExtensions.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/ExpressionExtensions.cs @@ -5,19 +5,12 @@ using System.Linq; using System.Linq.Expressions; using System.Reflection; -using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; -using System.Threading.Tasks; -using System.Xml; -using System.Xml.XPath; using MarkMpn.Sql4Cds.Engine.Visitors; -using Microsoft.Crm.Sdk.Messages; using Microsoft.SqlServer.TransactSql.ScriptDom; using Microsoft.Xrm.Sdk; -using Newtonsoft.Json.Linq; using Wmhelp.XPath2; -using Wmhelp.XPath2.Extensions; namespace MarkMpn.Sql4Cds.Engine.ExecutionPlan { @@ -640,47 +633,59 @@ private static MethodInfo GetMethod(FunctionCall func, ExpressionCompilationCont { KeyValuePair[] paramExpressionsWithType; - // Special case for DATEPART / DATEDIFF / DATEADD - first parameter looks like a field but is actually an identifier - if (func.FunctionName.Value.Equals("DATEPART", StringComparison.OrdinalIgnoreCase) || - func.FunctionName.Value.Equals("DATEDIFF", StringComparison.OrdinalIgnoreCase) || - func.FunctionName.Value.Equals("DATEADD", StringComparison.OrdinalIgnoreCase)) - { - paramExpressionsWithType = func.Parameters - .Select((param, index) => + paramExpressionsWithType = func.Parameters + .Select((param, index) => + { + // Special case for DATEPART / DATEDIFF / DATEADD - first parameter looks like a field but is actually an identifier + if (index == 0 && + ( + func.FunctionName.Value.Equals("DATEPART", StringComparison.OrdinalIgnoreCase) || + func.FunctionName.Value.Equals("DATEDIFF", StringComparison.OrdinalIgnoreCase) || + func.FunctionName.Value.Equals("DATEADD", StringComparison.OrdinalIgnoreCase) + )) { - if (index == 0) + // Check parameter is an expected datepart value + if (!(param is ColumnReferenceExpression col) || col.MultiPartIdentifier.Identifiers.Count != 1) + throw new NotSupportedQueryFragmentException("Expected a datepart name", param); + + try + { + ExpressionFunctions.DatePartToInterval(col.MultiPartIdentifier.Identifiers.Single().Value); + } + catch { - // Check parameter is an expected datepart value - if (!(param is ColumnReferenceExpression col)) - throw new NotSupportedQueryFragmentException("Expected a datepart name", param); - - try - { - ExpressionFunctions.DatePartToInterval(col.MultiPartIdentifier.Identifiers.Single().Value); - } - catch - { - throw new NotSupportedQueryFragmentException("Expected a datepart name", param); - } - - return new KeyValuePair(Expression.Constant(col.MultiPartIdentifier.Identifiers.Single().Value), DataTypeHelpers.NVarChar(col.MultiPartIdentifier.Identifiers.Single().Value.Length, context.PrimaryDataSource.DefaultCollation, CollationLabel.CoercibleDefault)); + throw new NotSupportedQueryFragmentException("Expected a datepart name", param); } - var paramExpr = param.ToExpression(context, contextParam, out var paramType); - return new KeyValuePair(paramExpr, paramType); - }) - .ToArray(); - } - else - { - paramExpressionsWithType = func.Parameters - .Select(param => + return new KeyValuePair(Expression.Constant(col.MultiPartIdentifier.Identifiers.Single().Value), DataTypeHelpers.NVarChar(col.MultiPartIdentifier.Identifiers.Single().Value.Length, context.PrimaryDataSource.DefaultCollation, CollationLabel.CoercibleDefault)); + } + + // Special case for ISJSON - second optional parameter looks like a field but is actually a JSON data type + if (index == 1 && func.FunctionName.Value.Equals("ISJSON", StringComparison.OrdinalIgnoreCase)) { - var paramExpr = param.ToExpression(context, contextParam, out var paramType); - return new KeyValuePair(paramExpr, paramType); - }) - .ToArray(); - } + // Check parameter is an expected datepart value + if (!(param is ColumnReferenceExpression col) || col.MultiPartIdentifier.Identifiers.Count != 1) + throw new NotSupportedQueryFragmentException("Expected a JSON type", param); + + switch (col.MultiPartIdentifier.Identifiers.Single().Value.ToLowerInvariant()) + { + case "value": + case "array": + case "object": + case "scalar": + break; + + default: + throw new NotSupportedQueryFragmentException("Expected a JSON type", param); + } + + return new KeyValuePair(Expression.Constant(col.MultiPartIdentifier.Identifiers.Single().Value), DataTypeHelpers.NVarChar(col.MultiPartIdentifier.Identifiers.Single().Value.Length, context.PrimaryDataSource.DefaultCollation, CollationLabel.CoercibleDefault)); + } + + var paramExpr = param.ToExpression(context, contextParam, out var paramType); + return new KeyValuePair(paramExpr, paramType); + }) + .ToArray(); if (func.CallTarget != null) { diff --git a/MarkMpn.Sql4Cds.Engine/ExpressionFunctions.cs b/MarkMpn.Sql4Cds.Engine/ExpressionFunctions.cs index c1716f46..0ea35309 100644 --- a/MarkMpn.Sql4Cds.Engine/ExpressionFunctions.cs +++ b/MarkMpn.Sql4Cds.Engine/ExpressionFunctions.cs @@ -52,6 +52,7 @@ public static SqlEntityReference CreateLookup(SqlString logicalName, SqlGuid id) /// A JSON path that specifies the property to extract /// Returns a single text value of type nvarchar(4000) [MaxLength(4000)] + [CollationSensitive] public static SqlString Json_Value(SqlString json, SqlString jpath) { if (json.IsNull || jpath.IsNull) @@ -73,18 +74,20 @@ public static SqlString Json_Value(SqlString json, SqlString jpath) throw new QueryExecutionException("Property does not exist"); } - if (jtoken.Value.ValueKind == JsonValueKind.Object || jtoken.Value.ValueKind == JsonValueKind.Array) + switch (jtoken.Value.ValueKind) { - if (jsonPath.Mode == JsonPathMode.Lax) + case JsonValueKind.Object: + case JsonValueKind.Array: + if (jsonPath.Mode == JsonPathMode.Lax) + return SqlString.Null; + else + throw new QueryExecutionException("Not a scalar value"); + + case JsonValueKind.Null: return SqlString.Null; - else - throw new QueryExecutionException("Not a scalar value"); } - var value = jtoken.Value.GetString(); - - if (value == null) - return SqlString.Null; + var value = jtoken.Value.ToString(); if (value.Length > 4000) { @@ -102,6 +105,53 @@ public static SqlString Json_Value(SqlString json, SqlString jpath) } } + /// + /// Extracts an object or an array from a JSON string + /// + /// An expression containing the JSON document to parse + /// A JSON path that specifies the property to extract + /// Returns a JSON fragment of type nvarchar(max) + [CollationSensitive] + public static SqlString Json_Query(SqlString json, SqlString jpath) + { + if (json.IsNull || jpath.IsNull) + return SqlString.Null; + + var path = jpath.Value; + + try + { + var jsonPath = new JsonPath(path); + var jsonDoc = JsonDocument.Parse(json.Value); + var jtoken = jsonPath.Evaluate(jsonDoc.RootElement); + + if (jtoken == null) + { + if (jsonPath.Mode == JsonPathMode.Lax) + return SqlString.Null; + else + throw new QueryExecutionException("Property does not exist"); + } + + switch (jtoken.Value.ValueKind) + { + case JsonValueKind.Object: + case JsonValueKind.Array: + return new SqlString(jtoken.Value.ToString(), json.LCID, json.SqlCompareOptions); + + default: + if (jsonPath.Mode == JsonPathMode.Lax) + return SqlString.Null; + else + throw new QueryExecutionException("Not a scalar value"); + } + } + catch (Newtonsoft.Json.JsonException ex) + { + throw new QueryExecutionException(ex.Message, ex); + } + } + /// /// Tests whether a specified SQL/JSON path exists in the input JSON string. /// @@ -995,6 +1045,77 @@ public static SqlVariant Sql_Variant_Property(SqlVariant expression, SqlString p return SqlVariant.Null; } + + /// + /// Tests whether a string contains valid JSON + /// + /// The string to test + /// null if is null, true if the input is a valid JSON object or array or false otherwise + public static SqlBoolean IsJson(SqlString json) + { + if (json.IsNull) + return SqlBoolean.Null; + + var reader = new Utf8JsonReader(Encoding.UTF8.GetBytes(json.Value).AsSpan()); + JsonElement? element; + + try + { + if (!JsonElement.TryParseValue(ref reader, out element) || element == null) + return false; + } + catch (JsonException) + { + return false; + } + + if (!reader.IsFinalBlock) + return false; + + return element.Value.ValueKind == JsonValueKind.Array || element.Value.ValueKind == JsonValueKind.Object; + } + + /// + /// Tests whether a string contains valid JSON + /// + /// The string to test + /// Specifies the JSON type to check in the input + /// Returns true if the string contains valid JSON; otherwise, returns false. Returns null if expression is null + public static SqlBoolean IsJson(SqlString json, SqlString type) + { + if (json.IsNull) + return SqlBoolean.Null; + + var reader = new Utf8JsonReader(Encoding.UTF8.GetBytes(json.Value).AsSpan()); + JsonElement? element; + + try + { + if (!JsonElement.TryParseValue(ref reader, out element) || element == null) + return false; + } + catch (JsonException) + { + return false; + } + + if (!reader.IsFinalBlock) + return false; + + if (type.Value.Equals("VALUE", StringComparison.OrdinalIgnoreCase)) + return true; + + if (type.Value.Equals("ARRAY", StringComparison.OrdinalIgnoreCase)) + return element.Value.ValueKind == JsonValueKind.Array; + + if (type.Value.Equals("OBJECT", StringComparison.OrdinalIgnoreCase)) + return element.Value.ValueKind == JsonValueKind.Object; + + if (type.Value.Equals("SCALAR", StringComparison.OrdinalIgnoreCase)) + return element.Value.ValueKind == JsonValueKind.String || element.Value.ValueKind == JsonValueKind.Number; + + return false; + } } /// diff --git a/MarkMpn.Sql4Cds.Engine/JsonPath.cs b/MarkMpn.Sql4Cds.Engine/JsonPath.cs index 7bc9a236..a500733c 100644 --- a/MarkMpn.Sql4Cds.Engine/JsonPath.cs +++ b/MarkMpn.Sql4Cds.Engine/JsonPath.cs @@ -27,7 +27,7 @@ public JsonPath(string expression) /// /// Returns the mode the path should be evaluated in /// - public JsonPathMode Mode { get; } + public JsonPathMode Mode { get => _mode; } /// /// Finds the token matching the path diff --git a/MarkMpn.Sql4Cds.LanguageServer/Autocomplete/FunctionMetadata.cs b/MarkMpn.Sql4Cds.LanguageServer/Autocomplete/FunctionMetadata.cs index 100893a4..b6523c58 100644 --- a/MarkMpn.Sql4Cds.LanguageServer/Autocomplete/FunctionMetadata.cs +++ b/MarkMpn.Sql4Cds.LanguageServer/Autocomplete/FunctionMetadata.cs @@ -58,6 +58,12 @@ public abstract class SqlFunctions [Description("Extracts a scalar value from a JSON string")] public abstract string json_value(string json, string path); + [Description("Extracts an object or an array from a JSON string")] + public abstract string json_query(string json, string path); + + [Description("Tests whether a string contains valid JSON")] + public abstract string isjson(string json, string type); + [Description("Tests whether a specified SQL/JSON path exists in the input JSON string")] public abstract bool json_path_exists(string json, string path); diff --git a/MarkMpn.Sql4Cds.XTB/FunctionMetadata.cs b/MarkMpn.Sql4Cds.XTB/FunctionMetadata.cs index da81ce41..f9dcbe3e 100644 --- a/MarkMpn.Sql4Cds.XTB/FunctionMetadata.cs +++ b/MarkMpn.Sql4Cds.XTB/FunctionMetadata.cs @@ -58,6 +58,12 @@ public abstract class SqlFunctions [Description("Extracts a scalar value from a JSON string")] public abstract string json_value(string json, string path); + [Description("Extracts an object or an array from a JSON string")] + public abstract string json_query(string json, string path); + + [Description("Tests whether a string contains valid JSON")] + public abstract string isjson(string json, string type); + [Description("Tests whether a specified SQL/JSON path exists in the input JSON string")] public abstract bool json_path_exists(string json, string path); From 6497d277981dd0e927955a27492ea5e7e5789866 Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Fri, 17 Nov 2023 08:53:40 +0000 Subject: [PATCH 63/81] Added new files to project --- MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.projitems | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.projitems b/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.projitems index 36ff8fa9..597c12b4 100644 --- a/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.projitems +++ b/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.projitems @@ -29,11 +29,13 @@ + + From 9670131fef98b9b7bfe7b0909b4c0d9e14ad657d Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Fri, 17 Nov 2023 17:20:50 +0000 Subject: [PATCH 64/81] Made TVF display consistent in execution plan --- MarkMpn.Sql4Cds.Controls/ExecutionPlanView.cs | 2 ++ MarkMpn.Sql4Cds.Engine/ExecutionPlan/ExecuteMessageNode.cs | 5 +++++ MarkMpn.Sql4Cds.Engine/ExecutionPlan/OpenJsonNode.cs | 5 +++++ MarkMpn.Sql4Cds.Engine/ExecutionPlan/SystemFunctionNode.cs | 5 +++++ .../QueryExecution/QueryExecutionHandler.cs | 4 ++++ 5 files changed, 21 insertions(+) diff --git a/MarkMpn.Sql4Cds.Controls/ExecutionPlanView.cs b/MarkMpn.Sql4Cds.Controls/ExecutionPlanView.cs index e3f054b0..0c9f553b 100644 --- a/MarkMpn.Sql4Cds.Controls/ExecutionPlanView.cs +++ b/MarkMpn.Sql4Cds.Controls/ExecutionPlanView.cs @@ -145,6 +145,8 @@ protected override void OnPaint(PaintEventArgs e) if (imageName == "AdaptiveIndexSpoolNode") imageName = "IndexSpoolNode"; + else if (imageName == "OpenJsonNode" || imageName == "SystemFunctionNode") + imageName = "ExecuteMessageNode"; using (var stream = GetType().Assembly.GetManifestResourceStream(GetType(), "Images." + imageName + ".ico")) { diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/ExecuteMessageNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/ExecuteMessageNode.cs index 16d59673..485b67a7 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/ExecuteMessageNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/ExecuteMessageNode.cs @@ -704,5 +704,10 @@ IRootExecutionPlanNodeInternal[] IRootExecutionPlanNodeInternal.FoldQuery(NodeCo FoldQuery(context, hints); return new[] { this }; } + + public override string ToString() + { + return $"Table Valued Function\r\n[{MessageName}]"; + } } } diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/OpenJsonNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/OpenJsonNode.cs index 3626cc7b..37b86509 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/OpenJsonNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/OpenJsonNode.cs @@ -440,5 +440,10 @@ public override object Clone() _conversions = _conversions, }; } + + public override string ToString() + { + return $"Table Valued Function\r\n[OPENJSON_{(Schema == null ? "DEFAULT" : "EXPLICIT")}]"; + } } } diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/SystemFunctionNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/SystemFunctionNode.cs index a74c8867..51c6a6a5 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/SystemFunctionNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/SystemFunctionNode.cs @@ -110,6 +110,11 @@ private string PrefixWithAlias(string columnName) return Alias + "." + columnName; } + + public override string ToString() + { + return $"Table Valued Function\r\n[{SystemFunction}]"; + } } enum SystemFunction diff --git a/MarkMpn.Sql4Cds.LanguageServer/QueryExecution/QueryExecutionHandler.cs b/MarkMpn.Sql4Cds.LanguageServer/QueryExecution/QueryExecutionHandler.cs index 692f4ec3..86e16af5 100644 --- a/MarkMpn.Sql4Cds.LanguageServer/QueryExecution/QueryExecutionHandler.cs +++ b/MarkMpn.Sql4Cds.LanguageServer/QueryExecution/QueryExecutionHandler.cs @@ -725,6 +725,10 @@ private ExecutionPlanNode ConvertExecutionPlanNode(IExecutionPlanNode node, Time converted.Type = "udx"; else if (converted.Type == "adaptiveIndexSpool") converted.Type = "indexSpool"; + else if (converted.Type == "openJson") + converted.Type = "tableValuedFunction"; + else if (converted.Type == "systemFunction") + converted.Type = "tableValuedFunction"; // Get the filtered list of properties var typeDescriptor = new ExecutionPlanNodeTypeDescriptor(node, !executed, _ => null); From 7d52cc7a0f2745877c343968b2fc156120d35a28 Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Fri, 17 Nov 2023 17:21:12 +0000 Subject: [PATCH 65/81] Made OPENJSON handling of scalar values consistent with SQL Server --- MarkMpn.Sql4Cds.Engine/ExecutionPlan/OpenJsonNode.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/OpenJsonNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/OpenJsonNode.cs index 37b86509..8a1ed57b 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/OpenJsonNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/OpenJsonNode.cs @@ -224,6 +224,11 @@ protected override IEnumerable ExecuteInternal(NodeExecutionContext cont { jpath = new JsonPath(path); jsonDoc = JsonDocument.Parse(json.Value).RootElement; + + // Don't allow JSON scalar values, only objects or arrays + if (jsonDoc.ValueKind != JsonValueKind.Object && jsonDoc.ValueKind != JsonValueKind.Array) + throw new JsonException("JSON text is not properly formatted. Object or array is required"); + jtoken = jpath.Evaluate(jsonDoc); } catch (JsonException ex) From 7d14f8e5ba0fa5508c91b2dfa757236cfd1a4d88 Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Sat, 18 Nov 2023 14:30:20 +0000 Subject: [PATCH 66/81] Find & Replace improvements --- MarkMpn.Sql4Cds.XTB/FindReplace.Designer.cs | 2 ++ MarkMpn.Sql4Cds.XTB/FindReplace.cs | 37 +++++++++++++++++++-- MarkMpn.Sql4Cds.XTB/FindReplace.resx | 36 ++++++++++---------- 3 files changed, 54 insertions(+), 21 deletions(-) diff --git a/MarkMpn.Sql4Cds.XTB/FindReplace.Designer.cs b/MarkMpn.Sql4Cds.XTB/FindReplace.Designer.cs index 34c49d6d..9900f0d2 100644 --- a/MarkMpn.Sql4Cds.XTB/FindReplace.Designer.cs +++ b/MarkMpn.Sql4Cds.XTB/FindReplace.Designer.cs @@ -155,6 +155,7 @@ private void InitializeComponent() this.replaceToolStripButton.Name = "replaceToolStripButton"; this.replaceToolStripButton.Size = new System.Drawing.Size(23, 20); this.replaceToolStripButton.Text = "Replace Next"; + this.replaceToolStripButton.ToolTipText = "Replace Next (Alt+A)"; this.replaceToolStripButton.Click += new System.EventHandler(this.replaceToolStripButton_Click); // // replaceAllToolStripButton @@ -165,6 +166,7 @@ private void InitializeComponent() this.replaceAllToolStripButton.Name = "replaceAllToolStripButton"; this.replaceAllToolStripButton.Size = new System.Drawing.Size(23, 20); this.replaceAllToolStripButton.Text = "Replace All"; + this.replaceAllToolStripButton.ToolTipText = "Replace All (Alt+R)"; this.replaceAllToolStripButton.Click += new System.EventHandler(this.replaceAllToolStripButton_Click); // // optionsSpacerToolStripLabel diff --git a/MarkMpn.Sql4Cds.XTB/FindReplace.cs b/MarkMpn.Sql4Cds.XTB/FindReplace.cs index df007127..654a1f9e 100644 --- a/MarkMpn.Sql4Cds.XTB/FindReplace.cs +++ b/MarkMpn.Sql4Cds.XTB/FindReplace.cs @@ -132,6 +132,18 @@ protected override bool ProcessCmdKey(ref Message msg, Keys keyData) return true; } + if (keyData == (Keys.Alt | Keys.R) && ShowReplace) + { + Replace(false); + return true; + } + + if (keyData == (Keys.Alt | Keys.A) && ShowReplace) + { + Replace(true); + return true; + } + return base.ProcessCmdKey(ref msg, keyData); } @@ -176,6 +188,7 @@ public void FindNext() if (match != -1) { _editor.SetSelection(_editor.TargetStart, _editor.TargetEnd); + _editor.ScrollCaret(); break; } else if (_editor.TargetStart > 0) @@ -219,6 +232,7 @@ public void FindPrevious() if (match != -1) { _editor.SetSelection(_editor.TargetStart, _editor.TargetEnd); + _editor.ScrollCaret(); break; } else if (_editor.TargetStart < _editor.TextLength) @@ -252,7 +266,7 @@ private void replaceAllToolStripButton_Click(object sender, EventArgs e) Replace(true); } - private void Replace(bool all) + public void Replace(bool all) { AddHistory(findToolStripComboBox); AddHistory(replaceToolStripComboBox); @@ -273,20 +287,28 @@ private void Replace(bool all) _editor.TargetStart = all ? 0 : _editor.SelectionStart + 1; _editor.TargetEnd = _editor.TextLength; + var replacements = 0; + var lastMatch = -1; + var lastReplacementLength = 0; + while (true) { var match = _editor.SearchInTarget(findToolStripComboBox.Text); if (match != -1) { + lastMatch = match; + if (regexToolStripButton.Checked) - _editor.ReplaceTargetRe(replaceToolStripComboBox.Text); + lastReplacementLength = _editor.ReplaceTargetRe(replaceToolStripComboBox.Text); else - _editor.ReplaceTarget(replaceToolStripComboBox.Text); + lastReplacementLength = _editor.ReplaceTarget(replaceToolStripComboBox.Text); if (!all) break; + replacements++; + _editor.TargetStart = _editor.TargetEnd; _editor.TargetEnd = _editor.TextLength; } @@ -301,6 +323,15 @@ private void Replace(bool all) } _editor.EndUndoAction(); + + if (replacements > 0) + { + _editor.SetSelection(lastMatch, lastMatch + lastReplacementLength); + _editor.ScrollCaret(); + } + + if (all) + MessageBox.Show($"{replacements} occurrence(s) replaced.", "Replace All", MessageBoxButtons.OK, MessageBoxIcon.Information); } } } diff --git a/MarkMpn.Sql4Cds.XTB/FindReplace.resx b/MarkMpn.Sql4Cds.XTB/FindReplace.resx index 4e24c47e..eaf5e9df 100644 --- a/MarkMpn.Sql4Cds.XTB/FindReplace.resx +++ b/MarkMpn.Sql4Cds.XTB/FindReplace.resx @@ -128,21 +128,12 @@ aC/86M4GG1mxO/tV6P5/X0LdECIa+LlhL/sRY3zmnD8ppZFPM7ghQ4dPLSxP1lry3lM9gjduyNDpjpTg FUIgrTUZY+YRkXFDhg66rC2U/z1K+e2ca0ZqGRk66LLW0hv5WxbWI4dkoR45LAsyckoWIJ6Wr4JSXwmW 2bf59kcYAAAAAElFTkSuQmCC - - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACZSURBVDhPYyAEvn//nvzp0ydRKJc08O3bt4rXr1//B9KX - STYEpPnu3bv/Q0ND/y9cuJA0Q/7//88B0rBq1ar/Tk5OYEyyISCFIA0gjbQ1BMgBCRDEOA0BScIkSMEw - Q6hjADF42rRpGJoJBiZRgYgLUKQZlpBWrFhBumYYACquuHbt2v+AgADSNcMAyJAXL16QpxkG8GdnBgYA - FtuEliCNINgAAAAASUVORK5CYII= iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - xAAADsQBlSsOGwAAAJpJREFUOE+1k7kNQyEQRAndwG+ICkiowE38SsjJEO1YIiNHIiddzyJvZP1jkT3S + wwAADsMBx2+oZAAAAJpJREFUOE+1k7kNQyEQRAndwG+ICkiowE38SsjJEO1YIiNHIiddzyJvZP1jkT3S iGvfSFzmSmOMJ7x9hjoB3HvvhPalDmG41kree4ox6kJQ+GAg50zW2umVkI0BBv8bgg5PXPowhBdlQWMJ +U3AHYcQvmB4buHMtw7xyOvXiIL5kFJKeliEwr2UQs45PSzikNbaGiwCePKdjXkDE3GqrEJQ/eEAAAAA SUVORK5CYII= @@ -151,10 +142,19 @@ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - xAAADsQBlSsOGwAAAJdJREFUOE9jwAW+ffsmCsTJUC5pAKr58uvXr/8D6QqoMHEApnnhwoX/Q0ND/9+9 + wwAADsMBx2+oZAAAAJdJREFUOE9jwAW+ffsmCsTJUC5pAKr58uvXr/8D6QqoMHEApnnhwoX/Q0ND/9+9 e5d4Q5A1Ozk5gfGqVatABlwGYg6oMuwAm2YQG6pZFKoMO6CVZqIwyAAUzaRgqhmA4YVp06ahOBMfJhQO 4EAEYpAarBgOgByyDEEBQAEMQ4hOSDCAbAjJSRkGYIaQlZlgAGoIgezMwAAAzlaq30/lAWMAAAAASUVO RK5CYII= + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACZSURBVDhPYyAEvn//nvzp0ydRKJc08O3bt4rXr1//B9KX + STYEpPnu3bv/Q0ND/y9cuJA0Q/7//88B0rBq1ar/Tk5OYEyyISCFIA0gjbQ1BMgBCRDEOA0BScIkSMEw + Q6hjADF42rRpGJoJBiZRgYgLUKQZlpBWrFhBumYYACquuHbt2v+AgADSNcMAyJAXL16QpxkG8GdnBgYA + FtuEliCNINgAAAAASUVORK5CYII= @@ -208,13 +208,13 @@ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAFOSURBVDhPzVK/S8NAFI6Lg6M4iKv/hGuCg2R1LATBxQ5C - QyFLoFMHs+WP6OQgDckYFff+AWKJcaqBZEjzE4r1+d1xCjWHOPaDB+/ufd93996dsp0got22bS/KsqQ0 - TSnLMloulx/Y3xOUv1HX9UPTNHdRFJGmadTv9wnr96qqnlC7EjQ5QDhaLBafnucRcm7gui4lSUK+77O9 - e0GVA4TrIAhIVVUu7vV6ZFkWz1nAaJ3n+b6gdwGDR2YwGo341ZlI13UaDoc0Ho9pPp8T5nMp6JvAkHbQ - qwWTZzY80zTJMAxuMplM2BxY3GIWupB0AfE5Iw4GAy4Mw5Bs2+b5dDqloijepK8h3H8ijmPeO/pdz2Yz - chyHcHKKA06EZBNMxAb3HWyNt19BcIP/8ArxC3o/FvQuZAYQnEJ4iDjD1Q8EVQ6ZgSj9D0zwO0Rpq6Eo - X0BoPgmkWlyhAAAAAElFTkSuQmCC + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAFPSURBVDhPzVIxS8NAGI2Lg6M4iKt/wrXBQbI6BoLgYgYh + IZAlkKmD2fIjMjlISjtGxb0/QAwxLiGFBBLSNAWxfr47TqE2iGMffHB333vv7nuJtJ0got3lcnkxn8+p + KAoqy5Lquv7A+Z6g/I3FYvHQdd1dkiQkyzLpuk7Y523bPqF3JWj9AOEoy7LP0WhEWHMD3/dpNpvReDxm + Z/eC2g8QrieTCQ0GAy5WVZVs2+ZrVnmerzDOvqBvAgaPzMB1Xf50JlIUhSzLouFwSHEcE/K5FPR1IKQd + zGrD5JmFZ5omaZrGTYIgYDmwukUWipBsAuJzRjQMgwujKCLHcfg6DENqmuat92sI959K05TPXlXVajqd + kud5hJsLXHAiJOtgIhbcd7E9wnqH4Ab/wyvEL5j9WNA30WcAwSmEh6gzPP1AUPvRZyBa/wMT/C7R2mpI + 0hccaD36l+69nwAAAABJRU5ErkJggg== \ No newline at end of file From 595fcd4c7919bffbb0ee82f72efac3ecb9e83d75 Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Sat, 18 Nov 2023 14:31:00 +0000 Subject: [PATCH 67/81] Improved handling of ambiguous column names from un-aliased TVFs Fixed collation of OPENJSON values --- .../ExecutionPlan/NodeSchema.cs | 19 ++++++++++++++----- .../ExecutionPlan/OpenJsonNode.cs | 15 ++++++++------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/NodeSchema.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/NodeSchema.cs index 01999a90..d2e5b7d2 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/NodeSchema.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/NodeSchema.cs @@ -77,15 +77,24 @@ public NodeSchema(INodeSchema copy) /// true if the column name exists, or false otherwise public bool ContainsColumn(string column, out string normalized) { - if (Schema.TryGetValue(column, out _)) + if (Aliases.TryGetValue(column, out var names)) { - normalized = Schema.Keys.Single(k => k.Equals(column, StringComparison.OrdinalIgnoreCase)); - return true; + if (names.Count > 1) + { + normalized = null; + return false; + } + + if (names.Count == 1) + { + normalized = names[0]; + return true; + } } - if (Aliases.TryGetValue(column, out var names) && names.Count == 1) + if (Schema.TryGetValue(column, out _)) { - normalized = names[0]; + normalized = Schema.Keys.Single(k => k.Equals(column, StringComparison.OrdinalIgnoreCase)); return true; } diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/OpenJsonNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/OpenJsonNode.cs index 8a1ed57b..afd0f9a9 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/OpenJsonNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/OpenJsonNode.cs @@ -92,9 +92,6 @@ public override IDataExecutionPlanNodeInternal FoldQuery(NodeCompilationContext _jsonExpression = Json.Compile(ecc); _pathExpression = Path?.Compile(ecc); - Json.GetType(ecc, out var jsonType); - _jsonCollation = (jsonType as SqlDataTypeReferenceWithCollation)?.Collation ?? context.PrimaryDataSource.DefaultCollation; - return this; } @@ -105,6 +102,13 @@ public override INodeSchema GetSchema(NodeCompilationContext context) if (Schema == null) { + if (_jsonCollation == null) + { + var ecc = new ExpressionCompilationContext(context, null, null); + Json.GetType(ecc, out var jsonType); + _jsonCollation = (jsonType as SqlDataTypeReferenceWithCollation)?.Collation ?? context.PrimaryDataSource.DefaultCollation; + } + columns.Add(PrefixWithAlias("key", aliases), new ColumnDefinition(DataTypeHelpers.NVarChar(4000, _keyCollation, CollationLabel.Implicit), false, false)); columns.Add(PrefixWithAlias("value", aliases), new ColumnDefinition(DataTypeHelpers.NVarChar(Int32.MaxValue, _jsonCollation, CollationLabel.Implicit), true, false)); columns.Add(PrefixWithAlias("type", aliases), new ColumnDefinition(DataTypeHelpers.Int, false, false)); @@ -162,10 +166,7 @@ private string PrefixWithAlias(string name, IDictionary Date: Sat, 18 Nov 2023 17:56:42 +0000 Subject: [PATCH 68/81] Fix partitioned aggregate error handling for dense data Fixes #387 --- .../ExecutionPlan/PartitionedAggregateNode.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/PartitionedAggregateNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/PartitionedAggregateNode.cs index 5c82120c..9041e45d 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/PartitionedAggregateNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/PartitionedAggregateNode.cs @@ -103,8 +103,8 @@ protected override IEnumerable ExecuteInternal(NodeExecutionContext cont var minKey = GetMinMaxKey(fetchXmlNode, context, false); var maxKey = GetMinMaxKey(fetchXmlNode, context, true); - if (minKey.IsNull || maxKey.IsNull || minKey == maxKey) - throw new QueryExecutionException("Cannot partition query"); + if (minKey.IsNull || maxKey.IsNull || minKey >= maxKey) + throw new PartitionOverflowException(); // Add the filter to the FetchXML to partition the results fetchXmlNode.Entity.AddItem(new filter @@ -128,9 +128,6 @@ protected override IEnumerable ExecuteInternal(NodeExecutionContext cont partitionParameterTypes[kvp.Key] = kvp.Value; } - if (minKey > maxKey) - throw new QueryExecutionException("Cannot partition query"); - // Split recursively, add up values below & above split value if query returns successfully, or re-split on error // Range is > MinValue AND <= MaxValue, so start from just before first record to ensure the first record is counted var fullRange = new Partition @@ -167,7 +164,7 @@ protected override IEnumerable ExecuteInternal(NodeExecutionContext cont { var partitioner = Partitioner.Create(_queue.GetConsumingEnumerable(), EnumerablePartitionerOptions.NoBuffering); Parallel.ForEach(partitioner, - new ParallelOptions { MaxDegreeOfParallelism = maxDop }, + new ParallelOptions { MaxDegreeOfParallelism = maxDop, CancellationToken = context.Options.CancellationToken }, () => { var ds = new Dictionary @@ -284,7 +281,10 @@ private void SplitPartition(Partition partition) // Fail if we get stuck on a particularly dense partition. If there's > 50K records in a 10 second window we probably // won't be able to split it successfully if (partition.MaxValue.Value < partition.MinValue.Value.AddSeconds(10)) + { + _queue.CompleteAdding(); throw new PartitionOverflowException(); + } // Start splitting partitions in half. Once we've done that a few times and are still hitting the 50K limit, start // pre-emptively splitting into smaller chunks From e955970aa4908bd2274876cf67464bb2c3a1c0cd Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Mon, 20 Nov 2023 21:10:34 +0000 Subject: [PATCH 69/81] Added "Yes To All" option for DML confirmation dialogs --- AzureDataStudioExtension/CHANGELOG.md | 33 +- AzureDataStudioExtension/package-lock.json | 705 +++++++++++++--- AzureDataStudioExtension/package.json | 2 +- AzureDataStudioExtension/src/main.ts | 4 +- AzureDataStudioExtension/yarn.lock | 775 ++++++++++-------- .../Contracts/ConfirmationResponse.cs | 9 +- .../QueryExecution/QueryExecutionHandler.cs | 10 +- .../MarkMpn.Sql4Cds.XTB.csproj | 1 + MarkMpn.Sql4Cds.XTB/MessageBoxExt.cs | 431 ++++++++++ MarkMpn.Sql4Cds.XTB/QueryExecutionOptions.cs | 9 +- 10 files changed, 1513 insertions(+), 466 deletions(-) create mode 100644 MarkMpn.Sql4Cds.XTB/MessageBoxExt.cs diff --git a/AzureDataStudioExtension/CHANGELOG.md b/AzureDataStudioExtension/CHANGELOG.md index 8687af2b..6a1e3422 100644 --- a/AzureDataStudioExtension/CHANGELOG.md +++ b/AzureDataStudioExtension/CHANGELOG.md @@ -1,6 +1,37 @@ # Change Log -## [v7.6.1)(https://github.com/MarkMpn/Sql4Cds/releases/tag/v7.6.1) - 2023-10-15 +## [v8.0.0](https://github.com/MarkMpn/Sql4Cds/releases/tag/v8.0.0) - 2023-11-18 + +Added Common Table Expression support: +- Non-recursive CTEs are expanded to subqueries for compatibility with TDS Endpoint +- Recurve CTEs are converted to hierarchical FetchXML filters where possible + +Extended JSON support: +- `OPENJSON` table-valued function +- `JSON_QUERY` function +- `ISJSON` function + +Query optimizer improvements: +- Prefer hash joins over merge joins if sorts cannot be folded +- Switch FetchXML sorts to custom sorting after adding joins that require custom paging +- Avoid folding filters to tables in subqueries if the same alias exists in the outer query +- Do not use a left outer join to implement `NOT IN` queries where the subquery uses an inner join + +Added `IGNORE_DUP_KEY` query hint to ignore duplicate key errors on insert +Added check for multi-currency issues when aggregating non-base currency fields +Added support for disconnecting instances from Azure Data Studio object explorer +Added plugin log messages in error message output +Clearer progress messages for multi-threaded DML operations +Added autocomplete literal value suggestions for entityname attributes + +Fixed use of `UNION` with wildcard columns +Fixed error in nested loop joins with no records from inner source +Fixed use of columns from outer queries in join criteria in subqueries +Fixed time zone mismatch when starting bulk delete jobs +Fixed setting polymorphic lookup fields using TDS Endpoint +Fixed aggregates with very dense data distribution + +## [v7.6.1](https://github.com/MarkMpn/Sql4Cds/releases/tag/v7.6.1) - 2023-10-15 Fixed use of `IN` subqueries when data source cannot be converted to FetchXML Fixed use of `LIKE` filters with data containing embedded returns diff --git a/AzureDataStudioExtension/package-lock.json b/AzureDataStudioExtension/package-lock.json index 073b3572..103a1e88 100644 --- a/AzureDataStudioExtension/package-lock.json +++ b/AzureDataStudioExtension/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@microsoft/ads-service-downloader": "1.0.2", "crypto": "^1.0.1", - "dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#0.3.0", + "dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#1.3.1", "eventemitter2": "^5.0.1", "opener": "^1.5.2", "tmp": "0.2.1 ", @@ -19,11 +19,11 @@ "vscode-languageclient": "5.2.1" }, "devDependencies": { - "@types/azdata": "1.38.0", + "@types/azdata": "1.40.0", "@types/node": "^13.11.0", - "@types/vscode": "^1.39.0", + "@types/vscode": "1.71.0", "del": "^6.1.1", - "gulp": "github:gulpjs/gulp#4.0.2", + "gulp": "github:gulpjs/gulp#v4.0.2", "gulp-json-editor": "^2.5.6", "gulp-rename": "^2.0.0", "gulp-shell": "^0.8.0", @@ -35,7 +35,7 @@ "vscode-nls-dev": "https://github.com/Raymondd/vscode-nls-dev/releases/download/2.0.2/build.tar.gz" }, "engines": { - "azdata": ">=1.40.0", + "azdata": ">=1.30.0", "vscode": "*" } }, @@ -259,9 +259,9 @@ } }, "node_modules/@types/azdata": { - "version": "1.38.0", - "resolved": "https://registry.npmjs.org/@types/azdata/-/azdata-1.38.0.tgz", - "integrity": "sha512-yXvy8+j2LgWoe7cX33doTDdv/0d7LMDEm3IfrXZ/EU4AwwzjvKqSR/0Ae0CH3o8WOvDm63bws++gxDlmhoLsPg==", + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/@types/azdata/-/azdata-1.40.0.tgz", + "integrity": "sha512-CGsuH9wY6616UGskR1bMd3KcOTHhh43dQz9ruSji3EmzUG6EYJCE+6D3+UZ6M+Ub73XzDeYXobe/rk+fGkaYlg==", "dev": true, "dependencies": { "@types/vscode": "*" @@ -351,15 +351,6 @@ "node": ">=0.10.0" } }, - "node_modules/ansi-regex": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", - "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -680,6 +671,15 @@ "node": ">=0.10.0" } }, + "node_modules/array-sort/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -1030,6 +1030,28 @@ "fsevents": "^1.2.7" } }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", + "dev": true, + "dependencies": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + } + }, + "node_modules/chokidar/node_modules/glob-parent/node_modules/is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/chownr": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", @@ -1275,51 +1297,17 @@ } }, "node_modules/dataprotocol-client": { - "version": "0.3.0", - "resolved": "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/21487d15a5f753ba885ce1e489abc0af03487544", - "integrity": "sha512-QRQenym6p0KkXT8l/WRu86B8EkT9F5HzMuVzw0CFxpSr1zXjpxduAorvWI37amqWlMbS6MUVC1tLuMb11Ba7MA==", + "version": "1.3.1", + "resolved": "git+ssh://git@github.com/Microsoft/sqlops-dataprotocolclient.git#2df6982e07c0208c2b8a5f8cd4b3d65944138d15", "license": "ISC", "dependencies": { - "vscode-languageclient": "3.5.1" + "vscode-languageclient": "5.2.1" }, "engines": { "azdata": "*", "vscode": "*" } }, - "node_modules/dataprotocol-client/node_modules/vscode-jsonrpc": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.5.0.tgz", - "integrity": "sha512-LeE9LS1IOIRDZy5Xugrbk2tKeMa64vkRODrXPZbwyn2l/Q0e/jyYq8ze/Lo96sjOFiRe3HHbTVN39Ta8KN2RpA==", - "engines": { - "node": ">=4.0.0 || >=6.0.0" - } - }, - "node_modules/dataprotocol-client/node_modules/vscode-languageclient": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-3.5.1.tgz", - "integrity": "sha512-GTQ+hSq/o4c/y6GYmyP9XNrVoIu0NFZ67KltSkqN+tO0eUNDIlrVNX+3DJzzyLhSsrctuGzuYWm3t87mNAcBmQ==", - "dependencies": { - "vscode-languageserver-protocol": "3.5.1" - }, - "engines": { - "vscode": "^1.15" - } - }, - "node_modules/dataprotocol-client/node_modules/vscode-languageserver-protocol": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.1.tgz", - "integrity": "sha512-1fPDIwsAv1difCV+8daOrJEGunClNJWqnUHq/ncWrjhitKWXgGmRCjlwZ3gDUTt54yRcvXz1PXJDaRNvNH6pYA==", - "dependencies": { - "vscode-jsonrpc": "3.5.0", - "vscode-languageserver-types": "3.5.0" - } - }, - "node_modules/dataprotocol-client/node_modules/vscode-languageserver-types": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0.tgz", - "integrity": "sha512-D4rUfu/oKYdc9Tmec0nEfedj+uXO2tZHR+eoHs9rE9G/QpRyZaHuug8ZUNGTGdO+ALLGgenL6bRpY8y3J9acHg==" - }, "node_modules/dateformat": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz", @@ -1387,6 +1375,15 @@ "node": ">=0.10.0" } }, + "node_modules/default-compare/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/default-resolution": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", @@ -2327,6 +2324,28 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/glob-stream/node_modules/glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", + "dev": true, + "dependencies": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + } + }, + "node_modules/glob-stream/node_modules/is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/glob-watcher": { "version": "5.0.5", "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.5.tgz", @@ -2345,6 +2364,27 @@ "node": ">= 0.10" } }, + "node_modules/glob/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/glob/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/global-modules": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", @@ -2415,8 +2455,7 @@ }, "node_modules/gulp": { "version": "4.0.2", - "resolved": "https://codeload.github.com/gulpjs/gulp/tar.gz/069350a5febf65adc27bc816a7805471b7d96f03", - "integrity": "sha512-XrrOLkWNFDZi86El7qJyrou/+YzBzZ5B9h0Nhswn3FIoMY1cJG8H/WXy0BW0OE+sN1xYNQoC3Q8hflCxnrrEBw==", + "resolved": "git+ssh://git@github.com/gulpjs/gulp.git#069350a5febf65adc27bc816a7805471b7d96f03", "dev": true, "license": "MIT", "dependencies": { @@ -2683,6 +2722,33 @@ "integrity": "sha512-dhUqc57gSMCo6TX85FLfe51eC/s+Im2MLkAgJwfaRRexR2tA4dd3eLEW4L6efzHc2iNorrRRXITifnDLlRrhaA==", "dev": true }, + "node_modules/gulp-util/node_modules/lodash.template": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", + "integrity": "sha512-0B4Y53I0OgHUJkt+7RmlDFWKjVAI/YUpWNiL9GQz5ORDr4ttgfQGo+phBWKFLJbBdtOwgMuUkdOHOnPg45jKmQ==", + "dev": true, + "dependencies": { + "lodash._basecopy": "^3.0.0", + "lodash._basetostring": "^3.0.0", + "lodash._basevalues": "^3.0.0", + "lodash._isiterateecall": "^3.0.0", + "lodash._reinterpolate": "^3.0.0", + "lodash.escape": "^3.0.0", + "lodash.keys": "^3.0.0", + "lodash.restparam": "^3.0.0", + "lodash.templatesettings": "^3.0.0" + } + }, + "node_modules/gulp-util/node_modules/lodash.templatesettings": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", + "integrity": "sha512-TcrlEr31tDYnWkHFWDCV3dHYroKEXpJZ2YJYvJdhN+y4AkWMDZ5I4I8XDtUKqSAyG81N7w+I1mFEJtcED+tGqQ==", + "dev": true, + "dependencies": { + "lodash._reinterpolate": "^3.0.0", + "lodash.escape": "^3.0.0" + } + }, "node_modules/gulp-util/node_modules/object-assign": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", @@ -2770,6 +2836,15 @@ "node": ">=0.10.0" } }, + "node_modules/has-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -2842,6 +2917,18 @@ "node": ">=0.10.0" } }, + "node_modules/has-values/node_modules/kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/homedir-polyfill": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", @@ -2978,6 +3065,18 @@ "node": ">=0.10.0" } }, + "node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -3026,6 +3125,18 @@ "node": ">=0.10.0" } }, + "node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", @@ -3040,6 +3151,15 @@ "node": ">=0.10.0" } }, + "node_modules/is-descriptor/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", @@ -3103,6 +3223,18 @@ "node": ">=0.10.0" } }, + "node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-path-cwd": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", @@ -3361,6 +3493,36 @@ "node": ">=0.10.0" } }, + "node_modules/lodash._basecopy": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", + "integrity": "sha512-rFR6Vpm4HeCK1WPGvjZSJ+7yik8d8PVUdCJx5rT2pogG4Ve/2ZS7kfmO5l5T2o5V2mqlNIfSF5MZlr1+xOoYQQ==", + "dev": true + }, + "node_modules/lodash._basetostring": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", + "integrity": "sha512-mTzAr1aNAv/i7W43vOR/uD/aJ4ngbtsRaCubp2BfZhlGU/eORUjg/7F6X0orNMdv33JOrdgGybtvMN/po3EWrA==", + "dev": true + }, + "node_modules/lodash._basevalues": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", + "integrity": "sha512-H94wl5P13uEqlCg7OcNNhMQ8KvWSIyqXzOPusRgHC9DK3o54P6P3xtbXlVbRABG4q5gSmp7EDdJ0MSuW9HX6Mg==", + "dev": true + }, + "node_modules/lodash._getnative": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha512-RrL9VxMEPyDMHOd9uFbvMe8X55X16/cGM5IgOKgRElQZutpX89iS6vwl64duTV1/16w5JY7tuFNXqoekmh1EmA==", + "dev": true + }, + "node_modules/lodash._isiterateecall": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", + "integrity": "sha512-De+ZbrMu6eThFti/CSzhRvTKMgQToLxbij58LMfM8JnYDNSOjkjTCIaa8ixglOeGh2nyPlakbt5bJWJ7gvpYlQ==", + "dev": true + }, "node_modules/lodash._reescape": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", @@ -3379,6 +3541,50 @@ "integrity": "sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==", "dev": true }, + "node_modules/lodash._root": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", + "integrity": "sha512-O0pWuFSK6x4EXhM1dhZ8gchNtG7JMqBtrHdoUFUWXD7dJnNSUze1GuyQr5sOs0aCvgGeI3o/OJW8f4ca7FDxmQ==", + "dev": true + }, + "node_modules/lodash.escape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", + "integrity": "sha512-n1PZMXgaaDWZDSvuNZ/8XOcYO2hOKDqZel5adtR30VKQAtoWs/5AOeFA0vPV8moiPzlqe7F4cP2tzpFewQyelQ==", + "dev": true, + "dependencies": { + "lodash._root": "^3.0.0" + } + }, + "node_modules/lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==", + "dev": true + }, + "node_modules/lodash.isarray": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha512-JwObCrNJuT0Nnbuecmqr5DgtuBppuCvGD9lxjFpAzwnVtdGoDQ1zig+5W8k5/6Gcn0gZ3936HDAlGd28i7sOGQ==", + "dev": true + }, + "node_modules/lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha512-CuBsapFjcubOGMn3VD+24HOAPxM79tH+V6ivJL3CHYjtrawauDJHUk//Yew9Hvc6e9rbCrURGk8z6PC+8WJBfQ==", + "dev": true, + "dependencies": { + "lodash._getnative": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" + } + }, + "node_modules/lodash.restparam": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", + "integrity": "sha512-L4/arjjuq4noiUJpt3yS6KIKDtJwNe2fIYgMqyYYKoeIfV1iEqvPwhCx23o+R9dzouGihDAPN1dTIRWa7zk8tw==", + "dev": true + }, "node_modules/lodash.template": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", @@ -4017,6 +4223,18 @@ "node": ">=0.10.0" } }, + "node_modules/object-copy/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", @@ -4222,6 +4440,12 @@ "node": ">=0.10.0" } }, + "node_modules/path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==", + "dev": true + }, "node_modules/path-exists": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", @@ -5139,6 +5363,18 @@ "node": ">=0.10.0" } }, + "node_modules/snapdragon-util/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/snapdragon/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -5391,6 +5627,15 @@ "node": ">=0.10.0" } }, + "node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/strip-bom": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", @@ -5571,6 +5816,18 @@ "node": ">=0.10.0" } }, + "node_modules/to-object-path/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/to-regex": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", @@ -6597,9 +6854,9 @@ } }, "@types/azdata": { - "version": "1.38.0", - "resolved": "https://registry.npmjs.org/@types/azdata/-/azdata-1.38.0.tgz", - "integrity": "sha512-yXvy8+j2LgWoe7cX33doTDdv/0d7LMDEm3IfrXZ/EU4AwwzjvKqSR/0Ae0CH3o8WOvDm63bws++gxDlmhoLsPg==", + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/@types/azdata/-/azdata-1.40.0.tgz", + "integrity": "sha512-CGsuH9wY6616UGskR1bMd3KcOTHhh43dQz9ruSji3EmzUG6EYJCE+6D3+UZ6M+Ub73XzDeYXobe/rk+fGkaYlg==", "dev": true, "requires": { "@types/vscode": "*" @@ -6671,11 +6928,6 @@ "ansi-wrap": "0.1.0" } }, - "ansi-regex": { - "version": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", - "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", - "dev": true - }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -6922,6 +7174,14 @@ "default-compare": "^1.0.0", "get-value": "^2.0.6", "kind-of": "^5.0.2" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } } }, "array-union": { @@ -7199,6 +7459,29 @@ "path-is-absolute": "^1.0.0", "readdirp": "^2.2.1", "upath": "^1.1.1" + }, + "dependencies": { + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + } } }, "chownr": { @@ -7409,39 +7692,10 @@ } }, "dataprotocol-client": { - "version": "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/21487d15a5f753ba885ce1e489abc0af03487544", - "integrity": "sha512-QRQenym6p0KkXT8l/WRu86B8EkT9F5HzMuVzw0CFxpSr1zXjpxduAorvWI37amqWlMbS6MUVC1tLuMb11Ba7MA==", + "version": "git+ssh://git@github.com/Microsoft/sqlops-dataprotocolclient.git#2df6982e07c0208c2b8a5f8cd4b3d65944138d15", + "from": "dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#1.3.1", "requires": { - "vscode-languageclient": "3.5.1" - }, - "dependencies": { - "vscode-jsonrpc": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.5.0.tgz", - "integrity": "sha512-LeE9LS1IOIRDZy5Xugrbk2tKeMa64vkRODrXPZbwyn2l/Q0e/jyYq8ze/Lo96sjOFiRe3HHbTVN39Ta8KN2RpA==" - }, - "vscode-languageclient": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-3.5.1.tgz", - "integrity": "sha512-GTQ+hSq/o4c/y6GYmyP9XNrVoIu0NFZ67KltSkqN+tO0eUNDIlrVNX+3DJzzyLhSsrctuGzuYWm3t87mNAcBmQ==", - "requires": { - "vscode-languageserver-protocol": "3.5.1" - } - }, - "vscode-languageserver-protocol": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.1.tgz", - "integrity": "sha512-1fPDIwsAv1difCV+8daOrJEGunClNJWqnUHq/ncWrjhitKWXgGmRCjlwZ3gDUTt54yRcvXz1PXJDaRNvNH6pYA==", - "requires": { - "vscode-jsonrpc": "3.5.0", - "vscode-languageserver-types": "3.5.0" - } - }, - "vscode-languageserver-types": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0.tgz", - "integrity": "sha512-D4rUfu/oKYdc9Tmec0nEfedj+uXO2tZHR+eoHs9rE9G/QpRyZaHuug8ZUNGTGdO+ALLGgenL6bRpY8y3J9acHg==" - } + "vscode-languageclient": "5.2.1" } }, "dateformat": { @@ -7494,6 +7748,14 @@ "dev": true, "requires": { "kind-of": "^5.0.2" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } } }, "default-resolution": { @@ -8237,6 +8499,26 @@ "inherits": "2", "minimatch": "^5.0.1", "once": "^1.3.0" + }, + "dependencies": { + "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, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } } }, "glob-parent": { @@ -8279,6 +8561,25 @@ "once": "^1.3.0", "path-is-absolute": "^1.0.0" } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + } + }, + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } } } }, @@ -8351,9 +8652,9 @@ "dev": true }, "gulp": { - "version": "https://codeload.github.com/gulpjs/gulp/tar.gz/069350a5febf65adc27bc816a7805471b7d96f03", - "integrity": "sha512-XrrOLkWNFDZi86El7qJyrou/+YzBzZ5B9h0Nhswn3FIoMY1cJG8H/WXy0BW0OE+sN1xYNQoC3Q8hflCxnrrEBw==", + "version": "git+ssh://git@github.com/gulpjs/gulp.git#069350a5febf65adc27bc816a7805471b7d96f03", "dev": true, + "from": "gulp@github:gulpjs/gulp#v4.0.2", "requires": { "glob-watcher": "^5.0.3", "gulp-cli": "^2.2.0", @@ -8572,6 +8873,33 @@ "integrity": "sha512-dhUqc57gSMCo6TX85FLfe51eC/s+Im2MLkAgJwfaRRexR2tA4dd3eLEW4L6efzHc2iNorrRRXITifnDLlRrhaA==", "dev": true }, + "lodash.template": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", + "integrity": "sha512-0B4Y53I0OgHUJkt+7RmlDFWKjVAI/YUpWNiL9GQz5ORDr4ttgfQGo+phBWKFLJbBdtOwgMuUkdOHOnPg45jKmQ==", + "dev": true, + "requires": { + "lodash._basecopy": "^3.0.0", + "lodash._basetostring": "^3.0.0", + "lodash._basevalues": "^3.0.0", + "lodash._isiterateecall": "^3.0.0", + "lodash._reinterpolate": "^3.0.0", + "lodash.escape": "^3.0.0", + "lodash.keys": "^3.0.0", + "lodash.restparam": "^3.0.0", + "lodash.templatesettings": "^3.0.0" + } + }, + "lodash.templatesettings": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", + "integrity": "sha512-TcrlEr31tDYnWkHFWDCV3dHYroKEXpJZ2YJYvJdhN+y4AkWMDZ5I4I8XDtUKqSAyG81N7w+I1mFEJtcED+tGqQ==", + "dev": true, + "requires": { + "lodash._reinterpolate": "^3.0.0", + "lodash.escape": "^3.0.0" + } + }, "object-assign": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", @@ -8638,6 +8966,14 @@ "dev": true, "requires": { "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true + } } }, "has-flag": { @@ -8689,6 +9025,17 @@ "requires": { "is-number": "^3.0.0", "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } } }, "homedir-polyfill": { @@ -8800,6 +9147,17 @@ "dev": true, "requires": { "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } } }, "is-arrayish": { @@ -8839,6 +9197,17 @@ "dev": true, "requires": { "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } } }, "is-descriptor": { @@ -8850,6 +9219,14 @@ "is-accessor-descriptor": "^0.1.6", "is-data-descriptor": "^0.1.4", "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } } }, "is-extendable": { @@ -8895,6 +9272,17 @@ "dev": true, "requires": { "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } } }, "is-path-cwd": { @@ -9098,6 +9486,36 @@ "strip-bom": "^2.0.0" } }, + "lodash._basecopy": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", + "integrity": "sha512-rFR6Vpm4HeCK1WPGvjZSJ+7yik8d8PVUdCJx5rT2pogG4Ve/2ZS7kfmO5l5T2o5V2mqlNIfSF5MZlr1+xOoYQQ==", + "dev": true + }, + "lodash._basetostring": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", + "integrity": "sha512-mTzAr1aNAv/i7W43vOR/uD/aJ4ngbtsRaCubp2BfZhlGU/eORUjg/7F6X0orNMdv33JOrdgGybtvMN/po3EWrA==", + "dev": true + }, + "lodash._basevalues": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", + "integrity": "sha512-H94wl5P13uEqlCg7OcNNhMQ8KvWSIyqXzOPusRgHC9DK3o54P6P3xtbXlVbRABG4q5gSmp7EDdJ0MSuW9HX6Mg==", + "dev": true + }, + "lodash._getnative": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha512-RrL9VxMEPyDMHOd9uFbvMe8X55X16/cGM5IgOKgRElQZutpX89iS6vwl64duTV1/16w5JY7tuFNXqoekmh1EmA==", + "dev": true + }, + "lodash._isiterateecall": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", + "integrity": "sha512-De+ZbrMu6eThFti/CSzhRvTKMgQToLxbij58LMfM8JnYDNSOjkjTCIaa8ixglOeGh2nyPlakbt5bJWJ7gvpYlQ==", + "dev": true + }, "lodash._reescape": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", @@ -9116,6 +9534,50 @@ "integrity": "sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==", "dev": true }, + "lodash._root": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", + "integrity": "sha512-O0pWuFSK6x4EXhM1dhZ8gchNtG7JMqBtrHdoUFUWXD7dJnNSUze1GuyQr5sOs0aCvgGeI3o/OJW8f4ca7FDxmQ==", + "dev": true + }, + "lodash.escape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", + "integrity": "sha512-n1PZMXgaaDWZDSvuNZ/8XOcYO2hOKDqZel5adtR30VKQAtoWs/5AOeFA0vPV8moiPzlqe7F4cP2tzpFewQyelQ==", + "dev": true, + "requires": { + "lodash._root": "^3.0.0" + } + }, + "lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==", + "dev": true + }, + "lodash.isarray": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha512-JwObCrNJuT0Nnbuecmqr5DgtuBppuCvGD9lxjFpAzwnVtdGoDQ1zig+5W8k5/6Gcn0gZ3936HDAlGd28i7sOGQ==", + "dev": true + }, + "lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha512-CuBsapFjcubOGMn3VD+24HOAPxM79tH+V6ivJL3CHYjtrawauDJHUk//Yew9Hvc6e9rbCrURGk8z6PC+8WJBfQ==", + "dev": true, + "requires": { + "lodash._getnative": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" + } + }, + "lodash.restparam": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", + "integrity": "sha512-L4/arjjuq4noiUJpt3yS6KIKDtJwNe2fIYgMqyYYKoeIfV1iEqvPwhCx23o+R9dzouGihDAPN1dTIRWa7zk8tw==", + "dev": true + }, "lodash.template": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", @@ -9632,6 +10094,17 @@ "copy-descriptor": "^0.1.0", "define-property": "^0.2.5", "kind-of": "^3.0.3" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } } }, "object-keys": { @@ -9785,6 +10258,12 @@ "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==", "dev": true }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==", + "dev": true + }, "path-exists": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", @@ -10526,6 +11005,17 @@ "dev": true, "requires": { "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } } }, "source-map": { @@ -10707,6 +11197,14 @@ "dev": true, "requires": { "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true + } } }, "strip-bom": { @@ -10860,6 +11358,17 @@ "dev": true, "requires": { "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } } }, "to-regex": { diff --git a/AzureDataStudioExtension/package.json b/AzureDataStudioExtension/package.json index 31c3b023..ff6058a2 100644 --- a/AzureDataStudioExtension/package.json +++ b/AzureDataStudioExtension/package.json @@ -352,7 +352,7 @@ "@types/vscode": "1.71.0", "@types/azdata": "1.40.0", "del": "^6.1.1", - "gulp": "github:gulpjs/gulp#4.0.2", + "gulp": "github:gulpjs/gulp#v4.0.2", "gulp-json-editor": "^2.5.6", "gulp-rename": "^2.0.0", "gulp-shell": "^0.8.0", diff --git a/AzureDataStudioExtension/src/main.ts b/AzureDataStudioExtension/src/main.ts index 3ec73b7d..010cb023 100644 --- a/AzureDataStudioExtension/src/main.ts +++ b/AzureDataStudioExtension/src/main.ts @@ -71,9 +71,9 @@ export async function activate(context: vscode.ExtensionContext) { }); languageClient.onNotification("sql4cds/confirmation", (message: {ownerUri: string, msg: string}) => { vscode.window - .showInformationMessage(message.msg, "Yes", "No") + .showInformationMessage(message.msg, "Yes", "All", "No") .then(answer => { - languageClient.sendNotification("sql4cds/confirm", { ownerUri: message.ownerUri, result: answer === "Yes" }) + languageClient.sendNotification("sql4cds/confirm", { ownerUri: message.ownerUri, result: answer }) }); }); languageClient.onNotification("query/batchComplete", () => { diff --git a/AzureDataStudioExtension/yarn.lock b/AzureDataStudioExtension/yarn.lock index 20c29262..a7967127 100644 --- a/AzureDataStudioExtension/yarn.lock +++ b/AzureDataStudioExtension/yarn.lock @@ -64,7 +64,7 @@ "@nodelib/fs.stat" "2.0.5" run-parallel "^1.1.9" -"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": +"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5": version "2.0.5" resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== @@ -79,7 +79,7 @@ "@types/azdata@1.40.0": version "1.40.0" - resolved "https://registry.yarnpkg.com/@types/azdata/-/azdata-1.40.0.tgz#0a454d9261a6eadbb70692515184bcea5bbb9d61" + resolved "https://registry.npmjs.org/@types/azdata/-/azdata-1.40.0.tgz" integrity sha512-CGsuH9wY6616UGskR1bMd3KcOTHhh43dQz9ruSji3EmzUG6EYJCE+6D3+UZ6M+Ub73XzDeYXobe/rk+fGkaYlg== dependencies: "@types/vscode" "*" @@ -96,7 +96,7 @@ "@types/vscode@*", "@types/vscode@1.71.0": version "1.71.0" - resolved "https://registry.yarnpkg.com/@types/vscode/-/vscode-1.71.0.tgz#a8d9bb7aca49b0455060e6eb978711b510bdd2e2" + resolved "https://registry.npmjs.org/@types/vscode/-/vscode-1.71.0.tgz" integrity sha512-nB50bBC9H/x2CpwW9FzRRRDrTZ7G0/POttJojvN/LiVfzTGfLyQIje1L1QRMdFXK9G41k5UJN/1B9S4of7CSzA== abbrev@^1.0.0: @@ -109,7 +109,7 @@ acorn@^6.4.1: resolved "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz" integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== -agent-base@4, agent-base@^4.3.0: +agent-base@^4.3.0, agent-base@4: version "4.3.0" resolved "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz" integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg== @@ -143,10 +143,10 @@ ansi-gray@^0.1.1: dependencies: ansi-wrap "0.1.0" -ansi-regex@^2.0.0, ansi-regex@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.1.tgz#123d6479e92ad45ad897d4054e3c7ca7db4944e1" - integrity sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw== +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz" + integrity sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA== ansi-styles@^2.2.1: version "2.2.1" @@ -167,7 +167,7 @@ ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" -ansi-wrap@0.1.0, ansi-wrap@^0.1.0: +ansi-wrap@^0.1.0, ansi-wrap@0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz" integrity sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw== @@ -341,11 +341,6 @@ balanced-match@^1.0.0: resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== -base64-js@^1.3.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" - integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== - base@^0.11.1: version "0.11.2" resolved "https://registry.npmjs.org/base/-/base-0.11.2.tgz" @@ -369,21 +364,6 @@ binary-extensions@^1.0.0: resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz" integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== -bindings@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" - integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== - dependencies: - file-uri-to-path "1.0.0" - -bl@^1.0.0, bl@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.3.tgz#1e8dd80142eac80d7158c9dccc047fb620e035e7" - integrity sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww== - dependencies: - readable-stream "^2.3.5" - safe-buffer "^5.1.1" - brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" @@ -392,6 +372,13 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + braces@^2.3.1, braces@^2.3.2: version "2.3.2" resolved "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz" @@ -415,19 +402,6 @@ braces@^3.0.2: dependencies: fill-range "^7.0.1" -buffer-alloc-unsafe@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" - integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== - -buffer-alloc@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" - integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== - dependencies: - buffer-alloc-unsafe "^1.1.0" - buffer-fill "^1.0.0" - buffer-crc32@~0.2.3: version "0.2.13" resolved "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz" @@ -438,24 +412,11 @@ buffer-equal@^1.0.0: resolved "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz" integrity sha512-tcBWO2Dl4e7Asr9hTGcpVrCe+F7DubpmqWCTbj4FHLmjqO2hIaC383acQubWtRJhdceqs5uBHs6Es+Sk//RKiQ== -buffer-fill@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" - integrity sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ== - buffer-from@^1.0.0: version "1.1.2" resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== -buffer@^5.2.1: - version "5.7.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" - integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.1.13" - builtin-modules@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz" @@ -505,7 +466,16 @@ chalk@^1.0.0: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.0, chalk@^2.3.0: +chalk@^2.0.0: + version "2.4.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^2.3.0: version "2.4.2" resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -640,24 +610,24 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" - integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== - color-name@~1.1.4: version "1.1.4" resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + color-support@^1.1.3: version "1.1.3" resolved "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz" integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== -commander@^2.12.1, commander@^2.19.0, commander@^2.8.1: +commander@^2.12.1, commander@^2.19.0: version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== component-emitter@^1.2.1: @@ -700,9 +670,9 @@ copy-descriptor@^0.1.0: resolved "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz" integrity sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw== -copy-props@^2.0.1, copy-props@^2.0.5: +copy-props@^2.0.1: version "2.0.5" - resolved "https://registry.yarnpkg.com/copy-props/-/copy-props-2.0.5.tgz#03cf9ae328d4ebb36f8f1d804448a6af9ee3f2d2" + resolved "https://registry.npmjs.org/copy-props/-/copy-props-2.0.5.tgz" integrity sha512-XBlx8HSqrT0ObQwmSzM7WE5k8FxTV75h1DX1Z3n6NhQ/UYYAvInWYmG06vFt7hQZArE2fuO62aihiWIVQwh1sw== dependencies: each-props "^1.3.2" @@ -727,7 +697,7 @@ css@^3.0.0: source-map "^0.6.1" source-map-resolve "^0.6.0" -d@1, d@^1.0.1: +d@^1.0.1, d@1: version "1.0.1" resolved "https://registry.npmjs.org/d/-/d-1.0.1.tgz" integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== @@ -737,7 +707,7 @@ d@1, d@^1.0.1: "dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#1.3.1": version "1.3.1" - resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/2df6982e07c0208c2b8a5f8cd4b3d65944138d15" + resolved "git+ssh://git@github.com/Microsoft/sqlops-dataprotocolclient.git#2df6982e07c0208c2b8a5f8cd4b3d65944138d15" dependencies: vscode-languageclient "5.2.1" @@ -755,24 +725,31 @@ debug-fabulous@^1.0.0: memoizee "0.4.X" object-assign "4.X" -debug@3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz" - integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== +debug@^2.2.0: + version "2.6.9" + resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@^2.3.3: + version "2.6.9" + resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" -debug@3.X, debug@^3.1.0: +debug@^3.1.0, debug@3.X: version "3.2.7" resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz" integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== dependencies: ms "^2.1.1" -debug@^2.2.0, debug@^2.3.3: - version "2.6.9" - resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== +debug@3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== dependencies: ms "2.0.0" @@ -786,59 +763,6 @@ decode-uri-component@^0.2.0: resolved "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz" integrity sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og== -decompress-tar@^4.0.0, decompress-tar@^4.1.0, decompress-tar@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/decompress-tar/-/decompress-tar-4.1.1.tgz#718cbd3fcb16209716e70a26b84e7ba4592e5af1" - integrity sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ== - dependencies: - file-type "^5.2.0" - is-stream "^1.1.0" - tar-stream "^1.5.2" - -decompress-tarbz2@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz#3082a5b880ea4043816349f378b56c516be1a39b" - integrity sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A== - dependencies: - decompress-tar "^4.1.0" - file-type "^6.1.0" - is-stream "^1.1.0" - seek-bzip "^1.0.5" - unbzip2-stream "^1.0.9" - -decompress-targz@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/decompress-targz/-/decompress-targz-4.1.1.tgz#c09bc35c4d11f3de09f2d2da53e9de23e7ce1eee" - integrity sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w== - dependencies: - decompress-tar "^4.1.1" - file-type "^5.2.0" - is-stream "^1.1.0" - -decompress-unzip@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/decompress-unzip/-/decompress-unzip-4.0.1.tgz#deaaccdfd14aeaf85578f733ae8210f9b4848f69" - integrity sha512-1fqeluvxgnn86MOh66u8FjbtJpAFv5wgCT9Iw8rcBqQcCo5tO8eiJw7NNTrvt9n4CRBVq7CstiS922oPgyGLrw== - dependencies: - file-type "^3.8.0" - get-stream "^2.2.0" - pify "^2.3.0" - yauzl "^2.4.2" - -decompress@^4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/decompress/-/decompress-4.2.1.tgz#007f55cc6a62c055afa37c07eb6a4ee1b773f118" - integrity sha512-e48kc2IjU+2Zw8cTb6VZcJQ3lgVbS4uuB1TfCHbiZIP/haNXm+SVyhu+87jts5/3ROpd82GSVCoNs/z8l4ZOaQ== - dependencies: - decompress-tar "^4.0.0" - decompress-tarbz2 "^4.0.0" - decompress-targz "^4.0.0" - decompress-unzip "^4.0.1" - graceful-fs "^4.1.10" - make-dir "^1.0.0" - pify "^2.3.0" - strip-dirs "^2.0.0" - deepmerge@^4.2.2: version "4.2.2" resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz" @@ -927,6 +851,11 @@ dir-glob@^3.0.1: dependencies: path-type "^4.0.0" +duplexer@^0.1.1, duplexer@~0.1.1: + version "0.1.2" + resolved "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz" + integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== + duplexer2@0.0.2: version "0.0.2" resolved "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz" @@ -934,11 +863,6 @@ duplexer2@0.0.2: dependencies: readable-stream "~1.1.9" -duplexer@^0.1.1, duplexer@~0.1.1: - version "0.1.2" - resolved "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz" - integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== - duplexify@^3.6.0: version "3.7.1" resolved "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz" @@ -1099,7 +1023,15 @@ extend-shallow@^2.0.1: dependencies: is-extendable "^0.1.0" -extend-shallow@^3.0.0, extend-shallow@^3.0.2: +extend-shallow@^3.0.0: + version "3.0.2" + resolved "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz" + integrity sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q== + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extend-shallow@^3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz" integrity sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q== @@ -1126,7 +1058,7 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" -fancy-log@1.3.3, fancy-log@^1.1.0, fancy-log@^1.3.2, fancy-log@^1.3.3: +fancy-log@^1.1.0, fancy-log@^1.3.2, fancy-log@^1.3.3, fancy-log@1.3.3: version "1.3.3" resolved "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz" integrity sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw== @@ -1166,26 +1098,6 @@ fd-slicer@~1.1.0: dependencies: pend "~1.2.0" -file-type@^3.8.0: - version "3.9.0" - resolved "https://registry.yarnpkg.com/file-type/-/file-type-3.9.0.tgz#257a078384d1db8087bc449d107d52a52672b9e9" - integrity sha512-RLoqTXE8/vPmMuTI88DAzhMYC99I8BWv7zYP4A1puo5HIjEJ5EX48ighy4ZyKMG9EDXxBgW6e++cn7d1xuFghA== - -file-type@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/file-type/-/file-type-5.2.0.tgz#2ddbea7c73ffe36368dfae49dc338c058c2b8ad6" - integrity sha512-Iq1nJ6D2+yIO4c8HHg4fyVb8mAJieo1Oloy1mLLaB2PvezNedhBVm+QU7g0qM42aiMbRXTxKKwGD17rjKNJYVQ== - -file-type@^6.1.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/file-type/-/file-type-6.2.0.tgz#e50cd75d356ffed4e306dc4f5bcf52a79903a919" - integrity sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg== - -file-uri-to-path@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" - integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== - fill-range@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz" @@ -1279,11 +1191,6 @@ from@^0.1.7: resolved "https://registry.npmjs.org/from/-/from-0.1.7.tgz" integrity sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g== -fs-constants@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" - integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== - fs-minipass@^2.0.0: version "2.1.0" resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz" @@ -1304,14 +1211,6 @@ fs.realpath@^1.0.0: resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@^1.2.7: - version "1.2.13" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" - integrity sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw== - dependencies: - bindings "^1.5.0" - nan "^2.12.1" - function-bind@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" @@ -1331,20 +1230,20 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.1: has "^1.0.3" has-symbols "^1.0.3" -get-stream@^2.2.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-2.3.1.tgz#5f38f93f346009666ee0150a054167f91bdd95de" - integrity sha512-AUGhbbemXxrZJRD5cDvKtQxLuYaIbNtDTK8YqupCI393Q2KSTreEsLUN3ZxAWFGiKTzL6nKuzfcIvieflUX9qA== - dependencies: - object-assign "^4.0.1" - pinkie-promise "^2.0.0" - get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz" integrity sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA== -glob-parent@^3.1.0, glob-parent@^5.1.2: +glob-parent@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz" + integrity sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA== + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + +glob-parent@^5.1.2: version "5.1.2" resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== @@ -1391,7 +1290,19 @@ glob@^6.0.4: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.1.1, glob@^7.1.3: +glob@^7.1.1: + version "7.2.3" + resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.1.3: version "7.2.3" resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -1453,14 +1364,14 @@ glogg@^1.0.0: dependencies: sparkles "^1.0.0" -graceful-fs@^4.0.0, graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.4: +graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.4: version "4.2.10" resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz" integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== -gulp-cli@^2.2.0, gulp-cli@^2.3.0: +gulp-cli@^2.2.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/gulp-cli/-/gulp-cli-2.3.0.tgz#ec0d380e29e52aa45e47977f0d32e18fd161122f" + resolved "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.3.0.tgz" integrity sha512-zzGBl5fHo0EKSXsHzjspp3y5CONegCm8ErO5Qh0UzFzk2y4tMvzLWhoDokADbarfZRL2pGpRp7yt6gfJX4ph7A== dependencies: ansi-colors "^1.0.1" @@ -1575,9 +1486,9 @@ gulp-util@^3.0.7: through2 "^2.0.0" vinyl "^0.5.0" -"gulp@github:gulpjs/gulp#4.0.2": +"gulp@github:gulpjs/gulp#v4.0.2": version "4.0.2" - resolved "https://codeload.github.com/gulpjs/gulp/tar.gz/069350a5febf65adc27bc816a7805471b7d96f03" + resolved "git+ssh://git@github.com/gulpjs/gulp.git#069350a5febf65adc27bc816a7805471b7d96f03" dependencies: glob-watcher "^5.0.3" gulp-cli "^2.2.0" @@ -1672,9 +1583,9 @@ homedir-polyfill@^1.0.1: dependencies: parse-passwd "^1.0.0" -hosted-git-info@^2.1.4, hosted-git-info@^2.8.9: +hosted-git-info@^2.1.4: version "2.8.9" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" + resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz" integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== http-proxy-agent@^2.1.0: @@ -1693,11 +1604,6 @@ https-proxy-agent@^2.2.3: agent-base "^4.3.0" debug "^3.1.0" -ieee754@^1.1.13: - version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" - integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== - ignore@^5.2.0: version "5.2.0" resolved "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz" @@ -1716,14 +1622,14 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: +inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3, inherits@2: version "2.0.4" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -ini@^1.3.4, ini@^1.3.6: +ini@^1.3.4: version "1.3.8" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + resolved "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== interpret@^1.4.0: @@ -1805,7 +1711,16 @@ is-descriptor@^0.1.0: is-data-descriptor "^0.1.4" kind-of "^5.0.0" -is-descriptor@^1.0.0, is-descriptor@^1.0.2: +is-descriptor@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-descriptor@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz" integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== @@ -1852,11 +1767,6 @@ is-glob@^4.0.0, is-glob@^4.0.1: dependencies: is-extglob "^2.1.1" -is-natural-number@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/is-natural-number/-/is-natural-number-4.0.1.tgz#ab9d76e1db4ced51e35de0c72ebecf09f734cde8" - integrity sha512-Y4LTamMe0DDQIIAlaer9eKebAlDSV6huy+TWhJVPlzZh2o4tRP5SQWFlLn5N0To4mDD22/qdOq+veo1cSISLgQ== - is-negated-glob@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz" @@ -1889,7 +1799,21 @@ is-path-inside@^3.0.2: resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== -is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: +is-plain-object@^2.0.1: + version "2.0.4" + resolved "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-plain-object@^2.0.3: + version "2.0.4" + resolved "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-plain-object@^2.0.4: version "2.0.4" resolved "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz" integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== @@ -1913,11 +1837,6 @@ is-relative@^1.0.0: dependencies: is-unc-path "^1.0.0" -is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ== - is-unc-path@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz" @@ -1940,16 +1859,16 @@ is-windows@^1.0.1, is-windows@^1.0.2: resolved "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== +isarray@~1.0.0, isarray@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + isarray@0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== -isarray@1.0.0, isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" - integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== - isexe@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" @@ -2000,9 +1919,47 @@ just-debounce@^1.0.0: resolved "https://registry.npmjs.org/just-debounce/-/just-debounce-1.1.0.tgz" integrity sha512-qpcRocdkUmf+UTNBYx5w6dexX5J31AKK1OmPwH630a83DdVVUIngk55RSAiIGpQyoH0dlr872VHfPjnQnK1qDQ== -kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0, kind-of@^4.0.0, kind-of@^5.0.0, kind-of@^5.0.2, kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: +kind-of@^3.0.2: + version "3.2.2" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz" + integrity sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ== + dependencies: + is-buffer "^1.1.5" + +kind-of@^3.0.3: + version "3.2.2" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz" + integrity sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ== + dependencies: + is-buffer "^1.1.5" + +kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz" + integrity sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ== + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz" + integrity sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw== + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== + +kind-of@^5.0.2: + version "5.1.0" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== + +kind-of@^6.0.0, kind-of@^6.0.2: version "6.0.3" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== last-run@^1.1.0: @@ -2059,6 +2016,31 @@ load-json-file@^1.0.0: pinkie-promise "^2.0.0" strip-bom "^2.0.0" +lodash._basecopy@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz" + integrity sha512-rFR6Vpm4HeCK1WPGvjZSJ+7yik8d8PVUdCJx5rT2pogG4Ve/2ZS7kfmO5l5T2o5V2mqlNIfSF5MZlr1+xOoYQQ== + +lodash._basetostring@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz" + integrity sha512-mTzAr1aNAv/i7W43vOR/uD/aJ4ngbtsRaCubp2BfZhlGU/eORUjg/7F6X0orNMdv33JOrdgGybtvMN/po3EWrA== + +lodash._basevalues@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz" + integrity sha512-H94wl5P13uEqlCg7OcNNhMQ8KvWSIyqXzOPusRgHC9DK3o54P6P3xtbXlVbRABG4q5gSmp7EDdJ0MSuW9HX6Mg== + +lodash._getnative@^3.0.0: + version "3.9.1" + resolved "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz" + integrity sha512-RrL9VxMEPyDMHOd9uFbvMe8X55X16/cGM5IgOKgRElQZutpX89iS6vwl64duTV1/16w5JY7tuFNXqoekmh1EmA== + +lodash._isiterateecall@^3.0.0: + version "3.0.9" + resolved "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz" + integrity sha512-De+ZbrMu6eThFti/CSzhRvTKMgQToLxbij58LMfM8JnYDNSOjkjTCIaa8ixglOeGh2nyPlakbt5bJWJ7gvpYlQ== + lodash._reescape@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz" @@ -2074,7 +2056,58 @@ lodash._reinterpolate@^3.0.0: resolved "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz" integrity sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA== -lodash.template@^3.0.0, lodash.template@^4.5.0: +lodash._root@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz" + integrity sha512-O0pWuFSK6x4EXhM1dhZ8gchNtG7JMqBtrHdoUFUWXD7dJnNSUze1GuyQr5sOs0aCvgGeI3o/OJW8f4ca7FDxmQ== + +lodash.escape@^3.0.0: + version "3.2.0" + resolved "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz" + integrity sha512-n1PZMXgaaDWZDSvuNZ/8XOcYO2hOKDqZel5adtR30VKQAtoWs/5AOeFA0vPV8moiPzlqe7F4cP2tzpFewQyelQ== + dependencies: + lodash._root "^3.0.0" + +lodash.isarguments@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz" + integrity sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg== + +lodash.isarray@^3.0.0: + version "3.0.4" + resolved "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz" + integrity sha512-JwObCrNJuT0Nnbuecmqr5DgtuBppuCvGD9lxjFpAzwnVtdGoDQ1zig+5W8k5/6Gcn0gZ3936HDAlGd28i7sOGQ== + +lodash.keys@^3.0.0: + version "3.1.2" + resolved "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz" + integrity sha512-CuBsapFjcubOGMn3VD+24HOAPxM79tH+V6ivJL3CHYjtrawauDJHUk//Yew9Hvc6e9rbCrURGk8z6PC+8WJBfQ== + dependencies: + lodash._getnative "^3.0.0" + lodash.isarguments "^3.0.0" + lodash.isarray "^3.0.0" + +lodash.restparam@^3.0.0: + version "3.6.1" + resolved "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz" + integrity sha512-L4/arjjuq4noiUJpt3yS6KIKDtJwNe2fIYgMqyYYKoeIfV1iEqvPwhCx23o+R9dzouGihDAPN1dTIRWa7zk8tw== + +lodash.template@^3.0.0: + version "3.6.2" + resolved "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz" + integrity sha512-0B4Y53I0OgHUJkt+7RmlDFWKjVAI/YUpWNiL9GQz5ORDr4ttgfQGo+phBWKFLJbBdtOwgMuUkdOHOnPg45jKmQ== + dependencies: + lodash._basecopy "^3.0.0" + lodash._basetostring "^3.0.0" + lodash._basevalues "^3.0.0" + lodash._isiterateecall "^3.0.0" + lodash._reinterpolate "^3.0.0" + lodash.escape "^3.0.0" + lodash.keys "^3.0.0" + lodash.restparam "^3.0.0" + lodash.templatesettings "^3.0.0" + +lodash.template@^4.5.0: version "4.5.0" resolved "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz" integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A== @@ -2082,6 +2115,14 @@ lodash.template@^3.0.0, lodash.template@^4.5.0: lodash._reinterpolate "^3.0.0" lodash.templatesettings "^4.0.0" +lodash.templatesettings@^3.0.0: + version "3.1.1" + resolved "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz" + integrity sha512-TcrlEr31tDYnWkHFWDCV3dHYroKEXpJZ2YJYvJdhN+y4AkWMDZ5I4I8XDtUKqSAyG81N7w+I1mFEJtcED+tGqQ== + dependencies: + lodash._reinterpolate "^3.0.0" + lodash.escape "^3.0.0" + lodash.templatesettings@^4.0.0: version "4.2.0" resolved "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz" @@ -2104,13 +2145,6 @@ lru-queue@^0.1.0: dependencies: es5-ext "~0.10.2" -make-dir@^1.0.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" - integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== - dependencies: - pify "^3.0.0" - make-iterator@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz" @@ -2123,7 +2157,7 @@ map-cache@^0.2.0, map-cache@^0.2.2: resolved "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz" integrity sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg== -map-stream@0.0.7, map-stream@~0.0.7: +map-stream@~0.0.7, map-stream@0.0.7: version "0.0.7" resolved "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz" integrity sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ== @@ -2164,7 +2198,45 @@ merge2@^1.3.0, merge2@^1.4.1: resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4: +micromatch@^3.0.4: + version "3.1.10" + resolved "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +micromatch@^3.1.10: + version "3.1.10" + resolved "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +micromatch@^3.1.4: version "3.1.10" resolved "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz" integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== @@ -2191,17 +2263,24 @@ micromatch@^4.0.4: braces "^3.0.2" picomatch "^2.3.1" -"minimatch@2 || 3", minimatch@^3.0.2, minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^5.0.1: +minimatch@^3.0.4, minimatch@^3.1.1, "minimatch@2 || 3": version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" -minimist@^1.1.0, minimist@^1.2.3, minimist@^1.2.6: - version "1.2.7" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18" - integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g== +minimatch@^5.0.1: + version "5.1.6" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + +minimist@^1.1.0, minimist@^1.2.6: + version "1.2.6" + resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== minipass@^3.0.0: version "3.3.4" @@ -2218,19 +2297,14 @@ minizlib@^2.1.1: minipass "^3.0.0" yallist "^4.0.0" -mixin-deep@^1.2.0, mixin-deep@^1.3.2: +mixin-deep@^1.2.0: version "1.3.2" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + resolved "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz" integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== dependencies: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp@1.0.4, mkdirp@^1.0.3: - version "1.0.4" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz" - integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== - mkdirp@^0.5.3: version "0.5.6" resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz" @@ -2238,16 +2312,21 @@ mkdirp@^0.5.3: dependencies: minimist "^1.2.6" -ms@2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" - integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== +mkdirp@^1.0.3, mkdirp@1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== ms@^2.1.1: version "2.1.3" resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== +ms@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + multipipe@^0.1.2: version "0.1.2" resolved "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz" @@ -2260,11 +2339,6 @@ mute-stdout@^1.0.0: resolved "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz" integrity sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg== -nan@^2.12.1: - version "2.17.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.17.0.tgz#c0150a2368a182f033e9aa5195ec76ea41a199cb" - integrity sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ== - nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz" @@ -2282,7 +2356,7 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" -next-tick@1, next-tick@^1.1.0: +next-tick@^1.1.0, next-tick@1: version "1.1.0" resolved "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz" integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== @@ -2304,7 +2378,14 @@ normalize-package-data@^2.3.2: semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" -normalize-path@^2.0.1, normalize-path@^2.1.1: +normalize-path@^2.0.1: + version "2.1.1" + resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz" + integrity sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w== + dependencies: + remove-trailing-separator "^1.0.1" + +normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz" integrity sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w== @@ -2328,16 +2409,16 @@ number-is-nan@^1.0.0: resolved "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz" integrity sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ== -object-assign@4.X, object-assign@^4.0.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== - object-assign@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz" integrity sha512-jHP15vXVGeVh1HuaA2wY6lxk+whK/x4KBG88VXeRma7CCun7iGD5qPc4eYykQ9sdQvg8jkwFKsSxHln2ybW3xQ== +object-assign@4.X: + version "4.1.1" + resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + object-copy@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz" @@ -2471,6 +2552,11 @@ pascalcase@^0.1.1: resolved "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz" integrity sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw== +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz" + integrity sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q== + path-exists@^2.0.0: version "2.1.0" resolved "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz" @@ -2536,16 +2622,11 @@ picomatch@^2.3.1: resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== -pify@^2.0.0, pify@^2.3.0: +pify@^2.0.0: version "2.3.0" resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz" integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== -pify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg== - pinkie-promise@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz" @@ -2558,7 +2639,7 @@ pinkie@^2.0.0: resolved "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz" integrity sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg== -plugin-error@1.0.1, plugin-error@^1.0.1: +plugin-error@^1.0.1, plugin-error@1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz" integrity sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA== @@ -2640,7 +2721,7 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" -"readable-stream@2 || 3", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6: +readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6, "readable-stream@2 || 3": version "2.3.7" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -2653,15 +2734,6 @@ read-pkg@^1.0.0: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@3: - version "3.6.0" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz" - integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - readable-stream@~1.1.9: version "1.1.14" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz" @@ -2672,6 +2744,15 @@ readable-stream@~1.1.9: isarray "0.0.1" string_decoder "~0.10.x" +readable-stream@3: + version "3.6.0" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + readdirp@^2.2.1: version "2.2.1" resolved "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz" @@ -2728,16 +2809,16 @@ repeat-string@^1.6.1: resolved "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz" integrity sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w== -replace-ext@0.0.1: - version "0.0.1" - resolved "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz" - integrity sha512-AFBWBy9EVRTa/LhEcG8QDP3FvpwZqmvN2QFDuJswFeaVhWnZMp8q3E6Zd90SR04PlIwfGdyVjNyLPyen/ek5CQ== - replace-ext@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz" integrity sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw== +replace-ext@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz" + integrity sha512-AFBWBy9EVRTa/LhEcG8QDP3FvpwZqmvN2QFDuJswFeaVhWnZMp8q3E6Zd90SR04PlIwfGdyVjNyLPyen/ek5CQ== + replace-homedir@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz" @@ -2820,11 +2901,6 @@ safe-buffer@^5.1.0, safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@^5.1.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - safe-regex@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz" @@ -2832,13 +2908,6 @@ safe-regex@^1.1.0: dependencies: ret "~0.1.10" -seek-bzip@^1.0.5: - version "1.0.6" - resolved "https://registry.yarnpkg.com/seek-bzip/-/seek-bzip-1.0.6.tgz#35c4171f55a680916b52a07859ecf3b5857f21c4" - integrity sha512-e1QtP3YL5tWww8uKaOCQ18UxIT2laNBXHjV/S2WYCiK4udiv8lkG89KRIoCjUagnAmCBurjF4zEVX2ByBbnCjQ== - dependencies: - commander "^2.8.1" - semver-greatest-satisfied-range@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz" @@ -2846,7 +2915,7 @@ semver-greatest-satisfied-range@^1.1.0: dependencies: sver-compat "^1.5.0" -"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.5.0, semver@^5.6.0: +semver@^5.3.0, semver@^5.5.0, semver@^5.6.0, "semver@2 || 3 || 4 || 5": version "5.7.1" resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -2930,7 +2999,12 @@ source-map-url@^0.4.0: resolved "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz" integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== -source-map@^0.5.3, source-map@^0.5.6: +source-map@^0.5.3: + version "0.5.7" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz" + integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== + +source-map@^0.5.6: version "0.5.7" resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz" integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== @@ -3026,15 +3100,6 @@ stream-shift@^1.0.0: resolved "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz" integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== -string-width@^1.0.1, string-width@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz" - integrity sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw== - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - string_decoder@^1.1.1, string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" @@ -3047,6 +3112,15 @@ string_decoder@~0.10.x: resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" integrity sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ== +string-width@^1.0.1, string-width@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz" + integrity sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw== + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz" @@ -3066,13 +3140,6 @@ strip-bom@^2.0.0: dependencies: is-utf8 "^0.2.0" -strip-dirs@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/strip-dirs/-/strip-dirs-2.1.0.tgz#4987736264fc344cf20f6c34aca9d13d1d4ed6c5" - integrity sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g== - dependencies: - is-natural-number "^4.0.1" - supports-color@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz" @@ -3105,19 +3172,6 @@ sver-compat@^1.5.0: es6-iterator "^2.0.1" es6-symbol "^3.1.1" -tar-stream@^1.5.2: - version "1.6.2" - resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" - integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A== - dependencies: - bl "^1.0.0" - buffer-alloc "^1.2.0" - end-of-stream "^1.0.0" - fs-constants "^1.0.0" - readable-stream "^2.3.0" - to-buffer "^1.1.1" - xtend "^4.0.0" - tar@^6.1.11: version "6.1.11" resolved "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz" @@ -3130,6 +3184,11 @@ tar@^6.1.11: mkdirp "^1.0.3" yallist "^4.0.0" +through@^2.3.8, through@~2.3, through@~2.3.4, through@~2.3.8, through@2: + version "2.3.8" + resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz" + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== + through2-filter@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz" @@ -3138,7 +3197,15 @@ through2-filter@^3.0.0: through2 "~2.0.0" xtend "~4.0.0" -through2@^2.0.0, through2@^2.0.3, through2@~2.0.0: +through2@^2.0.0: + version "2.0.5" + resolved "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" + +through2@^2.0.3: version "2.0.5" resolved "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz" integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== @@ -3146,7 +3213,15 @@ through2@^2.0.0, through2@^2.0.3, through2@~2.0.0: readable-stream "~2.3.6" xtend "~4.0.1" -through2@^3.0.0, through2@^3.0.1: +through2@^3.0.0: + version "3.0.2" + resolved "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz" + integrity sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ== + dependencies: + inherits "^2.0.4" + readable-stream "2 || 3" + +through2@^3.0.1: version "3.0.2" resolved "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz" integrity sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ== @@ -3161,10 +3236,13 @@ through2@^4.0.2: dependencies: readable-stream "3" -through@2, through@^2.3.8, through@~2.3, through@~2.3.4, through@~2.3.8: - version "2.3.8" - resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz" - integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== +through2@~2.0.0: + version "2.0.5" + resolved "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" time-stamp@^1.0.0: version "1.1.0" @@ -3179,13 +3257,6 @@ timers-ext@^0.1.7: es5-ext "~0.10.46" next-tick "1" -"tmp@0.2.1 ": - version "0.2.1" - resolved "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz" - integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== - dependencies: - rimraf "^3.0.0" - tmp@^0.0.33: version "0.0.33" resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz" @@ -3193,6 +3264,13 @@ tmp@^0.0.33: dependencies: os-tmpdir "~1.0.2" +"tmp@0.2.1 ": + version "0.2.1" + resolved "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz" + integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== + dependencies: + rimraf "^3.0.0" + to-absolute-glob@^2.0.0: version "2.0.2" resolved "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz" @@ -3201,11 +3279,6 @@ to-absolute-glob@^2.0.0: is-absolute "^1.0.0" is-negated-glob "^1.0.0" -to-buffer@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" - integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg== - to-object-path@^0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz" @@ -3250,7 +3323,7 @@ tslib@^1.10.0, tslib@^1.13.0, tslib@^1.8.1: resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslint@^6.1.3: +tslint@^6.1.3, tslint@>=5.0.0-dev: version "6.1.3" resolved "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz" integrity sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg== @@ -3296,19 +3369,11 @@ typescript@^2.0.3: resolved "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz" integrity sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w== -typescript@^4.8.3: +typescript@^4.8.3, "typescript@>=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev", "typescript@>=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev || >= 4.0.0-dev", "typescript@~2.7.1 || >=2.8.0-dev || >=2.9.0-dev || ~3.0.0 || >=3.0.0-dev || >=3.1.0-dev || >= 3.2.0-dev || >= 3.3.0-dev": version "4.8.4" resolved "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz" integrity sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ== -unbzip2-stream@^1.0.9: - version "1.4.3" - resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz#b0da04c4371311df771cdc215e87f2130991ace7" - integrity sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg== - dependencies: - buffer "^5.2.1" - through "^2.3.8" - unc-path-regex@^0.1.2: version "0.1.2" resolved "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz" @@ -3474,12 +3539,12 @@ vscode-extension-telemetry@0.4.2: vscode-jsonrpc@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-4.0.0.tgz#a7bf74ef3254d0a0c272fab15c82128e378b3be9" + resolved "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-4.0.0.tgz" integrity sha512-perEnXQdQOJMTDFNv+UF3h1Y0z4iSiaN9jIlb0OqIYgosPCZGYh/MCUlkFtV2668PL69lRDO32hmvL2yiidUYg== vscode-languageclient@5.2.1: version "5.2.1" - resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-5.2.1.tgz#7cfc83a294c409f58cfa2b910a8cfeaad0397193" + resolved "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-5.2.1.tgz" integrity sha512-7jrS/9WnV0ruqPamN1nE7qCxn0phkH5LjSgSp9h6qoJGoeAKzwKz/PF6M+iGA/aklx4GLZg1prddhEPQtuXI1Q== dependencies: semver "^5.5.0" @@ -3487,7 +3552,7 @@ vscode-languageclient@5.2.1: vscode-languageserver-protocol@3.14.1: version "3.14.1" - resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.14.1.tgz#b8aab6afae2849c84a8983d39a1cf742417afe2f" + resolved "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.14.1.tgz" integrity sha512-IL66BLb2g20uIKog5Y2dQ0IiigW0XKrvmWiOvc0yXw80z3tMEzEnHjaGAb3ENuU7MnQqgnYJ1Cl2l9RvNgDi4g== dependencies: vscode-jsonrpc "^4.0.0" @@ -3495,7 +3560,7 @@ vscode-languageserver-protocol@3.14.1: vscode-languageserver-types@3.14.0: version "3.14.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.14.0.tgz#d3b5952246d30e5241592b6dde8280e03942e743" + resolved "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.14.0.tgz" integrity sha512-lTmS6AlAlMHOvPQemVwo3CezxBp0sNB95KNPkqp3Nxd5VFEnuG1ByM0zlRWos0zjO3ZWtkvhal0COgiV1xIA4A== "vscode-nls-dev@https://github.com/Raymondd/vscode-nls-dev/releases/download/2.0.2/build.tar.gz": @@ -3542,14 +3607,14 @@ wrappy@1: resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== -xtend@^4.0.0, xtend@~4.0.0, xtend@~4.0.1: +xtend@~4.0.0, xtend@~4.0.1: version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== -y18n@^3.2.0, y18n@^3.2.1, y18n@^3.2.2: +y18n@^3.2.0, y18n@^3.2.1: version "3.2.2" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.2.tgz#85c901bd6470ce71fc4bb723ad209b70f7f28696" + resolved "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz" integrity sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ== yallist@^2.1.2: @@ -3602,9 +3667,9 @@ yargs@^7.1.0: y18n "^3.2.1" yargs-parser "^5.0.1" -yauzl@^2.10.0, yauzl@^2.4.2: +yauzl@^2.10.0: version "2.10.0" - resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" + resolved "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz" integrity sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g== dependencies: buffer-crc32 "~0.2.3" diff --git a/MarkMpn.Sql4Cds.LanguageServer/QueryExecution/Contracts/ConfirmationResponse.cs b/MarkMpn.Sql4Cds.LanguageServer/QueryExecution/Contracts/ConfirmationResponse.cs index bd2793da..ef66e37a 100644 --- a/MarkMpn.Sql4Cds.LanguageServer/QueryExecution/Contracts/ConfirmationResponse.cs +++ b/MarkMpn.Sql4Cds.LanguageServer/QueryExecution/Contracts/ConfirmationResponse.cs @@ -6,7 +6,14 @@ public class ConfirmationResponseParams { public string OwnerUri { get; set; } - public bool Result { get; set; } + public ConfirmationResult Result { get; set; } + } + + public enum ConfirmationResult + { + No, + Yes, + All } public class ConfirmationResponse diff --git a/MarkMpn.Sql4Cds.LanguageServer/QueryExecution/QueryExecutionHandler.cs b/MarkMpn.Sql4Cds.LanguageServer/QueryExecution/QueryExecutionHandler.cs index 86e16af5..2e0ab3c0 100644 --- a/MarkMpn.Sql4Cds.LanguageServer/QueryExecution/QueryExecutionHandler.cs +++ b/MarkMpn.Sql4Cds.LanguageServer/QueryExecution/QueryExecutionHandler.cs @@ -33,7 +33,7 @@ class QueryExecutionHandler : IJsonRpcMethodHandler private readonly ConcurrentDictionary> _resultSets; private readonly ConcurrentDictionary _commands; private readonly ConcurrentDictionary _confirmationEvents; - private readonly ConcurrentDictionary _confirmationResults; + private readonly ConcurrentDictionary _confirmationResults; public QueryExecutionHandler(JsonRpc lsp, ConnectionManager connectionManager, TextDocumentManager documentManager) { @@ -43,7 +43,7 @@ public QueryExecutionHandler(JsonRpc lsp, ConnectionManager connectionManager, T _resultSets = new ConcurrentDictionary>(); _commands = new ConcurrentDictionary(); _confirmationEvents = new ConcurrentDictionary(); - _confirmationResults = new ConcurrentDictionary(); + _confirmationResults = new ConcurrentDictionary(); } public void Initialize(JsonRpc lsp) @@ -139,6 +139,7 @@ private async Task ExecuteAsync(Connection.Session session, ExecuteRequestParams // query/batchComplete (BatchEventParams) var startTime = DateTime.UtcNow; ResultSetSummary resultSetInProgress = null; + var bypassWarnings = false; var batchSummary = new BatchSummary { @@ -191,7 +192,7 @@ private async Task ExecuteAsync(Connection.Session session, ExecuteRequestParams { e.Cancel = false; - if (e.Count > threshold || e.BypassCustomPluginExecution) + if ((e.Count > threshold || e.BypassCustomPluginExecution) && !bypassWarnings) { var msg = $"{operation} will affect {e.Count:N0} {GetDisplayName(e.Count, e.Metadata)}."; if (e.BypassCustomPluginExecution) @@ -202,7 +203,8 @@ private async Task ExecuteAsync(Connection.Session session, ExecuteRequestParams _confirmationEvents[request.OwnerUri] = evt; _ = _lsp.NotifyAsync(ConfirmationRequest.Type, new ConfirmationParams { OwnerUri = request.OwnerUri, Msg = msg }); evt.Wait(); - e.Cancel = !_confirmationResults[request.OwnerUri]; + e.Cancel = _confirmationResults[request.OwnerUri] == ConfirmationResult.No; + bypassWarnings = _confirmationResults[request.OwnerUri] == ConfirmationResult.All; _confirmationEvents.Remove(request.OwnerUri, out _); _confirmationResults.Remove(request.OwnerUri, out _); }; diff --git a/MarkMpn.Sql4Cds.XTB/MarkMpn.Sql4Cds.XTB.csproj b/MarkMpn.Sql4Cds.XTB/MarkMpn.Sql4Cds.XTB.csproj index 90d3bd8f..637a9546 100644 --- a/MarkMpn.Sql4Cds.XTB/MarkMpn.Sql4Cds.XTB.csproj +++ b/MarkMpn.Sql4Cds.XTB/MarkMpn.Sql4Cds.XTB.csproj @@ -66,6 +66,7 @@ + True True diff --git a/MarkMpn.Sql4Cds.XTB/MessageBoxExt.cs b/MarkMpn.Sql4Cds.XTB/MessageBoxExt.cs new file mode 100644 index 00000000..bdb87f9a --- /dev/null +++ b/MarkMpn.Sql4Cds.XTB/MessageBoxExt.cs @@ -0,0 +1,431 @@ +using System; +using System.Text; +using System.Runtime.InteropServices; +using System.Windows.Forms; +using System.Activities; + +// https://learn.microsoft.com/en-us/archive/msdn-magazine/2002/november/cutting-edge-using-windows-hooks-to-enhance-messagebox-in-net + +namespace MarkMpn.Sql4Cds.XTB +{ + static class YesYesToAllNoMessageBox + { + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + static extern bool SetWindowText(IntPtr hwnd, String lpString); + + [DllImport("user32.dll")] + static extern IntPtr GetDlgItem(IntPtr hDlg, int nIDDlgItem); + + public static DialogResult Show(IWin32Window owner, string text, string title, MessageBoxIcon icon, out bool all) + { + var cbt = new LocalCbtHook(); + var handle = IntPtr.Zero; + var alreadySetup = false; + + cbt.WindowCreated += (sender, e) => + { + if (e.IsDialogWindow) + { + alreadySetup = false; + handle = e.Handle; + } + }; + + cbt.WindowActivated += (sender, e) => + { + if (e.Handle == handle && !alreadySetup) + { + alreadySetup = true; + + // Map button text + SetWindowText(GetDlgItem(handle, (int)DialogResult.No), "Yes to &All"); + SetWindowText(GetDlgItem(handle, (int)DialogResult.Cancel), DialogResult.No.ToString()); + } + }; + + cbt.WindowDestroyed += (sender, e) => + { + if (e.Handle == handle) + { + alreadySetup = false; + handle = IntPtr.Zero; + } + }; + + cbt.Install(); + + try + { + var result = MessageBox.Show(owner, text, title, MessageBoxButtons.YesNoCancel, icon, MessageBoxDefaultButton.Button3); + + switch (result) + { + case DialogResult.Yes: + all = false; + return DialogResult.Yes; + + case DialogResult.No: + all = true; + return DialogResult.Yes; + + case DialogResult.Cancel: + all = false; + return DialogResult.No; + + default: + all = false; + return result; + } + } + finally + { + cbt.Uninstall(); + } + } + } + + // CBT hook actions + enum CbtHookAction + { + HCBT_MOVESIZE = 0, + HCBT_MINMAX = 1, + HCBT_QS = 2, + HCBT_CREATEWND = 3, + HCBT_DESTROYWND = 4, + HCBT_ACTIVATE = 5, + HCBT_CLICKSKIPPED = 6, + HCBT_KEYSKIPPED = 7, + HCBT_SYSCOMMAND = 8, + HCBT_SETFOCUS = 9 + } + + class CbtEventArgs : EventArgs + { + /// + /// Win32 handle of the window + /// + public IntPtr Handle { get; set; } + + /// + /// caption of the window + /// + public string Title { get; set; } + + /// + /// class of the window + /// + public string ClassName { get; set; } + + /// + /// whether it's a popup dialog + /// + public bool IsDialogWindow { get; set; } + } + + /// + /// Event delegate + /// + /// + /// + delegate void CbtEventHandler(object sender, CbtEventArgs e); + + class LocalCbtHook : LocalWindowsHook + { + public event CbtEventHandler WindowCreated; + public event CbtEventHandler WindowDestroyed; + public event CbtEventHandler WindowActivated; + + private IntPtr _hwnd; + private string _title; + private string _class; + private bool _isDialog; + + public LocalCbtHook() : base(HookType.WH_CBT) + { + HookInvoked += new HookEventHandler(CbtHookInvoked); + } + + public LocalCbtHook(HookProc func) : base(HookType.WH_CBT, func) + { + HookInvoked += new HookEventHandler(CbtHookInvoked); + } + + /// + /// Handles the hook event + /// + /// + /// + private void CbtHookInvoked(object sender, HookEventArgs e) + { + var code = (CbtHookAction)e.HookCode; + var wParam = e.wParam; + var lParam = e.lParam; + + // Handle hook events (only a few of available actions) + switch (code) + { + case CbtHookAction.HCBT_CREATEWND: + HandleCreateWndEvent(wParam, lParam); + break; + + case CbtHookAction.HCBT_DESTROYWND: + HandleDestroyWndEvent(wParam, lParam); + break; + + case CbtHookAction.HCBT_ACTIVATE: + HandleActivateEvent(wParam, lParam); + break; + } + + return; + } + + /// + /// Handle the CREATEWND hook event + /// + /// + /// + private void HandleCreateWndEvent(IntPtr wParam, IntPtr lParam) + { + // Cache some information + UpdateWindowData(wParam); + + // raise event + OnWindowCreated(); + } + + /// + /// Handle the DESTROYWND hook event + /// + /// + /// + private void HandleDestroyWndEvent(IntPtr wParam, IntPtr lParam) + { + // Cache some information + UpdateWindowData(wParam); + + // raise event + OnWindowDestroyed(); + } + + /// + /// Handle the ACTIVATE hook event + /// + /// + /// + private void HandleActivateEvent(IntPtr wParam, IntPtr lParam) + { + // Cache some information + UpdateWindowData(wParam); + + // raise event + OnWindowActivated(); + } + + /// + /// Read and store some information about the window + /// + /// + private void UpdateWindowData(IntPtr wParam) + { + // Cache the window handle + _hwnd = wParam; + + // Cache the window's class name + var className = new StringBuilder(40); + GetClassName(_hwnd, className, 40); + _class = className.ToString(); + + // Cache the window's title bar + var text = new StringBuilder(256); + GetWindowText(_hwnd, text, 256); + _title = text.ToString(); + + // Cache the dialog flag + _isDialog = _class == "#32770"; + } + + /// + /// Helper functions that fire events by executing user code + /// + protected virtual void OnWindowCreated() + { + if (WindowCreated != null) + { + var e = new CbtEventArgs(); + PrepareEventData(e); + WindowCreated(this, e); + } + } + + protected virtual void OnWindowDestroyed() + { + if (WindowDestroyed != null) + { + CbtEventArgs e = new CbtEventArgs(); + PrepareEventData(e); + WindowDestroyed(this, e); + } + } + + protected virtual void OnWindowActivated() + { + if (WindowActivated != null) + { + CbtEventArgs e = new CbtEventArgs(); + PrepareEventData(e); + WindowActivated(this, e); + } + } + + /// + /// Prepare the event data structure + /// + /// + private void PrepareEventData(CbtEventArgs e) + { + e.Handle = _hwnd; + e.Title = _title; + e.ClassName = _class; + e.IsDialogWindow = _isDialog; + } + + [DllImport("user32.dll")] + private static extern int GetClassName(IntPtr hwnd, StringBuilder lpClassName, int nMaxCount); + + [DllImport("user32.dll")] + private static extern int GetWindowText(IntPtr hwnd, StringBuilder lpString, int nMaxCount); + } + + class HookEventArgs : EventArgs + { + /// + /// Hook code + /// + public int HookCode { get; set; } + + /// + /// WPARAM argument + /// + public IntPtr wParam { get; set; } + + /// + /// LPARAM argument + /// + public IntPtr lParam { get; set; } + } + + // Hook Types + enum HookType + { + WH_JOURNALRECORD = 0, + WH_JOURNALPLAYBACK = 1, + WH_KEYBOARD = 2, + WH_GETMESSAGE = 3, + WH_CALLWNDPROC = 4, + WH_CBT = 5, + WH_SYSMSGFILTER = 6, + WH_MOUSE = 7, + WH_HARDWARE = 8, + WH_DEBUG = 9, + WH_SHELL = 10, + WH_FOREGROUNDIDLE = 11, + WH_CALLWNDPROCRET = 12, + WH_KEYBOARD_LL = 13, + WH_MOUSE_LL = 14 + } + + class LocalWindowsHook + { + private IntPtr _hhook; + private HookProc _filterFunc; + private HookType _hookType; + + public event HookEventHandler HookInvoked; + + protected void OnHookInvoked(HookEventArgs e) + { + if (HookInvoked != null) + HookInvoked(this, e); + } + + public LocalWindowsHook(HookType hook) + { + _hookType = hook; + _filterFunc = new HookProc(this.CoreHookProc); + } + + public LocalWindowsHook(HookType hook, HookProc func) + { + _hookType = hook; + _filterFunc = func; + } + + /// + /// Default filter function + /// + /// + /// + /// + /// + public int CoreHookProc(int code, IntPtr wParam, IntPtr lParam) + { + if (code < 0) + return CallNextHookEx(_hhook, code, wParam, lParam); + + // Let clients determine what to do + var e = new HookEventArgs + { + HookCode = code, + wParam = wParam, + lParam = lParam + }; + + OnHookInvoked(e); + + // Yield to the next hook in the chain + return CallNextHookEx(_hhook, code, wParam, lParam); + } + + /// + /// Install the hook + /// + public void Install() + { + _hhook = SetWindowsHookEx(_hookType, _filterFunc, IntPtr.Zero, AppDomain.GetCurrentThreadId()); + } + + /// + /// Uninstall the hook + /// + public void Uninstall() + { + UnhookWindowsHookEx(_hhook); + } + + [DllImport("user32.dll")] + private static extern IntPtr SetWindowsHookEx(HookType code, HookProc func, IntPtr hInstance, int threadID); + + [DllImport("user32.dll")] + private static extern int UnhookWindowsHookEx(IntPtr hhook); + + [DllImport("user32.dll")] + private static extern int CallNextHookEx(IntPtr hhook, int code, IntPtr wParam, IntPtr lParam); + } + + /// + /// Filter function delegate + /// + /// + /// + /// + /// + delegate int HookProc(int code, IntPtr wParam, IntPtr lParam); + + /// + /// Event delegate + /// + /// + /// + delegate void HookEventHandler(object sender, HookEventArgs e); +} diff --git a/MarkMpn.Sql4Cds.XTB/QueryExecutionOptions.cs b/MarkMpn.Sql4Cds.XTB/QueryExecutionOptions.cs index b34fd529..4fe682c5 100644 --- a/MarkMpn.Sql4Cds.XTB/QueryExecutionOptions.cs +++ b/MarkMpn.Sql4Cds.XTB/QueryExecutionOptions.cs @@ -22,6 +22,7 @@ class QueryExecutionOptions : IDisposable private readonly Sql4CdsConnection _con; private readonly Sql4CdsCommand _cmd; private int _retrievedPages; + private bool _suppressWarnings; public QueryExecutionOptions(Control host, BackgroundWorker worker, Sql4CdsConnection con, Sql4CdsCommand cmd) { @@ -60,7 +61,7 @@ private void ConfirmInsert(object sender, ConfirmDmlStatementEventArgs e) private bool ConfirmInsert(Sql4CdsConnection con, ConfirmDmlStatementEventArgs e) { - if (e.Count > Settings.Instance.InsertWarnThreshold || e.BypassCustomPluginExecution) + if ((e.Count > Settings.Instance.InsertWarnThreshold || e.BypassCustomPluginExecution) && !_suppressWarnings) { var msg = $"Insert will affect {e.Count:N0} {GetDisplayName(e.Count, e.Metadata)}."; if (e.BypassCustomPluginExecution) @@ -82,7 +83,7 @@ private void ConfirmUpdate(object sender, ConfirmDmlStatementEventArgs e) private bool ConfirmUpdate(Sql4CdsConnection con, ConfirmDmlStatementEventArgs e) { - if (e.Count > Settings.Instance.UpdateWarnThreshold || e.BypassCustomPluginExecution) + if ((e.Count > Settings.Instance.UpdateWarnThreshold || e.BypassCustomPluginExecution) && !_suppressWarnings) { var msg = $"Update will affect {e.Count:N0} {GetDisplayName(e.Count, e.Metadata)}."; if (e.BypassCustomPluginExecution) @@ -104,7 +105,7 @@ private void ConfirmDelete(object sender, ConfirmDmlStatementEventArgs e) private bool ConfirmDelete(Sql4CdsConnection con, ConfirmDmlStatementEventArgs e) { - if (e.Count > Settings.Instance.DeleteWarnThreshold || e.BypassCustomPluginExecution) + if ((e.Count > Settings.Instance.DeleteWarnThreshold || e.BypassCustomPluginExecution) && !_suppressWarnings) { var msg = $"Delete will affect {e.Count:N0} {GetDisplayName(e.Count, e.Metadata)}."; if (e.BypassCustomPluginExecution) @@ -170,7 +171,7 @@ private DialogResult ShowMessageBox(string msg) if (_host.InvokeRequired) return (DialogResult)_host.Invoke(new Func(ShowMessageBox), msg); - return MessageBox.Show(_host, msg + "\r\n\r\nDo you want to proceed?", "Confirm", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2); + return YesYesToAllNoMessageBox.Show(_host, msg + "\r\n\r\nDo you want to proceed?", "Confirm", MessageBoxIcon.Warning, out _suppressWarnings); } public void Dispose() From f7cd40751aa4fd3e13378c73a7e0565fff74f31e Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Tue, 21 Nov 2023 19:41:48 +0000 Subject: [PATCH 70/81] Preserve comments during formatting Fixes #393 --- MarkMpn.Sql4Cds.XTB/SqlQueryControl.cs | 123 ++++++++++++++++++++++++- 1 file changed, 121 insertions(+), 2 deletions(-) diff --git a/MarkMpn.Sql4Cds.XTB/SqlQueryControl.cs b/MarkMpn.Sql4Cds.XTB/SqlQueryControl.cs index 1c22c782..5b678958 100644 --- a/MarkMpn.Sql4Cds.XTB/SqlQueryControl.cs +++ b/MarkMpn.Sql4Cds.XTB/SqlQueryControl.cs @@ -235,8 +235,127 @@ public void Format() if (errors.Count != 0) return; - new Sql160ScriptGenerator().GenerateScript(fragment, out var sql); - _editor.Text = sql; + var tokens = new Sql160ScriptGenerator().GenerateTokens(fragment); + + // Insert any comments from the original tokens. Ignore whitespace tokens. + var targetIndex = 0; + var minDstIndex = 0; + var matchedTokens = 0; + + for (var srcIndex = 0; srcIndex < fragment.ScriptTokenStream.Count; srcIndex++) + { + var token = fragment.ScriptTokenStream[srcIndex]; + + if (token.TokenType == TSqlTokenType.WhiteSpace) + continue; + + if (token.TokenType == TSqlTokenType.MultilineComment || token.TokenType == TSqlTokenType.SingleLineComment) + { + for (var dstIndex = minDstIndex; dstIndex < tokens.Count; dstIndex++) + { + if (matchedTokens == targetIndex) + { + // Also skip over any matching whitespace + var whitespaceCount = 0; + + while (dstIndex + whitespaceCount < tokens.Count && + srcIndex - whitespaceCount - 1 >= 0 && + IsMatchingWhitespace(tokens[dstIndex + whitespaceCount], fragment.ScriptTokenStream[srcIndex - whitespaceCount - 1])) + whitespaceCount++; + + minDstIndex = CopyComment(fragment.ScriptTokenStream, srcIndex, tokens, dstIndex + whitespaceCount); + break; + } + + if (tokens[dstIndex].TokenType != TSqlTokenType.SingleLineComment && + tokens[dstIndex].TokenType != TSqlTokenType.MultilineComment && + tokens[dstIndex].TokenType != TSqlTokenType.WhiteSpace) + { + matchedTokens++; + } + } + + if (matchedTokens < targetIndex) + minDstIndex = CopyComment(fragment.ScriptTokenStream, srcIndex, tokens, tokens.Count); + + continue; + } + + targetIndex++; + } + + using (var writer = new StringWriter()) + { + foreach (var token in tokens) + writer.Write(token.Text); + + writer.Flush(); + + _editor.Text = writer.ToString(); + } + } + + private int CopyComment(IList src, int srcIndex, IList dst, int dstIndex) + { + if (dstIndex >= dst.Count) + dst.Add(src[srcIndex]); + else + dst.Insert(dstIndex, src[srcIndex]); + + // Also add any leading or trailing whitespace + var leadingSrcIndex = srcIndex - 1; + var leadingDstIndex = dstIndex - 1; + var insertPoint = dstIndex; + + while (leadingSrcIndex >= 0 && src[leadingSrcIndex].TokenType == TSqlTokenType.WhiteSpace) + { + if (IsMatchingWhitespace(dst[leadingDstIndex], src[leadingSrcIndex])) + break; + + dst.Insert(insertPoint, src[leadingSrcIndex]); + leadingSrcIndex--; + leadingDstIndex--; + dstIndex++; + } + + var trailingSrcIndex = srcIndex + 1; + var trailingDstIndex = dstIndex + 1; + + while (trailingSrcIndex < src.Count && src[trailingSrcIndex].TokenType == TSqlTokenType.WhiteSpace) + { + if (trailingDstIndex < dst.Count && IsMatchingWhitespace(dst[trailingDstIndex], src[trailingSrcIndex])) + break; + + if (trailingDstIndex >= dst.Count) + dst.Add(src[trailingSrcIndex]); + else + dst.Insert(trailingDstIndex, src[trailingSrcIndex]); + + trailingSrcIndex++; + trailingDstIndex++; + } + + return trailingDstIndex; + } + + private bool IsMatchingWhitespace(TSqlParserToken x, TSqlParserToken y) + { + if (x.TokenType != TSqlTokenType.WhiteSpace) + return false; + + if (y.TokenType != TSqlTokenType.WhiteSpace) + return false; + + if (x.Text == y.Text) + return true; + + if (x.Text == "\n" && y.Text == "\r\n") + return true; + + if (x.Text == "\r\n" && y.Text == "\n") + return true; + + return false; } private Scintilla CreateEditor() From f6ec7cc564c188822d8dc480bc124c1e0e66602b Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Tue, 21 Nov 2023 21:11:03 +0000 Subject: [PATCH 71/81] Fixed errors with CTE rewrites using alises in recursive references and unnecessary quotes in column references --- .../ExecutionPlan/ExpressionExtensions.cs | 2 +- .../TSqlFragmentExtensions.cs | 34 ++++++++++++++++++- ...emoveRecursiveCTETableReferencesVisitor.cs | 10 ++++-- .../Visitors/RewriteVisitor.cs | 6 ++-- 4 files changed, 45 insertions(+), 7 deletions(-) diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/ExpressionExtensions.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/ExpressionExtensions.cs index 85a0e4c9..69d5ec90 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/ExpressionExtensions.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/ExpressionExtensions.cs @@ -1826,7 +1826,7 @@ public static string EscapeIdentifier(this string identifier) /// /// https://learn.microsoft.com/en-us/sql/relational-databases/databases/database-identifiers?view=sql-server-ver16&redirectedfrom=MSDN#rules-for-regular-identifiers /// - private static bool IsValidIdentifier(string identifier) + public static bool IsValidIdentifier(this string identifier) { if (String.IsNullOrEmpty(identifier)) return false; diff --git a/MarkMpn.Sql4Cds.Engine/TSqlFragmentExtensions.cs b/MarkMpn.Sql4Cds.Engine/TSqlFragmentExtensions.cs index 6116f4ea..8eb6c667 100644 --- a/MarkMpn.Sql4Cds.Engine/TSqlFragmentExtensions.cs +++ b/MarkMpn.Sql4Cds.Engine/TSqlFragmentExtensions.cs @@ -1,7 +1,9 @@ -using Microsoft.SqlServer.TransactSql.ScriptDom; +using MarkMpn.Sql4Cds.Engine.ExecutionPlan; +using Microsoft.SqlServer.TransactSql.ScriptDom; using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Linq.Expressions; @@ -31,6 +33,36 @@ public static string ToSql(this TSqlFragment fragment) return sql; } + /// + /// Converts a to the corresponding SQL string in a standardised way + /// + /// The SQL DOM fragment to convert + /// The SQL string that the fragment can be parsed from + public static string ToNormalizedSql(this TSqlFragment fragment) + { + var tokens = new Sql160ScriptGenerator().GenerateTokens(fragment); + + using (var writer = new StringWriter()) + { + foreach (var token in tokens) + { + if (token.TokenType == TSqlTokenType.Identifier) + { + var value = Identifier.DecodeIdentifier(token.Text, out var quoteType); + + if (quoteType != QuoteType.NotQuoted && value.IsValidIdentifier()) + token.Text = value; + } + + writer.Write(token.Text); + } + + writer.Flush(); + + return writer.ToString(); + } + } + /// /// Creates a clone of a /// diff --git a/MarkMpn.Sql4Cds.Engine/Visitors/RemoveRecursiveCTETableReferencesVisitor.cs b/MarkMpn.Sql4Cds.Engine/Visitors/RemoveRecursiveCTETableReferencesVisitor.cs index 7e1a763e..f197efff 100644 --- a/MarkMpn.Sql4Cds.Engine/Visitors/RemoveRecursiveCTETableReferencesVisitor.cs +++ b/MarkMpn.Sql4Cds.Engine/Visitors/RemoveRecursiveCTETableReferencesVisitor.cs @@ -12,7 +12,7 @@ namespace MarkMpn.Sql4Cds.Engine.Visitors /// class RemoveRecursiveCTETableReferencesVisitor : TSqlConcreteFragmentVisitor { - private readonly string _name; + private string _name; private readonly string[] _columnNames; private readonly Dictionary _outerReferences; private BooleanExpression _joinPredicate; @@ -34,7 +34,13 @@ private bool IsRecursiveReference(TableReference tableReference) if (namedTable.SchemaObject.Identifiers.Count != 1) return false; - return namedTable.SchemaObject.BaseIdentifier.Value.Equals(_name, StringComparison.OrdinalIgnoreCase); + if (!namedTable.SchemaObject.BaseIdentifier.Value.Equals(_name, StringComparison.OrdinalIgnoreCase)) + return false; + + if (namedTable.Alias != null) + _name = namedTable.Alias.Value; + + return true; } private InlineDerivedTable CreateInlineDerivedTable() diff --git a/MarkMpn.Sql4Cds.Engine/Visitors/RewriteVisitor.cs b/MarkMpn.Sql4Cds.Engine/Visitors/RewriteVisitor.cs index 90f77f43..d66b521d 100644 --- a/MarkMpn.Sql4Cds.Engine/Visitors/RewriteVisitor.cs +++ b/MarkMpn.Sql4Cds.Engine/Visitors/RewriteVisitor.cs @@ -27,7 +27,7 @@ class RewriteVisitor : RewriteVisitorBase public RewriteVisitor(IDictionary rewrites) { _mappings = rewrites - .GroupBy(kvp => kvp.Key.ToSql(), StringComparer.OrdinalIgnoreCase) + .GroupBy(kvp => kvp.Key.ToNormalizedSql(), StringComparer.OrdinalIgnoreCase) .ToDictionary( g => g.Key, g => (ScalarExpression) g.First().Value.ToColumnReference(), @@ -37,7 +37,7 @@ public RewriteVisitor(IDictionary rewrites) public RewriteVisitor(IDictionary rewrites) { _mappings = rewrites - .GroupBy(kvp => kvp.Key.ToSql(), StringComparer.OrdinalIgnoreCase) + .GroupBy(kvp => kvp.Key.ToNormalizedSql(), StringComparer.OrdinalIgnoreCase) .ToDictionary( g => g.Key, g => g.First().Value, @@ -51,7 +51,7 @@ protected override ScalarExpression ReplaceExpression(ScalarExpression expressio if (expression == null) return null; - if (_mappings.TryGetValue(expression.ToSql(), out var column)) + if (_mappings.TryGetValue(expression.ToNormalizedSql(), out var column)) { name = (column as ColumnReferenceExpression)?.MultiPartIdentifier?.Identifiers?.Last()?.Value; return column; From 4546d398adedb7faabdd5840fe1667fd41a4c5fd Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Wed, 22 Nov 2023 08:45:43 +0000 Subject: [PATCH 72/81] Updated dependencies --- .../MarkMpn.Sql4Cds.Engine.NetCore.csproj | 4 ++-- MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.nuspec | 4 ++-- MarkMpn.Sql4Cds/MarkMpn.SQL4CDS.nuspec | 2 +- MarkMpn.Sql4Cds/MarkMpn.Sql4Cds.csproj | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/MarkMpn.Sql4Cds.Engine.NetCore/MarkMpn.Sql4Cds.Engine.NetCore.csproj b/MarkMpn.Sql4Cds.Engine.NetCore/MarkMpn.Sql4Cds.Engine.NetCore.csproj index f8ecc95d..fb4ad13c 100644 --- a/MarkMpn.Sql4Cds.Engine.NetCore/MarkMpn.Sql4Cds.Engine.NetCore.csproj +++ b/MarkMpn.Sql4Cds.Engine.NetCore/MarkMpn.Sql4Cds.Engine.NetCore.csproj @@ -10,10 +10,10 @@ - + - + diff --git a/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.nuspec b/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.nuspec index 21432f0c..01ea9fcb 100644 --- a/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.nuspec +++ b/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.nuspec @@ -33,8 +33,8 @@ Avoid using custom paging for IN and EXISTS filters, and where a single child re - - + + diff --git a/MarkMpn.Sql4Cds/MarkMpn.SQL4CDS.nuspec b/MarkMpn.Sql4Cds/MarkMpn.SQL4CDS.nuspec index b1eccd9c..29d6e379 100644 --- a/MarkMpn.Sql4Cds/MarkMpn.SQL4CDS.nuspec +++ b/MarkMpn.Sql4Cds/MarkMpn.SQL4CDS.nuspec @@ -34,7 +34,7 @@ Avoid using custom paging for IN and EXISTS filters, and where a single child re en-GB XrmToolBox SQL CDS - + diff --git a/MarkMpn.Sql4Cds/MarkMpn.Sql4Cds.csproj b/MarkMpn.Sql4Cds/MarkMpn.Sql4Cds.csproj index edc405c7..14525b16 100644 --- a/MarkMpn.Sql4Cds/MarkMpn.Sql4Cds.csproj +++ b/MarkMpn.Sql4Cds/MarkMpn.Sql4Cds.csproj @@ -96,7 +96,7 @@ 4.3.1 - 1.2023.6.65 + 1.2023.10.67 From d70055d76467dc76fdd62358945b0db077f263e4 Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Wed, 22 Nov 2023 08:46:49 +0000 Subject: [PATCH 73/81] Updated release notes --- .../MarkMpn.Sql4Cds.Engine.nuspec | 32 ++++++++++++---- MarkMpn.Sql4Cds/MarkMpn.SQL4CDS.nuspec | 38 +++++++++++++++---- 2 files changed, 55 insertions(+), 15 deletions(-) diff --git a/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.nuspec b/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.nuspec index 01ea9fcb..f585ab96 100644 --- a/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.nuspec +++ b/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.nuspec @@ -11,13 +11,31 @@ https://markcarrington.dev/sql4cds-icon/ Convert SQL queries to FetchXml and execute them against Dataverse / D365 Convert SQL queries to FetchXml and execute them against Dataverse / D365 - Fixed use of IN subqueries when data source cannot be converted to FetchXML -Fixed use of LIKE filters with data containing embedded returns -Fixed incorrect row count estimates with joins of huge tables -Fixed left outer join in nested loop when the first record has no matching records from the right source -Fixed use of partitioned aggregates within a loop -Avoid errors when using DEBUG_BYPASS_OPTIMIZATION hint -Avoid using custom paging for IN and EXISTS filters, and where a single child record is guaranteed by the filters + Added Common Table Expression support: +- Non-recursive CTEs are expanded to subqueries for compatibility with TDS Endpoint +- Recurve CTEs are converted to hierarchical FetchXML filters where possible + +Extended JSON support: +- OPENJSON table-valued function +- JSON_QUERY function +- ISJSON function + +Query optimizer improvements: +- Prefer hash joins over merge joins if sorts cannot be folded +- Switch FetchXML sorts to custom sorting after adding joins that require custom paging +- Avoid folding filters to tables in subqueries if the same alias exists in the outer query +- Do not use a left outer join to implement `NOT IN` queries where the subquery uses an inner join + +Added IGNORE_DUP_KEY query hint to ignore duplicate key errors on insert +Added check for multi-currency issues when aggregating non-base currency fields +Clearer progress messages for multi-threaded DML operations + +Fixed use of `UNION` with wildcard columns +Fixed error in nested loop joins with no records from inner source +Fixed use of columns from outer queries in join criteria in subqueries +Fixed time zone mismatch when starting bulk delete jobs +Fixed setting polymorphic lookup fields using TDS Endpoint +Fixed aggregates with very dense data distribution Copyright © 2020 Mark Carrington en-GB diff --git a/MarkMpn.Sql4Cds/MarkMpn.SQL4CDS.nuspec b/MarkMpn.Sql4Cds/MarkMpn.SQL4CDS.nuspec index 29d6e379..23f58502 100644 --- a/MarkMpn.Sql4Cds/MarkMpn.SQL4CDS.nuspec +++ b/MarkMpn.Sql4Cds/MarkMpn.SQL4CDS.nuspec @@ -20,15 +20,37 @@ Supports Where possible the queries are converted to FetchXML, allowing you to generate FetchXML queries for plugins or integrations by writing familiar SQL and converting it. -Using the preview TDS Endpoint, SELECT queries can also be run that aren't convertible to FetchXML. +Queries can also run using the preview TDS Endpoint. A wide range of SQL functionality is also built +in to allow running queries that aren't directly supported by either FetchXML or the TDS Endpoint. Convert SQL queries to FetchXML and execute them against Dataverse / D365 - Fixed use of IN subqueries when data source cannot be converted to FetchXML -Fixed use of LIKE filters with data containing embedded returns -Fixed incorrect row count estimates with joins of huge tables -Fixed left outer join in nested loop when the first record has no matching records from the right source -Fixed use of partitioned aggregates within a loop -Avoid errors when using DEBUG_BYPASS_OPTIMIZATION hint -Avoid using custom paging for IN and EXISTS filters, and where a single child record is guaranteed by the filters + Added Common Table Expression support: +- Non-recursive CTEs are expanded to subqueries for compatibility with TDS Endpoint +- Recurve CTEs are converted to hierarchical FetchXML filters where possible + +Extended JSON support: +- OPENJSON table-valued function +- JSON_QUERY function +- ISJSON function + +Query optimizer improvements: +- Prefer hash joins over merge joins if sorts cannot be folded +- Switch FetchXML sorts to custom sorting after adding joins that require custom paging +- Avoid folding filters to tables in subqueries if the same alias exists in the outer query +- Do not use a left outer join to implement `NOT IN` queries where the subquery uses an inner join + +Added IGNORE_DUP_KEY query hint to ignore duplicate key errors on insert +Added check for multi-currency issues when aggregating non-base currency fields +Clearer progress messages for multi-threaded DML operations +Added autocomplete literal value suggestions for entityname attributes + +Fixed inconsistent display of plugin log messages in error message output +Fixed use of `UNION` with wildcard columns +Fixed error in nested loop joins with no records from inner source +Fixed use of columns from outer queries in join criteria in subqueries +Fixed time zone mismatch when starting bulk delete jobs +Fixed setting polymorphic lookup fields using TDS Endpoint +Fixed aggregates with very dense data distribution +Preserve comments when formatting query Copyright © 2019 Mark Carrington en-GB From 80778081fbc3ea865ce3000164cc962df710ad43 Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Wed, 22 Nov 2023 08:47:22 +0000 Subject: [PATCH 74/81] Updated dependencies --- MarkMpn.Sql4Cds.XTB/MarkMpn.Sql4Cds.XTB.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MarkMpn.Sql4Cds.XTB/MarkMpn.Sql4Cds.XTB.csproj b/MarkMpn.Sql4Cds.XTB/MarkMpn.Sql4Cds.XTB.csproj index 637a9546..4bb95bff 100644 --- a/MarkMpn.Sql4Cds.XTB/MarkMpn.Sql4Cds.XTB.csproj +++ b/MarkMpn.Sql4Cds.XTB/MarkMpn.Sql4Cds.XTB.csproj @@ -282,7 +282,7 @@ - 1.2023.7.65 + 1.2023.10.67 From 79462c34e75da47ce2e5a0d7a8c993bfce64a923 Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Wed, 22 Nov 2023 21:17:34 +0000 Subject: [PATCH 75/81] Added option to copy URL to record --- .../SqlQueryControl.Designer.cs | 13 +++++++- MarkMpn.Sql4Cds.XTB/SqlQueryControl.cs | 33 +++++++++++++++++-- MarkMpn.Sql4Cds.XTB/SqlQueryControl.resx | 2 +- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/MarkMpn.Sql4Cds.XTB/SqlQueryControl.Designer.cs b/MarkMpn.Sql4Cds.XTB/SqlQueryControl.Designer.cs index be408829..8fb4f589 100644 --- a/MarkMpn.Sql4Cds.XTB/SqlQueryControl.Designer.cs +++ b/MarkMpn.Sql4Cds.XTB/SqlQueryControl.Designer.cs @@ -43,6 +43,7 @@ private void InitializeComponent() this.copyWithHeadersToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator(); this.openRecordToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.copyRecordUrlToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.createSELECTStatementToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.statusStrip = new System.Windows.Forms.StatusStrip(); this.toolStripStatusLabel = new System.Windows.Forms.ToolStripStatusLabel(); @@ -176,9 +177,10 @@ private void InitializeComponent() this.copyWithHeadersToolStripMenuItem, this.toolStripMenuItem1, this.openRecordToolStripMenuItem, + this.copyRecordUrlToolStripMenuItem, this.createSELECTStatementToolStripMenuItem}); this.gridContextMenuStrip.Name = "gridContextMenuStrip"; - this.gridContextMenuStrip.Size = new System.Drawing.Size(207, 98); + this.gridContextMenuStrip.Size = new System.Drawing.Size(207, 142); this.gridContextMenuStrip.Opening += new System.ComponentModel.CancelEventHandler(this.gridContextMenuStrip_Opening); // // copyToolStripMenuItem @@ -208,6 +210,14 @@ private void InitializeComponent() this.openRecordToolStripMenuItem.Text = "Open Record"; this.openRecordToolStripMenuItem.Click += new System.EventHandler(this.openRecordToolStripMenuItem_Click); // + // copyRecordUrlToolStripMenuItem + // + this.copyRecordUrlToolStripMenuItem.Enabled = false; + this.copyRecordUrlToolStripMenuItem.Name = "copyRecordUrlToolStripMenuItem"; + this.copyRecordUrlToolStripMenuItem.Size = new System.Drawing.Size(206, 22); + this.copyRecordUrlToolStripMenuItem.Text = "Copy Record Url"; + this.copyRecordUrlToolStripMenuItem.Click += new System.EventHandler(this.copyRecordUrlToolStripMenuItem_Click); + // // createSELECTStatementToolStripMenuItem // this.createSELECTStatementToolStripMenuItem.Enabled = false; @@ -378,5 +388,6 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripMenuItem openRecordToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem createSELECTStatementToolStripMenuItem; private System.Windows.Forms.Label environmentHighlightLabel; + private System.Windows.Forms.ToolStripMenuItem copyRecordUrlToolStripMenuItem; } } diff --git a/MarkMpn.Sql4Cds.XTB/SqlQueryControl.cs b/MarkMpn.Sql4Cds.XTB/SqlQueryControl.cs index 5b678958..0268d0d7 100644 --- a/MarkMpn.Sql4Cds.XTB/SqlQueryControl.cs +++ b/MarkMpn.Sql4Cds.XTB/SqlQueryControl.cs @@ -1378,13 +1378,25 @@ private int BorderThickness(DataGridViewAdvancedCellBorderStyle style) } } + private string GetRecordUrl(SqlEntityReference entityReference, out XtbDataSource dataSource) + { + dataSource = null; + + if (!DataSources.TryGetValue(entityReference.DataSource, out var ds)) + return null; + + dataSource = (XtbDataSource)ds; + return dataSource.ConnectionDetail.GetEntityReferenceUrl(entityReference); + } + private void OpenRecord(SqlEntityReference entityReference) { - if (!DataSources.TryGetValue(entityReference.DataSource, out var dataSource)) + var url = GetRecordUrl(entityReference, out var dataSource); + + if (url == null) return; - var url = ((XtbDataSource) dataSource).ConnectionDetail.GetEntityReferenceUrl(entityReference); - ((XtbDataSource)dataSource).ConnectionDetail.OpenUrlWithBrowserProfile(new Uri(url)); + dataSource.ConnectionDetail.OpenUrlWithBrowserProfile(new Uri(url)); } private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) @@ -1514,11 +1526,13 @@ private void gridContextMenuStrip_Opening(object sender, CancelEventArgs e) var grid = (DataGridView)gridContextMenuStrip.SourceControl; openRecordToolStripMenuItem.Enabled = false; + copyRecordUrlToolStripMenuItem.Enabled = false; createSELECTStatementToolStripMenuItem.Enabled = false; if (grid.CurrentCell?.Value is SqlEntityReference er && !er.IsNull) { openRecordToolStripMenuItem.Enabled = true; + copyRecordUrlToolStripMenuItem.Enabled = true; createSELECTStatementToolStripMenuItem.Enabled = true; } @@ -1533,6 +1547,19 @@ private void openRecordToolStripMenuItem_Click(object sender, EventArgs e) OpenRecord(er); } + private void copyRecordUrlToolStripMenuItem_Click(object sender, EventArgs e) + { + var grid = (DataGridView)gridContextMenuStrip.SourceControl; + + if (grid.CurrentCell?.Value is SqlEntityReference er && !er.IsNull) + { + var url = GetRecordUrl(er, out _); + + if (url != null) + Clipboard.SetText(url); + } + } + private void createSELECTStatementToolStripMenuItem_Click(object sender, EventArgs e) { var grid = (DataGridView)gridContextMenuStrip.SourceControl; diff --git a/MarkMpn.Sql4Cds.XTB/SqlQueryControl.resx b/MarkMpn.Sql4Cds.XTB/SqlQueryControl.resx index a1f0afae..4b4bd978 100644 --- a/MarkMpn.Sql4Cds.XTB/SqlQueryControl.resx +++ b/MarkMpn.Sql4Cds.XTB/SqlQueryControl.resx @@ -125,7 +125,7 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAACM - CQAAAk1TRnQBSQFMAgEBAwEAAXABAAFwAQABEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo + CQAAAk1TRnQBSQFMAgEBAwEAAYABAAGAAQABEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo AwABQAMAARADAAEBAQABCAYAAQQYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5 AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA From 55f2938c8a82a92b837fabcc26febb297a9a4aad Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Wed, 22 Nov 2023 22:02:51 +0000 Subject: [PATCH 76/81] Simplified comment reformatting logic --- MarkMpn.Sql4Cds.XTB/SqlQueryControl.cs | 66 +++++++++++++------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/MarkMpn.Sql4Cds.XTB/SqlQueryControl.cs b/MarkMpn.Sql4Cds.XTB/SqlQueryControl.cs index 0268d0d7..c7d7a3c6 100644 --- a/MarkMpn.Sql4Cds.XTB/SqlQueryControl.cs +++ b/MarkMpn.Sql4Cds.XTB/SqlQueryControl.cs @@ -238,11 +238,7 @@ public void Format() var tokens = new Sql160ScriptGenerator().GenerateTokens(fragment); // Insert any comments from the original tokens. Ignore whitespace tokens. - var targetIndex = 0; - var minDstIndex = 0; - var matchedTokens = 0; - - for (var srcIndex = 0; srcIndex < fragment.ScriptTokenStream.Count; srcIndex++) + for (int srcIndex = 0, dstIndex = -1; srcIndex < fragment.ScriptTokenStream.Count; srcIndex++) { var token = fragment.ScriptTokenStream[srcIndex]; @@ -251,37 +247,32 @@ public void Format() if (token.TokenType == TSqlTokenType.MultilineComment || token.TokenType == TSqlTokenType.SingleLineComment) { - for (var dstIndex = minDstIndex; dstIndex < tokens.Count; dstIndex++) - { - if (matchedTokens == targetIndex) - { - // Also skip over any matching whitespace - var whitespaceCount = 0; + // dstIndex currently points to the previously matched token. Move forward one so we insert the comment after that token + dstIndex++; - while (dstIndex + whitespaceCount < tokens.Count && - srcIndex - whitespaceCount - 1 >= 0 && - IsMatchingWhitespace(tokens[dstIndex + whitespaceCount], fragment.ScriptTokenStream[srcIndex - whitespaceCount - 1])) - whitespaceCount++; + // We may well have added a semicolon at the end of the statement - move after that too + if ((srcIndex == fragment.ScriptTokenStream.Count - 1 || fragment.ScriptTokenStream[srcIndex + 1].TokenType != TSqlTokenType.Semicolon) && + dstIndex <= tokens.Count - 1 && + tokens[dstIndex].TokenType == TSqlTokenType.Semicolon) + dstIndex++; - minDstIndex = CopyComment(fragment.ScriptTokenStream, srcIndex, tokens, dstIndex + whitespaceCount); - break; - } + // Also skip over any matching whitespace + var whitespaceCount = 0; - if (tokens[dstIndex].TokenType != TSqlTokenType.SingleLineComment && - tokens[dstIndex].TokenType != TSqlTokenType.MultilineComment && - tokens[dstIndex].TokenType != TSqlTokenType.WhiteSpace) - { - matchedTokens++; - } - } - - if (matchedTokens < targetIndex) - minDstIndex = CopyComment(fragment.ScriptTokenStream, srcIndex, tokens, tokens.Count); + while (dstIndex + whitespaceCount < tokens.Count && + srcIndex - whitespaceCount - 1 >= 0 && + IsMatchingWhitespace(tokens[dstIndex + whitespaceCount], fragment.ScriptTokenStream[srcIndex - whitespaceCount - 1])) + whitespaceCount++; - continue; + CopyComment(fragment.ScriptTokenStream, srcIndex, tokens, dstIndex + whitespaceCount); } + else + { + dstIndex++; - targetIndex++; + while (dstIndex < tokens.Count && !IsSameType(token, tokens[dstIndex])) + dstIndex++; + } } using (var writer = new StringWriter()) @@ -295,7 +286,18 @@ public void Format() } } - private int CopyComment(IList src, int srcIndex, IList dst, int dstIndex) + private bool IsSameType(TSqlParserToken srcToken, TSqlParserToken dstToken) + { + if (srcToken.TokenType == dstToken.TokenType) + return true; + + if (srcToken.TokenType == TSqlTokenType.Variable && dstToken.TokenType == TSqlTokenType.Identifier && dstToken.Text.StartsWith("@")) + return true; + + return false; + } + + private void CopyComment(IList src, int srcIndex, IList dst, int dstIndex) { if (dstIndex >= dst.Count) dst.Add(src[srcIndex]); @@ -334,8 +336,6 @@ private int CopyComment(IList src, int srcIndex, IList Date: Thu, 23 Nov 2023 19:35:02 +0000 Subject: [PATCH 77/81] Updated node --- build.yml | 2 +- pr-build.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.yml b/build.yml index ab3db880..81475300 100644 --- a/build.yml +++ b/build.yml @@ -41,7 +41,7 @@ steps: - task: NodeTool@0 displayName: Install Node.js inputs: - versionSpec: '18.x' + versionSpec: '20.x' - task: DotNetCoreCLI@2 displayName: dotnet restore diff --git a/pr-build.yml b/pr-build.yml index c96958c7..719fbc1f 100644 --- a/pr-build.yml +++ b/pr-build.yml @@ -57,7 +57,7 @@ steps: - task: NodeTool@0 displayName: Install Node.js inputs: - versionSpec: '18.x' + versionSpec: '20.x' - script: | call npm --no-git-tag-version version $(GitVersion.SemVer) From 51aa85aa492e39bbf82feafdfe89cbc63c8ba59d Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Thu, 23 Nov 2023 20:12:07 +0000 Subject: [PATCH 78/81] Removed npm package lock file - install packages with yarn --- AzureDataStudioExtension/package-lock.json | 12053 ------------------- 1 file changed, 12053 deletions(-) delete mode 100644 AzureDataStudioExtension/package-lock.json diff --git a/AzureDataStudioExtension/package-lock.json b/AzureDataStudioExtension/package-lock.json deleted file mode 100644 index 103a1e88..00000000 --- a/AzureDataStudioExtension/package-lock.json +++ /dev/null @@ -1,12053 +0,0 @@ -{ - "name": "azuredatastudio-sql4cds", - "version": "4.9.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "azuredatastudio-sql4cds", - "version": "4.9.0", - "license": "MIT", - "dependencies": { - "@microsoft/ads-service-downloader": "1.0.2", - "crypto": "^1.0.1", - "dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#1.3.1", - "eventemitter2": "^5.0.1", - "opener": "^1.5.2", - "tmp": "0.2.1 ", - "vscode-extension-telemetry": "0.4.2", - "vscode-languageclient": "5.2.1" - }, - "devDependencies": { - "@types/azdata": "1.40.0", - "@types/node": "^13.11.0", - "@types/vscode": "1.71.0", - "del": "^6.1.1", - "gulp": "github:gulpjs/gulp#v4.0.2", - "gulp-json-editor": "^2.5.6", - "gulp-rename": "^2.0.0", - "gulp-shell": "^0.8.0", - "gulp-sourcemaps": "^3.0.0", - "gulp-tslint": "^8.1.4", - "gulp-typescript": "^5.0.1", - "tslint": "^6.1.3", - "typescript": "^4.8.3", - "vscode-nls-dev": "https://github.com/Raymondd/vscode-nls-dev/releases/download/2.0.2/build.tar.gz" - }, - "engines": { - "azdata": ">=1.30.0", - "vscode": "*" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@gulp-sourcemaps/identity-map": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/identity-map/-/identity-map-2.0.1.tgz", - "integrity": "sha512-Tb+nSISZku+eQ4X1lAkevcQa+jknn/OVUgZ3XCxEKIsLsqYuPoJwJOPQeaOk75X3WPftb29GWY1eqE7GLsXb1Q==", - "dev": true, - "dependencies": { - "acorn": "^6.4.1", - "normalize-path": "^3.0.0", - "postcss": "^7.0.16", - "source-map": "^0.6.0", - "through2": "^3.0.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/@gulp-sourcemaps/identity-map/node_modules/through2": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", - "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", - "dev": true, - "dependencies": { - "inherits": "^2.0.4", - "readable-stream": "2 || 3" - } - }, - "node_modules/@gulp-sourcemaps/map-sources": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/map-sources/-/map-sources-1.0.0.tgz", - "integrity": "sha512-o/EatdaGt8+x2qpb0vFLC/2Gug/xYPRXb6a+ET1wGYKozKN3krDWC/zZFZAtrzxJHuDL12mwdfEFKcKMNvc55A==", - "dev": true, - "dependencies": { - "normalize-path": "^2.0.1", - "through2": "^2.0.3" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/@gulp-sourcemaps/map-sources/node_modules/normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", - "dev": true, - "dependencies": { - "remove-trailing-separator": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@gulp-sourcemaps/map-sources/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "node_modules/@microsoft/ads-service-downloader": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@microsoft/ads-service-downloader/-/ads-service-downloader-1.0.2.tgz", - "integrity": "sha512-Qpc5HNLywVZbSxeUC4S7d+VRAUddrYjkIfDXl76UwCA0iuwzi71RtciEgWfCWAZMm9CbKTIbtFGh4pYw+h81nQ==", - "dependencies": { - "async-retry": "^1.2.3", - "eventemitter2": "^5.0.1", - "http-proxy-agent": "^2.1.0", - "https-proxy-agent": "^2.2.3", - "mkdirp": "1.0.4", - "tar": "^6.1.11", - "tmp": "^0.0.33", - "yauzl": "^2.10.0" - } - }, - "node_modules/@microsoft/ads-service-downloader/node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@types/azdata": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/@types/azdata/-/azdata-1.40.0.tgz", - "integrity": "sha512-CGsuH9wY6616UGskR1bMd3KcOTHhh43dQz9ruSji3EmzUG6EYJCE+6D3+UZ6M+Ub73XzDeYXobe/rk+fGkaYlg==", - "dev": true, - "dependencies": { - "@types/vscode": "*" - } - }, - "node_modules/@types/fancy-log": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@types/fancy-log/-/fancy-log-1.3.0.tgz", - "integrity": "sha512-mQjDxyOM1Cpocd+vm1kZBP7smwKZ4TNokFeds9LV7OZibmPJFEzY3+xZMrKfUdNT71lv8GoCPD6upKwHxubClw==", - "dev": true - }, - "node_modules/@types/node": { - "version": "13.13.52", - "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.52.tgz", - "integrity": "sha512-s3nugnZumCC//n4moGGe6tkNMyYEdaDBitVjwPxXmR5lnMG5dHePinH2EdxkG3Rh1ghFHHixAG4NJhpJW1rthQ==", - "dev": true - }, - "node_modules/@types/vscode": { - "version": "1.71.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.71.0.tgz", - "integrity": "sha512-nB50bBC9H/x2CpwW9FzRRRDrTZ7G0/POttJojvN/LiVfzTGfLyQIje1L1QRMdFXK9G41k5UJN/1B9S4of7CSzA==", - "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": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/agent-base": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", - "dependencies": { - "es6-promisify": "^5.0.0" - }, - "engines": { - "node": ">= 4.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/ansi-colors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", - "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", - "dev": true, - "dependencies": { - "ansi-wrap": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ansi-gray": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", - "integrity": "sha512-HrgGIZUl8h2EHuZaU9hTR/cU5nhKxpVE1V6kdGsQ8e4zirElJ5fvtfc8N7Q1oq1aatO275i8pUFUCpNWCAnVWw==", - "dev": true, - "dependencies": { - "ansi-wrap": "0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "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/ansi-wrap": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", - "integrity": "sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "dependencies": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - } - }, - "node_modules/anymatch/node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "dev": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", - "dev": true, - "dependencies": { - "remove-trailing-separator": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/append-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", - "integrity": "sha512-WLbYiXzD3y/ATLZFufV/rZvWdZOs+Z/+5v1rBZ463Jn398pa6kcde27cvozYnBoxXblGZTFfoPpsaEw0orU5BA==", - "dev": true, - "dependencies": { - "buffer-equal": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", - "dev": true - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arr-filter": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz", - "integrity": "sha512-A2BETWCqhsecSvCkWAeVBFLH6sXEUGASuzkpjL3GR1SlL/PWL6M3J8EAAld2Uubmh39tvkJTqC9LeLHCUKmFXA==", - "dev": true, - "dependencies": { - "make-iterator": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arr-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz", - "integrity": "sha512-tVqVTHt+Q5Xb09qRkbu+DidW1yYzz5izWS2Xm2yFm7qJnmUfz4HPzNxbHkdRJbz2lrqI7S+z17xNYdFcBBO8Hw==", - "dev": true, - "dependencies": { - "make-iterator": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-differ": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", - "integrity": "sha512-LeZY+DZDRnvP7eMuQ6LHfCzUGxAAIViUBliK24P3hWXL6y4SortgR6Nim6xrkfSLlmH0+k+9NYNwVC2s53ZrYQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", - "integrity": "sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-initial": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz", - "integrity": "sha512-BC4Yl89vneCYfpLrs5JU2aAu9/a+xWbeKhvISg9PT7eWFB9UlRvI+rKEtk6mgxWr3dSkk9gQ8hCrdqt06NXPdw==", - "dev": true, - "dependencies": { - "array-slice": "^1.0.0", - "is-number": "^4.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-initial/node_modules/is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-last": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz", - "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==", - "dev": true, - "dependencies": { - "is-number": "^4.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-last/node_modules/is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-slice": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", - "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-sort": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-1.0.0.tgz", - "integrity": "sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==", - "dev": true, - "dependencies": { - "default-compare": "^1.0.0", - "get-value": "^2.0.6", - "kind-of": "^5.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-sort/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/async-done": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.2.tgz", - "integrity": "sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.2", - "process-nextick-args": "^2.0.0", - "stream-exhaust": "^1.0.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/async-each": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", - "dev": true - }, - "node_modules/async-retry": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", - "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", - "dependencies": { - "retry": "0.13.1" - } - }, - "node_modules/async-settle": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz", - "integrity": "sha512-VPXfB4Vk49z1LHHodrEQ6Xf7W4gg1w0dAPROHngx7qgDjqmIQ+fXmwgGXTW/ITLai0YLSvWepJOP9EVpMnEAcw==", - "dev": true, - "dependencies": { - "async-done": "^1.2.2" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true, - "bin": { - "atob": "bin/atob.js" - }, - "engines": { - "node": ">= 4.5.0" - } - }, - "node_modules/bach": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz", - "integrity": "sha512-bZOOfCb3gXBXbTFXq3OZtGR88LwGeJvzu6szttaIzymOTS4ZttBNOWSv7aLZja2EMycKtRYV0Oa8SNKH/zkxvg==", - "dev": true, - "dependencies": { - "arr-filter": "^1.1.1", - "arr-flatten": "^1.0.1", - "arr-map": "^2.0.0", - "array-each": "^1.0.0", - "array-initial": "^1.0.0", - "array-last": "^1.1.1", - "async-done": "^1.2.2", - "async-settle": "^1.0.0", - "now-and-later": "^2.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "dependencies": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/beeper": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", - "integrity": "sha512-3vqtKL1N45I5dV0RdssXZG7X6pCqQrWPNOlBPZPrd+QkE2HEhR57Z04m0KtpbsZH73j+a3F8UD1TQnn+ExTvIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "dev": true, - "optional": true, - "dependencies": { - "file-uri-to-path": "1.0.0" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "dependencies": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "engines": { - "node": "*" - } - }, - "node_modules/buffer-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz", - "integrity": "sha512-tcBWO2Dl4e7Asr9hTGcpVrCe+F7DubpmqWCTbj4FHLmjqO2hIaC383acQubWtRJhdceqs5uBHs6Es+Sk//RKiQ==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha512-wxXCdllwGhI2kCC0MnvTGYTMvnVZTvqgypkiTI8Pa5tcz2i6VqsqwYGgqwXji+4RgCzms6EajE4IxiUH6HH8nQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "dependencies": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "deprecated": "Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies", - "dev": true, - "dependencies": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - }, - "optionalDependencies": { - "fsevents": "^1.2.7" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", - "dev": true, - "dependencies": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - } - }, - "node_modules/chokidar/node_modules/glob-parent/node_modules/is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "engines": { - "node": ">=10" - } - }, - "node_modules/class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "dependencies": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "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/cliui": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==", - "dev": true, - "dependencies": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wrap-ansi": "^2.0.0" - } - }, - "node_modules/clone": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/clone-buffer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", - "integrity": "sha512-KLLTJWrvwIP+OPfMn0x2PheDEP20RPUcGXj/ERegTgdmPEZylALQldygiqrPPu8P45uNuPs7ckmReLY6v/iA5g==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/clone-stats": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", - "integrity": "sha512-au6ydSpg6nsrigcZ4m8Bc9hxjeW+GJ8xh5G3BJCMt4WXe1H10UNaVOamqQTmrx1kjVuxAHIQSNU6hY4Nsn9/ag==", - "dev": true - }, - "node_modules/cloneable-readable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz", - "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "process-nextick-args": "^2.0.0", - "readable-stream": "^2.3.5" - } - }, - "node_modules/code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/collection-map": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz", - "integrity": "sha512-5D2XXSpkOnleOI21TG7p3T0bGAsZ/XknZpKBmGYyluO8pw4zA3K8ZlrBIbC4FXg3m6z/RNFiUFfT2sQK01+UHA==", - "dev": true, - "dependencies": { - "arr-map": "^2.0.2", - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", - "dev": true, - "dependencies": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "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/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/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true, - "bin": { - "color-support": "bin.js" - } - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "node_modules/component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "node_modules/concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "engines": [ - "node >= 0.8" - ], - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "node_modules/config-chain": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", - "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", - "dev": true, - "dependencies": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" - } - }, - "node_modules/convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.1" - } - }, - "node_modules/copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/copy-props": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.5.tgz", - "integrity": "sha512-XBlx8HSqrT0ObQwmSzM7WE5k8FxTV75h1DX1Z3n6NhQ/UYYAvInWYmG06vFt7hQZArE2fuO62aihiWIVQwh1sw==", - "dev": true, - "dependencies": { - "each-props": "^1.3.2", - "is-plain-object": "^5.0.0" - } - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, - "node_modules/crypto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz", - "integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==", - "deprecated": "This package is no longer supported. It's now a built-in Node module. If you've depended on crypto, you should switch to the one that's built-in." - }, - "node_modules/css": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/css/-/css-3.0.0.tgz", - "integrity": "sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ==", - "dev": true, - "dependencies": { - "inherits": "^2.0.4", - "source-map": "^0.6.1", - "source-map-resolve": "^0.6.0" - } - }, - "node_modules/d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "dev": true, - "dependencies": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, - "node_modules/dataprotocol-client": { - "version": "1.3.1", - "resolved": "git+ssh://git@github.com/Microsoft/sqlops-dataprotocolclient.git#2df6982e07c0208c2b8a5f8cd4b3d65944138d15", - "license": "ISC", - "dependencies": { - "vscode-languageclient": "5.2.1" - }, - "engines": { - "azdata": "*", - "vscode": "*" - } - }, - "node_modules/dateformat": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz", - "integrity": "sha512-GODcnWq3YGoTnygPfi02ygEiRxqUxpJwuRHjdhJYuxpcZmDq4rjBiXYmbCCzStxo176ixfLT6i4NPwQooRySnw==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/debug-fabulous": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/debug-fabulous/-/debug-fabulous-1.1.0.tgz", - "integrity": "sha512-GZqvGIgKNlUnHUPQhepnUZFIMoi3dgZKQBzKDeL2g7oJF9SNAji/AAu36dusFUas0O+pae74lNeoIPHqXWDkLg==", - "dev": true, - "dependencies": { - "debug": "3.X", - "memoizee": "0.4.X", - "object-assign": "4.X" - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/default-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz", - "integrity": "sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==", - "dev": true, - "dependencies": { - "kind-of": "^5.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/default-compare/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/default-resolution": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", - "integrity": "sha512-2xaP6GiwVwOEbXCGoJ4ufgC76m8cj805jrghScewJC2ZDsb9U0b4BIrba+xt/Uytyd0HvQ6+WymSRTfnYj59GQ==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/define-properties": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", - "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", - "dev": true, - "dependencies": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/del": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", - "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", - "dev": true, - "dependencies": { - "globby": "^11.0.1", - "graceful-fs": "^4.2.4", - "is-glob": "^4.0.1", - "is-path-cwd": "^2.2.0", - "is-path-inside": "^3.0.2", - "p-map": "^4.0.0", - "rimraf": "^3.0.2", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/detect-file": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/detect-indent": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", - "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/detect-newline": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", - "integrity": "sha512-CwffZFvlJffUg9zZA0uqrjQayUTC8ob94pnr5sFwaVv3IOmkfUHcWH+jXaQK3askE51Cqe8/9Ql/0uXNwqZ8Zg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "dev": true - }, - "node_modules/duplexer2": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", - "integrity": "sha512-+AWBwjGadtksxjOQSFDhPNQbed7icNXApT4+2BNpsXzcCBiInq2H9XW0O8sfHFaPmnQRs7cg/P0fAr2IWQSW0g==", - "dev": true, - "dependencies": { - "readable-stream": "~1.1.9" - } - }, - "node_modules/duplexer2/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "node_modules/duplexer2/node_modules/readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/duplexer2/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - }, - "node_modules/duplexify": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", - "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" - } - }, - "node_modules/each-props": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz", - "integrity": "sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.1", - "object.defaults": "^1.1.0" - } - }, - "node_modules/each-props/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/editorconfig": { - "version": "0.15.3", - "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", - "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", - "dev": true, - "dependencies": { - "commander": "^2.19.0", - "lru-cache": "^4.1.5", - "semver": "^5.6.0", - "sigmund": "^1.0.1" - }, - "bin": { - "editorconfig": "bin/editorconfig" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es5-ext": { - "version": "0.10.62", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", - "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.3", - "next-tick": "^1.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", - "dev": true, - "dependencies": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" - }, - "node_modules/es6-promisify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", - "dependencies": { - "es6-promise": "^4.0.3" - } - }, - "node_modules/es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", - "dev": true, - "dependencies": { - "d": "^1.0.1", - "ext": "^1.1.2" - } - }, - "node_modules/es6-weak-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", - "dev": true, - "dependencies": { - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", - "dev": true, - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, - "node_modules/event-stream": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.5.tgz", - "integrity": "sha512-vyibDcu5JL20Me1fP734QBH/kenBGLZap2n0+XXM7mvuUPzJ20Ydqj1aKcIeMdri1p+PU+4yAKugjN8KCVst+g==", - "dev": true, - "dependencies": { - "duplexer": "^0.1.1", - "from": "^0.1.7", - "map-stream": "0.0.7", - "pause-stream": "^0.0.11", - "split": "^1.0.1", - "stream-combiner": "^0.2.2", - "through": "^2.3.8" - } - }, - "node_modules/eventemitter2": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-5.0.1.tgz", - "integrity": "sha512-5EM1GHXycJBS6mauYAbVKT1cVs7POKWb2NXD4Vyt8dDqeZa7LaDK1/sjtL+Zb0lzTpSNil4596Dyu97hz37QLg==" - }, - "node_modules/expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", - "dev": true, - "dependencies": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/expand-brackets/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", - "dev": true, - "dependencies": { - "homedir-polyfill": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ext": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", - "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", - "dev": true, - "dependencies": { - "type": "^2.7.2" - } - }, - "node_modules/ext/node_modules/type": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", - "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", - "dev": true - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "dependencies": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fancy-log": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", - "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==", - "dev": true, - "dependencies": { - "ansi-gray": "^0.1.1", - "color-support": "^1.1.3", - "parse-node-version": "^1.0.0", - "time-stamp": "^1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-levenshtein": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.1.4.tgz", - "integrity": "sha512-Ia0sQNrMPXXkqVFt6w6M1n1oKo3NfKs+mvaV811Jwir7vAk9a6PVV9VPYf6X3BU97QiLEmuW3uXH9u87zDFfdw==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "dependencies": { - "pend": "~1.2.0" - } - }, - "node_modules/file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "dev": true, - "optional": true - }, - "node_modules/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", - "dev": true, - "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", - "dev": true, - "dependencies": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", - "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", - "dev": true, - "dependencies": { - "detect-file": "^1.0.0", - "is-glob": "^4.0.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/findup-sync/node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "dev": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fined": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", - "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", - "dev": true, - "dependencies": { - "expand-tilde": "^2.0.2", - "is-plain-object": "^2.0.3", - "object.defaults": "^1.1.0", - "object.pick": "^1.2.0", - "parse-filepath": "^1.0.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/fined/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/flagged-respawn": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", - "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/flush-write-stream": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", - "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "readable-stream": "^2.3.6" - } - }, - "node_modules/for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/for-own": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==", - "dev": true, - "dependencies": { - "for-in": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", - "dev": true, - "dependencies": { - "map-cache": "^0.2.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/from": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", - "integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==", - "dev": true - }, - "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/fs-mkdirp-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", - "integrity": "sha512-+vSd9frUnapVC2RZYfL3FCB2p3g4TBhaUmrsWlSudsGdnxIuUvBB2QM1VZeBtc49QFwrp+wQLrDs3+xxDgI5gQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.11", - "through2": "^2.0.3" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/fs-mkdirp-stream/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "node_modules/fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "deprecated": "fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "dependencies": { - "bindings": "^1.5.0", - "nan": "^2.12.1" - }, - "engines": { - "node": ">= 4.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/get-caller-file": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", - "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", - "dev": true - }, - "node_modules/get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/glob": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", - "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", - "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/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/glob-stream": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz", - "integrity": "sha512-uMbLGAP3S2aDOHUDfdoYcdIePUCfysbAd0IAoWVZbeGU/oNQ8asHVSshLDJUPWxfzj8zsCG7/XeHPHTtow0nsw==", - "dev": true, - "dependencies": { - "extend": "^3.0.0", - "glob": "^7.1.1", - "glob-parent": "^3.1.0", - "is-negated-glob": "^1.0.0", - "ordered-read-streams": "^1.0.0", - "pumpify": "^1.3.5", - "readable-stream": "^2.1.5", - "remove-trailing-separator": "^1.0.1", - "to-absolute-glob": "^2.0.0", - "unique-stream": "^2.0.2" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/glob-stream/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-stream/node_modules/glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", - "dev": true, - "dependencies": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - } - }, - "node_modules/glob-stream/node_modules/is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/glob-watcher": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.5.tgz", - "integrity": "sha512-zOZgGGEHPklZNjZQaZ9f41i7F2YwE+tS5ZHrDhbBCk3stwahn5vQxnFmBJZHoYdusR6R1bLSXeGUy/BhctwKzw==", - "dev": true, - "dependencies": { - "anymatch": "^2.0.0", - "async-done": "^1.2.0", - "chokidar": "^2.0.0", - "is-negated-glob": "^1.0.0", - "just-debounce": "^1.0.0", - "normalize-path": "^3.0.0", - "object.defaults": "^1.1.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/glob/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/glob/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/global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", - "dev": true, - "dependencies": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", - "dev": true, - "dependencies": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/glogg": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz", - "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==", - "dev": true, - "dependencies": { - "sparkles": "^1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, - "node_modules/gulp": { - "version": "4.0.2", - "resolved": "git+ssh://git@github.com/gulpjs/gulp.git#069350a5febf65adc27bc816a7805471b7d96f03", - "dev": true, - "license": "MIT", - "dependencies": { - "glob-watcher": "^5.0.3", - "gulp-cli": "^2.2.0", - "undertaker": "^1.2.1", - "vinyl-fs": "^3.0.0" - }, - "bin": { - "gulp": "bin/gulp.js" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/gulp-cli": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.3.0.tgz", - "integrity": "sha512-zzGBl5fHo0EKSXsHzjspp3y5CONegCm8ErO5Qh0UzFzk2y4tMvzLWhoDokADbarfZRL2pGpRp7yt6gfJX4ph7A==", - "dev": true, - "dependencies": { - "ansi-colors": "^1.0.1", - "archy": "^1.0.0", - "array-sort": "^1.0.0", - "color-support": "^1.1.3", - "concat-stream": "^1.6.0", - "copy-props": "^2.0.1", - "fancy-log": "^1.3.2", - "gulplog": "^1.0.0", - "interpret": "^1.4.0", - "isobject": "^3.0.1", - "liftoff": "^3.1.0", - "matchdep": "^2.0.0", - "mute-stdout": "^1.0.0", - "pretty-hrtime": "^1.0.0", - "replace-homedir": "^1.0.0", - "semver-greatest-satisfied-range": "^1.1.0", - "v8flags": "^3.2.0", - "yargs": "^7.1.0" - }, - "bin": { - "gulp": "bin/gulp.js" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/gulp-json-editor": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/gulp-json-editor/-/gulp-json-editor-2.5.6.tgz", - "integrity": "sha512-66Xr6Q6m4mUNd0OOHflMB/RHgFNnLjlHgizOzUcx9CyMRymVZEM+/SpZcCDlvThBdXtQwXpdvtSepxVY/V6nQA==", - "dev": true, - "dependencies": { - "deepmerge": "^4.2.2", - "detect-indent": "^6.0.0", - "js-beautify": "^1.13.13", - "plugin-error": "^1.0.1", - "through2": "^4.0.2" - } - }, - "node_modules/gulp-rename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/gulp-rename/-/gulp-rename-2.0.0.tgz", - "integrity": "sha512-97Vba4KBzbYmR5VBs9mWmK+HwIf5mj+/zioxfZhOKeXtx5ZjBk57KFlePf5nxq9QsTtFl0ejnHE3zTC9MHXqyQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/gulp-shell": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/gulp-shell/-/gulp-shell-0.8.0.tgz", - "integrity": "sha512-wHNCgmqbWkk1c6Gc2dOL5SprcoeujQdeepICwfQRo91DIylTE7a794VEE+leq3cE2YDoiS5ulvRfKVIEMazcTQ==", - "dev": true, - "dependencies": { - "chalk": "^3.0.0", - "fancy-log": "^1.3.3", - "lodash.template": "^4.5.0", - "plugin-error": "^1.0.1", - "through2": "^3.0.1", - "tslib": "^1.10.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/gulp-shell/node_modules/through2": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", - "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", - "dev": true, - "dependencies": { - "inherits": "^2.0.4", - "readable-stream": "2 || 3" - } - }, - "node_modules/gulp-sourcemaps": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-3.0.0.tgz", - "integrity": "sha512-RqvUckJkuYqy4VaIH60RMal4ZtG0IbQ6PXMNkNsshEGJ9cldUPRb/YCgboYae+CLAs1HQNb4ADTKCx65HInquQ==", - "dev": true, - "dependencies": { - "@gulp-sourcemaps/identity-map": "^2.0.1", - "@gulp-sourcemaps/map-sources": "^1.0.0", - "acorn": "^6.4.1", - "convert-source-map": "^1.0.0", - "css": "^3.0.0", - "debug-fabulous": "^1.0.0", - "detect-newline": "^2.0.0", - "graceful-fs": "^4.0.0", - "source-map": "^0.6.0", - "strip-bom-string": "^1.0.0", - "through2": "^2.0.0" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/gulp-sourcemaps/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "node_modules/gulp-tslint": { - "version": "8.1.4", - "resolved": "https://registry.npmjs.org/gulp-tslint/-/gulp-tslint-8.1.4.tgz", - "integrity": "sha512-wBoZIEMJRz9urHwolsvQpngA9l931p6g/Liwz1b/KrsVP6jEBFZv/o0NS1TFCQZi/l8mXxz8+v3twhf4HOXxPQ==", - "dev": true, - "dependencies": { - "@types/fancy-log": "1.3.0", - "ansi-colors": "^1.0.1", - "fancy-log": "1.3.3", - "map-stream": "~0.0.7", - "plugin-error": "1.0.1", - "through": "~2.3.8" - }, - "engines": { - "node": ">= 4" - }, - "peerDependencies": { - "tslint": ">=5.0.0-dev" - } - }, - "node_modules/gulp-typescript": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/gulp-typescript/-/gulp-typescript-5.0.1.tgz", - "integrity": "sha512-YuMMlylyJtUSHG1/wuSVTrZp60k1dMEFKYOvDf7OvbAJWrDtxxD4oZon4ancdWwzjj30ztiidhe4VXJniF0pIQ==", - "dev": true, - "dependencies": { - "ansi-colors": "^3.0.5", - "plugin-error": "^1.0.1", - "source-map": "^0.7.3", - "through2": "^3.0.0", - "vinyl": "^2.1.0", - "vinyl-fs": "^3.0.3" - }, - "engines": { - "node": ">= 8" - }, - "peerDependencies": { - "typescript": "~2.7.1 || >=2.8.0-dev || >=2.9.0-dev || ~3.0.0 || >=3.0.0-dev || >=3.1.0-dev || >= 3.2.0-dev || >= 3.3.0-dev" - } - }, - "node_modules/gulp-typescript/node_modules/ansi-colors": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", - "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/gulp-typescript/node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/gulp-typescript/node_modules/through2": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", - "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", - "dev": true, - "dependencies": { - "inherits": "^2.0.4", - "readable-stream": "2 || 3" - } - }, - "node_modules/gulp-util": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", - "integrity": "sha512-q5oWPc12lwSFS9h/4VIjG+1NuNDlJ48ywV2JKItY4Ycc/n1fXJeYPVQsfu5ZrhQi7FGSDBalwUCLar/GyHXKGw==", - "deprecated": "gulp-util is deprecated - replace it, following the guidelines at https://medium.com/gulpjs/gulp-util-ca3b1f9f9ac5", - "dev": true, - "dependencies": { - "array-differ": "^1.0.0", - "array-uniq": "^1.0.2", - "beeper": "^1.0.0", - "chalk": "^1.0.0", - "dateformat": "^2.0.0", - "fancy-log": "^1.1.0", - "gulplog": "^1.0.0", - "has-gulplog": "^0.1.0", - "lodash._reescape": "^3.0.0", - "lodash._reevaluate": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.template": "^3.0.0", - "minimist": "^1.1.0", - "multipipe": "^0.1.2", - "object-assign": "^3.0.0", - "replace-ext": "0.0.1", - "through2": "^2.0.0", - "vinyl": "^0.5.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/gulp-util/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-util/node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", - "dev": true, - "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-util/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/gulp-util/node_modules/clone-stats": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", - "integrity": "sha512-dhUqc57gSMCo6TX85FLfe51eC/s+Im2MLkAgJwfaRRexR2tA4dd3eLEW4L6efzHc2iNorrRRXITifnDLlRrhaA==", - "dev": true - }, - "node_modules/gulp-util/node_modules/lodash.template": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", - "integrity": "sha512-0B4Y53I0OgHUJkt+7RmlDFWKjVAI/YUpWNiL9GQz5ORDr4ttgfQGo+phBWKFLJbBdtOwgMuUkdOHOnPg45jKmQ==", - "dev": true, - "dependencies": { - "lodash._basecopy": "^3.0.0", - "lodash._basetostring": "^3.0.0", - "lodash._basevalues": "^3.0.0", - "lodash._isiterateecall": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0", - "lodash.keys": "^3.0.0", - "lodash.restparam": "^3.0.0", - "lodash.templatesettings": "^3.0.0" - } - }, - "node_modules/gulp-util/node_modules/lodash.templatesettings": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", - "integrity": "sha512-TcrlEr31tDYnWkHFWDCV3dHYroKEXpJZ2YJYvJdhN+y4AkWMDZ5I4I8XDtUKqSAyG81N7w+I1mFEJtcED+tGqQ==", - "dev": true, - "dependencies": { - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0" - } - }, - "node_modules/gulp-util/node_modules/object-assign": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", - "integrity": "sha512-jHP15vXVGeVh1HuaA2wY6lxk+whK/x4KBG88VXeRma7CCun7iGD5qPc4eYykQ9sdQvg8jkwFKsSxHln2ybW3xQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-util/node_modules/replace-ext": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", - "integrity": "sha512-AFBWBy9EVRTa/LhEcG8QDP3FvpwZqmvN2QFDuJswFeaVhWnZMp8q3E6Zd90SR04PlIwfGdyVjNyLPyen/ek5CQ==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/gulp-util/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/gulp-util/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "node_modules/gulp-util/node_modules/vinyl": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", - "integrity": "sha512-P5zdf3WB9uzr7IFoVQ2wZTmUwHL8cMZWJGzLBNCHNZ3NB6HTMsYABtt7z8tAGIINLXyAob9B9a1yzVGMFOYKEA==", - "dev": true, - "dependencies": { - "clone": "^1.0.0", - "clone-stats": "^0.0.1", - "replace-ext": "0.0.1" - }, - "engines": { - "node": ">= 0.9" - } - }, - "node_modules/gulplog": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", - "integrity": "sha512-hm6N8nrm3Y08jXie48jsC55eCZz9mnb4OirAStEk2deqeyhXU3C1otDVh+ccttMuc1sBi6RX6ZJ720hs9RCvgw==", - "dev": true, - "dependencies": { - "glogg": "^1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-ansi/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "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/has-gulplog": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz", - "integrity": "sha512-+F4GzLjwHNNDEAJW2DC1xXfEoPkRDmUdJ7CBYw4MpqtDwOnqdImJl7GWlpqx+Wko6//J8uKTnIe4wZSv7yCqmw==", - "dev": true, - "dependencies": { - "sparkles": "^1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", - "dev": true, - "dependencies": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", - "dev": true, - "dependencies": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values/node_modules/kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/homedir-polyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", - "dev": true, - "dependencies": { - "parse-passwd": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "node_modules/http-proxy-agent": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", - "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", - "dependencies": { - "agent-base": "4", - "debug": "3.1.0" - }, - "engines": { - "node": ">= 4.5.0" - } - }, - "node_modules/http-proxy-agent/node_modules/debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/http-proxy-agent/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/https-proxy-agent": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", - "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", - "dependencies": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" - }, - "engines": { - "node": ">= 4.5.0" - } - }, - "node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "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/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "node_modules/interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/invert-kv": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-absolute": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", - "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", - "dev": true, - "dependencies": { - "is-relative": "^1.0.0", - "is-windows": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "node_modules/is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==", - "dev": true, - "dependencies": { - "binary-extensions": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "node_modules/is-core-module": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", - "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-descriptor/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", - "dev": true, - "dependencies": { - "number-is-nan": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-negated-glob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", - "integrity": "sha512-czXVVn/QEmgvej1f50BZ648vUI+em0xqMq2Sn+QncCLN4zj1UAxlT+kw/6ggQTOaZPd1HqKQGEqbpQVtJucWug==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-promise": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", - "dev": true - }, - "node_modules/is-relative": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", - "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", - "dev": true, - "dependencies": { - "is-unc-path": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-unc-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", - "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", - "dev": true, - "dependencies": { - "unc-path-regex": "^0.1.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", - "dev": true - }, - "node_modules/is-valid-glob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz", - "integrity": "sha512-AhiROmoEFDSsjx8hW+5sGwgKVIORcXnrlAx/R0ZSeaPw70Vw0CqkGBBhHGL58Uox2eXnU1AnvXJl1XlyedO5bA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/js-beautify": { - "version": "1.14.6", - "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.14.6.tgz", - "integrity": "sha512-GfofQY5zDp+cuHc+gsEXKPpNw2KbPddreEo35O6jT6i0RVK6LhsoYBhq5TvK4/n74wnA0QbK8gGd+jUZwTMKJw==", - "dev": true, - "dependencies": { - "config-chain": "^1.1.13", - "editorconfig": "^0.15.3", - "glob": "^8.0.3", - "nopt": "^6.0.0" - }, - "bin": { - "css-beautify": "js/bin/css-beautify.js", - "html-beautify": "js/bin/html-beautify.js", - "js-beautify": "js/bin/js-beautify.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/just-debounce": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.1.0.tgz", - "integrity": "sha512-qpcRocdkUmf+UTNBYx5w6dexX5J31AKK1OmPwH630a83DdVVUIngk55RSAiIGpQyoH0dlr872VHfPjnQnK1qDQ==", - "dev": true - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/last-run": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", - "integrity": "sha512-U/VxvpX4N/rFvPzr3qG5EtLKEnNI0emvIQB3/ecEwv+8GHaUKbIB8vxv1Oai5FAF0d0r7LXHhLLe5K/yChm5GQ==", - "dev": true, - "dependencies": { - "default-resolution": "^2.0.0", - "es6-weak-map": "^2.0.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/lazystream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", - "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", - "dev": true, - "dependencies": { - "readable-stream": "^2.0.5" - }, - "engines": { - "node": ">= 0.6.3" - } - }, - "node_modules/lcid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==", - "dev": true, - "dependencies": { - "invert-kv": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/lead": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz", - "integrity": "sha512-IpSVCk9AYvLHo5ctcIXxOBpMWUe+4TKN3VPWAKUbJikkmsGp0VrSM8IttVc32D6J4WUsiPE6aEFRNmIoF/gdow==", - "dev": true, - "dependencies": { - "flush-write-stream": "^1.0.2" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/liftoff": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", - "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==", - "dev": true, - "dependencies": { - "extend": "^3.0.0", - "findup-sync": "^3.0.0", - "fined": "^1.0.1", - "flagged-respawn": "^1.0.0", - "is-plain-object": "^2.0.4", - "object.map": "^1.0.0", - "rechoir": "^0.6.2", - "resolve": "^1.1.7" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/liftoff/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/lodash._basecopy": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", - "integrity": "sha512-rFR6Vpm4HeCK1WPGvjZSJ+7yik8d8PVUdCJx5rT2pogG4Ve/2ZS7kfmO5l5T2o5V2mqlNIfSF5MZlr1+xOoYQQ==", - "dev": true - }, - "node_modules/lodash._basetostring": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", - "integrity": "sha512-mTzAr1aNAv/i7W43vOR/uD/aJ4ngbtsRaCubp2BfZhlGU/eORUjg/7F6X0orNMdv33JOrdgGybtvMN/po3EWrA==", - "dev": true - }, - "node_modules/lodash._basevalues": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", - "integrity": "sha512-H94wl5P13uEqlCg7OcNNhMQ8KvWSIyqXzOPusRgHC9DK3o54P6P3xtbXlVbRABG4q5gSmp7EDdJ0MSuW9HX6Mg==", - "dev": true - }, - "node_modules/lodash._getnative": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha512-RrL9VxMEPyDMHOd9uFbvMe8X55X16/cGM5IgOKgRElQZutpX89iS6vwl64duTV1/16w5JY7tuFNXqoekmh1EmA==", - "dev": true - }, - "node_modules/lodash._isiterateecall": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", - "integrity": "sha512-De+ZbrMu6eThFti/CSzhRvTKMgQToLxbij58LMfM8JnYDNSOjkjTCIaa8ixglOeGh2nyPlakbt5bJWJ7gvpYlQ==", - "dev": true - }, - "node_modules/lodash._reescape": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", - "integrity": "sha512-Sjlavm5y+FUVIF3vF3B75GyXrzsfYV8Dlv3L4mEpuB9leg8N6yf/7rU06iLPx9fY0Mv3khVp9p7Dx0mGV6V5OQ==", - "dev": true - }, - "node_modules/lodash._reevaluate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz", - "integrity": "sha512-OrPwdDc65iJiBeUe5n/LIjd7Viy99bKwDdk7Z5ljfZg0uFRFlfQaCy9tZ4YMAag9WAZmlVpe1iZrkIMMSMHD3w==", - "dev": true - }, - "node_modules/lodash._reinterpolate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==", - "dev": true - }, - "node_modules/lodash._root": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", - "integrity": "sha512-O0pWuFSK6x4EXhM1dhZ8gchNtG7JMqBtrHdoUFUWXD7dJnNSUze1GuyQr5sOs0aCvgGeI3o/OJW8f4ca7FDxmQ==", - "dev": true - }, - "node_modules/lodash.escape": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", - "integrity": "sha512-n1PZMXgaaDWZDSvuNZ/8XOcYO2hOKDqZel5adtR30VKQAtoWs/5AOeFA0vPV8moiPzlqe7F4cP2tzpFewQyelQ==", - "dev": true, - "dependencies": { - "lodash._root": "^3.0.0" - } - }, - "node_modules/lodash.isarguments": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==", - "dev": true - }, - "node_modules/lodash.isarray": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", - "integrity": "sha512-JwObCrNJuT0Nnbuecmqr5DgtuBppuCvGD9lxjFpAzwnVtdGoDQ1zig+5W8k5/6Gcn0gZ3936HDAlGd28i7sOGQ==", - "dev": true - }, - "node_modules/lodash.keys": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", - "integrity": "sha512-CuBsapFjcubOGMn3VD+24HOAPxM79tH+V6ivJL3CHYjtrawauDJHUk//Yew9Hvc6e9rbCrURGk8z6PC+8WJBfQ==", - "dev": true, - "dependencies": { - "lodash._getnative": "^3.0.0", - "lodash.isarguments": "^3.0.0", - "lodash.isarray": "^3.0.0" - } - }, - "node_modules/lodash.restparam": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", - "integrity": "sha512-L4/arjjuq4noiUJpt3yS6KIKDtJwNe2fIYgMqyYYKoeIfV1iEqvPwhCx23o+R9dzouGihDAPN1dTIRWa7zk8tw==", - "dev": true - }, - "node_modules/lodash.template": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", - "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", - "dev": true, - "dependencies": { - "lodash._reinterpolate": "^3.0.0", - "lodash.templatesettings": "^4.0.0" - } - }, - "node_modules/lodash.templatesettings": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", - "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", - "dev": true, - "dependencies": { - "lodash._reinterpolate": "^3.0.0" - } - }, - "node_modules/lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, - "dependencies": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "node_modules/lru-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", - "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==", - "dev": true, - "dependencies": { - "es5-ext": "~0.10.2" - } - }, - "node_modules/make-iterator": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", - "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/map-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", - "integrity": "sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==", - "dev": true - }, - "node_modules/map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", - "dev": true, - "dependencies": { - "object-visit": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", - "integrity": "sha512-LFgVbaHIHMqCRuCZyfCtUOq9/Lnzhi7Z0KFUE2fhD54+JN2jLh3hC02RLkqauJ3U4soU6H1J3tfj/Byk7GoEjA==", - "dev": true, - "dependencies": { - "findup-sync": "^2.0.0", - "micromatch": "^3.0.4", - "resolve": "^1.4.0", - "stack-trace": "0.0.10" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/matchdep/node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "dev": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/findup-sync": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", - "integrity": "sha512-vs+3unmJT45eczmcAZ6zMJtxN3l/QXeccaXQx5cu/MeJMhewVfoWZqibRkOxPnmoR59+Zy5hjabfQc6JLSah4g==", - "dev": true, - "dependencies": { - "detect-file": "^1.0.0", - "is-glob": "^3.1.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/matchdep/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/memoizee": { - "version": "0.4.15", - "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz", - "integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==", - "dev": true, - "dependencies": { - "d": "^1.0.1", - "es5-ext": "^0.10.53", - "es6-weak-map": "^2.0.3", - "event-emitter": "^0.3.5", - "is-promise": "^2.2.2", - "lru-queue": "^0.1.0", - "next-tick": "^1.1.0", - "timers-ext": "^0.1.7" - } - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/micromatch/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/micromatch/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/micromatch/node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/micromatch/node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, - "node_modules/minipass": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.4.tgz", - "integrity": "sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw==", - "dependencies": { - "yallist": "^4.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", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "dependencies": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mixin-deep/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mixin-deep/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/multipipe": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", - "integrity": "sha512-7ZxrUybYv9NonoXgwoOqtStIu18D1c3eFZj27hqgf5kBrBF8Q+tE8V0MW8dKM5QLkQPh1JhhbKgHLY9kifov4Q==", - "dev": true, - "dependencies": { - "duplexer2": "0.0.2" - } - }, - "node_modules/mute-stdout": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz", - "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/nan": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.16.0.tgz", - "integrity": "sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA==", - "dev": true, - "optional": true - }, - "node_modules/nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nanomatch/node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nanomatch/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "dev": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nanomatch/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nanomatch/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nanomatch/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nanomatch/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nanomatch/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/next-tick": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", - "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", - "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", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/now-and-later": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz", - "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==", - "dev": true, - "dependencies": { - "once": "^1.3.2" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", - "dev": true, - "dependencies": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", - "dev": true, - "dependencies": { - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.defaults": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", - "integrity": "sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==", - "dev": true, - "dependencies": { - "array-each": "^1.0.1", - "array-slice": "^1.0.0", - "for-own": "^1.0.0", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object.map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", - "integrity": "sha512-3+mAJu2PLfnSVGHwIWubpOFLscJANBKuB/6A4CxBstc4aqwQY0FWcsppuy4jU5GSB95yES5JHSI+33AWuS4k6w==", - "dev": true, - "dependencies": { - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object.reduce": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz", - "integrity": "sha512-naLhxxpUESbNkRqc35oQ2scZSJueHGQNUfMW/0U37IgN6tE2dgDWg3whf+NEliy3F/QysrO48XKUz/nGPe+AQw==", - "dev": true, - "dependencies": { - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/opener": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", - "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", - "bin": { - "opener": "bin/opener-bin.js" - } - }, - "node_modules/ordered-read-streams": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", - "integrity": "sha512-Z87aSjx3r5c0ZB7bcJqIgIRX5bxR7A4aSzvIbaxd0oTkWBCOoKfuGHiKj60CHVUgg1Phm5yMZzBdt8XqRs73Mw==", - "dev": true, - "dependencies": { - "readable-stream": "^2.0.1" - } - }, - "node_modules/os-locale": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", - "integrity": "sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g==", - "dev": true, - "dependencies": { - "lcid": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "engines": { - "node": ">=0.10.0" - } - }, - "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/parse-filepath": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", - "integrity": "sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==", - "dev": true, - "dependencies": { - "is-absolute": "^1.0.0", - "map-cache": "^0.2.0", - "path-root": "^0.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", - "dev": true, - "dependencies": { - "error-ex": "^1.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/parse-node-version": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", - "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==", - "dev": true - }, - "node_modules/path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", - "dev": true, - "dependencies": { - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-root": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", - "integrity": "sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==", - "dev": true, - "dependencies": { - "path-root-regex": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-root-regex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", - "integrity": "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/pause-stream": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", - "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==", - "dev": true, - "dependencies": { - "through": "~2.3" - } - }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==" - }, - "node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", - "dev": true, - "dependencies": { - "pinkie": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/plugin-error": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", - "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", - "dev": true, - "dependencies": { - "ansi-colors": "^1.0.1", - "arr-diff": "^4.0.0", - "arr-union": "^3.1.0", - "extend-shallow": "^3.0.2" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/plugin-error/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "dev": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/plugin-error/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/plugin-error/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dev": true, - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/pretty-hrtime": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", - "integrity": "sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "node_modules/proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", - "dev": true - }, - "node_modules/pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", - "dev": true - }, - "node_modules/pump": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/pumpify": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", - "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", - "dev": true, - "dependencies": { - "duplexify": "^3.6.0", - "inherits": "^2.0.3", - "pump": "^2.0.0" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "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" - } - ] - }, - "node_modules/read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", - "dev": true, - "dependencies": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", - "dev": true, - "dependencies": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/read-pkg/node_modules/path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/readdirp/node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/readdirp/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "dev": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/readdirp/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/readdirp/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/readdirp/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/readdirp/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/readdirp/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/readdirp/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", - "dev": true, - "dependencies": { - "resolve": "^1.1.6" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "dependencies": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/regex-not/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "dev": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/regex-not/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/regex-not/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/remove-bom-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz", - "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5", - "is-utf8": "^0.2.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/remove-bom-stream": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz", - "integrity": "sha512-wigO8/O08XHb8YPzpDDT+QmRANfW6vLqxfaXm1YXhnFf3AkSLyjfG3GEFg4McZkmgL7KvCj5u2KczkvSP6NfHA==", - "dev": true, - "dependencies": { - "remove-bom-buffer": "^3.0.0", - "safe-buffer": "^5.1.0", - "through2": "^2.0.3" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/remove-bom-stream/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "node_modules/remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", - "dev": true - }, - "node_modules/repeat-element": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", - "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/replace-ext": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz", - "integrity": "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/replace-homedir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz", - "integrity": "sha512-CHPV/GAglbIB1tnQgaiysb8H2yCy8WQ7lcEwQ/eT+kLj0QHV8LnJW0zpqpE7RSkrMSRoa+EBoag86clf7WAgSg==", - "dev": true, - "dependencies": { - "homedir-polyfill": "^1.0.1", - "is-absolute": "^1.0.0", - "remove-trailing-separator": "^1.1.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==", - "dev": true - }, - "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-dir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", - "dev": true, - "dependencies": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve-options": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz", - "integrity": "sha512-NYDgziiroVeDC29xq7bp/CacZERYsA9bXYd1ZmcJlF3BcrZv5pTb4NG7SjdyKDnXZ84aC4vo2u6sNKIA1LCu/A==", - "dev": true, - "dependencies": { - "value-or-function": "^3.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", - "deprecated": "https://github.com/lydell/resolve-url#deprecated", - "dev": true - }, - "node_modules/ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "engines": { - "node": ">= 4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "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": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", - "dev": true, - "dependencies": { - "ret": "~0.1.10" - } - }, - "node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/semver-greatest-satisfied-range": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz", - "integrity": "sha512-Ny/iyOzSSa8M5ML46IAx3iXc6tfOsYU2R4AXi2UpHk60Zrgyq6eqPj/xiOfS0rRl/iiQ/rdJkVjw/5cdUyCntQ==", - "dev": true, - "dependencies": { - "sver-compat": "^1.5.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true - }, - "node_modules/set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, - "dependencies": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/set-value/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha512-fCvEXfh6NWpm+YSuY2bpXb/VIihqWA6hLsgboC+0nl71Q7N7o2eaCW8mJa/NLvQhs6jpd3VZV4UiUQlV6+lc8g==", - "dev": true - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "dependencies": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "dependencies": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "dependencies": { - "kind-of": "^3.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-util/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/snapdragon/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/snapdragon/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", - "dev": true, - "dependencies": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-resolve": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.6.0.tgz", - "integrity": "sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==", - "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", - "dev": true, - "dependencies": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0" - } - }, - "node_modules/source-map-url": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", - "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", - "deprecated": "See https://github.com/lydell/source-map-url#deprecated", - "dev": true - }, - "node_modules/sparkles": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", - "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", - "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", - "dev": true - }, - "node_modules/split": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", - "dev": true, - "dependencies": { - "through": "2" - }, - "engines": { - "node": "*" - } - }, - "node_modules/split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "dependencies": { - "extend-shallow": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/split-string/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "dev": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/split-string/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/split-string/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "node_modules/stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==", - "dev": true, - "dependencies": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stream-combiner": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", - "integrity": "sha512-6yHMqgLYDzQDcAkL+tjJDC5nSNuNIx0vZtRZeiPh7Saef7VHX9H5Ijn9l2VIol2zaNYlYEX6KyuT/237A58qEQ==", - "dev": true, - "dependencies": { - "duplexer": "~0.1.1", - "through": "~2.3.4" - } - }, - "node_modules/stream-exhaust": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz", - "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==", - "dev": true - }, - "node_modules/stream-shift": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", - "dev": true - }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", - "dev": true, - "dependencies": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-ansi/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", - "dev": true, - "dependencies": { - "is-utf8": "^0.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-bom-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", - "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "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/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/sver-compat": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz", - "integrity": "sha512-aFTHfmjwizMNlNE6dsGmoAM4lHjL0CyiobWaFiXWSlD7cIxshW422Nb8KbXCmR6z+0ZEPY+daXJrDyh/vuwTyg==", - "dev": true, - "dependencies": { - "es6-iterator": "^2.0.1", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/tar": { - "version": "6.1.11", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", - "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^3.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/tar/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/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true - }, - "node_modules/through2": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", - "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", - "dev": true, - "dependencies": { - "readable-stream": "3" - } - }, - "node_modules/through2-filter": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", - "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==", - "dev": true, - "dependencies": { - "through2": "~2.0.0", - "xtend": "~4.0.0" - } - }, - "node_modules/through2-filter/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "node_modules/through2/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/time-stamp": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", - "integrity": "sha512-gLCeArryy2yNTRzTGKbZbloctj64jkZ57hj5zdraXue6aFgd6PmvVtEyiUU+hvU0v7q08oVv8r8ev0tRo6bvgw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/timers-ext": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", - "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", - "dev": true, - "dependencies": { - "es5-ext": "~0.10.46", - "next-tick": "1" - } - }, - "node_modules/tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "dependencies": { - "rimraf": "^3.0.0" - }, - "engines": { - "node": ">=8.17.0" - } - }, - "node_modules/to-absolute-glob": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", - "integrity": "sha512-rtwLUQEwT8ZeKQbyFJyomBRYXyE16U5VKuy0ftxLMK/PZb2fkOsg5r9kHdauuVDbsNdIBoC/HCthpidamQFXYA==", - "dev": true, - "dependencies": { - "is-absolute": "^1.0.0", - "is-negated-glob": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-object-path/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "dependencies": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", - "dev": true, - "dependencies": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex/node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "dev": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-through": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz", - "integrity": "sha512-+QIz37Ly7acM4EMdw2PRN389OneM5+d844tirkGp4dPKzI5OE72V9OsbFp+CIYJDahZ41ZV05hNtcPAQUAm9/Q==", - "dev": true, - "dependencies": { - "through2": "^2.0.3" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/to-through/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/tslint": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz", - "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", - "deprecated": "TSLint has been deprecated in favor of ESLint. Please see https://github.com/palantir/tslint/issues/4534 for more information.", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "builtin-modules": "^1.1.1", - "chalk": "^2.3.0", - "commander": "^2.12.1", - "diff": "^4.0.1", - "glob": "^7.1.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.3", - "resolve": "^1.3.2", - "semver": "^5.3.0", - "tslib": "^1.13.0", - "tsutils": "^2.29.0" - }, - "bin": { - "tslint": "bin/tslint" - }, - "engines": { - "node": ">=4.8.0" - }, - "peerDependencies": { - "typescript": ">=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev || >= 4.0.0-dev" - } - }, - "node_modules/tslint/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/tslint/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/tslint/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/tslint/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/tslint/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/tslint/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/tslint/node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/tslint/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/tsutils": { - "version": "2.29.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", - "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "peerDependencies": { - "typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev" - } - }, - "node_modules/type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", - "dev": true - }, - "node_modules/typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", - "dev": true - }, - "node_modules/typescript": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", - "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/unc-path-regex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", - "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/undertaker": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.3.0.tgz", - "integrity": "sha512-/RXwi5m/Mu3H6IHQGww3GNt1PNXlbeCuclF2QYR14L/2CHPz3DFZkvB5hZ0N/QUkiXWCACML2jXViIQEQc2MLg==", - "dev": true, - "dependencies": { - "arr-flatten": "^1.0.1", - "arr-map": "^2.0.0", - "bach": "^1.0.0", - "collection-map": "^1.0.0", - "es6-weak-map": "^2.0.1", - "fast-levenshtein": "^1.0.0", - "last-run": "^1.1.0", - "object.defaults": "^1.0.0", - "object.reduce": "^1.0.0", - "undertaker-registry": "^1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/undertaker-registry": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz", - "integrity": "sha512-UR1khWeAjugW3548EfQmL9Z7pGMlBgXteQpr1IZeZBtnkCJQJIJ1Scj0mb9wQaPvUZ9Q17XqW6TIaPchJkyfqw==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dev": true, - "dependencies": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unique-stream": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz", - "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==", - "dev": true, - "dependencies": { - "json-stable-stringify-without-jsonify": "^1.0.1", - "through2-filter": "^3.0.0" - } - }, - "node_modules/unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==", - "dev": true, - "dependencies": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", - "dev": true, - "dependencies": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", - "dev": true, - "dependencies": { - "isarray": "1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", - "dev": true, - "engines": { - "node": ">=4", - "yarn": "*" - } - }, - "node_modules/urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==", - "deprecated": "Please see https://github.com/lydell/urix#deprecated", - "dev": true - }, - "node_modules/use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "node_modules/v8flags": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", - "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", - "dev": true, - "dependencies": { - "homedir-polyfill": "^1.0.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/value-or-function": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz", - "integrity": "sha512-jdBB2FrWvQC/pnPtIqcLsMaQgjhdb6B7tk1MMyTKapox+tQZbdRP4uLxu/JY0t7fbfDCUMnuelzEYv5GsxHhdg==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/vinyl": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz", - "integrity": "sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==", - "dev": true, - "dependencies": { - "clone": "^2.1.1", - "clone-buffer": "^1.0.0", - "clone-stats": "^1.0.0", - "cloneable-readable": "^1.0.0", - "remove-trailing-separator": "^1.0.1", - "replace-ext": "^1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/vinyl-fs": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz", - "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==", - "dev": true, - "dependencies": { - "fs-mkdirp-stream": "^1.0.0", - "glob-stream": "^6.1.0", - "graceful-fs": "^4.0.0", - "is-valid-glob": "^1.0.0", - "lazystream": "^1.0.0", - "lead": "^1.0.0", - "object.assign": "^4.0.4", - "pumpify": "^1.3.5", - "readable-stream": "^2.3.3", - "remove-bom-buffer": "^3.0.0", - "remove-bom-stream": "^1.2.0", - "resolve-options": "^1.1.0", - "through2": "^2.0.0", - "to-through": "^2.0.0", - "value-or-function": "^3.0.0", - "vinyl": "^2.0.0", - "vinyl-sourcemap": "^1.1.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/vinyl-fs/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "node_modules/vinyl-sourcemap": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz", - "integrity": "sha512-NiibMgt6VJGJmyw7vtzhctDcfKch4e4n9TBeoWlirb7FMg9/1Ov9k+A5ZRAtywBpRPiyECvQRQllYM8dECegVA==", - "dev": true, - "dependencies": { - "append-buffer": "^1.0.2", - "convert-source-map": "^1.5.0", - "graceful-fs": "^4.1.6", - "normalize-path": "^2.1.1", - "now-and-later": "^2.0.0", - "remove-bom-buffer": "^3.0.0", - "vinyl": "^2.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/vinyl-sourcemap/node_modules/normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", - "dev": true, - "dependencies": { - "remove-trailing-separator": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/vscode-extension-telemetry": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/vscode-extension-telemetry/-/vscode-extension-telemetry-0.4.2.tgz", - "integrity": "sha512-y0f51mVoFxHIzULQNCC26TBFIKdEC7uckS3tFoK++OOOl8mU2LlOxgmbd52T/SXoXNg5aI7xqs+4V2ug5ITvKw==", - "deprecated": "This package has been renamed to @vscode/extension-telemetry, please update to the new name", - "engines": { - "vscode": "^1.60.0" - } - }, - "node_modules/vscode-jsonrpc": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-4.0.0.tgz", - "integrity": "sha512-perEnXQdQOJMTDFNv+UF3h1Y0z4iSiaN9jIlb0OqIYgosPCZGYh/MCUlkFtV2668PL69lRDO32hmvL2yiidUYg==", - "engines": { - "node": ">=8.0.0 || >=10.0.0" - } - }, - "node_modules/vscode-languageclient": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-5.2.1.tgz", - "integrity": "sha512-7jrS/9WnV0ruqPamN1nE7qCxn0phkH5LjSgSp9h6qoJGoeAKzwKz/PF6M+iGA/aklx4GLZg1prddhEPQtuXI1Q==", - "dependencies": { - "semver": "^5.5.0", - "vscode-languageserver-protocol": "3.14.1" - }, - "engines": { - "vscode": "^1.30" - } - }, - "node_modules/vscode-languageserver-protocol": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.14.1.tgz", - "integrity": "sha512-IL66BLb2g20uIKog5Y2dQ0IiigW0XKrvmWiOvc0yXw80z3tMEzEnHjaGAb3ENuU7MnQqgnYJ1Cl2l9RvNgDi4g==", - "dependencies": { - "vscode-jsonrpc": "^4.0.0", - "vscode-languageserver-types": "3.14.0" - } - }, - "node_modules/vscode-languageserver-types": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.14.0.tgz", - "integrity": "sha512-lTmS6AlAlMHOvPQemVwo3CezxBp0sNB95KNPkqp3Nxd5VFEnuG1ByM0zlRWos0zjO3ZWtkvhal0COgiV1xIA4A==" - }, - "node_modules/vscode-nls-dev": { - "version": "2.0.1", - "resolved": "https://github.com/Raymondd/vscode-nls-dev/releases/download/2.0.2/build.tar.gz", - "integrity": "sha512-U8SoBs3upxlVvuxNNQqZJilypQsd4a7rRdHllp3NRKAZGzL8SXLoICZBCKpFDfmGKEAYYdTogf8iOB3CD78UaQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "clone": "^1.0.2", - "event-stream": "^3.3.2", - "glob": "^6.0.4", - "gulp-util": "^3.0.7", - "source-map": "^0.5.3", - "typescript": "^2.0.3", - "vinyl": "^1.1.1", - "yargs": "^3.32.0" - }, - "bin": { - "vscl": "lib/vscl.js" - } - }, - "node_modules/vscode-nls-dev/node_modules/camelcase": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "integrity": "sha512-DLIsRzJVBQu72meAKPkWQOLcujdXT32hwdfnkI1frSiSRMK1MofjKHf+MEx0SB6fjEFXL8fBDv1dKymBlOp4Qw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/vscode-nls-dev/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/vscode-nls-dev/node_modules/clone-stats": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", - "integrity": "sha512-dhUqc57gSMCo6TX85FLfe51eC/s+Im2MLkAgJwfaRRexR2tA4dd3eLEW4L6efzHc2iNorrRRXITifnDLlRrhaA==", - "dev": true - }, - "node_modules/vscode-nls-dev/node_modules/glob": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", - "integrity": "sha512-MKZeRNyYZAVVVG1oZeLaWie1uweH40m9AZwIwxyPbTSX4hHrVYSzLg0Ro5Z5R7XKkIX+Cc6oD1rqeDJnwsB8/A==", - "dev": true, - "dependencies": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/vscode-nls-dev/node_modules/replace-ext": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", - "integrity": "sha512-AFBWBy9EVRTa/LhEcG8QDP3FvpwZqmvN2QFDuJswFeaVhWnZMp8q3E6Zd90SR04PlIwfGdyVjNyLPyen/ek5CQ==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/vscode-nls-dev/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/vscode-nls-dev/node_modules/typescript": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz", - "integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/vscode-nls-dev/node_modules/vinyl": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", - "integrity": "sha512-Ci3wnR2uuSAWFMSglZuB8Z2apBdtOyz8CV7dC6/U1XbltXBC+IuutUkXQISz01P+US2ouBuesSbV6zILZ6BuzQ==", - "dev": true, - "dependencies": { - "clone": "^1.0.0", - "clone-stats": "^0.0.1", - "replace-ext": "0.0.1" - }, - "engines": { - "node": ">= 0.9" - } - }, - "node_modules/vscode-nls-dev/node_modules/yargs": { - "version": "3.32.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz", - "integrity": "sha512-ONJZiimStfZzhKamYvR/xvmgW3uEkAUFSP91y2caTEPhzF6uP2JfPiVZcq66b/YR0C3uitxSV7+T1x8p5bkmMg==", - "dev": true, - "dependencies": { - "camelcase": "^2.0.1", - "cliui": "^3.0.3", - "decamelize": "^1.1.1", - "os-locale": "^1.4.0", - "string-width": "^1.0.1", - "window-size": "^0.1.4", - "y18n": "^3.2.0" - } - }, - "node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/which-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", - "integrity": "sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==", - "dev": true - }, - "node_modules/window-size": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz", - "integrity": "sha512-2thx4pB0cV3h+Bw7QmMXcEbdmOzv9t0HFplJH/Lz6yu60hXYy5RT8rUu+wlIreVxWsGN20mo+MHeCSfUpQBwPw==", - "dev": true, - "bin": { - "window-size": "cli.js" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==", - "dev": true, - "dependencies": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true, - "engines": { - "node": ">=0.4" - } - }, - "node_modules/y18n": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", - "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==", - "dev": true - }, - "node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", - "dev": true - }, - "node_modules/yargs": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.2.tgz", - "integrity": "sha512-ZEjj/dQYQy0Zx0lgLMLR8QuaqTihnxirir7EwUHp1Axq4e3+k8jXU5K0VLbNvedv1f4EWtBonDIZm0NUr+jCcA==", - "dev": true, - "dependencies": { - "camelcase": "^3.0.0", - "cliui": "^3.2.0", - "decamelize": "^1.1.1", - "get-caller-file": "^1.0.1", - "os-locale": "^1.4.0", - "read-pkg-up": "^1.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^1.0.2", - "which-module": "^1.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^5.0.1" - } - }, - "node_modules/yargs-parser": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.1.tgz", - "integrity": "sha512-wpav5XYiddjXxirPoCTUPbqM0PXvJ9hiBMvuJgInvo4/lAOTZzUprArw17q2O1P2+GHhbBr18/iQwjL5Z9BqfA==", - "dev": true, - "dependencies": { - "camelcase": "^3.0.0", - "object.assign": "^4.1.0" - } - }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - } - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "dev": true, - "requires": { - "@babel/highlight": "^7.18.6" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true - }, - "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@gulp-sourcemaps/identity-map": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/identity-map/-/identity-map-2.0.1.tgz", - "integrity": "sha512-Tb+nSISZku+eQ4X1lAkevcQa+jknn/OVUgZ3XCxEKIsLsqYuPoJwJOPQeaOk75X3WPftb29GWY1eqE7GLsXb1Q==", - "dev": true, - "requires": { - "acorn": "^6.4.1", - "normalize-path": "^3.0.0", - "postcss": "^7.0.16", - "source-map": "^0.6.0", - "through2": "^3.0.1" - }, - "dependencies": { - "through2": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", - "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", - "dev": true, - "requires": { - "inherits": "^2.0.4", - "readable-stream": "2 || 3" - } - } - } - }, - "@gulp-sourcemaps/map-sources": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/map-sources/-/map-sources-1.0.0.tgz", - "integrity": "sha512-o/EatdaGt8+x2qpb0vFLC/2Gug/xYPRXb6a+ET1wGYKozKN3krDWC/zZFZAtrzxJHuDL12mwdfEFKcKMNvc55A==", - "dev": true, - "requires": { - "normalize-path": "^2.0.1", - "through2": "^2.0.3" - }, - "dependencies": { - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - }, - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - } - } - }, - "@microsoft/ads-service-downloader": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@microsoft/ads-service-downloader/-/ads-service-downloader-1.0.2.tgz", - "integrity": "sha512-Qpc5HNLywVZbSxeUC4S7d+VRAUddrYjkIfDXl76UwCA0iuwzi71RtciEgWfCWAZMm9CbKTIbtFGh4pYw+h81nQ==", - "requires": { - "async-retry": "^1.2.3", - "eventemitter2": "^5.0.1", - "http-proxy-agent": "^2.1.0", - "https-proxy-agent": "^2.2.3", - "mkdirp": "1.0.4", - "tar": "^6.1.11", - "tmp": "^0.0.33", - "yauzl": "^2.10.0" - }, - "dependencies": { - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "requires": { - "os-tmpdir": "~1.0.2" - } - } - } - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@types/azdata": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/@types/azdata/-/azdata-1.40.0.tgz", - "integrity": "sha512-CGsuH9wY6616UGskR1bMd3KcOTHhh43dQz9ruSji3EmzUG6EYJCE+6D3+UZ6M+Ub73XzDeYXobe/rk+fGkaYlg==", - "dev": true, - "requires": { - "@types/vscode": "*" - } - }, - "@types/fancy-log": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@types/fancy-log/-/fancy-log-1.3.0.tgz", - "integrity": "sha512-mQjDxyOM1Cpocd+vm1kZBP7smwKZ4TNokFeds9LV7OZibmPJFEzY3+xZMrKfUdNT71lv8GoCPD6upKwHxubClw==", - "dev": true - }, - "@types/node": { - "version": "13.13.52", - "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.52.tgz", - "integrity": "sha512-s3nugnZumCC//n4moGGe6tkNMyYEdaDBitVjwPxXmR5lnMG5dHePinH2EdxkG3Rh1ghFHHixAG4NJhpJW1rthQ==", - "dev": true - }, - "@types/vscode": { - "version": "1.71.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.71.0.tgz", - "integrity": "sha512-nB50bBC9H/x2CpwW9FzRRRDrTZ7G0/POttJojvN/LiVfzTGfLyQIje1L1QRMdFXK9G41k5UJN/1B9S4of7CSzA==", - "dev": true - }, - "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 - }, - "acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", - "dev": true - }, - "agent-base": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", - "requires": { - "es6-promisify": "^5.0.0" - } - }, - "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, - "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - } - }, - "ansi-colors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", - "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", - "dev": true, - "requires": { - "ansi-wrap": "^0.1.0" - } - }, - "ansi-gray": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", - "integrity": "sha512-HrgGIZUl8h2EHuZaU9hTR/cU5nhKxpVE1V6kdGsQ8e4zirElJ5fvtfc8N7Q1oq1aatO275i8pUFUCpNWCAnVWw==", - "dev": true, - "requires": { - "ansi-wrap": "0.1.0" - } - }, - "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, - "requires": { - "color-convert": "^2.0.1" - } - }, - "ansi-wrap": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", - "integrity": "sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw==", - "dev": true - }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - }, - "dependencies": { - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - } - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - } - } - }, - "append-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", - "integrity": "sha512-WLbYiXzD3y/ATLZFufV/rZvWdZOs+Z/+5v1rBZ463Jn398pa6kcde27cvozYnBoxXblGZTFfoPpsaEw0orU5BA==", - "dev": true, - "requires": { - "buffer-equal": "^1.0.0" - } - }, - "archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", - "dev": true - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", - "dev": true - }, - "arr-filter": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz", - "integrity": "sha512-A2BETWCqhsecSvCkWAeVBFLH6sXEUGASuzkpjL3GR1SlL/PWL6M3J8EAAld2Uubmh39tvkJTqC9LeLHCUKmFXA==", - "dev": true, - "requires": { - "make-iterator": "^1.0.0" - } - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "arr-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz", - "integrity": "sha512-tVqVTHt+Q5Xb09qRkbu+DidW1yYzz5izWS2Xm2yFm7qJnmUfz4HPzNxbHkdRJbz2lrqI7S+z17xNYdFcBBO8Hw==", - "dev": true, - "requires": { - "make-iterator": "^1.0.0" - } - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", - "dev": true - }, - "array-differ": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", - "integrity": "sha512-LeZY+DZDRnvP7eMuQ6LHfCzUGxAAIViUBliK24P3hWXL6y4SortgR6Nim6xrkfSLlmH0+k+9NYNwVC2s53ZrYQ==", - "dev": true - }, - "array-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", - "integrity": "sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==", - "dev": true - }, - "array-initial": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz", - "integrity": "sha512-BC4Yl89vneCYfpLrs5JU2aAu9/a+xWbeKhvISg9PT7eWFB9UlRvI+rKEtk6mgxWr3dSkk9gQ8hCrdqt06NXPdw==", - "dev": true, - "requires": { - "array-slice": "^1.0.0", - "is-number": "^4.0.0" - }, - "dependencies": { - "is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "dev": true - } - } - }, - "array-last": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz", - "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==", - "dev": true, - "requires": { - "is-number": "^4.0.0" - }, - "dependencies": { - "is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "dev": true - } - } - }, - "array-slice": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", - "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", - "dev": true - }, - "array-sort": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-1.0.0.tgz", - "integrity": "sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==", - "dev": true, - "requires": { - "default-compare": "^1.0.0", - "get-value": "^2.0.6", - "kind-of": "^5.0.2" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", - "dev": true - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", - "dev": true - }, - "async-done": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.2.tgz", - "integrity": "sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.2", - "process-nextick-args": "^2.0.0", - "stream-exhaust": "^1.0.1" - } - }, - "async-each": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", - "dev": true - }, - "async-retry": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", - "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", - "requires": { - "retry": "0.13.1" - } - }, - "async-settle": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz", - "integrity": "sha512-VPXfB4Vk49z1LHHodrEQ6Xf7W4gg1w0dAPROHngx7qgDjqmIQ+fXmwgGXTW/ITLai0YLSvWepJOP9EVpMnEAcw==", - "dev": true, - "requires": { - "async-done": "^1.2.2" - } - }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true - }, - "bach": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz", - "integrity": "sha512-bZOOfCb3gXBXbTFXq3OZtGR88LwGeJvzu6szttaIzymOTS4ZttBNOWSv7aLZja2EMycKtRYV0Oa8SNKH/zkxvg==", - "dev": true, - "requires": { - "arr-filter": "^1.1.1", - "arr-flatten": "^1.0.1", - "arr-map": "^2.0.0", - "array-each": "^1.0.0", - "array-initial": "^1.0.0", - "array-last": "^1.1.1", - "async-done": "^1.2.2", - "async-settle": "^1.0.0", - "now-and-later": "^2.0.0" - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "beeper": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", - "integrity": "sha512-3vqtKL1N45I5dV0RdssXZG7X6pCqQrWPNOlBPZPrd+QkE2HEhR57Z04m0KtpbsZH73j+a3F8UD1TQnn+ExTvIA==", - "dev": true - }, - "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "dev": true - }, - "bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "dev": true, - "optional": true, - "requires": { - "file-uri-to-path": "1.0.0" - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - } - }, - "buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==" - }, - "buffer-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz", - "integrity": "sha512-tcBWO2Dl4e7Asr9hTGcpVrCe+F7DubpmqWCTbj4FHLmjqO2hIaC383acQubWtRJhdceqs5uBHs6Es+Sk//RKiQ==", - "dev": true - }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha512-wxXCdllwGhI2kCC0MnvTGYTMvnVZTvqgypkiTI8Pa5tcz2i6VqsqwYGgqwXji+4RgCzms6EajE4IxiUH6HH8nQ==", - "dev": true - }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==", - "dev": true - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "dev": true, - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - }, - "dependencies": { - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", - "dev": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - } - } - }, - "chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" - }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - } - }, - "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 - }, - "cliui": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==", - "dev": true, - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wrap-ansi": "^2.0.0" - } - }, - "clone": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", - "dev": true - }, - "clone-buffer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", - "integrity": "sha512-KLLTJWrvwIP+OPfMn0x2PheDEP20RPUcGXj/ERegTgdmPEZylALQldygiqrPPu8P45uNuPs7ckmReLY6v/iA5g==", - "dev": true - }, - "clone-stats": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", - "integrity": "sha512-au6ydSpg6nsrigcZ4m8Bc9hxjeW+GJ8xh5G3BJCMt4WXe1H10UNaVOamqQTmrx1kjVuxAHIQSNU6hY4Nsn9/ag==", - "dev": true - }, - "cloneable-readable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz", - "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "process-nextick-args": "^2.0.0", - "readable-stream": "^2.3.5" - } - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", - "dev": true - }, - "collection-map": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz", - "integrity": "sha512-5D2XXSpkOnleOI21TG7p3T0bGAsZ/XknZpKBmGYyluO8pw4zA3K8ZlrBIbC4FXg3m6z/RNFiUFfT2sQK01+UHA==", - "dev": true, - "requires": { - "arr-map": "^2.0.2", - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" - } - }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", - "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, - "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, - "requires": { - "color-name": "~1.1.4" - } - }, - "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 - }, - "color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true - }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "config-chain": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", - "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", - "dev": true, - "requires": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" - } - }, - "convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==", - "dev": true - }, - "copy-props": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.5.tgz", - "integrity": "sha512-XBlx8HSqrT0ObQwmSzM7WE5k8FxTV75h1DX1Z3n6NhQ/UYYAvInWYmG06vFt7hQZArE2fuO62aihiWIVQwh1sw==", - "dev": true, - "requires": { - "each-props": "^1.3.2", - "is-plain-object": "^5.0.0" - } - }, - "core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, - "crypto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz", - "integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==" - }, - "css": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/css/-/css-3.0.0.tgz", - "integrity": "sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ==", - "dev": true, - "requires": { - "inherits": "^2.0.4", - "source-map": "^0.6.1", - "source-map-resolve": "^0.6.0" - } - }, - "d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "dev": true, - "requires": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, - "dataprotocol-client": { - "version": "git+ssh://git@github.com/Microsoft/sqlops-dataprotocolclient.git#2df6982e07c0208c2b8a5f8cd4b3d65944138d15", - "from": "dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#1.3.1", - "requires": { - "vscode-languageclient": "5.2.1" - } - }, - "dateformat": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz", - "integrity": "sha512-GODcnWq3YGoTnygPfi02ygEiRxqUxpJwuRHjdhJYuxpcZmDq4rjBiXYmbCCzStxo176ixfLT6i4NPwQooRySnw==", - "dev": true - }, - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "requires": { - "ms": "^2.1.1" - } - }, - "debug-fabulous": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/debug-fabulous/-/debug-fabulous-1.1.0.tgz", - "integrity": "sha512-GZqvGIgKNlUnHUPQhepnUZFIMoi3dgZKQBzKDeL2g7oJF9SNAji/AAu36dusFUas0O+pae74lNeoIPHqXWDkLg==", - "dev": true, - "requires": { - "debug": "3.X", - "memoizee": "0.4.X", - "object-assign": "4.X" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==", - "dev": true - }, - "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true - }, - "default-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz", - "integrity": "sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==", - "dev": true, - "requires": { - "kind-of": "^5.0.2" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "default-resolution": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", - "integrity": "sha512-2xaP6GiwVwOEbXCGoJ4ufgC76m8cj805jrghScewJC2ZDsb9U0b4BIrba+xt/Uytyd0HvQ6+WymSRTfnYj59GQ==", - "dev": true - }, - "define-properties": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", - "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", - "dev": true, - "requires": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "del": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", - "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", - "dev": true, - "requires": { - "globby": "^11.0.1", - "graceful-fs": "^4.2.4", - "is-glob": "^4.0.1", - "is-path-cwd": "^2.2.0", - "is-path-inside": "^3.0.2", - "p-map": "^4.0.0", - "rimraf": "^3.0.2", - "slash": "^3.0.0" - } - }, - "detect-file": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", - "dev": true - }, - "detect-indent": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", - "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", - "dev": true - }, - "detect-newline": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", - "integrity": "sha512-CwffZFvlJffUg9zZA0uqrjQayUTC8ob94pnr5sFwaVv3IOmkfUHcWH+jXaQK3askE51Cqe8/9Ql/0uXNwqZ8Zg==", - "dev": true - }, - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, - "duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "dev": true - }, - "duplexer2": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", - "integrity": "sha512-+AWBwjGadtksxjOQSFDhPNQbed7icNXApT4+2BNpsXzcCBiInq2H9XW0O8sfHFaPmnQRs7cg/P0fAr2IWQSW0g==", - "dev": true, - "requires": { - "readable-stream": "~1.1.9" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - } - } - }, - "duplexify": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", - "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", - "dev": true, - "requires": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" - } - }, - "each-props": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz", - "integrity": "sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.1", - "object.defaults": "^1.1.0" - }, - "dependencies": { - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - } - } - }, - "editorconfig": { - "version": "0.15.3", - "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", - "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", - "dev": true, - "requires": { - "commander": "^2.19.0", - "lru-cache": "^4.1.5", - "semver": "^5.6.0", - "sigmund": "^1.0.1" - } - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es5-ext": { - "version": "0.10.62", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", - "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", - "dev": true, - "requires": { - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.3", - "next-tick": "^1.1.0" - } - }, - "es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" - }, - "es6-promisify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", - "requires": { - "es6-promise": "^4.0.3" - } - }, - "es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", - "dev": true, - "requires": { - "d": "^1.0.1", - "ext": "^1.1.2" - } - }, - "es6-weak-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.1" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, - "event-stream": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.5.tgz", - "integrity": "sha512-vyibDcu5JL20Me1fP734QBH/kenBGLZap2n0+XXM7mvuUPzJ20Ydqj1aKcIeMdri1p+PU+4yAKugjN8KCVst+g==", - "dev": true, - "requires": { - "duplexer": "^0.1.1", - "from": "^0.1.7", - "map-stream": "0.0.7", - "pause-stream": "^0.0.11", - "split": "^1.0.1", - "stream-combiner": "^0.2.2", - "through": "^2.3.8" - } - }, - "eventemitter2": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-5.0.1.tgz", - "integrity": "sha512-5EM1GHXycJBS6mauYAbVKT1cVs7POKWb2NXD4Vyt8dDqeZa7LaDK1/sjtL+Zb0lzTpSNil4596Dyu97hz37QLg==" - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - } - } - }, - "expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", - "dev": true, - "requires": { - "homedir-polyfill": "^1.0.1" - } - }, - "ext": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", - "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", - "dev": true, - "requires": { - "type": "^2.7.2" - }, - "dependencies": { - "type": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", - "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", - "dev": true - } - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "fancy-log": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", - "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==", - "dev": true, - "requires": { - "ansi-gray": "^0.1.1", - "color-support": "^1.1.3", - "parse-node-version": "^1.0.0", - "time-stamp": "^1.0.0" - } - }, - "fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - } - }, - "fast-levenshtein": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.1.4.tgz", - "integrity": "sha512-Ia0sQNrMPXXkqVFt6w6M1n1oKo3NfKs+mvaV811Jwir7vAk9a6PVV9VPYf6X3BU97QiLEmuW3uXH9u87zDFfdw==", - "dev": true - }, - "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "requires": { - "pend": "~1.2.0" - } - }, - "file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "dev": true, - "optional": true - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - } - }, - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", - "dev": true, - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "findup-sync": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", - "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", - "dev": true, - "requires": { - "detect-file": "^1.0.0", - "is-glob": "^4.0.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" - }, - "dependencies": { - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - } - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - } - } - }, - "fined": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", - "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", - "dev": true, - "requires": { - "expand-tilde": "^2.0.2", - "is-plain-object": "^2.0.3", - "object.defaults": "^1.1.0", - "object.pick": "^1.2.0", - "parse-filepath": "^1.0.1" - }, - "dependencies": { - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - } - } - }, - "flagged-respawn": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", - "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", - "dev": true - }, - "flush-write-stream": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", - "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "readable-stream": "^2.3.6" - } - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", - "dev": true - }, - "for-own": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==", - "dev": true, - "requires": { - "for-in": "^1.0.1" - } - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } - }, - "from": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", - "integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==", - "dev": true - }, - "fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "requires": { - "minipass": "^3.0.0" - } - }, - "fs-mkdirp-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", - "integrity": "sha512-+vSd9frUnapVC2RZYfL3FCB2p3g4TBhaUmrsWlSudsGdnxIuUvBB2QM1VZeBtc49QFwrp+wQLrDs3+xxDgI5gQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "through2": "^2.0.3" - }, - "dependencies": { - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - } - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "dev": true, - "optional": true, - "requires": { - "bindings": "^1.5.0", - "nan": "^2.12.1" - } - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "get-caller-file": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", - "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", - "dev": true - }, - "get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - } - }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", - "dev": true - }, - "glob": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", - "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "dependencies": { - "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, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - } - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "glob-stream": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz", - "integrity": "sha512-uMbLGAP3S2aDOHUDfdoYcdIePUCfysbAd0IAoWVZbeGU/oNQ8asHVSshLDJUPWxfzj8zsCG7/XeHPHTtow0nsw==", - "dev": true, - "requires": { - "extend": "^3.0.0", - "glob": "^7.1.1", - "glob-parent": "^3.1.0", - "is-negated-glob": "^1.0.0", - "ordered-read-streams": "^1.0.0", - "pumpify": "^1.3.5", - "readable-stream": "^2.1.5", - "remove-trailing-separator": "^1.0.1", - "to-absolute-glob": "^2.0.0", - "unique-stream": "^2.0.2" - }, - "dependencies": { - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", - "dev": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - } - }, - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "glob-watcher": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.5.tgz", - "integrity": "sha512-zOZgGGEHPklZNjZQaZ9f41i7F2YwE+tS5ZHrDhbBCk3stwahn5vQxnFmBJZHoYdusR6R1bLSXeGUy/BhctwKzw==", - "dev": true, - "requires": { - "anymatch": "^2.0.0", - "async-done": "^1.2.0", - "chokidar": "^2.0.0", - "is-negated-glob": "^1.0.0", - "just-debounce": "^1.0.0", - "normalize-path": "^3.0.0", - "object.defaults": "^1.1.0" - } - }, - "global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", - "dev": true, - "requires": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" - } - }, - "global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", - "dev": true, - "requires": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" - } - }, - "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - } - }, - "glogg": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz", - "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==", - "dev": true, - "requires": { - "sparkles": "^1.0.0" - } - }, - "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, - "gulp": { - "version": "git+ssh://git@github.com/gulpjs/gulp.git#069350a5febf65adc27bc816a7805471b7d96f03", - "dev": true, - "from": "gulp@github:gulpjs/gulp#v4.0.2", - "requires": { - "glob-watcher": "^5.0.3", - "gulp-cli": "^2.2.0", - "undertaker": "^1.2.1", - "vinyl-fs": "^3.0.0" - } - }, - "gulp-cli": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.3.0.tgz", - "integrity": "sha512-zzGBl5fHo0EKSXsHzjspp3y5CONegCm8ErO5Qh0UzFzk2y4tMvzLWhoDokADbarfZRL2pGpRp7yt6gfJX4ph7A==", - "dev": true, - "requires": { - "ansi-colors": "^1.0.1", - "archy": "^1.0.0", - "array-sort": "^1.0.0", - "color-support": "^1.1.3", - "concat-stream": "^1.6.0", - "copy-props": "^2.0.1", - "fancy-log": "^1.3.2", - "gulplog": "^1.0.0", - "interpret": "^1.4.0", - "isobject": "^3.0.1", - "liftoff": "^3.1.0", - "matchdep": "^2.0.0", - "mute-stdout": "^1.0.0", - "pretty-hrtime": "^1.0.0", - "replace-homedir": "^1.0.0", - "semver-greatest-satisfied-range": "^1.1.0", - "v8flags": "^3.2.0", - "yargs": "^7.1.0" - } - }, - "gulp-json-editor": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/gulp-json-editor/-/gulp-json-editor-2.5.6.tgz", - "integrity": "sha512-66Xr6Q6m4mUNd0OOHflMB/RHgFNnLjlHgizOzUcx9CyMRymVZEM+/SpZcCDlvThBdXtQwXpdvtSepxVY/V6nQA==", - "dev": true, - "requires": { - "deepmerge": "^4.2.2", - "detect-indent": "^6.0.0", - "js-beautify": "^1.13.13", - "plugin-error": "^1.0.1", - "through2": "^4.0.2" - } - }, - "gulp-rename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/gulp-rename/-/gulp-rename-2.0.0.tgz", - "integrity": "sha512-97Vba4KBzbYmR5VBs9mWmK+HwIf5mj+/zioxfZhOKeXtx5ZjBk57KFlePf5nxq9QsTtFl0ejnHE3zTC9MHXqyQ==", - "dev": true - }, - "gulp-shell": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/gulp-shell/-/gulp-shell-0.8.0.tgz", - "integrity": "sha512-wHNCgmqbWkk1c6Gc2dOL5SprcoeujQdeepICwfQRo91DIylTE7a794VEE+leq3cE2YDoiS5ulvRfKVIEMazcTQ==", - "dev": true, - "requires": { - "chalk": "^3.0.0", - "fancy-log": "^1.3.3", - "lodash.template": "^4.5.0", - "plugin-error": "^1.0.1", - "through2": "^3.0.1", - "tslib": "^1.10.0" - }, - "dependencies": { - "through2": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", - "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", - "dev": true, - "requires": { - "inherits": "^2.0.4", - "readable-stream": "2 || 3" - } - } - } - }, - "gulp-sourcemaps": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-3.0.0.tgz", - "integrity": "sha512-RqvUckJkuYqy4VaIH60RMal4ZtG0IbQ6PXMNkNsshEGJ9cldUPRb/YCgboYae+CLAs1HQNb4ADTKCx65HInquQ==", - "dev": true, - "requires": { - "@gulp-sourcemaps/identity-map": "^2.0.1", - "@gulp-sourcemaps/map-sources": "^1.0.0", - "acorn": "^6.4.1", - "convert-source-map": "^1.0.0", - "css": "^3.0.0", - "debug-fabulous": "^1.0.0", - "detect-newline": "^2.0.0", - "graceful-fs": "^4.0.0", - "source-map": "^0.6.0", - "strip-bom-string": "^1.0.0", - "through2": "^2.0.0" - }, - "dependencies": { - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - } - } - }, - "gulp-tslint": { - "version": "8.1.4", - "resolved": "https://registry.npmjs.org/gulp-tslint/-/gulp-tslint-8.1.4.tgz", - "integrity": "sha512-wBoZIEMJRz9urHwolsvQpngA9l931p6g/Liwz1b/KrsVP6jEBFZv/o0NS1TFCQZi/l8mXxz8+v3twhf4HOXxPQ==", - "dev": true, - "requires": { - "@types/fancy-log": "1.3.0", - "ansi-colors": "^1.0.1", - "fancy-log": "1.3.3", - "map-stream": "~0.0.7", - "plugin-error": "1.0.1", - "through": "~2.3.8" - } - }, - "gulp-typescript": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/gulp-typescript/-/gulp-typescript-5.0.1.tgz", - "integrity": "sha512-YuMMlylyJtUSHG1/wuSVTrZp60k1dMEFKYOvDf7OvbAJWrDtxxD4oZon4ancdWwzjj30ztiidhe4VXJniF0pIQ==", - "dev": true, - "requires": { - "ansi-colors": "^3.0.5", - "plugin-error": "^1.0.1", - "source-map": "^0.7.3", - "through2": "^3.0.0", - "vinyl": "^2.1.0", - "vinyl-fs": "^3.0.3" - }, - "dependencies": { - "ansi-colors": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", - "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", - "dev": true - }, - "source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", - "dev": true - }, - "through2": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", - "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", - "dev": true, - "requires": { - "inherits": "^2.0.4", - "readable-stream": "2 || 3" - } - } - } - }, - "gulp-util": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", - "integrity": "sha512-q5oWPc12lwSFS9h/4VIjG+1NuNDlJ48ywV2JKItY4Ycc/n1fXJeYPVQsfu5ZrhQi7FGSDBalwUCLar/GyHXKGw==", - "dev": true, - "requires": { - "array-differ": "^1.0.0", - "array-uniq": "^1.0.2", - "beeper": "^1.0.0", - "chalk": "^1.0.0", - "dateformat": "^2.0.0", - "fancy-log": "^1.1.0", - "gulplog": "^1.0.0", - "has-gulplog": "^0.1.0", - "lodash._reescape": "^3.0.0", - "lodash._reevaluate": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.template": "^3.0.0", - "minimist": "^1.1.0", - "multipipe": "^0.1.2", - "object-assign": "^3.0.0", - "replace-ext": "0.0.1", - "through2": "^2.0.0", - "vinyl": "^0.5.0" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "dev": true - }, - "clone-stats": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", - "integrity": "sha512-dhUqc57gSMCo6TX85FLfe51eC/s+Im2MLkAgJwfaRRexR2tA4dd3eLEW4L6efzHc2iNorrRRXITifnDLlRrhaA==", - "dev": true - }, - "lodash.template": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", - "integrity": "sha512-0B4Y53I0OgHUJkt+7RmlDFWKjVAI/YUpWNiL9GQz5ORDr4ttgfQGo+phBWKFLJbBdtOwgMuUkdOHOnPg45jKmQ==", - "dev": true, - "requires": { - "lodash._basecopy": "^3.0.0", - "lodash._basetostring": "^3.0.0", - "lodash._basevalues": "^3.0.0", - "lodash._isiterateecall": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0", - "lodash.keys": "^3.0.0", - "lodash.restparam": "^3.0.0", - "lodash.templatesettings": "^3.0.0" - } - }, - "lodash.templatesettings": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", - "integrity": "sha512-TcrlEr31tDYnWkHFWDCV3dHYroKEXpJZ2YJYvJdhN+y4AkWMDZ5I4I8XDtUKqSAyG81N7w+I1mFEJtcED+tGqQ==", - "dev": true, - "requires": { - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0" - } - }, - "object-assign": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", - "integrity": "sha512-jHP15vXVGeVh1HuaA2wY6lxk+whK/x4KBG88VXeRma7CCun7iGD5qPc4eYykQ9sdQvg8jkwFKsSxHln2ybW3xQ==", - "dev": true - }, - "replace-ext": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", - "integrity": "sha512-AFBWBy9EVRTa/LhEcG8QDP3FvpwZqmvN2QFDuJswFeaVhWnZMp8q3E6Zd90SR04PlIwfGdyVjNyLPyen/ek5CQ==", - "dev": true - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", - "dev": true - }, - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "vinyl": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", - "integrity": "sha512-P5zdf3WB9uzr7IFoVQ2wZTmUwHL8cMZWJGzLBNCHNZ3NB6HTMsYABtt7z8tAGIINLXyAob9B9a1yzVGMFOYKEA==", - "dev": true, - "requires": { - "clone": "^1.0.0", - "clone-stats": "^0.0.1", - "replace-ext": "0.0.1" - } - } - } - }, - "gulplog": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", - "integrity": "sha512-hm6N8nrm3Y08jXie48jsC55eCZz9mnb4OirAStEk2deqeyhXU3C1otDVh+ccttMuc1sBi6RX6ZJ720hs9RCvgw==", - "dev": true, - "requires": { - "glogg": "^1.0.0" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "dev": true - } - } - }, - "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 - }, - "has-gulplog": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz", - "integrity": "sha512-+F4GzLjwHNNDEAJW2DC1xXfEoPkRDmUdJ7CBYw4MpqtDwOnqdImJl7GWlpqx+Wko6//J8uKTnIe4wZSv7yCqmw==", - "dev": true, - "requires": { - "sparkles": "^1.0.0" - } - }, - "has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.1" - } - }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true - }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", - "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "homedir-polyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", - "dev": true, - "requires": { - "parse-passwd": "^1.0.0" - } - }, - "hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "http-proxy-agent": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", - "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", - "requires": { - "agent-base": "4", - "debug": "3.1.0" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - } - } - }, - "https-proxy-agent": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", - "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", - "requires": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" - } - }, - "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true - }, - "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 - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "dev": true - }, - "invert-kv": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==", - "dev": true - }, - "is-absolute": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", - "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", - "dev": true, - "requires": { - "is-relative": "^1.0.0", - "is-windows": "^1.0.1" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==", - "dev": true, - "requires": { - "binary-extensions": "^1.0.0" - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "is-core-module": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", - "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-negated-glob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", - "integrity": "sha512-czXVVn/QEmgvej1f50BZ648vUI+em0xqMq2Sn+QncCLN4zj1UAxlT+kw/6ggQTOaZPd1HqKQGEqbpQVtJucWug==", - "dev": true - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", - "dev": true - }, - "is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true - }, - "is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "dev": true - }, - "is-promise": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", - "dev": true - }, - "is-relative": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", - "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", - "dev": true, - "requires": { - "is-unc-path": "^1.0.0" - } - }, - "is-unc-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", - "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", - "dev": true, - "requires": { - "unc-path-regex": "^0.1.2" - } - }, - "is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", - "dev": true - }, - "is-valid-glob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz", - "integrity": "sha512-AhiROmoEFDSsjx8hW+5sGwgKVIORcXnrlAx/R0ZSeaPw70Vw0CqkGBBhHGL58Uox2eXnU1AnvXJl1XlyedO5bA==", - "dev": true - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "dev": true - }, - "js-beautify": { - "version": "1.14.6", - "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.14.6.tgz", - "integrity": "sha512-GfofQY5zDp+cuHc+gsEXKPpNw2KbPddreEo35O6jT6i0RVK6LhsoYBhq5TvK4/n74wnA0QbK8gGd+jUZwTMKJw==", - "dev": true, - "requires": { - "config-chain": "^1.1.13", - "editorconfig": "^0.15.3", - "glob": "^8.0.3", - "nopt": "^6.0.0" - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "just-debounce": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.1.0.tgz", - "integrity": "sha512-qpcRocdkUmf+UTNBYx5w6dexX5J31AKK1OmPwH630a83DdVVUIngk55RSAiIGpQyoH0dlr872VHfPjnQnK1qDQ==", - "dev": true - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, - "last-run": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", - "integrity": "sha512-U/VxvpX4N/rFvPzr3qG5EtLKEnNI0emvIQB3/ecEwv+8GHaUKbIB8vxv1Oai5FAF0d0r7LXHhLLe5K/yChm5GQ==", - "dev": true, - "requires": { - "default-resolution": "^2.0.0", - "es6-weak-map": "^2.0.1" - } - }, - "lazystream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", - "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", - "dev": true, - "requires": { - "readable-stream": "^2.0.5" - } - }, - "lcid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==", - "dev": true, - "requires": { - "invert-kv": "^1.0.0" - } - }, - "lead": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz", - "integrity": "sha512-IpSVCk9AYvLHo5ctcIXxOBpMWUe+4TKN3VPWAKUbJikkmsGp0VrSM8IttVc32D6J4WUsiPE6aEFRNmIoF/gdow==", - "dev": true, - "requires": { - "flush-write-stream": "^1.0.2" - } - }, - "liftoff": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", - "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==", - "dev": true, - "requires": { - "extend": "^3.0.0", - "findup-sync": "^3.0.0", - "fined": "^1.0.1", - "flagged-respawn": "^1.0.0", - "is-plain-object": "^2.0.4", - "object.map": "^1.0.0", - "rechoir": "^0.6.2", - "resolve": "^1.1.7" - }, - "dependencies": { - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - } - } - }, - "load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" - } - }, - "lodash._basecopy": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", - "integrity": "sha512-rFR6Vpm4HeCK1WPGvjZSJ+7yik8d8PVUdCJx5rT2pogG4Ve/2ZS7kfmO5l5T2o5V2mqlNIfSF5MZlr1+xOoYQQ==", - "dev": true - }, - "lodash._basetostring": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", - "integrity": "sha512-mTzAr1aNAv/i7W43vOR/uD/aJ4ngbtsRaCubp2BfZhlGU/eORUjg/7F6X0orNMdv33JOrdgGybtvMN/po3EWrA==", - "dev": true - }, - "lodash._basevalues": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", - "integrity": "sha512-H94wl5P13uEqlCg7OcNNhMQ8KvWSIyqXzOPusRgHC9DK3o54P6P3xtbXlVbRABG4q5gSmp7EDdJ0MSuW9HX6Mg==", - "dev": true - }, - "lodash._getnative": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha512-RrL9VxMEPyDMHOd9uFbvMe8X55X16/cGM5IgOKgRElQZutpX89iS6vwl64duTV1/16w5JY7tuFNXqoekmh1EmA==", - "dev": true - }, - "lodash._isiterateecall": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", - "integrity": "sha512-De+ZbrMu6eThFti/CSzhRvTKMgQToLxbij58LMfM8JnYDNSOjkjTCIaa8ixglOeGh2nyPlakbt5bJWJ7gvpYlQ==", - "dev": true - }, - "lodash._reescape": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", - "integrity": "sha512-Sjlavm5y+FUVIF3vF3B75GyXrzsfYV8Dlv3L4mEpuB9leg8N6yf/7rU06iLPx9fY0Mv3khVp9p7Dx0mGV6V5OQ==", - "dev": true - }, - "lodash._reevaluate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz", - "integrity": "sha512-OrPwdDc65iJiBeUe5n/LIjd7Viy99bKwDdk7Z5ljfZg0uFRFlfQaCy9tZ4YMAag9WAZmlVpe1iZrkIMMSMHD3w==", - "dev": true - }, - "lodash._reinterpolate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==", - "dev": true - }, - "lodash._root": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", - "integrity": "sha512-O0pWuFSK6x4EXhM1dhZ8gchNtG7JMqBtrHdoUFUWXD7dJnNSUze1GuyQr5sOs0aCvgGeI3o/OJW8f4ca7FDxmQ==", - "dev": true - }, - "lodash.escape": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", - "integrity": "sha512-n1PZMXgaaDWZDSvuNZ/8XOcYO2hOKDqZel5adtR30VKQAtoWs/5AOeFA0vPV8moiPzlqe7F4cP2tzpFewQyelQ==", - "dev": true, - "requires": { - "lodash._root": "^3.0.0" - } - }, - "lodash.isarguments": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==", - "dev": true - }, - "lodash.isarray": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", - "integrity": "sha512-JwObCrNJuT0Nnbuecmqr5DgtuBppuCvGD9lxjFpAzwnVtdGoDQ1zig+5W8k5/6Gcn0gZ3936HDAlGd28i7sOGQ==", - "dev": true - }, - "lodash.keys": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", - "integrity": "sha512-CuBsapFjcubOGMn3VD+24HOAPxM79tH+V6ivJL3CHYjtrawauDJHUk//Yew9Hvc6e9rbCrURGk8z6PC+8WJBfQ==", - "dev": true, - "requires": { - "lodash._getnative": "^3.0.0", - "lodash.isarguments": "^3.0.0", - "lodash.isarray": "^3.0.0" - } - }, - "lodash.restparam": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", - "integrity": "sha512-L4/arjjuq4noiUJpt3yS6KIKDtJwNe2fIYgMqyYYKoeIfV1iEqvPwhCx23o+R9dzouGihDAPN1dTIRWa7zk8tw==", - "dev": true - }, - "lodash.template": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", - "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", - "dev": true, - "requires": { - "lodash._reinterpolate": "^3.0.0", - "lodash.templatesettings": "^4.0.0" - } - }, - "lodash.templatesettings": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", - "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", - "dev": true, - "requires": { - "lodash._reinterpolate": "^3.0.0" - } - }, - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "lru-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", - "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==", - "dev": true, - "requires": { - "es5-ext": "~0.10.2" - } - }, - "make-iterator": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", - "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", - "dev": true, - "requires": { - "kind-of": "^6.0.2" - } - }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", - "dev": true - }, - "map-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", - "integrity": "sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==", - "dev": true - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", - "dev": true, - "requires": { - "object-visit": "^1.0.0" - } - }, - "matchdep": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", - "integrity": "sha512-LFgVbaHIHMqCRuCZyfCtUOq9/Lnzhi7Z0KFUE2fhD54+JN2jLh3hC02RLkqauJ3U4soU6H1J3tfj/Byk7GoEjA==", - "dev": true, - "requires": { - "findup-sync": "^2.0.0", - "micromatch": "^3.0.4", - "resolve": "^1.4.0", - "stack-trace": "0.0.10" - }, - "dependencies": { - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - } - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "findup-sync": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", - "integrity": "sha512-vs+3unmJT45eczmcAZ6zMJtxN3l/QXeccaXQx5cu/MeJMhewVfoWZqibRkOxPnmoR59+Zy5hjabfQc6JLSah4g==", - "dev": true, - "requires": { - "detect-file": "^1.0.0", - "is-glob": "^3.1.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - }, - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - } - } - }, - "memoizee": { - "version": "0.4.15", - "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz", - "integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==", - "dev": true, - "requires": { - "d": "^1.0.1", - "es5-ext": "^0.10.53", - "es6-weak-map": "^2.0.3", - "event-emitter": "^0.3.5", - "is-promise": "^2.2.2", - "lru-queue": "^0.1.0", - "next-tick": "^1.1.0", - "timers-ext": "^0.1.7" - } - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "requires": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "dependencies": { - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - } - } - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, - "minipass": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.4.tgz", - "integrity": "sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw==", - "requires": { - "yallist": "^4.0.0" - }, - "dependencies": { - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - } - } - }, - "minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "requires": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "dependencies": { - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - } - } - }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - } - } - }, - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "multipipe": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", - "integrity": "sha512-7ZxrUybYv9NonoXgwoOqtStIu18D1c3eFZj27hqgf5kBrBF8Q+tE8V0MW8dKM5QLkQPh1JhhbKgHLY9kifov4Q==", - "dev": true, - "requires": { - "duplexer2": "0.0.2" - } - }, - "mute-stdout": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz", - "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==", - "dev": true - }, - "nan": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.16.0.tgz", - "integrity": "sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA==", - "dev": true, - "optional": true - }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - } - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - } - } - }, - "next-tick": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", - "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", - "dev": true - }, - "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, - "requires": { - "abbrev": "^1.0.0" - } - }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "now-and-later": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz", - "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==", - "dev": true, - "requires": { - "once": "^1.3.2" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true - }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", - "dev": true, - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", - "dev": true, - "requires": { - "isobject": "^3.0.0" - } - }, - "object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - } - }, - "object.defaults": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", - "integrity": "sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==", - "dev": true, - "requires": { - "array-each": "^1.0.1", - "array-slice": "^1.0.0", - "for-own": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "object.map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", - "integrity": "sha512-3+mAJu2PLfnSVGHwIWubpOFLscJANBKuB/6A4CxBstc4aqwQY0FWcsppuy4jU5GSB95yES5JHSI+33AWuS4k6w==", - "dev": true, - "requires": { - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "object.reduce": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz", - "integrity": "sha512-naLhxxpUESbNkRqc35oQ2scZSJueHGQNUfMW/0U37IgN6tE2dgDWg3whf+NEliy3F/QysrO48XKUz/nGPe+AQw==", - "dev": true, - "requires": { - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "requires": { - "wrappy": "1" - } - }, - "opener": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", - "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==" - }, - "ordered-read-streams": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", - "integrity": "sha512-Z87aSjx3r5c0ZB7bcJqIgIRX5bxR7A4aSzvIbaxd0oTkWBCOoKfuGHiKj60CHVUgg1Phm5yMZzBdt8XqRs73Mw==", - "dev": true, - "requires": { - "readable-stream": "^2.0.1" - } - }, - "os-locale": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", - "integrity": "sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g==", - "dev": true, - "requires": { - "lcid": "^1.0.0" - } - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==" - }, - "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, - "requires": { - "aggregate-error": "^3.0.0" - } - }, - "parse-filepath": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", - "integrity": "sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==", - "dev": true, - "requires": { - "is-absolute": "^1.0.0", - "map-cache": "^0.2.0", - "path-root": "^0.1.1" - } - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", - "dev": true, - "requires": { - "error-ex": "^1.2.0" - } - }, - "parse-node-version": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", - "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", - "dev": true - }, - "parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", - "dev": true - }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==", - "dev": true - }, - "path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==", - "dev": true - }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", - "dev": true, - "requires": { - "pinkie-promise": "^2.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "path-root": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", - "integrity": "sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==", - "dev": true, - "requires": { - "path-root-regex": "^0.1.0" - } - }, - "path-root-regex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", - "integrity": "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==", - "dev": true - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - }, - "pause-stream": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", - "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==", - "dev": true, - "requires": { - "through": "~2.3" - } - }, - "pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==" - }, - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true - }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", - "dev": true - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", - "dev": true, - "requires": { - "pinkie": "^2.0.0" - } - }, - "plugin-error": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", - "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", - "dev": true, - "requires": { - "ansi-colors": "^1.0.1", - "arr-diff": "^4.0.0", - "arr-union": "^3.1.0", - "extend-shallow": "^3.0.2" - }, - "dependencies": { - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - } - } - }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==", - "dev": true - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dev": true, - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "pretty-hrtime": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", - "integrity": "sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==", - "dev": true - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", - "dev": true - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", - "dev": true - }, - "pump": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "pumpify": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", - "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", - "dev": true, - "requires": { - "duplexify": "^3.6.0", - "inherits": "^2.0.3", - "pump": "^2.0.0" - } - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true - }, - "read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", - "dev": true, - "requires": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" - }, - "dependencies": { - "path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - } - } - }, - "read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", - "dev": true, - "requires": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" - } - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - }, - "dependencies": { - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - } - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - } - } - }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", - "dev": true, - "requires": { - "resolve": "^1.1.6" - } - }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - } - } - }, - "remove-bom-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz", - "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==", - "dev": true, - "requires": { - "is-buffer": "^1.1.5", - "is-utf8": "^0.2.1" - } - }, - "remove-bom-stream": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz", - "integrity": "sha512-wigO8/O08XHb8YPzpDDT+QmRANfW6vLqxfaXm1YXhnFf3AkSLyjfG3GEFg4McZkmgL7KvCj5u2KczkvSP6NfHA==", - "dev": true, - "requires": { - "remove-bom-buffer": "^3.0.0", - "safe-buffer": "^5.1.0", - "through2": "^2.0.3" - }, - "dependencies": { - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - } - } - }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", - "dev": true - }, - "repeat-element": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", - "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", - "dev": true - }, - "replace-ext": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz", - "integrity": "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==", - "dev": true - }, - "replace-homedir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz", - "integrity": "sha512-CHPV/GAglbIB1tnQgaiysb8H2yCy8WQ7lcEwQ/eT+kLj0QHV8LnJW0zpqpE7RSkrMSRoa+EBoag86clf7WAgSg==", - "dev": true, - "requires": { - "homedir-polyfill": "^1.0.1", - "is-absolute": "^1.0.0", - "remove-trailing-separator": "^1.1.0" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true - }, - "require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==", - "dev": true - }, - "resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, - "requires": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "resolve-dir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", - "dev": true, - "requires": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" - } - }, - "resolve-options": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz", - "integrity": "sha512-NYDgziiroVeDC29xq7bp/CacZERYsA9bXYd1ZmcJlF3BcrZv5pTb4NG7SjdyKDnXZ84aC4vo2u6sNKIA1LCu/A==", - "dev": true, - "requires": { - "value-or-function": "^3.0.0" - } - }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", - "dev": true - }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true - }, - "retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==" - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "requires": { - "glob": "^7.1.3" - }, - "dependencies": { - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } - } - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", - "dev": true, - "requires": { - "ret": "~0.1.10" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - }, - "semver-greatest-satisfied-range": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz", - "integrity": "sha512-Ny/iyOzSSa8M5ML46IAx3iXc6tfOsYU2R4AXi2UpHk60Zrgyq6eqPj/xiOfS0rRl/iiQ/rdJkVjw/5cdUyCntQ==", - "dev": true, - "requires": { - "sver-compat": "^1.5.0" - } - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true - }, - "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - } - } - }, - "sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha512-fCvEXfh6NWpm+YSuY2bpXb/VIihqWA6hLsgboC+0nl71Q7N7o2eaCW8mJa/NLvQhs6jpd3VZV4UiUQlV6+lc8g==", - "dev": true - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "dev": true - }, - "source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "dev": true, - "requires": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "requires": { - "kind-of": "^3.2.0" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "source-map-resolve": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.6.0.tgz", - "integrity": "sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==", - "dev": true, - "requires": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0" - } - }, - "source-map-url": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", - "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", - "dev": true - }, - "sparkles": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", - "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==", - "dev": true - }, - "spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", - "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", - "dev": true - }, - "split": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", - "dev": true, - "requires": { - "through": "2" - } - }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.0" - }, - "dependencies": { - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - } - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", - "dev": true - }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==", - "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - } - }, - "stream-combiner": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", - "integrity": "sha512-6yHMqgLYDzQDcAkL+tjJDC5nSNuNIx0vZtRZeiPh7Saef7VHX9H5Ijn9l2VIol2zaNYlYEX6KyuT/237A58qEQ==", - "dev": true, - "requires": { - "duplexer": "~0.1.1", - "through": "~2.3.4" - } - }, - "stream-exhaust": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz", - "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==", - "dev": true - }, - "stream-shift": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", - "dev": true - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "dev": true - } - } - }, - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", - "dev": true, - "requires": { - "is-utf8": "^0.2.0" - } - }, - "strip-bom-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", - "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", - "dev": true - }, - "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, - "requires": { - "has-flag": "^4.0.0" - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true - }, - "sver-compat": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz", - "integrity": "sha512-aFTHfmjwizMNlNE6dsGmoAM4lHjL0CyiobWaFiXWSlD7cIxshW422Nb8KbXCmR6z+0ZEPY+daXJrDyh/vuwTyg==", - "dev": true, - "requires": { - "es6-iterator": "^2.0.1", - "es6-symbol": "^3.1.1" - } - }, - "tar": { - "version": "6.1.11", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", - "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", - "requires": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^3.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "dependencies": { - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - } - } - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true - }, - "through2": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", - "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", - "dev": true, - "requires": { - "readable-stream": "3" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "through2-filter": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", - "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==", - "dev": true, - "requires": { - "through2": "~2.0.0", - "xtend": "~4.0.0" - }, - "dependencies": { - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - } - } - }, - "time-stamp": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", - "integrity": "sha512-gLCeArryy2yNTRzTGKbZbloctj64jkZ57hj5zdraXue6aFgd6PmvVtEyiUU+hvU0v7q08oVv8r8ev0tRo6bvgw==", - "dev": true - }, - "timers-ext": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", - "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", - "dev": true, - "requires": { - "es5-ext": "~0.10.46", - "next-tick": "1" - } - }, - "tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "requires": { - "rimraf": "^3.0.0" - } - }, - "to-absolute-glob": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", - "integrity": "sha512-rtwLUQEwT8ZeKQbyFJyomBRYXyE16U5VKuy0ftxLMK/PZb2fkOsg5r9kHdauuVDbsNdIBoC/HCthpidamQFXYA==", - "dev": true, - "requires": { - "is-absolute": "^1.0.0", - "is-negated-glob": "^1.0.0" - } - }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - }, - "dependencies": { - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - } - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - } - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - }, - "to-through": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz", - "integrity": "sha512-+QIz37Ly7acM4EMdw2PRN389OneM5+d844tirkGp4dPKzI5OE72V9OsbFp+CIYJDahZ41ZV05hNtcPAQUAm9/Q==", - "dev": true, - "requires": { - "through2": "^2.0.3" - }, - "dependencies": { - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - } - } - }, - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "tslint": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz", - "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "builtin-modules": "^1.1.1", - "chalk": "^2.3.0", - "commander": "^2.12.1", - "diff": "^4.0.1", - "glob": "^7.1.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.3", - "resolve": "^1.3.2", - "semver": "^5.3.0", - "tslib": "^1.13.0", - "tsutils": "^2.29.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "requires": { - "minimist": "^1.2.6" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "tsutils": { - "version": "2.29.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", - "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - } - }, - "type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", - "dev": true - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", - "dev": true - }, - "typescript": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", - "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", - "dev": true - }, - "unc-path-regex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", - "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==", - "dev": true - }, - "undertaker": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.3.0.tgz", - "integrity": "sha512-/RXwi5m/Mu3H6IHQGww3GNt1PNXlbeCuclF2QYR14L/2CHPz3DFZkvB5hZ0N/QUkiXWCACML2jXViIQEQc2MLg==", - "dev": true, - "requires": { - "arr-flatten": "^1.0.1", - "arr-map": "^2.0.0", - "bach": "^1.0.0", - "collection-map": "^1.0.0", - "es6-weak-map": "^2.0.1", - "fast-levenshtein": "^1.0.0", - "last-run": "^1.1.0", - "object.defaults": "^1.0.0", - "object.reduce": "^1.0.0", - "undertaker-registry": "^1.0.0" - } - }, - "undertaker-registry": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz", - "integrity": "sha512-UR1khWeAjugW3548EfQmL9Z7pGMlBgXteQpr1IZeZBtnkCJQJIJ1Scj0mb9wQaPvUZ9Q17XqW6TIaPchJkyfqw==", - "dev": true - }, - "union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - } - }, - "unique-stream": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz", - "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==", - "dev": true, - "requires": { - "json-stable-stringify-without-jsonify": "^1.0.1", - "through2-filter": "^3.0.0" - } - }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==", - "dev": true, - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==", - "dev": true - } - } - }, - "upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", - "dev": true - }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==", - "dev": true - }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "v8flags": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", - "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", - "dev": true, - "requires": { - "homedir-polyfill": "^1.0.1" - } - }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "value-or-function": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz", - "integrity": "sha512-jdBB2FrWvQC/pnPtIqcLsMaQgjhdb6B7tk1MMyTKapox+tQZbdRP4uLxu/JY0t7fbfDCUMnuelzEYv5GsxHhdg==", - "dev": true - }, - "vinyl": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz", - "integrity": "sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==", - "dev": true, - "requires": { - "clone": "^2.1.1", - "clone-buffer": "^1.0.0", - "clone-stats": "^1.0.0", - "cloneable-readable": "^1.0.0", - "remove-trailing-separator": "^1.0.1", - "replace-ext": "^1.0.0" - } - }, - "vinyl-fs": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz", - "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==", - "dev": true, - "requires": { - "fs-mkdirp-stream": "^1.0.0", - "glob-stream": "^6.1.0", - "graceful-fs": "^4.0.0", - "is-valid-glob": "^1.0.0", - "lazystream": "^1.0.0", - "lead": "^1.0.0", - "object.assign": "^4.0.4", - "pumpify": "^1.3.5", - "readable-stream": "^2.3.3", - "remove-bom-buffer": "^3.0.0", - "remove-bom-stream": "^1.2.0", - "resolve-options": "^1.1.0", - "through2": "^2.0.0", - "to-through": "^2.0.0", - "value-or-function": "^3.0.0", - "vinyl": "^2.0.0", - "vinyl-sourcemap": "^1.1.0" - }, - "dependencies": { - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - } - } - }, - "vinyl-sourcemap": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz", - "integrity": "sha512-NiibMgt6VJGJmyw7vtzhctDcfKch4e4n9TBeoWlirb7FMg9/1Ov9k+A5ZRAtywBpRPiyECvQRQllYM8dECegVA==", - "dev": true, - "requires": { - "append-buffer": "^1.0.2", - "convert-source-map": "^1.5.0", - "graceful-fs": "^4.1.6", - "normalize-path": "^2.1.1", - "now-and-later": "^2.0.0", - "remove-bom-buffer": "^3.0.0", - "vinyl": "^2.0.0" - }, - "dependencies": { - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - } - } - }, - "vscode-extension-telemetry": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/vscode-extension-telemetry/-/vscode-extension-telemetry-0.4.2.tgz", - "integrity": "sha512-y0f51mVoFxHIzULQNCC26TBFIKdEC7uckS3tFoK++OOOl8mU2LlOxgmbd52T/SXoXNg5aI7xqs+4V2ug5ITvKw==" - }, - "vscode-jsonrpc": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-4.0.0.tgz", - "integrity": "sha512-perEnXQdQOJMTDFNv+UF3h1Y0z4iSiaN9jIlb0OqIYgosPCZGYh/MCUlkFtV2668PL69lRDO32hmvL2yiidUYg==" - }, - "vscode-languageclient": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-5.2.1.tgz", - "integrity": "sha512-7jrS/9WnV0ruqPamN1nE7qCxn0phkH5LjSgSp9h6qoJGoeAKzwKz/PF6M+iGA/aklx4GLZg1prddhEPQtuXI1Q==", - "requires": { - "semver": "^5.5.0", - "vscode-languageserver-protocol": "3.14.1" - } - }, - "vscode-languageserver-protocol": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.14.1.tgz", - "integrity": "sha512-IL66BLb2g20uIKog5Y2dQ0IiigW0XKrvmWiOvc0yXw80z3tMEzEnHjaGAb3ENuU7MnQqgnYJ1Cl2l9RvNgDi4g==", - "requires": { - "vscode-jsonrpc": "^4.0.0", - "vscode-languageserver-types": "3.14.0" - } - }, - "vscode-languageserver-types": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.14.0.tgz", - "integrity": "sha512-lTmS6AlAlMHOvPQemVwo3CezxBp0sNB95KNPkqp3Nxd5VFEnuG1ByM0zlRWos0zjO3ZWtkvhal0COgiV1xIA4A==" - }, - "vscode-nls-dev": { - "version": "https://github.com/Raymondd/vscode-nls-dev/releases/download/2.0.2/build.tar.gz", - "integrity": "sha512-U8SoBs3upxlVvuxNNQqZJilypQsd4a7rRdHllp3NRKAZGzL8SXLoICZBCKpFDfmGKEAYYdTogf8iOB3CD78UaQ==", - "dev": true, - "requires": { - "clone": "^1.0.2", - "event-stream": "^3.3.2", - "glob": "^6.0.4", - "gulp-util": "^3.0.7", - "source-map": "^0.5.3", - "typescript": "^2.0.3", - "vinyl": "^1.1.1", - "yargs": "^3.32.0" - }, - "dependencies": { - "camelcase": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "integrity": "sha512-DLIsRzJVBQu72meAKPkWQOLcujdXT32hwdfnkI1frSiSRMK1MofjKHf+MEx0SB6fjEFXL8fBDv1dKymBlOp4Qw==", - "dev": true - }, - "clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "dev": true - }, - "clone-stats": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", - "integrity": "sha512-dhUqc57gSMCo6TX85FLfe51eC/s+Im2MLkAgJwfaRRexR2tA4dd3eLEW4L6efzHc2iNorrRRXITifnDLlRrhaA==", - "dev": true - }, - "glob": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", - "integrity": "sha512-MKZeRNyYZAVVVG1oZeLaWie1uweH40m9AZwIwxyPbTSX4hHrVYSzLg0Ro5Z5R7XKkIX+Cc6oD1rqeDJnwsB8/A==", - "dev": true, - "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "replace-ext": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", - "integrity": "sha512-AFBWBy9EVRTa/LhEcG8QDP3FvpwZqmvN2QFDuJswFeaVhWnZMp8q3E6Zd90SR04PlIwfGdyVjNyLPyen/ek5CQ==", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "dev": true - }, - "typescript": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz", - "integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==", - "dev": true - }, - "vinyl": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", - "integrity": "sha512-Ci3wnR2uuSAWFMSglZuB8Z2apBdtOyz8CV7dC6/U1XbltXBC+IuutUkXQISz01P+US2ouBuesSbV6zILZ6BuzQ==", - "dev": true, - "requires": { - "clone": "^1.0.0", - "clone-stats": "^0.0.1", - "replace-ext": "0.0.1" - } - }, - "yargs": { - "version": "3.32.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz", - "integrity": "sha512-ONJZiimStfZzhKamYvR/xvmgW3uEkAUFSP91y2caTEPhzF6uP2JfPiVZcq66b/YR0C3uitxSV7+T1x8p5bkmMg==", - "dev": true, - "requires": { - "camelcase": "^2.0.1", - "cliui": "^3.0.3", - "decamelize": "^1.1.1", - "os-locale": "^1.4.0", - "string-width": "^1.0.1", - "window-size": "^0.1.4", - "y18n": "^3.2.0" - } - } - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", - "integrity": "sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==", - "dev": true - }, - "window-size": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz", - "integrity": "sha512-2thx4pB0cV3h+Bw7QmMXcEbdmOzv9t0HFplJH/Lz6yu60hXYy5RT8rUu+wlIreVxWsGN20mo+MHeCSfUpQBwPw==", - "dev": true - }, - "wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==", - "dev": true, - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true - }, - "y18n": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", - "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==", - "dev": true - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", - "dev": true - }, - "yargs": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.2.tgz", - "integrity": "sha512-ZEjj/dQYQy0Zx0lgLMLR8QuaqTihnxirir7EwUHp1Axq4e3+k8jXU5K0VLbNvedv1f4EWtBonDIZm0NUr+jCcA==", - "dev": true, - "requires": { - "camelcase": "^3.0.0", - "cliui": "^3.2.0", - "decamelize": "^1.1.1", - "get-caller-file": "^1.0.1", - "os-locale": "^1.4.0", - "read-pkg-up": "^1.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^1.0.2", - "which-module": "^1.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^5.0.1" - } - }, - "yargs-parser": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.1.tgz", - "integrity": "sha512-wpav5XYiddjXxirPoCTUPbqM0PXvJ9hiBMvuJgInvo4/lAOTZzUprArw17q2O1P2+GHhbBr18/iQwjL5Z9BqfA==", - "dev": true, - "requires": { - "camelcase": "^3.0.0", - "object.assign": "^4.1.0" - } - }, - "yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "requires": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - } - } -} From bc70b33d11ad5e6449dfcc7375a3b191f085fa09 Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Thu, 23 Nov 2023 20:12:37 +0000 Subject: [PATCH 79/81] Give direct link to new download file --- .../Capabilities/CapabilitiesHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MarkMpn.Sql4Cds.LanguageServer/Capabilities/CapabilitiesHandler.cs b/MarkMpn.Sql4Cds.LanguageServer/Capabilities/CapabilitiesHandler.cs index a627417d..e09d26c1 100644 --- a/MarkMpn.Sql4Cds.LanguageServer/Capabilities/CapabilitiesHandler.cs +++ b/MarkMpn.Sql4Cds.LanguageServer/Capabilities/CapabilitiesHandler.cs @@ -84,7 +84,7 @@ public CapabilitiesResult HandleCapabilities(CapabilitiesRequest request) _ = _lsp.NotifyAsync(Methods.WindowLogMessage, new LogMessageParams { MessageType = MessageType.Warning, - Message = $"Update to v{result.Result.ToString(3)} available from https://markcarrington.dev/sql-4-cds/" + Message = $"Update to v{result.Result.ToString(3)} available from https://github.com/MarkMpn/Sql4Cds/releases/download/v{result.Result.ToString(3)}/azuredatastudio-sql4cds-{result.Result.ToString(3)}.vsix" }); } }, TaskScheduler.Default); From f9293e56a819c558aaa6d05f1539aa4af5bc3cd6 Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Thu, 23 Nov 2023 21:25:46 +0000 Subject: [PATCH 80/81] Use https instead of ssh for github --- build.yml | 2 ++ pr-build.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/build.yml b/build.yml index 81475300..6c0c1124 100644 --- a/build.yml +++ b/build.yml @@ -128,6 +128,8 @@ steps: - script: | call npm --no-git-tag-version version $(GitVersion.SemVer) call npm i -g vsce + call git config --global url."https://github".insteadOf ssh://git@github + call git config --global url."https://github.com/".insteadOf git@github.com: call yarn install call gulp build call gulp package:offline diff --git a/pr-build.yml b/pr-build.yml index 719fbc1f..bad453b6 100644 --- a/pr-build.yml +++ b/pr-build.yml @@ -62,6 +62,8 @@ steps: - script: | call npm --no-git-tag-version version $(GitVersion.SemVer) call npm i -g vsce + call git config --global url."https://github".insteadOf ssh://git@github + call git config --global url."https://github.com/".insteadOf git@github.com: call yarn install call gulp build displayName: Build ADS extension From c0404f044a64fc80680dc51c5924480d73342661 Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Fri, 24 Nov 2023 08:43:18 +0000 Subject: [PATCH 81/81] Give direct link to new download file --- AzureDataStudioExtension/CHANGELOG.md | 2 +- .../Reflection/DisplaySQLResultsControlWrapper.cs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/AzureDataStudioExtension/CHANGELOG.md b/AzureDataStudioExtension/CHANGELOG.md index 6a1e3422..23fed47d 100644 --- a/AzureDataStudioExtension/CHANGELOG.md +++ b/AzureDataStudioExtension/CHANGELOG.md @@ -1,6 +1,6 @@ # Change Log -## [v8.0.0](https://github.com/MarkMpn/Sql4Cds/releases/tag/v8.0.0) - 2023-11-18 +## [v8.0.0](https://github.com/MarkMpn/Sql4Cds/releases/tag/v8.0.0) - 2023-11-25 Added Common Table Expression support: - Non-recursive CTEs are expanded to subqueries for compatibility with TDS Endpoint diff --git a/MarkMpn.Sql4Cds.SSMS/Reflection/DisplaySQLResultsControlWrapper.cs b/MarkMpn.Sql4Cds.SSMS/Reflection/DisplaySQLResultsControlWrapper.cs index 2d2ba086..c3484ddb 100644 --- a/MarkMpn.Sql4Cds.SSMS/Reflection/DisplaySQLResultsControlWrapper.cs +++ b/MarkMpn.Sql4Cds.SSMS/Reflection/DisplaySQLResultsControlWrapper.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Reflection; using System.Text; @@ -62,8 +63,9 @@ public void StartExecution() if (VersionChecker.Result.IsCompleted && !VersionChecker.Result.IsFaulted && VersionChecker.Result.Result > currentVersion) { + var ssmsVersion = Process.GetCurrentProcess().MainModule.FileVersionInfo.ProductMajorPart; AddStringToErrors(" An updated version of SQL 4 CDS is available", true); - AddStringToMessages($" Update to v{VersionChecker.Result.Result.ToString(3)} available from https://markcarrington.dev/sql-4-cds/"); + AddStringToMessages($" Update to v{VersionChecker.Result.Result.ToString(3)} available from https://github.com/MarkMpn/Sql4Cds/releases/download/v{VersionChecker.Result.Result.ToString(3)}/MarkMpn.Sql4Cds.SSMS.{ssmsVersion}.Setup.msi"); AddStringToMessages(""); } }