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

com.google.javascript.jscomp.SourceMapResolver Maven / Gradle / Ivy

/*
 * Copyright 2017 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 java.nio.charset.StandardCharsets.UTF_8;

import com.google.common.annotations.GwtIncompatible;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableSet;
import com.google.common.io.BaseEncoding;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.FileSystems;
import javax.annotation.Nullable;

/** Utility class for resolving source maps and files referenced in source maps. */
@GwtIncompatible("Accesses the file system")
public class SourceMapResolver {
  private static final String BASE64_URL_PREFIX = "data:";
  private static final String BASE64_START = "base64,";

  // For now only accept UTF-8. We could use the actual charset information in the future.
  private static final ImmutableSet ACCEPTED_MEDIA_TYPES = ImmutableSet.of(
      "application/json;charset=utf-8;",
      // default is UTF-8 if unspecified.
      "application/json;");

  /**
   * For a given //# sourceMappingUrl, this locates the appropriate sourcemap on disk. This is use
   * for sourcemap merging (--apply_input_source_maps) and for error resolution.
   *
   * @param parseInlineSourceMaps Whether to parse Base64 encoded source maps.
   */
  static SourceFile extractSourceMap(
      SourceFile jsFile, String sourceMapURL, boolean parseInlineSourceMaps) {
    if (parseInlineSourceMaps && sourceMapURL.startsWith(BASE64_URL_PREFIX)) {
      String extractedString = extractBase64String(sourceMapURL);
      if (extractedString != null) {
        return SourceFile.fromCode(jsFile.getName() + ".inline.map", extractedString);
      }
      return null;
    }
    // TODO(tdeegan): Handle absolute urls here.  The compiler needs to come up with a scheme for
    // properly resolving absolute urls from http:// or the root /some/abs/path/... See b/62544959.
    if (isAbsolute(sourceMapURL)) {
      return null;
    }
    // If not absolute, its relative.
    // TODO(tdeegan): Handle urls relative to //# sourceURL. See the sourcemap spec.
    return getRelativePath(jsFile.getName(), sourceMapURL);
  }

  /**
   * Based on https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs
   * @param url
   * @return String or null.
   */
  @Nullable
  private static String extractBase64String(String url) {
    if (url.startsWith(BASE64_URL_PREFIX) && url.contains(BASE64_START)) {
      int base64StartIndex = url.indexOf(BASE64_START);
      String mediaType = url.substring(BASE64_URL_PREFIX.length(), base64StartIndex);
      if (ACCEPTED_MEDIA_TYPES.contains(mediaType)) {
        byte[] data = BaseEncoding.base64().decode(
                url.substring(base64StartIndex + BASE64_START.length()));
        return new String(data, UTF_8);
      }
    }
    return null;
  }

  @VisibleForTesting
  private static boolean isAbsolute(String url) {
    try {
      return new URI(url).isAbsolute() || url.startsWith("/");
    } catch (URISyntaxException e) {
      throw new RuntimeException("Sourcemap url was invalid: " + url, e);
    }
  }

  /**
   * Returns the relative path, resolved relative to the base path, where the base path is
   * interpreted as a filename rather than a directory. E.g.: getRelativeTo("../foo/bar.js",
   * "baz/bam/qux.js") --> "baz/foo/bar.js"
   */
  @Nullable
  static SourceFile getRelativePath(String baseFilePath, String relativePath) {
    return SourceFile.fromPath(
        FileSystems.getDefault().getPath(baseFilePath).resolveSibling(relativePath).normalize(),
        UTF_8);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy