diff --git a/packages/pastojs/src/pas2jscompiler.pp b/packages/pastojs/src/pas2jscompiler.pp index 34133bd4ab..218eb6eeab 100644 --- a/packages/pastojs/src/pas2jscompiler.pp +++ b/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 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= : use x as "sourceRoot", prefix URL for source file names.'); l(' -Jmbasedir= : 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 : Enable or disable extra option. The x is case insensitive:'); + l(' -JoSearchLikeFPC : search source files like FPC, default: search case insensitive.'); l(' -Ju : Add 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]); diff --git a/packages/pastojs/src/pas2jsfilecache.pp b/packages/pastojs/src/pas2jsfilecache.pp index 76945990fa..b79a41d8c4 100644 --- a/packages/pastojs/src/pas2jsfilecache.pp +++ b/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; diff --git a/packages/pastojs/tests/tcmodules.pas b/packages/pastojs/tests/tcmodules.pas index 624a223ade..a320e9b159 100644 --- a/packages/pastojs/tests/tcmodules.pas +++ b/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); diff --git a/utils/pas2js/docs/translation.html b/utils/pas2js/docs/translation.html index dec507ebcf..3b0b0dc114 100644 --- a/utils/pas2js/docs/translation.html +++ b/utils/pas2js/docs/translation.html @@ -146,6 +146,7 @@ Put + after a boolean switch option to enable it, - to disable it -Jmsourceroot=<x> : use x as "sourceRoot", prefix URL for source file names. -Jmbasedir=<x> : 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<x> : Add <x> to foreign unit paths. Foreign units are not compiled. -Je<x> : Encode messages as <x>. @@ -1854,7 +1855,12 @@ rtl = {

Translating assert()

The Assert(boolean[,string]) function is translated to if(bool) throw x. If unit sysutils is used, it creates an EAssertFailed exception.
- Otherwise it throws a string. + Otherwise it throws a string.
+
    +
  • Command line enable with -Sa, disable with -Sa-
  • +
  • In code enable with {$C+} or {$Assertions on}, + disable with {$C-} or {$Assertions off}
  • +
@@ -2674,6 +2680,11 @@ End. -Jminclude.

To show the generated mapping for each line you can use the tool fpc/packages/fcl-js/examples/srcmapdump.
+
  • The sourcemap starts with the line )]} 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 +