コード例 #1
1
        private bool m_useStrict; //= false;

        #endregion Fields

        #region Constructors

        protected JsActivationObject(JsActivationObject parent, JsSettings codeSettings)
        {
            m_isKnownAtCompileTime = true;
            m_useStrict = false;
            m_settings = codeSettings;

            Parent = parent;
            NameTable = new Dictionary<string, JsVariableField>();
            ChildScopes = new List<JsActivationObject>();

            // if our parent is a scope....
            if (parent != null)
            {
                // add us to the parent's list of child scopes
                parent.ChildScopes.Add(this);

                // if the parent is strict, so are we
                UseStrict = parent.UseStrict;
            }

            // create the two lists of declared items for this scope
            ScopeLookups = new HashSet<JsLookup>();
            VarDeclaredNames = new HashSet<IJsNameDeclaration>();
            LexicallyDeclaredNames = new HashSet<IJsNameDeclaration>();

            GhostedCatchParameters = new HashSet<JsParameterDeclaration>();
            GhostedFunctions = new HashSet<JsFunctionObject>();
        }
コード例 #2
0
        protected JsActivationObject(JsActivationObject parent, JsSettings codeSettings)
        {
            m_isKnownAtCompileTime = true;
            m_useStrict            = false;
            m_settings             = codeSettings;

            Parent      = parent;
            NameTable   = new Dictionary <string, JsVariableField>();
            ChildScopes = new List <JsActivationObject>();

            // if our parent is a scope....
            if (parent != null)
            {
                // add us to the parent's list of child scopes
                parent.ChildScopes.Add(this);

                // if the parent is strict, so are we
                UseStrict = parent.UseStrict;
            }

            // create the two lists of declared items for this scope
            ScopeLookups           = new HashSet <JsLookup>();
            VarDeclaredNames       = new HashSet <IJsNameDeclaration>();
            LexicallyDeclaredNames = new HashSet <IJsNameDeclaration>();

            GhostedCatchParameters = new HashSet <JsParameterDeclaration>();
            GhostedFunctions       = new HashSet <JsFunctionObject>();
        }
コード例 #3
0
        internal void SetAssumedGlobals(JsSettings settings)
        {
            if (settings != null)
            {
                // start off with any known globals
                m_assumedGlobals = settings.KnownGlobalCollection == null ? new HashSet <string>() : new HashSet <string>(settings.KnownGlobalCollection);

                // chek to see if there are any debug lookups
                foreach (var debugLookup in settings.DebugLookupCollection)
                {
                    m_assumedGlobals.Add(debugLookup.SubstringUpToFirst('.'));
                }

                // and the root name of any resource strings is also an assumed global
                foreach (var resourceStrings in settings.ResourceStrings)
                {
                    if (!resourceStrings.Name.IsNullOrWhiteSpace())
                    {
                        m_assumedGlobals.Add(resourceStrings.Name.SubstringUpToFirst('.'));
                    }
                }
            }
            else
            {
                // empty set
                m_assumedGlobals = new HashSet <string>();
            }
        }
コード例 #4
0
        private static void ResolveLookups(JsActivationObject scope, JsSettings settings)
        {
            // resolve each lookup this scope contains
            foreach (var lookup in scope.ScopeLookups)
            {
                ResolveLookup(scope, lookup, settings);
            }

            // and recurse
            foreach (var childScope in scope.ChildScopes)
            {
                ResolveLookups(childScope, settings);
            }

            // mark any variables defined in this scope that don't have any references
            // so we can throw warnings later. We can't rely on the reference count because
            // we might remove references while optimizing code -- if we throw an error when
            // the count gets to zero, then we would be reporting errors that don't exist.
            // but we DO know right now what isn't referenced at all.
            foreach (var field in scope.NameTable.Values)
            {
                if (field.RefCount == 0)
                {
                    field.HasNoReferences = true;
                }
            }
        }
コード例 #5
0
        public MinifierParser()
        {
            // initialize with default values
            JSSettings = new JsSettings();
            CssSettings = new CssSettings();

            // see if this is running under the Mono runtime (on UNIX)
            m_isMono = Type.GetType("Mono.Runtime") != null;
        }
コード例 #6
0
        public JsBlockScope(JsActivationObject parent, JsContext context, JsSettings settings)
            : base(parent, settings)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            m_context = context.Clone();
        }
コード例 #7
0
        private JsResolutionVisitor(JsActivationObject rootScope, JsSettings settings)
        {
            // create the lexical and variable scope stacks and push the root scope onto them
            m_lexicalStack = new Stack <JsActivationObject>();
            m_lexicalStack.Push(rootScope);

            m_variableStack = new Stack <JsActivationObject>();
            m_variableStack.Push(rootScope);

            m_settings = settings;
        }
