diff --git a/extension.bundle.ts b/extension.bundle.ts index 100f1485a..74f713d9e 100644 --- a/extension.bundle.ts +++ b/extension.bundle.ts @@ -76,6 +76,7 @@ export { mapJsonObjectValue } from "./src/util/mapJsonObjectValue"; export { indentMultilineString, unindentMultilineString as removeIndentation } from "./src/util/multilineStrings"; export * from "./src/util/nonNull"; export { normalizePath } from "./src/util/normalizePath"; +export * from "./src/util/readUtf8FileWithBom"; export * from './src/util/time'; export { getVSCodePositionFromPosition } from "./src/util/vscodePosition"; export { wrapError } from "./src/util/wrapError"; diff --git a/src/AzureRMTools.ts b/src/AzureRMTools.ts index 26c35b9ab..33a8ab63b 100644 --- a/src/AzureRMTools.ts +++ b/src/AzureRMTools.ts @@ -47,6 +47,7 @@ import { JsonOutlineProvider } from "./Treeview"; import { UnrecognizedBuiltinFunctionIssue } from "./UnrecognizedFunctionIssues"; import { getRenameError } from "./util/getRenameError"; import { normalizePath } from "./util/normalizePath"; +import { readUtf8FileWithBom } from "./util/readUtf8FileWithBom"; import { Cancellation } from "./util/throwOnCancel"; import { onCompletionActivated, toVsCodeCompletionItem } from "./util/toVsCodeCompletionItem"; import { getVSCodeRangeFromSpan } from "./util/vscodePosition"; @@ -1199,7 +1200,7 @@ export class AzureRMTools { } // Nope, have to read it from disk - const contents = (await fse.readFile(uri.fsPath, { encoding: 'utf8' })).toString(); + const contents = await readUtf8FileWithBom(uri.fsPath); return new DeploymentTemplate(contents, uri); } @@ -1215,7 +1216,7 @@ export class AzureRMTools { } // Nope, have to read it from disk - const contents = (await fse.readFile(uri.fsPath, { encoding: 'utf8' })).toString(); + const contents = await readUtf8FileWithBom(uri.fsPath); return new DeploymentParameters(contents, uri); } diff --git a/src/parameterFiles/parameterFiles.ts b/src/parameterFiles/parameterFiles.ts index 6f4391c92..ce9608385 100644 --- a/src/parameterFiles/parameterFiles.ts +++ b/src/parameterFiles/parameterFiles.ts @@ -13,6 +13,7 @@ import { ext } from '../extensionVariables'; import { queryCreateParameterFile } from '../parameterFileGeneration'; import { containsParametersSchema } from '../schemas'; import { normalizePath } from '../util/normalizePath'; +import { readUtf8FileWithBom } from '../util/readUtf8FileWithBom'; import { DeploymentFileMapping } from './DeploymentFileMapping'; const readAtMostBytesToFindParamsSchema = 4 * 1024; @@ -47,8 +48,8 @@ export async function selectParameterFile(actionContext: IActionContext, mapping let templateUri: Uri = sourceUri; // Verify it's a template file (have to read in entire file to do full validation) - const contents = (await fse.readFile(templateUri.fsPath, { encoding: "utf8" })).toString(); - const template: DeploymentTemplate = new DeploymentTemplate(contents, Uri.file("https://Check file is template")); + const contents = await readUtf8FileWithBom(templateUri.fsPath); + const template: DeploymentTemplate = new DeploymentTemplate(contents, templateUri); if (!template.hasArmSchemaUri()) { throw new Error(`"${templateUri.fsPath}" does not appear to be an Azure Resource Manager deployment template file.`); } diff --git a/src/util/readUtf8FileWithBom.ts b/src/util/readUtf8FileWithBom.ts new file mode 100644 index 000000000..52578fa29 --- /dev/null +++ b/src/util/readUtf8FileWithBom.ts @@ -0,0 +1,15 @@ +// ---------------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ---------------------------------------------------------------------------- + +import * as fse from 'fs-extra'; + +const utf8Bom = 65279; + +export async function readUtf8FileWithBom(fsPath: string): Promise { + let contents = (await fse.readFile(fsPath, { encoding: "utf8" })); + if (contents.charCodeAt(0) === utf8Bom) { + contents = contents.slice(1); + } + return contents; +} diff --git a/test/support/TempFile.ts b/test/support/TempFile.ts index f8a91a59f..53298ecf5 100644 --- a/test/support/TempFile.ts +++ b/test/support/TempFile.ts @@ -6,9 +6,9 @@ import * as assert from 'assert'; import * as fs from 'fs'; -import * as fse from 'fs-extra'; import * as path from 'path'; import { commands, TextDocument, TextEditor, Uri, window, workspace } from 'vscode'; +import { readUtf8FileWithBom } from "../../extension.bundle"; import { getTempFilePath } from './getTempFilePath'; export class TempFile { @@ -22,8 +22,8 @@ export class TempFile { fs.writeFileSync(this.fsPath, contents); } - public static fromExistingFile(filepath: string): TempFile { - const contents: string = fse.readFileSync(filepath).toString(); + public static async fromExistingFile(filepath: string): Promise { + const contents: string = await readUtf8FileWithBom(filepath); return new TempFile(contents, path.basename(filepath), path.extname(filepath)); } diff --git a/test/support/diagnostics.ts b/test/support/diagnostics.ts index 6aec0a773..7daee66af 100644 --- a/test/support/diagnostics.ts +++ b/test/support/diagnostics.ts @@ -394,7 +394,7 @@ export async function getDiagnosticsForTemplate( paramsFile = new TempFile(unmarkedParams); } else { const absPath = path.join(testFolder, options.parametersFile!); - paramsFile = TempFile.fromExistingFile(absPath); + paramsFile = await TempFile.fromExistingFile(absPath); } // Map template to params