* Copyright (c) 2023 - present TinyEngine Authors.
* Copyright (c) 2023 - present Huawei Cloud Computing Technologies Co., Ltd.
*
* Use of this source code is governed by an MIT-style license.
*
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
*
*/
import { createZip, writeZip } from './fszip'
export const isSupportFileSystemAccess =
Object.prototype.hasOwnProperty.call(window, 'showDirectoryPicker') && window.self === window.top
* 获取用户选择并授权的文件夹根路径
* @param {*} options
* mode: 授权模式 e.g. 'readwrite'
* @returns dirHandle 目录句柄
*/
export const getUserBaseDirHandle = async (options = {}) => {
if (!isSupportFileSystemAccess) {
return createZip()
}
const dirHandle = await window.showDirectoryPicker({ mode: 'readwrite', ...options })
return dirHandle
}
* 获取目录句柄
* @param {*} baseDirHandle 根目录句柄
* @param {Array<string>} pathArr 相对路径(相对根路径)
* @param {boolean} create true:不存在则创建
* @returns dirHandle | null
*/
export async function getDirectoryHandle(baseDirHandle, pathArr = [], { create = false } = {}) {
if (!baseDirHandle) {
return null
}
let currentHandle = baseDirHandle
for (const curPath of pathArr) {
currentHandle = await currentHandle.getDirectoryHandle(curPath, { create })
}
return currentHandle
}
* 获取文件句柄
* @param {*} baseDirHandle 根目录句柄
* @param {string} filePath 相对路径(相对根路径)
* @param {*} options
* {boolean} create true:不存在则创建
* @returns fileHandle | null
*/
export async function getFileHandle(baseDirHandle, filePath, { create = false } = {}) {
if (!baseDirHandle || !filePath) {
return null
}
const pathArr = filePath.split('/')
const fileName = pathArr.pop()
const dirHandle = await getDirectoryHandle(baseDirHandle, pathArr, { create })
const fileHandle = await dirHandle.getFileHandle(fileName, { create })
return fileHandle
}
* 获取用户选择并授权的文件路径
* @param {*} options
* mode: 授权模式 e.g. 'readwrite'
* @returns fileHandle 文件句柄
*/
export const getUserFileHandle = async (options = {}) => {
if (!isSupportFileSystemAccess) {
throw new Error('不支持的浏览器或处于iframe中')
}
const [fileHandle] = await window.showOpenFilePicker({ mode: 'readwrite', ...options })
return fileHandle
}
* 读取文件内容
* @param {*} baseDirHandle 根目录句柄
* @param {*} filePath 文件相对路径(相对根目录)
* @return {string} 文件内容
*/
export const readFile = async (baseDirHandle, filePath) => {
if (!baseDirHandle || !filePath) {
return undefined
}
const fileHandle = await getFileHandle(baseDirHandle, filePath)
const file = await fileHandle.getFile()
const content = await file.text()
return content
}
* 读取目录文件列表
* @param {*} baseDirHandle 根目录句柄
* @param {string} dirPath 目录相对路径
* @returns {Array<Handle>} 目录文件列表 Handle:句柄
* Handle.type 类型 'file' | 'directory'
* Handle.name 名称
*/
export const readDir = async (baseDirHandle, dirPath) => {
let dirHandle = baseDirHandle
if (!baseDirHandle) {
return undefined
}
if (dirPath) {
const pathArr = dirPath.split('/')
dirHandle = await getDirectoryHandle(baseDirHandle, pathArr)
}
const dirs = []
for await (const value of dirHandle.values()) {
dirs.push(value)
}
return dirs
}
* 写入文件(不存在则创建)
* @param {*} baseDirHandle 根目录句柄
* @param {Object} fileInfo
* {string} filePath 文件相对路径(相对根目录)
* {string} fileContent 文件内容
*/
export const writeFile = async (handle, { filePath, fileContent }) => {
let directoryHandle = null
let fileHandle = null
let fileName
if (!handle || (handle.type === 'directory' && !filePath)) {
throw new Error('invalid handle.')
}
if (handle.type === 'file') {
fileHandle = handle
fileName = handle.name
} else {
directoryHandle = handle
const pathArr = filePath.split('/')
fileName = pathArr.pop()
const dirHandle = await getDirectoryHandle(directoryHandle, pathArr, { create: true })
fileHandle = await dirHandle.getFileHandle(fileName, { create: true })
}
const writable = await fileHandle.createWritable()
await writable.write(fileContent)
await writable.close()
}
* 批量写入文件(不存在则创建)
* @param {*} baseDirHandle 根目录句柄
* @param {Array<FileInfo>} filesInfo 文件信息
* FileInfo.filePath 文件相对路径
* FileInfo.fileContent 文件内容
* @param {Boolean} supportZipCache 是否支持zip缓存,zip缓存可能会导致文件不能及时更新,默认不缓存
*
*/
export const writeFiles = async (
baseDirHandle,
filesInfo,
zipName = 'tiny-engine-generate-code',
supportZipCache = false
) => {
if (!filesInfo?.length) {
return
}
if (!isSupportFileSystemAccess) {
const zipInfo = { zipName, zipHandle: supportZipCache && baseDirHandle }
await writeZip(filesInfo, zipInfo)
return
}
let directoryHandle = baseDirHandle
if (!directoryHandle) {
directoryHandle = await window.showDirectoryPicker({ mode: 'readwrite' })
}
await Promise.all(filesInfo.map((fileInfo) => writeFile(directoryHandle, fileInfo)))
}