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>(); } }
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; } } }
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>(); }
public JsBlockScope(JsActivationObject parent, JsContext context, JsSettings settings) : base(parent, settings) { if (context == null) { throw new ArgumentNullException("context"); } m_context = context.Clone(); }
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; }
/// <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); }
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; }
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" }); }
/// <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); }
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); } }
internal JsCatchScope(JsActivationObject parent, JsContext catchContext, JsSettings settings, JsParameterDeclaration catchParameter) : base(parent, catchContext, settings) { CatchParameter = catchParameter; }
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; }
public JsWithScope(JsActivationObject parent, JsContext context, JsSettings settings) : base(parent, context, settings) { IsInWithScope = true; }
/// <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); }