fs:exports & file names
This commit is contained in:
parent
365fe2c039
commit
a6280d442a
1
packages/fs/dist/file.js
vendored
1
packages/fs/dist/file.js
vendored
@ -118,7 +118,6 @@ const checkContentAsync = (path, mode, options) => {
|
||||
const writeAsync = async (path, stat, options) => {
|
||||
const mode = normalizeFileMode(stat.mode);
|
||||
return checkContentAsync(path, mode, options);
|
||||
//.then()
|
||||
};
|
||||
const touchAsync = (path, options) => {
|
||||
return writeASync(path, options.content !== undefined ? options.content : '', {
|
||||
|
||||
62
packages/fs/dist/index.d.ts
vendored
62
packages/fs/dist/index.d.ts
vendored
@ -1,61 +1 @@
|
||||
import { Options as AppendOptions } from './append.js';
|
||||
import { IOptions as DirOptions } from './dir.js';
|
||||
import { IOptions as FileOptions } from './file.js';
|
||||
import { IOptions as FindOptions } from './find.js';
|
||||
import { Options as InspectTreeOptions } from './inspect_tree.js';
|
||||
import { IWriteOptions } from './interfaces.js';
|
||||
import { ICopyOptions, INode, IInspectOptions } from './interfaces.js';
|
||||
import { ReadWriteDataType, TCopyResult, ENodeType, TDeleteResult } from './interfaces.js';
|
||||
export interface IJetpack {
|
||||
cwd(w?: any): IJetpack | string;
|
||||
path(): string;
|
||||
append(path: string, data: string | Buffer | object, options?: AppendOptions): void;
|
||||
appendAsync(path: string, data: string | Buffer | object, options?: AppendOptions): Promise<void>;
|
||||
copy(from: string, to: string, options?: ICopyOptions): void;
|
||||
copyAsync(from: string, to: string, options?: ICopyOptions): Promise<TCopyResult>;
|
||||
createWriteStream(path: string, options?: {
|
||||
flags?: string;
|
||||
encoding?: string;
|
||||
fd?: number;
|
||||
mode?: number;
|
||||
autoClose?: boolean;
|
||||
start?: number;
|
||||
}): any;
|
||||
createReadStream(path: string, options?: {
|
||||
flags?: string;
|
||||
encoding?: string;
|
||||
fd?: number;
|
||||
mode?: number;
|
||||
autoClose?: boolean;
|
||||
start?: number;
|
||||
end?: number;
|
||||
}): any;
|
||||
dir(path: string, criteria?: DirOptions): IJetpack;
|
||||
dirAsync(path: string, criteria?: DirOptions): Promise<IJetpack>;
|
||||
exists(path: string): boolean | string;
|
||||
existsAsync(path: string): Promise<boolean | string | ENodeType>;
|
||||
file(path: string, criteria?: FileOptions): void;
|
||||
fileAsync(path: string, criteria?: FileOptions): Promise<null>;
|
||||
find(startPath: string, options: FindOptions): string[];
|
||||
findAsync(startPath: string, options: FindOptions): Promise<string[]>;
|
||||
inspect(path: string, fieldsToInclude: IInspectOptions): INode;
|
||||
inspectAsync(path: string, fieldsToInclude: IInspectOptions): Promise<INode>;
|
||||
inspectTree(path: string, options?: InspectTreeOptions): INode;
|
||||
inspectTreeAsync(path: string, options?: InspectTreeOptions): Promise<INode>;
|
||||
list(path: string): string[];
|
||||
listAsync(path: string): Promise<string[]>;
|
||||
move(from: string, to: string): void;
|
||||
moveAsync(from: string, to: string): Promise<null>;
|
||||
read(path: string, returnAs?: string): ReadWriteDataType;
|
||||
readAsync(path: string, returnAs?: string): Promise<ReadWriteDataType>;
|
||||
remove(path: string): void;
|
||||
removeAsync(path: string): Promise<TDeleteResult>;
|
||||
rename(path: string, newName: string): void;
|
||||
renameAsync(path: string, newName: string): Promise<null>;
|
||||
symlink(symlinkValue: string, path: string): void;
|
||||
symlinkAsync(symlinkValue: string, path: string): Promise<void>;
|
||||
write(path: string, data: string | Buffer | object, options?: IWriteOptions): void;
|
||||
writeAsync(path: string, data: string | Buffer | object, options?: IWriteOptions): Promise<null>;
|
||||
}
|
||||
export declare const fs: (cwdPath?: string) => IJetpack;
|
||||
export default fs;
|
||||
export {};
|
||||
|
||||
48
packages/fs/dist/index.js
vendored
48
packages/fs/dist/index.js
vendored
@ -1,47 +1 @@
|
||||
import * as util from 'util';
|
||||
import * as pathUtil from 'path';
|
||||
// The Jetpack Context object.
|
||||
// It provides the public API, and resolves all paths regarding to
|
||||
// passed cwdPath, or default process.cwd() if cwdPath was not specified.
|
||||
export const fs = (cwdPath) => {
|
||||
const getCwdPath = function () {
|
||||
return cwdPath || process.cwd();
|
||||
};
|
||||
const cwd = function (w) {
|
||||
let args;
|
||||
let pathParts;
|
||||
// return current CWD if no arguments specified...
|
||||
if (arguments.length === 0) {
|
||||
return getCwdPath();
|
||||
}
|
||||
// ...create new CWD context otherwise
|
||||
args = Array.prototype.slice.call(arguments);
|
||||
pathParts = [getCwdPath()].concat(args);
|
||||
const res = fs(pathUtil.resolve.apply(null, pathParts));
|
||||
return res;
|
||||
};
|
||||
// resolves path to inner CWD path of this jetpack instance
|
||||
const resolvePath = function (path) {
|
||||
return pathUtil.resolve(getCwdPath(), path);
|
||||
};
|
||||
const getPath = function () {
|
||||
// add CWD base path as first element of arguments array
|
||||
Array.prototype.unshift.call(arguments, getCwdPath());
|
||||
return pathUtil.resolve.apply(null, arguments);
|
||||
};
|
||||
const normalizeOptions = function (options) {
|
||||
return options || { cwd: getCwdPath() };
|
||||
};
|
||||
// API
|
||||
const api = {};
|
||||
if (util.inspect['custom'] !== undefined) {
|
||||
// Without this console.log(jetpack) throws obscure error. Details:
|
||||
// https://github.com/szwacz/fs-jetpack/issues/29
|
||||
// https://nodejs.org/api/util.html#util_custom_inspection_functions_on_objects
|
||||
api[util.inspect['custom']] = function () {
|
||||
return getCwdPath();
|
||||
};
|
||||
}
|
||||
return api;
|
||||
};
|
||||
export default fs;
|
||||
export {};
|
||||
|
||||
6
packages/fs/dist/utils/index.d.ts
vendored
Normal file
6
packages/fs/dist/utils/index.d.ts
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
export * from "./wildcard.js";
|
||||
export * from "./paths.js";
|
||||
export * from "./name.js";
|
||||
export * from "./matcher.js";
|
||||
export * from "./mime_match.js";
|
||||
export * from "./validate.js";
|
||||
6
packages/fs/dist/utils/index.js
vendored
Normal file
6
packages/fs/dist/utils/index.js
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
export * from "./wildcard.js";
|
||||
export * from "./paths.js";
|
||||
export * from "./name.js";
|
||||
export * from "./matcher.js";
|
||||
export * from "./mime_match.js";
|
||||
export * from "./validate.js";
|
||||
31
packages/fs/dist/utils/name.d.ts
vendored
Normal file
31
packages/fs/dist/utils/name.d.ts
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
export declare enum E_FilenameError {
|
||||
NONE = 0,// No error
|
||||
EMPTY = 1,// Empty or whitespace-only filename
|
||||
INVALID_CHAR = 2,// Contains invalid characters
|
||||
RESERVED_NAME = 4,// Matches a reserved system name
|
||||
LEADING_TRAILING_SPACE = 8,// Starts/ends with space
|
||||
ONLY_DOTS = 16
|
||||
}
|
||||
export interface I_SanitizeOptions {
|
||||
lowercase?: boolean;
|
||||
whitespace?: boolean;
|
||||
}
|
||||
export interface I_ValidationResult {
|
||||
isValid: boolean;
|
||||
errorFlags: number;
|
||||
}
|
||||
/**
|
||||
* Sanitizes a filename by removing invalid characters and normalizing it.
|
||||
*
|
||||
* @param filename - The original filename
|
||||
* @param options - Configuration options
|
||||
* @returns Sanitized filename
|
||||
*/
|
||||
export declare function sanitizeFilename(filename?: string, options?: I_SanitizeOptions): string;
|
||||
/**
|
||||
* Validates a filename and returns a flag-based error representation.
|
||||
*
|
||||
* @param filename - The filename to validate
|
||||
* @returns I_ValidationResult object with bitwise error flags
|
||||
*/
|
||||
export declare function validateFilename(filename: string): I_ValidationResult;
|
||||
81
packages/fs/dist/utils/name.js
vendored
Normal file
81
packages/fs/dist/utils/name.js
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
const RESERVED_NAMES = new Set([
|
||||
"con", "prn", "aux", "nul",
|
||||
"com1", "com2", "com3", "com4", "com5", "com6", "com7", "com8", "com9",
|
||||
"lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9"
|
||||
]);
|
||||
// Validation error flags (bitwise)
|
||||
export var E_FilenameError;
|
||||
(function (E_FilenameError) {
|
||||
E_FilenameError[E_FilenameError["NONE"] = 0] = "NONE";
|
||||
E_FilenameError[E_FilenameError["EMPTY"] = 1] = "EMPTY";
|
||||
E_FilenameError[E_FilenameError["INVALID_CHAR"] = 2] = "INVALID_CHAR";
|
||||
E_FilenameError[E_FilenameError["RESERVED_NAME"] = 4] = "RESERVED_NAME";
|
||||
E_FilenameError[E_FilenameError["LEADING_TRAILING_SPACE"] = 8] = "LEADING_TRAILING_SPACE";
|
||||
E_FilenameError[E_FilenameError["ONLY_DOTS"] = 16] = "ONLY_DOTS"; // Filename is only "." or ".."
|
||||
})(E_FilenameError || (E_FilenameError = {}));
|
||||
/**
|
||||
* Sanitizes a filename by removing invalid characters and normalizing it.
|
||||
*
|
||||
* @param filename - The original filename
|
||||
* @param options - Configuration options
|
||||
* @returns Sanitized filename
|
||||
*/
|
||||
export function sanitizeFilename(filename = "", options = { lowercase: false, whitespace: false }) {
|
||||
const { lowercase = false, whitespace = true } = options;
|
||||
// Normalize Unicode (removes diacritics)
|
||||
let sanitized = filename
|
||||
.normalize("NFD")
|
||||
.replace(/[\u0300-\u036f]/g, "") // Strip accents
|
||||
.replace(/[^\w.\- ]/g, "") // Keep only alphanumeric, dot, hyphen, underscore, and space
|
||||
.trim(); // Remove leading/trailing spaces
|
||||
// Replace spaces with underscores if enabled
|
||||
if (whitespace) {
|
||||
sanitized = sanitized.replace(/\s+/g, "_");
|
||||
}
|
||||
// Convert to lowercase if enabled
|
||||
if (lowercase) {
|
||||
sanitized = sanitized.toLowerCase();
|
||||
}
|
||||
// Prevent reserved names (Windows)
|
||||
if (RESERVED_NAMES.has(sanitized.toLowerCase())) {
|
||||
return sanitized + "_safe";
|
||||
}
|
||||
// Prevent filenames that are just dots or empty
|
||||
if (!sanitized || sanitized === "." || sanitized === "..") {
|
||||
return "untitled";
|
||||
}
|
||||
return sanitized;
|
||||
}
|
||||
/**
|
||||
* Validates a filename and returns a flag-based error representation.
|
||||
*
|
||||
* @param filename - The filename to validate
|
||||
* @returns I_ValidationResult object with bitwise error flags
|
||||
*/
|
||||
export function validateFilename(filename) {
|
||||
let errorFlags = E_FilenameError.NONE;
|
||||
const trimmed = filename.trim();
|
||||
if (!trimmed) {
|
||||
errorFlags |= E_FilenameError.EMPTY;
|
||||
}
|
||||
// Detect invalid characters (only allow alphanumeric, dot, hyphen, underscore)
|
||||
if (/[^a-zA-Z0-9._-]/.test(filename)) {
|
||||
errorFlags |= E_FilenameError.INVALID_CHAR;
|
||||
}
|
||||
// Prevent reserved filenames (Windows)
|
||||
if (RESERVED_NAMES.has(filename.toLowerCase())) {
|
||||
errorFlags |= E_FilenameError.RESERVED_NAME;
|
||||
}
|
||||
// Check for leading or trailing spaces
|
||||
if (/^\s|\s$/.test(filename)) {
|
||||
errorFlags |= E_FilenameError.LEADING_TRAILING_SPACE;
|
||||
}
|
||||
// Prevent filenames that are only "." or ".."
|
||||
if (filename === "." || filename === "..") {
|
||||
errorFlags |= E_FilenameError.ONLY_DOTS;
|
||||
}
|
||||
return {
|
||||
isValid: errorFlags === E_FilenameError.NONE,
|
||||
errorFlags
|
||||
};
|
||||
}
|
||||
@ -7,6 +7,14 @@
|
||||
"access": "public"
|
||||
},
|
||||
"exports": {
|
||||
"./utils": {
|
||||
"import": "./dist/utils/index.js",
|
||||
"require": "./dist/utils/index.cjs"
|
||||
},
|
||||
"./append": {
|
||||
"import": "./dist/append.js",
|
||||
"require": "./dist/append.cjs"
|
||||
},
|
||||
"./write": {
|
||||
"import": "./dist/write.js",
|
||||
"require": "./dist/write.cjs"
|
||||
|
||||
@ -136,7 +136,6 @@ const checkContentAsync = (path: string, mode: string, options: IOptions):Promis
|
||||
const writeAsync = async (path: string, stat: Stats, options: IOptions): Promise<any> => {
|
||||
const mode = normalizeFileMode(stat.mode);
|
||||
return checkContentAsync(path, mode, options)
|
||||
//.then()
|
||||
}
|
||||
|
||||
const touchAsync = (path: string, options: IOptions) => {
|
||||
|
||||
@ -29,111 +29,3 @@ import * as stats from './stats.js'
|
||||
import { ICopyOptions, INode, IInspectOptions } from './interfaces.js'
|
||||
import { ReadWriteDataType, TCopyResult, ENodeType, TDeleteResult } from './interfaces.js'
|
||||
|
||||
|
||||
export interface IJetpack {
|
||||
cwd(w?: any): IJetpack | string;
|
||||
path(): string;
|
||||
append(path: string, data: string | Buffer | object, options?: AppendOptions): void;
|
||||
appendAsync(path: string, data: string | Buffer | object, options?: AppendOptions): Promise<void>;
|
||||
copy(from: string, to: string, options?: ICopyOptions): void;
|
||||
copyAsync(from: string, to: string, options?: ICopyOptions): Promise<TCopyResult>;
|
||||
createWriteStream(path: string, options?: {
|
||||
flags?: string;
|
||||
encoding?: string;
|
||||
fd?: number;
|
||||
mode?: number;
|
||||
autoClose?: boolean;
|
||||
start?: number;
|
||||
}): any;
|
||||
createReadStream(path: string, options?: {
|
||||
flags?: string;
|
||||
encoding?: string;
|
||||
fd?: number;
|
||||
mode?: number;
|
||||
autoClose?: boolean;
|
||||
start?: number;
|
||||
end?: number;
|
||||
}): any;
|
||||
dir(path: string, criteria?: DirOptions): IJetpack;
|
||||
dirAsync(path: string, criteria?: DirOptions): Promise<IJetpack>;
|
||||
exists(path: string): boolean | string;
|
||||
existsAsync(path: string): Promise<boolean | string | ENodeType>;
|
||||
file(path: string, criteria?: FileOptions): void;
|
||||
fileAsync(path: string, criteria?: FileOptions): Promise<null>;
|
||||
find(startPath: string, options: FindOptions): string[];
|
||||
findAsync(startPath: string, options: FindOptions): Promise<string[]>;
|
||||
inspect(path: string, fieldsToInclude: IInspectOptions): INode;
|
||||
inspectAsync(path: string, fieldsToInclude: IInspectOptions): Promise<INode>;
|
||||
inspectTree(path: string, options?: InspectTreeOptions): INode;
|
||||
inspectTreeAsync(path: string, options?: InspectTreeOptions): Promise<INode>;
|
||||
list(path: string): string[];
|
||||
listAsync(path: string): Promise<string[]>;
|
||||
move(from: string, to: string): void;
|
||||
moveAsync(from: string, to: string): Promise<null>;
|
||||
read(path: string, returnAs?: string): ReadWriteDataType;
|
||||
readAsync(path: string, returnAs?: string): Promise<ReadWriteDataType>;
|
||||
remove(path: string): void;
|
||||
removeAsync(path: string): Promise<TDeleteResult>;
|
||||
rename(path: string, newName: string): void;
|
||||
renameAsync(path: string, newName: string): Promise<null>;
|
||||
symlink(symlinkValue: string, path: string): void;
|
||||
symlinkAsync(symlinkValue: string, path: string): Promise<void>;
|
||||
write(path: string, data: string | Buffer | object, options?: IWriteOptions): void;
|
||||
writeAsync(path: string, data: string | Buffer | object, options?: IWriteOptions): Promise<null>;
|
||||
}
|
||||
// The Jetpack Context object.
|
||||
// It provides the public API, and resolves all paths regarding to
|
||||
// passed cwdPath, or default process.cwd() if cwdPath was not specified.
|
||||
export const fs = (cwdPath?: string): IJetpack => {
|
||||
const getCwdPath = function () {
|
||||
return cwdPath || process.cwd();
|
||||
};
|
||||
|
||||
const cwd = function (w?: any): IJetpack | string {
|
||||
let args;
|
||||
let pathParts;
|
||||
|
||||
// return current CWD if no arguments specified...
|
||||
if (arguments.length === 0) {
|
||||
return getCwdPath();
|
||||
}
|
||||
|
||||
// ...create new CWD context otherwise
|
||||
args = Array.prototype.slice.call(arguments);
|
||||
pathParts = [getCwdPath()].concat(args);
|
||||
const res = fs(pathUtil.resolve.apply(null, pathParts));
|
||||
return res;
|
||||
};
|
||||
|
||||
// resolves path to inner CWD path of this jetpack instance
|
||||
const resolvePath = function (path: string): string {
|
||||
return pathUtil.resolve(getCwdPath(), path);
|
||||
};
|
||||
|
||||
const getPath = function (): string {
|
||||
// add CWD base path as first element of arguments array
|
||||
Array.prototype.unshift.call(arguments, getCwdPath());
|
||||
return pathUtil.resolve.apply(null, arguments);
|
||||
};
|
||||
|
||||
const normalizeOptions = function (options: { cwd?: string }): any {
|
||||
return options || { cwd: getCwdPath() };
|
||||
};
|
||||
|
||||
// API
|
||||
const api: any = {
|
||||
|
||||
};
|
||||
if ((util.inspect as any)['custom'] !== undefined) {
|
||||
// Without this console.log(jetpack) throws obscure error. Details:
|
||||
// https://github.com/szwacz/fs-jetpack/issues/29
|
||||
// https://nodejs.org/api/util.html#util_custom_inspection_functions_on_objects
|
||||
(api as any)[(util.inspect as any)['custom']] = function () {
|
||||
return getCwdPath();
|
||||
};
|
||||
}
|
||||
|
||||
return api;
|
||||
};
|
||||
|
||||
export default fs;
|
||||
|
||||
@ -1,11 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
import * as cli from 'yargs'
|
||||
|
||||
const argv: any = cli.argv
|
||||
|
||||
if (argv.h || argv.help) {
|
||||
cli.showHelp();
|
||||
process.exit();
|
||||
} else if (argv.v || argv.version) {
|
||||
process.exit();
|
||||
}
|
||||
@ -8,3 +8,4 @@ export function isDotFile(str: string) {
|
||||
const last = str.lastIndexOf('/');
|
||||
return last !== -1 ? str.charCodeAt(last + 1) === 46 /* . */ : false;
|
||||
}
|
||||
|
||||
6
packages/fs/src/utils/index.ts
Normal file
6
packages/fs/src/utils/index.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export * from "./wildcard.js"
|
||||
export * from "./paths.js"
|
||||
export * from "./name.js"
|
||||
export * from "./matcher.js"
|
||||
export * from "./mime_match.js"
|
||||
export * from "./validate.js"
|
||||
106
packages/fs/src/utils/name.ts
Normal file
106
packages/fs/src/utils/name.ts
Normal file
@ -0,0 +1,106 @@
|
||||
const RESERVED_NAMES = new Set([
|
||||
"con", "prn", "aux", "nul",
|
||||
"com1", "com2", "com3", "com4", "com5", "com6", "com7", "com8", "com9",
|
||||
"lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9"
|
||||
]);
|
||||
|
||||
// Validation error flags (bitwise)
|
||||
export enum E_FilenameError {
|
||||
NONE = 0, // No error
|
||||
EMPTY = 1 << 0, // Empty or whitespace-only filename
|
||||
INVALID_CHAR = 1 << 1, // Contains invalid characters
|
||||
RESERVED_NAME = 1 << 2, // Matches a reserved system name
|
||||
LEADING_TRAILING_SPACE = 1 << 3, // Starts/ends with space
|
||||
ONLY_DOTS = 1 << 4 // Filename is only "." or ".."
|
||||
}
|
||||
|
||||
export interface I_SanitizeOptions {
|
||||
lowercase?: boolean; // Convert to lowercase (default: false)
|
||||
whitespace?: boolean; // Replace spaces with underscores (default: true)
|
||||
}
|
||||
|
||||
export interface I_ValidationResult {
|
||||
isValid: boolean; // Overall validation status
|
||||
errorFlags: number; // Bitwise error representation
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes a filename by removing invalid characters and normalizing it.
|
||||
*
|
||||
* @param filename - The original filename
|
||||
* @param options - Configuration options
|
||||
* @returns Sanitized filename
|
||||
*/
|
||||
export function sanitizeFilename(filename: string = "", options: I_SanitizeOptions = { lowercase: false, whitespace: false }): string {
|
||||
|
||||
const { lowercase = false, whitespace = true } = options;
|
||||
|
||||
// Normalize Unicode (removes diacritics)
|
||||
let sanitized = filename
|
||||
.normalize("NFD")
|
||||
.replace(/[\u0300-\u036f]/g, "") // Strip accents
|
||||
.replace(/[^\w.\- ]/g, "") // Keep only alphanumeric, dot, hyphen, underscore, and space
|
||||
.trim(); // Remove leading/trailing spaces
|
||||
|
||||
// Replace spaces with underscores if enabled
|
||||
if (whitespace) {
|
||||
sanitized = sanitized.replace(/\s+/g, "_");
|
||||
}
|
||||
|
||||
// Convert to lowercase if enabled
|
||||
if (lowercase) {
|
||||
sanitized = sanitized.toLowerCase();
|
||||
}
|
||||
|
||||
// Prevent reserved names (Windows)
|
||||
if (RESERVED_NAMES.has(sanitized.toLowerCase())) {
|
||||
return sanitized + "_safe";
|
||||
}
|
||||
|
||||
// Prevent filenames that are just dots or empty
|
||||
if (!sanitized || sanitized === "." || sanitized === "..") {
|
||||
return "untitled";
|
||||
}
|
||||
|
||||
return sanitized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a filename and returns a flag-based error representation.
|
||||
*
|
||||
* @param filename - The filename to validate
|
||||
* @returns I_ValidationResult object with bitwise error flags
|
||||
*/
|
||||
export function validateFilename(filename: string): I_ValidationResult {
|
||||
let errorFlags = E_FilenameError.NONE;
|
||||
const trimmed = filename.trim();
|
||||
|
||||
if (!trimmed) {
|
||||
errorFlags |= E_FilenameError.EMPTY;
|
||||
}
|
||||
|
||||
// Detect invalid characters (only allow alphanumeric, dot, hyphen, underscore)
|
||||
if (/[^a-zA-Z0-9._-]/.test(filename)) {
|
||||
errorFlags |= E_FilenameError.INVALID_CHAR;
|
||||
}
|
||||
|
||||
// Prevent reserved filenames (Windows)
|
||||
if (RESERVED_NAMES.has(filename.toLowerCase())) {
|
||||
errorFlags |= E_FilenameError.RESERVED_NAME;
|
||||
}
|
||||
|
||||
// Check for leading or trailing spaces
|
||||
if (/^\s|\s$/.test(filename)) {
|
||||
errorFlags |= E_FilenameError.LEADING_TRAILING_SPACE;
|
||||
}
|
||||
|
||||
// Prevent filenames that are only "." or ".."
|
||||
if (filename === "." || filename === "..") {
|
||||
errorFlags |= E_FilenameError.ONLY_DOTS;
|
||||
}
|
||||
|
||||
return {
|
||||
isValid: errorFlags === E_FilenameError.NONE,
|
||||
errorFlags
|
||||
};
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user