Browse Source

pas2js: added option -Jmxssiheader

git-svn-id: trunk@38028 -
Mattias Gaertner 7 years ago
parent
commit
eebfb65131

+ 50 - 5
packages/pastojs/src/pas2jscompiler.pp

@@ -23,7 +23,7 @@ interface
 uses
   Classes, SysUtils, AVL_Tree, contnrs,
   PScanner, PParser, PasTree, PasResolver, PasUseAnalyzer, PasResolveEval,
-  jstree, jswriter, FPPas2Js, FPPJsSrcMap,
+  jstree, jswriter, JSSrcMap, FPPas2Js, FPPJsSrcMap,
   Pas2jsFileUtils, Pas2jsLogger, Pas2jsFileCache, Pas2jsPParser;
 
 const
@@ -99,7 +99,8 @@ type
     coKeepNotUsedPrivates,
     coKeepNotUsedDeclarationsWPO,
     coSourceMapCreate,
-    coSourceMapInclude
+    coSourceMapInclude,
+    coSourceMapXSSIHeader
     );
   TP2jsCompilerOptions = set of TP2jsCompilerOption;
 const
@@ -133,7 +134,8 @@ const
     'Keep not used private declarations',
     'Keep not used declarations (WPO)',
     'Create source map',
-    'Include Pascal sources in source map'
+    'Include Pascal sources in source map',
+    'Prepend XSSI protection )]} to source map'
     );
 
 //------------------------------------------------------------------------------
@@ -329,6 +331,7 @@ type
     function GetSrcMapBaseDir: string;
     function GetSrcMapEnable: boolean;
     function GetSrcMapInclude: boolean;
