Преглед изворни кода

* DefinitelyTyped now converts

Michaël Van Canneyt пре 3 година
родитељ
комит
60a09b65f4

+ 163 - 0
packages/fcl-js/examples/cgutils.pp

@@ -0,0 +1,163 @@
+unit cgutils;
+
+{$mode ObjFPC}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, pascodegen, tstopas;
+
+Type
+   TSettings = record
+     basedir : string;
+     cachefile : string;
+   end;
+
+   { TLoggingConverter }
+
+   TLoggingConverter = Class(TTypescriptToPas)
+   private
+     FLogs: TStrings;
+     procedure DoMyLog(Sender: TObject; LogType: TCodegenLogType; const Msg: String);
+   Public
+     Constructor Create(Aowner: TComponent); override;
+     Property Logs : TStrings Read FLogs Write Flogs;
+   end;
+
+Procedure GetDeclarationFileNames(const BaseDir,aDir : String; aList: TStrings);
+Procedure ConvertFile(Const BaseDir,aFileName,aUnitName : String; aOptions : TConversionOptions; aPascal,aLog : TStrings);
+Function GetOutputUnitName(Const aFileName,aUnitName : String) : string;
+Function GetInputFileName(Const BaseDir,aFileName : String) : string;
+Function GetSettings : TSettings;
+
+implementation
+
+uses inifiles;
+
+Function GetSettings : TSettings;
+
+begin
+  Result.BaseDir:=ExtractFilePath(ParamStr(0));
+  Result.CacheFile:=GetTempDir(True)+'definitelytypedcache.lst';
+  With TIniFile.Create(GetAppConfigFile(True)) do
+    try
+      Result.BaseDir:=ReadString('Settings','BaseDir',Result.BaseDir);
+      Result.cachefile:=ReadString('Settings','CacheDir',Result.CacheFile);
+    finally
+      Free;
+    end;
+end;
+
+Procedure GetDeclarationFileNames(Const BaseDir,aDir : String; aList: TStrings);
+
+Var
+  Info : TSearchRec;
+  D,FN : string;
+
+begin
+  D:=IncludeTrailingPathDelimiter(aDir);
+  if FindFirst(D+'*.d.ts',0,Info)=0 then
+    try
+      Repeat
+      FN:=Info.Name;
+      if (FN<>'.') and (FN<>'..') then
+        Alist.Add(ExtractRelativePath(BaseDir,D+FN));
+      until FindNext(Info)<>0;
+    finally
+      FindClose(Info);
+    end;
+   if FindFirst(D+AllFilesMask,faDirectory,Info)=0 then
+      try
+        Repeat
+          if (Info.Attr and faDirectory)<>0 then
+            begin
+            FN:=Info.Name;
+            if (FN<>'.') and (FN<>'..') then
+              GetDeclarationFileNames(BaseDir,D+FN,aList);
+            end;
+        until FindNext(Info)<>0;
+      finally
+        FindClose(Info);
+      end;
+end;
+
+Function GetInputFileName(Const BaseDir,aFileName : String) : string;
+
+Var
+  BD,FN : String;
+
+begin
+  BD:=IncludeTrailingPathDelimiter(BaseDir);
+  FN:=BD+aFileName;
+  if Not FileExists(FN) then
+    if Not DirectoryExists(BD+aFileName) then
+      FN:=''
+    else
+      begin
+      FN:=IncludeTrailingPathDelimiter(BD+aFileName)+'index.d.ts';
+      if not FileExists(FN) then
+        Fn:='';
+      end;
+  if FN='' then
+    Raise ETSToPas.Create('No such file: '+aFileName);
+  Result:=FN;
+end;
+
+Function GetOutputUnitName(Const aFileName,aUnitName : String) : string;
+
+Var
+  UN : String;
+begin
+  UN:=aUnitName;
+  if aUnitName='' then
+    begin
+    UN:=ChangeFileExt(ChangeFileExt(ExtractFileName(aFilename),''),'');
+    if UN='index' then
+      UN:=ExtractFileName(ExcludeTrailingPathDelimiter(ExtractFilePath(aFileName)));
+    end;
+  Result:=UN;
+end;
+
+Procedure ConvertFile(Const BaseDir,aFileName,aUnitName : String; aOptions : TConversionOptions; aPascal,aLog : TStrings);
+
+Var
+  L : TLoggingConverter;
+  UN,Fn : String;
+
+begin
+  FN:=GetInputFileName(BaseDir,aFileName);
+  UN:=GetOutputUnitName(FN,aUnitName);
+  L:=TLoggingConverter.Create(Nil);
+  try
+    L.Options:=aOptions;
+    L.InputFileName:=FN;
+    L.OutputUnitName:=UN;
+    L.Logs:=aLog;
+    L.Execute;
+    aPascal.Assign(L.Source);
+  finally
+    L.Free;
+  end;
+end;
+
+{ TLoggingConverter }
+
+procedure TLoggingConverter.DoMyLog(Sender: TObject; LogType: TCodegenLogType; const Msg: String);
+
+Var
+  S : String;
+
+begin
+  Str(LogType,S);
+  If Assigned(Flogs) then
+    Flogs.Add('['+S+']: '+Msg);
+end;
+
+constructor TLoggingConverter.Create(Aowner: TComponent);
+begin
+  inherited Create(Aowner);
+  OnLog:=@DoMyLog;
+end;
+
+end.
+

+ 176 - 0
packages/fcl-js/examples/convcgi.lpr

@@ -0,0 +1,176 @@
+program convcgi;
+
+
+uses sysutils, classes, cgutils, {fphttpapp, } fpcgi, httpdefs, httproute;
+
+Procedure touch(fn : string);
+
+begin
+  With TStringList.Create do
+    try
+      Add(FN);
+      SaveToFile('/tmp/touch-'+FN);
+    finally
+      Free;
+    end;
+end;
+
+Procedure CreateJSONFileList(aDir : String; aFileName : string);
+
+Var
+  L,O : TStrings;
+  I : integer;
+  S : String;
+
+
+begin
+  O:=Nil;
+  L:=TStringList.Create;
+  try
+    O:=TstringList.Create;
+    GetDeclarationFileNames(aDir,aDir,L);
+    TstringList(l).Sort;
+    O.Add('var dtsfiles = [');
+    for I:=0 to L.Count-1 do
+      begin
+      S:=L[i];
+      S:=''''+StringReplace(S,'''','''''',[rfReplaceAll])+'''';
+      if I<L.Count-1 then
+        S:=S+',';
+      O.Add('  '+S);
+      end;
+    O.Add('  ];');
+    O.SaveToFile(aFileName);
+  finally
+    O.Free;
+    L.Free;
+  end;
+end;
+
+Procedure ConvertFile(const aFilename : string);
+
+Var
+  S : TSettings;
+  aPas : TStrings;
+  FN,aLine : string;
+
+begin
+  S:=GetSettings;
+  aPas:=TStringList.Create;
+  try
+    if FileExists(aFileName) then
+      FN:=ExtractRelativePath(S.BaseDir,aFilename)
+    else
+      FN:=aFileName;
+    cgUtils.ConvertFile(S.BaseDir,FN,'',[],aPas,Nil);
+    for aLine in aPas do
+      writeln(aLine);
+  Finally
+    aPas.Free;
+  end;
+end;
+
+procedure DoList(ARequest: TRequest; AResponse: TResponse);
+Var
+  S : TSettings;
+  aList : TStrings;
+
+begin
+  Touch('i');
+  S:=GetSettings;
+  Touch('k');
+  aList:=TstringList.Create;
+  try
+    aList.Add(S.BaseDir);
+    aList.Add(S.cachefile);
+    Alist.SaveToFile('/tmp/sett.txt');
+    aList.Clear;
+    if Not FileExists(S.cachefile) then
+      CreateJSONFileList(S.BaseDir,S.cachefile);
+    aList.LoadFromFile(S.cachefile);
+    aResponse.Content:=aList.text;
+    aResponse.ContentLength:=Length(aResponse.Content);
+    aResponse.ContentType:='application/javascript';
+    aResponse.SendResponse;
+  finally
+    aList.Free;
+  end;
+end;
+
+procedure DoConvertFile(ARequest: TRequest; AResponse: TResponse);
+
+Var
+  S : TSettings;
+  aPas : TStrings;
+  aFileName : string;
+
+begin
+  Touch('g');
+  S:=GetSettings;
+  Touch('h');
+  aPas:=TStringList.Create;
+  try
+    aFileName:=aRequest.QueryFields.Values['file'];
+    cgUtils.ConvertFile(S.BaseDir,aFileName,'',[],aPas,Nil);
+    aResponse.Content:=aPas.text;
+    aResponse.ContentLength:=Length(aResponse.Content);
+    aResponse.ContentType:='text/x-pascal';
+    aResponse.SendResponse;
+  Finally
+    aPas.Free;
+  end;
+end;
+
+procedure d;
+
+Var
+  S : TSettings;
+  aList : TStrings;
+
+begin
+  S:=GetSettings;
+  aList:=TstringList.Create;
+  try
+    if Not FileExists(S.cachefile) then
+      CreateJSONFileList(S.BaseDir,S.cachefile);
+    aList.LoadFromFile(S.cachefile);
+    Writeln(aList.text);
+//    aResponse.Content:=aList.text;
+//    aResponse.ContentLength:=Length(aResponse.Content);
+//    aResponse.ContentType:='application/javascript';
+//    aResponse.SendResponse;
+  finally
+    aList.Free;
+  end;
+end;
+
+begin
+//  D;
+//  exit;
+  Touch('w0');
+  if GetEnvironmentVariable('REQUEST_METHOD')='' then
+    begin
+    Touch('wa');
+    if ParamCount=2 then
+      CreateJSONFileList(Paramstr(1),ParamStr(2))
+    else if ParamCount=1 then
+      ConvertFile(Paramstr(1));
+    Touch('wb');
+    end
+  else
+    begin
+    Touch('a');
+    HTTPRouter.RegisterRoute('list',rmGet,@DoList);
+    Touch('b');
+    HTTPRouter.RegisterRoute('convert',rmAll,@DoConvertFile);
+    Touch('c');
+    // Application.Port:=8080;
+    Application.Title:='Typescript to pascal converter';
+    Touch('d');
+    Application.Initialize;
+    Touch('e');
+    Application.Run;
+    Touch('f');
+    end
+end.
+

+ 251 - 0
packages/fcl-js/examples/dts2pas.pp

@@ -0,0 +1,251 @@
+{ *********************************************************************
+    This file is part of the Free Component Library (FCL)
+    Copyright (c) 2021 Michael Van Canneyt.
+
+    Javascript & typescript parser demo
+
+    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.
+
+  **********************************************************************}
+
+program dts2pas;
+
+{$mode objfpc}{$H+}
+
+uses
+  Classes, SysUtils, StrUtils, CustApp, pascodegen, tstopas;
+
+type
+  { TParseTSApplication }
+
+  TParseTSApplication = class(TCustomApplication)
+  private
+    FVerbose,
+    FWeb : Boolean;
+    FLinks,
+    FUnits,
+    FAliases : TStringArray;
+
+    procedure AddAliases(Converter: TTypescriptToPas; aAlias: String);
+    procedure AddWebAliases(S: Tstrings);
+    procedure AddJSAliases(S: Tstrings);
+    procedure DoLog(Sender: TObject; LogType: TCodegenLogType; const Msg: String);
+    function ParseFile(const aInputFileName, aOutputFileName, aUnitName: string): Boolean;
+  protected
+    procedure DoRun; override;
+  public
+    constructor Create(TheOwner: TComponent); override;
+    destructor Destroy; override;
+    procedure Usage(Msg : string); virtual;
+  end;
+
+{ TParseTSApplication }
+
+procedure TParseTSApplication.DoRun;
+
+var
+  ErrorMsg: String;
+  aUnitName,InputFile,OutputFile : String;
+
+begin
+  Terminate;
+  ErrorMsg:=CheckOptions('hi:o:a:wx:u:vl:', ['help','input:','output:','alias:','web','extra-units:','unitname:','verbose','link:']);
+  if (ErrorMsg<>'') or HasOption('h','help') then
+    begin
+    Usage(ErrorMsg);
+    Exit;
+    end;
+  InputFile:=GetOptionValue('i','input');
+  OutputFile:=GetOptionValue('o','output');
+  FAliases:=GetOptionValues('a','alias');
+  FLinks:=GetOptionValues('l','link');
+  FUnits:=GetOptionValues('x','extra-units');
+  FWeb:=HasOption('w','web');
+  FVerbose:=HasOption('v','verbose');
+  If OutputFile='' then
+    if InputFile.EndsWith('d.ts') then
+      OutputFile:=ChangeFileExt(ChangeFileExt(InputFile,''),'.pp')
+    else
+      OutputFile:=ChangeFileExt(InputFile,'.pp');
+  aUnitName:=GetOptionValue('u','unitname');
+  if aUnitName='' then
+    aUnitName:=ChangeFileExt(ExtractFileName(outputFile),'');
+  if not ParseFile(InputFIle,OutputFile,aUnitName) then
+    ExitCode:=1;
+end;
+
+procedure TParseTSApplication.AddAliases(Converter : TTypescriptToPas; aAlias : String);
+
+Var
+  aList : TStringList;
+  S : String;
+
+begin
+  if (aAlias='') then
+    exit;
+  if aAlias[1]='@' then
+    begin
+    AList:=TStringList.Create;
+    try
+      aList.LoadFromFile(Copy(aAlias,2,Length(aAlias)-1));
+      Converter.TypeAliases.AddStrings(AList);
+    finally
+      AList.Free;
+    end;
+    end
+  else
+    For S in SplitString(aAlias,',;') do
+      if Pos('=',S)<>0 then
+        Converter.TypeAliases.Add(S);
+end;
+
+Function TParseTSApplication.ParseFile(const aInputFileName,aOutputFileName,aUnitName : string) : Boolean;
+
+Var
+  Converter : TTypescriptToPas;
+  A, S,U,U1,U2 : String;
+  L : TStringArray;
+begin
+  Result:=False;
+  try
+    Converter:=TTypescriptToPas.Create(Self);
+    try
+      AddJSAliases(Converter.TypeAliases);
+      For A in FAliases do
+        AddAliases(Converter,A);
+      if FWeb then
+        begin
+        AddWebAliases(Converter.TypeAliases);
+        Funits:=Concat(Funits, [ 'web' ]);
+        end;
+      U:='';
+      For S in FUnits do
+        begin
+        L:=SplitString(S,',');
+        For U1 in L do
+          begin
+          U2:=Trim(U1);
+          if U2<>'' then
+            begin
+            if U<>'' then
+              U:=U+', ';
+            U:=U+U2;
+            end;
+          end;
+        end;
+      For S in Flinks do
+        Converter.LinkStatements.Add(S);
+      Converter.Verbose:=FVerbose;
+      Converter.Options:=Converter.Options+[coInterfaceAsClass];
+      Converter.ExtraUnits:=U;
+      Converter.InputFileName:=aInputFileName;
+      Converter.OutputFileName:=aOutputFileName;
+      Converter.OutputUnitName:=aUnitName;
+      Converter.Execute;
+      Converter.OnLog:=@DoLog;
+      Result:=True;
+    finally
+      Converter.Free;
+    end;
+  except
+    on E : Exception do
+      Writeln('Conversion error ',E.ClassName,' : ',E.Message);
+  end;
+end;
+
+constructor TParseTSApplication.Create(TheOwner: TComponent);
+begin
+  inherited Create(TheOwner);
+  StopOnException:=True;
+end;
+
+destructor TParseTSApplication.Destroy;
+begin
+  inherited Destroy;
+end;
+
+procedure TParseTSApplication.AddWebAliases(S : Tstrings);
+
+begin
+  With S do
+    begin
+    {$i web.inc}
+    end;
+end;
+
+procedure TParseTSApplication.AddJSAliases(S: Tstrings);
+begin
+  With S do
+    begin
+    Add('Object=TJSObject');
+    Add('Function=TJSFunction');
+    Add('RegExp=TJSRegexp');
+    Add('Promise=TJSPromise');
+    Add('Date=TJSDate');
+    Add('Array=TJSArray');
+    Add('Iterator=TJSIterator');
+    Add('IteratorResult=TJSIteratorResult');
+    Add('AsyncIterator=TJSAsyncIterator');
+    Add('ArrayBuffer=TJSArrayBuffer');
+    Add('Set=TJSSet');
+    Add('Map=TJSMap');
+    Add('BufferSource=TJSBufferSource');
+    Add('DataView=TJSDataView');
+    Add('Int8Array=TJSInt8Array');
+    Add('Int8ClampedArray=TJSInt8ClampedArray');
+    Add('Int16Array=TJSInt16Array');
+    Add('Int32Array=TJSInt32Array');
+    Add('Uint8Array=TJSUInt8Array');
+    Add('Uint8ClampedArray=TJSUInt8ClampedArray');
+    Add('Uint16Array=TJSUInt16Array');
+    Add('Uint32Array=TJSUInt32Array');
+    Add('Float32Array=TJSFloat32Array');
+    Add('Float64Array=TJSFloat64Array');
+    Add('JSON=TJSJSON');
+    Add('TextDecoder=TJSTextDecoder');
+    Add('TextEncoder=TJSTextEncoder');
+    Add('SyntaxError=TJSSyntaxError');
+    Add('Error=TJSError');
+    end;
+end;
+
+procedure TParseTSApplication.DoLog(Sender: TObject; LogType: TCodegenLogType; const Msg: String);
+begin
+  Writeln('[',LogType,'] : ',Msg);
+end;
+
+
+procedure TParseTSApplication.Usage(Msg: string);
+begin
+  if Msg<>'' then
+    Writeln('Error : ',Msg);
+  writeln('Usage: ', ExeName, ' [options]');
+  Writeln('Where options is one or mote of:');
+  Writeln('-a --alias=ALIAS      Define type aliases (option can be speficied multiple times)');
+  Writeln('                      where ALIAS is one of');
+  Writeln('                      a comma-separated list of Alias=TypeName values');
+  Writeln('                      a @FILE : list is read from FILENAME, one line per alias');
+  Writeln('-h --help             Display this help text');
+  Writeln('-i --input=FILENAME   Parse .d.ts file FILENAME');
+  Writeln('-l --link=FILENAME    add {$linklib FILENAME} statement. (option can be specified multiple times)');
+  Writeln('-o --output=FILENAME  Output unit in file FILENAME');
+  Writeln('-u --unit=NAME        Set output unitname');
+  Writeln('-w --web              Add web unit to uses, define type aliases for web unit');
+  Writeln('-x --extra-units=UNITLIST   Add units (comma-separated list of unit names) to uses clause.');
+  Writeln('                      This option can be specified multiple times.');
+end;
+
+var
+  Application: TParseTSApplication;
+begin
+  Application:=TParseTSApplication.Create(nil);
+  Application.Title:='My Application';
+  Application.Run;
+  Application.Free;
+end.
+

+ 1 - 1
packages/fcl-js/examples/parsefiles.pas

@@ -91,7 +91,7 @@ begin
     aFile.LoadFromFile(aFileName);
     S:=TStringStream.Create('');
     S.LoadFromFile(aFileName);
-    P:=TJSParser.Create(S,ecma2021,FTypescript);
+    P:=TJSParser.Create(S,ecma2021,FTypescript,aFileName);
     try
       El:=P.Parse;
       Result:=True;

+ 166 - 0
packages/fcl-js/examples/web.inc

@@ -0,0 +1,166 @@
+Add('Attr=TJSAttr');
+Add('AudioTrackList=TJSHTMLAudioTrackList');
+Add('AudioTrack=TJSHTMLAudioTrack');
+Add('Blob=TJSBlob');
+Add('Body=TJSBody');
+Add('CanvasGradient=TJSCanvasGradient');
+Add('CanvasPattern=TJSCanvasPattern');
+Add('CanvasRenderingContext2D=TJSCanvasRenderingContext2D');
+Add('CharacterData=TJSCharacterData');
+Add('ClipboardEvent=TJSClipBoardEvent');
+Add('ClipboardItem=TJSClipBoardItem');
+Add('Clipboard=TJSClipBoard');
+Add('CloseEvent=TJSCloseEvent');
+Add('Console=TJSConsole');
+Add('CryptoKey=TJSCryptoKey');
+Add('Crypto=TJSCrypto');
+Add('CSSRuleList=TJSCSSRuleList');
+Add('CSSRule=TJSCSSRule');
+Add('CSSStyleDeclaration=TJSCSSStyleDeclaration');
+Add('CSSStyleRule=TJSCSSStyleRule');
+Add('CSSStyleSheet=TJSCSSStyleSheet');
+Add('DataTransferItemList=TJSDataTransferItemList');
+Add('DataTransferItem=TJSDataTransferItem');
+Add('DataTransfer=TJSDataTransfer');
+Add('DocumentFragment=TJSDocumentFragment');
+Add('DocumentImplementation=TJSDOMImplementation');
+Add('Document=TJSDocument');
+Add('DocumentType=TJSDocumentType');
+Add('DOMException=TJSDOMException');
+Add('DOMParser=TDOMParser');
+Add('DOMRect=TJSDOMRect');
+Add('DOMSettableTokenList=TJSDOMSettableTokenList');
+Add('DOMTokenList=TJSDOMTokenList');
+Add('DragEvent=TJSDragEvent');
+Add('Element=TJSElement');
+Add('ErrorEvent=TJSErrorEvent');
+Add('EventListenerEvent=TEventListenerEvent');
+Add('EventTarget=TJSEventTarget');
+Add('Event=TJSEvent');
+Add('FileList=TJSHTMLFileList');
+Add('FileReader=TJSFileReader');
+Add('FileSystemDirectoryHandle=TJSFileSystemDirectoryHandle');
+Add('FileSystemFileHandle=TJSFileSystemFileHandle');
+Add('FileSystemHandle=TJSFileSystemHandle');
+Add('FileSystemWritableFileStream=TJSFileSystemWritableFileStream');
+Add('File=TJSHTMLFile');
+Add('FormData=TJSFormData');
+Add('GeoLocation=TJSGeoLocation');
+Add('HashChangeEvent=TJSHashChangeEvent');
+Add('Headers=TJSHTMLHeaders');
+Add('History=TJSHistory');
+Add('HTMLAnchorElement=TJSHTMLAnchorElement');
+Add('HTMLAudioElement=TJSHTMLAudioElement');
+Add('HTMLButtonElement=TJSHTMLButtonElement');
+Add('HTMLCanvasElement=TJSHTMLCanvasElement');
+Add('HTMLCollection=TJSHTMLCollection');
+Add('HTMLDivElement=TJSHTMLDivElement');
+Add('HTMLDocument=TJSHTMLDocument');
+Add('HTMLElement=TJSHTMLElement');
+Add('HTMLEmbedElement=TJSHTMLEmbedElement');
+Add('HTMLFormControlsCollection=TJSHTMLFormControlsCollection');
+Add('HTMLFormElement=TJSHTMLFormElement');
+Add('HTMLIFrameElement=TJSHTMLIFrameElement');
+Add('HTMLInputElement=TJSHTMLInputElement');
+Add('HTMLLabelElement=TJSHTMLLabelElement');
+Add('HTMLLinkElement=TJSHTMLLinkElement');
+Add('HTMLMediaElement=TJSHTMLMediaElement');
+Add('HTMLMenuElement=TJSHTMLMenuElement');
+Add('HTMLOptGroupElement=TJSHTMLOptGroupElement');
+Add('HTMLOptionsCollection=TJSHTMLOptionsCollection');
+Add('HTMLOutputElement=TJSHTMLOutputElement');
+Add('HTMLProgressElement=TJSHTMLProgressElement');
+Add('HTMLScriptElement=TJSHTMLScriptElement');
+Add('HTMLSelectElement=TJSHTMLSelectElement');
+Add('HTMLStyleElement=TJSHTMLStyleElement');
+Add('HTMLTableCellElement=TJSHTMLTableCellElement');
+Add('HTMLTableDataCellElement=TJSHTMLTableDataCellElement');
+Add('HTMLTableElement=TJSHTMLTableElement');
+Add('HTMLTableRowElement=TJSHTMLTableRowElement');
+Add('HTMLTableSectionElement=TJSHTMLTableSectionElement');
+Add('HTMLTemplateElement=TJSHTMLTemplateElement');
+Add('HTMLTextAreaElement=TJSHTMLTextAreaElement');
+Add('HTMLVideoElement=TJSHTMLVideoElement');
+Add('IDBCursorDirection=TJSIDBCursorDirection');
+Add('IDBCursor=TJSIDBCursor');
+Add('IDBDatabase=TIDBDatabase');
+Add('IDBFactory=TJSIDBFactory');
+Add('IDBIndex=TJSIDBIndex');
+Add('IDBKeyRange=TJSIDBKeyRange');
+Add('IDBObjectStore=TJSIDBObjectStore');
+Add('IDBOpenDBRequest=TJSIDBOpenDBRequest');
+Add('IDBRequest=TJSIDBRequest');
+Add('IDBTransaction=TJSIDBTransaction');
+Add('IdleDeadline=TJSIdleDeadline');
+Add('ImageData=TJSImageData');
+Add('Image=TJSHTMLImageElement');
+Add('IVisible=TJSVisibleItem');
+Add('KeyboardEvent=TJSKeyboardEvent');
+Add('LocationBar=TJSLocationBar');
+Add('Location=TJSLocation');
+Add('MediaController=TJSHTMLMediaController');
+Add('MediaDevices=TJSMediaDevices');
+Add('MediaError=TJSMEdiaError');
+Add('MediaQueryList=TJSMediaQueryList');
+Add('MediaStream=TJSHTMLMediaStream');
+Add('MediaStreamTrack=TJSMediaStreamTrack');
+Add('MenuBar=TJSMenuBar');
+Add('MessageEvent=TJSMessageEvent');
+Add('MessagePort=TJSMessagePort');
+Add('MouseEvent=TJSMouseEvent');
+Add('MutationObserver=TJSMutationObserver');
+Add('NamedNodeMap=TJSNamedNodeMap');
+Add('Navigator=TJSNavigator');
+Add('NodeFilter=TJSNodeFilter');
+Add('NodeList=TJSNodeList');
+Add('Node=TJSNode');
+Add('Option=TJSHTMLOptionElement');
+Add('Path2D=TJSPath2D');
+Add('Performance=TJSPerformance');
+Add('PermissionStatus=TJSPermissionStatus');
+Add('Permissions=TJSPermissions');
+Add('PersonalBar=TJSPersonalBar');
+Add('PointerEvent=TJSPointerEvent');
+Add('PopStateEvent=TJSPopStateEvent');
+Add('ProcessingInstruction=TJSProcessingInstruction');
+Add('ProgressEvent=TJSProgressEvent');
+Add('Range=TJSRange');
+Add('ReadableStream=TJSReadableStream');
+Add('Response=TJSResponse');
+Add('Screen=TJSScreen');
+Add('ScrollBars=TJSScrollBars');
+Add('Selection=TJSSelection');
+Add('ServiceWorkerContainer=TJSServiceWorkerContainer');
+Add('ServiceWorkerRegistration=TJSServiceWorkerRegistration');
+Add('ServiceWorker=TJSServiceWorker');
+Add('SharedWorker=TJSSharedWorker');
+Add('StorageEvent=TJSStorageEvent');
+Add('Storage=TJSStorage');
+Add('StyleSheetList=TJSStyleSheetList');
+Add('StyleSheet=TJSStyleSheet');
+Add('SubtleCrypto=TJSSubtleCrypto');
+Add('TextMetrics=TJSTextMetrics');
+Add('TextTrackList=TJSHTMLTextTrackList');
+Add('TextTrack=TJSHTMLTextTrack');
+Add('ToolBar=TJSToolBar');
+Add('TouchEvent=TJSTouchEvent');
+Add('TouchList=TJSTouchList');
+Add('Touch=TJSTouch');
+Add('TreeWalker=TJSTreeWalker');
+Add('UIEvent=TJSUIEvent');
+Add('URLSearchParams=TJSURLSearchParams');
+Add('URL=TJSURL');
+Add('ValidityState=TJSValidityState');
+Add('VideoTrackList=TJSHTMLVideoTrackList');
+Add('VideoTrack=TJSHTMLVideoTrack');
+Add('WebSocket=TJSWebSocket');
+Add('WheelEvent=TJSWheelEvent');
+Add('Window=TJSWindow');
+Add('Worker=TJSWorker');
+Add('WritableStream=TJSWritableStream');
+Add('XMLHttpRequestEventTarget=TJSXMLHttpRequestEventTarget');
+Add('XMLHttpRequest=TJSXMLHttpRequest');
+Add('XMLHttpRequestUpload=TJSXMLHttpRequestUpload');
+Add('XPathExpression=TJSXPathExpression');
+Add('XPathNSResolver=TJSXPathNSResolver');
+Add('XPathResult=TJSXPathResult');

Разлика између датотеке није приказан због своје велике величине
+ 416 - 248
packages/fcl-js/src/jsparser.pp


+ 58 - 13
packages/fcl-js/src/jsscanner.pp

@@ -19,7 +19,7 @@ unit JSScanner;
 
 interface
 
-uses SysUtils, Classes, jsbase, jstoken;
+uses SysUtils, Classes, jstoken;
 
 Type
   TECMAVersion = (ecma5,ecma2015,ecma2021);
@@ -47,10 +47,16 @@ resourcestring
   SErrInvalidRegularExpression = 'Syntax error in regular expression: / expected, got: %s';
 
 Type
+
+  { TLineReader }
+
   TLineReader = class
+  private
+    FLastLF: string;
   public
     function IsEOF: Boolean; virtual; abstract;
     function ReadLine: string; virtual; abstract;
+    Property LastLF : string Read FLastLF Write FLastLF;
   end;
 
   { TStreamLineReader }
@@ -96,6 +102,7 @@ Type
     FCurToken: TJSToken;
     FCurTokenString: String;
     FCurLine: string;
+    FWasMultilineString: Boolean;
     TokenStr: PChar;
     FWasEndOfLine : Boolean;
     FSourceStream : TStream;
@@ -119,7 +126,7 @@ Type
     procedure Error(const Msg: string; Args: array of Const);overload;
   public
     constructor Create(ALineReader: TLineReader; aECMAVersion : TECMAVersion = ecma5);
-    constructor Create(AStream : TStream; aECMAVersion : TECMAVersion = ecma5);
+    constructor Create(AStream : TStream; aECMAVersion : TECMAVersion = ecma5; aFileName : string = '');
     destructor Destroy; override;
     procedure OpenFile(const AFilename: string);
     Function FetchRegexprToken: TJSToken;
@@ -138,6 +145,7 @@ Type
     property ECMAVersion : TECMAVersion Read FECMAVersion Write SetECMAVersion;
     Property IsTypeScript : Boolean Read FIsTypeScript Write SetIsTypeScript;
     Property DisableRShift : Boolean Read FDisableRShift Write FDisableRShift;
+    Property WasMultilineString : Boolean Read FWasMultilineString;
   end;
 
 
@@ -177,10 +185,11 @@ begin
   FNonKeyWords:=NonJSKeywords[aECMAVersion];
 end;
 
-constructor TJSScanner.Create(AStream: TStream; aECMAVersion: TECMAVersion);
+constructor TJSScanner.Create(AStream: TStream; aECMAVersion: TECMAVersion; aFileName : string = '');
 begin
   FSourceStream:=ASTream;
   FOwnSourceFile:=True;
+  FSourceFilename:=aFilename;
   Create(TStreamLineReader.Create(AStream),aECMAVersion);
 end;
 
@@ -419,6 +428,16 @@ Var
   Len,OLen: Integer;
   S : String;
 
+  Procedure AddToString;
+
+  begin
+    Len := TokenStr - TokenStart;
+    SetLength(FCurTokenString, OLen + Len);
+    if Len > 0 then
+      Move(TokenStart^, FCurTokenString[OLen+1], Len);
+    OLen:=OLen+Len;
+  end;
+
 begin
   Delim:=TokenStr[0];
   Inc(TokenStr);
@@ -459,16 +478,25 @@ begin
       // Inc(TokenStr);
       TokenStart := TokenStr+1;
       end;
-    if TokenStr[0] = #0 then
-      Error(SErrOpenString);
     Inc(TokenStr);
+    if TokenStr[0] = #0 then
+      begin
+      if Delim<>'`' then
+        Error(SErrOpenString)
+      else
+        begin
+        AddToString;
+        FCurTokenString:=FCurTokenString+FSourceFile.LastLF;
+        oLen:=oLen+Length(FSourceFile.LastLF);
+        if Not FetchLine then
+          Error(SErrOpenString);
+        TokenStart:=TokenStr;
+        end
+      end;
     end;
   if TokenStr[0] = #0 then
     Error(SErrOpenString);
-  Len := TokenStr - TokenStart;
-  SetLength(FCurTokenString, OLen + Len);
-  if Len > 0 then
-    Move(TokenStart^, FCurTokenString[OLen+1], Len);
+  AddToString;
   Inc(TokenStr);
   Result := tjsString;
 end;
@@ -478,10 +506,8 @@ function TJSScanner.DoNumericLiteral :TJSToken;
 Var
   TokenStart : PChar;
   Len : Integer;
-  Hex : Boolean;
 
 begin
-  Hex:=False;
   TokenStart := TokenStr;
   while true do
     begin
@@ -586,8 +612,11 @@ begin
          Result:=CommentDiv;
       #9, ' ':
          Result := DoWhiteSpace;
-      '''','"':
+      '''','"','`':
+         begin
+         FWasMultilineString:=(TokenStr[0]='`');
          Result:=DoStringLiteral;
+         end;
       '0'..'9':
          Result:=DoNumericLiteral;
      '&':
@@ -865,6 +894,18 @@ begin
       Inc(TokenStr);
       Result := tJSCurlyBraceClose;
       end;
+    #$C2:
+      begin
+      // Non-breaking space in UTF8
+      if TokenStr[1]=#$A0 then
+        begin
+        Inc(TokenStr);
+        Inc(TokenStr);
+        Result:=tjsWhiteSpace;
+        end
+      else
+        Result:=DoIdentifier;
+      end;
    else
      Result:=DoIdentifier;
    end; // Case
@@ -917,8 +958,8 @@ Var
   PRun : PByte;
 
 begin
+  Result:='';
   FPos:=FBufPos;
-  SetLength(Result,0);
   Repeat
     PRun:=@Buffer[FBufPos];
     While (FBufPos<FBufLen) and Not (PRun^ in [10,13]) do
@@ -948,6 +989,7 @@ begin
     end;
   If (PRun^ in [10,13]) and (FBufPos<FBufLen) then
     begin
+    LastLF:=PChar(PRun)^;
     Inc(FBufPos);
     // Check #13#10
     If (PRun^=13) then
@@ -955,7 +997,10 @@ begin
       If (FBufPos=FBufLen) then
         FillBuffer;
       If (FBufPos<FBufLen) and (Buffer[FBufpos]=10) then
+        begin
+        LastLF:=LastLF+#10;
         Inc(FBufPos);
+        end;
       end;
     end;
 end;

+ 335 - 18
packages/fcl-js/src/jstree.pp

@@ -131,7 +131,9 @@ Type
   TJSFuncDef = Class(TJSObject)
   private
     FBody: TJSFunctionBody;
+    FIsAsserts: Boolean;
     FIsAsync: Boolean;
+    FIsConstructor: Boolean;
     FIsEmpty: Boolean;
     FName: TJSString;
     FParams: TStrings;
