Example #1
0
        private string GenerateMappings(IList <string> fileList, IList <string> nameList)
        {
            var sb = StringBuilderPool.Acquire();

            try
            {
                var currentLine = 1;
                foreach (var segment in m_segments)
                {
                    if (currentLine < segment.DestinationLine)
                    {
                        // we've jumped forward at least one line in the minified file.
                        // add a semicolon for each line we've advanced
                        do
                        {
                            sb.Append(';');
                        }while (++currentLine < segment.DestinationLine);
                    }
                    else if (sb.Length > 0)
                    {
                        // same line; separate segments by comma. But only
                        // if we've already output something
                        sb.Append(',');
                    }

                    EncodeNumbers(sb, segment, fileList, nameList);
                }

                return(sb.ToString());
            }
            finally
            {
                sb.Release();
            }
        }
Example #2
0
        private void WriteBlockHeader(BlockScope blockScope, string blockType)
        {
            string scopeFlags = null;
            var    sb         = StringBuilderPool.Acquire();

            try
            {
                if (!blockScope.IsKnownAtCompileTime)
                {
                    sb.Append('[');
                    sb.Append(AjaxMin.NotKnown);
                    sb.Append(']');
                }

                if (blockScope.UseStrict)
                {
                    sb.Append(AjaxMin.ScopeIsStrictFlag);
                }

                scopeFlags = sb.ToString();
            }
            finally
            {
                sb.Release();
            }

            WriteProgress();
            WriteProgress(AjaxMin.BlockScopeHeader.FormatInvariant(
                              blockType,
                              blockScope.Owner.Context.StartLineNumber,
                              blockScope.Owner.Context.StartColumn + 1,
                              scopeFlags));
        }
        private static void AddEscape(string unescapedRun, string escapedText, ref StringBuilder sb)
        {
            // if we haven't yet created the string builder, do it now
            if (sb == null)
            {
                sb = StringBuilderPool.Acquire();
            }

            // add the run of unescaped text (if any), followed by the escaped text
            sb.Append(unescapedRun);
            sb.Append(escapedText);
        }
Example #4
0
        /// <summary>
        /// get the algorithmically-generated minified variable name based on the given number
        /// zero is the first name, 1 is the next, etc. This method needs to be tuned to
        /// get better gzip results.
        /// </summary>
        /// <param name="index">integer position of the name to retrieve</param>
        /// <returns>minified variable name</returns>
        public static string GenerateNameFromNumber(int index)
        {
            if ((s_smallNames != null) && (index >= 0) && (index < PrecalculateLength))
            {
                return(s_smallNames[index]);
            }

            var sb = StringBuilderPool.Acquire();

            try
            {
                // this REALLY needs some 'splainin.
                // first off, we want to use a different set of characters for the first digit
                // than we use for the second digit (they could be the same, but if we want the shortest
                // possible names, there are more characters available for the second digit than
                // the first. We could use the same strings if we wanted to limit the available characters
                // and therefore increase the length of the strings.
                // But let's think digits for a sec. normal base-10 would be:
                // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 ... 9 0 1
                //                     1 1 1 1 1 1 1 1 1 1 2 2 2 2 ... 9 0 0
                //                                                       1 1
                // but we want to go:
                // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 ... ... ... 9 0 1
                //                     0 0 0 0 0 0 0 0 0 0 1 1 1 1 ... ... ... 9 0 0
                //                                                     ... ...   0 0
                // this is because for base-10, the leading zeros are blanks, but in our strings,
                // the leading blanks are NOT zeros. In essence what we do it START OVER FROM ZERO
                // but with explicit leading zeros every time we add another character to the length
                // of the string.
                // so after we peel off the last character, we divide by the number of possibilities to get
                // the next number in base-10. But WE want to divide by possibilities AND THEN SUBSTRACT ONE.
                // that not only gets us starting at 0, it also makes us push out the the number of iterations
                // we can go through before we need to increase the number of digits again.
                if (index >= 0)
                {
                    sb.Append(s_varFirstLetters[index % s_varFirstLetters.Length]);
                    index /= s_varFirstLetters.Length;

                    // this is where we substract the one after our division to get the next character (if any)
                    while (--index >= 0)
                    {
                        sb.Append(s_varPartLetters[index % s_varPartLetters.Length]);
                        index /= s_varPartLetters.Length;
                    }
                }

                return(sb.ToString());
            }
            finally
            {
                sb.Release();
            }
        }
