diff --git a/.travis.yml b/.travis.yml
index d98d3945..3a04a0a1 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -39,5 +39,6 @@ script:
- dotnet test test/Microsoft.SqlTools.ServiceLayer.Test
env:
- - ProjectPath=home/travis/build/Microsoft/sqltoolsservice
+# Since we are building from root, current directory is the project path
+ - ProjectPath=./
\ No newline at end of file
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs b/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs
index 2ca48d8c..a47f8460 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs
@@ -720,7 +720,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
}
// open connection based on request details
- result = await Instance.Connect(connectParams);
+ result = await Connect(connectParams);
await ServiceHost.SendEvent(ConnectionCompleteNotification.Type, result);
}
catch (Exception ex)
@@ -745,7 +745,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
try
{
- bool result = Instance.CancelConnect(cancelParams);
+ bool result = CancelConnect(cancelParams);
await requestContext.SendResult(result);
}
catch(Exception ex)
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Connection/ReliableConnection/ReliableConnectionHelper.cs b/src/Microsoft.SqlTools.ServiceLayer/Connection/ReliableConnection/ReliableConnectionHelper.cs
index 2cad15d4..4a5a559e 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/Connection/ReliableConnection/ReliableConnectionHelper.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/Connection/ReliableConnection/ReliableConnectionHelper.cs
@@ -55,7 +55,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection
try
{
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(connectionString);
- Debug.Assert(builder.Pooling == false, "Pooling should be false");
+ Debug.Assert(!builder.Pooling, "Pooling should be false");
}
catch (Exception ex)
{
@@ -63,7 +63,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection
}
#endif
- if (AmbientSettings.AlwaysRetryOnTransientFailure == true)
+ if (AmbientSettings.AlwaysRetryOnTransientFailure)
{
useRetry = true;
}
@@ -368,8 +368,6 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection
IDbCommand cmd = null;
try
{
- Debug.Assert(conn.State == ConnectionState.Open, "connection passed to ExecuteReader should be open.");
-
cmd = conn.CreateCommand();
if (initializeCommand == null)
@@ -603,11 +601,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection
Validate.IsNotNullOrEmptyString(nameof(commandText), commandText);
string filePath = ExecuteScalar(conn, commandText, initializeCommand, catchException) as string;
- if (!String.IsNullOrWhiteSpace(filePath))
+ if (!string.IsNullOrWhiteSpace(filePath))
{
// Remove filename from the filePath
Uri pathUri;
- if (Uri.TryCreate(filePath, UriKind.Absolute, out pathUri) == false)
+ if (!Uri.TryCreate(filePath, UriKind.Absolute, out pathUri))
{
// Invalid Uri
return null;
@@ -931,7 +929,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection
serverInfo = GetServerVersion(connection);
- tempDatabaseName = (String.IsNullOrEmpty(builder.InitialCatalog) == false) ?
+ tempDatabaseName = (!string.IsNullOrEmpty(builder.InitialCatalog)) ?
builder.InitialCatalog : builder.AttachDBFilename;
// If at this point the dbName remained an empty string then
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Credentials/CredentialService.cs b/src/Microsoft.SqlTools.ServiceLayer/Credentials/CredentialService.cs
index 6b558f8c..0054ec05 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/Credentials/CredentialService.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/Credentials/CredentialService.cs
@@ -58,7 +58,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Credentials
///
internal CredentialService(ICredentialStore store, StoreConfig config)
{
- this.credStore = store != null ? store : GetStoreForOS(config);
+ credStore = store != null ? store : GetStoreForOS(config);
}
///
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Extensibility/ExtensionServiceProvider.cs b/src/Microsoft.SqlTools.ServiceLayer/Extensibility/ExtensionServiceProvider.cs
new file mode 100644
index 00000000..a3802e36
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Extensibility/ExtensionServiceProvider.cs
@@ -0,0 +1,184 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Composition.Convention;
+using System.Composition.Hosting;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.Loader;
+using Microsoft.Extensions.DependencyModel;
+using Microsoft.SqlTools.ServiceLayer.Utility;
+
+namespace Microsoft.SqlTools.ServiceLayer.Extensibility
+{
+ public class ExtensionServiceProvider : RegisteredServiceProvider
+ {
+ private Func config;
+
+ public ExtensionServiceProvider(Func config)
+ {
+ Validate.IsNotNull(nameof(config), config);
+ this.config = config;
+ }
+
+ public static ExtensionServiceProvider CreateDefaultServiceProvider()
+ {
+ return Create(typeof(ExtensionStore).GetTypeInfo().Assembly.SingleItemAsEnumerable());
+ }
+
+ public static ExtensionServiceProvider Create(IEnumerable assemblies)
+ {
+ Validate.IsNotNull(nameof(assemblies), assemblies);
+ return new ExtensionServiceProvider(conventions => new ContainerConfiguration().WithAssemblies(assemblies, conventions));
+ }
+
+ public static ExtensionServiceProvider Create(IEnumerable types)
+ {
+ Validate.IsNotNull(nameof(types), types);
+ return new ExtensionServiceProvider(conventions => new ContainerConfiguration().WithParts(types, conventions));
+ }
+
+ protected override IEnumerable GetServicesImpl()
+ {
+ EnsureExtensionStoreRegistered();
+ return base.GetServicesImpl();
+ }
+
+ private void EnsureExtensionStoreRegistered()
+ {
+ if (!services.ContainsKey(typeof(T)))
+ {
+ ExtensionStore store = new ExtensionStore(typeof(T), config);
+ base.Register(() => store.GetExports());
+ }
+ }
+ }
+
+ ///
+ /// A store for MEF exports of a specific type. Provides basic wrapper functionality around MEF to standarize how
+ /// we lookup types and return to callers.
+ ///
+ public class ExtensionStore
+ {
+ private CompositionHost host;
+ private IList exports;
+ private Type contractType;
+
+ ///
+ /// Initializes the store with a type to lookup exports of, and a function that configures the
+ /// lookup parameters.
+ ///
+ /// Type to use as a base for all extensions being looked up
+ /// Function that returns the configuration to be used
+ public ExtensionStore(Type contractType, Func configure)
+ {
+ Validate.IsNotNull(nameof(contractType), contractType);
+ Validate.IsNotNull(nameof(configure), configure);
+ this.contractType = contractType;
+ ConventionBuilder builder = GetExportBuilder();
+ ContainerConfiguration config = configure(builder);
+ host = config.CreateContainer();
+ }
+
+ ///
+ /// Loads extensions from the current assembly
+ ///
+ /// ExtensionStore
+ public static ExtensionStore CreateDefaultLoader()
+ {
+ return CreateAssemblyStore(typeof(ExtensionStore).GetTypeInfo().Assembly);
+ }
+
+ public static ExtensionStore CreateAssemblyStore(Assembly assembly)
+ {
+ Validate.IsNotNull(nameof(assembly), assembly);
+ return new ExtensionStore(typeof(T), (conventions) =>
+ new ContainerConfiguration().WithAssembly(assembly, conventions));
+ }
+
+ public static ExtensionStore CreateStoreForCurrentDirectory()
+ {
+ string assemblyPath = typeof(ExtensionStore).GetTypeInfo().Assembly.Location;
+ string directory = Path.GetDirectoryName(assemblyPath);
+ return new ExtensionStore(typeof(T), (conventions) =>
+ new ContainerConfiguration().WithAssembliesInPath(directory, conventions));
+ }
+
+ public IEnumerable GetExports()
+ {
+ if (exports == null)
+ {
+ exports = host.GetExports(contractType).ToList();
+ }
+ return exports.Cast();
+ }
+
+ private ConventionBuilder GetExportBuilder()
+ {
+ // Define exports as matching a parent type, export as that parent type
+ var builder = new ConventionBuilder();
+ builder.ForTypesDerivedFrom(contractType).Export(exportConventionBuilder => exportConventionBuilder.AsContractType(contractType));
+ return builder;
+ }
+ }
+
+ public static class ContainerConfigurationExtensions
+ {
+ public static ContainerConfiguration WithAssembliesInPath(this ContainerConfiguration configuration, string path, SearchOption searchOption = SearchOption.TopDirectoryOnly)
+ {
+ return WithAssembliesInPath(configuration, path, null, searchOption);
+ }
+
+ public static ContainerConfiguration WithAssembliesInPath(this ContainerConfiguration configuration, string path, AttributedModelProvider conventions, SearchOption searchOption = SearchOption.TopDirectoryOnly)
+ {
+ AssemblyLoadContext context = new AssemblyLoader(path);
+ var assemblyNames = Directory
+ .GetFiles(path, "*.dll", searchOption)
+ .Select(AssemblyLoadContext.GetAssemblyName);
+
+ var assemblies = assemblyNames
+ .Select(context.LoadFromAssemblyName)
+ .ToList();
+
+ configuration = configuration.WithAssemblies(assemblies, conventions);
+
+ return configuration;
+ }
+ }
+
+ public class AssemblyLoader : AssemblyLoadContext
+ {
+ private string folderPath;
+
+ public AssemblyLoader(string folderPath)
+ {
+ this.folderPath = folderPath;
+ }
+
+ protected override Assembly Load(AssemblyName assemblyName)
+ {
+ var deps = DependencyContext.Default;
+ var res = deps.CompileLibraries.Where(d => d.Name.Equals(assemblyName.Name)).ToList();
+ if (res.Count > 0)
+ {
+ return Assembly.Load(new AssemblyName(res.First().Name));
+ }
+ else
+ {
+ var apiApplicationFileInfo = new FileInfo($"{folderPath}{Path.DirectorySeparatorChar}{assemblyName.Name}.dll");
+ if (File.Exists(apiApplicationFileInfo.FullName))
+ {
+ var asl = new AssemblyLoader(apiApplicationFileInfo.DirectoryName);
+ return asl.LoadFromAssemblyPath(apiApplicationFileInfo.FullName);
+ }
+ }
+ return Assembly.Load(assemblyName);
+ }
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Extensibility/IComposableService.cs b/src/Microsoft.SqlTools.ServiceLayer/Extensibility/IComposableService.cs
new file mode 100644
index 00000000..072b12e5
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Extensibility/IComposableService.cs
@@ -0,0 +1,22 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+
+namespace Microsoft.SqlTools.ServiceLayer.Extensibility
+{
+ ///
+ /// A Service that expects to lookup other services. Using this interface on an exported service
+ /// will ensure the method is called during
+ /// service initialization
+ ///
+ public interface IComposableService
+ {
+ ///
+ /// Supports settings the service provider being used to initialize the service.
+ /// This is useful to look up other services and use them in your own service.
+ ///
+ void SetServiceProvider(IMultiServiceProvider provider);
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Extensibility/IEnumerableExt.cs b/src/Microsoft.SqlTools.ServiceLayer/Extensibility/IEnumerableExt.cs
new file mode 100644
index 00000000..07412622
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Extensibility/IEnumerableExt.cs
@@ -0,0 +1,18 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System.Collections.Generic;
+
+namespace Microsoft.SqlTools.ServiceLayer.Extensibility
+{
+
+ internal static class IEnumerableExt
+ {
+ public static IEnumerable SingleItemAsEnumerable(this T item)
+ {
+ yield return item;
+ }
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Extensibility/IMultiServiceProvider.cs b/src/Microsoft.SqlTools.ServiceLayer/Extensibility/IMultiServiceProvider.cs
new file mode 100644
index 00000000..5a11065d
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Extensibility/IMultiServiceProvider.cs
@@ -0,0 +1,104 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.SqlTools.ServiceLayer.Utility;
+
+namespace Microsoft.SqlTools.ServiceLayer.Extensibility
+{
+ public interface IMultiServiceProvider
+ {
+ ///
+ /// Gets a service of a specific type. It is expected that only 1 instance of this type will be
+ /// available
+ ///
+ /// Type of service to be found
+ /// Instance of T or null if not found
+ /// The input sequence contains more than one element.-or-The input sequence is empty.
+ T GetService();
+
+ ///
+ /// Gets a service of a specific type. The first service matching the specified filter will be returned
+ /// available
+ ///
+ /// Type of service to be found
+ /// Filter to use in
+ /// Instance of T or null if not found
+ /// The input sequence contains more than one element.-or-The input sequence is empty.
+ T GetService(Predicate filter);
+
+ ///
+ /// Gets multiple services of a given type
+ ///
+ ///
+ /// An enumerable of matching services
+ IEnumerable GetServices();
+
+ ///
+ /// Gets multiple services of a given type, where they match a filter
+ ///
+ ///
+ ///
+ ///
+ IEnumerable GetServices(Predicate filter);
+ }
+
+
+ public abstract class ServiceProviderBase : IMultiServiceProvider
+ {
+
+ public T GetService()
+ {
+ return GetServices().SingleOrDefault();
+ }
+
+ public T GetService(Predicate filter)
+ {
+ Validate.IsNotNull(nameof(filter), filter);
+ return GetServices().Where(t => filter(t)).SingleOrDefault();
+ }
+
+ public IEnumerable GetServices(Predicate filter)
+ {
+ Validate.IsNotNull(nameof(filter), filter);
+ return GetServices().Where(t => filter(t));
+ }
+
+ public virtual IEnumerable GetServices()
+ {
+ var services = GetServicesImpl();
+ if (services == null)
+ {
+ return Enumerable.Empty();
+ }
+
+ return services.Select(t =>
+ {
+ InitComposableService(t);
+ return t;
+ });
+ }
+
+ private void InitComposableService(T t)
+ {
+ IComposableService c = t as IComposableService;
+ if (c != null)
+ {
+ c.SetServiceProvider(this);
+ }
+ }
+
+ ///
+ /// Gets all services using the build in implementation
+ ///
+ ///
+ ///
+ protected abstract IEnumerable GetServicesImpl();
+
+ }
+
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Extensibility/RegisteredServiceProvider.cs b/src/Microsoft.SqlTools.ServiceLayer/Extensibility/RegisteredServiceProvider.cs
new file mode 100644
index 00000000..fe205eda
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Extensibility/RegisteredServiceProvider.cs
@@ -0,0 +1,110 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Reflection;
+using Microsoft.SqlTools.ServiceLayer.Utility;
+
+namespace Microsoft.SqlTools.ServiceLayer.Extensibility
+{
+
+ ///
+ /// A service provider implementation that allows registering of specific services
+ ///
+ public class RegisteredServiceProvider : ServiceProviderBase
+ {
+ public delegate IEnumerable ServiceLookup();
+
+ protected Dictionary services = new Dictionary();
+
+ ///
+ /// Registers a singular service to be returned during lookup
+ ///
+ ///
+ /// this provider, to simplify fluent declarations
+ /// If service is null
+ /// If an existing service is already registered
+ public RegisteredServiceProvider RegisterSingleService(T service)
+ {
+ Validate.IsNotNull(nameof(service), service);
+ ThrowIfAlreadyRegistered();
+ services.Add(typeof(T), () => service.SingleItemAsEnumerable());
+ return this;
+ }
+
+ ///
+ /// Registers a singular service to be returned during lookup
+ ///
+ ///
+ /// Type or interface this service should be registed as. Any request
+ /// for that type will return this service
+ ///
+ /// service object to be added
+ /// this provider, to simplify fluent declarations
+ /// If service is null
+ /// If an existing service is already registered
+ public RegisteredServiceProvider RegisterSingleService(Type type, object service)
+ {
+ Validate.IsNotNull(nameof(type), type);
+ Validate.IsNotNull(nameof(service), service);
+ ThrowIfAlreadyRegistered(type);
+ ThrowIfIncompatible(type, service);
+ services.Add(type, () => service.SingleItemAsEnumerable());
+ return this;
+ }
+
+ ///
+ /// Registers a function that can look up multiple services
+ ///
+ ///
+ /// this provider, to simplify fluent declarations
+ /// If is null
+ /// If an existing service is already registered
+ public RegisteredServiceProvider Register(Func> serviceLookup)
+ {
+ Validate.IsNotNull(nameof(serviceLookup), serviceLookup);
+ ThrowIfAlreadyRegistered();
+ services.Add(typeof(T), () => serviceLookup());
+ return this;
+ }
+
+ private void ThrowIfAlreadyRegistered()
+ {
+ ThrowIfAlreadyRegistered(typeof(T));
+ }
+
+ private void ThrowIfAlreadyRegistered(Type type)
+ {
+ if (services.ContainsKey(type))
+ {
+ throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, SR.ServiceAlreadyRegistered, type.Name));
+ }
+
+ }
+
+ private void ThrowIfIncompatible(Type type, object service)
+ {
+ if (!type.IsInstanceOfType(service))
+ {
+ throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, SR.ServiceNotOfExpectedType, service.GetType().Name, type.Name));
+ }
+
+ }
+
+ protected override IEnumerable GetServicesImpl()
+ {
+ ServiceLookup serviceLookup;
+ if (services.TryGetValue(typeof(T), out serviceLookup))
+ {
+ return serviceLookup().Cast();
+ }
+ return Enumerable.Empty();
+ }
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Contracts/DocumentFormatting.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Contracts/DocumentFormatting.cs
new file mode 100644
index 00000000..1d2778a4
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Contracts/DocumentFormatting.cs
@@ -0,0 +1,113 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
+using Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts;
+using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter.Contracts
+{
+ ///
+ /// A formatting request to process an entire document
+ ///
+ public class DocumentFormattingRequest
+ {
+ public static readonly
+ RequestType Type =
+ RequestType.Create("textDocument/formatting");
+ }
+
+ ///
+ /// A formatting request to process a specific range inside a document
+ ///
+ public class DocumentRangeFormattingRequest
+ {
+ public static readonly
+ RequestType Type =
+ RequestType.Create("textDocument/rangeFormatting");
+ }
+
+ ///
+ /// A formatting request to handle a user typing, giving a chance to update the text based on this
+ ///
+ public class DocumentOnTypeFormattingRequest
+ {
+ public static readonly
+ RequestType Type =
+ RequestType.Create("textDocument/onTypeFormatting");
+ }
+
+
+ ///
+ /// Params for the
+ ///
+ public class DocumentFormattingParams
+ {
+
+ ///
+ /// The document to format.
+ ///
+ public TextDocumentIdentifier TextDocument { get; set; }
+
+ ///
+ /// The formatting options
+ ///
+ public FormattingOptions Options { get; set; }
+
+ }
+
+
+ ///
+ /// Params for the
+ ///
+ public class DocumentRangeFormattingParams : DocumentFormattingParams
+ {
+
+ ///
+ /// The range to format
+ ///
+ public Range Range { get; set; }
+
+ }
+
+ ///
+ /// Params for the
+ ///
+ public class DocumentOnTypeFormattingParams : DocumentFormattingParams
+ {
+ ///
+ /// The position at which this request was sent.
+
+ ///
+ Position Position { get; set; }
+
+ ///
+ /// The character that has been typed.
+
+ ///
+ string Ch { get; set; }
+ }
+
+ ///
+ /// Value-object describing what options formatting should use.
+ ///
+ public class FormattingOptions
+ {
+ ///
+ /// Size of a tab in spaces
+ ///
+ public int TabSize { get; set; }
+
+ ///
+ /// Prefer spaces over tabs.
+ ///
+ public bool InsertSpaces { get; set; }
+
+ // TODO there may be other options passed by VSCode - format is
+ // [key: string]: boolean | number | string;
+ // Determine how these might be passed and add them here
+}
+
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/ASTNodeFormatter.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/ASTNodeFormatter.cs
new file mode 100644
index 00000000..651df2dc
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/ASTNodeFormatter.cs
@@ -0,0 +1,23 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using Babel.ParserGenerator;
+using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+ public abstract class ASTNodeFormatter
+ {
+ ///
+ /// Formats the text for a specific node.
+ ///
+ public abstract void Format();
+
+ internal static LexLocation GetLexLocationForNode(SqlCodeObject obj)
+ {
+ return obj.Position;
+ }
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/ASTNodeFormatterT.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/ASTNodeFormatterT.cs
new file mode 100644
index 00000000..ad00970d
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/ASTNodeFormatterT.cs
@@ -0,0 +1,330 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.Diagnostics;
+using System.Globalization;
+using System.Linq;
+using System.Runtime.InteropServices;
+using Babel.ParserGenerator;
+using Microsoft.SqlServer.Management.SqlParser.Parser;
+using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
+using Microsoft.SqlTools.ServiceLayer.Utility;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+ internal abstract class ASTNodeFormatterT : ASTNodeFormatter where T : SqlCodeObject
+ {
+ protected FormatterVisitor Visitor { get; private set; }
+ protected T CodeObject { get; private set; }
+
+ public ASTNodeFormatterT(FormatterVisitor visitor, T codeObject)
+ {
+ Validate.IsNotNull(nameof(visitor), visitor);
+ Validate.IsNotNull(nameof(codeObject), codeObject);
+
+ Visitor = visitor;
+ CodeObject = codeObject;
+ }
+
+ protected TokenManager TokenManager
+ {
+ get { return Visitor.Context.Script.TokenManager; }
+ }
+
+ protected FormatOptions FormatOptions
+ {
+ get { return Visitor.Context.FormatOptions; }
+ }
+
+ internal virtual void ProcessChild(SqlCodeObject child)
+ {
+ Validate.IsNotNull(nameof(child), child);
+ child.Accept(Visitor);
+ }
+
+ protected void IncrementIndentLevel()
+ {
+ Visitor.Context.IncrementIndentLevel();
+ }
+
+ protected void DecrementIndentLevel()
+ {
+ Visitor.Context.DecrementIndentLevel();
+ }
+
+ protected void ProcessTokenRange(int startTokenNumber, int endTokenNumber)
+ {
+ Visitor.Context.ProcessTokenRange(startTokenNumber, endTokenNumber);
+ }
+
+ protected void ProcessTokenRangeEnsuringOneNewLineMinumum(int startindex, int endIndex)
+ {
+ ProcessAndNormalizeWhitespaceRange(startindex, endIndex, FormatterUtilities.NormalizeNewLinesEnsureOneNewLineMinimum);
+ }
+
+ protected void ProcessAndNormalizeWhitespaceRange(int startindex, int endIndex, NormalizeWhitespace normalizer)
+ {
+ ProcessAndNormalizeTokenRange(startindex, endIndex, normalizer, true);
+ }
+
+
+ protected void ProcessAndNormalizeTokenRange(int startindex, int endIndex,
+ NormalizeWhitespace normalizer, bool areAllTokensWhitespace)
+ {
+ for (int i = startindex; i < endIndex; i++)
+ {
+ ProcessTokenAndNormalize(i, normalizer, areAllTokensWhitespace);
+ }
+ }
+
+ protected void ProcessTokenAndNormalize(int tokenIndex, NormalizeWhitespace normalizeFunction, bool areAllTokensWhitespace = true)
+ {
+ TokenData iTokenData = GetTokenData(tokenIndex);
+
+ if (areAllTokensWhitespace)
+ {
+ DebugAssertTokenIsWhitespaceOrComment(iTokenData, tokenIndex);
+ }
+ normalizeFunction = normalizeFunction ?? FormatterUtilities.NormalizeNewLinesEnsureOneNewLineMinimum;
+ SimpleProcessToken(tokenIndex, normalizeFunction);
+ }
+
+ protected void DebugAssertTokenIsWhitespaceOrComment(TokenData td, int tokenIndex)
+ {
+ Debug.Assert(TokenManager.IsTokenComment(td.TokenId) || IsTokenWhitespace(td), string.Format(CultureInfo.CurrentCulture,
+ "Unexpected token \"{0}\", expected whitespace or comment.", GetTextForCurrentToken(tokenIndex))
+ );
+ }
+
+ ///
+ /// Logical aliases for ProcessTokenRange that indicates the starting region is to be analyzed
+ ///
+ internal virtual void ProcessPrefixRegion(int startTokenNumber, int firstChildStartTokenNumber)
+ {
+ ProcessTokenRange(startTokenNumber, firstChildStartTokenNumber);
+ }
+
+ ///
+ /// Logical aliases for ProcessTokenRange that indicates the end region is to be analyzed
+ ///
+ internal virtual void ProcessSuffixRegion(int lastChildEndTokenNumber, int endTokenNumber)
+ {
+ ProcessTokenRange(lastChildEndTokenNumber, endTokenNumber);
+ }
+
+ internal virtual void ProcessInterChildRegion(SqlCodeObject lastChild, SqlCodeObject nextChild)
+ {
+ Validate.IsNotNull(nameof(lastChild), lastChild);
+ Validate.IsNotNull(nameof(nextChild), nextChild);
+
+ int lastChildEnd = lastChild.Position.endTokenNumber;
+ int nextChildStart = nextChild.Position.startTokenNumber;
+
+ ProcessTokenRange(lastChildEnd, nextChildStart);
+ }
+
+ public override void Format()
+ {
+ LexLocation loc = GetLexLocationForNode(CodeObject);
+
+ SqlCodeObject firstChild = CodeObject.Children.FirstOrDefault();
+ if (firstChild != null)
+ {
+ //
+ // format the text from the start of the object to the start of it's first child
+ //
+ LexLocation firstChildStart = GetLexLocationForNode(firstChild);
+ ProcessPrefixRegion(loc.startTokenNumber, firstChildStart.startTokenNumber);
+
+ //LexLocation lastChildLexLocation = null;
+ SqlCodeObject previousChild = null;
+ foreach (SqlCodeObject child in CodeObject.Children)
+ {
+ //
+ // format text between the last child's end & current child's start
+ //
+ if (previousChild != null)
+ {
+ //ProcessInterChildRegion(lastChildLexLocation.endTokenNumber, childLexLocation.startTokenNumber);
+ ProcessInterChildRegion(previousChild, child);
+ }
+
+ //
+ // format text of the the current child
+ //
+ ProcessChild(child);
+ previousChild = child;
+
+ }
+
+ //
+ // format text from end of last child to end of object.
+ //
+ Debug.Assert(previousChild != null, "last child is null. Need to write code to deal with this case");
+ ProcessSuffixRegion(previousChild.Position.endTokenNumber, loc.endTokenNumber);
+ }
+ else
+ {
+ // no children
+ ProcessTokenRange(loc.startTokenNumber, loc.endTokenNumber);
+ }
+ }
+
+ protected void SimpleProcessToken(int currentToken, NormalizeWhitespace normalizeFunction)
+ {
+ TokenData t = GetTokenData(currentToken);
+ if (IsTokenWhitespace(t))
+ {
+ ProcessWhitepace(currentToken, normalizeFunction, t);
+ }
+ else if (t.TokenId == FormatterTokens.LEX_END_OF_LINE_COMMENT)
+ {
+ ProcessEndOfLine(currentToken, t);
+ }
+ else
+ {
+ ProcessTokenRange(currentToken, currentToken + 1);
+ }
+ }
+
+ private void ProcessWhitepace(int currentToken, NormalizeWhitespace normalizeFunction, TokenData token)
+ {
+ string originalWhiteSpace = GetTextForCurrentToken(currentToken);
+ if (HasPreviousToken(currentToken))
+ {
+ TokenData previousToken = PreviousTokenData(currentToken);
+ if (previousToken.TokenId == FormatterTokens.LEX_END_OF_LINE_COMMENT)
+ {
+ if (originalWhiteSpace.StartsWith("\n", StringComparison.OrdinalIgnoreCase)
+ && RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ // Replace \n with \r\n on Windows platforms
+ originalWhiteSpace = Environment.NewLine + originalWhiteSpace.Substring(1);
+ }
+ }
+ }
+
+ string newWhiteSpace = normalizeFunction(originalWhiteSpace, Visitor.Context);
+
+ AddReplacement(new Replacement(token.StartIndex, GetTextForCurrentToken(currentToken), newWhiteSpace));
+ }
+
+ protected string GetTextForCurrentToken(int currentToken)
+ {
+ return Visitor.Context.GetTokenRangeAsOriginalString(currentToken, currentToken + 1);
+ }
+
+ protected string GetTokenRangeAsOriginalString(int startTokenNumber, int endTokenNumber)
+ {
+ return Visitor.Context.GetTokenRangeAsOriginalString(startTokenNumber, endTokenNumber);
+ }
+
+ private void ProcessEndOfLine(int currentToken, TokenData t)
+ {
+ //
+ // the new line character is split over the LEX_END_OF_LINE_COMMENT token and a following whitespace token.
+ // we deal with that here.
+ //
+ string comment = GetTextForCurrentToken(currentToken);
+ if (comment.EndsWith("\r", StringComparison.OrdinalIgnoreCase))
+ {
+ AddReplacement(new Replacement(t.StartIndex, comment, comment.Substring(0, comment.Length - 1)));
+ }
+ }
+
+ protected bool IsTokenWithIdWhitespace(int tokenId)
+ {
+ if (HasToken(tokenId))
+ {
+ return TokenManager.IsTokenWhitespace(TokenManager.TokenList[tokenId].TokenId);
+ }
+ return false;
+ }
+
+ protected bool IsTokenWhitespace(TokenData tokenData)
+ {
+ return TokenManager.IsTokenWhitespace(tokenData.TokenId);
+ }
+
+
+ protected TokenData GetTokenData(int currentToken)
+ {
+ if (HasToken(currentToken))
+ {
+ return TokenManager.TokenList[currentToken];
+ }
+ return default(TokenData);
+ }
+
+ protected TokenData PreviousTokenData(int currentToken)
+ {
+ if (HasPreviousToken(currentToken))
+ {
+ return TokenManager.TokenList[currentToken - 1];
+ }
+ return default(TokenData);
+ }
+
+ protected TokenData NextTokenData(int currentToken)
+ {
+ if (HasToken(currentToken))
+ {
+ return TokenManager.TokenList[currentToken + 1];
+ }
+ return default(TokenData);
+ }
+
+ protected bool HasPreviousToken(int currentToken)
+ {
+ return HasToken(currentToken - 1);
+ }
+
+ protected bool HasToken(int tokenIndex)
+ {
+ return tokenIndex >= 0 && tokenIndex < TokenManager.TokenList.Count;
+ }
+
+ protected void AddReplacement(Replacement replacement)
+ {
+ Visitor.Context.Replacements.Add(replacement);
+ }
+
+ protected void AddReplacement(int startIndex, string oldValue, string newValue)
+ {
+ AddReplacement(new Replacement(startIndex, oldValue, newValue));
+ }
+
+ protected void AddIndentedNewLineReplacement(int startIndex)
+ {
+ AddReplacement(new Replacement(startIndex, string.Empty, Environment.NewLine + Visitor.Context.GetIndentString()));
+ }
+
+ protected string GetIndentString()
+ {
+ return Visitor.Context.GetIndentString();
+ }
+
+ ///
+ /// Finds an expected token
+ ///
+ /// Current index to start the search at
+ /// ID defining the type of token being looked for - e.g. parenthesis, INSERT
+ protected int FindTokenWithId(int currentIndex, int id)
+ {
+ TokenData td = GetTokenData(currentIndex);
+ while (td.TokenId != id && currentIndex < CodeObject.Position.endTokenNumber)
+ {
+ DebugAssertTokenIsWhitespaceOrComment(td, currentIndex);
+ ++currentIndex;
+ td = GetTokenData(currentIndex);
+ }
+ Debug.Assert(currentIndex < CodeObject.Position.endTokenNumber, "No token with ID" + id + " found in the columns definition.");
+ return currentIndex;
+ }
+
+ internal delegate string NormalizeWhitespace(string original, FormatContext context);
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/AstNodeFormatterFactory.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/AstNodeFormatterFactory.cs
new file mode 100644
index 00000000..ec312280
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/AstNodeFormatterFactory.cs
@@ -0,0 +1,39 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
+using Microsoft.SqlTools.ServiceLayer.Utility;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+ internal abstract class ASTNodeFormatterFactory
+ {
+ public abstract Type SupportedNodeType { get; }
+ public abstract ASTNodeFormatter Create(FormatterVisitor visitor, SqlCodeObject codeObject);
+ }
+
+ internal abstract class ASTNodeFormatterFactoryT : ASTNodeFormatterFactory
+ where T : SqlCodeObject
+ {
+ public override Type SupportedNodeType
+ {
+ get
+ {
+ return typeof(T);
+ }
+ }
+
+ public override ASTNodeFormatter Create(FormatterVisitor visitor, SqlCodeObject codeObject)
+ {
+ Validate.IsNotNull(nameof(visitor), visitor);
+ Validate.IsNotNull(nameof(codeObject), codeObject);
+
+ return DoCreate(visitor, codeObject as T);
+ }
+
+ protected abstract ASTNodeFormatter DoCreate(FormatterVisitor visitor, T codeObject);
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/CommaSeparatedListFormatter.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/CommaSeparatedListFormatter.cs
new file mode 100644
index 00000000..6af6e3db
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/CommaSeparatedListFormatter.cs
@@ -0,0 +1,145 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.Diagnostics;
+using Babel.ParserGenerator;
+using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
+using Microsoft.SqlTools.ServiceLayer.Utility;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+
+ internal class CommaSeparatedListFormatter : ASTNodeFormatterT
+ {
+ private bool PlaceEachElementOnNewLine { get; set; }
+
+ internal CommaSeparatedListFormatter(FormatterVisitor visitor, SqlCodeObject codeObject, bool placeEachElementOnNewLine)
+ : base(visitor, codeObject)
+ {
+ PlaceEachElementOnNewLine = placeEachElementOnNewLine;
+ }
+
+ internal override void ProcessPrefixRegion(int startTokenNumber, int firstChildStartTokenNumber)
+ {
+ IncrementIndentLevel();
+
+ NormalizeWhitespace f = FormatterUtilities.NormalizeNewLinesOrCondenseToOneSpace;
+ if (PlaceEachElementOnNewLine)
+ {
+ f = FormatterUtilities.NormalizeNewLinesEnsureOneNewLineMinimum;
+ }
+
+ for (int i = startTokenNumber; i < firstChildStartTokenNumber; i++)
+ {
+ SimpleProcessToken(i, f);
+ }
+ }
+
+ internal override void ProcessSuffixRegion(int lastChildEndTokenNumber, int endTokenNumber)
+ {
+ DecrementIndentLevel();
+ ProcessTokenRange(lastChildEndTokenNumber, endTokenNumber);
+ }
+
+ internal override void ProcessInterChildRegion(SqlCodeObject previousChild, SqlCodeObject nextChild)
+ {
+ Validate.IsNotNull(nameof(previousChild), previousChild);
+ Validate.IsNotNull(nameof(nextChild), nextChild);
+
+ int start = previousChild.Position.endTokenNumber;
+ int end = nextChild.Position.startTokenNumber;
+
+ bool foundNonWhitespaceTokenBeforeComma = false;
+ int commaToken = -1;
+
+ for (int i = start; i < end && HasToken(i); i++)
+ {
+ TokenData td = GetTokenData(i);
+ if (td.TokenId == 44)
+ {
+ commaToken = i;
+ break;
+ }
+ else if (IsTokenWhitespace(td))
+ {
+ foundNonWhitespaceTokenBeforeComma = true;
+ }
+ }
+
+ Debug.Assert(commaToken > -1, "No comma separating the children.");
+
+ if (foundNonWhitespaceTokenBeforeComma)
+ {
+ ProcessTokenRange(start, commaToken);
+ }
+ else
+ {
+
+#if DEBUG
+ for (int i = start; i < commaToken && HasToken(i); i++)
+ {
+ TokenData td = GetTokenData(i);
+ if (!IsTokenWhitespace(td))
+ {
+ Debug.Fail("unexpected token type of " + td.TokenId);
+ }
+ }
+#endif
+
+ // strip whitespace before comma
+ for (int i = start; i < commaToken; i++)
+ {
+ SimpleProcessToken(i, FormatterUtilities.StripAllWhitespace);
+ }
+ }
+
+ // include comma after each element?
+ if (!FormatOptions.PlaceCommasBeforeNextStatement)
+ {
+ ProcessTokenRange(commaToken, commaToken + 1);
+ }
+ else
+ {
+ TokenData token = GetTokenData(commaToken);
+ AddReplacement(new Replacement(token.StartIndex, ",", ""));
+ }
+
+ // special case if there is no white space between comma token and end of region
+ if (commaToken + 1 == end)
+ {
+ string newValue = PlaceEachElementOnNewLine ? Environment.NewLine + GetIndentString() : " ";
+ AddReplacement(new Replacement(
+ GetTokenData(end).StartIndex,
+ string.Empty,
+ newValue
+ ));
+ }
+ else
+ {
+ NormalizeWhitespace f = FormatterUtilities.NormalizeNewLinesOrCondenseToOneSpace;
+ if (PlaceEachElementOnNewLine)
+ {
+ f = FormatterUtilities.NormalizeNewLinesEnsureOneNewLineMinimum;
+ }
+
+ for (int i = commaToken + 1; i < end; i++)
+ {
+ SimpleProcessToken(i, f);
+ }
+
+ }
+
+ // do we need to place the comma before the next statement in the list?
+ if (FormatOptions.PlaceCommasBeforeNextStatement)
+ {
+ SimpleProcessToken(commaToken, FormatterUtilities.NormalizeNewLinesInWhitespace);
+ TokenData tok = GetTokenData(end);
+ AddReplacement(new Replacement(tok.StartIndex, "", ","));
+ }
+ }
+ }
+
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/FormatContext.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/FormatContext.cs
new file mode 100644
index 00000000..61837b89
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/FormatContext.cs
@@ -0,0 +1,198 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Text;
+using Babel.ParserGenerator;
+using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+ internal class FormatContext
+ {
+ private ReplacementQueue replacements = new ReplacementQueue();
+ private string formattedSql;
+
+ internal FormatContext(SqlScript sqlScript, FormatOptions options)
+ {
+ FormatOptions = options;
+ Script = sqlScript;
+ LoadKeywordIdentifiers();
+ }
+
+ internal SqlScript Script { get; private set; }
+ internal FormatOptions FormatOptions { get; set; }
+ internal int IndentLevel { get; set; }
+ internal HashSet KeywordIdentifiers { get; set; }
+
+ private void LoadKeywordIdentifiers()
+ {
+ KeywordIdentifiers = new HashSet();
+ KeywordIdentifiers.Add(FormatterTokens.TOKEN_FROM);
+ KeywordIdentifiers.Add(FormatterTokens.TOKEN_SELECT);
+ KeywordIdentifiers.Add(FormatterTokens.TOKEN_TABLE);
+ KeywordIdentifiers.Add(FormatterTokens.TOKEN_CREATE);
+ KeywordIdentifiers.Add(FormatterTokens.TOKEN_USEDB);
+ KeywordIdentifiers.Add(FormatterTokens.TOKEN_NOT);
+ KeywordIdentifiers.Add(FormatterTokens.TOKEN_NULL);
+ KeywordIdentifiers.Add(FormatterTokens.TOKEN_IDENTITY);
+ KeywordIdentifiers.Add(FormatterTokens.TOKEN_ORDER);
+ KeywordIdentifiers.Add(FormatterTokens.TOKEN_BY);
+ KeywordIdentifiers.Add(FormatterTokens.TOKEN_DESC);
+ KeywordIdentifiers.Add(FormatterTokens.TOKEN_ASC);
+ KeywordIdentifiers.Add(FormatterTokens.TOKEN_GROUP);
+ KeywordIdentifiers.Add(FormatterTokens.TOKEN_WHERE);
+ KeywordIdentifiers.Add(FormatterTokens.TOKEN_JOIN);
+ KeywordIdentifiers.Add(FormatterTokens.TOKEN_ON);
+ KeywordIdentifiers.Add(FormatterTokens.TOKEN_UNION);
+ KeywordIdentifiers.Add(FormatterTokens.TOKEN_ALL);
+ KeywordIdentifiers.Add(FormatterTokens.TOKEN_EXCEPT);
+ KeywordIdentifiers.Add(FormatterTokens.TOKEN_INTERSECT);
+ KeywordIdentifiers.Add(FormatterTokens.TOKEN_INTO);
+ KeywordIdentifiers.Add(FormatterTokens.TOKEN_DEFAULT);
+ KeywordIdentifiers.Add(FormatterTokens.TOKEN_WITH);
+ KeywordIdentifiers.Add(FormatterTokens.TOKEN_AS);
+ KeywordIdentifiers.Add(FormatterTokens.LEX_BATCH_SEPERATOR);
+ KeywordIdentifiers.Add(FormatterTokens.TOKEN_IS);
+ }
+
+ public string FormattedSql
+ {
+ get
+ {
+ if (formattedSql == null)
+ {
+ DoFormatSql();
+ }
+ return formattedSql;
+ }
+ }
+
+ private void DoFormatSql()
+ {
+ StringBuilder code = new StringBuilder(Script.Sql);
+ foreach (Replacement r in Replacements)
+ {
+ r.Apply((int position, int length, string formattedText) =>
+ {
+ if (length > 0)
+ {
+ if (formattedText.Length > 0)
+ {
+ code.Remove(position, length);
+ code.Insert(position, formattedText);
+ }
+ else
+ {
+ code.Remove(position, length);
+ }
+ }
+ else
+ {
+ if (formattedText.Length > 0)
+ {
+ code.Insert(position, formattedText);
+ }
+ else
+ {
+ throw new FormatException(SR.ErrorEmptyStringReplacement);
+ }
+ }
+ });
+ }
+ formattedSql = code.ToString();
+ }
+
+ public ReplacementQueue Replacements
+ {
+ get
+ {
+ return replacements;
+ }
+ }
+
+ internal void IncrementIndentLevel()
+ {
+ IndentLevel++;
+ }
+
+ internal void DecrementIndentLevel()
+ {
+ if (IndentLevel == 0)
+ {
+ throw new FormatFailedException("can't decrement indent level. It is already 0.");
+ }
+ IndentLevel--;
+ }
+
+ public string GetIndentString()
+ {
+ if (FormatOptions.UseTabs)
+ {
+ return new string('\t', IndentLevel);
+ }
+ else
+ {
+ return new string(' ', IndentLevel * FormatOptions.SpacesPerIndent);
+ }
+ }
+
+ internal string GetTokenRangeAsOriginalString(int startTokenNumber, int endTokenNumber)
+ {
+ string sql = string.Empty;
+ if (endTokenNumber > startTokenNumber && startTokenNumber > -1 && endTokenNumber > -1)
+ {
+ sql = Script.TokenManager.GetText(startTokenNumber, endTokenNumber);
+ }
+ return sql;
+ }
+
+ ///
+ /// Will apply any token-level formatting (e.g., uppercase/lowercase of keywords).
+ ///
+ [SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase")]
+ internal void ProcessTokenRange(int startTokenNumber, int endTokenNumber)
+ {
+
+ for (int i = startTokenNumber; i < endTokenNumber; i++)
+ {
+ string sql = GetTokenRangeAsOriginalString(i, i + 1);
+
+ if (IsKeywordToken(Script.TokenManager.TokenList[i].TokenId))
+ {
+ if (FormatOptions.UppercaseKeywords)
+ {
+ TokenData tok = Script.TokenManager.TokenList[i];
+ Replacements.Add(new Replacement(tok.StartIndex, sql, sql.ToUpperInvariant()));
+ sql = sql.ToUpperInvariant();
+ }
+ else if (FormatOptions.LowercaseKeywords)
+ {
+ TokenData tok = Script.TokenManager.TokenList[i];
+ Replacements.Add(new Replacement(tok.StartIndex, sql, sql.ToLowerInvariant()));
+ sql = sql.ToLowerInvariant();
+ }
+ }
+ }
+
+ }
+
+ internal void AppendTokenRangeAsString(int startTokenNumber, int endTokenNumber)
+ {
+ ProcessTokenRange(startTokenNumber, endTokenNumber);
+ }
+
+ private bool IsKeywordToken(int tokenId)
+ {
+ return KeywordIdentifiers.Contains(tokenId);
+ }
+
+ internal List CurrentColumnSpacingFormatDefinitions { get; set; }
+
+ }
+
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/FormatFailedException.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/FormatFailedException.cs
new file mode 100644
index 00000000..c3896347
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/FormatFailedException.cs
@@ -0,0 +1,28 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+ public class FormatFailedException : Exception
+ {
+ public FormatFailedException()
+ : base()
+ {
+ }
+
+ public FormatFailedException(string message, Exception exception)
+ : base(message, exception)
+ {
+ }
+
+
+ public FormatFailedException(string message)
+ : base(message)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/FormatOptions.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/FormatOptions.cs
new file mode 100644
index 00000000..3071c066
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/FormatOptions.cs
@@ -0,0 +1,171 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.ComponentModel;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+
+ public enum CasingOptions { None, Uppercase, Lowercase };
+
+ ///
+ /// The supported options to use when formatting text
+ ///
+ public class FormatOptions : INotifyPropertyChanged
+ {
+
+ private int spacesPerIndent;
+ private bool useTabs = false;
+ private bool encloseIdentifiersInSquareBrackets;
+ private bool placeCommasBeforeNextStatement;
+ private bool placeEachReferenceOnNewLineInQueryStatements;
+ private CasingOptions keywordCasing;
+ private CasingOptions datatypeCasing;
+ private bool alignColumnDefinitionsInColumns;
+
+ internal FormatOptions()
+ {
+ SpacesPerIndent = 4;
+ UseTabs = false;
+ PlaceCommasBeforeNextStatement = false;
+ EncloseIdentifiersInSquareBrackets = false;
+ PlaceEachReferenceOnNewLineInQueryStatements = false;
+ }
+
+ public int SpacesPerIndent
+ {
+ get { return spacesPerIndent; }
+ set { spacesPerIndent = value;
+ RaisePropertyChanged("SpacesPerIndent"); }
+ }
+
+ public bool UseTabs
+ {
+ get { return useTabs; }
+ set
+ {
+ useTabs = value;
+ // raise UseTabs & UseSpaces property changed events
+ RaisePropertyChanged("UseTabs");
+ RaisePropertyChanged("UseSpaces");
+ }
+ }
+
+ public bool UseSpaces
+ {
+ get { return !UseTabs; }
+ set { UseTabs = !value; }
+ }
+
+ public bool EncloseIdentifiersInSquareBrackets
+ {
+ get { return encloseIdentifiersInSquareBrackets; }
+ set
+ {
+ encloseIdentifiersInSquareBrackets = value;
+ RaisePropertyChanged("EncloseIdentifiersInSquareBrackets");
+ }
+ }
+
+ public bool PlaceCommasBeforeNextStatement
+ {
+ get { return placeCommasBeforeNextStatement; }
+ set
+ {
+ placeCommasBeforeNextStatement = value;
+ RaisePropertyChanged("PlaceCommasBeforeNextStatement");
+ }
+ }
+
+ public bool PlaceEachReferenceOnNewLineInQueryStatements
+ {
+ get { return placeEachReferenceOnNewLineInQueryStatements; }
+ set
+ {
+ placeEachReferenceOnNewLineInQueryStatements = value;
+ RaisePropertyChanged("PlaceEachReferenceOnNewLineInQueryStatements");
+ }
+ }
+
+ public CasingOptions KeywordCasing
+ {
+ get { return keywordCasing; }
+ set
+ {
+ keywordCasing = value;
+ RaisePropertyChanged("KeywordCasing");
+ }
+ }
+
+ public bool UppercaseKeywords
+ {
+ get { return KeywordCasing == CasingOptions.Uppercase; }
+ }
+ public bool LowercaseKeywords
+ {
+ get { return KeywordCasing == CasingOptions.Lowercase; }
+ }
+
+ public bool DoNotFormatKeywords
+ {
+ get { return KeywordCasing == CasingOptions.None; }
+ }
+
+ public CasingOptions DatatypeCasing
+ {
+ get { return datatypeCasing; }
+ set
+ {
+ datatypeCasing = value;
+ RaisePropertyChanged("DatatypeCasing");
+ }
+ }
+
+ public bool UppercaseDataTypes
+ {
+ get { return DatatypeCasing == CasingOptions.Uppercase; }
+ }
+ public bool LowercaseDataTypes
+ {
+ get { return DatatypeCasing == CasingOptions.Lowercase; }
+ }
+ public bool DoNotFormatDataTypes
+ {
+ get { return DatatypeCasing == CasingOptions.None; }
+ }
+
+ public bool AlignColumnDefinitionsInColumns
+ {
+ get { return alignColumnDefinitionsInColumns; }
+ set
+ {
+ alignColumnDefinitionsInColumns = value;
+ RaisePropertyChanged("AlignColumnDefinitionsInColumns");
+ }
+ }
+
+ private void RaisePropertyChanged(string propertyName)
+ {
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+ }
+
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ public static void Copy(FormatOptions target, FormatOptions source)
+ {
+ target.AlignColumnDefinitionsInColumns = source.AlignColumnDefinitionsInColumns;
+ target.DatatypeCasing = source.DatatypeCasing;
+ target.EncloseIdentifiersInSquareBrackets = source.EncloseIdentifiersInSquareBrackets;
+ target.KeywordCasing = source.KeywordCasing;
+ target.PlaceCommasBeforeNextStatement = source.PlaceCommasBeforeNextStatement;
+ target.PlaceEachReferenceOnNewLineInQueryStatements = source.PlaceEachReferenceOnNewLineInQueryStatements;
+ target.SpacesPerIndent = source.SpacesPerIndent;
+ target.UseSpaces = source.UseSpaces;
+ target.UseTabs = source.UseTabs;
+ }
+ }
+
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/FormatterTokens.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/FormatterTokens.cs
new file mode 100644
index 00000000..38b1e008
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/FormatterTokens.cs
@@ -0,0 +1,60 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System.ComponentModel;
+using Microsoft.SqlServer.Management.SqlParser.Parser;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+ ///
+ /// Dynamically resolves the token IDs to match the values in the enum Microsoft.SqlServer.Management.SqlParser.Parser.Tokens.
+ /// This way, if the values in the enum change but their names remain the same
+ /// (when the Microsoft.SqlServer.Management.SqlParser.Parser.dll adds new tokens to the enum and is rebuilt),
+ /// the new values are retreived at runtime without having to rebuild Microsoft.SqlTools.ServiceLayer.Formatter.dll
+ ///
+ static class FormatterTokens
+ {
+ private static int ResolveTokenId(string tokenName)
+ {
+ EnumConverter converter = new EnumConverter(typeof(Tokens));
+ return (int)converter.ConvertFromString(tokenName);
+ }
+
+ public static readonly int TOKEN_FOR = ResolveTokenId("TOKEN_FOR");
+ public static readonly int TOKEN_REPLICATION = ResolveTokenId("TOKEN_REPLICATION");
+ public static readonly int TOKEN_ID = ResolveTokenId("TOKEN_ID");
+ public static readonly int LEX_END_OF_LINE_COMMENT = ResolveTokenId("LEX_END_OF_LINE_COMMENT");
+ public static readonly int TOKEN_FROM = ResolveTokenId("TOKEN_FROM");
+ public static readonly int TOKEN_SELECT = ResolveTokenId("TOKEN_SELECT");
+ public static readonly int TOKEN_TABLE = ResolveTokenId("TOKEN_TABLE");
+ public static readonly int TOKEN_USEDB = ResolveTokenId("TOKEN_USEDB");
+ public static readonly int TOKEN_NOT = ResolveTokenId("TOKEN_NOT");
+ public static readonly int TOKEN_NULL = ResolveTokenId("TOKEN_NULL");
+ public static readonly int TOKEN_IDENTITY = ResolveTokenId("TOKEN_IDENTITY");
+ public static readonly int TOKEN_ORDER = ResolveTokenId("TOKEN_ORDER");
+ public static readonly int TOKEN_BY = ResolveTokenId("TOKEN_BY");
+ public static readonly int TOKEN_DESC = ResolveTokenId("TOKEN_DESC");
+ public static readonly int TOKEN_ASC = ResolveTokenId("TOKEN_ASC");
+ public static readonly int TOKEN_GROUP = ResolveTokenId("TOKEN_GROUP");
+ public static readonly int TOKEN_WHERE = ResolveTokenId("TOKEN_WHERE");
+ public static readonly int TOKEN_JOIN = ResolveTokenId("TOKEN_JOIN");
+ public static readonly int TOKEN_ON = ResolveTokenId("TOKEN_ON");
+ public static readonly int TOKEN_UNION = ResolveTokenId("TOKEN_UNION");
+ public static readonly int TOKEN_ALL = ResolveTokenId("TOKEN_ALL");
+ public static readonly int TOKEN_EXCEPT = ResolveTokenId("TOKEN_EXCEPT");
+ public static readonly int TOKEN_INTERSECT = ResolveTokenId("TOKEN_INTERSECT");
+ public static readonly int TOKEN_INTO = ResolveTokenId("TOKEN_INTO");
+ public static readonly int TOKEN_DEFAULT = ResolveTokenId("TOKEN_DEFAULT");
+ public static readonly int TOKEN_WITH = ResolveTokenId("TOKEN_WITH");
+ public static readonly int TOKEN_AS = ResolveTokenId("TOKEN_AS");
+ public static readonly int TOKEN_IS = ResolveTokenId("TOKEN_IS");
+ public static readonly int TOKEN_BEGIN_CS = ResolveTokenId("TOKEN_BEGIN_CS");
+ public static readonly int TOKEN_END_CS = ResolveTokenId("TOKEN_END_CS");
+ public static readonly int LEX_BATCH_SEPERATOR = ResolveTokenId("LEX_BATCH_SEPERATOR");
+ public static readonly int TOKEN_CREATE = ResolveTokenId("TOKEN_CREATE");
+ public static readonly int LAST_TOKEN = ResolveTokenId("LAST_TOKEN");
+
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/FormatterUtilities.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/FormatterUtilities.cs
new file mode 100644
index 00000000..657f35b9
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/FormatterUtilities.cs
@@ -0,0 +1,77 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.Text;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+ internal static class FormatterUtilities
+ {
+ internal static string StripAllWhitespace(string original, FormatContext context)
+ {
+ return String.Empty;
+ }
+
+ internal static string NormalizeToOneSpace(string original, FormatContext context)
+ {
+ return " ";
+ }
+
+ internal static string NormalizeNewLinesInWhitespace(string original, FormatContext context)
+ {
+ return NormalizeNewLinesInWhitespace(original, context, 0);
+ }
+
+ internal static string NormalizeNewLinesEnsureOneNewLineMinimum(string original, FormatContext context)
+ {
+ return NormalizeNewLinesInWhitespace(original, context, 1);
+ }
+
+ private static string NormalizeNewLinesInWhitespace(string original, FormatContext context, int minimumNewLines)
+ {
+ return NormalizeNewLinesInWhitespace(original, context, 1, () => { return original; });
+ }
+
+ internal static string NormalizeNewLinesOrCondenseToOneSpace(string original, FormatContext context)
+ {
+ return NormalizeNewLinesOrCondenseToNSpaces(original, context, 1);
+ }
+
+ internal static string NormalizeNewLinesOrCondenseToNSpaces(string original, FormatContext context, int nSpaces)
+ {
+ return NormalizeNewLinesInWhitespace(original, context, 0, () => { return new String(' ', nSpaces); });
+ }
+
+ private static string NormalizeNewLinesInWhitespace(string original, FormatContext context, int minimumNewLines, Func noNewLinesProcessor)
+ {
+ int nNewLines = 0;
+ int idx = original.IndexOf(Environment.NewLine, StringComparison.OrdinalIgnoreCase);
+ while (idx > -1)
+ {
+ ++nNewLines;
+ idx = original.IndexOf(Environment.NewLine, idx + 1, StringComparison.OrdinalIgnoreCase);
+ }
+
+ StringBuilder sb = new StringBuilder();
+ nNewLines = Math.Max(minimumNewLines, nNewLines);
+ for (int i = 0; i < nNewLines; i++)
+ {
+ sb.Append(Environment.NewLine);
+ }
+ sb.Append(context.GetIndentString());
+
+ if (nNewLines > 0)
+ {
+ return sb.ToString();
+ }
+ else
+ {
+ return noNewLinesProcessor();
+ }
+ }
+
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/FormatterVisitor.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/FormatterVisitor.cs
new file mode 100644
index 00000000..7ff83662
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/FormatterVisitor.cs
@@ -0,0 +1,168 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.Diagnostics;
+using System.Globalization;
+using System.Linq;
+using Microsoft.SqlServer.Management.SqlParser.Parser;
+using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
+using Microsoft.SqlTools.ServiceLayer.Extensibility;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+ ///
+ /// The main entry point for our formatter implementation, via the method.
+ /// This converts a text string into a parsed AST using the Intellisense parser.
+ /// It then uses the Visitor pattern to find each element in the tree and determine if any edits are needed based on
+ /// All edits are applied after the entire AST has been visited using an algorithm that keeps track of index changes caused by previous updates. This allows
+ /// us to apply multiple edits to a text string in one sweep.
+ ///
+ /// A note on the implementation: All of the override nodes in the Intellisense AST are defined here, and routed to the Format method which looks up a matching
+ /// formatter to handle them. Any entry not explicitly formatted will use the no-op formatter which passes through the text unchanged.
+ ///
+ internal partial class FormatterVisitor : SqlCodeObjectVisitor
+ {
+ private readonly IMultiServiceProvider serviceProvider;
+
+ public FormatterVisitor(FormatContext context, IMultiServiceProvider serviceProvider)
+ : base()
+ {
+ Context = context;
+ this.serviceProvider = serviceProvider;
+ }
+
+ private void Format(T codeObject) where T : SqlCodeObject
+ {
+ ASTNodeFormatter f = GetFormatter(codeObject);
+ f.Format();
+ }
+
+ private ASTNodeFormatter GetFormatter(T codeObject) where T:SqlCodeObject
+ {
+ Type astType = typeof(T);
+ ASTNodeFormatter formatter;
+
+ var formatterFactory = serviceProvider.GetServices().FirstOrDefault(f => astType.Equals(f.SupportedNodeType));
+ if (formatterFactory != null)
+ {
+ formatter = formatterFactory.Create(this, codeObject);
+ }
+ else
+ {
+ formatter = new NoOpFormatter(this, codeObject);
+ }
+
+ return formatter;
+ }
+
+ public FormatContext Context { get; private set; }
+
+ public void VerifyFormat()
+ {
+ ParseResult result = Parser.Parse(Context.FormattedSql);
+ SqlScript newScript = result.Script;
+ VerifyTokenStreamsOnlyDifferByWhitespace(Context.Script, newScript);
+ }
+
+ internal static bool IsTokenWhitespaceOrComma(SqlScript script, int tokenIndex)
+ {
+ int tokenId = script.TokenManager.TokenList[tokenIndex].TokenId;
+ return script.TokenManager.IsTokenWhitespace(tokenId) || (tokenId == 44);
+ }
+
+ internal static bool IsTokenWhitespaceOrComment(SqlScript script, int tokenIndex)
+ {
+ int tokenId = script.TokenManager.TokenList[tokenIndex].TokenId;
+
+ return script.TokenManager.IsTokenWhitespace(tokenId) || script.TokenManager.IsTokenComment(tokenId);
+ }
+
+ ///
+ /// Checks that the token streams of two SqlScript objects differ only by whitespace tokens or
+ /// by the relative positioning of commas and comments. The important rule enforced is that there are
+ /// no changes in relative positioning which involve tokens other than commas, comments or whitespaces.
+ ///
+ /// SQL script containing the first token stream.
+ /// SQL script containing the second token stream.
+ public static void VerifyTokenStreamsOnlyDifferByWhitespace(SqlScript script1, SqlScript script2)
+ {
+ // We break down the relative positioning problem into assuring that the token streams have identical ids
+ // both when we ignore whitespaces and commas as well as when we ignore whitespaces and comments
+ VerifyTokenStreamsOnlyDifferBy(script1, script2, IsTokenWhitespaceOrComma);
+ VerifyTokenStreamsOnlyDifferBy(script1, script2, IsTokenWhitespaceOrComment);
+ }
+
+ internal delegate bool IgnoreToken(SqlScript script, int tokenIndex);
+
+ public static void VerifyTokenStreamsOnlyDifferBy(SqlScript script1, SqlScript script2, IgnoreToken ignoreToken )
+ {
+ int t1 = 0;
+ int t2 = 0;
+
+ while (t1 < script1.TokenManager.Count && t2 < script2.TokenManager.Count)
+ {
+ // advance t1 until it is pointing at a non-whitespace token
+ while (t1 < script1.TokenManager.Count && ignoreToken(script1, t1))
+ {
+ ++t1;
+ }
+
+ // advance t2 until it is pointing at a non-whitespace token
+ while (t2 < script2.TokenManager.Count && ignoreToken(script2, t2))
+ {
+ ++t2;
+ }
+
+ if (t1 >= script1.TokenManager.Count || t2 >= script2.TokenManager.Count)
+ {
+ break;
+ }
+
+
+ //
+ // TODO: need special logic here to deal with the placement of commas
+ //
+
+ // verify the tokens are equal
+ if (script1.TokenManager.TokenList[t1].TokenId != script2.TokenManager.TokenList[t2].TokenId)
+ {
+ string msg = "The comparison failed between tokens at {0} & {1}. The token IDs were {2} and {3} respectively. Script1 = {4}. Script2 = {5}";
+ msg = string.Format(CultureInfo.CurrentCulture, msg, t1, t2, script1.TokenManager.TokenList[t1].TokenId, script2.TokenManager.TokenList[t2].TokenId, script1.Sql, script2.Sql);
+ throw new FormatFailedException(msg);
+ }
+
+ ++t1;
+ ++t2;
+ }
+
+ // one of the streams is exhausted, verify that the only tokens left in the other stream are whitespace tokens
+ Debug.Assert(t1 >= script1.TokenManager.Count || t2 >= script2.TokenManager.Count, "expected to be at the end of one of the token's streams");
+ int t = t1;
+ SqlScript s = script1;
+ if (t2 < script2.TokenManager.Count)
+ {
+ Debug.Assert(t1 >= script1.TokenManager.Count, "expected to be at end of script1's token stream");
+ t = t2;
+ s = script2;
+ }
+
+ while (t < s.TokenManager.Count)
+ {
+ if (!ignoreToken(s, t))
+ {
+ string msg = "Unexpected non-whitespace token at index {0}, token ID {1}";
+ msg = string.Format(CultureInfo.CurrentCulture, msg, t, s.TokenManager.TokenList[t].TokenId);
+ throw new FormatFailedException(msg);
+ }
+ }
+ }
+
+
+
+
+ }
+
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/FormatterVisitor_SqlCodeObjectVisitor.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/FormatterVisitor_SqlCodeObjectVisitor.cs
new file mode 100644
index 00000000..7c406d00
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/FormatterVisitor_SqlCodeObjectVisitor.cs
@@ -0,0 +1,300 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System.Diagnostics.CodeAnalysis;
+using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+ // Any new SqlCodeObject types should have a Visit method added, and this class should then be updated with a matching
+ // Visit implementation that routes to the Format method.
+ [SuppressMessage("Microsoft.Maintainability","CA1506:AvoidExcessiveClassCoupling")]
+ partial class FormatterVisitor : SqlCodeObjectVisitor
+ {
+ public override void Visit(SqlAggregateFunctionCallExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlAllAnyComparisonBooleanExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlAllowPageLocksIndexOption codeObject) { Format(codeObject); }
+ public override void Visit(SqlAllowRowLocksIndexOption codeObject) { Format(codeObject); }
+ public override void Visit(SqlAlterFunctionStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlAlterProcedureStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlAlterTriggerStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlAlterViewStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlAssignment codeObject) { Format(codeObject); }
+ public override void Visit(SqlBackupCertificateStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlBackupDatabaseStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlBackupLogStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlBackupMasterKeyStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlBackupServiceMasterKeyStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlBackupTableStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlBatch codeObject) { Format(codeObject); }
+ public override void Visit(SqlBetweenBooleanExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlBinaryBooleanExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlBinaryFilterExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlBinaryQueryExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlBinaryScalarExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlBooleanExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlBooleanFilterExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlBreakStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlBuiltinScalarFunctionCallExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlCastExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlChangeTrackingContext codeObject) { Format(codeObject); }
+ public override void Visit(SqlCheckConstraint codeObject) { Format(codeObject); }
+ public override void Visit(SqlClrAssemblySpecifier codeObject) { Format(codeObject); }
+ public override void Visit(SqlClrClassSpecifier codeObject) { Format(codeObject); }
+ public override void Visit(SqlClrFunctionBodyDefinition codeObject) { Format(codeObject); }
+ public override void Visit(SqlClrMethodSpecifier codeObject) { Format(codeObject); }
+ public override void Visit(SqlCollateScalarExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlCollation codeObject) { Format(codeObject); }
+ public override void Visit(SqlColumnAssignment codeObject) { Format(codeObject); }
+ public override void Visit(SqlColumnDefinition codeObject) { Format(codeObject); }
+ public override void Visit(SqlColumnIdentity codeObject) { Format(codeObject); }
+ public override void Visit(SqlColumnRefExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlCommentStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlCommonTableExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlComparisonBooleanExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlCompoundStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlCompressionPartitionRange codeObject) { Format(codeObject); }
+ public override void Visit(SqlComputedColumnDefinition codeObject) { Format(codeObject); }
+ public override void Visit(SqlConditionClause codeObject) { Format(codeObject); }
+ public override void Visit(SqlConstraint codeObject) { Format(codeObject); }
+ public override void Visit(SqlContinueStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlConvertExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlCreateFunctionStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlCreateIndexStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlCreateLoginFromAsymKeyStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlCreateLoginFromCertificateStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlCreateLoginFromWindowsStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlCreateLoginWithPasswordStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlCreateProcedureStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlCreateRoleStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlCreateSchemaStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlCreateSynonymStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlCreateTableStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlCreateTriggerStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlCreateUserDefinedDataTypeStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlCreateUserDefinedTableTypeStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlCreateUserDefinedTypeStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlCreateUserFromAsymKeyStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlCreateUserFromCertificateStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlCreateUserFromLoginStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlCreateUserOption codeObject) { Format(codeObject); }
+ public override void Visit(SqlCreateUserStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlCreateUserWithImplicitAuthenticationStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlCreateUserWithoutLoginStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlCreateViewStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlCubeGroupByItem codeObject) { Format(codeObject); }
+ public override void Visit(SqlCursorDeclareStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlCursorOption codeObject) { Format(codeObject); }
+ public override void Visit(SqlCursorVariableAssignment codeObject) { Format(codeObject); }
+ public override void Visit(SqlCursorVariableRefExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlDataCompressionIndexOption codeObject) { Format(codeObject); }
+ public override void Visit(SqlDataType codeObject) { Format(codeObject); }
+ public override void Visit(SqlDataTypeSpecification codeObject) { Format(codeObject); }
+ public override void Visit(SqlDBCCStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlDdlTriggerDefinition codeObject) { Format(codeObject); }
+ public override void Visit(SqlDefaultConstraint codeObject) { Format(codeObject); }
+ public override void Visit(SqlDefaultValuesInsertMergeActionSource codeObject) { Format(codeObject); }
+ public override void Visit(SqlDefaultValuesInsertSource codeObject) { Format(codeObject); }
+ public override void Visit(SqlDeleteMergeAction codeObject) { Format(codeObject); }
+ public override void Visit(SqlDeleteSpecification codeObject) { Format(codeObject); }
+ public override void Visit(SqlDeleteStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlDenyStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlDerivedTableExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlDmlSpecificationTableSource codeObject) { Format(codeObject); }
+ public override void Visit(SqlDmlTriggerDefinition codeObject) { Format(codeObject); }
+ public override void Visit(SqlDropAggregateStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlDropDatabaseStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlDropDefaultStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlDropExistingIndexOption codeObject) { Format(codeObject); }
+ public override void Visit(SqlDropFunctionStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlDropLoginStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlDropProcedureStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlDropRuleStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlDropSchemaStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlDropSynonymStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlDropTableStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlDropTriggerStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlDropTypeStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlDropUserStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlDropViewStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlExecuteAsClause codeObject) { Format(codeObject); }
+ public override void Visit(SqlExecuteModuleStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlExistsBooleanExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlFillFactorIndexOption codeObject) { Format(codeObject); }
+ public override void Visit(SqlFilterClause codeObject) { Format(codeObject); }
+ public override void Visit(SqlForBrowseClause codeObject) { Format(codeObject); }
+ public override void Visit(SqlForeignKeyConstraint codeObject) { Format(codeObject); }
+ public override void Visit(SqlForXmlAutoClause codeObject) { Format(codeObject); }
+ public override void Visit(SqlForXmlClause codeObject) { Format(codeObject); }
+ public override void Visit(SqlForXmlDirective codeObject) { Format(codeObject); }
+ public override void Visit(SqlForXmlExplicitClause codeObject) { Format(codeObject); }
+ public override void Visit(SqlForXmlPathClause codeObject) { Format(codeObject); }
+ public override void Visit(SqlForXmlRawClause codeObject) { Format(codeObject); }
+ public override void Visit(SqlFromClause codeObject) { Format(codeObject); }
+ public override void Visit(SqlFullTextBooleanExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlFullTextColumn codeObject) { Format(codeObject); }
+ public override void Visit(SqlFunctionDefinition codeObject) { Format(codeObject); }
+ public override void Visit(SqlGlobalScalarVariableRefExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlGrandTotalGroupByItem codeObject) { Format(codeObject); }
+ public override void Visit(SqlGrandTotalGroupingSet codeObject) { Format(codeObject); }
+ public override void Visit(SqlGrantStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlGroupByClause codeObject) { Format(codeObject); }
+ public override void Visit(SqlGroupBySets codeObject) { Format(codeObject); }
+ public override void Visit(SqlGroupingSetItemsCollection codeObject) { Format(codeObject); }
+ public override void Visit(SqlHavingClause codeObject) { Format(codeObject); }
+ public override void Visit(SqlIdentifier codeObject) { Format(codeObject); }
+ public override void Visit(SqlIdentityFunctionCallExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlIfElseStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlIgnoreDupKeyIndexOption codeObject) { Format(codeObject); }
+ public override void Visit(SqlInBooleanExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlInBooleanExpressionCollectionValue codeObject) { Format(codeObject); }
+ public override void Visit(SqlInBooleanExpressionQueryValue codeObject) { Format(codeObject); }
+ public override void Visit(SqlIndexedColumn codeObject) { Format(codeObject); }
+ public override void Visit(SqlIndexHint codeObject) { Format(codeObject); }
+ public override void Visit(SqlIndexOption codeObject) { Format(codeObject); }
+ public override void Visit(SqlInlineFunctionBodyDefinition codeObject) { Format(codeObject); }
+ public override void Visit(SqlInlineTableRelationalFunctionDefinition codeObject) { Format(codeObject); }
+ public override void Visit(SqlInlineTableVariableDeclaration codeObject) { Format(codeObject); }
+ public override void Visit(SqlInlineTableVariableDeclareStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlInsertMergeAction codeObject) { Format(codeObject); }
+ public override void Visit(SqlInsertSource codeObject) { Format(codeObject); }
+ public override void Visit(SqlInsertSpecification codeObject) { Format(codeObject); }
+ public override void Visit(SqlInsertStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlIntoClause codeObject) { Format(codeObject); }
+ public override void Visit(SqlIsNullBooleanExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlLargeDataStorageInformation codeObject) { Format(codeObject); }
+ public override void Visit(SqlLikeBooleanExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlLiteralExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlLoginPassword codeObject) { Format(codeObject); }
+ public override void Visit(SqlMaxDegreeOfParallelismIndexOption codeObject) { Format(codeObject); }
+ public override void Visit(SqlMergeActionClause codeObject) { Format(codeObject); }
+ public override void Visit(SqlMergeSpecification codeObject) { Format(codeObject); }
+ public override void Visit(SqlMergeStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlModuleArgument codeObject) { Format(codeObject); }
+ public override void Visit(SqlModuleCalledOnNullInputOption codeObject) { Format(codeObject); }
+ public override void Visit(SqlModuleEncryptionOption codeObject) { Format(codeObject); }
+ public override void Visit(SqlModuleExecuteAsOption codeObject) { Format(codeObject); }
+ public override void Visit(SqlModuleOption codeObject) { Format(codeObject); }
+ public override void Visit(SqlModuleRecompileOption codeObject) { Format(codeObject); }
+ public override void Visit(SqlModuleReturnsNullOnNullInputOption codeObject) { Format(codeObject); }
+ public override void Visit(SqlModuleSchemaBindingOption codeObject) { Format(codeObject); }
+ public override void Visit(SqlModuleViewMetadataOption codeObject) { Format(codeObject); }
+ public override void Visit(SqlMultistatementFunctionBodyDefinition codeObject) { Format(codeObject); }
+ public override void Visit(SqlMultistatementTableRelationalFunctionDefinition codeObject) { Format(codeObject); }
+ public override void Visit(SqlNotBooleanExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlObjectIdentifier codeObject) { Format(codeObject); }
+ public override void Visit(SqlObjectReference codeObject) { Format(codeObject); }
+ public override void Visit(SqlOnlineIndexOption codeObject) { Format(codeObject); }
+ public override void Visit(SqlOrderByClause codeObject) { Format(codeObject); }
+ public override void Visit(SqlOrderByItem codeObject) { Format(codeObject); }
+ public override void Visit(SqlOutputClause codeObject) { Format(codeObject); }
+ public override void Visit(SqlOutputIntoClause codeObject) { Format(codeObject); }
+ public override void Visit(SqlPadIndexOption codeObject) { Format(codeObject); }
+ public override void Visit(SqlParameterDeclaration codeObject) { Format(codeObject); }
+ public override void Visit(SqlPivotClause codeObject) { Format(codeObject); }
+ public override void Visit(SqlPivotTableExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlPrimaryKeyConstraint codeObject) { Format(codeObject); }
+ public override void Visit(SqlProcedureDefinition codeObject) { Format(codeObject); }
+ public override void Visit(SqlQualifiedJoinTableExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlQueryExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlQuerySpecification codeObject) { Format(codeObject); }
+ public override void Visit(SqlQueryWithClause codeObject) { Format(codeObject); }
+ public override void Visit(SqlRestoreDatabaseStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlRestoreInformationStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlRestoreLogStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlRestoreMasterKeyStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlRestoreServiceMasterKeyStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlRestoreTableStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlReturnStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlRevokeStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlRollupGroupByItem codeObject) { Format(codeObject); }
+ public override void Visit(SqlRowConstructorExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlScalarClrFunctionDefinition codeObject) { Format(codeObject); }
+ public override void Visit(SqlScalarExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlScalarFunctionReturnType codeObject) { Format(codeObject); }
+ public override void Visit(SqlScalarRefExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlScalarRelationalFunctionDefinition codeObject) { Format(codeObject); }
+ public override void Visit(SqlScalarSubQueryExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlScalarVariableAssignment codeObject) { Format(codeObject); }
+ public override void Visit(SqlScalarVariableRefExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlScript codeObject) { Format(codeObject); }
+ public override void Visit(SqlSearchedCaseExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlSearchedWhenClause codeObject) { Format(codeObject); }
+ public override void Visit(SqlSelectClause codeObject) { Format(codeObject); }
+ public override void Visit(SqlSelectIntoClause codeObject) { Format(codeObject); }
+ public override void Visit(SqlSelectScalarExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlSelectSpecification codeObject) { Format(codeObject); }
+ public override void Visit(SqlSelectSpecificationInsertSource codeObject) { Format(codeObject); }
+ public override void Visit(SqlSelectStarExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlSelectStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlSelectVariableAssignmentExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlSetAssignmentStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlSetClause codeObject) { Format(codeObject); }
+ public override void Visit(SqlSetStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlSimpleCaseExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlSimpleGroupByItem codeObject) { Format(codeObject); }
+ public override void Visit(SqlSimpleOrderByClause codeObject) { Format(codeObject); }
+ public override void Visit(SqlSimpleOrderByItem codeObject) { Format(codeObject); }
+ public override void Visit(SqlSimpleWhenClause codeObject) { Format(codeObject); }
+ public override void Visit(SqlSortedDataIndexOption codeObject) { Format(codeObject); }
+ public override void Visit(SqlSortedDataReorgIndexOption codeObject) { Format(codeObject); }
+ public override void Visit(SqlSortInTempDbIndexOption codeObject) { Format(codeObject); }
+ public override void Visit(SqlStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlStatisticsNoRecomputeIndexOption codeObject) { Format(codeObject); }
+ public override void Visit(SqlStatisticsOnlyIndexOption codeObject) { Format(codeObject); }
+ public override void Visit(SqlStorageSpecification codeObject) { Format(codeObject); }
+ public override void Visit(SqlTableClrFunctionDefinition codeObject) { Format(codeObject); }
+ public override void Visit(SqlTableConstructorExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlTableConstructorInsertSource codeObject) { Format(codeObject); }
+ public override void Visit(SqlTableDefinition codeObject) { Format(codeObject); }
+ public override void Visit(SqlTableExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlTableFunctionReturnType codeObject) { Format(codeObject); }
+ public override void Visit(SqlTableHint codeObject) { Format(codeObject); }
+ public override void Visit(SqlTableRefExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlTableUdtInstanceMethodExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlTableValuedFunctionRefExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlTableVariableRefExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlTargetTableExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlTopSpecification codeObject) { Format(codeObject); }
+ public override void Visit(SqlTriggerAction codeObject) { Format(codeObject); }
+ public override void Visit(SqlTriggerDefinition codeObject) { Format(codeObject); }
+ public override void Visit(SqlTriggerEvent codeObject) { Format(codeObject); }
+ public override void Visit(SqlTryCatchStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlUdtInstanceDataMemberExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlUdtInstanceMethodExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlUdtStaticDataMemberExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlUdtStaticMethodExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlUnaryScalarExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlUniqueConstraint codeObject) { Format(codeObject); }
+ public override void Visit(SqlUnpivotClause codeObject) { Format(codeObject); }
+ public override void Visit(SqlUnpivotTableExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlUnqualifiedJoinTableExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlUpdateBooleanExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlUpdateMergeAction codeObject) { Format(codeObject); }
+ public override void Visit(SqlUpdateSpecification codeObject) { Format(codeObject); }
+ public override void Visit(SqlUpdateStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlUserDefinedScalarFunctionCallExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlUseStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlValuesInsertMergeActionSource codeObject) { Format(codeObject); }
+ public override void Visit(SqlVariableColumnAssignment codeObject) { Format(codeObject); }
+ public override void Visit(SqlVariableDeclaration codeObject) { Format(codeObject); }
+ public override void Visit(SqlVariableDeclareStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlViewDefinition codeObject) { Format(codeObject); }
+ public override void Visit(SqlWhereClause codeObject) { Format(codeObject); }
+ public override void Visit(SqlWhileStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlXmlNamespacesDeclaration codeObject) { Format(codeObject); }
+ public override void Visit(SqlAtTimeZoneExpression codeObject) { Format(codeObject); }
+ public override void Visit(SqlBucketCountIndexOption codeObject) { Format(codeObject); }
+ public override void Visit(SqlCompressionDelayIndexOption codeObject) { Format(codeObject); }
+ public override void Visit(SqlCreateUserFromExternalProviderStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlDropSecurityPolicyStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlDropSequenceStatement codeObject) { Format(codeObject); }
+ public override void Visit(SqlInlineIndexConstraint codeObject) { Format(codeObject); }
+ public override void Visit(SqlModuleNativeCompilationOption codeObject) { Format(codeObject); }
+ public override void Visit(SqlStatisticsIncrementalIndexOption codeObject) { Format(codeObject); }
+ public override void Visit(SqlTemporalPeriodDefinition codeObject) { Format(codeObject); }
+ }
+
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/NoOpFormatter.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/NoOpFormatter.cs
new file mode 100644
index 00000000..0b3f319d
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/NoOpFormatter.cs
@@ -0,0 +1,20 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.Composition;
+using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+ internal class NoOpFormatter : ASTNodeFormatterT
+ {
+ public NoOpFormatter(FormatterVisitor visitor, SqlCodeObject codeObject)
+ : base(visitor, codeObject)
+ {
+
+ }
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/PaddedSpaceSeparatedListFormatter.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/PaddedSpaceSeparatedListFormatter.cs
new file mode 100644
index 00000000..1677a4f7
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/PaddedSpaceSeparatedListFormatter.cs
@@ -0,0 +1,74 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Composition;
+using System.Diagnostics;
+using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
+using Microsoft.SqlTools.ServiceLayer.Utility;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+ internal class PaddedSpaceSeparatedListFormatter : SpaceSeparatedListFormatter
+ {
+ private List ColumnSpacingDefinitions { get; set; }
+ private int nextColumn = 0;
+
+
+ internal PaddedSpaceSeparatedListFormatter(FormatterVisitor visitor, SqlCodeObject codeObject, List spacingDefinitions, bool incrementIndentLevelOnPrefixRegion)
+ : base(visitor, codeObject, incrementIndentLevelOnPrefixRegion)
+ {
+ ColumnSpacingDefinitions = spacingDefinitions;
+ }
+
+ internal override void ProcessInterChildRegion(SqlCodeObject previousChild, SqlCodeObject nextChild)
+ {
+ Validate.IsNotNull(nameof(previousChild), previousChild);
+ Validate.IsNotNull(nameof(nextChild), nextChild);
+
+ // first, figure out how big to make the pad
+ int padLength = 1;
+ if (ColumnSpacingDefinitions != null && nextColumn < ColumnSpacingDefinitions.Count)
+ {
+ if (previousChild.GetType() == ColumnSpacingDefinitions[nextColumn].PreviousType &&
+ (ColumnSpacingDefinitions[nextColumn].NextType == null || nextChild.GetType() == ColumnSpacingDefinitions[nextColumn].NextType))
+ {
+ string text = previousChild.TokenManager.GetText(previousChild.Position.startTokenNumber, previousChild.Position.endTokenNumber);
+ int stringLength = text.Length;
+ padLength = ColumnSpacingDefinitions[nextColumn].PaddedLength - stringLength;
+
+ Debug.Assert(padLength > 0, "unexpected value for Pad Length");
+ padLength = Math.Max(padLength, 1);
+
+ ++nextColumn;
+ }
+ }
+ // next, normalize the tokens
+ int start = previousChild.Position.endTokenNumber;
+ int end = nextChild.Position.startTokenNumber;
+
+ for (int i = start; i < end; i++)
+ {
+ SimpleProcessToken(i, (string original, FormatContext context) => { return FormatterUtilities.NormalizeNewLinesOrCondenseToNSpaces(original, context, padLength); });
+ }
+
+ }
+
+ internal class ColumnSpacingFormatDefinition
+ {
+ internal ColumnSpacingFormatDefinition(Type previousType, Type nextType, int padLength)
+ {
+ PreviousType = previousType;
+ NextType = nextType;
+ PaddedLength = padLength;
+ }
+
+ internal Type PreviousType { get; private set; }
+ internal Type NextType { get; private set; }
+ internal int PaddedLength { get; private set; }
+ }
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/Replacement.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/Replacement.cs
new file mode 100644
index 00000000..79f50623
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/Replacement.cs
@@ -0,0 +1,85 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+ ///
+ /// Describes a string editing action which requests that a particular
+ /// substring found at a given location be replaced by another string
+ ///
+ public class Replacement
+ {
+ public Replacement(int startIndex, string oldValue, string newValue)
+ {
+ StartIndex = startIndex;
+ OldValue = oldValue;
+ NewValue = newValue;
+ }
+
+ public int StartIndex { get; private set; }
+ public string OldValue { get; private set; }
+ public string NewValue { get; private set; }
+
+ public int EndIndex
+ {
+ get
+ {
+ return StartIndex + OldValue.Length;
+ }
+ }
+
+ ///
+ /// Checks whether the replacement will have any effect.
+ ///
+ ///
+ internal bool IsIdentity()
+ {
+ return OldValue.Equals(NewValue);
+ }
+
+ ///
+ /// Reports the relative change in text length (number of characters)
+ /// between the initial and the formatted code introduced by this
+ /// particular replacement.
+ ///
+ public int InducedOffset
+ {
+ get
+ {
+ return NewValue.Length - OldValue.Length;
+ }
+ }
+
+ ///
+ /// Replacements will often change the length of the code, making
+ /// indexing relative to the original text ambiguous. The CumulatedOffset
+ /// can be used to adjust the relative indexing between the original and the
+ /// edited text as perceived at the start of this replacement and help
+ /// compensate for the difference.
+ ///
+ public int CumulativeOffset { set; private get; }
+
+ ///
+ /// A delegate responsible for applying the replacement. Each application assumes
+ /// nothing about other replacements which might have taken place before or which
+ /// might take place after the current one.
+ ///
+ /// Position of the begining of the replacement relative to the beginig of the character stream.
+ /// The number of consecutive characters which are to be replaced.
+ /// The characters which are to replace the old ones. Note that the length of this string might be greater or smaller than the number of replaced characters.
+ public delegate void OnReplace(int pos, int len, string with);
+
+ ///
+ /// Applies a replacement action according to a given strategy defined by the delegate procedure.
+ ///
+ /// This delegate function implements the strategy for applying the replacement.
+ public void Apply(OnReplace replace)
+ {
+ replace(StartIndex + CumulativeOffset, OldValue.Length, NewValue);
+ }
+
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/ReplacementQueue.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/ReplacementQueue.cs
new file mode 100644
index 00000000..e4acebab
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/ReplacementQueue.cs
@@ -0,0 +1,48 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System.Collections.Generic;
+using System.Collections;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+ internal class ReplacementQueue : IEnumerable
+ {
+ internal int offset = 0;
+
+ private Queue Replacements { get; set; }
+
+ public ReplacementQueue()
+ {
+ Replacements = new Queue();
+ }
+
+ ///
+ /// Adds a replace action to the queue and adjusts its absolute
+ /// offset to reflect the global indexing after applying the replacements
+ /// in the queue.
+ ///
+ /// NOTE: The method assumes the replacements occur in front-to-back order
+ /// and that they never overlap.
+ ///
+ ///
+ /// The latest replacement to be added to the queue.
+ public void Add(Replacement r)
+ {
+ if (!r.IsIdentity())
+ {
+ r.CumulativeOffset = offset;
+ Replacements.Enqueue(r);
+ offset += r.InducedOffset;
+ }
+ }
+
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return Replacements.GetEnumerator();
+ }
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SpaceSeparatedListFormatter.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SpaceSeparatedListFormatter.cs
new file mode 100644
index 00000000..56fcbf67
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SpaceSeparatedListFormatter.cs
@@ -0,0 +1,37 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System.Composition;
+using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+ internal class SpaceSeparatedListFormatter : WhiteSpaceSeparatedListFormatter
+ {
+ internal SpaceSeparatedListFormatter(FormatterVisitor visitor, SqlCodeObject codeObject, bool incrementIndentLevelOnPrefixRegion)
+ : base(visitor, codeObject, incrementIndentLevelOnPrefixRegion)
+ {
+ }
+
+ internal override string FormatWhitespace(string original, FormatContext context)
+ {
+ return FormatterUtilities.NormalizeNewLinesOrCondenseToOneSpace(original, context);
+ }
+
+ }
+
+ internal class NewLineSeparatedListFormatter : WhiteSpaceSeparatedListFormatter
+ {
+ public NewLineSeparatedListFormatter(FormatterVisitor visitor, SqlCodeObject codeObject, bool incrementIndentLevelOnPrefixRegion)
+ : base(visitor, codeObject, incrementIndentLevelOnPrefixRegion)
+ {
+ }
+
+ internal override string FormatWhitespace(string original, FormatContext context)
+ {
+ return FormatterUtilities.NormalizeNewLinesEnsureOneNewLineMinimum(original, context);
+ }
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlBatchFormatter.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlBatchFormatter.cs
new file mode 100644
index 00000000..93404982
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlBatchFormatter.cs
@@ -0,0 +1,36 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System.Composition;
+using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+ [Export(typeof(ASTNodeFormatterFactory))]
+ internal class SqlBatchFormatterFactory : ASTNodeFormatterFactoryT
+ {
+ protected override ASTNodeFormatter DoCreate(FormatterVisitor visitor, SqlBatch codeObject)
+ {
+ return new SqlBatchFormatter(visitor, codeObject);
+ }
+ }
+
+ class SqlBatchFormatter : NewLineSeparatedListFormatter
+ {
+ public SqlBatchFormatter(FormatterVisitor visitor, SqlCodeObject codeObject)
+ :base(visitor, codeObject, false)
+ {
+ }
+
+ internal override void ProcessPrefixRegion(int startTokenNumber, int firstChildStartTokenNumber)
+ {
+ for (int i = startTokenNumber; i < firstChildStartTokenNumber; i++)
+ {
+ SimpleProcessToken(i, FormatterUtilities.NormalizeNewLinesEnsureOneNewLineMinimum);
+ }
+ }
+
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlBinaryBooleanExpressionFormatter.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlBinaryBooleanExpressionFormatter.cs
new file mode 100644
index 00000000..d6258352
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlBinaryBooleanExpressionFormatter.cs
@@ -0,0 +1,58 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.Composition;
+using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
+using Microsoft.SqlTools.ServiceLayer.Utility;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+
+ [Export(typeof(ASTNodeFormatterFactory))]
+ internal class SqlBinaryBooleanExpressionFormatterFactory : ASTNodeFormatterFactoryT
+ {
+ protected override ASTNodeFormatter DoCreate(FormatterVisitor visitor, SqlBinaryBooleanExpression codeObject)
+ {
+ return new SqlBinaryBooleanExpressionFormatter(visitor, codeObject);
+ }
+ }
+
+ internal class SqlBinaryBooleanExpressionFormatter : ASTNodeFormatterT
+ {
+ SpaceSeparatedListFormatter SpaceSeparatedListFormatter { get; set; }
+
+ internal SqlBinaryBooleanExpressionFormatter(FormatterVisitor visitor, SqlBinaryBooleanExpression codeObject)
+ : base(visitor, codeObject)
+ {
+ SpaceSeparatedListFormatter = new SpaceSeparatedListFormatter(visitor, codeObject, true);
+ }
+
+ internal override void ProcessChild(SqlCodeObject child)
+ {
+ Validate.IsNotNull(nameof(child), child);
+ SpaceSeparatedListFormatter.ProcessChild(child);
+ }
+
+ internal override void ProcessPrefixRegion(int startTokenNumber, int firstChildStartTokenNumber)
+ {
+ SpaceSeparatedListFormatter.ProcessPrefixRegion(startTokenNumber, firstChildStartTokenNumber);
+ }
+
+ internal override void ProcessSuffixRegion(int lastChildEndTokenNumber, int endTokenNumber)
+ {
+ SpaceSeparatedListFormatter.ProcessSuffixRegion(lastChildEndTokenNumber, endTokenNumber);
+ }
+
+ internal override void ProcessInterChildRegion(SqlCodeObject previousChild, SqlCodeObject nextChild)
+ {
+ Validate.IsNotNull(nameof(previousChild), previousChild);
+ Validate.IsNotNull(nameof(nextChild), nextChild);
+
+ SpaceSeparatedListFormatter.ProcessInterChildRegion(previousChild, nextChild);
+ }
+
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlBinaryQueryExpressionFormatter.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlBinaryQueryExpressionFormatter.cs
new file mode 100644
index 00000000..f48c6f5e
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlBinaryQueryExpressionFormatter.cs
@@ -0,0 +1,216 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.Composition;
+using System.Diagnostics;
+using Babel.ParserGenerator;
+using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
+using Microsoft.SqlTools.ServiceLayer.Utility;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+
+ [Export(typeof(ASTNodeFormatterFactory))]
+ internal class SqlBinaryQueryExpressionFormatterFactory : ASTNodeFormatterFactoryT
+ {
+ protected override ASTNodeFormatter DoCreate(FormatterVisitor visitor, SqlBinaryQueryExpression codeObject)
+ {
+ return new SqlBinaryQueryExpressionFormatter(visitor, codeObject);
+ }
+ }
+
+ class SqlBinaryQueryExpressionFormatter : ASTNodeFormatterT
+ {
+
+ internal SqlBinaryQueryExpressionFormatter(FormatterVisitor visitor, SqlBinaryQueryExpression codeObject)
+ : base(visitor, codeObject)
+ {
+ }
+
+ internal override void ProcessPrefixRegion(int startTokenNumber, int firstChildStartTokenNumber)
+ {
+ if (CodeObject.Left is SqlQuerySpecification)
+ {
+ IncrementIndentLevel();
+ }
+
+ // if the start token is not a whitespace, we need to insert the indent string
+ TokenData td = GetTokenData(startTokenNumber);
+ if (!IsTokenWhitespace(td))
+ {
+ string newWhiteSpace = GetIndentString();
+ AddReplacement(new Replacement(td.StartIndex, string.Empty, newWhiteSpace));
+ }
+
+ for (int i = startTokenNumber; i < firstChildStartTokenNumber; i++)
+ {
+ SimpleProcessToken(i, FormatterUtilities.NormalizeNewLinesEnsureOneNewLineMinimum);
+ }
+
+ if (firstChildStartTokenNumber - 1 >= startTokenNumber)
+ {
+ IndentChild(firstChildStartTokenNumber);
+ }
+ }
+
+ private void IndentChild(int firstChildStartTokenNumber)
+ {
+ string newWhiteSpace = GetIndentString();
+
+ if (!IsTokenWhitespace(PreviousTokenData(firstChildStartTokenNumber)))
+ {
+ newWhiteSpace = Environment.NewLine + newWhiteSpace;
+ }
+
+ TokenData td = GetTokenData(firstChildStartTokenNumber);
+ AddReplacement(td.StartIndex, string.Empty, newWhiteSpace);
+ }
+
+ internal override void ProcessInterChildRegion(SqlCodeObject previousChild, SqlCodeObject nextChild)
+ {
+ Validate.IsNotNull(nameof(previousChild), previousChild);
+ Validate.IsNotNull(nameof(nextChild), nextChild);
+
+ // find the potition of the operator token:
+ // operatorTokenNumber
+ #region FindOperator
+
+ // look for the expression type based on the operator and determine its type and position
+ int binaryOperatorTokenID = FormatterTokens.LAST_TOKEN;
+ bool foundOperator = false;
+ int operatorTokenNumber = nextChild.Position.startTokenNumber;
+ for (int i = previousChild.Position.endTokenNumber; !foundOperator && i < nextChild.Position.startTokenNumber; i++)
+ {
+ TokenData td = GetTokenData(i);
+ if ( td.TokenId == FormatterTokens.TOKEN_UNION ||
+ td.TokenId == FormatterTokens.TOKEN_INTERSECT ||
+ td.TokenId == FormatterTokens.TOKEN_EXCEPT )
+ {
+ foundOperator = true;
+ binaryOperatorTokenID = td.TokenId;
+ operatorTokenNumber = i;
+ }
+ }
+
+ // check that we actually found one
+ Debug.Assert(foundOperator);
+ // if we found the operator, it means we also know its position number.
+ Debug.Assert(operatorTokenNumber >= previousChild.Position.endTokenNumber);
+ Debug.Assert(operatorTokenNumber < nextChild.Position.startTokenNumber);
+ // and we know its type
+ Debug.Assert(
+ binaryOperatorTokenID == FormatterTokens.TOKEN_UNION ||
+ binaryOperatorTokenID == FormatterTokens.TOKEN_INTERSECT ||
+ binaryOperatorTokenID == FormatterTokens.TOKEN_EXCEPT);
+ #endregion
+
+ // process the tokens before the operator:
+ // [lastChild.Position.endTokenNumber, operatorTokenNumber)
+ #region BeforeOperator
+
+ // If the first token is not a whitespace and it, we need to insert a newline in front
+ TokenData endTokenData = GetTokenData(previousChild.Position.endTokenNumber);
+ if (!IsTokenWhitespace(endTokenData))
+ {
+ AddIndentedNewLineReplacement(endTokenData.StartIndex);
+ }
+
+ for (int i = previousChild.Position.endTokenNumber; i < operatorTokenNumber - 1; i++)
+ {
+ SimpleProcessToken(i, FormatterUtilities.NormalizeNewLinesEnsureOneNewLineMinimum);
+ }
+
+ if (CodeObject.Left is SqlQuerySpecification)
+ {
+ DecrementIndentLevel();
+ }
+
+ if (operatorTokenNumber - 1 >= previousChild.Position.endTokenNumber)
+ {
+ SimpleProcessToken(operatorTokenNumber - 1, FormatterUtilities.NormalizeNewLinesEnsureOneNewLineMinimum);
+ if (!IsTokenWhitespace(PreviousTokenData(operatorTokenNumber)))
+ {
+ TokenData td = GetTokenData(operatorTokenNumber);
+ AddIndentedNewLineReplacement(td.StartIndex);
+ }
+ }
+
+ #endregion // BeforeOperator
+
+ // process the operator:
+ // [operatorTokenNumber, firstTokenAfterOperator)
+ #region Operator
+
+ // since the operator might contain more than one token, we will keep track of its end
+ int firstTokenAfterOperator = operatorTokenNumber + 1;
+
+ // find where the operator ends
+ if (binaryOperatorTokenID == FormatterTokens.TOKEN_UNION)
+ {
+ // the union operator may or may not be followed by the "ALL" modifier, so it might span over a number of tokens
+ bool foundModifier = false;
+ int modifierTokenNumber = nextChild.Position.startTokenNumber;
+
+ for (int i = operatorTokenNumber; !foundModifier && i < nextChild.Position.startTokenNumber; i++)
+ {
+ if (GetTokenData(i).TokenId == FormatterTokens.TOKEN_ALL)
+ {
+ foundModifier = true;
+ modifierTokenNumber = i;
+ }
+ }
+
+ if (foundModifier)
+ {
+ // leave everythong between "UNION" and "ALL" just as it was, but format the keywords
+ firstTokenAfterOperator = modifierTokenNumber + 1;
+ }
+ }
+ else
+ {
+ // only format the operator
+ firstTokenAfterOperator = operatorTokenNumber + 1;
+ }
+
+ ProcessTokenRange(operatorTokenNumber, firstTokenAfterOperator);
+
+ #endregion // Operator
+
+ // process tokens after the operator:
+ // [firstTokenAfterOperator, nextChild.Position.startTokenNumber)
+ #region AfterOperator
+
+ if (CodeObject.Right is SqlQuerySpecification)
+ {
+ IncrementIndentLevel();
+ }
+
+ // if the first token is not a whitespace, we need to insert a newline in front
+ if (!TokenManager.IsTokenWhitespace(TokenManager.TokenList[firstTokenAfterOperator].TokenId))
+ {
+ TokenData td = GetTokenData(firstTokenAfterOperator);
+ AddIndentedNewLineReplacement(td.StartIndex);
+ }
+
+ for (int i = firstTokenAfterOperator; i < nextChild.Position.startTokenNumber; i++)
+ {
+ SimpleProcessToken(i, FormatterUtilities.NormalizeNewLinesEnsureOneNewLineMinimum);
+ }
+
+ #endregion // AfterOperator
+
+ }
+
+ internal override void ProcessSuffixRegion(int lastChildEndTokenNumber, int endTokenNumber)
+ {
+ if (CodeObject.Right is SqlQuerySpecification)
+ {
+ DecrementIndentLevel();
+ }
+ base.ProcessSuffixRegion(lastChildEndTokenNumber, endTokenNumber);
+ }
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlColumnDefinitionFormatter.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlColumnDefinitionFormatter.cs
new file mode 100644
index 00000000..3582bbd0
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlColumnDefinitionFormatter.cs
@@ -0,0 +1,56 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System.Composition;
+using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
+using Microsoft.SqlTools.ServiceLayer.Utility;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+ [Export(typeof(ASTNodeFormatterFactory))]
+ internal class SqlColumnDefinitionFormatterFactory : ASTNodeFormatterFactoryT
+ {
+ protected override ASTNodeFormatter DoCreate(FormatterVisitor visitor, SqlColumnDefinition codeObject)
+ {
+ return new SqlColumnDefinitionFormatter(visitor, codeObject);
+ }
+ }
+
+ internal class SqlColumnDefinitionFormatter : ASTNodeFormatterT
+ {
+ private PaddedSpaceSeparatedListFormatter SpaceSeparatedListFormatter { get; set; }
+
+ internal SqlColumnDefinitionFormatter(FormatterVisitor visitor, SqlColumnDefinition codeObject)
+ : base(visitor, codeObject)
+ {
+ SpaceSeparatedListFormatter = new PaddedSpaceSeparatedListFormatter(visitor, codeObject, Visitor.Context.CurrentColumnSpacingFormatDefinitions, true);
+ }
+
+ internal override void ProcessChild(SqlCodeObject child)
+ {
+ Validate.IsNotNull(nameof(child), child);
+ SpaceSeparatedListFormatter.ProcessChild(child);
+ }
+
+ internal override void ProcessPrefixRegion(int startTokenNumber, int firstChildStartTokenNumber)
+ {
+ SpaceSeparatedListFormatter.ProcessPrefixRegion(startTokenNumber, firstChildStartTokenNumber);
+ }
+
+ internal override void ProcessSuffixRegion(int lastChildEndTokenNumber, int endTokenNumber)
+ {
+ SpaceSeparatedListFormatter.ProcessSuffixRegion(lastChildEndTokenNumber, endTokenNumber);
+ }
+
+ internal override void ProcessInterChildRegion(SqlCodeObject previousChild, SqlCodeObject nextChild)
+ {
+ Validate.IsNotNull(nameof(previousChild), previousChild);
+ Validate.IsNotNull(nameof(nextChild), nextChild);
+
+ SpaceSeparatedListFormatter.ProcessInterChildRegion(previousChild, nextChild);
+ }
+
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlCommonTableExpressionFormatter.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlCommonTableExpressionFormatter.cs
new file mode 100644
index 00000000..f05efb88
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlCommonTableExpressionFormatter.cs
@@ -0,0 +1,107 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System.Collections.Generic;
+using System.Composition;
+using System.Diagnostics;
+using Babel.ParserGenerator;
+using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+ [Export(typeof(ASTNodeFormatterFactory))]
+ internal class SqlCommonTableExpressionFormatterFactory : ASTNodeFormatterFactoryT
+ {
+ protected override ASTNodeFormatter DoCreate(FormatterVisitor visitor, SqlCommonTableExpression codeObject)
+ {
+ return new SqlCommonTableExpressionFormatter(visitor, codeObject);
+ }
+ }
+
+ internal class SqlCommonTableExpressionFormatter : SysCommentsFormatterBase
+ {
+
+ public SqlCommonTableExpressionFormatter(FormatterVisitor visitor, SqlCommonTableExpression codeObject)
+ : base(visitor, codeObject)
+ {
+ }
+
+ protected override bool ShouldPlaceEachElementOnNewLine()
+ {
+ return FormatOptions.PlaceEachReferenceOnNewLineInQueryStatements;
+ }
+
+ internal override void ProcessPrefixRegion(int startTokenNumber, int firstChildStartTokenNumber)
+ {
+ IncrementIndentLevel();
+ base.ProcessPrefixRegion(startTokenNumber, firstChildStartTokenNumber);
+ }
+
+ internal override void ProcessSuffixRegion(int lastChildEndTokenNumber, int endTokenNumber)
+ {
+ DecrementIndentLevel();
+ base.ProcessSuffixRegion(lastChildEndTokenNumber, endTokenNumber);
+ }
+
+ public override void Format()
+ {
+ int nextToken = ProcessExpressionName(CodeObject.Position.startTokenNumber);
+
+ nextToken = ProcessColumns(nextToken);
+
+ // TODO: should we indent the AS statement and then decrement indent at the end?
+ nextToken = ProcessAsToken(nextToken, indentAfterAs: false);
+
+ nextToken = ProcessQueryExpression(nextToken);
+
+ }
+
+ private int ProcessQueryExpression(int nextToken)
+ {
+ NormalizeWhitespace normalizer = GetColumnWhitespaceNormalizer();
+ nextToken = ProcessSectionInsideParentheses(nextToken,
+ normalizer: FormatterUtilities.NormalizeNewLinesEnsureOneNewLineMinimum,
+ isNewlineRequired: true,
+ processSection: (n) => ProcessQuerySection(n, CodeObject.QueryExpression));
+ return nextToken;
+ }
+
+ private int ProcessColumns(int nextToken)
+ {
+ if (CodeObject.ColumnList != null && CodeObject.ColumnList.Count > 0)
+ {
+ NormalizeWhitespace normalizer = GetColumnWhitespaceNormalizer();
+ nextToken = ProcessSectionInsideParentheses(nextToken, normalizer,
+ isNewlineRequired: FormatOptions.PlaceEachReferenceOnNewLineInQueryStatements,
+ processSection: (n) => ProcessColumnList(n, CodeObject.ColumnList, normalizer));
+ }
+ return nextToken;
+ }
+
+ private NormalizeWhitespace GetColumnWhitespaceNormalizer()
+ {
+ if (FormatOptions.PlaceEachReferenceOnNewLineInQueryStatements)
+ {
+ return FormatterUtilities.NormalizeNewLinesEnsureOneNewLineMinimum;
+ }
+ return FormatterUtilities.NormalizeNewLinesOrCondenseToOneSpace;
+ }
+
+ private int ProcessExpressionName(int nextToken)
+ {
+ SqlIdentifier name = CodeObject.Name;
+ for (int i = nextToken; i < name.Position.startTokenNumber; i++)
+ {
+ ProcessTokenEnsuringOneNewLineMinimum(i);
+ }
+
+ ProcessTokenRange(name.Position.startTokenNumber, name.Position.endTokenNumber);
+
+ nextToken = name.Position.endTokenNumber;
+
+ return nextToken;
+ }
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlCompoundStatementFormatter.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlCompoundStatementFormatter.cs
new file mode 100644
index 00000000..13fb9b25
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlCompoundStatementFormatter.cs
@@ -0,0 +1,61 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.Composition;
+using Babel.ParserGenerator;
+using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+
+ [Export(typeof(ASTNodeFormatterFactory))]
+ internal class SqlCompoundStatementFormatterFactory : ASTNodeFormatterFactoryT
+ {
+ protected override ASTNodeFormatter DoCreate(FormatterVisitor visitor, SqlCompoundStatement codeObject)
+ {
+ return new SqlCompoundStatementFormatter(visitor, codeObject);
+ }
+ }
+
+ class SqlCompoundStatementFormatter : NewLineSeparatedListFormatter
+ {
+ internal SqlCompoundStatementFormatter(FormatterVisitor visitor, SqlCompoundStatement codeObject)
+ : base(visitor, codeObject, true)
+ {
+ }
+
+ internal override void ProcessPrefixRegion(int startTokenNumber, int firstChildStartTokenNumber)
+ {
+
+ for (int i = startTokenNumber; i < firstChildStartTokenNumber; i++)
+ {
+ if (TokenManager.TokenList[i].TokenId == FormatterTokens.TOKEN_BEGIN_CS)
+ {
+ IncrementIndentLevel();
+ }
+ SimpleProcessToken(i, FormatterUtilities.NormalizeNewLinesEnsureOneNewLineMinimum);
+ }
+ }
+
+ internal override void ProcessSuffixRegion(int lastChildEndTokenNumber, int endTokenNumber)
+ {
+ DecrementIndentLevel();
+
+ for (int i = lastChildEndTokenNumber; i < endTokenNumber; i++)
+ {
+ if (TokenManager.TokenList[i].TokenId == FormatterTokens.TOKEN_END_CS
+ && !TokenManager.IsTokenWhitespace(TokenManager.TokenList[i-1].TokenId))
+ {
+ TokenData td = TokenManager.TokenList[i];
+ AddIndentedNewLineReplacement(td.StartIndex);
+ }
+ SimpleProcessToken(i, FormatterUtilities.NormalizeNewLinesEnsureOneNewLineMinimum);
+ }
+ }
+
+ }
+
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlCreateProcedureStatementFormatter.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlCreateProcedureStatementFormatter.cs
new file mode 100644
index 00000000..a6ec2465
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlCreateProcedureStatementFormatter.cs
@@ -0,0 +1,28 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System.Composition;
+using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+
+ [Export(typeof(ASTNodeFormatterFactory))]
+ internal class SqlCreateProcedureStatementFormatterFactory : ASTNodeFormatterFactoryT
+ {
+ protected override ASTNodeFormatter DoCreate(FormatterVisitor visitor, SqlCreateProcedureStatement codeObject)
+ {
+ return new SqlCreateProcedureStatementFormatter(visitor, codeObject);
+ }
+ }
+
+ class SqlCreateProcedureStatementFormatter : NewLineSeparatedListFormatter
+ {
+ internal SqlCreateProcedureStatementFormatter(FormatterVisitor visitor, SqlCreateProcedureStatement codeObject)
+ : base(visitor, codeObject, false)
+ {
+ }
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlCreateTableStatementFormatter.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlCreateTableStatementFormatter.cs
new file mode 100644
index 00000000..326476c7
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlCreateTableStatementFormatter.cs
@@ -0,0 +1,195 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.Composition;
+using System.Diagnostics;
+using Babel.ParserGenerator;
+using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
+using Microsoft.SqlTools.ServiceLayer.Utility;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+
+ [Export(typeof(ASTNodeFormatterFactory))]
+ internal class SqlCreateTableStatementFormatterFactory : ASTNodeFormatterFactoryT
+ {
+ protected override ASTNodeFormatter DoCreate(FormatterVisitor visitor, SqlCreateTableStatement codeObject)
+ {
+ return new SqlCreateTableStatementFormatter(visitor, codeObject);
+ }
+ }
+
+ internal class SqlCreateTableStatementFormatter : ASTNodeFormatterT
+ {
+ internal SqlCreateTableStatementFormatter(FormatterVisitor visitor, SqlCreateTableStatement codeObject)
+ : base(visitor, codeObject)
+ { }
+
+ internal override void ProcessPrefixRegion(int startTokenNumber, int firstChildStartTokenNumber)
+ {
+ int nTokens = firstChildStartTokenNumber - startTokenNumber;
+ Debug.Assert(nTokens >= 4, "unexpected token count for SqlCreateTableStatement prefix region");
+
+ int createTokenIndex = -1;
+ int tableTokenIndex = -1;
+ bool foundComment = false;
+ for (int i = startTokenNumber; i < firstChildStartTokenNumber; i++)
+ {
+ TokenData td = TokenManager.TokenList[i];
+
+ if (td.TokenId == FormatterTokens.LEX_END_OF_LINE_COMMENT)
+ {
+ foundComment = true;
+ } else if (td.TokenId == FormatterTokens.TOKEN_TABLE)
+ {
+ tableTokenIndex = i;
+ } else if (td.TokenId == FormatterTokens.TOKEN_CREATE)
+ {
+ createTokenIndex = i;
+ }
+ }
+
+ // logic below doesn't support single-line comments inside of a create table statement
+ if (!foundComment && createTokenIndex < tableTokenIndex)
+ {
+ for (int i = startTokenNumber; i < firstChildStartTokenNumber; i++)
+ {
+ SimpleProcessToken(i, FormatterUtilities.NormalizeToOneSpace);
+ }
+ }
+ else
+ {
+ ProcessTokenRange(startTokenNumber, firstChildStartTokenNumber);
+ }
+ }
+
+ internal override void ProcessSuffixRegion(int lastChildEndTokenNumber, int endTokenNumber)
+ {
+ // Due to a current limitation of the parser, the suffix region stops right after the list of column definitions.
+ // According to the TSQL grammar schema, the statement could continue (see: http://msdn.microsoft.com/en-us/library/ms174979.aspx).
+ // We will preserve the text in the sufix region in its current formatting, with the exception that we ensure the closed parenthesis
+ // which closes the list of column definitions is on a new line and that all the tokens preceding it (which should only be comments)
+ // are also each on a separate line and indented
+
+ IncrementIndentLevel();
+
+ int closeParenToken = -1;
+
+ for (int i = lastChildEndTokenNumber; i < endTokenNumber && closeParenToken < 0; i++)
+ {
+ if (TokenManager.TokenList[i].TokenId == 41) closeParenToken = i;
+ }
+
+ if (closeParenToken > 0)
+ {
+ for (int i = lastChildEndTokenNumber; i < closeParenToken - 1; i++)
+ {
+ SimpleProcessToken(i, FormatterUtilities.NormalizeNewLinesInWhitespace);
+ }
+
+ DecrementIndentLevel();
+
+ TokenData td2 = TokenManager.TokenList[closeParenToken - 1];
+
+ if (TokenManager.IsTokenWhitespace(td2.TokenId))
+ {
+ SimpleProcessToken(closeParenToken - 1, FormatterUtilities.NormalizeNewLinesInWhitespace);
+ }
+ else
+ {
+ TokenData td = TokenManager.TokenList[closeParenToken];
+ AddIndentedNewLineReplacement(td.StartIndex);
+ }
+
+ // Add the closed parenthesis and the additional unparsed elements of the statement
+ // which should keep their old formatting
+ ProcessTokenRange(closeParenToken, endTokenNumber);
+ }
+ else
+ {
+ ProcessTokenRange(lastChildEndTokenNumber, endTokenNumber);
+ }
+ }
+
+ internal override void ProcessInterChildRegion(SqlCodeObject previousChild, SqlCodeObject nextChild)
+ {
+ Validate.IsNotNull(nameof(previousChild), previousChild);
+ Validate.IsNotNull(nameof(nextChild), nextChild);
+
+ if (previousChild is SqlObjectIdentifier && nextChild is SqlTableDefinition)
+ {
+ //
+ // We want to make sure that the open-paren is on a new line and followed by a new-line & correctly indented.
+ //
+
+ // find the open paren token
+ int openParenToken = -1;
+ for (int i = previousChild.Position.endTokenNumber; i < nextChild.Position.startTokenNumber; i++)
+ {
+ TokenData currentToken = TokenManager.TokenList[i];
+ if (currentToken.TokenId == 40)
+ {
+ openParenToken = i;
+ break;
+ }
+ }
+
+
+
+ // normalize whitespace between last token & open paren. Each whitespace token should be condensed down to a single space character
+ for (int i = previousChild.Position.endTokenNumber; i < openParenToken - 1; i++)
+ {
+ SimpleProcessToken(i, FormatterUtilities.NormalizeToOneSpace);
+ }
+
+ // If there is a whitespace before the open parenthisis, normalize it to a new line
+ TokenData td = TokenManager.TokenList[openParenToken - 1];
+
+ if (TokenManager.IsTokenWhitespace(td.TokenId))
+ {
+ if (previousChild.Position.endTokenNumber < openParenToken)
+ {
+ SimpleProcessToken(openParenToken - 1, FormatterUtilities.NormalizeNewLinesInWhitespace);
+ }
+ }
+ else
+ {
+ if (previousChild.Position.endTokenNumber < openParenToken)
+ {
+ SimpleProcessToken(openParenToken - 1, FormatterUtilities.NormalizeToOneSpace);
+ }
+ TokenData tok = TokenManager.TokenList[openParenToken];
+ AddIndentedNewLineReplacement(tok.StartIndex);
+ }
+
+ // append open-paren token
+ ProcessTokenRange(openParenToken, openParenToken + 1);
+
+ // process tokens between open paren & first child start
+ IncrementIndentLevel();
+ for (int i = openParenToken + 1; i < nextChild.Position.startTokenNumber; i++)
+ {
+ SimpleProcessToken(i, FormatterUtilities.NormalizeNewLinesInWhitespace);
+ }
+
+ // ensure we have at least one new line
+ if (openParenToken + 1 >= nextChild.Position.startTokenNumber || !TokenManager.IsTokenWhitespace(TokenManager.TokenList[nextChild.Position.startTokenNumber - 1].TokenId))
+ {
+ TokenData tok = TokenManager.TokenList[nextChild.Position.startTokenNumber];
+ AddIndentedNewLineReplacement(tok.StartIndex);
+ }
+ DecrementIndentLevel();
+
+ }
+ else
+ {
+ ProcessTokenRange(previousChild.Position.endTokenNumber, nextChild.Position.startTokenNumber);
+ }
+
+ }
+
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlDataTypeFormatter.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlDataTypeFormatter.cs
new file mode 100644
index 00000000..16797cc6
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlDataTypeFormatter.cs
@@ -0,0 +1,61 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System.Composition;
+using System.Diagnostics.CodeAnalysis;
+using Babel.ParserGenerator;
+using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+
+ [Export(typeof(ASTNodeFormatterFactory))]
+ internal class SqlDataTypeFormatterFactory : ASTNodeFormatterFactoryT
+ {
+ protected override ASTNodeFormatter DoCreate(FormatterVisitor visitor, SqlDataType codeObject)
+ {
+ return new SqlDataTypeFormatter(visitor, codeObject);
+ }
+ }
+
+ internal class SqlDataTypeFormatter : ASTNodeFormatterT
+ {
+ internal SqlDataTypeFormatter(FormatterVisitor visitor, SqlDataType codeObject)
+ : base(visitor, codeObject)
+ {
+ }
+
+ [SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase")]
+ public override void Format()
+ {
+ int startTokenIndex = CodeObject.Position.startTokenNumber;
+ int endTokenIndex = CodeObject.Position.endTokenNumber;
+
+ if (startTokenIndex == endTokenIndex - 1 &&
+ CodeObject.TokenManager.TokenList[startTokenIndex].TokenId == FormatterTokens.TOKEN_ID)
+ {
+ string sql = GetTokenRangeAsOriginalString(startTokenIndex, startTokenIndex + 1);
+ if (FormatOptions.UppercaseDataTypes)
+ {
+ TokenData tok = TokenManager.TokenList[startTokenIndex];
+ AddReplacement(tok.StartIndex, sql, sql.ToUpperInvariant());
+ sql = sql.ToUpperInvariant();
+ }
+ else if (FormatOptions.LowercaseDataTypes)
+ {
+ TokenData tok = TokenManager.TokenList[startTokenIndex];
+ AddReplacement(tok.StartIndex, sql, sql.ToLowerInvariant());
+ sql = sql.ToLowerInvariant();
+ }
+
+ }
+ else
+ {
+ base.Format();
+ }
+ }
+
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlFromClauseFormatter.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlFromClauseFormatter.cs
new file mode 100644
index 00000000..0a33dfcb
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlFromClauseFormatter.cs
@@ -0,0 +1,57 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System.Composition;
+using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
+using Microsoft.SqlTools.ServiceLayer.Utility;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+
+ [Export(typeof(ASTNodeFormatterFactory))]
+ internal class SqlFromClauseFormatterFactory : ASTNodeFormatterFactoryT
+ {
+ protected override ASTNodeFormatter DoCreate(FormatterVisitor visitor, SqlFromClause codeObject)
+ {
+ return new SqlFromClauseFormatter(visitor, codeObject);
+ }
+ }
+
+ internal class SqlFromClauseFormatter : ASTNodeFormatterT
+ {
+ private CommaSeparatedListFormatter CommaSeparatedListFormatter { get; set; }
+
+ internal SqlFromClauseFormatter(FormatterVisitor visitor, SqlFromClause codeObject)
+ : base(visitor, codeObject)
+ {
+ CommaSeparatedListFormatter = new CommaSeparatedListFormatter(visitor, codeObject, FormatOptions.PlaceEachReferenceOnNewLineInQueryStatements);
+ }
+
+ internal override void ProcessChild(SqlCodeObject child)
+ {
+ Validate.IsNotNull(nameof(child), child);
+ CommaSeparatedListFormatter.ProcessChild(child);
+ }
+
+ internal override void ProcessPrefixRegion(int startTokenNumber, int firstChildStartTokenNumber)
+ {
+ CommaSeparatedListFormatter.ProcessPrefixRegion(startTokenNumber, firstChildStartTokenNumber);
+ }
+
+ internal override void ProcessSuffixRegion(int lastChildEndTokenNumber, int endTokenNumber)
+ {
+ CommaSeparatedListFormatter.ProcessSuffixRegion(lastChildEndTokenNumber, endTokenNumber);
+ }
+
+ internal override void ProcessInterChildRegion(SqlCodeObject previousChild, SqlCodeObject nextChild)
+ {
+ Validate.IsNotNull(nameof(previousChild), previousChild);
+ Validate.IsNotNull(nameof(nextChild), nextChild);
+
+ CommaSeparatedListFormatter.ProcessInterChildRegion(previousChild, nextChild);
+ }
+
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlInsertSpecificationFormatter.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlInsertSpecificationFormatter.cs
new file mode 100644
index 00000000..d75d8078
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlInsertSpecificationFormatter.cs
@@ -0,0 +1,205 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Composition;
+using System.Diagnostics;
+using System.Globalization;
+using Babel.ParserGenerator;
+using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+
+ [Export(typeof(ASTNodeFormatterFactory))]
+ internal class SqlInsertSpecificationFormatterFactory : ASTNodeFormatterFactoryT
+ {
+ protected override ASTNodeFormatter DoCreate(FormatterVisitor visitor, SqlInsertSpecification codeObject)
+ {
+ return new SqlInsertSpecificationFormatter(visitor, codeObject);
+ }
+ }
+
+ class SqlInsertSpecificationFormatter : ASTNodeFormatterT
+ {
+ internal SqlInsertSpecificationFormatter(FormatterVisitor visitor, SqlInsertSpecification codeObject)
+ : base(visitor, codeObject)
+ {
+ }
+
+ public override void Format()
+ {
+
+ IEnumerator firstChildEnum = CodeObject.Children.GetEnumerator();
+ if (firstChildEnum.MoveNext())
+ {
+ //
+ // format the text from the start of the object to the start of it's first child
+ //
+ ProcessPrefixRegion(CodeObject.Position.startTokenNumber, firstChildEnum.Current.Position.startTokenNumber);
+ int nextToken = firstChildEnum.Current.Position.startTokenNumber;
+
+ // handle top specification
+ nextToken = ProcessTopSpecification(nextToken);
+
+ // handle target
+ nextToken = ProcessTarget(nextToken);
+
+ // handle target columns
+ nextToken = ProcessColumns(nextToken);
+
+ // handle output clause
+ nextToken = ProcessOutputClause(nextToken);
+
+ // handle values / derived table / execute statement / dml_table_source
+ nextToken = ProcessValues(nextToken);
+ }
+ else
+ {
+ throw new FormatFailedException("Insert statement has no children.");
+ }
+ }
+
+
+ internal int ProcessTopSpecification(int nextToken)
+ {
+ if (CodeObject.TopSpecification != null)
+ {
+ ProcessAndNormalizeWhitespaceRange(nextToken, CodeObject.TopSpecification.Position.startTokenNumber,
+ FormatterUtilities.NormalizeNewLinesOrCondenseToOneSpace);
+
+ ProcessChild(CodeObject.TopSpecification);
+
+ nextToken = CodeObject.TopSpecification.Position.endTokenNumber;
+ }
+
+ return nextToken;
+ }
+
+
+ private int ProcessTarget(int nextToken)
+ {
+ Debug.Assert(CodeObject.Target != null, "No target in insert statement.");
+
+ // find out if there is an "INTO" token
+ int intoTokenIndexOrTargetStartTokenIndex = CodeObject.Target.Position.startTokenNumber;
+ for (int i = nextToken; i < CodeObject.Target.Position.startTokenNumber; i++)
+ {
+ if (TokenManager.TokenList[i].TokenId == FormatterTokens.TOKEN_INTO)
+ {
+ intoTokenIndexOrTargetStartTokenIndex = i;
+ }
+ }
+
+ // Process up to the INTO or Target index. If INTO isn't there, expect all whitespace tokens
+ ProcessAndNormalizeWhitespaceRange(nextToken, intoTokenIndexOrTargetStartTokenIndex,
+ FormatterUtilities.NormalizeNewLinesEnsureOneNewLineMinimum);
+
+ IncrementIndentLevel();
+
+ // Process the INTO token and all whitespace up to the target start
+ ProcessAndNormalizeTokenRange(intoTokenIndexOrTargetStartTokenIndex, CodeObject.Target.Position.startTokenNumber,
+ FormatterUtilities.NormalizeNewLinesOrCondenseToOneSpace, areAllTokensWhitespace: false);
+
+ ProcessChild(CodeObject.Target);
+
+ nextToken = CodeObject.Target.Position.endTokenNumber;
+ DecrementIndentLevel();
+
+ return nextToken;
+ }
+
+ private int ProcessColumns(int nextToken)
+ {
+ if (CodeObject.TargetColumns != null)
+ {
+ if (CodeObject.TargetColumns.Count > 0)
+ {
+ IncrementIndentLevel();
+
+ // if the next token is not a whitespace, a newline is enforced.
+ TokenData nextTokenData = GetTokenData(nextToken);
+ if (!IsTokenWhitespace(nextTokenData))
+ {
+ AddIndentedNewLineReplacement(nextTokenData.StartIndex);
+ }
+
+ NormalizeWhitespace f = FormatterUtilities.NormalizeNewLinesEnsureOneNewLineMinimum;
+
+ // process tokens until we reach the closed parenthesis (with id 41)
+ for (int id = TokenManager.TokenList[nextToken].TokenId; id != 41; id = TokenManager.TokenList[++nextToken].TokenId)
+ {
+ SimpleProcessToken(nextToken, f);
+ if (id == 40) // open parenthesis (id == 40) changes the formatting
+ {
+ f = FormatterUtilities.NormalizeNewLinesOrCondenseToOneSpace;
+ }
+ }
+
+ // process the cosed paren
+ SimpleProcessToken(nextToken, f);
+
+ nextToken++;
+
+ DecrementIndentLevel();
+ }
+ }
+
+ return nextToken;
+ }
+
+
+ private int ProcessValues(int nextToken)
+ {
+ if (CodeObject.Source != null && HasToken(nextToken))
+ {
+ TokenData nextTokenData = GetTokenData(nextToken);
+ // if the next token is not a whitespace, a newline is enforced.
+ if (!IsTokenWhitespace(nextTokenData))
+ {
+ AddIndentedNewLineReplacement(nextTokenData.StartIndex);
+ }
+
+ ProcessAndNormalizeWhitespaceRange(nextToken, CodeObject.Source.Position.startTokenNumber,
+ FormatterUtilities.NormalizeNewLinesEnsureOneNewLineMinimum);
+
+ ProcessChild(CodeObject.Source);
+ }
+
+ return nextToken;
+ }
+
+ private int ProcessOutputClause(int nextToken)
+ {
+ if (CodeObject.OutputIntoClause != null)
+ {
+ if (nextToken == CodeObject.OutputIntoClause.Position.startTokenNumber)
+ {
+ AddIndentedNewLineReplacement(GetTokenData(nextToken).StartIndex);
+ }
+ else
+ {
+ while (nextToken < CodeObject.OutputIntoClause.Position.startTokenNumber)
+ {
+ DebugAssertTokenIsWhitespaceOrComment(GetTokenData(nextToken), nextToken);
+ SimpleProcessToken(nextToken, FormatterUtilities.NormalizeNewLinesEnsureOneNewLineMinimum);
+ nextToken++;
+ }
+
+ TokenData previousTokenData = PreviousTokenData(nextToken);
+ if (!IsTokenWhitespace(previousTokenData))
+ {
+ AddIndentedNewLineReplacement(previousTokenData.StartIndex);
+ }
+ }
+ ProcessChild(CodeObject.OutputIntoClause);
+ nextToken = CodeObject.OutputIntoClause.Position.endTokenNumber;
+ }
+
+ return nextToken;
+ }
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlInsertStatementFormatter.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlInsertStatementFormatter.cs
new file mode 100644
index 00000000..f2f2ccb7
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlInsertStatementFormatter.cs
@@ -0,0 +1,30 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System.Composition;
+using System.Diagnostics.CodeAnalysis;
+using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+
+ [Export(typeof(ASTNodeFormatterFactory))]
+ internal class SqlInsertStatementFormatterFactory : ASTNodeFormatterFactoryT
+ {
+ protected override ASTNodeFormatter DoCreate(FormatterVisitor visitor, SqlInsertStatement codeObject)
+ {
+ return new SqlInsertStatementFormatter(visitor, codeObject);
+ }
+ }
+
+ internal class SqlInsertStatementFormatter : NewLineSeparatedListFormatter
+ {
+ [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ public SqlInsertStatementFormatter(FormatterVisitor visitor, SqlInsertStatement codeObject)
+ : base(visitor, codeObject, false)
+ {
+ }
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlProcedureDefinitionFormatter.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlProcedureDefinitionFormatter.cs
new file mode 100644
index 00000000..1291807c
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlProcedureDefinitionFormatter.cs
@@ -0,0 +1,91 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.Composition;
+using Babel.ParserGenerator;
+using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
+using Microsoft.SqlTools.ServiceLayer.Utility;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+
+ [Export(typeof(ASTNodeFormatterFactory))]
+ internal class SqlProcedureDefinitionFormatterFactory : ASTNodeFormatterFactoryT
+ {
+ protected override ASTNodeFormatter DoCreate(FormatterVisitor visitor, SqlProcedureDefinition codeObject)
+ {
+ return new SqlProcedureDefinitionFormatter(visitor, codeObject);
+ }
+ }
+
+ class SqlProcedureDefinitionFormatter : CommaSeparatedListFormatter
+ {
+ NewLineSeparatedListFormatter NewLineSeparatedListFormatter { get; set; }
+ bool foundTokenWith;
+
+ internal SqlProcedureDefinitionFormatter(FormatterVisitor visitor, SqlProcedureDefinition codeObject)
+ : base(visitor, codeObject, true)
+ {
+ NewLineSeparatedListFormatter = new NewLineSeparatedListFormatter(visitor, codeObject, false);
+ foundTokenWith = false;
+ }
+
+ internal override void ProcessInterChildRegion(SqlCodeObject previousChild, SqlCodeObject nextChild)
+ {
+ Validate.IsNotNull(nameof(previousChild), previousChild);
+ Validate.IsNotNull(nameof(nextChild), nextChild);
+
+ if (nextChild is SqlModuleOption)
+ {
+ if (!foundTokenWith)
+ {
+ DecrementIndentLevel();
+ }
+ for (int i = previousChild.Position.endTokenNumber; i < nextChild.Position.startTokenNumber; i++)
+ {
+ if (!foundTokenWith && TokenManager.TokenList[i].TokenId == FormatterTokens.TOKEN_WITH)
+ {
+ IncrementIndentLevel();
+ foundTokenWith = true;
+ }
+ SimpleProcessToken(i, FormatterUtilities.NormalizeNewLinesEnsureOneNewLineMinimum);
+ }
+ }
+ else if (previousChild is SqlObjectIdentifier)
+ {
+ NewLineSeparatedListFormatter.ProcessInterChildRegion(previousChild, nextChild);
+ }
+ else
+ {
+ base.ProcessInterChildRegion(previousChild, nextChild);
+ }
+ }
+
+ internal override void ProcessSuffixRegion(int lastChildEndTokenNumber, int endTokenNumber)
+ {
+ DecrementIndentLevel();
+ NormalizeWhitespace f = FormatterUtilities.NormalizeNewLinesEnsureOneNewLineMinimum;
+ for (int i = lastChildEndTokenNumber; i < endTokenNumber; i++)
+ {
+ if (TokenManager.TokenList[i].TokenId == FormatterTokens.TOKEN_AS
+ && !TokenManager.IsTokenWhitespace(TokenManager.TokenList[i-1].TokenId))
+ {
+ TokenData td = TokenManager.TokenList[i];
+ AddIndentedNewLineReplacement(td.StartIndex);
+ }
+ if (TokenManager.TokenList[i].TokenId == FormatterTokens.TOKEN_FOR)
+ {
+ f = FormatterUtilities.NormalizeNewLinesOrCondenseToOneSpace;
+ }
+ else if (TokenManager.TokenList[i].TokenId == FormatterTokens.TOKEN_REPLICATION)
+ {
+ f = FormatterUtilities.NormalizeNewLinesEnsureOneNewLineMinimum;
+ }
+ SimpleProcessToken(i, f);
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlQualifiedJoinTableExpressionFormatter.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlQualifiedJoinTableExpressionFormatter.cs
new file mode 100644
index 00000000..150c3150
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlQualifiedJoinTableExpressionFormatter.cs
@@ -0,0 +1,57 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System.Composition;
+using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
+using Microsoft.SqlTools.ServiceLayer.Utility;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+
+ [Export(typeof(ASTNodeFormatterFactory))]
+ internal class SqlQualifiedJoinTableExpressionFormatterFactory : ASTNodeFormatterFactoryT
+ {
+ protected override ASTNodeFormatter DoCreate(FormatterVisitor visitor, SqlQualifiedJoinTableExpression codeObject)
+ {
+ return new SqlQualifiedJoinTableExpressionFormatter(visitor, codeObject);
+ }
+ }
+
+ internal class SqlQualifiedJoinTableExpressionFormatter : ASTNodeFormatterT
+ {
+ SpaceSeparatedListFormatter SpaceSeparatedListFormatter { get; set; }
+
+ internal SqlQualifiedJoinTableExpressionFormatter(FormatterVisitor visitor, SqlQualifiedJoinTableExpression codeObject)
+ : base(visitor, codeObject)
+ {
+ SpaceSeparatedListFormatter = new SpaceSeparatedListFormatter(visitor, codeObject, false);
+ }
+
+ internal override void ProcessChild(SqlCodeObject child)
+ {
+ Validate.IsNotNull(nameof(child), child);
+ SpaceSeparatedListFormatter.ProcessChild(child);
+ }
+
+ internal override void ProcessPrefixRegion(int startTokenNumber, int firstChildStartTokenNumber)
+ {
+ SpaceSeparatedListFormatter.ProcessPrefixRegion(startTokenNumber, firstChildStartTokenNumber);
+ }
+
+ internal override void ProcessSuffixRegion(int lastChildEndTokenNumber, int endTokenNumber)
+ {
+ SpaceSeparatedListFormatter.ProcessSuffixRegion(lastChildEndTokenNumber, endTokenNumber);
+ }
+
+ internal override void ProcessInterChildRegion(SqlCodeObject previousChild, SqlCodeObject nextChild)
+ {
+ Validate.IsNotNull(nameof(previousChild), previousChild);
+ Validate.IsNotNull(nameof(nextChild), nextChild);
+
+ SpaceSeparatedListFormatter.ProcessInterChildRegion(previousChild, nextChild);
+ }
+
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlQuerySpecificationFormatter.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlQuerySpecificationFormatter.cs
new file mode 100644
index 00000000..c90993f7
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlQuerySpecificationFormatter.cs
@@ -0,0 +1,57 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System.Composition;
+using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
+using Microsoft.SqlTools.ServiceLayer.Utility;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+
+ [Export(typeof(ASTNodeFormatterFactory))]
+ internal class SqlQuerySpecificationFormatterFactory : ASTNodeFormatterFactoryT
+ {
+ protected override ASTNodeFormatter DoCreate(FormatterVisitor visitor, SqlQuerySpecification codeObject)
+ {
+ return new SqlQuerySpecificationFormatter(visitor, codeObject);
+ }
+ }
+
+ internal class SqlQuerySpecificationFormatter : ASTNodeFormatterT
+ {
+ WhiteSpaceSeparatedListFormatter WhiteSpaceSeparatedListFormatter { get; set; }
+
+ internal SqlQuerySpecificationFormatter(FormatterVisitor visitor, SqlQuerySpecification codeObject)
+ : base(visitor, codeObject)
+ {
+ WhiteSpaceSeparatedListFormatter = new NewLineSeparatedListFormatter(visitor, codeObject, false);
+ }
+
+ internal override void ProcessChild(SqlCodeObject child)
+ {
+ Validate.IsNotNull(nameof(child), child);
+ WhiteSpaceSeparatedListFormatter.ProcessChild(child);
+ }
+
+ internal override void ProcessPrefixRegion(int startTokenNumber, int firstChildStartTokenNumber)
+ {
+ WhiteSpaceSeparatedListFormatter.ProcessPrefixRegion(startTokenNumber, firstChildStartTokenNumber);
+ }
+
+ internal override void ProcessSuffixRegion(int lastChildEndTokenNumber, int endTokenNumber)
+ {
+ WhiteSpaceSeparatedListFormatter.ProcessSuffixRegion(lastChildEndTokenNumber, endTokenNumber);
+ }
+
+ internal override void ProcessInterChildRegion(SqlCodeObject previousChild, SqlCodeObject nextChild)
+ {
+ Validate.IsNotNull(nameof(previousChild), previousChild);
+ Validate.IsNotNull(nameof(nextChild), nextChild);
+
+ WhiteSpaceSeparatedListFormatter.ProcessInterChildRegion(previousChild, nextChild);
+ }
+
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlQueryWithClauseFormatter.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlQueryWithClauseFormatter.cs
new file mode 100644
index 00000000..389791ae
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlQueryWithClauseFormatter.cs
@@ -0,0 +1,28 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System.Composition;
+using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+
+ [Export(typeof(ASTNodeFormatterFactory))]
+ internal class SqlQueryWithClauseFormatterFactory : ASTNodeFormatterFactoryT
+ {
+ protected override ASTNodeFormatter DoCreate(FormatterVisitor visitor, SqlQueryWithClause codeObject)
+ {
+ return new SqlQueryWithClauseFormatter(visitor, codeObject);
+ }
+ }
+
+ class SqlQueryWithClauseFormatter : CommaSeparatedListFormatter
+ {
+ public SqlQueryWithClauseFormatter(FormatterVisitor visitor, SqlQueryWithClause codeObject)
+ : base(visitor, codeObject, true)
+ {
+ }
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlRowConstructorExpressionFormatter.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlRowConstructorExpressionFormatter.cs
new file mode 100644
index 00000000..892082d4
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlRowConstructorExpressionFormatter.cs
@@ -0,0 +1,30 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System.Composition;
+using System.Diagnostics.CodeAnalysis;
+using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+
+ [Export(typeof(ASTNodeFormatterFactory))]
+ internal class SqlRowConstructorExpressionFormatterFactory : ASTNodeFormatterFactoryT
+ {
+ protected override ASTNodeFormatter DoCreate(FormatterVisitor visitor, SqlRowConstructorExpression codeObject)
+ {
+ return new SqlRowConstructorExpressionFormatter(visitor, codeObject);
+ }
+ }
+
+ internal class SqlRowConstructorExpressionFormatter : CommaSeparatedListFormatter
+ {
+ [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ public SqlRowConstructorExpressionFormatter(FormatterVisitor visitor, SqlRowConstructorExpression codeObject)
+ : base(visitor, codeObject, false)
+ {
+ }
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlSelectClauseFormatter.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlSelectClauseFormatter.cs
new file mode 100644
index 00000000..17ab0ed3
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlSelectClauseFormatter.cs
@@ -0,0 +1,46 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System.Composition;
+using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
+using Microsoft.SqlTools.ServiceLayer.Utility;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+ [Export(typeof(ASTNodeFormatterFactory))]
+ internal class SqlSelectClauseFormatterFactory : ASTNodeFormatterFactoryT
+ {
+ protected override ASTNodeFormatter DoCreate(FormatterVisitor visitor, SqlSelectClause codeObject)
+ {
+ return new SqlSelectClauseFormatter(visitor, codeObject);
+ }
+ }
+
+ internal class SqlSelectClauseFormatter : CommaSeparatedListFormatter
+ {
+ private NewLineSeparatedListFormatter NewLineSeparatedListFormatter { get; set; }
+
+ internal SqlSelectClauseFormatter(FormatterVisitor visitor, SqlSelectClause codeObject)
+ : base(visitor, codeObject, visitor.Context.FormatOptions.PlaceEachReferenceOnNewLineInQueryStatements)
+ {
+ NewLineSeparatedListFormatter = new NewLineSeparatedListFormatter(visitor, codeObject, true);
+ }
+
+ internal override void ProcessInterChildRegion(SqlCodeObject previousChild, SqlCodeObject nextChild)
+ {
+ Validate.IsNotNull(nameof(previousChild), previousChild);
+ Validate.IsNotNull(nameof(nextChild), nextChild);
+
+ if (previousChild is SqlTopSpecification)
+ {
+ NewLineSeparatedListFormatter.ProcessInterChildRegion(previousChild, nextChild);
+ }
+ else
+ {
+ base.ProcessInterChildRegion(previousChild, nextChild);
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlSelectSpecificationFormatter.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlSelectSpecificationFormatter.cs
new file mode 100644
index 00000000..53574b5e
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlSelectSpecificationFormatter.cs
@@ -0,0 +1,124 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.Composition;
+using System.Diagnostics;
+using System.Globalization;
+using Babel.ParserGenerator;
+using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
+using Microsoft.SqlTools.ServiceLayer.Utility;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+
+ [Export(typeof(ASTNodeFormatterFactory))]
+ internal class SqlSelectSpecificationFormatterFactory : ASTNodeFormatterFactoryT
+ {
+ protected override ASTNodeFormatter DoCreate(FormatterVisitor visitor, SqlSelectSpecification codeObject)
+ {
+ return new SqlSelectSpecificationFormatter(visitor, codeObject);
+ }
+ }
+
+ internal class SqlSelectSpecificationFormatter : NewLineSeparatedListFormatter
+ {
+
+ internal SqlSelectSpecificationFormatter(FormatterVisitor visitor, SqlSelectSpecification codeObject)
+ : base(visitor, codeObject, false)
+ {
+
+ }
+
+ internal override void ProcessChild(SqlCodeObject child)
+ {
+ Validate.IsNotNull(nameof(child), child);
+ base.ProcessChild(child);
+ if (child is SqlForBrowseClause)
+ {
+ DecrementIndentLevel();
+ }
+ }
+
+ internal override void ProcessSuffixRegion(int lastChildEndTokenNumber, int endTokenNumber)
+ {
+ for (int i = lastChildEndTokenNumber; i < endTokenNumber; i++)
+ {
+ SimpleProcessToken(i, FormatterUtilities.NormalizeNewLinesEnsureOneNewLineMinimum);
+ }
+ }
+
+ internal override void ProcessInterChildRegion(SqlCodeObject previousChild, SqlCodeObject nextChild)
+ {
+ Validate.IsNotNull(nameof(previousChild), previousChild);
+ Validate.IsNotNull(nameof(nextChild), nextChild);
+
+ /* Due to the current behavior of the T-SQL Parser, the FOR clause needs to be treated separately */
+ if (nextChild is SqlForBrowseClause || nextChild is SqlForXmlClause)
+ {
+ #region Find the "FOR" token
+ int forTokenIndex = previousChild.Position.endTokenNumber;
+ TokenData td = TokenManager.TokenList[forTokenIndex];
+ while (td.TokenId != FormatterTokens.TOKEN_FOR && forTokenIndex < CodeObject.Position.endTokenNumber)
+ {
+ Debug.Assert(
+ TokenManager.IsTokenComment(td.TokenId)
+ || TokenManager.IsTokenWhitespace(td.TokenId)
+ , string.Format(CultureInfo.CurrentCulture, "Unexpected token \"{0}\" before the FOR token.", Visitor.Context.GetTokenRangeAsOriginalString(forTokenIndex, forTokenIndex + 1))
+ );
+ ++forTokenIndex;
+ td = TokenManager.TokenList[forTokenIndex];
+ }
+ Debug.Assert(forTokenIndex < CodeObject.Position.endTokenNumber, "No FOR token.");
+ #endregion // Find the "FOR" token
+
+
+ #region Process the tokens before the "FOR" token
+ for (int i = previousChild.Position.endTokenNumber; i < forTokenIndex; i++)
+ {
+ Debug.Assert(
+ TokenManager.IsTokenComment(TokenManager.TokenList[i].TokenId)
+ || TokenManager.IsTokenWhitespace(TokenManager.TokenList[i].TokenId)
+ , string.Format(CultureInfo.CurrentCulture, "Unexpected token \"{0}\" before the FOR token.", Visitor.Context.GetTokenRangeAsOriginalString(i, i + 1))
+ );
+ SimpleProcessToken(i, FormatterUtilities.NormalizeNewLinesEnsureOneNewLineMinimum);
+ }
+ #endregion // Process the tokens before the "FOR" token
+
+ #region Process the "FOR" token
+ if (previousChild.Position.endTokenNumber >= forTokenIndex
+ || !TokenManager.IsTokenWhitespace(TokenManager.TokenList[forTokenIndex - 1].TokenId))
+ {
+ td = TokenManager.TokenList[forTokenIndex];
+ AddIndentedNewLineReplacement(td.StartIndex);
+ }
+ Visitor.Context.ProcessTokenRange(forTokenIndex, forTokenIndex + 1);
+ IncrementIndentLevel();
+
+ int nextToken = forTokenIndex + 1;
+ Debug.Assert(nextToken < CodeObject.Position.endTokenNumber, "View Definition ends unexpectedly after the FOR token.");
+ // Ensure a whitespace after the "FOR" token
+ if (!TokenManager.IsTokenWhitespace(TokenManager.TokenList[nextToken].TokenId))
+ {
+ td = TokenManager.TokenList[forTokenIndex];
+ AddIndentedNewLineReplacement(td.StartIndex);
+ }
+ #endregion // Process the "FOR" token
+
+ #region Process tokens after the FOR token
+ for (int i = nextToken; i < nextChild.Position.startTokenNumber; i++)
+ {
+ SimpleProcessToken(i, FormatterUtilities.NormalizeNewLinesOrCondenseToOneSpace);
+ }
+ #endregion // Process tokens after the FOR token
+ }
+ else
+ {
+ base.ProcessInterChildRegion(previousChild, nextChild);
+ }
+ }
+
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlSelectStatementFormatter.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlSelectStatementFormatter.cs
new file mode 100644
index 00000000..b3698ae3
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlSelectStatementFormatter.cs
@@ -0,0 +1,31 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System.Composition;
+using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+
+ [Export(typeof(ASTNodeFormatterFactory))]
+ internal class SqlSelectStatementFormatterFactory : ASTNodeFormatterFactoryT
+ {
+ protected override ASTNodeFormatter DoCreate(FormatterVisitor visitor, SqlSelectStatement codeObject)
+ {
+ return new SqlSelectStatementFormatter(visitor, codeObject);
+ }
+ }
+
+ class SqlSelectStatementFormatter : NewLineSeparatedListFormatter
+ {
+
+ internal SqlSelectStatementFormatter(FormatterVisitor visitor, SqlSelectStatement codeObject)
+ : base(visitor, codeObject, false)
+ {
+
+ }
+
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlTableConstructorExpressionFormatter.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlTableConstructorExpressionFormatter.cs
new file mode 100644
index 00000000..70d5bd22
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlTableConstructorExpressionFormatter.cs
@@ -0,0 +1,30 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System.Composition;
+using System.Diagnostics.CodeAnalysis;
+using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+
+ [Export(typeof(ASTNodeFormatterFactory))]
+ internal class SqlTableConstructorExpressionFormatterFactory : ASTNodeFormatterFactoryT
+ {
+ protected override ASTNodeFormatter DoCreate(FormatterVisitor visitor, SqlTableConstructorExpression codeObject)
+ {
+ return new SqlTableConstructorExpressionFormatter(visitor, codeObject);
+ }
+ }
+
+ internal class SqlTableConstructorExpressionFormatter : CommaSeparatedListFormatter
+ {
+ [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ public SqlTableConstructorExpressionFormatter(FormatterVisitor visitor, SqlTableConstructorExpression codeObject)
+ : base(visitor, codeObject, true)
+ {
+ }
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlTableDefinitionFormatter.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlTableDefinitionFormatter.cs
new file mode 100644
index 00000000..4b20e059
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlTableDefinitionFormatter.cs
@@ -0,0 +1,99 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Composition;
+using System.Linq;
+using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
+using Microsoft.SqlTools.ServiceLayer.Utility;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+ [Export(typeof(ASTNodeFormatterFactory))]
+ internal class SqlTableDefinitionFormatterFactory : ASTNodeFormatterFactoryT
+ {
+ protected override ASTNodeFormatter DoCreate(FormatterVisitor visitor, SqlTableDefinition codeObject)
+ {
+ return new SqlTableDefinitionFormatter(visitor, codeObject);
+ }
+ }
+
+ [Export(typeof(ASTNodeFormatter))]
+ internal class SqlTableDefinitionFormatter : ASTNodeFormatterT
+ {
+ private CommaSeparatedListFormatter CommaSeparatedListFormatter { get; set; }
+
+ public SqlTableDefinitionFormatter(FormatterVisitor visitor, SqlTableDefinition codeObject)
+ : base(visitor, codeObject)
+ {
+ CommaSeparatedListFormatter = new CommaSeparatedListFormatter(visitor, codeObject, true);
+
+ // figure out the size of paddings required to align column definitions in a "columnar" form
+ if (FormatOptions.AlignColumnDefinitionsInColumns)
+ {
+ int range1MaxLength = 0;
+ int range2MaxLength = 0;
+
+ foreach (SqlCodeObject child in CodeObject.Children)
+ {
+ if (child is SqlColumnDefinition && !(child is SqlComputedColumnDefinition))
+ {
+ SqlIdentifier identifierChild = child.Children.ElementAtOrDefault(0) as SqlIdentifier;
+
+ if (identifierChild == null)
+ {
+ throw new FormatFailedException("unexpected token at index start Token Index");
+ }
+
+ string s1 = child.TokenManager.GetText(identifierChild.Position.startTokenNumber, identifierChild.Position.endTokenNumber);
+ range1MaxLength = Math.Max(range1MaxLength, s1.Length);
+
+ SqlDataTypeSpecification dataTypeChildchild = child.Children.ElementAtOrDefault(1) as SqlDataTypeSpecification;
+
+ // token "timestamp" should be ignorred
+ if (dataTypeChildchild != null)
+ {
+ string s2 = child.TokenManager.GetText(dataTypeChildchild.Position.startTokenNumber, dataTypeChildchild.Position.endTokenNumber);
+ range2MaxLength = Math.Max(range2MaxLength, s2.Length);
+ }
+ }
+ }
+
+ PaddedSpaceSeparatedListFormatter.ColumnSpacingFormatDefinition d1 = new PaddedSpaceSeparatedListFormatter.ColumnSpacingFormatDefinition(typeof(SqlIdentifier), typeof(SqlDataTypeSpecification), range1MaxLength + 1);
+ PaddedSpaceSeparatedListFormatter.ColumnSpacingFormatDefinition d2 = new PaddedSpaceSeparatedListFormatter.ColumnSpacingFormatDefinition(typeof(SqlDataTypeSpecification), null, range2MaxLength + 1);
+ List columnSpacingFormatDefinitions = new List(2);
+ columnSpacingFormatDefinitions.Add(d1);
+ columnSpacingFormatDefinitions.Add(d2);
+ Visitor.Context.CurrentColumnSpacingFormatDefinitions = columnSpacingFormatDefinitions;
+ }
+ }
+
+ internal override void ProcessChild(SqlCodeObject child)
+ {
+ Validate.IsNotNull(nameof(child), child);
+ CommaSeparatedListFormatter.ProcessChild(child);
+ }
+
+ internal override void ProcessPrefixRegion(int startTokenNumber, int firstChildStartTokenNumber)
+ {
+ CommaSeparatedListFormatter.ProcessPrefixRegion(startTokenNumber, firstChildStartTokenNumber);
+ }
+
+ internal override void ProcessSuffixRegion(int lastChildEndTokenNumber, int endTokenNumber)
+ {
+ Visitor.Context.CurrentColumnSpacingFormatDefinitions = null;
+ CommaSeparatedListFormatter.ProcessSuffixRegion(lastChildEndTokenNumber, endTokenNumber);
+ }
+
+ internal override void ProcessInterChildRegion(SqlCodeObject previousChild, SqlCodeObject nextChild)
+ {
+ Validate.IsNotNull(nameof(previousChild), previousChild);
+ Validate.IsNotNull(nameof(nextChild), nextChild);
+
+ CommaSeparatedListFormatter.ProcessInterChildRegion(previousChild, nextChild);
+ }
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlViewDefinitionFormatter.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlViewDefinitionFormatter.cs
new file mode 100644
index 00000000..cd40334a
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SqlViewDefinitionFormatter.cs
@@ -0,0 +1,151 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+
+using System;
+using System.Collections.Generic;
+using System.Composition;
+using System.Diagnostics;
+using System.Globalization;
+using System.Linq;
+using Babel.ParserGenerator;
+using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+
+ [Export(typeof(ASTNodeFormatterFactory))]
+ internal class SqlViewDefinitionFormatterFactory : ASTNodeFormatterFactoryT
+ {
+ protected override ASTNodeFormatter DoCreate(FormatterVisitor visitor, SqlViewDefinition codeObject)
+ {
+ return new SqlViewDefinitionFormatter(visitor, codeObject);
+ }
+ }
+
+ class SqlViewDefinitionFormatter : SysCommentsFormatterBase
+ {
+
+ internal SqlViewDefinitionFormatter(FormatterVisitor visitor, SqlViewDefinition sqlCodeObject)
+ : base(visitor, sqlCodeObject)
+ {
+ }
+
+ protected override bool ShouldPlaceEachElementOnNewLine()
+ {
+ return true;
+ }
+
+ public override void Format()
+ {
+ LexLocation loc = CodeObject.Position;
+
+ SqlCodeObject firstChild = CodeObject.Children.FirstOrDefault();
+ if (firstChild != null)
+ {
+ //
+ // format the text from the start of the object to the start of its first child
+ //
+ LexLocation firstChildStart = firstChild.Position;
+ ProcessPrefixRegion(loc.startTokenNumber, firstChildStart.startTokenNumber);
+
+ ProcessChild(firstChild);
+
+ // keep track of the next token to process
+ int nextToken = firstChildStart.endTokenNumber;
+
+ // process the columns if available
+ nextToken = ProcessColumns(nextToken);
+
+ // process options if available
+ nextToken = ProcessOptions(nextToken);
+
+ // process the region containing the AS token
+ nextToken = ProcessAsToken(nextToken, indentAfterAs: true);
+
+ // process the query with clause if present
+ nextToken = ProcessQueryWithClause(nextToken);
+
+ // process the query expression
+ nextToken = ProcessQueryExpression(nextToken);
+
+ DecrementIndentLevel();
+
+ // format text from end of last child to end of object.
+ SqlCodeObject lastChild = CodeObject.Children.LastOrDefault();
+ Debug.Assert(lastChild != null, "last child is null. Need to write code to deal with this case");
+ ProcessSuffixRegion(lastChild.Position.endTokenNumber, loc.endTokenNumber);
+ }
+ else
+ {
+ // no children
+ Visitor.Context.ProcessTokenRange(loc.startTokenNumber, loc.endTokenNumber);
+ }
+ }
+
+ private int ProcessColumns(int nextToken)
+ {
+ if (CodeObject.ColumnList != null && CodeObject.ColumnList.Count > 0)
+ {
+ nextToken = ProcessSectionInsideParentheses(nextToken, FormatterUtilities.NormalizeNewLinesEnsureOneNewLineMinimum,
+ isNewlineRequired: true,
+ processSection: (n) => ProcessColumnList(n, CodeObject.ColumnList, FormatterUtilities.NormalizeNewLinesEnsureOneNewLineMinimum));
+ }
+ return nextToken;
+ }
+
+ private int ProcessOptions(int nextToken)
+ {
+ if (CodeObject.Options != null && CodeObject.Options.Count > 0)
+ {
+ int withTokenIndex = FindTokenWithId(nextToken, FormatterTokens.TOKEN_WITH);
+
+ // Preprocess
+ ProcessTokenRangeEnsuringOneNewLineMinumum(nextToken, withTokenIndex);
+
+ nextToken = ProcessWithStatementStart(nextToken, withTokenIndex);
+
+ nextToken = ProcessOptionsSection(nextToken);
+
+ DecrementIndentLevel();
+ }
+ return nextToken;
+ }
+
+ private int ProcessOptionsSection(int nextToken)
+ {
+ // find where the options start
+ IEnumerator optionEnum = CodeObject.Options.GetEnumerator();
+ if (optionEnum.MoveNext())
+ {
+ ProcessAndNormalizeWhitespaceRange(nextToken, optionEnum.Current.Position.startTokenNumber,
+ FormatterUtilities.NormalizeNewLinesEnsureOneNewLineMinimum);
+
+ // Process options
+ ProcessChild(optionEnum.Current);
+ SqlModuleOption previousOption = optionEnum.Current;
+ while (optionEnum.MoveNext())
+ {
+ CommaSeparatedList.ProcessInterChildRegion(previousOption, optionEnum.Current);
+ ProcessChild(optionEnum.Current);
+ previousOption = optionEnum.Current;
+ }
+ nextToken = previousOption.Position.endTokenNumber;
+ }
+
+ return nextToken;
+ }
+
+ private int ProcessQueryWithClause(int nextToken)
+ {
+ return ProcessQuerySection(nextToken, CodeObject.QueryWithClause);
+ }
+
+ private int ProcessQueryExpression(int nextToken)
+ {
+ return ProcessQuerySection(nextToken, CodeObject.QueryExpression);
+ }
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SysCommentsFormatterBase.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SysCommentsFormatterBase.cs
new file mode 100644
index 00000000..885702a9
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/SysCommentsFormatterBase.cs
@@ -0,0 +1,210 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using Babel.ParserGenerator;
+using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+ ///
+ /// Common base class for objects dealing with sys comments. These follow
+ /// similar patterns so identical methods are held here
+ ///
+ internal abstract class SysCommentsFormatterBase : ASTNodeFormatterT
+ where T : SqlCodeObject
+ {
+
+ internal CommaSeparatedListFormatter CommaSeparatedList { get; set; }
+
+ public SysCommentsFormatterBase(FormatterVisitor visitor, T codeObject)
+ : base(visitor, codeObject)
+ {
+ CommaSeparatedList = new CommaSeparatedListFormatter(Visitor, CodeObject, ShouldPlaceEachElementOnNewLine());
+ }
+
+ protected abstract bool ShouldPlaceEachElementOnNewLine();
+
+ protected void ProcessTokenEnsuringOneNewLineMinimum(int tokenIndex)
+ {
+ ProcessTokenAndNormalize(tokenIndex, FormatterUtilities.NormalizeNewLinesEnsureOneNewLineMinimum);
+ }
+
+
+ ///
+ /// processes any section in a query, since the basic behavior is constant
+ ///
+ protected int ProcessQuerySection(int nextToken, SqlCodeObject queryObject)
+ {
+ if (queryObject != null)
+ {
+ ProcessAndNormalizeWhitespaceRange(nextToken, queryObject.Position.startTokenNumber,
+ FormatterUtilities.NormalizeNewLinesEnsureOneNewLineMinimum);
+ ProcessChild(queryObject);
+ nextToken = queryObject.Position.endTokenNumber;
+ }
+ return nextToken;
+ }
+
+ protected int ProcessSectionInsideParentheses(int nextToken, NormalizeWhitespace normalizer, bool isNewlineRequired,
+ Func processSection)
+ {
+ int openParenIndex = FindOpenParenthesis(nextToken);
+ ProcessAndNormalizeWhitespaceRange(nextToken, openParenIndex, normalizer);
+ nextToken = ProcessOpenParenthesis(nextToken, openParenIndex, isNewlineRequired);
+
+ nextToken = processSection(nextToken);
+
+ int closedParenIndex = FindClosedParenthesis(nextToken);
+
+ ProcessRegionBeforeClosedParenthesis(nextToken, closedParenIndex, normalizer, isNewlineRequired);
+
+ // Process closed parenthesis
+ ProcessTokenRange(closedParenIndex, closedParenIndex + 1);
+ nextToken = closedParenIndex + 1;
+
+ return nextToken;
+ }
+
+ protected int FindOpenParenthesis(int openParenIndex)
+ {
+ return FindTokenWithId(openParenIndex, 40);
+ }
+
+ protected int FindClosedParenthesis(int nextToken)
+ {
+ return FindTokenWithId(nextToken, 41);
+ }
+
+ ///
+ /// if there was no whitespace before the parenthesis to be converted into a newline,
+ /// and the references need to be on a newline, then append a newline
+ ///
+ protected int ProcessOpenParenthesis(int nextToken, int openParenIndex, bool isNewlineRequired)
+ {
+ return ProcessCompoundStatementStart(ref nextToken, openParenIndex, isNewlineRequired);
+ }
+
+ protected int ProcessWithStatementStart(int nextToken, int withTokenIndex)
+ {
+ return ProcessCompoundStatementStart(ref nextToken, withTokenIndex, true);
+ }
+
+ protected int ProcessCompoundStatementStart(ref int nextToken, int compoundStartIndex, bool isNewlineRequired)
+ {
+ // if a newline is required and there was no whitespace before the start to be
+ // converted into a newline, then append a newline
+ if (isNewlineRequired
+ && (nextToken >= compoundStartIndex
+ || !IsTokenWhitespace(PreviousTokenData(compoundStartIndex))))
+ {
+ // Note: nextToken index value does not match the Startindex of the TokenData. When adding
+ // indentation, always get the TokenData and its StartIndex value
+ TokenData td = GetTokenData(compoundStartIndex);
+ AddIndentedNewLineReplacement(td.StartIndex);
+ }
+ ProcessTokenRange(compoundStartIndex, compoundStartIndex + 1);
+ IncrementIndentLevel();
+
+ // Move our pointer past the start of the compount statement
+ nextToken = compoundStartIndex + 1;
+ TokenData nextTokenData = GetTokenData(nextToken);
+
+ // Ensure a newline after the open parenthesis
+ if (isNewlineRequired
+ && !IsTokenWhitespace(nextTokenData))
+ {
+ AddIndentedNewLineReplacement(nextTokenData.StartIndex);
+ }
+ return nextToken;
+ }
+
+ protected void ProcessRegionBeforeClosedParenthesis(int startIndex, int closedParenIndex, NormalizeWhitespace normalizer, bool isNewlineRequired)
+ {
+ for (int i = startIndex; i < closedParenIndex - 1; i++)
+ {
+ ProcessTokenAndNormalize(i, normalizer);
+ }
+ DecrementIndentLevel();
+ if (startIndex < closedParenIndex)
+ {
+ SimpleProcessToken(closedParenIndex - 1, normalizer);
+ }
+
+ // Enforce a whitespace before the closing parenthesis
+ TokenData td = PreviousTokenData(closedParenIndex);
+ if (isNewlineRequired && !IsTokenWhitespace(td))
+ {
+ td = GetTokenData(closedParenIndex);
+ AddIndentedNewLineReplacement(td.StartIndex);
+ }
+ }
+
+ protected int ProcessColumnList(int nextToken, SqlIdentifierCollection columnList, NormalizeWhitespace normalizer)
+ {
+ // find where the columns start
+ IEnumerator columnEnum = columnList.GetEnumerator();
+ if (columnEnum.MoveNext())
+ {
+ ProcessAndNormalizeWhitespaceRange(nextToken, columnEnum.Current.Position.startTokenNumber, normalizer);
+
+ ProcessChild(columnEnum.Current);
+ SqlIdentifier previousColumn = columnEnum.Current;
+ while (columnEnum.MoveNext())
+ {
+ CommaSeparatedList.ProcessInterChildRegion(previousColumn, columnEnum.Current);
+ ProcessChild(columnEnum.Current);
+ previousColumn = columnEnum.Current;
+ }
+ nextToken = previousColumn.Position.endTokenNumber;
+ }
+ return nextToken;
+ }
+
+ protected int ProcessAsToken(int nextToken, bool indentAfterAs)
+ {
+ int asTokenIndex = FindTokenWithId(nextToken, FormatterTokens.TOKEN_AS);
+
+ // Preprocess
+ ProcessTokenRangeEnsuringOneNewLineMinumum(nextToken, asTokenIndex);
+
+ // Process As
+ if (nextToken >= asTokenIndex
+ || !IsTokenWhitespace(PreviousTokenData(asTokenIndex)))
+ {
+ TokenData td = GetTokenData(asTokenIndex);
+ AddIndentedNewLineReplacement(td.StartIndex);
+ }
+ ProcessTokenRange(asTokenIndex, asTokenIndex + 1);
+
+ if (indentAfterAs)
+ {
+ IncrementIndentLevel();
+ }
+ // Post Process
+ nextToken = EnsureWhitespaceAfterAs(asTokenIndex);
+
+ return nextToken;
+ }
+
+ private int EnsureWhitespaceAfterAs(int asTokenIndex)
+ {
+ int nextToken = asTokenIndex + 1;
+ Debug.Assert(nextToken < CodeObject.Position.endTokenNumber, "View definition ends unexpectedly after the AS token.");
+
+ TokenData nextTokenData = GetTokenData(nextToken);
+ // Ensure a whitespace after the "AS" token
+ if (!IsTokenWhitespace(nextTokenData))
+ {
+ AddIndentedNewLineReplacement(nextTokenData.StartIndex);
+ }
+
+ return nextToken;
+ }
+
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/WhiteSpaceSeparatedListFormatter.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/WhiteSpaceSeparatedListFormatter.cs
new file mode 100644
index 00000000..4ac931d2
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/Impl/WhiteSpaceSeparatedListFormatter.cs
@@ -0,0 +1,75 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
+using Microsoft.SqlTools.ServiceLayer.Utility;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+ ///
+ /// Base class for a set of utility formatters that are used by Node-specific formatters when dealing with whitespace
+ ///
+ internal abstract class WhiteSpaceSeparatedListFormatter : ASTNodeFormatterT
+ {
+ private bool IncremenetIndentLevelOnPrefixRegion { get; set; }
+
+ ///
+ /// This constructor initalizes the and properties since the formatter's entry point
+ /// is not the Format method
+ ///
+ ///
+ ///
+ ///
+ internal WhiteSpaceSeparatedListFormatter(FormatterVisitor visitor, SqlCodeObject codeObject, bool incrementIndentLevelOnPrefixRegion)
+ : base(visitor, codeObject)
+ {
+ IncremenetIndentLevelOnPrefixRegion = incrementIndentLevelOnPrefixRegion;
+ }
+
+ internal override void ProcessPrefixRegion(int startTokenNumber, int firstChildStartTokenNumber)
+ {
+ if (IncremenetIndentLevelOnPrefixRegion)
+ {
+ IncrementIndentLevel();
+ }
+ base.ProcessPrefixRegion(startTokenNumber, firstChildStartTokenNumber);
+ }
+
+ internal override void ProcessSuffixRegion(int lastChildEndTokenNumber, int endTokenNumber)
+ {
+ if (IncremenetIndentLevelOnPrefixRegion)
+ {
+ DecrementIndentLevel();
+ }
+ base.ProcessSuffixRegion(lastChildEndTokenNumber, endTokenNumber);
+ }
+
+ internal override void ProcessInterChildRegion(SqlCodeObject previousChild, SqlCodeObject nextChild)
+ {
+ Validate.IsNotNull(nameof(previousChild), previousChild);
+ Validate.IsNotNull(nameof(nextChild), nextChild);
+
+ int start = previousChild.Position.endTokenNumber;
+ int end = nextChild.Position.startTokenNumber;
+
+ if (start < end)
+ {
+ for (int i = start; i < end; i++)
+ {
+ SimpleProcessToken(i, FormatWhitespace);
+ }
+ }
+ else
+ {
+ // Insert the minimum whitespace
+ string minWhite = FormatWhitespace(" ", Visitor.Context);
+ int insertLocation = TokenManager.TokenList[start].StartIndex;
+ AddReplacement(insertLocation, "", minWhite);
+ }
+ }
+
+ internal abstract string FormatWhitespace(string original, FormatContext context);
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Formatter/TSqlFormatterService.cs b/src/Microsoft.SqlTools.ServiceLayer/Formatter/TSqlFormatterService.cs
new file mode 100644
index 00000000..c6afa157
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Formatter/TSqlFormatterService.cs
@@ -0,0 +1,266 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Composition;
+using System.IO;
+using System.Threading.Tasks;
+using Microsoft.SqlServer.Management.SqlParser.Parser;
+using Microsoft.SqlTools.ServiceLayer.Extensibility;
+using Microsoft.SqlTools.ServiceLayer.Formatter.Contracts;
+using Microsoft.SqlTools.ServiceLayer.Hosting;
+using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
+using Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts;
+using Microsoft.SqlTools.ServiceLayer.SqlContext;
+using Microsoft.SqlTools.ServiceLayer.Utility;
+using Microsoft.SqlTools.ServiceLayer.Workspace;
+using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts;
+
+namespace Microsoft.SqlTools.ServiceLayer.Formatter
+{
+
+ [Export(typeof(IHostedService))]
+ public class TSqlFormatterService : HostedService, IComposableService
+ {
+ private FormatterSettings settings;
+ ///
+ /// The default constructor is required for MEF-based composable services
+ ///
+ public TSqlFormatterService()
+ {
+ settings = new FormatterSettings();
+ }
+
+ public override void InitializeService(IProtocolEndpoint serviceHost)
+ {
+ serviceHost.SetRequestHandler(DocumentFormattingRequest.Type, HandleDocFormatRequest);
+ serviceHost.SetRequestHandler(DocumentRangeFormattingRequest.Type, HandleDocRangeFormatRequest);
+
+ WorkspaceService?.RegisterConfigChangeCallback(HandleDidChangeConfigurationNotification);
+ }
+
+ ///
+ /// Gets the workspace service. Note: should handle case where this is null in cases where unit tests do not set this up
+ ///
+ private WorkspaceService WorkspaceService
+ {
+ get { return ServiceProvider.GetService>(); }
+ }
+
+
+ ///
+ /// Ensure formatter settings are always up to date
+ ///
+ public Task HandleDidChangeConfigurationNotification(
+ SqlToolsSettings newSettings,
+ SqlToolsSettings oldSettings,
+ EventContext eventContext)
+ {
+ // update the current settings to reflect any changes (assuming formatter settings exist)
+ settings = newSettings.SqlTools.Format ?? settings;
+ return Task.FromResult(true);
+ }
+
+ public async Task HandleDocFormatRequest(DocumentFormattingParams docFormatParams, RequestContext requestContext)
+ {
+ Func> requestHandler = () =>
+ {
+ return FormatAndReturnEdits(docFormatParams);
+ };
+ await HandleRequest(requestHandler, requestContext, "HandleDocFormatRequest");
+ }
+
+ public async Task HandleDocRangeFormatRequest(DocumentRangeFormattingParams docRangeFormatParams, RequestContext requestContext)
+ {
+ Func> requestHandler = () =>
+ {
+ return FormatRangeAndReturnEdits(docRangeFormatParams);
+ };
+ await HandleRequest(requestHandler, requestContext, "HandleDocRangeFormatRequest");
+ }
+
+ private async Task FormatRangeAndReturnEdits(DocumentRangeFormattingParams docFormatParams)
+ {
+ return await Task.Factory.StartNew(() =>
+ {
+ var range = docFormatParams.Range;
+ ScriptFile scriptFile = GetFile(docFormatParams);
+ TextEdit textEdit = new TextEdit { Range = range };
+ string text = scriptFile.GetTextInRange(range.ToBufferRange());
+ return DoFormat(docFormatParams, textEdit, text);
+ });
+ }
+
+ private async Task FormatAndReturnEdits(DocumentFormattingParams docFormatParams)
+ {
+ return await Task.Factory.StartNew(() =>
+ {
+ var scriptFile = GetFile(docFormatParams);
+ if (scriptFile.FileLines.Count == 0)
+ {
+ return new TextEdit[0];
+ }
+ TextEdit textEdit = PrepareEdit(scriptFile);
+ string text = scriptFile.Contents;
+ return DoFormat(docFormatParams, textEdit, text);
+ });
+ }
+
+ private TextEdit[] DoFormat(DocumentFormattingParams docFormatParams, TextEdit edit, string text)
+ {
+ Validate.IsNotNull(nameof(docFormatParams), docFormatParams);
+
+ FormatOptions options = GetOptions(docFormatParams);
+ List edits = new List();
+ edit.NewText = Format(text, options, false);
+ // TODO do not add if no formatting needed?
+ edits.Add(edit);
+ return edits.ToArray();
+ }
+
+ private FormatOptions GetOptions(DocumentFormattingParams docFormatParams)
+ {
+ FormatOptions options = new FormatOptions();
+ if (docFormatParams.Options != null)
+ {
+ options.UseSpaces = docFormatParams.Options.InsertSpaces;
+ options.SpacesPerIndent = docFormatParams.Options.TabSize;
+ }
+ if (settings != null)
+ {
+ if (settings.AlignColumnDefinitionsInColumns.HasValue) { options.AlignColumnDefinitionsInColumns = settings.AlignColumnDefinitionsInColumns.Value; }
+
+ if (settings.PlaceCommasBeforeNextStatement.HasValue) { options.PlaceCommasBeforeNextStatement = settings.PlaceCommasBeforeNextStatement.Value; }
+
+ if (settings.PlaceSelectStatementReferencesOnNewLine.HasValue) { options.PlaceEachReferenceOnNewLineInQueryStatements = settings.PlaceSelectStatementReferencesOnNewLine.Value; }
+
+ if (settings.UseBracketForIdentifiers.HasValue) { options.EncloseIdentifiersInSquareBrackets = settings.UseBracketForIdentifiers.Value; }
+
+ }
+ return options;
+ }
+
+ internal static void UpdateFormatOptionsFromSettings(FormatOptions options, FormatterSettings settings)
+ {
+ Validate.IsNotNull(nameof(options), options);
+ if (settings != null)
+ {
+ if (settings.AlignColumnDefinitionsInColumns.HasValue) { options.AlignColumnDefinitionsInColumns = settings.AlignColumnDefinitionsInColumns.Value; }
+
+ if (settings.PlaceCommasBeforeNextStatement.HasValue) { options.PlaceCommasBeforeNextStatement = settings.PlaceCommasBeforeNextStatement.Value; }
+
+ if (settings.PlaceSelectStatementReferencesOnNewLine.HasValue) { options.PlaceEachReferenceOnNewLineInQueryStatements = settings.PlaceSelectStatementReferencesOnNewLine.Value; }
+
+ if (settings.UseBracketForIdentifiers.HasValue) { options.EncloseIdentifiersInSquareBrackets = settings.UseBracketForIdentifiers.Value; }
+
+ options.DatatypeCasing = settings.DatatypeCasing;
+ options.KeywordCasing = settings.KeywordCasing;
+ }
+ }
+
+ private ScriptFile GetFile(DocumentFormattingParams docFormatParams)
+ {
+ return WorkspaceService.Workspace.GetFile(docFormatParams.TextDocument.Uri);
+ }
+
+ private static TextEdit PrepareEdit(ScriptFile scriptFile)
+ {
+ int fileLines = scriptFile.FileLines.Count;
+ Position start = new Position { Line = 0, Character = 0 };
+ int lastChar = scriptFile.FileLines[scriptFile.FileLines.Count - 1].Length;
+ Position end = new Position { Line = scriptFile.FileLines.Count - 1, Character = lastChar };
+
+ TextEdit edit = new TextEdit
+ {
+ Range = new Range { Start = start, End = end }
+ };
+ return edit;
+ }
+
+ private async Task HandleRequest(Func> handler, RequestContext requestContext, string requestType)
+ {
+ Logger.Write(LogLevel.Verbose, requestType);
+
+ try
+ {
+ T result = await handler();
+ await requestContext.SendResult(result);
+ }
+ catch (Exception ex)
+ {
+ await requestContext.SendError(ex.ToString());
+ }
+ }
+
+
+
+ public string Format(TextReader input)
+ {
+ string originalSql = input.ReadToEnd();
+ return Format(originalSql, new FormatOptions());
+ }
+
+ public string Format(string input, FormatOptions options)
+ {
+ return Format(input, options, true);
+ }
+
+ public string Format(string input, FormatOptions options, bool verifyOutput)
+ {
+ string result = null;
+ DoFormat(input, options, verifyOutput, visitor =>
+ {
+ result = visitor.Context.FormattedSql;
+ });
+
+ return result;
+ }
+
+ public void Format(string input, FormatOptions options, bool verifyOutput, Replacement.OnReplace replace)
+ {
+ DoFormat(input, options, verifyOutput, visitor =>
+ {
+ foreach (Replacement r in visitor.Context.Replacements)
+ {
+ r.Apply(replace);
+ }
+ });
+ }
+
+ private void DoFormat(string input, FormatOptions options, bool verifyOutput, Action postFormatAction)
+ {
+ Validate.IsNotNull(nameof(input), input);
+ Validate.IsNotNull(nameof(options), options);
+
+ ParseResult result = Parser.Parse(input);
+ FormatContext context = new FormatContext(result.Script, options);
+
+ FormatterVisitor visitor = new FormatterVisitor(context, ServiceProvider);
+ result.Script.Accept(visitor);
+ if (verifyOutput)
+ {
+ visitor.VerifyFormat();
+ }
+
+ postFormatAction?.Invoke(visitor);
+ }
+ }
+
+ internal static class RangeExtensions
+ {
+ public static BufferRange ToBufferRange(this Range range)
+ {
+ // It turns out that VSCode sends Range objects as 0-indexed lines, while
+ // our BufferPosition and BufferRange logic assumes 1-indexed. Therefore
+ // need to increment all ranges by 1 when copying internally and reduce
+ // when returning to the caller
+ return new BufferRange(
+ new BufferPosition(range.Start.Line + 1, range.Start.Character + 1),
+ new BufferPosition(range.End.Line + 1, range.End.Character + 1)
+ );
+ }
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/HostLoader.cs b/src/Microsoft.SqlTools.ServiceLayer/HostLoader.cs
new file mode 100644
index 00000000..429e3732
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/HostLoader.cs
@@ -0,0 +1,105 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.SqlTools.ServiceLayer.Connection;
+using Microsoft.SqlTools.ServiceLayer.Credentials;
+using Microsoft.SqlTools.ServiceLayer.Extensibility;
+using Microsoft.SqlTools.ServiceLayer.Hosting;
+using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
+using Microsoft.SqlTools.ServiceLayer.LanguageServices;
+using Microsoft.SqlTools.ServiceLayer.QueryExecution;
+using Microsoft.SqlTools.ServiceLayer.SqlContext;
+using Microsoft.SqlTools.ServiceLayer.Workspace;
+
+namespace Microsoft.SqlTools.ServiceLayer
+{
+ ///
+ /// Provides support for starting up a service host. This is a common responsibility
+ /// for both the main service program and test driver that interacts with it
+ ///
+ public static class HostLoader
+ {
+ private static object lockObject = new object();
+ private static bool isLoaded;
+
+ internal static ServiceHost CreateAndStartServiceHost(SqlToolsContext sqlToolsContext)
+ {
+ ServiceHost serviceHost = ServiceHost.Instance;
+ lock (lockObject)
+ {
+ if (!isLoaded)
+ {
+ // Grab the instance of the service host
+ serviceHost.Initialize();
+
+ InitializeRequestHandlersAndServices(serviceHost, sqlToolsContext);
+
+ // Start the service only after all request handlers are setup. This is vital
+ // as otherwise the Initialize event can be lost - it's processed and discarded before the handler
+ // is hooked up to receive the message
+ serviceHost.Start().Wait();
+ isLoaded = true;
+ }
+ }
+ return serviceHost;
+ }
+
+ private static void InitializeRequestHandlersAndServices(ServiceHost serviceHost, SqlToolsContext sqlToolsContext)
+ {
+ // Load extension provider, which currently finds all exports in current DLL. Can be changed to find based
+ // on directory or assembly list quite easily in the future
+ ExtensionServiceProvider serviceProvider = ExtensionServiceProvider.CreateDefaultServiceProvider();
+ serviceProvider.RegisterSingleService(sqlToolsContext);
+ serviceProvider.RegisterSingleService(serviceHost);
+
+ // Initialize and register singleton services so they're accessible for any MEF service. In the future, these
+ // could be updated to be IComposableServices, which would avoid the requirement to define a singleton instance
+ // and instead have MEF handle discovery & loading
+ WorkspaceService.Instance.InitializeService(serviceHost);
+ serviceProvider.RegisterSingleService(WorkspaceService.Instance);
+
+ LanguageService.Instance.InitializeService(serviceHost, sqlToolsContext);
+ serviceProvider.RegisterSingleService(LanguageService.Instance);
+
+ ConnectionService.Instance.InitializeService(serviceHost);
+ serviceProvider.RegisterSingleService(ConnectionService.Instance);
+
+ CredentialService.Instance.InitializeService(serviceHost);
+ serviceProvider.RegisterSingleService(CredentialService.Instance);
+
+ QueryExecutionService.Instance.InitializeService(serviceHost);
+ serviceProvider.RegisterSingleService(QueryExecutionService.Instance);
+
+ InitializeHostedServices(serviceProvider, serviceHost);
+
+ serviceHost.InitializeRequestHandlers();
+ }
+
+ ///
+ /// Internal to support testing. Initializes instances in the service,
+ /// and registers them for their preferred service type
+ ///
+ internal static void InitializeHostedServices(RegisteredServiceProvider provider, IProtocolEndpoint host)
+ {
+ // Pre-register all services before initializing. This ensures that if one service wishes to reference
+ // another one during initialization, it will be able to safely do so
+ foreach (IHostedService service in provider.GetServices())
+ {
+ provider.RegisterSingleService(service.ServiceType, service);
+ }
+
+ foreach (IHostedService service in provider.GetServices())
+ {
+ // Initialize all hosted services, and register them in the service provider for their requested
+ // service type. This ensures that when searching for the ConnectionService you can get it without
+ // searching for an IHostedService of type ConnectionService
+ service.InitializeService(host);
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Hosting/Contracts/ServerCapabilities.cs b/src/Microsoft.SqlTools.ServiceLayer/Hosting/Contracts/ServerCapabilities.cs
index 32f0e736..cba641da 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/Hosting/Contracts/ServerCapabilities.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/Hosting/Contracts/ServerCapabilities.cs
@@ -21,6 +21,10 @@ namespace Microsoft.SqlTools.ServiceLayer.Hosting.Contracts
public bool? DocumentHighlightProvider { get; set; }
+ public bool? DocumentFormattingProvider { get; set; }
+
+ public bool? DocumentRangeFormattingProvider { get; set; }
+
public bool? DocumentSymbolProvider { get; set; }
public bool? WorkspaceSymbolProvider { get; set; }
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Hosting/IHostedService.cs b/src/Microsoft.SqlTools.ServiceLayer/Hosting/IHostedService.cs
new file mode 100644
index 00000000..848c5820
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Hosting/IHostedService.cs
@@ -0,0 +1,71 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+using Microsoft.SqlTools.ServiceLayer.Extensibility;
+using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
+
+namespace Microsoft.SqlTools.ServiceLayer.Hosting
+{
+ ///
+ /// Defines a hosted service that communicates with external processes via
+ /// messages passed over the . The service defines
+ /// a standard initialization method where it can hook up to the host.
+ ///
+ public interface IHostedService
+ {
+ ///
+ /// Callback to initialize this service
+ ///
+ /// which supports registering
+ /// event handlers and other callbacks for messages passed to external callers
+ void InitializeService(IProtocolEndpoint serviceHost);
+
+ ///
+ /// What is the service type that you wish to register?
+ ///
+ Type ServiceType { get; }
+ }
+
+ ///
+ /// Base class for implementations that handles defining the
+ /// being registered. This simplifies service registration. This also implements which
+ /// allows injection of the service provider for lookup of other services.
+ ///
+ /// Extending classes should implement per below code example
+ ///
+ /// [Export(typeof(IHostedService)]
+ /// MyService : HostedService<MyService>
+ /// {
+ /// public override void InitializeService(IProtocolEndpoint serviceHost)
+ /// {
+ /// serviceHost.SetRequestHandler(MyRequest.Type, HandleMyRequest);
+ /// }
+ /// }
+ ///
+ ///
+ /// Type to be registered for lookup in the service provider
+ public abstract class HostedService : IHostedService, IComposableService
+ {
+
+ protected IMultiServiceProvider ServiceProvider { get; private set; }
+
+ public void SetServiceProvider(IMultiServiceProvider provider)
+ {
+ ServiceProvider = provider;
+ }
+
+ public Type ServiceType
+ {
+ get
+ {
+ return typeof(T);
+ }
+ }
+
+ public abstract void InitializeService(IProtocolEndpoint serviceHost);
+
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Hosting/Protocol/ProtocolEndpoint.cs b/src/Microsoft.SqlTools.ServiceLayer/Hosting/Protocol/ProtocolEndpoint.cs
index 2a0652ac..9c9eda9e 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/Hosting/Protocol/ProtocolEndpoint.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/Hosting/Protocol/ProtocolEndpoint.cs
@@ -19,6 +19,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Hosting.Protocol
///
public class ProtocolEndpoint : IProtocolEndpoint
{
+ private bool isInitialized;
private bool isStarted;
private int currentMessageId;
private ChannelBase protocolChannel;
@@ -64,12 +65,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Hosting.Protocol
}
///
- /// Starts the language server client and sends the Initialize method.
+ /// Initializes
///
- /// A Task that can be awaited for initialization to complete.
- public async Task Start()
+ public void Initialize()
{
- if (!this.isStarted)
+ if (!this.isInitialized)
{
// Start the provided protocol channel
this.protocolChannel.Start(this.messageProtocolType);
@@ -83,6 +83,19 @@ namespace Microsoft.SqlTools.ServiceLayer.Hosting.Protocol
// Listen for unhandled exceptions from the dispatcher
this.MessageDispatcher.UnhandledException += MessageDispatcher_UnhandledException;
+ this.isInitialized = true;
+ }
+ }
+
+ ///
+ /// Starts the language server client and sends the Initialize method.
+ ///
+ /// A Task that can be awaited for initialization to complete.
+ public async Task Start()
+ {
+ if (!this.isStarted)
+ {
+
// Notify implementation about endpoint start
await this.OnStart();
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Hosting/ServiceHost.cs b/src/Microsoft.SqlTools.ServiceLayer/Hosting/ServiceHost.cs
index 93136013..c33a289f 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/Hosting/ServiceHost.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/Hosting/ServiceHost.cs
@@ -58,7 +58,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Hosting
///
/// Provide initialization that must occur after the service host is started
///
- public void Initialize()
+ public void InitializeRequestHandlers()
{
// Register the requests that this service host will handle
this.SetRequestHandler(InitializeRequest.Type, this.HandleInitializeRequest);
@@ -153,6 +153,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Hosting
TextDocumentSync = TextDocumentSyncKind.Incremental,
DefinitionProvider = true,
ReferencesProvider = false,
+ DocumentFormattingProvider = true,
+ DocumentRangeFormattingProvider = true,
DocumentHighlightProvider = false,
HoverProvider = true,
CompletionProvider = new CompletionOptions
diff --git a/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/Contracts/Completion.cs b/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/Contracts/Completion.cs
index 64c0464f..b018bc97 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/Contracts/Completion.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/Contracts/Completion.cs
@@ -45,14 +45,6 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts
Reference = 18
}
- [DebuggerDisplay("NewText = {NewText}, Range = {Range.Start.Line}:{Range.Start.Character} - {Range.End.Line}:{Range.End.Character}")]
- public class TextEdit
- {
- public Range Range { get; set; }
-
- public string NewText { get; set; }
- }
-
[DebuggerDisplay("Kind = {Kind.ToString()}, Label = {Label}, Detail = {Detail}")]
public class CompletionItem
{
diff --git a/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/Contracts/TextEdit.cs b/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/Contracts/TextEdit.cs
new file mode 100644
index 00000000..45769639
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/Contracts/TextEdit.cs
@@ -0,0 +1,20 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System.Diagnostics;
+using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts;
+
+namespace Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts
+{
+
+ [DebuggerDisplay("NewText = {NewText}, Range = {Range.Start.Line}:{Range.Start.Character} - {Range.End.Line}:{Range.End.Character}")]
+ public class TextEdit
+ {
+ public Range Range { get; set; }
+
+ public string NewText { get; set; }
+ }
+
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Program.cs b/src/Microsoft.SqlTools.ServiceLayer/Program.cs
index 25bc92b1..1d1310a7 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/Program.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/Program.cs
@@ -4,11 +4,6 @@
using System;
using Microsoft.SqlTools.ServiceLayer.Hosting;
using Microsoft.SqlTools.ServiceLayer.SqlContext;
-using Microsoft.SqlTools.ServiceLayer.Workspace;
-using Microsoft.SqlTools.ServiceLayer.LanguageServices;
-using Microsoft.SqlTools.ServiceLayer.Connection;
-using Microsoft.SqlTools.ServiceLayer.QueryExecution;
-using Microsoft.SqlTools.ServiceLayer.Credentials;
using Microsoft.SqlTools.ServiceLayer.Utility;
namespace Microsoft.SqlTools.ServiceLayer
@@ -36,25 +31,13 @@ namespace Microsoft.SqlTools.ServiceLayer
Logger.Write(LogLevel.Normal, "Starting SQL Tools Service Host");
// set up the host details and profile paths
- var hostDetails = new HostDetails(version: new Version(1,0));
+ var hostDetails = new HostDetails(version: new Version(1, 0));
SqlToolsContext sqlToolsContext = new SqlToolsContext(hostDetails);
+ ServiceHost serviceHost = HostLoader.CreateAndStartServiceHost(sqlToolsContext);
- // Grab the instance of the service host
- ServiceHost serviceHost = ServiceHost.Instance;
-
- // Start the service
- serviceHost.Start().Wait();
-
- // Initialize the services that will be hosted here
- WorkspaceService.Instance.InitializeService(serviceHost);
- LanguageService.Instance.InitializeService(serviceHost, sqlToolsContext);
- ConnectionService.Instance.InitializeService(serviceHost);
- CredentialService.Instance.InitializeService(serviceHost);
- QueryExecutionService.Instance.InitializeService(serviceHost);
-
- serviceHost.Initialize();
serviceHost.WaitForExit();
}
+
}
}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlContext/FormatterSettings.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlContext/FormatterSettings.cs
new file mode 100644
index 00000000..f6bb6bfe
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/SqlContext/FormatterSettings.cs
@@ -0,0 +1,88 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using Microsoft.SqlTools.ServiceLayer.Formatter;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Converters;
+
+namespace Microsoft.SqlTools.ServiceLayer.SqlContext
+{
+ ///
+ /// Contract for receiving formatter-specific settings as part of workspace settings
+ ///
+ public class FormatterSettings
+ {
+ ///
+ /// Should names be escaped, for example converting dbo.T1 to [dbo].[T1]
+ ///
+ public bool? UseBracketForIdentifiers
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Should comma separated lists have the comma be at the start of a new line.
+ ///
+ /// CREATE TABLE T1 (
+ /// C1 INT
+ /// , C2 INT)
+ ///
+ ///
+ public bool? PlaceCommasBeforeNextStatement
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Should each reference be on its own line or should references to multiple objects
+ /// be kept on a single line
+ ///
+ /// SELECT *
+ /// FROM T1,
+ /// T2
+ ///
+ ///
+ public bool? PlaceSelectStatementReferencesOnNewLine
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Should keyword casing be ignored, converted to all uppercase, or
+ /// converted to all lowercase
+ ///
+ [JsonConverter(typeof(StringEnumConverter))]
+ public CasingOptions KeywordCasing
+ {
+ get;
+ set;
+ }
+
+
+ ///
+ /// Should data type casing be ignored, converted to all uppercase, or
+ /// converted to all lowercase
+ ///
+ [JsonConverter(typeof(StringEnumConverter))]
+ public CasingOptions DatatypeCasing
+ {
+ get;
+ set;
+ }
+
+
+ ///
+ /// Should column definitions be aligned or left non-aligned?
+ ///
+ public bool? AlignColumnDefinitionsInColumns
+ {
+ get;
+ set;
+ }
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlContext/SqlToolsSettings.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlContext/SqlToolsSettings.cs
index 0359df16..93f677ed 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/SqlContext/SqlToolsSettings.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/SqlContext/SqlToolsSettings.cs
@@ -113,9 +113,9 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlContext
///
public SqlToolsSettingsValues()
{
-
- this.IntelliSense = new IntelliSenseSettings();
- this.QueryExecutionSettings = new QueryExecutionSettings();
+ IntelliSense = new IntelliSenseSettings();
+ QueryExecutionSettings = new QueryExecutionSettings();
+ Format = new FormatterSettings();
}
///
@@ -127,5 +127,11 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlContext
/// Gets or sets the query execution settings
///
public QueryExecutionSettings QueryExecutionSettings { get; set; }
+
+ ///
+ /// Gets or sets the formatter settings
+ ///
+ [JsonProperty("format")]
+ public FormatterSettings Format { get; set; }
}
}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Workspace/Contracts/FilePosition.cs b/src/Microsoft.SqlTools.ServiceLayer/Workspace/Contracts/FilePosition.cs
index 65fe268a..ae507af7 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/Workspace/Contracts/FilePosition.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/Workspace/Contracts/FilePosition.cs
@@ -63,7 +63,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace.Contracts
/// A new FilePosition instance for the calculated position.
public FilePosition AddOffset(int lineOffset, int columnOffset)
{
- return this.scriptFile.CalculatePosition(
+ return scriptFile.CalculatePosition(
this,
lineOffset,
columnOffset);
@@ -77,7 +77,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace.Contracts
/// A new FilePosition instance for the calculated position.
public FilePosition GetLineStart()
{
- string scriptLine = scriptFile.FileLines[this.Line - 1];
+ string scriptLine = scriptFile.FileLines[Line - 1];
int lineStartColumn = 1;
for (int i = 0; i < scriptLine.Length; i++)
@@ -89,7 +89,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace.Contracts
}
}
- return new FilePosition(this.scriptFile, this.Line, lineStartColumn);
+ return new FilePosition(scriptFile, Line, lineStartColumn);
}
///
@@ -99,8 +99,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace.Contracts
/// A new FilePosition instance for the calculated position.
public FilePosition GetLineEnd()
{
- string scriptLine = scriptFile.FileLines[this.Line - 1];
- return new FilePosition(this.scriptFile, this.Line, scriptLine.Length + 1);
+ string scriptLine = scriptFile.FileLines[Line - 1];
+ return new FilePosition(scriptFile, Line, scriptLine.Length + 1);
}
#endregion
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Workspace/Contracts/ScriptFile.cs b/src/Microsoft.SqlTools.ServiceLayer/Workspace/Contracts/ScriptFile.cs
index 4cb5948c..463da178 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/Workspace/Contracts/ScriptFile.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/Workspace/Contracts/ScriptFile.cs
@@ -61,11 +61,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace.Contracts
{
get
{
- return string.Join("\r\n", this.FileLines);
+ return string.Join("\r\n", FileLines);
}
set
{
- this.FileLines = value != null ? value.Split('\n') : null;
+ FileLines = value != null ? value.Split('\n') : null;
}
}
@@ -118,12 +118,12 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace.Contracts
string clientFilePath,
TextReader textReader)
{
- this.FilePath = filePath;
- this.ClientFilePath = clientFilePath;
- this.IsAnalysisEnabled = true;
- this.IsInMemory = Workspace.IsPathInMemory(filePath);
+ FilePath = filePath;
+ ClientFilePath = clientFilePath;
+ IsAnalysisEnabled = true;
+ IsInMemory = Workspace.IsPathInMemory(filePath);
- this.SetFileContents(textReader.ReadToEnd());
+ SetFileContents(textReader.ReadToEnd());
}
///
@@ -137,11 +137,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace.Contracts
string clientFilePath,
string initialBuffer)
{
- this.FilePath = filePath;
- this.ClientFilePath = clientFilePath;
- this.IsAnalysisEnabled = true;
+ FilePath = filePath;
+ ClientFilePath = clientFilePath;
+ IsAnalysisEnabled = true;
- this.SetFileContents(initialBuffer);
+ SetFileContents(initialBuffer);
}
#endregion
@@ -157,9 +157,17 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace.Contracts
{
Validate.IsWithinRange(
"lineNumber", lineNumber,
- 1, this.FileLines.Count + 1);
+ 1, FileLines.Count + 1);
- return this.FileLines[lineNumber - 1];
+ return FileLines[lineNumber - 1];
+ }
+
+ ///
+ /// Gets the text under a specific range
+ ///
+ public string GetTextInRange(BufferRange range)
+ {
+ return string.Join(Environment.NewLine, GetLinesInRange(range));
}
///
@@ -170,8 +178,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace.Contracts
/// An array of strings from the specified range of the file.
public virtual string[] GetLinesInRange(BufferRange bufferRange)
{
- this.ValidatePosition(bufferRange.Start);
- this.ValidatePosition(bufferRange.End);
+ ValidatePosition(bufferRange.Start);
+ ValidatePosition(bufferRange.End);
List linesInRange = new List();
@@ -180,7 +188,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace.Contracts
for (int line = startLine; line <= endLine; line++)
{
- string currentLine = this.FileLines[line - 1];
+ string currentLine = FileLines[line - 1];
int startColumn =
line == startLine
? bufferRange.Start.Column
@@ -208,7 +216,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace.Contracts
/// The position in the buffer to be validated.
public void ValidatePosition(BufferPosition bufferPosition)
{
- this.ValidatePosition(
+ ValidatePosition(
bufferPosition.Line,
bufferPosition.Column);
}
@@ -221,14 +229,14 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace.Contracts
/// The 1-based column to be validated.
public void ValidatePosition(int line, int column)
{
- if (line < 1 || line > this.FileLines.Count + 1)
+ if (line < 1 || line > FileLines.Count + 1)
{
throw new ArgumentOutOfRangeException(nameof(line), SR.WorkspaceServicePositionLineOutOfRange);
}
// The maximum column is either one past the length of the string
// or 1 if the string is empty.
- string lineString = this.FileLines[line - 1];
+ string lineString = FileLines[line - 1];
int maxColumn = lineString.Length > 0 ? lineString.Length + 1 : 1;
if (column < 1 || column > maxColumn)
@@ -243,28 +251,28 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace.Contracts
/// The FileChange to apply to the file's contents.
public void ApplyChange(FileChange fileChange)
{
- this.ValidatePosition(fileChange.Line, fileChange.Offset);
- this.ValidatePosition(fileChange.EndLine, fileChange.EndOffset);
+ ValidatePosition(fileChange.Line, fileChange.Offset);
+ ValidatePosition(fileChange.EndLine, fileChange.EndOffset);
// Break up the change lines
string[] changeLines = fileChange.InsertString.Split('\n');
// Get the first fragment of the first line
string firstLineFragment =
- this.FileLines[fileChange.Line - 1]
+ FileLines[fileChange.Line - 1]
.Substring(0, fileChange.Offset - 1);
// Get the last fragment of the last line
- string endLine = this.FileLines[fileChange.EndLine - 1];
+ string endLine = FileLines[fileChange.EndLine - 1];
string lastLineFragment =
endLine.Substring(
fileChange.EndOffset - 1,
- (this.FileLines[fileChange.EndLine - 1].Length - fileChange.EndOffset) + 1);
+ (FileLines[fileChange.EndLine - 1].Length - fileChange.EndOffset) + 1);
// Remove the old lines
for (int i = 0; i <= fileChange.EndLine - fileChange.Line; i++)
{
- this.FileLines.RemoveAt(fileChange.Line - 1);
+ FileLines.RemoveAt(fileChange.Line - 1);
}
// Build and insert the new lines
@@ -287,7 +295,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace.Contracts
finalLine = finalLine + lastLineFragment;
}
- this.FileLines.Insert(currentLineNumber - 1, finalLine);
+ FileLines.Insert(currentLineNumber - 1, finalLine);
currentLineNumber++;
}
}
@@ -301,7 +309,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace.Contracts
/// The zero-based offset for the given file position.
public int GetOffsetAtPosition(int lineNumber, int columnNumber)
{
- Validate.IsWithinRange("lineNumber", lineNumber, 1, this.FileLines.Count);
+ Validate.IsWithinRange("lineNumber", lineNumber, 1, FileLines.Count);
Validate.IsGreaterThan("columnNumber", columnNumber, 0);
int offset = 0;
@@ -316,7 +324,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace.Contracts
else
{
// Add an offset to account for the current platform's newline characters
- offset += this.FileLines[i].Length + Environment.NewLine.Length;
+ offset += FileLines[i].Length + Environment.NewLine.Length;
}
}
@@ -339,9 +347,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace.Contracts
int newLine = originalPosition.Line + lineOffset,
newColumn = originalPosition.Column + columnOffset;
- this.ValidatePosition(newLine, newColumn);
+ ValidatePosition(newLine, newColumn);
- string scriptLine = this.FileLines[newLine - 1];
+ string scriptLine = FileLines[newLine - 1];
newColumn = Math.Min(scriptLine.Length + 1, newColumn);
return new FilePosition(this, newLine, newColumn);
@@ -379,9 +387,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace.Contracts
BufferPosition endPosition = startPosition;
int line = 0;
- while (line < this.FileLines.Count)
+ while (line < FileLines.Count)
{
- if (searchedOffset <= currentOffset + this.FileLines[line].Length)
+ if (searchedOffset <= currentOffset + FileLines[line].Length)
{
int column = searchedOffset - currentOffset;
@@ -415,7 +423,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace.Contracts
}
// Increase the current offset and include newline length
- currentOffset += this.FileLines[line].Length + Environment.NewLine.Length;
+ currentOffset += FileLines[line].Length + Environment.NewLine.Length;
line++;
}
@@ -430,7 +438,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace.Contracts
{
// Split the file contents into lines and trim
// any carriage returns from the strings.
- this.FileLines =
+ FileLines =
fileContents
.Split('\n')
.Select(line => line.TrimEnd('\r'))
diff --git a/src/Microsoft.SqlTools.ServiceLayer/project.json b/src/Microsoft.SqlTools.ServiceLayer/project.json
index ab58448a..3e0b83db 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/project.json
+++ b/src/Microsoft.SqlTools.ServiceLayer/project.json
@@ -28,8 +28,15 @@
"NETStandard.Library": "1.6.0",
"Microsoft.NETCore.Runtime.CoreCLR": "1.0.2",
"Microsoft.NETCore.DotNetHostPolicy": "1.0.1",
+ "Microsoft.DiaSymReader.Native": "1.4.1",
"System.Diagnostics.Process": "4.1.0",
"System.Threading.Thread": "4.0.0",
+ "System.Runtime.Loader": "4.0.0",
+ "System.Composition.Runtime": "1.0.31",
+ "System.Composition.Convention": "1.0.31",
+ "System.Composition.TypedParts": "1.0.31",
+ "Microsoft.Extensions.DependencyModel": "1.0.0",
+ "System.Runtime": "4.3.0",
"Microsoft.DiaSymReader.Native": "1.4.1"
},
"frameworks": {
diff --git a/src/Microsoft.SqlTools.ServiceLayer/sr.cs b/src/Microsoft.SqlTools.ServiceLayer/sr.cs
index 3bb109f3..dd310334 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/sr.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/sr.cs
@@ -117,6 +117,62 @@ namespace Microsoft.SqlTools.ServiceLayer
}
}
+ public static string ServiceAlreadyRegistered
+ {
+ get
+ {
+ return Keys.GetString(Keys.ServiceAlreadyRegistered);
+ }
+ }
+
+ public static string MultipleServicesFound
+ {
+ get
+ {
+ return Keys.GetString(Keys.MultipleServicesFound);
+ }
+ }
+
+ public static string IncompatibleServiceForExtensionLoader
+ {
+ get
+ {
+ return Keys.GetString(Keys.IncompatibleServiceForExtensionLoader);
+ }
+ }
+
+ public static string ServiceProviderNotSet
+ {
+ get
+ {
+ return Keys.GetString(Keys.ServiceProviderNotSet);
+ }
+ }
+
+ public static string ServiceNotFound
+ {
+ get
+ {
+ return Keys.GetString(Keys.ServiceNotFound);
+ }
+ }
+
+ public static string ServiceNotOfExpectedType
+ {
+ get
+ {
+ return Keys.GetString(Keys.ServiceNotOfExpectedType);
+ }
+ }
+
+ public static string ErrorUnexpectedCodeObjectType
+ {
+ get
+ {
+ return Keys.GetString(Keys.ErrorUnexpectedCodeObjectType);
+ }
+ }
+
public static string HostingUnexpectedEndOfStream
{
get
@@ -413,6 +469,14 @@ namespace Microsoft.SqlTools.ServiceLayer
}
}
+ public static string ErrorEmptyStringReplacement
+ {
+ get
+ {
+ return Keys.GetString(Keys.ErrorEmptyStringReplacement);
+ }
+ }
+
public static string WorkspaceServicePositionLineOutOfRange
{
get
@@ -774,6 +838,27 @@ namespace Microsoft.SqlTools.ServiceLayer
public const string CredentialServiceWin32CredentialDisposed = "CredentialServiceWin32CredentialDisposed";
+ public const string ServiceAlreadyRegistered = "ServiceAlreadyRegistered";
+
+
+ public const string MultipleServicesFound = "MultipleServicesFound";
+
+
+ public const string IncompatibleServiceForExtensionLoader = "IncompatibleServiceForExtensionLoader";
+
+
+ public const string ServiceProviderNotSet = "ServiceProviderNotSet";
+
+
+ public const string ServiceNotFound = "ServiceNotFound";
+
+
+ public const string ServiceNotOfExpectedType = "ServiceNotOfExpectedType";
+
+
+ public const string ErrorUnexpectedCodeObjectType = "ErrorUnexpectedCodeObjectType";
+
+
public const string HostingUnexpectedEndOfStream = "HostingUnexpectedEndOfStream";
@@ -903,6 +988,9 @@ namespace Microsoft.SqlTools.ServiceLayer
public const string PeekDefinitionTypeNotSupportedError = "PeekDefinitionTypeNotSupportedError";
+ public const string ErrorEmptyStringReplacement = "ErrorEmptyStringReplacement";
+
+
public const string WorkspaceServicePositionLineOutOfRange = "WorkspaceServicePositionLineOutOfRange";
diff --git a/src/Microsoft.SqlTools.ServiceLayer/sr.resx b/src/Microsoft.SqlTools.ServiceLayer/sr.resx
index b3fdd780..d9af1add 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/sr.resx
+++ b/src/Microsoft.SqlTools.ServiceLayer/sr.resx
@@ -181,6 +181,34 @@
Win32Credential object is already disposed
+
+ Cannot register service for type {0}, one or more services already registered
+
+
+
+ Multiple services found for type {0}, expected only 1
+
+
+
+ Service of type {0} cannot be created by ExtensionLoader<{1}>
+
+
+
+ SetServiceProvider() was not called to establish the required service provider
+
+
+
+ Service {0} was not found in the service provider
+
+
+
+ Service of Type {0} is not compatible with registered Type {1}
+
+
+
+ Cannot convert SqlCodeObject Type {0} to Type {1}
+
+
MessageReader's input stream ended unexpectedly, terminating
@@ -359,6 +387,10 @@
This object type is currently not supported by this feature.
+
+ Replacement of an empty string by an empty string.
+
+
Position is outside of file line range
diff --git a/src/Microsoft.SqlTools.ServiceLayer/sr.strings b/src/Microsoft.SqlTools.ServiceLayer/sr.strings
index 6757d0df..90ea969c 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/sr.strings
+++ b/src/Microsoft.SqlTools.ServiceLayer/sr.strings
@@ -59,6 +59,21 @@ CredentialsServiceTargetForLookup = Target must be specified to check existance
CredentialServiceWin32CredentialDisposed = Win32Credential object is already disposed
+############################################################################
+# Extensibility
+
+ServiceAlreadyRegistered = Cannot register service for type {0}, one or more services already registered
+MultipleServicesFound = Multiple services found for type {0}, expected only 1
+IncompatibleServiceForExtensionLoader = Service of type {0} cannot be created by ExtensionLoader<{1}>
+ServiceProviderNotSet = SetServiceProvider() was not called to establish the required service provider
+ServiceNotFound = Service {0} was not found in the service provider
+ServiceNotOfExpectedType = Service of Type {0} is not compatible with registered Type {1}
+
+############################################################################
+# Formatter
+
+ErrorUnexpectedCodeObjectType = Cannot convert SqlCodeObject Type {0} to Type {1}
+
############################################################################
# Hosting
@@ -168,6 +183,8 @@ PeekDefinitionTimedoutError = Operation timed out.
PeekDefinitionTypeNotSupportedError = This object type is currently not supported by this feature.
+ErrorEmptyStringReplacement = Replacement of an empty string by an empty string.
+
############################################################################
# Workspace Service
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/ComparisonFailureException.cs b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/ComparisonFailureException.cs
new file mode 100644
index 00000000..f9981550
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/ComparisonFailureException.cs
@@ -0,0 +1,28 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+
+namespace Microsoft.SqlTools.ServiceLayer.Test.Common
+{
+ internal class ComparisonFailureException : InvalidOperationException
+ {
+ internal string FullMessageWithDiff { get; private set; }
+ internal string EditAndCopyMessage { get; private set; }
+
+ internal ComparisonFailureException(string fullMessageWithDiff, string editAndCopyMessage)
+ : base(fullMessageWithDiff)
+ {
+ FullMessageWithDiff = fullMessageWithDiff;
+ EditAndCopyMessage = editAndCopyMessage;
+ }
+
+ internal ComparisonFailureException(string editAndCopyMessage)
+ : base(editAndCopyMessage)
+ {
+ EditAndCopyMessage = FullMessageWithDiff = editAndCopyMessage;
+ }
+ }
+}
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/RunEnvironmentInfo.cs b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/RunEnvironmentInfo.cs
index 7f0b753b..2889214e 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/RunEnvironmentInfo.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/RunEnvironmentInfo.cs
@@ -1,3 +1,4 @@
+
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
@@ -5,10 +6,15 @@
using System;
using System.IO;
+using System.Linq;
using System.Reflection;
+using System.Runtime.InteropServices;
namespace Microsoft.SqlTools.ServiceLayer.Test.Common
{
+ ///
+ /// Contains environment information needed when running tests.
+ ///
public class RunEnvironmentInfo
{
private static string cachedTestFolderPath;
@@ -30,7 +36,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Common
public static string GetTestDataLocation()
{
string testFolderPath;
- string testPath = @"test\Microsoft.SqlTools.ServiceLayer.Test.Common\TestData";
+ string testPath = Path.Combine("test", "Microsoft.SqlTools.ServiceLayer.Test.Common", "TestData");
string projectPath = Environment.GetEnvironmentVariable(Constants.ProjectPath);
if (projectPath != null)
@@ -45,13 +51,23 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Common
}
else
{
- string defaultPath = Path.Combine(typeof(Scripts).GetTypeInfo().Assembly.Location, @"..\..\..\..\..");
- testFolderPath = Path.Combine(defaultPath, @"Microsoft.SqlTools.ServiceLayer.Test.Common\TestData");
+ // We are running tests locally, which means we expect to be running inside the bin\debug\netcoreapp directory
+ // Test Files should be found at the root of the project so go back the necessary number of directories for this
+ // to be found. We are manually specifying the testFolderPath here for clarity on where to expect this
+
+ string assemblyDir = Path.GetDirectoryName(typeof(Scripts).GetTypeInfo().Assembly.Location);
+ string defaultPath = Path.Combine(assemblyDir, GoUpNDirectories(4));
+ testFolderPath = Path.Combine(defaultPath, "Microsoft.SqlTools.ServiceLayer.Test.Common", "TestData");
+
cachedTestFolderPath = testFolderPath;
}
}
return testFolderPath;
}
-
+ private static string GoUpNDirectories(int n)
+ {
+ string up = ".." + (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "\\" : "/");
+ return string.Concat(Enumerable.Repeat(up, n));
+ }
}
}
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestConfigPersistenceHelper.cs b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestConfigPersistenceHelper.cs
index b790dfb9..074e13a5 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestConfigPersistenceHelper.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestConfigPersistenceHelper.cs
@@ -78,7 +78,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Common
return Enumerable.Empty();
}
}
- catch (Exception ex)
+ catch (Exception)
{
return Enumerable.Empty();
}
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/BQE_IndentOperands.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/BQE_IndentOperands.sql
new file mode 100644
index 00000000..c4481069
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/BQE_IndentOperands.sql
@@ -0,0 +1,5 @@
+ select *
+ from mytable
+intersect
+ select *
+ from mytable
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/BQE_KeywordCasing_LowerCase.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/BQE_KeywordCasing_LowerCase.sql
new file mode 100644
index 00000000..de979b13
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/BQE_KeywordCasing_LowerCase.sql
@@ -0,0 +1,15 @@
+
+ select *
+ from mytable
+union
+ select *
+ from mytable
+union all
+ select *
+ from mytable
+except
+ select *
+ from mytable
+intersect
+ select *
+ from mytable
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/BQE_KeywordCasing_NoFormat.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/BQE_KeywordCasing_NoFormat.sql
new file mode 100644
index 00000000..1967b68f
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/BQE_KeywordCasing_NoFormat.sql
@@ -0,0 +1,15 @@
+
+ seLect *
+ from mytable
+unIon
+ selECT *
+ fROM mytable
+union ALL
+ select *
+ from mytable
+excepT
+ select *
+ from mytable
+Intersect
+ select *
+ from mytable
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/BQE_KeywordCasing_UpperCase.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/BQE_KeywordCasing_UpperCase.sql
new file mode 100644
index 00000000..92e83f0e
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/BQE_KeywordCasing_UpperCase.sql
@@ -0,0 +1,15 @@
+
+ SELECT *
+ FROM mytable
+UNION
+ SELECT *
+ FROM mytable
+UNION ALL
+ SELECT *
+ FROM mytable
+EXCEPT
+ SELECT *
+ FROM mytable
+INTERSECT
+ SELECT *
+ FROM mytable
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/BQE_OperatorsOnNewLine.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/BQE_OperatorsOnNewLine.sql
new file mode 100644
index 00000000..dbba4f22
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/BQE_OperatorsOnNewLine.sql
@@ -0,0 +1,14 @@
+ select *
+ from mytable
+union
+ select *
+ from mytable
+except
+ select *
+ from mytable
+union all
+ select *
+ from mytable
+intersect
+ select *
+ from mytable
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CTE.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CTE.sql
new file mode 100644
index 00000000..cbfb31a3
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CTE.sql
@@ -0,0 +1,19 @@
+USE AdventureWorks2008R2;
+GO
+-- Define the CTE expression name and column list.
+WITH
+ Sales_CTE (SalesPersonID, SalesOrderID, SalesYear)
+ AS
+ -- Define the CTE query.
+ (
+ SELECT SalesPersonID, SalesOrderID, YEAR(OrderDate) AS SalesYear
+ FROM Sales.SalesOrderHeader
+ WHERE SalesPersonID IS NOT NULL
+ )
+-- Define the outer query referencing the CTE name.
+SELECT SalesPersonID, COUNT(SalesOrderID) AS TotalSales, SalesYear
+FROM Sales_CTE
+GROUP BY SalesYear, SalesPersonID
+ORDER BY SalesPersonID, SalesYear;
+GO
+
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CTE_20Spaces.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CTE_20Spaces.sql
new file mode 100644
index 00000000..f337650b
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CTE_20Spaces.sql
@@ -0,0 +1,32 @@
+USE AdventureWorks2008R2;
+GO
+-- Define the CTE expression name and column list.
+WITH
+ Sales_CTE
+ (
+ SalesPersonID,
+ SalesOrderID,
+ SalesYear
+ )
+ AS
+ -- Define the CTE query.
+ (
+ SELECT
+ SalesPersonID,
+ SalesOrderID,
+ YEAR(OrderDate) AS SalesYear
+ FROM
+ Sales.SalesOrderHeader
+ WHERE SalesPersonID IS NOT NULL
+ )
+-- Define the outer query referencing the CTE name.
+SELECT
+ SalesPersonID,
+ COUNT(SalesOrderID) AS TotalSales,
+ SalesYear
+FROM
+ Sales_CTE
+GROUP BY SalesYear, SalesPersonID
+ORDER BY SalesPersonID, SalesYear;
+GO
+
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CTE_CommasBeforeDefinition.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CTE_CommasBeforeDefinition.sql
new file mode 100644
index 00000000..f2ada26d
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CTE_CommasBeforeDefinition.sql
@@ -0,0 +1,19 @@
+USE AdventureWorks2008R2;
+GO
+-- Define the CTE expression name and column list.
+WITH
+ Sales_CTE (SalesPersonID ,SalesOrderID ,SalesYear)
+ AS
+ -- Define the CTE query.
+ (
+ SELECT SalesPersonID ,SalesOrderID ,YEAR(OrderDate) AS SalesYear
+ FROM Sales.SalesOrderHeader
+ WHERE SalesPersonID IS NOT NULL
+ )
+-- Define the outer query referencing the CTE name.
+SELECT SalesPersonID ,COUNT(SalesOrderID) AS TotalSales ,SalesYear
+FROM Sales_CTE
+GROUP BY SalesYear, SalesPersonID
+ORDER BY SalesPersonID, SalesYear;
+GO
+
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CTE_EachReferenceOnNewLine.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CTE_EachReferenceOnNewLine.sql
new file mode 100644
index 00000000..d2494a15
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CTE_EachReferenceOnNewLine.sql
@@ -0,0 +1,32 @@
+USE AdventureWorks2008R2;
+GO
+-- Define the CTE expression name and column list.
+WITH
+ Sales_CTE
+ (
+ SalesPersonID,
+ SalesOrderID,
+ SalesYear
+ )
+ AS
+ -- Define the CTE query.
+ (
+ SELECT
+ SalesPersonID,
+ SalesOrderID,
+ YEAR(OrderDate) AS SalesYear
+ FROM
+ Sales.SalesOrderHeader
+ WHERE SalesPersonID IS NOT NULL
+ )
+-- Define the outer query referencing the CTE name.
+SELECT
+ SalesPersonID,
+ COUNT(SalesOrderID) AS TotalSales,
+ SalesYear
+FROM
+ Sales_CTE
+GROUP BY SalesYear, SalesPersonID
+ORDER BY SalesPersonID, SalesYear;
+GO
+
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CTE_EachReferenceOnNewLine_CommasBeforeDefinition.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CTE_EachReferenceOnNewLine_CommasBeforeDefinition.sql
new file mode 100644
index 00000000..bdc47e57
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CTE_EachReferenceOnNewLine_CommasBeforeDefinition.sql
@@ -0,0 +1,32 @@
+USE AdventureWorks2008R2;
+GO
+-- Define the CTE expression name and column list.
+WITH
+ Sales_CTE
+ (
+ SalesPersonID
+ ,SalesOrderID
+ ,SalesYear
+ )
+ AS
+ -- Define the CTE query.
+ (
+ SELECT
+ SalesPersonID
+ ,SalesOrderID
+ ,YEAR(OrderDate) AS SalesYear
+ FROM
+ Sales.SalesOrderHeader
+ WHERE SalesPersonID IS NOT NULL
+ )
+-- Define the outer query referencing the CTE name.
+SELECT
+ SalesPersonID
+ ,COUNT(SalesOrderID) AS TotalSales
+ ,SalesYear
+FROM
+ Sales_CTE
+GROUP BY SalesYear, SalesPersonID
+ORDER BY SalesPersonID, SalesYear;
+GO
+
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CTE_LowerCaseKeywords.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CTE_LowerCaseKeywords.sql
new file mode 100644
index 00000000..149c982d
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CTE_LowerCaseKeywords.sql
@@ -0,0 +1,32 @@
+use AdventureWorks2008R2;
+go
+-- Define the CTE expression name and column list.
+with
+ Sales_CTE
+ (
+ SalesPersonID,
+ SalesOrderID,
+ SalesYear
+ )
+ as
+ -- Define the CTE query.
+ (
+ select
+ SalesPersonID,
+ SalesOrderID,
+ YEAR(OrderDate) as SalesYear
+ from
+ Sales.SalesOrderHeader
+ where SalesPersonID is not null
+ )
+-- Define the outer query referencing the CTE name.
+select
+ SalesPersonID,
+ COUNT(SalesOrderID) as TotalSales,
+ SalesYear
+from
+ Sales_CTE
+group by SalesYear, SalesPersonID
+order by SalesPersonID, SalesYear;
+go
+
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CTE_MultipleExpressions.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CTE_MultipleExpressions.sql
new file mode 100644
index 00000000..be00e55b
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CTE_MultipleExpressions.sql
@@ -0,0 +1,17 @@
+with
+ my_initial_table( column1, column2 )
+ AS
+ (
+ select *
+ from mytable
+ ),
+ my_other_table( column1X, column2X )
+ AS
+ (
+ select *
+ from mytable2
+ )
+select distinct top (10) PERCENT with ties
+ alias1 = SIZE(mytable.mycol1), another = COUNT(new_elements), count(money) AS encore, id
+INTO my_new_table
+FROM my_initial_table
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CTE_OneColumn.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CTE_OneColumn.sql
new file mode 100644
index 00000000..2d753d2f
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CTE_OneColumn.sql
@@ -0,0 +1,17 @@
+USE AdventureWorks2008R2;
+GO
+-- Define the CTE expression name and column list.
+WITH
+ Sales_CTE (SalesOrderID)
+ AS
+ -- Define the CTE query.
+ (
+ SELECT SalesOrderID
+ FROM Sales.SalesOrderHeader
+ WHERE SalesPersonID IS NOT NULL
+ )
+-- Define the outer query referencing the CTE name.
+SELECT COUNT(SalesOrderID) AS TotalSales
+FROM Sales_CTE;
+GO
+
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CTE_UpperCaseKeywords.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CTE_UpperCaseKeywords.sql
new file mode 100644
index 00000000..d2494a15
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CTE_UpperCaseKeywords.sql
@@ -0,0 +1,32 @@
+USE AdventureWorks2008R2;
+GO
+-- Define the CTE expression name and column list.
+WITH
+ Sales_CTE
+ (
+ SalesPersonID,
+ SalesOrderID,
+ SalesYear
+ )
+ AS
+ -- Define the CTE query.
+ (
+ SELECT
+ SalesPersonID,
+ SalesOrderID,
+ YEAR(OrderDate) AS SalesYear
+ FROM
+ Sales.SalesOrderHeader
+ WHERE SalesPersonID IS NOT NULL
+ )
+-- Define the outer query referencing the CTE name.
+SELECT
+ SalesPersonID,
+ COUNT(SalesOrderID) AS TotalSales,
+ SalesYear
+FROM
+ Sales_CTE
+GROUP BY SalesYear, SalesPersonID
+ORDER BY SalesPersonID, SalesYear;
+GO
+
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CTE_UseTabs.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CTE_UseTabs.sql
new file mode 100644
index 00000000..6716f8de
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CTE_UseTabs.sql
@@ -0,0 +1,32 @@
+USE AdventureWorks2008R2;
+GO
+-- Define the CTE expression name and column list.
+WITH
+ Sales_CTE
+ (
+ SalesPersonID,
+ SalesOrderID,
+ SalesYear
+ )
+ AS
+ -- Define the CTE query.
+ (
+ SELECT
+ SalesPersonID,
+ SalesOrderID,
+ YEAR(OrderDate) AS SalesYear
+ FROM
+ Sales.SalesOrderHeader
+ WHERE SalesPersonID IS NOT NULL
+ )
+-- Define the outer query referencing the CTE name.
+SELECT
+ SalesPersonID,
+ COUNT(SalesOrderID) AS TotalSales,
+ SalesYear
+FROM
+ Sales_CTE
+GROUP BY SalesYear, SalesPersonID
+ORDER BY SalesPersonID, SalesYear;
+GO
+
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_BackwardsCompatible.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_BackwardsCompatible.sql
new file mode 100644
index 00000000..12e6a6a5
Binary files /dev/null and b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_BackwardsCompatible.sql differ
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_BeginEnd.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_BeginEnd.sql
new file mode 100644
index 00000000..291212c7
Binary files /dev/null and b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_BeginEnd.sql differ
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_Minimal.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_Minimal.sql
new file mode 100644
index 00000000..bd8b987f
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_Minimal.sql
@@ -0,0 +1,4 @@
+
+-- my comment
+Create Procedure P1
+AS
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_MultipleBatches.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_MultipleBatches.sql
new file mode 100644
index 00000000..06450016
Binary files /dev/null and b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_MultipleBatches.sql differ
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_MultipleParams.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_MultipleParams.sql
new file mode 100644
index 00000000..2da484e1
Binary files /dev/null and b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_MultipleParams.sql differ
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_OneParam.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_OneParam.sql
new file mode 100644
index 00000000..fa2847d8
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_OneParam.sql
@@ -0,0 +1,3 @@
+Create Procedure dbo.P1
+ @param1 int
+AS
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_ParamsRecompileReturn.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_ParamsRecompileReturn.sql
new file mode 100644
index 00000000..20e86813
Binary files /dev/null and b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_ParamsRecompileReturn.sql differ
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_Select.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_Select.sql
new file mode 100644
index 00000000..82de07c4
Binary files /dev/null and b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_Select.sql differ
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_TwoPartName.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_TwoPartName.sql
new file mode 100644
index 00000000..a1dd20ef
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_TwoPartName.sql
@@ -0,0 +1,2 @@
+Create Procedure dbo.P1
+AS
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_WithCTE.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_WithCTE.sql
new file mode 100644
index 00000000..1f612471
Binary files /dev/null and b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_WithCTE.sql differ
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_WithEncryptionModule.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_WithEncryptionModule.sql
new file mode 100644
index 00000000..4746cf3f
Binary files /dev/null and b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_WithEncryptionModule.sql differ
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_WithExecuteAsModule.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_WithExecuteAsModule.sql
new file mode 100644
index 00000000..2ecf1515
Binary files /dev/null and b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_WithExecuteAsModule.sql differ
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_WithThreeModules.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_WithThreeModules.sql
new file mode 100644
index 00000000..40eb8b04
Binary files /dev/null and b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateProcedure_WithThreeModules.sql differ
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable.sql
new file mode 100644
index 00000000..64740fbc
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable.sql
@@ -0,0 +1,18 @@
+
+-- this is a comment before create table
+CREATE TABLE [SimpleTable]
+(
+
+ -- this is a comment before document
+ [DocumentID] INT IDENTITY (1, 1) NOT NULL,
+
+ -- this is a comment before Title
+ [Title] NVARCHAR (50) NOT NULL,
+
+
+ -- this is a comment before FileName
+ [FileName] NVARCHAR (400) NOT NULL,
+
+ -- this is a comment before FileExtension
+ [FileExtension] nvarchar(8)
+);
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTableAddress_AlignInColumns.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTableAddress_AlignInColumns.sql
new file mode 100644
index 00000000..9d733b69
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTableAddress_AlignInColumns.sql
@@ -0,0 +1,22 @@
+CREATE TABLE [Person].[Address]
+(
+ [AddressID] INT IDENTITY (1, 1) NOT FOR REPLICATION NOT NULL,
+ CONSTRAINT [PK_Address_AddressID] PRIMARY KEY CLUSTERED ([AddressID] ASC),
+
+ [AddressLine1] NVARCHAR (60) NOT NULL,
+
+ [AddressLine2] NVARCHAR (60) NULL,
+
+ Address NVarChar (60) Null,
+
+ [City] NVARCHAR (30) NOT NULL,
+
+ [StateProvinceID] INT NOT NULL,
+
+ [PostalCode] NVARCHAR (15) NOT NULL,
+ [rowguid] UNIQUEIDENTIFIER CONSTRAINT [DF_Address_rowguid] DEFAULT (newid()) ROWGUIDCOL NOT NULL,
+ [ModifiedDate] DATETIME CONSTRAINT [DF_Address_ModifiedDate] DEFAULT (getdate()) NOT NULL,
+
+
+ CONSTRAINT [FK_Address_StateProvince_StateProvinceID] FOREIGN KEY ([StateProvinceID]) REFERENCES [Person].[StateProvince] ([StateProvinceID]) ON DELETE NO ACTION ON UPDATE NO ACTION
+);
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTableAddress_AlignInColumnsUseTabs.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTableAddress_AlignInColumnsUseTabs.sql
new file mode 100644
index 00000000..1ef3f37d
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTableAddress_AlignInColumnsUseTabs.sql
@@ -0,0 +1,22 @@
+CREATE TABLE [Person].[Address]
+(
+ [AddressID] INT IDENTITY (1, 1) NOT FOR REPLICATION NOT NULL,
+ CONSTRAINT [PK_Address_AddressID] PRIMARY KEY CLUSTERED ([AddressID] ASC),
+
+ [AddressLine1] NVARCHAR (60) NOT NULL,
+
+ [AddressLine2] NVARCHAR (60) NULL,
+
+ Address NVarChar (60) Null,
+
+ [City] NVARCHAR (30) NOT NULL,
+
+ [StateProvinceID] INT NOT NULL,
+
+ [PostalCode] NVARCHAR (15) NOT NULL,
+ [rowguid] UNIQUEIDENTIFIER CONSTRAINT [DF_Address_rowguid] DEFAULT (newid()) ROWGUIDCOL NOT NULL,
+ [ModifiedDate] DATETIME CONSTRAINT [DF_Address_ModifiedDate] DEFAULT (getdate()) NOT NULL,
+
+
+ CONSTRAINT [FK_Address_StateProvince_StateProvinceID] FOREIGN KEY ([StateProvinceID]) REFERENCES [Person].[StateProvince] ([StateProvinceID]) ON DELETE NO ACTION ON UPDATE NO ACTION
+);
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTableOn.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTableOn.sql
new file mode 100644
index 00000000..a132bd7e
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTableOn.sql
@@ -0,0 +1,9 @@
+CREATE TABLE db_name.schema_name.table_name
+(
+ col_name1 INT,
+ col_name2 VARCHAR (20)
+
+
+ -- here is my comment
+)
+ ON partition_schema_name (partition_column_name);
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_20Spaces.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_20Spaces.sql
new file mode 100644
index 00000000..3280200a
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_20Spaces.sql
@@ -0,0 +1,18 @@
+
+-- this is a comment before create table
+CREATE TABLE [SimpleTable]
+(
+
+ -- this is a comment before document
+ [DocumentID] INT IDENTITY (1, 1) NOT NULL,
+
+ -- this is a comment before Title
+ [Title] NVARCHAR (50) NOT NULL,
+
+
+ -- this is a comment before FileName
+ [FileName] NVARCHAR (400) NOT NULL,
+
+ -- this is a comment before FileExtension
+ [FileExtension] nvarchar(8)
+);
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_AlignInColumns.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_AlignInColumns.sql
new file mode 100644
index 00000000..6ff0549f
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_AlignInColumns.sql
@@ -0,0 +1,18 @@
+
+-- this is a comment before create table
+CREATE TABLE [SimpleTable]
+(
+
+ -- this is a comment before document
+ [DocumentID] INT IDENTITY (1, 1) NOT NULL,
+
+ -- this is a comment before Title
+ [Title] NVARCHAR (50) NOT NULL,
+
+
+ -- this is a comment before FileName
+ [FileName] NVARCHAR (400) NOT NULL,
+
+ -- this is a comment before FileExtension
+ [FileExtension] nvarchar(8)
+);
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_AlignInColumnsUseTabs.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_AlignInColumnsUseTabs.sql
new file mode 100644
index 00000000..b60f7c8f
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_AlignInColumnsUseTabs.sql
@@ -0,0 +1,18 @@
+
+-- this is a comment before create table
+CREATE TABLE [SimpleTable]
+(
+
+ -- this is a comment before document
+ [DocumentID] INT IDENTITY (1, 1) NOT NULL,
+
+ -- this is a comment before Title
+ [Title] NVARCHAR (50) NOT NULL,
+
+
+ -- this is a comment before FileName
+ [FileName] NVARCHAR (400) NOT NULL,
+
+ -- this is a comment before FileExtension
+ [FileExtension] nvarchar(8)
+);
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_CommasBeforeDefinition.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_CommasBeforeDefinition.sql
new file mode 100644
index 00000000..bd88941c
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_CommasBeforeDefinition.sql
@@ -0,0 +1,18 @@
+
+-- this is a comment before create table
+CREATE TABLE [SimpleTable]
+(
+
+ -- this is a comment before document
+ [DocumentID] INT IDENTITY (1, 1) NOT NULL
+
+ -- this is a comment before Title
+ ,[Title] NVARCHAR (50) NOT NULL
+
+
+ -- this is a comment before FileName
+ ,[FileName] NVARCHAR (400) NOT NULL
+
+ -- this is a comment before FileExtension
+ ,[FileExtension] nvarchar(8)
+);
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_CommentBeforeComma.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_CommentBeforeComma.sql
new file mode 100644
index 00000000..57d26fc9
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_CommentBeforeComma.sql
@@ -0,0 +1,13 @@
+
+create table t1
+(
+ id INT not null /* awesome */
+ ,x INT not null
+ /* cool */
+ ,y INT not null
+ -- tremendeous
+)
+with
+(
+ data_compression = row
+);
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_Formatted.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_Formatted.sql
new file mode 100644
index 00000000..e16e281d
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_Formatted.sql
@@ -0,0 +1,7 @@
+
+create table t1
+(
+ col1 int,
+
+ col2 int
+)
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_LowerCaseDataTypes.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_LowerCaseDataTypes.sql
new file mode 100644
index 00000000..3a357be2
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_LowerCaseDataTypes.sql
@@ -0,0 +1,18 @@
+
+-- this is a comment before create table
+CREATE TABLE [SimpleTable]
+(
+
+ -- this is a comment before document
+ [DocumentID] int IDENTITY (1, 1) NOT NULL,
+
+ -- this is a comment before Title
+ [Title] nvarchar (50) NOT NULL,
+
+
+ -- this is a comment before FileName
+ [FileName] nvarchar (400) NOT NULL,
+
+ -- this is a comment before FileExtension
+ [FileExtension] nvarchar(8)
+);
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_LowerCaseKeywords.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_LowerCaseKeywords.sql
new file mode 100644
index 00000000..437816aa
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_LowerCaseKeywords.sql
@@ -0,0 +1,18 @@
+
+-- this is a comment before create table
+create table [SimpleTable]
+(
+
+ -- this is a comment before document
+ [DocumentID] INT identity (1, 1) not null,
+
+ -- this is a comment before Title
+ [Title] NVARCHAR (50) not null,
+
+
+ -- this is a comment before FileName
+ [FileName] NVARCHAR (400) not null,
+
+ -- this is a comment before FileExtension
+ [FileExtension] nvarchar(8)
+);
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_Timestamp.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_Timestamp.sql
new file mode 100644
index 00000000..18a7ff18
Binary files /dev/null and b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_Timestamp.sql differ
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_UpperCaseDataTypes.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_UpperCaseDataTypes.sql
new file mode 100644
index 00000000..8f9cd99b
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_UpperCaseDataTypes.sql
@@ -0,0 +1,18 @@
+
+-- this is a comment before create table
+CREATE TABLE [SimpleTable]
+(
+
+ -- this is a comment before document
+ [DocumentID] INT IDENTITY (1, 1) NOT NULL,
+
+ -- this is a comment before Title
+ [Title] NVARCHAR (50) NOT NULL,
+
+
+ -- this is a comment before FileName
+ [FileName] NVARCHAR (400) NOT NULL,
+
+ -- this is a comment before FileExtension
+ [FileExtension] NVARCHAR(8)
+);
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_UpperCaseKeywords.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_UpperCaseKeywords.sql
new file mode 100644
index 00000000..64740fbc
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_UpperCaseKeywords.sql
@@ -0,0 +1,18 @@
+
+-- this is a comment before create table
+CREATE TABLE [SimpleTable]
+(
+
+ -- this is a comment before document
+ [DocumentID] INT IDENTITY (1, 1) NOT NULL,
+
+ -- this is a comment before Title
+ [Title] NVARCHAR (50) NOT NULL,
+
+
+ -- this is a comment before FileName
+ [FileName] NVARCHAR (400) NOT NULL,
+
+ -- this is a comment before FileExtension
+ [FileExtension] nvarchar(8)
+);
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_UseTabs.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_UseTabs.sql
new file mode 100644
index 00000000..0659f45e
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateTable_UseTabs.sql
@@ -0,0 +1,18 @@
+
+-- this is a comment before create table
+CREATE TABLE [SimpleTable]
+(
+
+ -- this is a comment before document
+ [DocumentID] INT IDENTITY (1, 1) NOT NULL,
+
+ -- this is a comment before Title
+ [Title] NVARCHAR (50) NOT NULL,
+
+
+ -- this is a comment before FileName
+ [FileName] NVARCHAR (400) NOT NULL,
+
+ -- this is a comment before FileExtension
+ [FileExtension] nvarchar(8)
+);
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateView_Full.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateView_Full.sql
new file mode 100644
index 00000000..be912cc7
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateView_Full.sql
@@ -0,0 +1,13 @@
+CREATE VIEW my_schema.my_view_name
+(
+ column1,
+ column2,
+ column3
+)
+WITH
+ SCHEMABINDING,
+ ENCRYPTION,
+ VIEW_METADATA
+AS
+ SELECT *
+ FROM mytable
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateView_FullWithComments.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateView_FullWithComments.sql
new file mode 100644
index 00000000..00194b53
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateView_FullWithComments.sql
@@ -0,0 +1,25 @@
+CREATE VIEW my_schema.my_view_name
+--and
+(
+ /* we */
+ column1,
+ column2,
+ /* can */
+ column3
+)
+-- put
+WITH
+ /* comments */
+ /*even multiple ones */
+ -- and of various types
+ SCHEMABINDING,
+ -- everywhere
+ ENCRYPTION,
+ -- we
+ VIEW_METADATA
+/* want*/
+AS
+ /* because */
+ SELECT *
+ FROM mytable
+-- it's SQL
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateView_MultipleColumns.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateView_MultipleColumns.sql
new file mode 100644
index 00000000..849df871
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateView_MultipleColumns.sql
@@ -0,0 +1,8 @@
+CREATE VIEW my_view
+(
+ mycol,
+ my_other_col
+)
+AS
+ select *
+ from mytable
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateView_MultipleOptions.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateView_MultipleOptions.sql
new file mode 100644
index 00000000..2f0d19d7
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateView_MultipleOptions.sql
@@ -0,0 +1,8 @@
+CREATE VIEW my_view_name
+WITH
+ SCHEMABINDING,
+ ENCRYPTION,
+ VIEW_METADATA
+AS
+ SELECT *
+ FROM mytable
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateView_OneColumn.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateView_OneColumn.sql
new file mode 100644
index 00000000..6ebf8210
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateView_OneColumn.sql
@@ -0,0 +1,8 @@
+
+CREATE VIEW my_view
+(
+ mycol
+)
+AS
+ select *
+ from mytable
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateView_OneColumnOneOption.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateView_OneColumnOneOption.sql
new file mode 100644
index 00000000..1e349955
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateView_OneColumnOneOption.sql
@@ -0,0 +1,10 @@
+CREATE VIEW my_view
+(
+ mycol
+)
+WITH
+ ENCRYPTION
+AS
+ select *
+ from mytable
+
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateView_OneOption.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateView_OneOption.sql
new file mode 100644
index 00000000..fe86fb73
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateView_OneOption.sql
@@ -0,0 +1,8 @@
+
+CREATE VIEW my_view
+WITH
+ ENCRYPTION
+AS
+ select *
+ from mytable
+
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateView_Simple.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateView_Simple.sql
new file mode 100644
index 00000000..74bf0c2d
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/CreateView_Simple.sql
@@ -0,0 +1,5 @@
+CREATE VIEW my_view
+AS
+ select *
+ from mytable
+
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/Insert_DefaultValues.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/Insert_DefaultValues.sql
new file mode 100644
index 00000000..16b7d032
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/Insert_DefaultValues.sql
@@ -0,0 +1,3 @@
+
+INSERT INTO NUMBERS
+DEFAULT VALUES;
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/Insert_Full.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/Insert_Full.sql
new file mode 100644
index 00000000..58c0fc85
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/Insert_Full.sql
@@ -0,0 +1,20 @@
+with
+ my_initial_table( column1, column2 )
+ AS
+ (
+ select *
+ from mytable
+ ),
+ my_other_table( column1, column2 )
+ AS
+ (
+ select *
+ from mytable
+ )
+Insert top (10) PERCENT
+into myserver.mydatabase.myschema.mytable_or_view WITH (TABLOCK)
+ ( col1, col2, col3, col4, col5 )
+VALUES
+ ( DEFault, NULL, 1, N'My Value', 'Today'),
+ ( 45, 5, 1, N'My Last Value', 'Yesterday'),
+ ( 8, 6, 1, N'My Next Value', 'Tomorrow')
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/Insert_OpenQuery.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/Insert_OpenQuery.sql
new file mode 100644
index 00000000..59e1eafe
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/Insert_OpenQuery.sql
@@ -0,0 +1,5 @@
+
+INSERT OPENQUERY (OracleSvr, 'SELECT name FROM joe.titles')
+-- comment
+VALUES
+ ('NewTitle');
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/Insert_OutputInto.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/Insert_OutputInto.sql
new file mode 100644
index 00000000..8beb52b6
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/Insert_OutputInto.sql
@@ -0,0 +1,8 @@
+
+INSERT Production.ScrapReason
+OUTPUT
+ INSERTED.ScrapReasonID, INSERTED.Name, INSERTED.ModifiedDate
+INTO @MyTableVar
+VALUES
+ (N'Operator error', GETDATE());
+
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/Insert_OutputStatement.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/Insert_OutputStatement.sql
new file mode 100644
index 00000000..e62a7329
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/Insert_OutputStatement.sql
@@ -0,0 +1,8 @@
+
+INSERT Production.ScrapReason
+/*comments like this one*/
+OUTPUT
+ INSERTED.ScrapReasonID, INSERTED.Name, INSERTED.ModifiedDate
+INTO @MyTableVar
+VALUES
+ (N'Operator error',/*comments like this one*/ GETDATE());
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/Insert_Select.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/Insert_Select.sql
new file mode 100644
index 00000000..9cf79922
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/Insert_Select.sql
@@ -0,0 +1,9 @@
+
+INSERT INTO myTable
+ (FileName, FileType, Document)
+SELECT
+ 'Text1.txt' AS FileName,
+ '.txt' AS FileType,
+ *
+FROM
+ OPENROWSET(BULK N'C:\Text1.txt', SINGLE_BLOB) AS Document;
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/Insert_SelectSource.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/Insert_SelectSource.sql
new file mode 100644
index 00000000..9f9aad46
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/Insert_SelectSource.sql
@@ -0,0 +1,10 @@
+
+INSERT INTO myTable
+ (FileName, FileType, Document)
+--comment
+SELECT
+ 'Text1.txt' AS FileName,
+ '.txt' AS FileType,
+ *
+FROM
+ OPENROWSET(BULK N'C:\Text1.txt', SINGLE_BLOB) AS Document;
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/Insert_TopSpecification.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/Insert_TopSpecification.sql
new file mode 100644
index 00000000..809f87c2
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/Insert_TopSpecification.sql
@@ -0,0 +1,6 @@
+
+insert top (10)
+into mytable
+values
+ (10, 11);
+
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/Insert_TopWithComments.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/Insert_TopWithComments.sql
new file mode 100644
index 00000000..de21b0b0
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/Insert_TopWithComments.sql
@@ -0,0 +1,6 @@
+insert top (10)
+mytable
+/*comments like this one*//*comments like this one*/
+values
+ /*comments like this one*/
+ (10, 11);
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/SimpleQuery.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/SimpleQuery.sql
new file mode 100644
index 00000000..2bd69b33
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/SimpleQuery.sql
@@ -0,0 +1,7 @@
+
+select c1, c2, t3.c3
+
+
+
+
+From t1, t2, t3
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/SimpleQuery_20Spaces.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/SimpleQuery_20Spaces.sql
new file mode 100644
index 00000000..5c76ea01
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/SimpleQuery_20Spaces.sql
@@ -0,0 +1,13 @@
+
+select
+ c1,
+ c2,
+ t3.c3
+
+
+
+
+From
+ t1,
+ t2,
+ t3
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/SimpleQuery_CommasBeforeDefinition.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/SimpleQuery_CommasBeforeDefinition.sql
new file mode 100644
index 00000000..aa604a19
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/SimpleQuery_CommasBeforeDefinition.sql
@@ -0,0 +1,7 @@
+
+select c1 ,c2 ,t3.c3
+
+
+
+
+From t1 ,t2 ,t3
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/SimpleQuery_EachReferenceOnNewLine.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/SimpleQuery_EachReferenceOnNewLine.sql
new file mode 100644
index 00000000..a3fe8739
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/SimpleQuery_EachReferenceOnNewLine.sql
@@ -0,0 +1,13 @@
+
+select
+ c1,
+ c2,
+ t3.c3
+
+
+
+
+From
+ t1,
+ t2,
+ t3
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/SimpleQuery_EachReferenceOnNewLine_CommasBeforeDefinition.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/SimpleQuery_EachReferenceOnNewLine_CommasBeforeDefinition.sql
new file mode 100644
index 00000000..3c4ab4a2
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/SimpleQuery_EachReferenceOnNewLine_CommasBeforeDefinition.sql
@@ -0,0 +1,13 @@
+
+select
+ c1
+ ,c2
+ ,t3.c3
+
+
+
+
+From
+ t1
+ ,t2
+ ,t3
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/SimpleQuery_ForBrowseClause.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/SimpleQuery_ForBrowseClause.sql
new file mode 100644
index 00000000..9ab839b4
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/SimpleQuery_ForBrowseClause.sql
@@ -0,0 +1,9 @@
+
+select c1, c2, t3.c3
+
+
+
+
+From t1, t2, t3
+
+for browse
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/SimpleQuery_ForXmlClause.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/SimpleQuery_ForXmlClause.sql
new file mode 100644
index 00000000..9da4f29c
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/SimpleQuery_ForXmlClause.sql
@@ -0,0 +1,9 @@
+
+select c1, c2, t3.c3
+
+
+
+
+From t1, t2, t3
+
+FOR XML AUTO, TYPE, XMLSCHEMA, ELEMENTS XSINIL;
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/SimpleQuery_LowerCaseKeywords.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/SimpleQuery_LowerCaseKeywords.sql
new file mode 100644
index 00000000..254e1a75
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/SimpleQuery_LowerCaseKeywords.sql
@@ -0,0 +1,13 @@
+
+select
+ c1,
+ c2,
+ t3.c3
+
+
+
+
+from
+ t1,
+ t2,
+ t3
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/SimpleQuery_UpperCaseKeywords.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/SimpleQuery_UpperCaseKeywords.sql
new file mode 100644
index 00000000..1e2a0624
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/SimpleQuery_UpperCaseKeywords.sql
@@ -0,0 +1,13 @@
+
+SELECT
+ c1,
+ c2,
+ t3.c3
+
+
+
+
+FROM
+ t1,
+ t2,
+ t3
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/SimpleQuery_UseTabs.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/SimpleQuery_UseTabs.sql
new file mode 100644
index 00000000..2722c411
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/BaselineFiles/SimpleQuery_UseTabs.sql
@@ -0,0 +1,13 @@
+
+select
+ c1,
+ c2,
+ t3.c3
+
+
+
+
+From
+ t1,
+ t2,
+ t3
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/Address.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/Address.sql
new file mode 100644
index 00000000..cd061941
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/Address.sql
@@ -0,0 +1,21 @@
+CREATE TABLE [Person].[Address] (
+ [AddressID] INT IDENTITY (1, 1) NOT FOR REPLICATION NOT NULL,
+ CONSTRAINT [PK_Address_AddressID] PRIMARY KEY CLUSTERED ([AddressID] ASC),
+
+ [AddressLine1] NVARCHAR (60) NOT NULL,
+
+ [AddressLine2] NVARCHAR (60) NULL,
+
+ Address NVarChar (60) Null,
+
+ [City] NVARCHAR (30) NOT NULL,
+
+ [StateProvinceID] INT NOT NULL,
+
+ [PostalCode] NVARCHAR (15) NOT NULL,
+ [rowguid] UNIQUEIDENTIFIER CONSTRAINT [DF_Address_rowguid] DEFAULT (newid()) ROWGUIDCOL NOT NULL,
+ [ModifiedDate] DATETIME CONSTRAINT [DF_Address_ModifiedDate] DEFAULT (getdate()) NOT NULL,
+
+
+ CONSTRAINT [FK_Address_StateProvince_StateProvinceID] FOREIGN KEY ([StateProvinceID]) REFERENCES [Person].[StateProvince] ([StateProvinceID]) ON DELETE NO ACTION ON UPDATE NO ACTION
+);
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/AddressSimple.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/AddressSimple.sql
new file mode 100644
index 00000000..5e6675fd
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/AddressSimple.sql
@@ -0,0 +1,5 @@
+CREATE TABLE [Person].[Address] (
+ [AddressID] INT IDENTITY (1, 1) NOT FOR REPLICATION NOT NULL,
+ CONSTRAINT [PK_Address_AddressID] PRIMARY KEY CLUSTERED ([AddressID] ASC),[AddressLine1] NVARCHAR (60) NOT NULL,
+);
+--closing comment
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/BQE_IndentOperands.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/BQE_IndentOperands.sql
new file mode 100644
index 00000000..87ab1289
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/BQE_IndentOperands.sql
@@ -0,0 +1,5 @@
+select *
+from mytable
+intersect
+select *
+from mytable
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/BQE_KeywordCasing.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/BQE_KeywordCasing.sql
new file mode 100644
index 00000000..1967b68f
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/BQE_KeywordCasing.sql
@@ -0,0 +1,15 @@
+
+ seLect *
+ from mytable
+unIon
+ selECT *
+ fROM mytable
+union ALL
+ select *
+ from mytable
+excepT
+ select *
+ from mytable
+Intersect
+ select *
+ from mytable
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/BQE_OperatorsOnNewLine.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/BQE_OperatorsOnNewLine.sql
new file mode 100644
index 00000000..847da065
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/BQE_OperatorsOnNewLine.sql
@@ -0,0 +1 @@
+select * from mytable union select * from mytable except select * from mytable union all select * from mytable intersect select * from mytable
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CTE.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CTE.sql
new file mode 100644
index 00000000..7a33693b
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CTE.sql
@@ -0,0 +1,18 @@
+USE AdventureWorks2008R2;
+GO
+-- Define the CTE expression name and column list.
+WITH Sales_CTE (SalesPersonID, SalesOrderID, SalesYear)
+AS
+-- Define the CTE query.
+(
+ SELECT SalesPersonID, SalesOrderID, YEAR(OrderDate) AS SalesYear
+ FROM Sales.SalesOrderHeader
+ WHERE SalesPersonID IS NOT NULL
+)
+-- Define the outer query referencing the CTE name.
+SELECT SalesPersonID, COUNT(SalesOrderID) AS TotalSales, SalesYear
+FROM Sales_CTE
+GROUP BY SalesYear, SalesPersonID
+ORDER BY SalesPersonID, SalesYear;
+GO
+
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CTE_MultipleExpressions.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CTE_MultipleExpressions.sql
new file mode 100644
index 00000000..5fb85014
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CTE_MultipleExpressions.sql
@@ -0,0 +1 @@
+with my_initial_table( column1, column2 ) AS ( select * from mytable ), my_other_table( column1X, column2X ) AS ( select * from mytable2 ) select distinct top (10) PERCENT with ties alias1 = SIZE(mytable.mycol1), another = COUNT(new_elements), count(money) AS encore, id INTO my_new_table FROM my_initial_table
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CTE_OneColumn.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CTE_OneColumn.sql
new file mode 100644
index 00000000..d26d33c7
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CTE_OneColumn.sql
@@ -0,0 +1,16 @@
+USE AdventureWorks2008R2;
+GO
+-- Define the CTE expression name and column list.
+WITH Sales_CTE (SalesOrderID)
+AS
+-- Define the CTE query.
+(
+ SELECT SalesOrderID
+ FROM Sales.SalesOrderHeader
+ WHERE SalesPersonID IS NOT NULL
+)
+-- Define the outer query referencing the CTE name.
+SELECT COUNT(SalesOrderID) AS TotalSales
+FROM Sales_CTE;
+GO
+
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure.sql
new file mode 100644
index 00000000..88dd73b1
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure.sql
@@ -0,0 +1,12 @@
+CREATE PROCEDURE au_info
+ @lastname varchar(40),
+ @firstname varchar(20)
+AS
+SELECT au_lname, au_fname, title, pub_name
+ FROM authors a INNER JOIN titleauthor ta
+ ON a.au_id = ta.au_id INNER JOIN titles t
+ ON t.title_id = ta.title_id INNER JOIN publishers p
+ ON t.pub_id = p.pub_id
+ WHERE au_fname = @firstname
+ AND au_lname = @lastname
+GO
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_BackwardsCompatible.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_BackwardsCompatible.sql
new file mode 100644
index 00000000..3129d11a
Binary files /dev/null and b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_BackwardsCompatible.sql differ
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_BeginEnd.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_BeginEnd.sql
new file mode 100644
index 00000000..d78b2346
Binary files /dev/null and b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_BeginEnd.sql differ
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_Minimal.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_Minimal.sql
new file mode 100644
index 00000000..00cf829c
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_Minimal.sql
@@ -0,0 +1,3 @@
+
+ -- my comment
+Create Procedure P1 AS
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_MultipleBatches.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_MultipleBatches.sql
new file mode 100644
index 00000000..871678f0
Binary files /dev/null and b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_MultipleBatches.sql differ
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_MultipleParams.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_MultipleParams.sql
new file mode 100644
index 00000000..8badc9b8
Binary files /dev/null and b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_MultipleParams.sql differ
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_OneParam.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_OneParam.sql
new file mode 100644
index 00000000..f5de7101
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_OneParam.sql
@@ -0,0 +1 @@
+Create Procedure dbo.P1 @param1 int AS
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_ParamsRecompileReturn.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_ParamsRecompileReturn.sql
new file mode 100644
index 00000000..e7d85407
Binary files /dev/null and b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_ParamsRecompileReturn.sql differ
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_Select.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_Select.sql
new file mode 100644
index 00000000..420d5d07
Binary files /dev/null and b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_Select.sql differ
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_TwoPartName.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_TwoPartName.sql
new file mode 100644
index 00000000..80515c95
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_TwoPartName.sql
@@ -0,0 +1 @@
+Create Procedure dbo.P1 AS
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_WithCTE.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_WithCTE.sql
new file mode 100644
index 00000000..7b072ce8
Binary files /dev/null and b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_WithCTE.sql differ
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_WithEncryptionModule.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_WithEncryptionModule.sql
new file mode 100644
index 00000000..a0c65c2d
Binary files /dev/null and b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_WithEncryptionModule.sql differ
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_WithExecuteAsModule.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_WithExecuteAsModule.sql
new file mode 100644
index 00000000..ad09da9e
Binary files /dev/null and b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_WithExecuteAsModule.sql differ
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_WithThreeModules.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_WithThreeModules.sql
new file mode 100644
index 00000000..43770414
Binary files /dev/null and b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateProcedure_WithThreeModules.sql differ
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateTable.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateTable.sql
new file mode 100644
index 00000000..580d6ac5
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateTable.sql
@@ -0,0 +1,17 @@
+
+ -- this is a comment before create table
+CREATE TABLE [SimpleTable] (
+
+ -- this is a comment before document
+ [DocumentID] INT IDENTITY (1, 1) NOT NULL,
+
+ -- this is a comment before Title
+[Title] NVARCHAR (50) NOT NULL,
+
+
+ -- this is a comment before FileName
+ [FileName] NVARCHAR (400) NOT NULL,
+
+ -- this is a comment before FileExtension
+ [FileExtension] nvarchar(8)
+);
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateTableFull.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateTableFull.sql
new file mode 100644
index 00000000..17ee81e8
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateTableFull.sql
@@ -0,0 +1,10 @@
+CREATE TABLE
+ db_name.schema_name.table_name
+ (
+ col_name1 INT,
+ col_name2 VARCHAR (20)
+
+
+-- here is my comment
+)
+ ON partition_schema_name (partition_column_name);
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateTable_CommentBeforeComma.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateTable_CommentBeforeComma.sql
new file mode 100644
index 00000000..ee2ed324
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateTable_CommentBeforeComma.sql
@@ -0,0 +1,9 @@
+
+create table t1
+(
+ id INT not null /* awesome */, x INT not null, /* cool */ y INT not null -- tremendeous
+)
+with
+(
+ data_compression = row
+);
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateTable_Formatted.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateTable_Formatted.sql
new file mode 100644
index 00000000..e16e281d
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateTable_Formatted.sql
@@ -0,0 +1,7 @@
+
+create table t1
+(
+ col1 int,
+
+ col2 int
+)
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateTable_Timestamp.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateTable_Timestamp.sql
new file mode 100644
index 00000000..32493073
Binary files /dev/null and b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateTable_Timestamp.sql differ
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateView_Full.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateView_Full.sql
new file mode 100644
index 00000000..25ae8eb9
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateView_Full.sql
@@ -0,0 +1,6 @@
+CREATE VIEW my_schema.my_view_name
+(column1, column2,
+ column3
+)
+WITH SCHEMABINDING, ENCRYPTION,VIEW_METADATA
+AS SELECT * FROM mytable
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateView_FullWithComments.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateView_FullWithComments.sql
new file mode 100644
index 00000000..d952d0a6
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateView_FullWithComments.sql
@@ -0,0 +1,11 @@
+CREATE VIEW my_schema.my_view_name --and
+( /* we */ column1, column2, /* can */ column3
+) -- put
+WITH /* comments */ /*even multiple ones */ -- and of various types
+ SCHEMABINDING, -- everywhere
+ ENCRYPTION,
+-- we
+ VIEW_METADATA /* want*/
+AS /* because */
+ SELECT * FROM mytable
+-- it's SQL
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateView_MultipleColumns.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateView_MultipleColumns.sql
new file mode 100644
index 00000000..1d29a253
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateView_MultipleColumns.sql
@@ -0,0 +1,3 @@
+CREATE VIEW my_view (mycol, my_other_col)
+AS
+ select * from mytable
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateView_MultipleOptions.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateView_MultipleOptions.sql
new file mode 100644
index 00000000..b1647f1b
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateView_MultipleOptions.sql
@@ -0,0 +1,4 @@
+CREATE VIEW my_view_name
+WITH SCHEMABINDING, ENCRYPTION, VIEW_METADATA
+AS
+SELECT * FROM mytable
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateView_OneColumn.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateView_OneColumn.sql
new file mode 100644
index 00000000..b1ee1ff9
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateView_OneColumn.sql
@@ -0,0 +1,4 @@
+
+CREATE VIEW my_view (mycol)
+AS
+ select * from mytable
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateView_OneColumnOneOption.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateView_OneColumnOneOption.sql
new file mode 100644
index 00000000..49fdf21f
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateView_OneColumnOneOption.sql
@@ -0,0 +1,4 @@
+CREATE VIEW my_view (mycol) WITH ENCRYPTION
+AS
+ select * from mytable
+
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateView_OneOption.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateView_OneOption.sql
new file mode 100644
index 00000000..5f5c6524
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateView_OneOption.sql
@@ -0,0 +1,5 @@
+
+CREATE VIEW my_view WITH ENCRYPTION
+AS
+ select * from mytable
+
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateView_Simple.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateView_Simple.sql
new file mode 100644
index 00000000..331874f3
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/CreateView_Simple.sql
@@ -0,0 +1,4 @@
+CREATE VIEW my_view
+AS
+ select * from mytable
+
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/Insert_DefaultValues.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/Insert_DefaultValues.sql
new file mode 100644
index 00000000..e48e2969
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/Insert_DefaultValues.sql
@@ -0,0 +1,2 @@
+
+ INSERT INTO NUMBERS DEFAULT VALUES;
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/Insert_Full.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/Insert_Full.sql
new file mode 100644
index 00000000..bc6729aa
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/Insert_Full.sql
@@ -0,0 +1 @@
+with my_initial_table( column1, column2 )AS ( select * from mytable ), my_other_table( column1, column2 ) AS ( select * from mytable ) Insert top (10) PERCENT into myserver.mydatabase.myschema.mytable_or_view WITH (TABLOCK)( col1, col2, col3, col4, col5 ) VALUES ( DEFault, NULL, 1, N'My Value', 'Today'),( 45, 5, 1, N'My Last Value', 'Yesterday'),( 8, 6, 1, N'My Next Value', 'Tomorrow')
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/Insert_OpenQuery.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/Insert_OpenQuery.sql
new file mode 100644
index 00000000..99427306
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/Insert_OpenQuery.sql
@@ -0,0 +1,3 @@
+
+INSERT OPENQUERY (OracleSvr, 'SELECT name FROM joe.titles')-- comment
+VALUES ('NewTitle');
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/Insert_OutputInto.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/Insert_OutputInto.sql
new file mode 100644
index 00000000..ec4826fd
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/Insert_OutputInto.sql
@@ -0,0 +1,5 @@
+
+INSERT Production.ScrapReason OUTPUT
+ INSERTED.ScrapReasonID, INSERTED.Name, INSERTED.ModifiedDate
+INTO @MyTableVar VALUES (N'Operator error', GETDATE());
+
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/Insert_OutputStatement.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/Insert_OutputStatement.sql
new file mode 100644
index 00000000..d9289344
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/Insert_OutputStatement.sql
@@ -0,0 +1,4 @@
+
+INSERT Production.ScrapReason /*comments like this one*/ OUTPUT
+ INSERTED.ScrapReasonID, INSERTED.Name, INSERTED.ModifiedDate
+INTO @MyTableVar VALUES (N'Operator error',/*comments like this one*/ GETDATE());
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/Insert_Select.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/Insert_Select.sql
new file mode 100644
index 00000000..324bda12
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/Insert_Select.sql
@@ -0,0 +1,2 @@
+
+INSERT INTO myTable(FileName, FileType, Document) SELECT 'Text1.txt' AS FileName, '.txt' AS FileType, * FROM OPENROWSET(BULK N'C:\Text1.txt', SINGLE_BLOB) AS Document;
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/Insert_SelectSource.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/Insert_SelectSource.sql
new file mode 100644
index 00000000..1ba6ada2
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/Insert_SelectSource.sql
@@ -0,0 +1,4 @@
+
+INSERT INTO myTable(FileName, FileType, Document) --comment
+ SELECT 'Text1.txt' AS FileName, '.txt' AS FileType,
+ * FROM OPENROWSET(BULK N'C:\Text1.txt', SINGLE_BLOB) AS Document;
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/Insert_TopSpecification.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/Insert_TopSpecification.sql
new file mode 100644
index 00000000..88f0756f
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/Insert_TopSpecification.sql
@@ -0,0 +1,3 @@
+
+insert top (10) into mytable values (10, 11);
+
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/Insert_TopWithComments.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/Insert_TopWithComments.sql
new file mode 100644
index 00000000..10bb8c2b
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/Insert_TopWithComments.sql
@@ -0,0 +1 @@
+insert top (10) mytable /*comments like this one*//*comments like this one*/ values /*comments like this one*/ (10, 11);
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/NestedSelect.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/NestedSelect.sql
new file mode 100644
index 00000000..c223cd26
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/NestedSelect.sql
@@ -0,0 +1,13 @@
+-- number of tests in number of failed tests in control queue
+select (select count(TestResults.TestName)
+ from TestResults
+ JOIN Jobs ON (TestResults.JobPath = Jobs.JobPath)
+ JOIN SnapSubmissions on (SnapSubmissions.JobsPath = jobs.SubmissionParent)
+ where SnapSubmissions.SnapQueueName = 'SqlStudio_control'
+ AND TestResults.Outcome = 'Failed') as FailedTestsInControlQueue,
+ (select count(TestResults.TestName)
+ from TestResults
+ JOIN Jobs ON (TestResults.JobPath = Jobs.JobPath)
+ JOIN SnapSubmissions on (SnapSubmissions.JobsPath = jobs.SubmissionParent)
+ where SnapSubmissions.SnapQueueName = 'SqlStudio_control') as NumberOfTestsInControlQueue
+ -- (FailedTestsInControlQueue / NumberOfTestsInControlQueue) as PercentageOfTestsFailed
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/SelectWithColumnAlias.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/SelectWithColumnAlias.sql
new file mode 100644
index 00000000..6d501d31
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/SelectWithColumnAlias.sql
@@ -0,0 +1,10 @@
+USE AdventureWorks2008R2;
+GO
+SELECT p.Name AS ProductName,
+NonDiscountSales = (OrderQty * UnitPrice),
+Discounts = ((OrderQty * UnitPrice) * UnitPriceDiscount)
+FROM Production.Product AS p
+INNER JOIN Sales.SalesOrderDetail AS sod
+ON p.ProductID = sod.ProductID
+ORDER BY ProductName DESC;
+GO
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/SimpleQuery.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/SimpleQuery.sql
new file mode 100644
index 00000000..fdbe04f5
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/SimpleQuery.sql
@@ -0,0 +1,7 @@
+
+select c1, c2,t3.c3
+
+
+
+
+From t1, t2,t3
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/SimpleQuery_ForBrowseClause.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/SimpleQuery_ForBrowseClause.sql
new file mode 100644
index 00000000..a424acd2
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/SimpleQuery_ForBrowseClause.sql
@@ -0,0 +1,9 @@
+
+select c1, c2,t3.c3
+
+
+
+
+From t1, t2,t3
+
+for browse
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/SimpleQuery_ForXmlClause.sql b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/SimpleQuery_ForXmlClause.sql
new file mode 100644
index 00000000..ed665612
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/TSqlFormatter/TestFiles/SimpleQuery_ForXmlClause.sql
@@ -0,0 +1,9 @@
+
+select c1, c2,t3.c3
+
+
+
+
+From t1, t2,t3
+
+FOR XML AUTO, TYPE, XMLSCHEMA, ELEMENTS XSINIL;
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestServiceProvider.cs b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestServiceProvider.cs
index c92c5261..1ed51b65 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestServiceProvider.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestServiceProvider.cs
@@ -11,7 +11,6 @@ using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.Connection.Contracts;
using Microsoft.SqlTools.ServiceLayer.Credentials;
using Microsoft.SqlTools.ServiceLayer.Hosting;
-using Microsoft.SqlTools.ServiceLayer.LanguageServices;
using Microsoft.SqlTools.ServiceLayer.QueryExecution;
using Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage;
using Microsoft.SqlTools.ServiceLayer.SqlContext;
@@ -145,19 +144,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Common
SqlToolsContext sqlToolsContext = new SqlToolsContext(hostDetails);
// Grab the instance of the service host
- ServiceHost serviceHost = ServiceHost.Instance;
-
- // Start the service
- serviceHost.Start().Wait();
-
- // Initialize the services that will be hosted here
- WorkspaceService.Instance.InitializeService(serviceHost);
- LanguageService.Instance.InitializeService(serviceHost, sqlToolsContext);
- ConnectionService.Instance.InitializeService(serviceHost);
- CredentialService.Instance.InitializeService(serviceHost);
- QueryExecutionService.Instance.InitializeService(serviceHost);
-
- serviceHost.Initialize();
+ ServiceHost serviceHost = HostLoader.CreateAndStartServiceHost(sqlToolsContext);
}
}
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestUtilities.cs b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestUtilities.cs
new file mode 100644
index 00000000..695be588
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestUtilities.cs
@@ -0,0 +1,90 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.IO;
+
+namespace Microsoft.SqlTools.ServiceLayer.Test.Common
+{
+ public class TestUtilities
+ {
+
+ public static void CompareTestFiles(FileInfo baselinePath, FileInfo outputPath, int maxDiffLines = -1 /* unlimited */)
+ {
+ if (!baselinePath.Exists)
+ {
+ throw new ComparisonFailureException("echo Test Failed: Baseline file " + baselinePath.FullName + " does not exist" +
+ Environment.NewLine + Environment.NewLine + "echo test > \"" + baselinePath.FullName + "\"");
+ }
+
+ if (!outputPath.Exists)
+ {
+ throw new ComparisonFailureException("Test Failed: output file " + outputPath.FullName + " doesn't exist.");
+ }
+
+ string baseline = ReadTextAndNormalizeLineEndings(baselinePath.FullName);
+ string actual = ReadTextAndNormalizeLineEndings(outputPath.FullName);
+
+ if (baseline.CompareTo(actual) != 0)
+ {
+ string header = "Test Failed: Baseline file " + baselinePath.FullName + " differs from output file " + outputPath.FullName + "\r\n\r\n";
+ string editAndCopyMessage =
+ "\r\n\r\n copy \"" + outputPath.FullName + "\" \"" + baselinePath.FullName + "\"" +
+ "\r\n\r\n";
+ string diffCmdMessage =
+ "code --diff \"" + baselinePath.FullName + "\" \"" + outputPath.FullName + "\"" +
+ "\r\n\r\n";
+
+ string diffContents = FindFirstDifference(baseline, actual);
+ throw new ComparisonFailureException(header + diffCmdMessage + editAndCopyMessage + diffContents, editAndCopyMessage);
+ }
+ }
+
+
+ private static string FindFirstDifference(string baseline, string actual)
+ {
+ int index = 0;
+ int minEnd = Math.Min(baseline.Length, actual.Length);
+ while (index < minEnd && baseline[index] == actual[index])
+ index++;
+
+ int firstDiffIndex = (index == minEnd && baseline.Length == actual.Length) ? -1 : index;
+
+ int startRange = Math.Max(firstDiffIndex - 50, 0);
+ int endRange = Math.Min(firstDiffIndex + 50, minEnd);
+
+ string baselineDiff = ShowWhitespace(baseline.Substring(startRange, endRange));
+ string actualDiff = ShowWhitespace(actual.Substring(startRange, endRange));
+ return "\r\nFirst Diff:\r\n===== Baseline =====\r\n"
+ + baselineDiff
+ + "\r\n===== Actual =====\r\n"
+ + actualDiff;
+ }
+
+ private static string ShowWhitespace(string input)
+ {
+ return input.Replace("\r", "\\r").Replace("\n", "\\n");
+ }
+
+ ///
+ /// Normalizes line endings in a file to facilitate comparisons regardless of OS. On Windows line endings are \r\n, while
+ /// on other systems only \n is used
+ ///
+ public static string ReadTextAndNormalizeLineEndings(string filePath)
+ {
+ string text = File.ReadAllText(filePath);
+ return NormalizeLineEndings(text);
+ }
+
+ public static string NormalizeLineEndings(string text)
+ {
+ // To work on all platforms, we first stript \r and then replace any remaining \n characters
+ // with a newline string. This helps keep things consistent with file formats for each OS
+ string noCrs = text.Replace("\r", "");
+ return noCrs.Replace("\n", Environment.NewLine);
+ }
+
+ }
+}
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/Credentials/CredentialServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/Credentials/CredentialServiceTests.cs
index d174c48e..d49cfa75 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.Test/Credentials/CredentialServiceTests.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test/Credentials/CredentialServiceTests.cs
@@ -81,7 +81,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Connection
var contextMock = RequestContextMocks.Create(null).AddErrorHandling(obj => errorResponse = obj);
await service.HandleSaveCredentialRequest(new Credential(null), contextMock.Object);
- VerifyErrorSent(contextMock);
+ TestUtils.VerifyErrorSent(contextMock);
Assert.True(((string)errorResponse).Contains("ArgumentException"));
}
@@ -92,14 +92,14 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Connection
var contextMock = RequestContextMocks.Create(null).AddErrorHandling(obj => errorResponse = obj);
await service.HandleSaveCredentialRequest(new Credential(credentialId), contextMock.Object);
- VerifyErrorSent(contextMock);
+ TestUtils.VerifyErrorSent(contextMock);
Assert.True(((string)errorResponse).Contains("ArgumentException"));
}
[Fact]
public async Task SaveCredentialWorksForSingleCredential()
{
- await RunAndVerify(
+ await TestUtils.RunAndVerify(
test: (requestContext) => service.HandleSaveCredentialRequest(new Credential(credentialId, password1), requestContext),
verify: (actual => Assert.True(actual)));
}
@@ -107,11 +107,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Connection
[Fact]
public async Task SaveCredentialSupportsSavingCredentialMultipleTimes()
{
- await RunAndVerify(
+ await TestUtils.RunAndVerify(
test: (requestContext) => service.HandleSaveCredentialRequest(new Credential(credentialId, password1), requestContext),
verify: (actual => Assert.True(actual)));
- await RunAndVerify(
+ await TestUtils.RunAndVerify(
test: (requestContext) => service.HandleSaveCredentialRequest(new Credential(credentialId, password1), requestContext),
verify: (actual => Assert.True(actual)));
}
@@ -120,13 +120,13 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Connection
public async Task ReadCredentialWorksForSingleCredential()
{
// Given we have saved the credential
- await RunAndVerify(
+ await TestUtils.RunAndVerify(
test: (requestContext) => service.HandleSaveCredentialRequest(new Credential(credentialId, password1), requestContext),
verify: (actual => Assert.True(actual, "Expect Credential to be saved successfully")));
// Expect read of the credential to return the password
- await RunAndVerify(
+ await TestUtils.RunAndVerify(
test: (requestContext) => service.HandleReadCredentialRequest(new Credential(credentialId, null), requestContext),
verify: (actual =>
{
@@ -139,22 +139,22 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Connection
{
// Given we have saved multiple credentials
- await RunAndVerify(
+ await TestUtils.RunAndVerify(
test: (requestContext) => service.HandleSaveCredentialRequest(new Credential(credentialId, password1), requestContext),
verify: (actual => Assert.True(actual, "Expect Credential to be saved successfully")));
- await RunAndVerify(
+ await TestUtils.RunAndVerify(
test: (requestContext) => service.HandleSaveCredentialRequest(new Credential(otherCredId, otherPassword), requestContext),
verify: (actual => Assert.True(actual, "Expect Credential to be saved successfully")));
// Expect read of the credentials to return the right password
- await RunAndVerify(
+ await TestUtils.RunAndVerify(
test: (requestContext) => service.HandleReadCredentialRequest(new Credential(credentialId, null), requestContext),
verify: (actual =>
{
Assert.Equal(password1, actual.Password);
}));
- await RunAndVerify(
+ await TestUtils.RunAndVerify(
test: (requestContext) => service.HandleReadCredentialRequest(new Credential(otherCredId, null), requestContext),
verify: (actual =>
{
@@ -166,17 +166,17 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Connection
public async Task ReadCredentialHandlesPasswordUpdate()
{
// Given we have saved twice with a different password
- await RunAndVerify(
+ await TestUtils.RunAndVerify(
test: (requestContext) => service.HandleSaveCredentialRequest(new Credential(credentialId, password1), requestContext),
verify: (actual => Assert.True(actual)));
- await RunAndVerify(
+ await TestUtils.RunAndVerify(
test: (requestContext) => service.HandleSaveCredentialRequest(new Credential(credentialId, password2), requestContext),
verify: (actual => Assert.True(actual)));
// When we read the value for this credential
// Then we expect only the last saved password to be found
- await RunAndVerify(
+ await TestUtils.RunAndVerify(
test: (requestContext) => service.HandleReadCredentialRequest(new Credential(credentialId), requestContext),
verify: (actual =>
{
@@ -192,7 +192,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Connection
// Verify throws on null, and this is sent as an error
await service.HandleReadCredentialRequest(null, contextMock.Object);
- VerifyErrorSent(contextMock);
+ TestUtils.VerifyErrorSent(contextMock);
Assert.True(((string)errorResponse).Contains("ArgumentNullException"));
}
@@ -204,7 +204,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Connection
// Verify throws with no ID
await service.HandleReadCredentialRequest(new Credential(), contextMock.Object);
- VerifyErrorSent(contextMock);
+ TestUtils.VerifyErrorSent(contextMock);
Assert.True(((string)errorResponse).Contains("ArgumentException"));
}
@@ -216,7 +216,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Connection
// When reading the credential
// Then expect the credential to be returned but password left blank
- await RunAndVerify(
+ await TestUtils.RunAndVerify(
test: (requestContext) => service.HandleReadCredentialRequest(new Credential(credWithNoPassword, null), requestContext),
verify: (actual =>
{
@@ -234,7 +234,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Connection
// Verify throws with no ID
await service.HandleDeleteCredentialRequest(new Credential(), contextMock.Object);
- VerifyErrorSent(contextMock);
+ TestUtils.VerifyErrorSent(contextMock);
Assert.True(((string)errorResponse).Contains("ArgumentException"));
}
@@ -242,49 +242,21 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Connection
public async Task DeleteCredentialReturnsTrueOnlyIfCredentialExisted()
{
// Save should be true
- await RunAndVerify(
+ await TestUtils.RunAndVerify(
test: (requestContext) => service.HandleSaveCredentialRequest(new Credential(credentialId, password1), requestContext),
verify: (actual => Assert.True(actual)));
// Then delete - should return true
- await RunAndVerify(
+ await TestUtils.RunAndVerify(
test: (requestContext) => service.HandleDeleteCredentialRequest(new Credential(credentialId), requestContext),
verify: (actual => Assert.True(actual)));
// Then delete - should return false as no longer exists
- await RunAndVerify(
+ await TestUtils.RunAndVerify(
test: (requestContext) => service.HandleDeleteCredentialRequest(new Credential(credentialId), requestContext),
verify: (actual => Assert.False(actual)));
}
- private async Task RunAndVerify(Func, Task> test, Action verify)
- {
- T result = default(T);
- var contextMock = RequestContextMocks.Create(r => result = r).AddErrorHandling(null);
- await test(contextMock.Object);
- VerifyResult(contextMock, verify, result);
- }
-
- private void VerifyErrorSent(Mock> contextMock)
- {
- contextMock.Verify(c => c.SendResult(It.IsAny()), Times.Never);
- contextMock.Verify(c => c.SendError(It.IsAny()), Times.Once);
- }
-
- private void VerifyResult(Mock> contextMock, U expected, U actual)
- {
- contextMock.Verify(c => c.SendResult(It.IsAny()), Times.Once);
- Assert.Equal(expected, actual);
- contextMock.Verify(c => c.SendError(It.IsAny()), Times.Never);
- }
-
- private void VerifyResult(Mock> contextMock, Action verify, T actual)
- {
- contextMock.Verify(c => c.SendResult(It.IsAny()), Times.Once);
- contextMock.Verify(c => c.SendError(It.IsAny()), Times.Never);
- verify(actual);
- }
-
}
}
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/Extensibility/ExtensionTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/Extensibility/ExtensionTests.cs
new file mode 100644
index 00000000..009c0531
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test/Extensibility/ExtensionTests.cs
@@ -0,0 +1,88 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.Composition;
+using System.Linq;
+using System.Reflection;
+using Microsoft.SqlTools.ServiceLayer.Extensibility;
+using Microsoft.SqlTools.ServiceLayer.Formatter;
+using Xunit;
+
+namespace Microsoft.SqlTools.ServiceLayer.Test.Extensibility
+{
+ public class ExtensionTests
+ {
+
+ [Fact]
+ public void CreateAssemblyStoreShouldFindTypesInAssembly()
+ {
+ // Given a store for MyExportType
+ ExtensionStore store = ExtensionStore.CreateAssemblyStore(GetType().GetTypeInfo().Assembly);
+ // Then should get any export for this type and subtypes
+ Assert.Equal(2, store.GetExports().Count());
+
+ // But for a different type, expect throw as the store only contains MyExportType
+ Assert.Throws(() => store.GetExports().Count());
+ }
+
+ [Fact]
+ public void CreateDefaultLoaderShouldOnlyFindTypesInMainAssembly()
+ {
+ // Given a store created using CreateDefaultLoader
+ // Then should not find exports from a different assembly
+ ExtensionStore store = ExtensionStore.CreateDefaultLoader();
+ Assert.Equal(0, store.GetExports().Count());
+
+ // But should find exports that are defined in the main assembly
+ store = ExtensionStore.CreateDefaultLoader();
+ Assert.NotEmpty(store.GetExports());
+ }
+
+
+ [Fact]
+ public void CreateDefaultServiceProviderShouldOnlyFindTypesInMainAssembly()
+ {
+ // Given a default ExtensionServiceProvider
+ // Then should not find exports from a different assembly
+ ExtensionServiceProvider serviceProvider = ExtensionServiceProvider.CreateDefaultServiceProvider();
+ Assert.Empty(serviceProvider.GetServices());
+
+ // But should find exports that are defined in the main assembly
+ Assert.NotEmpty(serviceProvider.GetServices());
+ }
+
+ [Fact]
+ public void CreateStoreForCurrentDirectoryShouldFindExportsInDirectory()
+ {
+ // Given stores created for types in different assemblies
+ ExtensionStore myStore = ExtensionStore.CreateStoreForCurrentDirectory();
+ ExtensionStore querierStore = ExtensionStore.CreateStoreForCurrentDirectory();
+
+ // When I query exports
+ // Then exports for all assemblies should be found
+ Assert.Equal(2, myStore.GetExports().Count());
+ Assert.NotEmpty(querierStore.GetExports());
+ }
+ }
+
+ // Note: in order for the MEF lookup to succeed, one class must have
+ [Export(typeof(MyExportType))]
+ public class MyExportType
+ {
+
+ }
+
+ public class MyExportSubType : MyExportType
+ {
+
+ }
+
+ public class MyOtherType
+ {
+
+ }
+}
+
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/Extensibility/ServiceProviderTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/Extensibility/ServiceProviderTests.cs
new file mode 100644
index 00000000..1596bd21
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test/Extensibility/ServiceProviderTests.cs
@@ -0,0 +1,115 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.Linq;
+using Microsoft.SqlTools.ServiceLayer.Extensibility;
+using Xunit;
+
+namespace Microsoft.SqlTools.ServiceLayer.Test.Extensibility
+{
+ public class ServiceProviderTests
+ {
+ private RegisteredServiceProvider provider;
+ public ServiceProviderTests()
+ {
+ provider = new RegisteredServiceProvider();
+ }
+
+ [Fact]
+ public void GetServiceShouldReturnNullIfNoServicesRegistered()
+ {
+ // Given no service registered
+ // When I call GetService
+ var service = provider.GetService();
+ // Then I expect null to be returned
+ Assert.Null(service);
+ }
+
+
+ [Fact]
+ public void GetSingleServiceThrowsMultipleServicesRegistered()
+ {
+ // Given 2 services registered
+ provider.Register(() => new[] { new MyProviderService(), new MyProviderService() });
+ // When I call GetService
+ // Then I expect to throw
+ Assert.Throws(() => provider.GetService());
+ }
+
+ [Fact]
+ public void GetServicesShouldReturnEmptyIfNoServicesRegistered()
+ {
+ // Given no service regisstered
+ // When I call GetService
+ var services = provider.GetServices();
+ // Then I expect empty enumerable to be returned
+ Assert.NotNull(services);
+ Assert.Equal(0, services.Count());
+ }
+
+ [Fact]
+ public void GetServiceShouldReturnRegisteredService()
+ {
+ MyProviderService service = new MyProviderService();
+ provider.RegisterSingleService(service);
+
+ var returnedService = provider.GetService();
+ Assert.Equal(service, returnedService);
+ }
+
+ [Fact]
+ public void GetServicesShouldReturnRegisteredServiceWhenMultipleServicesRegistered()
+ {
+ MyProviderService service = new MyProviderService();
+ provider.RegisterSingleService(service);
+
+ var returnedServices = provider.GetServices();
+ Assert.Equal(service, returnedServices.Single());
+ }
+
+ [Fact]
+ public void RegisterServiceProviderShouldThrowIfServiceIsIncompatible()
+ {
+ MyProviderService service = new MyProviderService();
+ Assert.Throws(() => provider.RegisterSingleService(typeof(OtherService), service));
+ }
+ [Fact]
+ public void RegisterServiceProviderShouldThrowIfServiceAlreadyRegistered()
+ {
+ MyProviderService service = new MyProviderService();
+ provider.RegisterSingleService(service);
+
+ Assert.Throws(() => provider.RegisterSingleService(service));
+ }
+
+ [Fact]
+ public void RegisterShouldThrowIfServiceAlreadyRegistered()
+ {
+ MyProviderService service = new MyProviderService();
+ provider.RegisterSingleService(service);
+
+ Assert.Throws(() => provider.Register(() => service.SingleItemAsEnumerable()));
+ }
+
+ [Fact]
+ public void RegisterShouldThrowIfServicesAlreadyRegistered()
+ {
+ provider.Register(() => new [] { new MyProviderService(), new MyProviderService() });
+ Assert.Throws(() => provider.Register(() => new MyProviderService().SingleItemAsEnumerable()));
+ }
+ }
+
+
+ public class MyProviderService
+ {
+
+ }
+
+ public class OtherService
+ {
+
+ }
+}
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/Formatter/BinaryQueryExpressionFormatterTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/Formatter/BinaryQueryExpressionFormatterTests.cs
new file mode 100644
index 00000000..0639b01f
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test/Formatter/BinaryQueryExpressionFormatterTests.cs
@@ -0,0 +1,57 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using Microsoft.SqlTools.ServiceLayer.Formatter;
+using Xunit;
+
+namespace Microsoft.SqlTools.ServiceLayer.Test.Formatter
+{
+ public class BinaryQueryExpressionFormatterTests : FormatterUnitTestsBase
+ {
+ [Fact]
+ public void BQE_IndentOperands()
+ {
+ FormatOptions options = new FormatOptions();
+ //options.PlaceEachReferenceOnNewLineInQueryStatements = true;
+ LoadAndFormatAndCompare("BQE_IndentOperands", GetInputFile("BQE_IndentOperands.sql"),
+ GetBaselineFile("BQE_IndentOperands.sql"), options, true);
+ }
+
+ [Fact]
+ public void BQE_KeywordCasing_UpperCase()
+ {
+ FormatOptions options = new FormatOptions();
+ options.KeywordCasing = CasingOptions.Uppercase;
+ LoadAndFormatAndCompare("BQE_KeywordCasing_UpperCase", GetInputFile("BQE_KeywordCasing.sql"),
+ GetBaselineFile("BQE_KeywordCasing_UpperCase.sql"), options, true);
+ }
+
+ [Fact]
+ public void BQE_KeywordCasing_LowerCase()
+ {
+ FormatOptions options = new FormatOptions();
+ options.KeywordCasing = CasingOptions.Lowercase;
+ LoadAndFormatAndCompare("BQE_KeywordCasing_LowerCase", GetInputFile("BQE_KeywordCasing.sql"),
+ GetBaselineFile("BQE_KeywordCasing_LowerCase.sql"), options, true);
+ }
+
+ [Fact]
+ public void BQE_KeywordCasing_NoFormat()
+ {
+ FormatOptions options = new FormatOptions();
+ options.KeywordCasing = CasingOptions.None;
+ LoadAndFormatAndCompare("BQE_KeywordCasing_NoFormat", GetInputFile("BQE_KeywordCasing.sql"),
+ GetBaselineFile("BQE_KeywordCasing_NoFormat.sql"), options, true);
+ }
+
+ [Fact]
+ public void BQE_OperatorsOnNewLine()
+ {
+ FormatOptions options = new FormatOptions();
+ LoadAndFormatAndCompare("BQE_OperatorsOnNewLine", GetInputFile("BQE_OperatorsOnNewLine.sql"),
+ GetBaselineFile("BQE_OperatorsOnNewLine.sql"), options, true);
+ }
+ }
+}
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/Formatter/CommonTableExpressionFormatterTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/Formatter/CommonTableExpressionFormatterTests.cs
new file mode 100644
index 00000000..eee819f9
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test/Formatter/CommonTableExpressionFormatterTests.cs
@@ -0,0 +1,110 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+
+using Microsoft.SqlTools.ServiceLayer.Formatter;
+using Xunit;
+
+namespace Microsoft.SqlTools.ServiceLayer.Test.Formatter
+{
+
+ public class CommonTableExpressionFormatterTests : FormatterUnitTestsBase
+ {
+ [Fact]
+ public void CTE()
+ {
+ LoadAndFormatAndCompare("CTE", GetInputFile("CTE.sql"),
+ GetBaselineFile("CTE.sql"), new FormatOptions(), true);
+ }
+
+ [Fact]
+ public void CTE_OneColumn()
+ {
+ LoadAndFormatAndCompare("CTE_OneColumn", GetInputFile("CTE_OneColumn.sql"),
+ GetBaselineFile("CTE_OneColumn.sql"), new FormatOptions(), true);
+ }
+
+ [Fact]
+ public void CTE_MultipleExpressions()
+ {
+ LoadAndFormatAndCompare("CTE_MultipleExpressions", GetInputFile("CTE_MultipleExpressions.sql"),
+ GetBaselineFile("CTE_MultipleExpressions.sql"), new FormatOptions(), true);
+ }
+
+ [Fact]
+ public void CTE_CommasBeforeDefinition()
+ {
+ FormatOptions options = new FormatOptions();
+ options.PlaceCommasBeforeNextStatement = true;
+
+ // TODO: fix verify to account for commma placement - this can
+ LoadAndFormatAndCompare("CTE_CommasBeforeDefinition", GetInputFile("CTE.sql"),
+ GetBaselineFile("CTE_CommasBeforeDefinition.sql"), options, false);
+ }
+
+ [Fact]
+ public void CTE_EachReferenceOnNewLine()
+ {
+ FormatOptions options = new FormatOptions();
+ options.PlaceEachReferenceOnNewLineInQueryStatements = true;
+
+ LoadAndFormatAndCompare("CTE_EachReferenceOnNewLine", GetInputFile("CTE.sql"),
+ GetBaselineFile("CTE_EachReferenceOnNewLine.sql"), options, true);
+ }
+
+ [Fact]
+ public void CTE_EachReferenceOnNewLine_CommasBeforeDefinition()
+ {
+ FormatOptions options = new FormatOptions();
+ options.PlaceCommasBeforeNextStatement = true;
+ options.PlaceEachReferenceOnNewLineInQueryStatements = true;
+
+ // TODO: fix verify to account for commma placement - this can
+ LoadAndFormatAndCompare("CTE_EachReferenceOnNewLine_CommasBeforeDefinition", GetInputFile("CTE.sql"),
+ GetBaselineFile("CTE_EachReferenceOnNewLine_CommasBeforeDefinition.sql"), options, false);
+ }
+
+ [Fact]
+ public void CTE_UseTabs()
+ {
+ FormatOptions options = new FormatOptions();
+ options.UseTabs = true;
+ options.PlaceEachReferenceOnNewLineInQueryStatements = true;
+ LoadAndFormatAndCompare("CTE_UseTabs", GetInputFile("CTE.sql"),
+ GetBaselineFile("CTE_UseTabs.sql"), options, true);
+ }
+
+ [Fact]
+ public void CTE_20Spaces()
+ {
+ FormatOptions options = new FormatOptions();
+ options.SpacesPerIndent = 20;
+ options.PlaceEachReferenceOnNewLineInQueryStatements = true;
+ LoadAndFormatAndCompare("CTE_20Spaces", GetInputFile("CTE.sql"),
+ GetBaselineFile("CTE_20Spaces.sql"), options, true);
+ }
+
+ [Fact]
+ public void CTE_UpperCaseKeywords()
+ {
+ FormatOptions options = new FormatOptions();
+ options.KeywordCasing = CasingOptions.Uppercase;
+ options.PlaceEachReferenceOnNewLineInQueryStatements = true;
+ LoadAndFormatAndCompare("CTE_UpperCaseKeywords", GetInputFile("CTE.sql"),
+ GetBaselineFile("CTE_UpperCaseKeywords.sql"), options, true);
+ }
+
+ [Fact]
+ public void CTE_LowerCaseKeywords()
+ {
+ FormatOptions options = new FormatOptions();
+ options.KeywordCasing = CasingOptions.Lowercase;
+ options.PlaceEachReferenceOnNewLineInQueryStatements = true;
+ LoadAndFormatAndCompare("CTE_LowerCaseKeywords", GetInputFile("CTE.sql"),
+ GetBaselineFile("CTE_LowerCaseKeywords.sql"), options, true);
+ }
+
+ }
+}
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/Formatter/CreateProcedureFormatterTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/Formatter/CreateProcedureFormatterTests.cs
new file mode 100644
index 00000000..1870e41b
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test/Formatter/CreateProcedureFormatterTests.cs
@@ -0,0 +1,104 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using Microsoft.SqlTools.ServiceLayer.Formatter;
+using Xunit;
+
+namespace Microsoft.SqlTools.ServiceLayer.Test.Formatter
+{
+
+ public class CreateProcedureFormatterTests : FormatterUnitTestsBase
+ {
+ [Fact]
+ public void CreateProcedure_BackwardsCompatible()
+ {
+ LoadAndFormatAndCompare("CreateProcedure_BackwardsCompatible", GetInputFile("CreateProcedure_BackwardsCompatible.sql"),
+ GetBaselineFile("CreateProcedure_BackwardsCompatible.sql"), new FormatOptions(), true);
+ }
+
+ [Fact]
+ public void CreateProcedure_BeginEnd()
+ {
+ LoadAndFormatAndCompare("CreateProcedure_BeginEnd", GetInputFile("CreateProcedure_BeginEnd.sql"),
+ GetBaselineFile("CreateProcedure_BeginEnd.sql"), new FormatOptions(), true);
+ }
+
+ [Fact]
+ public void CreateProcedure_Minimal()
+ {
+ LoadAndFormatAndCompare("CreateProcedure_Minimal", GetInputFile("CreateProcedure_Minimal.sql"),
+ GetBaselineFile("CreateProcedure_Minimal.sql"), new FormatOptions(), true);
+ }
+
+ [Fact]
+ public void CreateProcedure_MultipleBatches()
+ {
+ LoadAndFormatAndCompare("CreateProcedure_MultipleBatches", GetInputFile("CreateProcedure_MultipleBatches.sql"),
+ GetBaselineFile("CreateProcedure_MultipleBatches.sql"), new FormatOptions(), true);
+ }
+ [Fact]
+ public void CreateProcedure_MultipleParams()
+ {
+ LoadAndFormatAndCompare("CreateProcedure_MultipleParams", GetInputFile("CreateProcedure_MultipleParams.sql"),
+ GetBaselineFile("CreateProcedure_MultipleParams.sql"), new FormatOptions(), true);
+ }
+
+ [Fact]
+ public void CreateProcedure_OneParam()
+ {
+ LoadAndFormatAndCompare("CreateProcedure_OneParam", GetInputFile("CreateProcedure_OneParam.sql"),
+ GetBaselineFile("CreateProcedure_OneParam.sql"), new FormatOptions(), true);
+ }
+
+ [Fact]
+ public void CreateProcedure_ParamsRecompileReturn()
+ {
+ LoadAndFormatAndCompare("CreateProcedure_ParamsRecompileReturn", GetInputFile("CreateProcedure_ParamsRecompileReturn.sql"),
+ GetBaselineFile("CreateProcedure_ParamsRecompileReturn.sql"), new FormatOptions(), true);
+ }
+
+ [Fact]
+ public void CreateProcedure_Select()
+ {
+ LoadAndFormatAndCompare("CreateProcedure_Select", GetInputFile("CreateProcedure_Select.sql"),
+ GetBaselineFile("CreateProcedure_Select.sql"), new FormatOptions(), true);
+ }
+
+ [Fact]
+ public void CreateProcedure_TwoPartName()
+ {
+ LoadAndFormatAndCompare("CreateProcedure_TwoPartName", GetInputFile("CreateProcedure_TwoPartName.sql"),
+ GetBaselineFile("CreateProcedure_TwoPartName.sql"), new FormatOptions(), true);
+ }
+
+ [Fact]
+ public void CreateProcedure_WithCTE()
+ {
+ LoadAndFormatAndCompare("CreateProcedure_WithCTE", GetInputFile("CreateProcedure_WithCTE.sql"),
+ GetBaselineFile("CreateProcedure_WithCTE.sql"), new FormatOptions(), true);
+ }
+
+ [Fact]
+ public void CreateProcedure_WithEncryptionModule()
+ {
+ LoadAndFormatAndCompare("CreateProcedure_WithEncryptionModule", GetInputFile("CreateProcedure_WithEncryptionModule.sql"),
+ GetBaselineFile("CreateProcedure_WithEncryptionModule.sql"), new FormatOptions(), true);
+ }
+
+ [Fact]
+ public void CreateProcedure_WithExecuteAsModule()
+ {
+ LoadAndFormatAndCompare("CreateProcedure_WithExecuteAsModule", GetInputFile("CreateProcedure_WithExecuteAsModule.sql"),
+ GetBaselineFile("CreateProcedure_WithExecuteAsModule.sql"), new FormatOptions(), true);
+ }
+
+ [Fact]
+ public void CreateProcedure_WithThreeModules()
+ {
+ LoadAndFormatAndCompare("CreateProcedure_WithThreeModules", GetInputFile("CreateProcedure_WithThreeModules.sql"),
+ GetBaselineFile("CreateProcedure_WithThreeModules.sql"), new FormatOptions(), true);
+ }
+ }
+}
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/Formatter/CreateTableFormatterTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/Formatter/CreateTableFormatterTests.cs
new file mode 100644
index 00000000..479ae462
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test/Formatter/CreateTableFormatterTests.cs
@@ -0,0 +1,146 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using Microsoft.SqlTools.ServiceLayer.Formatter;
+using Xunit;
+
+namespace Microsoft.SqlTools.ServiceLayer.Test.Formatter
+{
+
+ public class CreateTableFormatterTests : FormatterUnitTestsBase
+ {
+ [Fact]
+ public void CreateTable()
+ {
+ LoadAndFormatAndCompare("CreateTable", GetInputFile("CreateTable.sql"), GetBaselineFile("CreateTable.sql"), new FormatOptions(), true);
+ }
+
+ /**
+ * The test contains a timestamp column, which is the shortest (1 token) possible length for a column item.
+ */
+ [Fact]
+ public void CreateTable_Timestamp()
+ {
+ FormatOptions options = new FormatOptions();
+ options.AlignColumnDefinitionsInColumns = true;
+ LoadAndFormatAndCompare("CreateTable_Timestamp", GetInputFile("CreateTable_Timestamp.sql"), GetBaselineFile("CreateTable_Timestamp.sql"), options, true);
+ }
+
+ [Fact]
+ public void CreateTable_CommasBeforeDefinition()
+ {
+ FormatOptions options = new FormatOptions();
+ options.PlaceCommasBeforeNextStatement = true;
+
+ // TODO: fix verify to account for commma placement - this can
+ LoadAndFormatAndCompare("CreateTable_CommasBeforeDefinition", GetInputFile("CreateTable.sql"), GetBaselineFile("CreateTable_CommasBeforeDefinition.sql"), options, false);
+ }
+
+ [Fact]
+ public void CreateTable_UseTabs()
+ {
+ FormatOptions options = new FormatOptions();
+ options.UseTabs = true;
+ LoadAndFormatAndCompare("CreateTable_UseTabs", GetInputFile("CreateTable.sql"), GetBaselineFile("CreateTable_UseTabs.sql"), options, true);
+ }
+
+ [Fact]
+ public void CreateTable_20Spaces()
+ {
+ FormatOptions options = new FormatOptions();
+ options.SpacesPerIndent = 20;
+ LoadAndFormatAndCompare("CreateTable_20Spaces", GetInputFile("CreateTable.sql"), GetBaselineFile("CreateTable_20Spaces.sql"), options, true);
+ }
+
+ [Fact]
+ public void CreateTable_UpperCaseKeywords()
+ {
+ FormatOptions options = new FormatOptions();
+ options.KeywordCasing = CasingOptions.Uppercase;
+ LoadAndFormatAndCompare("CreateTable_UpperCaseKeywords", GetInputFile("CreateTable.sql"), GetBaselineFile("CreateTable_UpperCaseKeywords.sql"), options, true);
+ }
+
+ [Fact]
+ public void CreateTable_LowerCaseKeywords()
+ {
+ FormatOptions options = new FormatOptions();
+ options.KeywordCasing = CasingOptions.Lowercase;
+ LoadAndFormatAndCompare("CreateTable_LowerCaseKeywords", GetInputFile("CreateTable.sql"), GetBaselineFile("CreateTable_LowerCaseKeywords.sql"), options, true);
+ }
+
+ [Fact]
+ public void CreateTable_UpperCaseDataTypes()
+ {
+ FormatOptions options = new FormatOptions();
+ options.DatatypeCasing = CasingOptions.Uppercase;
+ LoadAndFormatAndCompare("CreateTable_UpperCaseDataTypes", GetInputFile("CreateTable.sql"), GetBaselineFile("CreateTable_UpperCaseDataTypes.sql"), options, true);
+ }
+
+ [Fact]
+ public void CreateTable_LowerCaseDataTypes()
+ {
+ FormatOptions options = new FormatOptions();
+ options.DatatypeCasing = CasingOptions.Lowercase;
+ LoadAndFormatAndCompare("CreateTable_LowerCaseDataTypes", GetInputFile("CreateTable.sql"), GetBaselineFile("CreateTable_LowerCaseDataTypes.sql"), options, true);
+ }
+
+ [Fact]
+ public void CreateTable_AlignInColumns()
+ {
+ FormatOptions options = new FormatOptions() { AlignColumnDefinitionsInColumns = true };
+ LoadAndFormatAndCompare("CreateTable_AlignInColumns", GetInputFile("CreateTable.sql"), GetBaselineFile("CreateTable_AlignInColumns.sql"), options, true);
+ }
+
+ [Fact]
+ public void CreateTable_AlignInColumnsUseTabs()
+ {
+ FormatOptions options = new FormatOptions();
+ options.UseTabs = true;
+ options.AlignColumnDefinitionsInColumns = true;
+ LoadAndFormatAndCompare("CreateTable_AlignInColumnsUseTabs", GetInputFile("CreateTable.sql"), GetBaselineFile("CreateTable_AlignInColumnsUseTabs.sql"), options, true);
+ }
+
+ [Fact]
+ public void CreateTable_On()
+ {
+ LoadAndFormatAndCompare("CreateTableOn", GetInputFile("CreateTableFull.sql"), GetBaselineFile("CreateTableOn.sql"), new FormatOptions(), true);
+ }
+
+ [Fact]
+ public void CreateTable_Formatted()
+ {
+ LoadAndFormatAndCompare("CreateTable_Formatted", GetInputFile("CreateTable_Formatted.sql"), GetBaselineFile("CreateTable_Formatted.sql"), new FormatOptions(), true);
+ }
+
+ [Fact]
+ public void CreateTable_CommentsBeforeComma()
+ {
+ FormatOptions options = new FormatOptions();
+ options.UseTabs = false;
+ options.AlignColumnDefinitionsInColumns = true;
+ options.PlaceCommasBeforeNextStatement = true;
+ LoadAndFormatAndCompare("CreateTable_CommentsBeforeComma", GetInputFile("CreateTable_CommentBeforeComma.sql"), GetBaselineFile("CreateTable_CommentBeforeComma.sql"), options, true);
+ }
+
+ [Fact]
+ public void CreateTableAddress_AlignInColumns()
+ {
+ FormatOptions options = new FormatOptions();
+ options.AlignColumnDefinitionsInColumns = true;
+ LoadAndFormatAndCompare("CreateTableAddress_AlignInColumns", GetInputFile("Address.sql"), GetBaselineFile("CreateTableAddress_AlignInColumns.sql"), options, true);
+ }
+
+ [Fact]
+ public void CreateTableAddress_AlignInColumnsUseTabs()
+ {
+ FormatOptions options = new FormatOptions();
+ options.UseTabs = true;
+ options.AlignColumnDefinitionsInColumns = true;
+ LoadAndFormatAndCompare("CreateTableAddress_AlignInColumnsUseTabs", GetInputFile("Address.sql"), GetBaselineFile("CreateTableAddress_AlignInColumnsUseTabs.sql"), options, true);
+ }
+
+
+ }
+}
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/Formatter/CreateViewFormatterTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/Formatter/CreateViewFormatterTests.cs
new file mode 100644
index 00000000..c0521652
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test/Formatter/CreateViewFormatterTests.cs
@@ -0,0 +1,70 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+
+using Microsoft.SqlTools.ServiceLayer.Formatter;
+using Xunit;
+
+namespace Microsoft.SqlTools.ServiceLayer.Test.Formatter
+{
+
+ public class CreateViewFormatterTests : FormatterUnitTestsBase
+ {
+ [Fact]
+ public void CreateView_Full()
+ {
+ LoadAndFormatAndCompare("CreateView_Full", GetInputFile("CreateView_Full.sql"),
+ GetBaselineFile("CreateView_Full.sql"), new FormatOptions(), true);
+ }
+
+ [Fact]
+ public void CreateView_FullWithComments()
+ {
+ LoadAndFormatAndCompare("CreateView_FullWithComments", GetInputFile("CreateView_FullWithComments.sql"), GetBaselineFile("CreateView_FullWithComments.sql"), new FormatOptions(), true);
+ }
+
+ [Fact]
+ public void CreateView_MultipleColumns()
+ {
+ LoadAndFormatAndCompare("CreateView_MultipleColumns", GetInputFile("CreateView_MultipleColumns.sql"),
+ GetBaselineFile("CreateView_MultipleColumns.sql"), new FormatOptions(), true);
+ }
+
+ [Fact]
+ public void CreateView_MultipleOptions()
+ {
+ LoadAndFormatAndCompare("CreateView_MultipleOptions", GetInputFile("CreateView_MultipleOptions.sql"),
+ GetBaselineFile("CreateView_MultipleOptions.sql"), new FormatOptions(), true);
+ }
+
+ [Fact]
+ public void CreateView_OneColumn()
+ {
+ LoadAndFormatAndCompare("CreateView_OneColumn", GetInputFile("CreateView_OneColumn.sql"),
+ GetBaselineFile("CreateView_OneColumn.sql"), new FormatOptions(), true);
+ }
+
+ [Fact]
+ public void CreateView_OneColumnOneOption()
+ {
+ LoadAndFormatAndCompare("CreateView_OneColumnOneOption", GetInputFile("CreateView_OneColumnOneOption.sql"),
+ GetBaselineFile("CreateView_OneColumnOneOption.sql"), new FormatOptions(), true);
+ }
+
+ [Fact]
+ public void CreateView_OneOption()
+ {
+ LoadAndFormatAndCompare("CreateView_OneOption", GetInputFile("CreateView_OneOption.sql"),
+ GetBaselineFile("CreateView_OneOption.sql"), new FormatOptions(), true);
+ }
+
+ [Fact]
+ public void CreateView_Simple()
+ {
+ LoadAndFormatAndCompare("CreateView_Simple", GetInputFile("CreateView_Simple.sql"),
+ GetBaselineFile("CreateView_Simple.sql"), new FormatOptions(), true);
+ }
+ }
+}
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/Formatter/FormatterSettingsTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/Formatter/FormatterSettingsTests.cs
new file mode 100644
index 00000000..3ce0f58e
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test/Formatter/FormatterSettingsTests.cs
@@ -0,0 +1,108 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using Microsoft.SqlTools.ServiceLayer.Formatter;
+using Microsoft.SqlTools.ServiceLayer.SqlContext;
+using Newtonsoft.Json.Linq;
+using Xunit;
+
+namespace Microsoft.SqlTools.ServiceLayer.Test.Formatter
+{
+ public class FormatterSettingsTests
+ {
+ [Fact]
+ public void ValidateFormatterServiceDefaults()
+ {
+ var sqlToolsSettings = new SqlToolsSettings();
+ Assert.Null(sqlToolsSettings.SqlTools.Format.AlignColumnDefinitionsInColumns);
+ Assert.Equal(CasingOptions.None, sqlToolsSettings.SqlTools.Format.DatatypeCasing);
+ Assert.Equal(CasingOptions.None, sqlToolsSettings.SqlTools.Format.KeywordCasing);
+ Assert.Null(sqlToolsSettings.SqlTools.Format.PlaceCommasBeforeNextStatement);
+ Assert.Null(sqlToolsSettings.SqlTools.Format.PlaceSelectStatementReferencesOnNewLine);
+ Assert.Null(sqlToolsSettings.SqlTools.Format.UseBracketForIdentifiers);
+ }
+
+ [Fact]
+ public void ValidateFormatSettingsParsedFromJson()
+ {
+ const string settingsJson = @"
+{
+ ""params"": {
+ ""mssql"": {
+ ""format"": {
+ useBracketForIdentifiers: true,
+ placeCommasBeforeNextStatement: true,
+ placeSelectStatementReferencesOnNewLine: true,
+ keywordCasing: ""uppercase"",
+ datatypeCasing: ""lowercase"",
+ alignColumnDefinitionsInColumns: true
+ }
+ }
+ }
+}";
+
+ JObject message = JObject.Parse(settingsJson);
+ JToken messageParams = null;
+ message.TryGetValue("params", out messageParams);
+ SqlToolsSettings sqlToolsSettings = messageParams.ToObject();
+
+ Assert.True(sqlToolsSettings.SqlTools.Format.AlignColumnDefinitionsInColumns);
+ Assert.Equal(CasingOptions.Lowercase, sqlToolsSettings.SqlTools.Format.DatatypeCasing);
+ Assert.Equal(CasingOptions.Uppercase, sqlToolsSettings.SqlTools.Format.KeywordCasing);
+ Assert.True(sqlToolsSettings.SqlTools.Format.PlaceCommasBeforeNextStatement);
+ Assert.True(sqlToolsSettings.SqlTools.Format.PlaceSelectStatementReferencesOnNewLine);
+ Assert.True(sqlToolsSettings.SqlTools.Format.UseBracketForIdentifiers);
+ }
+
+ [Fact]
+ public void FormatOptionsMatchDefaultSettings()
+ {
+ var options = new FormatOptions();
+ AssertOptionsHaveDefaultValues(options);
+ }
+
+ private static void AssertOptionsHaveDefaultValues(FormatOptions options)
+ {
+ Assert.False(options.AlignColumnDefinitionsInColumns);
+ Assert.Equal(CasingOptions.None, options.DatatypeCasing);
+ Assert.Equal(CasingOptions.None, options.KeywordCasing);
+ Assert.False(options.PlaceCommasBeforeNextStatement);
+ Assert.False(options.PlaceEachReferenceOnNewLineInQueryStatements);
+ Assert.False(options.EncloseIdentifiersInSquareBrackets);
+ }
+
+ [Fact]
+ public void CanCopyDefaultFormatSettingsToOptions()
+ {
+ var sqlToolsSettings = new SqlToolsSettings();
+ FormatOptions options = new FormatOptions();
+ TSqlFormatterService.UpdateFormatOptionsFromSettings(options, sqlToolsSettings.SqlTools.Format);
+ AssertOptionsHaveDefaultValues(options);
+ }
+
+ [Fact]
+ public void CanCopyAlteredFormatSettingsToOptions()
+ {
+ var sqlToolsSettings = new SqlToolsSettings();
+ sqlToolsSettings.SqlTools.Format.AlignColumnDefinitionsInColumns = true;
+ sqlToolsSettings.SqlTools.Format.DatatypeCasing = CasingOptions.Lowercase;
+ sqlToolsSettings.SqlTools.Format.KeywordCasing = CasingOptions.Uppercase;
+ sqlToolsSettings.SqlTools.Format.PlaceCommasBeforeNextStatement = true;
+ sqlToolsSettings.SqlTools.Format.PlaceSelectStatementReferencesOnNewLine = true;
+ sqlToolsSettings.SqlTools.Format.UseBracketForIdentifiers = true;
+
+ FormatOptions options = new FormatOptions();
+ TSqlFormatterService.UpdateFormatOptionsFromSettings(options, sqlToolsSettings.SqlTools.Format);
+
+ Assert.True(options.AlignColumnDefinitionsInColumns);
+ Assert.Equal(CasingOptions.Lowercase, options.DatatypeCasing);
+ Assert.Equal(CasingOptions.Uppercase, options.KeywordCasing);
+ Assert.True(options.PlaceCommasBeforeNextStatement);
+ Assert.True(options.PlaceEachReferenceOnNewLineInQueryStatements);
+ Assert.True(options.EncloseIdentifiersInSquareBrackets);
+ }
+
+ }
+}
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/Formatter/FormatterUnitTestBase.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/Formatter/FormatterUnitTestBase.cs
new file mode 100644
index 00000000..96c4cc77
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test/Formatter/FormatterUnitTestBase.cs
@@ -0,0 +1,90 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.IO;
+using System.Reflection;
+using Microsoft.SqlTools.ServiceLayer.Extensibility;
+using Microsoft.SqlTools.ServiceLayer.Formatter;
+using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
+using Microsoft.SqlTools.ServiceLayer.SqlContext;
+using Microsoft.SqlTools.ServiceLayer.Test.Common;
+using Microsoft.SqlTools.ServiceLayer.Workspace;
+using Moq;
+
+namespace Microsoft.SqlTools.ServiceLayer.Test.Formatter
+{
+ public class FormatterUnitTestsBase
+ {
+ public FormatterUnitTestsBase()
+ {
+ HostMock = new Mock();
+ WorkspaceServiceMock = new Mock>();
+ ServiceProvider = ExtensionServiceProvider.CreateDefaultServiceProvider();
+ ServiceProvider.RegisterSingleService(WorkspaceServiceMock.Object);
+ HostLoader.InitializeHostedServices(ServiceProvider, HostMock.Object);
+ FormatterService = ServiceProvider.GetService();
+ }
+
+ protected ExtensionServiceProvider ServiceProvider { get; private set; }
+ protected Mock HostMock { get; private set; }
+ protected Mock> WorkspaceServiceMock { get; private set; }
+
+ protected TSqlFormatterService FormatterService { get; private set; }
+
+ protected void LoadAndFormatAndCompare(string testName, FileInfo inputFile, FileInfo baselineFile, FormatOptions options, bool verifyFormat)
+ {
+ string inputSql = TestUtilities.ReadTextAndNormalizeLineEndings(inputFile.FullName);
+ string formattedSql = string.Empty;
+ formattedSql = FormatterService.Format(inputSql, options, verifyFormat);
+
+ formattedSql = TestUtilities.NormalizeLineEndings(formattedSql);
+
+ string assemblyPath = GetType().GetTypeInfo().Assembly.Location;
+ string directory = Path.Combine(Path.GetDirectoryName(assemblyPath), "FormatterTests");
+ Directory.CreateDirectory(directory);
+
+ FileInfo outputFile = new FileInfo(Path.Combine(directory, testName + ".out"));
+ File.WriteAllText(outputFile.FullName, formattedSql);
+ TestUtilities.CompareTestFiles(baselineFile, outputFile);
+ }
+
+ public FileInfo GetInputFile(string fileName)
+ {
+ return new FileInfo(Path.Combine(InputFileDirectory.FullName, fileName));
+ }
+
+ public FileInfo GetBaselineFile(string fileName)
+ {
+ return new FileInfo(Path.Combine(BaselineDirectory.FullName, fileName));
+ }
+
+ public DirectoryInfo BaselineDirectory
+ {
+ get
+ {
+ string d = Path.Combine(TestLocationDirectory, "BaselineFiles");
+ return new DirectoryInfo(d);
+ }
+ }
+
+ public DirectoryInfo InputFileDirectory
+ {
+ get
+ {
+ string d = Path.Combine(TestLocationDirectory, "TestFiles");
+ return new DirectoryInfo(d);
+ }
+ }
+
+ private static string TestLocationDirectory
+ {
+ get
+ {
+ return Path.Combine(RunEnvironmentInfo.GetTestDataLocation(), "TSqlFormatter");
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/Formatter/InsertFormatterTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/Formatter/InsertFormatterTests.cs
new file mode 100644
index 00000000..4e5d3cbb
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test/Formatter/InsertFormatterTests.cs
@@ -0,0 +1,82 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+
+using Microsoft.SqlTools.ServiceLayer.Formatter;
+using Xunit;
+
+namespace Microsoft.SqlTools.ServiceLayer.Test.Formatter
+{
+
+ public class InsertFormatterTests : FormatterUnitTestsBase
+ {
+ [Fact]
+ public void Insert_DefaultValues()
+ {
+ LoadAndFormatAndCompare("Insert_DefaultValues", GetInputFile("Insert_DefaultValues.sql"),
+ GetBaselineFile("Insert_DefaultValues.sql"), new FormatOptions(), true);
+ }
+
+ [Fact]
+ public void Insert_OpenQuery()
+ {
+ LoadAndFormatAndCompare("Insert_OpenQuery", GetInputFile("Insert_OpenQuery.sql"),
+ GetBaselineFile("Insert_OpenQuery.sql"), new FormatOptions(), true);
+ }
+
+ [Fact]
+ public void Insert_OutputInto()
+ {
+ LoadAndFormatAndCompare("Insert_OutputInto", GetInputFile("Insert_OutputInto.sql"),
+ GetBaselineFile("Insert_OutputInto.sql"), new FormatOptions(), true);
+ }
+
+ [Fact]
+ public void Insert_OutputStatement()
+ {
+ LoadAndFormatAndCompare("Insert_OutputStatement", GetInputFile("Insert_OutputStatement.sql"),
+ GetBaselineFile("Insert_OutputStatement.sql"), new FormatOptions(), true);
+ }
+
+ [Fact]
+ public void Insert_Select()
+ {
+ FormatOptions options = new FormatOptions();
+ options.PlaceEachReferenceOnNewLineInQueryStatements = true;
+ LoadAndFormatAndCompare("Insert_Select", GetInputFile("Insert_Select.sql"),
+ GetBaselineFile("Insert_Select.sql"), options, true);
+ }
+
+ [Fact]
+ public void Insert_SelectSource()
+ {
+ FormatOptions options = new FormatOptions();
+ options.PlaceEachReferenceOnNewLineInQueryStatements = true;
+ LoadAndFormatAndCompare("Insert_SelectSource", GetInputFile("Insert_SelectSource.sql"),
+ GetBaselineFile("Insert_SelectSource.sql"), options, true);
+ }
+
+ [Fact]
+ public void Insert_TopSpecification()
+ {
+ LoadAndFormatAndCompare("Insert_TopSpecification", GetInputFile("Insert_TopSpecification.sql"),
+ GetBaselineFile("Insert_TopSpecification.sql"), new FormatOptions(), true);
+ }
+
+ [Fact]
+ public void Insert_TopWithComments()
+ {
+ LoadAndFormatAndCompare("Insert_TopWithComments", GetInputFile("Insert_TopWithComments.sql"),
+ GetBaselineFile("Insert_TopWithComments.sql"), new FormatOptions(), true);
+ }
+
+ [Fact]
+ public void Insert_Full()
+ {
+ LoadAndFormatAndCompare("Insert_Full", GetInputFile("Insert_Full.sql"),
+ GetBaselineFile("Insert_Full.sql"), new FormatOptions(), true);
+ }
+ }
+}
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/Formatter/SqlSelectStatementFormatterTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/Formatter/SqlSelectStatementFormatterTests.cs
new file mode 100644
index 00000000..30844a6f
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test/Formatter/SqlSelectStatementFormatterTests.cs
@@ -0,0 +1,108 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using Microsoft.SqlTools.ServiceLayer.Formatter;
+using Xunit;
+
+namespace Microsoft.SqlTools.ServiceLayer.Test.Formatter
+{
+
+ public class SqlSelectStatementFormatterTests : FormatterUnitTestsBase
+ {
+ [Fact]
+ public void SimpleQuery()
+ {
+ LoadAndFormatAndCompare("SimpleQuery", GetInputFile("SimpleQuery.sql"),
+ GetBaselineFile("SimpleQuery.sql"), new FormatOptions(), true);
+ }
+
+ [Fact]
+ public void SimpleQuery_CommasBeforeDefinition()
+ {
+ FormatOptions options = new FormatOptions();
+ options.PlaceCommasBeforeNextStatement = true;
+
+ // TODO: fix verify to account for commma placement - this can
+ LoadAndFormatAndCompare("SimpleQuery_CommasBeforeDefinition", GetInputFile("SimpleQuery.sql"),
+ GetBaselineFile("SimpleQuery_CommasBeforeDefinition.sql"), options, false);
+ }
+
+ [Fact]
+ public void SimpleQuery_EachReferenceOnNewLine()
+ {
+ FormatOptions options = new FormatOptions();
+ options.PlaceEachReferenceOnNewLineInQueryStatements = true;
+
+ LoadAndFormatAndCompare("SimpleQuery_EachReferenceOnNewLine", GetInputFile("SimpleQuery.sql"),
+ GetBaselineFile("SimpleQuery_EachReferenceOnNewLine.sql"), options, true);
+ }
+
+ [Fact]
+ public void SimpleQuery_EachReferenceOnNewLine_CommasBeforeDefinition()
+ {
+ FormatOptions options = new FormatOptions();
+ options.PlaceCommasBeforeNextStatement = true;
+ options.PlaceEachReferenceOnNewLineInQueryStatements = true;
+
+ // TODO: fix verify to account for commma placement - this can
+ LoadAndFormatAndCompare("SimpleQuery_EachReferenceOnNewLine_CommasBeforeDefinition",
+ GetInputFile("SimpleQuery.sql"), GetBaselineFile("SimpleQuery_EachReferenceOnNewLine_CommasBeforeDefinition.sql"), options, false);
+ }
+
+ [Fact]
+ public void SimpleQuery_UseTabs()
+ {
+ FormatOptions options = new FormatOptions();
+ options.UseTabs = true;
+ options.PlaceEachReferenceOnNewLineInQueryStatements = true;
+ LoadAndFormatAndCompare("SimpleQuery_UseTabs", GetInputFile("SimpleQuery.sql"),
+ GetBaselineFile("SimpleQuery_UseTabs.sql"), options, true);
+ }
+
+ [Fact]
+ public void SimpleQuery_20Spaces()
+ {
+ FormatOptions options = new FormatOptions();
+ options.SpacesPerIndent = 20;
+ options.PlaceEachReferenceOnNewLineInQueryStatements = true;
+ LoadAndFormatAndCompare("SimpleQuery_20Spaces", GetInputFile("SimpleQuery.sql"),
+ GetBaselineFile("SimpleQuery_20Spaces.sql"), options, true);
+ }
+
+ [Fact]
+ public void SimpleQuery_UpperCaseKeywords()
+ {
+ FormatOptions options = new FormatOptions();
+ options.KeywordCasing = CasingOptions.Uppercase;
+ options.PlaceEachReferenceOnNewLineInQueryStatements = true;
+ LoadAndFormatAndCompare("SimpleQuery_UpperCaseKeywords", GetInputFile("SimpleQuery.sql"),
+ GetBaselineFile("SimpleQuery_UpperCaseKeywords.sql"), options, true);
+ }
+
+ [Fact]
+ public void SimpleQuery_LowerCaseKeywords()
+ {
+ FormatOptions options = new FormatOptions();
+ options.KeywordCasing = CasingOptions.Lowercase;
+ options.PlaceEachReferenceOnNewLineInQueryStatements = true;
+ LoadAndFormatAndCompare("SimpleQuery_LowerCaseKeywords", GetInputFile("SimpleQuery.sql"),
+ GetBaselineFile("SimpleQuery_LowerCaseKeywords.sql"), options, true);
+ }
+
+ [Fact]
+ public void SimpleQuery_ForBrowseClause()
+ {
+ LoadAndFormatAndCompare("SimpleQuery_ForBrowseClause", GetInputFile("SimpleQuery_ForBrowseClause.sql"),
+ GetBaselineFile("SimpleQuery_ForBrowseClause.sql"), new FormatOptions(), true);
+ }
+
+ [Fact]
+ public void SimpleQuery_ForXmlClause()
+ {
+ LoadAndFormatAndCompare("SimpleQuery_ForXmlClause", GetInputFile("SimpleQuery_ForXmlClause.sql"),
+ GetBaselineFile("SimpleQuery_ForXmlClause.sql"), new FormatOptions(), true);
+ }
+ }
+}
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/Formatter/TSqlFormatterServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/Formatter/TSqlFormatterServiceTests.cs
new file mode 100644
index 00000000..6f7f4883
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test/Formatter/TSqlFormatterServiceTests.cs
@@ -0,0 +1,95 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.SqlTools.ServiceLayer.Formatter.Contracts;
+using Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts;
+using Microsoft.SqlTools.ServiceLayer.Test.Common;
+using Microsoft.SqlTools.ServiceLayer.Test.Utility;
+using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts;
+using Moq;
+using Xunit;
+
+namespace Microsoft.SqlTools.ServiceLayer.Test.Formatter
+{
+ public class TSqlFormatterServiceTests : FormatterUnitTestsBase
+ {
+ private Mock workspaceMock = new Mock();
+ private TextDocumentIdentifier textDocument;
+ DocumentFormattingParams docFormatParams;
+
+ public TSqlFormatterServiceTests()
+ {
+ textDocument = new TextDocumentIdentifier
+ {
+ Uri = "script file"
+ };
+ docFormatParams = new DocumentFormattingParams()
+ {
+ TextDocument = textDocument,
+ Options = new FormattingOptions() { InsertSpaces = true, TabSize = 4 }
+ };
+ }
+
+ private string defaultSqlContents = TestUtilities.NormalizeLineEndings(@"create TABLE T1 ( C1 int NOT NULL, C2 nvarchar(50) NULL)");
+ // TODO fix bug where '\r' is appended
+ private string formattedSqlContents = TestUtilities.NormalizeLineEndings(@"create TABLE T1
+(
+ C1 int NOT NULL,
+ C2 nvarchar(50) NULL
+)");
+
+ [Fact]
+ public async Task FormatDocumentShouldReturnSingleEdit()
+ {
+ // Given a document that we want to format
+ SetupScriptFile(defaultSqlContents);
+ // When format document is called
+ await TestUtils.RunAndVerify(
+ test: (requestContext) => FormatterService.HandleDocFormatRequest(docFormatParams, requestContext),
+ verify: (edits =>
+ {
+ // Then expect a single edit to be returned and for it to match the standard formatting
+ Assert.Equal(1, edits.Length);
+ AssertFormattingEqual(formattedSqlContents, edits[0].NewText);
+
+ }));
+ }
+
+ private static void AssertFormattingEqual(string expected, string actual)
+ {
+ if (string.Compare(expected, actual) != 0)
+ {
+ StringBuilder error = new StringBuilder();
+ error.AppendLine("======================");
+ error.AppendLine("Comparison failed:");
+ error.AppendLine("==Expected==");
+ error.AppendLine(expected);
+ error.AppendLine("==Actual==");
+ error.AppendLine(actual);
+ Assert.False(false, error.ToString());
+ }
+ }
+
+ private void SetupScriptFile(string fileContents)
+ {
+ WorkspaceServiceMock.SetupGet(service => service.Workspace).Returns(workspaceMock.Object);
+ workspaceMock.Setup(w => w.GetFile(It.IsAny())).Returns(CreateScriptFile(fileContents));
+ }
+
+ private ScriptFile CreateScriptFile(string content)
+ {
+ ScriptFile scriptFile = new ScriptFile()
+ {
+ Contents = content
+ };
+ return scriptFile;
+ }
+
+
+ }
+}
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/LanguageServer/PeekDefinitionTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/LanguageServer/PeekDefinitionTests.cs
index d751b57c..0b7efbb7 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.Test/LanguageServer/PeekDefinitionTests.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test/LanguageServer/PeekDefinitionTests.cs
@@ -141,11 +141,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.LanguageServices
[Fact]
public void GetLocationFromFileForValidFilePathTest()
{
- String filePath = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "C:\\test\\script.sql" : "/test/script.sql";
+ string filePath = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "C:\\test\\script.sql" : "/test/script.sql";
PeekDefinition peekDefinition = new PeekDefinition(null, null);
Location[] locations = peekDefinition.GetLocationFromFile(filePath, 0);
- String expectedFilePath = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "file:///C:/test/script.sql" : "file:/test/script.sql";
+ string expectedFilePath = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "file:///C:/test/script.sql" : "file:/test/script.sql";
Assert.Equal(locations[0].Uri, expectedFilePath);
}
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/ServiceHost/ScriptFileTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/ServiceHost/ScriptFileTests.cs
index 817f3328..c5023d25 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.Test/ServiceHost/ScriptFileTests.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test/ServiceHost/ScriptFileTests.cs
@@ -119,7 +119,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.ServiceHost
[Fact]
public void CanApplySingleLineInsert()
{
- this.AssertFileChange(
+ AssertFileChange(
"This is a test.",
"This is a working test.",
new FileChange
@@ -135,7 +135,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.ServiceHost
[Fact]
public void CanApplySingleLineReplace()
{
- this.AssertFileChange(
+ AssertFileChange(
"This is a potentially broken test.",
"This is a working test.",
new FileChange
@@ -151,7 +151,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.ServiceHost
[Fact]
public void CanApplySingleLineDelete()
{
- this.AssertFileChange(
+ AssertFileChange(
"This is a test of the emergency broadcasting system.",
"This is a test.",
new FileChange
@@ -167,7 +167,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.ServiceHost
[Fact]
public void CanApplyMultiLineInsert()
{
- this.AssertFileChange(
+ AssertFileChange(
"first\r\nsecond\r\nfifth",
"first\r\nsecond\r\nthird\r\nfourth\r\nfifth",
new FileChange
@@ -183,7 +183,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.ServiceHost
[Fact]
public void CanApplyMultiLineReplace()
{
- this.AssertFileChange(
+ AssertFileChange(
"first\r\nsecoXX\r\nXXfth",
"first\r\nsecond\r\nthird\r\nfourth\r\nfifth",
new FileChange
@@ -199,7 +199,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.ServiceHost
[Fact]
public void CanApplyMultiLineReplaceWithRemovedLines()
{
- this.AssertFileChange(
+ AssertFileChange(
"first\r\nsecoXX\r\nREMOVE\r\nTHESE\r\nLINES\r\nXXfth",
"first\r\nsecond\r\nthird\r\nfourth\r\nfifth",
new FileChange
@@ -215,7 +215,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.ServiceHost
[Fact]
public void CanApplyMultiLineDelete()
{
- this.AssertFileChange(
+ AssertFileChange(
"first\r\nsecond\r\nREMOVE\r\nTHESE\r\nLINES\r\nthird",
"first\r\nsecond\r\nthird",
new FileChange
@@ -235,7 +235,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.ServiceHost
typeof(ArgumentOutOfRangeException),
() =>
{
- this.AssertFileChange(
+ AssertFileChange(
"first\r\nsecond\r\nREMOVE\r\nTHESE\r\nLINES\r\nthird",
"first\r\nsecond\r\nthird",
new FileChange
@@ -275,7 +275,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.ServiceHost
public ScriptFileGetLinesTests()
{
- this.scriptFile =
+ scriptFile =
ScriptFileTests.GetTestScriptFile(
"Line One\r\nLine Two\r\nLine Three\r\nLine Four\r\nLine Five\r\n");
}
@@ -284,7 +284,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.ServiceHost
public void CanGetWholeLine()
{
string[] lines =
- this.scriptFile.GetLinesInRange(
+ scriptFile.GetLinesInRange(
new BufferRange(5, 1, 5, 10));
Assert.Equal(1, lines.Length);
@@ -295,7 +295,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.ServiceHost
public void CanGetMultipleWholeLines()
{
string[] lines =
- this.scriptFile.GetLinesInRange(
+ scriptFile.GetLinesInRange(
new BufferRange(2, 1, 4, 10));
Assert.Equal(TestStringLines.Skip(1).Take(3), lines);
@@ -305,7 +305,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.ServiceHost
public void CanGetSubstringInSingleLine()
{
string[] lines =
- this.scriptFile.GetLinesInRange(
+ scriptFile.GetLinesInRange(
new BufferRange(4, 3, 4, 8));
Assert.Equal(1, lines.Length);
@@ -316,7 +316,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.ServiceHost
public void CanGetEmptySubstringRange()
{
string[] lines =
- this.scriptFile.GetLinesInRange(
+ scriptFile.GetLinesInRange(
new BufferRange(4, 3, 4, 3));
Assert.Equal(1, lines.Length);
@@ -334,7 +334,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.ServiceHost
};
string[] lines =
- this.scriptFile.GetLinesInRange(
+ scriptFile.GetLinesInRange(
new BufferRange(2, 6, 4, 9));
Assert.Equal(expectedLines, lines);
@@ -351,7 +351,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.ServiceHost
};
string[] lines =
- this.scriptFile.GetLinesInRange(
+ scriptFile.GetLinesInRange(
new BufferRange(2, 9, 4, 1));
Assert.Equal(expectedLines, lines);
@@ -364,7 +364,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.ServiceHost
public ScriptFilePositionTests()
{
- this.scriptFile =
+ scriptFile =
ScriptFileTests.GetTestScriptFile(@"
First line
Second line is longer
@@ -375,12 +375,12 @@ First line
[Fact]
public void CanOffsetByLine()
{
- this.AssertNewPosition(
+ AssertNewPosition(
1, 1,
2, 0,
3, 1);
- this.AssertNewPosition(
+ AssertNewPosition(
3, 1,
-2, 0,
1, 1);
@@ -389,12 +389,12 @@ First line
[Fact]
public void CanOffsetByColumn()
{
- this.AssertNewPosition(
+ AssertNewPosition(
2, 1,
0, 2,
2, 3);
- this.AssertNewPosition(
+ AssertNewPosition(
2, 5,
0, -3,
2, 2);
@@ -447,7 +447,7 @@ First line
[Fact]
public void CanFindBeginningOfLine()
{
- this.AssertNewPosition(
+ AssertNewPosition(
4, 12,
pos => pos.GetLineStart(),
4, 5);
@@ -456,7 +456,7 @@ First line
[Fact]
public void CanFindEndOfLine()
{
- this.AssertNewPosition(
+ AssertNewPosition(
4, 12,
pos => pos.GetLineEnd(),
4, 15);
@@ -465,7 +465,7 @@ First line
[Fact]
public void CanComposePositionOperations()
{
- this.AssertNewPosition(
+ AssertNewPosition(
4, 12,
pos => pos.AddOffset(-1, 1).GetLineStart(),
3, 3);
@@ -476,7 +476,7 @@ First line
int lineOffset, int columnOffset,
int expectedLine, int expectedColumn)
{
- this.AssertNewPosition(
+ AssertNewPosition(
originalLine, originalColumn,
pos => pos.AddOffset(lineOffset, columnOffset),
expectedLine, expectedColumn);
@@ -490,7 +490,7 @@ First line
var newPosition =
positionOperation(
new FilePosition(
- this.scriptFile,
+ scriptFile,
originalLine,
originalColumn));
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/SqlContext/SettingsTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/SqlContext/SettingsTests.cs
index e06764de..c0677307 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.Test/SqlContext/SettingsTests.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test/SqlContext/SettingsTests.cs
@@ -75,7 +75,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.LanguageServices
Assert.False(sqlToolsSettings.IsSuggestionsEnabled);
}
- ///
+ ///
/// Validate that the IsQuickInfoEnabled flag behavior
///
[Fact]
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/Utility/TestUtils.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/Utility/TestUtils.cs
index a1a88c13..10db8c87 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.Test/Utility/TestUtils.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test/Utility/TestUtils.cs
@@ -2,6 +2,9 @@
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
+using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
+using Moq;
+using Xunit;
namespace Microsoft.SqlTools.ServiceLayer.Test.Utility
{
@@ -49,5 +52,35 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Utility
return (count < intervalCount);
}
+
+
+ public static async Task RunAndVerify(Func, Task> test, Action verify)
+ {
+ T result = default(T);
+ var contextMock = RequestContextMocks.Create(r => result = r).AddErrorHandling(null);
+ await test(contextMock.Object);
+ VerifyResult(contextMock, verify, result);
+ }
+
+ public static void VerifyErrorSent(Mock> contextMock)
+ {
+ contextMock.Verify(c => c.SendResult(It.IsAny()), Times.Never);
+ contextMock.Verify(c => c.SendError(It.IsAny()), Times.Once);
+ }
+
+ public static void VerifyResult(Mock> contextMock, U expected, U actual)
+ {
+ contextMock.Verify(c => c.SendResult(It.IsAny()), Times.Once);
+ Assert.Equal(expected, actual);
+ contextMock.Verify(c => c.SendError(It.IsAny()), Times.Never);
+ }
+
+ public static void VerifyResult(Mock> contextMock, Action verify, T actual)
+ {
+ contextMock.Verify(c => c.SendResult(It.IsAny()), Times.Once);
+ contextMock.Verify(c => c.SendError(It.IsAny()), Times.Never);
+ verify(actual);
+ }
+
}
}
diff --git a/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Driver/ServiceTestDriver.cs b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Driver/ServiceTestDriver.cs
index 637c064c..01d50f08 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Driver/ServiceTestDriver.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Driver/ServiceTestDriver.cs
@@ -18,7 +18,6 @@ using Microsoft.SqlTools.ServiceLayer.Connection.Contracts;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Channel;
using Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts;
-using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts;
using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts.ExecuteRequests;
namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Driver
@@ -101,6 +100,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Driver
startTime = DateTime.Now;
// Launch the process
+ this.protocolClient.Initialize();
await this.protocolClient.Start();
await Task.Delay(1000); // Wait for the service host to start
diff --git a/test/Microsoft.SqlTools.ServiceLayer.TestEnvConfig/Program.cs b/test/Microsoft.SqlTools.ServiceLayer.TestEnvConfig/Program.cs
index 3c801203..a22852a8 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.TestEnvConfig/Program.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.TestEnvConfig/Program.cs
@@ -26,7 +26,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestEnvConfig
{
ShowUsage();
}
- else if (File.Exists(arg) == false)
+ else if (!File.Exists(arg))
{
Console.WriteLine("setting file {0} does not exist.", arg);
}