+    function GetSrcMapXSSIHeader: boolean;
     function OnMacroCfgDir(Sender: TObject; var Params: string; Lvl: integer
       ): boolean;
     function OnMacroEnv(Sender: TObject; var Params: string; Lvl: integer
@@ -361,6 +364,7 @@ type
     procedure SetSrcMapBaseDir(const AValue: string);
     procedure SetSrcMapEnable(const AValue: boolean);
     procedure SetSrcMapInclude(const AValue: boolean);
+    procedure SetSrcMapXSSIHeader(const AValue: boolean);
     procedure SetTargetPlatform(const AValue: TPasToJsPlatform);
     procedure SetTargetProcessor(const AValue: TPasToJsProcessor);
   protected
@@ -429,6 +433,7 @@ type
     property SrcMapSourceRoot: string read FSrcMapSourceRoot write FSrcMapSourceRoot;
     property SrcMapBaseDir: string read GetSrcMapBaseDir write SetSrcMapBaseDir;
     property SrcMapInclude: boolean read GetSrcMapInclude write SetSrcMapInclude;
+    property SrcMapXSSIHeader: boolean read GetSrcMapXSSIHeader write SetSrcMapXSSIHeader;
     property ShowDebug: boolean read GetShowDebug write SetShowDebug;
     property ShowFullPaths: boolean read GetShowFullPaths write SetShowFullPaths;
     property ShowLogo: Boolean read GetShowLogo write SetShowLogo;
@@ -1681,6 +1686,10 @@ var
       SrcMap.Release;// release the refcount from the Create
       SrcMap.SourceRoot:=SrcMapSourceRoot;
       SrcMap.LocalFilename:=aFile.JSFilename;
+      if SrcMapXSSIHeader then
+        SrcMap.Options:=SrcMap.Options+[smoSafetyHeader]
+      else
+        SrcMap.Options:=SrcMap.Options-[smoSafetyHeader];
     end;
   end;
 
@@ -1925,6 +1934,11 @@ begin
   Result:=coSourceMapInclude in FOptions;
 end;
 
+function TPas2jsCompiler.GetSrcMapXSSIHeader: boolean;
+begin
+  Result:=coSourceMapXSSIHeader in FOptions;
+end;
+
 procedure TPas2jsCompiler.LoadConfig(CfgFilename: string);
 type
   TSkip = (
@@ -2375,6 +2389,10 @@ begin
                 SrcMapInclude:=true
               else if Value='include-' then
                 SrcMapInclude:=false
+              else if Value='xssiheader' then
+                SrcMapXSSIHeader:=true
+              else if Value='xssiheader-' then
+                SrcMapXSSIHeader:=false
               else
                 begin
                 i:=Pos('=',Value);
@@ -2392,6 +2410,24 @@ begin
               // enable source maps when setting any -Jm<x> option
               SrcMapEnable:=true;
               end;
+          'o':
+            begin
+              Identifier:=String(p);
+              if Identifier='' then
+                ParamFatal('missing -Jo option');
+              inc(p,length(Identifier));
+              Enable:=true;
+              c:=Identifier[length(Identifier)];
+              if c in ['+','-'] then
+              begin
+                Enable:=c='+';
+                Delete(Identifier,length(Identifier),1);
+              end;
+              if CompareText(Identifier,'SearchLikeFPC')=0 then
+                FileCache.SearchLikeFPC:=Enable
+              else
+                UnknownParam;
+            end;
           'u':
             if not Quick then
               if not FileCache.AddSrcUnitPaths(String(p),FromCmdLine,ErrorMsg) then
@@ -2451,7 +2487,8 @@ begin
           begin
           inc(p);
           Identifier:=String(p);
-          if Identifier='' then UnknownParam;
+          if Identifier='' then
+            ParamFatal('missing -Oo option');
           inc(p,length(Identifier));
           Enable:=true;
           c:=Identifier[length(Identifier)];
@@ -2833,6 +2870,11 @@ begin
   SetOption(coSourceMapInclude,AValue);
 end;
 
+procedure TPas2jsCompiler.SetSrcMapXSSIHeader(const AValue: boolean);
+begin
+  SetOption(coSourceMapXSSIHeader,AValue);
+end;
+
 procedure TPas2jsCompiler.SetTargetPlatform(const AValue: TPasToJsPlatform);
 begin
   if FTargetPlatform=AValue then Exit;
@@ -3179,7 +3221,10 @@ begin
   l('     -Jmsourceroot=<x> : use x as "sourceRoot", prefix URL for source file names.');
   l('     -Jmbasedir=<x> : write source file names relative to directory x.');
   l('     -Jminclude : include Pascal sources in source map.');
+  l('     -Jmxssiheader : start source map with XSSI protection )]}.');
   l('     -Jm- : disable generating source maps');
+  l('   -Jo<x> : Enable or disable extra option. The x is case insensitive:');
+  l('     -JoSearchLikeFPC : search source files like FPC, default: search case insensitive.');
   l('   -Ju<x> : Add <x> to foreign unit paths. Foreign units are not compiled.');
   {$IFDEF EnablePas2jsPrecompiled}
   l('   -JU    : Create precompiled units in '+PrecompiledExt+' format.');
@@ -3230,7 +3275,7 @@ begin
   l('  -?      : Show this help');
   l('  -h      : Show this help');
   Log.LogLn;
-  l('Macros:  $Name, $Name$ or $Name()');
+  l('Macros: Format is $Name, $Name$ or $Name()');
   for i:=0 to ParamMacros.Count-1 do begin
     ParamMacro:=ParamMacros[i];
     Log.LogRaw(['  $',ParamMacro.Name,BoolToStr(ParamMacro.CanHaveParams,'()',''),': ',ParamMacro.Description]);

+ 22 - 7
packages/pastojs/src/pas2jsfilecache.pp

@@ -141,7 +141,8 @@ type
   TP2jsFileCacheOption = (
     caoShowFullFilenames,
     caoShowTriedUsedFiles,
-    caoAllJSIntoMainJS
+    caoAllJSIntoMainJS,
+    caoSearchLikeFPC
     );
   TP2jsFileCacheOptions = set of TP2jsFileCacheOption;
 const
@@ -150,7 +151,8 @@ const
     // only used by experts, no need for resourcestrings
     'Show full filenames',
     'Show tried/used files',
-    'Combine all JavaScript into main file'
+    'Combine all JavaScript into main file',
+    'Search files like FPC'
     );
 
 type
@@ -262,6 +264,7 @@ type
     FUnitPaths: TStringList;
     FUnitPathsFromCmdLine: integer;
     function GetAllJSIntoMainJS: Boolean;
+    function GetSearchLikeFPC: boolean;
     function GetShowFullFilenames: boolean;
     function GetShowTriedUsedFiles: boolean;
     procedure RegisterMessages;
@@ -271,8 +274,9 @@ type
       FromCmdLine: boolean; var List: TStringList; var CmdLineCount: integer): string;
     procedure SetMainJSFile(AValue: string);
     procedure SetOptions(AValue: TP2jsFileCacheOptions);