Example #5
0
        private void OutputTimingPoints(JSParser parser, int groupIndex, int groupCount)
        {
            // frequency is ticks per second, so if we divide by 1000.0, then we will have a
            // double-precision value indicating the ticks per millisecond. Divide this into the
            // number of ticks we measure, and we'll get the milliseconds in double-precision.
            var frequency = Stopwatch.Frequency / 1000.0;

            // step names
            var stepNames = new[] { AjaxMin.StepParse, AjaxMin.StepResolve, AjaxMin.StepReorder,
                                    AjaxMin.StepAnalyzeNode, AjaxMin.StepAnalyzeScope, AjaxMin.StepAutoRename,
                                    AjaxMin.StepEvaluateLiterals, AjaxMin.StepFinalPass, AjaxMin.StepValidateNames };

            // and output other steps to debug
            var stepCount           = parser.TimingPoints.Count;
            var latestTimingPoint   = 0L;
            var previousTimingPoint = 0L;
            var message             = string.Empty;
            var sb = StringBuilderPool.Acquire();

            try
            {
                for (var ndx = stepCount - 1; ndx >= 0; --ndx)
                {
                    if (parser.TimingPoints[ndx] != 0)
                    {
                        // 1-based step index
                        var stepIndex = stepCount - ndx;
                        latestTimingPoint = parser.TimingPoints[ndx];
                        var deltaMS = (latestTimingPoint - previousTimingPoint) / frequency;
                        previousTimingPoint = latestTimingPoint;

                        sb.AppendFormat(AjaxMin.Culture, AjaxMin.TimerStepFormat, stepIndex, deltaMS, stepNames[stepIndex - 1]);
                        sb.AppendLine();
                    }
                }

                message = sb.ToString();
            }
            finally
            {
                sb.Release();
            }

            var timerFormat  = groupCount > 1 ? AjaxMin.TimerMultiFormat : AjaxMin.TimerFormat;
            var timerMessage = string.Format(CultureInfo.CurrentUICulture, timerFormat, groupIndex + 1, latestTimingPoint / frequency);

            Debug.WriteLine(timerMessage);
            Debug.Write(message);
            WriteProgress(timerMessage);
            WriteProgress(message);
        }
Example #6
0
        private void WriteModuleHeader(ModuleScope moduleScope)
        {
            var    blockType  = AjaxMin.BlockTypeModule.FormatInvariant(moduleScope.ScopeName.IfNullOrWhiteSpace(AjaxMin.ModuleNameImplicit));
            string scopeFlags = null;
            var    sb         = StringBuilderPool.Acquire();

            try
            {
                if (!moduleScope.IsKnownAtCompileTime)
                {
                    sb.Append('[');
                    sb.Append(AjaxMin.NotKnown);
                    sb.Append(']');
                }

                if (moduleScope.UseStrict)
                {
                    sb.Append(AjaxMin.ScopeIsStrictFlag);
                }

                if (moduleScope.IsNotComplete)
                {
                    sb.Append(AjaxMin.ModuleIncompleteFlag);
                }

                scopeFlags = sb.ToString();
            }
            finally
            {
                sb.Release();
            }

            WriteProgress();
            WriteProgress(AjaxMin.BlockScopeHeader.FormatInvariant(
                              blockType,
                              moduleScope.Owner.Context.StartLineNumber,
                              moduleScope.Owner.Context.StartColumn + 1,
                              scopeFlags));

            if (moduleScope.HasDefaultExport)
            {
                // when there's a default export, we want to flag a line under the module
                // header that indicates that it's okay to bind to the default export.
                WriteProgress(AjaxMin.ModuleHasDefaultExport);
            }
        }
Example #7
0
        public override string ToString()
        {
            var sb = StringBuilderPool.Acquire();

            try
            {
                if (m_list.Count > 0)
                {
                    // output the first one; then all subsequent, each prefaced with a comma
                    sb.Append(m_list[0].ToString());
                    for (var ndx = 1; ndx < m_list.Count; ++ndx)
                    {
                        sb.Append(" , ");
                        sb.Append(m_list[ndx].ToString());
                    }
                }

                return(sb.ToString());
            }
            finally
            {
                sb.Release();
            }
        }
