mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Few renames to distinguish between fs File and File in the test case to load in the VFS with watch
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
/// <reference path="harness.ts" />
|
||||
|
||||
namespace ts.TestFSWithWatch {
|
||||
export const libFile: FileOrFolder = {
|
||||
export const libFile: File = {
|
||||
path: "/a/lib/lib.d.ts",
|
||||
content: `/// <reference no-default-lib="true"/>
|
||||
interface Boolean {}
|
||||
@@ -39,7 +39,7 @@ interface Array<T> {}`
|
||||
environmentVariables?: Map<string>;
|
||||
}
|
||||
|
||||
export function createWatchedSystem(fileOrFolderList: ReadonlyArray<FileOrFolder>, params?: TestServerHostCreationParameters): TestServerHost {
|
||||
export function createWatchedSystem(fileOrFolderList: ReadonlyArray<FileOrFolderOrSymLink>, params?: TestServerHostCreationParameters): TestServerHost {
|
||||
if (!params) {
|
||||
params = {};
|
||||
}
|
||||
@@ -54,7 +54,7 @@ interface Array<T> {}`
|
||||
return host;
|
||||
}
|
||||
|
||||
export function createServerHost(fileOrFolderList: ReadonlyArray<FileOrFolder>, params?: TestServerHostCreationParameters): TestServerHost {
|
||||
export function createServerHost(fileOrFolderList: ReadonlyArray<FileOrFolderOrSymLink>, params?: TestServerHostCreationParameters): TestServerHost {
|
||||
if (!params) {
|
||||
params = {};
|
||||
}
|
||||
@@ -69,11 +69,28 @@ interface Array<T> {}`
|
||||
return host;
|
||||
}
|
||||
|
||||
export interface FileOrFolder {
|
||||
export interface File {
|
||||
path: string;
|
||||
content?: string;
|
||||
content: string;
|
||||
fileSize?: number;
|
||||
symLink?: string;
|
||||
}
|
||||
|
||||
export interface Folder {
|
||||
path: string;
|
||||
}
|
||||
|
||||
export interface SymLink {
|
||||
path: string;
|
||||
symLink: string;
|
||||
}
|
||||
|
||||
export type FileOrFolderOrSymLink = File | Folder | SymLink;
|
||||
function isFile(fileOrFolderOrSymLink: FileOrFolderOrSymLink): fileOrFolderOrSymLink is File {
|
||||
return isString((<File>fileOrFolderOrSymLink).content);
|
||||
}
|
||||
|
||||
function isSymLink(fileOrFolderOrSymLink: FileOrFolderOrSymLink): fileOrFolderOrSymLink is SymLink {
|
||||
return isString((<SymLink>fileOrFolderOrSymLink).symLink);
|
||||
}
|
||||
|
||||
interface FSEntry {
|
||||
@@ -82,29 +99,29 @@ interface Array<T> {}`
|
||||
modifiedTime: Date;
|
||||
}
|
||||
|
||||
interface File extends FSEntry {
|
||||
interface FsFile extends FSEntry {
|
||||
content: string;
|
||||
fileSize?: number;
|
||||
}
|
||||
|
||||
interface Folder extends FSEntry {
|
||||
interface FsFolder extends FSEntry {
|
||||
entries: SortedArray<FSEntry>;
|
||||
}
|
||||
|
||||
interface SymLink extends FSEntry {
|
||||
interface FsSymLink extends FSEntry {
|
||||
symLink: string;
|
||||
}
|
||||
|
||||
function isFolder(s: FSEntry): s is Folder {
|
||||
return s && isArray((<Folder>s).entries);
|
||||
function isFsFolder(s: FSEntry): s is FsFolder {
|
||||
return s && isArray((<FsFolder>s).entries);
|
||||
}
|
||||
|
||||
function isFile(s: FSEntry): s is File {
|
||||
return s && isString((<File>s).content);
|
||||
function isFsFile(s: FSEntry): s is FsFile {
|
||||
return s && isString((<FsFile>s).content);
|
||||
}
|
||||
|
||||
function isSymLink(s: FSEntry): s is SymLink {
|
||||
return s && isString((<SymLink>s).symLink);
|
||||
function isFsSymLink(s: FSEntry): s is FsSymLink {
|
||||
return s && isString((<FsSymLink>s).symLink);
|
||||
}
|
||||
|
||||
function invokeWatcherCallbacks<T>(callbacks: T[], invokeCallback: (cb: T) => void): void {
|
||||
@@ -306,12 +323,12 @@ interface Array<T> {}`
|
||||
private readonly dynamicPriorityWatchFile: HostWatchFile;
|
||||
private readonly customRecursiveWatchDirectory: HostWatchDirectory | undefined;
|
||||
|
||||
constructor(public withSafeList: boolean, public useCaseSensitiveFileNames: boolean, executingFilePath: string, currentDirectory: string, fileOrFolderList: ReadonlyArray<FileOrFolder>, public readonly newLine = "\n", public readonly useWindowsStylePath?: boolean, private readonly environmentVariables?: Map<string>) {
|
||||
constructor(public withSafeList: boolean, public useCaseSensitiveFileNames: boolean, executingFilePath: string, currentDirectory: string, fileOrFolderorSymLinkList: ReadonlyArray<FileOrFolderOrSymLink>, public readonly newLine = "\n", public readonly useWindowsStylePath?: boolean, private readonly environmentVariables?: Map<string>) {
|
||||
this.getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames);
|
||||
this.toPath = s => toPath(s, currentDirectory, this.getCanonicalFileName);
|
||||
this.executingFilePath = this.getHostSpecificPath(executingFilePath);
|
||||
this.currentDirectory = this.getHostSpecificPath(currentDirectory);
|
||||
this.reloadFS(fileOrFolderList);
|
||||
this.reloadFS(fileOrFolderorSymLinkList);
|
||||
this.dynamicPriorityWatchFile = this.environmentVariables && this.environmentVariables.get("TSC_WATCHFILE") === "DynamicPriorityPolling" ?
|
||||
createDynamicPriorityPollingWatchFile(this) :
|
||||
undefined;
|
||||
@@ -373,12 +390,12 @@ interface Array<T> {}`
|
||||
return new Date(this.time);
|
||||
}
|
||||
|
||||
reloadFS(fileOrFolderList: ReadonlyArray<FileOrFolder>, options?: Partial<ReloadWatchInvokeOptions>) {
|
||||
reloadFS(fileOrFolderOrSymLinkList: ReadonlyArray<FileOrFolderOrSymLink>, options?: Partial<ReloadWatchInvokeOptions>) {
|
||||
const mapNewLeaves = createMap<true>();
|
||||
const isNewFs = this.fs.size === 0;
|
||||
fileOrFolderList = fileOrFolderList.concat(this.withSafeList ? safeList : []);
|
||||
const filesOrFoldersToLoad: ReadonlyArray<FileOrFolder> = !this.useWindowsStylePath ? fileOrFolderList :
|
||||
fileOrFolderList.map<FileOrFolder>(f => {
|
||||
fileOrFolderOrSymLinkList = fileOrFolderOrSymLinkList.concat(this.withSafeList ? safeList : []);
|
||||
const filesOrFoldersToLoad: ReadonlyArray<FileOrFolderOrSymLink> = !this.useWindowsStylePath ? fileOrFolderOrSymLinkList :
|
||||
fileOrFolderOrSymLinkList.map<FileOrFolderOrSymLink>(f => {
|
||||
const result = clone(f);
|
||||
result.path = this.getHostSpecificPath(f.path);
|
||||
return result;
|
||||
@@ -389,8 +406,8 @@ interface Array<T> {}`
|
||||
// If its a change
|
||||
const currentEntry = this.fs.get(path);
|
||||
if (currentEntry) {
|
||||
if (isFile(currentEntry)) {
|
||||
if (isString(fileOrDirectory.content)) {
|
||||
if (isFsFile(currentEntry)) {
|
||||
if (isFile(fileOrDirectory)) {
|
||||
// Update file
|
||||
if (currentEntry.content !== fileOrDirectory.content) {
|
||||
this.modifyFile(fileOrDirectory.path, fileOrDirectory.content, options);
|
||||
@@ -400,12 +417,12 @@ interface Array<T> {}`
|
||||
// TODO: Changing from file => folder/Symlink
|
||||
}
|
||||
}
|
||||
else if (isSymLink(currentEntry)) {
|
||||
else if (isFsSymLink(currentEntry)) {
|
||||
// TODO: update symlinks
|
||||
}
|
||||
else {
|
||||
// Folder
|
||||
if (isString(fileOrDirectory.content)) {
|
||||
if (isFile(fileOrDirectory)) {
|
||||
// TODO: Changing from folder => file
|
||||
}
|
||||
else {
|
||||
@@ -424,7 +441,7 @@ interface Array<T> {}`
|
||||
// If this entry is not from the new file or folder
|
||||
if (!mapNewLeaves.get(path)) {
|
||||
// Leaf entries that arent in new list => remove these
|
||||
if (isFile(fileOrDirectory) || isSymLink(fileOrDirectory) || isFolder(fileOrDirectory) && fileOrDirectory.entries.length === 0) {
|
||||
if (isFsFile(fileOrDirectory) || isFsSymLink(fileOrDirectory) || isFsFolder(fileOrDirectory) && fileOrDirectory.entries.length === 0) {
|
||||
this.removeFileOrFolder(fileOrDirectory, folder => !mapNewLeaves.get(folder.path));
|
||||
}
|
||||
}
|
||||
@@ -435,7 +452,7 @@ interface Array<T> {}`
|
||||
modifyFile(filePath: string, content: string, options?: Partial<ReloadWatchInvokeOptions>) {
|
||||
const path = this.toFullPath(filePath);
|
||||
const currentEntry = this.fs.get(path);
|
||||
if (!currentEntry || !isFile(currentEntry)) {
|
||||
if (!currentEntry || !isFsFile(currentEntry)) {
|
||||
throw new Error(`file not present: ${filePath}`);
|
||||
}
|
||||
|
||||
@@ -459,7 +476,7 @@ interface Array<T> {}`
|
||||
renameFolder(folderName: string, newFolderName: string) {
|
||||
const fullPath = getNormalizedAbsolutePath(folderName, this.currentDirectory);
|
||||
const path = this.toPath(fullPath);
|
||||
const folder = this.fs.get(path) as Folder;
|
||||
const folder = this.fs.get(path) as FsFolder;
|
||||
Debug.assert(!!folder);
|
||||
|
||||
// Only remove the folder
|
||||
@@ -467,19 +484,19 @@ interface Array<T> {}`
|
||||
|
||||
// Add updated folder with new folder name
|
||||
const newFullPath = getNormalizedAbsolutePath(newFolderName, this.currentDirectory);
|
||||
const newFolder = this.toFolder(newFullPath);
|
||||
const newFolder = this.toFsFolder(newFullPath);
|
||||
const newPath = newFolder.path;
|
||||
const basePath = getDirectoryPath(path);
|
||||
Debug.assert(basePath !== path);
|
||||
Debug.assert(basePath === getDirectoryPath(newPath));
|
||||
const baseFolder = this.fs.get(basePath) as Folder;
|
||||
const baseFolder = this.fs.get(basePath) as FsFolder;
|
||||
this.addFileOrFolderInFolder(baseFolder, newFolder);
|
||||
|
||||
// Invoke watches for files in the folder as deleted (from old path)
|
||||
this.renameFolderEntries(folder, newFolder);
|
||||
}
|
||||
|
||||
private renameFolderEntries(oldFolder: Folder, newFolder: Folder) {
|
||||
private renameFolderEntries(oldFolder: FsFolder, newFolder: FsFolder) {
|
||||
for (const entry of oldFolder.entries) {
|
||||
this.fs.delete(entry.path);
|
||||
this.invokeFileWatcher(entry.fullPath, FileWatcherEventKind.Deleted);
|
||||
@@ -491,38 +508,38 @@ interface Array<T> {}`
|
||||
}
|
||||
this.fs.set(entry.path, entry);
|
||||
this.invokeFileWatcher(entry.fullPath, FileWatcherEventKind.Created);
|
||||
if (isFolder(entry)) {
|
||||
if (isFsFolder(entry)) {
|
||||
this.renameFolderEntries(entry, entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ensureFileOrFolder(fileOrDirectory: FileOrFolder, ignoreWatchInvokedWithTriggerAsFileCreate?: boolean) {
|
||||
if (isString(fileOrDirectory.content)) {
|
||||
const file = this.toFile(fileOrDirectory);
|
||||
ensureFileOrFolder(fileOrDirectoryOrSymLink: FileOrFolderOrSymLink, ignoreWatchInvokedWithTriggerAsFileCreate?: boolean) {
|
||||
if (isFile(fileOrDirectoryOrSymLink)) {
|
||||
const file = this.toFsFile(fileOrDirectoryOrSymLink);
|
||||
// file may already exist when updating existing type declaration file
|
||||
if (!this.fs.get(file.path)) {
|
||||
const baseFolder = this.ensureFolder(getDirectoryPath(file.fullPath));
|
||||
this.addFileOrFolderInFolder(baseFolder, file, ignoreWatchInvokedWithTriggerAsFileCreate);
|
||||
}
|
||||
}
|
||||
else if (isString(fileOrDirectory.symLink)) {
|
||||
const symLink = this.toSymLink(fileOrDirectory);
|
||||
else if (isSymLink(fileOrDirectoryOrSymLink)) {
|
||||
const symLink = this.toFsSymLink(fileOrDirectoryOrSymLink);
|
||||
Debug.assert(!this.fs.get(symLink.path));
|
||||
const baseFolder = this.ensureFolder(getDirectoryPath(symLink.fullPath));
|
||||
this.addFileOrFolderInFolder(baseFolder, symLink, ignoreWatchInvokedWithTriggerAsFileCreate);
|
||||
}
|
||||
else {
|
||||
const fullPath = getNormalizedAbsolutePath(fileOrDirectory.path, this.currentDirectory);
|
||||
const fullPath = getNormalizedAbsolutePath(fileOrDirectoryOrSymLink.path, this.currentDirectory);
|
||||
this.ensureFolder(fullPath);
|
||||
}
|
||||
}
|
||||
|
||||
private ensureFolder(fullPath: string): Folder {
|
||||
private ensureFolder(fullPath: string): FsFolder {
|
||||
const path = this.toPath(fullPath);
|
||||
let folder = this.fs.get(path) as Folder;
|
||||
let folder = this.fs.get(path) as FsFolder;
|
||||
if (!folder) {
|
||||
folder = this.toFolder(fullPath);
|
||||
folder = this.toFsFolder(fullPath);
|
||||
const baseFullPath = getDirectoryPath(fullPath);
|
||||
if (fullPath !== baseFullPath) {
|
||||
// Add folder in the base folder
|
||||
@@ -535,11 +552,11 @@ interface Array<T> {}`
|
||||
this.fs.set(path, folder);
|
||||
}
|
||||
}
|
||||
Debug.assert(isFolder(folder));
|
||||
Debug.assert(isFsFolder(folder));
|
||||
return folder;
|
||||
}
|
||||
|
||||
private addFileOrFolderInFolder(folder: Folder, fileOrDirectory: File | Folder | SymLink, ignoreWatch?: boolean) {
|
||||
private addFileOrFolderInFolder(folder: FsFolder, fileOrDirectory: FsFile | FsFolder | FsSymLink, ignoreWatch?: boolean) {
|
||||
insertSorted(folder.entries, fileOrDirectory, (a, b) => compareStringsCaseSensitive(getBaseFileName(a.path), getBaseFileName(b.path)));
|
||||
folder.modifiedTime = this.now();
|
||||
this.fs.set(fileOrDirectory.path, fileOrDirectory);
|
||||
@@ -551,9 +568,9 @@ interface Array<T> {}`
|
||||
this.invokeDirectoryWatcher(folder.fullPath, fileOrDirectory.fullPath);
|
||||
}
|
||||
|
||||
private removeFileOrFolder(fileOrDirectory: File | Folder | SymLink, isRemovableLeafFolder: (folder: Folder) => boolean, isRenaming?: boolean) {
|
||||
private removeFileOrFolder(fileOrDirectory: FsFile | FsFolder | FsSymLink, isRemovableLeafFolder: (folder: FsFolder) => boolean, isRenaming?: boolean) {
|
||||
const basePath = getDirectoryPath(fileOrDirectory.path);
|
||||
const baseFolder = this.fs.get(basePath) as Folder;
|
||||
const baseFolder = this.fs.get(basePath) as FsFolder;
|
||||
if (basePath !== fileOrDirectory.path) {
|
||||
Debug.assert(!!baseFolder);
|
||||
baseFolder.modifiedTime = this.now();
|
||||
@@ -562,7 +579,7 @@ interface Array<T> {}`
|
||||
this.fs.delete(fileOrDirectory.path);
|
||||
|
||||
this.invokeFileWatcher(fileOrDirectory.fullPath, FileWatcherEventKind.Deleted);
|
||||
if (isFolder(fileOrDirectory)) {
|
||||
if (isFsFolder(fileOrDirectory)) {
|
||||
Debug.assert(fileOrDirectory.entries.length === 0 || isRenaming);
|
||||
const relativePath = this.getRelativePathToDirectory(fileOrDirectory.fullPath, fileOrDirectory.fullPath);
|
||||
// Invoke directory and recursive directory watcher for the folder
|
||||
@@ -635,23 +652,23 @@ interface Array<T> {}`
|
||||
};
|
||||
}
|
||||
|
||||
private toFile(fileOrDirectory: FileOrFolder): File {
|
||||
const file = this.toFsEntry(fileOrDirectory.path) as File;
|
||||
file.content = fileOrDirectory.content;
|
||||
file.fileSize = fileOrDirectory.fileSize;
|
||||
return file;
|
||||
private toFsFile(file: File): FsFile {
|
||||
const fsFile = this.toFsEntry(file.path) as FsFile;
|
||||
fsFile.content = file.content;
|
||||
fsFile.fileSize = file.fileSize;
|
||||
return fsFile;
|
||||
}
|
||||
|
||||
private toSymLink(fileOrDirectory: FileOrFolder): SymLink {
|
||||
const symLink = this.toFsEntry(fileOrDirectory.path) as SymLink;
|
||||
symLink.symLink = getNormalizedAbsolutePath(fileOrDirectory.symLink, getDirectoryPath(symLink.fullPath));
|
||||
return symLink;
|
||||
private toFsSymLink(symLink: SymLink): FsSymLink {
|
||||
const fsSymLink = this.toFsEntry(symLink.path) as FsSymLink;
|
||||
fsSymLink.symLink = getNormalizedAbsolutePath(symLink.symLink, getDirectoryPath(fsSymLink.fullPath));
|
||||
return fsSymLink;
|
||||
}
|
||||
|
||||
private toFolder(path: string): Folder {
|
||||
const folder = this.toFsEntry(path) as Folder;
|
||||
folder.entries = [] as SortedArray<FSEntry>;
|
||||
return folder;
|
||||
private toFsFolder(path: string): FsFolder {
|
||||
const fsFolder = this.toFsEntry(path) as FsFolder;
|
||||
fsFolder.entries = [] as SortedArray<FSEntry>;
|
||||
return fsFolder;
|
||||
}
|
||||
|
||||
private getRealFsEntry<T extends FSEntry>(isFsEntry: (fsEntry: FSEntry) => fsEntry is T, path: Path, fsEntry = this.fs.get(path)): T | undefined {
|
||||
@@ -659,7 +676,7 @@ interface Array<T> {}`
|
||||
return fsEntry;
|
||||
}
|
||||
|
||||
if (isSymLink(fsEntry)) {
|
||||
if (isFsSymLink(fsEntry)) {
|
||||
return this.getRealFsEntry(isFsEntry, this.toPath(fsEntry.symLink));
|
||||
}
|
||||
|
||||
@@ -676,20 +693,20 @@ interface Array<T> {}`
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private isFile(fsEntry: FSEntry) {
|
||||
private isFsFile(fsEntry: FSEntry) {
|
||||
return !!this.getRealFile(fsEntry.path, fsEntry);
|
||||
}
|
||||
|
||||
private getRealFile(path: Path, fsEntry?: FSEntry): File | undefined {
|
||||
return this.getRealFsEntry(isFile, path, fsEntry);
|
||||
private getRealFile(path: Path, fsEntry?: FSEntry): FsFile | undefined {
|
||||
return this.getRealFsEntry(isFsFile, path, fsEntry);
|
||||
}
|
||||
|
||||
private isFolder(fsEntry: FSEntry) {
|
||||
private isFsFolder(fsEntry: FSEntry) {
|
||||
return !!this.getRealFolder(fsEntry.path, fsEntry);
|
||||
}
|
||||
|
||||
private getRealFolder(path: Path, fsEntry = this.fs.get(path)): Folder | undefined {
|
||||
return this.getRealFsEntry(isFolder, path, fsEntry);
|
||||
private getRealFolder(path: Path, fsEntry = this.fs.get(path)): FsFolder | undefined {
|
||||
return this.getRealFsEntry(isFsFolder, path, fsEntry);
|
||||
}
|
||||
|
||||
fileExists(s: string) {
|
||||
@@ -711,7 +728,7 @@ interface Array<T> {}`
|
||||
getFileSize(s: string) {
|
||||
const path = this.toFullPath(s);
|
||||
const entry = this.fs.get(path);
|
||||
if (isFile(entry)) {
|
||||
if (isFsFile(entry)) {
|
||||
return entry.fileSize ? entry.fileSize : entry.content.length;
|
||||
}
|
||||
return undefined;
|
||||
@@ -726,7 +743,7 @@ interface Array<T> {}`
|
||||
const path = this.toFullPath(s);
|
||||
const folder = this.getRealFolder(path);
|
||||
if (folder) {
|
||||
return mapDefined(folder.entries, entry => this.isFolder(entry) ? getBaseFileName(entry.fullPath) : undefined);
|
||||
return mapDefined(folder.entries, entry => this.isFsFolder(entry) ? getBaseFileName(entry.fullPath) : undefined);
|
||||
}
|
||||
Debug.fail(folder ? "getDirectories called on file" : "getDirectories called on missing folder");
|
||||
return [];
|
||||
@@ -739,10 +756,10 @@ interface Array<T> {}`
|
||||
const folder = this.getRealFolder(this.toPath(dir));
|
||||
if (folder) {
|
||||
folder.entries.forEach((entry) => {
|
||||
if (this.isFolder(entry)) {
|
||||
if (this.isFsFolder(entry)) {
|
||||
directories.push(getBaseFileName(entry.fullPath));
|
||||
}
|
||||
else if (this.isFile(entry)) {
|
||||
else if (this.isFsFile(entry)) {
|
||||
files.push(getBaseFileName(entry.fullPath));
|
||||
}
|
||||
else {
|
||||
@@ -840,24 +857,24 @@ interface Array<T> {}`
|
||||
}
|
||||
|
||||
createDirectory(directoryName: string): void {
|
||||
const folder = this.toFolder(directoryName);
|
||||
const folder = this.toFsFolder(directoryName);
|
||||
|
||||
// base folder has to be present
|
||||
const base = getDirectoryPath(folder.path);
|
||||
const baseFolder = this.fs.get(base) as Folder;
|
||||
Debug.assert(isFolder(baseFolder));
|
||||
const baseFolder = this.fs.get(base) as FsFolder;
|
||||
Debug.assert(isFsFolder(baseFolder));
|
||||
|
||||
Debug.assert(!this.fs.get(folder.path));
|
||||
this.addFileOrFolderInFolder(baseFolder, folder);
|
||||
}
|
||||
|
||||
writeFile(path: string, content: string): void {
|
||||
const file = this.toFile({ path, content });
|
||||
const file = this.toFsFile({ path, content });
|
||||
|
||||
// base folder has to be present
|
||||
const base = getDirectoryPath(file.path);
|
||||
const folder = this.fs.get(base) as Folder;
|
||||
Debug.assert(isFolder(folder));
|
||||
const folder = this.fs.get(base) as FsFolder;
|
||||
Debug.assert(isFsFolder(folder));
|
||||
|
||||
this.addFileOrFolderInFolder(folder, file);
|
||||
}
|
||||
@@ -885,7 +902,7 @@ interface Array<T> {}`
|
||||
const dirFullPath = this.realpath(getDirectoryPath(fullPath));
|
||||
const realFullPath = combinePaths(dirFullPath, getBaseFileName(fullPath));
|
||||
const fsEntry = this.fs.get(this.toPath(realFullPath));
|
||||
if (isSymLink(fsEntry)) {
|
||||
if (isFsSymLink(fsEntry)) {
|
||||
return this.realpath(fsEntry.symLink);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user