@@ -150,7 +152,9 @@ Type
     Property Name : TJSString Read FName Write FName;
     Property IsEmpty : Boolean Read FIsEmpty Write FIsEmpty;
     Property IsAsync : Boolean Read FIsAsync Write FIsAsync;
-    Property GenericParams : TJSElementNodes Read FGenericParams Write FGenericParams; 
+    Property IsAsserts : Boolean Read FIsAsserts Write FIsAsserts;
+    Property IsConstructor : Boolean Read FIsConstructor Write FIsConstructor;
+    Property GenericParams : TJSElementNodes Read FGenericParams Write FGenericParams;
   end;
 
   { TJSElement }
@@ -162,8 +166,12 @@ Type
     FLine: Integer;
     FColumn: Integer;
     FSource: String;
+  Public
+    class var
+      GlobalFreeHook : Procedure(aEl : TJSElement) of object;
   Public
     Constructor Create(ALine,AColumn : Integer; Const ASource : String = ''); virtual;
+    Destructor Destroy; override;
     Procedure AssignPosition(El: TJSElement); virtual;
     Property Source : String Read FSource Write FSource;
     Property Line : Integer Read FLine Write FLine;
@@ -252,11 +260,13 @@ Type
   TJSArrayLiteral = Class(TJSElement)
   private
     FElements: TJSArrayLiteralElements;
+    function GetCount: Integer;
   Public
     Constructor Create(ALine,AColumn : Integer; const ASource : String = ''); override;
     procedure AddElement(El: TJSElement);
     Destructor Destroy; override;
     Property Elements : TJSArrayLiteralElements Read FElements;
+    Property Count : Integer Read GetCount;
   end;
 
   { TJSObjectLiteralElement - an item of TJSObjectLiteralElements }
@@ -822,6 +832,7 @@ Type
   TJSVarDeclaration = Class(TJSElement)
   private
     FInit: TJSElement;
+    FIsUnique: Boolean;
     FName: TJSString;
     FOwnsType: Boolean;
     FTyped: TJSTypeDef;
@@ -837,6 +848,7 @@ Type
     // Typescript type. Setting to non-nil value will set OwnsType
     Property Typed : TJSTypeDef Read FTyped Write SetTyped;
     Property OwnsType : Boolean Read FOwnsType;
+    Property IsUnique : Boolean Read FIsUnique Write FIsUnique;
   end;
 
   { TJSIfStatement - e.g. if (Cond) btrue else bfalse }
@@ -1128,11 +1140,26 @@ Type
     FNode: TJSElement;
   Public
     Destructor Destroy; override;
+    Procedure Assign(aSource : TPersistent); override;
     Property Node : TJSElement Read FNode Write FNode;
     Property IsAmbient : Boolean Read FIsAmbient Write FIsAmbient;
     Property IsExport : Boolean Read FIsExport Write FIsExport;
   end;
 
+  { TJSTransientElementNode }
+
+  // Will not free the node.
+  TJSTransientElementNode = Class(TJSElementNode)
+  Public
+    Destructor Destroy; override;
+  end;
+  { TElementNodeEnumerator }
+
+  TElementNodeEnumerator = Class(TCollectionEnumerator)
+  public
+    function GetCurrent: TJSElementNode; reintroduce;
+    property Current: TJSElementNode read GetCurrent;
+  end;
   { TJSElementNodes - see TJSSourceElements }
 
   TJSElementNodes = Class(TCollection)
@@ -1144,6 +1171,7 @@ Type
   Public
     Destructor Destroy; override;
     Procedure ClearNodes;
+    Function GetEnumerator : TElementNodeEnumerator;
     Function AddNode(aIsAmbient : Boolean = False; aIsExport : Boolean = False) : TJSElementNode;
     Function AddNode(aEl : TJSElement; aIsAmbient : Boolean = False; aIsExport : Boolean = False) : TJSElementNode;
     Function InsertNode(Index: integer) : TJSElementNode;
@@ -1158,17 +1186,29 @@ Type
   TJSTypedParam = Class(TJSElementNode)
   private
     FDestructured: TJSObjectTypeDef;
+    FIsInferred: Boolean;
     FIsOptional: Boolean;
     FIsSpread: Boolean;
     FName: jsbase.TJSString;
+    function GetTypeDef: TJSTypeDef;
   Public
+    Procedure Assign(Source : TPersistent); override;
     Destructor Destroy; override;
+    Property Type_ : TJSTypeDef read GetTypeDef;
     Property Name : jsbase.TJSString Read FName Write FName;
+    Property IsInferred : Boolean Read FIsInferred Write FIsInferred;
     Property IsOptional : Boolean Read FIsOptional Write FIsOptional;
     Property IsSpread : Boolean Read FIsSpread Write FIsSpread;
     Property Destructured : TJSObjectTypeDef Read FDestructured Write FDestructured;
   end;
 
+  { TJSTransientParamType }
+
+  TJSTransientParamType = Class(TJSTypedParam)
+  Public
+    Destructor Destroy; override;
+  end;
+
   { TJSTypedParams }
 
   TJSTypedParams = class(TJSElementNodes)
@@ -1177,10 +1217,12 @@ Type
     function GetParams(aIndex : Integer): TJSTypedParam;
     function GetTypes(aIndex : Integer): TJSElement;
   Public
+    Constructor Create; Reintroduce;
+    Constructor CreateTransient;
     function AddParam(aName : jsBase.TJSString) : TJSTypedParam;
-    Property Params[aIndex : Integer] : TJSTypedParam Read GetParams;
+    Property Params[aIndex : Integer] : TJSTypedParam Read GetParams; default;
     Property Types[aIndex : Integer] : TJSElement Read GetTypes;
-    Property Names[aIndex : Integer] : TJSString Read GetNames; default;
+    Property Names[aIndex : Integer] : TJSString Read GetNames;
   end;
 
 
@@ -1222,22 +1264,30 @@ Type
   end;
 
   { TJSTypeDef }
-
+  TTypeGuardKind = (tgkIs,tgkExtendsCond,tgkExtendsEquals);
   TJSTypeDef = class(TJSElement)
   Private
+    FIsInferred: Boolean;
     FIsKeyOf : Boolean;
     FIsExtends : Boolean;
+    FIsReadonly: Boolean;
     FIsSpread: Boolean;
+    FIsTypeOf: Boolean;
     FTypeGuard: TJSTypeDef;
     FExtendsCond : TJSTypeDef;
     FExtendsTrue : TJSTypeDef;
     FExtendsFalse : TJSTypeDef;
+    FTypeGuardKind: TTypeGuardKind;
   Public
     Destructor destroy; override;
     Property IsKeyOf : Boolean Read FIsKeyOf Write FIsKeyof;
+    Property IsReadonly : Boolean Read FIsReadonly Write FIsReadonly;
+    Property IsInferred : Boolean Read FIsInferred Write FIsInferred;
+    Property IsTypeOf : Boolean Read FIsTypeOf Write FIsTypeOf;
     Property IsExtends : Boolean Read FIsExtends Write FIsExtends;
     Property IsSpread : Boolean Read FIsSpread Write FIsSpread;
     property TypeGuard : TJSTypeDef Read FTypeGuard Write FTypeGuard;
+    property TypeGuardKind : TTypeGuardKind Read FTypeGuardKind Write FTypeGuardKind;
     Property ExtendsCond : TJSTypeDef Read FExtendsCond Write FExtendsCond;
     Property ExtendsTrue : TJSTypeDef Read FExtendsTrue Write FExtendsTrue;
     Property ExtendsFalse : TJSTypeDef Read FExtendsFalse Write FExtendsFalse;
@@ -1259,14 +1309,30 @@ Type
 
   TJSTypeReference = class(TJSTypeDef)
   Private
-    FIsTypeOf: Boolean;
     FName: TJSString;
-    FIsImport : Boolean;
   Public
     // Type name or filename in import('filename') when IsImport is True
     Property Name : TJSString Read FName Write FName;
-    Property IsTypeOf : Boolean Read FIsTypeOf Write FIsTypeOf;
-    Property IsImport: Boolean Read FIsImport Write FIsImport;
+  end;
+
+  { TJSImportTypeRef }
+
+  TJSImportTypeRef = Class(TJSTypeReference)
+  private
+    FFileName: String;
+  Public
+    Property FileName : String Read FFileName Write FFileName;
+  end;
+
+
+  { TJSTypeFuncCall }
+
+  TJSTypeFuncCall = Class(TJSTypeReference)
+  private
+    FArgType: TJSTypeDef;
+  Public
+    Destructor Destroy; override;
+    Property ArgType : TJSTypeDef Read FArgType Write FargType;
   end;
 
   { TJSFixedStringReference }
@@ -1368,15 +1434,27 @@ Type
     property TypeCount : Integer Read GetTypeCount;
   end;
 
-  TJSUnionTypeDef = class(TJSUnionOrTupleTypeDef)
+  { TJSTupleTypeDef }
+
+  TJSTupleTypeDef = class(TJSUnionOrTupleTypeDef)
+  Public
+    Function GetEqualTypes : Boolean;
+  end;
+
+  TOnlyConstants = (ocFalse,ocTrue,ocAllSameTypes);
+
+  { TJSUnionOrIntersectTypeDef }
+
+  TJSUnionOrIntersectTypeDef = class(TJSUnionOrTupleTypeDef)
   private
     FAllowEmpty: Boolean;
   Public
+    Function GetOnlyConstants : TOnlyConstants;
     Property AllowEmpty : Boolean Read FAllowEmpty Write FAllowEmpty;
   end;
 
-  TJSTupleTypeDef = class(TJSUnionOrTupleTypeDef);
-  TJSInterSectionTypeDef = class(TJSUnionOrTupleTypeDef);
+  TJSUnionTypeDef = Class(TJSUnionOrIntersectTypeDef);
+  TJSInterSectionTypeDef = class(TJSUnionOrIntersectTypeDef);
 
   { TJSArrayTypeDef }
 
@@ -1409,20 +1487,24 @@ Type
   TAccessibility = (accDefault,accPrivate,accProtected,accPublic);
 
   { TJSObjectTypeElementDef }
+  TKeyOptionality = (koDefault,koOptional,koForceOptional,koDisableOptional);
+  TKeyOptionalities = Set of TKeyOptionality;
 
   TJSObjectTypeElementDef = Class(TJSNamedTypedElement)
   private
     FAccessibility: TAccessibility;
+    FIsReadOnly: Boolean;
     FIsStatic: Boolean;
-    FOptional: Boolean;
+    FOptional: TKeyOptionality;
     FIsAbstract : Boolean;
     FIsSet : Boolean;
     FIsGet : Boolean;
   Public
     Destructor Destroy; override;
-    Property Optional : Boolean Read FOptional Write FOptional;
+    Property Optional : TKeyOptionality Read FOptional Write FOptional;
     Property Accessibility : TAccessibility Read FAccessibility Write FAccessibility;
     Property IsStatic : Boolean Read FIsStatic Write FIsStatic;
+    Property IsReadOnly : Boolean Read FIsReadOnly Write FIsReadOnly;
     Property IsAbstract : Boolean Read FIsAbstract Write FIsAbstract;
     Property IsGet : Boolean Read FIsGet Write FIsGet;
     Property IsSet : Boolean Read FIsSet Write FIsSet;
@@ -1432,11 +1514,19 @@ Type
 
   TJSPropertyDeclaration = Class(TJSObjectTypeElementDef)
   private
-    FIsReadOnly: Boolean;
     function GetFixedStringValue: jsBase.TJSString;
   Public
     Property FixedStringValue : jsBase.TJSString Read GetFixedStringValue;
-    Property IsReadOnly : Boolean Read FIsReadOnly Write FisReadonly;
+  end;
+
+  { TJSClassConstDeclaration }
+
+  TJSClassConstDeclaration = Class(TJSObjectTypeElementDef)
+  private
+    FValue: TJSElement;
+  Public
+    Destructor Destroy; override;
+    Property Value : TJSElement Read FValue Write FValue;
   end;
 
   { TJSIndexSignatureDeclaration }
@@ -1476,6 +1566,11 @@ Type
     function GetElementCount: Integer;
   Public
     procedure AddElement(const aEl: TJSObjectTypeElementDef);
+    function HasSetter(const aName: TJSString): Boolean;
+    Function HasAccessMembers(aAccess : TAccessibility) : Boolean;
+    Function HasProperties : Boolean;
+    Function IsFunctionDef : Boolean;
+    Function FunctionDef : TJSFuncDef;
     Property Name : TJSString Read FName Write FName;
     Property Elements[aIndex : Integer] : TJSObjectTypeElementDef Read GetElement;
     Property ElementCount : Integer Read GetElementCount;
@@ -1575,7 +1670,7 @@ Type
     Destructor Destroy; override;
     Property ClassDef : TJSObjectTypeDef Read FClassDef Write FClassDef;
   end;
-
+  TJSAmbientClassDeclarationArray = Array of TJSAmbientClassDeclaration;
   { TJSClassStatement }
 
   TJSClassStatement =  Class(TJSDeclarationStatement)
@@ -1597,7 +1692,7 @@ Type
     Procedure AddExtends(Const aName : TJSString);
     property Extends : TJSElementNodes Read FExtends;
   end;
-
+  TJSInterfaceDeclarationArray = array of TJSInterfaceDeclaration;
 
   { TJSInterfaceStatement }
 
@@ -1658,8 +1753,124 @@ Type
 
 implementation
 
+{ TJSTupleTypeDef }
+
+function TJSTupleTypeDef.GetEqualTypes: Boolean;
+
+Var
+  I : Integer;
+  N : TJSString;
+
+begin
+  I:=Values.Count-1;
+  Result:=True;
+  While (I>=0) and (Result) do
+    begin
+    Result:=(Values[I].Node is TJSTypeReference);
+    if Result then
+      if I=Values.Count-1 then
+        N:=(Values[I].Node as TJSTypeReference).Name
+      else
+        Result:=N=(Values[I].Node as TJSTypeReference).Name;
+    Dec(i);
+    end;
+end;
+
+{ TJSUnionOrIntersectTypeDef }
+
+function TJSUnionOrIntersectTypeDef.GetOnlyConstants: TOnlyConstants;
+
+Var
+  I : integer;
+  FT : TJSType;
+  Ref : TJSFixedValueReference;
+
+begin
+  Result:=ocAllSameTypes;
+  I:=Values.Count-1;
+  While (I>=0) and (Result<>ocFalse) do
+    begin
+    if Not (Values[I].Node is TJSFixedValueReference) then
+      Result:=ocFalse
+    else
+      begin
+      Ref:=Values[I].Node as TJSFixedValueReference;
+      If (I=Values.Count-1) then
+        ft:=Ref.FixedValue.Value.ValueType
+      else if (ft<>Ref.FixedValue.Value.ValueType) then
+        Result:=ocTrue
+      end;
+    Dec(I);
+    end;
+end;
+
+{ TJSTransientParamType }
+
+destructor TJSTransientParamType.Destroy;
+begin
+  FDestructured:=Nil;
+  FNode:=nil;
+  inherited Destroy;
+end;
+
+{ TJSTransientElementNode }
+
+destructor TJSTransientElementNode.Destroy;
+begin
+  Node:=Nil;
+  inherited Destroy;
+end;
+
+{ TElementNodeEnumerator }
+
+function TElementNodeEnumerator.GetCurrent: TJSElementNode;
+begin
+  Result:=(Inherited GetCurrent) as TJSElementNode
+end;
+
+{ TJSClassConstDeclaration }
+
+destructor TJSClassConstDeclaration.Destroy;
+begin
+  FreeAndNil(FValue);
+  inherited Destroy;
+end;
+
+{ TTJSTypeFuncCall }
+
+destructor TJSTypeFuncCall.Destroy;
+begin
+  FreeAndNil(FArgType);
+  inherited Destroy;
+end;
+
 { TJSTypedParam }
 
+function TJSTypedParam.GetTypeDef: TJSTypeDef;
+begin
+  if Assigned(Node) then
+    Result:=Node as TJSTypeDef
+  else
+    Result:=Nil;
+end;
+
+procedure TJSTypedParam.Assign(Source: TPersistent);
+
+Var
+  aParam : TJSTypedParam absolute Source;
+
+begin
+  If Source is TJSTypedParam then
+    begin
+    FDestructured:=aParam.FDestructured;
+    FIsInferred:=aParam.IsInferred;
+    FIsOptional:=aParam.FIsOptional;
+    FIsSpread:=aParam.FIsSpread;
+    FName:=aParam.Name;
+    end;
+  inherited Assign(Source);
+end;
+
 destructor TJSTypedParam.Destroy;
 begin
   FreeAndNil(FDestructured);
@@ -1956,6 +2167,67 @@ begin
   Values.AddNode(False).Node:=aEl;
 end;
 
+Function TJSObjectTypeDef.HasSetter(Const aName : TJSString) : Boolean;
+
+Var
+  I : Integer;
+  aEl : TJSObjectTypeElementDef;
+
+begin
+  Result:=False;
+  I:=ElementCount-1;
+  While (Not Result) and (I>=0) do
+    begin
+    aEl:=Elements[i];
+    Result:=(aName=aEl.Name) and (aEl is TJSMethodDeclaration) and (aEl.IsSet);
+    Dec(I);
+    end;
+end;
+
+
+function TJSObjectTypeDef.HasAccessMembers(aAccess: TAccessibility): Boolean;
+
+Var
+  I : integer;
+
+begin
+  Result:=False;
+  I:=ElementCount-1;
+  While (Not Result) and (I>=0) do
+    begin
+    Result:=Elements[i].Accessibility=aAccess;
+    Dec(I);
+    end;
+end;
+
+function TJSObjectTypeDef.HasProperties: Boolean;
+
+Var
+  I : Integer;
+
+begin
+  Result:=False;
+  I:=ElementCount-1;
+  While (not Result) and (I>=0) do
+    begin
+    Result:=Elements[I] is TJSPropertyDeclaration;
+    Dec(i);
+    end;
+end;
+
+function TJSObjectTypeDef.IsFunctionDef: Boolean;
+begin
+  Result:=(ElementCount=1) and (Elements[0] is TJSMethodDeclaration) and (TJSMethodDeclaration(Elements[0]).Name='');
+end;
+
+function TJSObjectTypeDef.FunctionDef: TJSFuncDef;
+begin
+  if IsFunctionDef then
+    Result:=TJSMethodDeclaration(Elements[0]).FuncDef
+  else
+    Result:=Nil;
+end;
+
 { TJSObjectTypeElementDef }
 
 destructor TJSObjectTypeElementDef.Destroy;
@@ -2076,6 +2348,18 @@ begin
   Result:=Params[aIndex].Node;
 end;
 
+constructor TJSTypedParams.Create;
+
+begin
+  Inherited Create(TJSTypedParam);
+end;
+
+constructor TJSTypedParams.CreateTransient;
+
+begin
+  Inherited Create(TJSTransientParamType);
+end;
+
 function TJSTypedParams.AddParam(aName: jsBase.TJSString): TJSTypedParam;
 begin
   Result:=add as TJSTypedParam;
@@ -2717,6 +3001,13 @@ begin
   FSource:=ASource;
 end;
 
+destructor TJSElement.Destroy;
+begin
+  if Assigned(GlobalFreeHook) then
+    GlobalFreeHook(Self);
+  inherited Destroy;
+end;
+
 procedure TJSElement.AssignPosition(El: TJSElement);
 begin
   Source:=El.Source;
@@ -2766,6 +3057,11 @@ end;
 
 { TJSArrayLiteral }
 
+function TJSArrayLiteral.GetCount: Integer;
+begin
+  Result:=Elements.Count;
+end;
+
 constructor TJSArrayLiteral.Create(ALine, AColumn: Integer; const ASource: String);
 begin
   inherited Create(ALine, AColumn, ASource);
@@ -3213,6 +3509,11 @@ begin
      end;
 end;
 
+function TJSElementNodes.GetEnumerator: TElementNodeEnumerator;
+begin
+  Result:=TElementNodeEnumerator.Create(Self);
+end;
+
 function TJSElementNodes.AddNode(aIsAmbient : Boolean = False; aIsExport : Boolean = False): TJSElementNode;
 begin
   Result:=TJSElementNode(Add);
@@ -3247,6 +3548,22 @@ begin
   inherited Destroy;
 end;
 
+procedure TJSElementNode.Assign(aSource: TPersistent);
+
+Var
+  aNode : TJSElementNode absolute aSource;
+
+begin
+  if aSource is TJSElementNode then
+    begin
+    FIsAmbient:=aNode.FIsAmbient;
+    FIsExport:=aNode.FIsExport;
+    FNode:=aNode.Node;
+    end
+  else
+    inherited Assign(aSource);
+end;
+
 { TJSFuncDef }
 
 procedure TJSFuncDef.SetParams(const AValue: TStrings);
@@ -3260,7 +3577,7 @@ end;
 constructor TJSFuncDef.Create;
 begin
   FParams:=TStringList.Create;
-  FTypedParams:=TJSTypedParams.Create(TJSTypedParam);
+  FTypedParams:=TJSTypedParams.Create;
 end;
 
 destructor TJSFuncDef.Destroy;

+ 2569 - 1095
packages/fcl-js/src/tstopas.pp

@@ -24,41 +24,65 @@ uses
 Type
   ETSToPas = Class(Exception);
 
+  TJSFuncDefArray = Array of TJSFuncDef;
+
   { TPasData }
 
   TPasData = Class(TObject)
   private
-    FOriginalName: String;
+    FOriginalName: TJSString;
     FPasName: String;
   Public
     Constructor Create(const aOriginalName : jsBase.TJSString; const APasName : String);
     Destructor destroy; override;
     Property PasName : String read FPasName;
-    Property OriginalName : String Read FOriginalName;
+    Property OriginalName : TJSString Read FOriginalName;
   end;
 
-  TConversionOption = (coRaw,coGenericArrays,coUseNativeTypeAliases,coExternalConst,coExpandUnionTypeArgs,coaddOptionsToheader);
+  TConversionOption = (coRaw,coGenericArrays,coUseNativeTypeAliases,coLocalArgumentTypes, coUntypedTuples, coDynamicTuples,
+                       coExternalConst,coExpandUnionTypeArgs,coaddOptionsToheader,coInterfaceAsClass,coSkipImportStatements);
   TConversionOptions = Set of TConversionOption;
 
   TTypescriptToPas = Class;
+  TScope = Record
+    Source : TJSSourceElements;
+    Forwards : TStringList;
+  end;
 
   { TTSContext }
 
   TTSContext = class(TObject)
   Private
+    FCurrentScopeIdx: Integer;
     FTypeMap : TFPObjectHashTable;
     FTypeDeclarations : TFPObjectList;
     FConverter : TTypescriptToPas;
-    procedure TypesToMap;
+    FScopes : Array of TScope;
+    function GetCurrentForwards: TStringList;
+    function GetCurrentScope: TJSSourceElements;
+  Protected
+    procedure TypesToMap; virtual;
   Public
     Constructor Create(aConverter : TTypescriptToPas);
     Destructor Destroy; override;
+    procedure DoGlobalFree(aEl: TJSElement);
     Procedure AddAliases(aAliases : TStrings);
+    Procedure PushScope(aScope : TJSSourceElements; aForwards : TStringList);
+    Procedure PopScope(aScope : TJSSourceElements; aForwards : TStringList);
+    function ResolveTypeRef(D: TJSTypeDef): TJSTypeDef;
+    function GetTypeName(const aTypeName: jsBase.TJSString; ForTypeDef: Boolean; UsePascal : Boolean): String;
+    Function FindInNodes(aNodes: TJSElementNodes; const aName: String): TJSTypeDeclaration;
+    Function FindInScope(aScope: TJSSourceElements; const aName: String): TJSTypeDef;
+    Function FindTypeDef(const aName : String) : TJSTypeDef;
     Function FindTypeAlias(aName : jsbase.TJSString) : String;
     Procedure AddToTypeMap(aName : UTF8String; const aPasName : String);
     Procedure AddToTypeMap(aName : jsbase.TJSString; const aPasName : String);
     Procedure AddToTypeMap(aType : TJSElement);
+    Procedure RemoveFromTypeMap(aType : TJSElement);
     Property TypeMap : TFPObjectHashTable Read FTypeMap;
+    Property CurrentScopeIdx : Integer Read FCurrentScopeIdx;
+    Property CurrentScope : TJSSourceElements Read GetCurrentScope;
+    Property CurrentForwards : TStringList Read GetCurrentForwards;
   end;
 
   { TTSJSScanner }
@@ -76,11 +100,22 @@ Type
   private
     FContext: TTSContext;
   Protected
+    Procedure FreeElement(aElement : TJSElement); override;
     Function CreateElement(AElementClass : TJSElementClass)  : TJSElement; override;
   Public
     Property Context : TTSContext Read FContext Write FContext;
   end;
 
+  // List of TJSTypedParams
+
+  { TFunctionOverLoadArgumentsList }
+
+  TFunctionOverLoadArgumentsList = Class(TFPObjectList)
+    Procedure AddOverload(aTypedParams : TJSTypedParams);
+    Procedure RemoveDuplicates(aContext : TTSContext);
+  end;
+
+
   { TTypescriptToPas }
 
   TTypescriptToPas = Class(TPascalCodeGenerator)
@@ -88,6 +123,7 @@ Type
     FClassPrefix: String;
     FClassSuffix: String;
     FContext: TTSContext;
+    FDefaultClassParent: String;
     FDictionaryClassParent: String;
     FElements: TJSFunctionBody;
     FFieldPrefix: String;
@@ -95,82 +131,121 @@ Type
     FIncludeInterfaceCode: TStrings;
     FInputFileName: String;
     FInputStream: TStream;
+    FLinkStatements: TStrings;
     FOptions: TConversionOptions;
     FOutputFileName: String;
     FTypeAliases: TStrings;
     FVerbose: Boolean;
     FECMAVersion: TECMAVersion;
     FPasNameList : TFPObjectList;
-    FAutoTypes : TStrings;
+    FScopeNameList : Array[0..16] of TFPStringHashTable;
+    FScopeIdx : Integer;
+    FCurrentNameSpace : String;
+    FForwards : TStrings;
+    procedure CheckUnitName(SourceElements: TJSSourceElements);
     procedure DumpElements;
+    function GetAccessName(aAccess: TAccessibility): string;
+    function GetFixedValueTypeName(ATypeDef: TJSFixedValueReference): String;
     function GetIsRaw: Boolean;
+    function HasReadOnlyPropFields(aTypeDef: TJSObjectTypeDef): Boolean;
+    function HaveClass(aName: TJSString): Boolean;
+    function HaveModule(aName: TJSString): Boolean;
+    function NamespaceExtendsClass(aNs: TJSNamespaceDeclaration): Boolean;
+    function NamespaceExtendsModule(aNs: TJSNamespaceDeclaration): Boolean;
+    function ResolveTypeRef(D: TJSTypeDef): TJSTypeDef;
+    procedure SetFLinkStatements(AValue: TStrings);
     procedure SetIncludeImplementationCode(AValue: TStrings);
     procedure SetIncludeInterfaceCode(AValue: TStrings);
     procedure SetTypeAliases(AValue: TStrings);
   Protected
     function GetGenericParams(aTypeParams: TJSElementNodes): String; virtual;
     procedure AddOptionsToHeader;
+    Procedure PushNameScope;
+    Procedure PopNameScope;
+    function NameScopeHas(const aName : string) : Boolean;
+    procedure AddToNameScope(const aName : String; aData : jsbase.TJSString);
     Procedure Parse; virtual;
     Procedure WritePascal; virtual;
+    Function NeedsTypeMap(El : TJSElement) : Boolean;
     function CreateParser(aContext: TTSContext; S: TJSScanner): TJSParser; virtual;
     function CreateScanner(aContext : TTSContext; S: TStream): TJSScanner;virtual;
     Function CreateContext : TTSContext; virtual;
     Function BaseUnits : String; override;
+    procedure WriteLinkStatements(aList: TStrings);
     // Auxiliary routines
     procedure Getoptions(L: TStrings); virtual;
     procedure ProcessDefinitions; virtual;
+    Function ExportNode(aNode : TJSElementNode) : Boolean;
+    function CheckUnionTypeDefinition(D: TJSTypeDef): TJSUnionTypeDef;
     function CreatePasName(const aOriginal : jsBase.TJSString; const aName: String): TPasData;virtual;
+    function TypeNeedsTypeName(aType: TJSElement; IgnoreData : Boolean; IsResultType : Boolean = False): Boolean;
+    procedure AllocatePasNames(FD: TJSFuncDef; aPrefix: String='');
     procedure AllocatePasNames(aList: TJSSourceElements; ParentName: String=''); virtual;
     procedure AllocatePasNames(aList: TJSElementNodes; ParentName: String=''); virtual;
     Function AllocatePasName(D: TJSElement; ParentName: String='') : TPasData;virtual;
     procedure EnsureUniqueNames(ML: TJSSourceElements);virtual;
+    function GetExternalMemberName(const aName: jsBase.TJSString): string;
     function GetName(ADef: TJSElement): String;virtual;
+    function GetName(ADef: TJSTypedParam): String;virtual;
+    function GetName(ADef: TJSFuncDef): String;virtual;
     function HaveConsts(aList: TJSSourceElements): Boolean;virtual;
     function GetTypeName(Const aTypeName: JSBase.TJSString; ForTypeDef: Boolean=False): String;virtual;
     function GetTypeName(aTypeDef: TJSTypeDef; ForTypeDef: Boolean=False): String;virtual;
-{    function AddSequenceDef(ST: TIDLSequenceTypeDefDefinition): Boolean; virtual;
-    function CheckUnionTypeDefinition(D: TIDLDefinition): TIDLUnionTypeDefDefinition;virtual;
-    procedure AddArgumentToOverloads(aList: TFPObjectlist; AName, ATypeName: String);virtual;
-    procedure AddUnionOverloads(aList: TFPObjectlist; AName: String;  UT: TIDLUnionTypeDefDefinition);virtual;
-    procedure AddArgumentToOverloads(aList: TFPObjectlist; adef: TIDLArgumentDefinition);virtual;
-    procedure AddOverloads(aList: TFPObjectlist; adef: TIDLFunctionDefinition; aIdx: Integer);virtual;
-    function CloneNonPartialArgumentList(aList: TFPObjectlist; ADest: TFPObjectlist= Nil; AsPartial: Boolean=True): integer;virtual;
-    function GetOverloads(aDef: TIDLFunctionDefinition): TFPObjectlist;virtual;
-    function GetArguments(aList: TIDLDefinitionList; ForceBrackets: Boolean): String;virtual;
-    // Actual code generation routines
-    // Lists. Return the number of actually written defs.
-    function WriteCallBackDefs(aList: TIDLDefinitionList): Integer; virtual;
-    Function WriteDictionaryDefs(aList: TIDLDefinitionList) : Integer;virtual;
-    Function WriteForwardClassDefs(aList: TIDLDefinitionList) : Integer;virtual;
-    Function WriteInterfaceDefs(aList: TIDLDefinitionList) : Integer;virtual;
-    Function WriteMethodDefs(aList: TIDLDefinitionList) : Integer;virtual;
-    Function WriteEnumDefs(aList: TIDLDefinitionList) : Integer;virtual;
-    function WriteConsts(aList: TIDLDefinitionList): Integer;virtual;
-    function WritePlainFields(aList: TIDLDefinitionList): Integer;virtual;
-    function WriteDictionaryFields(aList: TIDLDefinitionList): Integer;virtual;
-    function WritePrivateReadOnlyFields(aList: TIDLDefinitionList): Integer;virtual;
+    // Functions
+    // Overload handling
+    function GetOverloads(const aDefs: TJSFuncDefArray): TFunctionOverLoadArgumentsList;
+    procedure AddOverloadParams(aList: TFunctionOverLoadArgumentsList; adef: TJSFuncDef; aIdx: Integer);
+    procedure AddUnionOverloads(aList: TFunctionOverLoadArgumentsList; AName: TJSString; UT: TJSUnionTypeDef);
+    procedure AddParameterToOverloads(aList: TFunctionOverLoadArgumentsList; const AName: TJSString; ATypeDef: TJSTypeDef);
+    procedure AddParameterToOverloads(aList: TFunctionOverLoadArgumentsList; const aParam : TJSTypedParam);
+    function CloneNonPartialParameterList(aList: TFunctionOverLoadArgumentsList; ADest: TFunctionOverLoadArgumentsList = Nil; AsPartial: Boolean = True): integer;
+    function GetArguments(aList: TJSTypedParams; ForceBrackets: Boolean): String;
+    function WriteFunctionDefinition(const aName: String; const aDefs: TJSFuncDefArray; UseExternal : Boolean): Boolean;
+    function WriteFunctionDefs(aElements : TJSElementNodes; UseExternal : Boolean) : Integer;
+
+    // Classes
     // Actual definitions. Return true if a definition was written.
-    Function WriteForwardClassDef(D: TIDLStructuredDefinition) : Boolean;virtual;
-    function WriteFunctionTypeDefinition(aDef: TIDLFunctionDefinition): Boolean;virtual;
-    function WriteFunctionDefinition(aDef: TIDLFunctionDefinition): Boolean;virtual;
-    function WriteTypeDef(aDef: TIDLTypeDefDefinition): Boolean; virtual;
-    function WriteRecordDef(aDef: TIDLRecordDefinition): Boolean; virtual;
-    function WriteEnumDef(aDef: TIDLEnumDefinition): Boolean; virtual;
-    function WriteDictionaryField(aField: TIDLDictionaryMemberDefinition): Boolean;virtual;
-    Function WritePrivateReadOnlyField(aAttr: TIDLAttributeDefinition) : Boolean;virtual;
-    Function WriteField(aAttr: TIDLAttributeDefinition) : Boolean;virtual;
-    Function WriteReadonlyProperty(aAttr: TIDLAttributeDefinition) : Boolean;virtual;
-    Function WriteConst(aConst: TIDLConstDefinition) : Boolean ;virtual;
-    function WriteInterfaceDef(Intf: TIDLInterfaceDefinition): Boolean; virtual;
-    function WriteDictionaryDef(aDict: TIDLDictionaryDefinition): Boolean; virtual;
-    // Additional
-    }
+
+    function WritePrivateReadOnlyField(P: TJSPropertyDeclaration): Boolean;
+    function WritePrivateReadOnlyField(M: TJSMethodDeclaration): Boolean;
+    function WriteReadonlyProperty(aProp: TJSPropertyDeclaration): Boolean;
+    function WritePropertyDef(aProp: TJSPropertyDeclaration): Boolean;
+    function WriteReadOnlyPropFields(aTypeDef: TJSObjectTypeDef): Integer;
+    function WriteAmbientClassDef(aPasName: String; aOrgName: TJSString; aTypeParams: TJSElementNodes; aClass: TJSAmbientClassDeclarationArray): Boolean;
+    function WriteClassDefs(aClasses: TJSElementNodes) : Integer;
+
+    // Forwards
+    function WriteForwardClass(aName: string): Boolean;
+    function WriteForwardClassDef(aIntf: TJSInterfaceDeclaration): Boolean;
+    function WriteForwardClassDef(aObj: TJSTypeDeclaration): Boolean;
+    function WriteForwardClassDef(aClass: TJSClassDeclaration): Boolean;
+    function WriteForwardClassDef(aModule: TJSModuleDeclaration): Boolean;
+    function WriteForwardClassDef(aNamespace: TJSNameSpaceDeclaration): Boolean;
+    function WriteForwardClassDefs(aClassList: TJSElementNodes): Integer;
+
+
+    Function WriteNamespaceDef(aNameSpace: TJSNamespaceDeclaration): Boolean;
+    Function WriteNamespaceDefs(aNameSpaces: TJSElementNodes): Integer;
+
+    Function WriteModuleDef(aModule: TJSModuleDeclaration): Boolean;
+    Function WriteModuleDefs(aModules: TJSElementNodes): Integer;
+
+
+    // Interfaces
+    function WriteInterfaceDef(Intfs: TJSInterfaceDeclarationArray): Boolean;
+    function WriteInterfaceDefs(aList: TJSElementNodes): Integer;
+
     // Properties
     procedure WritePropertyDeclaration(D: TJSVariableStatement);
     function WriteProperties(aClass: TJSClassDeclaration): Integer;
