diff --git a/src/VSCodeExtension/src/commands.ts b/src/VSCodeExtension/src/commands.ts index dec82fb2e0..f170c5bf12 100644 --- a/src/VSCodeExtension/src/commands.ts +++ b/src/VSCodeExtension/src/commands.ts @@ -40,7 +40,7 @@ export function createNewProject(context: vscode.ExtensionContext) { export function installTemplates(dotNetSdk: DotnetInfo, packageInfo?: IPackageInfo) { let packageVersion = - oc(packageInfo).nugetVersion + oc(packageInfo).nugetVersion() ? `::${packageInfo!.nugetVersion}` : ""; let proc = cp.spawn( diff --git a/src/VSCodeExtension/src/formatter/format-document.ts b/src/VSCodeExtension/src/formatter/format-document.ts index a1d49d240f..3eeeacb9ad 100644 --- a/src/VSCodeExtension/src/formatter/format-document.ts +++ b/src/VSCodeExtension/src/formatter/format-document.ts @@ -4,7 +4,7 @@ import * as vscode from "vscode"; import { FormatRule, formatter } from "./formatter"; import indentRules from "./rules/indent"; -import operationRules from "./rules/operation"; +import operationRules from "./rules/declaration"; import controlStructureRules from "./rules/control-structure"; const rules: FormatRule[] = [ diff --git a/src/VSCodeExtension/src/formatter/rules/control-structure.ts b/src/VSCodeExtension/src/formatter/rules/control-structure.ts index 557ba5cc77..c00d9189e8 100644 --- a/src/VSCodeExtension/src/formatter/rules/control-structure.ts +++ b/src/VSCodeExtension/src/formatter/rules/control-structure.ts @@ -1,14 +1,12 @@ import { FormatRule } from "../formatter"; /** - * Laves just one space after an if statement + * Leaves just one space after an if statement. * * @param code input string * * @example `if (1 == 1){H(qs[0]);}` -> * `if (1 == 1){H(qs[0]);}` - * - * more examples in the unit tests */ export const spaceAfterIf: FormatRule = (code: string): string => { return code.replace(/(^| +|;|})if[ \n]*/, "$1if "); diff --git a/src/VSCodeExtension/src/formatter/rules/operation.ts b/src/VSCodeExtension/src/formatter/rules/declaration.ts similarity index 78% rename from src/VSCodeExtension/src/formatter/rules/operation.ts rename to src/VSCodeExtension/src/formatter/rules/declaration.ts index 2b70a42aa4..b4982ff10c 100644 --- a/src/VSCodeExtension/src/formatter/rules/operation.ts +++ b/src/VSCodeExtension/src/formatter/rules/declaration.ts @@ -1,33 +1,33 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -/** - * Formats operation declarations. - * - * @param code incoming code - * - * @example `operation Foo(q:Qubit, n :Int) : Bool` -> - * `operation Foo (q : Qubit, n : Int) : Bool` - */ -export const argsRule = (code: string): string => { - const operationMatcher: RegExp = /operation\s*(\w+)\s*(\(.*\))\s*:\s*(\w+)/g; - const firstArgMatcher: RegExp = /\(((\w*)\s*:\s*([a-zA-Z]+))/g - const restArgMatcher: RegExp = /,\s*((\w*)\s*:\s*([a-zA-Z]+))/g; - - return code.replace(operationMatcher, (match, opName, args, retType) => { - args = args - .replace( - firstArgMatcher, - (match: string, group: string, variable: string, type: string) => - `(${variable} : ${type}` - ) - .replace( - restArgMatcher, - (match: string, group: string, variable: string, type: string) => - `, ${variable} : ${type}` - ); - return `operation ${opName} ${args} : ${retType}`; - }); -}; - -export default [argsRule]; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +/** + * Formats operation declarations. + * + * @param code incoming code + * + * @example `operation Foo(q:Qubit, n :Int) : Bool` -> + * `operation Foo (q : Qubit, n : Int) : Bool` + */ +export const argsRule = (code: string): string => { + const declarationMatcher: RegExp = /(operation|function)\s*(\w+)\s*(\(.*\))\s*:\s*(\w+)/g; + const firstArgMatcher: RegExp = /\(((\w*)\s*:\s*([a-zA-Z]+))/g + const restArgMatcher: RegExp = /,\s*((\w*)\s*:\s*([a-zA-Z]+))/g; + + return code.replace(declarationMatcher, (match, keyword, opName, args, retType) => { + args = args + .replace( + firstArgMatcher, + (match: string, group: string, variable: string, type: string) => + `(${variable} : ${type}` + ) + .replace( + restArgMatcher, + (match: string, group: string, variable: string, type: string) => + `, ${variable} : ${type}` + ); + return `${keyword} ${opName} ${args} : ${retType}`; + }); +}; + +export default [argsRule]; diff --git a/src/VSCodeExtension/src/formatter/rules/indent.ts b/src/VSCodeExtension/src/formatter/rules/indent.ts index 0459e87de6..48d4f1e5fb 100644 --- a/src/VSCodeExtension/src/formatter/rules/indent.ts +++ b/src/VSCodeExtension/src/formatter/rules/indent.ts @@ -12,7 +12,7 @@ import { FormatRule } from "../formatter"; * `namespace Foo {}` */ export const namespaceRule: FormatRule = (code: string) => { - const namespaceMatcher: RegExp = /^\s*namespace\s*(\w+)\s*(\S|\S.*\S)\s*$/g; + const namespaceMatcher: RegExp = /^\s*namespace\s+(\w+(?:\.\w+)*)\s*({|{.*})\s*$/g; return code.replace(namespaceMatcher, (match, namespace, rest) => `namespace ${namespace} ${rest}`); }; diff --git a/src/VSCodeExtension/src/tests/unit/operation.test.ts b/src/VSCodeExtension/src/tests/unit/declaration.test.ts similarity index 78% rename from src/VSCodeExtension/src/tests/unit/operation.test.ts rename to src/VSCodeExtension/src/tests/unit/declaration.test.ts index 28d2244166..26268c4b4c 100644 --- a/src/VSCodeExtension/src/tests/unit/operation.test.ts +++ b/src/VSCodeExtension/src/tests/unit/declaration.test.ts @@ -1,24 +1,24 @@ import "mocha"; import * as assert from "assert"; import { formatter } from "../../formatter/formatter"; -import { argsRule } from "../../formatter/rules/operation"; +import { argsRule } from "../../formatter/rules/declaration"; describe("arguments rule", () => { - it("no error", () => { + it("has no error", () => { const code = "operation Foo (q : Qubit, n : Int) : Bool"; const expectedCode = "operation Foo (q : Qubit, n : Int) : Bool"; assert.equal(formatter(code, [argsRule]), expectedCode); }); - it("keep leading whitespace", () => { + it("keeps leading whitespace", () => { const code = " operation Foo (q : Qubit, n : Int) : Bool"; const expectedCode = " operation Foo (q : Qubit, n : Int) : Bool"; assert.equal(formatter(code, [argsRule]), expectedCode); }); - it("remove unnecessary spaces (non-arguments)", () => { + it("removes unnecessary spaces (non-arguments)", () => { const expectedCode = "operation Foo (q : Qubit, n : Int) : Bool"; let code = "operation Foo (q : Qubit, n : Int) : Bool"; @@ -34,7 +34,7 @@ describe("arguments rule", () => { assert.equal(formatter(code, [argsRule]), expectedCode); }); - it("remove unnecessary spaces (arguments)", () => { + it("removes unnecessary spaces (arguments)", () => { const expectedCode = "operation Foo (q : Qubit, n : Int) : Bool"; let code = "operation Foo (q : Qubit, n : Int) : Bool"; @@ -52,4 +52,11 @@ describe("arguments rule", () => { code = "operation Foo (q : Qubit, n : Int) : Bool"; assert.equal(formatter(code, [argsRule]), expectedCode); }); + + it("matches functions", () => { + const code = " function Foo (q :Qubit, n : Int) : Bool"; + const expectedCode = " function Foo (q : Qubit, n : Int) : Bool"; + + assert.equal(formatter(code, [argsRule]), expectedCode); + }); }); diff --git a/src/VSCodeExtension/src/tests/unit/formatter.test.ts b/src/VSCodeExtension/src/tests/unit/formatter.test.ts index 693a44561b..a64b2bfc86 100644 --- a/src/VSCodeExtension/src/tests/unit/formatter.test.ts +++ b/src/VSCodeExtension/src/tests/unit/formatter.test.ts @@ -3,7 +3,7 @@ import * as assert from "assert"; import { formatter } from "../../formatter/formatter"; describe("formatter tests", () => { - it("with no rules, the code is unchanged", () => { + it("has no rules", () => { const code = "if(1 == 1){H(qs[0]);}"; const expectedCode = "if(1 == 1){H(qs[0]);}"; diff --git a/src/VSCodeExtension/src/tests/unit/indent.test.ts b/src/VSCodeExtension/src/tests/unit/indent.test.ts index 746c0b3130..a1943d2d53 100644 --- a/src/VSCodeExtension/src/tests/unit/indent.test.ts +++ b/src/VSCodeExtension/src/tests/unit/indent.test.ts @@ -4,14 +4,14 @@ import { formatter } from "../../formatter/formatter"; import { namespaceRule } from "../../formatter/rules/indent"; describe("namespace rule", () => { - it("no error", () => { + it("has no error", () => { const code = "namespace Foo {"; const expectedCode = "namespace Foo {"; assert.equal(formatter(code, []), expectedCode); }); - it("trim whitespace", () => { + it("trims whitespace", () => { const expectedCode = "namespace Foo {"; let code = " namespace Foo {"; @@ -30,7 +30,7 @@ describe("namespace rule", () => { assert.equal(formatter(code, [namespaceRule]), expectedCode); }); - it("match lines with inline body", () => { + it("matches lines with inline body", () => { const expectedCode = "namespace Foo { // ... }"; let code = " namespace Foo { // ... }"; @@ -48,4 +48,23 @@ describe("namespace rule", () => { code = " namespace Foo { // ... } "; assert.equal(formatter(code, [namespaceRule]), expectedCode); }); + + it("matches dot-separated names", () => { + const expectedCode = "namespace Microsoft.Quantum.Arrays { // ... }"; + + let code = " namespace Microsoft.Quantum.Arrays { // ... }"; + assert.equal(formatter(code, [namespaceRule]), expectedCode); + + code = "namespace Microsoft.Quantum.Arrays { // ... } "; + assert.equal(formatter(code, [namespaceRule]), expectedCode); + + code = "namespace Microsoft.Quantum.Arrays { // ... } "; + assert.equal(formatter(code, [namespaceRule]), expectedCode); + + code = "namespace Microsoft.Quantum.Arrays { // ... } "; + assert.equal(formatter(code, [namespaceRule]), expectedCode); + + code = " namespace Microsoft.Quantum.Arrays { // ... } "; + assert.equal(formatter(code, [namespaceRule]), expectedCode); + }); });