コード例 #8
0
        /// <summary>
        /// Instantiate a new CodeSettings object with the same settings as the current object.
        /// </summary>
        /// <returns>a copy CodeSettings object</returns>
        public JsSettings Clone()
        {
            // create a new settings object and set all the properties using this settings object
            var newSettings = new JsSettings()
            {
                // set the field, not the property. Setting the property will set a bunch of
                // other properties, which may not represent their actual values.
                m_minify = this.m_minify,

                AllowEmbeddedAspNetBlocks = this.AllowEmbeddedAspNetBlocks,
                AlwaysEscapeNonAscii      = this.AlwaysEscapeNonAscii,
                CollapseToLiteral         = this.CollapseToLiteral,
                ConstStatementsMozilla    = this.ConstStatementsMozilla,
                DebugLookupList           = this.DebugLookupList,
                EvalLiteralExpressions    = this.EvalLiteralExpressions,
                EvalTreatment             = this.EvalTreatment,
                Format = this.Format,
                IgnoreConditionalCompilation = this.IgnoreConditionalCompilation,
                IgnoreAllErrors           = this.IgnoreAllErrors,
                IgnoreErrorList           = this.IgnoreErrorList,
                IgnorePreprocessorDefines = this.IgnorePreprocessorDefines,
                IndentSize                    = this.IndentSize,
                InlineSafeStrings             = this.InlineSafeStrings,
                KillSwitch                    = this.KillSwitch,
                KnownGlobalNamesList          = this.KnownGlobalNamesList,
                LineBreakThreshold            = this.LineBreakThreshold,
                LocalRenaming                 = this.LocalRenaming,
                MacSafariQuirks               = this.MacSafariQuirks,
                ManualRenamesProperties       = this.ManualRenamesProperties,
                NoAutoRenameList              = this.NoAutoRenameList,
                OutputMode                    = this.OutputMode,
                PreprocessOnly                = this.PreprocessOnly,
                PreprocessorDefineList        = this.PreprocessorDefineList,
                PreserveFunctionNames         = this.PreserveFunctionNames,
                PreserveImportantComments     = this.PreserveImportantComments,
                QuoteObjectLiteralProperties  = this.QuoteObjectLiteralProperties,
                RemoveFunctionExpressionNames = this.RemoveFunctionExpressionNames,
                RemoveUnneededCode            = this.RemoveUnneededCode,
                RenamePairs                   = this.RenamePairs,
                ReorderScopeDeclarations      = this.ReorderScopeDeclarations,
                SourceMode                    = this.SourceMode,
                StrictMode                    = this.StrictMode,
                StripDebugStatements          = this.StripDebugStatements,
                TermSemicolons                = this.TermSemicolons,
                BlocksStartOnSameLine         = this.BlocksStartOnSameLine,
                ErrorIfNotInlineSafe          = this.ErrorIfNotInlineSafe,
                SymbolsMap                    = this.SymbolsMap,
            };

            // set the resource strings if there are any
            newSettings.AddResourceStrings(this.ResourceStrings);

            return(newSettings);
        }
コード例 #9
0
        private JsResolutionVisitor(JsActivationObject rootScope, JsSettings settings)
        {
            // create the lexical and variable scope stacks and push the root scope onto them
            m_lexicalStack = new Stack<JsActivationObject>();
            m_lexicalStack.Push(rootScope);

            m_variableStack = new Stack<JsActivationObject>();
            m_variableStack.Push(rootScope);

            m_settings = settings;
        }
コード例 #10
0
        public static void Apply(TextWriter writer, JsAstNode node, JsSettings settings)
        {
            if (node != null)
            {
                var outputVisitor = new JsOutputVisitor(writer, settings);
                node.Accept(outputVisitor);

                // if there is a symbol map that we are tracking, tell it that we have ended an output run
                // and pass it offsets to the last line and column positions.
                settings.IfNotNull(s => s.SymbolsMap.IfNotNull(m => m.EndOutputRun(outputVisitor.m_lineCount, outputVisitor.m_lineLength)));
            }
        }
コード例 #11
0
        internal JsFunctionScope(JsActivationObject parent, bool isExpression, JsSettings settings, JsFunctionObject funcObj)
            : base(parent, settings)
        {
            m_refScopes = new HashSet <JsActivationObject>();
            if (isExpression)
            {
                // parent scopes automatically reference enclosed function expressions
                AddReference(Parent);
            }

            FunctionObject = funcObj;
        }
コード例 #12
0
        internal JsFunctionScope(JsActivationObject parent, bool isExpression, JsSettings settings, JsFunctionObject funcObj)
            : base(parent, settings)
        {
            m_refScopes = new HashSet<JsActivationObject>();
            if (isExpression)
            {
                // parent scopes automatically reference enclosed function expressions
                AddReference(Parent);
            }

            FunctionObject = funcObj;
        }