+    function WriteProperties(aAccess : TAccessibility; aMembers: TJSElementNodes): Integer;
+    function WriteObjectMethods(aAccess: TAccessibility; aTypeDef: TJSObjectTypeDef): Integer;
+    procedure WriteIndexSignature(aSign: TJSIndexSignatureDeclaration);
+
     // Variables
     procedure WriteVariable(aVar: TJSVarDeclaration);
     procedure WriteVariables(Vars: TJSElementNodes); virtual;
+
     // Get type defs as string
     function GetTypeAsString(aType: TJSTypeDef; asPascal, asSubType: Boolean): String;
     function GetArrayTypeAsString(aTypeDef: TJSArrayTypeDef; asPascal, asSubType: Boolean): String;
@@ -178,17 +253,40 @@ Type
     function GetIntersectionTypeAsString(aTypeDef: TJSIntersectionTypeDef; asPascal, asSubType: Boolean): String;
     function GetUnionTypeAsString(aTypeDef: TJSUnionTypeDef; asPascal, asSubType: Boolean): String;
     function GetEnumTypeAsString(aTypeDef: TJSEnumTypeDef; asPascal, asSubType: Boolean): String;
-
+    function GetFixedValueTypeAsString(aTypeDef : TJSFixedValueReference; asPascal,asSubType : Boolean) : string;
+    function GetTupleTypeAsString(aTypeDef: TJSTupleTypeDef; asPascal, asSubType: Boolean): String;
     // Write types
     procedure WriteTypeDefs(Types: TJSElementNodes); virtual;
+    procedure WriteObjectTypeMembers(const aPasName: String; const aOrigName: jsBase.TJSString; aTypeParams: TJSElementNodes; aTypeDef: TJSObjectTypeDef);
+    procedure WriteObjectTypedef(const aPasName: String; const aOrigName : jsBase.TJSString; aTypeParams: TJSElementNodes; aTypeDef: TJSObjectTypeDef); virtual;
     procedure WriteAliasTypeDef(const aPasName: string; const aOrgName: jsBase.TJSString; aTypeParams: TJSElementNodes;  aTypeDef: TJSTypeReference); virtual;
-    procedure WriteTypeDef(const aPasName: string; const aOrgName: jsBase.TJSString; aTypeParams: TJSElementNodes; aTypeDef: TJSTypeDef);
-    procedure WriteUnionTypeDef(const aPasName: string; const aOrgName: jsBase.TJSString; aTypeParams: TJSElementNodes; aTypeDef: TJSUnionTypeDef);
-    procedure WriteIntersectionTypeDef(const aPasName: string; const aOrgName: jsBase.TJSString; aTypeParams: TJSElementNodes; aTypeDef: TJSIntersectionTypeDef);
-    procedure WriteArrayTypeDef(const aPasName: string; const aOrgName: jsBase.TJSString; aTypeParams: TJSElementNodes;  aTypeDef: TJSArrayTypeDef);
-    procedure WriteEnumTypeDef(const aPasName: string; const aOrgName: jsBase.TJSString; aTypeParams: TJSElementNodes;  aTypeDef: TJSEnumTypeDef);
-
+    procedure WriteUnionTypeDef(const aPasName: string; const aOrgName: jsBase.TJSString; aTypeParams: TJSElementNodes; aTypeDef: TJSUnionTypeDef); virtual;
+    procedure WriteTupleTypeDef(const aPasName: string; const aOrgName: jsBase.TJSString; aTypeParams: TJSElementNodes; aTypeDef: TJSTupleTypeDef); virtual;
+    procedure WriteIntersectionTypeDef(const aPasName: string; const aOrgName: jsBase.TJSString; aTypeParams: TJSElementNodes; aTypeDef: TJSIntersectionTypeDef); virtual;
+    procedure WriteArrayTypeDef(const aPasName: string; const aOrgName: jsBase.TJSString; aTypeParams: TJSElementNodes;  aTypeDef: TJSArrayTypeDef); virtual;
+    procedure WriteEnumTypeDef(const aPasName: string; const aOrgName: jsBase.TJSString; aTypeParams: TJSElementNodes;  aTypeDef: TJSEnumTypeDef); virtual;
+    function  WriteFunctionTypeDef(const aPasName: string; const aOrgName: jsBase.TJSString; aTypeParams: TJSElementNodes; aDef: TJSFuncDef): Boolean; virtual;
+    procedure WriteTypeDef(const aPasName: string; const aOrgName: jsBase.TJSString; aTypeParams: TJSElementNodes; aTypeDef: TJSTypeDef); virtual;
+    // Indirect type handling
+    Function HasIndirectTypeDefs(aParams: TJStypedParams): Boolean;
+    Function HasIndirectTypeDefs(aElements: TJSElementNodes): Boolean;
+    function AllocateIndirectTypeDef(El: TJSElement; const aPrefix, aName: String): Integer;
+    Function AllocateIndirectTypeDefs(aElements : TJSElementNodes; const aPrefix : String) : Integer;
+    function AllocateIndirectTypeDefs(FD: TJSFuncDef; const aPrefix: String): Integer;
+    Function AllocateIndirectTypeDefs(aParams : TJSTypedParams; const aPrefix : String) : Integer;
+    function AllocateTypeName(aType: TJSElement; const aPrefix, aName: String): Integer;
+    function WriteIndirectTypeDefs(aEl: TJSElement): Integer;
+    function WriteIndirectTypeDefs(FD: TJSFuncDef): Integer;
+    function WriteIndirectTypeDefs(aParams: TJStypedParams): Integer; overload; virtual;
+    Function WriteIndirectTypeDefs(aElements : TJSElementNodes) : Integer; overload; virtual;
+    function WriteClassIndirectTypeDefs(aElements: TJSElementNodes; isClassLocal: Boolean): Integer;
+    function WritePropertyTypeDefs(aElements: TJSElementNodes; SectionName: String=''): Integer;
+    function WriteMethodParameterDefs(aElements: TJSElementNodes; SectionName : String = ''): Integer;
+
+    // List of identifiers: global, namespace or class
+    procedure WriteSourceElements(SourceElements: TJSSourceElements; aNamespace: TJSString);
     // Extra interface/Implementation code.
+    procedure WriteImports(SourceElements: TJSSourceElements);
     procedure WriteImplementation; virtual;
     procedure WriteIncludeInterfaceCode; virtual;
     Property Elements : TJSFunctionBody Read FElements;
@@ -212,18 +310,119 @@ Type
     Property IncludeInterfaceCode : TStrings Read FIncludeInterfaceCode Write SetIncludeInterfaceCode;
     Property IncludeImplementationCode : TStrings Read FIncludeImplementationCode Write SetIncludeImplementationCode;
     Property DictionaryClassParent : String Read FDictionaryClassParent Write FDictionaryClassParent;
+    Property DefaultClassParent : String Read FDefaultClassParent Write FDefaultClassParent;
+    Property LinkStatements : TStrings Read FLinkStatements Write SetFLinkStatements;
   end;
 
 implementation
 
-uses typinfo;
+uses typinfo, strutils;
+
+{ TFunctionOverLoadArgumentsList }
+
+procedure TFunctionOverLoadArgumentsList.AddOverload(aTypedParams: TJSTypedParams);
+begin
+  Add(aTypedParams);
+end;
+
+procedure TFunctionOverLoadArgumentsList.RemoveDuplicates(aContext: TTSContext);
+
+  Function GetName(aDef : TJSTypeDef) : TJSString;
+
+  begin
+    Result:='';
+    if aDef is TJSFixedValueReference then
+      begin
+      Case TJSFixedValueReference(aDef).FixedValue.Value.ValueType of
+        jstString : Result:='string';
+        jstNumber : Result:='number';
+        jstBoolean : Result:='boolean';
+      else
+        Result:='';
+      end
+      end
+    else if aDef is TJSTypeReference then
+      Result:=(aDef as TJSTypeReference).Name
+    else if aDef is TJSUnionOrIntersectTypeDef then
+      Result:='jsvalue';
+  end;
+
+  Function IdenticalTypes(Src,Dest : TJSTypeDef) : boolean;
+
+
+  Var
+    N1,N2 : TJSString;
+
+  begin
+    Result:=Src=Dest;
+    If Result then exit;
+    Src:=aContext.ResolveTypeRef(Src);
+    Dest:=aContext.ResolveTypeRef(Dest);
+    Result:=Src=Dest;
+    if Result then
+      exit;
+    N1:=GetName(Src);
+    N2:=GetName(Dest);
+    Result:=(N1=N2) and (N1<>'')
+  end;
+
+  Function IdenticalParams(Src,Dest : TJSTypedParams) : boolean;
+
+  Var
+    I : Integer;
+
+  begin
+    Result:=(Src.Count=Dest.Count);
+    I:=Src.Count-1;
+    While Result and (I>=0) do
+      begin
+      Result:=IdenticalTypes(Src.Types[i] as TJSTypeDef,Dest.Types[i] as TJSTypeDef);
+      Dec(I);
+      end;
+  end;
+
+  Function HasDuplicate(MaxIndex : Integer; aParamList :TJSTypedParams) : Boolean;
+
+  Var
+    I : Integer;
+
+  begin
+    Result:=False;
+    I:=MaxIndex;
+    While (Not Result) and (I>=0) do
+      begin
+      Result:=IdenticalParams(Items[i] as TJSTypedParams, aParamList);
+      Dec(I);
+      end
+  end;
+
+Var
+  I : Integer;
+
+begin
+  For I:=Count-1 downto 1 do
+    If HasDuplicate(I-1,Items[I] as TJSTypedParams) then
+      Delete(I);
+end;
 
 { TTSJSParser }
+Procedure TTSJSParser.FreeElement(aElement : TJSElement);
+
+begin
+  if Assigned(aElement) then
+    FContext.RemoveFromTypeMap(aElement);
+  Inherited;
+end;
+
 
 function TTSJSParser.CreateElement(AElementClass: TJSElementClass): TJSElement;
 begin
   Result:=inherited CreateElement(AElementClass);
   If Result is TJSTypeDeclaration then
+    FContext.AddToTypeMap(Result)
+  else If Result is TJSObjectTypeDef then
+    FContext.AddToTypeMap(Result)
+  else If (Result is TJSClassDeclaration) then
     FContext.AddToTypeMap(Result);
 end;
 
@@ -231,13 +430,18 @@ end;
 
 constructor TTSContext.Create(aConverter : TTypescriptToPas);
 begin
+  TJSElement.GlobalFreeHook:=@DoGlobalFree;
+  FCurrentScopeIdx:=-1;
   FConverter:=aConverter;
   FTypeMap:=TFPObjectHashTable.Create(False);
   FTypeDeclarations:=TFPObjectList.Create(False);
+  SetLength(FScopes,10);
 end;
 
 destructor TTSContext.Destroy;
+
 begin
+  TJSElement.GlobalFreeHook:=Nil;
   FreeAndNil(FTypeDeclarations);
   FreeAndNil(FTypeMap);
   inherited Destroy;
@@ -253,7 +457,146 @@ begin
   For I:=0 to aAliases.Count-1 do
     begin
     aAliases.GetNameValue(I,N,V);
-    AddToTypeMap(UTF8String(N),V);
+    if FTypeMap.Find(UTF8String(N))=Nil then
+      AddToTypeMap(UTF8String(N),V);
+    end;
+end;
+
+procedure TTSContext.PushScope(aScope: TJSSourceElements; aForwards : TStringList);
+begin
+  if aScope=Nil then
+    Raise ETSToPas.Create('Cannot push nil scope');
+  Inc(FCurrentScopeIdx);
+  if FCurrentScopeIdx>=Length(FScopes) then
+    SetLength(FScopes,Length(FScopes)*2);
+  FScopes[FCurrentScopeIdx].Source:= aScope;
+  FScopes[FCurrentScopeIdx].Forwards:=aForwards;
+end;
+
+procedure TTSContext.PopScope(aScope: TJSSourceElements; aForwards : TStringList);
+begin
+  if (aScope=Nil) then
+    Raise ETSToPas.Create('Cannot pop nil scope');
+  if aScope<>CurrentScope then
+    Raise ETSToPas.Create('Can only pop toplevel scope');
+  Dec(FCurrentScopeIdx);
+end;
+
+function TTSContext.ResolveTypeRef(D: TJSTypeDef): TJSTypeDef;
+begin
+  Result:=D;
+  While Result is TJSTypeReference do
+    Result:=FindTypeDef(UTF8Encode((Result as TJSTypeReference).Name));
+  if Result=Nil then
+    Result:=D;
+end;
+
+function TTSContext.GetTypeName(const aTypeName: jsBase.TJSString; ForTypeDef: Boolean; UsePascal: Boolean): String;
+
+  Function UsePascalType(Const aPascalType : string) : String;
+
+  begin
+    if UsePascal and ForTypeDef then
+      Result:=StringReplace(UTF8Encode(aTypeName),' ','',[rfReplaceAll])
+    else
+      Result:=aPascalType;
+  end;
+
+Var
+  TN : UTF8String;
+
+begin
+  Case aTypeName of
+    'union': TN:='JSValue';
+    'short': TN:=UsePascalType('Integer');
+    'long': TN:=UsePascalType('Integer');
+    'long long': TN:=UsePascalType('NativeInt');
+    'unsigned short': TN:=UsePascalType('Cardinal');
+    'unrestricted float': TN:=UsePascalType('Double');
+    'unrestricted double': TN:=UsePascalType('Double');
+    'unsigned long': TN:=UsePascalType('NativeInt');
+    'unsigned long long': TN:=UsePascalType('NativeInt');
+    'octet': TN:=UsePascalType('Byte');
+    'any' : TN:=UsePascalType('JSValue');
+    'number' : TN:=UsePascalType('Double');
+    'float' : TN:=UsePascalType('Double');
+    'double' : TN:=UsePascalType('Double');
+    'DOMString',
+    'USVString',
+    'ByteString' : TN:=UsePascalType('String');
+    'object' : TN:=UsePascalType('TJSObject');
+    'Error' : TN:=UsePascalType('TJSError');
+    'DOMException' : TN:=UsePascalType('TJSError');
+    'ArrayBuffer',
+    'DataView',
+    'Int8Array',
+    'Int16Array',
+    'Int32Array',
+    'Uint8Array',
+    'Uint16Array',
+    'Uint32Array',
+    'Uint8ClampedArray',
+    'Float32Array',
+    'Float64Array' : TN:='TJS'+UTF8Encode(aTypeName);
+  else
+    TN:=FindTypeAlias(aTypeName);
+  end;
+  Result:=TN;
+end;
+
+Function TTSContext.FindInNodes(aNodes : TJSElementNodes; const aName: String) : TJSTypeDeclaration;
+
+Var
+  I : integer;
+  N : TJSString;
+
+
+begin
+  Result:=Nil;
+  N:=UTF8Decode(aName);
+  I:=aNodes.Count-1;
+  While (Result=Nil) and (I>=0) do
+    begin
+    If aNodes[i].Node is TJSTypeDeclaration then
+      begin
+      Result:=aNodes[i].Node as TJSTypeDeclaration;
+      if Result.Name<>N then
+        Result:=Nil;
+      end;
+    Dec(I);
+    end;
+end;
+
+function TTSContext.FindInScope(aScope : TJSSourceElements; const aName: String): TJSTypeDef;
+
+Var
+  Decl :TJSTypeDeclaration;
+
+begin
+  Result:=Nil;
+  Decl:=FindInNodes(aScope.Enums,aName);
+  if Decl=Nil then
+    Decl:=FindInNodes(aScope.Types,aName);
+  if Decl=Nil then
+    Decl:=FindInNodes(aScope.Classes,aName);
+  if Decl=Nil then
+    Decl:=FindInNodes(aScope.Interfaces,aName);
+  if Decl<>Nil then
+    Result:=Decl.TypeDef;
+end;
+
+function TTSContext.FindTypeDef(const aName: String): TJSTypeDef;
+
+Var
+  I : Integer;
+
+begin
+  Result:=Nil;
+  I:=FCurrentScopeIdx;
+  While (Result=nil) and (I>=0) do
+    begin
+    Result:=FindInscope(FScopes[i].Source,aName);
+    Dec(I);
     end;
 end;
 
@@ -261,17 +604,25 @@ function TTSContext.FindTypeAlias(aName: jsbase.TJSString): String;
 
 Var
   S : UTF8String;
+  Parts : TStringArray;
   Obj : TObject;
 
 begin
-  S:=UTF8Encode(aName);
+  Result:='';
   if FTypeDeclarations.Count>0 then
     TypesToMap;
-  Obj:=FTypeMap.Items[S];
-  if (Obj is TPasData) then
-    Result:=TPasData(Obj).PasName
-  else
-    Result:=S;
+  S:=UTF8Encode(aName);
+  Parts:=SplitString(S,'.');
+  For S in Parts do
+    begin
+    Obj:=FTypeMap.Items[S];
+    if Result<>'' then
+      Result:=Result+'.';
+    if (Obj is TPasData) then
+      Result:=Result+TPasData(Obj).PasName
+    else
+      Result:=Result+S;
+    end;
 end;
 
 procedure TTSContext.TypesToMap;
@@ -279,21 +630,56 @@ procedure TTSContext.TypesToMap;
 Var
   I : Integer;
   el : TJSElement;
+  N : String;
 
 begin
   For I:=0 to FTypeDeclarations.Count-1 do
     begin
     El:=TJSElement(FTypeDeclarations[i]);
     if El.Data=Nil then
+      begin
       FConverter.AllocatePasName(El,'');
-    FTypeMap.Add(TPasData(El.Data).OriginalName,El.Data) ;
+      end;
+    if EL.Data<>Nil then
+      begin
+      if FConverter.NeedsTypeMap(El) then
+        begin
+        N:=UTF8Encode(TPasData(El.Data).OriginalName);
+        if FTypeMap.Find(N)<>Nil then
+          FConverter.DoLog('Ignoring duplicate type name %s -> %s (%s)',[N,TPasData(El.Data).PasName,EL.ClassName])
+        else
+          FTypeMap.Add(N,El.Data) ;
+        end;
+      end;
     end;
   FTypeDeclarations.Clear;
 end;
 
+function TTSContext.GetCurrentScope: TJSSourceElements;
+
+begin
+  if CurrentScopeIdx>=0 then
+    Result:=FScopes[CurrentScopeIdx].Source
+  else
+    Result:=Nil;
+end;
+
+function TTSContext.GetCurrentForwards: TStringList;
+begin
+  if CurrentScopeIdx>=0 then
+    Result:=FScopes[CurrentScopeIdx].Forwards
+  else
+    Result:=Nil;
+end;
+
+procedure TTSContext.DoGlobalFree(aEl: TJSElement);
+begin
+  FTypeDeclarations.Extract(aEl);
+end;
+
 procedure TTSContext.AddToTypeMap(aName: UTF8String; const aPasName: String);
 begin
-  FTypeMap.Add(aName,FConverter.CreatePasName(aName,aPasName));
+  FTypeMap.Add(aName,FConverter.CreatePasName(UTF8Decode(aName),aPasName));
 end;
 
 procedure TTSContext.AddToTypeMap(aName: jsbase.TJSString; const aPasName: String);
@@ -303,9 +689,16 @@ end;
 
 procedure TTSContext.AddToTypeMap(aType: TJSElement);
 begin
+//  Writeln('aType : ',FTypeDeclarations.Count,': ',aType.Classname);
   FTypeDeclarations.Add(aType);
 end;
 
+procedure TTSContext.RemoveFromTypeMap(aType: TJSElement);
+begin
+//  Writeln('Removing : ',FTypeDeclarations.Count,': ',aType.Classname, ' at ',FTypeDeclarations.IndexOf(aTYpe));
+  FTypeDeclarations.Extract(aType);
+end;
+
 { TPasData }
 
 constructor TPasData.Create(const aOriginalName : jsBase.TJSString; const APasName : String);
@@ -369,8 +762,31 @@ begin
   DumpNodes('enums',Els.Enums);
   DumpNodes('functions',Els.Functions);
   DumpNodes('namespaces',Els.Namespaces);
+  DumpNodes('modules',Els.Modules);
+end;
+
+function TTypescriptToPas.ResolveTypeRef(D: TJSTypeDef): TJSTypeDef;
+
+begin
+  Result:=Context.ResolveTypeRef(D);
+end;
+
+procedure TTypescriptToPas.SetFLinkStatements(AValue: TStrings);
+begin
+  if FLinkStatements=AValue then Exit;
+  FLinkStatements.Assign(AValue);
+end;
+
+function TTypescriptToPas.CheckUnionTypeDefinition(D: TJSTypeDef): TJSUnionTypeDef;
+
+begin
+  Result:=Nil;
+  D:=ResolveTypeRef(D);
+  If (D is TJSUnionTypeDef) then
+    Result:=D as TJSUnionTypeDef;
 end;
 
+
 procedure TTypescriptToPas.Parse;
 
 Var
@@ -395,7 +811,7 @@ begin
       Raise ETStoPas.Create('Parse result is not a function body');
       end;
     FElements:=El as TJSFunctionBody;
-    DumpElements;
+    // DumpElements;
   finally
     P.Free;
     S.Free;
@@ -404,15 +820,35 @@ begin
   end;
 end;
 
+function TTypescriptToPas.GetExternalMemberName(const aName : jsBase.TJSString) : string;
+
+begin
+  if FCurrentNameSpace<>'' then
+    Result:=FCurrentNameSpace+'.'+UTF8Encode(aName)
+  else
+    Result:=UTF8Encode(aName);
+end;
+
 function TTypescriptToPas.GetName(ADef: TJSElement): String;
 
 begin
   If Assigned(ADef) and (TObject(ADef.Data) is TPasData) then
     Result:=TPasData(ADef.Data).PasName
   else if aDef is TJSNamedElement then
-    Result:=TJSNamedElement(ADef).Name
+    Result:=EscapeKeyWord(UTF8Encode(TJSNamedElement(ADef).Name))
   else
     Result:='';
+
+end;
+
+function TTypescriptToPas.GetName(ADef: TJSTypedParam): String;
+begin
+  Result:=EscapeKeyWord(UTF8Encode(aDef.Name));
+end;
+
+function TTypescriptToPas.GetName(ADef: TJSFuncDef): String;
+begin
+  Result:=EscapeKeyWord(UTF8Encode(aDef.Name));
 end;
 
 function TTypescriptToPas.HaveConsts(aList: TJSSourceElements): Boolean;
@@ -434,67 +870,51 @@ end;
 function TTypescriptToPas.GetTypeName(const aTypeName: jsBase.TJSString; ForTypeDef: Boolean): String;
 
 
-  Function UsePascalType(Const aPascalType : string) : String;
+begin
+  Result:=Context.GetTypeName(aTypeName,ForTypeDef,(coUseNativeTypeAliases in Options));
+end;
 
-  begin
-    if (coUseNativeTypeAliases in Options) and ForTypeDef then
-      Result:=StringReplace(UTF8Encode(aTypeName),' ','',[rfReplaceAll])
+function TTypescriptToPas.GetFixedValueTypeName(ATypeDef : TJSFixedValueReference) : String;
+
+begin
+  if Not (Assigned(ATypeDef.FixedValue) and Assigned(ATypeDef.FixedValue.Value)) then
+    Result:='JSValue'
+  else
+    Case ATypeDef.FixedValue.Value.ValueType of
+      jstBoolean : Result:='Boolean';
+      jstNumber : Result:='Double';
+      jstString : Result:='String';
+      jstObject : Result:='TJSObject';
     else
-      Result:=aPascalType;
-  end;
+      Result:='JSValue';
+    end;
+end;
+
+function TTypescriptToPas.GetTypeName(aTypeDef : TJSTypeDef; ForTypeDef : Boolean = False): String;
 
 Var
-  TN : UTF8String;
-
-begin
-  Case aTypeName of
-    'union': TN:='JSValue';
-    'short': TN:=UsePascalType('Integer');
-    'long': TN:=UsePascalType('Integer');
-    'long long': TN:=UsePascalType('NativeInt');
-    'unsigned short': TN:=UsePascalType('Cardinal');
-    'unrestricted float': TN:=UsePascalType('Double');
-    'unrestricted double': TN:=UsePascalType('Double');
-    'unsigned long': TN:=UsePascalType('NativeInt');
-    'unsigned long long': TN:=UsePascalType('NativeInt');
-    'octet': TN:=UsePascalType('Byte');
-    'any' : TN:=UsePascalType('JSValue');
-    'number' : TN:=UsePascalType('Double');
-    'float' : TN:=UsePascalType('Double');
-    'double' : TN:=UsePascalType('Double');
-    'DOMString',
-    'USVString',
-    'ByteString' : TN:=UsePascalType('String');
-    'object' : TN:=UsePascalType('TJSObject');
-    'Error' : TN:=UsePascalType('TJSError');
-    'DOMException' : TN:=UsePascalType('TJSError');
-    'ArrayBuffer',
-    'DataView',
-    'Int8Array',
-    'Int16Array',
-    'Int32Array',
-    'Uint8Array',
-    'Uint16Array',
-    'Uint32Array',
-    'Uint8ClampedArray',
-    'Float32Array',
-    'Float64Array' : TN:='TJS'+UTF8Encode(aTypeName);
-  else
-    TN:=FContext.FindTypeAlias(aTypeName);
-  end;
-  Result:=TN;
-end;
-
-
-function TTypescriptToPas.GetTypeName(aTypeDef : TJSTypeDef; ForTypeDef : Boolean = False): String;
+  S : jsbase.TJSString;
 
 begin
   if (aTypeDef.Data is TPasData) then
     Result:=TPasData(aTypeDef.Data).PasName
   else if ATypeDef is TJSTypeReference then
-    Result:=GetTypeName(TJSTypeReference(aTypeDef).Name,ForTypeDef)
+    begin
+    S:=TJSTypeReference(aTypeDef).Name;
+    Result:=GetTypeName(S,ForTypeDef)
+    end
+  else if ATypeDef is TJSArrayTypeDef then
+    Result:='array of '+GetTypeName(TJSArrayTypeDef(aTypeDef).BaseType,ForTypeDef)
+  else if ATypeDef is TJSUnionOrIntersectTypeDef then
+    Result:='jsvalue'
+  else if ATypeDef is TJSGenericTypeRef then
+    Result:=GetTypeName(TJSGenericTypeRef(aTypeDef).BaseType,ForTypeDef)
+  else if ATypeDef is TJSArrowFunctionTypeDef then
+    Result:='procedure'
+  else if ATypeDef is TJSFixedValueReference then
+    Result:=GetFixedValueTypeName(ATypeDef as TJSFixedValueReference)
   else
-    Raise ETSToPas.Create('Cannot get type name from '+aTypeDef.ClassName);
+    Raise ETSToPas.CreateFmt('Cannot get type name from %s at row %d, col %d.',[aTypeDef.ClassName,aTypeDef.Line,aTypeDef.Column]);
 end;
 
 
@@ -505,30 +925,88 @@ Var
   D : TJSVariableStatement;
 
 begin
+  Result:=0;
   For I:=0 to aClass.Members.Vars.Count-1 do
-    begin
-    D:=aClass.Members.Vars[i].Node as TJSVariableStatement;
-    if (D.VarType=vtVar) then
-      WritePropertyDeclaration(D);
-    end;
+    if ExportNode(aClass.Members.Vars[i]) then
+      begin
+      D:=aClass.Members.Vars[i].Node as TJSVariableStatement;
+      if (D.VarType=vtVar) then
+        begin
+        WritePropertyDeclaration(D);
+        Inc(Result);
+        end;
+      end;
+end;
+
+function TTypescriptToPas.GetAccessName(aAccess : TAccessibility) : string;
+
+Const
+  AccessNames : Array[TAccessibility] of string
+              = ('','Private','Protected','Public');
+
+begin
+  Result:=AccessNames[aAccess];
 end;
 
+function TTypescriptToPas.WriteProperties(aAccess: TAccessibility; aMembers: TJSElementNodes): Integer;
+
+Var
+  EN : TJSElementNode;
+  P : TJSPropertyDeclaration;
+  OK : Boolean;
+
+begin
+  Result:=0;
+  For EN in aMembers do
+   begin
+   if EN.Node is TJSPropertyDeclaration then
+     begin
+     P:=TJSPropertyDeclaration(EN.Node);
+     if (P.Accessibility=aAccess) then
+       begin
+       if P.IsReadOnly then
+         OK:=WriteReadOnlyProperty(P)
+       else
+         OK:=WritePropertyDef(P);
+       if Ok then
+         Inc(Result);
+       end;
+     end;
+   end;
+end;
+
+
 function TTypescriptToPas.GetGenericParams(aTypeParams: TJSElementNodes) : String;
 
 Var
   I : Integer;
   aName: jsBase.TJSString;
+  N : TJSTypeDef;
 
 begin
   Result:='';
   if aTypeParams=nil then exit;
   For I:=0 to aTypeParams.Count-1 do
-    begin
-    aName:=(aTypeParams[i].Node as TJSTypeReference).Name;
-    if Result<>'' then
-      Result:=Result+',';
-    Result:=Result+aName;
-    end;
+    if (aTypeParams[i].Node is TJSTypeReference) then
+      begin
+      aName:=(aTypeParams[i].Node as TJSTypeReference).Name;
+      if Result<>'' then
+        Result:=Result+',';
+      Result:=Result+UTF8Encode(aName);
+      end
+    else if (aTypeParams[i].Node is TJSNamedParamTypeDef) then
+      begin
+      N:=(aTypeParams[i].Node as TJSNamedParamTypeDef).ParamName;
+      if (N is TJSTypeReference) then
+        aName:=(N as TJSTypeReference).Name
+      else
+        Raise ETSToPas.CreateFmt('Unsupported named type parameter: "%s"',[ATypeParams[I].Node.ClassName]);
+      if Result<>'' then
+        Result:=Result+',';
+      Result:=Result+UTF8Encode(aName);
+      end
+    else
+      Raise ETSToPas.CreateFmt('Unsupported type parameter: "%s"',[ATypeParams[I].Node.ClassName]);
   if Result<>'' then
     Result:='<'+Result+'>';
 end;
@@ -539,7 +1017,7 @@ begin
   if asPascal then
     Result:=GetTypeName(aTypeDef.Name,True)
   else
-    Result:=aTypeDef.Name
+    Result:=UTF8Encode(aTypeDef.Name);
 end;
 
 procedure TTypescriptToPas.WriteAliasTypeDef(const aPasName : string; const aOrgName : jsBase.TJSString; aTypeParams: TJSElementNodes; aTypeDef : TJSTypeReference);
@@ -563,1353 +1041,2349 @@ end;
 Procedure TTypescriptToPas.WritePropertyDeclaration(D : TJSVariableStatement);
 
 begin
+
 end;
 
