use of com.google.javascript.jscomp.modules.Binding in project closure-compiler by google.
the class RewriteGoogJsImports method process.
@Override
public void process(Node externs, Node root) {
googModule = null;
Node googJsScriptNode = findGoogJsScriptNode(root);
if (googJsScriptNode == null) {
// Potentially in externs if library level type checking.
googJsScriptNode = findGoogJsScriptNode(externs);
}
if (mode == Mode.LINT_AND_REWRITE) {
if (googJsScriptNode != null) {
ModulePath googJsPath = compiler.getInput(googJsScriptNode.getInputId()).getPath();
googModule = moduleMap.getModule(googJsPath);
checkNotNull(googModule);
Predicate<Binding> isFromGoog = (Binding b) -> b.originatingExport().modulePath() == googJsPath;
checkState(googModule.boundNames().values().stream().allMatch(isFromGoog), "goog.js should never import anything");
checkState(!googModule.namespace().containsKey("default"), "goog.js should never have a default export.");
checkState(googModule.namespace().values().stream().allMatch(isFromGoog), "goog.js should never export from anything.");
}
} else {
checkState(mode == Mode.LINT_ONLY);
}
for (Node script = root.getFirstChild(); script != null; script = script.getNext()) {
rewriteImports(script);
}
changeModules();
}
use of com.google.javascript.jscomp.modules.Binding in project closure-compiler by google.
the class PolymerBehaviorExtractor method resolveModuleNamespaceBinding.
/**
* Resolves a name that imports the 'namespace' of a module or provide.
*/
private ResolveBehaviorNameResult resolveModuleNamespaceBinding(Binding b, String rest) {
if (b.metadata().isGoogModule()) {
return resolveBehaviorName(GOOG_MODULE_EXPORTS + rest, b.metadata());
} else if (b.metadata().isGoogProvide()) {
return resolveBehaviorName(b.closureNamespace() + rest, b.metadata());
}
// ES module import *.
checkState(b.metadata().isEs6Module());
if (rest.isEmpty()) {
// The namespace imported by `import *` is never a @polymerBehavior.
return FAILED_RESOLVE_RESULT;
}
// Remove leading '.'.
rest = rest.substring(1);
int dot = rest.indexOf('.');
// Given:
// `const internalName = 0; export {internalName as exportName};`
// `import * as mod from './x'; use(mod.exportName.Behavior);`
// 1. get the internal name `internalName` from` exportName`.
// 2. then proceed to resolve `internalName.Behavior` in './x'.
String exportedName = dot == -1 ? rest : rest.substring(0, dot);
Module originalModule = moduleMap.getModule(b.metadata().path());
Binding exportBinding = originalModule.namespace().get(exportedName);
if (exportBinding == null || !exportBinding.isCreatedByEsExport()) {
// This is an invalid import, and will cause an error elsewhere.
return FAILED_RESOLVE_RESULT;
}
return resolveBehaviorName(exportBinding.originatingExport().localName() + (dot == -1 ? "" : rest.substring(dot)), b.metadata());
}
use of com.google.javascript.jscomp.modules.Binding in project closure-compiler by google.
the class ModuleImportResolver method declareEsModuleImports.
/**
* Declares/updates the type of all bindings imported into the ES module scope
*
* @return A map from local nodes to ScopedNames for which {@link #nodeToScopeMapper} couldn't
* find a scope, despite the original module existing. This is expected to happen for circular
* references if not all module scopes are created and the caller should handle declaring
* these names later, e.g. in TypedScopeCreator.
*/
Map<Node, ScopedName> declareEsModuleImports(Module module, TypedScope scope, CompilerInput moduleInput) {
checkArgument(module.metadata().isEs6Module(), module);
checkArgument(scope.isModuleScope(), scope);
ImmutableMap.Builder<Node, ScopedName> missingNames = ImmutableMap.builder();
for (Map.Entry<String, Binding> boundName : module.boundNames().entrySet()) {
Binding binding = boundName.getValue();
String localName = boundName.getKey();
if (!binding.isCreatedByEsImport()) {
continue;
}
// ES imports fall into two categories:
// - namespace imports. These correspond to an object type containing all named exports.
// - named imports. These always correspond, eventually, to a name local to a module.
// Note that we include imports of an `export default` in this case and map them to a
// pseudo-variable named *default*.
ScopedName export = getScopedNameFromEsBinding(binding);
TypedScope modScope = nodeToScopeMapper.apply(export.getScopeRoot());
if (modScope == null) {
checkState(binding.sourceNode().getString().equals(localName), binding.sourceNode());
missingNames.put(binding.sourceNode(), export);
continue;
}
TypedVar originalVar = modScope.getVar(export.getName());
JSType importType = originalVar.getType();
scope.declare(localName, binding.sourceNode(), importType, moduleInput, /* inferred= */
originalVar.isTypeInferred());
// export and import bindings, if not already there.
if (!binding.isModuleNamespace() && binding.sourceNode().getTypedefTypeProp() == null) {
JSType typedefType = originalVar.getNameNode().getTypedefTypeProp();
if (typedefType != null) {
binding.sourceNode().setTypedefTypeProp(typedefType);
registry.declareType(scope, localName, typedefType);
}
}
}
return missingNames.buildOrThrow();
}
use of com.google.javascript.jscomp.modules.Binding in project closure-compiler by google.
the class ModuleImportResolver method updateEsModuleNamespaceType.
/**
* Declares or updates the type of properties representing exported names from ES module
*
* <p>When the given object type does not have existing properties corresponding to exported
* names, this method adds new properties to the object type. If the object type already has
* properties, this method will ignore declared properties and update the type of inferred
* properties.
*
* <p>The additional properties will be inferred (instead of declared) if and only if {@link
* TypedVar#isTypeInferred()} is true for the original exported name.
*
* <p>We create this type to support 'import *' and goog.requires of this module. Note: we could
* lazily initialize this type if always creating it hurts performance.
*
* @param namespace An object type which may already have properties representing exported names.
* @param scope The scope rooted at the given module.
*/
void updateEsModuleNamespaceType(ObjectType namespace, Module module, TypedScope scope) {
checkArgument(module.metadata().isEs6Module(), module);
checkArgument(scope.isModuleScope(), scope);
for (Map.Entry<String, Binding> boundName : module.namespace().entrySet()) {
String exportKey = boundName.getKey();
if (namespace.isPropertyTypeDeclared(exportKey)) {
// Cannot change the type of a declared property after it is added to the ObjectType.
continue;
}
Binding binding = boundName.getValue();
// e.g. 'x' in `export let x;` or `export {x};`
Node bindingSourceNode = binding.sourceNode();
ScopedName export = getScopedNameFromEsBinding(binding);
TypedScope originalScope = export.getScopeRoot() == scope.getRootNode() ? scope : nodeToScopeMapper.apply(export.getScopeRoot());
if (originalScope == null) {
// Exporting an import from an invalid module load or early reference.
namespace.defineInferredProperty(exportKey, registry.getNativeType(JSTypeNative.UNKNOWN_TYPE), bindingSourceNode);
updateAstForExport(bindingSourceNode, registry.getNativeType(JSTypeNative.UNKNOWN_TYPE), /* typedefType= */
null);
continue;
}
TypedVar originalName = originalScope.getSlot(export.getName());
JSType exportType = originalName.getType();
if (exportType == null) {
exportType = registry.getNativeType(JSTypeNative.NO_TYPE);
}
if (originalName.isTypeInferred()) {
// NB: this method may be either adding a new inferred property or updating the type of an
// existing inferred property.
namespace.defineInferredProperty(exportKey, exportType, bindingSourceNode);
} else {
namespace.defineDeclaredProperty(exportKey, exportType, bindingSourceNode);
}
updateAstForExport(bindingSourceNode, exportType, originalName.getNameNode().getTypedefTypeProp());
}
}
use of com.google.javascript.jscomp.modules.Binding in project closure-compiler by google.
the class PolymerBehaviorExtractor method getNameIfModuleImport.
/**
* Handles resolving behaviors whose root is imported from another module or a provide.
*
* <p>Returns null if the given name is not imported or {@link #FAILED_RESOLVE_RESULT} if it is
* imported but is not annotated @polymerBehavior.
*/
private ResolveBehaviorNameResult getNameIfModuleImport(String name, ModuleMetadata metadata) {
if (metadata == null || (!metadata.isEs6Module() && !metadata.isGoogModule())) {
return null;
}
Module module = metadata.isGoogModule() ? moduleMap.getClosureModule(metadata.googNamespaces().asList().get(0)) : moduleMap.getModule(metadata.path());
checkNotNull(module, metadata);
int dot = name.indexOf('.');
String root = dot == -1 ? name : name.substring(0, dot);
Binding b = module.boundNames().get(root);
if (b == null || !b.isSomeImport()) {
return null;
}
String rest = dot == -1 ? "" : name.substring(dot);
if (b.isModuleNamespace()) {
// `import * as x from '';` or `const ns = goog.require('...`
return resolveModuleNamespaceBinding(b, rest);
}
ModuleMetadata importMetadata = b.originatingExport().moduleMetadata();
// The name in the module being imported
String originatingName;
if (importMetadata.isEs6Module()) {
// import {exportName} from './mod';
originatingName = b.originatingExport().localName() + rest;
} else if (importMetadata.isGoogModule()) {
// `const {exportName: localName} = goog.require('some.module');`
originatingName = GOOG_MODULE_EXPORTS + "." + b.originatingExport().exportName() + rest;
} else {
// `const {exportName: localName} = goog.require('some.provide');`
checkState(importMetadata.isGoogProvide(), importMetadata);
originatingName = b.closureNamespace() + "." + b.originatingExport().exportName() + rest;
}
return resolveBehaviorName(originatingName, importMetadata);
}
Aggregations