-    procedure SetShowFullFilenames(AValue: boolean);
-    procedure SetShowTriedUsedFiles(AValue: boolean);
+    procedure SetSearchLikeFPC(const AValue: boolean);
+    procedure SetShowFullFilenames(const AValue: boolean);
+    procedure SetShowTriedUsedFiles(const AValue: boolean);
     procedure SetSrcMapBaseDir(const AValue: string);
     procedure SetUnitOutputPath(AValue: string);
     procedure SetOption(Flag: TP2jsFileCacheOption; Enable: boolean);
@@ -315,9 +319,10 @@ type
     property Options: TP2jsFileCacheOptions read FOptions write SetOptions default DefaultPas2jsFileCacheOptions;
     property ReadLineCounter: SizeInt read FReadLineCounter write FReadLineCounter;
     property ResetStamp: TChangeStamp read FResetStamp;
-    property SrcMapBaseDir: string read FSrcMapBaseDir write SetSrcMapBaseDir; // includes trailing pathdelim
+    property SearchLikeFPC: boolean read GetSearchLikeFPC write SetSearchLikeFPC;
     property ShowFullPaths: boolean read GetShowFullFilenames write SetShowFullFilenames;
     property ShowTriedUsedFiles: boolean read GetShowTriedUsedFiles write SetShowTriedUsedFiles;
+    property SrcMapBaseDir: string read FSrcMapBaseDir write SetSrcMapBaseDir; // includes trailing pathdelim
     property UnitOutputPath: string read FUnitOutputPath write SetUnitOutputPath; // includes trailing pathdelim
     property UnitPaths: TStringList read FUnitPaths;
     property UnitPathsFromCmdLine: integer read FUnitPathsFromCmdLine;
@@ -1334,6 +1339,11 @@ begin
   Result:=caoAllJSIntoMainJS in FOptions;
 end;
 
+function TPas2jsFilesCache.GetSearchLikeFPC: boolean;
+begin
+  Result:=caoSearchLikeFPC in FOptions;
+end;
+
 function TPas2jsFilesCache.GetShowFullFilenames: boolean;
 begin
   Result:=caoShowFullFilenames in FOptions;
@@ -1474,12 +1484,17 @@ begin
   FOptions:=AValue;
 end;
 
-procedure TPas2jsFilesCache.SetShowFullFilenames(AValue: boolean);
+procedure TPas2jsFilesCache.SetSearchLikeFPC(const AValue: boolean);
+begin
+  SetOption(caoSearchLikeFPC,AValue);
+end;
+
+procedure TPas2jsFilesCache.SetShowFullFilenames(const AValue: boolean);
 begin
   SetOption(caoShowFullFilenames,AValue);
 end;
 
-procedure TPas2jsFilesCache.SetShowTriedUsedFiles(AValue: boolean);
+procedure TPas2jsFilesCache.SetShowTriedUsedFiles(const AValue: boolean);
 begin
   SetOption(caoShowTriedUsedFiles,AValue);
 end;

+ 77 - 0
packages/pastojs/tests/tcmodules.pas

@@ -396,6 +396,7 @@ type
     Procedure TestClass_LocalVarSelfFail;
     Procedure TestClass_ArgSelfFail;
     Procedure TestClass_NestedProcSelf;
+    Procedure TestClass_NestedProcSelf2;
     Procedure TestClass_NestedProcClassSelf;
     Procedure TestClass_NestedProcCallInherited;
     Procedure TestClass_TObjectFree;
@@ -9369,6 +9370,82 @@ begin
     '']));
 end;
 
