com.google.javascript.jscomp.deps.ModuleNames Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of closure-compiler-unshaded Show documentation
Show all versions of closure-compiler-unshaded Show documentation
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.
/*
* Copyright 2016 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.deps;
import com.google.common.base.Joiner;
import java.util.Arrays;
/**
* Static methods related to module names.
*/
public class ModuleNames {
private ModuleNames() {} // Static methods only; do not instantiate.
/** According to the spec, the forward slash should be the delimiter on all platforms. */
static final String MODULE_SLASH = "/";
/** To join together normalized module names. */
private static final Joiner MODULE_JOINER = Joiner.on(MODULE_SLASH);
/** Returns a module name for an absolute path, with no resolution or checking. */
public static String fileToModuleName(String path) {
return toModuleName(escapePath(path));
}
/** Returns a module name for an absolute path, with no resolution or checking. */
public static String fileToJsIdentifier(String path) {
return toJSIdentifier(escapePath(path));
}
/** Escapes the given input path. */
static String escapePath(String input) {
// Handle special characters
String encodedInput = input.replace(':', '-')
.replace('\\', '/')
.replace(" ", "%20")
.replace("[", "%5B")
.replace("]", "%5D")
.replace("<", "%3C")
.replace(">", "%3E");
return canonicalizePath(encodedInput);
}
static String toJSIdentifier(String path) {
return stripJsExtension(path)
.replaceFirst("^\\./", "")
.replace(MODULE_SLASH, "$")
.replace('\\', '$')
.replace('@', '$')
.replace('+', '$')
.replace('-', '_')
.replace(':', '_')
.replace('.', '_')
.replace("%20", "_");
}
static String toModuleName(String path) {
if (path.startsWith(MODULE_SLASH)) {
path = path.substring(1);
}
return "module$" + toJSIdentifier(path);
}
private static String stripJsExtension(String fileName) {
if (fileName.endsWith(".js")) {
fileName = fileName.substring(0, fileName.length() - ".js".length());
// internal intermediary file format ".js.i.js"
if (fileName.endsWith(".js.i")) {
fileName = fileName.substring(0, fileName.length() - ".js.i".length());
}
}
return fileName;
}
/**
* Canonicalize a given path, removing segments containing "." and consuming segments for "..".
*
* If no segment could be consumed for "..", retains the segment.
*/
static String canonicalizePath(String path) {
String[] parts = path.split(MODULE_SLASH);
String[] buffer = new String[parts.length];
int position = 0;
int available = 0;
boolean absolutePath = (parts.length > 1 && parts[0].isEmpty());
if (absolutePath) {
// If the path starts with "/" (so the left side, index zero, is empty), then the path will
// always remain absolute. Make the first segment unavailable to touch.
--available;
}
for (String part : parts) {
if (part.equals(".")) {
continue;
}
if (part.equals("..")) {
if (available > 0) {
// Consume the previous segment.
--position;
--available;
buffer[position] = null;
} else if (!absolutePath) {
// If this is a relative path, retain "..", as it can't be consumed on the left.
buffer[position] = part;
++position;
}
continue;
}
buffer[position] = part;
++position;
++available;
}
if (absolutePath && position == 1) {
return MODULE_SLASH; // special-case single absolute segment as joining [""] doesn't work
}
return MODULE_JOINER.join(Arrays.copyOf(buffer, position));
}
}