コード例 #13
0
        internal JsGlobalScope(JsSettings settings)
            : base(null, settings)
        {
            // define the Global object's properties, and methods
            m_globalProperties = new HashSet <string>(new[] {
                "Infinity", "NaN", "undefined", "window", "Image", "JSON", "Map", "Math", "Set", "WeakMap", "XMLHttpRequest", "DOMParser",
                "applicationCache", "clientInformation", "clipboardData", "closed", "console", "document", "event", "external", "frameElement", "frames", "history", "length", "localStorage", "location", "name", "navigator", "opener", "parent", "screen", "self", "sessionStorage", "status", "top"
            });

            m_globalFunctions = new HashSet <string>(new[] {
                "decodeURI", "decodeURIComponent", "encodeURI", "encodeURIComponent", "escape", "eval", "importScripts", "isNaN", "isFinite", "parseFloat", "parseInt", "unescape", "ActiveXObject", "Array", "Boolean", "Date", "Error", "EvalError", "EventSource", "File", "FileList", "FileReader", "Function", "GeckoActiveXObject", "HTMLElement", "Number", "Object", "Proxy", "RangeError", "ReferenceError", "RegExp", "SharedWorker", "String", "SyntaxError", "TypeError", "URIError", "WebSocket", "Worker",
                "addEventListener", "alert", "attachEvent", "blur", "clearInterval", "clearTimeout", "close", "confirm", "createPopup", "detachEvent", "dispatchEvent", "execScript", "focus", "getComputedStyle", "getSelection", "moveBy", "moveTo", "navigate", "open", "postMessage", "prompt", "removeEventListener", "resizeBy", "resizeTo", "scroll", "scrollBy", "scrollTo", "setActive", "setInterval", "setTimeout", "showModalDialog", "showModelessDialog"
            });
        }
コード例 #14
0
        /// <summary>
        /// Minifies the CSS stylesheet passes to it using the given settings, returning the minified results
        /// The ErrorList property will be set with any errors found during the minification process.
        /// </summary>
        /// <param name="source">CSS Source</param>
        /// <param name="settings">CSS minification settings</param>
        /// <param name="scriptSettings">JS minification settings to use for expression-minification</param>
        /// <returns>Minified StyleSheet</returns>
        public string MinifyStyleSheet(string source, CssSettings settings, JsSettings scriptSettings)
        {
            // initialize some values, including the error list (which shoudl start off empty)
            string minifiedResults = string.Empty;

            m_errorList = new List <MinifierError>();

            // create the parser object and if we specified some settings,
            // use it to set the Parser's settings object
            CssParser parser = new CssParser();

            parser.FileContext = FileName;

            if (settings != null)
            {
                parser.Settings = settings;
            }

            if (scriptSettings != null)
            {
                parser.JSSettings = scriptSettings;
            }

            // hook the error handler
            parser.CssError += new EventHandler <CssErrorEventArgs>(OnCssError);

            // try parsing the source and return the results
            try
            {
                minifiedResults = parser.Parse(source);
            }
            catch (Exception e)
            {
                m_errorList.Add(new MinifierError(
                                    true,
                                    0,
                                    null,
                                    null,
                                    null,
                                    this.FileName,
                                    0,
                                    0,
                                    0,
                                    0,
                                    e.Message));
                throw;
            }
            return(minifiedResults);
        }
コード例 #15
0
        public static void Apply(JsAstNode node, JsActivationObject scope, JsSettings settings)
        {
            if (node != null && scope != null)
            {
                // create the visitor and run it. This will create all the child
                // scopes and populate all the scopes with the var-decl, lex-decl,
                // and lookup references within them.
                var visitor = new JsResolutionVisitor(scope, settings);
                node.Accept(visitor);

                // now that all the scopes are created and they all know what decls
                // they contains, create all the fields
                CreateFields(scope);

                // now that all the fields have been created in all the scopes,
                // let's go through and resolve all the references
                ResolveLookups(scope, settings);

                // now that everything is declared and resolved as per the language specs,
                // we need to go back and add ghosted fields for older versions of IE that
                // incorrectly implement catch-variables and named function expressions.
                AddGhostedFields(scope);
            }
        }
コード例 #16
0
 public JsWithScope(JsActivationObject parent, JsContext context, JsSettings settings)
     : base(parent, context, settings)
 {
     IsInWithScope = true;
 }
コード例 #17
0
        private void InitializeScanner(JsSettings settings)
        {
            // save the settings
            // if we are passed null, just create a default settings object
            m_settings = settings = settings ?? new JsSettings();

            // if the settings list is not null, use it to initialize a new list
            // with the same settings. If it is null, initialize an empty list
            // because we already determined that we want to strip debug statements,
            // and the scanner might add items to the list as it scans the source.
            DebugLookups = new HashSet<string>(m_settings.DebugLookupCollection);

            // pass our list to the scanner -- it might add more as we encounter special comments
            m_scanner.DebugLookupCollection = DebugLookups;

            m_scanner.AllowEmbeddedAspNetBlocks = m_settings.AllowEmbeddedAspNetBlocks;
            m_scanner.IgnoreConditionalCompilation = m_settings.IgnoreConditionalCompilation;

            // set any defines
            m_scanner.UsePreprocessorDefines = !m_settings.IgnorePreprocessorDefines;
            if (m_scanner.UsePreprocessorDefines)
            {
                m_scanner.SetPreprocessorDefines(m_settings.PreprocessorValues);
            }

            // if we want to strip debug statements, let's also strip ///#DEBUG comment
            // blocks for legacy reasons. ///#DEBUG will get stripped ONLY is this
            // flag is true AND the name "DEBUG" is not in the preprocessor defines.
            // Alternately, we will keep those blocks in the output is this flag is
            // set to false OR we define "DEBUG" in the preprocessor defines.
            m_scanner.StripDebugCommentBlocks = m_settings.StripDebugStatements;
        }
コード例 #18
0
        public void PreprocessOnly(JsSettings settings, TextWriter outputStream)
        {
            if (outputStream != null)
            {
                EchoWriter = outputStream;
                Parse(settings);
                EchoWriter = null;

                if (m_settings.TermSemicolons)
                {
                    // if we want to make sure this file has a terminating semicolon, start a new line
                    // (to make sure any single-line comments are terminated) and output a semicolon
                    // followed by another line break.
                    outputStream.WriteLine();
                    outputStream.WriteLine(';');
                }
            }
        }
コード例 #19
0
        public string PreprocessOnly(JsSettings settings)
        {
            // create an empty string builder
            using (var outputStream = new StringWriter(CultureInfo.InvariantCulture))
            {
                // output to the string builder
                PreprocessOnly(settings, outputStream);

                // return the resulting text
                return outputStream.ToString();
            }
        }
コード例 #20
0
 private JsOutputVisitor(TextWriter writer, JsSettings settings)
 {
     m_outputStream = writer;
     m_settings = settings ?? new JsSettings();
     m_onNewLine = true;
 }
コード例 #21
0
 internal JsCatchScope(JsActivationObject parent, JsContext catchContext, JsSettings settings, JsParameterDeclaration catchParameter)
     : base(parent, catchContext, settings)
 {
     CatchParameter = catchParameter;
 }
コード例 #22
0
        /// <summary>
        /// Minifies the CSS stylesheet passes to it using the given settings, returning the minified results
        /// The ErrorList property will be set with any errors found during the minification process.
        /// </summary>
        /// <param name="source">CSS Source</param>
        /// <param name="settings">CSS minification settings</param>
        /// <param name="scriptSettings">JS minification settings to use for expression-minification</param>
        /// <returns>Minified StyleSheet</returns>
        public string MinifyStyleSheet(string source, CssSettings settings, JsSettings scriptSettings)
        {
            // initialize some values, including the error list (which shoudl start off empty)
            string minifiedResults = string.Empty;
            m_errorList = new List<MinifierError>();

            // create the parser object and if we specified some settings,
            // use it to set the Parser's settings object
            CssParser parser = new CssParser();
            parser.FileContext = FileName;

            if (settings != null)
            {
                parser.Settings = settings;
            }

            if (scriptSettings != null)
            {
                parser.JSSettings = scriptSettings;
            }

            // hook the error handler
            parser.CssError += new EventHandler<CssErrorEventArgs>(OnCssError);

            // try parsing the source and return the results
            try
            {
                minifiedResults = parser.Parse(source);
            }
            catch (Exception e)
            {
                m_errorList.Add(new MinifierError(
                    true,
                    0,
                    null,
                    null,
                    null,
                    this.FileName,
                    0,
                    0,
                    0,
                    0,
                    e.Message));
                throw;
            }
            return minifiedResults;
        }
コード例 #23
0
 public JsWithScope(JsActivationObject parent, JsContext context, JsSettings settings)
     : base(parent, context, settings)
 {
     IsInWithScope = true;
 }
コード例 #24
0
 public MinifierParser(JsSettings scriptSettings, CssSettings cssSettings)
 {
     // apply the switches to these two settings objects
     JSSettings = scriptSettings ?? new JsSettings();
     CssSettings = cssSettings ?? new CssSettings();
 }
コード例 #25
0
        /// <summary>
        /// Instantiate a new CodeSettings object with the same settings as the current object.
        /// </summary>
        /// <returns>a copy CodeSettings object</returns>
        public JsSettings Clone()
        {
            // create a new settings object and set all the properties using this settings object
            var newSettings = new JsSettings()
            {
                // set the field, not the property. Setting the property will set a bunch of
                // other properties, which may not represent their actual values.
                m_minify = this.m_minify,

                AllowEmbeddedAspNetBlocks = this.AllowEmbeddedAspNetBlocks,
                AlwaysEscapeNonAscii = this.AlwaysEscapeNonAscii,
                CollapseToLiteral = this.CollapseToLiteral,
                ConstStatementsMozilla = this.ConstStatementsMozilla,
                DebugLookupList = this.DebugLookupList,
                EvalLiteralExpressions = this.EvalLiteralExpressions,
                EvalTreatment = this.EvalTreatment,
                Format = this.Format,
                IgnoreConditionalCompilation = this.IgnoreConditionalCompilation,
                IgnoreAllErrors = this.IgnoreAllErrors,
                IgnoreErrorList = this.IgnoreErrorList,
                IgnorePreprocessorDefines = this.IgnorePreprocessorDefines,
                IndentSize = this.IndentSize,
                InlineSafeStrings = this.InlineSafeStrings,
                KillSwitch = this.KillSwitch,
                KnownGlobalNamesList = this.KnownGlobalNamesList,
                LineBreakThreshold = this.LineBreakThreshold,
                LocalRenaming = this.LocalRenaming,
                MacSafariQuirks = this.MacSafariQuirks,
                ManualRenamesProperties = this.ManualRenamesProperties,
                NoAutoRenameList = this.NoAutoRenameList,
                OutputMode = this.OutputMode,
                PreprocessOnly = this.PreprocessOnly,
                PreprocessorDefineList = this.PreprocessorDefineList,
                PreserveFunctionNames = this.PreserveFunctionNames,
                PreserveImportantComments = this.PreserveImportantComments,
                QuoteObjectLiteralProperties = this.QuoteObjectLiteralProperties,
                RemoveFunctionExpressionNames = this.RemoveFunctionExpressionNames,
                RemoveUnneededCode = this.RemoveUnneededCode,
                RenamePairs = this.RenamePairs,
                ReorderScopeDeclarations = this.ReorderScopeDeclarations,
                SourceMode = this.SourceMode,
                StrictMode = this.StrictMode,
                StripDebugStatements = this.StripDebugStatements,
                TermSemicolons = this.TermSemicolons,
                BlocksStartOnSameLine = this.BlocksStartOnSameLine,
                ErrorIfNotInlineSafe = this.ErrorIfNotInlineSafe,
                SymbolsMap = this.SymbolsMap,
            };

            // set the resource strings if there are any
            newSettings.AddResourceStrings(this.ResourceStrings);

            return newSettings;
        }
コード例 #26
0
        /// <summary>
        /// Parse the source code using the given settings, getting back an abstract syntax tree Block node as the root
        /// representing the list of statements in the source code.
        /// </summary>
        /// <param name="settings">code settings to use to process the source code</param>
        /// <returns>root Block node representing the top-level statements</returns>
        public JsBlock Parse(JsSettings settings)
        {
            // initialize the scanner with our settings
            // make sure the RawTokens setting is OFF or we won't be able to create our AST
            InitializeScanner(settings);

            // make sure we initialize the global scope's strict mode to our flag, whether or not it
            // is true. This means if the setting is false, we will RESET the flag to false if we are
            // reusing the scope and a previous Parse call had code that set it to strict with a
            // program directive.
            GlobalScope.UseStrict = m_settings.StrictMode;

            // make sure the global scope knows about our known global names
            GlobalScope.SetAssumedGlobals(m_settings);

            // start of a new module
            m_newModule = true;

            var timePoints = m_timingPoints = new long[9];
            var timeIndex = timePoints.Length;
            var stopWatch = new Stopwatch();
            stopWatch.Start();

            JsBlock scriptBlock = null;
            JsBlock returnBlock = null;
            try
            {
                switch (m_settings.SourceMode)
                {
                    case JsSourceMode.Program:
                        // simply parse a block of statements
                        returnBlock = scriptBlock = ParseStatements();
                        break;

                    case JsSourceMode.Expression:
                        // create a block, get the first token, add in the parse of a single expression,
                        // and we'll go fron there.
                        returnBlock = scriptBlock = new JsBlock(CurrentPositionContext(), this);
                        GetNextToken();
                        try
                        {
                            var expr = ParseExpression();
                            if (expr != null)
                            {
                                scriptBlock.Append(expr);
                                scriptBlock.UpdateWith(expr.Context);
                            }
                        }
                        catch (EndOfStreamException)
                        {
                            Debug.WriteLine("EOF");
                        }
                        break;

                    case JsSourceMode.EventHandler:
                        // we're going to create the global block, add in a function expression with a single
                        // parameter named "event", and then we're going to parse the input as the body of that
                        // function expression. We're going to resolve the global block, but only return the body
                        // of the function.
                        scriptBlock = new JsBlock(null, this);

                        var parameters = new JsAstNodeList(null, this);
                        parameters.Append(new JsParameterDeclaration(null, this)
                            {
                                Name = "event",
                                RenameNotAllowed = true
                            });

                        var funcExpression = new JsFunctionObject(null, this)
                            {
                                FunctionType = JsFunctionType.Expression,
                                ParameterDeclarations = parameters
                            };
                        scriptBlock.Append(funcExpression);
                        funcExpression.Body = returnBlock = ParseStatements();
                        break;

                    default:
                        Debug.Fail("Unexpected source mode enumeration");
                        return null;
                }
            }
            catch (RecoveryTokenException)
            {
                // this should never happen but let's make SURE we don't expose our
                // private exception object to the outside world
                m_currentToken.HandleError(JsError.ApplicationError, true);
            }

            timePoints[--timeIndex] = stopWatch.ElapsedTicks;

            if (scriptBlock != null)
            {
                // resolve everything
                JsResolutionVisitor.Apply(scriptBlock, GlobalScope, m_settings);
            }

            timePoints[--timeIndex] = stopWatch.ElapsedTicks;

            if (scriptBlock != null && Settings.MinifyCode && !Settings.PreprocessOnly)
            {
                // this visitor doesn't just reorder scopes. It also combines the adjacent var variables,
                // unnests blocks, identifies prologue directives, and sets the strict mode on scopes.
                JsReorderScopeVisitor.Apply(scriptBlock, this);
                timePoints[--timeIndex] = stopWatch.ElapsedTicks;

                // analyze the entire node tree (needed for hypercrunch)
                // root to leaf (top down)
                var analyzeVisitor = new JsAnalyzeNodeVisitor(this);
                scriptBlock.Accept(analyzeVisitor);
                timePoints[--timeIndex] = stopWatch.ElapsedTicks;

                // analyze the scope chain (also needed for hypercrunch)
                // root to leaf (top down)
                GlobalScope.AnalyzeScope();
                timePoints[--timeIndex] = stopWatch.ElapsedTicks;

                // if we want to crunch any names....
                if (m_settings.LocalRenaming != JsLocalRenaming.KeepAll
                    && m_settings.IsModificationAllowed(JsTreeModifications.LocalRenaming))
                {
                    // then do a top-down traversal of the scope tree. For each field that had not
                    // already been crunched (globals and outers will already be crunched), crunch
                    // the name with a crunch iterator that does not use any names in the verboten set.
                    GlobalScope.AutoRenameFields();
                }

                timePoints[--timeIndex] = stopWatch.ElapsedTicks;

                // if we want to evaluate literal expressions, do so now
                if (m_settings.EvalLiteralExpressions)
                {
                    var visitor = new JsEvaluateLiteralVisitor(this);
                    scriptBlock.Accept(visitor);
                }

                timePoints[--timeIndex] = stopWatch.ElapsedTicks;

                // make the final cleanup pass
                JsFinalPassVisitor.Apply(scriptBlock, this);
                timePoints[--timeIndex] = stopWatch.ElapsedTicks;

                // we want to walk all the scopes to make sure that any generated
                // variables that haven't been crunched have been assigned valid
                // variable names that don't collide with any existing variables.
                GlobalScope.ValidateGeneratedNames();
                timePoints[--timeIndex] = stopWatch.ElapsedTicks;
            }

            if (returnBlock != null && returnBlock.Parent != null)
            {
                returnBlock.Parent = null;
            }

            return returnBlock;
        }
