/*
* Copyright 2015 Google Inc.
*
* 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.template.soy.jssrc.internal;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.template.soy.soytree.CallBasicNode;
import com.google.template.soy.soytree.SoyFileNode;
import com.google.template.soy.soytree.SoyTreeUtils;
import com.google.template.soy.soytree.TemplateBasicNode;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
final class AliasUtils {
private AliasUtils() {}
private static final class Aliases implements TemplateAliases {
final ImmutableMap<String, String> aliasMapping;
Aliases(Map<String, String> aliasMapping) {
this.aliasMapping = ImmutableMap.copyOf(aliasMapping);
}
@Override
public String get(String fullyQualifiedName) {
String alias = aliasMapping.get(fullyQualifiedName);
Preconditions.checkState(alias != null);
return alias;
}
}
private static final String TEMPLATE_ALIAS_PREFIX = "$templateAlias";
static final TemplateAliases IDENTITY_ALIASES =
new TemplateAliases() {
@Override
public String get(String fullyQualifiedName) {
return fullyQualifiedName;
}
};
static boolean isExternalFunction(String alias) {
return alias.startsWith(TEMPLATE_ALIAS_PREFIX);
}
/**
* Creates a mapping for assigning and looking up the variable alias for templates both within a
* file and referenced from external files. For local files, the alias is just the local
* template's name. For external templates, the alias is an identifier that is unique for that
* template.
*
* <p>For V1 templates, no alias is generated and the template should be called by the fully
* qualified name.
*
* @param fileNode The {@link SoyFileNode} to create an alias mapping for.
* @return A {@link TemplateAliases} to look up aliases with.
*/
static TemplateAliases createTemplateAliases(SoyFileNode fileNode) {
Map<String, String> aliasMap = new HashMap<>();
Set<String> localTemplates = new HashSet<>();
int counter = 0;
// Go through templates first and just alias them to their local name.
for (TemplateBasicNode templateBasicNode :
SoyTreeUtils.getAllNodesOfType(fileNode, TemplateBasicNode.class)) {
String partialName = templateBasicNode.getPartialTemplateName();
String fullyQualifiedName = templateBasicNode.getTemplateName();
localTemplates.add(fullyQualifiedName);
Preconditions.checkState(partialName != null, "Aliasing not supported for V1 templates");
// Need to start the alias with something that cannot be a part of a reserved
// JavaScript identifier like 'function' or 'catch'.
String alias = "$" + partialName.substring(1);
aliasMap.put(fullyQualifiedName, alias);
}
// Go through all call sites looking for foreign template calls and create an alias for them.
for (CallBasicNode callBasicNode :
SoyTreeUtils.getAllNodesOfType(fileNode, CallBasicNode.class)) {
String fullyQualifiedName = callBasicNode.getCalleeName();
// We could have either encountered the foreign fully qualified name before or it could belong
// to a local template.
if (localTemplates.contains(fullyQualifiedName) || aliasMap.containsKey(fullyQualifiedName)) {
continue;
}
String alias = TEMPLATE_ALIAS_PREFIX + (++counter);
aliasMap.put(fullyQualifiedName, alias);
}
return new Aliases(aliasMap);
}
}