-(*
-function TTypescriptToPas.WriteConst(aConst: T): Boolean;
+procedure TTypescriptToPas.Getoptions(L : TStrings);
 
-Const
-  ConstTypes : Array[TConstType] of String =
-     ('Double','NativeInt','Boolean','JSValue','JSValue','JSValue','JSValue','String','JSValue','JSValue');
 Var
   S : String;
+  I : Integer;
 
 begin
-  Result:=True;
-  // Consts cannot be strings
-  if coExternalConst in Options then
-    begin
-    S:=ConstTypes[aConst.ConstType];
-    Addln('%s : %s;',[GetName(aConst),S])
-    end
-  else
+  L.Add('Automatically generated file by '+ClassName+' on '+FormatDateTime('yyyy-mm-dd hh:nn:ss',Now));
+  L.Add('');
+  L.Add('Used command-line options : ');
+  For I:=1 to ParamCount do
+    L.Add(ParamStr(i));
+  L.Add('');
+  L.Add('Command-line options translate to: ');
+  L.Add('');
+  S:=SetToString(PtypeInfo(TypeInfo(TConversionOptions)),Integer(OPtions),True);
+  L.Add('Options : '+S);
+  L.Add('Keyword prefix : '+KeywordPrefix);
+  L.Add('Keyword suffix : '+KeywordSuffix);
+  L.Add('Class prefix : '+ClassPrefix);
+  L.Add('Class suffix : '+ClassSuffix);
+  L.Add('Field prefix : '+FieldPrefix);
+  Str(ECMAversion,S);
+  L.Add('ECMALversion : '+S);
+  if TypeAliases.Count>0 then
     begin
-    S:=aConst.Value;
-    if aConst.ConstType=ctInteger then
-      S:=StringReplace(S,'0x','$',[]);
-    Addln('%s = %s;',[GetName(aConst),S])
+    L.Add('Type aliases:');
+    L.AddStrings(Self.TypeAliases);
     end;
 end;
 
-function TTypescriptToPas.WriteConsts(aList: TIDLDefinitionList): Integer;
+procedure TTypescriptToPas.AddOptionsToHeader;
 
 Var
-  D : TIDLDefinition;
-
+  L : TStrings;
 begin
-  EnsureSection(csConst);
-  Indent;
-  Result:=0;
-  For D in aList do
-    if D is TIDLConstDefinition then
-      if WriteConst(D as TIDLConstDefinition) then
-        Inc(Result);
-  Undent;
+  L:=TStringList.Create;
+  try
+    GetOptions(L);
+    Comment(L);
+  finally
+    L.Free;
+  end;
 end;
 
-function TTypescriptToPas.WritePlainFields(aList: TIDLDefinitionList): Integer;
-
-Var
-  D : TIDLDefinition;
-  A : TIDLAttributeDefinition absolute D;
-
+procedure TTypescriptToPas.PushNameScope;
 begin
-  EnsureSection(csDeclaration);
-  Indent;
-  Result:=0;
-  For D in aList do
-    if D is TIDLAttributeDefinition then
-      if Not (aoReadOnly in A.Options) then
-        if WriteField(A) then
-          Inc(Result);
-  Undent;
+  Inc(FScopeIdx);
+  FScopeNameList[FScopeIdx]:=TFPStringHashTable.Create;
 end;
 
-function TTypescriptToPas.WriteDictionaryField(
-  aField: TIDLDictionaryMemberDefinition): Boolean;
+procedure TTypescriptToPas.PopNameScope;
+begin
+  if FScopeIdx<0 then
+    exit;
+  FreeAndNil(FScopeNameList[FScopeIdx]);
+  Dec(FScopeIdx);
 
-Var
-  Def,N,TN : String;
+end;
 
+function TTypescriptToPas.NameScopeHas(const aName: string): Boolean;
 begin
-  Result:=True;
-  N:=GetName(aField);
-  TN:=GetTypeName(aField.MemberType);
-  if TN='record' then
-    TN:='TJSObject';
-  if SameText(N,TN) then
-    N:='_'+N;
-  Def:=Format('%s : %s;',[N,TN]);
-  if (N<>aField.Name) then
-    Def:=Def+Format('external name ''%s'';',[aField.Name]);
-  AddLn(Def);
+  Result:=FScopeIdx>=0;
+  if Result then
+    Result:=Assigned(FScopeNameList[FScopeIdx].Find(aName));
 end;
 
-function TTypescriptToPas.WriteDictionaryFields(aList: TIDLDefinitionList): Integer;
-
-Var
-  D : TIDLDefinition;
-  M : TIDLDictionaryMemberDefinition absolute D;
-
+procedure TTypescriptToPas.AddToNameScope(const aName: String; aData: jsbase.TJSString);
 begin
-  Indent;
-  Result:=0;
-  For D in aList do
-    if D is TIDLDictionaryMemberDefinition then
-      if WriteDictionaryField(M) then
-        Inc(Result);
-  Undent;
+  if FScopeIdx>=0 then
+    FScopeNameList[FScopeIdx].Add(aName,UTF8Encode(aData));
 end;
 
-function TTypescriptToPas.WriteMethodDefs(aList: TIDLDefinitionList): Integer;
+procedure TTypescriptToPas.WriteIncludeInterfaceCode;
 
 Var
-  D : TIDLDefinition;
-  FD : TIDLFunctionDefinition absolute D;
+  S : String;
 
 begin
-  Result:=0;
-  for D in aList do
-    if D is TIDLFunctionDefinition then
-      if Not (foCallBack in FD.Options) then
-         if WriteFunctionDefinition(FD) then
-           Inc(Result);
+  For S in IncludeInterfaceCode do
+    Addln(S);
 end;
 
-function TTypescriptToPas.AddSequenceDef(ST: TIDLSequenceTypeDefDefinition
-  ): Boolean;
-
-var
-  TN : String;
+constructor TTypescriptToPas.Create(Aowner: TComponent);
 begin
-  TN:=GetTypeName(ST);
-  Result:=FAutoTypes.IndexOf(TN)=-1;
-  if Result then
-    begin
-    FAutoTypes.Add(TN);
-    DoLog('Automatically adding %s sequence definition.',[TN]);
-    AddLn('%s = Array of %s;',[TN,GetTypeName(ST.ElementType)]);
-    ST.Data:=CreatePasName(TN);
-    end;
+  inherited Create(Aowner);
+  ECMaVersion:=ecma2021;
+  FieldPrefix:='F';
+  ClassPrefix:='T';
+  ClassSuffix:='';
+  Switches.Add('modeswitch externalclass');
+  FTypeAliases:=TStringList.Create;
+  TStringList(FTypeAliases).Sorted:=true;
+  TStringList(FTypeAliases).Duplicates:=dupIgnore;
+  FPasNameList:=TFPObjectList.Create(True);
+  FIncludeInterfaceCode:=TStringList.Create;
+  FIncludeImplementationCode:=TStringList.Create;
+  FLinkStatements:=TStringList.Create;
+  FForwards:=TStringList.Create;
+  DefaultClassParent:='TJSObject';
+  FOptions:=[];
 end;
 
-function TTypescriptToPas.WriteFunctionImplicitTypes(aList: TIDLDefinitionList): Integer;
-
-Var
-  D,D2,D3 : TIDLDefinition;
-  FD : TIDLFunctionDefinition absolute D;
-  DA : TIDLArgumentDefinition absolute D2;
-  UT : TIDLUnionTypeDefDefinition;
 
+destructor TTypescriptToPas.Destroy;
 begin
-  Result:=0;
-  for D in aList do
-    if D is TIDLFunctionDefinition then
-      if Not (foCallBack in FD.Options) then
-        begin
-        if (FD.ReturnType is TIDLSequenceTypeDefDefinition) then
-          if AddSequenceDef(FD.ReturnType as TIDLSequenceTypeDefDefinition) then
-            Inc(Result);
-        For D2 in FD.Arguments do
-          if (DA.ArgumentType is TIDLSequenceTypeDefDefinition) then
-            begin
-            if AddSequenceDef(DA.ArgumentType as TIDLSequenceTypeDefDefinition) then
-              Inc(Result);
-            end
-          else
-            begin
-            UT:=CheckUnionTypeDefinition(DA.ArgumentType);
-            if Assigned(UT) then
-              For D3 in UT.Union do
-                if (D3 is TIDLSequenceTypeDefDefinition) then
-                  if AddSequenceDef(D3 as TIDLSequenceTypeDefDefinition) then
-                    Inc(Result);
-            end;
-        end;
-  if Result>0 then
-    AddLn('');
+  FreeAndNil(FForwards);
+  FreeAndNil(FLinkStatements);
+  FreeAndNil(FElements);
+  FreeAndNil(FIncludeInterfaceCode);
+  FreeAndNil(FIncludeImplementationCode);
+  FreeAndNil(FTypeAliases);
+  FreeAndNil(FPasNameList);
+  inherited Destroy;
 end;
 
-function TTypescriptToPas.WriteAttributeImplicitTypes(aList: TIDLDefinitionList
-  ): Integer;
-Var
-  D : TIDLDefinition;
-  FA : TIDLAttributeDefinition absolute D;
-
-begin
-  Result:=0;
-  for D in aList do
-    if D is TIDLAttributeDefinition then
-      if (FA.AttributeType is TIDLSequenceTypeDefDefinition) then
-        if AddSequenceDef(FA.AttributeType as TIDLSequenceTypeDefDefinition) then
-          Inc(Result);
-end;
 
-function TTypescriptToPas.WriteDictionaryMemberImplicitTypes(
-  aList: TIDLDefinitionList): Integer;
+procedure TTypescriptToPas.WriteVariable(aVar : TJSVarDeclaration);
 
 Var
-  D : TIDLDefinition;
-  FD : TIDLDictionaryMemberDefinition absolute D;
+  Src,aPasName,aTypeName: String;
+  aExportName : TJSString;
 
 begin
-  Result:=0;
-  for D in aList do
-    if D is TIDLDictionaryMemberDefinition then
-      if (FD.MemberType is TIDLSequenceTypeDefDefinition) then
-        if AddSequenceDef(FD.MemberType as TIDLSequenceTypeDefDefinition) then
-          Inc(Result);
+  aPasName:=GetName(aVar);
+  aExportName:=aVar.Name;
+  aTypeName:=GetTypeName(aVar.Typed,False);
+  Src:=aPasName + ' : '+aTypeName+';';
+  Src:=Src+' external name '''+Utf8Encode(aExportName)+''';';
+  AddLn(Src);
 end;
 
-procedure TTypescriptToPas.EnsureUniqueNames(ML : TIDLDefinitionList);
+procedure TTypescriptToPas.WriteVariables(Vars : TJSElementNodes);
 
 Var
-  L : TFPObjectHashTable;
-
-  Procedure CheckRename(aD : TIDLDefinition);
-
-  var
-    I : integer;
-    NOrig,N,N2 : String;
-    isDup : Boolean;
-    D2 : TIDLDefinition;
-
-  begin
-    NOrig:=GetName(aD);
-    N:=LowerCase(NOrig);
-    N2:=N;
-    I:=0;
-    isDup:=False;
-    Repeat
-      D2:=TIDLDefinition(L.Items[N2]);
-      if (D2<>Nil) then
-        // Overloads
-        begin
-        isDup:=((D2 is TIDLFunctionDefinition) and (ad is TIDLFunctionDefinition));
-        if IsDup then
-          D2:=Nil
-        else
-          begin
-          inc(I);
-          N2:=KeywordPrefix+N+KeywordSuffix;
-          Norig:=KeywordPrefix+NOrig+KeywordSuffix;
-          end;
-        end;
-    Until (D2=Nil);
-    if (N<>N2) then
-      begin
-      N:=GetName(aD);
-      DoLog('Renaming duplicate identifier (%s) %s to %s',[aD.ClassName,N,Norig]);
-      // Original TPasName is in list, will be freed automatically
-      aD.Data:=CreatePasName(NOrig);
-      end;
-    if not IsDup then
-      L.Add(N2,aD);
-  end;
-
-var
-  D : TIDLDefinition;
+  I : Integer;
 
 begin
-  L:=TFPObjectHashTable.Create(False);
-  try
-    For D in ML Do
-      if not (D is TIDLConstDefinition) then
-        CheckRename(D);
-    For D in ML Do
-      if (D is TIDLConstDefinition) then
-        CheckRename(D);
-  finally
-    L.Free;
-  end;
+  For I:=0 to Vars.Count-1 do
+    if ExportNode(Vars.Nodes[i]) then
+      WriteVariable(Vars.Nodes[i].Node as TJSVarDeclaration);
 end;
 
-function TTypescriptToPas.WriteInterfaceDef(Intf: TIDLInterfaceDefinition): Boolean;
+procedure TTypescriptToPas.WriteSourceElements(SourceElements : TJSSourceElements; aNamespace : TJSString);
 
 Var
-  CN,PN : String;
-  Decl : String;
-  ML : TIDLDefinitionList;
+  NS : String;
+  HasTypes : Boolean;
+  Written : Integer;
+  Fwds : TStringList;
 
 begin
-  Result:=True;
-  ML:=TIDLDefinitionList.Create(Nil,False);
+  NS:=FCurrentNameSpace;
+  Fwds:=TStringList.Create;
   try
-    Intf.GetFullMemberList(ML);
-    EnsureUniqueNames(ML);
-    CN:=GetName(Intf);
-    ClassHeader(CN);
-    WriteFunctionImplicitTypes(ML);
-    WriteAttributeImplicitTypes(ML);
-    Decl:=Format('%s = class external name %s ',[CN,MakePascalString(Intf.Name,True)]);
-    if Assigned(Intf.ParentInterface) then
-      PN:=GetName(Intf.ParentInterface)
-    else
-      PN:=GetTypeName(Intf.ParentName);
-    if PN<>'' then
-      Decl:=Decl+Format(' (%s)',[PN]);
-    AddLn(Decl);
-    AddLn('Private');
-    Indent;
-    WritePrivateReadOnlyFields(ML);
-    Undent;
-    AddLn('Public');
-    if HaveConsts(ML) then
+    if (FCurrentNameSpace<>'') then
+      FCurrentNameSpace:=FCurrentNameSpace+'.';
+    FCurrentNameSpace:=FCurrentNameSpace+NS;
+    Context.PushScope(SourceElements,Fwds);
+    HasTypes:=(SourceElements.Types.Count>0) or (SourceElements.Enums.Count>0);
+    HasTypes:=HasTypes or (SourceElements.Namespaces.Count>0) or (SourceElements.Modules.Count>0);
+    HasTypes:=HasTypes or (SourceElements.Classes.Count>0) or (SourceElements.Interfaces.Count>0);
+    HasTypes:=HasTypes or HasIndirectTypeDefs(SourceElements.Functions);
+    HasTypes:=HasTypes or HasIndirectTypeDefs(SourceElements.Types);
+    HasTypes:=HasTypes or HasIndirectTypeDefs(SourceElements.Vars);
+    if HasTypes then
       begin
+      EnsureSection(csType);
       Indent;
-      PushSection(csUnknown);
-      WriteConsts(ML);
-      PopSection;
+      Written:=WriteForwardClassDefs(SourceElements.Interfaces);
+      Written:=Written+WriteForwardClassDefs(SourceElements.Classes);
+      Written:=Written+WriteForwardClassDefs(SourceElements.Namespaces);
+      Written:=Written+WriteForwardClassDefs(SourceElements.Modules);
+      Written:=Written+WriteForwardClassDefs(SourceElements.Types); // object types
+      If Written>0 then
+        AddLn('');
+      WriteIndirectTypeDefs(SourceElements.Types);
+      WriteIndirectTypeDefs(SourceElements.Vars);
+      WriteTypeDefs(SourceElements.Types);
+      WriteTypeDefs(SourceElements.Enums);
+      WriteIndirectTypeDefs(SourceElements.Functions);
+      WriteClassDefs(SourceElements.Classes);
+
+      //
+      WriteNamespaceDefs(SourceElements.Namespaces);
+      WriteModuleDefs(SourceElements.Modules);
+      WriteInterfaceDefs(SourceElements.Interfaces);
+      {
+      WriteEnumDefs(Context.Definitions);
+      WriteCallbackDefs(Context.Definitions);
+      WriteDictionaryDefs(Context.Definitions);
+      }
       Undent;
-      AddLn('Public');
+      AddLn('');
       end;
-    Indent;
-    WritePlainFields(ML);
-    WriteMethodDefs(ML);
-    WriteProperties(ML);
-    Undent;
-    AddLn('end;');
+    if SourceElements.Vars.Count>0 then
+      begin
+      EnsureSection(csVar);
+      Indent;
+      WriteVariables(SourceElements.Vars);
+      Undent;
+      end;
+    if SourceElements.Functions.Count>0 then
+      begin
+      WriteFunctionDefs(SourceElements.Functions,aNameSpace='');
+      end;
+
   finally
-    ML.Free;
+    Context.PopScope(SourceElements,fwds);
+    Fwds.Free;
+    FCurrentNamespace:=NS;
   end;
 end;
 
-function TTypescriptToPas.WriteDictionaryDef(aDict: TIDLDictionaryDefinition
-  ): Boolean;
+procedure TTypescriptToPas.WriteLinkStatements(aList : TStrings);
 
 Var
-  CN,CP : String;
-  ML : TIDLDefinitionList;
-  PD: TIDLDictionaryDefinition;
+  i : Integer;
 
 begin
-  Result:=True;
-  ML:=TIDLDefinitionList.Create(Nil,False);
-  try
-    PD:=aDict;
-    While PD<>Nil do
-      begin
-      PD.GetFullMemberList(ML);
-      PD:=PD.ParentDictionary;
-      end;
-    CN:=GetName(aDict);
-    CP:=DictionaryClassParent;
-    if CP='' then
-      CP:='TJSObject';
-    ClassHeader(CN);
-    WriteDictionaryMemberImplicitTypes(ML);
-    if (coDictionaryAsClass in Options) then
-      Addln('%s = class(%s)',[CN,CP])
-    else
-      Addln('%s = record',[CN]);
-    WriteDictionaryFields(ML);
-    AddLn('end;');
-  finally
-    ML.Free;
-  end;
+  For I:=0 to aList.Count-1 do
+   AddLn('{$linklib '+aList[i]+'}');
 end;
 
-procedure TTypescriptToPas.WriteImplementation;
+procedure TTypescriptToPas.WriteImports(SourceElements : TJSSourceElements);
 
 Var
-  S : String;
-
-begin
-  Addln('');
-  For S in FIncludeImplementationCode do
-    Addln(S);
-  Addln('');
+  I : integer;
+  Imps : TJSImportStatement;
+  PE : TJSPrimaryExpressionIdent;
+  CE : TJSCallExpression;
+
+begin
+  For I:=0 to SourceElements.Statements.Count-1 do
+   if SourceElements.Statements[i].Node is TJSImportStatement then
+     begin
+     Imps:=TJSImportStatement(SourceElements.Statements[i].Node);
+     if (Imps.Expression is TJSCallExpression) then
+       begin
+       CE:=Imps.Expression as TJSCallExpression;
+       if CE.Expr is TJSPrimaryExpressionIdent then
+         begin
+         PE:=CE.Expr as TJSPrimaryExpressionIdent;
+         if (Pe.Name='require')
+             and (CE.Args.Count=1)
+             and (CE.Args.Elements[0].Expr is TJSLiteral) then
+           begin
+             Comment('Import (require) file : '+(CE.Args.Elements[0].expr as TJSLiteral).Value.AsString);
+           end;
+         end;
+       end
+     else
+       Comment('Import file : '+Imps.ModuleName)
+     end;
 end;
 
-function TTypescriptToPas.GetTypeName(aTypeDef : TIDLTypeDefDefinition; ForTypeDef : Boolean = False): String;
+procedure TTypescriptToPas.WritePascal;
+
+Var
+  SourceElements : TJSSourceElements;
 
 begin
-  if ATypeDef is TIDLSequenceTypeDefDefinition then
+  SourceElements:=FElements.A as TJSSourceElements;
+  if Not IsRaw then
     begin
-    if Assigned(aTypeDef.Data) then
-      Result:=GetName(aTypeDef)
-    else
-      begin
-      Result:=GetTypeName(TIDLSequenceTypeDefDefinition(aTypeDef).ElementType,ForTypeDef);
-      Result:='T'+Result+'DynArray';
-      end
-    end
-  else
-    Result:=GetTypeName(aTypeDef.TypeName,ForTypeDef);
+    CreateUnitClause;
+    if not (coSkipImportStatements in Options) then
+      WriteImports(SourceElements);
+    CreateHeader;
+    if coaddOptionsToheader in Options then
+      AddOptionsToHeader;
+    Addln('{$INTERFACES CORBA}');
+    WriteLinkStatements(FLinkStatements);
+    end;
+  WriteSourceElements(SourceElements,'');
+  if not IsRaw then
+    begin
+    WriteIncludeInterfaceCode;
+    Addln('');
+    AddLn('implementation');
+    WriteImplementation;
+    AddLn('end.');
+    end;
+  if OutputFileName<>'' then
+    Source.SaveToFile(OutputFileName);
 end;
 
-function TTypescriptToPas.GetTypeName(const aTypeName: String; ForTypeDef: Boolean
-  ): String;
+function TTypescriptToPas.NeedsTypeMap(El: TJSElement): Boolean;
+begin
+  Result:=true;
+  if El is TJSInterfaceDeclaration then
+    Result:=not HaveClass(TJSInterfaceDeclaration(El).Name)
+  else if El is TJSNameSpaceDeclaration then
+    Result:=not (HaveClass(TJSNameSpaceDeclaration(El).Name)
+                 or HaveModule(TJSNameSpaceDeclaration(El).Name))
+end;
 
+function TTypescriptToPas.BaseUnits: String;
 
-  Function UsePascalType(Const aPascalType : string) : String;
+begin
+  Result:='SysUtils, JS'
+end;
 
-  begin
-    if (coUseNativeTypeAliases in Options) and ForTypeDef then
-      Result:=StringReplace(aTypeName,' ','',[rfReplaceAll])
-    else
-      Result:=aPascalType;
-  end;
+function TTypescriptToPas.CreatePasName(const aOriginal: jsBase.TJSString; const aName: String): TPasData;
 
-Var
-  A,TN : UTF8String;
-  D : TIDLDefinition;
 
 begin
-  Case aTypeName of
-    'union': TN:='JSValue';
-    'short': TN:=UsePascalType('Integer');
-    'long': TN:=UsePascalType('Integer');
-    'long long': TN:=UsePascalType('NativeInt');
-    'unsigned short': TN:=UsePascalType('Cardinal');
-    'unrestricted float': TN:=UsePascalType('Double');
-    'unrestricted double': TN:=UsePascalType('Double');
-    'unsigned long': TN:=UsePascalType('NativeInt');
-    'unsigned long long': TN:=UsePascalType('NativeInt');
-    'octet': TN:=UsePascalType('Byte');
-    'any' : TN:=UsePascalType('JSValue');
-    'float' : TN:=UsePascalType('Double');
-    'double' : TN:=UsePascalType('Double');
-    'DOMString',
-    'USVString',
-    'ByteString' : TN:=UsePascalType('String');
-    'object' : TN:=UsePascalType('TJSObject');
-    'Error' : TN:=UsePascalType('TJSError');
-    'DOMException' : TN:=UsePascalType('TJSError');
-    'ArrayBuffer',
-    'DataView',
-    'Int8Array',
-    'Int16Array',
-    'Int32Array',
-    'Uint8Array',
-    'Uint16Array',
-    'Uint32Array',
-    'Uint8ClampedArray',
-    'Float32Array',
-    'Float64Array' : TN:='TJS'+aTypeName;
-  else
-    TN:=aTypeName;
-    D:=FContext.FindDefinition(TN);
-    if D<>Nil then
-      TN:=GetName(D)
-    else
-      begin
-      A:=FTypeAliases.Values[TN];
-      If (A<>'') then
-        TN:=A;
-      end;
-  end;
-  Result:=TN;
+  Result:=TPasData.Create(aOriginal,aName);
+  FPasNameList.Add(Result);
 end;
 
-function TTypescriptToPas.WritePrivateReadOnlyField(aAttr: TIDLAttributeDefinition
-  ): Boolean;
+function TTypescriptToPas.AllocatePasName(D: TJSElement; ParentName: String): TPasData;
+
+Var
+  Org : TJSString;
+  CN : String;
+  CD : TJSClassDeclaration absolute D;
+  AD : TJSAmbientClassDeclaration absolute D;
+  ID : TJSInterfaceDeclaration absolute D;
+  VD : TJSVarDeclaration absolute D;
+  TD : TJSTypeDeclaration absolute D;
+  FS : TJSFunctionStatement absolute D;
+  ND : TJSNameSpaceDeclaration absolute D;
+  MD : TJSModuleDeclaration absolute D;
+  OE : TJSObjectTypeElementDef absolute D;
+  OO : TJSObjectTypeDef absolute D;
 
 begin
-  AddLn('%s%s : %s; external name ''%s''; ',[FieldPrefix,GetName(aAttr),GetTypeName(aAttr.AttributeType),aAttr.Name]);
+  Result:=Nil;
+  if D Is TJSAmbientClassDeclaration then
+    begin
+    Org:=AD.Name;
+    CN:=ClassPrefix+UTF8Encode(Org)+ClassSuffix;
+    Result:=CreatePasname(Org,CN);
+    AllocatePasNames(AD.ClassDef.Values,UTF8Encode(AD.Name));
+    end
+  else if D Is TJSClassDeclaration then
+    begin
+    Org:=CD.Name;
+    CN:=ClassPrefix+UTF8Encode(Org)+ClassSuffix;
+    Result:=CreatePasname(Org,CN);
+    AllocatePasNames(CD.members,UTF8Encode(CD.Name));
+    end
+  else if D Is TJSInterfaceDeclaration then
+    begin
+    Org:=ID.Name;
+    CN:=ClassPrefix+UTF8Encode(Org)+ClassSuffix;
+    Result:=CreatePasname(Org,CN);
+    AllocatePasNames(ID.Values,EscapeKeyWord(UTF8Encode(ID.Name)));
+    end
+  else if D Is TJSVarDeclaration then
+    begin
+    Org:=VD.Name;
+    Result:=CreatePasName(Org, EscapeKeyWord(UTF8Encode(Org)));
+    end
+  else if D Is TJSFunctionStatement then
+    begin
+    Org:=FS.aFunction.Name;
+    Result:=CreatePasName(Org, EscapeKeyWord(UTF8Encode(Org)));
+    end
+  else if D Is TJSTypeDeclaration then
+    begin
+    Org:=TD.Name;
+    Result:=CreatePasName(Org, EscapeKeyWord('T'+UTF8Encode(Org)));
+    end
+  else if D Is TJSNameSpaceDeclaration then
+    begin
+    Org:=UTF8Decode(ClassPrefix)+ND.Name+UTF8Decode(ClassSuffix);
+    Result:=CreatePasName(Org, EscapeKeyWord(UTF8Encode(Org)));
+    end
+  else if D Is TJSModuleDeclaration then
+    begin
+    Org:=UTF8Decode(ClassPrefix)+MD.Name+UTF8Decode(ClassSuffix);
+    Result:=CreatePasName(Org, EscapeKeyWord(UTF8Encode(Org)));
+    end
+  else if D Is TJSObjectTypeElementDef then
+    begin
+    Org:=OE.Name;
+    Result:=CreatePasName(Org, EscapeKeyWord(UTF8Encode(Org)));
+    end
+  else if D Is TJSObjectTypeDef then
+    begin
+    Org:=OO.Name;
+    if Org<>'' then
+      Result:=CreatePasName(Org, EscapeKeyWord(UTF8Encode(Org)));
+    end
+  else
+    Raise ETSToPas.CreateFmt('Unsupported type to get name from: "%s"',[D.ClassName]);
+  D.Data:=Result;
+  if Verbose and (Result<>Nil) and (Result.PasName<>UTF8Encode(Org)) then
+    begin
+    if (ParentName<>'') then
+      ParentName:=ParentName+'.';
+    DoLog('Renamed %s to %s',[ParentName+UTF8Encode(Org),TPasData(D.Data).PasName]);
+    end;
 end;
 
-function TTypescriptToPas.WriteField(aAttr: TIDLAttributeDefinition): Boolean;
-
-Var
-  Def,TN,N : String;
+Function TTypescriptToPas.TypeNeedsTypeName(aType: TJSElement; IgnoreData : Boolean; IsResultType : Boolean = False): Boolean;
 
 begin
-  Result:=True;
-  N:=GetName(aAttr);
-  TN:=GetTypeName(aAttr.AttributeType);
-  if TN='record' then
-    TN:='TJSObject';
-  if SameText(N,TN) then
-    N:='_'+N;
-  Def:=Format('%s : %s;',[N,TN]);
-  if (N<>aAttr.Name) then
-    Def:=Def+Format('external name ''%s'';',[aAttr.Name]);
-  AddLn(Def);
+  if (aType=Nil) then // For example a parameter can have no type.
+    exit(False);
+  Result:=IgnoreData or (aType.Data=Nil);
+  if Result then
+    Result:=(aType is TJSArrowFunctionTypeDef)
+            or (aType is TJSObjectTypeDef)
+            or (aType is TJSTupleTypeDef)
+            or ((aType is TJSArrayTypeDef)
+                 and (IsResultType or TypeNeedsTypeName(TJSArrayTypeDef(aType).BaseType,IgnoreData,True)));
 end;
 
-function TTypescriptToPas.WriteReadonlyProperty(aAttr: TIDLAttributeDefinition
-  ): Boolean;
+Function TTypescriptToPas.AllocateTypeName(aType: TJSElement; const aPrefix,aName : String): Integer;
 
 Var
-  TN,N,PN : String;
+  aTypeName : String;
 
 begin
-  Result:=True;
-  N:=GetName(aAttr);
-  PN:=N;
-  TN:=GetTypeName(aAttr.AttributeType);
-  if SameText(PN,TN) then
-    PN:='_'+PN;
-  AddLn('Property %s : %s Read %s%s; ',[PN,TN,FieldPrefix,N]);
+  Result:=1;
+  aTypeName:=aPrefix+aName;
+  // Writeln('AITD Typename : ',aPrefix,', Parn: ',UTF8Decode(aName), ' Typen : ',aTypeName,' esc : ',EscapeKeyWord('T'+aTypeName));
+  aType.Data:=CreatePasName(UTF8Decode(aName), EscapeKeyWord('T'+aTypeName));
 end;
 
 
-function TTypescriptToPas.WriteForwardClassDef(D: TIDLStructuredDefinition): Boolean;
+function TTypescriptToPas.AllocateIndirectTypeDef(El : TJSElement; const aPrefix,aName : String) : Integer;
 
+var
+  FD : TJSFuncDef;
+  SubPrefix : String;
 begin
-  Result:=not D.IsPartial;
-  if Result then
-    AddLn('%s = Class;',[GetName(D)]);
+  // Writeln('AITD element: ',El.ClassName,' Prefix: ',aPrefix);
+  SubPrefix:=aPrefix;
+  if aName<>'' then
+    SubPrefix:=SubPrefix+aName+'_';
+  Result:=0;
+  if (el is TJSArrowFunctionTypeDef) then
+    begin
+    if el.Data=Nil then
+      AllocateTypeName(El,aPrefix,aName);
+    FD:=TJSArrowFunctionTypeDef(El).aFunction;
+    Result:=AllocateIndirectTypeDefs(FD,SubPrefix);
+    end
+  else if (el is TJSObjectTypeDef) then
+    begin
+    Inc(Result);
+    if el.Data=Nil then
+      AllocateTypeName(El,aPrefix,aName);
+    Result:=Result+AllocateIndirectTypeDefs(TJSObjectTypeDef(El).Values,SubPrefix);
+    end
+  else if (el is TJSTupleTypeDef) then
+    begin
+    Inc(Result);
+    AllocateTypeName(El,aPrefix,aName);
+    end
+  else if (el is TJSArrayTypeDef) then
+    begin
+    Inc(Result);
+    if TypeNeedsTypeName(TJSArrayTypeDef(el).BaseType,False,True) then
+       Result:=Result+AllocateIndirectTypeDef(TJSArrayTypeDef(el).BaseType,SubPrefix,'Item');
+    AllocateTypeName(El,aPrefix,aName);
+    end;
 end;
 
-function TTypescriptToPas.WriteForwardClassDefs(aList: TIDLDefinitionList): Integer;
+function TTypescriptToPas.AllocateIndirectTypeDefs(aElements: TJSElementNodes; const aPrefix : String): Integer;
 
-Var
-  D : TIDLDefinition;
+var
+  PD : TJSPropertyDeclaration;
+  VD : TJSVarDeclaration;
+  EN : TJSElementNode;
+  FD : TJSFuncDef;
 
 begin
   Result:=0;
-  Comment('Forward class definitions');
-  For D in aList do
-    if D is TIDLInterfaceDefinition then
-      if WriteForwardClassDef(D as TIDLInterfaceDefinition) then
-        Inc(Result);
-  if coDictionaryAsClass in Options then
-    For D in aList do
-      if D is TIDLDictionaryDefinition then
-        if WriteForwardClassDef(D as TIDLDictionaryDefinition) then
-          Inc(Result);
+  // Writeln('AITD List, prefix : ',aPrefix);
+  For EN in aElements do
+    begin
+    FD:=Nil;
+    if EN.Node is TJSFunctionStatement then
+      begin
+      FD:=TJSFunctionStatement(EN.Node).AFunction;
+      AllocateIndirectTypeDefs(FD,aPrefix);
+      end
+    else if EN.Node is TJSMethodDeclaration then
+      begin
+      FD:=TJSMethodDeclaration(EN.Node).FuncDef;
+      AllocateIndirectTypeDefs(FD,aPrefix);
+      end
+    else if (EN.Node is TJSPropertyDeclaration) then
+      begin
+      PD:=EN.Node as TJSPropertyDeclaration;
+      if TypeNeedsTypeName(PD.ElementType,False,True) then
+        Result:=Result+AllocateIndirectTypeDef(PD.ElementType,aPrefix,GetName(PD));
+      end
+    else if (EN.Node is TJSVarDeclaration) then
+      begin
+      VD:=EN.Node as TJSVarDeclaration;
+      if (VD.Typed is TJSObjectTypeDef) then
+        Result:=Result+AllocateIndirectTypeDef(VD.Typed,aPrefix,GetName(VD));
+      end;
+    end;
 end;
 
-procedure TTypescriptToPas.WriteSequenceDef(aDef : TIDLSequenceTypeDefDefinition);
-
-begin
-  Addln('%s = array of %s;',[GetName(aDef),GetTypeName(aDef.ElementType)])
-end;
+Function TTypescriptToPas.AllocateIndirectTypeDefs(aParams: TJSTypedParams; const aPrefix : String): Integer;
 
-procedure TTypescriptToPas.WritePromiseDef(aDef : TIDLPromiseTypeDefDefinition);
+Var
+  I : Integer;
+  aParam : TJSTypedParam;
 
 begin
-  AddLn('%s = TJSPromise;',[GetName(aDef)]);
+  // Writeln('AITD params prefix : ',aPrefix);
+  Result:=0;
+  For I:=0 to aParams.Count-1 do
+    begin
+    aParam:=aParams[i];
+    if TypeNeedsTypeName(aParam.Node,False) then
+      begin
+      AllocateIndirectTypeDef(aParam.Node,aPrefix,UTF8Encode(aParam.Name));
+//      Result:=Result+AllocateTypeName(aParam.Node,aPrefix,UTF8Encode(aParam.Name));
+      end;
+    end;
 end;
 
 
-function TTypescriptToPas.WriteRecordDef(aDef: TIDLRecordDefinition): Boolean;
+function TTypescriptToPas.AllocateIndirectTypeDefs(FD : TJSFuncDef; const aPrefix : String): Integer;
 
 Var
-  KT,VT : String;
+  fn,aTypePrefix : String;
 
 begin
-  Result:=True;
-  KT:=GetTypeName(aDef.KeyType);
-  VT:=GetTypeName(aDef.ValueType);
-  AddLn('%s = Class(TJSObject)',[GetName(aDef)]);
-  AddLn('private');
-  Indent;
-  AddLn('function GetValue(aKey: %s): %s; external name ''[]'';',[KT,VT]);
-  AddLn('procedure SetValue(aKey: %s; const AValue: %s); external name ''[]'';',[KT,VT]);
-  undent;
-  AddLn('public');
-  Indent;
-  AddLn('property Values[Name: %s]: %s read GetProperties write SetProperties; default;',[KT,VT]);
-  undent;
-  AddLn('end;');
+  fn:=UTF8Encode(FD.Name);
+  if fn<>'' then
+    FN:=FN+'_';
+  aTypePrefix:=aPrefix+FN;
+  // Writeln('AITD func (',fd.Name,') prefix : ',aPrefix,' Type prefix: ',aTypePrefix);
+  Result:=AllocateIndirectTypeDefs(FD.TypedParams,aTypePrefix);
+  if TypeNeedsTypeName(FD.ResultType,False,True) then
+    Result:=Result+AllocateIndirectTypeDef(FD.ResultType,aTypePrefix,'Result');
 end;
 
-
-function TTypescriptToPas.WriteEnumDef(aDef: TIDLEnumDefinition): Boolean;
-
+procedure TTypescriptToPas.SetTypeAliases(AValue: TStrings);
 begin
-  Result:=True;
-  AddLn('%s = String;',[GetName(aDef)]);
+  if FTypeAliases=AValue then Exit;
+  FTypeAliases.Assign(AValue);
 end;
 
-function TTypescriptToPas.WriteEnumDefs(aList: TIDLDefinitionList): Integer;
-
-Var
-  D : TIDLDefinition;
-  ED : TIDLEnumDefinition absolute D;
+procedure TTypescriptToPas.SetIncludeInterfaceCode(AValue: TStrings);
+begin
+  if FIncludeInterfaceCode=AValue then Exit;
+  FIncludeInterfaceCode.Assign(AValue);
+end;
 
+procedure TTypescriptToPas.SetIncludeImplementationCode(AValue: TStrings);
 begin
-  Result:=0;
-  EnsureSection(csType);
-  for D in aList do
-    if D is TIDLEnumDefinition then
-      if WriteEnumDef(ED) then
-        Inc(Result);
+  if FIncludeImplementationCode=AValue then Exit;
+  FIncludeImplementationCode.Assign(AValue);
 end;
 
-function TTypescriptToPas.GetArguments(aList: TIDLDefinitionList;
-  ForceBrackets: Boolean): String;
+function TTypescriptToPas.GetIsRaw: Boolean;
+begin
+  Result:=coRaw in Options;
+end;
 
-Var
-  I : TIDLDefinition;
-  A : TIDLArgumentDefinition absolute I;
-  Arg : string;
+procedure TTypescriptToPas.AllocatePasNames(FD : TJSFuncDef; aPrefix: String = '');
 
 begin
-  Result:='';
-  For I in aList do
-    begin
-    Arg:=GetName(A);
-    Arg:=Arg+' : '+GetTypeName(A.ArgumentType);
-    if Result<>'' then
-      Result:=Result+'; ';
-    Result:=Result+Arg;
-    end;
-  if (Result<>'') or ForceBrackets then
-    Result:='('+Result+')';
+  AllocateIndirectTypeDefs(FD.TypedParams,aPrefix);
+  if TypeNeedsTypeName(FD.ResultType,False,True) then
+    AllocateIndirectTypeDef(FD.ResultType,aPrefix,'Result');
 end;
 
-Type
-  // A partial argument list is a list which has been generated for a optional argument.
-  // Additional arguments can never be added to a partial list...
-  TIDLPartialDefinitionList = Class(TIDLDefinitionList);
-
-function TTypescriptToPas.CloneNonPartialArgumentList(aList: TFPObjectlist;
-  ADest: TFPObjectlist; AsPartial: Boolean): integer;
+procedure TTypescriptToPas.AllocatePasNames(aList : TJSElementNodes; ParentName: String = '');
 
 Var
-  I,J : Integer;
-  CD : TIDLDefinition;
-  DL,CL : TIDLDefinitionList;
+  I : Integer;
+  N : TJSElement;
+  TD : TJSTypeDeclaration absolute N;
+  MD : TJSMethodDeclaration absolute N;
+  AD : TJSArrowFunctionTypeDef;
+  PD : TJSPropertyDeclaration absolute N;
+  lParentName,aPrefix : String;
+
 
 begin
-  Result:=0;
-  if ADest=Nil then
-    ADest:=aList;
-  I:=aList.Count-1;
-  While (I>=0) do
+  lParentName:=ParentName;
+  if lParentName<>'' then
+    lParentName:=lParentName+'_';
+  For I:=0 to aList.Count-1 do
     begin
-    DL:=TIDLDefinitionList(alist[i]);
-    if Not (DL is TIDLPartialDefinitionList) then
+    APrefix:='';
+    N:=aList.Nodes[i].Node;
+    AllocatePasName(N,ParentName);
+    if N is TJSAmbientClassDeclaration then
+      AllocatePasNames(TJSAmbientClassDeclaration(N).ClassDef.Values,lParentName)
+    else if N is TJSMembersDeclaration then
+       AllocatePasNames(TJSMembersDeclaration(N).Members)
+    else if (N is TJSTypeDeclaration) then
+       begin
+       if (TD.TypeDef is TJSArrowFunctionTypeDef) then
+         begin
+         aPrefix:=StringReplace(GetName(TD),'&','',[rfReplaceAll])+'_';
+         AD:=TD.TypeDef as TJSArrowFunctionTypeDef;
+         AllocatePasNames(AD.aFunction,aPrefix);
+         end;
+       end
+    else if (N is TJSMethodDeclaration) then
       begin
-      Inc(Result);
-      if AsPartial then
-        CL:=TIDLPartialDefinitionList.Create(Nil,True)
-      else
-        CL:=TIDLDefinitionList.Create(Nil,True);
-      aDest.Add(CL);
-      For J:=0 to DL.Count-1 do
+      if Assigned(MD.FuncDef) then
         begin
-        CD:=(DL.Definitions[J] as TIDLArgumentDefinition).Clone(Nil);
-        CL.Add(CD);
-        AllocatePasName(CD);
+        aPrefix:=StringReplace(GetName(MD),'&','',[rfReplaceAll])+'_';
+        if (lParentName<>'') and not (coLocalArgumentTypes in Options) then
+          aPrefix:=lParentName+aPrefix;
+        AllocatePasNames(MD.FuncDef,aPrefix);
         end;
+      end
+    else if (N is TJSPropertyDeclaration) then
+      begin
+      if Assigned(PD.ElementType) then
+        if TypeNeedsTypeName(PD.ElementType,False,True) then
+          begin
+          AllocateTypeName(PD.ElementType,lParentName,GetName(PD));
+          aPrefix:=StringReplace(GetName(PD),'&','',[rfReplaceAll]);
+          AllocateIndirectTypeDef(PD.ElementType,lParentName,aPrefix);
+          end;
       end;
-    Dec(I);
     end;
 end;
 
-procedure TTypescriptToPas.AddArgumentToOverloads(aList: TFPObjectlist; AName,ATypeName : String);
+procedure TTypescriptToPas.AllocatePasNames(aList : TJSSourceElements; ParentName: String = '');
+
+begin
+  AllocatePasNames(aList.Types,ParentName);
+  AllocatePasNames(aList.Enums,ParentName);
+  AllocatePasNames(aList.Vars,ParentName);
+  AllocateIndirectTypeDefs(aList.Vars,'');
+  AllocatePasNames(aList.Functions,ParentName);
+  AllocateIndirectTypeDefs(aList.Functions,'');
+  AllocatePasNames(aList.Classes,ParentName);
+  AllocatePasNames(aList.Interfaces,ParentName);
+  AllocatePasNames(aList.NameSpaces,ParentName);
+  AllocatePasNames(aList.Modules,ParentName);
+end;
 
-Var
-  I : Integer;
-  CD : TIDLArgumentDefinition;
-  DL : TIDLDefinitionList;
 
+procedure TTypescriptToPas.EnsureUniqueNames(ML: TJSSourceElements);
 begin
-  For I:=0 to aList.Count-1 do
-    begin
-    DL:=TIDLDefinitionList(alist[i]);
-    if Not (DL is TIDLPartialDefinitionList) then
-      begin
-      CD:=TIDLArgumentDefinition.Create(Nil,aName);
-      CD.ArgumentType:=TIDLTypeDefDefinition.Create(CD,'');
-      CD.ArgumentType.TypeName:=aTypeName;
-      DL.Add(CD);
-      AllocatePasName(cd,'');
-      end;
-    end;
+
+end;
+
+procedure TTypescriptToPas.ProcessDefinitions;
+
+begin
+  AllocatePasNames((FElements.A as TJSSourceElements));
+end;
+
+function TTypescriptToPas.ExportNode(aNode: TJSElementNode): Boolean;
+begin
+  With aNode do
+    Result:=IsAmbient or IsExport;
 end;
 
-procedure TTypescriptToPas.AddArgumentToOverloads(aList: TFPObjectlist; adef: TIDLArgumentDefinition);
+procedure TTypescriptToPas.CheckUnitName(SourceElements:TJSSourceElements);
 
 Var
-  I : Integer;
-  CD : TIDLDefinition;
-  DL : TIDLDefinitionList;
+  I : integer;
+  NN : String;
 
 begin
-  For I:=0 to aList.Count-1 do
+  NN:=OutputUnitName;
+  if (NN<>'') and (NN[1] in ['0'..'9']) then
     begin
-    DL:=TIDLDefinitionList(alist[i]);
-    if Not (DL is TIDLPartialDefinitionList) then
+    Dolog('Renaming unit %s to %s to allow compilation.',[OutputUnitName,NN]);
+    NN:='_'+NN;
+    end;
+  For I:=0 to SourceElements.Functions.Count-1 do
+    if (SourceElements.Functions[i].Node as TJSFunctionStatement).AFunction.Name=OutputUnitName then
       begin
-      CD:=aDef.Clone(Nil);
-      DL.Add(CD);
-      if aDef.Data<>Nil then
-        CD.Data:=CreatePasName(TPasData(aDef.Data).PasName)
-      else
-        AllocatePasName(cd,'');
+      NN:=NN+'_';
+      Dolog('Renaming unit %s to %s to avoid name conflict.',[OutputUnitName,NN]);
       end;
-    end;
+  if OutputUnitName<>NN then
+    OutputUnitName:=NN;
 end;
 
-procedure TTypescriptToPas.AddUnionOverloads(aList: TFPObjectlist; AName : String; UT : TIDLUnionTypeDefDefinition);
+procedure TTypescriptToPas.Execute;
 
 Var
-  L,L2 : TFPObjectList;
-  I,J : Integer;
-  D : TIDLDefinitionList;
-  Dups : TStringList;
+  SourceElements:TJSSourceElements;
+  Fwds : TStringList;
 
 begin
-  L2:=Nil;
-  Dups:=TStringList.Create;
-  Dups.Sorted:=True;
-  Dups.Duplicates:=dupIgnore;
-  L:=TFPObjectList.Create(False);
+  FContext:=CreateContext;
   try
-    L2:=TFPObjectList.Create(False);
-    // Collect non partial argument lists
-    for I:=0 to AList.Count-1 do
-      begin
-      D:=TIDLDefinitionList(alist[i]);
-      if Not (D is TIDLPartialDefinitionList) then
-        L.Add(D);
-      end;
-    // Collect unique pascal types. Note that this can reduce the list to 1 element...
-    For I:=0 to UT.Union.Count-1 do
-      Dups.AddObject(GetTypeName(UT.Union[I] as TIDLTypeDefDefinition),UT.Union[I]);
-    // First, clone list and add argument to cloned lists
-    For I:=1 to Dups.Count-1 do
-      begin
-      // Clone list
-      CloneNonPartialArgumentList(L,L2,False);
-      // Add argument to cloned list
-      AddArgumentToOverloads(L2,aName,Dups[i]);
-      // Add overloads to original list
-      For J:=0 to L2.Count-1 do
-        aList.Add(L2[J]);
-      L2.Clear;
-      end;
-    // Add first Union to original list
-    AddArgumentToOverloads(L,aName,Dups[0]);
+    PushNameScope;
+    Parse;
+    SourceElements:=FElements.A as TJSSourceElements;
+    Fwds:=TStringList.Create;
+    try
+      Context.PushScope(SourceElements,fwds);
+      ProcessDefinitions;
+      CheckUnitName(SourceElements);
+      FContext.TypesToMap;
+      if Verbose then
+        DoLog('Parsed %d type definitions.',[FContext.FTypeMap.Count]);
+    finally
+      Context.PopScope(SourceElements,Fwds);
+    end;
+    if Assigned(TypeAliases) then
+      FContext.AddAliases(TypeAliases);
+    WritePascal;
+    if OutputFileName<>'' then
+      Source.SaveToFile(OutputFileName);
   finally
-    Dups.Free;
-    L2.Free;
-    L.Free;
+    PopNameScope;
+    FreeAndNil(FContext);
   end;
 end;
 
-function TTypescriptToPas.CheckUnionTypeDefinition(D: TIDLDefinition
-  ): TIDLUnionTypeDefDefinition;
+{ ----------------------------------------------------------------------
+  Simple types
+  ----------------------------------------------------------------------}
 
-begin
-  Result:=Nil;
-  If (D is TIDLUnionTypeDefDefinition) then
-    Result:=D as TIDLUnionTypeDefDefinition
+
+Function TTypescriptToPas.GetArrayTypeAsString(aTypeDef : TJSArrayTypeDef; asPascal,asSubType : Boolean) : String;
+
+begin
+  if Assigned(aTypeDef.BaseType.Data) then
+    Result:=TPasData(aTypeDef.BaseType.Data).PasName
   else
+    Result:=GetTypeAsString(aTypeDef.BaseType,asPascal,True);
+  if coGenericArrays in Options then
+    Result:='TArray<'+Result+'>'
+  else
+    Result:='array of '+Result;
+  if (not asPascal) and AsSubType then
+    Result:='('+Result+')'
+end;
+
+
+Function TTypescriptToPas.GetTypeAsString(aType : TJSTypeDef; asPascal,asSubType : Boolean) : String;
+
+begin
+  Result:='';
+  if aType is TJSTypeReference then
+    Result:=GetAliasTypeAsString(TJSTypeReference(aType),asPascal,asSubType)
+  else if aType is TJSUnionTypeDef then
+    Result:=GetUnionTypeAsString(TJSUnionTypeDef(aType),asPascal,asSubType)
+  else if aType is TJSIntersectionTypeDef then
+    Result:=GetIntersectionTypeAsString(TJSIntersectionTypeDef(aType),asPascal,asSubType)
+  else if aType is TJSArrayTypeDef then
+    Result:=GetArrayTypeAsString(TJSArrayTypeDef(aType),asPascal,asSubType)
+  else if aType is TJSEnumTypeDef then
+    Result:=GetEnumTypeAsString(TJSEnumTypeDef(aType),asPascal,asSubType)
+  else if aType is TJSTupleTypeDef then
+    Result:=GetTupleTypeAsString(TJSTupleTypeDef(aType),asPascal,True)
+  else if aType is TJSFixedValueReference then
+    Result:=GetFixedValueTypeAsString(TJSFixedValueReference(aType),asPascal,asSubType)
+  else
+    if asPascal then
+      if Assigned(aType.Data) then
+        Result:=TPasData(aType.Data).PasName;
+end;
+
+Function TTypescriptToPas.GetUnionTypeAsString(aTypeDef : TJSUnionTypeDef; asPascal,asSubType : Boolean) : String;
+
+Var
+  I : Integer;
+
+begin
+  Result:='';
+  For I:=0 to aTypeDef.TypeCount-1 do
+    begin
+    if Result<>'' then
+      Result:=Result+' | ';
+    Result:=Result+GetTypeAsString(aTypeDef.Types[I],asPascal,True);
+    end;
+  if AsSubType then
+    Result:='('+Result+')';
+end;
+
+function TTypescriptToPas.GetEnumTypeAsString(aTypeDef: TJSEnumTypeDef; asPascal, asSubType: Boolean): String;
+Var
+  I : Integer;
+  N : String;
+
+begin
+  Result:='';
+  For I:=0 to aTypeDef.NameCount-1 do
     begin
-    D:=Context.FindDefinition((D as TIDLTypeDefDefinition).TypeName);
-    if (D is TIDLUnionTypeDefDefinition) then
-      Result:=D as TIDLUnionTypeDefDefinition
+    if Result<>'' then
+      Result:=Result+', ';
+    N:=UTF8Encode(aTypeDef.Names[I]);
+    if IsKeyWord(N) then
+      N:='&'+N;
+    Result:=Result+N;
+    end;
+  Result:='('+Result+')';
+  if AsSubType then
+    Result:='('+Result+')';
+end;
+
+function TTypescriptToPas.GetFixedValueTypeAsString(aTypeDef: TJSFixedValueReference; asPascal, asSubType: Boolean): string;
+begin
+  case aTypeDef.FixedValue.Value.ValueType of
+    jstUNDEFINED : Result:='jsValue';
+    jstNull : Result:='jsValue';
+    jstBoolean : Result:='Boolean';
+    jstNumber : Result:='Double';
+    jstString : Result:='string';
+    jstObject : Result:='TJSObject';
+    jstReference : Result:='jsValue';
+    jstCompletion : Result:='jsValue';
+  end;
+end;
+
+Function TTypescriptToPas.GetIntersectionTypeAsString(aTypeDef : TJSIntersectionTypeDef; asPascal,asSubType : Boolean) : String;
+
+Var
+  I : Integer;
+
+begin
+  Result:='';
+  For I:=0 to aTypeDef.TypeCount-1 do
+    begin
+    if Result<>'' then
+      Result:=Result+' & ';
+    Result:=Result+GetTypeAsString(aTypeDef.Types[I],asPascal,True);
+    end;
+  if AsSubType then
+    Result:='('+Result+')';
+end;
+
+Procedure TTypescriptToPas.WriteUnionTypeDef(const aPasName : string; const aOrgName : jsBase.TJSString; aTypeParams: TJSElementNodes;aTypeDef : TJSUnionTypeDef);
+
+var
+  TN, gen, genparams, tcomment: String;
+
+begin
+  TN:='jsvalue';
+  if aTypeDef.GetOnlyConstants=ocAllSameTypes then
+    begin
+    TN:=GetTypeAsString((aTypeDef.Values[0].Node as TJSFixedValueReference),True,False);
+    tcomment:=' // Restricted values';
     end
+  else
+    tcomment:=' // '+GetTypeAsString(aTypeDef,False,False);
+  genparams:=GetGenericParams(aTypeParams);
+  if (genparams<>'') then
+    gen:='generic ';
+  AddLn('%s%s%s = %s;%s',[gen,aPasName,genparams,TN,tcomment]);
 end;
 
-procedure TTypescriptToPas.AddOverloads(aList: TFPObjectlist;
-  adef: TIDLFunctionDefinition; aIdx: Integer);
+function TTypescriptToPas.GetTupleTypeAsString(aTypeDef: TJSTupleTypeDef; asPascal,asSubType : Boolean) : String;
 
 Var
-  Arg : TIDLArgumentDefinition;
-  D : TIDLDefinition;
-  UT : TIDLUnionTypeDefDefinition;
+  N :TJSTypeReference;
+  elName : string;
 
 begin
- if aIdx>=ADef.Arguments.Count then
+  Result:='jsvalue';
+  if aTypeDef.Values.Count=0 then
     exit;
-  Arg:=ADef.Argument[aIdx];
-  if Arg.IsOptional then
-    CloneNonPartialArgumentList(aList);
-  // Add current to list.
-  D:=Arg.ArgumentType;
-  UT:=Nil;
-  if coExpandUnionTypeArgs in Options then
-    UT:=CheckUnionTypeDefinition(D);
-  if UT=Nil then
-    AddArgumentToOverloads(aList,Arg)
+  if (Not aTypeDef.GetEqualTypes) or (coUntypedTuples in Options) then
+    begin
+    if coDynamicTuples in Options then
+      Result:='TJSValueDynArray'
+    else
+      Result:=Format('Array[0..%d] of JSValue',[aTypeDef.Values.Count-1]);
+    end
+  else if  aTypeDef.Values[0].Node is TJSTypeReference then
+    begin
+    N:=aTypeDef.Values[0].Node as TJSTypeReference;
+    ElName:=GetTypeAsString(N,True,False);
+    if coDynamicTuples in Options then
+      Result:=Format('Array of %s',[ElName])
+    else
+      Result:=Format('Array[0..%d] of %s',[aTypeDef.Values.Count-1,elName]);
+    end
   else
-    AddUnionOverLoads(aList,Arg.Name,UT);
-  AddOverloads(aList,aDef,aIdx+1);
+    Raise ETSToPas.Create('Unsupported tuple element type');
 end;
+procedure TTypescriptToPas.WriteTupleTypeDef(const aPasName: string; const aOrgName: jsBase.TJSString;
+  aTypeParams: TJSElementNodes; aTypeDef: TJSTupleTypeDef);
+
+var
+  TN, gen, genparams: String;
 
-function TTypescriptToPas.GetOverloads(aDef: TIDLFunctionDefinition): TFPObjectlist;
 
 begin
-  Result:=TFPObjectList.Create;
-  try
-    Result.Add(TIDLDefinitionList.Create(Nil,True));
-    AddOverloads(Result,adef,0);
-  except
-    Result.Free;
-    Raise;
-  end;
+  genparams:=GetGenericParams(aTypeParams);
+  if (genparams<>'') then
+    gen:='generic ';
+  TN:=GetTupleTypeAsString(aTypeDef,True,False);
+  AddLn('%s%s%s = %s;',[gen,aPasName,genparams,TN]);
 end;
 
-function TTypescriptToPas.WriteFunctionTypeDefinition(aDef: TIDLFunctionDefinition): Boolean;
+
+Procedure TTypescriptToPas.WriteIntersectionTypeDef(const aPasName : string; const aOrgName : jsBase.TJSString; aTypeParams: TJSElementNodes;aTypeDef : TJSIntersectionTypeDef);
+
+var
+  TN, gen, genparams: String;
+
+begin
+  TN:='jsvalue';
+  genparams:=GetGenericParams(aTypeParams);
+  if (genparams<>'') then
+    gen:='generic ';
+  AddLn('%s%s%s = %s; // %s',[gen,aPasName,genparams,TN,GetTypeAsString(aTypeDef,False,false)]);
+end;
+
+Procedure TTypescriptToPas.WriteArrayTypeDef(const aPasName : string; const aOrgName : jsBase.TJSString; aTypeParams: TJSElementNodes;aTypeDef : TJSArrayTypeDef);
+
+var
+  arr,gen, genparams: String;
+
+begin
+  genparams:=GetGenericParams(aTypeParams);
+  if (genparams<>'') then
+    gen:='generic ';
+  arr:=GetArrayTypeAsString(aTypeDef,True,False);
+  AddLn('%s%s%s = %s;',[gen,aPasName,genparams,arr]);
+end;
+
+procedure TTypescriptToPas.WriteEnumTypeDef(const aPasName: string; const aOrgName: jsBase.TJSString; aTypeParams: TJSElementNodes;
+  aTypeDef: TJSEnumTypeDef);
+var
+ arr,gen, genparams: String;
+
+begin
+  genparams:=GetGenericParams(aTypeParams);
+  if (genparams<>'') then
+    gen:='generic ';
+  arr:=GetEnumTypeAsString(aTypeDef,True,False);
+  AddLn('%s%s%s = %s;',[gen,aPasName,genparams,arr]);
+end;
+
+
+Procedure TTypescriptToPas.WriteTypeDef(const aPasName : string; const aOrgName : jsBase.TJSString; aTypeParams: TJSElementNodes; aTypeDef : TJSTypeDef);
+
+begin
+  if NameScopeHas(aPasName) then
+    begin
+    Comment(Format('Ignoring duplicate type %s (%s)',[aPasName,UTF8Encode(aOrgName)]));
+    exit;
+    end;
+  AddToNameScope(aPasName,aOrgName);
+  If aTypeDef is TJSTypeReference then
+    WriteAliasTypeDef(aPasName,aOrgName,aTypeParams,TJSTypeReference(aTypeDef))
+  else if aTypeDef is TJSUnionTypeDef then
+    WriteUnionTypeDef(aPasName,aOrgName,aTypeParams,TJSUnionTypeDef(aTypeDef))
+  else if aTypeDef is TJSIntersectionTypeDef then
+    WriteIntersectionTypeDef(aPasName,aOrgName,aTypeParams,TJSIntersectionTypeDef(aTypeDef))
+  else if aTypeDef is TJSArrayTypeDef then
+    WriteArrayTypeDef(aPasName,aOrgName,aTypeParams,TJSArrayTypeDef(aTypeDef))
+  else if aTypeDef is TJSEnumTypeDef then
+    WriteEnumTypeDef(aPasName,aOrgName,aTypeParams,TJSEnumTypeDef(aTypeDef))
+  else if aTypeDef is TJSArrowFunctionTypeDef then
+    WriteFunctionTypeDef(aPasName,aOrgName,aTypeParams,TJSArrowFunctionTypeDef(aTypeDef).aFunction)
+  else if aTypeDef is TJSObjectTypeDef then
+    WriteObjectTypedef(aPasName,aOrgName,aTypeParams,TJSObjectTypeDef(aTypeDef))
+  else if aTypeDef is TJSTupleTypeDef then
+    WriteTupleTypedef(aPasName,aOrgName,aTypeParams,TJSTupleTypeDef(aTypeDef))
+  else
+    AddLn('%s (%s) has unsupported type "%s" : ',[aPasName,aOrgName,aTypeDef.ClassName]);
+end;
+
+function TTypescriptToPas.WriteIndirectTypeDefs(aParams: TJStypedParams): Integer;
 
 Var
-  FN,RT,Args : String;
+  I : Integer;
+  aParam : TJSTypedParam;
+  FuncDef : TJSFuncDef;
+  PD : TPasData;
+
+begin
+  // Writeln('WITD params');
+  Result:=0;
+  For I:=0 to aParams.Count-1 do
+    begin
+    aParam:=aParams[i];
+    if TypeNeedsTypeName(aParam.Node,True)  then
+      begin
+      Inc(Result);
+      PD:=TPasData(aParam.Node.Data);
+      // Recurse
+      if aParam.Node is TJSArrowFunctionTypeDef then
+        begin
+        FuncDef:=(aParam.Node as TJSArrowFunctionTypeDef).aFunction;
+        Result:=Result+WriteIndirectTypeDefs(FuncDef.TypedParams);
+        if TypeNeedsTypeName(FuncDef.ResultType,True) then
+          begin
+          PD:=TPasData(aParam.Node.Data);
+          Inc(Result);
+          WriteTypeDef(PD.PasName,PD.OriginalName,nil, FuncDef.ResultType);
+          end
+        end
+      else if aParam.Node is TJSArrayTypeDef then
+        begin
+        if TypeNeedsTypeName(TJSArrayTypeDef(aParam.Node).BaseType,True,True) then
+          begin
+          PD:=TPasData(TJSArrayTypeDef(aParam.Node).BaseType.Data);
+          Inc(Result);
+          WriteTypeDef(PD.PasName,PD.OriginalName,nil, TJSArrayTypeDef(aParam.Node).BaseType);
+          end
+        end;
+      PD:=TPasData(aParam.Node.Data);
+      WriteTypeDef(PD.PasName,PD.OriginalName,nil,(aParam.Node as TJSTypeDef));
+      end;
+    end;
+end;
+
+function TTypescriptToPas.HasIndirectTypeDefs(aParams: TJStypedParams): Boolean;
+
+Var
+  I : Integer;
+  aParam : TJSTypedParam;
+
+begin
+  Result:=False;
+  I:=0;
+  While (Not Result) and (I<aParams.Count) do
+    begin
+    aParam:=aParams[i];
+    Result:=Assigned(aParam.Node) and Assigned(aParam.Node.Data);
+    Inc(I);
+    end;
+end;
+
+function TTypescriptToPas.HasIndirectTypeDefs(aElements: TJSElementNodes): Boolean;
+
+var
+  EN : TJSElementNode;
+  FD : TJSFuncDef;
+
+begin
+  Result:=False;
+  For EN in aElements do
+    if ExportNode(EN) then
+      begin
+      if (EN.Node is TJSFunctionStatement) then
+        begin
+        FD:=TJSFunctionStatement(EN.Node).AFunction;
+        Result:=HasIndirectTypeDefs(FD.TypedParams);
+        if Result then
+          Exit;
+        end;
+      if (EN.Node is TJSObjectTypeDef) then
+        begin
+        Result:=HasIndirectTypeDefs(TJSObjectTypeDef(EN.Node).Values);
+        if Result then
+          Exit;
+        end;
+      if (EN.Node is TJSVarDeclaration) then
+        begin
+        Result:=TJSVarDeclaration(EN.Node).Typed is TJSObjectTypeDef;
+        if Result then
+          Exit;
+        end;
+      end;
+end;
+
+function TTypescriptToPas.WriteIndirectTypeDefs(aEl : TJSElement): Integer;
+
+Var
+  PD : TPasData;
+
+begin
+  Result:=0;
+  if aEl is TJSArrowFunctionTypeDef then
+    Result:=WriteIndirectTypeDefs((aEl as TJSArrowFunctionTypeDef).aFunction)
+  else if aEl is TJSArrayTypeDef then
+    begin
+    Result:=WriteIndirectTypeDefs((aEl as TJSArrayTypeDef).BaseType);
+    PD:=TPasData((aEl as TJSArrayTypeDef).BaseType.Data);
+    if assigned(PD) then
+      WriteTypeDef(PD.PasName,PD.OriginalName,Nil,(aEl as TJSArrayTypeDef).BaseType);
+    end
+  else if aEl is TJSObjectTypeDef then
+    Result:=WriteIndirectTypeDefs((aEl as TJSObjectTypeDef).Values);
+end;
+
+function TTypescriptToPas.WriteIndirectTypeDefs(FD : TJSFuncDef): Integer;
+
+var
+  PD : TPasData;
+begin
+  // Writeln('WIDT Func : ',FD.Name);
+  Result:=WriteIndirectTypeDefs(FD.TypedParams);
+  if TypeNeedsTypeName(FD.ResultType,True,True) then
+    begin
+    WriteIndirectTypeDefs(FD.ResultType);
+    PD:=TPasData(FD.ResultType.Data);
+    if PD=Nil then
+      Raise ETSToPas.CreateFmt('No name allocated for function %s (%d,%d) result type %s',[FD.Name,FD.ResultType.Line,FD.ResultType.Column,FD.ResultType.ClassName]);
+    WriteTypeDef(PD.PasName,PD.OriginalName,nil,FD.ResultType);
+    end;
+end;
+
+function TTypescriptToPas.WriteIndirectTypeDefs(aElements: TJSElementNodes): Integer;
+
+var
+  EN : TJSElementNode;
+  FD : TJSFuncDef;
+
+begin
+  // Writeln('WIDT elements: ');
+  Result:=0;
+  For EN in aElements do
+    begin
+    FD:=Nil;
+    if (EN.Node is TJSFunctionStatement) then
+      FD:=TJSFunctionStatement(EN.Node).AFunction
+    else if (EN.Node is TJSTypeDeclaration) and (TJSTypeDeclaration(EN.Node).TypeDef is TJSArrowFunctionTypeDef) then
+      FD:=TJSArrowFunctionTypeDef(TJSTypeDeclaration(En.Node).TypeDef).aFunction;
+    if Assigned(FD) then
+      Result:=Result+WriteIndirectTypeDefs(FD)
+    end;
+  WritePropertyTypeDefs(aElements,'');
+end;
+
+function TTypescriptToPas.WritePropertyTypeDefs(aElements: TJSElementNodes; SectionName : String = ''): Integer;
+
+Var
+  P : TJSPropertyDeclaration;
+  aName : String;
+  PD : TPasData;
+  EN : TJSElementNode;
+  TD : TJSTypeDef;
+  DidIndent : Boolean;
+
+begin
+  Result:=0;
+  DidIndent:=False;
+  For EN in aElements do
+    begin
+    TD:=Nil;
+    aName:='';
+    if EN.Node is TJSPropertyDeclaration then
+      begin
+      P:=TJSPropertyDeclaration(EN.Node);
+      aName:=P.Name;
+      TD:=P.ElementType;
+      If not TypeNeedsTypeName(TD,True,True) then
+        TD:=Nil
+      end
+    else if EN.Node is TJSVarDeclaration then
+      begin
+      aName:=TJSVarDeclaration(EN.Node).Name;
+      TD:=TJSVarDeclaration(EN.Node).Typed;
+      if not (TD is TJSObjectTypeDef) then
+        TD:=nil;
+      end;
+    if Assigned(TD) then
+      begin
+      if (Result=0) and (SectionName<>'') then
+        begin
+        AddLn(SectionName);
+        Indent;
+        AddLn('Type');
+        Indent;
+        DidIndent:=True;
+        end;
+      PD:=TPasData(TD.Data);
+      if TD is TJSArrowFunctionTypeDef then
+        Result:=Result+WriteIndirectTypeDefs((TD as TJSArrowFunctionTypeDef).aFunction)
+      else if TD is TJSObjectTypeDef then
+        Result:=Result+WriteIndirectTypeDefs((TD as TJSObjectTypeDef).Values);
+      if PD=Nil then
+        Raise ETSToPas.CreateFmt('Element without allocated typename: %s %s',[aName,TD.ClassName]);
+      WriteTypeDef(PD.PasName,PD.OriginalName,Nil,TD);
+      Inc(Result);
+      end;
+    end;
+  if DidIndent then
+    begin
+    Undent;
+    Undent;
+    end;
+end;
+
+function TTypescriptToPas.WriteMethodParameterDefs(aElements: TJSElementNodes; SectionName : String = ''): Integer;
+
+var
+  EN : TJSElementNode;
+  FD : TJSFuncDef;
+  Didindent : Boolean;
+  PD : TPasData;
+
+begin
+  Result:=0;
+  DidIndent:=False;
+  For EN in aElements do
+    if EN.Node is TJSMethodDeclaration then
+      begin
+      FD:=TJSMethodDeclaration(EN.Node).FuncDef;
+      if (Result=0) and (SectionName<>'') then
+        begin
+        AddLn(SectionName);
+        Indent;
+        AddLn('Type');
+        Indent;
+        DidIndent:=True;
+        end;
+      WriteIndirectTypeDefs(FD);
+      end;
+  if DidIndent then
+    begin
+    Undent;
+    Undent;
+    end;
+end;
+
+
+Procedure TTypescriptToPas.WriteTypeDefs(Types: TJSElementNodes);
+
+Var
+  I : Integer;
+  N : TJSElement;
+  Decl : TJSTypeDeclaration absolute N;
+  aName : String;
+
+begin
+  EnsureSection(csType);
+  for I:=0 to Types.Count-1 do
+    if ExportNode(Types[i]) then
+      begin
+      N:=Types[I].Node;
+      // TJSEnumDeclaration is a descendent
+      if N is TJSTypeDeclaration then
+        begin
+        aName:=GetName(Decl);
+        WriteTypeDef(aName, Decl.Name, Decl.TypeParams, Decl.TypeDef);
+        end
+      end;
+end;
+
+
+function TTypescriptToPas.WritePrivateReadOnlyField(P : TJSPropertyDeclaration) : Boolean;
+Var
+  FN : String;
 
 begin
   Result:=True;
-  FN:=GetName(aDef);
-  RT:=GetTypeName(aDef.ReturnType,False);
-  if (RT='void') then
-    RT:='';
-  Args:=GetArguments(aDef.Arguments,False);
-  if (RT='') then
-    AddLn('%s = Procedure %s;',[FN,Args])
-  else
-    AddLn('%s = function %s: %s;',[FN,Args,RT])
+  FN:=StringReplace(GetName(P),'&','',[rfReplaceAll]);
+  AddLn('%s%s : %s; external name ''%s''; ',[FieldPrefix,FN,GetTypeName(P.ElementType),P.Name]);
 end;
 
-function TTypescriptToPas.WriteFunctionDefinition(aDef: TIDLFunctionDefinition): Boolean;
+function TTypescriptToPas.WritePrivateReadOnlyField(M : TJSMethodDeclaration) : Boolean;
+
+Var
+  FN : String;
+
+begin
+  Result:=True;
+  FN:=StringReplace(GetName(M),'&','',[rfReplaceAll]);
+  AddLn('%s%s : %s; external name ''%s''; ',[FieldPrefix,FN,GetTypeName(M.FuncDef.ResultType),M.Name]);
+end;
+
+
+Function TTypescriptToPas.HasReadOnlyPropFields(aTypeDef : TJSObjectTypeDef) : Boolean;
+
+Var
+  I : Integer;
+  aEl : TJSObjectTypeElementDef;
+  P : TJSPropertyDeclaration;
+
+begin
+  Result:=False;
+  I:=0;
+  While (Not Result) and (I<aTypeDef.ElementCount) do
+    begin
+    aEl:=aTypeDef.Elements[i];
+    if aEl is TJSPropertyDeclaration then
+      begin
+      P:=TJSPropertyDeclaration(aTypeDef.Elements[i]);
+      Result:=P.IsReadOnly;
+      end
+    else if aEl is TJSMethodDeclaration then
+      Result:=TJSMethodDeclaration(aEl).IsGet and not aTypeDef.HasSetter(ael.Name);
+    Inc(I);
+    end;
+end;
+
+Function TTypescriptToPas.WriteReadOnlyPropFields(aTypeDef : TJSObjectTypeDef) : Integer;
+
 
 Var
-  FN,RT,Suff,Args : String;
-  Overloads : TFPObjectList;
   I : Integer;
+  aEl : TJSObjectTypeElementDef;
+  P : TJSPropertyDeclaration;
+
+begin
+  Result:=0;
+  For I:=0 to aTypeDef.ElementCount-1 do
+    begin
+    aEl:=aTypeDef.Elements[i];
+    if aEl is TJSPropertyDeclaration then
+      begin
+      P:=TJSPropertyDeclaration(aTypeDef.Elements[i]);
+      if P.IsReadOnly then
+        WritePrivateReadonlyField(P);
+      end
+    else if aEl is TJSMethodDeclaration then
+      if TJSMethodDeclaration(aEl).IsGet and not aTypeDef.HasSetter(ael.Name) then
+        WritePrivateReadonlyField(TJSMethodDeclaration(aEl));
+    end;
+end;
+
+function TTypescriptToPas.WriteClassIndirectTypeDefs(aElements: TJSElementNodes; isClassLocal : Boolean) : Integer;
+
+Var
+  Sect : String;
+
+begin
+  Result:=0;
+  if Not IsClassLocal then
+    begin
+    Result:=WritePropertyTypeDefs(aElements);
+    Result:=Result+WriteMethodParameterDefs(aElements);
+    end
+  else
+    begin
+    Result:=WriteMethodParameterDefs(aElements,'Public');
+    if Result>0 then
+      Sect:=''
+    else
+      Sect:='Public';
+    Result:=Result+WritePropertyTypeDefs(aElements,Sect);
+    end;
+end;
+function TTypescriptToPas.WriteAmbientClassDef(aPasName : String; aOrgName : TJSString; aTypeParams: TJSElementNodes; aClass: TJSAmbientClassDeclarationArray): Boolean;
+
+Type
+  TMembers = array of TJSSourceElements;
+
+  Procedure AddNameSpaceMembers(var AMembers : TMembers);
+
+  Var
+    I : Integer;
+    NS : TJSNameSpaceDeclaration;
+
+  begin
+    Result:=False;
+    I:=Context.CurrentScope.NameSpaces.Count-1;
+    While  (I>=0) do
+      begin
+      NS:=TJSNameSpaceDeclaration(Context.CurrentScope.NameSpaces[i].Node);
+      If (aOrgName = NS.Name) then
+        aMembers:=Concat(aMembers,[NS.Members]);
+      Dec(I);
+      end;
+  end;
+
+
+Var
+  Sect,aParentName : string;
+  aCount : Integer;
+  Members : TMembers;
+  M : TJSSourceElements;
+  C,C0 : TJSAmbientClassDeclaration;
 
 begin
   Result:=True;
-  if not (foConstructor in aDef.Options) then
+  C0:=aClass[0];
+  if C0.Extends is TJSTypeReference then
+    aParentName:=GetTypeName(C0.Extends)
+  else
+    aParentName:=DefaultClassParent;
+  Members:=[];
+  AddNameSpaceMembers(Members);
+  if not (coLocalArgumentTypes in Options) then
+    for C in aClass do
+      WriteClassIndirectTypeDefs(C.ClassDef.Values,False);
+  AddLn('%s = class external name ''%s'' (%s)',[aPasName,aOrgName,aParentName]);
+  if (coLocalArgumentTypes in Options) then
     begin
-    FN:=GetName(aDef);
-    if FN<>aDef.Name then
-      Suff:=Format('; external name ''%s''',[aDef.Name]);
-    RT:=GetTypeName(aDef.ReturnType,False);
-    if (RT='void') then
-      RT:='';
+    For C in aClass do
+      aCount:=WriteClassIndirectTypeDefs(C.ClassDef.Values,True)
     end
   else