コード例 #27
0
        /// <summary>
        /// Crunched JS string passed to it, returning crunched string.
        /// The ErrorList property will be set with any errors found during the minification process.
        /// </summary>
        /// <param name="source">source Javascript</param>
        /// <param name="codeSettings">code minification settings</param>
        /// <returns>minified Javascript</returns>
        public string MinifyJavaScript(string source, JsSettings codeSettings)
        {
            // default is an empty string
            var crunched = string.Empty;

            // reset the errors builder
            m_errorList = new List <MinifierError>();

            // create the parser from the source string.
            // pass null for the assumed globals array
            var parser = new JsParser(source);

            // file context is a property on the parser
            parser.FileContext = FileName;

            // hook the engine error event
            parser.CompilerError += OnJavaScriptError;

            try
            {
                var preprocessOnly = codeSettings != null && codeSettings.PreprocessOnly;
                var sb             = new StringBuilder();
                using (var stringWriter = new StringWriter(sb, CultureInfo.InvariantCulture))
                {
                    if (preprocessOnly)
                    {
                        parser.EchoWriter = stringWriter;
                    }

                    // parse the input
                    var scriptBlock = parser.Parse(codeSettings);
                    if (scriptBlock != null && !preprocessOnly)
                    {
                        // we'll return the crunched code
                        if (codeSettings != null && codeSettings.Format == JsFormat.JSON)
                        {
                            // we're going to use a different output visitor -- one
                            // that specifically returns valid JSON.
                            if (!JsonOutputVisitor.Apply(stringWriter, scriptBlock))
                            {
                                m_errorList.Add(new MinifierError(
                                                    true,
                                                    0,
                                                    null,
                                                    null,
                                                    null,
                                                    this.FileName,
                                                    0,
                                                    0,
                                                    0,
                                                    0,
                                                    JScript.InvalidJSONOutput));
                            }
                        }
                        else
                        {
                            // just use the normal output visitor
                            JsOutputVisitor.Apply(stringWriter, scriptBlock, codeSettings);
                        }
                    }
                }

                crunched = sb.ToString();
            }
            catch (Exception e)
            {
                m_errorList.Add(new MinifierError(
                                    true,
                                    0,
                                    null,
                                    null,
                                    null,
                                    this.FileName,
                                    0,
                                    0,
                                    0,
                                    0,
                                    e.Message));
                throw;
            }

            return(crunched);
        }
コード例 #28
0
 public JsBlock ParseExpression(JsSettings settings)
 {
     // we need to make sure the settings object has the expression source mode property set,
     // but let's not modify the settings object passed in. So clone it, set the property on the
     // clone, and use that object for parsing.
     settings = settings == null ? new JsSettings() : settings.Clone();
     settings.SourceMode = JsSourceMode.Expression;
     return Parse(settings);
 }
コード例 #29
0
        public static void Apply(JsAstNode node, JsActivationObject scope, JsSettings settings)
        {
            if (node != null && scope != null)
            {
                // create the visitor and run it. This will create all the child
                // scopes and populate all the scopes with the var-decl, lex-decl,
                // and lookup references within them.
                var visitor = new JsResolutionVisitor(scope, settings);
                node.Accept(visitor);

                // now that all the scopes are created and they all know what decls
                // they contains, create all the fields
                CreateFields(scope);

                // now that all the fields have been created in all the scopes,
                // let's go through and resolve all the references
                ResolveLookups(scope, settings);

                // now that everything is declared and resolved as per the language specs,
                // we need to go back and add ghosted fields for older versions of IE that
                // incorrectly implement catch-variables and named function expressions.
                AddGhostedFields(scope);
            }
        }
