UNPKG

9.9 kBJavaScriptView Raw
1"use strict";
2/*---------------------------------------------------------------------------------------------
3 * Copyright (c) Microsoft Corporation. All rights reserved.
4 * Licensed under the MIT License. See License.txt in the project root for license information.
5 *--------------------------------------------------------------------------------------------*/
6Object.defineProperty(exports, "__esModule", { value: true });
7function IsUri(uri) {
8 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);
9}
10exports.IsUri = IsUri;
11/***********************
12 * Data aquisition
13 ***********************/
14const promisify = require("pify");
15const url_1 = require("url");
16const path_1 = require("path");
17const stripBom = require("strip-bom");
18const getUri = require("get-uri");
19const getUriAsync = promisify(getUri);
20/**
21 * Loads a UTF8 string from given URI.
22 */
23async function ReadUri(uri) {
24 try {
25 const readable = await getUriAsync(uri);
26 const readAll = new Promise(function (resolve, reject) {
27 let result = "";
28 readable.on("data", data => result += data.toString());
29 readable.on("end", () => resolve(result));
30 readable.on("error", err => reject(err));
31 });
32 let result = await readAll;
33 // fix up UTF16le files
34 if (result.charCodeAt(0) === 65533 && result.charCodeAt(1) === 65533) {
35 result = Buffer.from(result.slice(2)).toString("utf16le");
36 }
37 return stripBom(result);
38 }
39 catch (e) {
40 throw new Error(`Failed to load '${uri}' (${e})`);
41 }
42}
43exports.ReadUri = ReadUri;
44async function ExistsUri(uri) {
45 try {
46 await ReadUri(uri);
47 return true;
48 }
49 catch (e) {
50 return false;
51 }
52}
53exports.ExistsUri = ExistsUri;
54/***********************
55 * URI manipulation
56 ***********************/
57const path_2 = require("path");
58const URI = require("urijs");
59const fileUri = require("file-url");
60/**
61 * remake of path.isAbsolute... because it's platform dependent:
62 * Windows: C:\\... -> true /... -> true
63 * Linux: C:\\... -> false /... -> true
64 */
65function isAbsolute(path) {
66 return !!path.match(/^([a-zA-Z]:)?(\/|\\)/);
67}
68/**
69 * determines what an absolute URI is for our purposes, consider:
70 * - we had Ruby try to use "Azure::ARM::SQL" as a file name, so that should not be considered absolute
71 * - we want simple, easily predictable semantics
72 */
73function isUriAbsolute(url) {
74 return /^[a-z]+:\/\//.test(url);
75}
76/**
77 * Create a 'file:///' URI from given absolute path.
78 * Examples:
79 * - "C:\swagger\storage.yaml" -> "file:///C:/swagger/storage.yaml"
80 * - "/input/swagger.yaml" -> "file:///input/swagger.yaml"
81 */
82function CreateFileOrFolderUri(absolutePath) {
83 if (!isAbsolute(absolutePath)) {
84 throw new Error(`Can only create file URIs from absolute paths. Got '${absolutePath}'`);
85 }
86 let result = fileUri(absolutePath, { resolve: false });
87 // handle UNCs
88 if (absolutePath.startsWith("//") || absolutePath.startsWith("\\\\")) {
89 result = result.replace(/^file:\/\/\/\//, "file://");
90 }
91 return result;
92}
93exports.CreateFileOrFolderUri = CreateFileOrFolderUri;
94function CreateFileUri(absolutePath) {
95 return EnsureIsFileUri(CreateFileOrFolderUri(absolutePath));
96}
97exports.CreateFileUri = CreateFileUri;
98function CreateFolderUri(absolutePath) {
99 return EnsureIsFolderUri(CreateFileOrFolderUri(absolutePath));
100}
101exports.CreateFolderUri = CreateFolderUri;
102function EnsureIsFolderUri(uri) {
103 return EnsureIsFileUri(uri) + "/";
104}
105exports.EnsureIsFolderUri = EnsureIsFolderUri;
106function EnsureIsFileUri(uri) {
107 return uri.replace(/\/$/g, "");
108}
109exports.EnsureIsFileUri = EnsureIsFileUri;
110function GetFilename(uri) {
111 return uri.split("/").reverse()[0].split("\\").reverse()[0];
112}
113exports.GetFilename = GetFilename;
114function GetFilenameWithoutExtension(uri) {
115 const lastPart = GetFilename(uri);
116 const ext = lastPart.indexOf(".") === -1 ? "" : lastPart.split(".").reverse()[0];
117 return lastPart.substr(0, lastPart.length - ext.length - 1);
118}
119exports.GetFilenameWithoutExtension = GetFilenameWithoutExtension;
120function ToRawDataUrl(uri) {
121 // special URI handlers
122 // - GitHub
123 if (uri.startsWith("https://github")) {
124 uri = uri.replace(/^https?:\/\/(github.com)(\/[^\/]+\/[^\/]+\/)(blob|tree)\/(.*)/ig, "https://raw.githubusercontent.com$2$4");
125 }
126 return uri;
127}
128exports.ToRawDataUrl = ToRawDataUrl;
129/**
130 * The singularity of all resolving.
131 * 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.
132 * @param baseUri Absolute base URI
133 * @param pathOrUri Relative/absolute path/URI
134 * @returns Absolute URI
135 */
136function ResolveUri(baseUri, pathOrUri) {
137 if (isAbsolute(pathOrUri)) {
138 return CreateFileOrFolderUri(pathOrUri);
139 }
140 // known here: `pathOrUri` is eiher URI (relative or absolute) or relative path - which we can normalize to a relative URI
141 pathOrUri = pathOrUri.replace(/\\/g, "/");
142 // known here: `pathOrUri` is a URI (relative or absolute)
143 if (isUriAbsolute(pathOrUri)) {
144 return pathOrUri;
145 }
146 // known here: `pathOrUri` is a relative URI
147 if (!baseUri) {
148 throw new Error("'pathOrUri' was detected to be relative so 'baseUri' is required");
149 }
150 try {
151 return new URI(pathOrUri).absoluteTo(baseUri).toString();
152 }
153 catch (e) {
154 throw new Error(`Failed resolving '${pathOrUri}' against '${baseUri}'.`);
155 }
156}
157exports.ResolveUri = ResolveUri;
158function ParentFolderUri(uri) {
159 // root?
160 if (uri.endsWith("//")) {
161 return null;
162 }
163 // folder? => cut away last "/"
164 if (uri.endsWith("/")) {
165 uri = uri.slice(0, uri.length - 1);
166 }
167 // cut away last component
168 const compLen = uri.split("/").reverse()[0].length;
169 return uri.slice(0, uri.length - compLen);
170}
171exports.ParentFolderUri = ParentFolderUri;
172function MakeRelativeUri(baseUri, absoluteUri) {
173 return new URI(absoluteUri).relativeTo(baseUri).toString();
174}
175exports.MakeRelativeUri = MakeRelativeUri;
176/***********************
177 * OS abstraction (writing files, enumerating files)
178 ***********************/
179const file_io_1 = require("./file-io");
180const fs_1 = require("fs");
181function isAccessibleFile(localPath) {
182 try {
183 return fs_1.lstatSync(localPath).isFile();
184 }
185 catch (e) {
186 return false;
187 }
188}
189function FileUriToLocalPath(fileUri) {
190 const uri = url_1.parse(fileUri);
191 if (!fileUri.startsWith("file:///")) {
192 throw new Error(!fileUri.startsWith("file://")
193 ? `Protocol '${uri.protocol}' not supported for writing.`
194 : `UNC paths not supported for writing.`);
195 }
196 // convert to path
197 let p = uri.path;
198 if (p === undefined) {
199 throw new Error(`Cannot write to '${uri}'. Path not found.`);
200 }
201 if (path_1.sep === "\\") {
202 p = p.substr(p.startsWith("/") ? 1 : 0);
203 p = p.replace(/\//g, "\\");
204 }
205 return decodeURI(p);
206}
207async function EnumerateFiles(folderUri, probeFiles = []) {
208 const results = new Array();
209 folderUri = EnsureIsFolderUri(folderUri);
210 if (folderUri.startsWith("file:")) {
211 let files = [];
212 try {
213 files = await file_io_1.readdir(FileUriToLocalPath(folderUri));
214 }
215 catch (e) { }
216 results.push(...files
217 .map(f => ResolveUri(folderUri, f))
218 .filter(f => isAccessibleFile(FileUriToLocalPath(f))));
219 }
220 else {
221 for (const candid of probeFiles.map(f => ResolveUri(folderUri, f))) {
222 if (await ExistsUri(candid)) {
223 results.push(candid);
224 }
225 }
226 }
227 return results;
228}
229exports.EnumerateFiles = EnumerateFiles;
230async function CreateDirectoryFor(filePath) {
231 var dir = path_2.dirname(filePath);
232 if (!await file_io_1.exists(dir)) {
233 await CreateDirectoryFor(dir);
234 try {
235 await file_io_1.mkdir(dir);
236 }
237 catch (e) {
238 // mkdir throws if directory already exists - which happens occasionally due to race conditions
239 }
240 }
241}
242async function WriteStringInternal(fileName, data) {
243 await CreateDirectoryFor(fileName);
244 await file_io_1.writeFile(fileName, data);
245}
246/**
247 * Writes string to local file system.
248 * @param fileUri Target file uri.
249 * @param data String to write (encoding: UTF8).
250 */
251function WriteString(fileUri, data) {
252 return WriteStringInternal(FileUriToLocalPath(fileUri), data);
253}
254exports.WriteString = WriteString;
255/**
256 * Clears a folder on the local file system.
257 * @param folderUri Folder uri.
258 */
259async function ClearFolder(folderUri) {
260 const path = FileUriToLocalPath(folderUri);
261 const deleteFolderRecursive = async (path) => {
262 if (await file_io_1.exists(path)) {
263 for (const file of await file_io_1.readdir(path)) {
264 var curPath = path + "/" + file;
265 if (fs_1.lstatSync(curPath).isDirectory()) {
266 await deleteFolderRecursive(curPath);
267 }
268 else {
269 fs_1.unlinkSync(curPath);
270 }
271 }
272 fs_1.rmdirSync(path);
273 }
274 };
275 await deleteFolderRecursive(path);
276}
277exports.ClearFolder = ClearFolder;
278//# sourceMappingURL=uri.js.map
\No newline at end of file