-    FN:='New';
-  Overloads:=GetOverloads(ADef);
-  try
-    for I:=0 to aDef.Arguments.Count-1 do
-      if aDef.Argument[i].HasEllipsis then
-        Suff:='; varargs';
-    if Overloads.Count>1 then
-      Suff:=Suff+'; overload';
-    For I:=0 to Overloads.Count-1 do
+    aCount:=0;
+  for M in Members do
+    begin
+    if aCount=0 then
       begin
-      Args:=GetArguments(TIDLDefinitionList(Overloads[i]),False);
-      if (RT='') then
+      Addln('Public');
+      Indent;
+      Addln('Type');
+      end;
+      WriteSourceElements(M,aOrgName);
+      Undent;
+      Addln('Public');
+      end;
+  For C in aClass do
+    WriteObjectTypeMembers(aPasName,aOrgName,aTypeParams,C.ClassDef);
+  AddLn('end;');
+  AddLn('');
+end;
+
+function TTypescriptToPas.WriteClassDefs(aClasses: TJSElementNodes): Integer;
+
+  Function GetClasses(aName : TJSString) : TJSAmbientClassDeclarationArray;
+
+  Var
+    I,aCount : Integer;
+    N : TJSElement;
+
+  begin
+    aCount:=0;
+    SetLength(Result,aClasses.Count);
+    For I:=0 to aClasses.Count-1 do
+      begin
+      N:=aClasses[I].Node;
+      if N is TJSAmbientClassDeclaration then
+        if aName=GetName(N) then
+          begin
+          Result[aCount]:=TJSAmbientClassDeclaration(N);
+          Inc(aCount);
+          end;
+      end;
+    SetLength(Result,aCount);
+  end;
+
+
+Var
+  I : Integer;
+  N : TJSElement;
+  AmbientDecl : TJSAmbientClassDeclarationArray;
+  // ClassDecl : TJSClassDeclaration absolute N;
+  aName : String;
+  L : TStringList;
+
+begin
+  Result:=0;
+  EnsureSection(csType);
+  L:=TStringList.Create;
+  try
+    L.Duplicates:=DupIgnore;
+    for I:=0 to aClasses.Count-1 do
+      if ExportNode(aClasses[i]) then
         begin