+procedure TTestModule.TestClass_NestedProcSelf2;
+begin
+  StartProgram(false);
+  Add([
+  'type',
+  '  TObject = class',
+  '    Key: longint;',
+  '    class var State: longint;',
+  '    function GetSize: longint; virtual; abstract;',
+  '    procedure SetSize(Value: longint); virtual; abstract;',
+  '    property Size: longint read GetSize write SetSize;',
+  '  end;',
+  '  TBird = class',
+  '    procedure DoIt;',
+  '  end;',
+  'procedure tbird.doit;',
+  '  procedure Sub;',
+  '  begin',
+  '    key:=key+2;',
+  '    self.key:=self.key+3;',
+  '    state:=state+4;',
+  '    self.state:=self.state+5;',
+  '    tobject.state:=tobject.state+6;',
+  '    size:=size+7;',
+  '    self.size:=self.size+8;',
+  '  end;',
+  'begin',
+  '  sub;',
+  '  key:=key+12;',
+  '  self.key:=self.key+13;',
+  '  state:=state+14;',
+  '  self.state:=self.state+15;',
+  '  tobject.state:=tobject.state+16;',
+  '  size:=size+17;',
+  '  self.size:=self.size+18;',
+  'end;',
+  'begin',
+  '']);
+  ConvertProgram;
+  CheckSource('TestClass_NestedProcSelf2',
+    LinesToStr([ // statements
+    'rtl.createClass($mod, "TObject", null, function () {',
+    '  this.State = 0;',
+    '  this.$init = function () {',
+    '    this.Key = 0;',
+    '  };',
+    '  this.$final = function () {',
+    '  };',
+    '});',
+    'rtl.createClass($mod, "TBird", $mod.TObject, function () {',
+    '  this.DoIt = function () {',
+    '    var Self = this;',
+    '    function Sub() {',
+    '      Self.Key = Self.Key + 2;',
+    '      Self.Key = Self.Key + 3;',
+    '      Self.$class.State = Self.State + 4;',
+    '      Self.$class.State = Self.State + 5;',
+    '      $mod.TObject.State = $mod.TObject.State + 6;',
+    '      Self.SetSize(Self.GetSize() + 7);',
+    '      Self.SetSize(Self.GetSize() + 8);',
+    '    };',
+    '    Sub();',
+    '    this.Key = this.Key + 12;',
+    '    Self.Key = Self.Key + 13;',
+    '    this.$class.State = this.State + 14;',
+    '    Self.$class.State = Self.State + 15;',
+    '    $mod.TObject.State = $mod.TObject.State + 16;',
+    '    this.SetSize(this.GetSize() + 17);',
+    '    Self.SetSize(Self.GetSize() + 18);',
+    '  };',
+    '});',
+    '']),
+    LinesToStr([ // $mod.$main
+    '']));
+end;
+
 procedure TTestModule.TestClass_NestedProcClassSelf;
 begin
   StartProgram(false);

+ 12 - 1
utils/pas2js/docs/translation.html

@@ -146,6 +146,7 @@ Put + after a boolean switch option to enable it, - to disable it
      -Jmsourceroot=&lt;x&gt; : use x as "sourceRoot", prefix URL for source file names.
      -Jmbasedir=&lt;x&gt; : write source file names relative to directory x.
      -Jminclude : include Pascal sources in source map.
+     -Jmxssiheader : start source map with XSSI protection )]}.
      -Jm- : disable generating source maps
    -Ju&lt;x&gt; : Add &lt;x&gt; to foreign unit paths. Foreign units are not compiled.
    -Je&lt;x&gt; : Encode messages as &lt;x&gt;.
@@ -1854,7 +1855,12 @@ rtl = {
     <h2 id="assert">Translating assert()</h2>
     The Assert(boolean[,string]) function is translated to <i>if(bool) throw x</i>.
     If unit sysutils is used, it creates an EAssertFailed exception.<br>
-    Otherwise it throws a string.
+    Otherwise it throws a string.<br>
+    <ul>
+    <li>Command line enable with -Sa, disable with -Sa-</li>
+    <li>In code enable with <i>{$C+}</i> or <i>{$Assertions on}</i>,
+      disable with <i>{$C-}</i> or <i>{$Assertions off}</i></li>
+    </ul>
     </div>
 
     <div class="section">
@@ -2674,6 +2680,11 @@ End.
     <i>-Jminclude</i>.<br>
     <br>
     To show the generated mapping for each line you can use the tool fpc/packages/fcl-js/examples/srcmapdump.<br>
+    <li>The sourcemap starts with the line <i>)]}</i> to avoid potential XSSI
+    (cross site script inclusion) issues. This is recommended in the specifications
+    and the browser should ignore it. See here
+    https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit#heading=h.h7yy76c5il9v
+    </li>
     </div>
 
     <div id="footer">