Example #8
0
        /// <summary>
        /// Convert the exception to a VisualStudio format error message
        /// file(startline[-endline]?,startcol[-endcol]?):[ subcategory] category [errorcode]: message
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            var sb = StringBuilderPool.Acquire();

            try
            {
                if (!string.IsNullOrEmpty(File))
                {
                    sb.Append(File);
                }

                // if there is a startline, then there must be a location.
                // no start line, then no location
                if (StartLine > 0)
                {
                    // we will always at least start with the start line
                    sb.AppendFormat("({0}", StartLine);

                    if (EndLine > StartLine)
                    {
                        if (StartColumn > 0 && EndColumn > 0)
                        {
                            // all four values were specified
                            sb.AppendFormat(",{0},{1},{2}", StartColumn, EndLine, EndColumn);
                        }
                        else
                        {
                            // one or both of the columns wasn't specified, so ignore them both
                            sb.AppendFormat("-{0}", EndLine);
                        }
                    }
                    else if (StartColumn > 0)
                    {
                        sb.AppendFormat(",{0}", StartColumn);
                        if (EndColumn > StartColumn)
                        {
                            sb.AppendFormat("-{0}", EndColumn);
                        }
                    }

                    sb.Append(')');
                }

                // seaprate the location from the error description
                sb.Append(':');

                // if there is a subcategory, add it prefaced with a space
                if (!string.IsNullOrEmpty(Subcategory))
                {
                    sb.Append(' ');
                    sb.Append(Subcategory);
                }

                // not localizable
                sb.Append(IsError ? " error " : " warning ");

                // if there is an error code
                if (!string.IsNullOrEmpty(ErrorCode))
                {
                    sb.Append(ErrorCode);
                }

                // separate description from the message
                sb.Append(": ");

                if (!string.IsNullOrEmpty(Message))
                {
                    sb.Append(Message);
                }

                return(sb.ToString());
            }
            finally
            {
                sb.Release();
            }
        }
Example #9
0
        private static string CreateJSFromResourceStrings(ResourceStrings resourceStrings)
        {
            var sb = StringBuilderPool.Acquire();

            try
            {
                // start the var statement using the requested name and open the initializer object literal
                sb.Append("var ");
                sb.Append(resourceStrings.Name);
                sb.Append("={");

                // we're going to need to insert commas between each pair, so we'll use a boolean
                // flag to indicate that we're on the first pair. When we output the first pair, we'll
                // set the flag to false. When the flag is false, we're about to insert another pair, so
                // we'll add the comma just before.
                bool firstItem = true;

                // loop through all items in the collection
                foreach (var keyPair in resourceStrings.NameValuePairs)
                {
                    // if this isn't the first item, we need to add a comma separator
                    if (!firstItem)
                    {
                        sb.Append(',');
                    }
                    else
                    {
                        // next loop is no longer the first item
                        firstItem = false;
                    }

                    // append the key as the name, a colon to separate the name and value,
                    // and then the value
                    // must quote if not valid JS identifier format, or if it is, but it's a keyword
                    // (use strict mode just to be safe)
                    string propertyName = keyPair.Key;
                    if (!JSScanner.IsValidIdentifier(propertyName) || JSScanner.IsKeyword(propertyName, true))
                    {
                        sb.Append("\"");
                        // because we are using quotes for the delimiters, replace any instances
                        // of a quote character (") with an escaped quote character (\")
                        sb.Append(propertyName.Replace("\"", "\\\""));
                        sb.Append("\"");
                    }
                    else
                    {
                        sb.Append(propertyName);
                    }
                    sb.Append(':');

                    // make sure the Value is properly escaped, quoted, and whatever we
                    // need to do to make sure it's a proper JS string.
                    // pass false for whether this string is an argument to a RegExp constructor.
                    // pass false for whether to use W3Strict formatting for character escapes (use maximum browser compatibility)
                    // pass true for ecma strict mode
                    string stringValue = ConstantWrapper.EscapeString(
                        keyPair.Value,
                        false,
                        false,
                        true
                        );
                    sb.Append(stringValue);
                }

                // close the object literal and return the string
                sb.AppendLine("};");
                return(sb.ToString());
            }
            finally
            {
                sb.Release();
            }
        }
Example #10
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, CodeSettings codeSettings)
        {
            // default is an empty string
            var crunched = string.Empty;

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

            // create the parser and hook the engine error event
            var parser = new JSParser();

            parser.CompilerError += OnJavaScriptError;

            var sb = StringBuilderPool.Acquire();

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

                    // parse the input
                    var scriptBlock = parser.Parse(new DocumentContext(source)
                    {
                        FileContext = this.FileName
                    }, codeSettings);
                    if (scriptBlock != null && !preprocessOnly)
                    {
                        // we'll return the crunched code
                        if (codeSettings != null && codeSettings.Format == JavaScriptFormat.JSON)
                        {
                            // we're going to use a different output visitor -- one
                            // that specifically returns valid JSON.
                            if (!JSONOutputVisitor.Apply(stringWriter, scriptBlock, codeSettings))
                            {
                                m_errorList.Add(new ContextError()
                                {
                                    Severity = 0,
                                    File     = this.FileName,
                                    Message  = CommonStrings.InvalidJSONOutput,
                                });
                            }
                        }
                        else
                        {
                            // just use the normal output visitor
                            OutputVisitor.Apply(stringWriter, scriptBlock, codeSettings);

                            // if we are asking for a symbols map, give it a chance to output a little something
                            // to the minified file.
                            if (codeSettings != null && codeSettings.SymbolsMap != null)
                            {
                                codeSettings.SymbolsMap.EndFile(stringWriter, codeSettings.LineTerminator);
                            }
                        }
                    }
                }

                crunched = sb.ToString();
            }
            catch (Exception e)
            {
                m_errorList.Add(new ContextError()
                {
                    Severity = 0,
                    File     = this.FileName,
                    Message  = e.Message,
                });
                throw;
            }
            finally
            {
                sb.Release();
            }

            return(crunched);
        }