-        if not (foConstructor in aDef.Options) then
-          AddLn('Procedure %s%s%s;',[FN,Args,Suff])
-        else
-          AddLn('constructor %s%s%s;',[FN,Args,Suff]);
-        end
-      else
-        AddLn('function %s%s: %s%s;',[FN,Args,RT,Suff])
+        N:=aClasses[I].Node;
+        // TJSEnumDeclaration is a descendent
+        if N is TJSAmbientClassDeclaration then
+          L.Add(GetName(N));
+        end;
+    For I:=0 to L.Count-1 do
+     begin
+     aName:=L[I];
+     AmbientDecl:=GetClasses(aName);
+     if Length(AmbientDecl)>0 then
+       begin
+       if Length(AmbientDecl)>1 then
+         DoLog('Folding %d definitions to 1 class for %s',[Length(AmbientDecl),aName]);
+       if WriteAmbientClassDef(aName, AmbientDecl[0].Name, AmbientDecl[0].TypeParams, AmbientDecl) then
+         Inc(Result);
+       end;
+     end;
+  finally
+    L.Free;
+  end;
+end;
+
+
+function TTypescriptToPas.WritePropertyDef(aProp: TJSPropertyDeclaration): Boolean;
+
+Var
+  Def,TN,FN,aName : String;
+
+begin
+  Result:=True;
+  FN:=GetName(aProp);
+  TN:=GetTypeName(aProp.ElementType);
+  if TN='record' then
+    TN:='TJSObject';
+  if SameText(FN,TN) then
+    FN:=FN+'_';
+  Def:=Format('%s : %s;',[FN,TN]);
+  aName:=UTF8Encode(aProp.Name);
+  if (FN<>aName) then
+    Def:=Def+Format('external name ''%s'';',[aName]);
+  AddLn(Def);
+end;
+
+function TTypescriptToPas.WriteReadonlyProperty(aProp: TJSPropertyDeclaration): Boolean;
+
+Var
+  TN,N,PN : String;
+
+begin
+  Result:=True;
+  N:=StringReplace(GetName(aProp),'&','',[rfReplaceAll]);
+  PN:=N;
+  TN:=GetTypeName(aProp.ElementType);
+  if SameText(PN,TN) then
+    PN:='_'+PN;
+  AddLn('Property %s : %s Read %s%s; ',[PN,TN,FieldPrefix,N]);
+end;
+
+Function TTypescriptToPas.WriteObjectMethods(aAccess : TAccessibility; aTypeDef: TJSObjectTypeDef) : Integer;
+
+
+Var
+  L : TStringList;
+  I,aCount : Integer;
+  FN : String;
+  aDefs : Array of TJSFuncDef;
+
+begin
+  Result:=0;
+  L:=TStringList.Create;
+  try
+    L.Sorted:=true;
+    L.Duplicates:=dupIgnore;
+    For I:=0 to aTypeDef.ElementCount-1 do
+      if (aTypeDef.Elements[I].Accessibility=aAccess) and
+         (aTypeDef.Elements[I] is TJSMethodDeclaration) then
+        L.Add(GetName(aTypeDef.Elements[I]));
+    For FN in L do
+      begin
+      aCount:=0;
+      aDefs:=[];
+      SetLength(aDefs,aTypeDef.ElementCount);
+      For I:=0 to aTypeDef.ElementCount-1 do
+        if (aTypeDef.Elements[I].Accessibility=aAccess) and
+           (aTypeDef.Elements[I] is TJSMethodDeclaration) and
+           (GetName(aTypeDef.Elements[I])=FN) then
+             begin
+             if TJSMethodDeclaration(aTypeDef.Elements[I]).FuncDef=nil then
+               DoLog('Ignoring empty method')
+             else
+               begin
+               aDefs[aCount]:=TJSMethodDeclaration(aTypeDef.Elements[I]).FuncDef;
+               inc(aCount);
+               end;
+             end;
+      SetLength(aDefs,aCount);
+      I:=Length(aDefs);
+      WriteFunctionDefinition(FN,aDefs,False);
+      end;
+  finally
+    L.Free;
+  end;
+end;
+
+procedure TTypescriptToPas.WriteIndexSignature(aSign : TJSIndexSignatureDeclaration);
+
+begin
+  If aSign=Nil then
+    exit;
+end;
+
+procedure TTypescriptToPas.WriteObjectTypeMembers(const aPasName: String; const aOrigName: jsBase.TJSString; aTypeParams: TJSElementNodes; aTypeDef: TJSObjectTypeDef);
+
+Var
+  I : Integer;
+  EmitAccessibility : Boolean;
+
+begin
+  EmitAccessibility:=Not (aTypeDef is TJSInterfaceDeclaration);
+
+  if HasReadOnlyPropFields(aTypeDef) or aTypeDef.HasAccessMembers(accPrivate) then
+    begin
+    if EmitAccessibility then
+      AddLn(GetAccessName(accPrivate));
+    Indent;
+    WriteReadOnlyPropFields(aTypeDef);
+    WriteObjectMethods(accPrivate,aTypeDef);
+    WriteProperties(accPrivate,aTypeDef.Values);
+    Undent;
+    end;
+  if aTypeDef.HasAccessMembers(accProtected) then
+    begin
+    if EmitAccessibility then
+      AddLn(GetAccessName(accProtected));
+    Indent;
+    WriteObjectMethods(accProtected,aTypeDef);
+    WriteProperties(accProtected,aTypeDef.Values);
+    Undent;
+    end;
+  if aTypeDef.HasAccessMembers(accPublic) then
+    begin
+    if EmitAccessibility then
+      AddLn(GetAccessName(accPublic));
+    Indent;
+    WriteObjectMethods(accPublic,aTypeDef);
+    WriteProperties(accPublic,aTypeDef.Values);
+    undent;
+    end;
+  if aTypeDef.HasAccessMembers(accDefault) then
+    begin
+    if EmitAccessibility then
+      AddLn(GetAccessName(accPublic));
+    Indent;
+    WriteObjectMethods(accDefault,aTypeDef);
+    WriteProperties(accDefault,aTypeDef.Values);
+    undent;
+    end;
+  For I:=0 to aTypeDef.ElementCount-1 do
+    if aTypeDef.Elements[I] is TJSIndexSignatureDeclaration then
+      begin
+      Indent;
+      WriteIndexSignature(aTypeDef.Elements[I] as TJSIndexSignatureDeclaration);
+      Undent;
       end;
-  finally
-    Overloads.Free;
-  end;
-end;
-
-function TTypescriptToPas.WriteCallBackDefs(aList: TIDLDefinitionList): Integer;
-
-Var
-  D : TIDLDefinition;
-  FD : TIDLFunctionDefinition absolute D;
-
-begin
-  Result:=0;
-  EnsureSection(csType);
-  for D in aList do
-    if D is TIDLFunctionDefinition then
-      if (foCallBack in FD.Options) then
-         if WriteFunctionTypeDefinition(FD) then
-           Inc(Result);
 end;
 
-function TTypescriptToPas.WriteDictionaryDefs(aList: TIDLDefinitionList): Integer;
+procedure TTypescriptToPas.WriteObjectTypedef(const aPasName: String; const aOrigName: jsBase.TJSString;
+  aTypeParams: TJSElementNodes; aTypeDef: TJSObjectTypeDef);
 
 Var
-  D : TIDLDefinition;
-  DD : TIDLDictionaryDefinition absolute D;
+  I : Integer;
+  aName : string;
 
 begin
-  Result:=0;
-  EnsureSection(csType);
-  for D in aList do
-    if D is TIDLDictionaryDefinition then
-      if not TIDLDictionaryDefinition(D).IsPartial then
-        if WriteDictionaryDef(DD) then
-          Inc(Result);
+  aName:='Object';
+  For I:=0 to aTypeDef.ElementCount-1 do
+   if (aTypeDef.Elements[I].Name='new') and (aTypeDef.Elements[I] is TJSMethodDeclaration) then
+     aName:=UTF8Encode(aOrigName);
+  AddLn('%s = class external name ''%s'' (TJSObject)',[aPasName,aName]);
+  WriteObjectTypeMembers(aPasName,aOrigName,aTypeParams,aTypeDef);
+  AddLn('end;');
+  AddLn('');
 end;
 
-function TTypescriptToPas.WriteInterfaceDefs(aList: TIDLDefinitionList): Integer;
-
-Var
-  D : TIDLDefinition;
-  ID : TIDLInterfaceDefinition absolute D;
+{ ----------------------------------------------------------------------
+  Functions
+  ----------------------------------------------------------------------}
 
-begin
-  Result:=0;
-  EnsureSection(csType);
-  for D in aList do
-    if D is TIDLInterfaceDefinition then
-      if not TIDLInterfaceDefinition(D).IsPartial then
-        if WriteInterfaceDef(ID) then
-          Inc(Result);
-end;
-*)
 
-procedure TTypescriptToPas.Getoptions(L : TStrings);
+function TTypescriptToPas.GetArguments(aList: TJSTypedParams; ForceBrackets: Boolean): String;
 
 Var
-  S : String;
-  I : Integer;
+  E : TJSElementNode;
+  aParam : TJSTypedParam absolute E;
+  aType : TJSTypeDef;
+  Arg,aArgType : string;
 
 begin
-  L.Add('Automatically generated file by '+ClassName+' on '+FormatDateTime('yyyy-mm-dd hh:nn:ss',Now));
-  L.Add('');
-  L.Add('Used command-line options : ');
-  For I:=1 to ParamCount do
-    L.Add(ParamStr(i));
-  L.Add('');
-  L.Add('Command-line options translate to: ');
-  L.Add('');
-  S:=SetToString(PtypeInfo(TypeInfo(TConversionOptions)),Integer(OPtions),True);
-  L.Add('Options : '+S);
-  L.Add('Keyword prefix : '+KeywordPrefix);
-  L.Add('Keyword suffix : '+KeywordSuffix);
-  L.Add('Class prefix : '+ClassPrefix);
-  L.Add('Class suffix : '+ClassSuffix);
-  L.Add('Field prefix : '+FieldPrefix);
-  Str(ECMAversion,S);
-  L.Add('ECMALversion : '+S);
-  if TypeAliases.Count>0 then
+  Result:='';
+  For E in aList do
     begin
-    L.Add('Type aliases:');
-    L.AddStrings(Self.TypeAliases);
+    Arg:=GetName(aParam);
+    if Not Assigned(aParam.Type_) then
+      aArgType:='jsvalue'
+    else
+      begin
+      aType:=aParam.Type_ as TJSTypeDef;
+      aArgType:=GetTypeName(AType);
+      end;
+    Arg:=Arg+' : '+aArgType;
+    if Result<>'' then
+      Result:=Result+'; ';
+    Result:=Result+Arg;
     end;
+  if (Result<>'') or ForceBrackets then
+    Result:='('+Result+')';
 end;
 
-procedure TTypescriptToPas.AddOptionsToHeader;
+Type
+  // A partial params list is a list which has been generated for a optional argument.
+  // This is how we distinguish lists that can be added to from lists that cannot be added to:
+  // Additional parameters can never be added to a partial list.
+  TJSPartialParams = Class(TJSTypedParams);
+
+
+procedure TTypescriptToPas.AddUnionOverloads(aList: TFunctionOverLoadArgumentsList; AName : TJSString; UT : TJSUnionTypeDef);
 
 Var
-  L : TStrings;
+  L,L2 : TFunctionOverLoadArgumentsList;
+  I,J : Integer;
+  D : TJSTypedParams;
+  Dups : TStringList;
+
 begin
-  L:=TStringList.Create;
+  L2:=Nil;
+  L:=Nil;
+  Dups:=TStringList.Create;
   try
-    GetOptions(L);
-    Comment(L);
+    Dups.Sorted:=True;
+    Dups.Duplicates:=dupIgnore;
+    L:=TFunctionOverLoadArgumentsList.Create(False);
+    L2:=TFunctionOverLoadArgumentsList.Create(False);
+    // Collect non partial argument lists
+    for I:=0 to AList.Count-1 do
+      begin
+      D:=TJSTypedParams(alist[i]);
+      if Not (D is TJSPartialParams) then
+        L.AddOverload(D);
+      end;
+    // Collect unique pascal types. Note that this can reduce the list to 1 element...
+    For I:=0 to UT.TypeCount-1 do
+      Dups.AddObject(GetTypeName(UT.Types[I]),UT.Types[I]);
+    // First, clone list and add argument to cloned lists
+    For I:=1 to Dups.Count-1 do
+      begin
+      // Clone list
+      CloneNonPartialParameterList(L,L2,False);
+      // Add argument to cloned list
+      AddParameterToOverloads(L2,aName,Dups.Objects[i] as TJSTypeDef);
+      // Add overloads to original list
+      For J:=0 to L2.Count-1 do
+        aList.Add(L2[J]);
+      L2.Clear;
+      end;
+    // Add first Union to original list
+    AddParameterToOverloads(L,aName,Dups.Objects[0] as TJSTypeDef);
   finally
+    Dups.Free;
+    L2.Free;
     L.Free;
   end;
 end;
 
-procedure TTypescriptToPas.WriteIncludeInterfaceCode;
+
+function TTypescriptToPas.CloneNonPartialParameterList(aList: TFunctionOverLoadArgumentsList; ADest: TFunctionOverLoadArgumentsList = Nil; AsPartial: Boolean = True): integer;
 
 Var
-  S : String;
+  I : Integer;
+  DL,CL : TJSTypedParams;
 
 begin
-  For S in IncludeInterfaceCode do
-    Addln(S);
+  Result:=0;
+  if ADest=Nil then
+    ADest:=aList;
+  I:=aList.Count-1;
+  While (I>=0) do
+    begin
+    DL:=TJSTypedParams(alist[i]);
+    if Not (DL is TJSPartialParams) then
+      begin
+      Inc(Result);
+      if AsPartial then
+        CL:=TJSPartialParams.CreateTransient
+      else
+        CL:=TJSTypedParams.CreateTransient;
+      CL.Assign(DL);
+      aDest.AddOverload(CL);
+      end;
+    Dec(I);
+    end;
 end;
 
-constructor TTypescriptToPas.Create(Aowner: TComponent);
-begin
-  inherited Create(Aowner);
-  ECMaVersion:=ecma2021;
-  FieldPrefix:='F';
-  ClassPrefix:='T';
-  ClassSuffix:='';
-  Switches.Add('modeswitch externalclass');
-  FTypeAliases:=TStringList.Create;
-  FPasNameList:=TFPObjectList.Create(True);
-  FAutoTypes:=TStringList.Create;
-  FIncludeInterfaceCode:=TStringList.Create;
-  FIncludeImplementationCode:=TStringList.Create;
-end;
+procedure TTypescriptToPas.AddParameterToOverloads(aList: TFunctionOverLoadArgumentsList; const AName : TJSString; ATypeDef : TJSTypeDef);
 
+Var
+  I : Integer;
+  aParam : TJSTypedParam;
+  aParams : TJSTypedParams;
 
-destructor TTypescriptToPas.Destroy;
 begin
-  FreeAndNil(FElements);
-  FreeAndNil(FIncludeInterfaceCode);
-  FreeAndNil(FIncludeImplementationCode);
-  FreeAndNil(FAutoTypes);
-  FreeAndNil(FTypeAliases);
-  FreeAndNil(FPasNameList);
-  inherited Destroy;
+  For I:=0 to aList.Count-1 do
+    begin
+    aParams:=TJSTypedParams(alist[i]);
+    if Not (aParams is TJSPartialParams) then
+      begin
+      aParam:=aParams.Add as TJSTypedParam;
+      aParam.Name:=aName;
+      aParam.Node:=ATypeDef;
+      end;
+    end;
 end;
 
-
-procedure TTypescriptToPas.WriteVariable(aVar : TJSVarDeclaration);
+procedure TTypescriptToPas.AddParameterToOverloads(aList: TFunctionOverLoadArgumentsList; const aParam: TJSTypedParam);
 
 Var
-  Src,aPasName,aTypeName,aExportName : String;
+  I : Integer;
+  aClonedParam : TJSTypedParam;
+  aParams : TJSTypedParams;
 
 begin
-  aPasName:=GetName(aVar);
-  aExportName:=aVar.Name;
-  aTypeName:=GetTypeName(aVar.Typed,False);
-  Src:=aPasName + ' : '+aTypeName+';';
-  if aExportName<>aPasName then
-    Src:=Src+' external name '''+aExportName+''';';
-  AddLn(Src);
+  For I:=0 to aList.Count-1 do
+    begin
+    aParams:=TJSTypedParams(alist[i]);
+    if Not (aParams is TJSPartialParams) then
+      begin
+      aClonedParam:=aParams.Add as TJSTypedParam;
+      aClonedParam.Assign(aParam);
+      end;
+    end;
 end;
 
-procedure TTypescriptToPas.WriteVariables(Vars : TJSElementNodes);
+
+procedure TTypescriptToPas.AddOverloadParams(aList: TFunctionOverLoadArgumentsList; adef: TJSFuncDef; aIdx: Integer);
 
 Var
-  I : Integer;
+  aParam : TJSTypedParam;
+  D : TJSTypeDef;
+  UT : TJSUnionTypeDef;
 
 begin
-  For I:=0 to Vars.Count-1 do
-    WriteVariable(Vars.Nodes[i].Node as TJSVarDeclaration);
+ if aIdx>=ADef.TypedParams.Count then
+    Exit;
+  aParam:=ADef.TypedParams[aIdx];
+  if aParam.IsOptional then
+    CloneNonPartialParameterList(aList);
+  // Add current to list.
+  D:=aParam.Node as TJSTypeDef;
+  UT:=Nil;
+  if coExpandUnionTypeArgs in Options then
+    UT:=CheckUnionTypeDefinition(D);
+  if UT=Nil then
+    AddParameterToOverloads(aList,aParam)
+  else
+    AddUnionOverLoads(aList,aParam.Name,UT);
+  AddOverloadParams(aList,aDef,aIdx+1);
 end;
 
-procedure TTypescriptToPas.WritePascal;
+
+function TTypescriptToPas.GetOverloads(const aDefs: TJSFuncDefArray): TFunctionOverLoadArgumentsList;
+
 
 Var
-  SourceElements : TJSSourceElements;
+  aDef : TJSFuncDef;
+  aFunc : TFunctionOverLoadArgumentsList;
+  Len,I : Integer;
 
 begin
-  SourceElements:=FElements.A as TJSSourceElements;
-  if Not IsRaw then
-    begin
-    CreateUnitClause;
-    CreateHeader;
-    if coaddOptionsToheader in Options then
-      AddOptionsToHeader;
-    end;
-  if (SourceElements.Types.Count>0) or (SourceElements.Enums.Count>0) then
-    begin
-    EnsureSection(csType);
-    Indent;
-    WriteTypeDefs(SourceElements.Types);
-    WriteTypeDefs(SourceElements.Enums);
-    {
-    WriteForwardClassDefs(Context.Definitions);
-    WriteEnumDefs(Context.Definitions);
-    WriteCallbackDefs(Context.Definitions);
-    WriteDictionaryDefs(Context.Definitions);
-    WriteInterfaceDefs(Context.Definitions);
-    }
-    Undent;
-    end;
-  if SourceElements.Vars.Count>0 then
-    begin
-    EnsureSection(csVar);
-    WriteVariables(SourceElements.Vars);
-    end;
-  if not IsRaw then
-    begin
-    WriteIncludeInterfaceCode;
-    Addln('');
-    AddLn('implementation');
-    WriteImplementation;
-    AddLn('end.');
+  Len:=Length(aDefs);
+  Result:=TFunctionOverLoadArgumentsList.Create;
+  try
+    aFunc:=TFunctionOverLoadArgumentsList.Create(False);
+    try
+      For aDef in aDefs do
+        begin
+        aFunc.Clear;
+        aFunc.Add(TJSTypedParams.CreateTransient);
+        AddOverloadParams(aFunc,adef,0);
+        For I:=0 to aFunc.Count-1 do
+          Result.Add(aFunc[I]);
+        end;
+    finally
+      aFunc.Free;
     end;
-  if OutputFileName<>'' then
-    Source.SaveToFile(OutputFileName);
+    Result.RemoveDuplicates(Self.Context);
+  except
+    Result.Free;
+    Raise;
+  end;
 end;
 
-function TTypescriptToPas.BaseUnits: String;
-
-begin
-  Result:='SysUtils, JS'
-end;
+function TTypescriptToPas.WriteFunctionTypeDef(const aPasName: string; const aOrgName: jsBase.TJSString; aTypeParams: TJSElementNodes; aDef: TJSFuncDef): Boolean;
 
-function TTypescriptToPas.CreatePasName(const aOriginal: jsBase.TJSString; const aName: String): TPasData;
+Var
+  FN,RT,Args : String;
 
 begin
-  Result:=TPasData.Create(aOriginal,EscapeKeyWord(aName));
-  FPasNameList.Add(Result);
+  Result:=True;
+  if aPasName<>'' then
+    FN:=aPasName
+  else
+    FN:=GetName(aDef);
+  RT:=GetTypeName(aDef.ResultType,False);
+  if (RT='void') then
+    RT:='';
+  Args:=GetArguments(aDef.TypedParams,False);
+  if Args<>'' then
+    Args:=' '+Args;
+  if (RT='') then
+    AddLn('%s = Procedure%s;',[FN,Args])
+  else
+    AddLn('%s = Function%s: %s;',[FN,Args,RT])
 end;
 
-function TTypescriptToPas.AllocatePasName(D: TJSElement; ParentName: String): TPasData;
+function TTypescriptToPas.WriteFunctionDefinition(const aName : String; const aDefs: TJSFuncDefArray; UseExternal : Boolean): Boolean;
 
 Var
-  Org : TJSString;
-  CN : String;
-  CD : TJSClassDeclaration absolute D;
-  ID : TJSInterfaceDeclaration absolute D;
-  VD : TJSVarDeclaration absolute D;
-  TD : TJSTypeDeclaration absolute D;
+  PN, FN,RT,Suff,Args : String;
+  Overloads : TFPObjectList;
+  I : Integer;
 
 begin
-  Result:=Nil;
-  if D Is TJSClassDeclaration then
-    begin
-    Org:=CD.Name;
-    CN:=ClassPrefix+Org+ClassSuffix;
-    Result:=CreatePasname(Org,CN);
-    AllocatePasNames(CD.members,CD.Name);
-    end
-  else if D Is TJSInterfaceDeclaration then
-    begin
-    Org:=ID.Name;
-    CN:=ClassPrefix+Org+ClassSuffix;
-    Result:=CreatePasname(Org,CN);
-    AllocatePasNames(ID.Values,EscapeKeyWord(UTF8Encode(ID.Name)));
-    end
-  else if D Is TJSVarDeclaration then
-    begin
-    Org:=VD.Name;
-    Result:=CreatePasName(Org, EscapeKeyWord(UTF8Encode(Org)));
-    end
-  else if D Is TJSTypeDeclaration then
+  Result:=True;
+  RT:='';
+  if (aDefs[0].IsConstructor) or (aName='&constructor') then
     begin
-    Org:=TD.Name;
-    Result:=CreatePasName(Org, EscapeKeyWord('T'+UTF8Encode(Org)));
+    PN:='New'
     end
   else
-    Raise ETSToPas.CreateFmt('Unsupported type to get name from: "%s"',[D.ClassName]);
-  D.Data:=Result;
-  if Verbose and (Result<>Nil) and (Result.PasName<>UTF8Encode(Org)) then
     begin
-    if (ParentName<>'') then
-      ParentName:=ParentName+'.';
-    DoLog('Renamed %s to %s',[ParentName+UTF8Encode(Org),TPasData(D.Data).PasName]);
+    PN:=aName;
+    FN:=UTF8Encode(aDefs[0].Name);
+    if (FN<>'') and ((FN<>StringReplace(aName,'&','',[rfReplaceAll])) or UseExternal) then
+      Suff:=Format('; external name ''%s''',[FN]);
+    if Assigned(aDefs[0].ResultType) then
+      RT:=GetTypeName(aDefs[0].ResultType,False);
+    if (RT='void') then
+      RT:='';
     end;
+  Overloads:=GetOverloads(ADefs);
+  try
+    if Overloads.Count>1 then
+      Suff:=Suff+'; overload';
+    For I:=0 to Overloads.Count-1 do
+      begin
+      Args:=GetArguments(TJSTypedParams(Overloads[i]),False);
+      if (RT='') then
+        begin
+        if (aDefs[0].IsConstructor) then
+          AddLn('Constructor %s%s%s;',[PN,Args,Suff])
+        else
+          AddLn('Procedure %s%s%s;',[PN,Args,Suff]);
+        end
+      else
+        AddLn('Function %s%s: %s%s;',[PN,Args,RT,Suff])
+      end;
+  finally
+    Overloads.Free;
+  end;
 end;
 
-procedure TTypescriptToPas.SetTypeAliases(AValue: TStrings);
-begin
-  if FTypeAliases=AValue then Exit;
-  FTypeAliases.Assign(AValue);
-end;
+function TTypescriptToPas.WriteFunctionDefs(aElements: TJSElementNodes; UseExternal : Boolean): Integer;
 
-procedure TTypescriptToPas.SetIncludeInterfaceCode(AValue: TStrings);
-begin
-  if FIncludeInterfaceCode=AValue then Exit;
-  FIncludeInterfaceCode.Assign(AValue);
-end;
+Var
+  aList : TStringList;
+  EN : TJSElementNode;
+  FN : String;
+  aDefs : TJSFuncDefArray;
+  aCount : Integer;
 
-procedure TTypescriptToPas.SetIncludeImplementationCode(AValue: TStrings);
 begin
-  if FIncludeImplementationCode=AValue then Exit;
-  FIncludeImplementationCode.Assign(AValue);
+  Result:=0;
+  aList:=TStringList.Create;
+  try
+    aList.Sorted:=True;
+    aList.Duplicates:=dupIgnore;
+    // Get Unique names
+    For EN in aElements do
+      if ExportNode(EN) then
+        aList.Add(GetName(EN.Node));
+    // Generate function definition for each unique name
+    For FN in aList do
+      begin
+      // Collect all function defs for this name
+      aDefs:=[];
+      aCount:=0;
+      SetLength(aDefs,aElements.Count);
+      For EN in aElements do
+        if ExportNode(EN) and (GetName(EN.Node)=FN) then
+          begin
+          if (EN.Node as TJSFunctionDeclarationStatement).AFunction = Nil then
+            DoLog('Ignoring empty function definition')
+          else
+            begin
+            aDefs[aCount]:=(EN.Node as TJSFunctionDeclarationStatement).AFunction;
+            inc(aCount)
+            end
+          end;
+      SetLength(aDefs,aCount);
+      WriteFunctionDefinition(FN,aDefs, UseExternal);
+      Inc(Result);
+      end;
+  finally
+    aList.Free;
+  end;
 end;
 
-function TTypescriptToPas.GetIsRaw: Boolean;
+
+{ ----------------------------------------------------------------------
+  Classes
+  ----------------------------------------------------------------------}
+
+function TTypescriptToPas.WriteForwardClass(aName : string) : Boolean;
+
 begin
-  Result:=coRaw in Options;
+  Result:=FContext.CurrentForwards.IndexOf(aName)=-1;
+  if Result then
+    AddLn('%s = Class;',[aName])
+  else
+    DoLog('Ignore double class definition: "%s"',[aName]);
 end;
 
-procedure TTypescriptToPas.AllocatePasNames(aList : TJSElementNodes; ParentName: String = '');
+function TTypescriptToPas.WriteForwardClassDef(aIntf: TJSInterfaceDeclaration): Boolean;
 
 Var
-  I : Integer;
+  N : String;
 
 begin
-  For I:=0 to aList.Count-1 do
-    AllocatePasName(aList.Nodes[i].Node,ParentName);
+  N:=GetName(aIntf);
+  if Context.CurrentForwards.indexOf(N)=-1 then
+    if (coInterfaceAsClass in Options) or (aIntf.HasProperties) then
+      AddLn('%s = Class;',[N])
+    else
+      AddLn('%s = Interface;',[N]);
+  Result:=True
 end;
 
-procedure TTypescriptToPas.AllocatePasNames(aList : TJSSourceElements; ParentName: String = '');
+function TTypescriptToPas.WriteForwardClassDef(aObj: TJSTypeDeclaration): Boolean;
 
 begin
-  AllocatePasNames(aList.Types,ParentName);
-  AllocatePasNames(aList.Enums,ParentName);
-  AllocatePasNames(aList.Vars,ParentName);
+  Result:=WriteForwardClass(GetName(aObj));
 end;
 
+function TTypescriptToPas.WriteForwardClassDef(aClass: TJSClassDeclaration): Boolean;
 
-procedure TTypescriptToPas.EnsureUniqueNames(ML: TJSSourceElements);
 begin
-
+  Result:=WriteForwardClass(GetName(aClass));
 end;
 
-procedure TTypescriptToPas.ProcessDefinitions;
+function TTypescriptToPas.WriteForwardClassDef(aModule: TJSModuleDeclaration): Boolean;
+begin
+  Result:=WriteForwardClass(GetName(aModule));
+end;
 
+function TTypescriptToPas.WriteForwardClassDef(aNamespace: TJSNameSpaceDeclaration): Boolean;
 begin
-  AllocatePasNames((FElements.A as TJSSourceElements));
+  Result:=WriteForwardClass(GetName(aNamespace));
 end;
 
-procedure TTypescriptToPas.Execute;
+function TTypescriptToPas.WriteForwardClassDefs(aClassList: TJSElementNodes): Integer;
 
-begin
-  FContext:=CreateContext;
-  try
-    if Assigned(TypeAliases) then
-      FContext.AddAliases(TypeAliases);
-    Parse;
-    if Verbose then
-      DoLog('Parsed %d definitions.',[]);
-    ProcessDefinitions;
-    WritePascal;
-  finally
-    FreeAndNil(FContext);
+  Procedure MaybeComment;
+  begin
+    if Result=0 then
+      Comment('Forward class definitions');
   end;
