UNPKG

@microsoft.azure/async-io

Version:

Promisify'd asnyc wrappers (for Azure Open Source Projects)

278 lines 9.9 kB
"use strict"; /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ Object.defineProperty(exports, "__esModule", { value: true }); function IsUri(uri) { return /^([a-z0-9+.-]+):(?:\/\/(?:((?:[a-z0-9-._~!$&'()*+,;=:]|%[0-9A-F]{2})*)@)?((?:[a-z0-9-._~!$&'()*+,;=]|%[0-9A-F]{2})*)(?::(\d*))?(\/(?:[a-z0-9-._~!$&'()*+,;=:@/]|%[0-9A-F]{2})*)?|(\/?(?:[a-z0-9-._~!$&'()*+,;=:@]|%[0-9A-F]{2})+(?:[a-z0-9-._~!$&'()*+,;=:@/]|%[0-9A-F]{2})*)?)(?:\?((?:[a-z0-9-._~!$&'()*+,;=:/?@]|%[0-9A-F]{2})*))?(?:#((?:[a-z0-9-._~!$&'()*+,;=:/?@]|%[0-9A-F]{2})*))?$/i.test(uri); } exports.IsUri = IsUri; /*********************** * Data aquisition ***********************/ const promisify = require("pify"); const url_1 = require("url"); const path_1 = require("path"); const stripBom = require("strip-bom"); const getUri = require("get-uri"); const getUriAsync = promisify(getUri); /** * Loads a UTF8 string from given URI. */ async function ReadUri(uri) { try { const readable = await getUriAsync(uri); const readAll = new Promise(function (resolve, reject) { let result = ""; readable.on("data", data => result += data.toString()); readable.on("end", () => resolve(result)); readable.on("error", err => reject(err)); }); let result = await readAll; // fix up UTF16le files if (result.charCodeAt(0) === 65533 && result.charCodeAt(1) === 65533) { result = Buffer.from(result.slice(2)).toString("utf16le"); } return stripBom(result); } catch (e) { throw new Error(`Failed to load '${uri}' (${e})`); } } exports.ReadUri = ReadUri; async function ExistsUri(uri) { try { await ReadUri(uri); return true; } catch (e) { return false; } } exports.ExistsUri = ExistsUri; /*********************** * URI manipulation ***********************/ const path_2 = require("path"); const URI = require("urijs"); const fileUri = require("file-url"); /** * remake of path.isAbsolute... because it's platform dependent: * Windows: C:\\... -> true /... -> true * Linux: C:\\... -> false /... -> true */ function isAbsolute(path) { return !!path.match(/^([a-zA-Z]:)?(\/|\\)/); } /** * determines what an absolute URI is for our purposes, consider: * - we had Ruby try to use "Azure::ARM::SQL" as a file name, so that should not be considered absolute * - we want simple, easily predictable semantics */ function isUriAbsolute(url) { return /^[a-z]+:\/\//.test(url); } /** * Create a 'file:///' URI from given absolute path. * Examples: * - "C:\swagger\storage.yaml" -> "file:///C:/swagger/storage.yaml" * - "/input/swagger.yaml" -> "file:///input/swagger.yaml" */ function CreateFileOrFolderUri(absolutePath) { if (!isAbsolute(absolutePath)) { throw new Error(`Can only create file URIs from absolute paths. Got '${absolutePath}'`); } let result = fileUri(absolutePath, { resolve: false }); // handle UNCs if (absolutePath.startsWith("//") || absolutePath.startsWith("\\\\")) { result = result.replace(/^file:\/\/\/\//, "file://"); } return result; } exports.CreateFileOrFolderUri = CreateFileOrFolderUri; function CreateFileUri(absolutePath) { return EnsureIsFileUri(CreateFileOrFolderUri(absolutePath)); } exports.CreateFileUri = CreateFileUri; function CreateFolderUri(absolutePath) { return EnsureIsFolderUri(CreateFileOrFolderUri(absolutePath)); } exports.CreateFolderUri = CreateFolderUri; function EnsureIsFolderUri(uri) { return EnsureIsFileUri(uri) + "/"; } exports.EnsureIsFolderUri = EnsureIsFolderUri; function EnsureIsFileUri(uri) { return uri.replace(/\/$/g, ""); } exports.EnsureIsFileUri = EnsureIsFileUri; function GetFilename(uri) { return uri.split("/").reverse()[0].split("\\").reverse()[0]; } exports.GetFilename = GetFilename; function GetFilenameWithoutExtension(uri) { const lastPart = GetFilename(uri); const ext = lastPart.indexOf(".") === -1 ? "" : lastPart.split(".").reverse()[0]; return lastPart.substr(0, lastPart.length - ext.length - 1); } exports.GetFilenameWithoutExtension = GetFilenameWithoutExtension; function ToRawDataUrl(uri) { // special URI handlers // - GitHub if (uri.startsWith("https://github")) { uri = uri.replace(/^https?:\/\/(github.com)(\/[^\/]+\/[^\/]+\/)(blob|tree)\/(.*)/ig, "https://raw.githubusercontent.com$2$4"); } return uri; } exports.ToRawDataUrl = ToRawDataUrl; /** * The singularity of all resolving. * With URI as our one data type of truth, this method maps an absolute or relative path or URI to a URI using given base URI. * @param baseUri Absolute base URI * @param pathOrUri Relative/absolute path/URI * @returns Absolute URI */ function ResolveUri(baseUri, pathOrUri) { if (isAbsolute(pathOrUri)) { return CreateFileOrFolderUri(pathOrUri); } // known here: `pathOrUri` is eiher URI (relative or absolute) or relative path - which we can normalize to a relative URI pathOrUri = pathOrUri.replace(/\\/g, "/"); // known here: `pathOrUri` is a URI (relative or absolute) if (isUriAbsolute(pathOrUri)) { return pathOrUri; } // known here: `pathOrUri` is a relative URI if (!baseUri) { throw new Error("'pathOrUri' was detected to be relative so 'baseUri' is required"); } try { return new URI(pathOrUri).absoluteTo(baseUri).toString(); } catch (e) { throw new Error(`Failed resolving '${pathOrUri}' against '${baseUri}'.`); } } exports.ResolveUri = ResolveUri; function ParentFolderUri(uri) { // root? if (uri.endsWith("//")) { return null; } // folder? => cut away last "/" if (uri.endsWith("/")) { uri = uri.slice(0, uri.length - 1); } // cut away last component const compLen = uri.split("/").reverse()[0].length; return uri.slice(0, uri.length - compLen); } exports.ParentFolderUri = ParentFolderUri; function MakeRelativeUri(baseUri, absoluteUri) { return new URI(absoluteUri).relativeTo(baseUri).toString(); } exports.MakeRelativeUri = MakeRelativeUri; /*********************** * OS abstraction (writing files, enumerating files) ***********************/ const file_io_1 = require("./file-io"); const fs_1 = require("fs"); function isAccessibleFile(localPath) { try { return fs_1.lstatSync(localPath).isFile(); } catch (e) { return false; } } function FileUriToLocalPath(fileUri) { const uri = url_1.parse(fileUri); if (!fileUri.startsWith("file:///")) { throw new Error(!fileUri.startsWith("file://") ? `Protocol '${uri.protocol}' not supported for writing.` : `UNC paths not supported for writing.`); } // convert to path let p = uri.path; if (p === undefined) { throw new Error(`Cannot write to '${uri}'. Path not found.`); } if (path_1.sep === "\\") { p = p.substr(p.startsWith("/") ? 1 : 0); p = p.replace(/\//g, "\\"); } return decodeURI(p); } async function EnumerateFiles(folderUri, probeFiles = []) { const results = new Array(); folderUri = EnsureIsFolderUri(folderUri); if (folderUri.startsWith("file:")) { let files = []; try { files = await file_io_1.readdir(FileUriToLocalPath(folderUri)); } catch (e) { } results.push(...files .map(f => ResolveUri(folderUri, f)) .filter(f => isAccessibleFile(FileUriToLocalPath(f)))); } else { for (const candid of probeFiles.map(f => ResolveUri(folderUri, f))) { if (await ExistsUri(candid)) { results.push(candid); } } } return results; } exports.EnumerateFiles = EnumerateFiles; async function CreateDirectoryFor(filePath) { var dir = path_2.dirname(filePath); if (!await file_io_1.exists(dir)) { await CreateDirectoryFor(dir); try { await file_io_1.mkdir(dir); } catch (e) { // mkdir throws if directory already exists - which happens occasionally due to race conditions } } } async function WriteStringInternal(fileName, data) { await CreateDirectoryFor(fileName); await file_io_1.writeFile(fileName, data); } /** * Writes string to local file system. * @param fileUri Target file uri. * @param data String to write (encoding: UTF8). */ function WriteString(fileUri, data) { return WriteStringInternal(FileUriToLocalPath(fileUri), data); } exports.WriteString = WriteString; /** * Clears a folder on the local file system. * @param folderUri Folder uri. */ async function ClearFolder(folderUri) { const path = FileUriToLocalPath(folderUri); const deleteFolderRecursive = async (path) => { if (await file_io_1.exists(path)) { for (const file of await file_io_1.readdir(path)) { var curPath = path + "/" + file; if (fs_1.lstatSync(curPath).isDirectory()) { await deleteFolderRecursive(curPath); } else { fs_1.unlinkSync(curPath); } } fs_1.rmdirSync(path); } }; await deleteFolderRecursive(path); } exports.ClearFolder = ClearFolder; //# sourceMappingURL=uri.js.map