Example #11
0
        //TYPE "NAME" - Starts at line LINE, col COLUMN STATUS [crunched to CRUNCH]
        //
        //TYPE: Function, Function getter, Function setter
        //STATUS: '', Unknown, Unreachable
        private void WriteFunctionHeader(FunctionObject funcObj, bool isKnown, bool useStrict)
        {
            // get the crunched value (if any)
            string crunched      = string.Empty;
            var    functionField = funcObj.Binding.IfNotNull(b => b.VariableField);

            if (functionField != null && functionField.CrunchedName != null)
            {
                crunched = AjaxMin.CrunchedTo.FormatInvariant(functionField.CrunchedName, functionField.RefCount);
            }

            // get the status if the function
            string status        = null;
            var    statusBuilder = StringBuilderPool.Acquire();

            try
            {
                if (!isKnown)
                {
                    statusBuilder.Append('[');
                    statusBuilder.Append(AjaxMin.NotKnown);
                }
                if (funcObj.EnclosingScope.Parent is GlobalScope)
                {
                    // global function.
                    // if this is a named function expression, we still want to know if it's
                    // referenced by anyone
                    if (funcObj.FunctionType == FunctionType.Expression &&
                        funcObj.Binding != null &&
                        !funcObj.Binding.Name.IsNullOrWhiteSpace())
                    {
                        // output a comma separator if not the first item, otherwise
                        // open the square bracket
                        if (statusBuilder.Length > 0)
                        {
                            statusBuilder.Append(", ");
                        }
                        else
                        {
                            statusBuilder.Append('[');
                        }
                        statusBuilder.Append(AjaxMin.FunctionInfoReferences.FormatInvariant(
                                                 funcObj.Binding.VariableField.IfNotNull(v => v.RefCount)
                                                 ));
                    }
                }
                else if (!funcObj.IsReferenced && m_useReferenceCounts)
                {
                    // local function that isn't referenced -- unreachable!
                    // output a comma separator if not the first item, otherwise
                    // open the square bracket
                    if (statusBuilder.Length > 0)
                    {
                        statusBuilder.Append(", ");
                    }
                    else
                    {
                        statusBuilder.Append('[');
                    }

                    statusBuilder.Append(AjaxMin.Unreachable);
                }

                if (statusBuilder.Length > 0)
                {
                    statusBuilder.Append(']');
                }

                if (useStrict)
                {
                    statusBuilder.Append(AjaxMin.ScopeIsStrictFlag);
                }

                status = statusBuilder.ToString();
            }
            finally
            {
                statusBuilder.Release();
            }

            string functionType;

            switch (funcObj.FunctionType)
            {
            case FunctionType.Getter:
                functionType = AjaxMin.FunctionTypePropGet;
                break;

            case FunctionType.Setter:
                functionType = AjaxMin.FunctionTypePropSet;
                break;

            case FunctionType.Expression:
                functionType = AjaxMin.FunctionTypeExpression;
                break;

            case FunctionType.ArrowFunction:
                functionType = AjaxMin.FunctionTypeArrow;
                break;

            case FunctionType.Method:
                functionType = AjaxMin.FunctionTypeMethod;
                break;

            default:
                functionType = AjaxMin.FunctionTypeFunction;
                break;
            }

            var functionName = funcObj.Binding.IfNotNull(b => b.Name);

            if (functionName.IsNullOrWhiteSpace())
            {
                functionName = !funcObj.NameGuess.IsNullOrWhiteSpace()
                    ? '"' + funcObj.NameGuess + '"'
                    : AjaxMin.AnonymousName;
            }

            // output
            WriteProgress();
            WriteProgress(AjaxMin.FunctionHeader.FormatInvariant(
                              functionType,
                              functionName,
                              funcObj.Context.StartLineNumber,
                              funcObj.Context.StartColumn + 1,
                              status,
                              crunched,
                              funcObj.IsGenerator ? AjaxMin.FunctionTypeGenerator : string.Empty));
        }