mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-09 21:48:35 +02:00
fcl-js: added TSourceMap
git-svn-id: trunk@36492 -
This commit is contained in:
parent
f91a9c07e7
commit
2df7e116e3
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -2511,11 +2511,13 @@ packages/fcl-js/src/jsbase.pp svneol=native#text/plain
|
||||
packages/fcl-js/src/jsminifier.pp svneol=native#text/plain
|
||||
packages/fcl-js/src/jsparser.pp svneol=native#text/plain
|
||||
packages/fcl-js/src/jsscanner.pp svneol=native#text/plain
|
||||
packages/fcl-js/src/jssrcmap.pas svneol=native#text/plain
|
||||
packages/fcl-js/src/jstoken.pp svneol=native#text/plain
|
||||
packages/fcl-js/src/jstree.pp svneol=native#text/plain
|
||||
packages/fcl-js/src/jswriter.pp svneol=native#text/plain
|
||||
packages/fcl-js/tests/tcparser.pp svneol=native#text/plain
|
||||
packages/fcl-js/tests/tcscanner.pp svneol=native#text/plain
|
||||
packages/fcl-js/tests/tcsrcmap.pas svneol=native#text/plain
|
||||
packages/fcl-js/tests/tcwriter.pp svneol=native#text/plain
|
||||
packages/fcl-js/tests/testjs.ico -text
|
||||
packages/fcl-js/tests/testjs.lpi svneol=native#text/plain
|
||||
|
602
packages/fcl-js/src/jssrcmap.pas
Normal file
602
packages/fcl-js/src/jssrcmap.pas
Normal file
@ -0,0 +1,602 @@
|
||||
{ *********************************************************************
|
||||
This file is part of the Free Component Library (FCL)
|
||||
Copyright (c) 2015 Mattias Gaertner.
|
||||
|
||||
Javascript Source Map
|
||||
|
||||
See Source Maps Revision 3:
|
||||
https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?hl=en_US&pli=1&pli=1#
|
||||
|
||||
See the file COPYING.FPC, included in this distribution,
|
||||
for details about the copyright.
|
||||
|
||||
This program 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.
|
||||
|
||||
**********************************************************************}
|
||||
unit JSSrcMap;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, contnrs, fpjson;
|
||||
|
||||
const
|
||||
Base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
||||
DefaultSrcMapHeader = ')]}'+LineEnding;
|
||||
|
||||
type
|
||||
|
||||
{ TSourceMapSegment }
|
||||
|
||||
TSourceMapSegment = class
|
||||
public
|
||||
Index: integer; // index in FNodes
|
||||
GeneratedLine: integer;
|
||||
GeneratedColumn: integer;
|
||||
SrcFileIndex: integer; // index in FSources
|
||||
SrcLine: integer;
|
||||
SrcColumn: integer;
|
||||
NameIndex: integer; // index in FNames
|
||||
end;
|
||||
|
||||
TSourceMapSrc = class
|
||||
public
|
||||
Filename: string;
|
||||
Source: String;
|
||||
end;
|
||||
|
||||
{ TSourceMap }
|
||||
|
||||
TSourceMap = class
|
||||
private
|
||||
type
|
||||
|
||||
{ TStringToIndex }
|
||||
|
||||
TStringToIndex = class
|
||||
private
|
||||
FItems: TFPHashList;
|
||||
public
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
procedure Clear;
|
||||
procedure Add(const Value: String; Index: integer);
|
||||
function FindValue(const Value: String): integer;
|
||||
end;
|
||||
private
|
||||
FAddMonotonous: boolean;
|
||||
FHeader: String;
|
||||
FGeneratedFilename: string;
|
||||
FNames: TStrings; // in adding order
|
||||
FNameToIndex: TStringToIndex; // name to index in FNames
|
||||
FItems: TFPList; // TSourceMapSegment, in adding order
|
||||
FSourceRoot: string;
|
||||
FSources: TFPList; // list of TSourceMapSrc, in adding order
|
||||
FSourceToIndex: TStringToIndex; // srcfile to index in FSources
|
||||
FVersion: integer;
|
||||
function GetNames(Index: integer): string;
|
||||
function GetItems(Index: integer): TSourceMapSegment;
|
||||
function GetSourceContents(Index: integer): String;
|
||||
function GetSourceFiles(Index: integer): String;
|
||||
procedure SetGeneratedFilename(const AValue: string);
|
||||
procedure SetSourceContents(Index: integer; const AValue: String);
|
||||
public
|
||||
constructor Create(const aGeneratedFilename: string);
|
||||
destructor Destroy; override;
|
||||
procedure Clear; virtual;
|
||||
function AddMapping(
|
||||
GeneratedLine: integer; // 1-based
|
||||
GeneratedCol: integer = 0; // 0-based
|
||||
const SourceFile: string = ''; // can be empty ''
|
||||
SrcLine: integer = 1; // 1-based
|
||||
SrcCol: integer = 0; // 0-based
|
||||
const Name: String = ''): TSourceMapSegment; virtual;
|
||||
property AddMonotonous: boolean read FAddMonotonous
|
||||
write FAddMonotonous default true;// true = AddMapping GeneratedLine/Col must be behind last add, false = check all adds for duplicate
|
||||
function CreateMappings: String; virtual;
|
||||
function ToJSON: TJSONObject; virtual;
|
||||
procedure SaveToStream(aStream: TStream); virtual;
|
||||
procedure SaveToFile(Filename: string); virtual;
|
||||
function ToString: string; override;
|
||||
property GeneratedFilename: string read FGeneratedFilename write SetGeneratedFilename;
|
||||
function IndexOfName(const Name: string; AddIfNotExists: boolean = false): integer;
|
||||
function IndexOfSourceFile(const SrcFile: string; AddIfNotExists: boolean = false): integer;
|
||||
function Count: integer;
|
||||
property Items[Index: integer]: TSourceMapSegment read GetItems; default; // segments
|
||||
function SourceCount: integer;
|
||||
property SourceRoot: string read FSourceRoot write FSourceRoot;
|
||||
property SourceFiles[Index: integer]: String read GetSourceFiles;
|
||||
property SourceContents[Index: integer]: String read GetSourceContents write SetSourceContents;
|
||||
function NameCount: integer;
|
||||
property Names[Index: integer]: string read GetNames;
|
||||
property Version: integer read FVersion; // 3
|
||||
property Header: String read FHeader write FHeader; // DefaultSrcMapHeader
|
||||
end;
|
||||
|
||||
function EncodeBase64VLQ(i: NativeInt): String; // base64 Variable Length Quantity
|
||||
function DecodeBase64VLQ(const s: string): NativeInt; // base64 Variable Length Quantity
|
||||
function DecodeBase64VLQ(var p: PChar): NativeInt; // base64 Variable Length Quantity
|
||||
|
||||
implementation
|
||||
|
||||
function EncodeBase64VLQ(i: NativeInt): String;
|
||||
{ Convert signed number to base64-VLQ:
|
||||
Each base64 has 6bit, where the most significant bit is the continuation bit
|
||||
(1=there is a next base64 character).
|
||||
The first character contains the 5 least significant bits of the number.
|
||||
The last bit of the first character is the sign bit (1=negative).
|
||||
For example:
|
||||
A = 0 = %000000 => 0
|
||||
B = 1 = %000001 => -0
|
||||
C = 2 = %000010 => 1
|
||||
iF = 34 5 = %100010 %000101 = 00010 00101 = 1000101 = 69
|
||||
}
|
||||
|
||||
procedure RaiseRange;
|
||||
begin
|
||||
raise ERangeError.Create('EncodeBase64VLQ');
|
||||
end;
|
||||
|
||||
var
|
||||
digits: NativeInt;
|
||||
begin
|
||||
Result:='';
|
||||
if i<0 then
|
||||
begin
|
||||
i:=-i;
|
||||
if i>(High(NativeInt)-1) shr 1 then
|
||||
RaiseRange;
|
||||
i:=(i shl 1)+1;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if i>High(NativeInt) shr 1 then
|
||||
RaiseRange;
|
||||
i:=i shl 1;
|
||||
end;
|
||||
repeat
|
||||
digits:=i and %11111;
|
||||
i:=i shr 5;
|
||||
if i>0 then
|
||||
inc(digits,%100000); // need another char -> set continuation bit
|
||||
Result:=Result+Base64Chars[digits+1];
|
||||
until i=0;
|
||||
end;
|
||||
|
||||
function DecodeBase64VLQ(const s: string): NativeInt;
|
||||
var
|
||||
p: PChar;
|
||||
begin
|
||||
if s='' then
|
||||
raise EConvertError.Create('DecodeBase64VLQ empty');
|
||||
p:=PChar(s);
|
||||
Result:=DecodeBase64VLQ(p);
|
||||
if p-PChar(s)<>length(s) then
|
||||
raise EConvertError.Create('DecodeBase64VLQ waste');
|
||||
end;
|
||||
|
||||
function DecodeBase64VLQ(var p: PChar): NativeInt;
|
||||
{ Convert base64-VLQ to signed number,
|
||||
For the fomat see EncodeBase64VLQ
|
||||
}
|
||||
|
||||
procedure RaiseInvalid;
|
||||
begin
|
||||
raise ERangeError.Create('DecodeBase64VLQ');
|
||||
end;
|
||||
|
||||
const
|
||||
MaxShift = 63-5; // actually log2(High(NativeInt))-5
|
||||
var
|
||||
c: Char;
|
||||
digit, Shift: Integer;
|
||||
begin
|
||||
Result:=0;
|
||||
Shift:=0;
|
||||
repeat
|
||||
c:=p^;
|
||||
case c of
|
||||
'A'..'Z': digit:=ord(c)-ord('A');
|
||||
'a'..'z': digit:=ord(c)-ord('a')+26;
|
||||
'0'..'9': digit:=ord(c)-ord('0')+52;
|
||||
'+': digit:=62;
|
||||
'/': digit:=63;
|
||||
else RaiseInvalid;
|
||||
end;
|
||||
inc(p);
|
||||
if Shift>MaxShift then
|
||||
RaiseInvalid;
|
||||
inc(Result,(digit and %11111) shl Shift);
|
||||
inc(Shift,5);
|
||||
until digit<%100000;
|
||||
if (Result and 1)>0 then
|
||||
Result:=-(Result shr 1)
|
||||
else
|
||||
Result:=Result shr 1;
|
||||
end;
|
||||
|
||||
{ TSourceMap.TStringToIndex }
|
||||
|
||||
constructor TSourceMap.TStringToIndex.Create;
|
||||
begin
|
||||
FItems:=TFPHashList.Create;
|
||||
end;
|
||||
|
||||
destructor TSourceMap.TStringToIndex.Destroy;
|
||||
begin
|
||||
FItems.Clear;
|
||||
FreeAndNil(FItems);
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TSourceMap.TStringToIndex.Clear;
|
||||
begin
|
||||
FItems.Clear;
|
||||
end;
|
||||
|
||||
procedure TSourceMap.TStringToIndex.Add(const Value: String; Index: integer);
|
||||
begin
|
||||
// Note: nil=0 means not found in TFPHashList
|
||||
FItems.Add(Value,{%H-}Pointer(PtrInt(Index+1)));
|
||||
end;
|
||||
|
||||
function TSourceMap.TStringToIndex.FindValue(const Value: String
|
||||
): integer;
|
||||
begin
|
||||
// Note: nil=0 means not found in TFPHashList
|
||||
Result:=integer({%H-}PtrInt(FItems.Find(Value)))-1;
|
||||
end;
|
||||
|
||||
{ TSourceMap }
|
||||
|
||||
procedure TSourceMap.SetGeneratedFilename(const AValue: string);
|
||||
begin
|
||||
if FGeneratedFilename=AValue then Exit;
|
||||
FGeneratedFilename:=AValue;
|
||||
end;
|
||||
|
||||
procedure TSourceMap.SetSourceContents(Index: integer; const AValue: String);
|
||||
begin
|
||||
TSourceMapSrc(FSources[Index]).Source:=AValue;
|
||||
end;
|
||||
|
||||
function TSourceMap.GetItems(Index: integer): TSourceMapSegment;
|
||||
begin
|
||||
Result:=TSourceMapSegment(FItems[Index]);
|
||||
end;
|
||||
|
||||
function TSourceMap.GetSourceContents(Index: integer): String;
|
||||
begin
|
||||
Result:=TSourceMapSrc(FSources[Index]).Source;
|
||||
end;
|
||||
|
||||
function TSourceMap.GetNames(Index: integer): string;
|
||||
begin
|
||||
Result:=FNames[Index];
|
||||
end;
|
||||
|
||||
function TSourceMap.GetSourceFiles(Index: integer): String;
|
||||
begin
|
||||
Result:=TSourceMapSrc(FSources[Index]).Filename;
|
||||
end;
|
||||
|
||||
constructor TSourceMap.Create(const aGeneratedFilename: string);
|
||||
begin
|
||||
FVersion:=3;
|
||||
FNames:=TStringList.Create;
|
||||
FNameToIndex:=TStringToIndex.Create;
|
||||
FItems:=TFPList.Create;
|
||||
FSources:=TFPList.Create;
|
||||
FSourceToIndex:=TStringToIndex.Create;
|
||||
FAddMonotonous:=true;
|
||||
FHeader:=DefaultSrcMapHeader;
|
||||
GeneratedFilename:=aGeneratedFilename;
|
||||
end;
|
||||
|
||||
destructor TSourceMap.Destroy;
|
||||
begin
|
||||
Clear;
|
||||
FreeAndNil(FSourceToIndex);
|
||||
FreeAndNil(FSources);
|
||||
FreeAndNil(FItems);
|
||||
FreeAndNil(FNameToIndex);
|
||||
FreeAndNil(FNames);
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TSourceMap.Clear;
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
FSourceToIndex.Clear;
|
||||
for i:=0 to FSources.Count-1 do
|
||||
TObject(FSources[i]).Free;
|
||||
FSources.Clear;
|
||||
for i:=0 to FItems.Count-1 do
|
||||
TObject(FItems[i]).Free;
|
||||
FItems.Clear;
|
||||
FNameToIndex.Clear;
|
||||
FNames.Clear;
|
||||
end;
|
||||
|
||||
function TSourceMap.AddMapping(GeneratedLine: integer; GeneratedCol: integer;
|
||||
const SourceFile: string; SrcLine: integer; SrcCol: integer;
|
||||
const Name: String): TSourceMapSegment;
|
||||
|
||||
procedure RaiseInvalid(Msg: string);
|
||||
begin
|
||||
raise Exception.CreateFmt('%s (GeneratedLine=%d GeneratedCol=%d SrcFile="%s" SrcLine=%d SrcCol=%d Name="%s")',
|
||||
[Msg,GeneratedLine,GeneratedCol,SourceFile,SrcLine,SrcCol,Name]);
|
||||
end;
|
||||
|
||||
var
|
||||
NodeCnt, i: Integer;
|
||||
OtherNode: TSourceMapSegment;
|
||||
begin
|
||||
if GeneratedLine<1 then
|
||||
RaiseInvalid('invalid GeneratedLine');
|
||||
if GeneratedCol<0 then
|
||||
RaiseInvalid('invalid GeneratedCol');
|
||||
if SourceFile='' then
|
||||
begin
|
||||
if Count=0 then
|
||||
RaiseInvalid('missing source file');
|
||||
if SrcLine<>1 then
|
||||
RaiseInvalid('invalid SrcLine');
|
||||
if SrcCol<>0 then
|
||||
RaiseInvalid('invalid SrcCol');
|
||||
if Name<>'' then
|
||||
RaiseInvalid('invalid Name');
|
||||
end
|
||||
else
|
||||
begin
|
||||
if SrcLine<1 then
|
||||
RaiseInvalid('invalid SrcLine');
|
||||
if SrcCol<0 then
|
||||
RaiseInvalid('invalid SrcCol');
|
||||
end;
|
||||
|
||||
// check if generated line/col already exists
|
||||
NodeCnt:=Count;
|
||||
if AddMonotonous then
|
||||
begin
|
||||
if NodeCnt>0 then
|
||||
begin
|
||||
OtherNode:=Items[NodeCnt-1];
|
||||
if (OtherNode.GeneratedLine>GeneratedLine)
|
||||
or ((OtherNode.GeneratedLine=GeneratedLine)
|
||||
and (OtherNode.GeneratedColumn>GeneratedCol)) then
|
||||
RaiseInvalid('GeneratedLine/Col not monotonous');
|
||||
// Note: same line/col is allowed
|
||||
end;
|
||||
end
|
||||
else
|
||||
begin
|
||||
for i:=0 to NodeCnt-1 do
|
||||
begin
|
||||
OtherNode:=Items[i];
|
||||
if (OtherNode.GeneratedLine=GeneratedLine) and (OtherNode.GeneratedColumn=GeneratedCol) then
|
||||
RaiseInvalid('duplicate GeneratedLine/Col');
|
||||
end;
|
||||
end;
|
||||
|
||||
// add
|
||||
Result:=TSourceMapSegment.Create;
|
||||
Result.Index:=FItems.Count;
|
||||
Result.GeneratedLine:=GeneratedLine;
|
||||
Result.GeneratedColumn:=GeneratedCol;
|
||||
if SourceFile='' then
|
||||
Result.SrcFileIndex:=-1
|
||||
else
|
||||
Result.SrcFileIndex:=IndexOfSourceFile(SourceFile,true);
|
||||
Result.SrcLine:=SrcLine;
|
||||
Result.SrcColumn:=SrcCol;
|
||||
if Name<>'' then
|
||||
Result.NameIndex:=IndexOfName(Name,true)
|
||||
else
|
||||
Result.NameIndex:=-1;
|
||||
FItems.Add(Result);
|
||||
end;
|
||||
|
||||
function TSourceMap.CreateMappings: String;
|
||||
|
||||
procedure Add(ms: TMemoryStream; const s: string);
|
||||
begin
|
||||
if s<>'' then
|
||||
ms.Write(s[1],length(s));
|
||||
end;
|
||||
|
||||
var
|
||||
ms: TMemoryStream;
|
||||
i, LastGeneratedLine, LastGeneratedColumn, j, LastSrcFileIndex, LastSrcLine,
|
||||
LastSrcColumn, SrcLine, LastNameIndex: Integer;
|
||||
Item: TSourceMapSegment;
|
||||
begin
|
||||
Result:='';
|
||||
LastGeneratedLine:=1;
|
||||
LastGeneratedColumn:=0;
|
||||
LastSrcFileIndex:=0;
|
||||
LastSrcLine:=0;
|
||||
LastSrcColumn:=0;
|
||||
LastNameIndex:=0;
|
||||
ms:=TMemoryStream.Create;
|
||||
try
|
||||
for i:=0 to Count-1 do
|
||||
begin
|
||||
Item:=Items[i];
|
||||
if LastGeneratedLine<Item.GeneratedLine then
|
||||
begin
|
||||
// new line
|
||||
LastGeneratedColumn:=0;
|
||||
for j:=LastGeneratedLine+1 to Item.GeneratedLine do
|
||||
ms.WriteByte(ord(';'));
|
||||
LastGeneratedLine:=Item.GeneratedLine;
|
||||
end
|
||||
else if i>0 then
|
||||
begin
|
||||
// not the first segment
|
||||
if (LastGeneratedLine=Item.GeneratedLine)
|
||||
and (LastGeneratedColumn=Item.GeneratedColumn) then
|
||||
continue;
|
||||
ms.WriteByte(ord(','));
|
||||
end;
|
||||
// column diff
|
||||
Add(ms,EncodeBase64VLQ(Item.GeneratedColumn-LastGeneratedColumn));
|
||||
LastGeneratedColumn:=Item.GeneratedColumn;
|
||||
|
||||
if Item.SrcFileIndex<0 then
|
||||
continue; // no source -> segment length 1
|
||||
// src file index diff
|
||||
Add(ms,EncodeBase64VLQ(Item.SrcFileIndex-LastSrcFileIndex));
|
||||
LastSrcFileIndex:=Item.SrcFileIndex;
|
||||
// src line diff
|
||||
SrcLine:=Item.SrcLine-1; // 0 based in version 3
|
||||
Add(ms,EncodeBase64VLQ(SrcLine-LastSrcLine));
|
||||
LastSrcLine:=SrcLine;
|
||||
// src column diff
|
||||
Add(ms,EncodeBase64VLQ(Item.SrcColumn-LastSrcColumn));
|
||||
LastSrcColumn:=Item.SrcColumn;
|
||||
// name index
|
||||
if Item.NameIndex<0 then
|
||||
continue; // no name -> segment length 4
|
||||
Add(ms,EncodeBase64VLQ(Item.NameIndex-LastNameIndex));
|
||||
LastNameIndex:=Item.NameIndex;
|
||||
end;
|
||||
SetLength(Result,ms.Size);
|
||||
if Result<>'' then
|
||||
Move(ms.Memory^,Result[1],ms.Size);
|
||||
finally
|
||||
ms.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TSourceMap.ToJSON: TJSONObject;
|
||||
var
|
||||
Obj: TJSONObject;
|
||||
i: Integer;
|
||||
Arr: TJSONArray;
|
||||
Mappings: String;
|
||||
begin
|
||||
Result:=nil;
|
||||
Mappings:=CreateMappings;
|
||||
|
||||
Obj:=TJSONObject.Create;
|
||||
try
|
||||
// "version" - integer
|
||||
Obj.Add('version',Version);
|
||||
|
||||
// "file" - GeneratedFilename
|
||||
if GeneratedFilename<>'' then
|
||||
Obj.Add('file',GeneratedFilename);
|
||||
|
||||
// "sourceRoot" - SourceRoot
|
||||
if SourceRoot<>'' then
|
||||
Obj.Add('sourceRoot',SourceRoot);
|
||||
|
||||
// "sources" - array of filenames
|
||||
Arr:=TJSONArray.Create;
|
||||
Obj.Add('sources',Arr);
|
||||
for i:=0 to SourceCount-1 do
|
||||
Arr.Add(SourceFiles[i]);
|
||||
|
||||
// "names" - array of names
|
||||
Arr:=TJSONArray.Create;
|
||||
Obj.Add('names',Arr);
|
||||
for i:=0 to NameCount-1 do
|
||||
Arr.Add(Names[i]);
|
||||
|
||||
// "mappings" - string
|
||||
Obj.Add('mappings',Mappings);
|
||||
|
||||
Result:=Obj;
|
||||
finally
|
||||
if Result=nil then
|
||||
Obj.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TSourceMap.SaveToStream(aStream: TStream);
|
||||
var
|
||||
Obj: TJSONObject;
|
||||
begin
|
||||
Obj:=ToJSON;
|
||||
try
|
||||
if Header<>'' then
|
||||
aStream.Write(Header[1],length(Header));
|
||||
Obj.DumpJSON(aStream);
|
||||
finally
|
||||
Obj.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TSourceMap.SaveToFile(Filename: string);
|
||||
var
|
||||
TheStream: TMemoryStream;
|
||||
begin
|
||||
TheStream:=TMemoryStream.Create;
|
||||
try
|
||||
SaveToStream(TheStream);
|
||||
TheStream.Position:=0;
|
||||
TheStream.SaveToFile(Filename);
|
||||
finally
|
||||
TheStream.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TSourceMap.ToString: string;
|
||||
var
|
||||
Obj: TJSONObject;
|
||||
begin
|
||||
Obj:=ToJSON;
|
||||
try
|
||||
Result:=Header+Obj.AsJSON;
|
||||
finally
|
||||
Obj.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TSourceMap.IndexOfName(const Name: string; AddIfNotExists: boolean
|
||||
): integer;
|
||||
begin
|
||||
Result:=FNameToIndex.FindValue(Name);
|
||||
if (Result>=0) or not AddIfNotExists then exit;
|
||||
Result:=FNames.Count;
|
||||
FNames.Add(Name);
|
||||
FNameToIndex.Add(Name,Result);
|
||||
end;
|
||||
|
||||
function TSourceMap.IndexOfSourceFile(const SrcFile: string;
|
||||
AddIfNotExists: boolean): integer;
|
||||
var
|
||||
Src: TSourceMapSrc;
|
||||
begin
|
||||
Result:=FSourceToIndex.FindValue(SrcFile);
|
||||
if (Result>=0) or not AddIfNotExists then exit;
|
||||
Src:=TSourceMapSrc.Create;
|
||||
Src.Filename:=SrcFile;
|
||||
Result:=FSources.Count;
|
||||
FSources.Add(Src);
|
||||
FSourceToIndex.Add(SrcFile,Result);
|
||||
end;
|
||||
|
||||
function TSourceMap.Count: integer;
|
||||
begin
|
||||
Result:=FItems.Count;
|
||||
end;
|
||||
|
||||
function TSourceMap.SourceCount: integer;
|
||||
begin
|
||||
Result:=FSources.Count;
|
||||
end;
|
||||
|
||||
function TSourceMap.NameCount: integer;
|
||||
begin
|
||||
Result:=FNames.Count;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
@ -23,15 +23,25 @@ uses
|
||||
SysUtils, jstoken, jsbase, jstree;
|
||||
|
||||
Type
|
||||
TTextWriter = class;
|
||||
|
||||
TTextWriterWriting = procedure(Sender: TTextWriter) of object;
|
||||
|
||||
{ TTextWriter }
|
||||
|
||||
TTextWriter = Class(TObject)
|
||||
private
|
||||
FCurElement: TJSElement;
|
||||
FCurLine: integer;
|
||||
FCurColumn: integer;
|
||||
FOnWriting: TTextWriterWriting;
|
||||
protected
|
||||
Function DoWrite(Const S : AnsiString) : Integer; virtual; abstract;
|
||||
Function DoWrite(Const S : UnicodeString) : Integer; virtual; abstract;
|
||||
Procedure Writing; // called before adding new characters
|
||||
Public
|
||||
// All functions return the number of bytes copied to output stream.
|
||||
constructor Create;
|
||||
Function Write(Const S : UnicodeString) : Integer;
|
||||
Function Write(Const S : AnsiString) : Integer;
|
||||
Function WriteLn(Const S : AnsiString) : Integer;
|
||||
@ -39,6 +49,10 @@ Type
|
||||
Function WriteLn(Const Fmt : AnsiString; Args : Array of const) : Integer;
|
||||
Function Write(Const Args : Array of const) : Integer;
|
||||
Function WriteLn(Const Args : Array of const) : Integer;
|
||||
Property CurLine: integer read FCurLine write FCurLine;
|
||||
Property CurColumn: integer read FCurColumn write FCurColumn;// char index, not codepoint
|
||||
Property CurElement: TJSElement read FCurElement write FCurElement;
|
||||
Property OnWriting: TTextWriterWriting read FOnWriting write FOnWriting;
|
||||
end;
|
||||
|
||||
{ TFileWriter }
|
||||
@ -105,14 +119,14 @@ Type
|
||||
TJSWriter = Class
|
||||
private
|
||||
FCurIndent : Integer;
|
||||
FLinePos : Integer;
|
||||
FIndentSize: Byte;
|
||||
FIndentChar : Char;
|
||||
FOptions: TWriteOptions;
|
||||
FWriter: TTextWriter;
|
||||
FFreeWriter : Boolean;
|
||||
FIndentChar : Char;
|
||||
FIndentSize: Byte;
|
||||
FLinePos : Integer;
|
||||
FOptions: TWriteOptions;
|
||||
FSkipCurlyBrackets : Boolean;
|
||||
FSkipRoundBrackets : Boolean;
|
||||
FWriter: TTextWriter;
|
||||
function GetUseUTF8: Boolean;
|
||||
procedure SetOptions(AValue: TWriteOptions);
|
||||
Protected
|
||||
@ -254,7 +268,7 @@ begin
|
||||
MinLen:=Result+FBufPos;
|
||||
If (MinLen>Capacity) then
|
||||
begin
|
||||
DesLen:=Round(FCapacity*1.25);
|
||||
DesLen:=(FCapacity*5) div 4;
|
||||
if DesLen>MinLen then
|
||||
MinLen:=DesLen;
|
||||
Capacity:=MinLen;
|
||||
@ -274,7 +288,7 @@ begin
|
||||
MinLen:=Result+FBufPos;
|
||||
If (MinLen>Capacity) then
|
||||
begin
|
||||
DesLen:=Round(FCapacity*1.25);
|
||||
DesLen:=(FCapacity*5) div 4;
|
||||
if DesLen>MinLen then
|
||||
MinLen:=DesLen;
|
||||
Capacity:=MinLen;
|
||||
@ -285,6 +299,7 @@ end;
|
||||
|
||||
Constructor TBufferWriter.Create(Const ACapacity: Cardinal);
|
||||
begin
|
||||
inherited Create;
|
||||
Capacity:=ACapacity;
|
||||
end;
|
||||
|
||||
@ -673,7 +688,9 @@ begin
|
||||
if El is TJSPrimaryExpressionThis then
|
||||
Write('this')
|
||||
else if El is TJSPrimaryExpressionIdent then
|
||||
Write(TJSPrimaryExpressionIdent(El).Name);
|
||||
Write(TJSPrimaryExpressionIdent(El).Name)
|
||||
else
|
||||
Error(SErrUnknownJSClass,[El.ClassName]);
|
||||
end;
|
||||
|
||||
procedure TJSWriter.WriteArrayLiteral(El: TJSArrayLiteral);
|
||||
@ -777,6 +794,7 @@ procedure TJSWriter.WriteMemberExpression(El: TJSMemberExpression);
|
||||
|
||||
var
|
||||
MExpr: TJSElement;
|
||||
Args: TJSArguments;
|
||||
begin
|
||||
if El is TJSNewMemberExpression then
|
||||
Write('new ');
|
||||
@ -809,8 +827,12 @@ begin
|
||||
end
|
||||
else if (El is TJSNewMemberExpression) then
|
||||
begin
|
||||
if (Assigned(TJSNewMemberExpression(El).Args)) then
|
||||
WriteArrayLiteral(TJSNewMemberExpression(El).Args)
|
||||
Args:=TJSNewMemberExpression(El).Args;
|
||||
if Assigned(Args) then
|
||||
begin
|
||||
Writer.CurElement:=Args;
|
||||
WriteArrayLiteral(Args);
|
||||
end
|
||||
else
|
||||
Write('()');
|
||||
end;
|
||||
@ -821,7 +843,10 @@ procedure TJSWriter.WriteCallExpression(El: TJSCallExpression);
|
||||
begin
|
||||
WriteJS(El.Expr);
|
||||
if Assigned(El.Args) then
|
||||
WriteArrayLiteral(El.Args)
|
||||
begin
|
||||
Writer.CurElement:=El.Args;
|
||||
WriteArrayLiteral(El.Args);
|
||||
end
|
||||
else
|
||||
Write('()');
|
||||
end;
|
||||
@ -1219,23 +1244,23 @@ Var
|
||||
TN : TJSString;
|
||||
|
||||
begin
|
||||
TN:=EL.TargetName;
|
||||
TN:=El.TargetName;
|
||||
if (El is TJSForStatement) then
|
||||
WriteForStatement(TJSForStatement(El))
|
||||
else if (El is TJSSwitchStatement) then
|
||||
WriteSwitchStatement(TJSSwitchStatement(El))
|
||||
else if (El is TJSForInStatement) then
|
||||
WriteForInStatement(TJSForInStatement(El))
|
||||
else if EL is TJSWhileStatement then
|
||||
else if El is TJSWhileStatement then
|
||||
WriteWhileStatement(TJSWhileStatement(El))
|
||||
else if (EL is TJSContinueStatement) then
|
||||
else if (El is TJSContinueStatement) then
|
||||
begin
|
||||
if (TN<>'') then
|
||||
Write('continue '+TN)
|
||||
else
|
||||
Write('continue');
|
||||
end
|
||||
else if (EL is TJSBreakStatement) then
|
||||
else if (El is TJSBreakStatement) then
|
||||
begin
|
||||
if (TN<>'') then
|
||||
Write('break '+TN)
|
||||
@ -1243,7 +1268,7 @@ begin
|
||||
Write('break');
|
||||
end
|
||||
else
|
||||
Error('Unknown target statement class: "%s"',[EL.ClassName])
|
||||
Error('Unknown target statement class: "%s"',[El.ClassName])
|
||||
end;
|
||||
|
||||
procedure TJSWriter.WriteReturnStatement(El: TJSReturnStatement);
|
||||
@ -1384,6 +1409,8 @@ begin
|
||||
end;
|
||||
|
||||
procedure TJSWriter.WriteJS(El: TJSElement);
|
||||
var
|
||||
LastWritingEl: TJSElement;
|
||||
begin
|
||||
{$IFDEF DEBUGJSWRITER}
|
||||
if (EL<>Nil) then
|
||||
@ -1391,6 +1418,8 @@ begin
|
||||
else
|
||||
system.Writeln('WriteJS : El = Nil');
|
||||
{$ENDIF}
|
||||
LastWritingEl:=Writer.CurElement;
|
||||
Writer.CurElement:=El;
|
||||
if (El is TJSEmptyBlockStatement ) then
|
||||
WriteEmptyBlockStatement(TJSEmptyBlockStatement(El))
|
||||
else if (El is TJSEmptyStatement) then
|
||||
@ -1449,6 +1478,7 @@ begin
|
||||
Error(SErrUnknownJSClass,[El.ClassName]);
|
||||
// Write('/* '+El.ClassName+' */');
|
||||
FSkipCurlyBrackets:=False;
|
||||
Writer.CurElement:=LastWritingEl;
|
||||
end;
|
||||
|
||||
{ TFileWriter }
|
||||
@ -1467,6 +1497,7 @@ end;
|
||||
|
||||
Constructor TFileWriter.Create(Const AFileNAme: String);
|
||||
begin
|
||||
inherited Create;
|
||||
FFileName:=AFileName;
|
||||
Assign(FFile,AFileName);
|
||||
Rewrite(FFile);
|
||||
@ -1490,33 +1521,103 @@ end;
|
||||
|
||||
{ TTextWriter }
|
||||
|
||||
Function TTextWriter.Write(Const S: UnicodeString) : Integer;
|
||||
procedure TTextWriter.Writing;
|
||||
begin
|
||||
if Assigned(OnWriting) then
|
||||
OnWriting(Self);
|
||||
end;
|
||||
|
||||
constructor TTextWriter.Create;
|
||||
begin
|
||||
FCurLine:=1;
|
||||
FCurColumn:=1;
|
||||
end;
|
||||
|
||||
function TTextWriter.Write(const S: UnicodeString): Integer;
|
||||
var
|
||||
p: PWideChar;
|
||||
c: WideChar;
|
||||
begin
|
||||
if S='' then exit;
|
||||
Writing;
|
||||
Result:=DoWrite(S);
|
||||
p:=PWideChar(S);
|
||||
repeat
|
||||
c:=p^;
|
||||
case c of
|
||||
#0:
|
||||
if p-PWideChar(S)=length(S)*2 then
|
||||
break
|
||||
else
|
||||
inc(FCurColumn);
|
||||
#10,#13:
|
||||
begin
|
||||
FCurColumn:=1;
|
||||
inc(FCurLine);
|
||||
inc(p);
|
||||
if (p^ in [#10,#13]) and (c<>p^) then inc(p);
|
||||
continue;
|
||||
end;
|
||||
else
|
||||
// ignore low/high surrogate, CurColumn is char index, not codepoint
|
||||
inc(FCurColumn);
|
||||
end;
|
||||
inc(p);
|
||||
until false;
|
||||
end;
|
||||
|
||||
Function TTextWriter.Write(Const S: AnsiString) : integer;
|
||||
function TTextWriter.Write(const S: AnsiString): Integer;
|
||||
var
|
||||
p: PChar;
|
||||
c: Char;
|
||||
begin
|
||||
if S='' then exit;
|
||||
Writing;
|
||||
Result:=DoWrite(S);
|
||||
p:=PChar(S);
|
||||
repeat
|
||||
c:=p^;
|
||||
case c of
|
||||
#0:
|
||||
if p-PChar(S)=length(S) then
|
||||
break
|
||||
else
|
||||
inc(FCurColumn);
|
||||
#10,#13:
|
||||
begin
|
||||
FCurColumn:=1;
|
||||
inc(FCurLine);
|
||||
inc(p);
|
||||
if (p^ in [#10,#13]) and (c<>p^) then inc(p);
|
||||
continue;
|
||||
end;
|
||||
else
|
||||
// ignore UTF-8 multibyte chars, CurColumn is char index, not codepoint
|
||||
inc(FCurColumn);
|
||||
end;
|
||||
inc(p);
|
||||
until false;
|
||||
end;
|
||||
|
||||
Function TTextWriter.WriteLn(Const S: AnsiString) : Integer;
|
||||
function TTextWriter.WriteLn(const S: AnsiString): Integer;
|
||||
begin
|
||||
Result:=DoWrite(S)+DoWrite(sLineBreak);
|
||||
Result:=Write(S)+Write(sLineBreak);
|
||||
end;
|
||||
|
||||
Function TTextWriter.Write(Const Fmt: AnsiString; Args: Array of const) : Integer;
|
||||
function TTextWriter.Write(const Fmt: AnsiString;
|
||||
Args: array of const): Integer;
|
||||
|
||||
begin
|
||||
Result:=DoWrite(Format(Fmt,Args));
|
||||
Result:=Write(Format(Fmt,Args));
|
||||
end;
|
||||
|
||||
Function TTextWriter.WriteLn(Const Fmt: AnsiString; Args: Array of const) : integer;
|
||||
function TTextWriter.WriteLn(const Fmt: AnsiString;
|
||||
Args: array of const): Integer;
|
||||
begin
|
||||
Result:=WriteLn(Format(Fmt,Args));
|
||||
end;
|
||||
|
||||
Function TTextWriter.Write(Const Args: Array of const) : Integer;
|
||||
function TTextWriter.Write(const Args: array of const): Integer;
|
||||
|
||||
Var
|
||||
I : Integer;
|
||||
@ -1552,11 +1653,11 @@ begin
|
||||
if (U<>'') then
|
||||
Result:=Result+Write(u)
|
||||
else if (S<>'') then
|
||||
Result:=Result+write(s);
|
||||
Result:=Result+Write(s);
|
||||
end;
|
||||
end;
|
||||
|
||||
Function TTextWriter.WriteLn(Const Args: Array of const) : integer;
|
||||
function TTextWriter.WriteLn(const Args: array of const): Integer;
|
||||
begin
|
||||
Result:=Write(Args)+Writeln('');
|
||||
end;
|
||||
|
175
packages/fcl-js/tests/tcsrcmap.pas
Normal file
175
packages/fcl-js/tests/tcsrcmap.pas
Normal file
@ -0,0 +1,175 @@
|
||||
unit TCSrcMap;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, fpcunit, testregistry, fpjson, JSSrcMap;
|
||||
|
||||
type
|
||||
|
||||
{ TCustomTestSrcMap }
|
||||
|
||||
TCustomTestSrcMap = class(TTestCase)
|
||||
protected
|
||||
procedure CheckEl(aName: String; El: TJSONData; aClass: TClass);
|
||||
function GetEl(Obj: TJSONObject; aName: String; aClass: TClass): TJSONData;
|
||||
end;
|
||||
|
||||
{ TTestSrcMap }
|
||||
|
||||
TTestSrcMap = class(TCustomTestSrcMap)
|
||||
published
|
||||
procedure Test_Base64VLQ;
|
||||
procedure TestSrcMapIgnoreDuplicate;
|
||||
procedure TestSrcMapNames;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
{ TCustomTestSrcMap }
|
||||
|
||||
procedure TCustomTestSrcMap.CheckEl(aName: String; El: TJSONData; aClass: TClass);
|
||||
begin
|
||||
AssertNotNull('json "'+aName+'" exists',El);
|
||||
AssertEquals('json "'+aName+'" class',El.ClassType,aClass);
|
||||
end;
|
||||
|
||||
function TCustomTestSrcMap.GetEl(Obj: TJSONObject; aName: String; aClass: TClass): TJSONData;
|
||||
begin
|
||||
Result:=Obj.Elements[aName];
|
||||
CheckEl(aName,Result,aClass);
|
||||
end;
|
||||
|
||||
{ TTestSrcMap }
|
||||
|
||||
procedure TTestSrcMap.Test_Base64VLQ;
|
||||
var
|
||||
i: Integer;
|
||||
s: String;
|
||||
p: PChar;
|
||||
j: NativeInt;
|
||||
begin
|
||||
for i:=-511 to 511 do
|
||||
begin
|
||||
s:=EncodeBase64VLQ(i);
|
||||
p:=PChar(s);
|
||||
j:=DecodeBase64VLQ(p);
|
||||
if i<>j then
|
||||
Fail('Encode/DecodeBase64VLQ OrigIndex='+IntToStr(i)+' Code="'+s+'" NewIndex='+IntToStr(j));
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TTestSrcMap.TestSrcMapIgnoreDuplicate;
|
||||
var
|
||||
sm: TSourceMap;
|
||||
Obj: TJSONObject;
|
||||
El: TJSONData;
|
||||
Arr: TJSONArray;
|
||||
begin
|
||||
Obj:=nil;
|
||||
sm:=TSourceMap.Create('generated.js');
|
||||
try
|
||||
sm.AddMapping(1,0,'a.js',1,0);
|
||||
sm.AddMapping(2,0);
|
||||
sm.AddMapping(2,0);
|
||||
sm.AddMapping(3,0,'a.js',2,0);
|
||||
|
||||
//writeln(sm.ToString);
|
||||
{
|
||||
version: 3,
|
||||
file: 'generated.js',
|
||||
sources: ['a.js'],
|
||||
names: [],
|
||||
mappings: 'AAAA;A;AACA'
|
||||
}
|
||||
Obj:=sm.ToJSON;
|
||||
|
||||
// version
|
||||
El:=GetEl(Obj,'version',TJSONIntegerNumber);
|
||||
AssertEquals('json "version" value',El.AsInt64,3);
|
||||
|
||||
// file
|
||||
El:=GetEl(Obj,'file',TJSONString);
|
||||
AssertEquals('json "file" value',El.AsString,'generated.js');
|
||||
|
||||
// sources
|
||||
Arr:=TJSONArray(GetEl(Obj,'sources',TJSONArray));
|
||||
AssertEquals('json "sources".count',Arr.Count,1);
|
||||
El:=Arr[0];
|
||||
CheckEl('sources[0]',El,TJSONString);
|
||||
AssertEquals('json "sources[0]" value',El.AsString,'a.js');
|
||||
|
||||
// names
|
||||
Arr:=TJSONArray(GetEl(Obj,'names',TJSONArray));
|
||||
AssertEquals('json "names".count',Arr.Count,0);
|
||||
|
||||
// mappings
|
||||
El:=GetEl(Obj,'mappings',TJSONString);
|
||||
AssertEquals('json "mappings" value',El.AsString,'AAAA;A;AACA');
|
||||
|
||||
finally
|
||||
Obj.Free;
|
||||
sm.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TTestSrcMap.TestSrcMapNames;
|
||||
var
|
||||
sm: TSourceMap;
|
||||
Obj: TJSONObject;
|
||||
El: TJSONData;
|
||||
Arr: TJSONArray;
|
||||
begin
|
||||
Obj:=nil;
|
||||
sm:=TSourceMap.Create('generated.js');
|
||||
try
|
||||
sm.AddMapping(1,1,'a.js',2,2,'foo');
|
||||
sm.AddMapping(3,3,'a.js',4,4,'foo');
|
||||
writeln(sm.ToString);
|
||||
{
|
||||
version: 3,
|
||||
file: 'generated.js',
|
||||
sources: ['a.js'],
|
||||
names: ['foo'],
|
||||
mappings: 'CACEA;;GAEEA'
|
||||
}
|
||||
Obj:=sm.ToJSON;
|
||||
|
||||
// version
|
||||
El:=GetEl(Obj,'version',TJSONIntegerNumber);
|
||||
AssertEquals('json "version" value',El.AsInt64,3);
|
||||
|
||||
// file
|
||||
El:=GetEl(Obj,'file',TJSONString);
|
||||
AssertEquals('json "file" value',El.AsString,'generated.js');
|
||||
|
||||
// sources
|
||||
Arr:=TJSONArray(GetEl(Obj,'sources',TJSONArray));
|
||||
AssertEquals('json "sources".count',Arr.Count,1);
|
||||
El:=Arr[0];
|
||||
CheckEl('sources[0]',El,TJSONString);
|
||||
AssertEquals('json "sources[0]" value',El.AsString,'a.js');
|
||||
|
||||
// names
|
||||
Arr:=TJSONArray(GetEl(Obj,'names',TJSONArray));
|
||||
AssertEquals('json "names".count',Arr.Count,1);
|
||||
El:=Arr[0];
|
||||
CheckEl('names[0]',El,TJSONString);
|
||||
AssertEquals('json "names[0]" value',El.AsString,'foo');
|
||||
|
||||
// mappings
|
||||
El:=GetEl(Obj,'mappings',TJSONString);
|
||||
AssertEquals('json "mappings" value',El.AsString,'CACEA;;GAEEA');
|
||||
|
||||
finally
|
||||
Obj.Free;
|
||||
sm.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
initialization
|
||||
RegisterTests([TTestSrcMap]);
|
||||
end.
|
||||
|
@ -1,32 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<CONFIG>
|
||||
<ProjectOptions>
|
||||
<Version Value="9"/>
|
||||
<Version Value="10"/>
|
||||
<General>
|
||||
<SessionStorage Value="InProjectDir"/>
|
||||
<MainUnit Value="0"/>
|
||||
<UseXPManifest Value="True"/>
|
||||
<Icon Value="0"/>
|
||||
<ActiveWindowIndexAtStart Value="0"/>
|
||||
<UseAppBundle Value="False"/>
|
||||
</General>
|
||||
<VersionInfo>
|
||||
<Language Value=""/>
|
||||
<CharSet Value=""/>
|
||||
<StringTable ProductVersion=""/>
|
||||
</VersionInfo>
|
||||
<BuildModes Count="1">
|
||||
<Item1 Name="default" Default="True"/>
|
||||
</BuildModes>
|
||||
<PublishOptions>
|
||||
<Version Value="2"/>
|
||||
<IgnoreBinaries Value="False"/>
|
||||
<IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
|
||||
<ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/>
|
||||
</PublishOptions>
|
||||
<RunParams>
|
||||
<local>
|
||||
<FormatVersion Value="1"/>
|
||||
<CommandLineParams Value="--suite=TTestStatementWriter"/>
|
||||
<LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/>
|
||||
</local>
|
||||
</RunParams>
|
||||
<RequiredPackages Count="1">
|
||||
@ -34,260 +23,84 @@
|
||||
<PackageName Value="FCL"/>
|
||||
</Item1>
|
||||
</RequiredPackages>
|
||||
<Units Count="16">
|
||||
<Units Count="13">
|
||||
<Unit0>
|
||||
<Filename Value="testjs.lpr"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<UnitName Value="testjs"/>
|
||||
<WindowIndex Value="1"/>
|
||||
<TopLine Value="1"/>
|
||||
<CursorPos X="48" Y="3"/>
|
||||
<UsageCount Value="201"/>
|
||||
</Unit0>
|
||||
<Unit1>
|
||||
<Filename Value="tcscanner.pp"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<UnitName Value="tcscanner"/>
|
||||
<WindowIndex Value="1"/>
|
||||
<TopLine Value="1"/>
|
||||
<CursorPos X="17" Y="22"/>
|
||||
<UsageCount Value="201"/>
|
||||
</Unit1>
|
||||
<Unit2>
|
||||
<Filename Value="../src/jsbase.pp"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<UnitName Value="jsbase"/>
|
||||
<WindowIndex Value="1"/>
|
||||
<TopLine Value="1"/>
|
||||
<CursorPos X="1" Y="12"/>
|
||||
<UsageCount Value="200"/>
|
||||
</Unit2>
|
||||
<Unit3>
|
||||
<Filename Value="../src/jsparser.pp"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<UnitName Value="jsparser"/>
|
||||
<EditorIndex Value="3"/>
|
||||
<WindowIndex Value="1"/>
|
||||
<TopLine Value="67"/>
|
||||
<CursorPos X="14" Y="85"/>
|
||||
<UsageCount Value="201"/>
|
||||
<Loaded Value="True"/>
|
||||
</Unit3>
|
||||
<Unit4>
|
||||
<Filename Value="../src/jsscanner.pp"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<UnitName Value="JSScanner"/>
|
||||
<EditorIndex Value="6"/>
|
||||
<WindowIndex Value="1"/>
|
||||
<TopLine Value="342"/>
|
||||
<CursorPos X="76" Y="345"/>
|
||||
<UsageCount Value="201"/>
|
||||
<Loaded Value="True"/>
|
||||
</Unit4>
|
||||
<Unit5>
|
||||
<Filename Value="../src/jstree.pp"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<UnitName Value="jstree"/>
|
||||
<EditorIndex Value="5"/>
|
||||
<WindowIndex Value="1"/>
|
||||
<TopLine Value="739"/>
|
||||
<CursorPos X="3" Y="757"/>
|
||||
<UsageCount Value="200"/>
|
||||
<Loaded Value="True"/>
|
||||
</Unit5>
|
||||
<Unit6>
|
||||
<Filename Value="tcparser.pp"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<UnitName Value="tcparser"/>
|
||||
<EditorIndex Value="4"/>
|
||||
<WindowIndex Value="1"/>
|
||||
<TopLine Value="1878"/>
|
||||
<CursorPos X="3" Y="1883"/>
|
||||
<UsageCount Value="201"/>
|
||||
<Loaded Value="True"/>
|
||||
</Unit6>
|
||||
<Unit7>
|
||||
<Filename Value="../src/jswriter.pp"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<UnitName Value="jswriter"/>
|
||||
<EditorIndex Value="0"/>
|
||||
<WindowIndex Value="1"/>
|
||||
<TopLine Value="8"/>
|
||||
<CursorPos X="28" Y="15"/>
|
||||
<UsageCount Value="202"/>
|
||||
<Loaded Value="True"/>
|
||||
</Unit7>
|
||||
<Unit8>
|
||||
<Filename Value="tctextwriter.pp"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<UnitName Value="tctextwriter"/>
|
||||
<WindowIndex Value="1"/>
|
||||
<TopLine Value="4"/>
|
||||
<CursorPos X="15" Y="22"/>
|
||||
<UsageCount Value="201"/>
|
||||
</Unit8>
|
||||
<Unit9>
|
||||
<Filename Value="../../../../../projects/lazarus/components/fpcunit/console/consoletestrunner.pas"/>
|
||||
<UnitName Value="consoletestrunner"/>
|
||||
<WindowIndex Value="1"/>
|
||||
<TopLine Value="157"/>
|
||||
<CursorPos X="1" Y="175"/>
|
||||
<UsageCount Value="4"/>
|
||||
<Filename Value="tcwriter.pp"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit9>
|
||||
<Unit10>
|
||||
<Filename Value="tcwriter.pp"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<UnitName Value="tcwriter"/>
|
||||
<IsVisibleTab Value="True"/>
|
||||
<EditorIndex Value="2"/>
|
||||
<WindowIndex Value="1"/>
|
||||
<TopLine Value="668"/>
|
||||
<CursorPos X="45" Y="698"/>
|
||||
<UsageCount Value="220"/>
|
||||
<Loaded Value="True"/>
|
||||
</Unit10>
|
||||
<Unit11>
|
||||
<Filename Value="../../../../released/packages/fcl-json/src/fpjson.pp"/>
|
||||
<UnitName Value="fpjson"/>
|
||||
<WindowIndex Value="1"/>
|
||||
<TopLine Value="558"/>
|
||||
<CursorPos X="21" Y="580"/>
|
||||
<UsageCount Value="61"/>
|
||||
</Unit11>
|
||||
<Unit12>
|
||||
<Filename Value="../src/jstoken.pp"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<UnitName Value="jstoken"/>
|
||||
<EditorIndex Value="1"/>
|
||||
<WindowIndex Value="1"/>
|
||||
<TopLine Value="1"/>
|
||||
<CursorPos X="18" Y="8"/>
|
||||
<UsageCount Value="200"/>
|
||||
<Loaded Value="True"/>
|
||||
</Unit10>
|
||||
<Unit11>
|
||||
<Filename Value="tcsrcmap.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<UnitName Value="TCSrcMap"/>
|
||||
</Unit11>
|
||||
<Unit12>
|
||||
<Filename Value="../src/jssrcmap.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<UnitName Value="JSSrcMap"/>
|
||||
</Unit12>
|
||||
<Unit13>
|
||||
<Filename Value="../../../../released/packages/fcl-fpcunit/src/testregistry.pp"/>
|
||||
<UnitName Value="testregistry"/>
|
||||
<WindowIndex Value="1"/>
|
||||
<TopLine Value="106"/>
|
||||
<CursorPos X="22" Y="108"/>
|
||||
<UsageCount Value="13"/>
|
||||
</Unit13>
|
||||
<Unit14>
|
||||
<Filename Value="../../../rtl/tests/punit.pp"/>
|
||||
<UnitName Value="punit"/>
|
||||
<WindowIndex Value="1"/>
|
||||
<TopLine Value="405"/>
|
||||
<CursorPos X="41" Y="415"/>
|
||||
<UsageCount Value="18"/>
|
||||
</Unit14>
|
||||
<Unit15>
|
||||
<Filename Value="../../../../released/rtl/inc/mathh.inc"/>
|
||||
<WindowIndex Value="1"/>
|
||||
<TopLine Value="60"/>
|
||||
<CursorPos X="14" Y="78"/>
|
||||
<UsageCount Value="13"/>
|
||||
</Unit15>
|
||||
</Units>
|
||||
<JumpHistory Count="6" HistoryIndex="5">
|
||||
<Position1>
|
||||
<Filename Value="tcparser.pp"/>
|
||||
<Caret Line="1" Column="1" TopLine="1"/>
|
||||
</Position1>
|
||||
<Position2>
|
||||
<Filename Value="tcparser.pp"/>
|
||||
<Caret Line="1732" Column="55" TopLine="1713"/>
|
||||
</Position2>
|
||||
<Position3>
|
||||
<Filename Value="tcparser.pp"/>
|
||||
<Caret Line="1883" Column="3" TopLine="1878"/>
|
||||
</Position3>
|
||||
<Position4>
|
||||
<Filename Value="tcwriter.pp"/>
|
||||
<Caret Line="66" Column="43" TopLine="51"/>
|
||||
</Position4>
|
||||
<Position5>
|
||||
<Filename Value="tcwriter.pp"/>
|
||||
<Caret Line="76" Column="43" TopLine="48"/>
|
||||
</Position5>
|
||||
<Position6>
|
||||
<Filename Value="tcwriter.pp"/>
|
||||
<Caret Line="251" Column="31" TopLine="232"/>
|
||||
</Position6>
|
||||
</JumpHistory>
|
||||
</ProjectOptions>
|
||||
<CompilerOptions>
|
||||
<Version Value="11"/>
|
||||
<SearchPaths>
|
||||
<IncludeFiles Value="$(ProjOutDir)"/>
|
||||
<OtherUnitFiles Value="/home/michael/source/fcl-js/;..;../src"/>
|
||||
<OtherUnitFiles Value="../src"/>
|
||||
</SearchPaths>
|
||||
<CodeGeneration>
|
||||
<Checks>
|
||||
<IOChecks Value="True"/>
|
||||
<RangeChecks Value="True"/>
|
||||
<OverflowChecks Value="True"/>
|
||||
<StackChecks Value="True"/>
|
||||
</Checks>
|
||||
<VerifyObjMethodCallValidity Value="True"/>
|
||||
<Optimizations>
|
||||
<OptimizationLevel Value="0"/>
|
||||
</Optimizations>
|
||||
</CodeGeneration>
|
||||
<Linking>
|
||||
<Debugging>
|
||||
<UseHeaptrc Value="True"/>
|
||||
</Debugging>
|
||||
</Linking>
|
||||
<Other>
|
||||
<CompilerPath Value="$(CompPath)"/>
|
||||
</Other>
|
||||
</CompilerOptions>
|
||||
<Debugging>
|
||||
<BreakPoints Count="7">
|
||||
<Item1>
|
||||
<Kind Value="bpkSource"/>
|
||||
<WatchScope Value="wpsGlobal"/>
|
||||
<WatchKind Value="wpkWrite"/>
|
||||
<Source Value="../jsscanner.pp"/>
|
||||
<Line Value="717"/>
|
||||
</Item1>
|
||||
<Item2>
|
||||
<Kind Value="bpkSource"/>
|
||||
<WatchScope Value="wpsLocal"/>
|
||||
<WatchKind Value="wpkWrite"/>
|
||||
<Source Value="tcparser.pp"/>
|
||||
<Line Value="2086"/>
|
||||
</Item2>
|
||||
<Item3>
|
||||
<Kind Value="bpkSource"/>
|
||||
<WatchScope Value="wpsLocal"/>
|
||||
<WatchKind Value="wpkWrite"/>
|
||||
<Source Value="tcparser.pp"/>
|
||||
<Line Value="2566"/>
|
||||
</Item3>
|
||||
<Item4>
|
||||
<Kind Value="bpkSource"/>
|
||||
<WatchScope Value="wpsLocal"/>
|
||||
<WatchKind Value="wpkWrite"/>
|
||||
<Source Value="../src/jsparser.pp"/>
|
||||
<Line Value="845"/>
|
||||
</Item4>
|
||||
<Item5>
|
||||
<Kind Value="bpkSource"/>
|
||||
<WatchScope Value="wpsLocal"/>
|
||||
<WatchKind Value="wpkWrite"/>
|
||||
<Source Value="../src/jsparser.pp"/>
|
||||
<Line Value="754"/>
|
||||
</Item5>
|
||||
<Item6>
|
||||
<Kind Value="bpkSource"/>
|
||||
<WatchScope Value="wpsLocal"/>
|
||||
<WatchKind Value="wpkWrite"/>
|
||||
<Source Value="../src/jsparser.pp"/>
|
||||
<Line Value="1287"/>
|
||||
</Item6>
|
||||
<Item7>
|
||||
<Kind Value="bpkSource"/>
|
||||
<WatchScope Value="wpsLocal"/>
|
||||
<WatchKind Value="wpkWrite"/>
|
||||
<Source Value="tcparser.pp"/>
|
||||
<Line Value="2253"/>
|
||||
</Item7>
|
||||
</BreakPoints>
|
||||
<Exceptions Count="3">
|
||||
<Item1>
|
||||
<Name Value="EAbort"/>
|
||||
@ -300,5 +113,4 @@
|
||||
</Item3>
|
||||
</Exceptions>
|
||||
</Debugging>
|
||||
<EditorMacros Count="0"/>
|
||||
</CONFIG>
|
||||
|
@ -7,7 +7,7 @@ uses
|
||||
cwstring,
|
||||
{$ENDIF}
|
||||
Classes, consoletestrunner, tcscanner, jsparser, jsscanner, jstree, jsbase,
|
||||
tcparser, jswriter, tcwriter, jstoken;
|
||||
tcparser, jswriter, tcwriter, jstoken, JSSrcMap, TCSrcMap;
|
||||
|
||||
var
|
||||
Application: TTestRunner;
|
||||
|
Loading…
Reference in New Issue
Block a user