コード例 #30
0
        private static void ResolveLookup(JsActivationObject scope, JsLookup lookup, JsSettings settings)
        {
            // resolve lookup via the lexical scope
            lookup.VariableField = scope.FindReference(lookup.Name);
            if (lookup.VariableField.FieldType == JsFieldType.UndefinedGlobal)
            {
                // couldn't find it.
                // if the lookup isn't generated and isn't the object of a typeof operator,
                // then we want to throw an error.
                if (!lookup.IsGenerated)
                {
                    var parentUnaryOp = lookup.Parent as JsUnaryOperator;
                    if (parentUnaryOp != null && parentUnaryOp.OperatorToken == JsToken.TypeOf)
                    {
                        // this undefined lookup is the target of a typeof operator.
                        // I think it's safe to assume we're going to use it. Don't throw an error
                        // and instead add it to the "known" expected globals of the global scope
                        MakeExpectedGlobal(lookup.VariableField);
                    }
                    else
                    {
                        // report this undefined reference
                        lookup.Context.ReportUndefined(lookup);

                        // possibly undefined global (but definitely not local).
                        // see if this is a function or a variable.
                        var callNode   = lookup.Parent as JsCallNode;
                        var isFunction = callNode != null && callNode.Function == lookup;
                        lookup.Context.HandleError((isFunction ? JsError.UndeclaredFunction : JsError.UndeclaredVariable), false);
                    }
                }
            }
            else if (lookup.VariableField.FieldType == JsFieldType.Predefined)
            {
                if (string.CompareOrdinal(lookup.Name, "window") == 0)
                {
                    // it's the global window object
                    // see if it's the child of a member or call-brackets node
                    var member = lookup.Parent as JsMember;
                    if (member != null)
                    {
                        // we have window.XXXX. Add XXXX to the known globals if it
                        // isn't already a known item.
                        scope.AddGlobal(member.Name);
                    }
                    else
                    {
                        var callNode = lookup.Parent as JsCallNode;
                        if (callNode != null && callNode.InBrackets &&
                            callNode.Arguments.Count == 1 &&
                            callNode.Arguments[0] is JsConstantWrapper &&
                            callNode.Arguments[0].FindPrimitiveType() == JsPrimitiveType.String)
                        {
                            // we have window["XXXX"]. See if XXXX is a valid identifier.
                            // TODO: we could get rid of the ConstantWrapper restriction and use an Evaluate visitor
                            // to evaluate the argument, since we know for sure that it's a string.
                            var identifier = callNode.Arguments[0].ToString();
                            if (JsScanner.IsValidIdentifier(identifier))
                            {
                                // Add XXXX to the known globals if it isn't already a known item.
                                scope.AddGlobal(identifier);
                            }
                        }
                    }
                }
                else if (settings.EvalTreatment != JsEvalTreatment.Ignore &&
                         string.CompareOrdinal(lookup.Name, "eval") == 0)
                {
                    // it's an eval -- but are we calling it?
                    // TODO: what if we are assigning it to a variable? Should we track that variable and see if we call it?
                    // What about passing it as a parameter to a function? track that as well in case the function calls it?
                    var parentCall = lookup.Parent as JsCallNode;
                    if (parentCall != null && parentCall.Function == lookup)
                    {
                        scope.IsKnownAtCompileTime = false;
                    }
                }
            }

            // add the reference
            lookup.VariableField.AddReference(lookup);

            // we are actually referencing this field, so it's no longer a placeholder field if it
            // happens to have been one.
            lookup.VariableField.IsPlaceholder = false;
        }
コード例 #31
0
        /// <summary>
        /// Crunched JS string passed to it, returning crunched string.
        /// The ErrorList property will be set with any errors found during the minification process.
        /// </summary>
        /// <param name="source">source Javascript</param>
        /// <param name="codeSettings">code minification settings</param>
        /// <returns>minified Javascript</returns>
        public string MinifyJavaScript(string source, JsSettings codeSettings)
        {
            // default is an empty string
            var crunched = string.Empty;

            // reset the errors builder
            m_errorList = new List<MinifierError>();

            // create the parser from the source string.
            // pass null for the assumed globals array
            var parser = new JsParser(source);

            // file context is a property on the parser
            parser.FileContext = FileName;

            // hook the engine error event
            parser.CompilerError += OnJavaScriptError;

            try
            {
                var preprocessOnly = codeSettings != null && codeSettings.PreprocessOnly;
                var sb = new StringBuilder();
                using (var stringWriter = new StringWriter(sb, CultureInfo.InvariantCulture))
                {
                    if (preprocessOnly)
                    {
                        parser.EchoWriter = stringWriter;
                    }

                    // parse the input
                    var scriptBlock = parser.Parse(codeSettings);
                    if (scriptBlock != null && !preprocessOnly)
                    {
                        // we'll return the crunched code
                        if (codeSettings != null && codeSettings.Format == JsFormat.JSON)
                        {
                            // we're going to use a different output visitor -- one
                            // that specifically returns valid JSON.
                            if (!JsonOutputVisitor.Apply(stringWriter, scriptBlock))
                            {
                                m_errorList.Add(new MinifierError(
                                    true,
                                    0,
                                    null,
                                    null,
                                    null,
                                    this.FileName,
                                    0,
                                    0,
                                    0,
                                    0,
                                    JScript.InvalidJSONOutput));
                            }
                        }
                        else
                        {
                            // just use the normal output visitor
                            JsOutputVisitor.Apply(stringWriter, scriptBlock, codeSettings);
                        }
                    }
                }

                crunched = sb.ToString();
            }
            catch (Exception e)
            {
                m_errorList.Add(new MinifierError(
                    true,
                    0,
                    null,
                    null,
                    null,
                    this.FileName,
                    0,
                    0,
                    0,
                    0,
                    e.Message));
                throw;
            }

            return crunched;
        }
