1/* 2 * Copyright (c) 2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import { existsSync, readFileSync, writeFileSync } from 'fs'; 17import { readJsonSync } from 'fs-extra'; 18import type { IOptions } from '../configs/IOptions'; 19import { fileExtensions } from '../common/type'; 20import type { PathAndExtension } from '../common/type'; 21import fs from 'fs'; 22 23export class FileUtils { 24 /** 25 * Read file and return content 26 * 27 * @param filePath file path 28 */ 29 public static readFile(filePath: string): string | undefined { 30 if (!existsSync(filePath)) { 31 console.error(`File <${this.getFileName(filePath)} is not found.>`); 32 return undefined; 33 } 34 return readFileSync(filePath, 'utf-8'); 35 } 36 37 /** 38 * Read file and convert to json object. 39 * 40 * @param filePath file path 41 */ 42 public static readFileAsJson(filePath: string): IOptions | undefined { 43 if (!existsSync(filePath)) { 44 console.error(`File <${this.getFileName(filePath)} is not found.>`); 45 return undefined; 46 } 47 48 try { 49 return readJsonSync(filePath); 50 } catch (e) { 51 console.error('json file read error: ' + filePath); 52 return undefined; 53 } 54 } 55 56 /** 57 * Get File Name 58 * 59 * @param filePath file path 60 */ 61 public static getFileName(filePath: string): string | undefined { 62 if (!filePath) { 63 return undefined; 64 } 65 66 const lastSepIndex: number = filePath.lastIndexOf('/'); 67 if (lastSepIndex >= 0) { 68 return filePath.slice(lastSepIndex + 1); 69 } 70 71 return filePath.slice(filePath.lastIndexOf('\\') + 1); 72 } 73 74 /** 75 * Get suffix of a file. 76 * 77 * @param filePath file path 78 */ 79 public static getFileExtension(filePath: string): string | undefined { 80 if (!filePath || !filePath.includes('.')) { 81 return undefined; 82 } 83 84 // get file name 85 let fileName: string = this.getFileName(filePath); 86 if (!fileName.includes('.')) { 87 return undefined; 88 } 89 90 return fileName.slice(fileName.lastIndexOf('.') + 1); 91 } 92 93 public static writeFile(filePath: string, content: string): void { 94 writeFileSync(filePath, content); 95 } 96 97 /** 98 * get prefix of directory 99 * @param dirPath 100 */ 101 public static getPrefix(dirPath: string): string | undefined { 102 if (!dirPath || (!dirPath.includes('/') && !dirPath.includes('\\'))) { 103 return undefined; 104 } 105 106 const sepIndex: number = dirPath.lastIndexOf('/'); 107 if (sepIndex >= 0) { 108 return dirPath.slice(0, sepIndex + 1); 109 } 110 111 return dirPath.slice(0, dirPath.lastIndexOf('\\') + 1); 112 } 113 114 public static getPathWithoutPrefix(filePath: string, prefix: string): string | undefined { 115 if (!filePath.startsWith(prefix)) { 116 return filePath; 117 } 118 119 return filePath.slice(prefix.length); 120 } 121 122 public static splitFilePath(filePath: string): string[] { 123 if (!filePath.includes('\\') && !filePath.includes('\/')) { 124 return [filePath]; 125 } 126 const directories = filePath.split(/[\/\\]/); 127 const output: string[] = []; 128 /* path: /foo//bar; the target output is ['', 'foo', '', 'bar']. 129 * if the first empty string is deleted, the path joining of the Linux platform folder is 'foo/bar'. 130 */ 131 if (directories.length > 0 && directories[0] === '') { 132 output.push(''); 133 } 134 135 output.push(...(directories.filter(part => part !== ''))); 136 return directories; 137 } 138 139 static relativePathBegins: string[] = ['./', '../', '.\\', '..\\']; 140 public static isRelativePath(filePath: string): boolean { 141 for (const bebin of this.relativePathBegins) { 142 if (filePath.startsWith(bebin)) { 143 return true; 144 } 145 } 146 return false; 147 } 148 149 public static getFileSuffix(filePath: string): PathAndExtension { 150 for (let ext of fileExtensions) { 151 if (filePath.endsWith(ext)) { 152 const filePathWithoutSuffix: string = filePath.replace(new RegExp(`${ext}$`), ''); 153 return { path: filePathWithoutSuffix, ext: ext }; 154 } 155 } 156 return { path: filePath, ext: '' }; 157 } 158 159 public static isReadableFile(filePath: string): boolean { 160 try { 161 fs.accessSync(filePath, fs.constants.R_OK); 162 } catch (err) { 163 return false; 164 } 165 return true; 166 } 167} 168