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

com.google.javascript.jscomp.JsIterables 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.

There is a newer version: v20240317
Show newest version
/*
 * Copyright 2014 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;

import static com.google.javascript.rhino.jstype.JSTypeNative.ASYNC_ITERABLE_TYPE;
import static com.google.javascript.rhino.jstype.JSTypeNative.ITERABLE_TYPE;
import static com.google.javascript.rhino.jstype.JSTypeNative.UNKNOWN_TYPE;

import com.google.javascript.rhino.jstype.JSType;
import com.google.javascript.rhino.jstype.JSTypeRegistry;
import com.google.javascript.rhino.jstype.TemplateType;
import com.google.javascript.rhino.jstype.TemplateTypeMap;
import java.util.ArrayList;
import java.util.List;
import org.jspecify.nullness.Nullable;

/**
 * Models type transformations of JavaScript `Iterable` and `Iterator` types.
 *
 * 

These tranformations can be especially helpful when working with generator functions. * `Generator` is a subtype of `Iterable`. */ final class JsIterables { /** * Returns the given `Iterable`s element type. * *

If the given type is not an `Iterator`, `Iterable`, `AsyncIterator`, or `AsyncIterable`, * returns the unknown type. */ static final JSType getElementType(JSType iterableOrIterator, JSTypeRegistry typeRegistry) { TemplateTypeMap templateTypeMap = iterableOrIterator // Remember that `string` will box to a `Iterable`. .autobox() .getTemplateTypeMap(); if (templateTypeMap.hasTemplateKey(typeRegistry.getIterableTemplate())) { // `Iterable` or `Generator` return templateTypeMap.getResolvedTemplateType(typeRegistry.getIterableTemplate()); } else if (templateTypeMap.hasTemplateKey(typeRegistry.getIteratorValueTemplate())) { // `Iterator` return templateTypeMap.getResolvedTemplateType(typeRegistry.getIteratorValueTemplate()); } else if (templateTypeMap.hasTemplateKey(typeRegistry.getAsyncIterableTemplate())) { // `AsyncIterable` or `AsyncGenerator` return templateTypeMap.getResolvedTemplateType(typeRegistry.getAsyncIterableTemplate()); } else if (templateTypeMap.hasTemplateKey(typeRegistry.getAsyncIteratorValueTemplate())) { // `AsyncIterator` return templateTypeMap.getResolvedTemplateType(typeRegistry.getAsyncIteratorValueTemplate()); } return typeRegistry.getNativeType(UNKNOWN_TYPE); } /** * Returns an `Iterable` type templated on {@code elementType}. * *

Example: `number' => `Iterable`. */ static final JSType createIterableTypeOf(JSType elementType, JSTypeRegistry typeRegistry) { return typeRegistry.createTemplatizedType( typeRegistry.getNativeObjectType(ITERABLE_TYPE), elementType); } /** * The template of an Iterable|AsyncIterable, or a mismatch if subtype of Iterable|AsyncIterable. */ static final class MaybeBoxedType { private final JSType templatedType; private final JSType mismatchType; /** * @param templatedType the unwrapped type that is being yieled by the iterable / async * iterable. e.g. in {@code Iterable|AsyncIterable|string}, this should be * {@code number|Qux|string}. Null if a mismatch. * @param mismatchType the type that caused the mismatch. This can be the entire type (e.g. * {@code number} is not iterable or async iterable) or a piece of a union that caused the * mismatch (e.g. {@code number} in {@code number|Iterable}). Null if a match. */ private MaybeBoxedType(@Nullable JSType templatedType, @Nullable JSType mismatchType) { this.templatedType = templatedType; this.mismatchType = mismatchType; } /** * @return the template of the iterable / async iterable * @throws if not an iterable / async iterable */ JSType getTemplatedType() { if (!isMatch()) { throw new IllegalStateException("Type was not boxable to iterable or async iterable!"); } return templatedType; } /** @return the type that caused the mismatch, if any */ JSType getMismatchType() { return mismatchType; } JSType orElse(JSType type) { if (isMatch()) { return templatedType; } return type; } boolean isMatch() { return templatedType != null; } } /** * Returns the template for iterable types. * *

This does not apply to async-iterables. * *

If this value is not an Iterable, we return a sentinel. */ static final MaybeBoxedType maybeBoxIterable(JSType type, JSTypeRegistry typeRegistry) { return maybeBoxIterableAndPossiblyAsyncIterable( type, typeRegistry, /* includeAsyncIterable= */ false); } /** * Returns the template for iterable or async-iterable types. * *

If this value is not an Iterable or AsyncIterable, we return a sentinel. */ static final MaybeBoxedType maybeBoxIterableOrAsyncIterable( JSType type, JSTypeRegistry typeRegistry) { return maybeBoxIterableAndPossiblyAsyncIterable( type, typeRegistry, /* includeAsyncIterable= */ true); } /** * Given a type, if it is an iterable or async iterable, will return its template. If not a * subtype of Iterable|AsyncIterable, returns an object that has no match, and will indicate the * mismatch. e.g. both {@code number} and {@code number|Iterable} are not subtypes of * Iterable|AsyncIterable. * * @param includeAsyncIterable whether to look for AsyncIterable as opposed to just Iterable */ private static final MaybeBoxedType maybeBoxIterableAndPossiblyAsyncIterable( JSType type, JSTypeRegistry typeRegistry, boolean includeAsyncIterable) { List templatedTypes = new ArrayList<>(); // Note: we don't just use JSType.autobox() here because that removes null and undefined. // We want to keep null and undefined around because they should cause a mismatch. if (type.isUnionType()) { for (JSType alt : type.toMaybeUnionType().getAlternates()) { alt = alt.isBoxableScalar() ? alt.autoboxesTo() : alt; boolean isIterable = alt.isSubtypeOf(typeRegistry.getNativeType(ITERABLE_TYPE)); boolean isAsyncIterable = includeAsyncIterable && alt.isSubtypeOf(typeRegistry.getNativeType(ASYNC_ITERABLE_TYPE)); if (!isIterable && !isAsyncIterable) { return new MaybeBoxedType(null, alt); } TemplateType valueTemplate = isAsyncIterable ? typeRegistry.getAsyncIterableTemplate() : typeRegistry.getIterableTemplate(); templatedTypes.add(alt.getTemplateTypeMap().getResolvedTemplateType(valueTemplate)); } } else { JSType autoboxedType = type.isBoxableScalar() ? type.autoboxesTo() : type; boolean isIterable = autoboxedType.isSubtypeOf(typeRegistry.getNativeType(ITERABLE_TYPE)); boolean isAsyncIterable = includeAsyncIterable && autoboxedType.isSubtypeOf(typeRegistry.getNativeType(ASYNC_ITERABLE_TYPE)); if (!isIterable && !isAsyncIterable) { return new MaybeBoxedType(null, autoboxedType); } TemplateType templateType = isAsyncIterable ? typeRegistry.getAsyncIterableTemplate() : typeRegistry.getIterableTemplate(); templatedTypes.add(autoboxedType.getTemplateTypeMap().getResolvedTemplateType(templateType)); } return new MaybeBoxedType(typeRegistry.createUnionType(templatedTypes), null); } private JsIterables() {} }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy