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

com.google.javascript.refactoring.ScriptMetadata 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.

The 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.refactoring;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;

import com.google.common.base.Splitter;
import com.google.javascript.jscomp.AbstractCompiler;
import com.google.javascript.jscomp.NodeTraversal;
import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback;
import com.google.javascript.jscomp.NodeUtil;
import com.google.javascript.rhino.JSDocInfo;
import com.google.javascript.rhino.JSTypeExpression;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.QualifiedName;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import org.jspecify.nullness.Nullable;

/**
 * A summary of a script for use during fixes.
 *
 * 

Instances are mutable so that changes to a script caused by one fix cen be reflected during * subseuqent fixes. */ public final class ScriptMetadata { private final Node script; private boolean supportsRequireAliases; private final LinkedHashMap requireAliases = new LinkedHashMap<>(); private final LinkedHashSet namesInUse = new LinkedHashSet<>(); static ScriptMetadata create(Node script, NodeMetadata metadata) { return create(script, metadata.getCompiler()); } public static ScriptMetadata create(Node script, AbstractCompiler compiler) { checkArgument(script.isScript()); ScriptMetadata toFill = new ScriptMetadata(script); NodeTraversal.traverse(compiler, script, new FillerCallback(toFill)); // Even if the file was not found to be a module, the existence of other aliases means aliases // are supported. if (!toFill.requireAliases.isEmpty()) { toFill.supportsRequireAliases = true; } return toFill; } private ScriptMetadata(Node script) { this.script = script; } Node getScript() { return this.script; } /** When requires are added to this script, should they be given local aliases? */ boolean supportsRequireAliases() { return this.supportsRequireAliases; } /** * Is `name` in use within this script? * *

This includes both executable and JsDoc references. */ boolean usesName(String name) { return this.namesInUse.contains(name); } /** * Returns the local alias for `namespace`. * *

If `namespace` is not required or has no alias, returns `null`. In particular, destructured * aliases will not be available. */ @Nullable String getAlias(String namespace) { return this.requireAliases.get(namespace); } /** * Record that `namespace` has ben required with local alias `alias`. * *

As a corallary, any alias is also a name in use within this script. */ void addAlias(String namespace, String alias) { checkState(this.supportsRequireAliases); this.namesInUse.add(alias); this.requireAliases.put(namespace, alias); } private static class FillerCallback extends AbstractPostOrderCallback { private static final QualifiedName GOOG_MODULE = QualifiedName.of("goog.module"); private static final QualifiedName GOOG_REQUIRE = QualifiedName.of("goog.require"); private static final QualifiedName GOOG_REQUIRETYPE = QualifiedName.of("goog.requireType"); private static final QualifiedName GOOG_FORWARDDECLARE = QualifiedName.of("goog.forwardDeclare"); private final ScriptMetadata toFill; public FillerCallback(ScriptMetadata toFill) { this.toFill = toFill; } @Override public void visit(NodeTraversal nodeTraversal, Node n, Node parent) { this.updateSupportsRequireAlias(n); this.maybeCollectRequirelikeAlias(n); this.maybeCollectNames(n); } private void updateSupportsRequireAlias(Node n) { switch (n.getToken()) { case MODULE_BODY: break; case CALL: if (n.getChildCount() != 2 || !GOOG_MODULE.matches(n.getFirstChild()) || !n.getSecondChild().isStringLit()) { return; } break; default: return; } this.toFill.supportsRequireAliases = true; } private void maybeCollectRequirelikeAlias(Node n) { if (!NodeUtil.isNameDeclaration(n)) { return; } Node aliasNode = n.getFirstChild(); // TODO(b/139953612): respect destructured goog.requires if (aliasNode.isDestructuringLhs()) { return; } Node requirelikeCall = aliasNode.getFirstChild(); if (!this.isRequirelikeCall(requirelikeCall)) { return; } String alias = aliasNode.getOriginalName(); if (alias == null) { alias = aliasNode.getString(); } String namespace = requirelikeCall.getSecondChild().getString(); this.toFill.requireAliases.put(namespace, alias); } private boolean isRequirelikeCall(Node call) { if (call == null || !call.isCall() || call.getChildCount() != 2 || !call.getSecondChild().isStringLit()) { return false; } Node callee = call.getFirstChild(); return GOOG_REQUIRE.matches(callee) || GOOG_REQUIRETYPE.matches(callee) || GOOG_FORWARDDECLARE.matches(callee); } private void maybeCollectNames(Node n) { if (n.isName()) { this.toFill.namesInUse.add(n.getString()); } JSDocInfo jsdoc = n.getJSDocInfo(); if (jsdoc != null) { for (JSTypeExpression expr : jsdoc.getTypeExpressions()) { for (String type : expr.getAllTypeNames()) { this.toFill.namesInUse.add(DOT_SPLITTER.split(type).iterator().next()); } } } } } private static final Splitter DOT_SPLITTER = Splitter.on('.'); }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy