nodejs: added fs as NJS_FS:TNJSFS and path as NJS_Path: TNJSPath

This commit is contained in:
mattias 2018-10-30 23:14:56 +00:00
parent c2de3046cf
commit 658876f00d

View File

@ -18,7 +18,7 @@ unit NodeJSFS;
interface
uses
JS, SysUtils;
JS, NodeJS, SysUtils;
var
DirectorySeparator: char = '/';
@ -27,13 +27,14 @@ var
PathSeparator: char = ':';
AllowDirectorySeparators: set of char = ['\','/'];
AllowDriveSeparators: set of char = [];
AllDirectorySeparators: set of char = ['\','/'];
AllFilesMask: string = '*';
//MaxPathLen: integer = 4096;
MaxPathLen: integer = 4096;
PathDelim: char = '/'; // = DirectorySeparator;
DriveDelim: string = ''; // = DriveSeparator;
PathSep: char = ':'; // = PathSeparator;
//MAX_PATH: integer = 4096; // = MaxPathLen;
PathDelim: char = '/'; // FPC = DirectorySeparator
DriveDelim: string = ''; // FPC = DriveSeparator
PathSep: char = ':';// FPC = PathSeparator
MAX_PATH: integer = 4096; // FPC = MaxPathLen;
const
//faReadOnly = 1;
@ -43,90 +44,570 @@ const
faDirectory = 16;
//faArchive = 32;
function FileExists(Filename: string): boolean;
function DirectoryExists(Filename: string): boolean;
function ExtractFilePath(Filename: string): string;
function ExtractFileName(Filename: string): string;
function ExtractFileExt(Filename: string): string;
function SetDirSeparators(Filename: string): string;
function ExpandFileName(Filename: string): string;
function IncludeTrailingPathDelimiter(Filename: string): string;
function ChangeFileExt(Filename, NewExt: string): string;
function GetCurrentDir: string;
function FileExists(const Filename: string): boolean;
function DirectoryExists(const Filename: string): boolean;
function ExtractFilePath(const Filename: string): string;
function ExtractFileName(const Filename: string): string;
function ExtractFileExt(const Filename: string): string;
function SetDirSeparators(const Filename: string): string;
function ExpandFileName(const Filename: string): string;
function ExcludeTrailingPathDelimiter(const Filename: string): string;
function IncludeTrailingPathDelimiter(const Filename: string): string;
function ChangeFileExt(const Filename, NewExt: string): string;
function DeleteFile(const Filename: String): Boolean;
function RenameFile(const OldName, NewName: String): Boolean;
type
TSearchRec = record
Time : Longint;
Size : nativeint;
Attr : Longint;
Name : String;
ExcludeAttr : Longint;
FindHandle : Pointer;
//Mode : TMode;
//FindData : TFindData;
end;
function FindFirst(const Path: String; Attr : Longint; out Rslt: TSearchRec): Longint;
function FindNext(var Rslt: TSearchRec): Longint;
procedure FindClose(var F: TSearchrec);
const
S_IRUSR = &400; // read by owner
S_IWUSR = &200; // write by owner
S_IXUSR = &100; // execute/search by owner
S_IRGRP = &40; // read by group
S_IWGRP = &20; // write by group
S_IXGRP = &10; // execute/search by group
S_IROTH = &4; // read by others
S_IWOTH = &2; // write by others
S_IXOTH = &1; // execute/search by others
F_OK: nativeint; external name 'fs.constants.F_OK'; // file visible
R_OK: nativeint; external name 'fs.constants.R_OK'; // file readable
W_OK: nativeint; external name 'fs.constants.W_OK'; // file writable
X_OK: nativeint; external name 'fs.constants.X_OK'; // file executable
COPYFILE_EXCL: nativeint; external name 'fs.constants.COPYFILE_EXCL';
COPYFILE_FICLONE: NativeInt; external name 'fs.constants.COPYFILE_FICLONE';
COPYFILE_FICLONE_FORCE: NativeInt; external name 'fs.constants.COPYFILE_FICLONE_FORCE';
type
TNJSFileDesc = JSValue; // integer or nil
TNJSFileMode = NativeInt;
{ TNJSDirEnt }
TNJSDirEnt = class external name 'fs.Dirent'
private
FName: string; external name 'name';
public
function isBlockDevice: boolean;
function isCharacterDevice: boolean;
function isDirectory: boolean;
function isFIFO: boolean;
function isFile: boolean;
function isSocket: boolean;
function isSymbolicLink: boolean;
property Name: string read FName;
end;
TNJSDirEntArray = array of TNJSDirEnt;
{ TNJSStats }
TNJSStats = class external name 'fs.Stats'
private
public
dev: NativeInt;
ino: NativeInt;
mode: TNJSFileMode;
nlink: NativeInt;
uid: NativeInt;
gid: NativeInt;
rdev: NativeInt;
size: NativeInt;
blksize: NativeInt;
blocks: NativeInt;
atimeMs: Double;
mtimeMs: Double;
ctimeMs: Double;
birthtimeMs: Double;
atime: TJSDate;
mtime: TJSDate;
ctime: TJSDate;
birthtime: TJSDate;
function isBlockDevice: boolean;
function isCharacterDevice: boolean;
function isDirectory: boolean;
function isFIFO: boolean;
function isFile: boolean;
function isSocket: boolean;
function isSymbolicLink: boolean;
end;
{ TNJSStreamReadable }
TNJSStreamReadable = class external name 'stream.Readable'
private
FReadableHighWaterMark: NativeInt external name 'readableHighWaterMark';
FReadableLength: NativeInt external name 'readableLength';
public
function destroy(Error: TJSError): TNJSStreamReadable;
function isPaused: boolean;
function pause: TNJSStreamReadable;
// pipe(destination[, options])
function read: jsvalue; // string | buffer | nil | any
function read(size: nativeint): jsvalue; // string | buffer | nil | any
property ReadableHighWaterMark: NativeInt read FReadableHighWaterMark;
property ReadableLength: NativeInt read FReadableLength;
function resume: TNJSStreamReadable;
function setEncoding(Encoding: string): TNJSStreamReadable;
// unpipe([destination])
// unshift(chunk)
// wrap(stream)
end;
{ TNJSReadStream }
TNJSReadStream = class external name 'fs.ReadStream'(TNJSStreamReadable)
private
fBytesRead: NativeInt external name 'bytesRead';
FPath: string external name 'path';
public
property BytesRead: NativeInt read fBytesRead;
property Path: string read FPath;
end;
TNJSStreamWritableEndHandler = reference to procedure;
{ TNJSStreamWritable }
TNJSStreamWritable = class external name 'stream.Writable'
private
FwritableHighWaterMark: nativeint external name 'writableHighWaterMark';
FwritableLength: nativeint external name 'writableLength';
public
procedure cork;
function destroy(Error: TJSError): TNJSStreamWritable;
function _end(chunk: string): TNJSStreamWritable; external name 'end';
function _end(chunk: string; encoding: string;
callback: TNJSStreamWritableEndHandler = nil): TNJSStreamWritable; external name 'end';
function setDefaultEncoding(Encoding: string): TNJSStreamWritable;
procedure uncork;
property writableHighWaterMark: NativeInt read FwritableHighWaterMark;
property writableLength: nativeint read FwritableLength;
function write(chunk: string): boolean;
function write(chunk: string; encoding: string;
callback: TNJSStreamWritableEndHandler): boolean;
end;
{ TNJSWriteStream }
TNJSWriteStream = class external name 'fs.WriteStream'(TNJSStreamWritable)
private
FBytesWritten: NativeInt external name 'bytesWritten';
FPath: string external name 'path';
public
property BytesWritten: NativeInt read FBytesWritten;
property Path: string read FPath;
end;
{ TNJSAppendFileOpts }
TNJSAppendFileOpts = record
Encoding: string external name 'encoding'; // default nil
Mode: TNJSFileMode external name 'mode'; // default &666
Flag: string external name 'flag'; // default 'a'
end;
{ TNJSReadStreamOpts }
TNJSReadStreamOpts = record
Flags: string external name 'flags'; // default 'r'
Encoding: string external name 'encoding'; // default nil
FD: TNJSFileDesc external name 'fd'; // default nil
Mode: TNJSFileMode external name 'mode'; // default &666
AutoClose: boolean external name 'autoclose'; // default true
StartByte: NativeInt external name 'start';
EndByte: NativeInt external name 'end'; // default Infinity
HighWaterMark: NativeInt external name 'highWaterMark'; // default 64*1024
end;
{ TNJSWriteStreamOpts }
TNJSWriteStreamOpts = record
Flags: string external name 'flags'; // default 'w'
Encoding: string external name 'encoding'; // default 'utf8'
FD: TNJSFileDesc external name 'fd'; // default nil
Mode: TNJSFileMode external name 'mode'; // default &666
AutoClose: boolean external name 'autoclose'; // default true
Start: NativeInt external name 'start';
end;
{ TNJSStatOpts }
TNJSStatOpts = record
bigint: boolean;
end;
{ TNJSMkdirOpts }
TNJSMkdirOpts = record
recursive: boolean; // default false
mode: nativeint; // default &777
end;
{ TNJSReadDirOpts }
TNJSReadDirOpts = record
encoding: string; // default 'utf8'
withFileTypes: boolean; // default false
end;
{ TNJSReadFileOpts }
TNJSReadFileOpts = record
encoding: string; // default nil
flag: string; // default 'r'
end;
{ TNJSReadLinkOpts }
TNJSReadLinkOpts = record
encoding: string; // default 'utf8'
end;
TNJSWriteFileOpts = record
encoding: string; // default 'utf8'
mode: nativeint; // default &666
flag: string; // default 'w'
end;
type
{ TNJSFS - nodejs filesystem }
TNJSFS = class external name 'fs'
public
procedure accessSync(Path: string; Mode: TNJSFileMode = F_OK); // throws Error if access is not granted
procedure appendFileSync(Path: string; Data: string);
procedure appendFileSync(Path: string; Data: string; const Options: TJSObject{TNJSAppendFileOpts});
procedure chmodSync(Path: string; Mode: TNJSFileMode);
procedure chownSync(Path: string; uid, gid: NativeInt);
procedure closeSync(fd: TNJSFileDesc);
procedure copyFileSync(Src, Dest: string;
Flags: NativeInt = 0 // see COPYFILE_EXCL etc
);
function createReadStream(Path: string): TNJSWriteStream;
function createReadStream(Path: string; const Options: TJSObject{TNJSReadStreamOpts}): TNJSReadStream;
function createWriteStream(Path: string): TNJSWriteStream;
function createWriteStream(Path: string; const Options: TJSObject{TNJSWriteStreamOpts}): TNJSWriteStream;
function existsSync(Path: string): boolean;
procedure fchmodSync(fd: TNJSFileDesc; mode: TNJSFileMode);
procedure fchownSync(fd: TNJSFileDesc; uid, gid: NativeInt);
procedure fdatasyncSync(fd: TNJSFileDesc);
procedure fstatSync(fd: TNJSFileDesc; const Options: TJSObject{TNJSStatOpts});
procedure fsyncSync(fd: TNJSFileDesc);
procedure ftruncateSync(fd: TNJSFileDesc; Len: nativeint = 0);
procedure futimesSync(fd: TNJSFileDesc; atime: NativeInt; mtime: NativeInt);
procedure lchownSync(path: string; uid, gid: NativeInt);
procedure linkSync(ExistingPath, NewPath: string);
procedure lstatSync(Path: string);
procedure lstatSync(Path: string; const Options: TJSObject{TNJSStatOpts});
procedure mkdirSync(Path: string; const Options: TJSObject{TNJSMkdirOpts});
// mkdtempSync
function openSync(Path: string; Flags: string; mode: TNJSFileMode): TNJSFileDesc;
function readdirSync(Path: string; const Options: TJSObject{TNJSReadDirOpts}): TJSArray; // can be TStringDynArray or TNJSDirEntArray if withFileTypes=true
function readFileSync(Path: string; const Options: TJSObject{TNJSReadFileOpts}): string;
function readlinkSync(Path: string): string;
function readlinkSync(Path: string; const Options: TJSObject{TNJSReadLinkOpts}): string;
// readSync(fd, buffer, offset, length, position)
// realpathSync(path[, options])
procedure renameSync(OldPath, NewPath: string);
procedure rmdirSync(Path: string);
function statSync(Path: string): TNJSStats;
function statSync(Path: string; const Options: TJSObject{TNJSStatOpts}): TNJSStats;
procedure symlinkSync(Target, Path: string; LinkType: string = 'file');
procedure truncateSync(Path: string; len: NativeInt = 0);
procedure unlinkSync(Path: string);
// unwatchFile(filename[, listener])
// utimesSync(path, atime, mtime)
// watch(filename[, options][, listener])
// watchFile(filename[, options], listener)
procedure writeFileSync(aFile: jsvalue; // string | buffer | URL | filedescriptor
Data: jsvalue; // string | buffer | typedarray | DataView
const Options: TNJSWriteFileOpts);
function writeSync(fd: TNJSFileDesc;
buffer: jsvalue; // buffer | TypedArray | DataView
Offset, Count, Position: NativeInt): NativeInt;
function writeSync(fd: TNJSFileDesc; Data: string; Position: NativeInt;
Encoding: string): NativeInt;
end;
type
{ TNJSPathParsed }
TNJSPathParsed = class external name 'TNJSPathParsed'
public
dir: string;
root: string;
base: string;
name: string;
ext: string;
end;
{ TNJSPath }
TNJSPath = class external name 'path'
public
win32: TJSObject; // todo
posix: TJSObject; // todo
public const
// Beware: nodejs uses "separator" and "delimiter" the other way round than FPC/Delphi
delimiter: char; // search PATH delimiter, windows ;, posix :
sep: char; // directory delimiter, windows \, posix: /
public
function basename(Path: string; Ext: string = ''): string; // remove the directory, optional ext to chomp off
function dirname(Path: string): string; // returns directory without trailing sep
function extname(Path: string): string; // returns from last occurence of '.', if path starts with '.' the empty string is returned
function format(PathObject: TJSObject): string; {
PathObjectis can contain the followinf string properties:
dir, root, base, name, ext
root is ignored if dir exists
ext and name are ignored if base exists
}
function isAbsolute(Path: string): boolean; // '' returns false
function join(Path1: string): string; varargs; // joins all passed strings with sep and normalizes, e.g. resolves '..', if the result is empty it returns '.'
function normalize(Path: string): string; // resolves '..' and '.' folders, reduces multiple delimiters, trailing sep is preserved, empty string is returned as '.', on windows replaces / with \\
function parse(Path: string): TNJSPathParsed;
function relative(FromPath, ToPath: string): string; // resolve both, then create relative, if both the same returns ''
function resolve(Path1: string): string; varargs; // resolve from right to left, prepend until an absolute path is created
function toNamespacedPath(Path: string): string; // windows only
end;
var
NJS_FS: TNJSFS;
NJS_Path: TNJSPath;
implementation
function FileExists(Filename: string): boolean;
function GetCurrentDir: string;
begin
writeln('FileExists TODO ',Filename);
Result:=false; // ToDo
if Filename='' then ;
raise Exception.Create('FileExists TODO');
Result:=NJS_Path.resolve('');
end;
function DirectoryExists(Filename: string): boolean;
function FileExists(const Filename: string): boolean;
begin
writeln('DirectoryExists TODO ',Filename);
Result:=false; // ToDo
if Filename='' then ;
raise Exception.Create('DirectoryExists TODO');
Result:=NJS_FS.existsSync(Filename);
end;
function ExtractFilePath(Filename: string): string;
function DirectoryExists(const Filename: string): boolean;
var
stats: TNJSStats;
begin
writeln('ExtractFilePath TODO ',Filename);
Result:=''; // ToDo
if Filename='' then ;
raise Exception.Create('ExtractFilePath TODO');
try
stats:=NJS_FS.statSync(Filename);
except
exit(false);
end;
Result:=stats.isDirectory;
end;
function ExtractFileName(Filename: string): string;
function ExtractFilePath(const Filename: string): string;
var
i : longint;
begin
writeln('ExtractFileName TODO ',Filename);
Result:=''; // ToDo
if Filename='' then ;
raise Exception.Create('ExtractFileName TODO');
i := Length(FileName);
while (i > 0) and not (FileName[i] in AllDirectorySeparators) do
Dec(i);
If I>0 then
Result := Copy(FileName, 1, i)
else
Result:='';
end;
function ExtractFileExt(Filename: string): string;
function ExtractFileName(const Filename: string): string;
var
i : longint;
begin
writeln('ExtractFileExt TODO ',Filename);
Result:=''; // ToDo
if Filename='' then ;
raise Exception.Create('ExtractFileExt TODO');
I := Length(FileName);
while (I > 0) and not (FileName[i] in AllDirectorySeparators) do
Dec(I);
Result := Copy(FileName, I + 1, MaxInt);
end;
function SetDirSeparators(Filename: string): string;
function ExtractFileExt(const Filename: string): string;
var
i : longint;
SOF : Boolean; // Dot at Start of filename ?
begin
writeln('SetDirSeparators TODO ',Filename);
Result:=''; // ToDo
if Filename='' then ;
raise Exception.Create('SetDirSeparators TODO');
Result:='';
I := Length(FileName);
while (I > 0) and not (FileName[i] in AllDirectorySeparators) do
begin
if (Filename[i]=ExtensionSeparator) then
begin
SOF:=(I=1) or (FileName[i-1] in AllowDirectorySeparators);
if (Not SOF) or FirstDotAtFileNameStartIsExtension then
Result:=Copy(FileName, I, MaxInt);
exit;
end;
Dec(I);
end;
end;
function ExpandFileName(Filename: string): string;
function SetDirSeparators(const Filename: string): string;
var
i: Integer;
begin
writeln('ExpandFileName TODO ',Filename);
Result:=''; // ToDo
if Filename='' then ;
raise Exception.Create('ExpandFileName TODO');
Result:=Filename;
For i:=1 to Length(Result) do
If (Result[i] in AllowDirectorySeparators)
and (Result[i]<>DirectorySeparator) then
Result[i]:=DirectorySeparator;
end;
function IncludeTrailingPathDelimiter(Filename: string): string;
function ExpandFileName(const Filename: string): string;
var
IsAbs: Boolean;
HomeDir, Fn: String;
begin
writeln('IncludeTrailingPathDelimiter TODO ',Filename);
Result:=''; // ToDo
if Filename='' then ;
raise Exception.Create('IncludeTrailingPathDelimiter TODO');
Fn := SetDirSeparators(Filename);
IsAbs := NJS_Path.isAbsolute(Fn);
if (not IsAbs) then
begin
if (PathDelim='/')
and (((Length(Fn) > 1) and (Fn[1] = '~') and (Fn[2] = '/'))
or (Fn = '~') ) then
begin
HomeDir := NJS_OS.homedir;
if not NJS_Path.isAbsolute(HomeDir) then
HomeDir := ExpandFileName(HomeDir);
Fn := HomeDir + Copy(Fn,2,length(Fn));
IsAbs := True;
end;
end;
if IsAbs then
begin
Result := NJS_Path.resolve(Fn);
end
else
begin
Fn := IncludeTrailingPathDelimiter(GetCurrentDir) + Fn;
Fn := NJS_Path.resolve(Fn);
Result := Fn;
end;
end;
function ChangeFileExt(Filename, NewExt: string): string;
function ExcludeTrailingPathDelimiter(const Filename: string): string;
Var
L : Integer;
begin
writeln('ChangeFileExt TODO ',Filename,' NewExt=',NewExt);
Result:=''; // ToDo
if Filename='' then ;
if NewExt='' then ;
raise Exception.Create('ChangeFileExt TODO');
L:=Length(Filename);
If (L>0) and (Filename[L] in AllowDirectorySeparators) then
Result:=LeftStr(Filename,L-1)
else
Result:=Filename;
end;
function IncludeTrailingPathDelimiter(const Filename: string): string;
Var
l : Integer;
begin
Result:=Filename;
l:=Length(Result);
If (L=0) or not (Result[l] in AllowDirectorySeparators) then
Result+=DirectorySeparator;
end;
function ChangeFileExt(const Filename, NewExt: string): string;
var
i : longint;
SOF : Boolean; // start of filename
begin
Result:=Filename;
i := Length(Result);
for i:=length(Result) downto 1 do
if Result[i] in AllDirectorySeparators then
break
else if (Result[i]=ExtensionSeparator) then
begin
SOF:=(I=1) or (Result[i-1] in AllowDirectorySeparators);
if (Not SOF) or FirstDotAtFileNameStartIsExtension then
begin
Result := LeftStr(Result, I - 1) + NewExt;
exit;
end;
end;
Result+=NewExt;
end;
function DeleteFile(const Filename: String): Boolean;
begin
try
NJS_FS.unlinkSync(Filename);
except
exit(false);
end;
Result:=true;
end;
function RenameFile(const OldName, NewName: String): Boolean;
begin
try
NJS_FS.renameSync(OldName,NewName);
except
exit(false);
end;
Result:=true;
end;
function FindFirst(const Path: String; Attr: Longint; out Rslt: TSearchRec
): Longint;
var
Mask: String;
Entries: TNJSDirEntArray;
begin
Mask:=ExtractFileName(Path);
if Mask<>AllFilesMask then
raise Exception.Create('FindFirst: ToDo: Mask='+Path);
try
Entries:=TNJSDirEntArray(NJS_FS.readdirSync(NJS_Path.dirname(Path),new(['withFileTypes',true])));
except
exit(-1);
end;
end;
function FindNext(var Rslt: TSearchRec): Longint;
begin
end;
procedure FindClose(var F: TSearchrec);
begin
end;
initialization
NJS_FS:=TNJSFS(Require('fs'));
NJS_Path:=TNJSPath(Require('path'));
PathDelim:=NJS_Path.sep;
PathSeparator:=NJS_Path.delimiter;
DirectorySeparator:=NJS_Path.sep;
PathSep:=NJS_Path.delimiter;
case lowercase(NJS_OS.platform) of
'win32':
begin
DriveSeparator:=':';
AllowDriveSeparators:=[':'];
MaxPathLen:=260;
MAX_PATH:=MaxPathLen;
end;
end;
AllDirectorySeparators:=AllowDirectorySeparators+AllowDriveSeparators;
end.