mirror of
https://github.com/fluxscape/fluxscape.git
synced 2026-01-11 14:52:54 +01:00
Initial commit
Co-Authored-By: Eric Tuvesson <eric.tuvesson@gmail.com> Co-Authored-By: mikaeltellhed <2311083+mikaeltellhed@users.noreply.github.com> Co-Authored-By: kotte <14197736+mrtamagotchi@users.noreply.github.com> Co-Authored-By: Anders Larsson <64838990+anders-topp@users.noreply.github.com> Co-Authored-By: Johan <4934465+joolsus@users.noreply.github.com> Co-Authored-By: Tore Knudsen <18231882+torekndsn@users.noreply.github.com> Co-Authored-By: victoratndl <99176179+victoratndl@users.noreply.github.com>
This commit is contained in:
6
packages/noodl-platform-node/jest.config.js
Normal file
6
packages/noodl-platform-node/jest.config.js
Normal file
@@ -0,0 +1,6 @@
|
||||
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
|
||||
module.exports = {
|
||||
preset: "ts-jest",
|
||||
testEnvironment: "node",
|
||||
modulePathIgnorePatterns: ["tests/testfs"],
|
||||
};
|
||||
24
packages/noodl-platform-node/package.json
Normal file
24
packages/noodl-platform-node/package.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "@noodl/platform-node",
|
||||
"version": "2.7.0",
|
||||
"main": "src/index.ts",
|
||||
"description": "Cross platform implementation of platform specific features.",
|
||||
"author": "Noodl <info@noodl.net>",
|
||||
"homepage": "https://noodl.net",
|
||||
"scripts": {
|
||||
"test": "jest",
|
||||
"test:coverage": "jest --coverage"
|
||||
},
|
||||
"dependencies": {
|
||||
"@noodl/platform": "file:../noodl-platform",
|
||||
"fs-extra": "^10.0.1",
|
||||
"jszip": "^3.10.1",
|
||||
"mkdirp-sync": "0.0.2",
|
||||
"rimraf": "^3.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^29.0.1",
|
||||
"ts-jest": "^29.0.0",
|
||||
"jest": "^29.0.3"
|
||||
}
|
||||
}
|
||||
319
packages/noodl-platform-node/src/filesystem-node.ts
Normal file
319
packages/noodl-platform-node/src/filesystem-node.ts
Normal file
@@ -0,0 +1,319 @@
|
||||
import fs from 'fs';
|
||||
import nodePath from 'path';
|
||||
import fse, { mkdirp } from 'fs-extra';
|
||||
import JSZip from 'jszip';
|
||||
import { FileBlob, FileInfo, FileStat, IFileSystem, OpenDialogOptions } from '@noodl/platform';
|
||||
|
||||
export class FileSystemNode implements IFileSystem {
|
||||
resolve(...paths: string[]): string {
|
||||
return nodePath.resolve(...paths);
|
||||
}
|
||||
|
||||
join(...paths: string[]): string {
|
||||
return nodePath.join(...paths);
|
||||
}
|
||||
|
||||
exists(path: string): boolean {
|
||||
return fs.existsSync(path);
|
||||
}
|
||||
|
||||
dirname(path: string): string {
|
||||
return nodePath.dirname(path);
|
||||
}
|
||||
|
||||
basename(path: string): string {
|
||||
return nodePath.basename(path);
|
||||
}
|
||||
|
||||
file(path: string): FileStat {
|
||||
const stat = fs.lstatSync(path);
|
||||
return { size: stat.size };
|
||||
}
|
||||
|
||||
writeFile(path: string, blob: FileBlob): Promise<void> {
|
||||
if (typeof blob === 'string') {
|
||||
return fs.promises.writeFile(path, Buffer.from(blob));
|
||||
}
|
||||
|
||||
return fs.promises.writeFile(path, blob);
|
||||
}
|
||||
|
||||
async writeFileOverride(path: string, blob: FileBlob): Promise<void> {
|
||||
try {
|
||||
await this.removeFile(path);
|
||||
} catch (error) {
|
||||
// noop
|
||||
}
|
||||
|
||||
await this.writeFile(path, blob);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read file content, with utf-8 encoding.
|
||||
*
|
||||
* @param path
|
||||
* @returns
|
||||
*/
|
||||
readFile(path: string): Promise<string> {
|
||||
return fs.promises.readFile(path, 'utf8');
|
||||
}
|
||||
|
||||
async readBinaryFile(path: string): Promise<Buffer> {
|
||||
const content = await fs.promises.readFile(path, 'binary');
|
||||
return Buffer.from(content, 'binary');
|
||||
}
|
||||
|
||||
removeFile(path: string): Promise<void> {
|
||||
return fs.promises.unlink(path);
|
||||
}
|
||||
|
||||
renameFile(oldPath: string, newPath: string): Promise<void> {
|
||||
return fs.promises.rename(oldPath, newPath);
|
||||
}
|
||||
|
||||
copyFile(from: string, to: string): Promise<void> {
|
||||
return fs.promises.copyFile(from, to);
|
||||
}
|
||||
|
||||
copyFolder(from: string, to: string): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
fse.copy(from, to, { recursive: true }, (err) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a JSON file, with utf-8 encoding.
|
||||
*
|
||||
* @param path
|
||||
* @returns
|
||||
*/
|
||||
async readJson<T = any>(path: string): Promise<T> {
|
||||
const fileContent = await fs.promises.readFile(path, 'utf8');
|
||||
return JSON.parse(fileContent) as T;
|
||||
}
|
||||
|
||||
async writeJson(path: string, obj: any): Promise<void> {
|
||||
const tmpFileName = path + '.tmp-' + Date.now();
|
||||
|
||||
let jsonText = '';
|
||||
|
||||
try {
|
||||
jsonText = JSON.stringify(obj);
|
||||
} catch (error) {
|
||||
console.log('Error serializing json', error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
try {
|
||||
await fs.promises.writeFile(tmpFileName, jsonText);
|
||||
await fs.promises.rename(tmpFileName, path);
|
||||
} catch (error) {
|
||||
await fs.promises.unlink(tmpFileName);
|
||||
console.log('Error writing json file', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the folder is empty.
|
||||
*
|
||||
* @param path
|
||||
* @returns Returns true, if the folder is empty; Otherwise, false.
|
||||
*/
|
||||
async isDirectoryEmpty(path: string): Promise<boolean> {
|
||||
const files = await this.listDirectory(path);
|
||||
return files.length === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* List all entries in the directory.
|
||||
*
|
||||
* @param path
|
||||
* @returns A list of all entries.
|
||||
*/
|
||||
async listDirectory(path: string): Promise<FileInfo[]> {
|
||||
const files = await fs.promises.readdir(path);
|
||||
return files.map(function (f) {
|
||||
return {
|
||||
fullPath: path + '/' + f,
|
||||
name: f,
|
||||
isDirectory: fs.lstatSync(path + '/' + f).isDirectory()
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the files including all sub folders.
|
||||
*
|
||||
* @param path
|
||||
* @returns
|
||||
*/
|
||||
listDirectoryFiles(path: string): Promise<FileInfo[]> {
|
||||
// https://stackoverflow.com/a/5827895
|
||||
const walk = function (dir: string, done: (error: unknown, results?: string[]) => void) {
|
||||
let results = [];
|
||||
fs.readdir(dir, function (err, list) {
|
||||
if (err) return done(err);
|
||||
let pending = list.length;
|
||||
if (!pending) return done(null, results);
|
||||
list.forEach(function (file) {
|
||||
file = nodePath.resolve(dir, file);
|
||||
fs.stat(file, function (err, stat) {
|
||||
if (stat && stat.isDirectory()) {
|
||||
walk(file, function (err, res) {
|
||||
results = results.concat(res);
|
||||
if (!--pending) done(null, results);
|
||||
});
|
||||
} else {
|
||||
results.push(file);
|
||||
if (!--pending) done(null, results);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return new Promise<FileInfo[]>((resolve, reject) => {
|
||||
walk(path, function (error, files) {
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve(
|
||||
files.map(function (fullPath) {
|
||||
const isDirectory = (function () {
|
||||
try {
|
||||
return fs.lstatSync(fullPath).isDirectory();
|
||||
} catch (_err) {
|
||||
return false;
|
||||
}
|
||||
})();
|
||||
|
||||
return {
|
||||
fullPath,
|
||||
name: nodePath.basename(fullPath),
|
||||
isDirectory
|
||||
};
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* https://github.com/jprichardson/node-fs-extra/blob/HEAD/docs/ensureDir.md
|
||||
* @param path
|
||||
* @returns
|
||||
*/
|
||||
makeDirectory(path: string): Promise<void> {
|
||||
if (path.length === 0 || fs.existsSync(path)) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
mkdirp(path, function (err) {
|
||||
if (err) reject({ result: 'failure', err: err });
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
removeDirRecursive(path: string): void {
|
||||
fse.removeSync(path);
|
||||
}
|
||||
|
||||
openDialog(args: OpenDialogOptions): Promise<string> {
|
||||
throw new Error('Not Supported');
|
||||
}
|
||||
|
||||
unzipUrl(url: string, to: string): Promise<void> {
|
||||
const _this = this;
|
||||
|
||||
function unzipToFolder(path: string, blob: any, callback: (_: { result: 'success' | 'failure' }) => void) {
|
||||
JSZip.loadAsync(blob)
|
||||
.then(function (zip) {
|
||||
let numFiles = Object.keys(zip.files).length;
|
||||
let err = false;
|
||||
function fileCompleted(_success?: boolean) {
|
||||
numFiles--;
|
||||
if (numFiles === 0) {
|
||||
if (err) callback({ result: 'failure' });
|
||||
else callback({ result: 'success' });
|
||||
}
|
||||
}
|
||||
|
||||
Object.keys(zip.files).forEach(function (filename) {
|
||||
if (zip.files[filename].dir) {
|
||||
fileCompleted();
|
||||
return;
|
||||
} // Ignore dirs
|
||||
|
||||
let dest, buffer;
|
||||
|
||||
zip
|
||||
.file(filename)
|
||||
.async('nodebuffer')
|
||||
.then((_buffer) => {
|
||||
dest = nodePath.join(path, filename);
|
||||
buffer = _buffer;
|
||||
return _this.makeDirectory(nodePath.dirname(dest));
|
||||
})
|
||||
.then(() => {
|
||||
fs.writeFileSync(dest, buffer);
|
||||
fileCompleted();
|
||||
})
|
||||
.catch((e) => {
|
||||
err = e;
|
||||
fileCompleted(false);
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(function (e) {
|
||||
callback({ result: 'failure' });
|
||||
});
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
// Make sure the folder is empty
|
||||
const isEmpty = this.isDirectoryEmpty(to);
|
||||
if (!isEmpty) {
|
||||
reject({ result: 'failure', message: 'Folder must be empty' });
|
||||
return;
|
||||
}
|
||||
|
||||
// Load zip file from URL
|
||||
// @ts-ignore XMLHttpRequest
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', url, true);
|
||||
xhr.responseType = 'blob';
|
||||
xhr.onload = function (_e) {
|
||||
unzipToFolder(to, this.response, function (r) {
|
||||
if (r.result !== 'success') {
|
||||
reject({ result: 'failure', message: 'Failed to extract' });
|
||||
_this.removeDirRecursive(to);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve();
|
||||
});
|
||||
};
|
||||
xhr.send();
|
||||
});
|
||||
}
|
||||
|
||||
makeUniquePath(path: string): string {
|
||||
let _path = path;
|
||||
let count = 1;
|
||||
while (fs.existsSync(_path)) {
|
||||
_path = path + '-' + count;
|
||||
count++;
|
||||
}
|
||||
return _path;
|
||||
}
|
||||
}
|
||||
14
packages/noodl-platform-node/src/helper.ts
Normal file
14
packages/noodl-platform-node/src/helper.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { PlatformOS } from "@noodl/platform";
|
||||
|
||||
export function processPlatformToPlatformOS() {
|
||||
switch (process.platform) {
|
||||
default:
|
||||
return PlatformOS.Unknown;
|
||||
case "darwin":
|
||||
return PlatformOS.MacOS;
|
||||
case "win32":
|
||||
return PlatformOS.Windows;
|
||||
case "linux":
|
||||
return PlatformOS.Linux;
|
||||
}
|
||||
}
|
||||
8
packages/noodl-platform-node/src/index.ts
Normal file
8
packages/noodl-platform-node/src/index.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { setFileSystem, setPlatform, setStorage } from "@noodl/platform";
|
||||
import { FileSystemNode } from "./filesystem-node";
|
||||
import { PlatformNode } from "./platform-node";
|
||||
import { StorageNode } from "./storage-node";
|
||||
|
||||
setPlatform(new PlatformNode());
|
||||
setFileSystem(new FileSystemNode());
|
||||
setStorage(new StorageNode());
|
||||
101
packages/noodl-platform-node/src/platform-node.ts
Normal file
101
packages/noodl-platform-node/src/platform-node.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import open from 'open';
|
||||
import { addTrailingSlash, IPlatform, PlatformOS } from '@noodl/platform';
|
||||
|
||||
import { processPlatformToPlatformOS } from './helper';
|
||||
|
||||
function getAppPath() {
|
||||
if (fs.existsSync(path.join(process.cwd(), 'package.json'))) {
|
||||
return process.cwd();
|
||||
}
|
||||
|
||||
if (fs.existsSync(path.join(__dirname, 'package.json'))) {
|
||||
return __dirname;
|
||||
}
|
||||
|
||||
throw `[@noodl/platform] Cannot find package.json, to get the build version. (${__dirname})`;
|
||||
}
|
||||
|
||||
export class PlatformNode implements IPlatform {
|
||||
get name(): string {
|
||||
return 'Node';
|
||||
}
|
||||
|
||||
get os(): PlatformOS {
|
||||
return this._os;
|
||||
}
|
||||
|
||||
private _os: PlatformOS;
|
||||
private _userDataPath: string;
|
||||
private _tempPath: string;
|
||||
private _appPath: string;
|
||||
private _buildNumber: string;
|
||||
private _version: string;
|
||||
private _versionTag: string;
|
||||
private _versionId: string;
|
||||
|
||||
constructor() {
|
||||
const os = require('os');
|
||||
const roamingPath =
|
||||
process.env.APPDATA ||
|
||||
(process.platform == 'darwin' ? process.env.HOME + '/Library/Preferences' : process.env.HOME + '/.local/share');
|
||||
|
||||
this._userDataPath = path.join(roamingPath, 'Noodl');
|
||||
this._tempPath = addTrailingSlash(os.tmpdir());
|
||||
this._appPath = addTrailingSlash(getAppPath());
|
||||
|
||||
const packagePath = path.join(this._appPath, 'package.json');
|
||||
// Double check, just to be sure
|
||||
if (!fs.existsSync(packagePath)) {
|
||||
throw `[@noodl/platform] Cannot find package.json, to get the build version. ('${packagePath}')`;
|
||||
}
|
||||
|
||||
const packageJson = fs.readFileSync(packagePath, 'utf8');
|
||||
const packageContent = JSON.parse(packageJson);
|
||||
this._buildNumber = packageContent.buildNumber || 1;
|
||||
this._version = packageContent.version;
|
||||
this._versionId = packageContent.fullVersion;
|
||||
this._versionTag = packageContent.versionTag;
|
||||
|
||||
this._os = processPlatformToPlatformOS();
|
||||
}
|
||||
|
||||
getBuildNumber(): string | undefined {
|
||||
return this._buildNumber;
|
||||
}
|
||||
getFullVersion(): string {
|
||||
return this._versionId;
|
||||
}
|
||||
getVersion(): string {
|
||||
return this._version;
|
||||
}
|
||||
getVersionWithTag(): string {
|
||||
return this._versionTag ? `${this._version}-${this._versionTag}` : this._version;
|
||||
}
|
||||
|
||||
getUserDataPath(): string {
|
||||
return this._userDataPath;
|
||||
}
|
||||
getDocumentsPath(): string {
|
||||
throw new Error('Method not supported.');
|
||||
}
|
||||
getTempPath(): string {
|
||||
return this._tempPath;
|
||||
}
|
||||
getAppPath(): string {
|
||||
return this._appPath;
|
||||
}
|
||||
|
||||
async openExternal(url: string): Promise<void> {
|
||||
await open(url);
|
||||
}
|
||||
|
||||
copyToClipboard(value: string): Promise<void> {
|
||||
// I really don't want to install more "dependencies" when I don't think
|
||||
// they will be used...
|
||||
//
|
||||
// https://github.com/sindresorhus/clipboardy
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
}
|
||||
50
packages/noodl-platform-node/src/storage-node.ts
Normal file
50
packages/noodl-platform-node/src/storage-node.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { platform, filesystem, IStorage } from "@noodl/platform";
|
||||
|
||||
import path from "path";
|
||||
import mkdir from "mkdirp-sync";
|
||||
import rimraf from "rimraf";
|
||||
|
||||
function fileNameForKey(key: string) {
|
||||
const keyFileName = path.basename(key, ".json") + ".json";
|
||||
|
||||
// Prevent ENOENT and other similar errors when using
|
||||
// reserved characters in Windows filenames.
|
||||
// See: https://en.wikipedia.org/wiki/Filename#Reserved%5Fcharacters%5Fand%5Fwords
|
||||
const escapedFileName = encodeURIComponent(keyFileName);
|
||||
|
||||
const userDataPath = platform.getUserDataPath();
|
||||
return path.join(userDataPath, escapedFileName);
|
||||
}
|
||||
|
||||
export class StorageNode implements IStorage {
|
||||
async get(key: string): Promise<any> {
|
||||
try {
|
||||
const filename = fileNameForKey(key);
|
||||
const fileContent = await filesystem.readJson(filename);
|
||||
return fileContent;
|
||||
} catch (error) {
|
||||
// In some cases there is no json file
|
||||
// so we just return an empty object.
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
async set(key: string, data: { [key: string]: any }): Promise<void> {
|
||||
const filename = fileNameForKey(key);
|
||||
mkdir(path.dirname(filename));
|
||||
await filesystem.writeJson(filename, data);
|
||||
}
|
||||
|
||||
async remove(key: string): Promise<void> {
|
||||
var filename = fileNameForKey(key);
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
rimraf(filename, (error) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
83
packages/noodl-platform-node/tests/filesystem-list.test.ts
Normal file
83
packages/noodl-platform-node/tests/filesystem-list.test.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import { describe, expect } from "@jest/globals";
|
||||
|
||||
import { FileSystemNode } from "../src/filesystem-node";
|
||||
|
||||
describe("File System", function () {
|
||||
it("isDirectoryEmpty: false", async function () {
|
||||
// arrange
|
||||
const filesystem = new FileSystemNode();
|
||||
const sourcePath = filesystem.join(
|
||||
process.cwd(),
|
||||
"/tests/testfs/list_tests/folder1"
|
||||
);
|
||||
|
||||
// act
|
||||
const isEmpty = await filesystem.isDirectoryEmpty(sourcePath);
|
||||
|
||||
// assert
|
||||
expect(isEmpty).toBeFalsy();
|
||||
});
|
||||
|
||||
it("isDirectoryEmpty: true", async function () {
|
||||
// arrange
|
||||
const filesystem = new FileSystemNode();
|
||||
const sourcePath = filesystem.join(
|
||||
process.cwd(),
|
||||
"/tests/testfs/empty_folder"
|
||||
);
|
||||
|
||||
// We cant save empty folders in git
|
||||
await filesystem.makeDirectory(sourcePath);
|
||||
|
||||
// act
|
||||
const isEmpty = await filesystem.isDirectoryEmpty(sourcePath);
|
||||
|
||||
// assert
|
||||
expect(isEmpty).toBeTruthy();
|
||||
});
|
||||
|
||||
it("listDirectory", async function () {
|
||||
// arrange
|
||||
const filesystem = new FileSystemNode();
|
||||
const sourcePath = filesystem.join(
|
||||
process.cwd(),
|
||||
"/tests/testfs/list_tests"
|
||||
);
|
||||
|
||||
// act
|
||||
const items = await filesystem.listDirectory(sourcePath);
|
||||
|
||||
// assert
|
||||
expect(items.length).toBe(3);
|
||||
expect(items[0].name).toBe("file2.txt");
|
||||
expect(items[0].isDirectory).toBe(false);
|
||||
expect(items[1].name).toBe("folder1");
|
||||
expect(items[1].isDirectory).toBe(true);
|
||||
expect(items[2].name).toBe("folder2");
|
||||
expect(items[2].isDirectory).toBe(true);
|
||||
});
|
||||
|
||||
it("listDirectoryFiles", async function () {
|
||||
// arrange
|
||||
const filesystem = new FileSystemNode();
|
||||
const sourcePath = filesystem.join(
|
||||
process.cwd(),
|
||||
"/tests/testfs/list_tests"
|
||||
);
|
||||
|
||||
// act
|
||||
let items = await filesystem.listDirectoryFiles(sourcePath);
|
||||
items = items.sort((a, b) => (a.name > b.name ? 1 : -1));
|
||||
|
||||
// assert
|
||||
expect(items.length).toBe(4);
|
||||
expect(items[0].name).toBe("file1.txt");
|
||||
expect(items[0].isDirectory).toBe(false);
|
||||
expect(items[1].name).toBe("file2.txt");
|
||||
expect(items[1].isDirectory).toBe(false);
|
||||
expect(items[2].name).toBe("file3.txt");
|
||||
expect(items[2].isDirectory).toBe(false);
|
||||
expect(items[3].name).toBe("file4.txt");
|
||||
expect(items[3].isDirectory).toBe(false);
|
||||
});
|
||||
});
|
||||
59
packages/noodl-platform-node/tests/filesystem-read.test.ts
Normal file
59
packages/noodl-platform-node/tests/filesystem-read.test.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { describe, expect } from "@jest/globals";
|
||||
|
||||
import { FileSystemNode } from "../src/filesystem-node";
|
||||
|
||||
describe("File System", function () {
|
||||
it("readFile: text.txt", async function () {
|
||||
// arrange
|
||||
const filesystem = new FileSystemNode();
|
||||
const sourcePath = filesystem.join(
|
||||
process.cwd(),
|
||||
"/tests/testfs/file_types/text.txt"
|
||||
);
|
||||
|
||||
// act
|
||||
const content = await filesystem.readFile(sourcePath);
|
||||
|
||||
// assert
|
||||
expect(content).toBe("Hello World");
|
||||
});
|
||||
|
||||
it("readFile not found", async function () {
|
||||
// arrange
|
||||
const filesystem = new FileSystemNode();
|
||||
const sourcePath = filesystem.join(
|
||||
process.cwd(),
|
||||
"/tests/testfs/file_types/not_found.txt"
|
||||
);
|
||||
|
||||
// act & assert
|
||||
await expect(() => filesystem.readFile(sourcePath)).rejects.toThrow();
|
||||
});
|
||||
|
||||
it("readJson: json.json", async function () {
|
||||
// arrange
|
||||
const filesystem = new FileSystemNode();
|
||||
const sourcePath = filesystem.join(
|
||||
process.cwd(),
|
||||
"/tests/testfs/file_types/json.json"
|
||||
);
|
||||
|
||||
// act
|
||||
const content = await filesystem.readJson(sourcePath);
|
||||
|
||||
// assert
|
||||
expect(content).toEqual({ hello: "world" });
|
||||
});
|
||||
|
||||
it("readJson not found", async function () {
|
||||
// arrange
|
||||
const filesystem = new FileSystemNode();
|
||||
const sourcePath = filesystem.join(
|
||||
process.cwd(),
|
||||
"/tests/testfs/file_types/not_found.json"
|
||||
);
|
||||
|
||||
// act & assert
|
||||
await expect(() => filesystem.readJson(sourcePath)).rejects.toThrow();
|
||||
});
|
||||
});
|
||||
104
packages/noodl-platform-node/tests/filesystem.test.ts
Normal file
104
packages/noodl-platform-node/tests/filesystem.test.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
import { describe, expect } from '@jest/globals';
|
||||
|
||||
import { FileSystemNode } from '../src/filesystem-node';
|
||||
import { PlatformNode } from '../src/platform-node';
|
||||
|
||||
describe('File System', function () {
|
||||
// TODO: Skipped because the folder contained package.json, which was picked up by lerna.
|
||||
xit('can sync dirs', async function () {
|
||||
const platform = new PlatformNode();
|
||||
const filesystem = new FileSystemNode();
|
||||
|
||||
const tempDir = filesystem.join(platform.getTempPath(), 'noodlunittests-filesystem-' + Date.now());
|
||||
|
||||
const destPath = filesystem.join(tempDir, 'dst1');
|
||||
const sourcePath = filesystem.join(process.cwd(), '/tests/testfs/fs_sync_dir_tests/dst1');
|
||||
|
||||
await filesystem.makeDirectory(tempDir);
|
||||
await filesystem.copyFolder(sourcePath, destPath);
|
||||
|
||||
const files = {
|
||||
'/dst1/popout-will-be-removed.svg': true,
|
||||
'/dst1/should-be-removed/test.js': true,
|
||||
'/dst1/project.json': true,
|
||||
'/dst1/loginsplash.jpg': false,
|
||||
'/dst1/test.js': false,
|
||||
'/dst1/test/ajax-loader.gif': false,
|
||||
'/dst1/one/delete-me/Roboto-Black.ttf': true,
|
||||
'/dst1/one/two/loginsplash2.jpg': false
|
||||
};
|
||||
|
||||
Object.keys(files).forEach((file) => {
|
||||
const filePath = filesystem.join(tempDir, file);
|
||||
const fileExists = filesystem.exists(filePath);
|
||||
|
||||
expect(fileExists).toBe(files[file]);
|
||||
});
|
||||
});
|
||||
|
||||
// TODO: Skipped because the folder contained package.json, which was picked up by lerna.
|
||||
xit('can remove dirs without a slash ending', async function () {
|
||||
const platform = new PlatformNode();
|
||||
const filesystem = new FileSystemNode();
|
||||
|
||||
const tempDir = filesystem.join(platform.getTempPath(), 'noodlunittests-filesystem-' + Date.now());
|
||||
const sourcePath = filesystem.join(process.cwd(), '/tests/testfs/fs_sync_dir_tests/dst1');
|
||||
|
||||
await filesystem.makeDirectory(tempDir);
|
||||
await filesystem.copyFolder(sourcePath, tempDir);
|
||||
|
||||
filesystem.removeDirRecursive(tempDir);
|
||||
|
||||
expect(filesystem.exists(tempDir)).toBe(false);
|
||||
});
|
||||
|
||||
// TODO: Skipped because the folder contained package.json, which was picked up by lerna.
|
||||
xit('can remove dirs with a slash ending', async function () {
|
||||
const platform = new PlatformNode();
|
||||
const filesystem = new FileSystemNode();
|
||||
|
||||
const tempDir = filesystem.join(platform.getTempPath(), 'noodlunittests-filesystem-' + Date.now()) + '/';
|
||||
const sourcePath = filesystem.join(process.cwd(), '/tests/testfs/fs_sync_dir_tests/dst1');
|
||||
|
||||
await filesystem.makeDirectory(tempDir);
|
||||
await filesystem.copyFolder(sourcePath, tempDir);
|
||||
|
||||
filesystem.removeDirRecursive(tempDir);
|
||||
|
||||
expect(filesystem.exists(tempDir)).toBe(false);
|
||||
});
|
||||
|
||||
// it("can copy dirs and ignore specific files", async function () {
|
||||
// const platform = new PlatformNode();
|
||||
// const filesystem = new FileSystemNode();
|
||||
//
|
||||
// const tempDir = filesystem.join(
|
||||
// platform.getTempPath(),
|
||||
// "noodlunittests-filesystem-" + Date.now()
|
||||
// );
|
||||
// const sourcePath = filesystem.join(
|
||||
// process.cwd(),
|
||||
// "/tests/testfs/fs_sync_dir_tests/dst1"
|
||||
// );
|
||||
//
|
||||
// await filesystem.makeDirectory(tempDir);
|
||||
// await filesystem.copyFolder(sourcePath, tempDir, {
|
||||
// filter(src) {
|
||||
// return !src.includes(path.sep + "test" + path.sep);
|
||||
// },
|
||||
// });
|
||||
//
|
||||
// expect(
|
||||
// filesystem.exists(filesystem.resolve(tempDir, "test/ajax-loader.gif"))
|
||||
// ).toBe(false);
|
||||
// expect(
|
||||
// filesystem.exists(filesystem.resolve(tempDir, "loginsplash.jpg"))
|
||||
// ).toBe(true);
|
||||
// expect(filesystem.exists(filesystem.resolve(tempDir, "project.json"))).toBe(
|
||||
// true
|
||||
// );
|
||||
// expect(filesystem.exists(filesystem.resolve(tempDir, "test.js"))).toBe(
|
||||
// true
|
||||
// );
|
||||
// });
|
||||
});
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"hello": "world"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
Hello World
|
||||
@@ -0,0 +1 @@
|
||||
Hello World
|
||||
3
packages/noodl-platform-node/tsconfig.json
Normal file
3
packages/noodl-platform-node/tsconfig.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json"
|
||||
}
|
||||
Reference in New Issue
Block a user