コード例 #32
0
        private static void ResolveLookup(JsActivationObject scope, JsLookup lookup, JsSettings settings)
        {
            // resolve lookup via the lexical scope
            lookup.VariableField = scope.FindReference(lookup.Name);
            if (lookup.VariableField.FieldType == JsFieldType.UndefinedGlobal)
            {
                // couldn't find it.
                // if the lookup isn't generated and isn't the object of a typeof operator,
                // then we want to throw an error.
                if (!lookup.IsGenerated)
                {
                    var parentUnaryOp = lookup.Parent as JsUnaryOperator;
                    if (parentUnaryOp != null && parentUnaryOp.OperatorToken == JsToken.TypeOf)
                    {
                        // this undefined lookup is the target of a typeof operator.
                        // I think it's safe to assume we're going to use it. Don't throw an error
                        // and instead add it to the "known" expected globals of the global scope
                        MakeExpectedGlobal(lookup.VariableField);
                    }
                    else
                    {
                        // report this undefined reference
                        lookup.Context.ReportUndefined(lookup);

                        // possibly undefined global (but definitely not local).
                        // see if this is a function or a variable.
                        var callNode = lookup.Parent as JsCallNode;
                        var isFunction = callNode != null && callNode.Function == lookup;
                        lookup.Context.HandleError((isFunction ? JsError.UndeclaredFunction : JsError.UndeclaredVariable), false);
                    }
                }
            }
            else if (lookup.VariableField.FieldType == JsFieldType.Predefined)
            {
                if (string.CompareOrdinal(lookup.Name, "window") == 0)
                {
                    // it's the global window object
                    // see if it's the child of a member or call-brackets node
                    var member = lookup.Parent as JsMember;
                    if (member != null)
                    {
                        // we have window.XXXX. Add XXXX to the known globals if it
                        // isn't already a known item.
                        scope.AddGlobal(member.Name);
                    }
                    else
                    {
                        var callNode = lookup.Parent as JsCallNode;
                        if (callNode != null && callNode.InBrackets
                            && callNode.Arguments.Count == 1
                            && callNode.Arguments[0] is JsConstantWrapper
                            && callNode.Arguments[0].FindPrimitiveType() == JsPrimitiveType.String)
                        {
                            // we have window["XXXX"]. See if XXXX is a valid identifier.
                            // TODO: we could get rid of the ConstantWrapper restriction and use an Evaluate visitor
                            // to evaluate the argument, since we know for sure that it's a string.
                            var identifier = callNode.Arguments[0].ToString();
                            if (JsScanner.IsValidIdentifier(identifier))
                            {
                                // Add XXXX to the known globals if it isn't already a known item.
                                scope.AddGlobal(identifier);
                            }
                        }
                    }
                }
                else if (settings.EvalTreatment != JsEvalTreatment.Ignore
                    && string.CompareOrdinal(lookup.Name, "eval") == 0)
                {
                    // it's an eval -- but are we calling it?
                    // TODO: what if we are assigning it to a variable? Should we track that variable and see if we call it?
                    // What about passing it as a parameter to a function? track that as well in case the function calls it?
                    var parentCall = lookup.Parent as JsCallNode;
                    if (parentCall != null && parentCall.Function == lookup)
                    {
                        scope.IsKnownAtCompileTime = false;
                    }
                }
            }

            // add the reference
            lookup.VariableField.AddReference(lookup);

            // we are actually referencing this field, so it's no longer a placeholder field if it
            // happens to have been one.
            lookup.VariableField.IsPlaceholder = false;
        }
コード例 #33
0
        private static void ResolveLookups(JsActivationObject scope, JsSettings settings)
        {
            // resolve each lookup this scope contains
            foreach (var lookup in scope.ScopeLookups)
            {
                ResolveLookup(scope, lookup, settings);
            }

            // and recurse
            foreach (var childScope in scope.ChildScopes)
            {
                ResolveLookups(childScope, settings);
            }

            // mark any variables defined in this scope that don't have any references
            // so we can throw warnings later. We can't rely on the reference count because
            // we might remove references while optimizing code -- if we throw an error when
            // the count gets to zero, then we would be reporting errors that don't exist.
            // but we DO know right now what isn't referenced at all.
            foreach (var field in scope.NameTable.Values)
            {
                if (field.RefCount == 0)
                {
                    field.HasNoReferences = true;
                }
            }
        }
コード例 #34
0
 internal JsCatchScope(JsActivationObject parent, JsContext catchContext, JsSettings settings, JsParameterDeclaration catchParameter)
     : base(parent, catchContext, settings)
 {
     CatchParameter = catchParameter;
 }