package com.digiarea.closure.model.export; import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.text.MessageFormat; import java.util.ResourceBundle; import com.digiarea.closure.core.IPathResolver; import com.digiarea.closure.core.Path; import com.digiarea.closure.model.Buildpath; import com.digiarea.closure.model.ClosureJs; import com.digiarea.closure.model.JsDefine; import com.digiarea.closure.model.JsDefineType; import com.digiarea.closure.model.JsDoc; import com.digiarea.closure.model.JsFunctionMap; import com.digiarea.closure.model.JsPropertyMap; import com.digiarea.closure.model.JsVariableMap; import com.digiarea.closure.model.LangType; import com.digiarea.closure.model.Language; import com.digiarea.closure.model.Optimizations; import com.digiarea.closure.model.Output; import com.digiarea.closure.model.SeverityType; import com.digiarea.closure.model.Warning; import com.digiarea.closure.model.visitor.VoidVisitorAdapter; import com.digiarea.closurefx.IConstants; import com.digiarea.closurefx.build.compiler.JSBuildpathContainerResolver; import com.digiarea.closurefx.build.validation.IStatus.StatusType; import com.digiarea.closurefx.build.validation.Status; import com.digiarea.closurefx.cli.console.IClosureConsole; import com.digiarea.closurefx.utils.ClosurerUtils; import com.digiarea.closurefx.utils.SourcePrinter; public class ClosureCLExporter extends VoidVisitorAdapter<Void> { private OutputStream stream; private SourcePrinter printer; private IPathResolver pathResolver; private IClosureConsole console; private ResourceBundle bundle; private String warningLevel; private String compilationLevel; public ClosureCLExporter(IPathResolver pathResolver, OutputStream stream, IClosureConsole console, ResourceBundle bundle) { this.bundle = bundle; this.console = console; this.stream = stream; this.printer = new SourcePrinter(this.stream, null); this.pathResolver = pathResolver; } public void setWarningLevel(String warningLevel) { this.warningLevel = warningLevel; } public void setCompilationLevel(String compilationLevel) { this.compilationLevel = compilationLevel; } public OutputStream getStream() { return stream; } @Override public void visit(Buildpath n, Void ctx) throws Exception { if (n.getParent() instanceof ClosureJs) { JSBuildpathContainerResolver resolver = new JSBuildpathContainerResolver( n, pathResolver); resolver.getDependencies(); resolver.resolve(); for (File source : resolver.getSources()) { printOption(IClosureCLConstants.JS, quote(source.getAbsolutePath()), " ", true); } for (File source : resolver.getExterns()) { printOption(IClosureCLConstants.JS_EXTERNS, quote(source.getAbsolutePath()), " ", true); } } else { super.visit(n, ctx); } } @Override public void visit(ClosureJs n, Void ctx) throws Exception { // if (n.getInfo() != null) { // n.getInfo().accept(this, ctx); // } if (n.getBuildpath() != null) { n.getBuildpath().accept(this, ctx); } if (n.getOutput() != null) { n.getOutput().accept(this, ctx); } if (warningLevel != null) { printOption(IClosureCLConstants.JS_WARNING_LEVEL, warningLevel, " ", true); } if (compilationLevel != null) { printOption(IClosureCLConstants.JS_COMPILATION_LEVEL, compilationLevel, " ", true); } if (n.getWarnings() != null) { n.getWarnings().accept(this, ctx); } // if (n.getChecks() != null) { // n.getChecks().accept(this, ctx); // } if (n.getOptimizations() != null) { n.getOptimizations().accept(this, ctx); } if (n.getJsDocs() != null) { n.getJsDocs().accept(this, ctx); } if (n.getLanguage() != null) { n.getLanguage().accept(this, ctx); } if (n.getJsDefines() != null) { n.getJsDefines().accept(this, ctx); } if (n.getRenaming() != null) { n.getRenaming().accept(this, ctx); } if (n.getTranslationsFile() != null && !n.getTranslationsFile().isEmpty()) { printOption(IClosureCLConstants.JS_TRANSLATION_FILE, n.getTranslationsFile(), " ", true); } if (n.getTranslationsProject() != null && !n.getTranslationsProject().isEmpty()) { printOption(IClosureCLConstants.JS_TRANSLATION_PROJECT, n.getTranslationsProject(), " ", true); } if (!n.isClosurePass() && !n.isJqueryPass()) { printOption(IClosureCLConstants.JS_THIRD_PARTY, true, " ", true); } printOption(IClosureCLConstants.JS_PROCESS_CLOSURE_PRIMITIVES, n.isClosurePass(), " ", true); printOption(IClosureCLConstants.JS_PROCESS_JQUERY_PRIMITIVES, n.isJqueryPass(), " ", true); printOption(IClosureCLConstants.JS_PROCESS_ANGULAR, n.isAngularPass(), " ", true); printOption(IClosureCLConstants.JS_ACCEPT_CONST, n.isAcceptConstKeyword(), " ", true); if (n.isPrettyPrint()) { printOption(IClosureCLConstants.JS_FORMATTING, IClosureCLConstants.JS_FORMATTING_PRETTY_PRINT, " ", true); } if (n.isPrintInputDelimeter()) { printOption(IClosureCLConstants.JS_FORMATTING, IClosureCLConstants.JS_FORMATTING_PRINT_INPUT_DELIMITER, " ", true); } if (n.isSingleQuotes()) { printOption(IClosureCLConstants.JS_FORMATTING, IClosureCLConstants.JS_FORMATTING_SINGLE_QUOTES, " ", true); } if (n.isGenerateExports()) { printOption(IClosureCLConstants.JS_GENERATE_EXPORTS, n.isGenerateExports(), " ", true); } if (n.getSourceMapFile() != null && !n.getSourceMapFile().isEmpty()) { printOption(IClosureCLConstants.JS_SOURCE_MAP, quote(pathResolver.toRealPath(n.getSourceMapFile())), " ", true); printOption(IClosureCLConstants.JS_SOURCE_MAP_FORMAT, ClosurerUtils .toSourceMapFormat(n.getSourceMapFormat()).name(), " ", true); } if (n.getCharset() != null && !n.getCharset().isEmpty()) { printOption(IClosureCLConstants.JS_CHARSET, n.getCharset(), " ", true); } } @Override public void visit(Optimizations n, Void ctx) throws Exception { console.report(new Status(StatusType.WARNING, bundle .getString(IConstants.ClosureCLExporter_Optimization), null)); } @Override public void visit(Output n, Void ctx) throws Exception { if (n.getParent() instanceof ClosureJs) { printOption( IClosureCLConstants.JS_OUTPUT, quote(new Path(pathResolver.toRealPath(n.getPath())).append( n.getFile()).toString()), " ", true); } else { super.visit(n, ctx); } } private String getWarningSeverityFlag(SeverityType type) { switch (type) { case OFF: return IClosureCLConstants.JS_OFF; case WARNING: return IClosureCLConstants.JS_WARNING; default: return IClosureCLConstants.JS_ERROR; } } @Override public void visit(Warning n, Void ctx) throws Exception { String value = null; switch (n.getType()) { case ACCESS_CONTROLS: value = "accessControls"; break; case AMBIGUOUS_FUNCTION_DECL: value = "ambiguousFunctionDecl"; break; case CHECK_MISSING_RETURN: value = "missingReturn"; break; case CHECK_PROVIDES: value = "missingProvide"; break; case CHECK_REGEXP: value = "checkRegExp"; break; case CHECK_REQUIRES: value = "missingRequire"; break; case CHECK_STRUCT_DICT_INHERITENCE: value = "checkStructDictInheritance"; break; case CHECK_TYPES: value = "checkTypes"; break; case CHECK_USELESS_CODE: value = "uselessCode"; break; case CHECK_VARS: value = "checkVars"; break; case CONST: value = "const"; break; case CONSTANT_PROPERTY: value = "constantProperty"; break; case DEPRECATED: value = "deprecated"; break; case DUPLICATE_MESSAGES: value = "duplicateMessage"; break; case ES_5_STRICT: value = "es5Strict"; break; case EXTERNS_VALIDATION: value = "externsValidation"; break; case FILEOVERVIEW_JSDOC: value = "fileoverviewTags"; break; case GLOBAL_THIS: value = "globalThis"; break; case INTERNET_EXPLORER_CHECKS: value = "internetExplorerChecks"; break; case INVALID_CASTS: value = "invalidCasts"; break; case MISPLACED_TYPE_ANNOTATION: value = "misplacedTypeAnnotation"; break; case MISSING_PROPERTIES: value = "missingProperties"; break; case NON_STANDARD_JS_DOCS: value = "nonStandardJsDocs"; break; case REPORT_UNKNOWN_TYPES: value = "reportUnknownTypes"; break; case STRICT_MODULE_DEP_CHECK: value = "strictModuleDepCheck"; break; case SUSPICIOUS_CODE: value = "suspiciousCode"; break; case TYPE_INVALIDATION: value = "typeInvalidation"; break; case UNDEFINED_NAMES: value = "undefinedNames"; break; case UNDEFINED_VARS: value = "undefinedVars"; break; case UNKNOWN_DEFINES: value = "unknownDefines"; break; case VISIBILITY: value = "visibility"; break; case CHECK_EVENTFUL_OBJECT_DISPOSAL: value = "checkEventfulObjectDisposal"; break; case ES3: value = "es3"; break; case UNNECESSARY_CASTS: case VIOLATED_MODULE_DEP: case TWEAKS: case REPORT_MISSING_OVERRIDE: case DUPLICATE_VARS: case DEBUGGER_STATEMENT_PRESENT: case CHECK_UNREACHABLE_CODE: case CHECK_GLOBAL_NAMES_LEVEL: case CHECK_GLOBAL_THIS_LEVEL: case BROKEN_REQUIRES_LEVEL: case AGGRESSIVE_VAR_CHECK: console.report(new Status(StatusType.WARNING, MessageFormat.format( bundle.getString(IConstants.ClosureCLExporter_Warning), n .getType().name()), null)); break; default: console.report(new Status(StatusType.ERROR, "Strange option: " + n.getType().name(), null)); break; } if (value != null) { printOption(getWarningSeverityFlag(n.getSeverity()), value, "=", true); } } @Override public void visit(JsDoc n, Void ctx) throws Exception { printOption(IClosureCLConstants.JS_EXTRA_ANNOTATIONS_NAME, n.getValue(), " ", true); } @Override public void visit(Language n, Void ctx) throws Exception { if (n.getInput() != null) { printOption(IClosureCLConstants.JS_LANGUAGE_IN, getJSLanguageFlag(n.getInput()), " ", true); } if (n.getOutput() != null) { console.report(new Status(StatusType.WARNING, bundle .getString(IConstants.ClosureCLExporter_LanguageOut), null)); } } private String getJSLanguageFlag(LangType type) { switch (type) { case ECMASCRIPT_3: return "ECMASCRIPT3"; case ECMASCRIPT_5: return "ECMASCRIPT5"; case ECMASCRIPT_5_STRICT: return "ECMASCRIPT5_STRICT"; default: return "ECMASCRIPT3"; } } @Override public void visit(JsDefine n, Void ctx) throws Exception { String value = n.getName() + "="; if (n.getType() == JsDefineType.STRING) { value = value + "'" + n.getValue() + "'"; } else { value = value + n.getValue(); } printOption(IClosureCLConstants.JS_DEFINE, value, " ", true); } @Override public void visit(JsVariableMap n, Void ctx) throws Exception { if (n.getInput() != null && !n.getInput().isEmpty()) { printOption(IClosureCLConstants.JS_VARIABLE_MAP_INPUT, quote(pathResolver.toRealPath(n.getInput())), " ", true); } if (n.getOutput() != null && !n.getOutput().isEmpty()) { printOption(IClosureCLConstants.JS_VARIABLE_MAP_OUTPUT, quote(pathResolver.toRealPath(n.getOutput())), " ", true); } } @Override public void visit(JsPropertyMap n, Void ctx) throws Exception { if (n.getInput() != null && !n.getInput().isEmpty()) { printOption(IClosureCLConstants.JS_PROPERTY_MAP_INPUT, quote(pathResolver.toRealPath(n.getInput())), " ", true); } if (n.getOutput() != null && !n.getOutput().isEmpty()) { printOption(IClosureCLConstants.JS_PROPERTY_MAP_OUTPUT, quote(pathResolver.toRealPath(n.getOutput())), " ", true); } } @Override public void visit(JsFunctionMap n, Void ctx) throws Exception { console.report(new Status(StatusType.WARNING, bundle .getString(IConstants.ClosureCLExporter_JSFunctionMap), null)); } private void printOption(String key, Object value, String delimiter, boolean newLine) throws IOException { printer.print(key + delimiter + value); printer.print(" "); } private String quote(Object string) { return "\"" + string + "\""; } }