+
+Var
+  D : TJSElementNode;
+
+
+begin
+  Result:=0;
+  For D in aClassList do
+    if (D.Node is TJSTypeDeclaration) and (TJSTypeDeclaration(D.Node).TypeDef is TJSObjectTypeDef) then
+      begin
+      MaybeComment;
+      if WriteForwardClassDef(TJSTypeDeclaration(D.Node)) then
+        Inc(Result);
+      end
+    else if D.Node is TJSClassDeclaration then
+      begin
+      MaybeComment;
+      if WriteForwardClassDef(D.Node as TJSClassDeclaration) then
+        Inc(Result);
+      end
+    else if (D.Node is TJSModuleDeclaration) then
+      begin
+      MaybeComment;
+      if WriteForwardClassDef(D.Node as TJSModuleDeclaration) then
+        Inc(Result);
+      end
+    else if (D.Node is TJSNameSpaceDeclaration)
+            and not (NamespaceExtendsClass(D.Node as TJSNamespaceDeclaration))
+            and not (NamespaceExtendsModule(D.Node as TJSNamespaceDeclaration))then
+      begin
+      MaybeComment;
+      if WriteForwardClassDef(D.Node as TJSNamespaceDeclaration) then
+        Inc(Result);
+      end
+    else if (D.Node is TJSInterfaceDeclaration) and not TJSInterfaceDeclaration(D.Node).IsFunctionDef then
+      begin
+      MaybeComment;
+      if WriteForwardClassDef(D.Node as TJSInterfaceDeclaration) then
+        Inc(Result);
+      end;
+    // Ignore other types
 end;
 
-Function TTypescriptToPas.GetArrayTypeAsString(aTypeDef : TJSArrayTypeDef; asPascal,asSubType : Boolean) : String;
+{ ----------------------------------------------------------------------
+  Namespaces
+  ----------------------------------------------------------------------}
+
+
+function TTypescriptToPas.WriteNamespaceDef(aNameSpace: TJSNamespaceDeclaration): Boolean;
+
+Var
+  aPasName,aName : String;
 
 begin
-  Result:=GetTypeAsString(aTypeDef,asPascal,True);
-  if coGenericArrays in Options then
-    Result:='TArray<'+Result+'>'
-  else
-    Result:='array of '+Result;
-  if AsSubType then
-    Result:='('+Result+')'
+  Result:=True;
+  aPasName:=GetName(aNameSpace);
+  aName:=GetExternalMemberName(aNamespace.Name);
+  AddLn('');
+  AddLn(Format('%s = class external name ''%s'' (TJSObject)',[aPasName,aName]));
+  Addln('Public');
+  Indent;
+    PushSection();
+    WriteSourceElements(aNameSpace.Members,aNamespace.Name);
+    PopSection;
+  Undent;
+  AddLn('end;');
+  AddLn('');
 end;
 
+Function TTypescriptToPas.NamespaceExtendsClass(aNs : TJSNamespaceDeclaration) : Boolean;
 
-Function TTypescriptToPas.GetTypeAsString(aType : TJSTypeDef; asPascal,asSubType : Boolean) : String;
+begin
+  Result:=HaveClass(aNS.Name);
+end;
 
+function TTypescriptToPas.NamespaceExtendsModule(aNs: TJSNamespaceDeclaration): Boolean;
 begin
-  Result:='';
-  if aType is TJSTypeReference then
-    Result:=GetAliasTypeAsString(TJSTypeReference(aType),asPascal,asSubType)
-  else if aType is TJSUnionTypeDef then
-    Result:=GetUnionTypeAsString(TJSUnionTypeDef(aType),asPascal,asSubType)
-  else if aType is TJSIntersectionTypeDef then
-    Result:=GetIntersectionTypeAsString(TJSIntersectionTypeDef(aType),asPascal,asSubType)
-  else if aType is TJSArrayTypeDef then
-    Result:=GetArrayTypeAsString(TJSArrayTypeDef(aType),asPascal,asSubType)
-  else if aType is TJSEnumTypeDef then
-    Result:=GetEnumTypeAsString(TJSEnumTypeDef(aType),asPascal,asSubType)
+  Result:=HaveModule(aNS.Name);
 end;
 
-Function TTypescriptToPas.GetUnionTypeAsString(aTypeDef : TJSUnionTypeDef; asPascal,asSubType : Boolean) : String;
+Function TTypescriptToPas.HaveClass(aName : TJSString) : Boolean;
 
 Var
   I : Integer;
 
 begin
-  Result:='';
-  For I:=0 to aTypeDef.TypeCount-1 do
+  Result:=False;
+  I:=Context.CurrentScope.Classes.Count-1;
+  While (Not Result) and (I>=0) do
     begin
-    if Result<>'' then
-      Result:=Result+' | ';
-    Result:=Result+GetTypeAsString(aTypeDef.Types[I],asPascal,True);
+    Result:=(aName) = TJSClassDeclaration(Context.CurrentScope.Classes[i].Node).Name;
+    Dec(I);
     end;
-  if AsSubType then
-    Result:='('+Result+')';
 end;
 
-function TTypescriptToPas.GetEnumTypeAsString(aTypeDef: TJSEnumTypeDef; asPascal, asSubType: Boolean): String;
+function TTypescriptToPas.HaveModule(aName: TJSString): Boolean;
 Var
   I : Integer;
-  N : String;
 
 begin
-  Result:='';
-  For I:=0 to aTypeDef.NameCount-1 do
+  Result:=False;
+  I:=Context.CurrentScope.Modules.Count-1;
+  While (Not Result) and (I>=0) do
     begin
-    if Result<>'' then
-      Result:=Result+', ';
-    N:=aTypeDef.Names[I];
-    if IsKeyWord(N) then
-      N:='&'+N;
-    Result:=Result+N;
+    Result:=(aName) = TJSClassDeclaration(Context.CurrentScope.Modules[i].Node).Name;
+    Dec(I);
     end;
-  Result:='('+Result+')';
-  if AsSubType then
-    Result:='('+Result+')';
 end;
 
-Function TTypescriptToPas.GetIntersectionTypeAsString(aTypeDef : TJSIntersectionTypeDef; asPascal,asSubType : Boolean) : String;
+function TTypescriptToPas.WriteNamespaceDefs(aNameSpaces: TJSElementNodes): Integer;
+
 
 Var
-  I : Integer;
+  EN : TJSElementNode;
+  NSDef : TJSNamespaceDeclaration;
+
 
 begin
-  Result:='';
-  For I:=0 to aTypeDef.TypeCount-1 do
-    begin
-    if Result<>'' then
-      Result:=Result+' & ';
-    Result:=Result+GetTypeAsString(aTypeDef.Types[I],asPascal,True);
-    end;
-  if AsSubType then
-    Result:='('+Result+')';
+  Result:=0;
+  For EN in aNameSpaces do
+   begin
+   NSDef:=EN.Node as TJSNamespaceDeclaration;
+   if Not NamespaceExtendsClass(NSDef) then
+     begin
+     If Result=0 then
+       Comment('Namespaces');
+     WriteNameSpaceDef(NSDef);
+     end;
+   end;
 end;
 
-Procedure TTypescriptToPas.WriteUnionTypeDef(const aPasName : string; const aOrgName : jsBase.TJSString; aTypeParams: TJSElementNodes;aTypeDef : TJSUnionTypeDef);
+{ ----------------------------------------------------------------------
+  Modules
+  ----------------------------------------------------------------------}
 
-var
-  TN, gen, genparams: String;
+
+function TTypescriptToPas.WriteModuleDef(aModule: TJSModuleDeclaration): Boolean;
+
+Var
+  aPasName,aName : String;
 
 begin
-  TN:='jsvalue';
-  genparams:=GetGenericParams(aTypeParams);
-  if (genparams<>'') then
-    gen:='generic ';
-  AddLn('%s%s%s = %s; // %s',[gen,aPasName,genparams,TN,GetTypeAsString(aTypeDef,False,False)]);
+  Result:=True;
+  aPasName:=GetName(aModule);
+  aName:=GetExternalMemberName(aModule.Name);
+  AddLn('');
+  AddLn(Format('%s = class external name ''%s'' (TJSObject)',[aPasName,aName]));
+  Addln('Public');
+  Indent;
+    PushSection();
+    WriteSourceElements(aModule.Members,aModule.Name);
+    PopSection;
+  Undent;
+  AddLn('end;');
+  AddLn('');
 end;
 
+function TTypescriptToPas.WriteModuleDefs(aModules: TJSElementNodes): Integer;
 
-Procedure TTypescriptToPas.WriteIntersectionTypeDef(const aPasName : string; const aOrgName : jsBase.TJSString; aTypeParams: TJSElementNodes;aTypeDef : TJSIntersectionTypeDef);
+  Function ExtendsClass(aNs : TJSModuleDeclaration) : Boolean;
 
-var
-  TN, gen, genparams: String;
+  Var
+    I : Integer;
 
-begin
-  TN:='jsvalue';
-  genparams:=GetGenericParams(aTypeParams);
-  if (genparams<>'') then
-    gen:='generic ';
-  AddLn('%s%s%s = %s; // %s',[gen,aPasName,genparams,TN,GetTypeAsString(aTypeDef,False,false)]);
-end;
+  begin
+    Result:=False;
+    I:=Context.CurrentScope.Classes.Count-1;
+    While (Not Result) and (I>=0) do
+      begin
+      Result:=(aNS.Name) = TJSClassDeclaration(Context.CurrentScope.Classes[i].Node).Name;
+      Dec(I);
+      end;
+  end;
 
-Procedure TTypescriptToPas.WriteArrayTypeDef(const aPasName : string; const aOrgName : jsBase.TJSString; aTypeParams: TJSElementNodes;aTypeDef : TJSArrayTypeDef);
+Var
+  EN : TJSElementNode;
+  NSDef : TJSModuleDeclaration;
 
-var
-  TN, arr,gen, genparams: String;
 
 begin
-  TN:='jsvalue';
-  genparams:=GetGenericParams(aTypeParams);
-  if (genparams<>'') then
-    gen:='generic ';
-  arr:=GetArrayTypeAsString(aTypeDef,True,False);
-  AddLn('%s%s%s = %s;',[gen,aPasName,genparams,arr]);
+  Result:=0;
+  For EN in aModules do
+   begin
+   NSDef:=EN.Node as TJSModuleDeclaration;
+   if Not ExtendsClass(NSDef) then
+     begin
+     If Result=0 then
+       Comment('Modules');
+     WriteModuleDef(NSDef);
+     end;
+   end;
 end;
 
-procedure TTypescriptToPas.WriteEnumTypeDef(const aPasName: string; const aOrgName: jsBase.TJSString; aTypeParams: TJSElementNodes;
-  aTypeDef: TJSEnumTypeDef);
-var
- arr,gen, genparams: String;
 
-begin
-  genparams:=GetGenericParams(aTypeParams);
-  if (genparams<>'') then
-    gen:='generic ';
-  arr:=GetEnumTypeAsString(aTypeDef,True,False);
-  AddLn('%s%s%s = %s;',[gen,aPasName,genparams,arr]);
-end;
+{ ----------------------------------------------------------------------
+  Interfaces
+  ----------------------------------------------------------------------}
 
+function TTypescriptToPas.WriteInterfaceDef(Intfs: TJSInterfaceDeclarationArray): Boolean;
 
-Procedure TTypescriptToPas.WriteTypeDef(const aPasName : string; const aOrgName : jsBase.TJSString; aTypeParams: TJSElementNodes; aTypeDef : TJSTypeDef);
+Var
+  CN,Decl,Sect : String;
+  UseLocal, UseClass : Boolean;
+  aCount : Integer;
+  PD : TPasData;
+  Func : TJSFuncDef;
+  Intf0: TJSInterfaceDeclaration;
+  Inf: TJSInterfaceDeclaration;
 
 begin
-  If aTypeDef is TJSTypeReference then
-    WriteAliasTypeDef(aPasName,aOrgName,aTypeParams,TJSTypeReference(aTypeDef))
-  else if aTypeDef is TJSUnionTypeDef then
-    WriteUnionTypeDef(aPasName,aOrgName,aTypeParams,TJSUnionTypeDef(aTypeDef))
-  else if aTypeDef is TJSIntersectionTypeDef then
-    WriteIntersectionTypeDef(aPasName,aOrgName,aTypeParams,TJSIntersectionTypeDef(aTypeDef))
-  else if aTypeDef is TJSArrayTypeDef then
-    WriteArrayTypeDef(aPasName,aOrgName,aTypeParams,TJSArrayTypeDef(aTypeDef))
-  else if aTypeDef is TJSEnumTypeDef then
-    WriteEnumTypeDef(aPasName,aOrgName,aTypeParams,TJSEnumTypeDef(aTypeDef))
+  Intf0:=Intfs[0];
+  if Intf0.IsFunctionDef then
+    begin
+    PD:=TPasData(Intf0.Data);
+    Func:=intf0.FunctionDef;
+    WriteMethodParameterDefs(intf0.Values);
+    WriteFunctionTypeDef(PD.PasName,PD.OriginalName,Intf0.TypeParams,Func);
+    Exit;
+    end;
+  Result:=True;
+  UseClass:=False;
+  CN:=GetName(Intf0);
+  For Inf in Intfs do
+    useClass:=useClass or (coInterfaceAsClass in Options) or Inf.HasProperties;
+  UseLocal:=(coLocalArgumentTypes in Options) and UseClass;
+  if not UseLocal then
+    begin
+    for Inf in Intfs do
+      begin
+      WritePropertyTypeDefs(inf.Values);
+      WriteMethodParameterDefs(inf.Values);
+      end;
+    end;
+  if UseClass then
+    Decl:=Format('%s = class external name ''Object'' (TJSObject)',[CN])
+  else
+    Decl:=Format('%s = interface',[CN]);
+  AddLn(Decl);
+  if UseLocal then
+    begin
+    aCount:=0;
+    for Inf in Intfs do
+      begin
+      if (aCount>0) then
+        Sect:=''
+      else
+        Sect:='Public';
+      aCount:=WritePropertyTypeDefs(inf.Values,Sect);
+      if (aCount>0) then
+        Sect:=''
+      else
+        Sect:='Public';
+      WriteMethodParameterDefs(inf.Values,Sect);
+      end;
+    end;
+  Indent;
+  for inf in Intfs do
+    WriteObjectTypeMembers(CN,Inf.name,Inf.TypeParams,Inf);
+  Undent;
+  AddLn('end;');
+  AddLn('');
 end;
 
-Procedure TTypescriptToPas.WriteTypeDefs(Types: TJSElementNodes);
+function TTypescriptToPas.WriteInterfaceDefs(aList: TJSElementNodes): Integer;
+
+  Function GetInterfaces(aName : TJSString) : TJSInterfaceDeclarationArray;
+
+  Var
+    I,aCount : Integer;
+    N : TJSElement;
+
+  begin
+    aCount:=0;
+    SetLength(Result,aList.Count);
+    For I:=0 to aList.Count-1 do
+      begin
+      N:=aList[I].Node;
+      if N is TJSInterfaceDeclaration then
+        if aName=GetName(N) then
+          begin
+          Result[aCount]:=TJSInterfaceDeclaration(N);
+          Inc(aCount);
+          end;
+      end;
+    SetLength(Result,aCount);
+  end;
+
 
 Var
   I : Integer;
   N : TJSElement;
-  Decl : TJSTypeDeclaration absolute N;
+  IntfDecl : TJSInterfaceDeclarationArray;
   aName : String;
+  L : TStringList;
 
 begin
+  Result:=0;
   EnsureSection(csType);
-  for I:=0 to Types.Count-1 do
-    begin
-    N:=Types[0].Node;
-    // TJSEnumDeclaration is a descendent
-    if N is TJSTypeDeclaration then
-      begin
-      aName:=GetName(Decl);
-      WriteTypeDef(aName, Decl.Name, Decl.TypeParams, Decl.TypeDef);
-      end
-    end;
+  L:=TStringList.Create;
+  try
+    L.Duplicates:=DupIgnore;
+    for I:=0 to aList.Count-1 do
+      if ExportNode(aList[i]) then
+        begin
+        N:=aList[I].Node;
+        // TJSEnumDeclaration is a descendent
+        if N is TJSInterfaceDeclaration then
+          L.Add(GetName(N));
+        end;
+    For I:=0 to L.Count-1 do
+     begin
+     aName:=L[I];
+     IntfDecl:=GetInterfaces(aName);
+     if Length(IntfDecl)>0 then
+       begin
+       if Length(IntfDecl)>1 then
+         DoLog('Folding %d definitions to 1 interface for %s',[Length(IntfDecl),aName]);
+       if WriteInterfaceDef(IntfDecl) then
+         Inc(Result);
+       end;
+     end;
+  finally
+    L.Free;
+  end;
 end;
 
-
 end.
 

+ 11 - 0
packages/fcl-js/tests/tcparser.pp

@@ -28,6 +28,7 @@ type
     Procedure AssertEquals(Const AMessage : String; Expected, Actual : TJSToken); overload;
     Procedure AssertEquals(Const AMessage : String; Expected, Actual : TJSType); overload;
     Procedure AssertEquals(Const AMessage : String; Expected, Actual : TJSVarType); overload;
+    Procedure AssertEquals(Const AMessage : String; Expected, Actual : TKeyOptionality); overload;
     Procedure AssertIdentifier(Msg : String; El : TJSElement; Const AName : TJSString);
     procedure AssertEquals(Const AMessage : String; aExpected : AnsiString; aActual : TJSString); overload;
     Function  GetSourceElements : TJSSourceElements;
@@ -337,6 +338,16 @@ begin
   AssertEquals(AMessage,NE,NA);
 end;
 
+procedure TTestBaseJSParser.AssertEquals(const AMessage: String; Expected, Actual: TKeyOptionality);
+Var
+  NE,NA : String;
+
+begin
+  NE:=GetEnumName(TypeInfo(TKeyOptionality),Ord(Expected));
+  NA:=GetEnumName(TypeInfo(TKeyOptionality),Ord(Actual));
+  AssertEquals(AMessage,NE,NA);
+end;
+
 Procedure TTestBaseJSParser.AssertIdentifier(Msg: String; El: TJSElement;
   Const AName: TJSString);
 

+ 38 - 5
packages/fcl-js/tests/tcscanner.pp

@@ -34,6 +34,7 @@ type
 
   TTestJSScanner = class(TTestCase)
   Private
+    FNeedWhiteSpace: Boolean;
     FStream : TStream;
     FLineReader : TLineReader;
     FScanner : TJSScanner;
@@ -43,14 +44,14 @@ type
     procedure CheckTokens(ASource: String; ATokens: array of TJSToken; aVersion : TECMAVersion = ecma5);
     procedure DoTestFloat(F: Double);
     procedure DoTestFloat(F: Double; S: String);
-    procedure DoTestString(S: String);
+    procedure DoTestString(S: String; WasMultiline : Boolean = False);
     procedure TestErrorSource;
   protected
     Function CreateScanner(AInput : String; aVersion : TECMAVersion = ecma5) : TJSScanner;
     procedure FreeScanner;
     procedure SetUp; override;
     procedure TearDown; override;
-
+    Property NeedWhiteSpace : Boolean Read FNeedWhiteSpace Write FNeedWhiteSpace;
     Property Scanner : TJSScanner Read FScanner;
   published
     Procedure TestEmpty;
@@ -171,7 +172,10 @@ type
     procedure TestFloat;
     procedure TestStringError;
     procedure TestFloatError;
-
+    procedure TestMultilineString;
+    procedure TestMultilineStringError;
+    procedure TestMultilineStringError2;
+    Procedure TestNonBreakingSpace;
   end;
 
 
@@ -185,6 +189,8 @@ begin
   FScanner:=TJSScanner.Create(FLineReader,aVersion);
   FScanner.IsTypeScript:=False;
   Result:=FScanner;
+  if FNeedWhiteSpace then
+    FScanner.ReturnWhiteSpace:=True;
 end;
 
 procedure TTestJSScanner.FreeScanner;
@@ -197,6 +203,7 @@ end;
 procedure TTestJSScanner.SetUp;
 begin
   inherited SetUp;
+  FNeedWhiteSpace:=False;
 end;
 
 
@@ -998,7 +1005,7 @@ begin
 end;
 
 
-procedure TTestJSScanner.DoTestString(S: String);
+procedure TTestJSScanner.DoTestString(S: String; WasMultiline : Boolean = False);
 
 Var
   J : TJSToken;
@@ -1007,9 +1014,10 @@ begin
   try
     J:=FScanner.FetchToken;
     AssertEquals(S+' is a string',tjsString,J);
