All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.javascript.jscomp.parsing.parser.FeatureSet Maven / Gradle / Ivy

Go to download

Closure Compiler is a JavaScript optimizing compiler. It parses your JavaScript, analyzes it, removes dead code and rewrites and minimizes what's left. It also checks syntax, variable references, and types, and warns about common JavaScript pitfalls. It is used in many of Google's JavaScript apps, including Gmail, Google Web Search, Google Maps, and Google Docs. This binary checks for style issues such as incorrect or missing JSDoc usage, and missing goog.require() statements. It does not do more advanced checks such as typechecking.

There is a newer version: v20200830
Show newest version
/*
 * Copyright 2015 The Closure Compiler Authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.javascript.jscomp.parsing.parser;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableSet;
import com.google.errorprone.annotations.Immutable;
import java.io.Serializable;
import java.util.EnumSet;
import java.util.Set;

/**
 * Represents various aspects of language version and support.
 *
 * 

This is somewhat redundant with LanguageMode, but is separate * for two reasons: (1) it's used for parsing, which cannot * depend on LanguageMode, and (2) it's concerned with slightly * different nuances: implemented features and modules rather * than strictness. * *

In the long term, it would be good to disentangle all these * concerns and pull out a single LanguageSyntax enum with a * separate strict mode flag, and then these could possibly be * unified. * *

Instances of this class are immutable. */ @Immutable public final class FeatureSet implements Serializable { private final ImmutableSet features; /** The bare minimum set of features. */ public static final FeatureSet BARE_MINIMUM = new FeatureSet(emptyEnumSet()); /** Features from ES3. */ public static final FeatureSet ES3 = BARE_MINIMUM.with(LangVersion.ES3.features()); /** Features from ES5 only. */ public static final FeatureSet ES5 = ES3.with(LangVersion.ES5.features()); /** All ES6 features, including modules. */ public static final FeatureSet ES6_MODULES = ES5.with(LangVersion.ES6.features()); /** The full set of ES6 features, not including modules. */ public static final FeatureSet ES6 = ES6_MODULES.without(Feature.MODULES); public static final FeatureSet ES7_MODULES = ES6_MODULES.with(LangVersion.ES7.features()); public static final FeatureSet ES7 = ES7_MODULES.without(Feature.MODULES); public static final FeatureSet ES8_MODULES = ES7_MODULES.with(LangVersion.ES8.features()); public static final FeatureSet ES8 = ES8_MODULES.without(Feature.MODULES); public static final FeatureSet ES2018_MODULES = ES8_MODULES.with(LangVersion.ES2018.features()); public static final FeatureSet ES2018 = ES2018_MODULES.without(Feature.MODULES); public static final FeatureSet ES2019_MODULES = ES2018_MODULES.with(LangVersion.ES2019.features()); public static final FeatureSet ES2019 = ES2019_MODULES.without(Feature.MODULES); public static final FeatureSet ES_NEXT = ES2019_MODULES.with(LangVersion.ES_NEXT.features()); public static final FeatureSet ES_UNSUPPORTED = ES_NEXT.with(LangVersion.ES_UNSUPPORTED.features()); public static final FeatureSet TYPESCRIPT = ES_NEXT.with(LangVersion.TYPESCRIPT.features()); public static final FeatureSet TYPE_CHECK_SUPPORTED = ES2019_MODULES; private enum LangVersion { ES3, ES5, ES6, ES7, ES8, ES2018, ES2019, ES_NEXT, ES_UNSUPPORTED, TYPESCRIPT; private EnumSet features() { EnumSet set = EnumSet.noneOf(Feature.class); for (Feature feature : Feature.values()) { if (feature.version == this) { set.add(feature); } } return set; } } /** Specific features that can be included in a FeatureSet. */ public enum Feature { // ES5 features ES3_KEYWORDS_AS_IDENTIFIERS("ES3 keywords as identifiers", LangVersion.ES5), GETTER("getters", LangVersion.ES5), KEYWORDS_AS_PROPERTIES("reserved words as properties", LangVersion.ES5), SETTER("setters", LangVersion.ES5), STRING_CONTINUATION("string continuation", LangVersion.ES5), TRAILING_COMMA("trailing comma", LangVersion.ES5), // ES6 features (besides modules): all stable browsers are now fully compliant ARRAY_PATTERN_REST("array pattern rest", LangVersion.ES6), ARROW_FUNCTIONS("arrow function", LangVersion.ES6), BINARY_LITERALS("binary literal", LangVersion.ES6), BLOCK_SCOPED_FUNCTION_DECLARATION("block-scoped function declaration", LangVersion.ES6), CLASSES("class", LangVersion.ES6), CLASS_EXTENDS("class extends", LangVersion.ES6), CLASS_GETTER_SETTER("class getters/setters", LangVersion.ES6), COMPUTED_PROPERTIES("computed property", LangVersion.ES6), CONST_DECLARATIONS("const declaration", LangVersion.ES6), DEFAULT_PARAMETERS("default parameter", LangVersion.ES6), ARRAY_DESTRUCTURING("array destructuring", LangVersion.ES6), OBJECT_DESTRUCTURING("object destructuring", LangVersion.ES6), EXTENDED_OBJECT_LITERALS("extended object literal", LangVersion.ES6), FOR_OF("for-of loop", LangVersion.ES6), GENERATORS("generator", LangVersion.ES6), LET_DECLARATIONS("let declaration", LangVersion.ES6), MEMBER_DECLARATIONS("member declaration", LangVersion.ES6), NEW_TARGET("new.target", LangVersion.ES6), OCTAL_LITERALS("octal literal", LangVersion.ES6), REGEXP_FLAG_U("RegExp flag 'u'", LangVersion.ES6), REGEXP_FLAG_Y("RegExp flag 'y'", LangVersion.ES6), REST_PARAMETERS("rest parameter", LangVersion.ES6), SPREAD_EXPRESSIONS("spread expression", LangVersion.ES6), SUPER("super", LangVersion.ES6), TEMPLATE_LITERALS("template literal", LangVersion.ES6), // ES6 modules MODULES("modules", LangVersion.ES6), // ES 2016 only added one new feature: EXPONENT_OP("exponent operator (**)", LangVersion.ES7), // ES 2017 features: ASYNC_FUNCTIONS("async function", LangVersion.ES8), TRAILING_COMMA_IN_PARAM_LIST("trailing comma in param list", LangVersion.ES8), // ES 2018 adds https://github.com/tc39/proposal-object-rest-spread OBJECT_LITERALS_WITH_SPREAD("object literals with spread", LangVersion.ES2018), OBJECT_PATTERN_REST("object pattern rest", LangVersion.ES2018), // https://github.com/tc39/proposal-async-iteration ASYNC_GENERATORS("async generator functions", LangVersion.ES2018), FOR_AWAIT_OF("for-await-of loop", LangVersion.ES2018), // ES 2018 adds Regex Features: // https://github.com/tc39/proposal-regexp-dotall-flag REGEXP_FLAG_S("RegExp flag 's'", LangVersion.ES2018), // https://github.com/tc39/proposal-regexp-lookbehind REGEXP_LOOKBEHIND("RegExp Lookbehind", LangVersion.ES2018), // https://github.com/tc39/proposal-regexp-named-groups REGEXP_NAMED_GROUPS("RegExp named groups", LangVersion.ES2018), // https://github.com/tc39/proposal-regexp-unicode-property-escapes REGEXP_UNICODE_PROPERTY_ESCAPE("RegExp unicode property escape", LangVersion.ES2018), // ES 2019 adds https://github.com/tc39/proposal-json-superset UNESCAPED_UNICODE_LINE_OR_PARAGRAPH_SEP( "Unescaped unicode line or paragraph separator", LangVersion.ES2019), // ES 2019 adds optional catch bindings: // https://github.com/tc39/proposal-optional-catch-binding OPTIONAL_CATCH_BINDING("Optional catch binding", LangVersion.ES2019), // Stage 3 proposals likely to be part of ES2020 DYNAMIC_IMPORT("Dynamic module import", LangVersion.ES_UNSUPPORTED), IMPORT_META("import.meta", LangVersion.ES_UNSUPPORTED), // ES6 typed features that are not at all implemented in browsers ACCESSIBILITY_MODIFIER("accessibility modifier", LangVersion.TYPESCRIPT), AMBIENT_DECLARATION("ambient declaration", LangVersion.TYPESCRIPT), CALL_SIGNATURE("call signature", LangVersion.TYPESCRIPT), CONSTRUCTOR_SIGNATURE("constructor signature", LangVersion.TYPESCRIPT), ENUM("enum", LangVersion.TYPESCRIPT), GENERICS("generics", LangVersion.TYPESCRIPT), IMPLEMENTS("implements", LangVersion.TYPESCRIPT), INDEX_SIGNATURE("index signature", LangVersion.TYPESCRIPT), INTERFACE("interface", LangVersion.TYPESCRIPT), MEMBER_VARIABLE_IN_CLASS("member variable in class", LangVersion.TYPESCRIPT), NAMESPACE_DECLARATION("namespace declaration", LangVersion.TYPESCRIPT), OPTIONAL_PARAMETER("optional parameter", LangVersion.TYPESCRIPT), TYPE_ALIAS("type alias", LangVersion.TYPESCRIPT), TYPE_ANNOTATION("type annotation", LangVersion.TYPESCRIPT); private final String name; private final LangVersion version; private Feature(String name, LangVersion version) { this.name = name; this.version = version; } @Override public String toString() { return name; } } private FeatureSet(EnumSet features) { // ImmutableSet will only use an EnumSet if the set starts as an EnumSet. this.features = ImmutableSet.copyOf(features); } /** Returns a string representation suitable for encoding in depgraph and deps.js files. */ public String version() { if (ES3.contains(this)) { return "es3"; } if (ES5.contains(this)) { return "es5"; } if (ES6_MODULES.contains(this)) { return "es6"; } if (ES7_MODULES.contains(this)) { return "es7"; } if (ES8_MODULES.contains(this)) { return "es8"; } if (ES2018_MODULES.contains(this)) { return "es9"; } if (ES2019_MODULES.contains(this)) { return "es_2019"; } if (ES_NEXT.contains(this)) { return "es_next"; } if (ES_UNSUPPORTED.contains(this)) { return "es_unsupported"; } if (TYPESCRIPT.contains(this)) { return "ts"; } throw new IllegalStateException(this.toString()); } /** * Returns a string representation useful for debugging. * *

This is not suitable for encoding in deps.js or depgraph files, because it may return * strings like 'otiSupported' and 'ntiSupported' which are not real language modes. */ public String versionForDebugging() { if (ES3.contains(this)) { return "es3"; } if (ES5.contains(this)) { return "es5"; } if (TYPE_CHECK_SUPPORTED.contains(this)) { return "typeCheckSupported"; } if (ES6_MODULES.contains(this)) { return "es6"; } if (ES7_MODULES.contains(this)) { return "es7"; } if (ES8_MODULES.contains(this)) { return "es8"; } if (ES2018_MODULES.contains(this)) { return "es9"; } if (ES2019_MODULES.contains(this)) { return "es_2019"; } if (ES_NEXT.contains(this)) { return "es_next"; } if (ES_UNSUPPORTED.contains(this)) { return "es_unsupported"; } if (TYPESCRIPT.contains(this)) { return "ts"; } throw new IllegalStateException(this.toString()); } public FeatureSet without(Feature featureToRemove, Feature... moreFeaturesToRemove) { return new FeatureSet(difference(features, EnumSet.of(featureToRemove, moreFeaturesToRemove))); } public FeatureSet without(FeatureSet other) { return new FeatureSet(difference(features, other.features)); } public FeatureSet withoutTypes() { return new FeatureSet(difference(features, LangVersion.TYPESCRIPT.features())); } /** * Returns a new {@link FeatureSet} including all features of both {@code this} and {@code other}. */ public FeatureSet union(FeatureSet other) { return new FeatureSet(union(features, other.features)); } /** * Does this {@link FeatureSet} contain all of the features of {@code other}? */ public boolean contains(FeatureSet other) { return this.features.containsAll(other.features); } /** * Does this {@link FeatureSet} contain the given feature? */ public boolean contains(Feature feature) { return this.features.containsAll(EnumSet.of(feature)); } private static EnumSet emptyEnumSet() { return EnumSet.noneOf(Feature.class); } private static EnumSet enumSetOf(Set set) { return set.isEmpty() ? emptyEnumSet() : EnumSet.copyOf(set); } private static EnumSet add(Set features, Feature feature) { EnumSet result = enumSetOf(features); result.add(feature); return result; } private static EnumSet union(Set features, Set newFeatures) { EnumSet result = enumSetOf(features); result.addAll(newFeatures); return result; } private static EnumSet difference(Set features, Set removedFeatures) { EnumSet result = enumSetOf(features); result.removeAll(removedFeatures); return result; } /** Returns a feature set combining all the features from {@code this} and {@code feature}. */ public FeatureSet with(Feature feature) { if (features.contains(feature)) { return this; } return new FeatureSet(add(features, feature)); } /** Returns a feature set combining all the features from {@code this} and {@code newFeatures}. */ @VisibleForTesting public FeatureSet with(Feature... newFeatures) { return new FeatureSet(union(features, ImmutableSet.copyOf(newFeatures))); } /** Returns a feature set combining all the features from {@code this} and {@code newFeatures}. */ @VisibleForTesting public FeatureSet with(Set newFeatures) { return new FeatureSet(union(features, newFeatures)); } /** Returns a feature set combining all the features from {@code this} and {@code newFeatures}. */ @VisibleForTesting public FeatureSet with(FeatureSet newFeatures) { return new FeatureSet(union(features, newFeatures.features)); } /** * Does this {@link FeatureSet} include {@code feature}? */ public boolean has(Feature feature) { return features.contains(feature); } public ImmutableSet getFeatures() { return features; } @Override public boolean equals(Object other) { return other instanceof FeatureSet && ((FeatureSet) other).features.equals(features); } @Override public int hashCode() { return features.hashCode(); } @Override public String toString() { return features.toString(); } /** Parses known strings into feature sets. */ public static FeatureSet valueOf(String name) { switch (name) { case "es3": return ES3; case "es5": return ES5; case "es6": return ES6; case "typeCheckSupported": return TYPE_CHECK_SUPPORTED; case "es7": return ES7; case "es8": return ES8; case "es2018": case "es9": return ES2018; case "es_2019": return ES2019; case "es_next": return ES_NEXT; case "ts": return TYPESCRIPT; default: throw new IllegalArgumentException("No such FeatureSet: " + name); } } public static FeatureSet all() { return TYPESCRIPT; } public static FeatureSet latest() { return ES_NEXT; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy