mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-16 04:39:38 +02:00
* Added jsminifier unit
git-svn-id: trunk@34652 -
This commit is contained in:
parent
3a3f490234
commit
95eb4ed2eb
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -2481,8 +2481,10 @@ packages/fcl-js/Makefile svneol=native#text/plain
|
||||
packages/fcl-js/Makefile.fpc svneol=native#text/plain
|
||||
packages/fcl-js/Makefile.fpc.fpcmake svneol=native#text/plain
|
||||
packages/fcl-js/README.TXT svneol=native#text/plain
|
||||
packages/fcl-js/examples/fpjsmin.pp svneol=native#text/plain
|
||||
packages/fcl-js/fpmake.pp svneol=native#text/plain
|
||||
packages/fcl-js/src/jsbase.pp svneol=native#text/plain
|
||||
packages/fcl-js/src/jsminifier.pp svneol=native#text/plain
|
||||
packages/fcl-js/src/jsparser.pp svneol=native#text/plain
|
||||
packages/fcl-js/src/jsscanner.pp svneol=native#text/plain
|
||||
packages/fcl-js/src/jstoken.pp svneol=native#text/plain
|
||||
|
21
packages/fcl-js/examples/fpjsmin.pp
Normal file
21
packages/fcl-js/examples/fpjsmin.pp
Normal file
@ -0,0 +1,21 @@
|
||||
{$mode objfpc}{$h+}
|
||||
{$inline on}
|
||||
program fpjsmin;
|
||||
|
||||
uses jsminifier;
|
||||
|
||||
|
||||
begin
|
||||
if ParamCount<>2 then
|
||||
begin
|
||||
Writeln('Usage: fpjsmin infile outfile');
|
||||
halt(1);
|
||||
end;
|
||||
With TJSONMinifier.Create(Nil) do
|
||||
try
|
||||
FileHeader.Add(paramstr(1));
|
||||
Execute(ParamStr(1),ParamStr(2));
|
||||
finally
|
||||
Free
|
||||
end;
|
||||
end.
|
@ -37,6 +37,8 @@ begin
|
||||
T.ResourceStrings:=true;
|
||||
T:=P.Targets.AddUnit('jswriter.pp');
|
||||
T.ResourceStrings:=true;
|
||||
T:=P.Targets.AddUnit('jsminifier.pp');
|
||||
T.ResourceStrings:=true;
|
||||
{$ifndef ALLPACKAGES}
|
||||
Run;
|
||||
end;
|
||||
|
440
packages/fcl-js/src/jsminifier.pp
Normal file
440
packages/fcl-js/src/jsminifier.pp
Normal file
@ -0,0 +1,440 @@
|
||||
{ *********************************************************************
|
||||
This file is part of the Free Component Library (FCL)
|
||||
Copyright (c) 2016 Michael Van Canneyt.
|
||||
|
||||
Javascript minifier
|
||||
|
||||
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.
|
||||
|
||||
**********************************************************************}
|
||||
{ ---------------------------------------------------------------------
|
||||
Javascript minifier, based on an implementation by Douglas Crockford,
|
||||
see original copyright.
|
||||
---------------------------------------------------------------------}
|
||||
{ jsmin.c
|
||||
2013-03-29
|
||||
|
||||
Copyright (c) 2002 Douglas Crockford (www.crockford.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
}
|
||||
|
||||
unit jsminifier;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
{$inline on}
|
||||
|
||||
interface
|
||||
|
||||
uses sysutils,classes,bufstream;
|
||||
|
||||
|
||||
Const
|
||||
EOS = #0;
|
||||
|
||||
Type
|
||||
|
||||
{ TJSONMinifier }
|
||||
EJSONMinifier = Class(Exception);
|
||||
|
||||
TJSONMinifier = Class(TComponent)
|
||||
Private
|
||||
FA : char;
|
||||
FB : char;
|
||||
FFileHeader: TStrings;
|
||||
FLookahead : char;
|
||||
FX : char;
|
||||
FY : char ;
|
||||
Fin : TStream;
|
||||
Fout : TStream;
|
||||
procedure SetFileHeader(AValue: TStrings);
|
||||
Protected
|
||||
// Token reading routines
|
||||
function Peek : char;
|
||||
function Get : char;inline;
|
||||
function Next : char;
|
||||
// Token writing routines
|
||||
procedure Putc(c: char);inline;
|
||||
Procedure Reset;
|
||||
procedure DoHeader; virtual;
|
||||
procedure Error(Const Msg: string);
|
||||
Class Function isAlphaNum(c: char): boolean;
|
||||
Class Function iif(B : Boolean; Const ifTrue,ifFalse : integer) : integer; inline;
|
||||
procedure Action(d: Byte);
|
||||
procedure Minify;
|
||||
Public
|
||||
Constructor Create(AOwner : TComponent); override;
|
||||
Destructor Destroy; override;
|
||||
Procedure Execute(Const SourceFilename,DestFilename : String);
|
||||
Procedure Execute(Source,Dest : TStream);
|
||||
Procedure Execute(SourceFilenames : TStrings; Const DestFilename : String);
|
||||
Procedure Execute(SourceFileNames : Array of string; Const DestFilename : String);
|
||||
Published
|
||||
Property FileHeader : TStrings Read FFileHeader Write SetFileHeader;
|
||||
end;
|
||||
|
||||
Implementation
|
||||
|
||||
Resourcestring
|
||||
SErrUnterminatedComment = 'Unterminated comment.';
|
||||
SErrUnterminatedStringLiteral = 'Unterminated string literal.';
|
||||
SErrUnterminatedSetInRegexp = 'Unterminated set in Regular Expression literal.';
|
||||
SerrUnterminatedRegexp = 'Unterminated Regular Expression literal.';
|
||||
|
||||
class function TJSONMinifier.iif(B: Boolean; const ifTrue, ifFalse: integer
|
||||
): integer;
|
||||
|
||||
begin
|
||||
if B then
|
||||
Result:=ifTrue
|
||||
else
|
||||
Result:=ifFalse;
|
||||
end;
|
||||
|
||||
procedure TJSONMinifier.Error(const Msg: string);
|
||||
|
||||
begin
|
||||
Raise EJSONMinifier.Create('JSMIN Error: '+Msg);
|
||||
end;
|
||||
|
||||
procedure TJSONMinifier.SetFileHeader(AValue: TStrings);
|
||||
begin
|
||||
if FFileHeader=AValue then Exit;
|
||||
FFileHeader.Assign(AValue);
|
||||
end;
|
||||
|
||||
procedure TJSONMinifier.Reset;
|
||||
|
||||
begin
|
||||
FA:=EOS;
|
||||
FB:=EOS;
|
||||
FLookahead:=EOS;
|
||||
FX:=EOS;
|
||||
FY:=EOS;
|
||||
end;
|
||||
|
||||
class function TJSONMinifier.isAlphaNum(c: char): boolean;
|
||||
|
||||
begin
|
||||
Result:= (C in ['a'..'z']) or (c in ['0'..'9']) or (c in ['A'..'Z']) or (C in ['_','$','\']) or (c > #126);
|
||||
end;
|
||||
|
||||
|
||||
function TJSONMinifier.Get: char;
|
||||
|
||||
begin
|
||||
Result:=FLookahead;
|
||||
FLookahead:=EOS;
|
||||
if (Result=EOS) then
|
||||
if Fin.Read(Result,sizeof(Result))=0 then exit;
|
||||
if (Result>' ') or (Result in [#10,EOS]) then
|
||||
Exit;
|
||||
if (Result=#13) then
|
||||
Result:=#10
|
||||
else
|
||||
Result:=' ';
|
||||
end;
|
||||
|
||||
|
||||
function TJSONMinifier.Peek: char;
|
||||
begin
|
||||
FLookahead := get();
|
||||
result:=FLookahead;
|
||||
end;
|
||||
|
||||
function TJSONMinifier.Next: char;
|
||||
|
||||
var
|
||||
c : char;
|
||||
|
||||
begin
|
||||
c:= get();
|
||||
if (c='/') then
|
||||
case peek of
|
||||
'/': Repeat
|
||||
c := get();
|
||||
until (c <= #10);
|
||||
'*':
|
||||
begin
|
||||
Get();
|
||||
while (c <> ' ') do
|
||||
case get of
|
||||
'*':
|
||||
begin
|
||||
if (peek()= '/') then
|
||||
begin
|
||||
get();
|
||||
c:=' ';
|
||||
end;
|
||||
end;
|
||||
EOS:
|
||||
Error(SErrUnterminatedComment);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
FY:=FX;
|
||||
FX:=c;
|
||||
Result:=c;
|
||||
end;
|
||||
|
||||
procedure TJSONMinifier.Putc(c: char);
|
||||
|
||||
begin
|
||||
Fout.writebuffer(c,sizeof(c));
|
||||
end;
|
||||
|
||||
procedure TJSONMinifier.Action(d : Byte);
|
||||
|
||||
Procedure Do1;
|
||||
|
||||
begin
|
||||
putc(FA);
|
||||
if ((FY in [#10,' '])
|
||||
and (FA in ['+','-','*','/'])
|
||||
and (FB in ['+','-','*','/'])) then
|
||||
putc(FY);
|
||||
end;
|
||||
|
||||
Procedure Do2;
|
||||
|
||||
begin
|
||||
FA:=FB;
|
||||
if (FA in ['''','"','`']) then
|
||||
While true do
|
||||
begin
|
||||
putc(FA);
|
||||
FA:= get();
|
||||
if (FA=FB) then
|
||||
break;
|
||||
if (FA='\') then
|
||||
begin
|
||||
putc(FA);
|
||||
FA:=get();
|
||||
end;
|
||||
if (FA=EOS) then
|
||||
Error(SErrUnterminatedStringLiteral);
|
||||
end;
|
||||
end;
|
||||
|
||||
begin
|
||||
if (D=1) then
|
||||
Do1;
|
||||
if (D in [1,2]) then
|
||||
Do2;
|
||||
FB := next();
|
||||
if (FB='/') and (FA in ['(',',','=',':','[','!','&','|','?','+','-','~','*','/','{',#10]) then
|
||||
begin
|
||||
putc(FA);
|
||||
if (FA in ['/','*']) then
|
||||
putc(' ');
|
||||
putc(FB);
|
||||
While true do
|
||||
begin
|
||||
FA := get();
|
||||
if (FA='[') then
|
||||
begin
|
||||
While true do
|
||||
begin
|
||||
putc(FA);
|
||||
FA := get();
|
||||
if (FA = ']') then
|
||||
break;
|
||||
if (FA = '\') then
|
||||
begin
|
||||
putc(FA);
|
||||
FA := get();
|
||||
end;
|
||||
if (FA = EOS) then
|
||||
Error(SErrUnterminatedSetInRegexp);
|
||||
end
|
||||
end
|
||||
else if (FA = '/') then
|
||||
begin
|
||||
case (peek()) of
|
||||
'/', '*':
|
||||
Error(SErrUnterminatedSetInRegexp);
|
||||
end;
|
||||
Break;
|
||||
end
|
||||
else if (FA ='\') then
|
||||
begin
|
||||
putc(FA);
|
||||
FA := get();
|
||||
end;
|
||||
if (FA = EOS) then
|
||||
Error(SErrUnterminatedRegexp);
|
||||
putc(FA);
|
||||
end;
|
||||
FB := next();
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure TJSONMinifier.Minify;
|
||||
|
||||
begin
|
||||
if (peek()= #$EF) then
|
||||
begin
|
||||
get();
|
||||
get();
|
||||
get();
|
||||
end;
|
||||
FA:=#10;
|
||||
action(3);
|
||||
while (FA <> EOS) do
|
||||
begin
|
||||
case (FA) of
|
||||
' ':
|
||||
action(iif(isAlphanum(FB),1,2));
|
||||
#10:
|
||||
case (FB) of
|
||||
'{', '[', '(', '+', '-', '!', '~':
|
||||
Action(1);
|
||||
' ':
|
||||
Action(3);
|
||||
else
|
||||
Action(iif(isAlphanum(FB), 1 , 2));
|
||||
end;
|
||||
else
|
||||
case (FB) of
|
||||
' ':
|
||||
Action(iif(isAlphanum(FA),1,3));
|
||||
#10:
|
||||
case (FA) of
|
||||
'}',']',')','+','-','"', '''', '`':
|
||||
Action(1);
|
||||
else
|
||||
Action(iif(isAlphanum(FA), 1, 3));
|
||||
end;
|
||||
else
|
||||
Action(1);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
constructor TJSONMinifier.Create(AOwner: TComponent);
|
||||
begin
|
||||
inherited Create(AOwner);
|
||||
FFileHeader:=TStringList.Create;
|
||||
end;
|
||||
|
||||
destructor TJSONMinifier.Destroy;
|
||||
begin
|
||||
FreeAndNil(FFileHeader);
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TJSONMinifier.Execute(const SourceFilename, DestFilename: String);
|
||||
|
||||
Var
|
||||
Src,Dest : TBufStream;
|
||||
|
||||
begin
|
||||
Dest:=Nil;
|
||||
Src:=TReadBufStream.Create(TFileStream.Create(SourceFileName,fmOpenRead or fmShareDenyWrite),1000);
|
||||
try
|
||||
Src.SourceOwner:=True;
|
||||
Dest:=TWriteBufStream.Create(TFileStream.create(DestFileName,fmCreate),1000);
|
||||
Dest.SourceOwner:=True;
|
||||
Execute(Src,Dest);
|
||||
finally
|
||||
Src.Free;
|
||||
Dest.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TJSONMinifier.DoHeader;
|
||||
|
||||
Var
|
||||
S,L : String;
|
||||
|
||||
begin
|
||||
For S in FFileHeader do
|
||||
begin
|
||||
L:='// '+S+sLineBreak;
|
||||
Fout.WriteBuffer(L[1],Length(L));
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TJSONMinifier.Execute(Source, Dest: TStream);
|
||||
|
||||
begin
|
||||
Fin:=Source;
|
||||
Fout:=Dest;
|
||||
try
|
||||
Reset;
|
||||
DoHeader;
|
||||
Minify;
|
||||
finally
|
||||
Fin:=Nil;
|
||||
Fout:=Nil;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TJSONMinifier.Execute(SourceFilenames: TStrings;const DestFilename: String);
|
||||
|
||||
Var
|
||||
Src,Dest : TBufStream;
|
||||
I : Integer;
|
||||
|
||||
begin
|
||||
Dest:=Src;
|
||||
Dest:=TWriteBufStream.Create(TFileStream.create(DestFileName,fmCreate),1000);
|
||||
try
|
||||
Dest.SourceOwner:=True;
|
||||
for I:=0 to SourceFileNames.Count-1 do
|
||||
begin
|
||||
Src:=TReadBufStream.Create(TFileStream.Create(SourceFileNames[i],fmOpenRead or fmShareDenyWrite),1000);
|
||||
Src.SourceOwner:=True;
|
||||
Execute(Src,Dest);
|
||||
FreeAndNil(Src);
|
||||
end;
|
||||
finally
|
||||
FreeAndNil(Src);
|
||||
FreeAndNil(Dest);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TJSONMinifier.Execute(SourceFileNames: array of string;
|
||||
const DestFilename: String);
|
||||
|
||||
Var
|
||||
S : TStrings;
|
||||
|
||||
begin
|
||||
S:=TStringList.Create;
|
||||
try
|
||||
S.AddStrings(SourceFileNames);
|
||||
Execute(S,DestFileName);
|
||||
finally
|
||||
S.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
end.
|
||||
|
Loading…
Reference in New Issue
Block a user