-    If (Length(S)>0) and (S[1] in ['"','''']) then
+    If (Length(S)>0) and (S[1] in ['"','''','`']) then
       S:=Copy(S,2,Length(S)-2);
     AssertEquals('Correct string is returned',S,FScanner.CurTokenString);
+    AssertEquals('Multiline ?',WasMultiline,FScanner.WasMultilineString);
   finally
     FreeScanner;
   end;
@@ -1044,6 +1052,31 @@ begin
   AssertException('Unterminated string',EJSScannerError,@TestErrorSource);
 end;
 
+procedure TTestJSScanner.TestMultilineString;
+
+begin
+  DoTestString('`A'#10'B`',True);
+end;
+
+procedure TTestJSScanner.TestMultilineStringError;
+begin
+  FErrorSource:='`A'#10;
+  AssertException('Unterminated string',EJSScannerError,@TestErrorSource);
+end;
+
+procedure TTestJSScanner.TestMultilineStringError2;
+begin
+  FErrorSource:='`A'#10'B';
+  AssertException('Unterminated string',EJSScannerError,@TestErrorSource);
+end;
+
+procedure TTestJSScanner.TestNonBreakingSpace;
+begin
+  NeedWhiteSpace:=True;
+  CheckToken(tjsWhiteSpace,#$C2#$A0);
+end;
+
+
 
 { TTestLineReader }
 

+ 211 - 14
packages/fcl-js/tests/tctsparser.pp

@@ -21,6 +21,7 @@ Type
     Procedure TestDeclareModuleIdentifier;
     Procedure TestDeclareNamespace;
     Procedure TestDeclareGlobal;
+    Procedure TestDeclareUniqueConst;
     Procedure TestDeclareFunction;
     Procedure TestDeclareFunctionOptionalArg;
     Procedure TestDeclareFunctionSpreadArg;
@@ -54,7 +55,14 @@ Type
     Procedure TestDeclareTypeArrowFunctionShort;
     Procedure TestDeclareTypeArrowFunctionTwoArgs;
     Procedure TestDeclareTypeArrowFunctionArgsCommaEnd;
+    procedure TestDeclareTypeGenericConstraint;
+    procedure TestDeclareTypeTypeImport;
+    procedure TestDeclareTypeTypeOfImport;
+    procedure TestDeclareTypeTypeOfDefault;
+    procedure TestDeclareTypeReadonly;
+    procedure TestDeclareArgTypeInferred;
     Procedure TestDeclareEnum;
+    Procedure TestDeclareEnumKeywordElement;
     Procedure TestDeclareConstEnum;
     Procedure TestDeclareConstEnumAssigned;
     procedure TestDeclareInterfaceEmpty;
@@ -72,6 +80,7 @@ Type
     procedure TestDeclateInterfaceGenericProperty;
     procedure TestDeclateInterfaceGeneric;
     procedure TestDeclareInterfaceExtendsGeneric;
+    Procedure TestDeclareInterfaceHidden;
     procedure TestDeclareClassEmpty;
     procedure TestDeclareAbstractClassEmpty;
     procedure TestDeclareClassIndexSignature;
@@ -79,9 +88,13 @@ Type
     procedure TestDeclareClassExtendsGeneric;
     procedure TestDeclareClassGeneric;
     procedure TestDeclareClassStaticFunction;
+    procedure TestDeclareClassStaticFunctionUntypedArg;
     procedure TestDeclareClassStaticReadonlyProperty;
     procedure TestDeclareClassReadonlyProperty;
+    procedure TestDeclareClassGenericFunctionProperty;
     procedure TestDeclareClassImplements;
+    procedure TestDeclareClassExtendsFunctionCall;
+    Procedure TestDeclareClassStaticReadOnly;
     procedure TestDeclareInterfaceIndexSignature;
     procedure TestDeclareInterfaceFixedStringProperty;
     procedure TestDeclareInterfaceFixedBooleanProperty;
@@ -96,6 +109,7 @@ Type
     procedure TestExportAbstractClass;
     procedure TestExportClassConstructor;
     procedure TestExportInterface;
+    procedure TestExportInterfaceDefault;
     procedure TestExportInterfaceIndexSignature;
     procedure TestExportInterfaceIndexSignatureOptional;
     procedure TestExportImportStatement;
@@ -107,8 +121,9 @@ Type
     procedure TestExportTypeArrowFunctionArgsComma;
     procedure TestDeclareExportInterfaceDestructuredFunctionProperty;
     procedure TestExportEnum;
-    procedure TestExportObjectUNion;
+    procedure TestExportObjectUnion;
     Procedure TestExportNoSemicolon;
+    Procedure TestExportAsKeyWord;
     procedure TestNamespaceInterfaceFUnction;
   end;
 
@@ -179,6 +194,17 @@ begin
   CheckMembers(N.Members,0,0,0,0,0,0,0);
 end;
 
+procedure TTestTypeScriptParser.TestDeclareUniqueConst;
+
+Var
+  V : TJSVarDeclaration;
+
+begin
+  StartTS('const A : unique symbol');
+  V:=TJSVarDeclaration(CheckClass('Var',TJSVarDeclaration,GetFirstVar));
+  AssertEquals('Unique ',True,V.IsUnique);
+end;
+
 procedure TTestTypeScriptParser.TestDeclareFunction;
 
 Var
@@ -260,7 +286,7 @@ begin
   AssertNotNull('Have type def',T.TypeDef);
   AssertEquals('Correct type def class',TJSTypeReference,T.TypeDef.ClassType);
   AssertEquals('Correct name def class','b',TJSTypeReference(T.TypeDef).Name);
-  AssertEquals('Correct name def class',False,TJSTypeReference(T.TypeDef).IsTypeOf);
+  AssertEquals('Correct IsTypeOf',False,TJSTypeReference(T.TypeDef).IsTypeOf);
 end;
 
 procedure TTestTypeScriptParser.TestDeclareTypeAliasDotted;
@@ -274,7 +300,7 @@ begin
   AssertNotNull('Have type def',T.TypeDef);
   AssertEquals('Correct type def class',TJSTypeReference,T.TypeDef.ClassType);
   AssertEquals('Correct name def class','b.c',TJSTypeReference(T.TypeDef).Name);
-  AssertEquals('Correct name def class',False,TJSTypeReference(T.TypeDef).IsTypeOf);
+  AssertEquals('Correct isTypeOf',False,TJSTypeReference(T.TypeDef).IsTypeOf);
 end;
 
 procedure TTestTypeScriptParser.TestDeclareTypeTypeQuery;
@@ -876,6 +902,23 @@ begin
   AssertEquals('Member 2','green',ET.Names[2]);
 end;
 
+procedure TTestTypeScriptParser.TestDeclareEnumKeywordElement;
+Var
+  E : TJSEnumDeclaration;
+  ET : TJSEnumTypeDef;
+
+begin
+  StartTS('enum Colors {delete,new,green};');
+  E:=GetFirstEnum;
+  AssertEquals('Name','Colors',E.Name);
+  ET:=TJSEnumTypeDef(CheckClass(E.EnumDef,TJSEnumTypeDef,'Have enum definition'));
+  AssertEquals('Member count',3,ET.NameCount);
+  AssertEquals('Member 0','delete',ET.Names[0]);
+  AssertEquals('Member 1','new',ET.Names[1]);
+  AssertEquals('Member 2','green',ET.Names[2]);
+
+end;
+
 procedure TTestTypeScriptParser.TestDeclareConstEnum;
 Var
   Stat : TJSEnumStatement;
@@ -1003,7 +1046,7 @@ begin
   AssertEquals('Member count',1,Decl.ElementCount);
   Prop:=TJSPropertyDeclaration(CheckClass('Property class',TJSPropertyDeclaration,Decl.Elements[0]));
   AssertEquals('Property name','name',Prop.Name);
-  AssertEquals('Property optional',False,Prop.Optional);
+  AssertEquals('Property optional',koDefault,Prop.Optional);
   R:=TJSTypeReference(CheckClass('Property type',TJSTypeReference,Prop.ElementType));
   AssertEquals('Property type name','string',R.Name);
 end;
@@ -1023,7 +1066,7 @@ begin
   AssertEquals('Member count',1,Decl.ElementCount);
   Prop:=TJSPropertyDeclaration(CheckClass('Property class',TJSPropertyDeclaration,Decl.Elements[0]));
   AssertEquals('Property name','name',Prop.Name);
-  AssertEquals('Property optional',True,Prop.Optional);
+  AssertEquals('Property optional',koOptional,Prop.Optional);
   R:=TJSTypeReference(CheckClass('Property type',TJSTypeReference,Prop.ElementType));
   AssertEquals('Property type name','string',R.Name);
 end;
@@ -1044,7 +1087,7 @@ begin
   AssertEquals('Member count',1,Decl.ElementCount);
   Prop:=TJSPropertyDeclaration(CheckClass('Property class',TJSPropertyDeclaration,Decl.Elements[0]));
   AssertEquals('Property name','name',Prop.Name);
-  AssertEquals('Property optional',False,Prop.Optional);
+  AssertEquals('Property optional',koDefault,Prop.Optional);
   R:=TJSTypeReference(CheckClass('Property type',TJSTypeReference,Prop.ElementType));
   AssertEquals('Property type name','any',R.Name);
 end;
@@ -1065,7 +1108,7 @@ begin
   AssertEquals('Member count',1,Decl.ElementCount);
   Prop:=TJSPropertyDeclaration(CheckClass('Property class',TJSPropertyDeclaration,Decl.Elements[0]));
   AssertEquals('Property name','name',Prop.Name);
-  AssertEquals('Property optional',True,Prop.Optional);
+  AssertEquals('Property optional',koOptional,Prop.Optional);
   R:=TJSTypeReference(CheckClass('Property type',TJSTypeReference,Prop.ElementType));
   AssertEquals('Property type name','any',R.Name);
 end;
@@ -1086,7 +1129,7 @@ begin
   AssertEquals('Member count',1,Decl.ElementCount);
   M:=TJSMethodDeclaration(CheckClass('Method class',TJSMethodDeclaration,Decl.Elements[0]));
   AssertEquals('Method name','text',M.Name);
-  AssertEquals('Method optional',False,M.Optional);
+  AssertEquals('Method optional',koDefault,M.Optional);
   AssertNotNull('Have function def',M.FuncDef);
   R:=TJSTypeReference(CheckClass('Result type',TJSTypeReference,M.FuncDef.ResultType));
   AssertEquals('Property type name','string',R.Name);
@@ -1107,7 +1150,7 @@ begin
   AssertEquals('Member count',1,Decl.ElementCount);
   M:=TJSMethodDeclaration(CheckClass('Method class',TJSMethodDeclaration,Decl.Elements[0]));
   AssertEquals('Method name','text',M.Name);
-  AssertEquals('Method optional',False,M.Optional);
+  AssertEquals('Method optional',koDefault,M.Optional);
   AssertNotNull('Have function def',M.FuncDef);
   R:=TJSTypeReference(CheckClass('Result type',TJSTypeReference,M.FuncDef.ResultType));
   AssertEquals('Property type name','any',R.Name);
@@ -1128,7 +1171,7 @@ begin
   AssertEquals('Member count',1,Decl.ElementCount);
   M:=TJSMethodDeclaration(CheckClass('Method class',TJSMethodDeclaration,Decl.Elements[0]));
   AssertEquals('Method name','',M.Name);
-  AssertEquals('Method optional',False,M.Optional);
+  AssertEquals('Method optional',koDefault,M.Optional);
   AssertNotNull('Have function def',M.FuncDef);
   R:=TJSTypeReference(CheckClass('Result type',TJSTypeReference,M.FuncDef.ResultType));
   AssertEquals('Property type name','JQuery',R.Name);
@@ -1149,7 +1192,7 @@ begin
   AssertEquals('Member count',1,Decl.ElementCount);
   M:=TJSMethodDeclaration(CheckClass('Method class',TJSMethodDeclaration,Decl.Elements[0]));
   AssertEquals('Method name','text',M.Name);
-  AssertEquals('Method optional',False,M.Optional);
+  AssertEquals('Method optional',koDefault,M.Optional);
   AssertNotNull('Have function def',M.FuncDef);
   R:=TJSTypeReference(CheckClass('Result type',TJSTypeReference,M.FuncDef.ResultType));
   AssertEquals('Property type name','this',R.Name);
@@ -1173,7 +1216,7 @@ begin
   AssertEquals('Count elements',2,Decl.ElementCount);
   Prop:=TJSPropertyDeclaration(CheckClass('Property class',TJSPropertyDeclaration,Decl.Elements[0]));
   AssertEquals('Property name','dayComponent',Prop.Name);
-  AssertEquals('Property optional',True,Prop.Optional);
+  AssertEquals('Property optional',koOptional,Prop.Optional);
   U:=TJSUnionTypeDef(CheckClass('Property type',TJSUnionTypeDef,Prop.ElementType));
   G:=TJSGenericTypeRef(CheckClass('Union 1',TJSGenericTypeRef,U.Types[0]));
   R:=TJSTypeReference(CheckClass('Generic base type',TJSTypeReference,G.BaseType));
@@ -1213,7 +1256,7 @@ Var
 begin
   StartTS('interface Empty <TItem> extends ParentEmpty<Titem> {};');
   Decl:=TJSInterfaceDeclaration(CheckClass(GetFirstInterface,TJSInterfaceDeclaration,'Interface'));
-  AssertNotNull('Have declaration');
+  AssertNotNull('Have declaration',Decl);
   AssertEquals('Name','Empty',Decl.Name);
   AssertNotNull('Extends',Decl.Extends);
   AssertEquals('Type param count',1,Decl.TypeParams.Count);
@@ -1222,6 +1265,19 @@ begin
   AssertEquals('Extends count',1,Decl.Extends.Count);
 end;
 
+procedure TTestTypeScriptParser.TestDeclareInterfaceHidden;
+Var
+  Decl : TJSInterfaceDeclaration;
+begin
+  StartTS('interface JQuery extends JQuerySlickInitials {'#10+
+          '   hidden: ''mozHidden'' | ''webkitHidden'' | ''hidden'';'#10+
+          '}');
+  Decl:=TJSInterfaceDeclaration(CheckClass(GetFirstInterface,TJSInterfaceDeclaration,'Interface'));
+  AssertNotNull('Have declaration',Decl);
+  AssertEquals('Name','JQuery',Decl.Name);
+  AssertNotNull('Extends',Decl.Extends);
+end;
+
 procedure TTestTypeScriptParser.TestDeclareClassEmpty;
 Var
   Decl : TJSClassDeclaration;
@@ -1328,6 +1384,17 @@ begin
   AssertEquals('Function count',1,Decl.Members.Functions.Count);
 end;
 
+procedure TTestTypeScriptParser.TestDeclareClassStaticFunctionUntypedArg;
+Var
+  Decl : TJSClassDeclaration;
+begin
+  StartTS('declare class JQuery { private soso(a) ; };');
+  Decl:=TJSAmbientClassDeclaration(CheckClass('Class',TJSAmbientClassDeclaration,GetFirstClass(True)));
+  AssertNotNull('Have declaration');
+  AssertEquals('Name','JQuery',Decl.Name);
+  AssertEquals('Function count',1,Decl.Members.Functions.Count);
+end;
+
 procedure TTestTypeScriptParser.TestDeclareClassStaticReadonlyProperty;
 Var
   Decl : TJSClassDeclaration;
@@ -1359,6 +1426,14 @@ begin
   AssertFalse('Prop Static',Prop.IsStatic);
 end;
 
+procedure TTestTypeScriptParser.TestDeclareClassGenericFunctionProperty;
+begin
+  StartTS('declare class changeRequestInterceptor {'#10+
+          ' getRequest: <T>(request: T, entity: Entity, index: number) => T;'#10+
+          '}');
+  GetFirstClass(True);
+end;
+
 procedure TTestTypeScriptParser.TestDeclareClassImplements;
 Var
   Decl : TJSClassDeclaration;
@@ -1374,6 +1449,40 @@ begin
   AssertFalse('Prop Static',Prop.IsStatic);
 end;
 
+procedure TTestTypeScriptParser.TestDeclareClassExtendsFunctionCall;
+
+Var
+  Decl: TJSAmbientClassDeclaration;
+  E : TJSTypeFuncCall;
+
+begin
+   StartTS('declare class TextArea extends Component.extend(TextSupport) {}');
+   Decl:=TJSAmbientClassDeclaration(CheckClass('Class',TJSAmbientClassDeclaration,GetFirstClass(True)));
+   AssertNotNull('Have declaration',Decl);
+   AssertEquals('Name','TextArea',Decl.Name);
+   E:=TJSTypeFuncCall(CheckClass('Extends',TJSTypeFuncCall,Decl.Extends));
+   AssertEquals('Function name','Component.extend',E.Name);
+end;
+
+procedure TTestTypeScriptParser.TestDeclareClassStaticReadOnly;
+
+Var
+  Decl: TJSAmbientClassDeclaration;
+  E : TJSClassConstDeclaration;
+
+begin
+   StartTS('declare class A { static readonly B = 1 }');
+   Decl:=TJSAmbientClassDeclaration(CheckClass('Class',TJSAmbientClassDeclaration,GetFirstClass(True)));
+   AssertNotNull('Have declaration',Decl);
+   AssertEquals('Name','A',Decl.Name);
+   AssertEquals('member count',1,Decl.ClassDef.ElementCount);
+   AssertEquals('Member name','B',Decl.ClassDef.Elements[0].Name);
+   E:=TJSClassConstDeclaration(CheckClass('Member class',TJSClassConstDeclaration,Decl.ClassDef.Elements[0]));
+   AssertNotNull(E);
+end;
+
+
+
 procedure TTestTypeScriptParser.TestDeclareInterfaceIndexSignature;
 Var
   Decl : TJSInterfaceDeclaration;
@@ -1499,6 +1608,79 @@ begin
   GetStatements;
 end;
 
+procedure TTestTypeScriptParser.TestDeclareTypeGenericConstraint;
+
+Var
+  Decl : TJSTypeDeclaration;
+
+begin
+  StartTs('type ValueMap<T extends BaseType, Datum> = { [key: string]: number | string | boolean | null | ValueFn<T, Datum, number | string | boolean | null> };');
+  Decl:=GetFirstType;
+  AssertNotNull(Decl);
+end;
+
+procedure TTestTypeScriptParser.TestDeclareTypeTypeImport;
+
+Var
+  Decl : TJSImportTypeRef;
+
+begin
+  StartTS('  type AppChannel = import(''main'').AppChannel;');
+  Decl:=TJSImportTypeRef(CheckClass('First',TJSImportTypeRef,GetFirstType.TypeDef));
+  AssertEquals('Name','AppChannel',Decl.Name);
+  AssertEquals('File','main',Decl.fileName);
+end;
+
+procedure TTestTypeScriptParser.TestDeclareTypeTypeOfImport;
+
+Var
+  Decl : TJSImportTypeRef;
+
+begin
+  StartTS('  type AppChannel = typeof import(''main'').AppChannel;');
+  Decl:=TJSImportTypeRef(CheckClass('First',TJSImportTypeRef,GetFirstType.TypeDef));
+  AssertEquals('Name','AppChannel',Decl.Name);
+  AssertEquals('File','main',Decl.fileName);
+  AssertEquals('File',True,Decl.IsTypeOf);
+end;
+
+procedure TTestTypeScriptParser.TestDeclareTypeTypeOfDefault;
+Var
+  Decl : TJSImportTypeRef;
+
+begin
+  StartTS('  type AppChannel = typeof import(''main'').default;');
+  Decl:=TJSImportTypeRef(CheckClass('First',TJSImportTypeRef,GetFirstType.TypeDef));
+  AssertEquals('Name','default',Decl.Name);
+  AssertEquals('File','main',Decl.fileName);
+  AssertEquals('File',True,Decl.IsTypeOf);
+end;
+
+procedure TTestTypeScriptParser.TestDeclareTypeReadonly;
+Var
+  Decl : TJSFunctionStatement;
+  Def : TJSFuncDef;
+  R : TJSTypeReference;
+
+begin
+  StartTS('declare function markdownTable(table: readonly string): string;');
+  Decl:=GetFirstFunction;
+  AssertNotNull('Have decl',Decl.AFunction);
+  Def:=Decl.AFunction;
+  AssertEquals('Params',1,Def.TypedParams.Count);
+  R:=TJSTypeReference(CheckClass('Arg type',TJSTypeReference,Def.TypedParams.Types[0]));
+  AssertTrue('Read only',R.IsReadonly);
+end;
+
+procedure TTestTypeScriptParser.TestDeclareArgTypeInferred;
+Var
+  Decl : TJSTypeDeclaration;
+begin
+  StartTS('type A = (args: infer B) => C;');
+  Decl:=GetFirstType;
+  AssertNotNull(Decl);
+end;
+
 procedure TTestTypeScriptParser.TestExportNamespacedClass;
 
 Var
@@ -1557,6 +1739,15 @@ begin
   AssertEquals('Interface name','Color',Decl.Name);
 end;
 
+procedure TTestTypeScriptParser.TestExportInterfaceDefault;
+Var
+  Decl : TJSInterfaceDeclaration;
+begin
+  StartTS('export default  interface Color { R,G,B : string; } ;');
+  Decl:=TJSInterfaceDeclaration(CheckClass('Interface',TJSInterfaceDeclaration,GetFirstInterface));
+  AssertEquals('Interface name','Color',Decl.Name);
+end;
+
 procedure TTestTypeScriptParser.TestExportInterfaceIndexSignature;
 Var
   Decl : TJSInterfaceDeclaration;
@@ -1691,7 +1882,7 @@ begin
   AssertEquals('Member 2','green',ET.Names[2]);
 end;
 
-procedure TTestTypeScriptParser.TestExportObjectUNion;
+procedure TTestTypeScriptParser.TestExportObjectUnion;
 
 begin
   StartTs('export type VisitorIdentifier = { id: string } | { user_id: string };'#10+
@@ -1708,6 +1899,12 @@ begin
   AssertNotNull(GetStatements);
 end;
 
+procedure TTestTypeScriptParser.TestExportAsKeyWord;
+begin
+  StartTs('export { del as delete };');
+  AssertNotNull(GetStatements);
+end;
+
 procedure TTestTypeScriptParser.TestNamespaceInterfaceFunction;
 
 Var

+ 672 - 17
packages/fcl-js/tests/tctstopas.pp

@@ -1,7 +1,7 @@
 unit tctstopas;
 
 {$mode ObjFPC}{$H+}
-
+{ $define dumpsource}
 interface
 
 uses
@@ -16,35 +16,104 @@ Type
   TTestTSToPas = Class(TTestCase)
   private
     FConverter: TTypescriptToPas;
+    function GetConversionOptions: TConversionOptions;
+    procedure SetConversionOptions(AValue: TConversionOptions);
   Public
     Procedure Setup; override;
     procedure TearDown; override;
     procedure Convert(aSource : string); overload;
+    procedure Convert(aSource : Array of String); overload;
     procedure Convert(aSource : TStrings); overload;
     procedure CheckDeclaration(const aSection, aDeclaration : String);
     procedure CheckDeclaration(const aSection, aDeclaration, aDeclaration2 : String);
     procedure CheckDeclarations(const aSection : String; Const Declarations : Array of string);
     Property Converter : TTypescriptToPas Read FConverter;
+    Property ConversionOptions : TConversionOptions Read GetConversionOptions Write SetConversionOptions;
   Published
     Procedure TestEmpty;
     Procedure TestVarDeclaration;
     Procedure Test2VarDeclarations;
     Procedure Test3VarDeclarations;
+    Procedure TestVarIndirectType;
     Procedure TestKeywordVarDeclaration;
     Procedure TestSimpleType;
     Procedure TestAliasType;
     Procedure TestAliasAliasedType;
     Procedure TestUnionType;
+    procedure TestUnionTypeAllStrings;
     Procedure TestIntersectionType;
     Procedure TestUnionIntersectionType;
     Procedure TestEnumType;
+    Procedure TestArrayType;
+    Procedure TestTupleType;
+    Procedure TestTupleTypeForceUntyped;
+    Procedure TestTupleTypeUnbounded;
+    Procedure TestTupleTypeForceUntypedUnbounded;
+    procedure TestTupleTypeUnequalTypes;
+    procedure TestTupleTypeUnequalTypesUnbounded;
+    Procedure TestFunctionType;
+    Procedure TestFunctionTypeWithArg;
+    Procedure TestFunctionTypeWithReturn;
+    procedure TestFunctionTypeWithTupleReturn;
+    Procedure TestFunctionTypeWithReturnNoArgs;
+    Procedure TestFunctionTypeArrayType;
+    Procedure TestFunctionTypeArrayTypeObj;
+    Procedure TestFunctionTypeArrayTypeArray;
+    Procedure TestFunctionCallbackArg;
+    Procedure TestFunctionCallbackArgRecursive;
+    Procedure TestSimpleFunction;
+    Procedure TestSimpleFunctionKeyword;
+    Procedure TestExportSimpleFunction;
+    Procedure TestFunctionSimpleResult;
+    Procedure TestFunctionTypeRefResult;
+    procedure TestFunctionOneArg;
+    procedure TestFunctionOneArgUntyped;
+    procedure TestFunctionTwoArgs;
+    Procedure TestFunctionFunctionResult;
+    Procedure TestOverloadedProcedures;
+    Procedure TestUnionProcedures;
+    Procedure TestIndirectUnionProcedures;
+    Procedure TestUniqueOverloadedProcedures;
+    Procedure TestEmptyNameSpace;
+    Procedure TestEmptyNameSpaceFunction;
     Procedure TestExportInterface;
+    Procedure TestExportInterfaceAsClass;
+    Procedure TestExportInterfaceWithPropertiesAsClass;
+    Procedure TestExportInterfacePropertyCallbackArgRecursive;
+    Procedure TestInterfaceNamedFunction;
+    Procedure TestInterfaceNamedFunctionCallback;
+    Procedure TestObjectEmpty;
+    procedure TestObjectOneProperty;
+    procedure TestObjectOneReadOnlyProperty;
+    procedure TestObjectOneReadOnlyPropertyKeyword;
+    procedure TestClassOnePrivateProperty;
+    procedure TestClassOneMethod;
+    Procedure TestClassOneMethodKeyword;
+    procedure TestClassOneConstructor;
+    procedure TestClassPropertyArrayType;
+    procedure TestClassPropertyObjectType;
+    procedure TestClassPropertyObjectTypeRecursive;
+    procedure TestClassMethodOneCallback;
+    procedure TestClassMethodCallBackArrayTuple;
+    procedure TestClassMethodTupleReturn;
+    procedure TestClassMethodOneCallbackLocalArgTypes;
+    procedure TestNameSpaceClassLocalType;
   end;
 
 implementation
 
 { TTestTSToPas }
 
+function TTestTSToPas.GetConversionOptions: TConversionOptions;
+begin
+  Result:=FConverter.Options;
+end;
+
+procedure TTestTSToPas.SetConversionOptions(AValue: TConversionOptions);
+begin
+  FConverter.Options:=aValue;
+end;
+
 procedure TTestTSToPas.Setup;
 
 begin
@@ -62,6 +131,12 @@ end;
 
 procedure TTestTSToPas.Convert(aSource: string);
 
+
+begin
+  Convert([aSource]);
+end;
+
+procedure TTestTSToPas.Convert(aSource: array of String);
 Var
   aSrc : TStrings;
 
@@ -69,15 +144,19 @@ begin
   aSrc:=TStringList.Create;
   try
     TStringList(aSrc).SkipLastLineBreak:=True;
-    aSrc.Text:=aSource;
-    Writeln('--');
-    Writeln(aSrc.Text);
-    Writeln('--');
+    aSrc.AddStrings(aSource);
+{$IFDEF dumpsource}
+    if IsConsole then
+      begin
+      Writeln('--');
+      Writeln(aSrc.Text);
+      Writeln('--');
+      end;
+{$ENDIF dumpsource}
     Convert(aSrc);
   finally
     aSrc.Free;
   end;
-
 end;
 
 procedure TTestTSToPas.Convert(aSource: TStrings);
@@ -113,24 +192,33 @@ Var
 
 begin
   Src:=FConverter.Source;
-  Writeln('>>>');
-  Writeln(Src.Text);
-  Writeln('<<<');
+{$IFDEF dumpsource}
+  if IsConsole then
+    begin
+    Writeln('>>>');
+    Writeln(Src.Text);
+    Writeln('<<<');
+    end;
+{$ENDIF dumpsource}
   I:=0;
   While (I<Src.Count) and (Trim(Src[i])='') do
     Inc(I);
-  AssertTrue('Section: Not at end',I<Src.Count);
-  AssertEquals('Section correct',LowerCase(aSection),LowerCase(Trim(Src[i])));
+  if aSection<>'' then
+    begin
+    AssertTrue('Section: Not at end',I<Src.Count);
+    AssertEquals('Section correct',LowerCase(aSection),LowerCase(Trim(Src[i])));
+    Inc(I);
+    end;
   For J:=0 to Length(Declarations)-1 do
     begin
     D:=Format('Declaration %d: ',[J]);
     S:=Declarations[J];
-    Inc(I);
     While (I<Src.Count) and (Trim(Src[i])='') do
       Inc(I);
     AssertTrue(D+'Not at end',I<Src.Count);
     actSrc:=Src[i];
     AssertEquals(D+'Declaration correct',LowerCase(S),LowerCase(Trim(actSrc)));
+    Inc(I);
     end;
 end;
 
@@ -142,19 +230,31 @@ end;
 procedure TTestTSToPas.TestVarDeclaration;
 begin
   Convert('declare var x : number;');
-  CheckDeclaration('var','x : double;');
+  CheckDeclaration('var','x : double; external name ''x'';');
 end;
 
 procedure TTestTSToPas.Test2VarDeclarations;
 begin
   Convert('declare var x,y : number;');
-  CheckDeclaration('var','x : double;','y : double;');
+  CheckDeclaration('var','x : double; external name ''x'';','y : double; external name ''y'';');
 end;
 
 procedure TTestTSToPas.Test3VarDeclarations;
 begin
   Convert('declare var x,y,z : number;');
-  CheckDeclarations('var',['x : double;','y : double;','z : double;']);
+  CheckDeclarations('var',['x : double; external name ''x'';','y : double; external name ''y'';','z : double; external name ''z'';']);
+end;
+
+procedure TTestTSToPas.TestVarIndirectType;
+begin
+  Convert('declare var a : { b : string;};');
+  CheckDeclarations('type',[
+    'TA = class external name ''Object'' (TJSObject)',
+    'public',
+    'b : string;',
+    'end;',
+    'var',
+    'a : ta; external name ''a'';']);
 end;
 
 procedure TTestTSToPas.TestKeywordVarDeclaration;
@@ -188,6 +288,12 @@ begin
   CheckDeclarations('type',['TMyType = JSValue; // string | number']);
 end;
 
+procedure TTestTSToPas.TestUnionTypeAllStrings;
+begin
+  Convert('declare type MyType = ''string'' | ''number'';');
+  CheckDeclarations('type',['TMyType = string; // Restricted values']);
+end;
+
 procedure TTestTSToPas.TestIntersectionType;
 begin
   Convert('declare type MyType = string & number;');
@@ -206,10 +312,559 @@ begin
   CheckDeclarations('type',['TColor = (Red, Green, Blue);']);
 end;
 
+procedure TTestTSToPas.TestArrayType;
+begin
+  Convert('declare type A = number[];');
+  CheckDeclarations('type',['TA = array of Double;']);
+end;
+
+procedure TTestTSToPas.TestTupleType;
+begin
+  Convert('declare type A = [number,number];');
+  CheckDeclarations('type',['TA = array[0..1] of Double;']);
+end;
+
+procedure TTestTSToPas.TestTupleTypeForceUntyped;
+begin
+  ConversionOptions:=ConversionOptions+[coUntypedTuples];
+  Convert('declare type A = [number,number];');
+  CheckDeclarations('type',['TA = array[0..1] of jsValue;']);
+end;
+
+procedure TTestTSToPas.TestTupleTypeUnbounded;
+begin
+  ConversionOptions:=ConversionOptions+[coDynamicTuples];
+  Convert('declare type A = [number,number];');
+  CheckDeclarations('type',['TA = array of double;']);
+end;
+
+procedure TTestTSToPas.TestTupleTypeForceUntypedUnbounded;
+begin
+  ConversionOptions:=ConversionOptions+[coDynamicTuples,coUntypedTuples];
+  Convert('declare type A = [number,number];');
+  CheckDeclarations('type',['TA = tjsvaluedynarray;']);
+end;
+
+procedure TTestTSToPas.TestTupleTypeUnequalTypes;
+begin
+  Convert('declare type A = [number,string];');
+  CheckDeclarations('type',['TA = array[0..1] of jsvalue;']);
+end;
+
+procedure TTestTSToPas.TestTupleTypeUnequalTypesUnbounded;
+begin
+  ConversionOptions:=ConversionOptions+[coDynamicTuples];
+  Convert('declare type A = [number,string];');
+  CheckDeclarations('type',['TA = tjsvaluedynarray;']);
+end;
+
+procedure TTestTSToPas.TestFunctionType;
+begin
+  Convert('declare type A = () => void;');
+  CheckDeclarations('type',['TA = procedure;']);
+end;
+
+procedure TTestTSToPas.TestFunctionTypeWithArg;
+begin
+  Convert('declare type A = (B : string) => void;');
+  CheckDeclarations('type',['TA = procedure (B : string);']);
+end;
+
+procedure TTestTSToPas.TestFunctionTypeWithReturn;
+begin
+  Convert('declare type A = (B : string) => number;');
+  CheckDeclarations('type',['TA = function (B : string): Double;']);
+end;
+
+procedure TTestTSToPas.TestFunctionTypeWithTupleReturn;
+begin
+  Convert('declare type A = (B : string) => [number,number];');
+  CheckDeclarations('type',[
+    'TTA_Result = array[0..1] of double;',
+    'TA = function (B : string): TTA_Result;'
+    ]);
+end;
+
+procedure TTestTSToPas.TestFunctionTypeWithReturnNoArgs;
+begin
+  Convert('declare type A = () => number;');
+  CheckDeclarations('type',['TA = function: Double;']);
+end;
+
+procedure TTestTSToPas.TestFunctionTypeArrayType;
+begin
+  Convert('declare type A = (B : string[]) => void;');
+  CheckDeclarations('type',['TA = procedure (B : array of string);']);
+end;
+
+procedure TTestTSToPas.TestFunctionTypeArrayTypeObj;
+begin
+  Convert('declare function b (a : Array<{}>): string;');
+  CheckDeclarations('type',[
+    'tb_a_item = class external name ''Object'' (TJSObject)',
+    'end;',
+    'tb_a = array of tb_a_item;',
+    'function b(a : Tb_a): string; external name ''b'';'
+  ]);
+end;
+
+procedure TTestTSToPas.TestFunctionTypeArrayTypeArray;
+begin
+  Convert('declare function a(b: string[][]): void;');
+  CheckDeclarations('type',[
+    'ta_b_item = array of string;',
+    'ta_b = array of ta_b_item;',
+    'Procedure a(b : Ta_b); external name ''a'';'
+  ]);
+end;
+
+procedure TTestTSToPas.TestFunctionCallbackArg;
+begin
+  Convert('declare function b (para1 : (a: number) => string) : string;');
+  CheckDeclarations('type',[
+    'tb_para1 = function (a : double): string;',
+    'function b(para1 : Tb_para1): string; external name ''b'';'
+  ]);
+end;
+
+procedure TTestTSToPas.TestFunctionCallbackArgRecursive;
+begin
+  Convert('declare function b (para1 : (a: (c: string) =>void) => string) : string;');
+  CheckDeclarations('type',[
+    'tb_para1_a = procedure (c : string);',
+    'tb_para1 = function (a : tb_para1_a): string;',
+    'function b(para1 : Tb_para1): string; external name ''b'';'
+  ]);
+end;
+
+procedure TTestTSToPas.TestSimpleFunction;
+begin
+  Convert('declare function A() : void;');
+  CheckDeclarations('',['Procedure A; external name ''a'';']);
+end;
+
+procedure TTestTSToPas.TestSimpleFunctionKeyword;
+begin
+  Convert('declare function on() : void;');
+  CheckDeclarations('',['Procedure &on; external name ''on'';']);
+end;
+
+procedure TTestTSToPas.TestExportSimpleFunction;
+begin
+  Convert('export function A() : void;');
+  CheckDeclarations('',['Procedure A; external name ''A'';']);
+end;
+
+procedure TTestTSToPas.TestFunctionSimpleResult;
+begin
+  Convert('declare function A() : number;');
+  CheckDeclarations('',['function A: double; external name ''A'';']);
+end;
+
+procedure TTestTSToPas.TestFunctionTypeRefResult;
+begin
+  Convert(['declare type B = number;','declare function A() : B;']);
+  CheckDeclarations('type',['TB = double;','function A: TB; external name ''A'';']);
+end;
+
+
+procedure TTestTSToPas.TestFunctionOneArg;
+
+begin
+  Convert('declare function A(b : string) : void;');
+  CheckDeclarations('',['procedure A(b : string); external name ''A'';']);
+end;
+
+procedure TTestTSToPas.TestFunctionOneArgUntyped;
+begin
+  Convert('declare function A(b) : void;');
+  CheckDeclarations('',['procedure A(b : jsvalue); external name ''A'';']);
+end;
+
+procedure TTestTSToPas.TestFunctionTwoArgs;
+begin
+  Convert('declare function A(b : string, c : number) : void;');
+  CheckDeclarations('',['procedure A(b : string; c : double); external name ''A'';']);
+end;
+
+procedure TTestTSToPas.TestFunctionFunctionResult;
+begin
+  convert('declare class A { b(): (c: { d : any }) => void; }');
+  CheckDeclarations('Type',[
+  '// Forward class definitions',
+  'ta = class;',
+  'ta_b_result_c = class external name ''object'' (TJSObject)',
+  'public',
+  'd : jsvalue;',
+  'end;',
+  'ta_b_result = procedure (c : ta_b_result_c);',
+  'ta = class external name ''A'' (TJSObject)',
+  'public',
+  'function b: ta_b_result;',
+  'end;'
+  ])
+end;
+
+procedure TTestTSToPas.TestOverloadedProcedures;
+begin
+  Convert(['declare function A() : void;','declare function A(b : string) : void;']);
+  CheckDeclarations('',[
+    'procedure A; external name ''A''; overload;',
+    'procedure A(b : string); external name ''A''; overload;']);
+end;
+
+procedure TTestTSToPas.TestUnionProcedures;
+begin
+  Converter.Options:=Converter.Options+[coExpandUnionTypeArgs];
+  Convert(['declare function A(b: number | string) : void;']);
+  CheckDeclarations('',[
+    'procedure A(b : double); external name ''A''; overload;',
+    'procedure A(b : string); external name ''A''; overload;']);
+end;
+
+procedure TTestTSToPas.TestIndirectUnionProcedures;
+begin
+  Converter.Options:=Converter.Options+[coExpandUnionTypeArgs];
+  Convert(['declare type U = number | string;','declare function A(b: U) : void;']);
+  CheckDeclarations('type',[
+    'TU = JSValue; // number | string',
+    'procedure A(b : double); external name ''A''; overload;',
+    'procedure A(b : string); external name ''A''; overload;'
+  ]);
+end;
+
+procedure TTestTSToPas.TestUniqueOverloadedProcedures;
+begin
+  Converter.Options:=Converter.Options+[coExpandUnionTypeArgs];
+  Convert(['declare function A(b: number) : void;','declare function A(b: number | string) : void;']);
+  CheckDeclarations('',[
+    'procedure A(b : double); external name ''A''; overload;',
+    'procedure A(b : string); external name ''A''; overload;'
+  ]);
+end;
+
+procedure TTestTSToPas.TestEmptyNameSpace;
+begin
+  Convert(['declare namespace A { };']);
+  CheckDeclarations('type',['// forward class definitions',
+                            'TA = Class;',
+                            '// Namespaces',
+                            'TA = class external name ''A'' (TJSObject)',
+                            'Public',
+                            'end;']);
+end;
+
+procedure TTestTSToPas.TestEmptyNameSpaceFunction;
+begin
+  Convert(['declare namespace A { ',
+           '  function B() : void;',
+           '}']);
+  CheckDeclarations('type',['// forward class definitions',
+                            'TA = Class;',
+                            '// Namespaces',
+                            'TA = class external name ''A'' (TJSObject)',
+                            'Public',
+                            'procedure B;',
+                            'end;']);
+
+end;
+
 procedure TTestTSToPas.TestExportInterface;
+
+begin
+  Convert('declare interface Color {  b () : string; } ;');
+  CheckDeclarations('type',[
+     '// Forward class definitions',
+     'TColor = interface;',
+     'TColor = interface',
+     'function b: string;',
+     'end;']
+  );
+end;
+
+procedure TTestTSToPas.TestExportInterfaceAsClass;
+begin
+  ConversionOptions:=ConversionOptions+[coInterfaceAsClass];
+  Convert('declare interface Color {  b () : string; } ;');
+  CheckDeclarations('type',[
+     '// Forward class definitions',
+     'TColor = class;',
+     'TColor = class external name ''object'' (TJSObject)',
+     'function b: string;',
+     'end;']
+  );
+end;
+
+procedure TTestTSToPas.TestExportInterfaceWithPropertiesAsClass;
+begin
+  Convert('declare interface Color {  b : string; } ;');
+  CheckDeclarations('type',[
+     '// Forward class definitions',
+     'TColor = class;',
+     'TColor = class external name ''object'' (TJSObject)',
+     'b : string;',
+     'end;']
+  );
+end;
+
+procedure TTestTSToPas.TestExportInterfacePropertyCallbackArgRecursive;
+begin
+  Convert('declare interface A { b?: (c: (d: Boolean) => void) => void; }');
+  CheckDeclarations('type',[
+     '// Forward class definitions',
+     'TA = class;',
+     'tA_b_c = procedure (d : boolean);',
+     'tA_b = procedure (c : tA_b_c);',
+     'TA = class external name ''object'' (TJSObject)',
+     'b : TA_b;',
+     'end;']
+  );
+
+end;
+
+procedure TTestTSToPas.TestInterfaceNamedFunction;
+begin
+  Convert('declare interface a { (b : String, c: string): number; }');
+  CheckDeclarations('type',[
+  // '// Forward class definitions',
+  'TA = function (B : String; C : string): double;'
+  ]);
+end;
+
+procedure TTestTSToPas.TestInterfaceNamedFunctionCallback;
+begin
+  Convert('declare interface a { (b : (c: string) => void): number; }');
+  CheckDeclarations('type',[
+  'Ta__b = procedure (c : string);',
+  'TA = function (B : TA__b): double;'
+  ]);
+end;
+
+procedure TTestTSToPas.TestObjectEmpty;
+begin
+  Convert('declare type A = {  }');
+  CheckDeclarations('type',[
+    '// Forward class definitions',
+    'TA = class;',
+    'TA = class external name ''Object'' (TJSObject)',
+    'end;']);
+end;
+
+procedure TTestTSToPas.TestObjectOneProperty;
+
+begin
+  Convert('declare type A = { prop : string; }');
+  CheckDeclarations('type',[
+    '// Forward class definitions',
+    'TA = class;',
+    'TA = class external name ''Object'' (TJSObject)',
+    'Public',
+    'prop : string;',
+    'end;']);
+end;
+
+procedure TTestTSToPas.TestClassOnePrivateProperty;
+begin
+  Convert('declare class A { private prop : string; }');
+  CheckDeclarations('type',[
+    '// Forward class definitions',
+    'TA = class;',
+    'TA = class external name ''A'' (TJSObject)',
+    'Private',
+    'prop : string;',
+    'end;']);
+end;
+
+procedure TTestTSToPas.TestClassOneMethod;
+
+begin
+  Convert(' export class A { b (c: string) : void; }');
+  CheckDeclarations('type',[
+    '// Forward class definitions',
+    'TA = class;',
+    'TA = class external name ''A'' (TJSObject)',
+    'public',
+    'procedure b(c : string);',
+    'end;']);
+end;
+
+procedure TTestTSToPas.TestClassOneMethodKeyword;
+begin
+  Convert(' export class A { to() : void; }');
+  CheckDeclarations('type',[
+    '// Forward class definitions',
+    'TA = class;',
+    'TA = class external name ''A'' (TJSObject)',
+    'public',
+    'procedure &to;',
+    'end;']);
+end;
+
+procedure TTestTSToPas.TestClassOneConstructor;
+begin
+  Convert(' export class A { constructor (c: string) : void; }');
+  CheckDeclarations('type',[
+    '// Forward class definitions',
+    'TA = class;',
+    'TA = class external name ''A'' (TJSObject)',
+    'public',
+    'constructor new(c : string);',
+    'end;']);
+end;
+
+procedure TTestTSToPas.TestClassPropertyArrayType;
+begin
+  Convert(' export class A { b : string[] ; }');
+  CheckDeclarations('type',[
+    '// Forward class definitions',
+    'TA = class;',
+    'tA_b = array of string;',
+    'TA = class external name ''A'' (TJSObject)',
+    'public',
+    'b : TA_b;',
+    'end;']);
+end;
+
+procedure TTestTSToPas.TestClassPropertyObjectType;
+begin
+  Convert('declare interface A { B: { C : number; };  }');
+  CheckDeclarations('type',[
+    '// Forward class definitions',
+    'TA = class;',
+    'TA_b = class external name ''Object'' (TJSObject)',
+    'public',
+    'c : double;',
+    'end;',
+    'TA = class external name ''object'' (TJSObject)',
+    'b : TA_B;',
+    'end;']);
+end;
+
+procedure TTestTSToPas.TestClassPropertyObjectTypeRecursive;
+begin
+  Convert('declare interface A { B: { C: { D : number; }; }; }');
+  CheckDeclarations('type',[
+    '// Forward class definitions',
+    'TA = class;',
+    'TA_b_c = class external name ''Object'' (TJSObject)',
+    'public',
+    'd : double;',
+    'end;',
+    'TA_b = class external name ''Object'' (TJSObject)',
+    'public',
+    'c : Ta_b_c;',
+    'end;',
+    'TA = class external name ''Object'' (TJSObject)',
+    'b : TA_B;',
+    'end;']);
+
+
+end;
+
+procedure TTestTSToPas.TestClassMethodOneCallback;
+
+begin
+  Convert(' export class A { b (c: (d : number) => string) : void; }');
+  CheckDeclarations('type',[
+    '// Forward class definitions',
+    'TA = class;',
+    'tA_b_c = function (d : double): string;',
+    'TA = class external name ''A'' (TJSObject)',
+    'public',
+    'procedure b(c : TA_b_c);',
+    'end;']);
+end;
+
+procedure TTestTSToPas.TestClassMethodCallBackArrayTuple;
+begin
+  Convert('declare class A { b() : [number, number][]; }');
+  CheckDeclarations('type',[
+    '// Forward class definitions',
+    'TA = class;',
+    'TA_b_Result_Item = array[0..1] of double;',
+    'tA_b_Result = array of TA_b_Result_Item;',
+    'TA = class external name ''A'' (TJSObject)',
+    'public',
+    'function b: tA_b_Result;',
+    'end;']);
+end;
+
+procedure TTestTSToPas.TestClassMethodTupleReturn;
+begin
+  Convert(' export class A { b () : [number, number]; }');
+  CheckDeclarations('type',[
+    '// Forward class definitions',
+    'TA = class;',
+    'tA_b_Result = array[0..1] of double;',
+    'TA = class external name ''A'' (TJSObject)',
+    'public',
+    'function b: tA_b_Result;',
+    'end;']);
+end;
+
+procedure TTestTSToPas.TestClassMethodOneCallbackLocalArgTypes;
+begin
+  ConversionOptions:=ConversionOptions+[coLocalArgumentTypes];
+  Convert(' export class A { b (c: (d : number) => string) : void; }');
+  CheckDeclarations('type',[
+    '// Forward class definitions',
+    'TA = class;',
+    'TA = class external name ''A'' (TJSObject)',
+    'public',
+    'Type',
+    'tb_c = function (d : double): string;',
+    'public',
+    'procedure b(c : Tb_c);',
+    'end;']);
+end;
+
+procedure TTestTSToPas.TestNameSpaceClassLocalType;
+begin
+  Convert('declare module "a" { class b { c(d : string): string[]; }; }');
+  CheckDeclarations('type',[
+    '// Forward class definitions',
+    'TA = class;',
+    '// Modules',
+    'TA = class external name ''a'' (TJSObject)',
+    'Public',
+    'Type',
+    '// Forward class definitions',
+    'TB = class;',
+    'TB_c_Result = Array of string;',
+    'TB = class external name ''b'' (TJSObject)',
+    'Public',
+    'function c(d : string): TB_c_Result;',
+    'end;'
+  ])
+end;
+
+
+procedure TTestTSToPas.TestObjectOneReadOnlyProperty;
+begin
+  Convert('declare type A = { readonly prop : string; }');
+  CheckDeclarations('type',[
+    '// Forward class definitions',
+    'TA = class;',
+    'TA = class external name ''Object'' (TJSObject)',
+    'Private',
+    'FProp : String; external name ''prop'';',
+    'Public',
+    'Property prop : string read FProp;',
+    'end;']);
+end;
+
+procedure TTestTSToPas.TestObjectOneReadOnlyPropertyKeyword;
 begin
-//  Convert('export interface Color { function get() : string; } ;');
-//  CheckDeclarations('type',['TColor = (Red, Green, Blue);']);
+  Convert('declare type A = { readonly on : string; }');
+  CheckDeclarations('type',[
+    '// Forward class definitions',
+    'TA = class;',
+    'TA = class external name ''Object'' (TJSObject)',
+    'Private',
+    'FOn : String; external name ''on'';',
+    'Public',
+    'Property on : string read FOn;',
+    'end;']);
 end;
 
 Initialization

+ 2 - 2
packages/fcl-js/tests/testjs.lpi

@@ -20,13 +20,13 @@
     </PublishOptions>
     <RunParams>
       <local>
-        <CommandLineParams Value="--suite=TTestTypeScriptParser.TestDeclareTypeArrowFunctionShort"/>
+        <CommandLineParams Value="--suite=TTestTSToPas.TestObjectOneReadOnlyPropertyKeyword"/>
       </local>
       <FormatVersion Value="2"/>
       <Modes Count="1">
         <Mode0 Name="default">
           <local>
-            <CommandLineParams Value="--suite=TTestTypeScriptParser.TestDeclareTypeArrowFunctionShort"/>
+            <CommandLineParams Value="--suite=TTestTSToPas.TestObjectOneReadOnlyPropertyKeyword"/>
           </local>
         </Mode0>
       </Modes>

Неке датотеке нису приказане због велике количине промена