chore(6.0): remove concatjs package
It should move to https://github.com/angular/dev-infra which is the only consumer that has resources to maintain it.
diff --git a/internal/js_library/js_library.bzl b/internal/js_library/js_library.bzl
index d387f94..96e962c 100644
--- a/internal/js_library/js_library.bzl
+++ b/internal/js_library/js_library.bzl
@@ -56,7 +56,7 @@
"named_module_srcs": attr.label_list(
doc = """Non-public legacy API, not recommended to make new usages.
A subset of srcs that are javascript named-UMD or
- named-AMD for use in rules such as concatjs_devserver.
+ named-AMD.
They will be copied into the package bin folder if needed.""",
allow_files = True,
),
@@ -350,10 +350,6 @@
)
```
- > To help work with "named AMD" modules as required by `concatjs_devserver` and other Google-style "concatjs" rules,
- > `js_library` has some undocumented advanced features you can find in the source code or in our examples.
- > These should not be considered a public API and aren't subject to our usual support and semver guarantees.
-
### Outputs
Like all Bazel rules it produces a default output by providing [DefaultInfo].
diff --git a/internal/providers/js_providers.bzl b/internal/providers/js_providers.bzl
index a9c3b71..c6e9a9d 100644
--- a/internal/providers/js_providers.bzl
+++ b/internal/providers/js_providers.bzl
@@ -40,7 +40,6 @@
doc = """JavaScript files whose module name is self-contained.
For example named AMD/UMD or goog.module format.
-These files can be efficiently served with the concatjs bundler.
These outputs should be named "foo.umd.js"
(note that renaming it from "foo.js" doesn't affect the module id)
diff --git a/packages/concatjs/BUILD.bazel b/packages/concatjs/BUILD.bazel
deleted file mode 100644
index 28bc65b..0000000
--- a/packages/concatjs/BUILD.bazel
+++ /dev/null
@@ -1,112 +0,0 @@
-# Copyright 2017 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-load("replacements.bzl", "TYPESCRIPT_REPLACEMENTS")
-load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
-load("@build_bazel_rules_nodejs//:index.bzl", "js_library")
-load("@build_bazel_rules_nodejs//:tools/defaults.bzl", "pkg_npm")
-load("@build_bazel_rules_nodejs//packages/typescript:index.bzl", "ts_project")
-load("@build_bazel_rules_nodejs//tools/stardoc:index.bzl", "stardoc")
-load("//third_party/github.com/bazelbuild/bazel-skylib:rules/copy_file.bzl", "copy_file")
-
-ts_project(
- name = "bazel_concatjs_lib",
- srcs = glob(["*.ts"]),
- tsconfig = {
- "compilerOptions": {
- "declaration": True,
- "module": "umd",
- "moduleResolution": "node",
- "types": ["node"],
- },
- },
- deps = [
- "@npm//@types/node",
- "@npm//karma",
- ],
-)
-
-js_library(
- name = "bazel_concatjs",
- package_name = "@bazel/concatjs",
- srcs = ["bazel_concatjs_lib"],
- visibility = ["//packages/concatjs:__subpackages__"],
-)
-
-bzl_library(
- name = "bzl",
- testonly = True,
- srcs = glob(["*.bzl"]),
- deps = [
- "//packages/concatjs/devserver:bzl",
- "//packages/concatjs/internal:bzl",
- "//packages/concatjs/web_test:bzl",
- "@bazel_skylib//lib:types",
- "@build_bazel_rules_nodejs//:bzl",
- "@build_bazel_rules_nodejs//internal/common:bzl",
- "@build_bazel_rules_nodejs//internal/node:bzl",
- "@rules_nodejs//nodejs:bzl",
- ],
-)
-
-stardoc(
- name = "docs",
- testonly = True,
- out = "README.md_",
- input = "index.docs.bzl",
- tags = ["fix-windows"],
- deps = [":bzl"],
-)
-
-genrule(
- name = "docs_scrub_platform",
- srcs = ["README.md_"],
- outs = ["README.md"],
- cmd = "sed -e 's#devserver:devserver_.*_a[mr][dm]64#devserver:devserver_[platform]#' <$< >$@",
- visibility = ["//docs:__pkg__"],
-)
-
-copy_file(
- name = "npm_version_check",
- src = "//internal:npm_version_check.js",
- out = ":npm_version_check.js",
-)
-
-pkg_npm(
- name = "npm_package",
- package_name = "@bazel/concatjs",
- srcs = [
- "index.bzl",
- "package.json",
- "//packages/concatjs/devserver:package_contents",
- "//packages/concatjs/internal:package_contents",
- "//packages/concatjs/third_party/github.com/bazelbuild/bazel/src/main/protobuf:npm_package_assets",
- "//packages/concatjs/third_party/npm/requirejs:package_contents",
- "//packages/concatjs/web_test:package_contents",
- ],
- build_file_content = "",
- substitutions = TYPESCRIPT_REPLACEMENTS,
- deps = [
- ":README.md",
- ":bazel_concatjs_lib",
- ":npm_version_check",
- "//packages/concatjs/devserver:devserver-darwin",
- "//packages/concatjs/devserver:devserver-darwin_arm64",
- "//packages/concatjs/devserver:devserver-linux",
- "//packages/concatjs/devserver:devserver-windows",
- "//packages/concatjs/internal:BUILD",
- "//packages/concatjs/internal:generated_BUILD",
- "//packages/concatjs/internal:tsc_wrapped",
- ],
-)
diff --git a/packages/concatjs/devserver/BUILD.bazel b/packages/concatjs/devserver/BUILD.bazel
deleted file mode 100644
index d0b267d..0000000
--- a/packages/concatjs/devserver/BUILD.bazel
+++ /dev/null
@@ -1,234 +0,0 @@
-# Copyright 2017 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
-
-# BEGIN-INTERNAL
-load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
-
-# END-INTERNAL
-licenses(["notice"]) # Apache 2.0
-
-package(default_visibility = [
- "//packages/concatjs:__subpackages__",
-])
-
-bzl_library(
- name = "bzl",
- srcs = glob(["*.bzl"]),
- deps = [
- "@build_bazel_rules_nodejs//internal/js_library:bzl",
- "@build_bazel_rules_nodejs//internal/pkg_web:bzl",
- ],
-)
-
-exports_files(["launcher_template.sh"])
-
-filegroup(
- name = "devserver_darwin_amd64",
- srcs = ["devserver-darwin_x64"],
- # Don't build on CI
- tags = ["manual"],
- visibility = ["//visibility:public"],
-)
-
-filegroup(
- name = "devserver_linux_amd64",
- srcs = ["devserver-linux_x64"],
- # Don't build on CI
- tags = ["manual"],
- visibility = ["//visibility:public"],
-)
-
-filegroup(
- name = "devserver_linux_arm64",
- srcs = ["devserver-linux_arm64"],
- # Don't build on CI
- tags = ["manual"],
- visibility = ["//visibility:public"],
-)
-
-filegroup(
- name = "devserver_linux_s390x",
- srcs = ["devserver-linux_s390x"],
- # Don't build on CI
- tags = ["manual"],
- visibility = ["//visibility:public"],
-)
-
-filegroup(
- name = "devserver_windows_amd64",
- srcs = ["devserver-windows_x64.exe"],
- # Don't build on CI
- tags = ["manual"],
- visibility = ["//visibility:public"],
-)
-
-filegroup(
- name = "devserver_linux_ppc64le",
- srcs = ["devserver-linux_ppc64le"],
- # Don't build on CI
- tags = ["manual"],
- visibility = ["//visibility:public"],
-)
-
-filegroup(
- name = "devserver_darwin_arm64",
- srcs = ["devserver-darwin_arm64"],
- # Don't build on CI
- tags = ["manual"],
- visibility = ["//visibility:public"],
-)
-
-config_setting(
- name = "darwin_x64",
- constraint_values = [
- "@platforms//os:osx",
- "@platforms//cpu:x86_64",
- ],
-)
-
-config_setting(
- name = "darwin_arm64",
- constraint_values = [
- "@platforms//os:osx",
- "@platforms//cpu:arm64",
- ],
-)
-
-config_setting(
- name = "linux_x64",
- constraint_values = [
- "@platforms//os:linux",
- "@platforms//cpu:x86_64",
- ],
-)
-
-config_setting(
- name = "linux_arm64",
- constraint_values = [
- "@platforms//os:linux",
- "@platforms//cpu:arm64",
- ],
-)
-
-config_setting(
- name = "linux_s390x",
- constraint_values = [
- "@platforms//os:linux",
- "@platforms//cpu:s390x",
- ],
-)
-
-config_setting(
- name = "windows_x64",
- constraint_values = [
- "@platforms//os:windows",
- "@platforms//cpu:x86_64",
- ],
-)
-
-config_setting(
- name = "linux_ppc64le",
- constraint_values = [
- "@platforms//os:linux",
- "@platforms//cpu:ppc",
- ],
-)
-
-filegroup(
- name = "devserver",
- srcs = select({
- ":darwin_arm64": [":devserver_darwin_arm64"],
- ":darwin_x64": [":devserver_darwin_amd64"],
- ":linux_arm64": [":devserver_linux_arm64"],
- ":linux_s390x": [":devserver_linux_s390x"],
- ":linux_x64": [":devserver_linux_amd64"],
- ":windows_x64": [":devserver_windows_amd64"],
- ":linux_ppc64le": [":devserver_linux_ppc64le"],
- }),
- # Don't build on CI
- tags = ["manual"],
- visibility = ["//visibility:public"],
-)
-
-filegroup(
- name = "package_contents",
- srcs = glob(["*"]),
- visibility = ["//packages/concatjs:__pkg__"],
-)
-
-# BEGIN-INTERNAL
-go_library(
- name = "go_default_library",
- srcs = [
- "main.go",
- "runfile-filesystem.go",
- ],
- importpath = "github.com/bazelbuild/rules_typescript/devserver",
- visibility = ["//visibility:private"],
- deps = [
- "//packages/concatjs/devserver/concatjs:go_default_library",
- "//packages/concatjs/devserver/devserver:go_default_library",
- "//packages/concatjs/devserver/runfiles:go_default_library",
- ],
-)
-
-go_binary(
- name = "devserver_bin",
- embed = [":go_default_library"],
- visibility = ["//visibility:public"],
-)
-
-go_binary(
- name = "devserver-darwin",
- out = "devserver-darwin_x64",
- embed = [":go_default_library"],
- goarch = "amd64",
- goos = "darwin",
- pure = "on",
- visibility = ["//visibility:public"],
-)
-
-go_binary(
- name = "devserver-linux",
- out = "devserver-linux_x64",
- embed = [":go_default_library"],
- goarch = "amd64",
- goos = "linux",
- pure = "on",
- visibility = ["//visibility:public"],
-)
-
-go_binary(
- name = "devserver-windows",
- out = "devserver-windows_x64.exe",
- embed = [":go_default_library"],
- goarch = "amd64",
- goos = "windows",
- pure = "on",
- visibility = ["//visibility:public"],
-)
-
-go_binary(
- name = "devserver-darwin_arm64",
- out = "devserver-darwin_arm64",
- embed = [":go_default_library"],
- goarch = "arm64",
- goos = "darwin",
- pure = "on",
- visibility = ["//visibility:public"],
-)
-
-# END-INTERNAL
diff --git a/packages/concatjs/devserver/concatjs/BUILD.bazel b/packages/concatjs/devserver/concatjs/BUILD.bazel
deleted file mode 100644
index 6cc1a74..0000000
--- a/packages/concatjs/devserver/concatjs/BUILD.bazel
+++ /dev/null
@@ -1,14 +0,0 @@
-load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
-
-go_library(
- name = "go_default_library",
- srcs = ["concatjs.go"],
- importpath = "github.com/bazelbuild/rules_typescript/devserver/concatjs",
- visibility = ["//visibility:public"],
-)
-
-go_test(
- name = "go_default_test",
- srcs = ["concatjs_test.go"],
- embed = [":go_default_library"],
-)
diff --git a/packages/concatjs/devserver/concatjs/concatjs.go b/packages/concatjs/devserver/concatjs/concatjs.go
deleted file mode 100644
index bde0244..0000000
--- a/packages/concatjs/devserver/concatjs/concatjs.go
+++ /dev/null
@@ -1,361 +0,0 @@
-// Package concatjs provides a simple way of serving JavaScript sources in development.
-package concatjs
-
-import (
- "bufio"
- "bytes"
- "compress/gzip"
- "fmt"
- "io"
- "io/ioutil"
- "log"
- "net/http"
- "os"
- "path/filepath"
- "regexp"
- "strings"
- "sync"
- "time"
-)
-
-// ServeConcatenatedJS returns an http.Handler that serves the JavaScript files
-// listed in manifestPath in one concatenated, eval separated response body.
-//
-// This greatly speeds up development load times due to fewer HTTP requests, but
-// still for easy debugging by giving the eval'ed fragments URLs through
-// sourceURL comments.
-//
-// Example usage:
-// http.Handle("/app_combined.js",
-// concatjs.ServeConcatenatedJS("my/app/web_srcs.MF", ".", [], [], nil))
-//
-// Relative paths in the manifest are resolved relative to the path given as root.
-func ServeConcatenatedJS(manifestPath string, root string, preScripts []string, postScripts []string, fs FileSystem) http.Handler {
- var lock sync.Mutex // Guards cache.
- cache := NewFileCache(root, fs)
-
- manifestPath = filepath.Join(root, manifestPath)
-
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Content-Type", "text/javascript; charset=utf-8")
- files, err := manifestFiles(manifestPath)
- if err != nil {
- w.WriteHeader(http.StatusInternalServerError)
- writeJSError(w, "Failed to read manifest: %v", err)
- return
- }
- var writer io.Writer = w
- if acceptGzip(r.Header) {
- // NB: gzip is not supported in App Engine, as the header is stripped:
- // https://cloud.google.com/appengine/docs/go/requests#Go_Request_headers
- // CompressionLevel = 3 is a reasonable compromise between speed and compression.
- gzw, err := gzip.NewWriterLevel(w, 3)
- if err != nil {
- log.Fatalf("Could not create gzip writer: %s", err)
- }
- defer gzw.Close()
- writer = gzw
- w.Header().Set("Content-Encoding", "gzip")
- }
-
- // Write out pre scripts
- for _, s := range preScripts {
- fmt.Fprint(writer, s)
- // Ensure scripts are separated by a newline
- fmt.Fprint(writer, "\n")
- }
-
- // Protect the cache with a lock because it's possible for multiple requests
- // to be handled in parallel.
- lock.Lock()
- cache.WriteFiles(writer, files)
- lock.Unlock()
-
- // Write out post scripts
- for _, s := range postScripts {
- fmt.Fprint(writer, s)
- // Ensure scripts are separated by a newline
- fmt.Fprint(writer, "\n")
- }
- })
-}
-
-var acceptHeader = http.CanonicalHeaderKey("Accept-Encoding")
-
-func acceptGzip(h http.Header) bool {
- for _, hv := range h[acceptHeader] {
- for _, enc := range strings.Split(hv, ",") {
- if strings.TrimSpace(enc) == "gzip" {
- return true
- }
- }
- }
- return false
-}
-
-// FileSystem is the interface to reading files from disk.
-// It's abstracted into an interface to allow tests to replace it.
-type FileSystem interface {
- StatMtime(filename string) (time.Time, error)
- ReadFile(filename string) ([]byte, error)
- ResolvePath(root string, file string) (string, error)
-}
-
-// RealFileSystem implements FileSystem by actual disk access.
-type RealFileSystem struct{}
-
-// StatMtime gets the last modification time of the specified file.
-func (fs *RealFileSystem) StatMtime(filename string) (time.Time, error) {
- s, err := os.Stat(filename)
- if err != nil {
- return time.Time{}, err
- }
- return s.ModTime(), nil
-}
-
-// ReadFile reads the specified file using the real filesystem.
-func (fs *RealFileSystem) ReadFile(filename string) ([]byte, error) {
- return ioutil.ReadFile(filename)
-}
-
-// ResolvePath resolves the specified path within a given root by joining root and the filepath.
-// This is only works if the specified file is located within the given root in the
-// real filesystem. This does not work in Bazel where requested files aren't always
-// located within the specified root. Files would need to be resolved as runfiles.
-func (fs *RealFileSystem) ResolvePath(root string, file string) (string, error) {
- return filepath.Join(root, file), nil
-}
-
-// FileCache caches a set of files in memory and provides a single
-// method, WriteFiles(), that streams them out in the concatjs format.
-type FileCache struct {
- fs FileSystem
- root string
-
- entries map[string]*cacheEntry
-}
-
-// NewFileCache constructs a new FileCache. Relative paths in the cache
-// are resolved relative to root. fs injects file system access, and
-// will use the real file system if nil.
-func NewFileCache(root string, fs FileSystem) *FileCache {
- if fs == nil {
- fs = &RealFileSystem{}
- }
- return &FileCache{
- root: root,
- fs: fs,
- entries: map[string]*cacheEntry{},
- }
-}
-
-type cacheEntry struct {
- // err holds an error encountered while updating the entry; if
- // it's non-nil, then mtime, contents and the resolved path are invalid.
- err error
- mtime time.Time
- contents []byte
- resolvedPath string
-}
-
-// manifestFiles parses a manifest, returning a list of the files in the manifest.
-// It skips blank lines and javascript/closure/deps.js.
-func manifestFiles(manifest string) ([]string, error) {
- f, err := os.Open(manifest)
- if err != nil {
- return nil, fmt.Errorf("could not read manifest %s: %s", manifest, err)
- }
- defer f.Close()
- return manifestFilesFromReader(f)
-}
-
-// manifestFilesFromReader is a helper for manifestFiles, split out for testing.
-func manifestFilesFromReader(r io.Reader) ([]string, error) {
- var lines []string
- s := bufio.NewScanner(r)
- for s.Scan() {
- path := s.Text()
- if path == "" {
- continue
- }
- if path == "javascript/closure/deps.js" {
- // Ignore/skip deps.js, it is unused due to CLOSURE_NO_DEPS = true and superseded by the
- // dependency handling in this file. It's harmless, but a large download (>450 KB).
- continue
- }
- lines = append(lines, path)
- }
- if err := s.Err(); err != nil {
- return nil, err
- }
-
- return lines, nil
-}
-
-// writeJSError writes an error both to the log and into w as a JavaScript throw statement.
-func writeJSError(w io.Writer, format string, a ...interface{}) {
- log.Printf(format, a...)
- fmt.Fprint(w, "throw new Error('")
- fmt.Fprintf(w, format, a...)
- fmt.Fprint(w, "');\n")
-}
-
-// WriteFiles updates the cache for a list of files, then streams them into an io.Writer.
-func (cache *FileCache) WriteFiles(w io.Writer, files []string) error {
- // Ensure the cache is up to date with respect to the on-disk state.
- // Note that refreshFiles cannot fail; any errors encountering while refreshing
- // are stored in the cache entry and streamed into the response.
- cache.refreshFiles(files)
-
- for _, path := range files {
- if _, err := fmt.Fprintf(w, "// %s\n", path); err != nil {
- return err
- }
- ce := cache.entries[path]
- if ce.err != nil {
- writeJSError(w, "loading %s failed: %s", path, ce.err)
- continue
- }
- if _, err := w.Write(ce.contents); err != nil {
- return err
- }
- }
- return nil
-}
-
-// refresh ensures a single cacheEntry is up to date. It stat()s and
-// potentially reads the contents of the file it is caching.
-func (e *cacheEntry) refresh(fs FileSystem) error {
- mt, err := fs.StatMtime(e.resolvedPath)
- if err != nil {
- return err
- }
- if e.mtime == mt && e.contents != nil {
- return nil // up to date
- }
-
- contents, err := fileContents(e.resolvedPath, fs)
- if err != nil {
- return err
- }
- e.mtime = mt
- e.contents = contents
- return nil
-}
-
-// Convert Windows paths separators. We can use this to create canonical paths that
-// can be also used as browser source urls.
-var pathReplacer = strings.NewReplacer("\\", "/")
-
-// refreshFiles stats the given files and updates the cache for them.
-func (cache *FileCache) refreshFiles(files []string) {
- // Stating many files asynchronously is faster on network file systems.
- // Push all files that need to be stat'd into a channel and have
- // a set of workers stat/read them to update the cache entry.
- type workItem struct {
- path string
- entry *cacheEntry
- }
- work := make(chan workItem)
-
- var wg sync.WaitGroup
- wg.Add(len(files))
- for i := 0; i < len(files); i++ {
- // TODO(evanm): benchmark limiting this to fewer goroutines.
- go func() {
- w := <-work
- w.entry.err = w.entry.refresh(cache.fs)
- wg.Done()
- }()
- }
-
- for _, path := range files {
- entry := cache.entries[path]
- if entry == nil {
- // Resolve path only once for a cache entry. The resolved path will be part of the
- // cache item.
- resolvedPath, err := cache.fs.ResolvePath(cache.root, path)
-
- if err != nil {
- fmt.Fprintf(os.Stderr, "could not resolve path %s. %v\n", path, err)
- os.Exit(1)
- }
-
- // Create a new cache entry with the corresponding resolved path. Also normalize the path
- // before storing it persistently in the cache. The normalizing is good to do here because
- // the path might be used in browser source URLs and should be kept in posix format.
- entry = &cacheEntry{
- resolvedPath: pathReplacer.Replace(resolvedPath),
- }
- cache.entries[path] = entry
- }
- work <- workItem{path, entry}
- }
- close(work)
-
- wg.Wait()
-}
-
-// The maximum number of bytes of a source file to be searched for the "goog.module" declaration.
-// Limited to 50,000 bytes to avoid degenerated performance on large compiled JS (e.g. a
-// pre-compiled AngularJS binary).
-const googModuleSearchLimit = 50 * 1000
-
-// Matches files containing "goog.module", which have to be served slightly differently.
-var googModuleRegExp = regexp.MustCompile(`(?m)^\s*goog\.module\s*\(\s*['"]`)
-
-// fileContents returns escaped JS file contents for the given path.
-func fileContents(path string, fs FileSystem) ([]byte, error) {
- contents, err := fs.ReadFile(path)
- if err != nil {
- return nil, err
- }
- var f bytes.Buffer
- // goog.module files must be wrapped in a goog.loadModule call. Check the first X bytes of the file for it.
- limit := googModuleSearchLimit
- if len(contents) < limit {
- limit = len(contents)
- }
- if googModuleRegExp.Match(contents[:limit]) {
- fmt.Fprint(&f, "goog.loadModule('")
- } else {
- fmt.Fprint(&f, "eval('")
- }
- if err := writeJSEscaped(&f, contents); err != nil {
- log.Printf("Failed to write file contents of %s: %s", path, err)
- return nil, err
- }
- fmt.Fprintf(&f, "\\n\\n//# sourceURL=http://concatjs/%s\\n');\n", path)
-
- return f.Bytes(), nil
-}
-
-// writeJSEscaped writes contents into the given writer, escaping for content in
-// a single quoted JavaScript string.
-func writeJSEscaped(out io.Writer, contents []byte) error {
- // template.JSEscape escapes whitespace and line breaks to bulky six-character
- // escapes, substantially blowing up response size, and is also a bit slower.
- // As this also doesn't need safe escaping, this code just rather escapes itself.
- for _, b := range contents {
- switch b {
- case '\n':
- if _, err := out.Write([]byte("\\n")); err != nil {
- return err
- }
- case '\r':
- if _, err := out.Write([]byte("\\r")); err != nil {
- return err
- }
- case '\\', '\'':
- if _, err := out.Write([]byte{'\\'}); err != nil {
- return err
- }
- fallthrough
- default:
- if _, err := out.Write([]byte{b}); err != nil {
- return err
- }
- }
- }
- return nil
-}
diff --git a/packages/concatjs/devserver/concatjs/concatjs_test.go b/packages/concatjs/devserver/concatjs/concatjs_test.go
deleted file mode 100644
index ddd1a47..0000000
--- a/packages/concatjs/devserver/concatjs/concatjs_test.go
+++ /dev/null
@@ -1,217 +0,0 @@
-package concatjs
-
-import (
- "bytes"
- "fmt"
- "net/http"
- "net/http/httptest"
- "path/filepath"
- "reflect"
- "strings"
- "sync"
- "testing"
- "time"
-)
-
-// This test is mostly verifying that we drop javascript/closure/deps.js
-// This is only important in google3.
-func TestManifestFiles(t *testing.T) {
- files, err := manifestFilesFromReader(strings.NewReader(`foo.js
-
-javascript/closure/deps.js
-bar.js
-`))
- if err != nil {
- t.Fatal(err)
- }
- want := []string{"foo.js", "bar.js"}
- if !reflect.DeepEqual(files, want) {
- t.Errorf("Parse incorrect, got %v, want %v", files, want)
- }
-}
-
-func TestWriteJSEscaped(t *testing.T) {
- var b bytes.Buffer
- if err := writeJSEscaped(&b, []byte("test \\ ' \n \r end")); err != nil {
- t.Error(err)
- }
- got := string(b.Bytes())
- want := `test \\ \' \n \r end`
- if got != want {
- t.Errorf("Incorrect escaping, want %s, got %s", want, got)
- }
-}
-
-type fakeFileSystem struct {
- mux sync.Mutex
- fakeReadFile func(filename string) ([]byte, error)
- fakeStatMtime func(filename string) (time.Time, error)
- fakeResolvePath func(root string, filename string) (string, error)
-}
-
-func (fs *fakeFileSystem) ReadFile(filename string) ([]byte, error) {
- fs.mux.Lock()
- defer fs.mux.Unlock()
- return fs.fakeReadFile(filename)
-}
-
-func (fs *fakeFileSystem) StatMtime(filename string) (time.Time, error) {
- fs.mux.Lock()
- defer fs.mux.Unlock()
- return fs.fakeStatMtime(filename)
-}
-
-func (fs *fakeFileSystem) ResolvePath(root string, filename string) (string, error) {
- fs.mux.Lock()
- defer fs.mux.Unlock()
- return fs.fakeResolvePath(root, filename)
-}
-
-func TestWriteFiles(t *testing.T) {
- var inputFiles = []string{"a", "missing", "module"}
-
- fs := fakeFileSystem{
- fakeReadFile: func(filename string) ([]byte, error) {
- var normalizedFilename = pathReplacer.Replace(filename)
- switch normalizedFilename {
- case "root/a":
- return []byte("a content"), nil
- case "root/module":
- return []byte("// A module\ngoog.module('hello');"), nil
- default:
- return []byte{}, fmt.Errorf("unexpected file read: %s", normalizedFilename)
- }
- },
- fakeStatMtime: func(filename string) (time.Time, error) {
- var normalizedFilename = pathReplacer.Replace(filename)
- switch normalizedFilename {
- case "root/a", "root/module":
- return time.Now(), nil
- default:
- return time.Time{}, fmt.Errorf("unexpected file stat: %s", normalizedFilename)
- }
- },
- fakeResolvePath: func(root string, filename string) (string, error) {
- return filepath.Join(root, filename), nil
- },
- }
-
- cache := NewFileCache("root", &fs)
-
- var b bytes.Buffer
- cache.WriteFiles(&b, inputFiles)
-
- got := string(b.Bytes())
- want := `// a
-eval('a content\n\n//# sourceURL=http://concatjs/root/a\n');
-// missing
-throw new Error('loading missing failed: unexpected file stat: root/missing');
-// module
-goog.loadModule('// A module\ngoog.module(\'hello\');\n\n//# sourceURL=http://concatjs/root/module\n');
-`
-
- if got != want {
- t.Errorf("Response differs, want %s, got %s", want, got)
- }
-}
-
-func TestFileCaching(t *testing.T) {
- var reads int
-
- fs := fakeFileSystem{
- fakeReadFile: func(string) ([]byte, error) {
- reads++
- return nil, nil
- },
- fakeStatMtime: func(string) (time.Time, error) {
- return time.Time{}, nil
- },
- fakeResolvePath: func(root string, filename string) (string, error) {
- return filepath.Join(root, filename), nil
- },
- }
-
- var b bytes.Buffer
- cache := NewFileCache("", &fs)
- cache.WriteFiles(&b, []string{"a", "b"})
- if reads != 2 {
- t.Errorf("got %d file reads, want 2", reads)
- }
- reads = 0
- cache.WriteFiles(&b, []string{"a", "b"})
- if reads != 0 {
- t.Errorf("got %d reads, expected no further", reads)
- }
-}
-
-func TestAcceptHeader(t *testing.T) {
- tests := []struct {
- header map[string][]string
- expected bool
- }{
- {header: map[string][]string{"Other": []string{"gzip"}}, expected: false},
- {header: map[string][]string{"Accept-Encoding": []string{"rot13"}}, expected: false},
- {header: map[string][]string{"Accept-Encoding": []string{"rot13, gzip, deflate"}}, expected: true},
- }
- for _, test := range tests {
- res := acceptGzip(test.header)
- if res != test.expected {
- t.Errorf("Expect %t, got %t for %s", test.expected, res, test.header)
- }
- }
-}
-
-func TestCustomFileResolving(t *testing.T) {
- fs := fakeFileSystem{
- fakeReadFile: func(filename string) ([]byte, error) {
- var normalizedFilename = pathReplacer.Replace(filename)
- switch normalizedFilename {
- case "/system_root/bazel-bin/a.txt":
- return []byte("a content"), nil
- case "/system_root/bazel-bin/nested/b.js":
- return []byte("b content"), nil
- default:
- return []byte{}, fmt.Errorf("unexpected file read: %s", normalizedFilename)
- }
- },
- fakeStatMtime: func(filename string) (time.Time, error) {
- return time.Now(), nil
- },
- fakeResolvePath: func(root string, filename string) (string, error) {
- // For this test, we use an absolute root. This is similar to how
- // Bazel resolves runfiles through the manifest.
- return filepath.Join("/system_root/bazel-bin/", filename), nil
- },
- }
-
- cache := NewFileCache("", &fs)
-
- var b bytes.Buffer
- cache.WriteFiles(&b, []string{"a.txt", "nested/b.js"})
-
- actual := string(b.Bytes())
- expected := `// a.txt
-eval('a content\n\n//# sourceURL=http://concatjs//system_root/bazel-bin/a.txt\n');
-// nested/b.js
-eval('b content\n\n//# sourceURL=http://concatjs//system_root/bazel-bin/nested/b.js\n');
-`
-
- if actual != expected {
- t.Errorf("Response differs, actual: %s, expected: %s", actual, expected)
- }
-}
-
-func runOneRequest(b *testing.B, handler http.Handler, gzip bool) {
- req, err := http.NewRequest("GET", "", nil)
- if err != nil {
- b.Fatal(err)
- }
- if gzip {
- req.Header["Accept-Encoding"] = []string{"gzip"}
- }
- w := httptest.NewRecorder()
- handler.ServeHTTP(w, req)
- if w.Code != http.StatusOK {
- b.Errorf("HTTP request failed: %d", w.Code)
- }
-}
diff --git a/packages/concatjs/devserver/concatjs_devserver.bzl b/packages/concatjs/devserver/concatjs_devserver.bzl
deleted file mode 100644
index 8f5d1ba..0000000
--- a/packages/concatjs/devserver/concatjs_devserver.bzl
+++ /dev/null
@@ -1,256 +0,0 @@
-# Copyright 2017 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-"Simple development server"
-
-load("@build_bazel_rules_nodejs//:providers.bzl", "ExternalNpmPackageInfo", "JSNamedModuleInfo", "node_modules_aspect")
-load(
- "@build_bazel_rules_nodejs//internal/js_library:js_library.bzl",
- "write_amd_names_shim",
-)
-
-# Avoid using non-normalized paths (workspace/../other_workspace/path)
-def _to_manifest_path(ctx, file):
- if file.short_path.startswith("../"):
- return file.short_path[3:]
- else:
- return ctx.workspace_name + "/" + file.short_path
-
-def _concatjs_devserver(ctx):
- files_depsets = []
- for dep in ctx.attr.deps:
- if JSNamedModuleInfo in dep:
- files_depsets.append(dep[JSNamedModuleInfo].sources)
- if not JSNamedModuleInfo in dep and not ExternalNpmPackageInfo in dep and hasattr(dep, "files"):
- # These are javascript files provided by DefaultInfo from a direct
- # dep that has no JSNamedModuleInfo provider or ExternalNpmPackageInfo
- # provider (not an npm dep). These files must be in named AMD or named
- # UMD format.
- files_depsets.append(dep.files)
- files = depset(transitive = files_depsets)
-
- # Also include files from npm fine grained deps as inputs.
- # These deps are identified by the ExternalNpmPackageInfo provider.
- node_modules_depsets = []
- for dep in ctx.attr.deps:
- if ExternalNpmPackageInfo in dep:
- node_modules_depsets.append(dep[ExternalNpmPackageInfo].sources)
- node_modules = depset(transitive = node_modules_depsets)
-
- workspace_name = ctx.label.workspace_name if ctx.label.workspace_name else ctx.workspace_name
-
- # Create a manifest file with the sources in arbitrary order, and without
- # bazel-bin prefixes ("root-relative paths").
- # TODO(alexeagle): we should experiment with keeping the files toposorted, to
- # see if we can get performance gains out of the module loader.
- ctx.actions.write(ctx.outputs.manifest, "".join([
- workspace_name + "/" + f.short_path + "\n"
- for f in files.to_list()
- if f.path.endswith(".js")
- ]))
-
- amd_names_shim = ctx.actions.declare_file(
- "_%s.amd_names_shim.js" % ctx.label.name,
- sibling = ctx.outputs.script,
- )
- write_amd_names_shim(ctx.actions, amd_names_shim, ctx.attr.bootstrap)
-
- # Requirejs is always needed so its included as the first script
- # in script_files before any user specified scripts for the devserver
- # to concat in order.
- script_files = []
- script_files.extend(ctx.files.bootstrap)
- script_files.append(ctx.file._requirejs_script)
- script_files.append(amd_names_shim)
- script_files.extend(ctx.files.scripts)
- ctx.actions.write(ctx.outputs.scripts_manifest, "".join([
- workspace_name + "/" + f.short_path + "\n"
- for f in script_files
- ]))
-
- # With cross-platform RBE for OSX & Windows ctx.executable.devserver will be linux as --cpu and
- # --host_cpu must be overridden to k8. However, we still want to be able to run the devserver on the host
- # machine so we need to include the host devserver binary, which is ctx.executable.devserver_host, in the
- # runfiles. For non-RBE and for RBE with a linux host, ctx.executable.devserver & ctx.executable.devserver_host
- # will be the same binary.
- devserver_runfiles = [
- ctx.executable.devserver,
- ctx.executable.devserver_host,
- ctx.outputs.manifest,
- ctx.outputs.scripts_manifest,
- ]
- devserver_runfiles += ctx.files.static_files
- devserver_runfiles += script_files
- devserver_runfiles += ctx.files._bash_runfile_helpers
-
- packages = depset(["/".join([workspace_name, ctx.label.package])] + ctx.attr.additional_root_paths)
-
- ctx.actions.expand_template(
- template = ctx.file._launcher_template,
- output = ctx.outputs.script,
- substitutions = {
- "TEMPLATED_entry_module": ctx.attr.entry_module,
- "TEMPLATED_main": _to_manifest_path(ctx, ctx.executable.devserver),
- "TEMPLATED_manifest": _to_manifest_path(ctx, ctx.outputs.manifest),
- "TEMPLATED_packages": ",".join(packages.to_list()),
- "TEMPLATED_port": str(ctx.attr.port),
- "TEMPLATED_scripts_manifest": _to_manifest_path(ctx, ctx.outputs.scripts_manifest),
- "TEMPLATED_serving_path": ctx.attr.serving_path if ctx.attr.serving_path else "",
- "TEMPLATED_workspace": workspace_name,
- },
- is_executable = True,
- )
-
- return [DefaultInfo(
- runfiles = ctx.runfiles(
- files = devserver_runfiles,
- # We don't expect executable targets to depend on the devserver, but if they do,
- # they can see the JavaScript code.
- transitive_files = depset(transitive = [files, node_modules]),
- collect_data = True,
- collect_default = True,
- ),
- )]
-
-concatjs_devserver = rule(
- implementation = _concatjs_devserver,
- attrs = {
- "additional_root_paths": attr.string_list(
- doc = """Additional root paths to serve `static_files` from.
- Paths should include the workspace name such as `["__main__/resources"]`
- """,
- ),
- "bootstrap": attr.label_list(
- doc = "Scripts to include in the JS bundle before the module loader (require.js)",
- allow_files = [".js"],
- ),
- "deps": attr.label_list(
- doc = "Targets that produce JavaScript, such as `ts_library`",
- allow_files = True,
- aspects = [node_modules_aspect],
- ),
- "devserver": attr.label(
- doc = """Go based devserver executable.
-
- With cross-platform RBE for OSX & Windows ctx.executable.devserver will be linux as --cpu and
- --host_cpu must be overridden to k8. However, we still want to be able to run the devserver on the host
- machine so we need to include the host devserver binary, which is ctx.executable.devserver_host, in the
- runfiles. For non-RBE and for RBE with a linux host, ctx.executable.devserver & ctx.executable.devserver_host
- will be the same binary.
-
- Defaults to precompiled go binary setup by @bazel/typescript npm package""",
- default = Label("//packages/concatjs/devserver"),
- executable = True,
- cfg = "exec",
- ),
- "devserver_host": attr.label(
- doc = """Go based devserver executable for the host platform.
- Defaults to precompiled go binary setup by @bazel/typescript npm package""",
- default = Label("//packages/concatjs/devserver"),
- executable = True,
- cfg = "exec",
- ),
- "entry_module": attr.string(
- doc = """The `entry_module` should be the AMD module name of the entry module such as `"__main__/src/index".`
- `concatjs_devserver` concats the following snippet after the bundle to load the application:
- `require(["entry_module"]);`
- """,
- ),
- "port": attr.int(
- doc = """The port that the devserver will listen on.""",
- default = 5432,
- ),
- "scripts": attr.label_list(
- doc = "User scripts to include in the JS bundle before the application sources",
- allow_files = [".js"],
- ),
- "serving_path": attr.string(
- # This default repeats the one in the go program. We make it explicit here so we can read it
- # when injecting scripts into the index file.
- default = "/_/ts_scripts.js",
- doc = """The path you can request from the client HTML which serves the JavaScript bundle.
- If you don't specify one, the JavaScript can be loaded at /_/ts_scripts.js""",
- ),
- "static_files": attr.label_list(
- doc = """Arbitrary files which to be served, such as index.html.
- They are served relative to the package where this rule is declared.""",
- allow_files = True,
- ),
- "_bash_runfile_helpers": attr.label(default = Label("@build_bazel_rules_nodejs//third_party/github.com/bazelbuild/bazel/tools/bash/runfiles")),
- "_launcher_template": attr.label(allow_single_file = True, default = Label("//packages/concatjs/devserver:launcher_template.sh")),
- "_requirejs_script": attr.label(allow_single_file = True, default = Label("//packages/concatjs/third_party/npm/requirejs:require.js")),
- },
- outputs = {
- "manifest": "%{name}.MF",
- "script": "%{name}.sh",
- "scripts_manifest": "scripts_%{name}.MF",
- },
- doc = """concatjs_devserver is a simple development server intended for a quick "getting started" experience.
-
-Additional documentation [here](https://github.com/alexeagle/angular-bazel-example/wiki/Running-a-devserver-under-Bazel)
-""",
-)
-
-def concatjs_devserver_macro(name, args = [], visibility = None, tags = [], testonly = 0, **kwargs):
- """Macro for creating a `concatjs_devserver`
-
- This macro re-exposes a `sh_binary` and `concatjs_devserver` target that can run the
- actual devserver implementation.
- The `concatjs_devserver` rule is just responsible for generating a launcher script
- that runs the Go devserver implementation. The `sh_binary` is the primary
- target that matches the specified "name" and executes the generated bash
- launcher script.
- This is re-exported in `//:index.bzl` as `concatjs_devserver` so if you load the rule
- from there, you actually get this macro.
-
- Args:
- name: Name of the devserver target
- args: Command line arguments that will be passed to the devserver Go implementation
- visibility: Visibility of the devserver targets
- tags: Standard Bazel tags, this macro adds a couple for ibazel
- testonly: Whether the devserver should only run in `bazel test`
- **kwargs: passed through to `concatjs_devserver`
- """
- concatjs_devserver(
- name = "%s_launcher" % name,
- testonly = testonly,
- visibility = ["//visibility:private"],
- tags = tags,
- **kwargs
- )
-
- # Expose the manifest file label
- native.alias(
- name = "%s.MF" % name,
- actual = "%s_launcher.MF" % name,
- tags = tags,
- visibility = visibility,
- )
-
- native.sh_binary(
- name = name,
- args = args,
- # Users don't need to know that these tags are required to run under ibazel
- tags = tags + [
- # Tell ibazel not to restart the devserver when its deps change.
- "ibazel_notify_changes",
- # Tell ibazel to serve the live reload script, since we expect a browser will connect to
- # this program.
- "ibazel_live_reload",
- ],
- srcs = ["%s_launcher.sh" % name],
- data = [":%s_launcher" % name],
- testonly = testonly,
- visibility = visibility,
- )
diff --git a/packages/concatjs/devserver/devserver/BUILD.bazel b/packages/concatjs/devserver/devserver/BUILD.bazel
deleted file mode 100644
index e2fc700..0000000
--- a/packages/concatjs/devserver/devserver/BUILD.bazel
+++ /dev/null
@@ -1,25 +0,0 @@
-load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
-
-go_library(
- name = "go_default_library",
- srcs = ["devserver.go"],
- importpath = "github.com/bazelbuild/rules_typescript/devserver/devserver",
- visibility = ["//visibility:public"],
- deps = [
- "//packages/concatjs/devserver/runfiles:go_default_library",
- ],
-)
-
-go_test(
- name = "go_default_test",
- srcs = ["devserver_test.go"],
- # Required runfiles for the devserver tests.
- data = [
- "test/index.html",
- "test/relative.html",
- "@devserver_test_workspace//:sources",
- ],
- embed = [":go_default_library"],
- # FIXME: broken on Windows
- tags = ["fix-windows"],
-)
diff --git a/packages/concatjs/devserver/devserver/devserver.go b/packages/concatjs/devserver/devserver/devserver.go
deleted file mode 100644
index 3ed5d88..0000000
--- a/packages/concatjs/devserver/devserver/devserver.go
+++ /dev/null
@@ -1,223 +0,0 @@
-// Package devserver provides code shared between Bazel and Blaze.
-package devserver
-
-import (
- "bytes"
- "fmt"
- "net"
- "net/http"
- "net/url"
- "os"
- "path/filepath"
- "strings"
- "time"
-
- "github.com/bazelbuild/rules_typescript/devserver/runfiles"
-)
-
-// Convert Windows paths separators.
-var pathReplacer = strings.NewReplacer("\\", "/")
-
-func shouldAllowCors(request *http.Request) bool {
- hostname, err := os.Hostname()
- if err != nil {
- return false
- }
- referer, err := url.Parse(request.Header.Get("Origin"))
- if err != nil {
- return false
- }
- host, _, err := net.SplitHostPort(referer.Host)
- // SplitHostPort fails when the parameter doesn't have a port.
- if err != nil {
- host = referer.Host
- }
- return host == hostname || host == "localhost"
-}
-
-func customNotFoundMiddleware(notFound http.HandlerFunc, passThrough http.HandlerFunc) http.HandlerFunc {
- return func(writer http.ResponseWriter, request *http.Request) {
- passThrough(
- &customNotFoundResponseWriter{ResponseWriter: writer, request: request, notFound: notFound},
- request,
- )
- }
-}
-
-type customNotFoundResponseWriter struct {
- http.ResponseWriter
-
- request *http.Request
- notFound http.HandlerFunc
- has404 bool
- hasWrite bool
-}
-
-// Write implements http.ResponseWriter.Write.
-func (w *customNotFoundResponseWriter) Write(b []byte) (int, error) {
- w.hasWrite = true
- if w.has404 {
- // We have already written the not found response, so drop this one.
- return len(b), nil
- }
- return w.ResponseWriter.Write(b)
-}
-
-// WriteHeader implements http.ResponseWriter.WriteHeader.
-func (w *customNotFoundResponseWriter) WriteHeader(code int) {
- if code != http.StatusNotFound || w.hasWrite {
- // We only intercept not found statuses. We also don't intercept statuses written after the
- // first write as these are an error and should be handled by the default ResponseWriter.
- w.ResponseWriter.WriteHeader(code)
- return
- }
-
- // WriteHeader writes out the entire header (including content type) and only the first call
- // will succeed. Therefore, if we want the correct content type set, we must set it here.
- w.Header().Del("Content-Type")
- w.Header().Add("Content-Type", "text/html; charset=utf-8")
- w.ResponseWriter.WriteHeader(code)
- w.has404 = true
-
- // We have already written the header, so drop any calls to WriteHeader made by the not found
- // handler. These additional calls are expected, and if passed through, would cause the base
- // ResponseWriter to unnecessarily spam the error log.
- w.notFound(&headerSuppressorResponseWriter{w.ResponseWriter}, w.request)
- w.hasWrite = true
-}
-
-type headerSuppressorResponseWriter struct {
- http.ResponseWriter
-}
-
-// WriteHeader implements http.ResponseWriter.WriteHeader.
-func (w *headerSuppressorResponseWriter) WriteHeader(code int) {}
-
-// CreateFileHandler returns an http handler to locate files on disk
-func CreateFileHandler(servingPath, manifest string, pkgs []string, base string) http.HandlerFunc {
- // We want to add the root runfile path because by default developers should be able to request
- // runfiles through their absolute manifest path (e.g. "my_workspace_name/src/file.css")
- pkgPaths := dirHTTPFileSystem{append(pkgs, "./"), base}
-
- fileHandler := http.FileServer(pkgPaths).ServeHTTP
-
- defaultPage := []byte(fmt.Sprintf(`<!doctype html>
- <html>
- <head>
- <title>ts_devserver (%s)</title>
- </head>
- <body>
- <script src="%s"></script>
- </body>
- </html>
- `, manifest, servingPath))
-
- // indexHandler serves an index.html if present, or otherwise serves a minimal
- // generated index.html with a script tag to include the bundled js source.
- indexHandler := func(w http.ResponseWriter, r *http.Request) {
- // search through pkgs for the first index.html file found if any exists
- for _, pkg := range pkgs {
- // File path is not cached, so that a user's edits will be reflected.
- userIndexFile, err := runfiles.Runfile(base, pathReplacer.Replace(filepath.Join(pkg, "index.html")))
-
- // In case the potential user index file couldn't be found in the runfiles,
- // continue searching within other packages.
- if err != nil {
- continue
- }
-
- // We can assume that the file is readable if it's listed in the runfiles manifest.
- http.ServeFile(w, r, userIndexFile)
- return
- }
- content := bytes.NewReader(defaultPage)
- http.ServeContent(w, r, "index.html", time.Now(), content)
- }
-
- // Serve a custom index.html so as to override the default directory listing
- // from http.FileServer when no index.html file present.
- indexOnNotFoundHandler := func(writer http.ResponseWriter, request *http.Request) {
- // The browser can't tell the difference between different source checkouts or different devserver
- // instances, so it may mistakenly cache static files (including templates) using versions from
- // old instances if they haven't been modified more recently. To prevent this, we force no-cache
- // on all static files.
- writer.Header().Add("Cache-Control", "no-cache, no-store, must-revalidate")
- if shouldAllowCors(request) {
- writer.Header().Add("Access-Control-Allow-Origin", request.Header.Get("Origin"))
- writer.Header().Add("Access-Control-Allow-Credentials", "true")
- }
- writer.Header().Add("Pragma", "no-cache")
- writer.Header().Add("Expires", "0")
- // Add gzip headers if serving .gz files.
- if strings.HasSuffix(request.URL.EscapedPath(), ".gz") {
- writer.Header().Add("Content-Encoding", "gzip")
- }
-
- if request.URL.Path == "/" {
- indexHandler(writer, request)
- return
- }
- // When a file is not found, serve a 404 code but serve the index.html from above as its body.
- // This allows applications to use html5 routing and reload the page at /some/sub/path, but still
- // get their web app served.
- // The responses is marked as an error (404) so that requests that are genuinely wrong (e.g.
- // incorrect URLs for CSS, images, etc) are marked as such. Otherwise they'd seem to succeed but
- // then fail to process correctly, which makes for a bad debugging experience.
- writer = &customNotFoundResponseWriter{ResponseWriter: writer, request: request, notFound: indexHandler}
- fileHandler(writer, request)
- }
-
- return indexOnNotFoundHandler
-}
-
-// dirHTTPFileSystem implements http.FileSystem by looking in the list of dirs one after each other.
-type dirHTTPFileSystem struct {
- packageDirs []string
- base string
-}
-
-func (fs dirHTTPFileSystem) Open(name string) (http.File, error) {
- for _, packageName := range fs.packageDirs {
- manifestFilePath := filepath.Join(packageName, name)
- realFilePath, err := runfiles.Runfile(fs.base, manifestFilePath)
-
- if err != nil {
- // In case the runfile could not be found, we also need to check that the requested
- // path does not refer to a directory containing an "index.html" file. This can
- // happen if Bazel runs without runfile symlinks, where only files can be resolved
- // from the manifest. In that case we dirty check if there is a "index.html" file.
- realFilePath, err = runfiles.Runfile(fs.base, filepath.Join(manifestFilePath, "index.html"))
-
- // Continue searching if the runfile couldn't be found for the requested file.
- if err != nil {
- continue
- }
- }
-
- stat, err := os.Stat(realFilePath)
- if err != nil {
- // This should actually never happen because runfiles resolved through the runfile helpers
- // should always exist. Just in order to properly handle the error, we add this error handling.
- return nil, fmt.Errorf("could not read runfile %s", manifestFilePath)
- }
-
- // In case the resolved file resolves to a directory. This can only happen if
- // Bazel runs with symlinked runfiles (e.g. on MacOS, linux). In that case, we
- // just look for a index.html in the directory.
- if stat.IsDir() {
- realFilePath, err = runfiles.Runfile(fs.base, filepath.Join(manifestFilePath, "index.html"))
-
- // In case the index.html file of the requested directory couldn't be found,
- // we just continue searching.
- if err != nil {
- continue
- }
- }
-
- // We can assume that the file is present, if it's listed in the runfile manifest. Though, we
- // return the error, in case something prevented the read-access.
- return os.Open(realFilePath)
- }
-
- return nil, os.ErrNotExist
-}
diff --git a/packages/concatjs/devserver/devserver/devserver_test.go b/packages/concatjs/devserver/devserver/devserver_test.go
deleted file mode 100644
index 8b0b2b7..0000000
--- a/packages/concatjs/devserver/devserver/devserver_test.go
+++ /dev/null
@@ -1,157 +0,0 @@
-package devserver
-
-import (
- "fmt"
- "io/ioutil"
- "net/http"
- "net/http/httptest"
- "os"
- "path/filepath"
- "strings"
- "testing"
-)
-
-func tmpfile(t *testing.T, name, contents string) (string, func()) {
- fullPath := filepath.Join(os.Getenv("TEST_TMPDIR"), name)
- dir := filepath.Dir(fullPath)
- if _, err := os.Stat(dir); err != nil {
- if os.IsNotExist(err) {
- if err := os.MkdirAll(dir, 0777); err != nil {
- t.Fatalf("failed to create dir: %v", err)
- }
- } else {
- t.Fatalf("failed to stat dir: %v", err)
- }
- }
- err := ioutil.WriteFile(fullPath, []byte(contents), 0666)
- if err != nil {
- t.Fatalf("failed to write temp file: %v", err)
- }
- return fullPath, func() {
- if err := os.Remove(fullPath); err != nil && !os.IsNotExist(err) {
- t.Errorf("failed to delete file %q: %v", fullPath, err)
- }
- }
-}
-
-func req(handler http.HandlerFunc, url string) (int, string) {
- req := httptest.NewRequest("GET", url, nil)
- w := httptest.NewRecorder()
- handler(w, req)
- resp := w.Result()
- body, _ := ioutil.ReadAll(resp.Body)
- return resp.StatusCode, string(body)
-}
-
-func TestDevserverFileHandling(t *testing.T) {
- handler := CreateFileHandler("/app.js", "manifest.MF", []string{
- // This verifies that we can resolve relatively to the current package. Usually the
- // devserver Bazel rule adds the current package here.
- "build_bazel_rules_nodejs/packages/concatjs/devserver/devserver",
- // Verifies that we can specify subfolders of workspaces
- "build_bazel_rules_nodejs/packages/concatjs/devserver/devserver/test",
- // Verifies that we can specify external workspaces as root dirs.
- "devserver_test_workspace",
- // Verifies that we can specify subfolders from external workspaces.
- "devserver_test_workspace/pkg2",
- }, "")
-
- defaultPageContent := `<script src="/app.js">`
-
- tests := []struct {
- code int
- url string
- content string
- }{
- // index file from pkg1.
- {http.StatusOK, "/", "contents of index.html"},
- // index file as a response to not found handler.
- {http.StatusNotFound, "/no/such/dir", "contents of index.html"},
- // index file as a response to not found handler.
- {http.StatusNotFound, "/no/such/dir/", "contents of index.html"},
- // index file as a response to a directory that is found.
- {http.StatusNotFound, "/pkg2/", "contents of index.html"},
- // file from relative to base package.
- {http.StatusOK, "/test/relative.html", "contents of relative.html"},
- // file from the base package with full path.
- {http.StatusOK, "/pkg1/foo.html", "contents of foo.html"},
- // file from pkg2.
- {http.StatusOK, "/bar.html", "contents of bar.html"},
- // file from pkg2 with full path.
- {http.StatusOK, "/pkg2/bar.html", "contents of bar.html"},
- // index file from disk
- {http.StatusOK, "/rpc/items", "contents of rpc/items/index.html"},
- // file from an unrelated package.
- {http.StatusOK, "/pkg3/baz.html", "contents of baz.html in pkg3"},
- }
-
- for _, tst := range tests {
- code, body := req(handler, fmt.Sprintf("http://test%s", tst.url))
- if code != tst.code {
- t.Errorf("got %d, expected %d", code, tst.code)
- }
- if !strings.Contains(body, tst.content) {
- t.Errorf("expected %q to contain %q, got %q", tst.url, tst.content, body)
- }
- if strings.Contains(body, defaultPageContent) {
- t.Errorf("got %q, default page shouldn't be part of response", body)
- }
- }
-}
-
-func TestDevserverGeneratedIndexFile(t *testing.T) {
- handler := CreateFileHandler("/app.js", "manifest.MF", []string{
- "devserver_test_workspace",
- }, "")
- defaultPageContent := `<script src="/app.js">`
-
- tests := []struct {
- code int
- url string
- content string
- }{
- // Assert generated index for root.
- {http.StatusOK, "/", defaultPageContent},
- // Assert generated index as a response to not found handler.
- {http.StatusNotFound, "/no/such/dir", defaultPageContent},
- // Assert index file as a response to a directory that is found, but does not
- // have an index file.
- {http.StatusNotFound, "/pkg2/", defaultPageContent},
- }
-
- for _, tst := range tests {
- code, body := req(handler, fmt.Sprintf("http://test%s", tst.url))
- if code != tst.code {
- t.Errorf("got %d, expected %d", code, tst.code)
- }
- if !strings.Contains(body, tst.content) {
- t.Errorf("expected %q to contain %q, got %q", tst.url, tst.content, body)
- }
- }
-}
-
-func TestDevserverAbsoluteRunfileRequest(t *testing.T) {
- handler := CreateFileHandler("/app.js", "manifest.MF", []string{}, "")
-
- tests := []struct {
- code int
- url string
- content string
- }{
- // Assert that it's possible to request a runfile through it's absolute manifest path.
- {http.StatusOK, "/devserver_test_workspace/pkg2/bar.html", "contents of bar.html"},
- // Assert that it's possible to request a runfile directory through it's absolute manifest path. This
- // should resolve to the directories "index.html" file.
- {http.StatusOK, "/devserver_test_workspace/pkg1", "contents of index.html"},
- }
-
- for _, tst := range tests {
- code, body := req(handler, fmt.Sprintf("http://test%s", tst.url))
- if code != tst.code {
- t.Errorf("got %d, expected %d", code, tst.code)
- }
- if !strings.Contains(body, tst.content) {
- t.Errorf("expected %q to contain %q, got %q", tst.url, tst.content, body)
- }
- }
-}
diff --git a/packages/concatjs/devserver/devserver/test/index.html b/packages/concatjs/devserver/devserver/test/index.html
deleted file mode 100644
index c04b444..0000000
--- a/packages/concatjs/devserver/devserver/test/index.html
+++ /dev/null
@@ -1 +0,0 @@
-contents of index.html
\ No newline at end of file
diff --git a/packages/concatjs/devserver/devserver/test/relative.html b/packages/concatjs/devserver/devserver/test/relative.html
deleted file mode 100644
index a0e4874..0000000
--- a/packages/concatjs/devserver/devserver/test/relative.html
+++ /dev/null
@@ -1 +0,0 @@
-contents of relative.html
\ No newline at end of file
diff --git a/packages/concatjs/devserver/devserver/test/test-workspace/BUILD.bazel b/packages/concatjs/devserver/devserver/test/test-workspace/BUILD.bazel
deleted file mode 100644
index 85d4777..0000000
--- a/packages/concatjs/devserver/devserver/test/test-workspace/BUILD.bazel
+++ /dev/null
@@ -1,5 +0,0 @@
-filegroup(
- name = "sources",
- srcs = glob(["**/*"]),
- visibility = ["//visibility:public"],
-)
diff --git a/packages/concatjs/devserver/devserver/test/test-workspace/WORKSPACE b/packages/concatjs/devserver/devserver/test/test-workspace/WORKSPACE
deleted file mode 100644
index e69de29..0000000
--- a/packages/concatjs/devserver/devserver/test/test-workspace/WORKSPACE
+++ /dev/null
diff --git a/packages/concatjs/devserver/devserver/test/test-workspace/pkg1/foo.html b/packages/concatjs/devserver/devserver/test/test-workspace/pkg1/foo.html
deleted file mode 100644
index 7923b1b..0000000
--- a/packages/concatjs/devserver/devserver/test/test-workspace/pkg1/foo.html
+++ /dev/null
@@ -1 +0,0 @@
-contents of foo.html
\ No newline at end of file
diff --git a/packages/concatjs/devserver/devserver/test/test-workspace/pkg1/index.html b/packages/concatjs/devserver/devserver/test/test-workspace/pkg1/index.html
deleted file mode 100644
index c04b444..0000000
--- a/packages/concatjs/devserver/devserver/test/test-workspace/pkg1/index.html
+++ /dev/null
@@ -1 +0,0 @@
-contents of index.html
\ No newline at end of file
diff --git a/packages/concatjs/devserver/devserver/test/test-workspace/pkg2/bar.html b/packages/concatjs/devserver/devserver/test/test-workspace/pkg2/bar.html
deleted file mode 100644
index 70646c6..0000000
--- a/packages/concatjs/devserver/devserver/test/test-workspace/pkg2/bar.html
+++ /dev/null
@@ -1 +0,0 @@
-contents of bar.html
\ No newline at end of file
diff --git a/packages/concatjs/devserver/devserver/test/test-workspace/pkg2/foo.html b/packages/concatjs/devserver/devserver/test/test-workspace/pkg2/foo.html
deleted file mode 100644
index 9c5a98c..0000000
--- a/packages/concatjs/devserver/devserver/test/test-workspace/pkg2/foo.html
+++ /dev/null
@@ -1 +0,0 @@
-contents of foo.html in pkg2
\ No newline at end of file
diff --git a/packages/concatjs/devserver/devserver/test/test-workspace/pkg2/rpc/items/index.html b/packages/concatjs/devserver/devserver/test/test-workspace/pkg2/rpc/items/index.html
deleted file mode 100644
index 3850cc9..0000000
--- a/packages/concatjs/devserver/devserver/test/test-workspace/pkg2/rpc/items/index.html
+++ /dev/null
@@ -1 +0,0 @@
-contents of rpc/items/index.html
\ No newline at end of file
diff --git a/packages/concatjs/devserver/devserver/test/test-workspace/pkg3/baz.html b/packages/concatjs/devserver/devserver/test/test-workspace/pkg3/baz.html
deleted file mode 100644
index f471ef4..0000000
--- a/packages/concatjs/devserver/devserver/test/test-workspace/pkg3/baz.html
+++ /dev/null
@@ -1 +0,0 @@
-contents of baz.html in pkg3
\ No newline at end of file
diff --git a/packages/concatjs/devserver/launcher_template.sh b/packages/concatjs/devserver/launcher_template.sh
deleted file mode 100644
index b9d5e85..0000000
--- a/packages/concatjs/devserver/launcher_template.sh
+++ /dev/null
@@ -1,80 +0,0 @@
-#!/usr/bin/env bash
-
-# Copyright 2018 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-# --- begin runfiles.bash initialization v2 ---
-# Copy-pasted from the Bazel Bash runfiles library v2.
-set -uo pipefail; f=build_bazel_rules_nodejs/third_party/github.com/bazelbuild/bazel/tools/bash/runfiles/runfiles.bash
-source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \
- source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \
- source "$0.runfiles/$f" 2>/dev/null || \
- source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
- source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
- { echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e
-# --- end runfiles.bash initialization v2 ---
-
-# Check environment for which node path to use
-unameOut="$(uname -s)"
-case "${unameOut}" in
- Linux*) machine=linux ;;
- Darwin*) machine=darwin ;;
- CYGWIN*) machine=windows ;;
- MINGW*) machine=windows ;;
- MSYS_NT*) machine=windows ;;
- *) machine=linux
- printf "\nUnrecongized uname '${unameOut}'; defaulting to use node for linux.\n" >&2
- printf "Please file an issue to https://github.com/bazelbuild/rules_nodejs/issues if \n" >&2
- printf "you would like to add your platform to the supported concatjs_devserver platforms.\n\n" >&2
- ;;
-esac
-
-case "${machine}" in
- # The following paths must match up with //packages/concatjs/devserver binaries
- # FIXME: we shouldn't hardcode "npm" repository name here
- darwin) readonly platform_main_manifest="npm/@bazel/concatjs/devserver/devserver-darwin_x64" ;;
- windows) readonly platform_main_manifest="npm/@bazel/concatjs/devserver/devserver-windows_x64.exe" ;;
- *) readonly platform_main_manifest="npm/@bazel/concatjs/devserver/devserver-linux_x64" ;;
-esac
-
-readonly platform_main=$(rlocation "${platform_main_manifest}")
-
-if [ -f "${platform_main}" ]; then
- readonly main=${platform_main}
-else
- # If the devserver binary is overridden then use the templated binary
- readonly main=$(rlocation "TEMPLATED_main")
-fi
-
-if [ ! -f "${main}" ]; then
- printf "\n>>>> FAIL: The concatjs_devserver binary '${main_platform}' not found in runfiles.\n" >&2
- printf "This node toolchain was chosen based on your uname '${unameOut}'.\n" >&2
- printf "Please file an issue to https://github.com/bazelbuild/rules_nodejs/issues if \n" >&2
- printf "you would like to add your platform to the supported concatjs_devserver platforms. <<<<\n\n" >&2
- exit 1
-fi
-
-readonly manifest=$(rlocation "TEMPLATED_manifest")
-readonly scripts_manifest=$(rlocation "TEMPLATED_scripts_manifest")
-
-# Workaround for https://github.com/bazelbuild/bazel/issues/6764
-# If this issue is incorporated into Bazel, the workaround here should be removed.
-MSYS2_ARG_CONV_EXCL="*" "${main}" \
- -packages=TEMPLATED_packages \
- -serving_path=TEMPLATED_serving_path \
- -entry_module=TEMPLATED_entry_module \
- -port=TEMPLATED_port \
- -manifest="${manifest}" \
- -scripts_manifest="${scripts_manifest}" \
- "$@"
diff --git a/packages/concatjs/devserver/main.go b/packages/concatjs/devserver/main.go
deleted file mode 100644
index 466a63d..0000000
--- a/packages/concatjs/devserver/main.go
+++ /dev/null
@@ -1,162 +0,0 @@
-package main
-
-import (
- "bufio"
- "flag"
- "fmt"
- "io"
- "io/ioutil"
- "net/http"
- "os"
- "strings"
-
- "github.com/bazelbuild/rules_typescript/devserver/concatjs"
- "github.com/bazelbuild/rules_typescript/devserver/devserver"
- "github.com/bazelbuild/rules_typescript/devserver/runfiles"
-)
-
-var (
- port = flag.Int("port", 5432, "server port to listen on")
- // The "base" CLI flag is only kept because within Google3 because removing would be a breaking change due to
- // ConcatJS and "devserver/devserver.go" still respecting the specified base flag.
- base = flag.String("base", "", "server base (required, runfiles of the binary)")
- pkgs = flag.String("packages", "", "root package(s) to serve, comma-separated")
- manifest = flag.String("manifest", "", "sources manifest (.MF)")
- scriptsManifest = flag.String("scripts_manifest", "", "preScripts manifest (.MF)")
- servingPath = flag.String("serving_path", "/_/ts_scripts.js", "path to serve the combined sources at")
- entryModule = flag.String("entry_module", "", "entry module name")
-)
-
-func main() {
- flag.Parse()
-
- if len(*pkgs) == 0 || (*manifest == "") || (*scriptsManifest == "") {
- fmt.Fprintf(os.Stderr, "Required argument not set\n")
- os.Exit(1)
- }
-
- manifestPath, err := runfiles.Runfile(*base, *scriptsManifest)
-
- if err != nil {
- fmt.Fprintf(os.Stderr, "Failed to find scripts_manifest in runfiles: %v\n", err)
- os.Exit(1)
- }
-
- scriptFiles, err := manifestFiles(manifestPath)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Failed to read scripts_manifest: %v\n", err)
- os.Exit(1)
- }
-
- if !strings.HasPrefix(*servingPath, "/") {
- fmt.Fprintf(os.Stderr, "The specified serving_path does not start with a slash. "+
- "This causes the serving path to not have any effect.\n")
- os.Exit(1)
- }
-
- preScripts := make([]string, 0, 100)
- postScripts := make([]string, 0, 1)
-
- // Include the livereload script if IBAZEL_LIVERELOAD_URL is set.
- livereloadUrl := os.Getenv("IBAZEL_LIVERELOAD_URL")
- if livereloadUrl != "" {
- fmt.Printf("Serving livereload script from %s\n", livereloadUrl)
- livereloadLoaderSnippet := fmt.Sprintf(`(function(){
- const script = document.createElement('script');
- script.src = "%s";
- document.head.appendChild(script);
-})();`, livereloadUrl)
- preScripts = append(preScripts, livereloadLoaderSnippet)
- }
-
- // Include the profiler script if IBAZEL_PROFILER_URL is set.
- profilerScriptURL := os.Getenv("IBAZEL_PROFILER_URL")
- if profilerScriptURL != "" {
- fmt.Printf("Serving profiler script from %s\n", profilerScriptURL)
- profilerLoaderSnippet := fmt.Sprintf(`(function(){
- const script = document.createElement('script');
- script.src = "%s";
- document.head.appendChild(script);
-})();`, profilerScriptURL)
- preScripts = append(preScripts, profilerLoaderSnippet)
- }
-
- // Include all user scripts in preScripts. This should always include
- // the requirejs script which is added to scriptFiles by the devserver
- // skylark rule.
- for _, v := range scriptFiles {
- runfile, err := runfiles.Runfile(*base, v)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Could not find runfile %s, got error %s", v, err)
- }
-
- js, err := loadScript(runfile)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Failed to read script %s: %v\n", v, err)
- } else {
- preScripts = append(preScripts, js)
- }
- }
-
- // If the entryModule is set then add a snippet to load
- // the application to postScripts to be outputted after the sources
- if *entryModule != "" {
- postScripts = append(postScripts, fmt.Sprintf("require([\"%s\"]);", *entryModule))
- }
-
- http.Handle(*servingPath, concatjs.ServeConcatenatedJS(*manifest, *base, preScripts, postScripts,
- &RunfileFileSystem{}))
- pkgList := strings.Split(*pkgs, ",")
- http.HandleFunc("/", devserver.CreateFileHandler(*servingPath, *manifest, pkgList, *base))
-
- h, err := os.Hostname()
- if err != nil {
- h = "localhost"
- }
- // Detect if we are running in a linux container inside ChromeOS
- // If so, we assume you want to use the native browser (outside the container)
- // so you'll need to modify the hostname to access the server
- if _, err := os.Stat("/etc/apt/sources.list.d/cros.list"); err == nil {
- h = h + ".linux.test"
- }
-
- fmt.Printf("Server listening on http://%s:%d/\n", h, *port)
- fmt.Fprintln(os.Stderr, http.ListenAndServe(fmt.Sprintf(":%d", *port), nil).Error())
- os.Exit(1)
-}
-
-func loadScript(path string) (string, error) {
- buf, err := ioutil.ReadFile(path)
- if err != nil {
- return "", err
- }
- return fmt.Sprintf("// %s\n%s", path, buf), nil
-}
-
-// manifestFiles parses a manifest, returning a list of the files in the manifest.
-func manifestFiles(manifest string) ([]string, error) {
- f, err := os.Open(manifest)
- if err != nil {
- return nil, fmt.Errorf("could not read manifest %s: %s", manifest, err)
- }
- defer f.Close()
- return manifestFilesFromReader(f)
-}
-
-// manifestFilesFromReader is a helper for manifestFiles, split out for testing.
-func manifestFilesFromReader(r io.Reader) ([]string, error) {
- var lines []string
- s := bufio.NewScanner(r)
- for s.Scan() {
- path := s.Text()
- if path == "" {
- continue
- }
- lines = append(lines, path)
- }
- if err := s.Err(); err != nil {
- return nil, err
- }
-
- return lines, nil
-}
diff --git a/packages/concatjs/devserver/runfile-filesystem.go b/packages/concatjs/devserver/runfile-filesystem.go
deleted file mode 100644
index 090ded6..0000000
--- a/packages/concatjs/devserver/runfile-filesystem.go
+++ /dev/null
@@ -1,35 +0,0 @@
-// Main package that provides a command line interface for starting a Bazel devserver
-// using Bazel runfile resolution and ConcatJS for in-memory bundling of specified AMD files.
-package main
-
-import (
- "io/ioutil"
- "os"
- "time"
-
- "github.com/bazelbuild/rules_typescript/devserver/runfiles"
-)
-
-// RunfileFileSystem implements FileSystem type from concatjs.
-type RunfileFileSystem struct{}
-
-// StatMtime gets the filestamp for the last file modification.
-func (fs *RunfileFileSystem) StatMtime(filename string) (time.Time, error) {
- s, err := os.Stat(filename)
- if err != nil {
- return time.Time{}, err
- }
- return s.ModTime(), nil
-}
-
-// ReadFile reads a file given its file name
-func (fs *RunfileFileSystem) ReadFile(filename string) ([]byte, error) {
- return ioutil.ReadFile(filename)
-}
-
-// ResolvePath resolves the specified path within a given root using Bazel's runfile resolution.
-// This is necessary because on Windows, runfiles are not symlinked and need to be
-// resolved using the runfile manifest file.
-func (fs *RunfileFileSystem) ResolvePath(root string, manifestFilePath string) (string, error) {
- return runfiles.Runfile(root, manifestFilePath)
-}
diff --git a/packages/concatjs/devserver/runfiles/BUILD.bazel b/packages/concatjs/devserver/runfiles/BUILD.bazel
deleted file mode 100644
index 2285f5b..0000000
--- a/packages/concatjs/devserver/runfiles/BUILD.bazel
+++ /dev/null
@@ -1,17 +0,0 @@
-load("@io_bazel_rules_go//go:def.bzl", "go_library")
-
-# Gazelle by default tries to map the import for the Bazel runfile go library to a repository with
-# an auto-generated name. This does not work for us because the rules_go repository name is different.
-# This gazelle directive ensures that Gazelle resolves the import to the proper Bazel label.
-# Read more here: https://github.com/bazelbuild/bazel-gazelle#directives
-# gazelle:resolve go github.com/bazelbuild/rules_go/go/tools/bazel @io_bazel_rules_go//go/tools/bazel:go_default_library
-
-go_library(
- name = "go_default_library",
- srcs = ["runfiles.go"],
- importpath = "github.com/bazelbuild/rules_typescript/devserver/runfiles",
- visibility = ["//visibility:public"],
- deps = [
- "@io_bazel_rules_go//go/tools/bazel:go_default_library",
- ],
-)
diff --git a/packages/concatjs/devserver/runfiles/runfiles.go b/packages/concatjs/devserver/runfiles/runfiles.go
deleted file mode 100644
index 3db23d9..0000000
--- a/packages/concatjs/devserver/runfiles/runfiles.go
+++ /dev/null
@@ -1,29 +0,0 @@
-// Package runfiles that provides utility helpers for resolving Bazel runfiles within Go.
-package runfiles
-
-import (
- "path/filepath"
- "strings"
-
- "github.com/bazelbuild/rules_go/go/tools/bazel"
-)
-
-// Runfile returns the base directory to the bazel runfiles
-func Runfile(_base string, manifestPath string) (string, error) {
- // Absolute paths don't require a lookup in the runfiles manifest
- if filepath.IsAbs(manifestPath) {
- return manifestPath, nil
- }
- // Very hacky workaround for breaking change in rules_go
- // https://github.com/bazelbuild/rules_go/pull/2076#issuecomment-520628083
- // devserver was originally written to resolve full paths from the runfiles manifest
- // including the workspace segment, but rules_go no longer includes the workspace
- // segment in the lookup. We simply remove the first path segment before calling
- // through to the rules_go runfiles helper library.
- parts := strings.SplitN(manifestPath, "/", 2)
- if len(parts) < 2 {
- return bazel.Runfile(manifestPath)
- }
- // throw away parts[0] which is the name of the repository
- return bazel.Runfile(parts[1])
-}
diff --git a/packages/concatjs/index.bzl b/packages/concatjs/index.bzl
deleted file mode 100644
index 678b9eb..0000000
--- a/packages/concatjs/index.bzl
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright 2017 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-"""Public API surface is re-exported here.
-
-Users should not load files under "/internal"
-"""
-
-load("//packages/concatjs/devserver:concatjs_devserver.bzl", _concatjs_devserver = "concatjs_devserver_macro")
-load(
- "//packages/concatjs/web_test:karma_web_test.bzl",
- _karma_web_test = "karma_web_test",
- _karma_web_test_suite = "karma_web_test_suite",
-)
-load("//packages/concatjs/internal:build_defs.bzl", _ts_library = "ts_library_macro")
-load("//packages/concatjs/internal:ts_config.bzl", _ts_config = "ts_config")
-
-karma_web_test = _karma_web_test
-karma_web_test_suite = _karma_web_test_suite
-concatjs_devserver = _concatjs_devserver
-ts_library = _ts_library
-ts_config = _ts_config
diff --git a/packages/concatjs/index.docs.bzl b/packages/concatjs/index.docs.bzl
deleted file mode 100644
index 88616f6..0000000
--- a/packages/concatjs/index.docs.bzl
+++ /dev/null
@@ -1,198 +0,0 @@
-# Copyright 2019 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-# This contains references to the symbols we want documented.
-# We can't point stardoc to the top-level index.bzl since then it will see macros rather than the rules they wrap.
-# So this is a copy of index.bzl with macro indirection removed.
-"""
-# @bazel/concatjs
-
-Concatjs is a JavaScript bundler, in a trivial sense: the UNIX `cat` command is a basic implementation:
-
-```bash
-$ cat one.js two.js > bundle.js
-```
-
-Clearly self-evident is that this bundler is super-fast and simple.
-A performant implementation adds some in-memory caching, and for developer ergonomics you add a simple IIFE wrapper
-around each file so that the Chrome DevTools shows the files in the tree as if they had been independently loaded.
-
-However at its core, concatjs requires a big tradeoff of a migration cost to buy-in, to get this incredible performance.
-The path of the JavaScript files is lost in the bundling process, so they must contain their module ID internally.
-
-[Named AMD/UMD modules](https://requirejs.org/docs/whyamd.html#namedmodules) and `goog.module` are the two JS module formats that are compatible with concatjs.
-Most packages do not ship with this format, so in order to use concatjs tooling, you have to shim your code and dependencies. See the [Compatibility](#compatibility) section below.
-
-This is at the core of how Google does JavaScript development.
-So Bazel rules that originated in Google's codebase have affordances for concatjs.
-For example `ts_library` produces named AMD modules in its "devmode" output, and
-`karma_web_test` expects to bundle inputs using concatjs.
-
-## Compatibility
-
-### First-party code
-
-First-party code has to be authored as named AMD/UMD modules.
-This is also historically referred to as "RequireJS" modules since that's the
-JS loader that is typically used with them.
-
-If you write TypeScript, you can do this following their [documentation](https://www.typescriptlang.org/docs/handbook/modules.html).
-
-There is an example in this repository: we have an `index.ts` file that wants
-to be used with require.js `require("@bazel/concatjs")`.
-So it
-[declares
-that module name](https://github.com/bazelbuild/rules_nodejs/blob/bd53eb524ea3bd56b46b7a5f2eff700443e281ec/packages/concatjs/index.ts#L1)
-using the TS triple-slash syntax:
-
-```typescript
-///<amd-module name="@bazel/concatjs"/>
-```
-
-it is [also compiled with](https://github.com/bazelbuild/rules_nodejs/blob/bd53eb524ea3bd56b46b7a5f2eff700443e281ec/packages/concatjs/BUILD.bazel#L28)
-the `"compilerOptions": { "module": "umd" }` TypeScript setting.
-
-### Third-party code
-
-To make it easier to produce a UMD version of a third-party npm package, we automatically generate a target that uses Browserify to build one, using the `main` entry from the package's `package.json`.
-In most cases this will make the package loadable under concatjs.
-This target has a `__umd` suffix. For example, if your library is at `@npm//foo` then the UMD target is `@npm//foo:foo__umd`.
-
-An example where this fixes a users issue: <https://github.com/bazelbuild/rules_nodejs/issues/2317#issuecomment-735921318>
-
-In some cases, the generated UMD bundle is not sufficient, and in others it fails to build because it requires some special Browserify configuration.
-You can always write your own shim that grabs a symbol from a package you use, and exposes it in an AMD/require.js-compatible way.
-For example, even though RxJS ships with a UMD bundle, it contains multiple entry points and uses anonymous modules, not named modules. So our Angular/concatjs example has a `rxjs_shims.js` file that exposes some RxJS operators, then at <https://github.com/bazelbuild/rules_nodejs/blob/2.3.1/examples/angular/src/BUILD.bazel#L65-L71> this is combined in a `filegroup` with the `rxjs.umd.js` file. Now we use this filegroup target when depending on RxJS in a `concatjs_*` rule.
-
-Ultimately by using concatjs, you're signing up for at least a superficial understanding of these shims and may need to update them when you change your dependencies.
-
-## Serving JS in development mode under Bazel
-
-There are two choices for development mode:
-
-1. Use the `concatjs_devserver` rule to bring up our simple, fast development server.
- This is intentionally very simple, to help you get started quickly. However,
- since there are many development servers available, we do not want to mirror
- their features in yet another server we maintain.
-2. Teach your real frontend server to serve files from Bazel's output directory.
- This is not yet documented. Choose this option if you have an existing server
- used in development mode, or if your requirements exceed what the
- `concatjs_devserver` supports. Be careful that your development round-trip stays
- fast (should be under two seconds).
-
-To use `concatjs_devserver`, you simply `load` the rule, and call it with `deps` that
-point to your `ts_library` target(s):
-
-```python
-load("//packages/concatjs:index.bzl", "concatjs_devserver", "ts_library")
-
-ts_library(
- name = "app",
- srcs = ["app.ts"],
-)
-
-concatjs_devserver(
- name = "devserver",
- # We'll collect all the devmode JS sources from these TypeScript libraries
- deps = [":app"],
- # This is the path we'll request from the browser, see index.html
- serving_path = "/bundle.js",
- # The devserver can serve our static files too
- static_files = ["index.html"],
-)
-```
-
-The `index.html` should be the same one you use for production, and it should
-load the JavaScript bundle from the path indicated in `serving_path`.
-
-If you don't have an index.html file, a simple one will be generated by the
-`concatjs_devserver`.
-
-See `examples/app` in this repository for a working example. To run the
-devserver, we recommend you use [ibazel]:
-
-```sh
-$ ibazel run examples/app:devserver
-```
-
-`ibazel` will keep the devserver program running, and provides a LiveReload
-server so the browser refreshes the application automatically when each build
-finishes.
-
-[ibazel]: https://github.com/bazelbuild/bazel-watcher
-
-## Testing with Karma
-
-The `karma_web_test` rule runs karma tests with Bazel.
-
-It depends on rules_webtesting, so you need to add this to your `WORKSPACE`
-if you use the web testing rules in `@bazel/concatjs`:
-
-```python
-# Fetch transitive Bazel dependencies of karma_web_test
-http_archive(
- name = "io_bazel_rules_webtesting",
- sha256 = "e9abb7658b6a129740c0b3ef6f5a2370864e102a5ba5ffca2cea565829ed825a",
- urls = ["https://github.com/bazelbuild/rules_webtesting/releases/download/0.3.5/rules_webtesting.tar.gz"],
-)
-
-# Set up web testing, choose browsers we can test on
-load("@io_bazel_rules_webtesting//web:repositories.bzl", "web_test_repositories")
-
-web_test_repositories()
-
-load("@io_bazel_rules_webtesting//web/versioned:browsers-0.3.3.bzl", "browser_repositories")
-
-browser_repositories(
- chromium = True,
- firefox = True,
-)
-```
-
-## Known issues with running Chromium for macOS/Windows in Bazel
-
-For macOS and Windows, Chromium comes with files that contain spaces in their file names. This breaks runfile tree
-creation within Bazel due to a bug. There are various workarounds that allow for Chromium on these platforms:
-
-* Instruct Bazel to automatically disable runfile tree creation if not needed. [More details here](https://github.com/bazelbuild/bazel/issues/4327#issuecomment-922106293)
-* Instruct Bazel to use an alternative experimental approach for creating runfile trees. [More details here](https://github.com/bazelbuild/bazel/issues/4327#issuecomment-627422865)
-
-## Installing with user-managed dependencies
-
-If you didn't use the `yarn_install` or `npm_install` rule to create an `npm` workspace, you'll have to declare a rule in your root `BUILD.bazel` file to execute karma:
-
-```python
-# Create a karma rule to use in karma_web_test_suite karma
-# attribute when using user-managed dependencies
-nodejs_binary(
- name = "karma/karma",
- entry_point = "//:node_modules/karma/bin/karma",
- # Point bazel to your node_modules to find the entry point
- data = ["//:node_modules"],
-)
-```
-"""
-
-load("//packages/concatjs/devserver:concatjs_devserver.bzl", _concatjs_devserver = "concatjs_devserver")
-load(
- "//packages/concatjs/web_test:karma_web_test.bzl",
- _karma_web_test = "karma_web_test",
- _karma_web_test_suite = "karma_web_test_suite",
-)
-load("//packages/concatjs/internal:build_defs.bzl", _ts_library = "ts_library")
-
-ts_library = _ts_library
-karma_web_test = _karma_web_test
-karma_web_test_suite = _karma_web_test_suite
-concatjs_devserver = _concatjs_devserver
diff --git a/packages/concatjs/index.ts b/packages/concatjs/index.ts
deleted file mode 100644
index cf7e68b..0000000
--- a/packages/concatjs/index.ts
+++ /dev/null
@@ -1,134 +0,0 @@
-///<amd-module name="@bazel/concatjs"/>
-/*
- * Concat all JS files before serving.
- */
-import * as crypto from 'crypto';
-import * as fs from 'fs';
-import * as File from 'karma/lib/file';
-import * as path from 'path';
-import * as process from 'process';
-import {createInterface} from 'readline';
-///<reference types="lib.dom"/>
-
-/**
- * Return SHA1 of data buffer.
- */
-function sha1(data) {
- const hash = crypto.createHash('sha1');
- hash.update(data);
- return hash.digest('hex');
-}
-
-/**
- * Entry-point for the Karma plugin.
- */
-function initConcatJs(logger, emitter, basePath, hostname, port) {
- const log = logger.create('framework.concat_js');
-
- // Create a tmp file for the concat bundle, rely on Bazel to clean the TMPDIR
- const tmpFile =
- path.join(process.env['TEST_TMPDIR'], crypto.randomBytes(6).readUIntLE(0, 6).toString(36));
-
- emitter.on('file_list_modified', files => {
- const bundleFile = new File('/concatjs_bundle.js') as any;
- bundleFile.contentPath = tmpFile;
- // Preserve all non-JS that were there in the included list.
- const included = files.included.filter(f => path.extname(f.originalPath) !== '.js');
- const bundledFiles =
- files.included.filter(f => path.extname(f.originalPath) === '.js').map((file) => {
- const relativePath = path.relative(basePath, file.originalPath).replace(/\\/g, '/');
-
- let content = file.content + `\n//# sourceURL=http://${hostname}:${port}/base/` +
- relativePath + '\n';
-
- return `
- loadFile(
- ${JSON.stringify(relativePath)},
- ${JSON.stringify(content)});`;
- });
-
- // Execute each file by putting it in a <script> tag. This makes them create
- // global variables, even with 'use strict'; (unlike eval).
- bundleFile.content = `
-(function() { // Hide local variables
- // Use policy to support Trusted Types enforcement.
- var policy = null;
- if (window.trustedTypes) {
- try {
- policy = window.trustedTypes.createPolicy('bazel-karma', {
- createScript: function(s) { return s; }
- });
- } catch (e) {
- // In case the policy has been unexpectedly created before, log the error
- // and fall back to the old behavior.
- console.log(e);
- }
- }
- // IE 8 and below do not support document.head.
- var parent = document.getElementsByTagName('head')[0] ||
- document.documentElement;
- function loadFile(path, src) {
- var trustedSrc = policy ? policy.createScript(src) : src;
- try {
- var script = document.createElement('script');
- if ('textContent' in script) {
- script.textContent = trustedSrc;
- } else {
- // This is for IE 8 and below.
- script.text = trustedSrc;
- }
- parent.appendChild(script);
- // Don't pollute the DOM with hundreds of <script> tags.
- parent.removeChild(script);
- } catch(err) {
- window.__karma__ && window.__karma__.error(
- 'An error occurred while loading ' + path + ':\\n' +
- (err.stack || err.message || err.toString()));
- console.error('An error occurred while loading ' + path, err);
- throw err;
- }
- }
-${bundledFiles.join('')}
-})();`;
- bundleFile.sha = sha1(Buffer.from(bundleFile.content));
- bundleFile.mtime = new Date();
- included.unshift(bundleFile);
-
- files.included = included;
- files.served.push(bundleFile);
-
- log.debug('Writing concatjs bundle to tmp file %s', bundleFile.contentPath);
- fs.writeFileSync(bundleFile.contentPath, bundleFile.content);
- });
-}
-
-(initConcatJs as any).$inject =
- ['logger', 'emitter', 'config.basePath', 'config.hostname', 'config.port'];
-
-function watcher(fileList: {refresh: () => void}) {
- // ibazel will write this string after a successful build
- // We don't want to re-trigger tests if the compilation fails, so
- // we should only listen for this event.
- const IBAZEL_NOTIFY_BUILD_SUCCESS = 'IBAZEL_BUILD_COMPLETED SUCCESS';
- // ibazel communicates with us via stdin
- const rl = createInterface({input: process.stdin, terminal: false});
- rl.on('line', (chunk: string) => {
- if (chunk === IBAZEL_NOTIFY_BUILD_SUCCESS) {
- fileList.refresh();
- }
- });
- rl.on('close', () => {
- // Give ibazel 5s to kill our process, otherwise do it ourselves
- setTimeout(() => {
- console.error('ibazel failed to stop karma after 5s; probably a bug');
- process.exit(1);
- }, 5000);
- });
-}
-
-(watcher as any).$inject = ['fileList'];
-
-module.exports = {
- 'framework:concat_js': ['factory', initConcatJs],
- 'watcher': ['value', watcher],
-};
diff --git a/packages/concatjs/internal/BUILD.bazel b/packages/concatjs/internal/BUILD.bazel
deleted file mode 100644
index 725a1d2..0000000
--- a/packages/concatjs/internal/BUILD.bazel
+++ /dev/null
@@ -1,160 +0,0 @@
-# Copyright 2017 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-# gazelle:exclude worker_protocol.proto
-
-load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
-load("//:index.bzl", "nodejs_binary")
-load("//packages/jasmine:index.bzl", "jasmine_node_test")
-load("//packages/concatjs:index.bzl", "ts_library")
-load("@npm//typescript:index.bzl", "tsc")
-
-package(default_visibility = ["//visibility:public"])
-
-bzl_library(
- name = "bzl",
- srcs = glob(
- [
- "*.bzl",
- "common/*.bzl",
- ],
- exclude = ["internal_*"],
- ),
- visibility = ["//visibility:public"],
- deps = [
- "@bazel_skylib//lib:types",
- "@build_bazel_rules_nodejs//:bzl",
- "@build_bazel_rules_nodejs//internal/common:bzl",
- "@rules_nodejs//nodejs:bzl",
- ],
-)
-
-exports_files(["tsetse/tsconfig.json"])
-
-_TSC_WRAPPED_TESTS = [
- "**/test_support.ts",
- "**/*_test.ts",
-]
-
-_TSC_WRAPPED_SRCS = glob(
- [
- "tsc_wrapped/*.ts",
- "tsetse/**/*.ts",
- ],
- exclude = _TSC_WRAPPED_TESTS + ["tsetse/tests/**"],
-)
-
-_TSC_WRAPPED_JS = [k[:-3] + ".js" for k in _TSC_WRAPPED_SRCS]
-
-_TSC_WRAPPED_TYPINGS = [k[:-3] + ".d.ts" for k in _TSC_WRAPPED_SRCS]
-
-# Build our custom compiler using the vanilla one
-tsc(
- name = "tsc_wrapped",
- outs = _TSC_WRAPPED_JS + _TSC_WRAPPED_TYPINGS,
- args = [
- "--declaration",
- "-p",
- "$(execpath //packages/concatjs/internal:tsconfig.json)",
- "--outDir",
- "$(RULEDIR)",
- ],
- data = _TSC_WRAPPED_SRCS + [
- "//packages/concatjs/internal:tsconfig.json",
- "@npm//@types/node",
- "@npm//@angular/compiler-cli",
- "@npm//protobufjs",
- "@npm//tsickle",
- "@npm//tsutils",
- "@npm//typescript",
- ],
- visibility = ["//visibility:public"],
-)
-
-# Other ts_library rules will use this custom compiler, which calls the
-# TypeScript APIs to act like tsc, but adds capabilities like Bazel workers.
-# TODO(gregmagolan): make @npm//tsickle dependency optional
-nodejs_binary(
- name = "tsc_wrapped_bin",
- data = [
- ":tsc_wrapped",
- "//packages/concatjs/third_party/github.com/bazelbuild/bazel/src/main/protobuf:worker_protocol.proto",
- "@npm//protobufjs",
- "@npm//source-map-support",
- "@npm//tsickle",
- "@npm//tsutils",
- "@npm//typescript",
- ],
- entry_point = ":tsc_wrapped/tsc_wrapped.js",
- # Disables the Bazel node modules linker. The node module linker is unreliable for the
- # persistent worker executable, as it would rely on the `node_modules/` folder in the
- # execroot that can be shared in non-sandbox environments or for persistent workers.
- # https://docs.bazel.build/versions/main/command-line-reference.html#flag--worker_sandboxing.
- templated_args = ["--nobazel_run_linker"],
- visibility = ["//visibility:public"],
-)
-
-ts_library(
- name = "test_lib",
- srcs = glob(_TSC_WRAPPED_TESTS) + _TSC_WRAPPED_TYPINGS,
- compiler = "//packages/concatjs/internal:tsc_wrapped_bin",
- tsconfig = "//packages/concatjs/internal:tsconfig.json",
- deps = [
- "@npm//@angular/compiler-cli",
- "@npm//@types/jasmine",
- "@npm//@types/node",
- "@npm//tsickle",
- "@npm//typescript",
- ],
-)
-
-jasmine_node_test(
- name = "test",
- srcs = [],
- tags = [
- # TODO: it seems like this test has been broken since we brought in from rules_typescript
- "manual",
- ],
- deps = _TSC_WRAPPED_JS + [
- ":test_lib",
- "//packages/concatjs/third_party/github.com/bazelbuild/bazel/src/main/protobuf:worker_protocol.proto",
- "@npm//jasmine",
- "@npm//protobufjs",
- "@npm//source-map",
- "@npm//typescript",
- ],
-)
-
-# We don't need to distribute any of the content of the BUILD.bazel file in this package
-# So generate an empty marker file
-genrule(
- name = "generated_BUILD",
- srcs = [],
- # Name the output "BUILD" so it doesn't collide with InputArtifact "BUILD.bazel"
- outs = ["BUILD"],
- cmd = "echo \"# Marker that this directory is a Bazel package\" > $@",
-)
-
-filegroup(
- name = "package_contents",
- srcs = [
- "build_defs.bzl",
- "common/compilation.bzl",
- "common/json_marshal.bzl",
- "common/module_mappings.bzl",
- "common/tsconfig.bzl",
- "ts_config.bzl",
- ],
- visibility = ["//packages/concatjs:__subpackages__"],
-)
diff --git a/packages/concatjs/internal/build_defs.bzl b/packages/concatjs/internal/build_defs.bzl
deleted file mode 100644
index 05792c8..0000000
--- a/packages/concatjs/internal/build_defs.bzl
+++ /dev/null
@@ -1,538 +0,0 @@
-# Copyright 2017 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-"TypeScript compilation"
-
-load("@rules_nodejs//nodejs:providers.bzl", "LinkablePackageInfo", "js_module_info")
-load("@build_bazel_rules_nodejs//:providers.bzl", "ExternalNpmPackageInfo", "js_ecma_script_module_info", "js_named_module_info", "node_modules_aspect", "run_node")
-
-# pylint: disable=unused-argument
-# pylint: disable=missing-docstring
-load("//packages/concatjs/internal:common/compilation.bzl", "COMMON_ATTRIBUTES", "DEPS_ASPECTS", "compile_ts", "ts_providers_dict_to_struct")
-load("//packages/concatjs/internal:common/tsconfig.bzl", "create_tsconfig")
-load("//packages/concatjs/internal:ts_config.bzl", "TsConfigInfo")
-
-_DOC = """type-check and compile a set of TypeScript sources to JavaScript.
-
-It produces declarations files (`.d.ts`) which are used for compiling downstream
-TypeScript targets and JavaScript for the browser and Closure compiler.
-
-By default, `ts_library` uses the `tsconfig.json` file in the workspace root
-directory. See the notes about the `tsconfig` attribute below.
-
-## Serving TypeScript for development
-
-`ts_library` is typically served by the concatjs_devserver rule, documented in the `@bazel/concatjs` package.
-
-## Accessing JavaScript outputs
-
-The default output of the `ts_library` rule is the `.d.ts` files.
-This is for a couple reasons:
-
-- help ensure that downstream rules which access default outputs will not require
- a cascading re-build when only the implementation changes but not the types
-- make you think about whether you want the `devmode` (named `UMD`) or `prodmode` outputs
-
-You can access the JS output by adding a `filegroup` rule after the `ts_library`,
-for example
-
-```python
-ts_library(
- name = "compile",
- srcs = ["thing.ts"],
-)
-
-filegroup(
- name = "thing.js",
- srcs = ["compile"],
- # Change to es6_sources to get the 'prodmode' JS
- output_group = "es5_sources",
-)
-
-my_rule(
- name = "uses_js",
- deps = ["thing.js"],
-)
-```
-
-"""
-
-# NB: substituted with "//@bazel/concatjs/bin:tsc_wrapped" in the pkg_npm rule
-_DEFAULT_COMPILER = "//packages/concatjs/internal:tsc_wrapped_bin"
-
-_TYPESCRIPT_TYPINGS = Label(
- # BEGIN-INTERNAL
- "@npm" +
- # END-INTERNAL
- "//typescript:typescript__typings",
-)
-
-_TYPESCRIPT_SCRIPT_TARGETS = ["es3", "es5", "es2015", "es2016", "es2017", "es2018", "es2019", "es2020", "esnext"]
-_TYPESCRIPT_MODULE_KINDS = ["none", "commonjs", "amd", "umd", "system", "es2015", "esnext"]
-
-_DEVMODE_TARGET_DEFAULT = "es2015"
-_DEVMODE_MODULE_DEFAULT = "umd"
-_PRODMODE_TARGET_DEFAULT = "es2015"
-_PRODMODE_MODULE_DEFAULT = "esnext"
-
-def _trim_package_node_modules(package_name):
- # trim a package name down to its path prior to a node_modules
- # segment. 'foo/node_modules/bar' would become 'foo' and
- # 'node_modules/bar' would become ''
- segments = []
- for n in package_name.split("/"):
- if n == "node_modules":
- break
- segments.append(n)
- return "/".join(segments)
-
-def _compute_node_modules_root(ctx):
- """Computes the node_modules root from the node_modules and deps attributes.
-
- Args:
- ctx: the starlark execution context
-
- Returns:
- The node_modules root as a string
- """
- node_modules_root = None
- for d in ctx.attr.deps:
- if ExternalNpmPackageInfo in d:
- possible_root = "/".join(["external", d[ExternalNpmPackageInfo].workspace, "node_modules"])
- if not node_modules_root:
- node_modules_root = possible_root
- elif node_modules_root != possible_root:
- fail("All npm dependencies need to come from a single workspace. Found '%s' and '%s'." % (node_modules_root, possible_root))
- if not node_modules_root:
- # there are no fine grained deps but we still need a node_modules_root even if its empty
- node_modules_root = "/".join(["external", ctx.attr._typescript_typings[ExternalNpmPackageInfo].workspace, "node_modules"])
- return node_modules_root
-
-def _filter_ts_inputs(all_inputs):
- return [
- f
- for f in all_inputs
- if f.extension in ["js", "jsx", "ts", "tsx", "json", "proto"]
- ]
-
-def _compile_action(ctx, inputs, outputs, tsconfig_file, node_opts, description = "prodmode"):
- externs_files = []
- action_inputs = inputs
- action_outputs = []
- for output in outputs:
- if output.basename.endswith(".externs.js"):
- externs_files.append(output)
- elif output.basename.endswith(".es5.MF"):
- ctx.actions.write(output, content = "")
- else:
- action_outputs.append(output)
-
- # TODO(plf): For now we mock creation of files other than {name}.js.
- for externs_file in externs_files:
- ctx.actions.write(output = externs_file, content = "")
-
- # A ts_library that has only .d.ts inputs will have no outputs,
- # therefore there are no actions to execute
- if not action_outputs:
- return None
-
- action_inputs.extend(_filter_ts_inputs(ctx.attr._typescript_typings[ExternalNpmPackageInfo].sources.to_list()))
-
- # Also include files from npm fine grained deps as action_inputs.
- # These deps are identified by the ExternalNpmPackageInfo provider.
- for d in ctx.attr.deps:
- if ExternalNpmPackageInfo in d:
- # Note: we can't avoid calling .to_list() on sources
- action_inputs.extend(_filter_ts_inputs(d[ExternalNpmPackageInfo].sources.to_list()))
-
- if ctx.file.tsconfig:
- action_inputs.append(ctx.file.tsconfig)
- if TsConfigInfo in ctx.attr.tsconfig:
- action_inputs.extend(ctx.attr.tsconfig[TsConfigInfo].deps)
-
- # Pass actual options for the node binary in the special "--node_options" argument.
- arguments = ["--node_options=%s" % opt for opt in node_opts]
-
- # We don't try to use the linker to launch the worker process
- # because it causes bazel to spawn a new worker for every action
- # See https://github.com/bazelbuild/rules_nodejs/issues/1803
- # TODO: understand the interaction between linker and workers better
- if ctx.attr.supports_workers:
- # One at-sign makes this a params-file, enabling the worker strategy.
- # Two at-signs escapes the argument so it's passed through to tsc_wrapped
- # rather than the contents getting expanded.
- arguments.append("@@" + tsconfig_file.path)
-
- # Spawn a plain action that runs worker process with no linker
- ctx.actions.run(
- progress_message = "Compiling TypeScript (%s) %s" % (description, ctx.label),
- mnemonic = "TypeScriptCompile",
- inputs = action_inputs,
- outputs = action_outputs,
- # Use the built-in shell environment
- # Allow for users who set a custom shell that can locate standard binaries like tr and uname
- # See https://github.com/NixOS/nixpkgs/issues/43955#issuecomment-407546331
- use_default_shell_env = True,
- arguments = arguments,
- executable = ctx.executable.compiler,
- execution_requirements = {
- "supports-workers": "1",
- },
- env = {"COMPILATION_MODE": ctx.var["COMPILATION_MODE"]},
- )
- else:
- # TODO: if compiler is vanilla tsc, then we need the '-p' argument too
- # arguments.append("-p")
- arguments.append(tsconfig_file.path)
-
- # Run with linker but not as a worker process
- run_node(
- ctx,
- progress_message = "Compiling TypeScript (%s) %s" % (description, ctx.label),
- mnemonic = "tsc",
- inputs = action_inputs,
- outputs = action_outputs,
- # Use the built-in shell environment
- # Allow for users who set a custom shell that can locate standard binaries like tr and uname
- # See https://github.com/NixOS/nixpkgs/issues/43955#issuecomment-407546331
- use_default_shell_env = True,
- arguments = arguments,
- executable = "compiler",
- env = {"COMPILATION_MODE": ctx.var["COMPILATION_MODE"]},
- link_workspace_root = ctx.attr.link_workspace_root,
- )
-
- # Enable the replay_params in case an aspect needs to re-build this library.
- return struct(
- label = ctx.label,
- tsconfig = tsconfig_file,
- inputs = action_inputs,
- outputs = action_outputs,
- compiler = ctx.executable.compiler,
- )
-
-def _devmode_compile_action(ctx, inputs, outputs, tsconfig_file, node_opts):
- _compile_action(
- ctx,
- inputs,
- outputs,
- tsconfig_file,
- node_opts,
- description = "devmode",
- )
-
-def tsc_wrapped_tsconfig(
- ctx,
- files,
- srcs,
- devmode_manifest = None,
- jsx_factory = None,
- **kwargs):
- """Produce a tsconfig.json that sets options required under Bazel.
-
- Args:
- ctx: the Bazel starlark execution context
- files: Labels of all TypeScript compiler inputs
- srcs: Immediate sources being compiled, as opposed to transitive deps
- devmode_manifest: path to the manifest file to write for --target=es5
- jsx_factory: the setting for tsconfig.json compilerOptions.jsxFactory
- **kwargs: remaining args to pass to the create_tsconfig helper
-
- Returns:
- The generated tsconfig.json as an object
- """
-
- # The location of tsconfig.json is interpreted as the root of the project
- # when it is passed to the TS compiler with the `-p` option:
- # https://www.typescriptlang.org/docs/handbook/tsconfig-json.html.
- # Our tsconfig.json is in bazel-foo/bazel-out/local-fastbuild/bin/{package_path}
- # because it's generated in the execution phase. However, our source files are in
- # bazel-foo/ and therefore we need to strip some parent directories for each
- # f.path.
-
- node_modules_root = _compute_node_modules_root(ctx)
- config = create_tsconfig(
- ctx,
- # Filter out package.json files that are included in DeclarationInfo
- # tsconfig files=[] property should only be .ts/.d.ts
- [f for f in files if f.path.endswith(".ts") or f.path.endswith(".tsx")],
- srcs,
- devmode_manifest = devmode_manifest,
- node_modules_root = node_modules_root,
- **kwargs
- )
- config["bazelOptions"]["nodeModulesPrefix"] = node_modules_root
-
- # Control target & module via attributes
- if devmode_manifest:
- # NB: devmode target may still be overriden with a tsconfig bazelOpts.devmodeTargetOverride but that
- # configuration settings will be removed in a future major release
- config["compilerOptions"]["target"] = ctx.attr.devmode_target if hasattr(ctx.attr, "devmode_target") else _DEVMODE_TARGET_DEFAULT
- config["compilerOptions"]["module"] = ctx.attr.devmode_module if hasattr(ctx.attr, "devmode_module") else _DEVMODE_MODULE_DEFAULT
- else:
- config["compilerOptions"]["target"] = ctx.attr.prodmode_target if hasattr(ctx.attr, "prodmode_target") else _PRODMODE_TARGET_DEFAULT
- config["compilerOptions"]["module"] = ctx.attr.prodmode_module if hasattr(ctx.attr, "prodmode_module") else _PRODMODE_MODULE_DEFAULT
-
- # It's fine for users to have types[] in their tsconfig.json to help the editor
- # know which of the node_modules/@types/* entries to include in the program.
- # But we don't want TypeScript to do any automatic resolution under tsc_wrapped
- # because when not run in a sandbox, it will scan the @types directory and find
- # entries that aren't in the action inputs.
- # See https://github.com/bazelbuild/rules_typescript/issues/449
- # This setting isn't shared with g3 because there is no node_modules directory there.
- config["compilerOptions"]["types"] = []
-
- # If the user gives a tsconfig attribute, the generated file should extend
- # from the user's tsconfig.
- # See https://github.com/Microsoft/TypeScript/issues/9876
- # We subtract the ".json" from the end before handing to TypeScript because
- # this gives extra error-checking.
- if ctx.file.tsconfig:
- workspace_path = config["compilerOptions"]["rootDir"]
- config["extends"] = "/".join([workspace_path, ctx.file.tsconfig.path[:-len(".json")]])
-
- if jsx_factory:
- config["compilerOptions"]["jsxFactory"] = jsx_factory
-
- return config
-
-# ************ #
-# ts_library #
-# ************ #
-
-def _ts_library_impl(ctx):
- """Implementation of ts_library.
-
- Args:
- ctx: the context.
-
- Returns:
- the struct returned by the call to compile_ts.
- """
- ts_providers = compile_ts(
- ctx,
- is_library = True,
- compile_action = _compile_action,
- devmode_compile_action = _devmode_compile_action,
- tsc_wrapped_tsconfig = tsc_wrapped_tsconfig,
- )
-
- # Add in shared JS providers.
- # See design doc https://docs.google.com/document/d/1ggkY5RqUkVL4aQLYm7esRW978LgX3GUCnQirrk5E1C0/edit#
- # and issue https://github.com/bazelbuild/rules_nodejs/issues/57 for more details.
- ts_providers["providers"].extend([
- js_module_info(
- sources = ts_providers["typescript"]["es5_sources"],
- deps = ctx.attr.deps,
- ),
- js_named_module_info(
- sources = ts_providers["typescript"]["es5_sources"],
- deps = ctx.attr.deps,
- ),
- js_ecma_script_module_info(
- sources = ts_providers["typescript"]["es6_sources"],
- deps = ctx.attr.deps,
- ),
- # TODO: remove legacy "typescript" provider
- # once it is no longer needed.
- ])
-
- if ctx.attr.package_name:
- link_path = "/".join([p for p in [ctx.bin_dir.path, ctx.label.workspace_root, ctx.label.package] if p])
- ts_providers["providers"].append(LinkablePackageInfo(
- package_name = ctx.attr.package_name,
- package_path = ctx.attr.package_path,
- path = link_path,
- files = ts_providers["typescript"]["es5_sources"],
- ))
-
- return ts_providers_dict_to_struct(ts_providers)
-
-ts_library = rule(
- _ts_library_impl,
- attrs = dict(COMMON_ATTRIBUTES, **{
- "angular_assets": attr.label_list(
- doc = """Additional files the Angular compiler will need to read as inputs.
- Includes .css and .html files""",
- allow_files = [".css", ".html"],
- ),
- "compiler": attr.label(
- doc = """Sets a different TypeScript compiler binary to use for this library.
-For example, we use the vanilla TypeScript tsc.js for bootstrapping,
-and Angular compilations can replace this with `ngc`.
-
-The default ts_library compiler depends on the `//@bazel/typescript`
-target which is setup for projects that use bazel managed npm deps and
-install the @bazel/typescript npm package.
-
-You can also use a custom compiler to increase the NodeJS heap size used for compilations.
-
-To do this, declare your own binary for running `tsc_wrapped`, e.g.:
-
-```python
-nodejs_binary(
- name = "tsc_wrapped_bin",
- entry_point = "@npm//:node_modules/@bazel/typescript/internal/tsc_wrapped/tsc_wrapped.js",
- templated_args = [
- "--node_options=--max-old-space-size=2048",
- ],
- data = [
- "@npm//protobufjs",
- "@npm//source-map-support",
- "@npm//tsutils",
- "@npm//typescript",
- "@npm//@bazel/typescript",
- ],
-)
-```
-
-then refer to that target in the `compiler` attribute.
-
-Note that `nodejs_binary` targets generated by `npm_install`/`yarn_install` can include data dependencies
-on packages which aren't declared as dependencies.
-For example, if you use [tsickle](https://github.com/angular/tsickle) to generate Closure Compiler-compatible JS,
-then it needs to be a data dependency of `tsc_wrapped` so that it can be loaded at runtime.
-""",
- default = Label(_DEFAULT_COMPILER),
- allow_files = True,
- executable = True,
- cfg = "exec",
- ),
- "deps": attr.label_list(
- aspects = DEPS_ASPECTS + [node_modules_aspect],
- doc = "Compile-time dependencies, typically other ts_library targets",
- ),
- "devmode_module": attr.string(
- doc = """Set the typescript `module` compiler option for devmode output.
-
-This value will override the `module` option in the user supplied tsconfig.""",
- values = _TYPESCRIPT_MODULE_KINDS,
- default = _DEVMODE_MODULE_DEFAULT,
- ),
- "devmode_target": attr.string(
- doc = """Set the typescript `target` compiler option for devmode output.
-
-This value will override the `target` option in the user supplied tsconfig.""",
- values = _TYPESCRIPT_SCRIPT_TARGETS,
- default = _DEVMODE_TARGET_DEFAULT,
- ),
- "internal_testing_type_check_dependencies": attr.bool(default = False, doc = "Testing only, whether to type check inputs that aren't srcs."),
- "link_workspace_root": attr.bool(
- doc = """Link the workspace root to the bin_dir to support absolute requires like 'my_wksp/path/to/file'.
-
-If source files need to be required then they can be copied to the bin_dir with copy_to_bin.""",
- ),
- "package_name": attr.string(
- doc = """The package name that the linker will link this ts_library output as.
-
-If package_path is set, the linker will link this package under <package_path>/node_modules/<package_name>.
-If package_path is not set the this will be the root node_modules of the workspace.""",
- ),
- "package_path": attr.string(
- doc = """The package path in the workspace that the linker will link this ts_library output to.
-
-If package_path is set, the linker will link this package under <package_path>/node_modules/<package_name>.
-If package_path is not set the this will be the root node_modules of the workspace.""",
- ),
- "prodmode_module": attr.string(
- doc = """Set the typescript `module` compiler option for prodmode output.
-
-This value will override the `module` option in the user supplied tsconfig.""",
- values = _TYPESCRIPT_MODULE_KINDS,
- default = _PRODMODE_MODULE_DEFAULT,
- ),
- "prodmode_target": attr.string(
- doc = """Set the typescript `target` compiler option for prodmode output.
-
-This value will override the `target` option in the user supplied tsconfig.""",
- values = _TYPESCRIPT_SCRIPT_TARGETS,
- default = _PRODMODE_TARGET_DEFAULT,
- ),
- "srcs": attr.label_list(
- doc = "The TypeScript source files to compile.",
- allow_files = [".ts", ".tsx"],
- mandatory = True,
- ),
- "supports_workers": attr.bool(
- doc = """Intended for internal use only.
-
-Allows you to disable the Bazel Worker strategy for this library.
-Typically used together with the "compiler" setting when using a
-non-worker aware compiler binary.""",
- default = True,
- ),
-
- # TODO(alexeagle): reconcile with google3: ts_library rules should
- # be portable across internal/external, so we need this attribute
- # internally as well.
- "tsconfig": attr.label(
- doc = """A tsconfig.json file containing settings for TypeScript compilation.
-Note that some properties in the tsconfig are governed by Bazel and will be
-overridden, such as `target` and `module`.
-
-The default value is set to `//:tsconfig.json` by a macro. This means you must
-either:
-
-- Have your `tsconfig.json` file in the workspace root directory
-- Use an alias in the root BUILD.bazel file to point to the location of tsconfig:
- `alias(name="tsconfig.json", actual="//path/to:tsconfig-something.json")`
- and also make the tsconfig.json file visible to other Bazel packages:
- `exports_files(["tsconfig.json"], visibility = ["//visibility:public"])`
-- Give an explicit `tsconfig` attribute to all `ts_library` targets
- """,
- allow_single_file = True,
- ),
- "tsickle_typed": attr.bool(
- default = True,
- doc = "If using tsickle, instruct it to translate types to ClosureJS format",
- ),
- "use_angular_plugin": attr.bool(
- doc = """Run the Angular ngtsc compiler under ts_library""",
- ),
- "_typescript_typings": attr.label(
- default = _TYPESCRIPT_TYPINGS,
- ),
- }),
- outputs = {
- "tsconfig": "%{name}_tsconfig.json",
- },
- doc = _DOC,
-)
-
-def ts_library_macro(tsconfig = None, **kwargs):
- """Wraps `ts_library` to set the default for the `tsconfig` attribute.
-
- This must be a macro so that the string is converted to a label in the context of the
- workspace that declares the `ts_library` target, rather than the workspace that defines
- `ts_library`, or the workspace where the build is taking place.
-
- This macro is re-exported as `ts_library` in the public API.
-
- Args:
- tsconfig: the label pointing to a tsconfig.json file
- **kwargs: remaining args to pass to the ts_library rule
- """
- if not tsconfig:
- tsconfig = "//:tsconfig.json"
-
- # plugins generally require the linker
- # (unless the user statically linked them into the compiler binary)
- # Therefore we disable workers for them by default
- if "supports_workers" in kwargs.keys():
- supports_workers = kwargs.pop("supports_workers")
- else:
- uses_plugin = kwargs.get("use_angular_plugin", False)
- supports_workers = not uses_plugin
-
- ts_library(tsconfig = tsconfig, supports_workers = supports_workers, **kwargs)
diff --git a/packages/concatjs/internal/common/compilation.bzl b/packages/concatjs/internal/common/compilation.bzl
deleted file mode 100644
index fed787a..0000000
--- a/packages/concatjs/internal/common/compilation.bzl
+++ /dev/null
@@ -1,534 +0,0 @@
-# Copyright 2017 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-"""Used for compilation by the different implementations of build_defs.bzl.
-"""
-
-load("@rules_nodejs//nodejs:providers.bzl", "DeclarationInfo")
-load(":common/json_marshal.bzl", "json_marshal")
-load(":common/module_mappings.bzl", "module_mappings_aspect")
-
-_DEBUG = False
-
-DEPS_ASPECTS = [
- module_mappings_aspect,
-]
-
-_ADDITIONAL_D_TS = attr.label_list(
- allow_files = True,
-)
-
-# Mock out the JsInfo blaze-only provider
-JsInfo = provider()
-
-# Attributes shared by any typescript-compatible rule (ts_library, ng_module)
-# @unsorted-dict-items
-COMMON_ATTRIBUTES = {
- "data": attr.label_list(
- default = [],
- allow_files = True,
- ),
- # A list of diagnostics expected when compiling this library, in the form of
- # "diagnostic:regexp", e.g. "TS1234:failed to quizzle the .* wobble".
- # Useful to test for expected compilation errors.
- "expected_diagnostics": attr.string_list(),
- # Whether to generate externs.js from any "declare" statement.
- "generate_externs": attr.bool(default = True),
- # Used to determine module mappings
- "module_name": attr.string(),
- "module_root": attr.string(),
- # TODO(evanm): make this the default and remove the option.
- "runtime": attr.string(default = "browser"),
- # TODO(radokirov): remove this attr when clutz is stable enough to consume
- # any closure JS code.
- "runtime_deps": attr.label_list(
- default = [],
- providers = [JsInfo],
- ),
- "deps": attr.label_list(
- aspects = DEPS_ASPECTS,
- providers = [DeclarationInfo],
- ),
- "_additional_d_ts": _ADDITIONAL_D_TS,
-}
-
-# Attributes shared by any typescript-compatible aspect.
-ASPECT_ATTRIBUTES = {
- "_additional_d_ts": _ADDITIONAL_D_TS,
-}
-
-COMMON_OUTPUTS = {
- # Allow the tsconfig.json to be generated without running compile actions.
- "tsconfig": "%{name}_tsconfig.json",
-}
-
-_DEPSET_TYPE = type(depset())
-
-def _collect_dep_declarations(ctx, declaration_infos):
- """Flattens DeclarationInfo from typescript and javascript dependencies.
-
- Args:
- ctx: ctx.
- declaration_infos: list of DeclarationInfo collected from dependent targets
-
- Returns:
- A struct of depsets for direct, transitive and type-blacklisted declarations.
- """
-
- # .d.ts files from direct dependencies, ok for strict deps
- direct_deps_declarations = [dep.declarations for dep in declaration_infos]
-
- # all reachable .d.ts files from dependencies.
- transitive_deps_declarations = [dep.transitive_declarations for dep in declaration_infos]
-
- # all reachable .d.ts files from node_modules attribute (if it has a typescript provider)
- # "node_modules" still checked for backward compat for ng_module
- if hasattr(ctx.attr, "node_modules"):
- if DeclarationInfo in ctx.attr.node_modules:
- transitive_deps_declarations.append(ctx.attr.node_modules[DeclarationInfo].transitive_declarations)
- elif hasattr(ctx.attr.node_modules, "typescript"):
- # TODO(b/139705078): remove this case after bazel BUILD file generation for node_modules is updated
- transitive_deps_declarations.append([ctx.attr.node_modules.typescript.transitive_declarations])
- if hasattr(ctx.attr, "_typescript_typings"):
- transitive_deps_declarations.append(ctx.attr._typescript_typings[DeclarationInfo].transitive_declarations)
-
- # .d.ts files whose types tsickle will not emit (used for ts_declaration(generate_externs=False).
- type_blocklisted_declarations = [dep.type_blocklisted_declarations for dep in declaration_infos]
-
- # If a tool like github.com/angular/clutz can create .d.ts from type annotated .js
- # its output will be collected here.
-
- return DeclarationInfo(
- declarations = depset(transitive = direct_deps_declarations),
- transitive_declarations = depset(ctx.files._additional_d_ts, transitive = transitive_deps_declarations),
- type_blocklisted_declarations = depset(transitive = type_blocklisted_declarations),
- )
-
-def _should_generate_externs(ctx):
- """Whether externs should be generated.
-
- If ctx has a generate_externs attribute, the value of that is returned.
- Otherwise, this is true."""
- return getattr(ctx.attr, "generate_externs", True)
-
-def _get_runtime(ctx):
- """Gets the runtime for the rule.
-
- Defaults to "browser" if the runtime attr isn't present."""
- return getattr(ctx.attr, "runtime", "browser")
-
-def _outputs(ctx, label, srcs_files = []):
- """Returns closure js, devmode js, and .d.ts output files.
-
- Args:
- ctx: ctx.
- label: Label. package label.
- srcs_files: File list. sources files list.
-
- Returns:
- A struct of file lists for different output types and their relationship to each other.
- """
- workspace_segments = label.workspace_root.split("/") if label.workspace_root else []
- package_segments = label.package.split("/") if label.package else []
- trim = len(workspace_segments) + len(package_segments)
- create_shim_files = False
-
- closure_js_files = []
- devmode_js_files = []
- declaration_files = []
- transpilation_infos = []
- for input_file in srcs_files:
- is_dts = input_file.short_path.endswith(".d.ts")
- if is_dts and not create_shim_files:
- continue
- basename = "/".join(input_file.short_path.split("/")[trim:])
- for ext in [".d.ts", ".tsx", ".ts"]:
- if basename.endswith(ext):
- basename = basename[:-len(ext)]
- break
- closure_js_file = ctx.actions.declare_file(basename + ".mjs")
- closure_js_files.append(closure_js_file)
-
- # Temporary until all imports of ngfactory/ngsummary files are removed
- # TODO(alexeagle): clean up after Ivy launch
- if getattr(ctx.attr, "use_angular_plugin", False):
- closure_js_files.append(ctx.actions.declare_file(basename + ".ngfactory.mjs"))
- closure_js_files.append(ctx.actions.declare_file(basename + ".ngsummary.mjs"))
-
- if not is_dts:
- devmode_js_file = ctx.actions.declare_file(basename + ".js")
- devmode_js_files.append(devmode_js_file)
- transpilation_infos.append(struct(closure = closure_js_file, devmode = devmode_js_file))
- declaration_files.append(ctx.actions.declare_file(basename + ".d.ts"))
-
- # Temporary until all imports of ngfactory/ngsummary files are removed
- # TODO(alexeagle): clean up after Ivy launch
- if getattr(ctx.attr, "use_angular_plugin", False):
- devmode_js_files.append(ctx.actions.declare_file(basename + ".ngfactory.js"))
- devmode_js_files.append(ctx.actions.declare_file(basename + ".ngsummary.js"))
- declaration_files.append(ctx.actions.declare_file(basename + ".ngfactory.d.ts"))
- declaration_files.append(ctx.actions.declare_file(basename + ".ngsummary.d.ts"))
- return struct(
- closure_js = closure_js_files,
- devmode_js = devmode_js_files,
- declarations = declaration_files,
- transpilation_infos = transpilation_infos,
- )
-
-def compile_ts(
- ctx,
- is_library,
- srcs = None,
- declaration_infos = None,
- compile_action = None,
- devmode_compile_action = None,
- jsx_factory = None,
- tsc_wrapped_tsconfig = None,
- tsconfig = None,
- outputs = _outputs,
- validation_outputs = None):
- """Creates actions to compile TypeScript code.
-
- This rule is shared between ts_library and ts_declaration.
-
- Args:
- ctx: ctx.
- is_library: boolean. False if only compiling .dts files.
- srcs: label list. Explicit list of sources to be used instead of ctx.attr.srcs.
- declaration_infos: list of DeclarationInfo. Explicit list of declarations to be used instead of those on ctx.attr.deps.
- compile_action: function. Creates the compilation action.
- devmode_compile_action: function. Creates the compilation action
- for devmode.
- jsx_factory: optional string. Enables overriding jsx pragma.
- tsc_wrapped_tsconfig: function that produces a tsconfig object.
- tsconfig: The tsconfig file to output, if other than ctx.outputs.tsconfig.
- outputs: function from a ctx to the expected compilation outputs.
- validation_outputs: Actions that produce validation outputs will be run whenever any part of
- a rule is run, even if its outputs are not used. This is useful for things like strict deps check.
-
- Returns:
- struct that will be returned by the rule implementation.
- """
-
- ### Collect srcs and outputs.
- srcs = srcs if srcs != None else ctx.attr.srcs
- if declaration_infos == None:
- if not hasattr(ctx.attr, "deps"):
- fail("compile_ts must either be called from a rule with a deps attr, or must be given declaration_infos")
-
- # By default, we collect dependencies from the ctx, when used as a rule
- declaration_infos = [
- d[DeclarationInfo]
- for d in ctx.attr.deps + getattr(ctx.attr, "_helpers", [])
- ]
-
- tsconfig = tsconfig if tsconfig != None else ctx.outputs.tsconfig
- srcs_files = [f for t in srcs for f in t.files.to_list()]
- src_declarations = [] # d.ts found in inputs.
- tsickle_externs = [] # externs.js generated by tsickle, if any.
- has_sources = False
-
- for src in srcs:
- if src.label.package != ctx.label.package:
- # Sources can be in sub-folders, but not in sub-packages.
- fail("Sources must be in the same package as the ts_library rule, " +
- "but %s is not in %s" % (src.label, ctx.label.package), "srcs")
- if hasattr(src, "typescript"):
- # Guard against users accidentally putting deps into srcs by
- # rejecting all srcs values that have a TypeScript provider.
- # TS rules produce a ".d.ts" file, which is a valid input in "srcs",
- # and will then be compiled as a source .d.ts file would, creating
- # externs etc.
- fail(
- "must not reference any TypeScript rules - did you mean deps?",
- "srcs",
- )
-
- for f in src.files.to_list():
- has_sources = True
- if not is_library and not f.path.endswith(".d.ts"):
- fail("srcs must contain only type declarations (.d.ts files), " +
- "but %s contains %s" % (src.label, f.short_path), "srcs")
- if f.path.endswith(".d.ts"):
- src_declarations.append(f)
- continue
-
- outs = outputs(ctx, ctx.label, srcs_files)
- transpiled_closure_js = outs.closure_js
- transpiled_devmode_js = outs.devmode_js
- gen_declarations = outs.declarations
-
- # Not all existing implementations of outputs() may return transpilation_infos
- transpilation_infos = getattr(outs, "transpilation_infos", [])
-
- if has_sources and _get_runtime(ctx) != "nodejs":
- # Note: setting this variable controls whether tsickle is run at all.
- tsickle_externs = [ctx.actions.declare_file(ctx.label.name + ".externs.js")]
-
- dep_declarations = _collect_dep_declarations(ctx, declaration_infos)
-
- type_blocklisted_declarations = dep_declarations.type_blocklisted_declarations
- if not is_library and not _should_generate_externs(ctx):
- type_blocklisted_declarations = depset(srcs_files, transitive = [type_blocklisted_declarations])
-
- # The depsets of output files. These are the files that are always built
- # (including e.g. if you "blaze build :the_target" directly).
- files_depsets = []
-
- # A manifest listing the order of this rule's *.ts files (non-transitive)
- # Only generated if the rule has any sources.
- devmode_manifest = None
-
- # Enable to produce a performance trace when compiling TypeScript to JS.
- # The trace file location will be printed as a build result and can be read
- # in Chrome's chrome://tracing/ UI.
- perf_trace = _DEBUG
- if "TYPESCRIPT_PERF_TRACE_TARGET" in ctx.var:
- perf_trace = str(ctx.label) == ctx.var["TYPESCRIPT_PERF_TRACE_TARGET"]
-
- compilation_inputs = dep_declarations.transitive_declarations.to_list() + srcs_files
- tsickle_externs_path = tsickle_externs[0] if tsickle_externs else None
-
- # Calculate allowed dependencies for strict deps enforcement.
- allowed_deps = depset(
- # A target's sources may depend on each other,
- srcs_files,
- # or on a .d.ts from a direct dependency
- transitive = [dep_declarations.declarations],
- )
-
- tsconfig_es6 = tsc_wrapped_tsconfig(
- ctx,
- compilation_inputs,
- srcs_files,
- jsx_factory = jsx_factory,
- tsickle_externs = tsickle_externs_path,
- type_blocklisted_declarations = type_blocklisted_declarations.to_list(),
- allowed_deps = allowed_deps,
- )
-
- # Do not produce declarations in ES6 mode, tsickle cannot produce correct
- # .d.ts (or even errors) from the altered Closure-style JS emit.
- tsconfig_es6["compilerOptions"]["declaration"] = False
- tsconfig_es6["compilerOptions"].pop("declarationDir")
- outputs = transpiled_closure_js + tsickle_externs
-
- node_profile_args = []
- if perf_trace and has_sources:
- perf_trace_file = ctx.actions.declare_file(ctx.label.name + ".es6.trace")
- tsconfig_es6["bazelOptions"]["perfTracePath"] = perf_trace_file.path
- outputs.append(perf_trace_file)
-
- profile_file = ctx.actions.declare_file(ctx.label.name + ".es6.v8.log")
- node_profile_args = [
- "--prof",
- # Without nologfile_per_isolate, v8 embeds an
- # unpredictable hash code in the file name, which
- # doesn't work with blaze.
- "--nologfile_per_isolate",
- "--logfile=" + profile_file.path,
- ]
- outputs.append(profile_file)
-
- files_depsets.append(depset([perf_trace_file, profile_file]))
-
- ctx.actions.write(
- output = tsconfig,
- content = json_marshal(tsconfig_es6),
- )
-
- # Parameters of this compiler invocation in case we need to replay this with different
- # settings.
- replay_params = None
-
- if has_sources:
- inputs = compilation_inputs + [tsconfig] + getattr(ctx.files, "angular_assets", [])
- replay_params = compile_action(
- ctx,
- inputs,
- outputs,
- tsconfig,
- node_profile_args,
- )
-
- devmode_manifest = ctx.actions.declare_file(ctx.label.name + ".es5.MF")
- tsconfig_json_es5 = ctx.actions.declare_file(ctx.label.name + "_es5_tsconfig.json")
- outputs = (
- transpiled_devmode_js + gen_declarations + [devmode_manifest]
- )
- tsconfig_es5 = tsc_wrapped_tsconfig(
- ctx,
- compilation_inputs,
- srcs_files,
- jsx_factory = jsx_factory,
- devmode_manifest = devmode_manifest.path,
- allowed_deps = allowed_deps,
- )
- node_profile_args = []
- if perf_trace:
- perf_trace_file = ctx.actions.declare_file(ctx.label.name + ".es5.trace")
- tsconfig_es5["bazelOptions"]["perfTracePath"] = perf_trace_file.path
- outputs.append(perf_trace_file)
-
- profile_file = ctx.actions.declare_file(ctx.label.name + ".es5.v8.log")
- node_profile_args = [
- "--prof",
- # Without nologfile_per_isolate, v8 embeds an
- # unpredictable hash code in the file name, which
- # doesn't work with blaze.
- "--nologfile_per_isolate",
- "--logfile=" + profile_file.path,
- ]
- outputs.append(profile_file)
-
- files_depsets.append(depset([perf_trace_file, profile_file]))
-
- ctx.actions.write(output = tsconfig_json_es5, content = json_marshal(
- tsconfig_es5,
- ))
- devmode_compile_action(
- ctx,
- compilation_inputs + [tsconfig_json_es5] + getattr(ctx.files, "angular_assets", []),
- outputs,
- tsconfig_json_es5,
- node_profile_args,
- )
-
- # TODO(martinprobst): Merge the generated .d.ts files, and enforce strict
- # deps (do not re-export transitive types from the transitive closure).
- transitive_decls = depset(src_declarations + gen_declarations, transitive = [dep_declarations.transitive_declarations])
-
- # both ts_library and ts_declarations generate .mjs files:
- # - for libraries, this is the ES6/production code
- # - for declarations, these are generated shims
- es6_sources = depset(transpiled_closure_js + tsickle_externs)
- if is_library:
- es5_sources = depset(transpiled_devmode_js)
- else:
- # In development mode, no code ever references shims as they only
- # contain types, and the ES5 code does not get type annotated.
- es5_sources = depset(tsickle_externs)
-
- # Similarly, in devmode these sources do not get loaded, so do not need
- # to be in a manifest.
- devmode_manifest = None
-
- # Downstream rules see the .d.ts files produced or declared by this rule.
- declarations_depsets = [depset(gen_declarations + src_declarations)]
- if not srcs_files:
- # Re-export sources from deps.
- # TODO(b/30018387): introduce an "exports" attribute.
- for dep in declaration_infos:
- declarations_depsets.append(dep.declarations)
- files_depsets.extend(declarations_depsets)
-
- # If this is a ts_declaration, add tsickle_externs to the outputs list to
- # force compilation of d.ts files. (tsickle externs are produced by running a
- # compilation over the d.ts file and extracting type information.)
- if not is_library:
- files_depsets.append(depset(tsickle_externs))
-
- transitive_es6_sources_sets = [es6_sources]
- for dep in getattr(ctx.attr, "deps", []):
- if hasattr(dep, "typescript"):
- transitive_es6_sources_sets.append(dep.typescript.transitive_es6_sources)
- transitive_es6_sources = depset(transitive = transitive_es6_sources_sets)
-
- declarations_provider = DeclarationInfo(
- declarations = depset(transitive = declarations_depsets),
- transitive_declarations = transitive_decls,
- type_blocklisted_declarations = type_blocklisted_declarations,
- )
-
- # @unsorted-dict-items
- return {
- "providers": [
- DefaultInfo(
- runfiles = ctx.runfiles(
- # Note: don't include files=... here, or they will *always* be built
- # by any dependent rule, regardless of whether it needs them.
- # But these attributes are needed to pass along any input runfiles:
- collect_default = True,
- collect_data = True,
- ),
- files = depset(transitive = files_depsets),
- ),
- OutputGroupInfo(
- _validation = depset(validation_outputs if validation_outputs else []),
- es5_sources = es5_sources,
- es6_sources = es6_sources,
- ),
- declarations_provider,
- ],
- # Also expose the DeclarationInfo as a named provider so that aspect implementations can reference it
- # Otherwise they would be forced to reference it by a numeric index out of the "providers" list above.
- "declarations": declarations_provider,
- "instrumented_files": {
- "dependency_attributes": ["deps", "runtime_deps"],
- "extensions": ["ts", "tsx"],
- "source_attributes": ["srcs"],
- },
- # Expose the module_name so that packaging rules can access it.
- # e.g. rollup_bundle under Bazel needs to convert this into a UMD global
- # name in the Rollup configuration.
- "module_name": getattr(ctx.attr, "module_name", None),
- # Expose the tags so that a Bazel aspect can access them.
- "tags": ctx.attr.tags if hasattr(ctx.attr, "tags") else ctx.rule.attr.tags,
- # @unsorted-dict-items
- "typescript": {
- "devmode_manifest": devmode_manifest,
- "es5_sources": es5_sources,
- "es6_sources": es6_sources,
- "replay_params": replay_params,
- "transitive_es6_sources": transitive_es6_sources,
- "tsickle_externs": tsickle_externs,
- "transpilation_infos": transpilation_infos,
- },
- }
-
-def ts_providers_dict_to_struct(d):
- """ Converts a dict to a struct, recursing into a single level of nested dicts.
-
- This allows users of compile_ts to modify or augment the returned dict before
- converting it to an immutable struct.
-
- Args:
- d: the dict to convert
-
- Returns:
- An immutable struct created from the input dict
- """
-
- # These keys are present in the dict so that aspects can reference them,
- # however they should not be output as legacy providers since we have modern
- # symbol-typed providers for them.
- js_provider = d.pop("js", None)
- declarations_provider = d.pop("declarations", None)
-
- # Promote the "js" string-typed provider to a modern provider
- if js_provider:
- # Create a new providers list rather than modify the existing list
- d["providers"] = d.get("providers", []) + [js_provider]
-
- for key, value in d.items():
- if key != "output_groups" and type(value) == type({}):
- d[key] = struct(**value)
- result = struct(**d)
-
- # Restore the elements we removed, to avoid side-effect of mutating the argument
- if js_provider:
- d["js"] = js_provider
- if declarations_provider:
- d["declarations"] = declarations_provider
- return result
diff --git a/packages/concatjs/internal/common/json_marshal.bzl b/packages/concatjs/internal/common/json_marshal.bzl
deleted file mode 100644
index 0199c45..0000000
--- a/packages/concatjs/internal/common/json_marshal.bzl
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright 2017 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-"""Marshal an arbitrary Starlark object to JSON."""
-
-def json_marshal(data):
- """Serializes arbitrary data to JSON.
-
- Args:
- data: any object
-
- Returns:
- JSON string representing the data
- """
- if type(data) == "dict" or type(data) == "list":
- return str(data).replace(": True", ": true").replace(": False", ": false").replace(": None", ": false")
- elif type(data) == "int":
- return str(data)
- elif type(data) == "string":
- return "\"" + data + "\""
- elif type(data) == "Label":
- return "\"//{}:{}\"".format(data.package, data.name)
- elif type(data) == "bool":
- return "true" if data else "false"
- return "unknown type {}: {}".format(type(data), data)
diff --git a/packages/concatjs/internal/common/json_marshal_test.bzl b/packages/concatjs/internal/common/json_marshal_test.bzl
deleted file mode 100644
index a83151c..0000000
--- a/packages/concatjs/internal/common/json_marshal_test.bzl
+++ /dev/null
@@ -1,33 +0,0 @@
-"""Unit tests for json marshaling.
-
-Note, this cannot live next to the file it tests, because that file is in
-third_party bazel rules, and bazel doesn't support starlark testing yet.
-"""
-
-load("//third_party/bazel_rules/rules_typescript/internal:common/json_marshal.bzl", "json_marshal")
-load("//third_party/bazel_skylib/lib:unittest.bzl", "asserts", "unittest")
-
-def _test_impl(ctx):
- env = unittest.begin(ctx)
- asserts.equals(env, "\"abc\"", json_marshal("abc"))
- asserts.equals(env, "123", json_marshal(123))
- asserts.equals(env, "true", json_marshal(True))
- asserts.equals(env, "false", json_marshal(False))
- asserts.equals(env, "\"//a:b\"", json_marshal(Label("//a:b")))
- asserts.equals(env, "[]", json_marshal([]))
- asserts.equals(env, "{}", json_marshal({}))
- asserts.equals(env, """[1, 2, 3]""", json_marshal([1, 2, 3]))
- asserts.equals(env, """{"a": "b"}""", json_marshal({"a": "b"}))
- asserts.equals(env, """{"none": false}""", json_marshal({"none": None}))
- asserts.equals(
- env,
- """{"a": {"d": 1, "e": true, "f": ["f1", "f2"]}, "b": "val", "c": [{"g": false}]}""",
- json_marshal({"a": {"d": 1, "e": True, "f": ["f1", "f2"]}, "b": "val", "c": [{"g": False}]}),
- )
-
- return unittest.end(env)
-
-_test = unittest.make(_test_impl)
-
-def json_marshal_test_suite():
- unittest.suite("json_marshal_tests", _test)
diff --git a/packages/concatjs/internal/common/module_mappings.bzl b/packages/concatjs/internal/common/module_mappings.bzl
deleted file mode 100644
index a4aedb7..0000000
--- a/packages/concatjs/internal/common/module_mappings.bzl
+++ /dev/null
@@ -1,144 +0,0 @@
-# Copyright 2017 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-# Definitions for handling path re-mapping, to support short module names.
-# See pathMapping doc: https://github.com/Microsoft/TypeScript/issues/5039
-#
-# This reads the module_root and module_name attributes from typescript rules in
-# the transitive closure, rolling these up to provide a mapping to the
-# TypeScript compiler and to editors.
-#
-"""Module mappings.
-"""
-
-def _get_deps(attrs, names):
- return [
- d
- for n in names
- if hasattr(attrs, n)
- for d in getattr(attrs, n)
- ]
-
-# Traverse 'srcs' in addition so that we can go across a genrule
-_MODULE_MAPPINGS_DEPS_NAMES = ["deps", "srcs", "_helpers"]
-
-_DEBUG = False
-
-def debug(msg, values = ()):
- if _DEBUG:
- print(msg % values)
-
-def get_module_mappings(label, attrs, srcs = [], workspace_name = None, mappings_attr = "es6_module_mappings"):
- """Returns the module_mappings from the given attrs.
-
- Collects a {module_name - module_root} hash from all transitive dependencies,
- checking for collisions. If a module has a non-empty `module_root` attribute,
- all sources underneath it are treated as if they were rooted at a folder
- `module_name`.
-
- Args:
- label: The label declaring a module mapping
- attrs: Attributes on that label
- srcs: The srcs attribute, used to validate that these are under the root
- workspace_name: name of the workspace where the user is building
- mappings_attr: name of the attribute we use to hand down transitive data
-
- Returns:
- the module_mappings from the given attrs.
- """
- mappings = dict()
- all_deps = _get_deps(attrs, names = _MODULE_MAPPINGS_DEPS_NAMES)
- for dep in all_deps:
- if not hasattr(dep, mappings_attr):
- continue
- for k, v in getattr(dep, mappings_attr).items():
- if k in mappings and mappings[k] != v:
- fail(("duplicate module mapping at %s: %s maps to both %s and %s" %
- (label, k, mappings[k], v)), "deps")
- mappings[k] = v
- if ((hasattr(attrs, "module_name") and attrs.module_name) or
- (hasattr(attrs, "module_root") and attrs.module_root)):
- mn = attrs.module_name
- if not mn:
- mn = label.name
- mr = "/".join([p for p in [
- workspace_name or label.workspace_root,
- label.package,
- ] if p])
- if hasattr(attrs, "module_root") and attrs.module_root and attrs.module_root != ".":
- mr = "%s/%s" % (mr, attrs.module_root)
- if attrs.module_root.endswith(".ts"):
- if workspace_name:
- mr = mr.replace(".d.ts", "")
-
- # Validate that sources are underneath the module root.
- # module_roots ending in .ts are a special case, they are used to
- # restrict what's exported from a build rule, e.g. only exports from a
- # specific index.d.ts file. For those, not every source must be under the
- # given module root.
-
- else:
- for s in srcs:
- short_path = s.short_path
-
- # Execroot paths for external repositories should start with external/
- # But the short_path property of file gives the relative path from our workspace
- # instead. We must correct this to compare with the module_root which is an
- # execroot path.
- if short_path.startswith("../"):
- short_path = "external/" + short_path[3:]
- if not short_path.startswith(mr):
- fail(("all sources must be under module root: %s, but found: %s" %
- (mr, short_path)))
- if mn in mappings and mappings[mn] != mr:
- fail(("duplicate module mapping at %s: %s maps to both %s and %s" %
- (label, mn, mappings[mn], mr)), "deps")
- mappings[mn] = mr
-
- debug("Mappings at %s: %s", (label, mappings))
- return mappings
-
-def _module_mappings_aspect_impl(target, ctx):
- mappings = get_module_mappings(target.label, ctx.rule.attr)
- return struct(es6_module_mappings = mappings)
-
-module_mappings_aspect = aspect(
- _module_mappings_aspect_impl,
- attr_aspects = _MODULE_MAPPINGS_DEPS_NAMES,
-)
-
-# When building a mapping for use at runtime, we need paths to be relative to
-# the runfiles directory. This requires the workspace_name to be prefixed on
-# each module root.
-def _module_mappings_runtime_aspect_impl(target, ctx):
- if target.label.workspace_root:
- # We need the workspace_name for the target being visited.
- # Starlark doesn't have this - instead they have a workspace_root
- # which looks like "external/repo_name" - so grab the second path segment.
- # TODO(alexeagle): investigate a better way to get the workspace name
- workspace_name = target.label.workspace_root.split("/")[1]
- else:
- workspace_name = ctx.workspace_name
- mappings = get_module_mappings(
- target.label,
- ctx.rule.attr,
- workspace_name = workspace_name,
- mappings_attr = "runfiles_module_mappings",
- )
- return struct(runfiles_module_mappings = mappings)
-
-module_mappings_runtime_aspect = aspect(
- _module_mappings_runtime_aspect_impl,
- attr_aspects = _MODULE_MAPPINGS_DEPS_NAMES,
-)
diff --git a/packages/concatjs/internal/common/tsconfig.bzl b/packages/concatjs/internal/common/tsconfig.bzl
deleted file mode 100644
index b01c999..0000000
--- a/packages/concatjs/internal/common/tsconfig.bzl
+++ /dev/null
@@ -1,306 +0,0 @@
-# Copyright 2017 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-"""Helpers for configuring the TypeScript compiler.
-"""
-
-load(":common/module_mappings.bzl", "get_module_mappings")
-
-_DEBUG = False
-
-def create_tsconfig(
- ctx,
- files,
- srcs,
- devmode_manifest = None,
- tsickle_externs = None,
- type_blocklisted_declarations = [],
- out_dir = None,
- disable_strict_deps = False,
- allowed_deps = depset(),
- extra_root_dirs = [],
- module_path_prefixes = None,
- module_roots = None,
- node_modules_root = None,
- type_check = True):
- """Creates an object representing the TypeScript configuration to run the compiler under Bazel.
-
- Args:
- ctx: the starlark execution context
- files: Labels of all TypeScript compiler inputs
- srcs: Immediate sources being compiled, as opposed to transitive deps.
- devmode_manifest: path to the manifest file to write for --target=es5
- tsickle_externs: path to write tsickle-generated externs.js.
- type_blocklisted_declarations: types declared in these files will never be
- mentioned in generated .d.ts.
- out_dir: directory for generated output. Default is ctx.bin_dir
- disable_strict_deps: whether to disable the strict deps check
- allowed_deps: the set of files that code in srcs may depend on (strict deps)
- extra_root_dirs: Extra root dirs to be passed to tsc_wrapped.
- module_path_prefixes: additional locations to resolve modules
- module_roots: standard locations to resolve modules
- node_modules_root: the node_modules root path
-
- Returns:
- A nested dict that corresponds to a tsconfig.json structure
- """
- if (type(files) != type([])):
- fail("expected files argument to be a list, got " + type(files))
-
- outdir_path = out_dir if out_dir != None else ctx.configuration.bin_dir.path
-
- # Callers can choose the filename for the tsconfig, but it must always live
- # in the output directory corresponding with the label where it's declared.
- tsconfig_dir = "/".join([
- p
- for p in [
- ctx.bin_dir.path,
- ctx.label.workspace_root,
- ctx.label.package,
- ] + ctx.label.name.split("/")[:-1]
- # Skip empty path segments (eg. workspace_root when in same repo)
- if p
- ])
- workspace_path = "/".join([".."] * len(tsconfig_dir.split("/")))
- if module_path_prefixes == None:
- module_path_prefixes = [
- "",
- ctx.configuration.genfiles_dir.path + "/",
- ctx.configuration.bin_dir.path + "/",
- ]
- if module_roots == None:
- base_path_mappings = ["%s/*" % p for p in [
- ".",
- ctx.configuration.genfiles_dir.path,
- ctx.configuration.bin_dir.path,
- ]]
-
- node_modules_mappings = []
-
- # "node_modules" still checked for backward compat for ng_module
- if hasattr(ctx.attr, "_typescript_typings") or hasattr(ctx.attr, "node_modules"):
- node_modules_mappings.append("/".join([p for p in [
- node_modules_root,
- "*",
- ] if p]))
-
- # TypeScript needs to look up ambient types from a 'node_modules'
- # directory, but when Bazel manages the dependencies, this directory
- # isn't in the project so TypeScript won't find it.
- # We can add it to the path mapping to make this lookup work.
- # See https://github.com/bazelbuild/rules_typescript/issues/179
- node_modules_mappings.append("/".join([p for p in [
- node_modules_root,
- "@types",
- "*",
- ] if p]))
-
- module_roots = {
- "*": node_modules_mappings,
- ctx.workspace_name + "/*": base_path_mappings,
- }
- module_mappings = get_module_mappings(ctx.label, ctx.attr, srcs = srcs)
-
- # To determine the path for auto-imports, TypeScript's language service
- # considers paths in the order they appear in tsconfig.json.
- # We want explicit module mappings ("@angular/core") to take precedence over
- # the general "*" mapping (which would create "third_party/javascript/..."),
- # so we create a new hash that contains the module_mappings and insert the
- # default lookup locations at the end.
- mapped_module_roots = {}
- for name, path in module_mappings.items():
- # Each module name maps to the immediate path, to resolve "index(.d).ts",
- # or module mappings that directly point to files (like index.d.ts).
- mapped_module_roots[name] = [
- "%s%s" % (p, path.replace(".d.ts", ""))
- for p in module_path_prefixes
- ]
- if not path.endswith(".d.ts"):
- # If not just mapping to a single .d.ts file, include a path glob that
- # maps the entire module root.
- mapped_module_roots["{}/*".format(name)] = [
- "%s%s/*" % (p, path)
- for p in module_path_prefixes
- ]
- for name, path in module_roots.items():
- mapped_module_roots[name] = path
-
- # Options for running the TypeScript compiler under Bazel.
- # See javascript/typescript/compiler/tsc_wrapped.ts:BazelOptions.
- # Unlike compiler_options, the paths here are relative to the rootDir,
- # not the location of the tsconfig.json file.
- # @unsorted-dict-items preserve historical order for golden tests
- bazel_options = {
- "workspaceName": ctx.workspace_name,
- "target": str(ctx.label),
- "package": ctx.label.package,
- "tsickleGenerateExterns": getattr(ctx.attr, "generate_externs", True),
- "tsickleExternsPath": tsickle_externs.path if tsickle_externs else "",
- "untyped": not getattr(ctx.attr, "tsickle_typed", False),
- "typeBlackListPaths": [f.path for f in type_blocklisted_declarations],
- # This is overridden by first-party javascript/typescript/tsconfig.bzl
- "ignoreWarningPaths": [],
- "es5Mode": devmode_manifest != None,
- "manifest": devmode_manifest if devmode_manifest else "",
- # Explicitly tell the compiler which sources we're interested in (emitting
- # and type checking).
- "compilationTargetSrc": [s.path for s in srcs],
- "addDtsClutzAliases": getattr(ctx.attr, "add_dts_clutz_aliases", False),
- "typeCheckDependencies": getattr(ctx.attr, "internal_testing_type_check_dependencies", False),
- "expectedDiagnostics": getattr(ctx.attr, "expected_diagnostics", []),
- "typeCheck": True,
- }
-
- if getattr(ctx.attr, "use_angular_plugin", False):
- # @unsorted-dict-items
- bazel_options["angularCompilerOptions"] = {
- # Needed for back-compat with explicit AOT bootstrap
- # which has imports from generated .ngfactory files
- "generateNgFactoryShims": True,
- # Needed for back-compat with AOT tests which import the
- # .ngsummary files
- "generateNgSummaryShims": True,
- # Bazel expects output files will always be produced
- "allowEmptyCodegenFiles": True,
- "assets": [a.path for a in getattr(ctx.files, "angular_assets", [])],
- }
-
- if disable_strict_deps:
- bazel_options["disableStrictDeps"] = disable_strict_deps
- bazel_options["allowedStrictDeps"] = []
- else:
- bazel_options["allowedStrictDeps"] = [f.path for f in allowed_deps.to_list()]
-
- if hasattr(ctx.attr, "module_name") and ctx.attr.module_name:
- bazel_options["moduleName"] = ctx.attr.module_name
- if hasattr(ctx.attr, "module_root") and ctx.attr.module_root:
- bazel_options["moduleRoot"] = ctx.attr.module_root
-
- if "TYPESCRIPT_WORKER_CACHE_SIZE_MB" in ctx.var:
- max_cache_size_mb = int(ctx.var["TYPESCRIPT_WORKER_CACHE_SIZE_MB"])
- if max_cache_size_mb < 0:
- fail("TYPESCRIPT_WORKER_CACHE_SIZE_MB set to a negative value (%d)." % max_cache_size_mb)
- bazel_options["maxCacheSizeMb"] = max_cache_size_mb
-
- has_node_runtime = getattr(ctx.attr, "runtime", "browser") == "nodejs"
- target_language_level = "es5" if devmode_manifest or has_node_runtime else "es2015"
-
- # Keep these options in sync with those in playground/playground.ts.
- # @unsorted-dict-items preserve historical order for golden tests
- compiler_options = {
- # De-sugar to this language level
- "target": target_language_level,
-
- # The "typescript.es5_sources" provider is expected to work
- # in both nodejs and in browsers, so we use umd in devmode.
- # NOTE: tsc-wrapped will always name the enclosed AMD modules
- # For production mode, we leave the module syntax alone and let the
- # bundler handle it (including dynamic import).
- # Note, in google3 we override this option with "commonjs" since Tsickle
- # will convert that to goog.module syntax.
- "module": "umd" if devmode_manifest or has_node_runtime else "esnext",
-
- # Has no effect in closure/ES2015 mode. Always true just for simplicity.
- "downlevelIteration": True,
-
- # Do not type-check the lib.*.d.ts.
- # We think this shouldn't be necessary but haven't figured out why yet
- # and builds are faster with the setting on.
- # See http://b/30709121
- "skipDefaultLibCheck": True,
- "moduleResolution": "node",
- "outDir": "/".join([workspace_path, outdir_path]),
-
- # We must set a rootDir to avoid TypeScript emit paths varying
- # due computeCommonSourceDirectory behavior.
- # TypeScript requires the rootDir be a parent of all sources in
- # files[], so it must be set to the workspace_path.
- "rootDir": workspace_path,
-
- # Path handling for resolving modules, see specification at
- # https://github.com/Microsoft/TypeScript/issues/5039
- # Paths where we attempt to load relative references.
- # Longest match wins
- #
- # tsc_wrapped also uses this property to strip leading paths
- # to produce a flattened output tree, see
- # https://github.com/Microsoft/TypeScript/issues/8245
- "rootDirs": ["/".join([workspace_path, e]) for e in extra_root_dirs] + [
- workspace_path,
- "/".join([workspace_path, ctx.configuration.genfiles_dir.path]),
- "/".join([workspace_path, ctx.configuration.bin_dir.path]),
- ],
-
- # Root for non-relative module names
- "baseUrl": workspace_path,
-
- # "short name" mappings for npm packages, such as "@angular/core"
- "paths": mapped_module_roots,
-
- # Inline const enums.
- "preserveConstEnums": False,
-
- # permit `@Decorator` syntax and allow runtime reflection on their types.
- "experimentalDecorators": True,
- "emitDecoratorMetadata": True,
-
- # Interpret JSX as React calls (until someone asks for something different)
- "jsx": "react",
-
- # Truncate excessively long errors.
- # While truncation can make some errors harder to understand, it makes
- # others easier to read. Additionally, for certain errors, TypeScript
- # can run out of memory trying to convert them into a humand readable
- # string (see https://github.com/Microsoft/TypeScript/issues/37230).
- # That's a bug, but the general default configuration of TypeScript is
- # to truncate, so following that seems safer and more in line with the
- # expected developer UX.
- "noErrorTruncation": False,
- # Do not emit files if they had errors (avoid accidentally serving
- # broken code).
- "noEmitOnError": False,
- # Create .d.ts files as part of compilation.
- "declaration": True,
-
- # We don't support this compiler option (See github #32), so
- # always emit declaration files in the same location as outDir.
- "declarationDir": "/".join([workspace_path, outdir_path]),
- "stripInternal": True,
-
- # Embed source maps and sources in .js outputs
- "inlineSourceMap": True,
- "inlineSources": True,
- # Implied by inlineSourceMap: True
- "sourceMap": False,
- }
-
- # "node_modules" still checked for backward compat for ng_module
- if hasattr(ctx.attr, "_typescript_typings") or hasattr(ctx.attr, "node_modules"):
- compiler_options["typeRoots"] = ["/".join([p for p in [
- workspace_path,
- node_modules_root,
- "@types",
- ] if p])]
-
- if _DEBUG:
- compiler_options["traceResolution"] = True
- compiler_options["diagnostics"] = True
-
- # @unsorted-dict-items preserve historical order for golden tests
- return {
- "compilerOptions": compiler_options,
- "bazelOptions": bazel_options,
- "files": [workspace_path + "/" + f.path for f in files],
- "compileOnSave": False,
- }
diff --git a/packages/concatjs/internal/ts_config.bzl b/packages/concatjs/internal/ts_config.bzl
deleted file mode 100644
index dcfd52a..0000000
--- a/packages/concatjs/internal/ts_config.bzl
+++ /dev/null
@@ -1,57 +0,0 @@
-# Copyright 2017 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-"tsconfig.json files using extends"
-
-TsConfigInfo = provider(
- doc = """Provides TypeScript configuration, in the form of a tsconfig.json file
- along with any transitively referenced tsconfig.json files chained by the
- "extends" feature""",
- fields = {
- "deps": "all tsconfig.json files needed to configure TypeScript",
- },
-)
-
-def _ts_config_impl(ctx):
- files = depset([ctx.file.src])
- transitive_deps = []
- for dep in ctx.attr.deps:
- if TsConfigInfo in dep:
- transitive_deps.extend(dep[TsConfigInfo].deps)
- return [
- DefaultInfo(files = files),
- TsConfigInfo(deps = [ctx.file.src] + ctx.files.deps + transitive_deps),
- ]
-
-ts_config = rule(
- implementation = _ts_config_impl,
- attrs = {
- "deps": attr.label_list(
- doc = """Additional tsconfig.json files referenced via extends""",
- allow_files = True,
- ),
- "src": attr.label(
- doc = """The tsconfig.json file passed to the TypeScript compiler""",
- allow_single_file = True,
- mandatory = True,
- ),
- },
- doc = """Allows a tsconfig.json file to extend another file.
-
-Normally, you just give a single `tsconfig.json` file as the tsconfig attribute
-of a `ts_library` rule. However, if your `tsconfig.json` uses the `extends`
-feature from TypeScript, then the Bazel implementation needs to know about that
-extended configuration file as well, to pass them both to the TypeScript compiler.
-""",
-)
diff --git a/packages/concatjs/internal/ts_repositories.bzl b/packages/concatjs/internal/ts_repositories.bzl
deleted file mode 100644
index a14f8a0..0000000
--- a/packages/concatjs/internal/ts_repositories.bzl
+++ /dev/null
@@ -1,64 +0,0 @@
-# Copyright 2017 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-"Install toolchain dependencies"
-
-# BEGIN-DEV-ONLY
-# Parts of this BUILD file only necessary when building within the bazelbuild/rules_typescript repo.
-# The generated `@bazel/typescript` npm package contains a trimmed BUILD file using # DEV-ONLY fences.
-load("@bazel_gazelle//:deps.bzl", "go_repository")
-
-# END-DEV-ONLY
-load("@bazel_skylib//lib:versions.bzl", "versions")
-
-def ts_setup_workspace():
- """This repository rule should be called from your WORKSPACE file.
-
- It creates some additional Bazel external repositories that are used internally
- by the TypeScript rules.
- """
-
- # 0.18.0: support for .bazelignore
- versions.check("0.18.0")
-
-# BEGIN-DEV-ONLY
-def ts_setup_dev_workspace():
- """
- Setup the toolchain needed for local development, but not needed by users.
-
- These needs to be in a separate file from ts_setup_workspace() so as not
- to leak load statements.
- """
-
- ts_setup_workspace()
-
- go_repository(
- name = "com_github_google_go_cmp",
- commit = "f144a35ed4ac538fae93fa3783175108738f71b9", # v0.5.8
- importpath = "github.com/google/go-cmp",
- )
-
- go_repository(
- name = "com_github_kylelemons_godebug",
- commit = "9ff306d4fbead574800b66369df5b6144732d58e", # v1.1.0
- importpath = "github.com/kylelemons/godebug",
- )
-
- go_repository(
- name = "com_github_mattn_go_isatty",
- commit = "504425e14f742f1f517c4586048b49b37f829c8e", # v0.0.14
- importpath = "github.com/mattn/go-isatty",
- )
-
-# END-DEV-ONLY
diff --git a/packages/concatjs/internal/tsc_wrapped/angular_plugin.ts b/packages/concatjs/internal/tsc_wrapped/angular_plugin.ts
deleted file mode 100644
index 522e72c..0000000
--- a/packages/concatjs/internal/tsc_wrapped/angular_plugin.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-// The `@angular/compiler-cli` module is optional so we only
-// access as type-only at the file top-level.
-import type {NgTscPlugin} from '@angular/compiler-cli';
-
-type CompilerCliModule = typeof import('@angular/compiler-cli');
-type CompilerInteropExports = Partial<CompilerCliModule> & {default?: CompilerCliModule};
-
-
-/**
- * Gets the constructor for instantiating the Angular `ngtsc`
- * emit plugin supported by `tsc_wrapped`.
- * @throws An error when the Angular emit plugin could not be retrieved.
- */
-export async function getAngularEmitPluginOrThrow(): Promise<typeof NgTscPlugin> {
- // Note: This is an interop allowing for the `@angular/compiler-cli` package
- // to be shipped as strict ESM, or as CommonJS. If the CLI is a CommonJS
- // package (pre v13 of Angular), then the exports are in the `default` property.
- // See: https://nodejs.org/api/esm.html#esm_import_statements.
- // Note: TypeScript downlevels the dynamic `import` to a `require` that is
- // not compatible with ESM. We create a function to workaround this issue.
- const exports = await loadEsmOrFallbackToRequire<CompilerInteropExports>(
- '@angular/compiler-cli');
- const plugin = exports.NgTscPlugin ?? exports.default?.NgTscPlugin;
-
- if (plugin === undefined) {
- throw new Error('Could not find `NgTscPlugin` export in `@angular/compiler-cli`.');
- }
-
- return plugin;
-}
-
-async function loadEsmOrFallbackToRequire<T>(moduleName: string): Promise<T> {
- try {
- return await new Function('m', `return import(m);`)(moduleName);
- } catch {
- // If the dynamic import failed, we still re-try with `require` because
- // some NodeJS versions do not even support the dynamic import expression.
- return require(moduleName);
- }
-}
\ No newline at end of file
diff --git a/packages/concatjs/internal/tsc_wrapped/cache.ts b/packages/concatjs/internal/tsc_wrapped/cache.ts
deleted file mode 100644
index 7fa5f3e..0000000
--- a/packages/concatjs/internal/tsc_wrapped/cache.ts
+++ /dev/null
@@ -1,395 +0,0 @@
-/**
- * @license
- * Copyright 2017 The Bazel Authors. All rights reserved.
- *
- * 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.
- */
-
-import * as fs from 'fs';
-import * as ts from 'typescript';
-import * as perfTrace from './perf_trace';
-
-type Debug = (...msg: Array<{}>) => void;
-
-interface CacheStats {
- reads: number;
- hits: number;
- evictions: number;
-}
-
-/**
- * Cache exposes a trivial LRU cache.
- *
- * This code uses the fact that JavaScript hash maps are linked lists - after
- * reaching the cache size limit, it deletes the oldest (first) entries. Used
- * cache entries are moved to the end of the list by deleting and re-inserting.
- */
-class Cache<T> {
- private map = new Map<string, T>();
- private stats: CacheStats = {reads: 0, hits: 0, evictions: 0};
-
- constructor(private name: string, private debug: Debug) {}
-
- set(key: string, value: T) {
- this.map.set(key, value);
- }
-
- get(key: string, updateCache = true): T|undefined {
- this.stats.reads++;
-
- const entry = this.map.get(key);
- if (updateCache) {
- if (entry) {
- this.debug(this.name, 'cache hit:', key);
- this.stats.hits++;
- // Move an entry to the end of the cache by deleting and re-inserting
- // it.
- this.map.delete(key);
- this.map.set(key, entry);
- } else {
- this.debug(this.name, 'cache miss:', key);
- }
- this.traceStats();
- }
- return entry;
- }
-
- delete(key: string) {
- this.map.delete(key);
- }
-
- evict(unevictableKeys?: {has: (key: string) => boolean}): number {
- // Drop half the cache, the least recently used entry == the first entry.
- this.debug('Evicting from the', this.name, 'cache...');
- const originalSize = this.map.size;
- let numberKeysToDrop = originalSize / 2;
- if (numberKeysToDrop === 0) {
- return 0;
- }
- // Map keys are iterated in insertion order, since we reinsert on access
- // this is indeed a LRU strategy.
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/keys
- for (const key of this.map.keys()) {
- if (numberKeysToDrop === 0) break;
- if (unevictableKeys && unevictableKeys.has(key)) continue;
- this.map.delete(key);
- numberKeysToDrop--;
- }
- const keysDropped = originalSize - this.map.size;
- this.stats.evictions += keysDropped;
- this.debug('Evicted', keysDropped, this.name, 'cache entries');
- this.traceStats();
- return keysDropped;
- }
-
- keys() {
- return this.map.keys();
- }
-
- resetStats() {
- this.stats = {hits: 0, reads: 0, evictions: 0};
- }
-
- printStats() {
- let percentage;
- if (this.stats.reads === 0) {
- percentage = 100.00; // avoid "NaN %"
- } else {
- percentage = (this.stats.hits / this.stats.reads * 100).toFixed(2);
- }
- this.debug(`${this.name} cache stats: ${percentage}% hits`, this.stats);
- }
-
- traceStats() {
- // counters are rendered as stacked bar charts, so record cache
- // hits/misses rather than the 'reads' stat tracked in stats
- // so the chart makes sense.
- perfTrace.counter(`${this.name} cache hit rate`, {
- 'hits': this.stats.hits,
- 'misses': this.stats.reads - this.stats.hits,
- });
- perfTrace.counter(`${this.name} cache evictions`, {
- 'evictions': this.stats.evictions,
- });
- perfTrace.counter(`${this.name} cache size`, {
- [`${this.name}s`]: this.map.size,
- });
- }
-}
-
-export interface SourceFileEntry {
- digest: string; // blaze's opaque digest of the file
- value: ts.SourceFile;
-}
-
-/**
- * Default memory size, beyond which we evict from the cache.
- */
-const DEFAULT_MAX_MEM_USAGE = 1024 * (1 << 20 /* 1 MB */);
-
-/**
- * FileCache is a trivial LRU cache for typescript-parsed bazel-output files.
- *
- * Cache entries include an opaque bazel-supplied digest to track staleness.
- * Expected digests must be set (using updateCache) before using the cache.
- */
-// TODO(martinprobst): Drop the <T> parameter, it's no longer used.
-export class FileCache<T = {}> {
- private fileCache = new Cache<SourceFileEntry>('file', this.debug);
- /**
- * FileCache does not know how to construct bazel's opaque digests. This
- * field caches the last (or current) compile run's digests, so that code
- * below knows what digest to assign to a newly loaded file.
- */
- private lastDigests = new Map<string, string>();
- /**
- * FileCache can enter a degenerate state, where all cache entries are pinned
- * by lastDigests, but the system is still out of memory. In that case, do not
- * attempt to free memory until lastDigests has changed.
- */
- private cannotEvict = false;
-
- /**
- * Because we cannot measuse the cache memory footprint directly, we evict
- * when the process' total memory usage goes beyond this number.
- */
- private maxMemoryUsage = DEFAULT_MAX_MEM_USAGE;
-
- constructor(protected debug: (...msg: Array<{}>) => void) {}
-
- setMaxCacheSize(maxCacheSize: number) {
- if (maxCacheSize < 0) {
- throw new Error(`FileCache max size is negative: ${maxCacheSize}`);
- }
- this.debug('Cache max size is', maxCacheSize >> 20, 'MB');
- this.maxMemoryUsage = maxCacheSize;
- this.maybeFreeMemory();
- }
-
- resetMaxCacheSize() {
- this.setMaxCacheSize(DEFAULT_MAX_MEM_USAGE);
- }
-
- /**
- * Updates the cache with the given digests.
- *
- * updateCache must be called before loading files - only files that were
- * updated (with a digest) previously can be loaded.
- */
- updateCache(digests: Map<string, string>): void {
- this.debug('updating digests:', digests);
- this.lastDigests = digests;
- this.cannotEvict = false;
- for (const [filePath, newDigest] of digests.entries()) {
- const entry = this.fileCache.get(filePath, /*updateCache=*/ false);
- if (entry && entry.digest !== newDigest) {
- this.debug(
- 'dropping file cache entry for', filePath, 'digests', entry.digest,
- newDigest);
- this.fileCache.delete(filePath);
- }
- }
- }
-
- getLastDigest(filePath: string): string {
- const digest = this.lastDigests.get(filePath);
- if (!digest) {
- const errorMsg = `missing input digest for ${filePath}. `;
- let entriesToPrint = Array.from(this.lastDigests.keys());
- if (entriesToPrint.length > 100) {
- throw new Error(
- errorMsg +
- `(only have ${entriesToPrint.slice(0, 100)} and ${
- entriesToPrint.length - 100} more)`);
- }
- throw new Error(errorMsg + `(only have ${entriesToPrint})`);
- }
- return digest;
- }
-
- getCache(filePath: string): ts.SourceFile|undefined {
- const entry = this.fileCache.get(filePath);
- if (entry) return entry.value;
- return undefined;
- }
-
- putCache(filePath: string, entry: SourceFileEntry): void {
- const dropped = this.maybeFreeMemory();
- this.fileCache.set(filePath, entry);
- this.debug('Loaded file:', filePath, 'dropped', dropped, 'files');
- }
-
- /**
- * Returns true if the given filePath was reported as an input up front and
- * has a known cache digest. FileCache can only cache known files.
- */
- isKnownInput(filePath: string): boolean {
- return this.lastDigests.has(filePath);
- }
-
- inCache(filePath: string): boolean {
- return !!this.getCache(filePath);
- }
-
- resetStats() {
- this.fileCache.resetStats();
- }
-
- printStats() {
- this.fileCache.printStats();
- }
-
- traceStats() {
- this.fileCache.traceStats();
- }
-
- /**
- * Returns whether the cache should free some memory.
- *
- * Defined as a property so it can be overridden in tests.
- */
- shouldFreeMemory: () => boolean = () => {
- return process.memoryUsage().heapUsed > this.maxMemoryUsage;
- };
-
- /**
- * Frees memory if required. Returns the number of dropped entries.
- */
- maybeFreeMemory() {
- if (!this.shouldFreeMemory() || this.cannotEvict) {
- return 0;
- }
- const dropped = this.fileCache.evict(this.lastDigests);
- if (dropped === 0) {
- // Freeing memory did not drop any cache entries, because all are pinned.
- // Stop evicting until the pinned list changes again. This prevents
- // degenerating into an O(n^2) situation where each file load iterates
- // through the list of all files, trying to evict cache keys in vain
- // because all are pinned.
- this.cannotEvict = true;
- }
- return dropped;
- }
-
- getFileCacheKeysForTest() {
- return Array.from(this.fileCache.keys());
- }
-}
-
-/**
- * ProgramAndFileCache is a trivial LRU cache for typescript-parsed programs and
- * bazel-output files.
- *
- * Programs are evicted before source files because they have less reuse across
- * compilations.
- */
-export class ProgramAndFileCache extends FileCache {
- private programCache = new Cache<ts.Program>('program', this.debug);
-
- getProgram(target: string): ts.Program|undefined {
- return this.programCache.get(target);
- }
-
- putProgram(target: string, program: ts.Program): void {
- const dropped = this.maybeFreeMemory();
- this.programCache.set(target, program);
- this.debug('Loaded program:', target, 'dropped', dropped, 'entries');
- }
-
- resetStats() {
- super.resetStats();
- this.programCache.resetStats();
- }
-
- printStats() {
- super.printStats();
- this.programCache.printStats();
- }
-
- traceStats() {
- super.traceStats();
- this.programCache.traceStats();
- }
-
- maybeFreeMemory() {
- if (!this.shouldFreeMemory()) return 0;
-
- const dropped = this.programCache.evict();
- if (dropped > 0) return dropped;
-
- return super.maybeFreeMemory();
- }
-
- getProgramCacheKeysForTest() {
- return Array.from(this.programCache.keys());
- }
-}
-
-export interface FileLoader {
- loadFile(fileName: string, filePath: string, langVer: ts.ScriptTarget):
- ts.SourceFile;
- fileExists(filePath: string): boolean;
-}
-
-/**
- * Load a source file from disk, or possibly return a cached version.
- */
-export class CachedFileLoader implements FileLoader {
- /** Total amount of time spent loading files, for the perf trace. */
- private totalReadTimeMs = 0;
-
- // TODO(alexeagle): remove unused param after usages updated:
- // angular:packages/bazel/src/ngc-wrapped/index.ts
- constructor(private readonly cache: FileCache, unused?: boolean) {}
-
- fileExists(filePath: string) {
- return this.cache.isKnownInput(filePath);
- }
-
- loadFile(fileName: string, filePath: string, langVer: ts.ScriptTarget):
- ts.SourceFile {
- let sourceFile = this.cache.getCache(filePath);
- if (!sourceFile) {
- const readStart = Date.now();
- const sourceText = fs.readFileSync(filePath, 'utf8');
- sourceFile = ts.createSourceFile(fileName, sourceText, langVer, true);
- const entry = {
- digest: this.cache.getLastDigest(filePath),
- value: sourceFile
- };
- const readEnd = Date.now();
- this.cache.putCache(filePath, entry);
-
- this.totalReadTimeMs += readEnd - readStart;
- perfTrace.counter('file load time', {
- 'read': this.totalReadTimeMs,
- });
- perfTrace.snapshotMemoryUsage();
- }
-
- return sourceFile;
- }
-}
-
-/** Load a source file from disk. */
-export class UncachedFileLoader implements FileLoader {
- fileExists(filePath: string): boolean {
- return ts.sys.fileExists(filePath);
- }
-
- loadFile(fileName: string, filePath: string, langVer: ts.ScriptTarget):
- ts.SourceFile {
- const sourceText = fs.readFileSync(filePath, 'utf8');
- return ts.createSourceFile(fileName, sourceText, langVer, true);
- }
-}
diff --git a/packages/concatjs/internal/tsc_wrapped/cache_test.ts b/packages/concatjs/internal/tsc_wrapped/cache_test.ts
deleted file mode 100644
index 09e0afa..0000000
--- a/packages/concatjs/internal/tsc_wrapped/cache_test.ts
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * @license
- * Copyright 2017 The Bazel Authors. All rights reserved.
- *
- * 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.
- */
-
-import 'jasmine';
-
-import * as ts from 'typescript';
-
-import {CachedFileLoader, FileCache, ProgramAndFileCache} from './cache';
-import {invalidateFileCache, writeTempFile} from './test_support';
-
-function fauxDebug(...args: [any?, ...any[]]) {
- console.error.apply(console, args);
-}
-
-describe('Cache', () => {
- let fileCache: FileCache;
- let fileLoader: CachedFileLoader;
-
- function loadFile(name: string, fn: string) {
- return fileLoader.loadFile(name, fn, ts.ScriptTarget.ES5);
- }
-
- function setCurrentFiles(...fileName: string[]) {
- // Give all files the same digest, so that the file cache allows reading
- // them, but does not evict them.
- const digests =
- new Map(fileName.map((fn): [string, string] => [fn, 'digest']));
- fileCache.updateCache(digests);
- }
-
- function expectFileCacheKeys() {
- // Strip the long /tmp paths created by writeTempFile.
- return expect(
- fileCache.getFileCacheKeysForTest().map(fn => fn.replace(/.*\./, '')));
- }
-
- describe('FileCache', () => {
- beforeEach(() => {
- fileCache = new FileCache(fauxDebug);
- fileLoader = new CachedFileLoader(fileCache);
- });
-
- it('caches files', () => {
- const fn = writeTempFile('file_cache_test', 'let x: number = 12;\n');
- invalidateFileCache(fileCache, fn);
-
- // Caches.
- const sourceFile =
- fileLoader.loadFile('fileName', fn, ts.ScriptTarget.ES5);
- let sourceFile2 =
- fileLoader.loadFile('fileName', fn, ts.ScriptTarget.ES5);
- expect(sourceFile).toBe(sourceFile2); // i.e., identical w/ ===
-
- // Invalidate the file.
- invalidateFileCache(fileCache, fn);
- sourceFile2 = fileLoader.loadFile('fileName', fn, ts.ScriptTarget.ES5);
- // New file after write/mtime change.
- expect(sourceFile).not.toBe(sourceFile2);
- });
-
- it('caches in LRU order', () => {
- let free = false;
- fileCache.shouldFreeMemory = () => free;
-
- const fn1 = writeTempFile('file_cache_test1', 'let x: number = 1;\n');
- const fn2 = writeTempFile('file_cache_test2', 'let x: number = 2;\n');
- const fn3 = writeTempFile('file_cache_test3', 'let x: number = 3;\n');
- const fn4 = writeTempFile('file_cache_test4', 'let x: number = 4;\n');
- const fn5 = writeTempFile('file_cache_test5', 'let x: number = 5;\n');
- setCurrentFiles(fn1, fn2, fn3, fn4, fn5);
-
- // Populate the cache.
- const f1 = loadFile('f1', fn1);
- const f2 = loadFile('f2', fn2);
- const f3 = loadFile('f3', fn3);
- const f4 = loadFile('f4', fn4);
-
- expectFileCacheKeys().toEqual([
- 'file_cache_test1',
- 'file_cache_test2',
- 'file_cache_test3',
- 'file_cache_test4',
- ]);
-
- // Load f1 from cache again. Now f1 is the most recently used file.
- expect(loadFile('f1', fn1)).toBe(f1, 'f1 should be cached');
- expectFileCacheKeys().toEqual([
- 'file_cache_test2',
- 'file_cache_test3',
- 'file_cache_test4',
- 'file_cache_test1',
- ]);
-
- // Now load f5 and pretend memory must be freed.
- // length / 2 == 2 files must be cleared.
- // f2 + f5 are pinned because they are part of the compilation unit.
- // f1, f3, f4 are eligible for eviction, and f1 is more recently used than
- // the others, so f1 shoud be retained, f3 + f4 dropped.
-
- setCurrentFiles(fn2, fn5);
- free = true;
- const f5 = loadFile('f5', fn5);
- expectFileCacheKeys().toEqual([
- 'file_cache_test2',
- 'file_cache_test1',
- 'file_cache_test5',
- ]);
- setCurrentFiles(fn1, fn2, fn3, fn4, fn5);
- expect(loadFile('f1', fn1))
- .toBe(f1, 'f1 should not be dropped, it was recently used');
- expect(loadFile('f2', fn2)).toBe(f2, 'f2 should be pinned');
- expect(loadFile('f3', fn3)).not.toBe(f3, 'f3 should have been dropped');
- expect(loadFile('f4', fn4)).not.toBe(f4, 'f4 should have been dropped');
- expect(loadFile('f5', fn5)).toBe(f5, 'f5 should be pinned');
- });
-
- it('degenerates to cannotEvict mode', () => {
- // Pretend to always be out of memory.
- fileCache.shouldFreeMemory = () => true;
-
- const fn1 = writeTempFile('file_cache_test1', 'let x: number = 1;\n');
- const fn2 = writeTempFile('file_cache_test2', 'let x: number = 2;\n');
- const fn3 = writeTempFile('file_cache_test3', 'let x: number = 3;\n');
- const fn4 = writeTempFile('file_cache_test4', 'let x: number = 4;\n');
- setCurrentFiles(fn1, fn2, fn3);
-
- loadFile('fn1', fn1), loadFile('fn2', fn2);
- loadFile('fn3', fn3);
-
- expect(fileCache['cannotEvict']).toBe(true, 'all files are pinned');
- expectFileCacheKeys().toEqual([
- 'file_cache_test1',
- 'file_cache_test2',
- 'file_cache_test3',
- ]);
- setCurrentFiles(fn1, fn4);
- expect(fileCache['cannotEvict']).toBe(false, 'pinned files reset');
- loadFile('fn4', fn4);
- expectFileCacheKeys().toEqual([
- 'file_cache_test1',
- 'file_cache_test4',
- ]);
- });
- });
-
- describe('ProgramAndFileCache', () => {
- let cache: ProgramAndFileCache;
-
- function loadProgram(name: string): ts.Program {
- const p = {} as ts.Program;
- cache.putProgram(name, p);
- return p;
- }
-
- function expectProgramCacheKeys() {
- return expect(cache.getProgramCacheKeysForTest());
- }
-
- beforeEach(() => {
- fileCache = new ProgramAndFileCache(fauxDebug);
- fileLoader = new CachedFileLoader(fileCache);
- cache = fileCache as ProgramAndFileCache;
- });
-
- it('caches programs', () => {
- const name = 'fauxprogram';
- const program = loadProgram(name);
-
- expect(cache.getProgram(name)).toBe(program);
- });
-
- it('caches programs in LRU order', () => {
- let free = false;
- cache.shouldFreeMemory = () => free;
-
- // Populate the cache.
- const p1 = loadProgram('p1');
- loadProgram('p2');
- loadProgram('p3');
- loadProgram('p4');
-
- expectProgramCacheKeys().toEqual([
- 'p1',
- 'p2',
- 'p3',
- 'p4',
- ]);
-
- // Load p1 from cache again. Now p1 is the most recently used program.
- expect(cache.getProgram('p1')).toBe(p1);
- expectProgramCacheKeys().toEqual([
- 'p2',
- 'p3',
- 'p4',
- 'p1',
- ]);
-
- // Now load p5 and pretend memory must be freed.
- // length / 2 == 2 files must be cleared.
-
- free = true;
- loadProgram('p5');
- expectProgramCacheKeys().toEqual([
- 'p4',
- 'p1',
- 'p5',
- ]);
- });
-
- it('evicts programs before files', () => {
- let free = false;
- cache.shouldFreeMemory = () => free;
-
- // Populate the cache.
- loadProgram('p1');
- const fn1 = writeTempFile('file_cache_test1', 'let x: number = 1;\n');
- const fn2 = writeTempFile('file_cache_test2', 'let x: number = 2;\n');
- setCurrentFiles(fn1);
- loadFile('fn1', fn1);
- expectProgramCacheKeys().toEqual(['p1']);
- expectFileCacheKeys().toEqual(['file_cache_test1']);
-
- free = true;
- setCurrentFiles(fn2);
- loadFile('fn2', fn2);
- expectProgramCacheKeys().toEqual([]);
- expectFileCacheKeys().toEqual(['file_cache_test1', 'file_cache_test2']);
- });
- });
-});
diff --git a/packages/concatjs/internal/tsc_wrapped/compiler_host.ts b/packages/concatjs/internal/tsc_wrapped/compiler_host.ts
deleted file mode 100644
index 0336ec4..0000000
--- a/packages/concatjs/internal/tsc_wrapped/compiler_host.ts
+++ /dev/null
@@ -1,653 +0,0 @@
-import * as fs from 'fs';
-import * as path from 'path';
-import * as tsickle from 'tsickle';
-import * as ts from 'typescript';
-
-import {FileLoader} from './cache';
-import * as perfTrace from './perf_trace';
-import {BazelOptions} from './tsconfig';
-import {DEBUG, debug} from './worker';
-
-export type ModuleResolver =
- (moduleName: string, containingFile: string,
- compilerOptions: ts.CompilerOptions, host: ts.ModuleResolutionHost) =>
- ts.ResolvedModuleWithFailedLookupLocations;
-
-/**
- * Narrows down the type of some properties from non-optional to required, so
- * that we do not need to check presence before each access.
- */
-export interface BazelTsOptions extends ts.CompilerOptions {
- rootDirs: string[];
- rootDir: string;
- outDir: string;
- typeRoots: string[];
-}
-
-declare interface packageJson {
- typings?: string;
-}
-
-export function narrowTsOptions(options: ts.CompilerOptions): BazelTsOptions {
- if (!options.rootDirs) {
- throw new Error(`compilerOptions.rootDirs should be set by tsconfig.bzl`);
- }
- if (!options.rootDir) {
- throw new Error(`compilerOptions.rootDir should be set by tsconfig.bzl`);
- }
- if (!options.outDir) {
- throw new Error(`compilerOptions.outDir should be set by tsconfig.bzl`);
- }
- return options as BazelTsOptions;
-}
-
-function validateBazelOptions(bazelOpts: BazelOptions) {
- if (!bazelOpts.isJsTranspilation) return;
-
- if (bazelOpts.compilationTargetSrc &&
- bazelOpts.compilationTargetSrc.length > 1) {
- throw new Error(
- 'In JS transpilation mode, only one file can appear in ' +
- 'bazelOptions.compilationTargetSrc.');
- }
-
- if (!bazelOpts.transpiledJsOutputFileName &&
- !bazelOpts.transpiledJsOutputDirectory) {
- throw new Error(
- 'In JS transpilation mode, either transpiledJsOutputFileName or ' +
- 'transpiledJsOutputDirectory must be specified in tsconfig.');
- }
-
- if (bazelOpts.transpiledJsOutputFileName &&
- bazelOpts.transpiledJsOutputDirectory) {
- throw new Error(
- 'In JS transpilation mode, cannot set both ' +
- 'transpiledJsOutputFileName and transpiledJsOutputDirectory.');
- }
-}
-
-const SOURCE_EXT = /((\.d)?\.tsx?|\.js)$/;
-
-const MAJOR_TS_VERSION = parseInt(ts.versionMajorMinor.split('.')[0], 10);
-
-/**
- * CompilerHost that knows how to cache parsed files to improve compile times.
- */
-export class CompilerHost implements ts.CompilerHost, tsickle.TsickleHost {
- /**
- * Lookup table to answer file stat's without looking on disk.
- */
- private knownFiles = new Set<string>();
-
- /**
- * rootDirs relative to the rootDir, eg "bazel-out/local-fastbuild/bin"
- */
- private relativeRoots: string[];
-
- getCancelationToken?: () => ts.CancellationToken;
- directoryExists?: (dir: string) => boolean;
-
- generateExtraSuppressions: boolean;
-
- googmodule: boolean;
- es5Mode: boolean;
- prelude: string;
- untyped: boolean;
- typeBlackListPaths: Set<string>;
- transformDecorators: boolean;
- transformTypesToClosure: boolean;
- addDtsClutzAliases: boolean;
- isJsTranspilation: boolean;
- provideExternalModuleDtsNamespace: boolean;
- options: BazelTsOptions;
- moduleResolutionHost: ts.ModuleResolutionHost = this;
- // TODO(evanm): delete this once tsickle is updated.
- host: ts.ModuleResolutionHost = this;
- private allowActionInputReads = true;
-
- constructor(
- public inputFiles: string[], options: ts.CompilerOptions,
- readonly bazelOpts: BazelOptions, private delegate: ts.CompilerHost,
- private fileLoader: FileLoader,
- private moduleResolver: ModuleResolver = ts.resolveModuleName) {
- this.options = narrowTsOptions(options);
- this.relativeRoots =
- this.options.rootDirs.map(r => path.relative(this.options.rootDir, r));
- inputFiles.forEach((f) => {
- this.knownFiles.add(f);
- });
-
- // getCancelationToken is an optional method on the delegate. If we
- // unconditionally implement the method, we will be forced to return null,
- // in the absense of the delegate method. That won't match the return type.
- // Instead, we optionally set a function to a field with the same name.
- if (delegate && delegate.getCancellationToken) {
- this.getCancelationToken = delegate.getCancellationToken.bind(delegate);
- }
-
- // Override directoryExists so that TypeScript can automatically
- // include global typings from node_modules/@types
- // see getAutomaticTypeDirectiveNames in
- // TypeScript:src/compiler/moduleNameResolver
- if (this.allowActionInputReads && delegate && delegate.directoryExists) {
- this.directoryExists = delegate.directoryExists.bind(delegate);
- }
-
- this.generateExtraSuppressions = true;
-
- validateBazelOptions(bazelOpts);
- this.googmodule = bazelOpts.googmodule;
- this.es5Mode = bazelOpts.es5Mode;
- this.prelude = bazelOpts.prelude;
- this.untyped = bazelOpts.untyped;
- this.typeBlackListPaths = new Set(bazelOpts.typeBlackListPaths);
- this.transformDecorators = bazelOpts.tsickle;
- this.transformTypesToClosure = bazelOpts.tsickle;
- this.addDtsClutzAliases = bazelOpts.addDtsClutzAliases;
- this.isJsTranspilation = Boolean(bazelOpts.isJsTranspilation);
- this.provideExternalModuleDtsNamespace = !bazelOpts.hasImplementation;
- }
-
- /**
- * For the given potentially absolute input file path (typically .ts), returns
- * the relative output path. For example, for
- * /path/to/root/blaze-out/k8-fastbuild/genfiles/my/file.ts, will return
- * my/file.js or my/file.mjs (depending on ES5 mode).
- */
- relativeOutputPath(fileName: string) {
- let result = this.rootDirsRelative(fileName);
- result = result.replace(/(\.d)?\.[jt]sx?$/, '');
- if (!this.bazelOpts.es5Mode) result += '.closure';
- return result + '.js';
- }
-
- /**
- * Workaround https://github.com/Microsoft/TypeScript/issues/8245
- * We use the `rootDirs` property both for module resolution,
- * and *also* to flatten the structure of the output directory
- * (as `rootDir` would do for a single root).
- * To do this, look for the pattern outDir/relativeRoots[i]/path/to/file
- * or relativeRoots[i]/path/to/file
- * and replace that with path/to/file
- */
- flattenOutDir(fileName: string): string {
- let result = fileName;
-
- // outDir/relativeRoots[i]/path/to/file -> relativeRoots[i]/path/to/file
- if (fileName.startsWith(this.options.rootDir)) {
- result = path.relative(this.options.outDir, fileName);
- }
-
- for (const dir of this.relativeRoots) {
- // relativeRoots[i]/path/to/file -> path/to/file
- const rel = path.relative(dir, result);
- if (!rel.startsWith('..')) {
- result = rel;
- // relativeRoots is sorted longest first so we can short-circuit
- // after the first match
- break;
- }
- }
- return result;
- }
-
- /** Avoid using tsickle on files that aren't in srcs[] */
- shouldSkipTsickleProcessing(fileName: string): boolean {
- return this.bazelOpts.isJsTranspilation ||
- this.bazelOpts.compilationTargetSrc.indexOf(fileName) === -1;
- }
-
- /** Whether the file is expected to be imported using a named module */
- shouldNameModule(fileName: string): boolean {
- return this.bazelOpts.compilationTargetSrc.indexOf(fileName) !== -1;
- }
-
- /** Allows suppressing warnings for specific known libraries */
- shouldIgnoreWarningsForPath(filePath: string): boolean {
- return this.bazelOpts.ignoreWarningPaths.some(
- p => !!filePath.match(new RegExp(p)));
- }
-
- /**
- * fileNameToModuleId gives the module ID for an input source file name.
- * @param fileName an input source file name, e.g.
- * /root/dir/bazel-out/host/bin/my/file.ts.
- * @return the canonical path of a file within blaze, without /genfiles/ or
- * /bin/ path parts, excluding a file extension. For example, "my/file".
- */
- fileNameToModuleId(fileName: string): string {
- return this.relativeOutputPath(
- fileName.substring(0, fileName.lastIndexOf('.')));
- }
-
- /**
- * TypeScript SourceFile's have a path with the rootDirs[i] still present, eg.
- * /build/work/bazel-out/local-fastbuild/bin/path/to/file
- * @return the path without any rootDirs, eg. path/to/file
- */
- rootDirsRelative(fileName: string): string {
- for (const root of this.options.rootDirs) {
- if (fileName.startsWith(root)) {
- // rootDirs are sorted longest-first, so short-circuit the iteration
- // see tsconfig.ts.
- return path.posix.relative(root, fileName);
- }
- }
- return fileName;
- }
-
- /**
- * Massages file names into valid goog.module names:
- * - resolves relative paths to the given context
- * - resolves non-relative paths which takes module_root into account
- * - replaces '/' with '.' in the '<workspace>' namespace
- * - replace first char if non-alpha
- * - replace subsequent non-alpha numeric chars
- */
- pathToModuleName(context: string, importPath: string): string {
- // tsickle hands us an output path, we need to map it back to a source
- // path in order to do module resolution with it.
- // outDir/relativeRoots[i]/path/to/file ->
- // rootDir/relativeRoots[i]/path/to/file
- if (context.startsWith(this.options.outDir)) {
- context = path.join(
- this.options.rootDir, path.relative(this.options.outDir, context));
- }
-
- // Try to get the resolved path name from TS compiler host which can
- // handle resolution for libraries with module_root like rxjs and @angular.
- let resolvedPath: string|null = null;
- const resolved =
- this.moduleResolver(importPath, context, this.options, this);
- if (resolved && resolved.resolvedModule &&
- resolved.resolvedModule.resolvedFileName) {
- resolvedPath = resolved.resolvedModule.resolvedFileName;
- // /build/work/bazel-out/local-fastbuild/bin/path/to/file ->
- // path/to/file
- resolvedPath = this.rootDirsRelative(resolvedPath);
- } else {
- // importPath can be an absolute file path in google3.
- // Try to trim it as a path relative to bin and genfiles, and if so,
- // handle its file extension in the block below and prepend the workspace
- // name.
- const trimmed = this.rootDirsRelative(importPath);
- if (trimmed !== importPath) {
- resolvedPath = trimmed;
- }
- }
- if (resolvedPath) {
- // Strip file extensions.
- importPath = resolvedPath.replace(SOURCE_EXT, '');
- // Make sure all module names include the workspace name.
- if (importPath.indexOf(this.bazelOpts.workspaceName) !== 0) {
- importPath = path.posix.join(this.bazelOpts.workspaceName, importPath);
- }
- }
-
- // Remove the __{LOCALE} from the module name.
- if (this.bazelOpts.locale) {
- const suffix = '__' + this.bazelOpts.locale.toLowerCase();
- if (importPath.toLowerCase().endsWith(suffix)) {
- importPath = importPath.substring(0, importPath.length - suffix.length);
- }
- }
-
- // Replace characters not supported by goog.module and '.' with
- // '$<Hex char code>' so that the original module name can be re-obtained
- // without any loss.
- // See goog.VALID_MODULE_RE_ in Closure's base.js for characters supported
- // by google.module.
-
- const escape = (c: string) => {
- return '$' + c.charCodeAt(0).toString(16);
- };
- const moduleName = importPath.replace(/^[0-9]|[^a-zA-Z_0-9_/]/g, escape)
- .replace(/\//g, '.');
- return moduleName;
- }
-
- /**
- * Converts file path into a valid AMD module name.
- *
- * An AMD module can have an arbitrary name, so that it is require'd by name
- * rather than by path. See http://requirejs.org/docs/whyamd.html#namedmodules
- *
- * "However, tools that combine multiple modules together for performance need
- * a way to give names to each module in the optimized file. For that, AMD
- * allows a string as the first argument to define()"
- */
- amdModuleName(sf: ts.SourceFile): string|undefined {
- if (!this.shouldNameModule(sf.fileName)) return undefined;
- // /build/work/bazel-out/local-fastbuild/bin/path/to/file.ts
- // -> path/to/file
- let fileName = this.rootDirsRelative(sf.fileName).replace(SOURCE_EXT, '');
-
- let workspace = this.bazelOpts.workspaceName;
-
- // Workaround https://github.com/bazelbuild/bazel/issues/1262
- //
- // When the file comes from an external bazel repository,
- // and TypeScript resolves runfiles symlinks, then the path will look like
- // output_base/execroot/local_repo/external/another_repo/foo/bar
- // We want to name such a module "another_repo/foo/bar" just as it would be
- // named by code in that repository.
- // As a workaround, check for the /external/ path segment, and fix up the
- // workspace name to be the name of the external repository.
- if (fileName.startsWith('external/')) {
- const parts = fileName.split('/');
- workspace = parts[1];
- fileName = parts.slice(2).join('/');
- }
-
- if (this.bazelOpts.moduleName) {
- const relativeFileName = path.posix.relative(this.bazelOpts.package, fileName);
- // check that the fileName was actually underneath the package directory
- if (!relativeFileName.startsWith('..')) {
- if (this.bazelOpts.moduleRoot) {
- const root = this.bazelOpts.moduleRoot.replace(SOURCE_EXT, '');
- if (root === relativeFileName ||
- path.posix.join(root, 'index') === relativeFileName) {
- return this.bazelOpts.moduleName;
- }
- }
- // Support the common case of commonjs convention that index is the
- // default module in a directory.
- // This makes our module naming scheme more conventional and lets users
- // refer to modules with the natural name they're used to.
- if (relativeFileName === 'index') {
- return this.bazelOpts.moduleName;
- }
- return path.posix.join(this.bazelOpts.moduleName, relativeFileName);
- }
- }
-
- if (fileName.startsWith('node_modules/')) {
- return fileName.substring('node_modules/'.length);
- }
-
- // path/to/file ->
- // myWorkspace/path/to/file
- return path.posix.join(workspace, fileName);
- }
-
- /**
- * Resolves the typings file from a package at the specified path. Helper
- * function to `resolveTypeReferenceDirectives`.
- */
- private resolveTypingFromDirectory(typePath: string, primary: boolean): ts.ResolvedTypeReferenceDirective | undefined {
- // Looks for the `typings` attribute in a package.json file
- // if it exists
- const pkgFile = path.posix.join(typePath, 'package.json');
- if (this.fileExists(pkgFile)) {
- const pkg = JSON.parse(fs.readFileSync(pkgFile, 'utf-8')) as packageJson;
- let typings = pkg['typings'];
- if (typings) {
- if (typings === '.' || typings === './') {
- typings = 'index.d.ts';
- }
- const maybe = path.posix.join(typePath, typings);
- if (this.fileExists(maybe)) {
- return { primary, resolvedFileName: maybe };
- }
- }
- }
-
- // Look for an index.d.ts file in the path
- const maybe = path.posix.join(typePath, 'index.d.ts');
- if (this.fileExists(maybe)) {
- return { primary, resolvedFileName: maybe };
- }
-
- return undefined;
- }
-
- /**
- * Override the default typescript resolveTypeReferenceDirectives function.
- * Resolves /// <reference types="x" /> directives under bazel. The default
- * typescript secondary search behavior needs to be overridden to support
- * looking under `bazelOpts.nodeModulesPrefix`
- */
- resolveTypeReferenceDirectives(names: string[] | ts.FileReference[]): (ts.ResolvedTypeReferenceDirective|undefined)[] {
- if (!this.allowActionInputReads) return [];
- const result: (ts.ResolvedTypeReferenceDirective|undefined)[] = [];
- names.forEach(name => {
- const fileName = typeof name === 'string' ? name : name.fileName;
- let resolved: ts.ResolvedTypeReferenceDirective | undefined;
-
- // primary search
- if (this.options.typeRoots) {
- this.options.typeRoots.forEach(typeRoot => {
- if (!resolved) {
- resolved = this.resolveTypingFromDirectory(path.posix.join(typeRoot, fileName), true);
- }
- });
- }
-
- // secondary search
- if (!resolved) {
- resolved = this.resolveTypingFromDirectory(path.posix.join(this.bazelOpts.nodeModulesPrefix, fileName), false);
- }
-
- // Types not resolved should be silently ignored. Leave it to Typescript
- // to either error out with "TS2688: Cannot find type definition file for
- // 'foo'" or for the build to fail due to a missing type that is used.
- if (!resolved && DEBUG) {
- debug(`Failed to resolve type reference directive '${fileName}'`);
- }
- // In typescript 2.x the return type for this function
- // is `(ts.ResolvedTypeReferenceDirective | undefined)[]` thus we actually
- // do allow returning `undefined` in the array but the function is typed
- // `(ts.ResolvedTypeReferenceDirective)[]` to compile with both typescript
- // 2.x and 3.0/3.1 without error. Typescript 3.0/3.1 do handle the `undefined`
- // values in the array correctly despite the return signature.
- // It looks like the return type change was a mistake because
- // it was changed back to include `| undefined` recently:
- // https://github.com/Microsoft/TypeScript/pull/28059.
- // As of version 5, it appears that the `undefined` values are expected
- // to be in the results, or the compiler will throw an error.
- if (resolved || MAJOR_TS_VERSION >= 5) {
- result.push(resolved);
- }
- });
- return result;
- }
-
- /** Loads a source file from disk (or the cache). */
- getSourceFile(
- fileName: string, languageVersion: ts.ScriptTarget,
- onError?: (message: string) => void) {
- return perfTrace.wrap(`getSourceFile ${fileName}`, () => {
- const sf = this.fileLoader.loadFile(fileName, fileName, languageVersion) as
- ts.SourceFile&{_hasGeneratedAmdModuleName?: boolean};
-
- if (!/\.d\.tsx?$/.test(fileName) &&
- (this.options.module === ts.ModuleKind.AMD ||
- this.options.module === ts.ModuleKind.UMD)) {
- const moduleName = this.amdModuleName(sf);
- if (sf.moduleName === moduleName || !moduleName) return sf;
- if (sf.moduleName) {
- throw new Error(
- `ERROR: ${sf.fileName} ` +
- `contains a module name declaration ${sf.moduleName} ` +
- `which would be overwritten with ${moduleName} ` +
- `by Bazel's TypeScript compiler.`);
- }
- // Setting the moduleName is equivalent to the original source having the triple
- // slash `///<amd-module name="some/name"/>` directive. Also note that we tag
- // source files for which we assigned a generated module name. This is necessary
- // so that we can reset the module name when the same source file is loaded from
- // a cache, but with a different module format where the auto-generated module
- // names are not desirable. The module name should not leak from previous
- // compilations through a potential source file cache.
- sf._hasGeneratedAmdModuleName = true;
- sf.moduleName = moduleName;
- return sf;
- }
-
- // If the loaded source file has a generated amd module name applied from
- // previous compilations (in worker mode), reset the file module name
- // as neither the UMD or AMD module format is used (for which we generate
- // the AMD module names automatically).
- if (sf._hasGeneratedAmdModuleName) {
- sf.moduleName = undefined;
- }
-
- return sf;
- });
- }
-
- writeFile(
- fileName: string, content: string, writeByteOrderMark: boolean,
- onError: ((message: string) => void)|undefined,
- sourceFiles: ReadonlyArray<ts.SourceFile>|undefined): void {
- perfTrace.wrap(
- `writeFile ${fileName}`,
- () => this.writeFileImpl(
- fileName, content, writeByteOrderMark, onError, sourceFiles));
- }
-
- writeFileImpl(
- fileName: string, content: string, writeByteOrderMark: boolean,
- onError: ((message: string) => void)|undefined,
- sourceFiles: ReadonlyArray<ts.SourceFile>|undefined): void {
- // Workaround https://github.com/Microsoft/TypeScript/issues/18648
- // This bug is fixed in TS 2.9
- const version = ts.versionMajorMinor;
- const [major, minor] = version.split('.').map(s => Number(s));
- const workaroundNeeded = major <= 2 && minor <= 8;
- if (workaroundNeeded &&
- (this.options.module === ts.ModuleKind.AMD ||
- this.options.module === ts.ModuleKind.UMD) &&
- fileName.endsWith('.d.ts') && sourceFiles && sourceFiles.length > 0 &&
- sourceFiles[0].moduleName) {
- content =
- `/// <amd-module name="${sourceFiles[0].moduleName}" />\n${content}`;
- }
- fileName = this.flattenOutDir(fileName);
-
- if (this.bazelOpts.isJsTranspilation) {
- if (this.bazelOpts.transpiledJsOutputFileName) {
- fileName = this.bazelOpts.transpiledJsOutputFileName!;
- } else {
- // Strip the input directory path off of fileName to get the logical
- // path within the input directory.
- fileName =
- path.relative(this.bazelOpts.transpiledJsInputDirectory!, fileName);
- // Then prepend the output directory name.
- fileName =
- path.join(this.bazelOpts.transpiledJsOutputDirectory!, fileName);
- }
- } else if (!this.bazelOpts.es5Mode) {
- // Write ES6 transpiled files to *.mjs.
- if (this.bazelOpts.locale) {
- // i18n paths are required to end with __locale.js so we put
- // the .closure segment before the __locale
- fileName = fileName.replace(/(__[^\.]+)?\.js$/, '.closure$1.js');
- } else {
- fileName = fileName.replace(/\.js$/, '.mjs');
- }
- }
-
- // Prepend the output directory.
- fileName = path.join(this.options.outDir, fileName);
-
- // Our file cache is based on mtime - so avoid writing files if they
- // did not change.
- if (!fs.existsSync(fileName) ||
- fs.readFileSync(fileName, 'utf-8') !== content) {
- this.delegate.writeFile(
- fileName, content, writeByteOrderMark, onError, sourceFiles);
- }
- }
-
- /**
- * Performance optimization: don't try to stat files we weren't explicitly
- * given as inputs.
- * This also allows us to disable Bazel sandboxing, without accidentally
- * reading .ts inputs when .d.ts inputs are intended.
- * Note that in worker mode, the file cache will also guard against arbitrary
- * file reads.
- */
- fileExists(filePath: string): boolean {
- // Under Bazel, users do not declare deps[] on their node_modules.
- // This means that we do not list all the needed .d.ts files in the files[]
- // section of tsconfig.json, and that is what populates the knownFiles set.
- // In addition, the node module resolver may need to read package.json files
- // and these are not permitted in the files[] section.
- // So we permit reading node_modules/* from action inputs, even though this
- // can include data[] dependencies and is broader than we would like.
- // This should only be enabled under Bazel, not Blaze.
- if (this.allowActionInputReads && filePath.indexOf('/node_modules/') >= 0) {
- const result = this.fileLoader.fileExists(filePath);
- if (DEBUG && !result && this.delegate.fileExists(filePath)) {
- debug("Path exists, but is not registered in the cache", filePath);
- Object.keys((this.fileLoader as any).cache.lastDigests).forEach(k => {
- if (k.endsWith(path.basename(filePath))) {
- debug(" Maybe you meant to load from", k);
- }
- });
- }
- return result;
- }
- return this.knownFiles.has(filePath);
- }
-
- getDefaultLibLocation(): string {
- // Since we override getDefaultLibFileName below, we must also provide the
- // directory containing the file.
- // Otherwise TypeScript looks in C:\lib.xxx.d.ts for the default lib.
- return path.dirname(
- this.getDefaultLibFileName({target: ts.ScriptTarget.ES5}));
- }
-
- getDefaultLibFileName(options: ts.CompilerOptions): string {
- if (this.bazelOpts.nodeModulesPrefix) {
- return path.join(
- this.bazelOpts.nodeModulesPrefix, 'typescript/lib',
- ts.getDefaultLibFileName({target: ts.ScriptTarget.ES5}));
- }
- return this.delegate.getDefaultLibFileName(options);
- }
-
- realpath(s: string): string {
- // tsc-wrapped relies on string matching of file paths for things like the
- // file cache and for strict deps checking.
- // TypeScript will try to resolve symlinks during module resolution which
- // makes our checks fail: the path we resolved as an input isn't the same
- // one the module resolver will look for.
- // See https://github.com/Microsoft/TypeScript/pull/12020
- // So we simply turn off symlink resolution.
- return s;
- }
-
- // Delegate everything else to the original compiler host.
-
- getCanonicalFileName(path: string) {
- return this.delegate.getCanonicalFileName(path);
- }
-
- getCurrentDirectory(): string {
- return this.delegate.getCurrentDirectory();
- }
-
- useCaseSensitiveFileNames(): boolean {
- return this.delegate.useCaseSensitiveFileNames();
- }
-
- getNewLine(): string {
- return this.delegate.getNewLine();
- }
-
- getDirectories(path: string) {
- return this.delegate.getDirectories ? this.delegate.getDirectories(path) :
- [];
- }
-
- readFile(fileName: string): string|undefined {
- return this.delegate.readFile(fileName);
- }
-
- trace(s: string): void {
- console.error(s);
- }
-}
diff --git a/packages/concatjs/internal/tsc_wrapped/compiler_host_test.ts b/packages/concatjs/internal/tsc_wrapped/compiler_host_test.ts
deleted file mode 100644
index 93bc096..0000000
--- a/packages/concatjs/internal/tsc_wrapped/compiler_host_test.ts
+++ /dev/null
@@ -1,115 +0,0 @@
-import 'jasmine';
-
-import * as ts from 'typescript';
-
-import {CompilerHost} from './compiler_host';
-import {BazelOptions} from './tsconfig';
-import { FileLoader } from './cache';
-
-describe('compiler host', () => {
- describe('computes the amd module name of a .ts source file', () => {
- const options: ts.CompilerOptions = {
- rootDirs: [],
- rootDir: 'base',
- outDir: 'out',
- };
- const bazelOptions: BazelOptions = {
- package: 'path/to/package',
- compilationTargetSrc: [
- 'path/to/package/index.ts',
- 'path/to/package/root_dir/index.ts',
- 'test.ts',
- ],
- workspaceName: 'my_wksp',
- } as any;
-
- const defaultHost =
- new CompilerHost([], options, bazelOptions, null as any, null as any);
- // A module is a file with at least an import or export statement.
- function createTsModule(filename: string) {
- return ts.createSourceFile(filename, 'export {}', ts.ScriptTarget.ES2015);
- }
-
- it('should name a module after the workspace and filename', () => {
- expect(defaultHost.amdModuleName(createTsModule('test.ts')))
- .toBe('my_wksp/test');
- });
-
- it('should not provide a name for files that are not in the compilation unit',
- () => {
- expect(
- defaultHost.amdModuleName(createTsModule('some_other_file.d.ts')))
- .toBeUndefined();
- });
-
- it('should name the index file with a short name', () => {
- const host = new CompilerHost(
- [], options, {...bazelOptions, moduleName: 'my_lib'}, null as any,
- null as any);
- expect(host.amdModuleName(createTsModule('path/to/package/index.ts')))
- .toBe('my_lib');
- });
- it('should name an index file under a module_root with a short name',
- () => {
- const host = new CompilerHost(
- [], options,
- {...bazelOptions, moduleName: 'my_lib', moduleRoot: 'root_dir'},
- null as any, null as any);
- expect(host.amdModuleName(
- createTsModule('path/to/package/root_dir/index.ts')))
- .toBe('my_lib');
- });
-
- describe('#pathToModuleName', () => {
- it('should escape non-identifier characters', () => {
- expect(defaultHost.pathToModuleName('context', '$-!@'))
- .toBe('$24$2d$21$40');
- });
-
- it('should escape leading numbers', () => {
- expect(defaultHost.pathToModuleName('context', '1234')).toBe('$31234');
- });
-
- it('should transform slashes to dots', () => {
- expect(defaultHost.pathToModuleName('context', 'a/b')).toBe('a.b');
- });
-
- it('should not escape valid identifers', () => {
- expect(defaultHost.pathToModuleName('context', 'a1/b2')).toBe('a1.b2');
- });
- });
- });
-
- describe('#getSourceFile', () => {
-
- it('should not leak generated AMD module name between compilations with cache', () => {
- const compilerOpts: ts.CompilerOptions = {
- rootDirs: ['.'],
- rootDir: '.',
- outDir: './dist',
- module: ts.ModuleKind.AMD,
- };
- const bazelOptions = {
- workspaceName: 'my_wksp',
- package: 'src/test',
- compilationTargetSrc: ["test.ts"]
- };
- const originalFile = ts.createSourceFile('test.ts', 'export const X = 1;',
- ts.ScriptTarget.ES2015, true);
- const fileLoader: FileLoader = {
- fileExists: () => true,
- loadFile: () => originalFile,
- };
- const tsHost = ts.createCompilerHost(compilerOpts, true);
- const umdBuildHost = new CompilerHost([], compilerOpts,
- bazelOptions as any, tsHost, fileLoader);
- const es2015BuildHost = new CompilerHost([], {...compilerOpts, module: ts.ModuleKind.ES2015},
- bazelOptions as any, tsHost, fileLoader);
-
- expect(umdBuildHost.getSourceFile('test.ts', ts.ScriptTarget.ES2015).moduleName)
- .toBe('my_wksp/test');
- expect(es2015BuildHost.getSourceFile('test.ts', ts.ScriptTarget.ES2015).moduleName)
- .toBe(undefined, 'Expected source file to not have module name from previous host.');
- });
- });
-});
diff --git a/packages/concatjs/internal/tsc_wrapped/diagnostics.ts b/packages/concatjs/internal/tsc_wrapped/diagnostics.ts
deleted file mode 100644
index 53f2928..0000000
--- a/packages/concatjs/internal/tsc_wrapped/diagnostics.ts
+++ /dev/null
@@ -1,167 +0,0 @@
-/**
- * @fileoverview extensions to TypeScript functionality around error handling
- * (ts.Diagnostics).
- */
-
-import * as ts from 'typescript';
-
-import {BazelOptions} from './tsconfig';
-
-/**
- * If the current compilation was a compilation test expecting certain
- * diagnostics, filter out the expected diagnostics, and add new diagnostics
- * (aka errors) for non-matched diagnostics.
- */
-export function filterExpected(
- bazelOpts: BazelOptions, diagnostics: ts.Diagnostic[],
- formatFn = uglyFormat): ts.Diagnostic[] {
- if (!bazelOpts.expectedDiagnostics.length) return diagnostics;
-
- // The regex contains two parts:
- // 1. Optional position: '\(5,1\)'
- // 2. Required TS error: 'TS2000: message text.'
- // Need triple escapes because the expected diagnostics that we're matching
- // here are regexes, too.
- const ERROR_RE = /^(?:\\\((\d*),(\d*)\\\).*)?TS(-?\d+):(.*)/;
- const incorrectErrors =
- bazelOpts.expectedDiagnostics.filter(e => !e.match(ERROR_RE));
- if (incorrectErrors.length) {
- const msg = `Expected errors must match regex ${ERROR_RE}\n\t` +
- `expected errors are "${incorrectErrors.join(', ')}"`;
- return [{
- file: undefined!,
- start: 0,
- length: 0,
- messageText: msg,
- category: ts.DiagnosticCategory.Error,
- code: 0,
- }];
- }
-
- // ExpectedDiagnostics represents the "expected_diagnostics" users provide in
- // the BUILD file. It is used for easier comparsion with the actual
- // diagnostics.
- interface ExpectedDiagnostics {
- line: number;
- column: number;
- expected: string;
- code: number;
- regexp: RegExp;
- matched: boolean;
- }
-
- const expectedDiags: ExpectedDiagnostics[] =
- bazelOpts.expectedDiagnostics.map(expected => {
- const m = expected.match(/^(?:\\\((\d*),(\d*)\\\).*)?TS(-?\d+):(.*)$/);
- if (!m) {
- throw new Error(
- 'Incorrect expected error, did you forget character escapes in ' +
- expected);
- }
- const [, lineStr, columnStr, codeStr, regexp] = m;
- const [line, column, code] = [lineStr, columnStr, codeStr].map(str => {
- const i = Number(str);
- if (Number.isNaN(i)) {
- return 0;
- }
- return i;
- });
- return {
- line,
- column,
- expected,
- code,
- regexp: new RegExp(regexp),
- matched: false,
- };
- });
-
- const unmatchedDiags = diagnostics.filter(diag => {
- let line = -1;
- let character = -1;
- if (diag.file !== undefined && diag.start !== undefined) {
- ({line, character} =
- ts.getLineAndCharacterOfPosition(diag.file, diag.start));
- }
- let matched = false;
- const msg = formatFn(bazelOpts.target, [diag]);
- // checkDiagMatchesExpected checks if the expected diagnostics matches the
- // actual diagnostics.
- const checkDiagMatchesExpected =
- (expDiag: ExpectedDiagnostics, diag: ts.Diagnostic) => {
- if (expDiag.code !== diag.code || msg.search(expDiag.regexp) === -1) {
- return false;
- }
- // line and column are optional fields, only check them if they
- // are explicitly specified.
- // line and character are zero based.
- if (expDiag.line !== 0 && expDiag.line !== line + 1) {
- return false;
- }
- if (expDiag.column !== 0 && expDiag.column !== character + 1) {
- return false;
- }
- return true;
- };
-
- for (const expDiag of expectedDiags) {
- if (checkDiagMatchesExpected(expDiag, diag)) {
- expDiag.matched = true;
- matched = true;
- // continue, one diagnostic may match multiple expected errors.
- }
- }
- return !matched;
- });
-
- const unmatchedErrors = expectedDiags.filter(err => !err.matched).map(err => {
- const file = ts.createSourceFile(
- bazelOpts.target, '/* fake source as marker */',
- ts.ScriptTarget.Latest);
- const messageText =
- `Expected a compilation error matching ${JSON.stringify(err.expected)}`;
- return {
- file,
- start: 0,
- length: 0,
- messageText,
- category: ts.DiagnosticCategory.Error,
- code: err.code,
- };
- });
-
- return unmatchedDiags.concat(unmatchedErrors);
-}
-
-/**
- * Formats the given diagnostics, without pretty printing. Without colors, it's
- * better for matching against programmatically.
- * @param target The bazel target, e.g. //my/package:target
- */
-export function uglyFormat(
- target: string, diagnostics: ReadonlyArray<ts.Diagnostic>): string {
- const diagnosticsHost: ts.FormatDiagnosticsHost = {
- getCurrentDirectory: () => ts.sys.getCurrentDirectory(),
- getNewLine: () => ts.sys.newLine,
- // Print filenames including their relativeRoot, so they can be located on
- // disk
- getCanonicalFileName: (f: string) => f
- };
- return ts.formatDiagnostics(diagnostics, diagnosticsHost);
-}
-
-/**
- * Pretty formats the given diagnostics (matching the --pretty tsc flag).
- * @param target The bazel target, e.g. //my/package:target
- */
-export function format(
- target: string, diagnostics: ReadonlyArray<ts.Diagnostic>): string {
- const diagnosticsHost: ts.FormatDiagnosticsHost = {
- getCurrentDirectory: () => ts.sys.getCurrentDirectory(),
- getNewLine: () => ts.sys.newLine,
- // Print filenames including their relativeRoot, so they can be located on
- // disk
- getCanonicalFileName: (f: string) => f
- };
- return ts.formatDiagnosticsWithColorAndContext(diagnostics, diagnosticsHost);
-}
diff --git a/packages/concatjs/internal/tsc_wrapped/diagnostics_test.ts b/packages/concatjs/internal/tsc_wrapped/diagnostics_test.ts
deleted file mode 100644
index 8acf212..0000000
--- a/packages/concatjs/internal/tsc_wrapped/diagnostics_test.ts
+++ /dev/null
@@ -1,67 +0,0 @@
-import 'jasmine';
-import * as ts from 'typescript';
-
-import * as diagnostics from './diagnostics';
-import {BazelOptions} from './tsconfig';
-
-describe('diagnostics', () => {
- describe('expected diagnostics', () => {
- const file = ts.createSourceFile(
- 'test.ts', '/* used for testing */', ts.ScriptTarget.Latest);
- function diag(code: number, messageText: string) {
- const category = ts.DiagnosticCategory.Error;
- return {file, code, messageText, start: 0, length: 0, category};
- }
- function filter(expectedDiagnostics: string[], diags: ts.Diagnostic[]) {
- const opts = {
- target: '//javascript/typescript/fake:target',
- expectedDiagnostics
- } as BazelOptions;
- return diagnostics.filterExpected(opts, diags)
- .map(d => `TS${d.code}:${d.messageText}`);
- }
-
- it('filters expected diagnostics', () => {
- expect(filter(['TS1234:very.*borked'], [
- diag(1234, 'the target is very badly borked'),
- diag(1234, 'the target is very sadly borked'),
- ])).toEqual([]);
- });
-
- it('returns unmatched expected diagnostics', () => {
- expect(filter(
- ['TS1234:very.*borked', 'TS1234:not matching', 'TS1235:very'],
- [diag(1234, 'the target is very badly borked')]))
- .toEqual([
- 'TS1234:Expected a compilation error matching "TS1234:not matching"',
- 'TS1235:Expected a compilation error matching "TS1235:very"',
- ]);
- });
-
- it('returns unmatched diagnostics', () => {
- expect(filter(
- ['TS1234:very.*borked'],
- [
- diag(1234, 'the target is very badly borked'),
- diag(5678, 'the target is very badly borked'),
- diag(1234, 'text not matching'),
- ]))
- .toEqual([
- 'TS5678:the target is very badly borked',
- 'TS1234:text not matching',
- ]);
- });
-
- it('throws when a charater is not escaped', () => {
- expect(() => filter(['TS1234:unescaped \n newline'], []))
- .toThrowError(
- 'Incorrect expected error, did you forget character escapes in ' +
- 'TS1234:unescaped \n newline');
- });
-
- it('handle negative diagnostic codes', () => {
- expect(filter(['TS-999:custom error'], [diag(-999, 'custom error')]))
- .toEqual([]);
- });
- });
-});
diff --git a/packages/concatjs/internal/tsc_wrapped/index.ts b/packages/concatjs/internal/tsc_wrapped/index.ts
deleted file mode 100644
index 725c2a9..0000000
--- a/packages/concatjs/internal/tsc_wrapped/index.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-export * from './tsconfig';
-export * from './cache';
-export * from './compiler_host';
-export * from './diagnostics';
-export * from './worker';
-export * from './manifest';
-export * from './plugin_api';
diff --git a/packages/concatjs/internal/tsc_wrapped/manifest.ts b/packages/concatjs/internal/tsc_wrapped/manifest.ts
deleted file mode 100644
index 3642dc7..0000000
--- a/packages/concatjs/internal/tsc_wrapped/manifest.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-/**
- * @fileoverview utilities to construct a static graph representation of the
- * import graph discovered in typescript inputs.
- */
-
-import * as tsickle from 'tsickle';
-
-/**
- * Recursively walk the import graph provided by tsickle, populating entries
- * in the result map such that if foo imports bar, foo will appear before bar
- * in the map.
- */
-function topologicalSort(
- result: tsickle.FileMap<boolean>, current: string,
- modulesManifest: tsickle.ModulesManifest,
- visiting: tsickle.FileMap<boolean>) {
- const referencedModules = modulesManifest.getReferencedModules(current);
- if (!referencedModules) return; // not in the local set of sources.
- for (const referencedModule of referencedModules) {
- const referencedFileName =
- modulesManifest.getFileNameFromModule(referencedModule);
- if (!referencedFileName) continue; // Ambient modules.
- if (!result[referencedFileName]) {
- if (visiting[referencedFileName]) {
- const path = [current, ...Object.keys(visiting)].join(' ->\n');
- throw new Error(`\n\nCyclical dependency between files:\n${path}\n`);
- }
- visiting[referencedFileName] = true;
- topologicalSort(result, referencedFileName, modulesManifest, visiting);
- delete visiting[referencedFileName];
- }
- }
- result[current] = true;
-}
-
-/**
- * Create the contents of the .es5.MF file which propagates partial ordering of
- * the import graph to later actions.
- * Each line in the resulting text corresponds with a workspace-relative file
- * path, and the lines are ordered to match the expected load order in a
- * browser.
- */
-export function constructManifest(
- modulesManifest: tsickle.ModulesManifest,
- host: {relativeOutputPath: (f: string) => string}): string {
- const result: tsickle.FileMap<boolean> = {};
- for (const file of modulesManifest.fileNames) {
- topologicalSort(result, file, modulesManifest, {});
- }
-
- // NB: The object literal maintains insertion order.
- return Object.keys(result).map(fn => host.relativeOutputPath(fn)).join('\n') +
- '\n';
-}
diff --git a/packages/concatjs/internal/tsc_wrapped/package.json b/packages/concatjs/internal/tsc_wrapped/package.json
deleted file mode 100644
index 497cfe6..0000000
--- a/packages/concatjs/internal/tsc_wrapped/package.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "description": "legacy build-time dependencies to compile and run tsc_wrapped",
- "devDependencies": {
- "@types/jasmine": "2.8.2",
- "@types/node": "10.12.20",
- "@types/tmp": "0.0.33",
- "protobufjs": "5.0.3",
- "tmp": "0.0.33",
- "tsickle": "0.28.0",
- "tsutils": "3.21.0",
- "typescript": "2.7.2"
- }
-}
diff --git a/packages/concatjs/internal/tsc_wrapped/perf_trace.ts b/packages/concatjs/internal/tsc_wrapped/perf_trace.ts
deleted file mode 100644
index c1f44e1..0000000
--- a/packages/concatjs/internal/tsc_wrapped/perf_trace.ts
+++ /dev/null
@@ -1,96 +0,0 @@
-/**
- * @license
- * Copyright 2017 The Bazel Authors. All rights reserved.
- *
- * 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.
- */
-
-/**
- * perf_trace records traces in the Chrome Trace format (which is actually used
- * for more than just Chrome). See:
- * https://github.com/catapult-project/catapult/blob/master/tracing/README.md
- */
-
-import * as fs from 'fs';
-
-type Microseconds = number;
-
-/** @return a high-res timestamp of the current time. */
-function now(): Microseconds {
- const [sec, nsec] = process.hrtime();
- return (sec * 1e6) + (nsec / 1e3);
-}
-
-/**
- * The type of entries in the Chrome Trace format:
- * https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/edit
- * Field names are chosen to match the JSON format.
- */
-declare interface Event {
- name: string;
- ph: 'B'|'E'|'X'|'C';
- pid: number; // Required field in the trace viewer, but we don't use it.
- ts: Microseconds;
- dur?: Microseconds;
- args?: any;
-}
-
-const events: Event[] = [];
-
-/** wrap wraps enter()/leave() calls around a block of code. */
-export function wrap<T>(name: string, f: () => T): T {
- const start = now();
- try {
- return f();
- } finally {
- const end = now();
- events.push({name, ph: 'X', pid: 1, ts: start, dur: (end - start)});
- }
-}
-
-/**
- * Records the execution of the given async function by invoking it. Execution
- * is recorded until the async function completes.
- */
-export async function wrapAsync<T>(name: string, f: () => Promise<T>): Promise<T> {
- const start = now();
- try {
- return await f();
- } finally {
- const end = now();
- events.push({name, ph: 'X', pid: 1, ts: start, dur: (end - start)});
- }
-}
-
-/**
- * counter records a snapshot of counts. The counter name identifies a
- * single graph, while the counts object provides data for each count
- * of a line on the stacked bar graph.
- */
-export function counter(name: string, counts: {[name: string]: number}) {
- events.push({name, ph: 'C', pid: 1, ts: now(), args: counts});
-}
-
-/** write writes the trace in Chrome Trace format to a given path. */
-export function write(path: string) {
- fs.writeFileSync(path, JSON.stringify(events), {encoding: 'utf8'});
-}
-
-/** Record the current heap usage to the performance trace. */
-export function snapshotMemoryUsage() {
- const snapshot = process.memoryUsage();
- // The counter displays as a stacked bar graph, so compute metrics
- // that sum to the appropriate total.
- const unused = snapshot.heapTotal - snapshot.heapUsed;
- counter('memory', {'used': snapshot.heapUsed, 'unused': unused});
-}
diff --git a/packages/concatjs/internal/tsc_wrapped/plugin_api.ts b/packages/concatjs/internal/tsc_wrapped/plugin_api.ts
deleted file mode 100644
index 5dbf497..0000000
--- a/packages/concatjs/internal/tsc_wrapped/plugin_api.ts
+++ /dev/null
@@ -1,117 +0,0 @@
-/**
- * @license
- * Copyright 2017 The Bazel Authors. All rights reserved.
- *
- * 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.
- */
-
-/**
- * @fileoverview
- * Provides APIs for extending TypeScript command-line compiler.
- * It's roughly analogous to how the Language Service allows plugins.
- */
-
-import * as ts from 'typescript';
-
-export interface PluginCompilerHost extends ts.CompilerHost {
- /**
- * Absolute file paths which should be included in the initial ts.Program.
- * In vanilla tsc, these are the ts.ParsedCommandLine#fileNames
- */
- inputFiles: ReadonlyArray<string>;
-}
-
-/**
- * This API is simpler than LanguageService plugins.
- * It's used for plugins that only target the command-line and never run in an
- * editor context.
- *
- * One instance of the TscPlugin will be created for each execution of the compiler, so it is
- * safe for these plugins to hold state that's local to one execution.
- *
- * The methods on the plugin will be called in the order shown below:
- * - wrapHost to intercept CompilerHost methods and contribute inputFiles to the program
- * - setupCompilation to capture the ts.Program
- * - createTransformers once it's time to emit
- */
-export interface EmitPlugin {
- /**
- * Allow plugins to add additional files to the program.
- * For example, Angular creates ngsummary and ngfactory files.
- * These files must be in the program since there may be incoming references to the symbols.
- * @param inputFiles the files that were part of the original program
- * @param compilerHost: the original host (likely a ts.CompilerHost) that we can delegate to
- */
- wrapHost?(compilerHost: ts.CompilerHost, inputFiles: string[], options: ts.CompilerOptions): PluginCompilerHost;
-
- setupCompilation(program: ts.Program, oldProgram?: ts.Program): {
- ignoreForDiagnostics: Set<ts.SourceFile>,
- ignoreForEmit: Set<ts.SourceFile>
- };
-
- getNextProgram?(): ts.Program;
-
- /**
- * Allow plugins to contribute additional TypeScript CustomTransformers.
- * These can modify the TS AST, JS AST, or .d.ts output AST.
- */
- createTransformers(): ts.CustomTransformers;
-}
-
-/**
- * The proxy design pattern, allowing us to customize behavior of the delegate
- * object.
- * This creates a property-by-property copy of the object, so it can be mutated
- * without affecting other users of the original object.
- * See https://en.wikipedia.org/wiki/Proxy_pattern
- */
-export function createProxy<T>(delegate: T): T {
- const proxy = Object.create(null);
- for (const k of Object.keys(delegate)) {
- proxy[k] = function() {
- return (delegate as any)[k].apply(delegate, arguments);
- };
- }
- return proxy;
-}
-
-/**
- * A plugin that contributes additional diagnostics during compilation.
- *
- * This is a more limited API than Plugin, which can overwrite any features of
- * the Program. A DiagnosticPlugin can't affect the output, and can only reject
- * otherwise valid programs.
- *
- * This means that disabling a DiagnosticPlugin is always safe. It will not
- * break any downstream projects, either at build time or in production.
- *
- * It also lets us instrument the plugin to track performance, and tag the
- * diagnostics it emits with the plugin name.
- */
-export interface DiagnosticPlugin {
- /**
- * A brief descriptive name for the plugin.
- *
- * Should not include 'ts', 'typescript', or 'plugin'.
- */
- readonly name: string;
-
- /**
- * Return diagnostics for the given file.
- *
- * Should only include new diagnostics that your plugin is contributing.
- * Should not include diagnostics from program.
- */
- getDiagnostics(sourceFile: ts.SourceFile):
- ReadonlyArray<Readonly<ts.Diagnostic>>;
-}
diff --git a/packages/concatjs/internal/tsc_wrapped/strict_deps.ts b/packages/concatjs/internal/tsc_wrapped/strict_deps.ts
deleted file mode 100644
index 447fc3e..0000000
--- a/packages/concatjs/internal/tsc_wrapped/strict_deps.ts
+++ /dev/null
@@ -1,113 +0,0 @@
-/**
- * @license
- * Copyright 2017 The Bazel Authors. All rights reserved.
- *
- * 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.
- */
-
-import * as path from 'path';
-import * as ts from 'typescript';
-
-import * as perfTrace from './perf_trace';
-import * as pluginApi from './plugin_api';
-
-export interface StrictDepsPluginConfig {
- compilationTargetSrc: string[];
- allowedStrictDeps: string[];
- rootDir: string;
-}
-
-/** The TypeScript diagnostic code for "Cannot find module ...". */
-export const TS_ERR_CANNOT_FIND_MODULE = 2307;
-
-/**
- * The strict_deps plugin checks the imports of the compiled modules.
- *
- * It implements strict deps, i.e. enforces that each file in
- * `config.compilationTargetSrc` only imports from files in
- * `config.allowedStrictDeps`.
- *
- * This is used to implement strict dependency checking -
- * source files in a build target may only import sources of their immediate
- * dependencies, but not sources of their transitive dependencies.
- *
- * strict_deps also makes sure that no imports ends in '.ts'. TypeScript
- * allows imports including the file extension, but our runtime loading support
- * fails with it.
- *
- * strict_deps currently does not check ambient/global definitions.
- */
-export class Plugin implements pluginApi.DiagnosticPlugin {
- constructor(
- private readonly program: ts.Program,
- private readonly config: StrictDepsPluginConfig) {}
-
- readonly name = 'strictDeps';
-
- getDiagnostics(sourceFile: ts.SourceFile) {
- return checkModuleDeps(
- sourceFile, this.program.getTypeChecker(),
- this.config.allowedStrictDeps, this.config.rootDir);
- }
-}
-
-// Exported for testing
-export function checkModuleDeps(
- sf: ts.SourceFile, tc: ts.TypeChecker, allowedDeps: string[],
- rootDir: string): ts.Diagnostic[] {
- function stripExt(fn: string) {
- return fn.replace(/(\.d)?\.tsx?$/, '');
- }
- const allowedMap: {[fileName: string]: boolean} = {};
- for (const d of allowedDeps) allowedMap[stripExt(d)] = true;
-
- const result: ts.Diagnostic[] = [];
- for (const stmt of sf.statements) {
- if (stmt.kind !== ts.SyntaxKind.ImportDeclaration &&
- stmt.kind !== ts.SyntaxKind.ExportDeclaration) {
- continue;
- }
- const id = stmt as ts.ImportDeclaration | ts.ExportDeclaration;
- const modSpec = id.moduleSpecifier;
- if (!modSpec) continue; // E.g. a bare "export {x};"
-
- const sym = tc.getSymbolAtLocation(modSpec);
- if (!sym || !sym.declarations || sym.declarations.length < 1) {
- continue;
- }
- const declFileNames =
- sym.declarations.map(decl => decl.getSourceFile().fileName);
- if (declFileNames.find(
- declFileName => !!allowedMap[stripExt(declFileName)])) {
- continue;
- }
- const importNames = declFileNames.map(
- declFileName => path.posix.relative(rootDir, declFileName));
-
- const extraDeclarationLocationsMessage = (importNames.length < 2) ?
- '' :
- `(It is also declared in ${importNames.slice(1).join(', ')}) `;
- result.push({
- file: sf,
- start: modSpec.getStart(),
- length: modSpec.getEnd() - modSpec.getStart(),
- messageText: `transitive dependency on ${importNames[0]} not allowed. ` +
- extraDeclarationLocationsMessage +
- `Please add the BUILD target to your rule's deps.`,
- category: ts.DiagnosticCategory.Error,
- // semantics are close enough, needs taze.
- code: TS_ERR_CANNOT_FIND_MODULE,
- });
- }
- return result;
-}
diff --git a/packages/concatjs/internal/tsc_wrapped/strict_deps_test.ts b/packages/concatjs/internal/tsc_wrapped/strict_deps_test.ts
deleted file mode 100644
index 1e3ae47..0000000
--- a/packages/concatjs/internal/tsc_wrapped/strict_deps_test.ts
+++ /dev/null
@@ -1,157 +0,0 @@
-/**
- * @license
- * Copyright 2017 The Bazel Authors. All rights reserved.
- *
- * 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.
- */
-
-import 'jasmine';
-import * as ts from 'typescript';
-
-import {checkModuleDeps} from './strict_deps';
-
-describe('strict deps', () => {
- // Cache ASTs that are not part of the test to avoid parsing lib.d.ts over and
- // over again.
- const astCache = new Map<string, ts.SourceFile>();
-
- function createProgram(files: ts.MapLike<string>) {
- const options: ts.CompilerOptions = {
- noResolve: true,
- baseUrl: '/src',
- rootDirs: ['/src', '/src/blaze-bin'],
- paths: {'*': ['*', 'blaze-bin/*']},
- };
- // Fake compiler host relying on `files` above.
- const host = ts.createCompilerHost(options);
- const originalGetSourceFile = host.getSourceFile.bind(host);
- host.getSourceFile = (fileName: string) => {
- if (!files[fileName]) {
- if (astCache.has(fileName)) return astCache.get(fileName);
- const file = originalGetSourceFile(fileName, ts.ScriptTarget.Latest);
- astCache.set(fileName, file!);
- return file;
- }
- return ts.createSourceFile(
- fileName, files[fileName], ts.ScriptTarget.Latest);
- };
-
- // Fake module resolution host relying on `files` above.
- host.fileExists = (f) => !!files[f];
- host.directoryExists = () => true;
- host.realpath = (f) => f;
- const rf = host.readFile.bind(host);
- host.readFile = (f) => files[f] || rf(f);
- host.getCurrentDirectory = () => '/src';
- host.getDirectories = (path) => [];
-
- const p = ts.createProgram(Object.keys(files), options, host);
- const diags = [...ts.getPreEmitDiagnostics(p)];
- if (diags.length > 0) {
- throw new Error(ts.formatDiagnostics(diags, {
- getCurrentDirectory: () => ts.sys.getCurrentDirectory(),
- getNewLine: () => ts.sys.newLine,
- getCanonicalFileName: (f: string) => f,
- }));
- }
- return p;
- }
-
- it('reports errors for transitive dependencies', () => {
- const p = createProgram({
- '/src/p/sd1.ts': 'export let x = 1;',
- '/src/p/sd2.ts': `import {x} from "./sd1";
- export let y = x;`,
- '/src/p/sd3.ts': `import {y} from "./sd2";
- import {x} from "./sd1";
- export let z = x + y;`,
- });
- const diags = checkModuleDeps(
- p.getSourceFile('p/sd3.ts')!, p.getTypeChecker(), ['/src/p/sd2.ts'],
- '/src');
- expect(diags.length).toBe(1);
- expect(diags[0].messageText)
- .toMatch(/transitive dependency on p\/sd1.ts not allowed/);
- });
-
- it('reports errors for exports', () => {
- const p = createProgram({
- '/src/p/sd1.ts': 'export let x = 1;',
- '/src/p/sd2.ts': `import {x} from "./sd1";
- export let y = x;`,
- '/src/p/sd3.ts': `export {x} from "./sd1";`,
- });
- const diags = checkModuleDeps(
- p.getSourceFile('p/sd3.ts')!, p.getTypeChecker(), ['/src/p/sd2.ts'],
- '/src');
- expect(diags.length).toBe(1);
- expect(diags[0].messageText)
- .toMatch(/transitive dependency on p\/sd1.ts not allowed/);
- });
-
- it('supports files mapped in blaze-bin', () => {
- const p = createProgram({
- '/src/blaze-bin/p/sd1.ts': 'export let x = 1;',
- '/src/blaze-bin/p/sd2.ts': `import {x} from "./sd1";
- export let y = x;`,
- '/src/p/sd3.ts': `import {y} from "./sd2";
- import {x} from "./sd1";
- export let z = x + y;`,
- });
- const diags = checkModuleDeps(
- p.getSourceFile('/src/p/sd3.ts')!, p.getTypeChecker(),
- ['/src/blaze-bin/p/sd2.ts'], '/src');
- expect(diags.length).toBe(1);
- expect(diags[0].messageText)
- .toMatch(/dependency on blaze-bin\/p\/sd1.ts not allowed/);
- });
-
- it('supports .d.ts files', () => {
- const p = createProgram({
- '/src/blaze-bin/p/sd1.d.ts': 'export declare let x: number;',
- '/src/blaze-bin/p/sd2.d.ts': `import {x} from "./sd1";
- export declare let y: number;`,
- '/src/p/sd3.ts': `import {y} from "./sd2";
- import {x} from "./sd1";
- export let z = x + y;`,
- });
- const diags = checkModuleDeps(
- p.getSourceFile('/src/p/sd3.ts')!, p.getTypeChecker(),
- ['/src/blaze-bin/p/sd2.d.ts'], '/src');
- expect(diags.length).toBe(1);
- expect(diags[0].messageText)
- .toMatch(/dependency on blaze-bin\/p\/sd1.d.ts not allowed/);
- });
-
- it('allows multiple declarations of the same clutz-generated module', () => {
- const p = createProgram({
- '/src/blaze-bin/p/js1.d.ts': `declare module 'goog:thing' {}`,
- '/src/blaze-bin/p/js2.d.ts': `declare module 'goog:thing' {}`,
- '/src/blaze-bin/p/js3.d.ts': `declare module 'goog:thing' {}`,
- // Import from the middle one, to be sure it doesn't pass just because the
- // order so happens that we checked the declaration from the first one
- '/src/p/my.ts': `import {} from 'goog:thing'; // taze: from //p:js2`,
- });
- const good = checkModuleDeps(
- p.getSourceFile('/src/p/my.ts')!, p.getTypeChecker(),
- ['/src/blaze-bin/p/js2.d.ts'], '/src');
- expect(good.length).toBe(0);
-
- const bad = checkModuleDeps(
- p.getSourceFile('/src/p/my.ts')!, p.getTypeChecker(), [], '/src');
- expect(bad.length).toBe(1);
- expect(bad[0].messageText)
- .toContain(
- '(It is also declared in blaze-bin/p/js2.d.ts, blaze-bin/p/js3.d.ts)');
- });
-});
diff --git a/packages/concatjs/internal/tsc_wrapped/test_support.ts b/packages/concatjs/internal/tsc_wrapped/test_support.ts
deleted file mode 100644
index 5f592e6..0000000
--- a/packages/concatjs/internal/tsc_wrapped/test_support.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-/**
- * @license
- * Copyright 2017 The Bazel Authors. All rights reserved.
- *
- * 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.
- */
-
-/** @fileoverview Helper functions for tests. */
-
-import * as fs from 'fs';
-
-import {FileCache} from './cache';
-
-export function writeTempFile(name: string, contents: string): string {
- // TEST_TMPDIR is set by bazel.
- const fn = (process.env['TEST_TMPDIR'] || '/tmp') + '/tmp.' +
- (Math.random() * 1000000).toFixed(0) + '.' + name;
- fs.writeFileSync(fn, contents);
- return fn;
-}
-
-let digestNumber = 0;
-
-export function invalidateFileCache(fc: FileCache, ...fileNames: string[]) {
- const digests = new Map<string, string>();
- for (const fp of fileNames) {
- digestNumber++;
- digests.set(fp, `${fp}${digestNumber}`);
- }
- fc.updateCache(digests);
-}
diff --git a/packages/concatjs/internal/tsc_wrapped/tsc_wrapped.ts b/packages/concatjs/internal/tsc_wrapped/tsc_wrapped.ts
deleted file mode 100644
index 04b4b21..0000000
--- a/packages/concatjs/internal/tsc_wrapped/tsc_wrapped.ts
+++ /dev/null
@@ -1,694 +0,0 @@
-import * as fs from 'fs';
-import * as path from 'path';
-import * as ts from 'typescript';
-
-// Tsickle is optional, but this import is just used for typechecking.
-import type * as tsickle from 'tsickle';
-
-import {Plugin as BazelConformancePlugin} from '../tsetse/runner';
-
-import {CachedFileLoader, FileLoader, ProgramAndFileCache, UncachedFileLoader} from './cache';
-import {CompilerHost} from './compiler_host';
-import * as bazelDiagnostics from './diagnostics';
-import {constructManifest} from './manifest';
-import * as perfTrace from './perf_trace';
-import {DiagnosticPlugin, PluginCompilerHost, EmitPlugin} from './plugin_api';
-import {Plugin as StrictDepsPlugin} from './strict_deps';
-import {BazelOptions, parseTsconfig, resolveNormalizedPath} from './tsconfig';
-import {debug, log, runAsWorker, runWorkerLoop} from './worker';
-import {getAngularEmitPluginOrThrow} from './angular_plugin';
-
-/**
- * Top-level entry point for tsc_wrapped.
- */
-export async function main(args: string[]) {
- if (runAsWorker(args)) {
- log('Starting TypeScript compiler persistent worker...');
- runWorkerLoop(runOneBuild);
- // Note: intentionally don't process.exit() here, because runWorkerLoop
- // is waiting for async callbacks from node.
- } else {
- debug('Running a single build...');
- if (args.length === 0) throw new Error('Not enough arguments');
- if (!await runOneBuild(args)) {
- return 1;
- }
- }
- return 0;
-}
-
-/** The one ProgramAndFileCache instance used in this process. */
-const cache = new ProgramAndFileCache(debug);
-
-function isCompilationTarget(
- bazelOpts: BazelOptions, sf: ts.SourceFile): boolean {
- if (bazelOpts.isJsTranspilation && bazelOpts.transpiledJsInputDirectory) {
- // transpiledJsInputDirectory is a relative logical path, so we cannot
- // compare it to the resolved, absolute path of sf here.
- // compilationTargetSrc is resolved, so use that for the comparison.
- return sf.fileName.startsWith(bazelOpts.compilationTargetSrc[0]);
- }
- return (bazelOpts.compilationTargetSrc.indexOf(sf.fileName) !== -1);
-}
-
-/**
- * Gather diagnostics from TypeScript's type-checker as well as other plugins we
- * install such as strict dependency checking.
- */
-export function gatherDiagnostics(
- options: ts.CompilerOptions, bazelOpts: BazelOptions, program: ts.Program,
- disabledTsetseRules: string[], plugins: DiagnosticPlugin[] = [],
- ignoreForDiagnostics: Set<ts.SourceFile> = new Set()): ts.Diagnostic[] {
- const diagnostics: ts.Diagnostic[] = [];
- perfTrace.wrap('type checking', () => {
- if (!bazelOpts.typeCheck) {
- return;
- }
- // These checks mirror ts.getPreEmitDiagnostics, with the important
- // exception of avoiding b/30708240, which is that if you call
- // program.getDeclarationDiagnostics() it somehow corrupts the emit.
- perfTrace.wrap(`global diagnostics`, () => {
- diagnostics.push(...program.getOptionsDiagnostics());
- diagnostics.push(...program.getGlobalDiagnostics());
- });
-
- // Check if `f` is a target for type-checking.
- let isTypeCheckTarget = (f: ts.SourceFile) =>
- bazelOpts.typeCheckDependencies || isCompilationTarget(bazelOpts, f);
-
- let sourceFilesToCheck: ReadonlyArray<ts.SourceFile> =
- program.getSourceFiles().filter(
- f => isTypeCheckTarget(f) && !ignoreForDiagnostics.has(f));
- for (const sf of sourceFilesToCheck) {
- perfTrace.wrap(`check ${sf.fileName}`, () => {
- diagnostics.push(...program.getSyntacticDiagnostics(sf));
- diagnostics.push(...program.getSemanticDiagnostics(sf));
- });
- perfTrace.snapshotMemoryUsage();
- }
-
- // Install extra diagnostic plugins
- plugins.push(
- ...getCommonPlugins(options, bazelOpts, program, disabledTsetseRules));
- for (const plugin of plugins) {
- perfTrace.wrap(`${plugin.name} diagnostics`, () => {
- for (const sf of sourceFilesToCheck) {
- perfTrace.wrap(`${plugin.name} checking ${sf.fileName}`, () => {
- const pluginDiagnostics = plugin.getDiagnostics(sf).map((d) => {
- return tagDiagnosticWithPlugin(plugin.name, d);
- });
- diagnostics.push(...pluginDiagnostics);
- });
- perfTrace.snapshotMemoryUsage();
- }
- });
- }
- });
-
- return diagnostics;
-}
-
-/**
- * Construct diagnostic plugins that we always want included.
- *
- * TODO: Call sites of getDiagnostics should initialize plugins themselves,
- * including these, and the arguments to getDiagnostics should be simplified.
- */
-export function getCommonPlugins(
- options: ts.CompilerOptions, bazelOpts: BazelOptions, program: ts.Program,
- disabledTsetseRules: string[]): DiagnosticPlugin[] {
- const plugins: DiagnosticPlugin[] = [];
- if (!bazelOpts.disableStrictDeps) {
- if (options.rootDir == null) {
- throw new Error(`StrictDepsPlugin requires that rootDir be specified`);
- }
- plugins.push(new StrictDepsPlugin(program, {
- ...bazelOpts,
- rootDir: options.rootDir,
- }));
- }
- if (!bazelOpts.isJsTranspilation) {
- let tsetsePluginConstructor:
- {new (program: ts.Program, disabledRules: string[]): DiagnosticPlugin} =
- BazelConformancePlugin;
- plugins.push(new tsetsePluginConstructor(program, disabledTsetseRules));
- }
- return plugins;
-}
-
-/**
- * Returns a copy of diagnostic with one whose text has been prepended with
- * an indication of what plugin contributed that diagnostic.
- *
- * This is slightly complicated because a diagnostic's message text can be
- * split up into a chain of diagnostics, e.g. when there's supplementary info
- * about a diagnostic.
- */
-function tagDiagnosticWithPlugin(
- pluginName: string, diagnostic: Readonly<ts.Diagnostic>): ts.Diagnostic {
- const tagMessageWithPluginName = (text: string) => `[${pluginName}] ${text}`;
-
- let messageText;
- if (typeof diagnostic.messageText === 'string') {
- // The simple case, where a diagnostic's message is just a string.
- messageText = tagMessageWithPluginName(diagnostic.messageText);
- } else {
- // In the case of a chain of messages we only want to tag the head of the
- // chain, as that's the first line of message on the CLI.
- const chain: ts.DiagnosticMessageChain = diagnostic.messageText;
- messageText = {
- ...chain,
- messageText: tagMessageWithPluginName(chain.messageText)
- };
- }
- return {
- ...diagnostic,
- messageText,
- };
-}
-
-/**
- * expandSourcesFromDirectories finds any directories under filePath and expands
- * them to their .js or .ts contents.
- */
-function expandSourcesFromDirectories(fileList: string[], filePath: string) {
- if (filePath.endsWith('.ts') || filePath.endsWith('.tsx') ||
- filePath.endsWith('.js')) {
- fileList.push(filePath);
- return;
- }
-
- if (!fs.statSync(filePath).isDirectory()) {
- // subdirectories may also contain e.g. .java files, which we ignore.
- return;
- }
- const entries = fs.readdirSync(filePath);
- for (const entry of entries) {
- expandSourcesFromDirectories(fileList, path.join(filePath, entry));
- }
-}
-
-/**
- * Runs a single build, returning false on failure. This is potentially called
- * multiple times (once per bazel request) when running as a bazel worker.
- * Any encountered errors are written to stderr.
- */
-async function runOneBuild(
- args: string[], inputs?: {[path: string]: string}): Promise<boolean> {
- if (args.length !== 1) {
- console.error('Expected one argument: path to tsconfig.json');
- return false;
- }
-
- perfTrace.snapshotMemoryUsage();
-
- // Strip leading at-signs, used in build_defs.bzl to indicate a params file
- const tsconfigFile = args[0].replace(/^@+/, '');
- const [parsed, errors, {target}] = parseTsconfig(tsconfigFile);
- if (errors) {
- console.error(bazelDiagnostics.format(target, errors));
- return false;
- }
- if (!parsed) {
- throw new Error(
- 'Impossible state: if parseTsconfig returns no errors, then parsed should be non-null');
- }
- const {options, bazelOpts, files, disabledTsetseRules} = parsed;
-
- let sourceFiles: string[] = [];
- if (bazelOpts.isJsTranspilation) {
- // Under JS transpilations, some inputs might be directories.
- for (const filePath of files) {
- expandSourcesFromDirectories(sourceFiles, filePath);
- }
- } else {
- sourceFiles = files;
- }
-
- if (bazelOpts.maxCacheSizeMb !== undefined) {
- const maxCacheSizeBytes = bazelOpts.maxCacheSizeMb * (1 << 20);
- cache.setMaxCacheSize(maxCacheSizeBytes);
- } else {
- cache.resetMaxCacheSize();
- }
-
- let fileLoader: FileLoader;
- if (inputs) {
- fileLoader = new CachedFileLoader(cache);
- // Resolve the inputs to absolute paths to match TypeScript internals
- const resolvedInputs = new Map<string, string>();
- for (const key of Object.keys(inputs)) {
- resolvedInputs.set(resolveNormalizedPath(key), inputs[key]);
- }
- cache.updateCache(resolvedInputs);
- } else {
- fileLoader = new UncachedFileLoader();
- }
-
- const diagnostics = await perfTrace.wrapAsync('createProgramAndEmit', async () => {
- return (await createProgramAndEmit(
- fileLoader, options, bazelOpts, sourceFiles, disabledTsetseRules))
- .diagnostics;
- });
-
- if (diagnostics.length > 0) {
- console.error(bazelDiagnostics.format(bazelOpts.target, diagnostics));
- return false;
- }
-
- const perfTracePath = bazelOpts.perfTracePath;
- if (perfTracePath) {
- log('Writing trace to', perfTracePath);
- perfTrace.snapshotMemoryUsage();
- perfTrace.write(perfTracePath);
- }
-
- return true;
-}
-
-// We use the expected_diagnostics attribute for writing compilation tests.
-// We don't want to expose it to users as a general-purpose feature, because
-// we don't want users to end up using it like a fancy @ts-ignore.
-// So instead it's limited to a whitelist.
-const expectDiagnosticsWhitelist: string[] = [
-];
-
-/** errorDiag produces an error diagnostic not bound to a file or location. */
-function errorDiag(messageText: string) {
- return {
- category: ts.DiagnosticCategory.Error,
- code: 0,
- file: undefined,
- start: undefined,
- length: undefined,
- messageText,
- };
-}
-
-/**
- * createProgramAndEmit creates a ts.Program from the given options and emits it
- * according to them (e.g. including running various plugins and tsickle). It
- * returns the program and any diagnostics generated.
- *
- * Callers should check and emit diagnostics.
- */
-export async function createProgramAndEmit(
- fileLoader: FileLoader, options: ts.CompilerOptions,
- bazelOpts: BazelOptions, files: string[], disabledTsetseRules: string[]):
- Promise<{program?: ts.Program, diagnostics: ts.Diagnostic[]}> {
- // Beware! createProgramAndEmit must not print to console, nor exit etc.
- // Handle errors by reporting and returning diagnostics.
- perfTrace.snapshotMemoryUsage();
- cache.resetStats();
- cache.traceStats();
-
- const compilerHostDelegate =
- ts.createCompilerHost({target: ts.ScriptTarget.ES5});
-
- const moduleResolver = bazelOpts.isJsTranspilation ?
- makeJsModuleResolver(bazelOpts.workspaceName) :
- ts.resolveModuleName;
-
- // Files which should be allowed to be read, but aren't TypeScript code
- const assets: string[] = [];
- if (bazelOpts.angularCompilerOptions) {
- if (bazelOpts.angularCompilerOptions.assets) {
- assets.push(...bazelOpts.angularCompilerOptions.assets);
- }
- }
-
- const tsickleCompilerHost = new CompilerHost(
- [...files, ...assets], options, bazelOpts, compilerHostDelegate, fileLoader,
- moduleResolver);
- let compilerHost: PluginCompilerHost = tsickleCompilerHost;
- const diagnosticPlugins: DiagnosticPlugin[] = [];
-
- let angularPlugin: EmitPlugin&DiagnosticPlugin|undefined;
- if (bazelOpts.angularCompilerOptions) {
- try {
- // Dynamically load the Angular emit plugin.
- // Lazy load, so that code that does not use the plugin doesn't even
- // have to spend the time to parse and load the plugin's source.
- const NgEmitPluginCtor = await getAngularEmitPluginOrThrow();
- const ngOptions = bazelOpts.angularCompilerOptions;
-
- // Add the rootDir setting to the options passed to NgTscPlugin.
- // Required so that synthetic files added to the rootFiles in the program
- // can be given absolute paths, just as we do in tsconfig.ts, matching
- // the behavior in TypeScript's tsconfig parsing logic.
- ngOptions['rootDir'] = options.rootDir;
-
- angularPlugin = new NgEmitPluginCtor(ngOptions);
- } catch (e) {
- return {
- diagnostics: [errorDiag(
- 'when using `ts_library(use_angular_plugin=True)`, ' +
- `you must install "@angular/compiler-cli". Error: ${e}`)]
- };
- }
-
- diagnosticPlugins.push(angularPlugin);
-
- // Wrap host so that Ivy compiler can add a file to it (has synthetic types for checking templates)
- // TODO(arick): remove after ngsummary and ngfactory files eliminated
- compilerHost = angularPlugin!.wrapHost!(compilerHost, files, options);
- }
-
-
- const oldProgram = cache.getProgram(bazelOpts.target);
- const program = perfTrace.wrap(
- 'createProgram',
- () => ts.createProgram(
- compilerHost.inputFiles, options, compilerHost, oldProgram));
- cache.putProgram(bazelOpts.target, program);
-
- let transformers: ts.CustomTransformers = {
- before: [],
- after: [],
- afterDeclarations: [],
- };
-
- let ignoreForDiagnostics = new Set<ts.SourceFile>();
-
- if (angularPlugin) {
- // The Angular plugin (via the `wrapHost` call above) inserts additional
- // "shim" files into the `ts.Program`, beyond the user's .ts files. For
- // proper operation, the plugin requires two modifications to the standard
- // flow of TypeScript compilation, relating to which files are either
- // type-checked or emitted.
- //
- // In tsc_wrapped, there is already a concept of which files should be
- // emitted (which is calculated from the compilation inputs, as well as any
- // paths that match expected Angular shims such as ngfactory files for those
- // inputs). So the `ignoreForEmit` set produced by the plugin can be
- // ignored here.
-
- const angularSetup = angularPlugin.setupCompilation(program);
-
- // Shims generated by the plugin do not benefit from normal type-checking,
- // for a few reasons.
- // 1) for emitted shims like ngfactory files, their proper contents are
- // programmatically added via TypeScript transforms, so checking their
- // initial contents is pointless and inefficient.
- // 2) for non-emitted shims like the ngtypecheck files used in template
- // type-checking, they are managed and checked internally via the plugin
- // `getDiagnostics` method. Checking them as part of the normal
- // diagnostics flow will at best produce spurious, duplicate errors that
- // are not reported in the correct context, and at worst can produce
- // incorrect errors.
- //
- // The `ignoreForDiagnostics` set informs tsc_wrapped which Angular shim
- // files should be skipped when gathering diagnostics.
- ignoreForDiagnostics = angularSetup.ignoreForDiagnostics;
-
- transformers = angularPlugin.createTransformers();
- }
-
- for (const pluginConfig of options['plugins'] as ts.PluginImport[] || []) {
- if (pluginConfig.name === 'ts-lit-plugin') {
- const litTscPlugin =
- // Lazy load, so that code that does not use the plugin doesn't even
- // have to spend the time to parse and load the plugin's source.
- //
- // tslint:disable-next-line:no-require-imports
- new (require('ts-lit-plugin/lib/bazel-plugin').Plugin)(
- program, pluginConfig) as DiagnosticPlugin;
- diagnosticPlugins.push(litTscPlugin);
- }
- }
-
- if (!bazelOpts.isJsTranspilation) {
- // If there are any TypeScript type errors abort now, so the error
- // messages refer to the original source. After any subsequent passes
- // (decorator downleveling or tsickle) we do not type check.
- let diagnostics = gatherDiagnostics(
- options, bazelOpts, program, disabledTsetseRules, diagnosticPlugins,
- ignoreForDiagnostics);
- if (!expectDiagnosticsWhitelist.length ||
- expectDiagnosticsWhitelist.some(p => bazelOpts.target.startsWith(p))) {
- diagnostics = bazelDiagnostics.filterExpected(
- bazelOpts, diagnostics, bazelDiagnostics.uglyFormat);
- } else if (bazelOpts.expectedDiagnostics.length > 0) {
- diagnostics.push(errorDiag(
- `Only targets under ${
- expectDiagnosticsWhitelist.join(', ')} can use ` +
- 'expected_diagnostics, but got ' + bazelOpts.target));
- }
-
- // The Angular plugin creates a new program with template type-check information
- // This consumes (destroys) the old program so it's not suitable for re-use anymore
- // Ask Angular to give us the updated reusable program.
- if (angularPlugin) {
- cache.putProgram(bazelOpts.target, angularPlugin.getNextProgram!());
- }
-
- if (diagnostics.length > 0) {
- debug('compilation failed at', new Error().stack!);
- return {program, diagnostics};
- }
- }
-
- // Angular might have added files like input.ngfactory.ts or input.ngsummary.ts
- // and these need to be emitted.
- // TODO(arick): remove after Ivy is enabled and ngsummary/ngfactory files no longer needed
- function isAngularFile(sf: ts.SourceFile) {
- if (!/\.ng(factory|summary)\.ts$/.test(sf.fileName)) {
- return false;
- }
- const base = sf.fileName.slice(0, /*'.ngfactory|ngsummary.ts'.length*/ -13);
- // It's possible a file was named ngsummary.ts or ngfactory.ts but *not* synthetic
- // So verify that base.ts or base.tsx was originally part of the compilation
- const tsCandidate = {fileName: `${base}.ts`} as ts.SourceFile;
- const tsxCandidate = {fileName: `${base}.tsx`} as ts.SourceFile;
- return isCompilationTarget(bazelOpts, tsCandidate) ||
- isCompilationTarget(bazelOpts, tsxCandidate);
- }
-
- // If the Angular plugin is in use, this list of files to emit should exclude
- // any files defined in the `ignoreForEmit` set returned by the plugin.
- // However limiting the outputs to the set of compilation target files (plus
- // any Angular shims defined by `isAngularFile`) already has that effect, so
- // `ignoreForEmit` does not need to be factored in here.
- const compilationTargets = program.getSourceFiles().filter(
- sf => isCompilationTarget(bazelOpts, sf) || isAngularFile(sf));
-
- let diagnostics: ts.Diagnostic[] = [];
- let useTsickleEmit = bazelOpts.tsickle;
-
- if (useTsickleEmit) {
- diagnostics = emitWithTsickle(
- program, tsickleCompilerHost, compilationTargets, options, bazelOpts,
- transformers);
- } else {
- diagnostics = emitWithTypescript(program, compilationTargets, transformers);
- }
-
- if (diagnostics.length > 0) {
- debug('compilation failed at', new Error().stack!);
- }
- cache.printStats();
- return {program, diagnostics};
-}
-
-function emitWithTypescript(
- program: ts.Program, compilationTargets: ts.SourceFile[],
- transforms: ts.CustomTransformers): ts.Diagnostic[] {
- const diagnostics: ts.Diagnostic[] = [];
- for (const sf of compilationTargets) {
- const result = program.emit(
- sf, /*writeFile*/ undefined,
- /*cancellationToken*/ undefined, /*emitOnlyDtsFiles*/ undefined,
- transforms);
- diagnostics.push(...result.diagnostics);
- }
- return diagnostics;
-}
-
-/**
- * Runs the emit pipeline with Tsickle transformations - goog.module rewriting
- * and Closure types emitted included.
- * Exported to be used by the internal global refactoring tools.
- * TODO(radokirov): investigate using runWithOptions and making this private
- * again, if we can make compilerHosts match.
- */
-export function emitWithTsickle(
- program: ts.Program, compilerHost: CompilerHost,
- compilationTargets: ts.SourceFile[], options: ts.CompilerOptions,
- bazelOpts: BazelOptions,
- transforms: ts.CustomTransformers): ts.Diagnostic[] {
- const emitResults: tsickle.EmitResult[] = [];
- const diagnostics: ts.Diagnostic[] = [];
- // The 'tsickle' import above is only used in type positions, so it won't
- // result in a runtime dependency on tsickle.
- // If the user requests the tsickle emit, then we dynamically require it
- // here for use at runtime.
- let optTsickle: typeof tsickle;
- try {
- // tslint:disable-next-line:no-require-imports
- optTsickle = require('tsickle');
- } catch (e) {
- if (e.code !== 'MODULE_NOT_FOUND') {
- throw e;
- }
- throw new Error(
- 'When setting bazelOpts { tsickle: true }, ' +
- 'you must also add a devDependency on the tsickle npm package');
- }
- perfTrace.wrap('emit', () => {
- for (const sf of compilationTargets) {
- perfTrace.wrap(`emit ${sf.fileName}`, () => {
- emitResults.push(optTsickle.emitWithTsickle(
- program, compilerHost, compilerHost, options, sf,
- /*writeFile*/ undefined,
- /*cancellationToken*/ undefined, /*emitOnlyDtsFiles*/ undefined, {
- beforeTs: transforms.before,
- afterTs: transforms.after,
- afterDeclarations: transforms.afterDeclarations,
- }));
- });
- }
- });
- const emitResult = optTsickle.mergeEmitResults(emitResults);
- diagnostics.push(...emitResult.diagnostics);
-
- // If tsickle reported diagnostics, don't produce externs or manifest outputs.
- if (diagnostics.length > 0) {
- return diagnostics;
- }
-
- let externs = '/** @externs */\n' +
- '// generating externs was disabled using generate_externs=False\n';
- if (bazelOpts.tsickleGenerateExterns) {
- externs =
- optTsickle.getGeneratedExterns(emitResult.externs, options.rootDir!);
- }
-
- if (!options.noEmit && bazelOpts.tsickleExternsPath) {
- // Note: when tsickleExternsPath is provided, we always write a file as a
- // marker that compilation succeeded, even if it's empty (just containing an
- // @externs).
- fs.writeFileSync(bazelOpts.tsickleExternsPath, externs);
-
- // When generating externs, generate an externs file for each of the input
- // .d.ts files.
- if (bazelOpts.tsickleGenerateExterns &&
- compilerHost.provideExternalModuleDtsNamespace) {
- for (const extern of compilationTargets) {
- if (!extern.isDeclarationFile) continue;
- const outputBaseDir = options.outDir!;
- const relativeOutputPath =
- compilerHost.relativeOutputPath(extern.fileName);
- mkdirp(outputBaseDir, path.dirname(relativeOutputPath));
- const outputPath = path.join(outputBaseDir, relativeOutputPath);
- const moduleName = compilerHost.pathToModuleName('', extern.fileName);
- fs.writeFileSync(
- outputPath,
- `goog.module('${moduleName}');\n` +
- `// Export an empty object of unknown type to allow imports.\n` +
- `// TODO: use typeof once available\n` +
- `exports = /** @type {?} */ ({});\n`);
- }
- }
- }
-
- if (!options.noEmit && bazelOpts.manifest) {
- perfTrace.wrap('manifest', () => {
- const manifest =
- constructManifest(emitResult.modulesManifest, compilerHost);
- fs.writeFileSync(bazelOpts.manifest, manifest);
- });
- }
-
- return diagnostics;
-}
-
-/**
- * Creates directories subdir (a slash separated relative path) starting from
- * base.
- */
-function mkdirp(base: string, subdir: string) {
- const steps = subdir.split(path.sep);
- let current = base;
- for (let i = 0; i < steps.length; i++) {
- current = path.join(current, steps[i]);
- if (!fs.existsSync(current)) fs.mkdirSync(current);
- }
-}
-
-
-/**
- * Resolve module filenames for JS modules.
- *
- * JS module resolution needs to be different because when transpiling JS we
- * do not pass in any dependencies, so the TS module resolver will not resolve
- * any files.
- *
- * Fortunately, JS module resolution is very simple. The imported module name
- * must either a relative path, or the workspace root (i.e. 'google3'),
- * so we can perform module resolution entirely based on file names, without
- * looking at the filesystem.
- */
-function makeJsModuleResolver(workspaceName: string) {
- // The literal '/' here is cross-platform safe because it's matching on
- // import specifiers, not file names.
- const workspaceModuleSpecifierPrefix = `${workspaceName}/`;
- const workspaceDir = `${path.sep}${workspaceName}${path.sep}`;
- function jsModuleResolver(
- moduleName: string, containingFile: string,
- compilerOptions: ts.CompilerOptions, host: ts.ModuleResolutionHost):
- ts.ResolvedModuleWithFailedLookupLocations {
- let resolvedFileName;
- if (containingFile === '') {
- // In tsickle we resolve the filename against '' to get the goog module
- // name of a sourcefile.
- resolvedFileName = moduleName;
- } else if (moduleName.startsWith(workspaceModuleSpecifierPrefix)) {
- // Given a workspace name of 'foo', we want to resolve import specifiers
- // like: 'foo/project/file.js' to the absolute filesystem path of
- // project/file.js within the workspace.
- const workspaceDirLocation = containingFile.indexOf(workspaceDir);
- if (workspaceDirLocation < 0) {
- return {resolvedModule: undefined};
- }
- const absolutePathToWorkspaceDir =
- containingFile.slice(0, workspaceDirLocation);
- resolvedFileName = path.join(absolutePathToWorkspaceDir, moduleName);
- } else {
- if (!moduleName.startsWith('./') && !moduleName.startsWith('../')) {
- throw new Error(
- `Unsupported module import specifier: ${
- JSON.stringify(moduleName)}.\n` +
- `JS module imports must either be relative paths ` +
- `(beginning with '.' or '..'), ` +
- `or they must begin with '${workspaceName}/'.`);
- }
- resolvedFileName = path.join(path.dirname(containingFile), moduleName);
- }
- return {
- resolvedModule: {
- resolvedFileName,
- extension: ts.Extension.Js, // js can only import js
- // These two fields are cargo culted from what ts.resolveModuleName
- // seems to return.
- packageId: undefined,
- isExternalLibraryImport: false,
- }
- };
- }
-
- return jsModuleResolver;
-}
-
-
-if (require.main === module) {
- // Do not call process.exit(), as that terminates the binary before
- // completing pending operations, such as writing to stdout or emitting the
- // v8 performance log. Rather, set the exit code and fall off the main
- // thread, which will cause node to terminate cleanly.
- main(process.argv.slice(2))
- .then(exitCode => process.exitCode = exitCode)
- .catch(e => {
- console.error(e);
- process.exitCode = 1;
- });
-}
diff --git a/packages/concatjs/internal/tsc_wrapped/tsc_wrapped_test.ts b/packages/concatjs/internal/tsc_wrapped/tsc_wrapped_test.ts
deleted file mode 100644
index fa77e96..0000000
--- a/packages/concatjs/internal/tsc_wrapped/tsc_wrapped_test.ts
+++ /dev/null
@@ -1,307 +0,0 @@
-import * as path from 'path';
-import {ModulesManifest} from 'tsickle';
-import * as ts from 'typescript';
-
-import {UncachedFileLoader} from './cache';
-import {CompilerHost} from './compiler_host';
-import {constructManifest} from './manifest';
-import {writeTempFile} from './test_support';
-import {BazelOptions} from './tsconfig';
-
-// tslint:disable-next-line:no-any mock for testing.
-const throwingCompilerHostFake: ts.CompilerHost = null as any;
-
-const testFileLoader = new UncachedFileLoader();
-
-const relativeOutputPath = (f: string) => f;
-
-type ModuleResolver =
- (moduleName: string, containingFile: string,
- compilerOptions: ts.CompilerOptions, host: ts.ModuleResolutionHost) =>
- ts.ResolvedModuleWithFailedLookupLocations;
-
-describe('tsc wrapped', () => {
- function f(
- res: ModulesManifest, fname: string, module: string, deps: string[]) {
- res.addModule(fname, module);
- for (let i = 0; i < deps.length; i++) {
- res.addReferencedModule(fname, deps[i]);
- }
- return res;
- }
-
- it('produces a topo-sorted manifest', () => {
- const res = new ModulesManifest();
- f(res, 'src/f3.js', 'test$f3', ['test$f2', 'test$f1']);
- f(res, 'src/f2.js', 'test$f2',
- ['external$ts_source_not_included', 'test$f1']);
- f(res, 'src/f1.js', 'test$f1', []);
- expect(constructManifest(res, {relativeOutputPath})).toBe([
- 'src/f1.js\n', 'src/f2.js\n', 'src/f3.js\n'
- ].join(''));
- });
-
- it('reports cyclical dependencies', () => {
- const res = new ModulesManifest();
- f(res, 'src/f2', 'src$f2', ['src$f3']);
- f(res, 'src/f3', 'src$f3', ['src$f1']);
- f(res, 'src/f1', 'src$f1', ['src$f2']);
- expect(() => constructManifest(res, {relativeOutputPath}))
- .toThrowError(/src\/f2 ->\nsrc\/f3 ->\nsrc\/f1 ->\nsrc\/f2/g);
- });
-
- it('toposorts diamonds', () => {
- // t
- // l r
- // b
- const res = new ModulesManifest();
- f(res, 'bottom.js', 'bottom', ['left', 'right']);
- f(res, 'right.js', 'right', ['top']);
- f(res, 'left.js', 'left', ['top']);
- f(res, 'top.js', 'top', []);
- expect(constructManifest(res, {relativeOutputPath})).toBe([
- 'top.js\n',
- 'left.js\n',
- 'right.js\n',
- 'bottom.js\n',
- ].join(''));
- });
-
-});
-
-// Create something that looks like CompilerOptions.
-const COMPILER_OPTIONS: ts.CompilerOptions = {
- rootDirs: [
- // Sorted by inverse length, as done by tsconfig.ts in production.
- '/root/google3/blaze-out/k8-fastbuild/genfiles',
- '/root/google3/blaze-out/k8-fastbuild/bin',
- '/root/google3',
- ],
- outDir: '/root/google3/blaze-out/k8-fastbuild/bin',
- rootDir: '/root/google3'
-};
-
-
-const defaultBazelOpts = {
- googmodule: true,
- workspaceName: 'google3',
- prelude: `goog.require('google3.third_party.javascript.tslib.tslib');`,
-} as BazelOptions;
-
-describe('compiler host', () => {
- const bazelOpts = {
- ...defaultBazelOpts,
- es5Mode: false,
- } as BazelOptions;
-
- it('looks up files', () => {
- const fn = writeTempFile('file_lookup', 'let x: number = 123;');
- const fn2 = writeTempFile('file_lookup2', 'let x: number = 124;');
- const host = new CompilerHost(
- [fn /* but not fn2! */], COMPILER_OPTIONS, bazelOpts,
- throwingCompilerHostFake, testFileLoader);
- expect(host.fileExists(fn)).toBe(true);
- expect(host.fileExists(fn2)).toBe(false);
- });
-
- describe('file writing', () => {
- let writtenFiles: {[key: string]: string};
- beforeEach(() => writtenFiles = {});
-
- const delegateHost = {
- writeFile: (fn: string, d: string) => {
- writtenFiles[fn.replace(/\\/g, '/')] = d;
- }
- // tslint:disable-next-line:no-any mock for testing.
- } as any;
-
- function createFakeModuleResolver(
- moduleRoots: {[moduleName: string]: string}): ModuleResolver {
- return (moduleName: string, containingFile: string,
- compilerOptions: ts.CompilerOptions,
- host: ts.ModuleResolutionHost) => {
- if (moduleName[0] === '.') {
- moduleName =
- path.posix.join(path.dirname(containingFile), moduleName);
- }
- for (const moduleRoot in moduleRoots) {
- if (moduleName.indexOf(moduleRoot) === 0) {
- const resolvedFileName = moduleRoots[moduleRoot] +
- moduleName.substring(moduleRoot.length) + '.d.ts';
- return {
- resolvedModule: {resolvedFileName, extension: ts.Extension.Dts},
- failedLookupLocations: []
- };
- }
- }
-
- return {
- resolvedModule:
- {resolvedFileName: moduleName, extension: ts.Extension.Dts},
- failedLookupLocations: []
- };
- };
- }
-
- function createFakeGoogle3Host({
- es5 = false,
- moduleRoots = {} as {[moduleName: string]: string},
- isJsTranspilation = false,
- transpiledJsOutputFileName = undefined as string | undefined,
- transpiledJsInputDirectory = undefined as string | undefined,
- transpiledJsOutputDirectory = undefined as string | undefined,
- } = {}) {
- const bazelOpts = {
- ...defaultBazelOpts,
- es5Mode: es5,
- isJsTranspilation,
- transpiledJsOutputFileName,
- transpiledJsInputDirectory,
- transpiledJsOutputDirectory,
- } as BazelOptions;
- return new CompilerHost(
- [], COMPILER_OPTIONS, bazelOpts, delegateHost, testFileLoader,
- createFakeModuleResolver(moduleRoots));
- }
-
- describe('converts path to module names', () => {
- let host: CompilerHost;
- beforeEach(() => {
- host = createFakeGoogle3Host({
- moduleRoots: {
- 'module': 'path/to/module',
- 'module2': 'path/to/module2',
- 'path/to/module2': 'path/to/module2',
- },
- });
- });
-
- function expectPath(context: string, path: string) {
- return expect(host.pathToModuleName(context, path));
- }
-
- it('mangles absolute paths', () => {
- expectPath('whatever/context', 'some/absolute/module')
- .toBe('google3.some.absolute.module');
- });
-
- it('escapes special symbols', () => {
- expectPath('', 'some|123').toBe('google3.some$7c123');
- expectPath('', '1some|').toBe('google3.1some$7c');
- expectPath('', 'bar/foo.bam.ts').toBe('google3.bar.foo$2ebam');
- expectPath('', '-foo-').toBe('google3.$2dfoo$2d');
- // Underscore is unmodified, because it is common in google3 paths.
- expectPath('', 'foo_bar').toBe('google3.foo_bar');
- });
-
- it('resolves paths', () => {
- const context = 'path/to/module';
-
- expectPath(context, './module2').toBe('google3.path.to.module2');
- expectPath(context, '././module2').toBe('google3.path.to.module2');
- expectPath(context, '../to/module2').toBe('google3.path.to.module2');
- expectPath(context, '../to/.././to/module2')
- .toBe('google3.path.to.module2');
- });
-
- it('ignores extra google3 sections in paths', () => {
- expectPath('', 'google3/foo/bar').toBe('google3.foo.bar');
- });
-
- it('resolves absolute paths', () => {
- const context = 'path/to/module/dir/file';
-
- expectPath(context, '/root/google3/some/file.ts')
- .toBe('google3.some.file');
- expectPath(context, '/root/google3/path/to/some/file')
- .toBe('google3.path.to.some.file');
- expectPath(
- context, '/root/google3/blaze-out/k8-fastbuild/bin/some/file')
- .toBe('google3.some.file');
- expectPath(
- context, '/root/google3/blaze-out/k8-fastbuild/genfiles/some/file')
- .toBe('google3.some.file');
- });
-
- describe('uses module name for resolved file paths', () => {
- it('for goog.module module names', () => {
- expectPath('', 'module/dir/file2')
- .toBe('google3.path.to.module.dir.file2');
- expectPath('', 'module2/dir/file2')
- .toBe('google3.path.to.module2.dir.file2');
- });
-
- it('for imports of files from the same module', () => {
- const context = 'path/to/module/dir/file';
-
- expectPath(context, 'module/dir/file2')
- .toBe('google3.path.to.module.dir.file2');
- expectPath(context, './foo/bar')
- .toBe('google3.path.to.module.dir.foo.bar');
- expectPath(context, '../foo/bar')
- .toBe('google3.path.to.module.foo.bar');
- expectPath(context, 'path/to/module/dir/file2')
- .toBe('google3.path.to.module.dir.file2');
- });
-
- it('for imports of files from a different module', () => {
- const context = 'path/to/module/dir/file';
-
- expectPath(context, 'module2/dir/file')
- .toBe('google3.path.to.module2.dir.file');
- expectPath(context, '../../module2/dir/file')
- .toBe('google3.path.to.module2.dir.file');
- expectPath(context, 'path/to/module2/dir/file')
- .toBe('google3.path.to.module2.dir.file');
- });
- });
- });
-
- describe('output files', () => {
- it('writes to .mjs in ES6 mode', () => {
- createFakeGoogle3Host({
- es5: false,
- }).writeFile('a.js', 'some.code();', false, undefined, []);
- expect(Object.keys(writtenFiles)).toEqual([
- '/root/google3/blaze-out/k8-fastbuild/bin/a.mjs'
- ]);
- });
-
- it('writes to .js in ES5 mode', () => {
- createFakeGoogle3Host({
- es5: true,
- }).writeFile('a/b.js', 'some.code();', false, undefined, []);
- expect(Object.keys(writtenFiles)).toEqual([
- '/root/google3/blaze-out/k8-fastbuild/bin/a/b.js'
- ]);
- });
-
- describe('transpiled JS', () => {
- it('writes to transpiledJsOutputFileName', () => {
- const host = createFakeGoogle3Host({
- isJsTranspilation: true,
- transpiledJsOutputFileName: 'foo/bar/a/b.dev_es5.js',
- });
- host.writeFile('a/b.js', 'some.code();', false, undefined, []);
- expect(Object.keys(writtenFiles)).toEqual([
- '/root/google3/blaze-out/k8-fastbuild/bin/foo/bar/a/b.dev_es5.js'
- ]);
- });
-
- it('writes to transpiledJsOutputDirectory', () => {
- const host = createFakeGoogle3Host({
- isJsTranspilation: true,
- transpiledJsInputDirectory: 'foo/bar/jsinputdir',
- transpiledJsOutputDirectory: 'foo/bar/jsoutputdir',
- });
- host.writeFile(
- 'foo/bar/jsinputdir/a/b.js', 'some.code();', false, undefined,
- []);
- expect(Object.keys(writtenFiles)).toEqual([
- '/root/google3/blaze-out/k8-fastbuild/bin/foo/bar/jsoutputdir/a/b.js'
- ]);
- });
- });
- });
- });
-});
diff --git a/packages/concatjs/internal/tsc_wrapped/tsconfig.json.oss b/packages/concatjs/internal/tsc_wrapped/tsconfig.json.oss
deleted file mode 100644
index 8c22290..0000000
--- a/packages/concatjs/internal/tsc_wrapped/tsconfig.json.oss
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "compilerOptions": {
- "strict": true,
- "types": [
- // Normally "node" should be listed here since we depend on it.
- // However this library is built with vanilla tsc.
- // Since the deps[] are passed into the ts.Program as files
- // (starting with https://github.com/bazelbuild/rules_nodejs/pull/756)
- // we cannot also list node as a types[] since vanilla tsc will load
- // both into the program and get a conflict.
- // Under tsc_wrapped this isn't a problem since we control the resolution.
- ],
- "lib": [
- "dom",
- "es5",
- "es2015.core",
- "es2015.collection",
- "es2015.iterable",
- "es2015.promise",
- // This will need to become es2018.asynciterable when
- // bumping the version of TypeScript in rules_typescript/package.json
- "esnext.asynciterable"
- ]
- }
-}
diff --git a/packages/concatjs/internal/tsc_wrapped/tsconfig.ts b/packages/concatjs/internal/tsc_wrapped/tsconfig.ts
deleted file mode 100644
index ca21ce3..0000000
--- a/packages/concatjs/internal/tsc_wrapped/tsconfig.ts
+++ /dev/null
@@ -1,417 +0,0 @@
-/**
- * @license
- * Copyright 2017 The Bazel Authors. All rights reserved.
- *
- * 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.
- */
-
-import * as path from 'path';
-import * as ts from 'typescript';
-
-
-/**
- * The configuration block provided by the tsconfig "bazelOptions".
- * Note that all paths here are relative to the rootDir, not absolute nor
- * relative to the location containing the tsconfig file.
- */
-export interface BazelOptions {
- /** Name of the bazel workspace where we are building. */
- workspaceName: string;
-
- /** The full bazel target that is being built, e.g. //my/pkg:library. */
- target: string;
-
- /** The bazel package, eg my/pkg */
- package: string;
-
- /** If true, convert require()s into goog.module(). */
- googmodule: boolean;
-
- /**
- * DEPRECATED. being replaced by devmode.
- * If true, emit devmode output into filename.js.
- * If false, emit prodmode output into filename.mjs.
- */
- es5Mode: boolean;
-
- /**
- * If true, emit devmode output into filename.js.
- * If false, emit prodmode output into filename.mjs.
- */
- devmode: boolean;
-
- /** If true, convert TypeScript code into a Closure-compatible variant. */
- tsickle: boolean;
-
- /** If true, generate externs from declarations in d.ts files. */
- tsickleGenerateExterns: boolean;
-
- /** Write generated externs to the given path. */
- tsickleExternsPath: string;
-
- /** Paths of declarations whose types must not appear in result .d.ts. */
- typeBlackListPaths: string[];
-
- /** If true, emit Closure types in TypeScript->JS output. */
- untyped: boolean;
-
- /** The list of sources we're interested in (emitting and type checking). */
- compilationTargetSrc: string[];
-
- /** Path to write the module dependency manifest to. */
- manifest: string;
-
- /**
- * Whether to disable strict deps check. If true the next parameter is
- * ignored.
- */
- disableStrictDeps?: boolean;
-
- /**
- * Paths of dependencies that are allowed by strict deps, i.e. that may be
- * imported by the source files in compilationTargetSrc.
- */
- allowedStrictDeps: string[];
-
- /** Write a performance trace to this path. Disabled when falsy. */
- perfTracePath?: string;
-
- /**
- * An additional prelude to insert after the `goog.module` call,
- * e.g. with additional imports or requires.
- */
- prelude: string;
-
- /**
- * Name of the current locale if processing a locale-specific file.
- */
- locale?: string;
-
- /**
- * A list of errors this compilation is expected to generate, in the form
- * "TS1234:regexp". If empty, compilation is expected to succeed.
- */
- expectedDiagnostics: string[];
-
- /**
- * To support node_module resolution, allow TypeScript to make arbitrary
- * file system access to paths under this prefix.
- */
- nodeModulesPrefix: string;
-
- /**
- * List of regexes on file paths for which we suppress tsickle's warnings.
- */
- ignoreWarningPaths: string[];
-
- /**
- * Whether to add aliases to the .d.ts files to add the exports to the
- * ಠ_ಠ.clutz namespace.
- */
- addDtsClutzAliases: true;
-
- /**
- * Whether to type check inputs that aren't srcs. Differs from
- * --skipLibCheck, which skips all .d.ts files, even those which are
- * srcs.
- */
- typeCheckDependencies: boolean;
-
- /**
- * The maximum cache size for bazel outputs, in megabytes.
- */
- maxCacheSizeMb?: number;
-
- /**
- * Suppress warnings about tsconfig.json properties that are overridden.
- * Currently unused, remains here for backwards compat for users who set it.
- */
- suppressTsconfigOverrideWarnings: boolean;
-
- /**
- * An explicit name for this module, given by the module_name attribute on a
- * ts_library.
- */
- moduleName?: string;
-
- /**
- * An explicit entry point for this module, given by the module_root attribute
- * on a ts_library.
- */
- moduleRoot?: string;
-
- /**
- * If true, indicates that this job is transpiling JS sources. If true, only
- * one file can appear in compilationTargetSrc, and either
- * transpiledJsOutputFileName or the transpiledJs*Directory options must be
- * set.
- */
- isJsTranspilation?: boolean;
-
- /**
- * The path where the file containing the JS transpiled output should be
- * written. Ignored if isJsTranspilation is false. transpiledJsOutputFileName
- *
- */
- transpiledJsOutputFileName?: string;
-
- /**
- * The path where transpiled JS output should be written. Ignored if
- * isJsTranspilation is false. Must not be set together with
- * transpiledJsOutputFileName.
- */
- transpiledJsInputDirectory?: string;
-
- /**
- * The path where transpiled JS output should be written. Ignored if
- * isJsTranspilation is false. Must not be set together with
- * transpiledJsOutputFileName.
- */
- transpiledJsOutputDirectory?: string;
-
- /**
- * Whether the user provided an implementation shim for .d.ts files in the
- * compilation unit.
- */
- hasImplementation?: boolean;
-
- /**
- * If present, run the Angular ngtsc plugin with the given options.
- */
- angularCompilerOptions?: {
- [k: string]: any,
- assets: string[],
- // Ideally we would
- // import {AngularCompilerOptions} from '@angular/compiler-cli';
- // and the type would be AngularCompilerOptions&{assets: string[]};
- // but we don't want a dependency from @bazel/typescript to @angular/compiler-cli
- // as it's conceptually cyclical.
- };
-
- /**
- * Override for ECMAScript target language level to use for devmode.
- *
- * This setting can be set in a user's tsconfig to override the default
- * devmode target.
- *
- * EXPERIMENTAL: This setting is experimental and may be removed in the
- * future.
- */
- devmodeTargetOverride?: string;
-
- /**
- * Whether to type check. Differs from typeCheckDependencies in that this
- * avoids type checking the srcs in addition to the dependencies.
- */
- typeCheck: boolean;
-}
-
-export interface ParsedTsConfig {
- options: ts.CompilerOptions;
- bazelOpts: BazelOptions;
- angularCompilerOptions?: {[k: string]: unknown};
- files: string[];
- disabledTsetseRules: string[];
- config: {};
-}
-
-// TODO(calebegg): Upstream?
-interface PluginImportWithConfig extends ts.PluginImport {
- [optionName: string]: string|{};
-}
-
-/**
- * The same as Node's path.resolve, however it returns a path with forward
- * slashes rather than joining the resolved path with the platform's path
- * separator.
- * Note that even path.posix.resolve('.') returns C:\Users\... with backslashes.
- */
-export function resolveNormalizedPath(...segments: string[]): string {
- return path.resolve(...segments).replace(/\\/g, '/');
-}
-
-/**
- * Load a tsconfig.json and convert all referenced paths (including
- * bazelOptions) to absolute paths.
- * Paths seen by TypeScript should be absolute, to match behavior
- * of the tsc ModuleResolution implementation.
- * @param tsconfigFile path to tsconfig, relative to process.cwd() or absolute
- * @return configuration parsed from the file, or error diagnostics
- */
-export function parseTsconfig(
- tsconfigFile: string, host: ts.ParseConfigHost = ts.sys):
- [ParsedTsConfig|null, ts.Diagnostic[]|null, {target: string}] {
- // TypeScript expects an absolute path for the tsconfig.json file
- tsconfigFile = resolveNormalizedPath(tsconfigFile);
-
- const isUndefined = (value: any): value is undefined => value === undefined;
-
- // Handle bazel specific options, but make sure not to crash when reading a
- // vanilla tsconfig.json.
-
- const readExtendedConfigFile =
- (configFile: string, existingConfig?: any): {config?: any, error?: ts.Diagnostic} => {
- const {config, error} = ts.readConfigFile(configFile, host.readFile);
-
- if (error) {
- return {error};
- }
-
- // Allow Bazel users to control some of the bazel options.
- // Since TypeScript's "extends" mechanism applies only to "compilerOptions"
- // we have to repeat some of their logic to get the user's bazelOptions.
- const mergedConfig = existingConfig || config;
-
- if (existingConfig) {
- const existingBazelOpts: BazelOptions = existingConfig.bazelOptions || {};
- const newBazelBazelOpts: BazelOptions = config.bazelOptions || {};
-
- mergedConfig.bazelOptions = {
- ...existingBazelOpts,
-
- disableStrictDeps: isUndefined(existingBazelOpts.disableStrictDeps)
- ? newBazelBazelOpts.disableStrictDeps
- : existingBazelOpts.disableStrictDeps,
-
- suppressTsconfigOverrideWarnings: isUndefined(existingBazelOpts.suppressTsconfigOverrideWarnings)
- ? newBazelBazelOpts.suppressTsconfigOverrideWarnings
- : existingBazelOpts.suppressTsconfigOverrideWarnings,
-
- tsickle: isUndefined(existingBazelOpts.tsickle)
- ? newBazelBazelOpts.tsickle
- : existingBazelOpts.tsickle,
-
- googmodule: isUndefined(existingBazelOpts.googmodule)
- ? newBazelBazelOpts.googmodule
- : existingBazelOpts.googmodule,
-
- devmodeTargetOverride: isUndefined(existingBazelOpts.devmodeTargetOverride)
- ? newBazelBazelOpts.devmodeTargetOverride
- : existingBazelOpts.devmodeTargetOverride,
- }
- }
-
- if (config.extends) {
- let extendedConfigPath = resolveNormalizedPath(path.dirname(configFile), config.extends);
- if (!extendedConfigPath.endsWith('.json')) extendedConfigPath += '.json';
-
- return readExtendedConfigFile(extendedConfigPath, mergedConfig);
- }
-
- return {config: mergedConfig};
- };
-
- const {config, error} = readExtendedConfigFile(tsconfigFile);
- if (error) {
- // target is in the config file we failed to load...
- return [null, [error], {target: ''}];
- }
-
- const {options, errors, fileNames} =
- ts.parseJsonConfigFileContent(config, host, path.dirname(tsconfigFile));
-
- // Handle bazel specific options, but make sure not to crash when reading a
- // vanilla tsconfig.json.
- const bazelOpts: BazelOptions = config.bazelOptions || {};
- const target = bazelOpts.target;
- bazelOpts.allowedStrictDeps = bazelOpts.allowedStrictDeps || [];
- bazelOpts.typeBlackListPaths = bazelOpts.typeBlackListPaths || [];
- bazelOpts.compilationTargetSrc = bazelOpts.compilationTargetSrc || [];
-
-
- if (errors && errors.length) {
- return [null, errors, {target}];
- }
-
- // Override the devmode target if devmodeTargetOverride is set
- if (bazelOpts.es5Mode && bazelOpts.devmodeTargetOverride) {
- switch (bazelOpts.devmodeTargetOverride.toLowerCase()) {
- case 'es3':
- options.target = ts.ScriptTarget.ES3;
- break;
- case 'es5':
- options.target = ts.ScriptTarget.ES5;
- break;
- case 'es2015':
- options.target = ts.ScriptTarget.ES2015;
- break;
- case 'es2016':
- options.target = ts.ScriptTarget.ES2016;
- break;
- case 'es2017':
- options.target = ts.ScriptTarget.ES2017;
- break;
- case 'es2018':
- options.target = ts.ScriptTarget.ES2018;
- break;
- case 'esnext':
- options.target = ts.ScriptTarget.ESNext;
- break;
- default:
- console.error(
- 'WARNING: your tsconfig.json file specifies an invalid bazelOptions.devmodeTargetOverride value of: \'${bazelOpts.devmodeTargetOverride\'');
- }
- }
-
- // Sort rootDirs with longest include directories first.
- // When canonicalizing paths, we always want to strip
- // `workspace/bazel-bin/file` to just `file`, not to `bazel-bin/file`.
- if (options.rootDirs) options.rootDirs.sort((a, b) => b.length - a.length);
-
- // If the user requested goog.module, we need to produce that output even if
- // the generated tsconfig indicates otherwise.
- if (bazelOpts.googmodule) options.module = ts.ModuleKind.CommonJS;
-
- // TypeScript's parseJsonConfigFileContent returns paths that are joined, eg.
- // /path/to/project/bazel-out/arch/bin/path/to/package/../../../../../../path
- // We normalize them to remove the intermediate parent directories.
- // This improves error messages and also matches logic in tsc_wrapped where we
- // expect normalized paths.
- const files = fileNames.map(f => path.posix.normalize(f));
-
- // The bazelOpts paths in the tsconfig are relative to
- // options.rootDir (the workspace root) and aren't transformed by
- // parseJsonConfigFileContent (because TypeScript doesn't know
- // about them). Transform them to also be absolute here.
- bazelOpts.compilationTargetSrc = bazelOpts.compilationTargetSrc.map(
- f => resolveNormalizedPath(options.rootDir!, f));
- bazelOpts.allowedStrictDeps = bazelOpts.allowedStrictDeps.map(
- f => resolveNormalizedPath(options.rootDir!, f));
- bazelOpts.typeBlackListPaths = bazelOpts.typeBlackListPaths.map(
- f => resolveNormalizedPath(options.rootDir!, f));
- if (bazelOpts.nodeModulesPrefix) {
- bazelOpts.nodeModulesPrefix =
- resolveNormalizedPath(options.rootDir!, bazelOpts.nodeModulesPrefix);
- }
- if (bazelOpts.angularCompilerOptions && bazelOpts.angularCompilerOptions.assets) {
- bazelOpts.angularCompilerOptions.assets = bazelOpts.angularCompilerOptions.assets.map(
- f => resolveNormalizedPath(options.rootDir!, f));
- }
-
- let disabledTsetseRules: string[] = [];
- for (const pluginConfig of options['plugins'] as PluginImportWithConfig[] ||
- []) {
- if (pluginConfig.name && pluginConfig.name === '@bazel/tsetse') {
- const disabledRules = pluginConfig['disabledRules'];
- if (disabledRules && !Array.isArray(disabledRules)) {
- throw new Error('Disabled tsetse rules must be an array of rule names');
- }
- disabledTsetseRules = disabledRules as string[];
- break;
- }
- }
-
- return [
- {options, bazelOpts, files, config, disabledTsetseRules}, null, {target}
- ];
-}
diff --git a/packages/concatjs/internal/tsc_wrapped/tsconfig_test.ts b/packages/concatjs/internal/tsc_wrapped/tsconfig_test.ts
deleted file mode 100644
index eac3ffe..0000000
--- a/packages/concatjs/internal/tsc_wrapped/tsconfig_test.ts
+++ /dev/null
@@ -1,116 +0,0 @@
-/**
- * @license
- * Copyright 2017 The Bazel Authors. All rights reserved.
- *
- * 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.
- */
-
-import * as ts from 'typescript';
-
-import {parseTsconfig, resolveNormalizedPath} from './tsconfig';
-
-describe('tsconfig', () => {
- it('honors bazelOptions in the users tsconfig', () => {
- const userTsconfig = {
- bazelOptions: {disableStrictDeps: true},
- };
- const generatedTsconfig = {
- extends: './user.tsconfig',
- files: ['a.ts'],
- bazelOptions: {},
- };
- const files = {
- [resolveNormalizedPath('path/to/user.tsconfig.json')]:
- '/*some comment*/\n' + JSON.stringify(userTsconfig),
- [resolveNormalizedPath('path/to/generated.tsconfig.json')]:
- JSON.stringify(generatedTsconfig),
- };
- const host: ts.ParseConfigHost = {
- useCaseSensitiveFileNames: true,
- fileExists: (path: string) => !!files[path],
- readFile: (path: string) => files[path],
- readDirectory(
- rootDir: string, extensions: ReadonlyArray<string>,
- excludes: ReadonlyArray<string>, includes: ReadonlyArray<string>,
- depth: number): string[] {
- throw new Error(`unexpected readDirectory of ${rootDir}`);
- },
- };
-
- const [parsed, diagnostics, {target}] =
- parseTsconfig('path/to/generated.tsconfig.json', host);
- expect(diagnostics).toBeNull();
- if (!parsed) {
- fail('Expected parsed');
- } else {
- const {options, bazelOpts, files, config} = parsed;
- expect(bazelOpts.disableStrictDeps).toBeTruthy();
- }
- });
-
- it('honors bazelOptions in recursive extends', ()=> {
- const tsconfigOne = {
- extends: './tsconfig-level-b.json',
- files: ['a.ts'],
- bazelOptions: {
- disableStrictDeps: false
- }
- };
-
- const tsconfigTwo = {
- extends: './tsconfig-level-c.json',
- bazelOptions: {
- suppressTsconfigOverrideWarnings: true
- }
- };
-
- const tsconfigThree = {
- bazelOptions: {
- tsickle: true,
- suppressTsconfigOverrideWarnings: false,
- disableStrictDeps: true
- }
- };
-
- const files = {
- [resolveNormalizedPath('path/to/tsconfig-level-a.json')]: JSON.stringify(tsconfigOne),
- [resolveNormalizedPath('path/to/tsconfig-level-b.json')]: JSON.stringify(tsconfigTwo),
- [resolveNormalizedPath('path/to/tsconfig-level-c.json')]: JSON.stringify(tsconfigThree),
- };
-
- const host: ts.ParseConfigHost = {
- useCaseSensitiveFileNames: true,
- fileExists: (path: string) => !!files[path],
- readFile: (path: string) => files[path],
- readDirectory(
- rootDir: string, extensions: ReadonlyArray<string>,
- excludes: ReadonlyArray<string>, includes: ReadonlyArray<string>,
- depth: number): string[] {
- return [];
- },
- };
-
- const [parsed, diagnostics] =
- parseTsconfig('path/to/tsconfig-level-a.json', host);
- expect(diagnostics).toBeNull();
-
- if (!parsed) {
- fail('Expected parsed');
- } else {
- const {bazelOpts} = parsed;
- expect(bazelOpts.tsickle).toBeTruthy();
- expect(bazelOpts.suppressTsconfigOverrideWarnings).toBeTruthy();
- expect(bazelOpts.disableStrictDeps).toBeFalsy();
- }
- })
-});
diff --git a/packages/concatjs/internal/tsc_wrapped/worker.ts b/packages/concatjs/internal/tsc_wrapped/worker.ts
deleted file mode 100644
index 3640937..0000000
--- a/packages/concatjs/internal/tsc_wrapped/worker.ts
+++ /dev/null
@@ -1,210 +0,0 @@
-import * as path from 'path';
-import * as protobufjs from 'protobufjs';
-
-// Equivalent of running node with --expose-gc
-// but easier to write tooling since we don't need to inject that arg to
-// nodejs_binary
-if (typeof global.gc !== 'function') {
- // tslint:disable-next-line:no-require-imports
- require('v8').setFlagsFromString('--expose_gc');
- // tslint:disable-next-line:no-require-imports
- global.gc = require('vm').runInNewContext('gc');
-}
-
-/**
- * Whether to print debug messages (to console.error) from the debug function
- * below.
- */
-export const DEBUG = false;
-
-/** Maybe print a debug message (depending on a flag defaulting to false). */
-export function debug(...args: Array<unknown>) {
- if (DEBUG) console.error.call(console, ...args);
-}
-
-/**
- * Write a message to stderr, which appears in the bazel log and is visible to
- * the end user.
- */
-export function log(...args: Array<unknown>) {
- console.error.call(console, ...args);
-}
-
-/**
- * runAsWorker returns true if the given arguments indicate the process should
- * run as a persistent worker.
- */
-export function runAsWorker(args: string[]) {
- return args.indexOf('--persistent_worker') !== -1;
-}
-
-/**
- * workerProto declares the static type of the object constructed at runtime by
- * protobufjs, based on reading the protocol buffer definition.
- */
-declare namespace workerProto {
- /** Input represents the blaze.worker.Input message. */
- interface Input extends protobufjs.Message<Input> {
- path: string;
- /**
- * In Node, digest is a Buffer. In the browser, it's a replacement
- * implementation. We only care about its toString(encoding) method.
- */
- digest: {toString(encoding: string): string};
- }
-
- /** WorkRequest repesents the blaze.worker.WorkRequest message. */
- interface WorkRequest extends protobufjs.Message<WorkRequest> {
- arguments: string[];
- inputs: Input[];
- }
-
- // tslint:disable:variable-name reflected, constructable types.
- const WorkRequest: protobufjs.Type;
- const WorkResponse: protobufjs.Type;
- // tslint:enable:variable-name
-}
-
-/**
- * loadWorkerPb finds and loads the protocol buffer definition for bazel's
- * worker protocol using protobufjs. In protobufjs, this means it's a reflection
- * object that also contains properties for the individual messages.
- */
-function loadWorkerPb() {
- const protoPath =
- '../../third_party/github.com/bazelbuild/bazel/src/main/protobuf/worker_protocol.proto';
-
- // Use node module resolution so we can find the .proto file in any of the
- // root dirs
- let protofile;
- try {
- // Look for the .proto file relative in its @bazel/typescript npm package
- // location
- protofile = require.resolve(protoPath);
- } catch (e) {
- }
- if (!protofile) {
- // If not found above, look for the .proto file in its rules_typescript
- // workspace location
- // This extra lookup should never happen in google3. It's only needed for
- // local development in the rules_typescript repo.
- const runfiles = process.env['BAZEL_NODE_RUNFILES_HELPER'];
- if (runfiles) {
- protofile = require(runfiles).resolve(
- 'build_bazel_rules_nodejs/packages/concatjs/third_party/github.com/bazelbuild/bazel/src/main/protobuf/worker_protocol.proto');
- }
- if (!protofile) {
- throw new Error(
- `cannot find worker_protocol.proto at ${protoPath} or in Runfiles`);
- }
- }
-
- const protoNamespace = protobufjs.loadSync(protofile);
- if (!protoNamespace) {
- throw new Error('Cannot find ' + path.resolve(protoPath));
- }
- const workerpb = protoNamespace.lookup('blaze.worker');
- if (!workerpb) {
- throw new Error(`Cannot find namespace blaze.worker`);
- }
- return workerpb as protobufjs.ReflectionObject & typeof workerProto;
-}
-
-/**
- * workerpb contains the runtime representation of the worker protocol buffer,
- * including accessor for the defined messages.
- */
-const workerpb = loadWorkerPb();
-
-/**
- * runWorkerLoop handles the interacton between bazel workers and the
- * TypeScript compiler. It reads compilation requests from stdin, unmarshals the
- * data, and dispatches into `runOneBuild` for the actual compilation to happen.
- *
- * The compilation handler is parameterized so that this code can be used by
- * different compiler entry points (currently TypeScript compilation, Angular
- * compilation, and the contrib vulcanize worker).
- *
- * It's also exposed publicly as an npm package:
- * https://www.npmjs.com/package/@bazel/worker
- */
-export async function runWorkerLoop(
- runOneBuild: (args: string[], inputs?: {[path: string]: string}) =>
- boolean | Promise<boolean>) {
- // Hook all output to stderr and write it to a buffer, then include
- // that buffer's in the worker protcol proto's textual output. This
- // means you can log via console.error() and it will appear to the
- // user as expected.
- let consoleOutput = '';
- process.stderr.write =
- (chunk: string|Buffer, ...otherArgs: Array<unknown>): boolean => {
- consoleOutput += chunk.toString();
- return true;
- };
-
- // Accumulator for asynchronously read input.
- // protobufjs uses node's Buffer, but has its own reader abstraction on top of
- // it (for browser compatiblity). It ignores Buffer's builtin start and
- // offset, which means the handling code below cannot use Buffer in a
- // meaningful way (such as cycling data through it). The handler below reads
- // any data available on stdin, concatenating it into this buffer. It then
- // attempts to read a delimited Message from it. If a message is incomplete,
- // it exits and waits for more input. If a message has been read, it strips
- // its data of this buffer.
- let buf: Buffer = Buffer.alloc(0);
- stdinLoop: for await (const chunk of process.stdin) {
- buf = Buffer.concat([buf, chunk as Buffer]);
- try {
- const reader = new protobufjs.Reader(buf);
- // Read all requests that have accumulated in the buffer.
- while (reader.len - reader.pos > 0) {
- const messageStart = reader.len;
- const msgLength: number = reader.uint32();
- // chunk might be an incomplete read from stdin. If there are not enough
- // bytes for the next full message, wait for more input.
- if ((reader.len - reader.pos) < msgLength) continue stdinLoop;
-
- const req = workerpb.WorkRequest.decode(reader, msgLength) as
- workerProto.WorkRequest;
- // Once a message has been read, remove it from buf so that if we pause
- // to read more input, this message will not be processed again.
- buf = buf.slice(messageStart);
- debug('=== Handling new build request');
- const args = req.arguments;
- const inputs: {[path: string]: string} = {};
- for (const input of req.inputs) {
- inputs[input.path] = input.digest.toString('hex');
- }
- debug('Compiling with:\n\t' + args.join('\n\t'));
- process.stdout.write(
- workerpb.WorkResponse.encodeDelimited({
- exitCode: await runOneBuild(args, inputs) ? 0 : 1,
- output: consoleOutput,
- }).finish() as Buffer
- );
- // Reset accumulated log output now that it has been printed.
- consoleOutput = '';
- // Force a garbage collection pass. This keeps our memory usage
- // consistent across multiple compilations, and allows the file
- // cache to use the current memory usage as a guideline for expiring
- // data. Note: this is intentionally not within runOneBuild(), as
- // we want to gc only after all its locals have gone out of scope.
- global.gc!();
- }
- // All messages have been handled, make sure the invariant holds and
- // Buffer is empty once all messages have been read.
- if (buf.length > 0) {
- throw new Error('buffer not empty after reading all messages');
- }
- } catch (e) {
- log('Compilation failed', e.stack);
- process.stdout.write(
- workerpb.WorkResponse
- .encodeDelimited({exitCode: 1, output: consoleOutput})
- .finish() as Buffer
- );
- // Clear buffer so the next build won't read an incomplete request.
- buf = Buffer.alloc(0);
- }
- }
-}
diff --git a/packages/concatjs/internal/tsc_wrapped/yarn.lock b/packages/concatjs/internal/tsc_wrapped/yarn.lock
deleted file mode 100644
index de1c0b0..0000000
--- a/packages/concatjs/internal/tsc_wrapped/yarn.lock
+++ /dev/null
@@ -1,311 +0,0 @@
-# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
-# yarn lockfile v1
-
-
-"@types/jasmine@2.8.2":
- version "2.8.2"
- resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-2.8.2.tgz#6ae4d8740c0da5d5a627df725b4eed71b8e36668"
- integrity sha512-RabEJPjYMpjWqW1qYj4k0rlgP5uzyguoc0yxedJdq7t5h19MYvqhjCR1evM3raZ/peHRxp1Qfl24iawvkibSug==
-
-"@types/node@7.0.18":
- version "7.0.18"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.18.tgz#cd67f27d3dc0cfb746f0bdd5e086c4c5d55be173"
- integrity sha1-zWfyfT3Az7dG8L3V4IbExdVb4XM=
-
-"@types/tmp@0.0.33":
- version "0.0.33"
- resolved "https://registry.yarnpkg.com/@types/tmp/-/tmp-0.0.33.tgz#1073c4bc824754ae3d10cfab88ab0237ba964e4d"
- integrity sha1-EHPEvIJHVK49EM+riKsCN7qWTk0=
-
-ansi-regex@^2.0.0:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
- integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8=
-
-ascli@~1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/ascli/-/ascli-1.0.1.tgz#bcfa5974a62f18e81cabaeb49732ab4a88f906bc"
- integrity sha1-vPpZdKYvGOgcq660lzKrSoj5Brw=
- dependencies:
- colour "~0.7.1"
- optjs "~3.2.2"
-
-balanced-match@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
- integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
-
-brace-expansion@^1.1.7:
- version "1.1.11"
- resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
- integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
- dependencies:
- balanced-match "^1.0.0"
- concat-map "0.0.1"
-
-buffer-from@^1.0.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
- integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
-
-bytebuffer@~5:
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/bytebuffer/-/bytebuffer-5.0.1.tgz#582eea4b1a873b6d020a48d58df85f0bba6cfddd"
- integrity sha1-WC7qSxqHO20CCkjVjfhfC7ps/d0=
- dependencies:
- long "~3"
-
-camelcase@^2.0.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f"
- integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=
-
-cliui@^3.0.3:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d"
- integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=
- dependencies:
- string-width "^1.0.1"
- strip-ansi "^3.0.1"
- wrap-ansi "^2.0.0"
-
-code-point-at@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
- integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
-
-colour@~0.7.1:
- version "0.7.1"
- resolved "https://registry.yarnpkg.com/colour/-/colour-0.7.1.tgz#9cb169917ec5d12c0736d3e8685746df1cadf778"
- integrity sha1-nLFpkX7F0SwHNtPoaFdG3xyt93g=
-
-concat-map@0.0.1:
- version "0.0.1"
- resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
- integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
-
-decamelize@^1.1.1:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
- integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
-
-fs.realpath@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
- integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
-
-glob@^7.0.5:
- version "7.1.3"
- resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1"
- integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==
- dependencies:
- fs.realpath "^1.0.0"
- inflight "^1.0.4"
- inherits "2"
- minimatch "^3.0.4"
- once "^1.3.0"
- path-is-absolute "^1.0.0"
-
-inflight@^1.0.4:
- version "1.0.6"
- resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
- integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
- dependencies:
- once "^1.3.0"
- wrappy "1"
-
-inherits@2:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
- integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
-
-invert-kv@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
- integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY=
-
-is-fullwidth-code-point@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
- integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs=
- dependencies:
- number-is-nan "^1.0.0"
-
-lcid@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
- integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=
- dependencies:
- invert-kv "^1.0.0"
-
-long@~3:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/long/-/long-3.2.0.tgz#d821b7138ca1cb581c172990ef14db200b5c474b"
- integrity sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=
-
-minimatch@^3.0.4:
- version "3.0.4"
- resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
- integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
- dependencies:
- brace-expansion "^1.1.7"
-
-minimist@0.0.8:
- version "0.0.8"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
- integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
-
-minimist@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
- integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
-
-mkdirp@^0.5.1:
- version "0.5.1"
- resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
- integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=
- dependencies:
- minimist "0.0.8"
-
-number-is-nan@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
- integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
-
-once@^1.3.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
- integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
- dependencies:
- wrappy "1"
-
-optjs@~3.2.2:
- version "3.2.2"
- resolved "https://registry.yarnpkg.com/optjs/-/optjs-3.2.2.tgz#69a6ce89c442a44403141ad2f9b370bd5bb6f4ee"
- integrity sha1-aabOicRCpEQDFBrS+bNwvVu29O4=
-
-os-locale@^1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9"
- integrity sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=
- dependencies:
- lcid "^1.0.0"
-
-os-tmpdir@~1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
- integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
-
-path-is-absolute@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
- integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
-
-protobufjs@5.0.3:
- version "5.0.3"
- resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-5.0.3.tgz#e4dfe9fb67c90b2630d15868249bcc4961467a17"
- integrity sha512-55Kcx1MhPZX0zTbVosMQEO5R6/rikNXd9b6RQK4KSPcrSIIwoXTtebIczUrXlwaSrbz4x8XUVThGPob1n8I4QA==
- dependencies:
- ascli "~1"
- bytebuffer "~5"
- glob "^7.0.5"
- yargs "^3.10.0"
-
-source-map-support@^0.5.0:
- version "0.5.10"
- resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.10.tgz#2214080bc9d51832511ee2bab96e3c2f9353120c"
- integrity sha512-YfQ3tQFTK/yzlGJuX8pTwa4tifQj4QS2Mj7UegOu8jAz59MqIiMGPXxQhVQiIMNzayuUSF/jEuVnfFF5JqybmQ==
- dependencies:
- buffer-from "^1.0.0"
- source-map "^0.6.0"
-
-source-map@^0.6.0:
- version "0.6.1"
- resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
- integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
-
-string-width@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
- integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=
- dependencies:
- code-point-at "^1.0.0"
- is-fullwidth-code-point "^1.0.0"
- strip-ansi "^3.0.0"
-
-strip-ansi@^3.0.0, strip-ansi@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
- integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=
- dependencies:
- ansi-regex "^2.0.0"
-
-tmp@0.0.33:
- version "0.0.33"
- resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
- integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==
- dependencies:
- os-tmpdir "~1.0.2"
-
-tsickle@0.28.0:
- version "0.28.0"
- resolved "https://registry.yarnpkg.com/tsickle/-/tsickle-0.28.0.tgz#6cd6fa004766c6ad9261b599c83866ee97cc7875"
- integrity sha512-cb/Z4NlKMPGiIIbgmklfBJIxDl4EQoYqC+0/BnPxZWzWcUvikeOHFkkkEmabJVqKh47jUqOwU/uMAu6UvhicZg==
- dependencies:
- minimist "^1.2.0"
- mkdirp "^0.5.1"
- source-map "^0.6.0"
- source-map-support "^0.5.0"
-
-tslib@^1.8.1:
- version "1.9.3"
- resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286"
- integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==
-
-tsutils@2.27.2:
- version "2.27.2"
- resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.27.2.tgz#60ba88a23d6f785ec4b89c6e8179cac9b431f1c7"
- integrity sha512-qf6rmT84TFMuxAKez2pIfR8UCai49iQsfB7YWVjV1bKpy/d0PWT5rEOSM6La9PiHZ0k1RRZQiwVdVJfQ3BPHgg==
- dependencies:
- tslib "^1.8.1"
-
-typescript@2.7.2:
- version "2.7.2"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.7.2.tgz#2d615a1ef4aee4f574425cdff7026edf81919836"
- integrity sha512-p5TCYZDAO0m4G344hD+wx/LATebLWZNkkh2asWUFqSsD2OrDNhbAHuSjobrmsUmdzjJjEeZVU9g1h3O6vpstnw==
-
-window-size@^0.1.4:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876"
- integrity sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY=
-
-wrap-ansi@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
- integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=
- dependencies:
- string-width "^1.0.1"
- strip-ansi "^3.0.1"
-
-wrappy@1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
- integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
-
-y18n@^3.2.0:
- version "3.2.1"
- resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
- integrity sha1-bRX7qITAhnnA136I53WegR4H+kE=
-
-yargs@^3.10.0:
- version "3.32.0"
- resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.32.0.tgz#03088e9ebf9e756b69751611d2a5ef591482c995"
- integrity sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU=
- dependencies:
- camelcase "^2.0.1"
- cliui "^3.0.3"
- decamelize "^1.1.1"
- os-locale "^1.4.0"
- string-width "^1.0.1"
- window-size "^0.1.4"
- y18n "^3.2.0"
diff --git a/packages/concatjs/internal/tsconfig.json b/packages/concatjs/internal/tsconfig.json
deleted file mode 100644
index f69878c..0000000
--- a/packages/concatjs/internal/tsconfig.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
- "compilerOptions": {
- "strict": true,
- "module": "CommonJS",
- "target": "ES2015",
- "types": [
- "node",
- ],
- "lib": [
- "dom",
- "es5",
- "es2015.core",
- "es2015.collection",
- "es2015.promise",
- // This will need to become es2018.asynciterable when
- // bumping the version of TypeScript in rules_typescript/package.json
- "es2018.asynciterable"
- ]
- },
- // We run the plain tsc compiler so we need to exclude files we don't want it to visit
- "exclude": [
- "**/test_support.ts",
- "**/*_test.ts",
- "*/tests"
- ]
-}
diff --git a/packages/concatjs/internal/tsetse/checker.ts b/packages/concatjs/internal/tsetse/checker.ts
deleted file mode 100644
index fcad3c7..0000000
--- a/packages/concatjs/internal/tsetse/checker.ts
+++ /dev/null
@@ -1,242 +0,0 @@
-/**
- * @fileoverview Checker contains all the information we need to perform source
- * file AST traversals and report errors.
- */
-
-import * as ts from 'typescript';
-import {Failure, Fix} from './failure';
-
-
-/**
- * A Handler contains a handler function and its corresponding error code so
- * when the handler function is triggered we know which rule is violated.
- */
-interface Handler<T extends ts.Node> {
- handlerFunction(checker: Checker, node: T): void;
- code: number;
-}
-
-/**
- * Tsetse rules use on() and addFailureAtNode() for rule implementations.
- * Rules can get a ts.TypeChecker from checker.typeChecker so typed rules are
- * possible. Compiler uses execute() to run the Tsetse check.
- */
-export class Checker {
- /** Node to handlers mapping for all enabled rules. */
- private readonly nodeHandlersMap =
- new Map<ts.SyntaxKind, Array<Handler<ts.Node>>>();
- /**
- * Mapping from identifier name to handlers for all rules inspecting property
- * names.
- */
- private readonly namedIdentifierHandlersMap =
- new Map<string, Array<Handler<ts.Identifier>>>();
- /**
- * Mapping from property name to handlers for all rules inspecting property
- * accesses expressions.
- */
- private readonly namedPropertyAccessHandlersMap =
- new Map<string, Array<Handler<ts.PropertyAccessExpression>>>();
- /**
- * Mapping from string literal value to handlers for all rules inspecting
- * string literals.
- */
- private readonly stringLiteralElementAccessHandlersMap =
- new Map<string, Array<Handler<ts.ElementAccessExpression>>>();
-
- private failures: Failure[] = [];
- private currentSourceFile: ts.SourceFile|undefined;
- // currentCode will be set before invoking any handler functions so the value
- // initialized here is never used.
- private currentCode = 0;
- /** Allow typed rules via typeChecker. */
- typeChecker: ts.TypeChecker;
-
- constructor(program: ts.Program) {
- // Avoid the cost for each rule to create a new TypeChecker.
- this.typeChecker = program.getTypeChecker();
- }
-
- /**
- * This doesn't run any checks yet. Instead, it registers `handlerFunction` on
- * `nodeKind` node in `nodeHandlersMap` map. After all rules register their
- * handlers, the source file AST will be traversed.
- */
- on<T extends ts.Node>(
- nodeKind: T['kind'], handlerFunction: (checker: Checker, node: T) => void,
- code: number) {
- const newHandler: Handler<T> = {handlerFunction, code};
- const registeredHandlers = this.nodeHandlersMap.get(nodeKind);
- if (registeredHandlers === undefined) {
- this.nodeHandlersMap.set(nodeKind, [newHandler]);
- } else {
- registeredHandlers.push(newHandler);
- }
- }
-
- /**
- * Similar to `on`, but registers handlers on more specific node type, i.e.,
- * identifiers.
- */
- onNamedIdentifier(
- identifierName: string,
- handlerFunction: (checker: Checker, node: ts.Identifier) => void,
- code: number) {
- const newHandler: Handler<ts.Identifier> = {handlerFunction, code};
- const registeredHandlers =
- this.namedIdentifierHandlersMap.get(identifierName);
- if (registeredHandlers === undefined) {
- this.namedIdentifierHandlersMap.set(identifierName, [newHandler]);
- } else {
- registeredHandlers.push(newHandler);
- }
- }
-
- /**
- * Similar to `on`, but registers handlers on more specific node type, i.e.,
- * property access expressions.
- */
- onNamedPropertyAccess(
- propertyName: string,
- handlerFunction:
- (checker: Checker, node: ts.PropertyAccessExpression) => void,
- code: number) {
- const newHandler:
- Handler<ts.PropertyAccessExpression> = {handlerFunction, code};
- const registeredHandlers =
- this.namedPropertyAccessHandlersMap.get(propertyName);
- if (registeredHandlers === undefined) {
- this.namedPropertyAccessHandlersMap.set(propertyName, [newHandler]);
- } else {
- registeredHandlers.push(newHandler);
- }
- }
-
- /**
- * Similar to `on`, but registers handlers on more specific node type, i.e.,
- * element access expressions with string literals as keys.
- */
- onStringLiteralElementAccess(
- key: string,
- handlerFunction:
- (checker: Checker, node: ts.ElementAccessExpression) => void,
- code: number) {
- const newHandler:
- Handler<ts.ElementAccessExpression> = {handlerFunction, code};
- const registeredHandlers =
- this.stringLiteralElementAccessHandlersMap.get(key);
- if (registeredHandlers === undefined) {
- this.stringLiteralElementAccessHandlersMap.set(key, [newHandler]);
- } else {
- registeredHandlers.push(newHandler);
- }
- }
-
- /**
- * Add a failure with a span.
- */
- addFailure(start: number, end: number, failureText: string, fix?: Fix) {
- if (!this.currentSourceFile) {
- throw new Error('Source file not defined');
- }
- if (start >= end || end > this.currentSourceFile.end || start < 0) {
- // Since only addFailureAtNode() is exposed for now this shouldn't happen.
- throw new Error(
- `Invalid start and end position: [${start}, ${end}]` +
- ` in file ${this.currentSourceFile.fileName}.`);
- }
-
- const failure = new Failure(
- this.currentSourceFile, start, end, failureText, this.currentCode, fix);
- this.failures.push(failure);
- }
-
- addFailureAtNode(node: ts.Node, failureText: string, fix?: Fix) {
- // node.getStart() takes a sourceFile as argument whereas node.getEnd()
- // doesn't need it.
- this.addFailure(
- node.getStart(this.currentSourceFile), node.getEnd(), failureText, fix);
- }
-
- /** Dispatch general handlers registered via `on` */
- dispatchNodeHandlers(node: ts.Node) {
- const handlers = this.nodeHandlersMap.get(node.kind);
- if (handlers === undefined) return;
-
- for (const handler of handlers) {
- this.currentCode = handler.code;
- handler.handlerFunction(this, node);
- }
- }
-
- /** Dispatch identifier handlers registered via `onNamedIdentifier` */
- dispatchNamedIdentifierHandlers(id: ts.Identifier) {
- const handlers = this.namedIdentifierHandlersMap.get(id.text);
- if (handlers === undefined) return;
-
- for (const handler of handlers) {
- this.currentCode = handler.code;
- handler.handlerFunction(this, id);
- }
- }
-
- /**
- * Dispatch property access handlers registered via `onNamedPropertyAccess`
- */
- dispatchNamedPropertyAccessHandlers(prop: ts.PropertyAccessExpression) {
- const handlers = this.namedPropertyAccessHandlersMap.get(prop.name.text);
- if (handlers === undefined) return;
-
- for (const handler of handlers) {
- this.currentCode = handler.code;
- handler.handlerFunction(this, prop);
- }
- }
-
- /**
- * Dispatch string literal handlers registered via
- * `onStringLiteralElementAccess`.
- */
- dispatchStringLiteralElementAccessHandlers(elem: ts.ElementAccessExpression) {
- const ty = this.typeChecker.getTypeAtLocation(elem.argumentExpression);
-
- if (!ty.isStringLiteral()) return;
-
- const handlers = this.stringLiteralElementAccessHandlersMap.get(ty.value);
- if (handlers === undefined) return;
-
- for (const handler of handlers) {
- this.currentCode = handler.code;
- handler.handlerFunction(this, elem);
- }
- }
-
- /**
- * Walk `sourceFile`, invoking registered handlers with Checker as the first
- * argument and current node as the second argument. Return failures if there
- * are any.
- */
- execute(sourceFile: ts.SourceFile): Failure[] {
- const thisChecker = this;
- this.currentSourceFile = sourceFile;
- this.failures = [];
- run(sourceFile);
- return this.failures;
-
- function run(node: ts.Node) {
- // Dispatch handlers registered via `on`
- thisChecker.dispatchNodeHandlers(node);
-
- // Dispatch handlers for named identifiers and properties
- if (ts.isIdentifier(node)) {
- thisChecker.dispatchNamedIdentifierHandlers(node);
- } else if (ts.isPropertyAccessExpression(node)) {
- thisChecker.dispatchNamedPropertyAccessHandlers(node);
- } else if (ts.isElementAccessExpression(node)) {
- thisChecker.dispatchStringLiteralElementAccessHandlers(node);
- }
-
- ts.forEachChild(node, run);
- }
- }
-}
diff --git a/packages/concatjs/internal/tsetse/error_code.ts b/packages/concatjs/internal/tsetse/error_code.ts
deleted file mode 100644
index 7b85b71..0000000
--- a/packages/concatjs/internal/tsetse/error_code.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Error codes for tsetse checks.
- *
- * Start with 21222 and increase linearly.
- * The intent is for these codes to be fixed, so that tsetse users can
- * search for them in user forums and other media.
- */
-export enum ErrorCode {
- CHECK_RETURN_VALUE = 21222,
- EQUALS_NAN = 21223,
- BAN_EXPECT_TRUTHY_PROMISE = 21224,
- MUST_USE_PROMISES = 21225,
- BAN_PROMISE_AS_CONDITION = 21226,
- PROPERTY_RENAMING_SAFE = 21227,
- CONFORMANCE_PATTERN = 21228,
- BAN_MUTABLE_EXPORTS = 21229,
- BAN_STRING_INITIALIZED_SETS = 21230,
- MUST_TYPE_ASSERT_JSON_PARSE = 21231,
-}
diff --git a/packages/concatjs/internal/tsetse/failure.ts b/packages/concatjs/internal/tsetse/failure.ts
deleted file mode 100644
index 02ccd48..0000000
--- a/packages/concatjs/internal/tsetse/failure.ts
+++ /dev/null
@@ -1,167 +0,0 @@
-import * as ts from 'typescript';
-
-/**
- * A Tsetse check Failure is almost identical to a Diagnostic from TypeScript
- * except that:
- * (1) The error code is defined by each individual Tsetse rule.
- * (2) The optional `source` property is set to `Tsetse` so the host (VS Code
- * for instance) would use that to indicate where the error comes from.
- * (3) There's an optional suggestedFix field.
- */
-export class Failure {
- constructor(
- private readonly sourceFile: ts.SourceFile,
- private readonly start: number, private readonly end: number,
- private readonly failureText: string, private readonly code: number,
- private readonly suggestedFix?: Fix) {}
-
- /**
- * This returns a structure compatible with ts.Diagnostic, but with added
- * fields, for convenience and to support suggested fixes.
- */
- toDiagnostic(): DiagnosticWithFix {
- return {
- file: this.sourceFile,
- start: this.start,
- end: this.end, // Not in ts.Diagnostic, but always useful for
- // start-end-using systems.
- length: this.end - this.start,
- messageText: this.failureText,
- category: ts.DiagnosticCategory.Error,
- code: this.code,
- // source is the name of the plugin.
- source: 'Tsetse',
- fix: this.suggestedFix
- };
- }
-
- /**
- * Same as toDiagnostic, but include the fix in the message, so that systems
- * that don't support displaying suggested fixes can still surface that
- * information. This assumes the diagnostic message is going to be presented
- * within the context of the problematic code
- */
- toDiagnosticWithStringifiedFix(): DiagnosticWithFix {
- const diagnostic = this.toDiagnostic();
- if (this.suggestedFix) {
- diagnostic.messageText += ' ' + this.fixToReadableStringInContext();
- }
- return diagnostic;
- }
-
- toString(): string {
- return `{ sourceFile:${
- this.sourceFile ? this.sourceFile.fileName : 'unknown'}, start:${
- this.start}, end:${this.end}, fix:${fixToString(this.suggestedFix)} }`;
- }
-
-
- /**
- * Stringifies a `Fix`, in a way that makes sense when presented alongside the
- * finding. This is a heuristic, obviously.
- */
- fixToReadableStringInContext() {
- if (!this.suggestedFix) return ''; // no changes, nothing to state.
- const f: Fix = this.suggestedFix;
- let fixText = '';
-
- for (const c of f.changes) {
- // Remove leading/trailing whitespace from the stringified suggestions:
- // since we add line breaks after each line of stringified suggestion, and
- // since users will manually apply the fix, there is no need to show
- // trailing whitespace. This is however just for stringification of the
- // fixes: the suggested fix itself still keeps trailing whitespace.
- const printableReplacement = c.replacement.trim();
-
- // Insertion.
- if (c.start === c.end) {
- // Try to see if that's an import.
- if (c.replacement.indexOf('import') !== -1) {
- fixText += `- Add new import: ${printableReplacement}\n`;
- } else {
- // Insertion that's not a full import. This should rarely happen in
- // our context, and we don't have a great message for these.
- // For instance, this could be the addition of a new symbol in an
- // existing import (`import {foo}` becoming `import {foo, bar}`).
- fixText += `- Insert ${this.readableRange(c.start, c.end)}: ${
- printableReplacement}\n`;
- }
- } else if (c.start === this.start && c.end === this.end) {
- // We assume the replacement is the main part of the fix, so put that
- // individual change first in `fixText`.
- fixText = `- Replace the full match with: ${printableReplacement}\n` +
- fixText;
- } else {
- // Fallback case: Use a numerical range to specify a replacement. In
- // general, falling through in this case should be avoided, as it's not
- // really readable without an IDE (the range can be outside of the
- // matched code).
- fixText = `- Replace ${this.readableRange(c.start, c.end)} with: ` +
- `${printableReplacement}\n${fixText}`;
- }
- }
-
- return 'Suggested fix:\n' + fixText.trim();
- }
-
- // TS indexes from 0 both ways, but tooling generally indexes from 1 for both
- // lines and columns. The translation is done here.
- readableRange(from: number, to: number) {
- const lcf = this.sourceFile.getLineAndCharacterOfPosition(from);
- const lct = this.sourceFile.getLineAndCharacterOfPosition(to);
- if (lcf.line === lct.line) {
- if (lcf.character === lct.character) {
- return `at line ${lcf.line + 1}, char ${lcf.character + 1}`;
- }
- return `line ${lcf.line + 1}, from char ${lcf.character + 1} to ${
- lct.character + 1}`;
- } else {
- return `from line ${lcf.line + 1}, char ${lcf.character + 1} to line ${
- lct.line + 1}, char ${lct.character + 1}`;
- }
- }
-}
-
-/**
- * A `Fix` is a potential repair to the associated `Failure`.
- */
-export interface Fix {
- /**
- * The individual text replacements composing that fix.
- */
- changes: IndividualChange[],
-}
-
-/**
- * An individual text replacement/insertion in a source file. Used as part of a
- * `Fix`.
- */
-export interface IndividualChange {
- sourceFile: ts.SourceFile, start: number, end: number, replacement: string
-}
-
-/**
- * A ts.Diagnostic that might include a `Fix`, and with an added `end` field for
- * convenience.
- */
-export interface DiagnosticWithFix extends ts.Diagnostic {
- end: number;
- fix?: Fix;
-}
-
-/**
- * Stringifies a `Fix`, replacing the `ts.SourceFile` with the matching
- * filename.
- */
-export function fixToString(f?: Fix) {
- if (!f) return 'undefined';
- return '{' + JSON.stringify(f.changes.map(ic => {
- return {
- start: ic.start,
- end: ic.end,
- replacement: ic.replacement,
- fileName: ic.sourceFile.fileName
- };
- })) +
- '}'
-}
diff --git a/packages/concatjs/internal/tsetse/language_service_plugin.ts b/packages/concatjs/internal/tsetse/language_service_plugin.ts
deleted file mode 100644
index 525241d..0000000
--- a/packages/concatjs/internal/tsetse/language_service_plugin.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import * as ts from 'typescript/lib/tsserverlibrary';
-import * as pluginApi from '../tsc_wrapped/plugin_api';
-import {Checker} from './checker';
-import {registerRules} from './runner';
-
-// Installs the Tsetse language server plugin, which checks Tsetse rules in your
-// editor and shows issues as semantic errors (red squiggly underline).
-
-function init() {
- return {
- create(info: ts.server.PluginCreateInfo) {
- const oldService = info.languageService;
- const proxy = pluginApi.createProxy(oldService);
- proxy.getSemanticDiagnostics = (fileName: string) => {
- const program = oldService.getProgram();
- if (!program) {
- throw new Error(
- 'Failed to initialize tsetse language_service_plugin: program is undefined');
- }
-
- const checker = new Checker(program);
-
- // Add disabledRules to tsconfig to disable specific rules
- // "plugins": [
- // {"name": "...", "disabledRules": ["equals-nan"]}
- // ]
- registerRules(checker, info.config.disabledRules || []);
- const result = [...oldService.getSemanticDiagnostics(fileName)];
- // Note that this ignores suggested fixes.
- result.push(...checker.execute(program.getSourceFile(fileName)!)
- .map(failure => failure.toDiagnostic()));
- return result;
- };
- return proxy;
- }
- };
-}
-
-export = init;
diff --git a/packages/concatjs/internal/tsetse/rule.ts b/packages/concatjs/internal/tsetse/rule.ts
deleted file mode 100644
index 7cc07a8..0000000
--- a/packages/concatjs/internal/tsetse/rule.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import {Checker} from './checker';
-
-/**
- * Tsetse rules should extend AbstractRule and provide a `register` function.
- * Rules are instantiated once per compilation operation and used across many
- * files.
- */
-export abstract class AbstractRule {
- /**
- * A lower-dashed-case name for that rule. This is not used by Tsetse itself,
- * but the integrators might (such as the TypeScript Bazel rules, for
- * instance).
- */
- abstract readonly ruleName: string;
- abstract readonly code: number;
-
- /**
- * Registers handler functions on nodes in Checker.
- */
- abstract register(checker: Checker): void;
-}
diff --git a/packages/concatjs/internal/tsetse/rules/ban_expect_truthy_promise_rule.ts b/packages/concatjs/internal/tsetse/rules/ban_expect_truthy_promise_rule.ts
deleted file mode 100644
index 6bee264..0000000
--- a/packages/concatjs/internal/tsetse/rules/ban_expect_truthy_promise_rule.ts
+++ /dev/null
@@ -1,79 +0,0 @@
-/**
- * @fileoverview Bans expect(returnsPromise()).toBeTruthy(). Promises are always
- * truthy, and this pattern is likely to be a bug where the developer meant
- * expect(await returnsPromise()).toBeTruthy() and forgot the await.
- */
-
-import * as tsutils from 'tsutils';
-import * as ts from 'typescript';
-
-import {Checker} from '../checker';
-import {ErrorCode} from '../error_code';
-import {AbstractRule} from '../rule';
-
-export class Rule extends AbstractRule {
- static readonly RULE_NAME = 'ban-expect-truthy-promise';
- readonly ruleName = Rule.RULE_NAME;
- readonly code = ErrorCode.BAN_EXPECT_TRUTHY_PROMISE;
-
- register(checker: Checker) {
- checker.on(
- ts.SyntaxKind.PropertyAccessExpression, checkForTruthy, this.code);
- }
-}
-
-function checkForTruthy(checker: Checker, node: ts.PropertyAccessExpression) {
- if (node.name.text !== 'toBeTruthy') {
- return;
- }
-
- const expectCallNode = getLeftmostNode(node);
- if (!ts.isCallExpression(expectCallNode)) {
- return;
- }
-
- if (!ts.isIdentifier(expectCallNode.expression) || expectCallNode.expression.text !== 'expect') {
- return;
- }
-
- if (expectCallNode.arguments.length === 0 || ts.isAwaitExpression(expectCallNode.arguments[0])) {
- return;
- }
-
- const tc = checker.typeChecker;
-
- const signature = tc.getResolvedSignature(expectCallNode);
- if (signature === undefined) {
- return;
- }
-
- const symbol = tc.getReturnTypeOfSignature(signature).getSymbol();
- if (symbol === undefined) {
- return;
- }
-
- // Only look for methods named expect that return a Matchers
- if (symbol.name !== 'Matchers') {
- return;
- }
-
- const argType = tc.getTypeAtLocation(expectCallNode.arguments[0]);
- if (!tsutils.isThenableType(tc, expectCallNode.arguments[0], argType)) {
- return;
- }
-
- checker.addFailureAtNode(
- node,
- `Value passed to expect() is of type ${tc.typeToString(argType)}, which` +
- ` is thenable. Promises are always truthy. Either use toBe(true) or` +
- ` await the value.` +
- `\n\tSee http://tsetse.info/ban-expect-truthy-promise`);
-}
-
-function getLeftmostNode(node: ts.PropertyAccessExpression) {
- let current: ts.LeftHandSideExpression|undefined = node;
- while (ts.isPropertyAccessExpression(current)) {
- current = current.expression;
- }
- return current;
-}
diff --git a/packages/concatjs/internal/tsetse/rules/ban_mutable_exports_rule.ts b/packages/concatjs/internal/tsetse/rules/ban_mutable_exports_rule.ts
deleted file mode 100644
index da852c6..0000000
--- a/packages/concatjs/internal/tsetse/rules/ban_mutable_exports_rule.ts
+++ /dev/null
@@ -1,67 +0,0 @@
-/**
- * @fileoverview Bans 'export' of mutable variables.
- * It is illegal to mutate them, so you might as well use 'const'.
- */
-
-import * as ts from 'typescript';
-
-import {Checker} from '../checker';
-import {ErrorCode} from '../error_code';
-import {AbstractRule} from '../rule';
-
-export class Rule extends AbstractRule {
- static readonly RULE_NAME = 'ban-mutable-exports';
- readonly ruleName = Rule.RULE_NAME;
- readonly code = ErrorCode.BAN_MUTABLE_EXPORTS;
-
- register(checker: Checker) {
- // Strategy: take all the exports of the file, then look at whether
- // they're const or not. This is simpler than the alternative of
- // trying to match all the various kinds of 'export' syntax, such
- // as 'export var ...', 'export {...}', 'export default ...'.
- checker.on(ts.SyntaxKind.SourceFile, checkFile, this.code);
- }
-}
-
-function checkFile(checker: Checker, file: ts.SourceFile) {
- // Allow in d.ts files, which are modelling external JS that doesn't
- // follow our rules.
- if (file.fileName.endsWith('.d.ts')) {
- return;
- }
- const sym = checker.typeChecker.getSymbolAtLocation(file);
- if (!sym) return;
- const exports = checker.typeChecker.getExportsOfModule(sym);
- for (const exp of exports) {
- // In the case of
- // let x = 3; export {x};
- // The exported symbol is the latter x, but we must dealias to
- // the former to judge whether it's const or not.
- let sym = exp;
- if (sym.flags & ts.SymbolFlags.Alias) {
- sym = checker.typeChecker.getAliasedSymbol(exp);
- }
- const decl = sym.valueDeclaration;
- if (!decl) continue; // Skip e.g. type declarations.
-
- if (decl.getSourceFile() !== file) {
- // Reexports are best warned about in the original file
- continue;
- }
-
- if (!ts.isVariableDeclaration(decl) && !ts.isBindingElement(decl)) {
- // Skip e.g. class declarations.
- continue;
- }
-
- const isConst = (ts.getCombinedNodeFlags(decl) & ts.NodeFlags.Const) !== 0;
- if (!isConst && exp.declarations !== undefined) {
- // Note: show the failure at the exported symbol's declaration site,
- // not the dealiased 'sym', so that the error message shows at the
- // 'export' statement and not the variable declaration.
- checker.addFailureAtNode(
- exp.declarations[0],
- `Exports must be const.`);
- }
- }
-}
diff --git a/packages/concatjs/internal/tsetse/rules/ban_promise_as_condition_rule.ts b/packages/concatjs/internal/tsetse/rules/ban_promise_as_condition_rule.ts
deleted file mode 100644
index a9da23e..0000000
--- a/packages/concatjs/internal/tsetse/rules/ban_promise_as_condition_rule.ts
+++ /dev/null
@@ -1,144 +0,0 @@
-/**
- * @fileoverview Bans using a promise as a condition. Promises are always
- * truthy, and this pattern is likely to be a bug where the developer meant
- * if(await returnsPromise()) {} and forgot the await.
- */
-
-import * as tsutils from 'tsutils';
-import * as ts from 'typescript';
-
-import {Checker} from '../checker';
-import {ErrorCode} from '../error_code';
-import {AbstractRule} from '../rule';
-
-export class Rule extends AbstractRule {
- static readonly RULE_NAME = 'ban-promise-as-condition';
- readonly ruleName = Rule.RULE_NAME;
- readonly code = ErrorCode.BAN_PROMISE_AS_CONDITION;
-
- register(checker: Checker) {
- checker.on(
- ts.SyntaxKind.ConditionalExpression, checkConditional, this.code);
- checker.on(
- ts.SyntaxKind.BinaryExpression, checkBinaryExpression, this.code);
- checker.on(ts.SyntaxKind.WhileStatement, checkWhileStatement, this.code);
- checker.on(ts.SyntaxKind.IfStatement, checkIfStatement, this.code);
- }
-}
-
-/** Error message to display. */
-function thenableText(nodeType: string, isVariable: boolean) {
- return `Found a thenable ${isVariable ? 'variable' : 'return value'} being` +
- ` used as ${
- nodeType}. Promises are always truthy, await the value to get` +
- ' a boolean value.';
-}
-
-function thenableVariableText(nodeType: string) {
- return thenableText(nodeType, true);
-}
-
-function thenableReturnText(nodeType: string) {
- return thenableText(nodeType, false);
-}
-
-/** Ternary: prom ? y : z */
-function checkConditional(checker: Checker, node: ts.ConditionalExpression) {
- addFailureIfThenableCallExpression(
- checker, node.condition, thenableReturnText('a conditional'));
-
- addFailureIfThenableIdentifier(
- checker, node.condition, thenableVariableText('a conditional'));
-}
-
-/**
- * Binary expression: prom || y or prom && y. Only check left side because
- * myThing && myThing.prom seems legitimate.
- */
-function checkBinaryExpression(checker: Checker, node: ts.BinaryExpression) {
- if (node.operatorToken.kind !== ts.SyntaxKind.BarBarToken &&
- node.operatorToken.kind !== ts.SyntaxKind.AmpersandAmpersandToken) {
- return;
- }
-
- addFailureIfThenableCallExpression(
- checker, node.left, thenableReturnText('a binary expression'));
-
- addFailureIfThenableIdentifier(
- checker, node.left, thenableVariableText('a binary expression'));
-}
-
-/** While statement: while (prom) {} */
-function checkWhileStatement(checker: Checker, node: ts.WhileStatement) {
- addFailureIfThenableCallExpression(
- checker, node.expression, thenableReturnText('a while statement'));
-
- addFailureIfThenableIdentifier(
- checker, node.expression, thenableVariableText('a while statement'));
-}
-
-/** If statement: if (prom) {} */
-function checkIfStatement(checker: Checker, node: ts.IfStatement) {
- addFailureIfThenableCallExpression(
- checker, node.expression, thenableReturnText('an if statement'));
-
- addFailureIfThenableIdentifier(
- checker, node.expression, thenableVariableText('an if statement'));
-}
-
-/** Helper methods */
-
-function addFailureIfThenableCallExpression(
- checker: Checker, callExpression: ts.Expression, errorMessage: string) {
- if (!tsutils.isCallExpression(callExpression)) {
- return;
- }
-
- const typeChecker = checker.typeChecker;
- const signature = typeChecker.getResolvedSignature(callExpression);
-
- // Return value of getResolvedSignature is `Signature | undefined` in ts 3.1
- // so we must check if the return value is valid to compile with ts 3.1.
- if (!signature) {
- throw new Error('Unexpected undefined signature for call expression');
- }
-
- const returnType = typeChecker.getReturnTypeOfSignature(signature);
-
- if (isNonFalsyThenableType(typeChecker, callExpression, returnType)) {
- checker.addFailureAtNode(callExpression, errorMessage);
- }
-}
-
-function addFailureIfThenableIdentifier(
- checker: Checker, identifier: ts.Expression, errorMessage: string) {
- if (!tsutils.isIdentifier(identifier)) {
- return;
- }
-
- if (isNonFalsyThenableType(checker.typeChecker, identifier)) {
- checker.addFailureAtNode(identifier, errorMessage);
- }
-}
-
-/**
- * If the type is a union type and has a falsy part it may be legitimate to use
- * it as a condition, so allow those through. (e.g. Promise<boolean> | boolean)
- * Otherwise, check if it's thenable. If so it should be awaited.
- */
-function isNonFalsyThenableType(
- typeChecker: ts.TypeChecker, node: ts.Expression,
- type = typeChecker.getTypeAtLocation(node)) {
- if (hasFalsyParts(typeChecker.getTypeAtLocation(node))) {
- return false;
- }
-
- return tsutils.isThenableType(typeChecker, node, type);
-}
-
-function hasFalsyParts(type: ts.Type) {
- const typeParts = tsutils.unionTypeParts(type);
- const hasFalsyParts =
- typeParts.filter((part) => tsutils.isFalsyType(part)).length > 0;
- return hasFalsyParts;
-}
diff --git a/packages/concatjs/internal/tsetse/rules/ban_string_initialized_sets_rule.ts b/packages/concatjs/internal/tsetse/rules/ban_string_initialized_sets_rule.ts
deleted file mode 100644
index 22d660d..0000000
--- a/packages/concatjs/internal/tsetse/rules/ban_string_initialized_sets_rule.ts
+++ /dev/null
@@ -1,65 +0,0 @@
-/**
- * @fileoverview Bans `new Set(<string>)` since it is a potential source of bugs
- * due to strings also implementing `Iterable<string>`.
- */
-
-import * as ts from 'typescript';
-
-import {Checker} from '../checker';
-import {ErrorCode} from '../error_code';
-import {AbstractRule} from '../rule';
-
-const errorMsg = 'Value passed to Set constructor is a string. This will' +
- ' create a Set of the characters of the string, rather than a Set' +
- ' containing the string. To make a Set of the string, pass an array' +
- ' containing the string. To make a Set of the characters, use \'as\' to ' +
- ' create an Iterable<string>, eg: new Set(myStr as Iterable<string>).';
-
-export class Rule extends AbstractRule {
- static readonly RULE_NAME = 'ban-string-initialized-sets';
- readonly ruleName = Rule.RULE_NAME;
- readonly code = ErrorCode.BAN_STRING_INITIALIZED_SETS;
-
- register(checker: Checker) {
- checker.on(ts.SyntaxKind.NewExpression, checkNewExpression, this.code);
- }
-}
-
-function checkNewExpression(checker: Checker, node: ts.NewExpression) {
- const typeChecker = checker.typeChecker;
-
- // Check that it's a Set which is being constructed
- const ctorTypeSymbol =
- typeChecker.getTypeAtLocation(node.expression).getSymbol();
-
- if (!ctorTypeSymbol || ctorTypeSymbol.declarations === undefined ||
- ctorTypeSymbol.getEscapedName() !== 'SetConstructor') {
- return;
- }
- const isES2015SetCtor = ctorTypeSymbol.declarations.some((decl) => {
- return sourceFileIsStdLib(decl.getSourceFile());
- });
- if (!isES2015SetCtor) return;
-
- // If there's no arguments provided, then it's not a string so bail out.
- if (!node.arguments || node.arguments.length !== 1) return;
-
- // Check the type of the first argument, expanding union & intersection types
- const arg = node.arguments[0];
- const argType = typeChecker.getTypeAtLocation(arg);
- const allTypes = argType.isUnionOrIntersection() ? argType.types : [argType];
-
- // Checks if the type (or any of the union/intersection types) are either
- // strings or string literals.
- const typeContainsString = allTypes.some((tsType) => {
- return (tsType.getFlags() & ts.TypeFlags.StringLike) !== 0;
- });
-
- if (!typeContainsString) return;
-
- checker.addFailureAtNode(arg, errorMsg);
-}
-
-function sourceFileIsStdLib(sourceFile: ts.SourceFile) {
- return /lib\.es2015\.(collection|iterable)\.d\.ts$/.test(sourceFile.fileName);
-}
diff --git a/packages/concatjs/internal/tsetse/rules/check_return_value_rule.ts b/packages/concatjs/internal/tsetse/rules/check_return_value_rule.ts
deleted file mode 100644
index 35e6b19..0000000
--- a/packages/concatjs/internal/tsetse/rules/check_return_value_rule.ts
+++ /dev/null
@@ -1,164 +0,0 @@
-/**
- * @fileoverview A Tsetse rule that checks the return value of certain functions
- * must be used.
- */
-
-import * as tsutils from 'tsutils';
-import * as ts from 'typescript';
-
-import {Checker} from '../checker';
-import {ErrorCode} from '../error_code';
-import {AbstractRule} from '../rule';
-
-const FAILURE_STRING = 'return value is unused.' +
- '\n\tSee http://tsetse.info/check-return-value';
-
-// A list of well-known functions that the return value must be used. If unused
-// then the function call is either a no-op (e.g. 'foo.trim()' foo is unchanged)
-// or can be replaced by another (Array.map() should be replaced with a loop or
-// Array.forEach() if the return value is unused).
-const METHODS_TO_CHECK = new Set<string>([
- ['Array', 'concat'],
- ['Array', 'filter'],
- ['Array', 'map'],
- ['Array', 'slice'],
- ['Function', 'bind'],
- ['Object', 'create'],
- ['string', 'concat'],
- ['string', 'normalize'],
- ['string', 'padStart'],
- ['string', 'padEnd'],
- ['string', 'repeat'],
- ['string', 'slice'],
- ['string', 'split'],
- ['string', 'substr'],
- ['string', 'substring'],
- ['string', 'toLocaleLowerCase'],
- ['string', 'toLocaleUpperCase'],
- ['string', 'toLowerCase'],
- ['string', 'toUpperCase'],
- ['string', 'trim'],
-].map(list => list.join('#')));
-
-/** A rule to ensure required return values from common functions are used. */
-export class Rule extends AbstractRule {
- static readonly RULE_NAME = 'check-return-value';
- readonly ruleName = Rule.RULE_NAME;
- readonly code = ErrorCode.CHECK_RETURN_VALUE;
-
- // registers checkCallExpression() function on ts.CallExpression node.
- // TypeScript conformance will traverse the AST of each source file and run
- // checkCallExpression() every time it encounters a ts.CallExpression node.
- register(checker: Checker) {
- checker.on(ts.SyntaxKind.CallExpression, checkCallExpression, this.code);
- }
-}
-
-function checkCallExpression(checker: Checker, node: ts.CallExpression) {
- // Short-circuit before using the typechecker if possible, as its expensive.
- // Workaround for https://github.com/Microsoft/TypeScript/issues/27997
- if (tsutils.isExpressionValueUsed(node)) {
- return;
- }
-
- // Check if this CallExpression is one of the well-known functions and returns
- // a non-void value that is unused.
- const signature = checker.typeChecker.getResolvedSignature(node);
- if (signature !== undefined) {
- const returnType = checker.typeChecker.getReturnTypeOfSignature(signature);
- if (!!(returnType.flags & ts.TypeFlags.Void)) {
- return;
- }
- // Although hasCheckReturnValueJsDoc() is faster than isBlackListed(), it
- // returns false most of the time and thus isBlackListed() would have to run
- // anyway. Therefore we short-circuit hasCheckReturnValueJsDoc().
- if (!isBlackListed(node, checker.typeChecker) &&
- !hasCheckReturnValueJsDoc(node, checker.typeChecker)) {
- return;
- }
-
- checker.addFailureAtNode(node, FAILURE_STRING);
- }
-}
-
-function isBlackListed(node: ts.CallExpression, tc: ts.TypeChecker): boolean {
- type AccessExpression =
- ts.PropertyAccessExpression|ts.ElementAccessExpression;
- switch (node.expression.kind) {
- case ts.SyntaxKind.PropertyAccessExpression:
- case ts.SyntaxKind.ElementAccessExpression:
- // Example: foo.bar() or foo[bar]()
- // expressionNode is foo
- const nodeExpression = (node.expression as AccessExpression).expression;
- const nodeExpressionString = nodeExpression.getText();
- const nodeType = tc.getTypeAtLocation(nodeExpression);
-
- // nodeTypeString is the string representation of the type of foo
- let nodeTypeString = tc.typeToString(nodeType);
- if (nodeTypeString.endsWith('[]')) {
- nodeTypeString = 'Array';
- }
- if (nodeTypeString === 'ObjectConstructor') {
- nodeTypeString = 'Object';
- }
- if (tsutils.isTypeFlagSet(nodeType, ts.TypeFlags.StringLiteral)) {
- nodeTypeString = 'string';
- }
-
- // nodeFunction is bar
- let nodeFunction = '';
- if (tsutils.isPropertyAccessExpression(node.expression)) {
- nodeFunction = node.expression.name.getText();
- }
- if (tsutils.isElementAccessExpression(node.expression)) {
- const argument = node.expression.argumentExpression;
- if (argument !== undefined) {
- nodeFunction = argument.getText();
- }
- }
-
- // Check if 'foo#bar' or `${typeof foo}#bar` is in the blacklist.
- if (METHODS_TO_CHECK.has(`${nodeTypeString}#${nodeFunction}`) ||
- METHODS_TO_CHECK.has(`${nodeExpressionString}#${nodeFunction}`)) {
- return true;
- }
-
- // For 'str.replace(regexp|substr, newSubstr|function)' only check when
- // the second parameter is 'newSubstr'.
- if ((`${nodeTypeString}#${nodeFunction}` === 'string#replace') ||
- (`${nodeExpressionString}#${nodeFunction}` === 'string#replace')) {
- return node.arguments.length === 2 &&
- !tsutils.isFunctionWithBody(node.arguments[1]);
- }
- break;
- case ts.SyntaxKind.Identifier:
- // Example: foo()
- // We currently don't have functions of this kind in blacklist.
- const identifier = node.expression as ts.Identifier;
- if (METHODS_TO_CHECK.has(identifier.text)) {
- return true;
- }
- break;
- default:
- break;
- }
- return false;
-}
-
-function hasCheckReturnValueJsDoc(node: ts.CallExpression, tc: ts.TypeChecker) {
- let symbol = tc.getSymbolAtLocation(node.expression);
- if (symbol === undefined) {
- return false;
- }
-
- if (tsutils.isSymbolFlagSet(symbol, ts.SymbolFlags.Alias)) {
- symbol = tc.getAliasedSymbol(symbol);
- }
-
- for (const jsDocTagInfo of symbol.getJsDocTags()) {
- if (jsDocTagInfo.name === 'checkReturnValue') {
- return true;
- }
- }
- return false;
-}
diff --git a/packages/concatjs/internal/tsetse/rules/conformance_pattern_rule.ts b/packages/concatjs/internal/tsetse/rules/conformance_pattern_rule.ts
deleted file mode 100644
index d620b87..0000000
--- a/packages/concatjs/internal/tsetse/rules/conformance_pattern_rule.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-import {Checker} from '../checker';
-import {ErrorCode} from '../error_code';
-import {AbstractRule} from '../rule';
-import {Fixer} from '../util/fixer';
-import {PatternKind, PatternRuleConfig} from '../util/pattern_config';
-import {NameEngine} from '../util/pattern_engines/name_engine';
-import {PatternEngine} from '../util/pattern_engines/pattern_engine';
-import {PropertyEngine} from '../util/pattern_engines/property_engine';
-import {PropertyNonConstantWriteEngine} from '../util/pattern_engines/property_non_constant_write_engine';
-import {PropertyWriteEngine} from '../util/pattern_engines/property_write_engine';
-
-
-/**
- * Builds a Rule that matches a certain pattern, given as parameter, and
- * that can additionally run a suggested fix generator on the matches.
- *
- * This is templated, mostly to ensure the nodes that have been matched
- * correspond to what the Fixer expects.
- */
-export class ConformancePatternRule implements AbstractRule {
- readonly ruleName: string;
- readonly code: number;
- private readonly engine: PatternEngine;
-
- constructor(config: PatternRuleConfig, fixer?: Fixer) {
- this.code = config.errorCode;
- // Avoid empty rule names.
- this.ruleName = config.name || `conformance-pattern-${config.kind}`;
-
- switch (config.kind) {
- case PatternKind.BANNED_PROPERTY:
- this.engine = new PropertyEngine(config, fixer);
- break;
- case PatternKind.BANNED_PROPERTY_WRITE:
- this.engine = new PropertyWriteEngine(config, fixer);
- break;
- case PatternKind.BANNED_PROPERTY_NON_CONSTANT_WRITE:
- this.engine = new PropertyNonConstantWriteEngine(config, fixer);
- break;
- case PatternKind.BANNED_NAME:
- this.engine = new NameEngine(config, fixer);
- break;
- default:
- throw new Error('Config type not recognized, or not implemented yet.');
- }
- }
-
- register(checker: Checker) {
- this.engine.register(checker);
- }
-}
-
-// Re-exported for convenience when instantiating rules.
-/**
- * The list of supported patterns useable in ConformancePatternRule. The
- * patterns whose name match JSConformance patterns should behave similarly (see
- * https://github.com/google/closure-compiler/wiki/JS-Conformance-Framework).
- */
-export {PatternKind};
-export {ErrorCode};
diff --git a/packages/concatjs/internal/tsetse/rules/conformance_pattern_rule_test.ts b/packages/concatjs/internal/tsetse/rules/conformance_pattern_rule_test.ts
deleted file mode 100644
index 1550812..0000000
--- a/packages/concatjs/internal/tsetse/rules/conformance_pattern_rule_test.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import 'jasmine';
-
-import {customMatchers} from '../util/testing/test_support';
-import {ConformancePatternRule, ErrorCode, PatternKind} from './conformance_pattern_rule';
-
-describe('ConformancePatternRule creation', () => {
- describe('naming', () => {
- const baseConfig = {
- errorCode: ErrorCode.CONFORMANCE_PATTERN,
- errorMessage: 'do not cite',
- kind: PatternKind.BANNED_PROPERTY_WRITE,
- values: ['HTMLQuoteElement.prototype.cite'],
- };
-
- it('generates a name by default', () => {
- const rule = new ConformancePatternRule(baseConfig);
- expect(rule.ruleName).toBe('conformance-pattern-banned-property-write');
- });
-
- it('accepts given names', () => {
- const namedConfig = {name: 'myRuleName', ...baseConfig};
- const rule = new ConformancePatternRule(namedConfig);
- expect(rule.ruleName).toBe('myRuleName');
- });
- });
-});
-
-beforeEach(() => {
- jasmine.addMatchers(customMatchers);
-});
diff --git a/packages/concatjs/internal/tsetse/rules/equals_nan_rule.ts b/packages/concatjs/internal/tsetse/rules/equals_nan_rule.ts
deleted file mode 100644
index ea6d8e8..0000000
--- a/packages/concatjs/internal/tsetse/rules/equals_nan_rule.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-/**
- * @fileoverview Bans `== NaN`, `=== NaN`, `!= NaN`, and `!== NaN` in TypeScript
- * code, since no value (including NaN) is equal to NaN.
- */
-
-import * as ts from 'typescript';
-
-import {Checker} from '../checker';
-import {ErrorCode} from '../error_code';
-import {AbstractRule} from '../rule';
-
-export class Rule extends AbstractRule {
- static readonly RULE_NAME = 'equals-nan';
- readonly ruleName = Rule.RULE_NAME;
- readonly code = ErrorCode.EQUALS_NAN;
-
- register(checker: Checker) {
- checker.on(
- ts.SyntaxKind.BinaryExpression, checkBinaryExpression, this.code);
- }
-}
-
-function checkBinaryExpression(checker: Checker, node: ts.BinaryExpression) {
- const isLeftNaN = ts.isIdentifier(node.left) && node.left.text === 'NaN';
- const isRightNaN = ts.isIdentifier(node.right) && node.right.text === 'NaN';
- if (!isLeftNaN && !isRightNaN) {
- return;
- }
-
- // We avoid calling getText() on the node.operatorToken because it's slow.
- // Instead, manually map back from the kind to the string form of the operator
- switch (node.operatorToken.kind) {
- case ts.SyntaxKind.EqualsEqualsToken:
- checker.addFailureAtNode(
- node,
- `x == NaN is always false; use isNaN(x) instead`,
- );
- break;
- case ts.SyntaxKind.EqualsEqualsEqualsToken:
- checker.addFailureAtNode(
- node,
- `x === NaN is always false; use isNaN(x) instead`,
- );
- break;
- case ts.SyntaxKind.ExclamationEqualsToken:
- checker.addFailureAtNode(
- node,
- `x != NaN is always true; use !isNaN(x) instead`,
- );
- break;
- case ts.SyntaxKind.ExclamationEqualsEqualsToken:
- checker.addFailureAtNode(
- node,
- `x !== NaN is always true; use !isNaN(x) instead`,
- );
- break;
- default:
- // We don't care about other operators acting on NaN
- break;
- }
-}
diff --git a/packages/concatjs/internal/tsetse/rules/must_type_assert_json_parse_rule.ts b/packages/concatjs/internal/tsetse/rules/must_type_assert_json_parse_rule.ts
deleted file mode 100644
index 45ee772..0000000
--- a/packages/concatjs/internal/tsetse/rules/must_type_assert_json_parse_rule.ts
+++ /dev/null
@@ -1,71 +0,0 @@
-/**
- * @fileoverview Bans `JSON.parse(...)` that is not wrapped in a type assertion.
- * See http://tsetse.info/must-type-assert-json-parse
- */
-
-
-import * as ts from 'typescript';
-
-import {Checker} from '../checker';
-import {ErrorCode} from '../error_code';
-import {AbstractRule} from '../rule';
-
-const FAILURE_STRING =
- 'type assert `JSON.parse() as SomeExplicitType` for type & optimization safety.\n\t' +
- 'See http://tsetse.info/must-type-assert-json-parse.';
-
-/**
- * Ensures that all calls to JSON.parse are wrapped in an `as` expression.
- */
-export class Rule extends AbstractRule {
- static readonly RULE_NAME = 'must-type-assert-json-parse';
- readonly ruleName = Rule.RULE_NAME;
- readonly code = ErrorCode.MUST_TYPE_ASSERT_JSON_PARSE;
-
- register(checker: Checker) {
- checker.on(ts.SyntaxKind.CallExpression, checkCallExpression, this.code);
- }
-}
-
-/**
- * Checks whether a given `parse` symbol is the JSON.parse symbol declared in
- * lib.es5.d.ts.
- */
-function isEcmascriptJsonParse(
- checker: Checker, node: ts.LeftHandSideExpression): boolean {
- const parseSymbol = checker.typeChecker.getSymbolAtLocation(node);
- if (parseSymbol === undefined) return false;
-
- const declaration = parseSymbol.valueDeclaration;
- if (declaration === undefined) return false;
-
- const fileName = declaration.getSourceFile().fileName;
- if (!fileName.includes('typescript')) return false;
- if (!fileName.endsWith('lib.es5.d.ts')) return false;
-
- // Narrow the node type so we can get `name`.
- if (!ts.isMethodSignature(declaration)) return false;
- if (declaration.name.getText() !== 'parse') return false;
-
- if (!ts.isInterfaceDeclaration(declaration.parent)) return false;
- if (declaration.parent.name.getText() !== 'JSON') return false;
-
- return true;
-}
-
-function checkCallExpression(checker: Checker, node: ts.CallExpression) {
- const funcexpr = node.expression;
- if (!ts.isPropertyAccessExpression(funcexpr)) {
- return;
- }
-
- // We're inside a type assert expression (JSON.parse as SomeExplicitType) so
- // this is an acceptable use. Don't add a failure.
- if (node.parent != null && node.parent.kind === ts.SyntaxKind.AsExpression) {
- return;
- }
-
- if (!isEcmascriptJsonParse(checker, funcexpr)) return;
-
- checker.addFailureAtNode(node, FAILURE_STRING);
-}
diff --git a/packages/concatjs/internal/tsetse/rules/must_use_promises_rule.ts b/packages/concatjs/internal/tsetse/rules/must_use_promises_rule.ts
deleted file mode 100644
index 293ea4b..0000000
--- a/packages/concatjs/internal/tsetse/rules/must_use_promises_rule.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-/**
- * @fileoverview A Tsetse rule that checks that all promises in async function
- * blocks are awaited or used.
- */
-
-import * as tsutils from 'tsutils';
-import * as ts from 'typescript';
-
-import {Checker} from '../checker';
-import {ErrorCode} from '../error_code';
-import {AbstractRule} from '../rule';
-
-const FAILURE_STRING =
- 'All Promises in async functions must either be awaited or used in an expression.' +
- '\n\tSee http://tsetse.info/must-use-promises';
-
-/** A rule to ensure promises in async functions are awaited or used. */
-export class Rule extends AbstractRule {
- static readonly RULE_NAME = 'must-use-promises';
- readonly ruleName = Rule.RULE_NAME;
- readonly code = ErrorCode.MUST_USE_PROMISES;
-
- register(checker: Checker) {
- checker.on(ts.SyntaxKind.CallExpression, checkCallExpression, this.code);
- }
-}
-
-function checkCallExpression(checker: Checker, node: ts.CallExpression) {
- // Short-circuit before using the typechecker if possible, as its expensive.
- // Workaround for https://github.com/Microsoft/TypeScript/issues/27997
- if (tsutils.isExpressionValueUsed(node) || !inAsyncFunction(node)) {
- return;
- }
-
- if (tsutils.isThenableType(checker.typeChecker, node)) {
- checker.addFailureAtNode(node, FAILURE_STRING);
- }
-}
-
-function inAsyncFunction(node: ts.Node): boolean {
- for (let inode = node.parent; inode !== undefined; inode = inode.parent) {
- switch (inode.kind) {
- case ts.SyntaxKind.ArrowFunction:
- case ts.SyntaxKind.FunctionDeclaration:
- case ts.SyntaxKind.FunctionExpression:
- case ts.SyntaxKind.MethodDeclaration:
- // Potentially async
- return tsutils.hasModifier(inode.modifiers, ts.SyntaxKind.AsyncKeyword);
- case ts.SyntaxKind.GetAccessor:
- case ts.SyntaxKind.SetAccessor:
- // These cannot be async
- return false;
- default:
- // Loop and check parent
- break;
- }
- }
-
- return false;
-}
diff --git a/packages/concatjs/internal/tsetse/rules/property_renaming_safe.ts b/packages/concatjs/internal/tsetse/rules/property_renaming_safe.ts
deleted file mode 100644
index ce8b95d..0000000
--- a/packages/concatjs/internal/tsetse/rules/property_renaming_safe.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-
-import * as ts from 'typescript';
-
-import {Checker} from '../checker';
-import {ErrorCode} from '../error_code';
-import {AbstractRule} from '../rule';
-
-/**
- * A Tsetse rule that checks for some potential unsafe property renaming
- * patterns.
- *
- * Note: This rule can have false positives.
- */
-export class Rule extends AbstractRule {
- static readonly RULE_NAME = 'property-renaming-safe';
- readonly ruleName = Rule.RULE_NAME;
- readonly code = ErrorCode.PROPERTY_RENAMING_SAFE;
-
- register(checker: Checker) {
- checker.on(
- ts.SyntaxKind.PropertyAccessExpression,
- checkIndexSignAccessedWithPropAccess, this.code);
- }
-}
-
-// Copied from tsickle/src/quoting_transformer.ts, with the intention of
-// removing it from there and only keeping a tsetse rule about this.
-function checkIndexSignAccessedWithPropAccess(
- checker: Checker, pae: ts.PropertyAccessExpression) {
- // Reject dotted accesses to types that have an index type declared to quoted
- // accesses, to avoid Closure renaming one access but not the other. This can
- // happen because TS allows dotted access to string index types.
- const typeChecker = checker.typeChecker;
- const t = typeChecker.getTypeAtLocation(pae.expression);
- if (!t.getStringIndexType()) return;
- // Types can have string index signatures and declared properties (of the
- // matching type). These properties have a symbol, as opposed to pure string
- // index types.
- const propSym = typeChecker.getSymbolAtLocation(pae.name);
- // The decision to return below is a judgement call. Presumably, in most
- // situations, dotted access to a property is correct, and should not be
- // turned into quoted access even if there is a string index on the type.
- // However it is possible to construct programs where this is incorrect, e.g.
- // where user code assigns into a property through the index access in another
- // location.
- if (propSym) return;
-
- checker.addFailureAtNode(
- pae.name,
- `Property ${pae.name.text} is not declared on Type ` +
- `${typeChecker.typeToString(t)}. The type has a string index ` +
- `signature, but it is being accessed using a dotted property ` +
- `access.
-See http://tsetse.info/property-renaming-safe.`);
-}
diff --git a/packages/concatjs/internal/tsetse/runner.ts b/packages/concatjs/internal/tsetse/runner.ts
deleted file mode 100644
index cbe85cd..0000000
--- a/packages/concatjs/internal/tsetse/runner.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-/**
- * @fileoverview Runner is the entry point of running Tsetse checks in compiler.
- */
-
-import * as ts from 'typescript';
-
-import * as perfTrace from '../tsc_wrapped/perf_trace';
-import * as pluginApi from '../tsc_wrapped/plugin_api';
-
-import {Checker} from './checker';
-import {AbstractRule} from './rule';
-import {Rule as BanExpectTruthyPromiseRule} from './rules/ban_expect_truthy_promise_rule';
-import {Rule as BanPromiseAsConditionRule} from './rules/ban_promise_as_condition_rule';
-import {Rule as BanStringInitializedSetsRule} from './rules/ban_string_initialized_sets_rule';
-import {Rule as CheckReturnValueRule} from './rules/check_return_value_rule';
-import {Rule as EqualsNanRule} from './rules/equals_nan_rule';
-import {Rule as MustTypeAssertJsonParseRule} from './rules/must_type_assert_json_parse_rule';
-import {Rule as MustUsePromisesRule} from './rules/must_use_promises_rule';
-
-/**
- * List of Tsetse rules. Shared between the program plugin and the language
- * service plugin.
- */
-const ENABLED_RULES: AbstractRule[] = [
- new CheckReturnValueRule(),
- new EqualsNanRule(),
- new BanExpectTruthyPromiseRule(),
- new MustUsePromisesRule(),
- new BanPromiseAsConditionRule(),
- new BanStringInitializedSetsRule(),
- new MustTypeAssertJsonParseRule(),
-];
-
-/**
- * The Tsetse check plugin performs compile-time static analysis for TypeScript
- * code.
- */
-export class Plugin implements pluginApi.DiagnosticPlugin {
- readonly name = 'tsetse';
- private readonly checker: Checker;
- constructor(program: ts.Program, disabledTsetseRules: string[] = []) {
- this.checker = new Checker(program);
- registerRules(this.checker, disabledTsetseRules);
- }
-
- getDiagnostics(sourceFile: ts.SourceFile) {
- // Tsetse, in its plugin form, outputs ts.Diagnostic that don't make use
- // of the potential suggested fixes Tsetse generates. These diagnostics are
- // however displayed in context: we can therefore stringify any potential
- // suggested fixes in the error message, so they don't go to waste.
- return this.checker.execute(sourceFile)
- .map(failure => failure.toDiagnosticWithStringifiedFix());
- }
-}
-
-export function registerRules(checker: Checker, disabledTsetseRules: string[]) {
- for (const rule of ENABLED_RULES) {
- if (disabledTsetseRules.indexOf(rule.ruleName) === -1) {
- rule.register(checker);
- }
- }
-}
diff --git a/packages/concatjs/internal/tsetse/tests/ban_expect_truthy_promise/BUILD b/packages/concatjs/internal/tsetse/tests/ban_expect_truthy_promise/BUILD
deleted file mode 100644
index 84fe023..0000000
--- a/packages/concatjs/internal/tsetse/tests/ban_expect_truthy_promise/BUILD
+++ /dev/null
@@ -1,60 +0,0 @@
-# Copyright 2017 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-load("//packages/concatjs:index.bzl", "ts_library")
-
-licenses(["notice"]) # Apache 2.0
-
-error_message = "error TS21224: Value passed.*"
-
-ts_library(
- name = "jasmine",
- testonly = 1,
- srcs = [
- "jasmine_types.ts",
- ],
-)
-
-ts_library(
- name = "positives",
- testonly = 1,
- srcs = [
- "positives.ts",
- ],
- expected_diagnostics = [
- "\\(31,5\\).*" + error_message,
- "\\(32,5\\).*" + error_message,
- "\\(33,5\\).*" + error_message,
- "\\(34,5\\).*" + error_message,
- "\\(35,5\\).*" + error_message,
- "\\(36,5\\).*" + error_message,
- "\\(37,5\\).*" + error_message,
- ],
- tsconfig = "//packages/concatjs/internal:tsetse/tsconfig.json",
- deps = [
- ":jasmine",
- ],
-)
-
-ts_library(
- name = "negatives",
- testonly = 1,
- srcs = [
- "negatives.ts",
- ],
- tsconfig = "//packages/concatjs/internal:tsetse/tsconfig.json",
- deps = [
- ":jasmine",
- ],
-)
diff --git a/packages/concatjs/internal/tsetse/tests/ban_expect_truthy_promise/jasmine_types.ts b/packages/concatjs/internal/tsetse/tests/ban_expect_truthy_promise/jasmine_types.ts
deleted file mode 100644
index bcea24f..0000000
--- a/packages/concatjs/internal/tsetse/tests/ban_expect_truthy_promise/jasmine_types.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-// Abbreviated Jasmine types for testing purposes
-
-declare function describe(
- description: string, specDefinitions: () => void): void;
-declare function it(
- expectation: string, assertion?: (done: Function) => void,
- timeout?: number): void;
-declare function expect(actual: any): Matchers;
-
-interface Matchers {
- toBeTruthy(expectationFailOutput?: any): boolean;
- toBeFalsy(expectationFailOutput?: any): boolean;
- not: Matchers;
-}
diff --git a/packages/concatjs/internal/tsetse/tests/ban_expect_truthy_promise/negatives.ts b/packages/concatjs/internal/tsetse/tests/ban_expect_truthy_promise/negatives.ts
deleted file mode 100644
index 62a3485..0000000
--- a/packages/concatjs/internal/tsetse/tests/ban_expect_truthy_promise/negatives.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-function expect(x: {}): ClassWithTruthy {
- return new ClassWithTruthy();
-}
-
-class ClassWithTruthy {
- toBeTruthy() {}
-}
-
-new ClassWithTruthy().toBeTruthy();
-expect(Promise.resolve(1)).toBeTruthy();
diff --git a/packages/concatjs/internal/tsetse/tests/ban_expect_truthy_promise/positives.ts b/packages/concatjs/internal/tsetse/tests/ban_expect_truthy_promise/positives.ts
deleted file mode 100644
index 1dfe40f..0000000
--- a/packages/concatjs/internal/tsetse/tests/ban_expect_truthy_promise/positives.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-import './jasmine_types';
-
-function returnsPromise() {
- return Promise.resolve(true);
-}
-
-type Future = Promise<number>;
-function aliasedPromise(): Future {
- return Promise.resolve(1);
-}
-
-class Extended extends Promise<number> {}
-function extendedPromise(): Extended {
- return Promise.resolve(1);
-}
-
-class DoubleExtended extends Extended {}
-function doubleExtendedPromise(): Extended {
- return Promise.resolve(1);
-}
-
-function maybePromise(): Promise<number>|number {
- return 3;
-}
-
-describe('example test', () => {
- it('should error when expecting promises toBeTruthy', async () => {
- const promise = returnsPromise();
-
- // Every expect here should fail the check.
- expect(promise).toBeTruthy();
- expect(maybePromise()).not.toBeTruthy();
- expect(maybePromise()).toBeTruthy();
- expect(returnsPromise()).toBeTruthy();
- expect(aliasedPromise()).toBeTruthy();
- expect(extendedPromise()).toBeTruthy();
- expect(doubleExtendedPromise()).toBeTruthy();
- });
-
- it('should allow awaited promises', async () => {
- const promise = returnsPromise();
- expect(await promise).toBeTruthy();
- expect(await maybePromise()).toBeTruthy();
- expect(await returnsPromise()).toBeTruthy();
- expect(await aliasedPromise()).toBeTruthy();
- expect(await extendedPromise()).toBeTruthy();
- });
-
- it('should only error for promises', async () => {
- expect('truthy').toBeTruthy();
- expect(1).toBeTruthy();
- expect(true).toBeTruthy();
- expect(null).not.toBeTruthy();
- });
-});
diff --git a/packages/concatjs/internal/tsetse/tests/ban_mutable_exports/examples.ts b/packages/concatjs/internal/tsetse/tests/ban_mutable_exports/examples.ts
deleted file mode 100644
index c687cad..0000000
--- a/packages/concatjs/internal/tsetse/tests/ban_mutable_exports/examples.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-/**
- * @fileoverview Examples for the mutable exports rule.
- * We expect every 'bad' to be an error, and every 'ok' to pass.
- * These are checked as expected diagnostics in the BUILD file.
- */
-
-export let bad1 = 3;
-export var bad2 = 3;
-export var bad3 = 3, bad4 = 3;
-var bad5 = 3;
-export {bad5};
-let bad6 = 3;
-export {bad6};
-export {bad6 as bad6alias};
-var bad7 = 3;
-export {bad7 as default};
-export let {bad8} = {
- bad8: 3
-};
-export let bad9: unknown;
-
-let ok1 = 3;
-var ok2 = 3;
-export const ok3 = 3;
-const ok4 = 3;
-const ok5 = 3;
-export {ok5};
-export type ok6 = string;
-export function ok7() {}
-export class ok8 {}
diff --git a/packages/concatjs/internal/tsetse/tests/ban_promise_as_condition/BUILD b/packages/concatjs/internal/tsetse/tests/ban_promise_as_condition/BUILD
deleted file mode 100644
index c6ccb67..0000000
--- a/packages/concatjs/internal/tsetse/tests/ban_promise_as_condition/BUILD
+++ /dev/null
@@ -1,47 +0,0 @@
-# Copyright 2017 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-load("//packages/concatjs:index.bzl", "ts_library")
-
-licenses(["notice"]) # Apache 2.0
-
-error_message = "error TS21226: Found a thenable.*"
-
-ts_library(
- name = "positives",
- testonly = 1,
- srcs = [
- "positives.ts",
- ],
- expected_diagnostics = [
- "\\(7,7\\).*" + error_message,
- "\\(15,7\\).*" + error_message,
- "\\(23,19\\).*" + error_message,
- "\\(25,10\\).*" + error_message,
- "\\(30,34\\).*" + error_message,
- "\\(31,34\\).*" + error_message,
- "\\(38,19\\).*" + error_message,
- "\\(40,10\\).*" + error_message,
- "\\(45,34\\).*" + error_message,
- "\\(47,34\\).*" + error_message,
- ],
- tsconfig = "//packages/concatjs/internal:tsetse/tsconfig.json",
-)
-
-ts_library(
- name = "negatives",
- testonly = 1,
- srcs = ["negatives.ts"],
- tsconfig = "//packages/concatjs/internal:tsetse/tsconfig.json",
-)
diff --git a/packages/concatjs/internal/tsetse/tests/ban_promise_as_condition/negatives.ts b/packages/concatjs/internal/tsetse/tests/ban_promise_as_condition/negatives.ts
deleted file mode 100644
index 7b41988..0000000
--- a/packages/concatjs/internal/tsetse/tests/ban_promise_as_condition/negatives.ts
+++ /dev/null
@@ -1,96 +0,0 @@
-// tslint:disable
-function returnsSynchronous(): boolean {
- return false;
-}
-
-async function returnsPromise() {
- return false;
-}
-
-async function asyncDoesHitElse() {
- if (returnsSynchronous()) {
- return true;
- } else {
- return false;
- }
-}
-
-function synchronousIsntAffected() {
- if (returnsSynchronous()) {
- console.log(true);
- } else {
- console.log(false);
- }
-
- const ternary = returnsSynchronous() ? 'always' : 'never';
-
- while (returnsSynchronous()) {
- // stuck in this loop
- break;
- }
-
- const a = returnsSynchronous() || 'other thing';
-}
-
-async function properlyAwaitedGivesNoBuildErrorsDirectCall() {
- if (await returnsPromise()) {
- console.log(true);
- } else {
- console.log(false);
- }
-
- const ternary = await returnsPromise() ? 'always' : 'never';
-
- while (await returnsPromise()) {
- // No longer stuck in this loop
- break;
- }
-
- const binaryExpressionBarBar = await returnsPromise() || 'other thing';
- const binaryExpressionAndAnd = await returnsPromise() && 'other thing';
-}
-
-async function properlyAwaitedGivesNoBuildErrorsPropertyAccess() {
- const prom = returnsPromise();
- if (await prom) {
- console.log(true);
- } else {
- console.log(false);
- }
-
- const ternary = await prom ? 'always' : 'never';
-
- while (await prom) {
- // No longer stuck in this loop
- break;
- }
-
- const binaryExpressionBarBar = await prom || 'other thing';
- const binaryExpressionAndAnd = await prom && 'other thing';
-}
-
-const savedPromise = returnsPromise();
-
-// These two verify that it doesn't tag = as a BinaryExpression when it should
-// only catch || and &&
-function takesPromise(prom: Promise<boolean>) {}
-
-function s() {
- let p = returnsPromise();
-
- takesPromise(p = returnsPromise());
-}
-
-// This verifies that Promise|null can still be checked with an if
-function takesPromiseMaybe(prom: Promise<boolean>|null|undefined) {
- if (prom) {
- // do stuff
- }
-}
-
-// Checking something exists with && before calling it is legitimate
-const boo = {
- sendPromise: async () => {
- return true;
- }
-};
diff --git a/packages/concatjs/internal/tsetse/tests/ban_promise_as_condition/positives.ts b/packages/concatjs/internal/tsetse/tests/ban_promise_as_condition/positives.ts
deleted file mode 100644
index 08c6771..0000000
--- a/packages/concatjs/internal/tsetse/tests/ban_promise_as_condition/positives.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-// tslint:disable
-async function returnsPromise() {
- return false;
-}
-
-function neverHitsElse() {
- if (returnsPromise()) {
- return true;
- } else {
- return false;
- }
-}
-
-async function asyncNeverHitsElse() {
- if (returnsPromise()) {
- return true;
- } else {
- return false;
- }
-}
-
-function detectsFunctionCalls() {
- const ternary = returnsPromise() ? 'always' : 'never';
-
- while (returnsPromise()) {
- // stuck in this loop
- break;
- }
-
- const binaryExpressionBarBar = returnsPromise() || 'other thing';
- const binaryExpressionAndAnd = returnsPromise() && 'other thing';
-}
-
-function detectsPropertyAccesses() {
- const prom = returnsPromise();
-
- // @ts-ignore TS2801
- const ternary = prom ? 'always' : 'never';
-
- while (prom) {
- // stuck in this loop
- break;
- }
-
- const binaryExpressionBarBar = prom || 'other thing';
- // @ts-ignore TS2801
- const binaryExpressionAndAnd = prom && 'other thing';
-}
diff --git a/packages/concatjs/internal/tsetse/tests/ban_string_initialized_sets/negatives.ts b/packages/concatjs/internal/tsetse/tests/ban_string_initialized_sets/negatives.ts
deleted file mode 100644
index e9a188a..0000000
--- a/packages/concatjs/internal/tsetse/tests/ban_string_initialized_sets/negatives.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-// tslint:disable
-function emptySet() {
- const set = new Set();
-}
-
-function noConstructorArgs() {
- const set = new Set;
-}
-
-function nonStringSet() {
- const set = new Set([1, 2, 3]);
-}
-
-// This is an allowable way to create a set of strings
-function setOfStrings() {
- const set = new Set(['abc']);
-}
-
-function setOfChars() {
- const set = new Set('abc'.split(''));
-}
-
-function explicitlyAllowString() {
- const set = new Set('abc' as Iterable<string>);
-}
-
-// checks that just a property called 'Set' doesn't trigger the error
-function justAKeyCalledSet(obj: {Set: {new (s: string): any}}) {
- const set = new obj.Set('abc');
-}
-
-function destructuredConstructorCalledSet(obj: {Set: {new (s: string): any}}) {
- const {Set} = obj;
- const set = new Set('abc');
-}
-
-function locallyDeclaredSet() {
- class Set {
- constructor(private s: string) {}
- }
- const set = new Set('abc');
-}
diff --git a/packages/concatjs/internal/tsetse/tests/ban_string_initialized_sets/positives.ts b/packages/concatjs/internal/tsetse/tests/ban_string_initialized_sets/positives.ts
deleted file mode 100644
index a4ec695..0000000
--- a/packages/concatjs/internal/tsetse/tests/ban_string_initialized_sets/positives.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-// tslint:disable
-function setWithStringLiteral() {
- const set = new Set('abc');
-}
-
-function setWithStringVariable(s: string) {
- const set = new Set(s);
-}
-
-function setWithStringUnionType(s: string|string[]) {
- const set = new Set(s);
-}
-
-function setWithStringExpression(fn: () => string) {
- const set = new Set(fn());
-}
-
-function setWithStringExpression2() {
- const set = new Set(Math.random() < 0.5 ? 'a' : 'b');
-}
-
-type TypeA = string|Set<string>;
-type TypeB = TypeA|(Iterable<string>&IterableIterator<string>);
-function setWithComplexInitializationType(s: TypeB) {
- const set = new Set(s);
-}
-
-function setWithUnionStringType(s: string&{toString(): string}) {
- const set = new Set(s);
-}
-
-function setWithLocalAlias() {
- const TotallyNotASet = Set;
- const set = new TotallyNotASet('abc');
-}
-
-function setWithMultipleAliases() {
- const Foo = Set;
- const Bar = Foo;
- const Baz = Bar;
- const set = new Baz('abc');
-}
-
-function setUsingSetConstructorType(ctor: SetConstructor) {
- const set = new ctor('abc');
-}
-
-type MySet = SetConstructor;
-function setUsingAliasedSetConstructor(ctor: MySet) {
- const set = new ctor('abc');
-}
diff --git a/packages/concatjs/internal/tsetse/tests/check_return_value/BUILD b/packages/concatjs/internal/tsetse/tests/check_return_value/BUILD
deleted file mode 100644
index 4a4c0b0..0000000
--- a/packages/concatjs/internal/tsetse/tests/check_return_value/BUILD
+++ /dev/null
@@ -1,66 +0,0 @@
-# Copyright 2017 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-load("//packages/concatjs:index.bzl", "ts_library")
-
-licenses(["notice"]) # Apache 2.0
-
-error_message = "TS21222: return value is unused.\\n\\tSee http://tsetse.info/check-return-value"
-
-ts_library(
- name = "no_expected_diagnostics_test",
- testonly = 1,
- srcs = ["no_expected_diagnostics.ts"],
- tsconfig = "//packages/concatjs/internal:tsetse/tsconfig.json",
-)
-
-ts_library(
- name = "expected_diagnostics_test",
- testonly = 1,
- srcs = ["expected_diagnostics.ts"],
- expected_diagnostics = [
- "\\(6,1\\).*" + error_message,
- "\\(8,1\\).*" + error_message,
- "\\(12,1\\).*" + error_message,
- "\\(16,1\\).*" + error_message,
- "\\(19,1\\).*" + error_message,
- ],
- tsconfig = "//packages/concatjs/internal:tsetse/tsconfig.json",
-)
-
-ts_library(
- name = "user_defined_check_return_value",
- testonly = 1,
- srcs = ["user_defined_check_return_value.ts"],
- tsconfig = "//packages/concatjs/internal:tsetse/tsconfig.json",
-)
-
-ts_library(
- name = "unused_return_value_user_defined_function",
- testonly = 1,
- srcs = ["unused_return_value_user_defined_function.ts"],
- expected_diagnostics = [
- "\\(4,1\\).*" + error_message,
- "\\(5,1\\).*" + error_message,
- "\\(7,1\\).*" + error_message,
- "\\(9,1\\).*" + error_message,
- "\\(15,1\\).*" + error_message,
- "\\(16,1\\).*" + error_message,
- ],
- tsconfig = "//packages/concatjs/internal:tsetse/tsconfig.json",
- deps = [
- ":user_defined_check_return_value",
- "@npm//@types/jasmine",
- ],
-)
diff --git a/packages/concatjs/internal/tsetse/tests/check_return_value/expected_diagnostics.ts b/packages/concatjs/internal/tsetse/tests/check_return_value/expected_diagnostics.ts
deleted file mode 100644
index 691f11a..0000000
--- a/packages/concatjs/internal/tsetse/tests/check_return_value/expected_diagnostics.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-export {};
-
-// string.trim() result is unused
-let stringUnused;
-stringUnused = 'hello';
-stringUnused.trim();
-const stringLiteralUnused = 'hello';
-stringLiteralUnused.trim();
-
-// Array.concat() result is unused.
-const arrayOfStringsUnused = ['hello'];
-arrayOfStringsUnused.concat(arrayOfStringsUnused);
-
-// Object.create() result is unused
-const objectUnused = {};
-Object.create(objectUnused);
-
-// string.replace() with a substring
-stringUnused.replace('o', 'O');
diff --git a/packages/concatjs/internal/tsetse/tests/check_return_value/no_expected_diagnostics.ts b/packages/concatjs/internal/tsetse/tests/check_return_value/no_expected_diagnostics.ts
deleted file mode 100644
index c1b3abd..0000000
--- a/packages/concatjs/internal/tsetse/tests/check_return_value/no_expected_diagnostics.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-// Array.pop() has side effects
-const arrayUsedWithSideEffects = [1];
-arrayUsedWithSideEffects.pop();
-
-// string.replace() result is assigned to a variable
-const stringFunctionAssignedToVar = 'hello';
-let world;
-world = stringFunctionAssignedToVar.replace('hello', 'world');
-
-// string.replace() result is used as an argument to another function
-const stringUsedInFunctionArguments = 'hello';
-console.debug(stringUsedInFunctionArguments.replace('hello', 'world'));
-
-// string.replace() result is returned
-export function foo(): string {
- const stringUsedInFunctionReturn = 'hello';
- return stringUsedInFunctionReturn.replace('hello', 'world');
-}
-
-function aRandomFunctionShouldNotTriggerThisRule() {}
-aRandomFunctionShouldNotTriggerThisRule();
-
-const stringFunctionUsedInIf = 'hello';
-if (stringFunctionUsedInIf.trim()) {
-}
-
-// string.replace() with a function
-const matches: string[] = [];
-'hello'.replace('l', (s) => {
- matches.push(s);
- return s;
-});
diff --git a/packages/concatjs/internal/tsetse/tests/check_return_value/unused_return_value_user_defined_function.ts b/packages/concatjs/internal/tsetse/tests/check_return_value/unused_return_value_user_defined_function.ts
deleted file mode 100644
index 05c1142..0000000
--- a/packages/concatjs/internal/tsetse/tests/check_return_value/unused_return_value_user_defined_function.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import 'jasmine';
-import {ClassContainingUserDefinedCheckReturnValueFunction, manyJsDocTags, userDefinedCheckReturnValueFunction} from './user_defined_check_return_value';
-
-userDefinedCheckReturnValueFunction('hello');
-manyJsDocTags('hello');
-
-new ClassContainingUserDefinedCheckReturnValueFunction().checkReturnValue(
- 'hello');
-new ClassContainingUserDefinedCheckReturnValueFunction().sameLineJsDoc('hello');
-new ClassContainingUserDefinedCheckReturnValueFunction().noJsDoc('hello');
-
-const nested = {
- child: new ClassContainingUserDefinedCheckReturnValueFunction()
-};
-nested.child.checkReturnValue('hello');
-expect(null);
diff --git a/packages/concatjs/internal/tsetse/tests/check_return_value/user_defined_check_return_value.ts b/packages/concatjs/internal/tsetse/tests/check_return_value/user_defined_check_return_value.ts
deleted file mode 100644
index 0965983..0000000
--- a/packages/concatjs/internal/tsetse/tests/check_return_value/user_defined_check_return_value.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-/**
- * @checkReturnValue The input string is unchanged.
- */
-export function userDefinedCheckReturnValueFunction(str: string) {
- return `input ${str}`;
-}
-
-/**
- * @tag1
- * @checkReturnValue The input string is unchanged.
- * @tag2
- */
-export function manyJsDocTags(str: string) {
- return `input ${str}`;
-}
-
-export class ClassContainingUserDefinedCheckReturnValueFunction {
- /**
- * @checkReturnValue The input string is unchanged.
- */
- checkReturnValue(str: string) {
- return `input ${str}`;
- }
- /** @checkReturnValue */ sameLineJsDoc(str: string) {
- return `input ${str}`;
- }
- noJsDoc(str: string) {
- return `input ${str}`;
- }
-}
diff --git a/packages/concatjs/internal/tsetse/tests/equals_nan/BUILD b/packages/concatjs/internal/tsetse/tests/equals_nan/BUILD
deleted file mode 100644
index 5e0918f..0000000
--- a/packages/concatjs/internal/tsetse/tests/equals_nan/BUILD
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright 2017 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-load("//packages/concatjs:index.bzl", "ts_library")
-
-licenses(["notice"]) # Apache 2.0
-
-ts_library(
- name = "positives",
- testonly = 1,
- srcs = [
- "positives.ts",
- ],
- expected_diagnostics = [
- "\\(2,19\\): error TS21223: x === NaN is always false; use isNaN\\(x\\) instead",
- "\\(6,5\\): error TS21223: x === NaN is always false; use isNaN\\(x\\) instead",
- "\\(7,5\\): error TS21223: x == NaN is always false; use isNaN\\(x\\) instead",
- "\\(8,5\\): error TS21223: x !== NaN is always true; use !isNaN\\(x\\) instead",
- "\\(9,5\\): error TS21223: x != NaN is always true; use !isNaN\\(x\\) instead",
- "\\(11,1\\): error TS21223: x === NaN is always false; use isNaN\\(x\\) instead",
- "\\(12,1\\): error TS21223: x === NaN is always false; use isNaN\\(x\\) instead",
- ],
-)
-
-ts_library(
- name = "negatives",
- testonly = 1,
- srcs = [
- "negatives.ts",
- ],
-)
diff --git a/packages/concatjs/internal/tsetse/tests/equals_nan/negatives.ts b/packages/concatjs/internal/tsetse/tests/equals_nan/negatives.ts
deleted file mode 100644
index dcb13d3..0000000
--- a/packages/concatjs/internal/tsetse/tests/equals_nan/negatives.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-// tslint:disable
-isNaN(1);
-let x = NaN;
-3 === 0 / 0;
-
-export {} // Make this file a module.
diff --git a/packages/concatjs/internal/tsetse/tests/equals_nan/positives.ts b/packages/concatjs/internal/tsetse/tests/equals_nan/positives.ts
deleted file mode 100644
index 9556f23..0000000
--- a/packages/concatjs/internal/tsetse/tests/equals_nan/positives.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-// tslint:disable
-const equalsNan = 1 === NaN;
-
-declare const x: number;
-
-if (x === NaN) alert('never happens');
-if (x == NaN) alert('never happens');
-if (x !== NaN) alert('always happens');
-if (x != NaN) alert('always happens');
-
-NaN === NaN;
-NaN === 0 / 0;
-
-export {} // Make this file a module.
diff --git a/packages/concatjs/internal/tsetse/tests/must_type_assert_json_parse/negatives.ts b/packages/concatjs/internal/tsetse/tests/must_type_assert_json_parse/negatives.ts
deleted file mode 100644
index 6c8e7c3..0000000
--- a/packages/concatjs/internal/tsetse/tests/must_type_assert_json_parse/negatives.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-// tslint:disable
-if (JSON.parse('false') as boolean) {
- alert('never happens');
-}
-
-if (JSON.parse('null') as null) {
- alert('never happens');
-}
-
-declare interface MyInterface {
- attr: string;
-}
-
-const a = JSON.parse('{}') as any;
-const b = JSON.parse('{}') as unknown;
-const c = JSON.parse('{}') as MyInterface;
-
-let d = JSON.parse('{}') as any;
-let e = JSON.parse('{}') as unknown;
-let f = JSON.parse('{}') as MyInterface;
-
-{
- const JSON = {parse: (a: any) => a};
- let g = JSON.parse('{}'); // User defined JSON, so no error.
-}
-
-export {}; // Make this file a module.
diff --git a/packages/concatjs/internal/tsetse/tests/must_type_assert_json_parse/positives.ts b/packages/concatjs/internal/tsetse/tests/must_type_assert_json_parse/positives.ts
deleted file mode 100644
index ce013ef..0000000
--- a/packages/concatjs/internal/tsetse/tests/must_type_assert_json_parse/positives.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-// tslint:disable
-
-const a = JSON.parse('{}');
-let b = JSON.parse('{}');
-if (JSON.parse('false')) {
- alert('never happens');
-}
-
-export {}; // Make this file a module.
diff --git a/packages/concatjs/internal/tsetse/tests/must_use_promises/BUILD b/packages/concatjs/internal/tsetse/tests/must_use_promises/BUILD
deleted file mode 100644
index 6050795..0000000
--- a/packages/concatjs/internal/tsetse/tests/must_use_promises/BUILD
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright 2017 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-load("//packages/concatjs:index.bzl", "ts_library")
-
-licenses(["notice"]) # Apache 2.0
-
-error_message = "TS21225: All Promises in async functions must either be awaited or used in an expression."
-
-ts_library(
- name = "positives",
- testonly = 1,
- srcs = [
- "positives.ts",
- ],
- expected_diagnostics = [
- "\\(29,3\\)" + error_message,
- "\\(30,3\\)" + error_message,
- "\\(31,3\\)" + error_message,
- "\\(32,3\\)" + error_message,
- "\\(34,3\\)" + error_message,
- ],
- tsconfig = "//packages/concatjs/internal:tsetse/tsconfig.json",
-)
diff --git a/packages/concatjs/internal/tsetse/tests/must_use_promises/no_await.ts b/packages/concatjs/internal/tsetse/tests/must_use_promises/no_await.ts
deleted file mode 100644
index d2b9adc..0000000
--- a/packages/concatjs/internal/tsetse/tests/must_use_promises/no_await.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import {noAwait} from 'google3/javascript/typescript/contrib/async';
-
-function returnsPromise() {
- return Promise.resolve(1);
-}
-
-async function unusedPromises() {
- noAwait(returnsPromise());
-}
diff --git a/packages/concatjs/internal/tsetse/tests/must_use_promises/positives.ts b/packages/concatjs/internal/tsetse/tests/must_use_promises/positives.ts
deleted file mode 100644
index 659802a..0000000
--- a/packages/concatjs/internal/tsetse/tests/must_use_promises/positives.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-function isPromise() {
- return Promise.resolve(1);
-}
-
-function maybePromise(): Promise<number>|number {
- return Promise.resolve(1);
-}
-
-type Future = Promise<number>;
-function aliasedPromise(): Future {
- return Promise.resolve(1);
-}
-
-class Extended extends Promise<number> {}
-
-function extendedPromise(): Extended {
- return Promise.resolve(1);
-}
-
-function usePromise(maybePromise: Promise<number>|number) {
- return false;
-}
-
-async function returnLaterPromise() {
- return () => Promise.resolve(1);
-}
-
-async function unusedPromises() {
- isPromise();
- maybePromise();
- aliasedPromise();
- extendedPromise();
- const later = await returnLaterPromise();
- later();
-}
-
-async function hasAwait() {
- await isPromise();
- await maybePromise();
- await aliasedPromise();
- await extendedPromise();
- const later = await returnLaterPromise();
- await later();
- usePromise(maybePromise());
-}
-
-function nonAsyncFunction() {
- isPromise();
- maybePromise();
- aliasedPromise();
- extendedPromise();
- const future = maybePromise();
- usePromise(future);
-}
diff --git a/packages/concatjs/internal/tsetse/tests/property_renaming_safe/errors.ts b/packages/concatjs/internal/tsetse/tests/property_renaming_safe/errors.ts
deleted file mode 100644
index b4ed844..0000000
--- a/packages/concatjs/internal/tsetse/tests/property_renaming_safe/errors.ts
+++ /dev/null
@@ -1,64 +0,0 @@
-/* tslint:disable */
-interface IdxSig {
- [key: string]: string;
-}
-
-function propAccess(x: IdxSig) {
- x.prop; // error
- x['prop']; // ok
-}
-
-function descructuring(x: IdxSig) {
- const {prop} = x; // ok, but should be an error.
-}
-
-interface MixedIdxSig extends IdxSig {
- namedProp: string;
-}
-
-function mixedPropAccess(x: MixedIdxSig) {
- x.namedProp; // ok
- x['namedProp']; // ok
- x.prop; // error
- x['prop']; // ok
-}
-
-function genericAccess<T extends IdxSig>(x: T) {
- x.prop; // error
- x['prop']; // ok
-}
-
-interface MixedIndexSigUsedInUnion {
- [key: string]: string;
- namedProp2: string;
-}
-
-function unionType(x: MixedIdxSig|MixedIndexSigUsedInUnion) {
- x.prop; // error
- x['prop']; // ok
-}
-
-/**
- * Curiously Record<string, T> is treated like an index signature.
- */
-function recordStringType(x: Record<string, number>) {
- x.prop; // error
- x['prop']; // ok
-}
-
-/**
- * But narrowing the generic parameter to a string literal union exempts it.
- */
-function recordNarrowType(x: Record<'prop'|'other', number>) {
- x.prop; // ok
- x['prop']; // ok
-}
-
-/**
- * Similary, to Records mapped types of of 'in string' are threated like a
- * string index signature.
- */
-function mappedType(x: {[x in string]: boolean}) {
- x.prop; // error
- x['prop']; // ok
-}
diff --git a/packages/concatjs/internal/tsetse/tsconfig.json b/packages/concatjs/internal/tsetse/tsconfig.json
deleted file mode 100644
index abc0d83..0000000
--- a/packages/concatjs/internal/tsetse/tsconfig.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "compilerOptions": {
- "strict": true,
- "types": [
- ],
- "lib": [
- "dom",
- "es5",
- "es2015.core",
- "es2015.collection",
- "es2015.promise"
- ],
- "plugins": [
- // Run `bazel build internal:tsc_wrapped` from root folder
- // (rules_typescript) to build the plugin.
- //
- // If you are using VSCode make sure you are using the workspace version
- // of TS, otherwise the plugin won't be loaded. Also, make sure you have
- // opened the repo as workspace (from the root folder).
- {
- "name": "../../bazel-bin/internal/tsetse/language_service_plugin.js"
- }
- ]
- }
-}
diff --git a/packages/concatjs/internal/tsetse/util/absolute_matcher.ts b/packages/concatjs/internal/tsetse/util/absolute_matcher.ts
deleted file mode 100644
index 1ba885d..0000000
--- a/packages/concatjs/internal/tsetse/util/absolute_matcher.ts
+++ /dev/null
@@ -1,180 +0,0 @@
-import * as ts from 'typescript';
-import {dealias, debugLog, isInStockLibraries, isNameInDeclaration, isPartOfImportStatement} from './ast_tools';
-
-const PATH_NAME_FORMAT = '[/\\.\\w\\d_-]+';
-const JS_IDENTIFIER_FORMAT = '[\\w\\d_-]+';
-const FQN_FORMAT = `(${JS_IDENTIFIER_FORMAT}\.)*${JS_IDENTIFIER_FORMAT}`;
-const GLOBAL = 'GLOBAL';
-const ANY_SYMBOL = 'ANY_SYMBOL';
-const CLOSURE = 'CLOSURE';
-/** A fqn made out of a dot-separated chain of JS identifiers. */
-const ABSOLUTE_RE = new RegExp(`^${PATH_NAME_FORMAT}\\|${FQN_FORMAT}$`);
-/**
- * Clutz glues js symbols to ts namespace by prepending "ಠ_ಠ.clutz.".
- * We need to include this prefix when the banned name is from Closure.
- */
-const CLUTZ_SYM_PREFIX = 'ಠ_ಠ.clutz.';
-
-/**
- * This class matches symbols given a "foo.bar.baz" name, where none of the
- * steps are instances of classes.
- *
- * Note that this isn't smart about subclasses and types: to write a check, we
- * strongly suggest finding the expected symbol in externs to find the object
- * name on which the symbol was initially defined.
- *
- * This matcher requires a scope for the symbol, which may be `GLOBAL`,
- * `ANY_SYMBOL`, `CLOSURE` or a file path filter. `CLOSURE` indicates that the
- * symbol is from the JS Closure library processed by clutz. The matcher begins
- * with this scope, then the separator "|", followed by the symbol name. For
- * example, "GLOBAL|eval".
- *
- * The file filter specifies
- * (part of) the path of the file in which the symbol of interest is defined.
- * For example, "path/to/file.ts|foo.bar.baz".
- * With this filter, only symbols named "foo.bar.baz" that are defined in a path
- * that contains "path/to/file.ts" are matched.
- *
- * This filter is useful when mutiple symbols have the same name but
- * you want to match with a specific one. For example, assume that there are
- * two classes named "Foo" defined in /path/to/file0 and /path/to/file1.
- * // in /path/to/file0
- * export class Foo { static bar() {return "Foo.bar in file0";} }
- *
- * // in /path/to/file1
- * export class Foo { static bar() {return "Foo.bar in file1";} }
- *
- * Suppose that these two classes are referenced in two other files.
- * // in /path/to/file2
- * import {Foo} from /path/to/file0;
- * Foo.bar();
- *
- * // in /path/to/file3
- * import {Foo} from /path/to/file1;
- * Foo.bar();
- *
- * An absolute matcher "Foo.bar" without a file filter will match with both
- * references to "Foo.bar" in /path/to/file2 and /path/to/file3.
- * An absolute matcher "/path/to/file1|Foo.bar", however, only matches with the
- * "Foo.bar()" in /path/to/file3 because that references the "Foo.bar" defined
- * in /path/to/file1.
- *
- * Note that an absolute matcher will match with any reference to the symbol
- * defined in the file(s) specified by the file filter. For example, assume that
- * Foo from file1 is extended in file4.
- *
- * // in /path/to/file4
- * import {Foo} from /path/to/file1;
- * class Moo { static tar() {return "Moo.tar in file4";} }
- * Moo.bar();
- *
- * An absolute matcher "/path/to/file1|Foo.bar" matches with "Moo.bar()" because
- * "bar" is defined as part of Foo in /path/to/file1.
- */
-export class AbsoluteMatcher {
- /**
- * From a "path/to/file.ts|foo.bar.baz", builds a Matcher.
- */
- readonly filePath: string;
- readonly bannedName: string;
-
- constructor(spec: string) {
- if (!spec.match(ABSOLUTE_RE)) {
- throw new Error('Malformed matcher selector.');
- }
-
- // JSConformance used to use a Foo.prototype.bar syntax for bar on
- // instances of Foo. TS doesn't surface the prototype part in the FQN, and
- // so you can't tell static `bar` on `foo` from the `bar` property/method
- // on `foo`. To avoid any confusion, throw there if we see `prototype` in
- // the spec: that way, it's obvious that you're not trying to match
- // properties.
- if (spec.match('.prototype.')) {
- throw new Error(
- 'Your pattern includes a .prototype, but the AbsoluteMatcher is ' +
- 'meant for non-object matches. Use the PropertyMatcher instead, or ' +
- 'the Property-based PatternKinds.');
- }
-
- // Split spec by the separator "|".
- [this.filePath, this.bannedName] = spec.split('|', 2);
-
- if (this.filePath === CLOSURE) {
- this.bannedName = CLUTZ_SYM_PREFIX + this.bannedName;
- }
- }
-
- matches(n: ts.Node, tc: ts.TypeChecker): boolean {
- debugLog(() => `start matching ${n.getText()} in ${n.parent.getText()}`);
-
- // Check if the node is being declared. Declaration may be imported without
- // programmer being aware of. We should not alert them about that.
- // Since import statments are also declarations, this have two notable
- // consequences.
- // - Match is negative for imports without renaming
- // - Match is positive for imports with renaming, when the imported name
- // is the target. Since Tsetse is flow insensitive and we don't track
- // symbol aliases, the import statement is the only place we can match
- // bad symbols if they get renamed.
- if (isNameInDeclaration(n)) {
- debugLog(() => `We don't flag symbol declarations`);
- return false;
- }
-
- // Get the symbol (or the one at the other end of this alias) that we're
- // looking at.
- const s = dealias(tc.getSymbolAtLocation(n), tc);
- if (!s) {
- debugLog(() => `cannot get symbol`);
- return false;
- }
-
- // The TS-provided FQN tells us the full identifier, and the origin file
- // in some circumstances.
- const fqn = tc.getFullyQualifiedName(s);
- debugLog(() => `got FQN ${fqn}`);
-
- // Name-based check: `getFullyQualifiedName` returns `"filename".foo.bar` or
- // just `foo.bar` if the symbol is ambient. The check here should consider
- // both cases.
- if (!fqn.endsWith('".' + this.bannedName) && fqn !== this.bannedName) {
- debugLog(() => `FQN ${fqn} doesn't match name ${this.bannedName}`);
- return false;
- }
-
- // If `ANY_SYMBOL` or `CLOSURE` is specified, it's sufficient to conclude we
- // have a match.
- if (this.filePath === ANY_SYMBOL || this.filePath === CLOSURE) {
- return true;
- }
-
- // If there is no declaration, the symbol is a language built-in object.
- // This is a match only if `GLOBAL` is specified.
- const declarations = s.getDeclarations();
- if (declarations === undefined) {
- return this.filePath === GLOBAL;
- }
-
- // No file info in the FQN means it's imported from a .d.ts declaration
- // file. This can be from a core library, a JS library, or an exported local
- // symbol defined in another TS target. We need to extract the name of the
- // declaration file.
- if (!fqn.startsWith('"')) {
- if (this.filePath === GLOBAL) {
- return declarations.some(isInStockLibraries);
- } else {
- return declarations.some((d) => {
- const srcFilePath = d.getSourceFile()?.fileName;
- return srcFilePath && srcFilePath.match(this.filePath);
- })
- }
- } else {
- const last = fqn.indexOf('"', 1);
- if (last === -1) {
- throw new Error('Malformed fully-qualified name.');
- }
- const filePath = fqn.substring(1, last);
- return filePath.match(this.filePath) !== null;
- }
- }
-}
diff --git a/packages/concatjs/internal/tsetse/util/absolute_matcher_test.ts b/packages/concatjs/internal/tsetse/util/absolute_matcher_test.ts
deleted file mode 100644
index 9f612c6..0000000
--- a/packages/concatjs/internal/tsetse/util/absolute_matcher_test.ts
+++ /dev/null
@@ -1,345 +0,0 @@
-import 'jasmine';
-import {ConformancePatternRule, ErrorCode, PatternKind} from '../rules/conformance_pattern_rule';
-import {compileAndCheck, customMatchers} from './testing/test_support';
-
-describe('AbsoluteMatcher', () => {
- beforeEach(() => {
- jasmine.addMatchers(customMatchers);
- });
-
- it('requires a matcher scope', () => {
- const config = {
- errorCode: ErrorCode.CONFORMANCE_PATTERN,
- errorMessage: 'banned name with no scope',
- kind: PatternKind.BANNED_NAME,
- values: ['exec']
- };
- const sources = [`eval('alert("hi");');`];
-
- const check = () =>
- compileAndCheck(new ConformancePatternRule(config), ...sources);
-
- expect(check).toThrowError('Malformed matcher selector.');
- });
-
- describe('file scope', () => {
- it('matches a file path', () => {
- const config = {
- errorCode: ErrorCode.CONFORMANCE_PATTERN,
- errorMessage: 'banned name with file path',
- kind: PatternKind.BANNED_NAME,
- values: ['./file_0|Foo.bar']
- };
- const sources = [
- `export class Foo { static bar(s: string) {return s + "abc";} }`,
- `import {Foo} from './file_0';
- var a = Foo.bar("123");`
- ];
- const results =
- compileAndCheck(new ConformancePatternRule(config), ...sources);
-
- expect(results).toHaveFailuresMatching(
- {matchedCode: `bar`, messageText: 'banned name with file path'});
- });
-
- it('ignores an exported symbol defined in an unmatched file path', () => {
- const config = {
- errorCode: ErrorCode.CONFORMANCE_PATTERN,
- errorMessage: 'banned name with file path',
- kind: PatternKind.BANNED_NAME,
- values: ['./file_0|Foo.bar']
- };
-
- // test exported symbols
- const sources = [
- `export class Foo { static bar(s: string) {return s + "abc";} }`,
- `export class Foo { static bar(s: string) {return s + "abc";} }`,
- `import {Foo} from './file_1';
- var a = Foo.bar("123");`
- ];
-
- const results =
- compileAndCheck(new ConformancePatternRule(config), ...sources);
- expect(results).toHaveNoFailures();
- });
-
- it('ignores an un-exported symbol defined in an unmatched file path',
- () => {
- const config = {
- errorCode: ErrorCode.CONFORMANCE_PATTERN,
- errorMessage: 'banned name with file path',
- kind: PatternKind.BANNED_NAME,
- values: ['./file_0|Foo.bar']
- };
-
- // test non-exported symbols
- const sources = [
- `export class Foo { static bar(s: string) {return s + "abc";} }`,
- `class Foo { static bar(s: string) {return s + "abc";} }
- var a = Foo.bar("123");`
- ];
-
- const results =
- compileAndCheck(new ConformancePatternRule(config), ...sources);
-
- expect(results).toHaveNoFailures();
- });
-
- it('matches a local exported definition', () => {
- // This is a match because Foo.bar is an exported symbol.
- const config = {
- errorCode: ErrorCode.CONFORMANCE_PATTERN,
- errorMessage: 'banned name with file path',
- kind: PatternKind.BANNED_NAME,
- values: ['./file_0|Foo.bar']
- };
- const sources =
- [`export class Foo { static bar(s: string) {return s + "abc";} }
- var a = Foo.bar("123");`];
-
- const results =
- compileAndCheck(new ConformancePatternRule(config), ...sources);
- expect(results).toHaveFailuresMatching(
- {matchedCode: `bar`, messageText: 'banned name with file path'});
- });
-
- it('matches names in import statement', () => {
- const config = {
- errorCode: ErrorCode.CONFORMANCE_PATTERN,
- errorMessage: 'banned name with file path',
- kind: PatternKind.BANNED_NAME,
- values: ['./file_0|foo', 'ANY_SYMBOL|bar']
- };
- const sources = [
- `export function foo(s: string) {return s + "abc";}
- function bar() {}
- export {bar};`,
- `import {foo} from './file_0';
- import {bar} from './file_0';`,
- `import {foo as okFoo} from './file_0';
- import {bar as okBar} from './file_0';`,
- ];
-
- const results =
- compileAndCheck(new ConformancePatternRule(config), ...sources);
- expect(results).toHaveFailuresMatching(
- {matchedCode: `foo`, messageText: 'banned name with file path'},
- {matchedCode: `bar`, messageText: 'banned name with file path'},
- );
- });
- });
-
- describe('global scope', () => {
- it('matches an in-stock library method', () => {
- const config = {
- errorCode: ErrorCode.CONFORMANCE_PATTERN,
- errorMessage: 'banned ambient name',
- kind: PatternKind.BANNED_NAME,
- values: ['GLOBAL|eval']
- };
- const sources = [`eval('alert("hi");');`];
-
- const results =
- compileAndCheck(new ConformancePatternRule(config), ...sources);
- expect(results).toHaveFailuresMatching(
- {matchedCode: `eval`, messageText: 'banned ambient name'});
- });
-
- it('does not match a custom exported method with the same name', () => {
- const config = {
- errorCode: ErrorCode.CONFORMANCE_PATTERN,
- errorMessage: 'banned ambient name',
- kind: PatternKind.BANNED_NAME,
- values: ['GLOBAL|eval']
- };
- const sources =
- [`export class Foo { static eval(s: string) { return s + "abc";} }
- var a = Foo.eval("123");`];
-
- const results =
- compileAndCheck(new ConformancePatternRule(config), ...sources);
- expect(results).toHaveNoFailures();
- });
-
- it('does not match a custom non-exported method with the same name', () => {
- const config = {
- errorCode: ErrorCode.CONFORMANCE_PATTERN,
- errorMessage: 'banned global name',
- kind: PatternKind.BANNED_NAME,
- values: ['GLOBAL|Foo.bar']
- };
- const sources = [`class Foo { static bar(s: string) {return s + "abc";} }
- var a = Foo.bar("123");`];
- const results =
- compileAndCheck(new ConformancePatternRule(config), ...sources);
- expect(results).toHaveNoFailures();
- });
-
- it('matches an initializer in a named declaration', () => {
- const config = {
- errorCode: ErrorCode.CONFORMANCE_PATTERN,
- errorMessage: 'banned ambient name',
- kind: PatternKind.BANNED_NAME,
- values: ['GLOBAL|open'],
- };
- const sources = ['const op = open;'];
-
- const results =
- compileAndCheck(new ConformancePatternRule(config), ...sources);
- expect(results).toHaveFailuresMatching(
- {matchedCode: 'open', messageText: 'banned ambient name'});
- });
- });
-
- describe('properties', () => {
- it('matches a static property', () => {
- const config = {
- errorCode: ErrorCode.CONFORMANCE_PATTERN,
- errorMessage: 'banned name with file path',
- kind: PatternKind.BANNED_NAME,
- values: ['./file_0|Foo.s']
- };
- const sources = [
- `export class Foo { static s : string; }`,
- `import {Foo} from './file_0';
- var a = Foo.s;`,
- ];
-
- const results =
- compileAndCheck(new ConformancePatternRule(config), ...sources);
- expect(results).toHaveFailuresMatching(
- {matchedCode: `s`, messageText: 'banned name with file path'});
- });
-
- it('does not match a property with a name overlapping an in-stock library',
- () => {
- const config = {
- errorCode: ErrorCode.CONFORMANCE_PATTERN,
- errorMessage: 'banned name without file path',
- kind: PatternKind.BANNED_NAME,
- values: ['GLOBAL|open']
- };
- const sources = [
- 'const elem = new XMLHttpRequest();',
- 'elem.open("get", "url");', // FQN of elem.open is
- // XMLHttpRequest.open and shouldn't be
- // banned
- ];
-
- const results =
- compileAndCheck(new ConformancePatternRule(config), ...sources);
- expect(results).toHaveNoFailures();
- });
- });
-
- describe('inheritance', () => {
- it('matches an inherited static property', () => {
- // This is a match because Moo inherits s from Foo.
- const config = {
- errorCode: ErrorCode.CONFORMANCE_PATTERN,
- errorMessage: 'banned name with file path',
- kind: PatternKind.BANNED_NAME,
- values: ['./file_0|Foo.s']
- };
- const sources = [
- `export class Foo { static s : string; }`,
- `import {Foo} from './file_0';
- export class Moo extends Foo { static t : string; }`,
- `import {Moo} from './file_1';
- var a = Moo.s;`,
- ];
-
- const results =
- compileAndCheck(new ConformancePatternRule(config), ...sources);
- expect(results).toHaveFailuresMatching(
- {matchedCode: `s`, messageText: 'banned name with file path'});
- });
-
- it('matches an inherited static method', () => {
- // This is a match because Moo inherits bar from Foo.
- const config = {
- errorCode: ErrorCode.CONFORMANCE_PATTERN,
- errorMessage: 'banned name with file path',
- kind: PatternKind.BANNED_NAME,
- values: ['./file_0|Foo.bar']
- };
- const sources = [
- `export class Foo { static bar(s: string) {return s + "abc";} }`,
- `import {Foo} from './file_0';
- export class Moo extends Foo { static far(s: string) {return s + "def";} }`,
- `import {Moo} from './file_1';
- Moo.bar("abc");`
- ];
-
- const results =
- compileAndCheck(new ConformancePatternRule(config), ...sources);
- expect(results).toHaveFailuresMatching(
- {matchedCode: `bar`, messageText: 'banned name with file path'});
- });
-
- it('does not match a redefined inherited static property', () => {
- // This is not a match because Moo redefines s.
- const config = {
- errorCode: ErrorCode.CONFORMANCE_PATTERN,
- errorMessage: 'banned name with file path',
- kind: PatternKind.BANNED_NAME,
- values: ['./file_0|Foo.s']
- };
- const sources = [
- `export class Foo { static s : string; }`,
- `import {Foo} from './file_0';
- export class Moo extends Foo { static s : string; }`,
- `import {Moo} from './file_1';
- var a = Moo.s;`,
- ];
-
- const results =
- compileAndCheck(new ConformancePatternRule(config), ...sources);
- expect(results).toHaveNoFailures();
- });
-
- it('does not match a redefined inherited static method', () => {
- // This is not a match because Moo redefines bar.
- const config = {
- errorCode: ErrorCode.CONFORMANCE_PATTERN,
- errorMessage: 'banned name with file path',
- kind: PatternKind.BANNED_NAME,
- values: ['./file_0|Foo.bar']
- };
- const sources = [
- `export class Foo { static bar(s: string) {return s + "abc";} }
- export class Moo extends Foo { static bar(s: string) {return s + "def";} }`,
- `import {Foo, Moo} from './file_0';
- Moo.bar("abc");`
- ];
-
- const results =
- compileAndCheck(new ConformancePatternRule(config), ...sources);
- expect(results).toHaveNoFailures();
- });
-
- it('does not match an interface\'s static method', () => {
- // This is not a match because even though bar specified is interface Moo,
- // its actual definition is in class Boo.
- const config = {
- errorCode: ErrorCode.CONFORMANCE_PATTERN,
- errorMessage: 'banned name with file path',
- kind: PatternKind.BANNED_NAME,
- values: ['./file_1|Moo.bar']
- };
- const sources = [
- `export class Foo { static bar(s: string) {return s + "abc";} }`,
- `import {Foo} from './file_0';
- export interface Moo extends Foo { }`,
- `import {Moo} from './file_1';
- export class Boo implements Moo { static bar(s: string) {return s + "def";} }`,
- `import {Boo} from './file_2';
- Boo.bar("abc");`,
- ];
-
- const results =
- compileAndCheck(new ConformancePatternRule(config), ...sources);
- expect(results).toHaveNoFailures();
- });
- });
-});
diff --git a/packages/concatjs/internal/tsetse/util/allowlist.ts b/packages/concatjs/internal/tsetse/util/allowlist.ts
deleted file mode 100644
index 07f64e9..0000000
--- a/packages/concatjs/internal/tsetse/util/allowlist.ts
+++ /dev/null
@@ -1,96 +0,0 @@
-/**
- * An exemption list entry, corresponding to a logical exemption rule. Use these
- * to distinguish between various logical reasons for exempting something:
- * for instance, tie these to particular bugs that needed to be exempted, per
- * legacy project, manually reviewed entries, and so on.
- *
- * Exemption lists are based on the file paths provided by the TS compiler, with
- * both regexp-based checks and prefix-based checks.
- *
- *
- * Follows the logic in
- * https://github.com/google/closure-compiler/blob/master/src/com/google/javascript/jscomp/conformance.proto.
- */
-export interface AllowlistEntry {
- /** The category corresponding to this entry. */
- readonly reason: ExemptionReason;
- /** Why is this okay to be exempted?. */
- readonly explanation?: string;
-
- /**
- * Regexps for the paths of files that will be ignored by the
- * ConformancePattern. Beware, escaping can be tricky.
- */
- readonly regexp?: readonly string[];
- /**
- * Prefixes for the paths of files that will be ignored by the
- * ConformancePattern.
- */
- readonly prefix?: readonly string[];
-}
-
-/**
- * The categories of exemption entries.
- */
-export enum ExemptionReason {
- /** No reason. */
- UNSPECIFIED,
- /** Code that has to be grandfathered in (no guarantees). */
- LEGACY,
- /**
- * Code that does not enter the scope of this particular check (no
- * guarantees).
- */
- OUT_OF_SCOPE,
- /** Manually reviewed exceptions (supposedly okay). */
- MANUALLY_REVIEWED
-}
-
-/**
- * A complete allowlist with all related AllowlistEntry grouped together, with
- * ExemptionReason ignored since it is purely for documentary purposes.
- */
-export class Allowlist {
- private readonly allowlistedPrefixes: readonly string[] = [];
- private readonly allowlistedRegExps: readonly RegExp[] = [];
- // To avoid repeated computation for allowlisting queries with the same file
- // path, create a memoizer to cache known results. This is useful in watch
- // mode (and possible in language service) when the same files can be compiled
- // repeatedly.
- private readonly allowlistMemoizer = new Map<string, boolean>();
-
- constructor(allowlistEntries?: AllowlistEntry[]) {
- if (allowlistEntries) {
- for (const e of allowlistEntries) {
- if (e.prefix) {
- this.allowlistedPrefixes =
- this.allowlistedPrefixes.concat(...e.prefix);
- }
- if (e.regexp) {
- this.allowlistedRegExps = this.allowlistedRegExps.concat(
- ...e.regexp.map(r => new RegExp(r)));
- }
- }
- }
- }
-
- isAllowlisted(filePath: string): boolean {
- if (this.allowlistMemoizer.has(filePath)) {
- return this.allowlistMemoizer.get(filePath)!;
- }
- for (const p of this.allowlistedPrefixes) {
- if (filePath.startsWith(p)) {
- this.allowlistMemoizer.set(filePath, true);
- return true;
- }
- }
- for (const re of this.allowlistedRegExps) {
- if (re.test(filePath)) {
- this.allowlistMemoizer.set(filePath, true);
- return true;
- }
- }
- this.allowlistMemoizer.set(filePath, false);
- return false;
- }
-}
diff --git a/packages/concatjs/internal/tsetse/util/allowlist_test.ts b/packages/concatjs/internal/tsetse/util/allowlist_test.ts
deleted file mode 100644
index d451c76..0000000
--- a/packages/concatjs/internal/tsetse/util/allowlist_test.ts
+++ /dev/null
@@ -1,163 +0,0 @@
-import 'jasmine';
-
-import {ConformancePatternRule, ErrorCode, PatternKind} from '../rules/conformance_pattern_rule';
-
-import {ExemptionReason} from './allowlist';
-import {compileAndCheck, customMatchers, getTempDirForAllowlist} from './testing/test_support';
-
-const tmpPrefixForAllowlist = getTempDirForAllowlist();
-const tmpRegexpForAllowlist =
- `^(?:${getTempDirForAllowlist().replace(/\\/g, '\\\\')})`;
-
-describe('ConformancePatternRule allowlist handling', () => {
- const source = `export {};\n` +
- `const q = document.createElement('q');\n` +
- `q.cite = 'some example string';\n`;
-
- // The initial config off which we run those checks.
- const baseConfig = {
- errorCode: ErrorCode.CONFORMANCE_PATTERN,
- errorMessage: 'do not cite',
- kind: PatternKind.BANNED_PROPERTY_WRITE,
- values: ['HTMLQuoteElement.prototype.cite'],
- };
-
- it('matches if no allowlist (sanity check)', () => {
- const config = {...baseConfig, allowlistEntries: []};
- const rule = new ConformancePatternRule(config);
- const results = compileAndCheck(rule, source);
-
- expect(results).toHaveNFailures(1);
- });
-
- it('matches if there is an empty allowlist group', () => {
- const config = {
- ...baseConfig,
- allowlistEntries: [{
- reason: ExemptionReason.UNSPECIFIED,
- }]
- };
- const rule = new ConformancePatternRule(config);
- const results = compileAndCheck(rule, source);
-
- expect(results).toHaveNFailures(1);
- });
-
- it('respects prefix-based allowlists (matching test)', () => {
- const config = {
- ...baseConfig,
- allowlistEntries: [{
- reason: ExemptionReason.UNSPECIFIED,
- prefix: [tmpPrefixForAllowlist],
- }]
- };
- const rule = new ConformancePatternRule(config);
- const results = compileAndCheck(rule, source);
-
- expect(results).toHaveNoFailures();
- });
-
- it('respects prefix-based allowlists (non-matching test)', () => {
- const config = {
- ...baseConfig,
- allowlistEntries: [{
- reason: ExemptionReason.UNSPECIFIED,
- prefix: ['/nowhere in particular/'],
- }]
- };
- const rule = new ConformancePatternRule(config);
- const results = compileAndCheck(rule, source);
-
- expect(results).toHaveNFailures(1);
- });
-
- it('respects regex-based allowlists', () => {
- const config = {
- ...baseConfig,
- allowlistEntries: [{
- reason: ExemptionReason.UNSPECIFIED,
- regexp: [`${tmpRegexpForAllowlist}.+[\\\\/]file_0\\.ts`]
- }]
- };
- const rule = new ConformancePatternRule(config);
- const results = compileAndCheck(rule, source);
-
- expect(results).toHaveNoFailures();
- });
-
- it('accepts several regex-based allowlists', () => {
- const config = {
- ...baseConfig,
- allowlistEntries: [{
- reason: ExemptionReason.UNSPECIFIED,
- regexp: [
- `${tmpRegexpForAllowlist}.+[\\\\/]file_0\\.ts`,
- `${tmpRegexpForAllowlist}.+[\\\\/]file_1\\.ts`
- ]
- }]
- };
- const rule = new ConformancePatternRule(config);
- // Testing two times the same file so that both regexps match.
- const results = compileAndCheck(rule, source, source);
-
- expect(results).toHaveNoFailures();
- });
-
- it('throws on creation of invalid regexps', () => {
- const config = {
- ...baseConfig,
- allowlistEntries: [{
- reason: ExemptionReason.UNSPECIFIED,
- regexp: ['(', '/tmp/', 'foo'],
- }]
- };
- expect(() => {
- // tslint:disable-next-line:no-unused-expression
- new ConformancePatternRule(config);
- }).toThrowError(/Invalid regular expression/);
- });
-
- it('test memoizer hit', () => {
- const config = {
- ...baseConfig,
- allowlistEntries: [{
- reason: ExemptionReason.UNSPECIFIED,
- regexp: [
- `${tmpRegexpForAllowlist}.+[\\\\/]file_0\\.ts`,
- ]
- }]
- };
- const rule = new ConformancePatternRule(config);
- // Compile the same file twice to make sure memoizer doesn't
- // break things.
- let results = compileAndCheck(rule, source);
- results = results.concat(compileAndCheck(rule, source));
-
- expect(results).toHaveNoFailures();
- });
-
- it('test memoizer miss', () => {
- const config = {
- ...baseConfig,
- allowlistEntries: [{
- reason: ExemptionReason.UNSPECIFIED,
- regexp: [
- `${tmpRegexpForAllowlist}.+[\\\\/]file_1\\.ts`,
- ],
- prefix: ['###PrefixNotExist###'],
- }]
- };
- const rule = new ConformancePatternRule(config);
- // Compile the same file twice to make sure memoizer doesn't
- // break things.
- let results = compileAndCheck(rule, source);
- expect(results).toHaveNFailures(1);
-
- results = compileAndCheck(rule, source);
- expect(results).toHaveNFailures(1);
- });
-});
-
-beforeEach(() => {
- jasmine.addMatchers(customMatchers);
-});
diff --git a/packages/concatjs/internal/tsetse/util/ast_tools.ts b/packages/concatjs/internal/tsetse/util/ast_tools.ts
deleted file mode 100644
index 57505cf..0000000
--- a/packages/concatjs/internal/tsetse/util/ast_tools.ts
+++ /dev/null
@@ -1,161 +0,0 @@
-/**
- * @fileoverview This is a collection of smaller utility functions to operate on
- * a TypeScript AST, used by JSConformance rules and elsewhere.
- */
-
-import * as ts from 'typescript';
-
-/**
- * Triggers increased verbosity in the rules.
- */
-let DEBUG = false;
-
-/**
- * Turns on or off logging for ConformancePatternRules.
- */
-export function setDebug(state: boolean) {
- DEBUG = state;
-}
-
-/**
- * Debug helper.
- */
-export function debugLog(msg: () => string) {
- if (DEBUG) {
- console.log(msg());
- }
-}
-
-/**
- * Returns `n`'s parents in order.
- */
-export function parents(n: ts.Node): ts.Node[] {
- const p = [];
- while (n.parent) {
- n = n.parent;
- p.push(n);
- }
- return p;
-}
-
-/**
- * Searches for something satisfying the given test in `n` or its children.
- */
-export function findInChildren(
- n: ts.Node, test: (n: ts.Node) => boolean): boolean {
- let toExplore: ts.Node[] = [n];
- let cur: ts.Node|undefined;
- while (cur = toExplore.pop()) {
- if (test(cur)) {
- return true;
- }
- // Recurse
- toExplore = toExplore.concat(cur.getChildren());
- }
- return false;
-}
-
-/**
- * Returns true if the pattern-based Rule should look at that node and consider
- * warning there. The goal is to make it easy to exclude on source files,
- * blocks, module declarations, JSDoc, lib.d.ts nodes, that kind of things.
- */
-export function shouldExamineNode(n: ts.Node) {
- // TODO(b/154674207): Only `isInStockLibraries` seems to be effective here.
- // Remove the others.
- return !(
- ts.isBlock(n) || ts.isModuleBlock(n) || ts.isModuleDeclaration(n) ||
- ts.isSourceFile(n) || (n.parent && ts.isTypeNode(n.parent)) ||
- ts.isJSDoc(n) || isInStockLibraries(n));
-}
-
-/**
- * Return whether the given Node is (or is in) a library included as default.
- * We currently look for a node_modules/typescript/ prefix, but this could
- * be expanded if needed.
- */
-export function isInStockLibraries(n: ts.Node|ts.SourceFile): boolean {
- const sourceFile = ts.isSourceFile(n) ? n : n.getSourceFile();
- if (sourceFile) {
- return sourceFile.fileName.indexOf('node_modules/typescript/') !== -1;
- } else {
- // the node is nowhere? Consider it as part of the core libs: we can't do
- // anything with it anyways, and it was likely included as default.
- return true;
- }
-}
-
-/**
- * Turns the given Symbol into its non-aliased version (which could be itself).
- * Returns undefined if given an undefined Symbol (so you can call
- * `dealias(typeChecker.getSymbolAtLocation(node))`).
- */
-export function dealias(
- symbol: ts.Symbol|undefined, tc: ts.TypeChecker): ts.Symbol|undefined {
- if (!symbol) {
- return undefined;
- }
- if (symbol.getFlags() & ts.SymbolFlags.Alias) {
- // Note: something that has only TypeAlias is not acceptable here.
- return dealias(tc.getAliasedSymbol(symbol), tc);
- }
- return symbol;
-}
-
-/**
- * Returns whether `n`'s parents are something indicating a type.
- */
-export function isPartOfTypeDeclaration(n: ts.Node) {
- return [n, ...parents(n)].some(
- p => p.kind === ts.SyntaxKind.TypeReference ||
- p.kind === ts.SyntaxKind.TypeLiteral);
-}
-
-/**
- * Returns whether `n` is under an import statement.
- */
-export function isPartOfImportStatement(n: ts.Node) {
- return [n, ...parents(n)].some(
- p => p.kind === ts.SyntaxKind.ImportDeclaration);
-}
-
-function isAllowlistedNamedDeclaration(n: ts.Node):
- n is ts.VariableDeclaration|ts.ClassDeclaration|ts.FunctionDeclaration|
- ts.MethodDeclaration|ts.PropertyDeclaration|ts.InterfaceDeclaration|
- ts.TypeAliasDeclaration|ts.EnumDeclaration|ts.ModuleDeclaration|
- ts.ImportEqualsDeclaration|ts.ExportDeclaration|ts.MissingDeclaration|
- ts.ImportClause|ts.ExportSpecifier|ts.ImportSpecifier {
- return ts.isVariableDeclaration(n) || ts.isClassDeclaration(n) ||
- ts.isFunctionDeclaration(n) || ts.isMethodDeclaration(n) ||
- ts.isPropertyDeclaration(n) || ts.isInterfaceDeclaration(n) ||
- ts.isTypeAliasDeclaration(n) || ts.isEnumDeclaration(n) ||
- ts.isModuleDeclaration(n) || ts.isImportEqualsDeclaration(n) ||
- ts.isExportDeclaration(n) || ts.isMissingDeclaration(n) ||
- ts.isImportClause(n) || ts.isExportSpecifier(n) ||
- ts.isImportSpecifier(n);
-}
-
-/** Returns whether `n` is being declared in a declaration statement. */
-export function isNameInDeclaration(n: ts.Node): boolean {
- const p = n.parent;
- if (p === undefined) return false;
-
- return (isAllowlistedNamedDeclaration(p) && p.name === n) ||
- // TODO(pwng) Double-check if these two cases are needed
- ts.isVariableDeclarationList(p) || ts.isImportDeclaration(p);
-}
-
-/**
- * If verbose, logs the given error that happened while walking n, with a
- * stacktrace.
- */
-export function logASTWalkError(verbose: boolean, n: ts.Node, e: Error) {
- let nodeText = `[error getting name for ${JSON.stringify(n)}]`;
- try {
- nodeText = '"' + n.getFullText().trim() + '"';
- } catch {
- }
- debugLog(
- () => `Walking node ${nodeText} failed with error ${e}.\n` +
- `Stacktrace:\n${e.stack}`);
-}
diff --git a/packages/concatjs/internal/tsetse/util/fixer.ts b/packages/concatjs/internal/tsetse/util/fixer.ts
deleted file mode 100644
index 75138ba..0000000
--- a/packages/concatjs/internal/tsetse/util/fixer.ts
+++ /dev/null
@@ -1,192 +0,0 @@
-import * as ts from 'typescript';
-import {Fix, IndividualChange} from '../failure';
-import {debugLog} from './ast_tools';
-
-/**
- * A Fixer turns Nodes (that are supposed to have been matched before) into a
- * Fix. This is meant to be implemented by Rule implementers (or
- * ban-preset-pattern users). See also `buildReplacementFixer` for a simpler way
- * of implementing a Fixer.
- */
-export interface Fixer {
- getFixForFlaggedNode(node: ts.Node): Fix|undefined;
-}
-
-/**
- * A simple Fixer builder based on a function that looks at a node, and
- * output either nothing, or a replacement. If this is too limiting, implement
- * Fixer instead.
- */
-export function buildReplacementFixer(
- potentialReplacementGenerator: (node: ts.Node) =>
- ({replaceWith: string} | undefined)): Fixer {
- return {
- getFixForFlaggedNode: (n: ts.Node): Fix | undefined => {
- const partialFix = potentialReplacementGenerator(n);
- if (!partialFix) {
- return;
- }
- return {
- changes: [{
- sourceFile: n.getSourceFile(),
- start: n.getStart(),
- end: n.getEnd(),
- replacement: partialFix.replaceWith,
- }],
- };
- }
- };
-}
-
-// TODO(rjamet): Both maybeAddNamedImport and maybeAddNamespacedImport are too
-// hard to read to my taste. This could probably be improved upon by being more
-// functionnal, to show the filter passes and get rid of the continues and
-// returns (which are confusing).
-
-/**
- * Builds an IndividualChange that imports the required symbol from the given
- * file under the given name. This might reimport the same thing twice in some
- * cases, but it will always make it available under the right name (though
- * its name might collide with other imports, as we don't currently check for
- * that).
- */
-export function maybeAddNamedImport(
- source: ts.SourceFile, importWhat: string, fromFile: string,
- importAs?: string, tazeComment?: string): IndividualChange|undefined {
- const importStatements = source.statements.filter(ts.isImportDeclaration);
- const importSpecifier =
- importAs ? `${importWhat} as ${importAs}` : importWhat;
-
- for (const iDecl of importStatements) {
- const parsedDecl = maybeParseImportNode(iDecl);
- if (!parsedDecl || parsedDecl.fromFile !== fromFile) {
- // Not an import from the right file, or couldn't understand the import.
- continue; // Jump to the next import.
- }
- if (ts.isNamespaceImport(parsedDecl.namedBindings)) {
- debugLog(() => `... but it's a wildcard import`);
- continue; // Jump to the next import.
- }
-
- // Else, bindings is a NamedImports. We can now search whether the right
- // symbol is there under the right name.
- const foundRightImport = parsedDecl.namedBindings.elements.some(
- iSpec => iSpec.propertyName ?
- iSpec.name.getText() === importAs && // import {foo as bar}
- iSpec.propertyName.getText() === importWhat :
- iSpec.name.getText() === importWhat); // import {foo}
-
- if (foundRightImport) {
- debugLog(
- () => `"${iDecl.getFullText()}" imports ${importWhat} as we want.`);
- return; // Our request is already imported under the right name.
- }
-
- // Else, insert our symbol in the list of imports from that file.
- debugLog(() => `No named imports from that file, generating new fix`);
- return {
- start: parsedDecl.namedBindings.elements[0].getStart(),
- end: parsedDecl.namedBindings.elements[0].getStart(),
- sourceFile: source,
- replacement: `${importSpecifier}, `,
- };
- }
-
- // If we get here, we didn't find anything imported from the wanted file, so
- // we'll need the full import string. Add it after the last import,
- // and let clang-format handle the rest.
- const newImportStatement = `import {${importSpecifier}} from '${fromFile}';` +
- (tazeComment ? ` ${tazeComment}\n` : `\n`);
- const insertionPosition = importStatements.length ?
- importStatements[importStatements.length - 1].getEnd() + 1 :
- 0;
- return {
- start: insertionPosition,
- end: insertionPosition,
- sourceFile: source,
- replacement: newImportStatement,
- };
-}
-
-/**
- * Builds an IndividualChange that imports the required namespace from the given
- * file under the given name. This might reimport the same thing twice in some
- * cases, but it will always make it available under the right name (though
- * its name might collide with other imports, as we don't currently check for
- * that).
- */
-export function maybeAddNamespaceImport(
- source: ts.SourceFile, fromFile: string, importAs: string,
- tazeComment?: string): IndividualChange|undefined {
- const importStatements = source.statements.filter(ts.isImportDeclaration);
-
- const hasTheRightImport = importStatements.some(iDecl => {
- const parsedDecl = maybeParseImportNode(iDecl);
- if (!parsedDecl || parsedDecl.fromFile !== fromFile) {
- // Not an import from the right file, or couldn't understand the import.
- return false;
- }
- debugLog(() => `"${iDecl.getFullText()}" is an import from the right file`);
-
- if (ts.isNamedImports(parsedDecl.namedBindings)) {
- debugLog(() => `... but it's a named import`);
- return false; // irrelevant to our namespace imports
- }
- // Else, bindings is a NamespaceImport.
- if (parsedDecl.namedBindings.name.getText() !== importAs) {
- debugLog(() => `... but not the right name, we need to reimport`);
- return false;
- }
- debugLog(() => `... and the right name, no need to reimport`);
- return true;
- });
-
- if (!hasTheRightImport) {
- const insertionPosition = importStatements.length ?
- importStatements[importStatements.length - 1].getEnd() + 1 :
- 0;
- return {
- start: insertionPosition,
- end: insertionPosition,
- sourceFile: source,
- replacement: tazeComment ?
- `import * as ${importAs} from '${fromFile}'; ${tazeComment}\n` :
- `import * as ${importAs} from '${fromFile}';\n`,
- };
- }
- return;
-}
-
-/**
- * This tries to make sense of an ImportDeclaration, and returns the interesting
- * parts, undefined if the import declaration is valid but not understandable by
- * the checker.
- */
-function maybeParseImportNode(iDecl: ts.ImportDeclaration): {
- namedBindings: ts.NamedImportBindings|ts.NamespaceImport,
- fromFile: string
-}|undefined {
- if (!iDecl.importClause) {
- // something like import "./file";
- debugLog(
- () =>
- `Ignoring import without imported symbol: ${iDecl.getFullText()}`);
- return;
- }
- if (iDecl.importClause.name || !iDecl.importClause.namedBindings) {
- // Seems to happen in defaults imports like import Foo from 'Bar'.
- // Not much we can do with that when trying to get a hold of some symbols,
- // so just ignore that line (worst case, we'll suggest another import
- // style).
- debugLog(() => `Ignoring import: ${iDecl.getFullText()}`);
- return;
- }
- if (!ts.isStringLiteral(iDecl.moduleSpecifier)) {
- debugLog(() => `Ignoring import whose module specifier is not literal`);
- return;
- }
- return {
- namedBindings: iDecl.importClause.namedBindings,
- fromFile: iDecl.moduleSpecifier.text
- };
-}
diff --git a/packages/concatjs/internal/tsetse/util/fixer_test.ts b/packages/concatjs/internal/tsetse/util/fixer_test.ts
deleted file mode 100644
index 470ffce..0000000
--- a/packages/concatjs/internal/tsetse/util/fixer_test.ts
+++ /dev/null
@@ -1,228 +0,0 @@
-import 'jasmine';
-import * as ts from 'typescript';
-import {Failure, Fix} from '../failure';
-import {ConformancePatternRule, ErrorCode, PatternKind} from '../rules/conformance_pattern_rule';
-import {buildReplacementFixer, Fixer, maybeAddNamedImport, maybeAddNamespaceImport} from './fixer';
-import {compile, compileAndCheck, customMatchers} from './testing/test_support';
-
-const uppercaseFixer: Fixer = {
- getFixForFlaggedNode(node: ts.Node): Fix {
- return {
- changes: [{
- start: node.getStart(),
- end: node.getEnd(),
- replacement: node.getText().toUpperCase(),
- sourceFile: node.getSourceFile(),
- }]
- };
- }
-};
-
-const uppercaseFixerBuilt: Fixer = buildReplacementFixer((node: ts.Node) => {
- return {replaceWith: node.getText().toUpperCase()};
-});
-
-// The initial config and source off which we run those checks.
-const baseConfig = {
- errorCode: ErrorCode.CONFORMANCE_PATTERN,
- errorMessage: 'found citation',
- kind: PatternKind.BANNED_PROPERTY_WRITE,
- values: ['HTMLQuoteElement.prototype.cite'],
-};
-
-const source = `export {};\n` +
- `const q = document.createElement('q');\n` +
- `q.cite = 'some example string';\n`;
-
-describe('ConformancePatternRule\'s fixer', () => {
- describe('Generates basic fixes', () => {
- it('for a single match', () => {
- const rule = new ConformancePatternRule(baseConfig, uppercaseFixer);
- const results = compileAndCheck(rule, source);
-
- expect(results).toHaveFailuresMatching({
- matchedCode: `q.cite = 'some example string'`,
- messageText: 'found citation',
- fix: [
- {start: 50, end: 80, replacement: `Q.CITE = 'SOME EXAMPLE STRING'`}
- ]
- });
- });
-
- it('for a single match (alternate fixer)', () => {
- const rule = new ConformancePatternRule(baseConfig, uppercaseFixerBuilt);
- const results = compileAndCheck(rule, source);
-
- expect(results).toHaveFailuresMatching({
- matchedCode: `q.cite = 'some example string'`,
- messageText: 'found citation',
- fix: [
- {start: 50, end: 80, replacement: `Q.CITE = 'SOME EXAMPLE STRING'`}
- ]
- });
- });
-
- it('for several matches', () => {
- const rule = new ConformancePatternRule(baseConfig, uppercaseFixer);
- const sourceTwoMatches =
- source + `q.cite = 'some other example string';\n`;
- const results = compileAndCheck(rule, sourceTwoMatches);
-
- expect(results).toHaveFailuresMatching(
- {
- matchedCode: `q.cite = 'some example string'`,
- messageText: 'found citation',
- fix: [{
- start: 50,
- end: 80,
- replacement: `Q.CITE = 'SOME EXAMPLE STRING'`
- }]
- },
- {
- matchedCode: `q.cite = 'some other example string'`,
- messageText: 'found citation',
- fix: [{
- start: 82,
- end: 118,
- replacement: `Q.CITE = 'SOME OTHER EXAMPLE STRING'`
- }]
- });
-
- expect(results[0].fixToReadableStringInContext())
- .toBe(
- `Suggested fix:\n` +
- `- Replace the full match with: Q.CITE = 'SOME EXAMPLE STRING'`);
- expect(results[1].fixToReadableStringInContext())
- .toBe(
- `Suggested fix:\n` +
- `- Replace the full match with: Q.CITE = 'SOME OTHER EXAMPLE STRING'`);
- });
- });
-
- describe('adds imports', () => {
- const addNamedImportFixer: Fixer = {
- getFixForFlaggedNode(n: ts.Node): Fix |
- undefined {
- const changes = [];
- const ic1 =
- maybeAddNamedImport(n.getSourceFile(), 'foo', './file_1', 'bar');
- if (ic1) {
- changes.push(ic1);
- }
- const ic2 =
- maybeAddNamedImport(n.getSourceFile(), 'foo2', './file_2', 'bar2');
- if (ic2) {
- changes.push(ic2);
- }
- return changes.length ? {changes} : undefined;
- }
- };
-
- it('maybeAddNamedImport additions', () => {
- const results = compileAndCheck(
- new ConformancePatternRule(baseConfig, addNamedImportFixer), source);
-
- expect(results[0]).toHaveFixMatching([
- {
- start: 0,
- end: 0,
- replacement: `import {foo as bar} from './file_1';\n`
- },
- {
- start: 0,
- end: 0,
- replacement: `import {foo2 as bar2} from './file_2';\n`
- }
- ]);
- expect(results[0].fixToReadableStringInContext())
- .toBe(
- `Suggested fix:\n` +
- `- Add new import: import {foo as bar} from './file_1';\n` +
- `- Add new import: import {foo2 as bar2} from './file_2';`);
- });
-
- it('maybeAddNamedImport already there', () => {
- const results = compileAndCheck(
- new ConformancePatternRule(baseConfig, addNamedImportFixer),
- 'import {foo as bar} from \'./file_1\';\n' + source,
- 'export const foo = 1;');
-
- expect(results[0]).toHaveFixMatching([{
- start: 37,
- end: 37,
- replacement: `import {foo2 as bar2} from './file_2';\n`
- }]);
- expect(results[0].fixToReadableStringInContext())
- .toBe(
- `Suggested fix:\n` +
- `- Add new import: import {foo2 as bar2} from './file_2';`);
- });
-
- it('maybeAddNamedImport different name', () => {
- const results = compileAndCheck(
- new ConformancePatternRule(baseConfig, addNamedImportFixer),
- 'import {foo as baz} from \'./file_1\';\n' + source,
- 'export const foo = 1;');
-
- expect(results[0]).toHaveFixMatching([
- {start: 8, end: 8, replacement: `foo as bar, `}, {
- start: 37,
- end: 37,
- replacement: `import {foo2 as bar2} from './file_2';\n`
- }
- ]);
- expect(results[0].fixToReadableStringInContext())
- .toBe(
- `Suggested fix:\n` +
- `- Insert at line 1, char 9: foo as bar,\n` +
- `- Add new import: import {foo2 as bar2} from './file_2';`);
- });
-
- it('maybeAddNamespacedImport', () => {
- const addNamespacedImportFixer: Fixer = {
- getFixForFlaggedNode(n: ts.Node): Fix |
- undefined {
- const ic =
- maybeAddNamespaceImport(n.getSourceFile(), './file_1', 'foo');
- if (ic) return {changes: [ic]};
- return;
- }
- };
- const results = compileAndCheck(
- new ConformancePatternRule(baseConfig, addNamespacedImportFixer),
- source);
-
- expect(results[0]).toHaveFixMatching([
- {start: 0, end: 0, replacement: `import * as foo from './file_1';\n`}
- ]);
- });
- });
-
- describe('the logic for location->text transforms', () => {
- const sourceFile = compile(`let a;\nlet b;\n`)
- .getSourceFiles()
- .filter(f => f.fileName.indexOf('file_0') !== -1)[0];
- // let a;\nlet b;\n
- // 0123456 7890123 Positions
- // 1234567 1234567 Expected result in characters
-
- it('stringifies as expected', () => {
- // Only the sourceFile matters here.
- const failure = new Failure(sourceFile, NaN, NaN, 'whatever', NaN);
-
- expect(failure.readableRange(0, 0)).toBe('at line 1, char 1');
- expect(failure.readableRange(1, 1)).toBe('at line 1, char 2');
- expect(failure.readableRange(0, 1)).toBe('line 1, from char 1 to 2');
- expect(failure.readableRange(0, 1)).toBe('line 1, from char 1 to 2');
- expect(failure.readableRange(7, 7)).toBe('at line 2, char 1');
- expect(failure.readableRange(0, 7))
- .toBe('from line 1, char 1 to line 2, char 1');
- });
- });
-});
-
-
-
-beforeEach(() => {
- jasmine.addMatchers(customMatchers);
-});
diff --git a/packages/concatjs/internal/tsetse/util/is_literal.ts b/packages/concatjs/internal/tsetse/util/is_literal.ts
deleted file mode 100644
index 2f44ce2..0000000
--- a/packages/concatjs/internal/tsetse/util/is_literal.ts
+++ /dev/null
@@ -1,108 +0,0 @@
-import * as ts from 'typescript';
-import {findInChildren} from './ast_tools';
-
-/**
- * Determines if the given ts.Node is literal enough for security purposes. This
- * is true when the value is built from compile-time constants, with a certain
- * tolerance for indirection in order to make this more user-friendly.
- *
- * This considers a few different things. We accept
- * - What TS deems literal (literal strings, literal numbers, literal booleans,
- * enum literals),
- * - Binary operations of two expressions that we accept (including
- * concatenation),
- * - Template interpolations of what we accept,
- * - `x?y:z` constructions, if we accept `y` and `z`
- * - Variables that are const, and initialized with an expression we accept
- *
- * And to prevent bypasses, expressions that include casts are not accepted, and
- * this checker does not follow imports.
- */
-export function isLiteral(typeChecker: ts.TypeChecker, node: ts.Node): boolean {
- if (ts.isBinaryExpression(node) &&
- node.operatorToken.kind === ts.SyntaxKind.PlusToken) {
- // Concatenation is fine, if the parts are literals.
- return (
- isLiteral(typeChecker, node.left) &&
- isLiteral(typeChecker, node.right));
- } else if (ts.isTemplateExpression(node)) {
- // Same for template expressions.
- return node.templateSpans.every(span => {
- return isLiteral(typeChecker, span.expression);
- });
- } else if (ts.isTemplateLiteral(node)) {
- // and literals (in that order).
- return true;
- } else if (ts.isConditionalExpression(node)) {
- return isLiteral(typeChecker, node.whenTrue) &&
- isLiteral(typeChecker, node.whenFalse);
- } else if (ts.isIdentifier(node)) {
- return isUnderlyingValueAStringLiteral(node, typeChecker);
- }
-
- const hasCasts = findInChildren(node, ts.isAsExpression);
-
- return !hasCasts && isLiteralAccordingToItsType(typeChecker, node);
-}
-
-/**
- * Given an identifier, this function goes around the AST to determine
- * whether we should consider it a string literal, on a best-effort basis. It
- * is an approximation, but should never have false positives.
- */
-function isUnderlyingValueAStringLiteral(
- identifier: ts.Identifier, tc: ts.TypeChecker) {
- // The identifier references a value, and we try to follow the trail: if we
- // find a variable declaration for the identifier, and it was declared as a
- // const (so we know it wasn't altered along the way), then the value used
- // in the declaration is the value our identifier references. That means we
- // should look at the value used in its initialization (by applying the same
- // rules as before).
- // Since we're best-effort, if a part of that operation failed due to lack
- // of support (for instance, the identifier was imported), then we fail
- // closed and don't consider the value a literal.
-
- // TODO(rjamet): This doesn't follow imports, which is a feature that we need
- // in a fair amount of cases.
- return getVariableDeclarationsInSameFile(identifier, tc)
- .filter(isConst)
- .some(d => d.initializer !== undefined && isLiteral(tc, d.initializer));
-}
-
-/**
- * Returns whether this thing is a literal based on TS's understanding. This is
- * only looking at the local type, so there's no magic in that function.
- */
-function isLiteralAccordingToItsType(
- typeChecker: ts.TypeChecker, node: ts.Node): boolean {
- const nodeType = typeChecker.getTypeAtLocation(node);
- return (nodeType.flags &
- (ts.TypeFlags.StringLiteral | ts.TypeFlags.NumberLiteral |
- ts.TypeFlags.BooleanLiteral | ts.TypeFlags.EnumLiteral)) !== 0;
-}
-
-/**
- * Follows the symbol behind the given identifier, assuming it is a variable,
- * and return all the variable declarations we can find that match it in the
- * same file.
- */
-function getVariableDeclarationsInSameFile(
- node: ts.Identifier, tc: ts.TypeChecker): ts.VariableDeclaration[] {
- const symbol = tc.getSymbolAtLocation(node);
- if (!symbol) {
- return [];
- }
- const decls = symbol.getDeclarations();
- if (!decls) {
- return [];
- }
- return decls.filter(ts.isVariableDeclaration);
-}
-
-// Tests whether the given variable declaration is Const.
-function isConst(varDecl: ts.VariableDeclaration): boolean {
- return Boolean(
- varDecl && varDecl.parent &&
- ts.isVariableDeclarationList(varDecl.parent) &&
- varDecl.parent.flags & ts.NodeFlags.Const);
-}
diff --git a/packages/concatjs/internal/tsetse/util/is_literal_test.ts b/packages/concatjs/internal/tsetse/util/is_literal_test.ts
deleted file mode 100644
index 92b49d6..0000000
--- a/packages/concatjs/internal/tsetse/util/is_literal_test.ts
+++ /dev/null
@@ -1,69 +0,0 @@
-import 'jasmine';
-import {isInStockLibraries} from './ast_tools';
-import {isLiteral} from './is_literal';
-import {compile} from './testing/test_support';
-
-describe('isLiteral', () => {
- // Different platforms pull in different files (or from different
- // paths) when compiling a .ts file. We only want to inspect source
- // defined in the tests. This pattern is determinted by `compile`.
- const testSrcNamePattern = /file_\d+.ts$/;
-
- it('understands constants', () => {
- // Keep these to single-expression programs.
- const constantExpressionsSources = [
- `'hello'`,
- `'hello' + 'hi'`,
- `1`,
- `1 + 1`,
- '`abcdef`',
- '`abcd${"ef"}`',
- '`abcd${1+1}`+`hi`',
- `1 ? 'hi' : 'hello'`,
- `window.name ? 'hi' : 'hello'`,
- ];
-
- // We don't bother with a rule for this one.
- const constantProgram = compile(...constantExpressionsSources);
- const constantCompiledSources = constantProgram.getSourceFiles();
-
- const constantExpressions =
- constantCompiledSources.filter(s => testSrcNamePattern.test(s.fileName))
- .map(s => s.statements[0].getChildren()[0]);
-
- const constantTc = constantProgram.getTypeChecker();
- for (const expr of constantExpressions) {
- expect(isLiteral(constantTc, expr))
- .toBe(
- true,
- `Expected "${expr.getFullText()}" to be considered constant.`);
- }
- });
-
- it('understands non-constants', () => {
- const nonconstantExpressionsSources = [
- `window.name`,
- `'hello' + window.name`,
- `window.name + 'hello'`,
- '`abcd${window.name}`',
- `1 ? window.name : 'hello'`,
- `1 ? 'hello' : window.name`,
- ];
-
- const nonconstantProgram = compile(...nonconstantExpressionsSources);
- const nonconstantCompiledSources = nonconstantProgram.getSourceFiles();
- const nonconstantTc = nonconstantProgram.getTypeChecker();
- const nonconstantExpressions =
- nonconstantCompiledSources
- .filter(s => testSrcNamePattern.test(s.fileName))
- .map(s => s.statements[0].getChildren()[0]);
-
- for (const expr of nonconstantExpressions) {
- expect(isLiteral(nonconstantTc, expr))
- .toBe(
- false,
- `Expected "${
- expr.getFullText()}" not to be considered constant.`);
- }
- });
-});
diff --git a/packages/concatjs/internal/tsetse/util/pattern_config.ts b/packages/concatjs/internal/tsetse/util/pattern_config.ts
deleted file mode 100644
index 7d0aa39..0000000
--- a/packages/concatjs/internal/tsetse/util/pattern_config.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-import {AllowlistEntry} from './allowlist';
-
-/**
- * The list of supported patterns useable in ConformancePatternRule. The
- * patterns whose name match JSConformance patterns should behave similarly (see
- * https://github.com/google/closure-compiler/wiki/JS-Conformance-Framework)
- */
-export enum PatternKind {
- /** Ban use of fully distinguished names. */
- BANNED_NAME = 'banned-name',
- /** Ban use of instance properties */
- BANNED_PROPERTY = 'banned-property',
- /**
- * Ban instance property, like BANNED_PROPERTY but where reads of the
- * property are allowed.
- */
- BANNED_PROPERTY_WRITE = 'banned-property-write',
- /**
- * Ban instance property write unless the property is assigned a constant
- * literal.
- */
- BANNED_PROPERTY_NON_CONSTANT_WRITE = 'banned-property-non-constant-write',
-}
-
-/**
- * A config for `PatternEngine`.
- */
-export interface PatternEngineConfig {
- /**
- * Values have a pattern-specific syntax.
- *
- * TODO(rjamet): We'll document them, but for now see each patternKind's
- * tests for examples.
- */
- values: string[];
-
- /** The error code assigned to this pattern. */
- errorCode: number;
-
- /** The error message this pattern will create. */
- errorMessage: string;
-
- /** A list of allowlist blocks. */
- allowlistEntries?: AllowlistEntry[];
-}
-
-/**
- * A config for `ConformancePatternRule`.
- */
-export interface PatternRuleConfig extends PatternEngineConfig {
- kind: PatternKind;
-
- /**
- * An optional name for that rule, which will be the rule's `ruleName`.
- * Should be lower-dashed-case.
- */
- name?: string;
-}
diff --git a/packages/concatjs/internal/tsetse/util/pattern_engines/name_engine.ts b/packages/concatjs/internal/tsetse/util/pattern_engines/name_engine.ts
deleted file mode 100644
index 27c97c2..0000000
--- a/packages/concatjs/internal/tsetse/util/pattern_engines/name_engine.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import * as ts from 'typescript';
-import {Checker} from '../../checker';
-import {ErrorCode} from '../../error_code';
-import {AbsoluteMatcher} from '../absolute_matcher';
-import {debugLog} from '../ast_tools';
-import {Fixer} from '../fixer';
-import {PatternEngine} from './pattern_engine';
-
-function checkId(
- tc: ts.TypeChecker, n: ts.Identifier,
- matcher: AbsoluteMatcher): ts.Identifier|undefined {
- debugLog(() => `inspecting ${n.getText().trim()}`);
- if (!matcher.matches(n, tc)) {
- debugLog(() => 'Not the right global name.');
- return;
- }
- return n;
-}
-
-/** Engine for the BANNED_NAME pattern */
-export class NameEngine extends PatternEngine {
- register(checker: Checker) {
- for (const value of this.config.values) {
- const matcher = new AbsoluteMatcher(value);
-
- // `String.prototype.split` only returns emtpy array when both the string
- // and the splitter are empty. Here we should be able to safely assert pop
- // returns a non-null result.
- const bannedIdName = matcher.bannedName.split('.').pop()!;
- checker.onNamedIdentifier(
- bannedIdName,
- this.wrapCheckWithAllowlistingAndFixer(
- (tc, n: ts.Identifier) => checkId(tc, n, matcher)),
- this.config.errorCode);
- }
- }
-}
diff --git a/packages/concatjs/internal/tsetse/util/pattern_engines/name_engine_test.ts b/packages/concatjs/internal/tsetse/util/pattern_engines/name_engine_test.ts
deleted file mode 100644
index ce39875..0000000
--- a/packages/concatjs/internal/tsetse/util/pattern_engines/name_engine_test.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-import 'jasmine';
-import {ConformancePatternRule, ErrorCode, PatternKind} from '../../rules/conformance_pattern_rule';
-import {compileAndCheck, customMatchers} from '../../util/testing/test_support';
-
-describe('BANNED_NAME', () => {
- it('matches simple example of globals', () => {
- const config = {
- errorCode: ErrorCode.CONFORMANCE_PATTERN,
- errorMessage: 'no Infinity',
- kind: PatternKind.BANNED_NAME,
- values: ['GLOBAL|Infinity']
- };
- const source = `Infinity; 1+1;`;
- const results = compileAndCheck(new ConformancePatternRule(config), source);
-
- expect(results).toHaveFailuresMatching(
- {matchedCode: `Infinity`, messageText: 'no Infinity'});
- });
-
- it('matches namespaced globals', () => {
- const config = {
- errorCode: ErrorCode.CONFORMANCE_PATTERN,
- errorMessage: 'no blob url',
- kind: PatternKind.BANNED_NAME,
- values: ['GLOBAL|URL.createObjectURL']
- };
- const source = `URL.createObjectURL({});`;
- const results = compileAndCheck(new ConformancePatternRule(config), source);
-
- expect(results).toHaveFailuresMatching(
- {matchedCode: `createObjectURL`, messageText: 'no blob url'});
- });
-
- it('does not choke on type aliases', () => {
- // This test case checks that we do not regress on the AbsoluteMatcher's
- // handling of type aliases. In dealias, from utils/ast_tools.ts, the
- // typechecker's getAliasedSymbol function should only be called with
- // Symbols that verify ts.SymbolFlags.Alias, and ts.SymbolFlags.TypeAlias is
- // not acceptable (the typechecker will throw).
-
- const config = {
- errorCode: ErrorCode.CONFORMANCE_PATTERN,
- errorMessage: 'should not trigger',
- kind: PatternKind.BANNED_NAME,
- values: ['ANY_SYMBOL|whatever']
- };
- const sources = [
- `export type Foo = {bar: number, baz: (x:string)=>void}`,
- `import {Foo} from './file_0';
- export const c: Foo["baz"] = (x:string)=>{};`,
- `import {c} from './file_1'; c(window.name);`
- ];
- const results =
- compileAndCheck(new ConformancePatternRule(config), ...sources);
-
- expect(results).toHaveNoFailures();
- });
-});
-
-beforeEach(() => {
- jasmine.addMatchers(customMatchers);
-});
diff --git a/packages/concatjs/internal/tsetse/util/pattern_engines/pattern_engine.ts b/packages/concatjs/internal/tsetse/util/pattern_engines/pattern_engine.ts
deleted file mode 100644
index df15ab5..0000000
--- a/packages/concatjs/internal/tsetse/util/pattern_engines/pattern_engine.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-import * as path from 'path';
-import * as ts from 'typescript';
-
-import {Checker} from '../../checker';
-import {Fix} from '../../failure';
-import {Allowlist} from '../../util/allowlist';
-import {Fixer} from '../../util/fixer';
-import {PatternEngineConfig} from '../../util/pattern_config';
-import {shouldExamineNode} from '../ast_tools';
-
-/**
- * A patternEngine is the logic that handles a specific PatternKind.
- */
-export abstract class PatternEngine {
- private readonly allowlist: Allowlist;
-
- constructor(
- protected readonly config: PatternEngineConfig,
- protected readonly fixer?: Fixer) {
- this.allowlist = new Allowlist(config.allowlistEntries);
- }
-
- /**
- * `register` will be called by the ConformanceRule to tell Tsetse the
- * PatternEngine will handle matching. Implementations should use
- * `checkAndFilterResults` as a wrapper for `check`.
- */
- abstract register(checker: Checker): void;
-
- /**
- * A composer that wraps checking functions with code handling aspects of the
- * analysis that are not engine-specific, and which defers to the
- * subclass-specific logic afterwards. Subclasses should transform their
- * checking logic with this composer before registered on the checker.
- */
- protected wrapCheckWithAllowlistingAndFixer<T extends ts.Node>(
- checkFunction: (tc: ts.TypeChecker, n: T) => ts.Node |
- undefined): (c: Checker, n: T) => void {
- return (c: Checker, n: T) => {
- const sf = n.getSourceFile();
- if (!shouldExamineNode(n) || sf.isDeclarationFile) {
- return;
- }
- const matchedNode = checkFunction(c.typeChecker, n);
- if (matchedNode &&
- !this.allowlist.isAllowlisted(path.resolve(sf.fileName))) {
- const fix: Fix|undefined = this.fixer ?
- this.fixer.getFixForFlaggedNode(matchedNode) :
- undefined;
- c.addFailureAtNode(matchedNode, this.config.errorMessage, fix);
- }
- }
- }
-}
diff --git a/packages/concatjs/internal/tsetse/util/pattern_engines/property_engine.ts b/packages/concatjs/internal/tsetse/util/pattern_engines/property_engine.ts
deleted file mode 100644
index 5cfc7af..0000000
--- a/packages/concatjs/internal/tsetse/util/pattern_engines/property_engine.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-import * as ts from 'typescript';
-
-import {Checker} from '../../checker';
-import {ErrorCode} from '../../error_code';
-import {debugLog} from '../ast_tools';
-import {Fixer} from '../fixer';
-import {PropertyMatcher} from '../property_matcher';
-
-import {PatternEngine} from './pattern_engine';
-
-/** Match an AST node with a property matcher. */
-export function matchProperty(
- tc: ts.TypeChecker,
- n: ts.PropertyAccessExpression|ts.ElementAccessExpression,
- matcher: PropertyMatcher): ts.Node|undefined {
- debugLog(() => `inspecting ${n.getText().trim()}`);
- if (!matcher.typeMatches(tc.getTypeAtLocation(n.expression))) return;
- return n;
-}
-
-/**
- * Engine for the BANNED_PROPERTY pattern. It captures accesses to property
- * matching the spec regardless whether it's a read or write.
- */
-export class PropertyEngine extends PatternEngine {
- protected registerWith(checker: Checker, matchNode: typeof matchProperty) {
- for (const value of this.config.values) {
- const matcher = PropertyMatcher.fromSpec(value);
- checker.onNamedPropertyAccess(
- matcher.bannedProperty,
- this.wrapCheckWithAllowlistingAndFixer(
- (tc, n) => matchNode(tc, n, matcher)),
- this.config.errorCode);
-
- checker.onStringLiteralElementAccess(
- matcher.bannedProperty,
- this.wrapCheckWithAllowlistingAndFixer(
- (tc, n) => matchNode(tc, n, matcher)),
- this.config.errorCode);
- }
- }
-
- register(checker: Checker) {
- this.registerWith(checker, matchProperty);
- }
-}
diff --git a/packages/concatjs/internal/tsetse/util/pattern_engines/property_engine_test.ts b/packages/concatjs/internal/tsetse/util/pattern_engines/property_engine_test.ts
deleted file mode 100644
index 121e5e6..0000000
--- a/packages/concatjs/internal/tsetse/util/pattern_engines/property_engine_test.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import 'jasmine';
-
-import {ConformancePatternRule, ErrorCode, PatternKind} from '../../rules/conformance_pattern_rule';
-import {compileAndCheck, customMatchers} from '../testing/test_support';
-
-describe('BANNED_PROPERTY', () => {
- beforeEach(() => {
- jasmine.addMatchers(customMatchers);
- });
-
- it('matches a trivial example', () => {
- const config = {
- errorCode: ErrorCode.CONFORMANCE_PATTERN,
- errorMessage: 'No Location#href access',
- kind: PatternKind.BANNED_PROPERTY,
- values: ['Location.prototype.href'],
- };
- const source = `const href = location.href + location['href'];`;
- const results = compileAndCheck(new ConformancePatternRule(config), source);
-
- expect(results).toHaveFailuresMatching(
- {
- matchedCode: 'location.href',
- messageText: 'No Location#href access',
- },
- {
- matchedCode: `location['href']`,
- messageText: 'No Location#href access',
- });
- });
-
- it('matches element access expressions with string literal types', () => {
- const config = {
- errorCode: ErrorCode.CONFORMANCE_PATTERN,
- errorMessage: 'No Location#href access',
- kind: PatternKind.BANNED_PROPERTY,
- values: ['Location.prototype.href'],
- };
- const source = `declare const key: 'href'; const href = location[key];`;
- const results = compileAndCheck(new ConformancePatternRule(config), source);
-
- expect(results).toHaveFailuresMatching(
- {matchedCode: 'location[key]', messageText: 'No Location#href access'});
- });
-});
diff --git a/packages/concatjs/internal/tsetse/util/pattern_engines/property_non_constant_write_engine.ts b/packages/concatjs/internal/tsetse/util/pattern_engines/property_non_constant_write_engine.ts
deleted file mode 100644
index d8f2f13..0000000
--- a/packages/concatjs/internal/tsetse/util/pattern_engines/property_non_constant_write_engine.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import * as ts from 'typescript';
-
-import {Checker} from '../../checker';
-import {ErrorCode} from '../../error_code';
-import {debugLog} from '../ast_tools';
-import {Fixer} from '../fixer';
-import {isLiteral} from '../is_literal';
-import {PropertyMatcher} from '../property_matcher';
-
-import {matchPropertyWrite, PropertyWriteEngine} from './property_write_engine';
-
-function matchPropertyNonConstantWrite(
- tc: ts.TypeChecker,
- n: ts.PropertyAccessExpression|ts.ElementAccessExpression,
- matcher: PropertyMatcher): ts.Node|undefined {
- debugLog(() => `inspecting ${n.getFullText().trim()}`);
- if (matchPropertyWrite(tc, n, matcher) === undefined) {
- return;
- }
- const rval = (n.parent as ts.BinaryExpression).right;
- if (isLiteral(tc, rval)) {
- debugLog(
- () => `Assigned value (${
- rval.getFullText()}) is a compile-time constant.`);
- return;
- }
- return n.parent;
-}
-
-/**
- * The engine for BANNED_PROPERTY_NON_CONSTANT_WRITE.
- */
-export class PropertyNonConstantWriteEngine extends PropertyWriteEngine {
- register(checker: Checker) {
- this.registerWith(checker, matchPropertyNonConstantWrite);
- }
-}
diff --git a/packages/concatjs/internal/tsetse/util/pattern_engines/property_non_constant_write_engine_test.ts b/packages/concatjs/internal/tsetse/util/pattern_engines/property_non_constant_write_engine_test.ts
deleted file mode 100644
index 6d2f4fa..0000000
--- a/packages/concatjs/internal/tsetse/util/pattern_engines/property_non_constant_write_engine_test.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import 'jasmine';
-import {ConformancePatternRule, ErrorCode, PatternKind} from '../../rules/conformance_pattern_rule';
-import {compileAndCheck, customMatchers} from '../../util/testing/test_support';
-
-describe('BANNED_PROPERTY_NON_CONSTANT_WRITE', () => {
- it('matches a trivial example', () => {
- const source = [
- `const q = document.createElement('q');`,
- `q.cite = 'some example string';`,
- `q['cite'] = 'some example string';`,
- `q.cite = window.name;`,
- `q['cite'] = window.name;`,
- ].join('\n');
- const config = {
- errorCode: ErrorCode.CONFORMANCE_PATTERN,
- errorMessage: 'do not cite dynamically',
- kind: PatternKind.BANNED_PROPERTY_NON_CONSTANT_WRITE,
- values: ['HTMLQuoteElement.prototype.cite']
- };
- const results = compileAndCheck(new ConformancePatternRule(config), source);
-
- expect(results).toHaveFailuresMatching(
- {
- matchedCode: `q.cite = window.name`,
- messageText: 'do not cite dynamically',
- },
- {
- matchedCode: `q['cite'] = window.name`,
- messageText: 'do not cite dynamically',
- });
- });
-});
-
-
-beforeEach(() => {
- jasmine.addMatchers(customMatchers);
-});
diff --git a/packages/concatjs/internal/tsetse/util/pattern_engines/property_write_engine.ts b/packages/concatjs/internal/tsetse/util/pattern_engines/property_write_engine.ts
deleted file mode 100644
index b640ce3..0000000
--- a/packages/concatjs/internal/tsetse/util/pattern_engines/property_write_engine.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-import * as ts from 'typescript';
-
-import {Checker} from '../../checker';
-import {ErrorCode} from '../../error_code';
-import {debugLog} from '../ast_tools';
-import {Fixer} from '../fixer';
-import {PropertyMatcher} from '../property_matcher';
-
-import {matchProperty, PropertyEngine} from './property_engine';
-
-/** Test if an AST node is a matched property write. */
-export function matchPropertyWrite(
- tc: ts.TypeChecker,
- n: ts.PropertyAccessExpression|ts.ElementAccessExpression,
- matcher: PropertyMatcher): ts.BinaryExpression|undefined {
- debugLog(() => `inspecting ${n.parent.getText().trim()}`);
-
- if (matchProperty(tc, n, matcher) === undefined) return;
-
- const assignment = n.parent;
-
- if (!ts.isBinaryExpression(assignment)) return;
- if (assignment.operatorToken.kind !== ts.SyntaxKind.EqualsToken) return;
- if (assignment.left !== n) return;
-
- return assignment;
-}
-
-/**
- * The engine for BANNED_PROPERTY_WRITE.
- */
-export class PropertyWriteEngine extends PropertyEngine {
- register(checker: Checker) {
- this.registerWith(checker, matchPropertyWrite);
- }
-}
diff --git a/packages/concatjs/internal/tsetse/util/pattern_engines/property_write_engine_test.ts b/packages/concatjs/internal/tsetse/util/pattern_engines/property_write_engine_test.ts
deleted file mode 100644
index eec8771..0000000
--- a/packages/concatjs/internal/tsetse/util/pattern_engines/property_write_engine_test.ts
+++ /dev/null
@@ -1,137 +0,0 @@
-import 'jasmine';
-import {ConformancePatternRule, ErrorCode, PatternKind} from '../../rules/conformance_pattern_rule';
-import {compileAndCheck, customMatchers} from '../testing/test_support';
-
-describe('BANNED_PROPERTY_WRITE', () => {
- describe('simple matcher tests', () => {
- const config = {
- errorCode: ErrorCode.CONFORMANCE_PATTERN,
- errorMessage: 'do not cite',
- kind: PatternKind.BANNED_PROPERTY_WRITE,
- values: ['HTMLQuoteElement.prototype.cite']
- };
- const rule = new ConformancePatternRule(config);
-
- it('matches simple examples', () => {
- const source = [
- `const q = document.createElement('q');`,
- `q.cite = 'some example string';`,
- `q['cite'] = 'some example string';`,
- ].join('\n');
- const results = compileAndCheck(rule, source);
-
- expect(results).toHaveFailuresMatching(
- {
- matchedCode: `q.cite = 'some example string'`,
- messageText: 'do not cite'
- },
- {
- matchedCode: `q['cite'] = 'some example string'`,
- messageText: 'do not cite'
- });
- });
-
- it('matches precisely, even with whitespace or comments', () => {
- const source = [
- `const q = document.createElement('q');`,
- ` q.cite = 'exampleA';`,
- `q.cite = 'exampleB' ;`,
- `/* test1 */ q.cite = /* test2 */ 'exampleC' /* test3 */;`,
- ].join('\n');
- const results = compileAndCheck(rule, source);
-
- expect(results).toHaveFailuresMatching(
- {matchedCode: `q.cite = 'exampleA'`, messageText: 'do not cite'},
- {matchedCode: `q.cite = 'exampleB'`, messageText: 'do not cite'}, {
- matchedCode: `q.cite = /* test2 */ 'exampleC'`,
- messageText: 'do not cite'
- });
- });
-
- it('understands function prototypes', () => {
- const source = [
- `function foo(q:HTMLQuoteElement) {`,
- ` q.cite = 'some example string';`,
- `}`,
- ].join('\n');
- const results = compileAndCheck(rule, source);
-
- expect(results).toHaveFailuresMatching({
- matchedCode: `q.cite = 'some example string'`,
- messageText: 'do not cite'
- });
- });
-
- it('understands imported symbols', () => {
- const sources = [
- `const q = document.createElement('q'); export {q};`,
- `import {q} from './file_0'; q.cite = window.name;`
- ];
- const results = compileAndCheck(rule, ...sources);
-
- expect(results).toHaveFailuresMatching({
- matchedCode: 'q.cite = window.name',
- fileName: 'file_1.ts',
- messageText: 'do not cite',
- });
- });
-
- it('understands shadowing', () => {
- const source = [
- `const q = document.createElement('q');`,
- `const f1 = (q: {cite: string}) => { q.cite = 'example 1'; };`,
- ].join('\n');
- const rule = new ConformancePatternRule(config);
- const results = compileAndCheck(rule, source);
-
- expect(results).toHaveNoFailures();
- });
- });
-
-
- describe('with inheritance', () => {
- const source = [
- `class Parent { x: number }`,
- `class Child extends Parent {}`,
- `const c: Child = new Child();`,
- `c.x = 1;`,
- ].join('\n');
-
- // Both of these should have the same results: in `c.x`, `x` matches,
- // and `c` is both a Parent and a Child.
- const expectedFailure = {
- matchedCode: 'c.x = 1',
- messageText: 'found write to x',
- };
-
- it('banning Parent.x matches (instance of Child).x', () => {
- const configOnParent = {
- errorCode: ErrorCode.CONFORMANCE_PATTERN,
- errorMessage: 'found write to x',
- kind: PatternKind.BANNED_PROPERTY_WRITE,
- values: ['Parent.prototype.x']
- };
- const ruleOnParent = new ConformancePatternRule(configOnParent);
- const results = compileAndCheck(ruleOnParent, source);
-
- expect(results).toHaveFailuresMatching(expectedFailure);
- });
-
- it('banning Child.x matches x defined on Parent', () => {
- const configOnChild = {
- errorCode: ErrorCode.CONFORMANCE_PATTERN,
- errorMessage: 'found write to x',
- kind: PatternKind.BANNED_PROPERTY_WRITE,
- values: ['Child.prototype.x']
- };
- const ruleOnChild = new ConformancePatternRule(configOnChild);
- const results = compileAndCheck(ruleOnChild, source);
-
- expect(results).toHaveFailuresMatching(expectedFailure);
- });
- });
-});
-
-beforeEach(() => {
- jasmine.addMatchers(customMatchers);
-});
diff --git a/packages/concatjs/internal/tsetse/util/property_matcher.ts b/packages/concatjs/internal/tsetse/util/property_matcher.ts
deleted file mode 100644
index 0caea62..0000000
--- a/packages/concatjs/internal/tsetse/util/property_matcher.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-import * as ts from 'typescript';
-
-// TODO: Export the matched node kinds here.
-/**
- * This class matches a property access node, based on a property holder type
- * (through its name), i.e. a class, and a property name.
- *
- * The logic is voluntarily simple: if a matcher for `a.b` tests a `x.y` node,
- * it will return true if:
- * - `x` is of type `a` either directly (name-based) or through inheritance
- * (ditto),
- * - and, textually, `y` === `b`.
- *
- * Note that the logic is different from TS's type system: this matcher doesn't
- * have any knowledge of structural typing.
- */
-export class PropertyMatcher {
- static fromSpec(spec: string): PropertyMatcher {
- if (spec.indexOf('.prototype.') === -1) {
- throw new Error(`BANNED_PROPERTY expects a .prototype in your query.`);
- }
- const requestParser = /^([\w\d_.-]+)\.prototype\.([\w\d_.-]+)$/;
- const matches = requestParser.exec(spec);
- if (!matches) {
- throw new Error('Cannot understand the BannedProperty spec' + spec);
- }
- const [bannedType, bannedProperty] = matches.slice(1);
- return new PropertyMatcher(bannedType, bannedProperty);
- }
-
- constructor(readonly bannedType: string, readonly bannedProperty: string) {}
-
- /**
- * @param n The PropertyAccessExpression we're looking at.
- */
- matches(n: ts.PropertyAccessExpression, tc: ts.TypeChecker) {
- return n.name.text === this.bannedProperty &&
- this.typeMatches(tc.getTypeAtLocation(n.expression));
- }
-
- private exactTypeMatches(inspectedType: ts.Type): boolean {
- const typeSymbol = inspectedType.getSymbol() || false;
- return typeSymbol && typeSymbol.getName() === this.bannedType;
- }
-
- // TODO: Account for unknown types/ '?', and 'loose type matches', i.e. if the
- // actual type is a supertype of the prohibited type.
- typeMatches(inspectedType: ts.Type): boolean {
- if (this.exactTypeMatches(inspectedType)) {
- return true;
- }
- // If the type is an intersection/union, check if any of the component matches
- if (inspectedType.isUnionOrIntersection()) {
- return inspectedType.types.some(comp => this.typeMatches(comp));
- }
-
- const baseTypes = inspectedType.getBaseTypes() || [];
- return baseTypes.some(base => this.typeMatches(base));
- }
-}
diff --git a/packages/concatjs/internal/tsetse/util/property_matcher_test.ts b/packages/concatjs/internal/tsetse/util/property_matcher_test.ts
deleted file mode 100644
index 74fded8..0000000
--- a/packages/concatjs/internal/tsetse/util/property_matcher_test.ts
+++ /dev/null
@@ -1,137 +0,0 @@
-import 'jasmine';
-import {ConformancePatternRule, ErrorCode, PatternKind} from '../rules/conformance_pattern_rule';
-import {compileAndCheck, customMatchers} from './testing/test_support';
-
-describe('PropertyMatcher', () => {
- beforeEach(() => {
- jasmine.addMatchers(customMatchers);
- });
-
- it('matches simple property access on dom properties', () => {
- const config = {
- errorCode: ErrorCode.CONFORMANCE_PATTERN,
- errorMessage: 'No Location#href access',
- kind: PatternKind.BANNED_PROPERTY,
- values: ['Location.prototype.href'],
- };
- const source = 'const href = location.href;';
- const results = compileAndCheck(new ConformancePatternRule(config), source);
-
- expect(results).toHaveFailuresMatching({
- matchedCode: 'location.href',
- messageText: 'No Location#href access',
- });
- });
-
- it('matches simple property access on properties of TS built-in types',
- () => {
- const config = {
- errorCode: ErrorCode.CONFORMANCE_PATTERN,
- errorMessage: 'No Array#map access',
- kind: PatternKind.BANNED_PROPERTY,
- values: ['Array.prototype.map'],
- };
- const source = '[].map(() => 1);';
-
- const results =
- compileAndCheck(new ConformancePatternRule(config), source);
-
- expect(results).toHaveFailuresMatching({
- matchedCode: '[].map',
- messageText: 'No Array#map access',
- });
- });
-
- it('matches simple property access on properties of user-defined global types',
- () => {
- const config = {
- errorCode: ErrorCode.CONFORMANCE_PATTERN,
- errorMessage: 'No Ty#foo access',
- kind: PatternKind.BANNED_PROPERTY,
- values: ['Ty.prototype.foo'],
- };
- const funcPropAccess = `class Ty {
- foo() {}
- bar: number = 1;
- }
- new Ty().foo();
- `;
- let results =
- compileAndCheck(new ConformancePatternRule(config), funcPropAccess);
-
- expect(results).toHaveFailuresMatching({
- matchedCode: 'new Ty().foo',
- messageText: 'No Ty#foo access',
- });
-
- const nonFuncPropAccess = `class Ty {
- foo: number = 1;
- bar() {}
- }
- new Ty().foo;
- `;
- results = compileAndCheck(
- new ConformancePatternRule(config), nonFuncPropAccess);
-
- expect(results).toHaveFailuresMatching({
- matchedCode: 'new Ty().foo',
- messageText: 'No Ty#foo access',
- });
- });
-
- it('matches property on indirect base types', () => {
- const config = {
- errorCode: ErrorCode.CONFORMANCE_PATTERN,
- errorMessage: 'No Element#innerHTML access',
- kind: PatternKind.BANNED_PROPERTY_WRITE,
- values: ['Element.prototype.innerHTML'],
- };
- // Element is an indirect base of HTMLDivElement (HTMLDivElement extends
- // HTMLElement, which extends Element).
- const proprAcessOnIndirectBaseType =
- `declare var div: HTMLDivElement; div.innerHTML = 'foo'`;
-
- const results = compileAndCheck(
- new ConformancePatternRule(config), proprAcessOnIndirectBaseType);
-
- expect(results).toHaveFailuresMatching({
- matchedCode: `div.innerHTML = 'foo'`,
- messageText: 'No Element#innerHTML access',
- });
- });
-
- it('does not match in-module defined type', () => {
- const config = {
- errorCode: ErrorCode.CONFORMANCE_PATTERN,
- errorMessage: 'No Location#replace access',
- kind: PatternKind.BANNED_PROPERTY,
- values: ['Location.prototype.location'],
- };
- const source = `export {}; // export makes the file a module
- class Location { replace(x: string) {} }
- new Location().replace('a');`;
- const results = compileAndCheck(new ConformancePatternRule(config), source);
-
- expect(results).toHaveNoFailures();
- });
-
- it('does not match properties after fancy type casts', () => {
- const config = {
- errorCode: ErrorCode.CONFORMANCE_PATTERN,
- errorMessage: 'No Location#href access',
- kind: PatternKind.BANNED_PROPERTY,
- values: ['Location.prototype.replace'],
- };
- const source = [
- // Grey area of tests that don't trigger, but probably could
- '(location as unknown as {replace: (url: string) => void}).replace(\'\');',
- // We don't trigger on any, since it's not the right type.
- 'const locationAsAny: any = location;',
- 'locationAsAny.replace(\'https://example.com/script.js\');',
- ];
- const results =
- compileAndCheck(new ConformancePatternRule(config), ...source);
-
- expect(results).toHaveNoFailures();
- });
-});
diff --git a/packages/concatjs/internal/tsetse/util/testing/test_support.ts b/packages/concatjs/internal/tsetse/util/testing/test_support.ts
deleted file mode 100644
index a3c32d3..0000000
--- a/packages/concatjs/internal/tsetse/util/testing/test_support.ts
+++ /dev/null
@@ -1,302 +0,0 @@
-import 'jasmine';
-
-import * as crypto from 'crypto';
-import * as fs from 'fs';
-import * as os from 'os';
-import * as path from 'path';
-import * as ts from 'typescript';
-
-import {Checker} from '../../checker';
-import {Failure, fixToString} from '../../failure';
-import {AbstractRule} from '../../rule';
-
-
-
-/**
- * Turns the provided source (as strings) into a ts.Program. The source files
- * will be named `.../file_${n}.ts`, with n the index of the source file in
- * the `sourceCode` array.
- */
-export function compile(...sourceCode: string[]): ts.Program {
- const temporaryFolder = os.tmpdir() + path.sep +
- `tslint_test_input_${crypto.randomBytes(16).toString('hex')}`;
- const fullPaths: string[] = [];
- sourceCode.forEach((s, i) => {
- fullPaths.push(`${temporaryFolder}${path.sep}file_${i}.ts`);
- });
-
- let error: Error|undefined = undefined;
- let program: ts.Program|undefined = undefined;
- try { // Wrap it all in a try/finally to clean up the temp files afterwards
- fs.mkdirSync(temporaryFolder);
- sourceCode.forEach((s, i) => {
- fs.writeFileSync(fullPaths[i], s);
- });
- program = ts.createProgram(fullPaths, {});
- if (ts.getPreEmitDiagnostics(program).length !== 0) {
- throw new Error(
- 'Your program does not compile cleanly. Diagnostics:\n' +
- ts.formatDiagnostics(
- ts.getPreEmitDiagnostics(program), ts.createCompilerHost({})));
- }
- } catch (e) {
- error = e;
- } finally {
- fullPaths.forEach(p => fs.unlinkSync(p));
- fs.rmdirSync(temporaryFolder);
- }
- if (program && !error) {
- return program;
- } else {
- throw error;
- }
-}
-
-function check(rule: AbstractRule, program: ts.Program): Failure[] {
- const checker = new Checker(program);
- rule.register(checker);
- return program.getSourceFiles()
- .map(s => checker.execute(s))
- .reduce((prev, cur) => prev.concat(cur));
-}
-
-/** Builds and run the given Rule upon the source files that were provided. */
-export function compileAndCheck(
- rule: AbstractRule, ...sourceCode: string[]): Failure[] {
- const program = compile(...sourceCode);
- return check(rule, program);
-}
-
-/** Turns a Failure to a fileName. */
-export function toFileName(f: Failure) {
- const file = f.toDiagnostic().file;
- return file ? file.fileName : 'unknown';
-}
-
-/**
- * Returns the location the temp directory for that platform (with forward
- * slashes).
- */
-export function getTempDirForAllowlist() {
- // TS uses forward slashes on Windows ¯\_(ツ)_/¯
- return os.platform() === 'win32' ? os.tmpdir() : os.tmpdir();
-}
-
-interface FailureExpectations {
- fileName?: string;
- start?: number;
- end?: number;
- matchedCode?: string;
- messageText?: string;
- fix?: FixExpectations;
-}
-
-type FixExpectations = Array<
- {fileName?: string; start?: number; end?: number; replacement?: string;}>;
-
-
-function failureMatchesExpectation(
- f1: Failure, exp: FailureExpectations): {pass: boolean, message: string} {
- const diagnostic = f1.toDiagnostic();
- let regrets = '';
- if (exp === undefined) {
- regrets += 'The matcher requires two arguments. ';
- }
- if (exp.fileName) {
- if (!diagnostic.file) {
- regrets += `Expected diagnostic to have a source file, but it had ${
- diagnostic.file}. `;
- } else if (!diagnostic.file.fileName.endsWith(exp.fileName)) {
- regrets +=
- `Expected ${diagnostic.file.fileName} to end with ${exp.fileName}. `;
- }
- }
- if (exp.messageText !== undefined &&
- exp.messageText !== diagnostic.messageText) {
- regrets +=
- expectation('errorMessage', exp.messageText, diagnostic.messageText);
- }
- if (exp.start !== undefined && diagnostic.start !== exp.start) {
- regrets += expectation('start', exp.start, diagnostic.start);
- }
- if (exp.end !== undefined && diagnostic.end !== exp.end) {
- regrets += expectation('end', exp.end, diagnostic.end);
- }
- if (exp.matchedCode) {
- if (!diagnostic.file) {
- regrets += `Expected diagnostic to have a source file, but it had ${
- diagnostic.file}. `;
- } else if (diagnostic.start === undefined) {
- // I don't know how this could happen, but typings say so.
- regrets += `Expected diagnostic to have a starting position. `;
- } else {
- const foundMatchedCode = diagnostic.file.getFullText().slice(
- Number(diagnostic.start), diagnostic.end);
- if (foundMatchedCode !== exp.matchedCode) {
- regrets += `Expected diagnostic to match ${exp.matchedCode}, but was ${
- foundMatchedCode} (from ${Number(diagnostic.start)} to ${
- diagnostic.end}). `;
- }
- }
- }
- if (exp.fix) {
- const {pass, message: fixMessage} = fixMatchesExpectation(f1, exp.fix);
- if (!pass) {
- regrets += fixMessage;
- }
- }
- return {pass: regrets === '', message: regrets};
-}
-
-function fixMatchesExpectation(failure: Failure, expected: FixExpectations):
- {pass: boolean, message: string} {
- let regrets = '';
- const actualFix = failure.toDiagnostic().fix;
- if (!actualFix) {
- regrets += `Expected ${failure.toString()} to have fix ${
- JSON.stringify(expected)}. `;
- } else if (actualFix.changes.length !== expected.length) {
- regrets += `Expected ${expected.length} individual changes, got ${
- actualFix.changes.length}. `;
- if (actualFix.changes.length) {
- regrets += '\n' + fixToString(actualFix);
- }
- } else {
- for (let i = 0; i < expected.length; i++) {
- const e = expected[i];
- const a = actualFix.changes[i];
- if (e.start !== undefined && e.start !== a.start) {
- regrets +=
- expectation(`${i}th individualChange's start`, e.start, a.start);
- }
- if (e.end !== undefined && e.end !== a.end) {
- regrets += expectation(`${i}th individualChange's end`, e.end, a.end);
- }
- if (e.replacement !== undefined && e.replacement !== a.replacement) {
- regrets += expectation(
- `${i}th individualChange's replacement`, e.replacement,
- a.replacement);
- }
- if (e.fileName !== undefined && e.fileName !== a.sourceFile.fileName) {
- regrets += expectation(
- `${i}th individualChange's fileName`, e.fileName,
- a.sourceFile.fileName);
- }
- }
- }
-
- return {pass: regrets === '', message: regrets};
-}
-
-
-/**
- * Custom matcher for Jasmine, for a better experience matching failures and
- * fixes.
- */
-export const customMatchers: jasmine.CustomMatcherFactories = {
-
- toBeFailureMatching(): jasmine.CustomMatcher {
- return {compare: failureMatchesExpectation};
- },
-
- /** Checks that a Failure has the expected Fix field. */
- toHaveFixMatching(): jasmine.CustomMatcher {
- return {compare: fixMatchesExpectation};
- },
-
- toHaveNFailures(): jasmine.CustomMatcher {
- return {
- compare: (actual: Failure[], expected: number) => {
- if (actual.length === expected) {
- return {pass: true};
- } else {
- let message =
- `Expected ${expected} Failures, but found ${actual.length}.`;
- if (actual.length) {
- message += '\n' + actual.map(f => f.toString()).join('\n');
- }
- return {pass: false, message};
- }
- }
- };
- },
-
- toHaveFailuresMatching(): jasmine.CustomMatcher {
- return {
- compare: (actual: Failure[], ...expected: FailureExpectations[]) => {
- if (actual.length !== expected.length) {
- let message =
- `Expected ${expected} Failures, but found ${actual.length}.`;
- if (actual.length) {
- message += '\n' + actual.map(f => f.toString()).join('\n');
- }
- return {pass: false, message};
- }
- let pass = true, message = '';
- for (let i = 0; i < actual.length; i++) {
- const comparison = failureMatchesExpectation(actual[i], expected[i]);
- pass = pass && comparison.pass;
- if (comparison.message) {
- message += `For failure ${i}: ${comparison.message}\n`;
- }
- message += comparison.message;
- }
- return {pass, message};
- }
- };
- },
-
- /**
- * Asserts that a Failure has no fix.
- */
- toHaveNoFix(): jasmine.CustomMatcher {
- return {
- compare: (actualFailure: Failure) => {
- return {
- pass: actualFailure.toDiagnostic().fix === undefined,
- message: 'This failure should not have a fix.'
- };
- }
- };
- },
-
- toHaveNoFailures(): jasmine.CustomMatcher {
- return {
- compare: (actual: Failure[]) => {
- if (actual.length !== 0) {
- let message = `Expected no Failures, but found ${actual.length}.`;
- message += '\n' + actual.map(f => f.toString()).join('\n');
- return {pass: false, message};
- }
- return {pass: true, message: ''};
- }
- };
- }
-};
-
-function expectation<T>(fieldname: string, expectation: T, actual: T) {
- return `Expected .${fieldname} to be ${expectation}, was ${actual}. `;
-}
-
-// And the matching type
-declare global {
- namespace jasmine {
- interface Matchers<T> {
- toBeFailureMatching(expected: FailureExpectations): void;
-
-
- /** Checks that a Failure has the expected Fix field. */
- toHaveFixMatching(expected: FixExpectations): void;
-
- /** Asserts that a Failure has no fix. */
- toHaveNoFix(): void;
-
- toHaveNFailures(expected: number): void;
-
- toHaveFailuresMatching(...expected: FailureExpectations[]): void;
-
- /** Asserts that the results are empty. */
- toHaveNoFailures(): void;
- }
- }
-}
diff --git a/packages/concatjs/package.bzl b/packages/concatjs/package.bzl
deleted file mode 100644
index b007879..0000000
--- a/packages/concatjs/package.bzl
+++ /dev/null
@@ -1,75 +0,0 @@
-# Copyright 2018 The Bazel Authors. All rights reserved.
-#
-# 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 file which defines build dependencies
-"""
-
-load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
-load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
-
-def rules_typescript_dev_dependencies():
- """
- Fetch dependencies needed for local development.
-
- These are in this file to keep version information in one place, and make the WORKSPACE
- shorter.
-
- Also this allows other repos to reference our sources with local_repository and install the needed deps.
- """
-
- maybe(
- http_archive,
- name = "build_bazel_rules_nodejs",
- sha256 = "b6670f9f43faa66e3009488bbd909bc7bc46a5a9661a33f6bc578068d1837f37",
- urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/1.3.0/rules_nodejs-1.3.0.tar.gz"],
- )
-
- # For protocol buffers
- maybe(
- http_archive,
- name = "io_bazel",
- urls = ["https://github.com/bazelbuild/bazel/releases/download/5.3.1/bazel-5.3.1-dist.zip"],
- sha256 = "18486e7152ca26b26585e9b2a6f49f332b116310d3b7e5b70583f1f1f24bb8ae",
- )
-
- # For building concatjs_devserver binary
- # See https://github.com/bazelbuild/rules_go#setup for the latest version.
- maybe(
- http_archive,
- name = "io_bazel_rules_go",
- sha256 = "8e968b5fcea1d2d64071872b12737bbb5514524ee5f0a4f54f5920266c261acb",
- urls = [
- "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.28.0/rules_go-v0.28.0.zip",
- "https://github.com/bazelbuild/rules_go/releases/download/v0.28.0/rules_go-v0.28.0.zip",
- ],
- )
-
- # go_repository is defined in bazel_gazelle
- maybe(
- http_archive,
- name = "bazel_gazelle",
- sha256 = "62ca106be173579c0a167deb23358fdfe71ffa1e4cfdddf5582af26520f1c66f",
- urls = [
- "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.23.0/bazel-gazelle-v0.23.0.tar.gz",
- "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.23.0/bazel-gazelle-v0.23.0.tar.gz",
- ],
- )
-
- maybe(
- http_archive,
- name = "com_google_protobuf",
- sha256 = "98e615d592d237f94db8bf033fba78cd404d979b0b70351a9e5aaff725398357",
- strip_prefix = "protobuf-3.9.1",
- urls = ["https://github.com/protocolbuffers/protobuf/archive/v3.9.1.tar.gz"],
- )
diff --git a/packages/concatjs/package.json b/packages/concatjs/package.json
deleted file mode 100644
index a60da18..0000000
--- a/packages/concatjs/package.json
+++ /dev/null
@@ -1,41 +0,0 @@
-{
- "name": "@bazel/concatjs",
- "description": "Fast JavaScript bundler for Bazel",
- "license": "Apache-2.0",
- "version": "0.0.0-PLACEHOLDER",
- "repository": {
- "type": "git",
- "url": "https://github.com/bazelbuild/rules_nodejs.git",
- "directory": "packages/concatjs"
- },
- "bugs": {
- "url": "https://github.com/bazelbuild/rules_nodejs/issues"
- },
- "keywords": [
- "bazel"
- ],
- "main": "./index.js",
- "typings": "./index.d.ts",
- "//main": "./internal/tsc_wrapped/index.js",
- "//typings": "./internal/tsc_wrapped/index.d.ts",
- "bin": {
- "tsc_wrapped": "./internal/tsc_wrapped/tsc_wrapped.js"
- },
- "dependencies": {
- "protobufjs": "6.8.8",
- "source-map-support": "0.5.9",
- "tsutils": "3.21.0"
- },
- "peerDependencies": {
- "karma": ">=4.0.0",
- "karma-chrome-launcher": ">=2.0.0",
- "karma-firefox-launcher": ">=1.0.0",
- "karma-jasmine": ">=2.0.0",
- "karma-junit-reporter": ">=2.0.0",
- "karma-requirejs": ">=1.0.0",
- "karma-sourcemap-loader": ">=0.3.0"
- },
- "scripts": {
- "postinstall": "node npm_version_check.js"
- }
-}
diff --git a/packages/concatjs/replacements.bzl b/packages/concatjs/replacements.bzl
deleted file mode 100644
index 97af89d..0000000
--- a/packages/concatjs/replacements.bzl
+++ /dev/null
@@ -1,34 +0,0 @@
-# Copyright 2019 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-"""Replacements for @bazel/typescript package
-"""
-
-load("@build_bazel_rules_nodejs//:index.bzl", "COMMON_REPLACEMENTS")
-
-TYPESCRIPT_REPLACEMENTS = dict(
- COMMON_REPLACEMENTS,
- **{
- "#@external ": "",
- "//packages/concatjs/web_test:karma_bin": "@npm//karma/bin:karma",
- # This BEGIN-DEV fencing is required as files pulled in from
- # //packages/concatjs:npm_bazel_typescript_package
- # use this alternate fencing
- "(#|\\/\\/)\\s+BEGIN-DEV-ONLY[\\w\\W]+?(#|\\/\\/)\\s+END-DEV-ONLY": "",
- # This file gets vendored into our repo
- "//packages/concatjs/internal:common": "//@bazel/concatjs/internal:common",
- # Replace the local compiler label with one that comes from npm
- "//packages/concatjs/internal:tsc_wrapped_bin": "//@bazel/concatjs/bin:tsc_wrapped",
- }
-)
diff --git a/packages/concatjs/test/absolute_imports/BUILD.bazel b/packages/concatjs/test/absolute_imports/BUILD.bazel
deleted file mode 100644
index 3de7d9c..0000000
--- a/packages/concatjs/test/absolute_imports/BUILD.bazel
+++ /dev/null
@@ -1,23 +0,0 @@
-# Copyright 2017 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-load("//packages/concatjs:index.bzl", "ts_library")
-
-ts_library(
- name = "absolute_imports",
- srcs = glob(["*.ts"]),
- expected_diagnostics = [
- "TS2307: Cannot find module 'packages/concatjs/test/absolute_imports/foo'",
- ],
-)
diff --git a/packages/concatjs/test/absolute_imports/foo.ts b/packages/concatjs/test/absolute_imports/foo.ts
deleted file mode 100644
index ea26727..0000000
--- a/packages/concatjs/test/absolute_imports/foo.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-const a = 1;
-export default a;
diff --git a/packages/concatjs/test/absolute_imports/importer.ts b/packages/concatjs/test/absolute_imports/importer.ts
deleted file mode 100644
index f0225f6..0000000
--- a/packages/concatjs/test/absolute_imports/importer.ts
+++ /dev/null
@@ -1 +0,0 @@
-import foo from 'packages/concatjs/test/absolute_imports/foo';
diff --git a/packages/concatjs/test/angular_plugin/BUILD.bazel b/packages/concatjs/test/angular_plugin/BUILD.bazel
deleted file mode 100644
index 1364da8..0000000
--- a/packages/concatjs/test/angular_plugin/BUILD.bazel
+++ /dev/null
@@ -1,23 +0,0 @@
-load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary")
-
-# Custom ts_library compiler that runs tsc_wrapped with angular/compiler-cli statically linked
-# This can be used with worker mode because we don't need the linker at runtime to make
-# the angular plugin loadable
-# Just a clone of //packages/concatjs/internal:tsc_wrapped with added deps
-nodejs_binary(
- name = "tsc_wrapped_with_angular",
- data = [
- "//packages/concatjs/internal:tsc_wrapped",
- "//packages/concatjs/third_party/github.com/bazelbuild/bazel/src/main/protobuf:worker_protocol.proto",
- "@npm//@angular/compiler-cli",
- "@npm//protobufjs",
- "@npm//source-map-support",
- "@npm//tsickle",
- "@npm//tsutils",
- "@npm//typescript",
- ],
- entry_point = "//packages/concatjs/internal:tsc_wrapped/tsc_wrapped.js",
- # TODO: turn on --worker_sandboxing and remove this flag to see failure to load the plugin
- templated_args = ["--bazel_patch_module_resolver"],
- visibility = ["//packages/concatjs/test/angular_plugin:__subpackages__"],
-)
diff --git a/packages/concatjs/test/angular_plugin/compiled_output/BUILD.bazel b/packages/concatjs/test/angular_plugin/compiled_output/BUILD.bazel
deleted file mode 100644
index 2a17442..0000000
--- a/packages/concatjs/test/angular_plugin/compiled_output/BUILD.bazel
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright 2017 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-load("//packages/jasmine:index.bzl", "jasmine_node_test")
-load("//packages/concatjs:index.bzl", "ts_library")
-
-ts_library(
- name = "compiled_output",
- srcs = glob(["*.ts"]),
- angular_assets = [
- "comp.ng.html",
- ],
- compiler = "//packages/concatjs/test/angular_plugin:tsc_wrapped_with_angular",
- tsconfig = ":tsconfig.json",
- use_angular_plugin = True,
- deps = [
- "@npm//@angular/core",
- ],
-)
-
-jasmine_node_test(
- name = "test",
- srcs = ["spec.js"],
- data = ["compiled_output"],
-)
diff --git a/packages/concatjs/test/angular_plugin/compiled_output/comp.ng.html b/packages/concatjs/test/angular_plugin/compiled_output/comp.ng.html
deleted file mode 100644
index c38b0fe..0000000
--- a/packages/concatjs/test/angular_plugin/compiled_output/comp.ng.html
+++ /dev/null
@@ -1 +0,0 @@
-<div>{{thing}}</div>
diff --git a/packages/concatjs/test/angular_plugin/compiled_output/component.ts b/packages/concatjs/test/angular_plugin/compiled_output/component.ts
deleted file mode 100644
index d4f2f68..0000000
--- a/packages/concatjs/test/angular_plugin/compiled_output/component.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import {Component} from '@angular/core';
-
-@Component({
- templateUrl: './comp.ng.html',
-})
-export class Comp { thing: string; }
diff --git a/packages/concatjs/test/angular_plugin/compiled_output/spec.js b/packages/concatjs/test/angular_plugin/compiled_output/spec.js
deleted file mode 100644
index 22ceb00..0000000
--- a/packages/concatjs/test/angular_plugin/compiled_output/spec.js
+++ /dev/null
@@ -1,13 +0,0 @@
-const runfiles = require(process.env['BAZEL_NODE_RUNFILES_HELPER']);
-const fs = require('fs');
-
-describe('angular plugin', () => {
- it('should produce typings with Angular metadata', () => {
- expect(fs.readFileSync(runfiles.resolvePackageRelative('component.d.ts'), 'utf-8'))
- .toContain('ɵɵComponentDeclaration<Comp');
- });
- it('should produce JS code with Angular runtime', () => {
- expect(fs.readFileSync(runfiles.resolvePackageRelative('component.js'), 'utf-8'))
- .toContain('defineComponent({ type: Comp');
- });
-});
diff --git a/packages/concatjs/test/angular_plugin/compiled_output/tsconfig.json b/packages/concatjs/test/angular_plugin/compiled_output/tsconfig.json
deleted file mode 100644
index 90fbfaf..0000000
--- a/packages/concatjs/test/angular_plugin/compiled_output/tsconfig.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "compilerOptions": {
- "experimentalDecorators": true
- }
-}
\ No newline at end of file
diff --git a/packages/concatjs/test/angular_plugin/diagnostic/BUILD.bazel b/packages/concatjs/test/angular_plugin/diagnostic/BUILD.bazel
deleted file mode 100644
index d620ba7..0000000
--- a/packages/concatjs/test/angular_plugin/diagnostic/BUILD.bazel
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright 2017 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-load("//packages/concatjs:index.bzl", "ts_library")
-
-ts_library(
- name = "angular_plugin",
- srcs = glob(["*.ts"]),
- angular_assets = [
- "comp.ng.html",
- ],
- compiler = "//packages/concatjs/test/angular_plugin:tsc_wrapped_with_angular",
- expected_diagnostics = [
- "TS2339: \\[ngtsc\\] Property 'thing' does not exist on type 'Comp'",
- ],
- tsconfig = ":tsconfig.json",
- use_angular_plugin = True,
- deps = [
- "@npm//@angular/core",
- ],
-)
diff --git a/packages/concatjs/test/angular_plugin/diagnostic/comp.ng.html b/packages/concatjs/test/angular_plugin/diagnostic/comp.ng.html
deleted file mode 100644
index c38b0fe..0000000
--- a/packages/concatjs/test/angular_plugin/diagnostic/comp.ng.html
+++ /dev/null
@@ -1 +0,0 @@
-<div>{{thing}}</div>
diff --git a/packages/concatjs/test/angular_plugin/diagnostic/component.ts b/packages/concatjs/test/angular_plugin/diagnostic/component.ts
deleted file mode 100644
index fe2ba1c..0000000
--- a/packages/concatjs/test/angular_plugin/diagnostic/component.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import {Component} from '@angular/core';
-
-@Component({
- templateUrl: './comp.ng.html',
-})
-export class Comp {}
diff --git a/packages/concatjs/test/angular_plugin/diagnostic/tsconfig.json b/packages/concatjs/test/angular_plugin/diagnostic/tsconfig.json
deleted file mode 100644
index 90fbfaf..0000000
--- a/packages/concatjs/test/angular_plugin/diagnostic/tsconfig.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "compilerOptions": {
- "experimentalDecorators": true
- }
-}
\ No newline at end of file
diff --git a/packages/concatjs/test/devmode_consumer/BUILD.bazel b/packages/concatjs/test/devmode_consumer/BUILD.bazel
deleted file mode 100644
index c605fc8..0000000
--- a/packages/concatjs/test/devmode_consumer/BUILD.bazel
+++ /dev/null
@@ -1,15 +0,0 @@
-load(":devmode_consumer.bzl", "devmode_consumer")
-
-devmode_consumer(
- name = "devmode_consumer",
- deps = ["//packages/concatjs/test/foobar:bar_ts_library"],
-)
-
-sh_test(
- name = "devmode_consumer_test",
- srcs = ["devmode_consumer_test.sh"],
- data = [
- ":devmode_consumer",
- "@build_bazel_rules_nodejs//third_party/github.com/bazelbuild/bazel/tools/bash/runfiles",
- ],
-)
diff --git a/packages/concatjs/test/devmode_consumer/devmode_consumer.bzl b/packages/concatjs/test/devmode_consumer/devmode_consumer.bzl
deleted file mode 100644
index ed90e10..0000000
--- a/packages/concatjs/test/devmode_consumer/devmode_consumer.bzl
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright 2017 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-"""Example of a rule that requires es2015 (devmode) inputs.
-"""
-
-load("@build_bazel_rules_nodejs//:providers.bzl", "JSNamedModuleInfo")
-
-def _devmode_consumer(ctx):
- sources_depsets = []
- for dep in ctx.attr.deps:
- if JSNamedModuleInfo in dep:
- sources_depsets.append(dep[JSNamedModuleInfo].sources)
- sources = depset(transitive = sources_depsets)
-
- return [DefaultInfo(
- files = sources,
- runfiles = ctx.runfiles(transitive_files = sources),
- )]
-
-devmode_consumer = rule(
- implementation = _devmode_consumer,
- attrs = {
- "deps": attr.label_list(),
- },
-)
diff --git a/packages/concatjs/test/devmode_consumer/devmode_consumer_test.sh b/packages/concatjs/test/devmode_consumer/devmode_consumer_test.sh
deleted file mode 100755
index d8ee7d3..0000000
--- a/packages/concatjs/test/devmode_consumer/devmode_consumer_test.sh
+++ /dev/null
@@ -1,72 +0,0 @@
-#!/bin/bash
-
-# --- begin runfiles.bash initialization v2 ---
-# Copy-pasted from the Bazel Bash runfiles library v2.
-set -uo pipefail; f=build_bazel_rules_nodejs/third_party/github.com/bazelbuild/bazel/tools/bash/runfiles/runfiles.bash
-source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \
- source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \
- source "$0.runfiles/$f" 2>/dev/null || \
- source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
- source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
- { echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e
-# --- end runfiles.bash initialization v2 ---
-
-readonly LIBRARY_JS=$(cat $(rlocation "build_bazel_rules_nodejs/packages/concatjs/test/some_library/library.js"))
-readonly BAR_JS=$(cat $(rlocation "build_bazel_rules_nodejs/packages/concatjs/test/foobar/bar.js"))
-readonly FOO_JS=$(cat $(rlocation "build_bazel_rules_nodejs/packages/concatjs/test/foobar/foo.js"))
-
-# should produce named UMD modules
-if [[ "$LIBRARY_JS" != *"define(\"some-lib\""* ]]; then
- echo "Expected library.js to declare module named some-lib, but was"
- echo "$LIBRARY_JS"
- exit 1
-fi
-
-# should produce named UMD modules
-if [[ "$BAR_JS" != *"define(\"build_bazel_rules_nodejs/packages/concatjs/test/foobar/bar\""* ]]; then
- echo "Expected bar.js to declare named module, but was"
- echo "$BAR_JS"
- exit 1
-fi
-
-# should give a name to required modules
-if [[ "$BAR_JS" != *"require(\"build_bazel_rules_nodejs/packages/concatjs/test/foobar/foo\")"* ]]; then
- echo "Expected bar.js to require named module foo, but was"
- echo "$BAR_JS"
- exit 1
-fi
-
-# should give a name to required modules from other compilation unit
-if [[ "$BAR_JS" != *"require(\"some-lib\")"* ]]; then
- echo "Expected bar.js to require named module library, but was"
- echo "$BAR_JS"
- exit 1
-fi
-
-# should give a name to required generated modules without bazel-bin
-if [[ "$BAR_JS" != *"require(\"build_bazel_rules_nodejs/packages/concatjs/test/generated_ts/foo\")"* ]]; then
- echo "Expected bar.js to require generated named module foo, but was"
- echo "$BAR_JS"
- exit 1
-fi
-
-# should not give a module name to external modules
-if [[ "$BAR_JS" != *"require(\"typescript\")"* ]]; then
- echo "Expected bar.js to require typescript by its original name, but was"
- echo "$BAR_JS"
- exit 1
-fi
-
-# should produce named UMD modules
-if [[ "$FOO_JS" != *"define(\"build_bazel_rules_nodejs/packages/concatjs/test/foobar/foo\""* ]]; then
- echo "Expected foo.js to declare named module, but was"
- echo "$FOO_JS"
- exit 1
-fi
-
-# should produce es2015 classes
-if [[ "$FOO_JS" != *"class Greeter"* ]]; then
- echo "Expected foo.js produce a es2015, but was"
- echo "$FOO_JS"
- exit 1
-fi
\ No newline at end of file
diff --git a/packages/concatjs/test/errorchecks/BUILD.bazel b/packages/concatjs/test/errorchecks/BUILD.bazel
deleted file mode 100644
index 66876ce..0000000
--- a/packages/concatjs/test/errorchecks/BUILD.bazel
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright 2017 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-load("//packages/concatjs:index.bzl", "ts_library")
-
-ts_library(
- name = "erroneous",
- srcs = glob(["*.ts"]),
- expected_diagnostics = [
- "TS2322: Type 'string' is not assignable to type 'number'",
- "TS2304: Cannot find name 'TypeThatDoesNotExist'",
- ],
-)
diff --git a/packages/concatjs/test/errorchecks/erroneous.ts b/packages/concatjs/test/errorchecks/erroneous.ts
deleted file mode 100644
index b0a583c..0000000
--- a/packages/concatjs/test/errorchecks/erroneous.ts
+++ /dev/null
@@ -1 +0,0 @@
-export const x: number = 'not a number';
diff --git a/packages/concatjs/test/errorchecks/erroneous_decl.d.ts b/packages/concatjs/test/errorchecks/erroneous_decl.d.ts
deleted file mode 100644
index c1a3b97..0000000
--- a/packages/concatjs/test/errorchecks/erroneous_decl.d.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-
-export declare class Foo { field: TypeThatDoesNotExist; }
diff --git a/packages/concatjs/test/es6_consumer/BUILD.bazel b/packages/concatjs/test/es6_consumer/BUILD.bazel
deleted file mode 100644
index 0308c83..0000000
--- a/packages/concatjs/test/es6_consumer/BUILD.bazel
+++ /dev/null
@@ -1,29 +0,0 @@
-# Copyright 2017 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-load(":es6_consumer.bzl", "es6_consumer")
-
-es6_consumer(
- name = "es6_output",
- deps = ["//packages/concatjs/test/foobar:bar_ts_library"],
-)
-
-sh_test(
- name = "es6_output_test",
- srcs = ["es6_output_test.sh"],
- data = [
- ":es6_output",
- "@build_bazel_rules_nodejs//third_party/github.com/bazelbuild/bazel/tools/bash/runfiles",
- ],
-)
diff --git a/packages/concatjs/test/es6_consumer/es6_consumer.bzl b/packages/concatjs/test/es6_consumer/es6_consumer.bzl
deleted file mode 100644
index c88a748..0000000
--- a/packages/concatjs/test/es6_consumer/es6_consumer.bzl
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright 2017 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-"""Example of a rule that requires ES6 inputs.
-"""
-
-load("@build_bazel_rules_nodejs//:providers.bzl", "JSEcmaScriptModuleInfo")
-
-def _es6_consumer(ctx):
- sources_depsets = []
- for dep in ctx.attr.deps:
- if JSEcmaScriptModuleInfo in dep:
- sources_depsets.append(dep[JSEcmaScriptModuleInfo].sources)
- sources = depset(transitive = sources_depsets)
-
- return [DefaultInfo(
- files = sources,
- runfiles = ctx.runfiles(transitive_files = sources),
- )]
-
-es6_consumer = rule(
- implementation = _es6_consumer,
- attrs = {
- "deps": attr.label_list(),
- },
-)
diff --git a/packages/concatjs/test/es6_consumer/es6_output_test.sh b/packages/concatjs/test/es6_consumer/es6_output_test.sh
deleted file mode 100755
index c517aad..0000000
--- a/packages/concatjs/test/es6_consumer/es6_output_test.sh
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/bin/bash
-
-# --- begin runfiles.bash initialization v2 ---
-# Copy-pasted from the Bazel Bash runfiles library v2.
-set -uo pipefail; f=build_bazel_rules_nodejs/third_party/github.com/bazelbuild/bazel/tools/bash/runfiles/runfiles.bash
-source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \
- source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \
- source "$0.runfiles/$f" 2>/dev/null || \
- source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
- source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
- { echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e
-# --- end runfiles.bash initialization v2 ---
-
-readonly FOO_JS=$(cat $(rlocation "build_bazel_rules_nodejs/packages/concatjs/test/foobar/foo.mjs"))
-readonly BAR_JS=$(cat $(rlocation "build_bazel_rules_nodejs/packages/concatjs/test/foobar/bar.mjs"))
-readonly LIBRARY_JS=$(cat $(rlocation "build_bazel_rules_nodejs/packages/concatjs/test/some_library/library.mjs"))
-
-# should not down-level ES2015 syntax, eg. `class`
-if [[ "$FOO_JS" != *"class Greeter"* ]]; then
- echo "Expected foo.js to contain 'class Greeter' but was"
- echo "$FOO_JS"
- exit 1
-fi
-
-# should not down-level ES Modules
-if [[ "$LIBRARY_JS" != *"export const cool = 1;"* ]]; then
- echo "Expected library.js to contain 'export const cool = 1;' but was"
- echo "$LIBRARY_JS"
- exit 1
-fi
-
-# should not down-level dynamic import
-if [[ "$BAR_JS" != *"import('./foo')"* ]]; then
- echo "Expected bar.js to contain 'import('./foo')' but was"
- echo "$BAR_JS"
- exit 1
-fi
diff --git a/packages/concatjs/test/foobar/BUILD.bazel b/packages/concatjs/test/foobar/BUILD.bazel
deleted file mode 100644
index 3594aa5..0000000
--- a/packages/concatjs/test/foobar/BUILD.bazel
+++ /dev/null
@@ -1,42 +0,0 @@
-load("//packages/concatjs:index.bzl", "ts_library")
-
-ts_library(
- name = "types",
- srcs = ["types.d.ts"],
-)
-
-ts_library(
- name = "foo_ts_library",
- srcs = [
- "conflict.d.ts",
- "foo.ts",
- ],
- tsconfig = ":tsconfig-foo.json",
- deps = [
- ":types",
- "//packages/concatjs/test/generated_ts",
- ],
-)
-
-ts_library(
- name = "bar_ts_library",
- srcs = ["bar.ts"],
- tsconfig = ":tsconfig-bar.json",
- visibility = [
- "//packages/concatjs/test/devmode_consumer:__pkg__",
- "//packages/concatjs/test/es6_consumer:__pkg__",
- ],
- deps = [
- ":foo_ts_library",
- "//packages/concatjs/test/generated_ts",
- "//packages/concatjs/test/some_library:lib",
- "@npm//typescript",
- # Example of using the `@npm//@types` target to depend on all
- # @types packages and with the types attribute of tsconfig not
- # specified. In this case, typescript will automatically discover
- # all types under node_modules/@types and included them in the compile.
- # See getAutomaticTypeDirectiveNames in
- # https://github.com/Microsoft/TypeScript/blob/master/src/compiler/moduleNameResolver.ts.
- "@npm//@types",
- ],
-)
diff --git a/packages/concatjs/test/foobar/bar.ts b/packages/concatjs/test/foobar/bar.ts
deleted file mode 100644
index a15665d..0000000
--- a/packages/concatjs/test/foobar/bar.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- * @license
- * Copyright 2017 The Bazel Authors. All rights reserved.
- *
- * 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.
- */
-
-import {Greeter} from 'build_bazel_rules_nodejs/packages/concatjs/test/foobar/foo';
-import {a} from 'build_bazel_rules_nodejs/packages/concatjs/test/generated_ts/foo';
-// Repro for #31, should automatically discover @types/node
-import * as fs from 'fs';
-import {cool} from 'some-lib';
-// Verify that typescript/lib/typescript.d.ts and typescript/lib/tsserverlibrary.d.ts
-// are available since we must exclude all other typescript/lib/*.d.ts which are
-// controlled by the compilerOptions.libs config.
-// See https://github.com/bazelbuild/rules_nodejs/pull/875 for more details.
-import * as ts from 'typescript';
-import * as tss from 'typescript/lib/tsserverlibrary';
-
-import('./foo').then(({greeter}) => {console.log(Greeter, fs, cool, ts, greeter, a);});
-
-const useTssType: tss.server.Project[] = [];
-if (useTssType) {
- console.log('foobar');
-}
diff --git a/packages/concatjs/test/foobar/conflict.d.ts b/packages/concatjs/test/foobar/conflict.d.ts
deleted file mode 100644
index ac24e9a..0000000
--- a/packages/concatjs/test/foobar/conflict.d.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-// Test that we can declare an interface named Client
-// which would conflict with typescript/lib/lib.webworker.d.ts if that
-// lib was included but should work if that lib is not
-declare class Client { id: string; }
diff --git a/packages/concatjs/test/foobar/foo.ts b/packages/concatjs/test/foobar/foo.ts
deleted file mode 100644
index 4965e6b..0000000
--- a/packages/concatjs/test/foobar/foo.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-/**
- * @license
- * Copyright 2017 The Bazel Authors. All rights reserved.
- *
- * 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.
- */
-
-import {Polite} from './types';
-
-export class Greeter implements Polite {
- constructor(public greeting: string) {}
- greet(): Promise<string> {
- return Promise.resolve('<h1>' + this.greeting + '</h1>');
- }
-}
-
-export const greeter = new Greeter('Hello, world!');
-greeter.greet().then(msg => {
- document.body.innerHTML = msg;
-});
diff --git a/packages/concatjs/test/foobar/tsconfig-bar.json b/packages/concatjs/test/foobar/tsconfig-bar.json
deleted file mode 100644
index 0307f47..0000000
--- a/packages/concatjs/test/foobar/tsconfig-bar.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "compilerOptions": {
- "strict": true,
- "lib": ["es2015.promise", "dom", "es5"],
- // Auto-discover all types in this configuration since we don't
- // specify `types = []` and the ts_library rule depends on `@npm//@types`.
- // Typescript will automatically discover all types under node_modules/@types
- // and included them in the build. See getAutomaticTypeDirectiveNames in
- // https://github.com/Microsoft/TypeScript/blob/master/src/compiler/moduleNameResolver.ts.
- }
-}
diff --git a/packages/concatjs/test/foobar/tsconfig-foo.json b/packages/concatjs/test/foobar/tsconfig-foo.json
deleted file mode 100644
index 9c14e74..0000000
--- a/packages/concatjs/test/foobar/tsconfig-foo.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "compilerOptions": {
- "strict": true,
- "lib": ["es2015.promise", "dom", "es5"],
- // Include the output directory in rootDirs so that generated .d.ts files
- // can be used for type-checking in the editor, for example the car.proto
- // produces a car.d.ts.
- "rootDirs": [".", "../dist/bin/examples"],
- // Explicitly set types settings so typescript doesn't auto-discover types.
- // If all types are discovered then all types need to be included as deps
- // or typescript may error out with TS2688: Cannot find type definition file for 'foo'.
- "types": []
- }
-}
-
diff --git a/packages/concatjs/test/foobar/types.d.ts b/packages/concatjs/test/foobar/types.d.ts
deleted file mode 100644
index dad5fdc..0000000
--- a/packages/concatjs/test/foobar/types.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export interface Polite { greet(): Promise<string>; }
diff --git a/packages/concatjs/test/generated_ts/BUILD.bazel b/packages/concatjs/test/generated_ts/BUILD.bazel
deleted file mode 100644
index 22176fe..0000000
--- a/packages/concatjs/test/generated_ts/BUILD.bazel
+++ /dev/null
@@ -1,15 +0,0 @@
-load("//packages/concatjs:index.bzl", "ts_library")
-
-genrule(
- name = "foo_ts",
- outs = ["foo.ts"],
- cmd = "echo 'export const a = 1;' > $@",
-)
-
-ts_library(
- name = "generated_ts",
- srcs = [":foo.ts"],
- visibility = [
- "//packages/concatjs/test/foobar:__pkg__",
- ],
-)
diff --git a/packages/concatjs/test/googmodule/BUILD.bazel b/packages/concatjs/test/googmodule/BUILD.bazel
deleted file mode 100644
index 6297bd5..0000000
--- a/packages/concatjs/test/googmodule/BUILD.bazel
+++ /dev/null
@@ -1,20 +0,0 @@
-load("//packages/jasmine:index.bzl", "jasmine_node_test")
-load("//packages/concatjs:index.bzl", "ts_library")
-load("//packages/concatjs/test/devmode_consumer:devmode_consumer.bzl", "devmode_consumer")
-
-ts_library(
- name = "googmodule",
- srcs = ["a.ts"],
- tsconfig = ":tsconfig-googmodule.json",
-)
-
-devmode_consumer(
- name = "devmode_output",
- deps = [":googmodule"],
-)
-
-jasmine_node_test(
- name = "googmodule_output_test",
- srcs = ["googmodule_output_test.js"],
- data = [":devmode_output"],
-)
diff --git a/packages/concatjs/test/googmodule/a.ts b/packages/concatjs/test/googmodule/a.ts
deleted file mode 100644
index 4f633f6..0000000
--- a/packages/concatjs/test/googmodule/a.ts
+++ /dev/null
@@ -1 +0,0 @@
-const a: number = 1;
diff --git a/packages/concatjs/test/googmodule/googmodule_output_test.js b/packages/concatjs/test/googmodule/googmodule_output_test.js
deleted file mode 100644
index 0ab4487..0000000
--- a/packages/concatjs/test/googmodule/googmodule_output_test.js
+++ /dev/null
@@ -1,18 +0,0 @@
-const fs = require('fs');
-const runfiles = require(process.env['BAZEL_NODE_RUNFILES_HELPER']);
-
-describe('googmodule', () => {
- let output;
- beforeAll(() => {
- output = runfiles.resolvePackageRelative('a.js');
- });
-
- it('should have goog module syntax in devmode', () => {
- expect(fs.readFileSync(output, {
- encoding: 'utf-8'
- })).toContain(`goog.module('build_bazel_rules_nodejs.packages.concatjs.test.googmodule.a')`);
- });
- it('should have tsickle type annotations', () => {
- expect(fs.readFileSync(output, {encoding: 'utf-8'})).toContain(`@type {number}`);
- });
-});
\ No newline at end of file
diff --git a/packages/concatjs/test/googmodule/tsconfig-googmodule.json b/packages/concatjs/test/googmodule/tsconfig-googmodule.json
deleted file mode 100644
index c3c478f..0000000
--- a/packages/concatjs/test/googmodule/tsconfig-googmodule.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "compilerOptions": {
- // Explicitly set types settings so typescript doesn't auto-discover types.
- // If all types are discovered then all types need to be included as deps
- // or typescript may error out with TS2688: Cannot find type definition file for 'foo'.
- "types": []
- },
- "bazelOptions": {
- "tsickle": true,
- "googmodule": true
- }
-}
\ No newline at end of file
diff --git a/packages/concatjs/test/lit_plugin/BUILD.bazel b/packages/concatjs/test/lit_plugin/BUILD.bazel
deleted file mode 100644
index 80f6868..0000000
--- a/packages/concatjs/test/lit_plugin/BUILD.bazel
+++ /dev/null
@@ -1,57 +0,0 @@
-# Copyright 2017 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary")
-load("//packages/concatjs:index.bzl", "ts_library")
-
-# Custom ts_library compiler that runs tsc_wrapped with ts-lit-plugin statically linked
-# This can be used with worker mode because we don't need the linker at runtime to make
-# the plugin loadable
-# Just a clone of //internal:tsc_wrapped with added deps
-nodejs_binary(
- name = "tsc_wrapped_with_lit_plugin",
- data = [
- "//packages/concatjs/internal:tsc_wrapped",
- "//packages/concatjs/third_party/github.com/bazelbuild/bazel/src/main/protobuf:worker_protocol.proto",
- "@npm//protobufjs",
- "@npm//source-map-support",
- "@npm//ts-lit-plugin",
- "@npm//tsickle",
- "@npm//tsutils",
- "@npm//typescript",
- ],
- entry_point = "//packages/concatjs/internal:tsc_wrapped/tsc_wrapped.js",
- # TODO: turn on --worker_sandboxing and remove this flag to see failure to load the plugin
- templated_args = ["--bazel_patch_module_resolver"],
- visibility = ["//packages/concatjs/test/angular_plugin:__subpackages__"],
-)
-
-ts_library(
- name = "lit_plugin",
- srcs = glob(["*.ts"]),
- compiler = "tsc_wrapped_with_lit_plugin",
- expected_diagnostics = [
- """TS2322: \\[lit\\] Unknown tag "unknown-element". Did you mean 'lit-element'?""",
- "TS2322: \\[lit\\] Type '222' is not assignable to 'string",
- "TS2322: \\[lit\\] Type '333' is not assignable to 'string",
- """TS2322: \\[lit\\] Type '"aaa"' is not assignable to 'number'""",
- """TS2322: \\[lit\\] Type '"ccc"' is not assignable to 'number'""",
- "TS2322: \\[lit\\] Type '444' is not assignable to 'string",
- "TS2322: \\[lit\\] Type '{ field: number; }' is not assignable to '{ field: string; }'",
- ],
- tsconfig = ":tsconfig.json",
- deps = [
- "@npm//lit-element",
- ],
-)
diff --git a/packages/concatjs/test/lit_plugin/bad.ts b/packages/concatjs/test/lit_plugin/bad.ts
deleted file mode 100644
index 9b834cd..0000000
--- a/packages/concatjs/test/lit_plugin/bad.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import './elements';
-import {html} from 'lit-element';
-
-
-const objValue = {
- field: 111,
-};
-console.log(html`
- <unknown-element></unknown-element>
-
- <div .id=${222}></div>
-
- <lit-element .strField=${333} .numField=${'aaa'}></lit-element>
-
- <lit-element numField="bbb"></lit-element>
-
- <vanilla-element .vanillaStr=${444}></vanilla-element>
-
- <declared-element
- .declaredNumberProp=${'ccc'}
- .declaredObjProp=${objValue}></declared-element>
-`);
diff --git a/packages/concatjs/test/lit_plugin/declared_element.d.ts b/packages/concatjs/test/lit_plugin/declared_element.d.ts
deleted file mode 100644
index 758b4f7..0000000
--- a/packages/concatjs/test/lit_plugin/declared_element.d.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-
-export {};
-
-/** An element that's only declared in a definition. */
-declare class DeclaredElement extends HTMLElement {
- declaredNumberProp: number;
- declaredObjProp: {field: string};
-}
-
-declare global {
- interface HTMLElementTagNameMap {
- 'declared-element': DeclaredElement;
- }
-}
diff --git a/packages/concatjs/test/lit_plugin/elements.ts b/packages/concatjs/test/lit_plugin/elements.ts
deleted file mode 100644
index 8249d7c..0000000
--- a/packages/concatjs/test/lit_plugin/elements.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * @fileoverview Elements used in multiple build tests.
- */
-
-import {customElement, LitElement} from 'lit-element';
-
-
-@customElement('lit-element')
-class LitElementElement extends LitElement {
- strField!: string;
- numField!: number;
-}
-
-class VanillaElement extends HTMLElement {
- vanillaStr = 'hi';
- str!: string;
-}
-customElements.define('vanilla-element', VanillaElement);
-
-declare global {
- interface HTMLElementTagNameMap {
- 'lit-element': LitElementElement;
- 'vanilla-element': VanillaElement;
- }
-}
diff --git a/packages/concatjs/test/lit_plugin/tsconfig.json b/packages/concatjs/test/lit_plugin/tsconfig.json
deleted file mode 100644
index 68b0f39..0000000
--- a/packages/concatjs/test/lit_plugin/tsconfig.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "compilerOptions": {
- "plugins": [
- {
- "name": "ts-lit-plugin",
- "strict": true,
- "rules": {
- "no-unknown-tag-name": "error",
- "no-unclosed-tag": "error",
- "no-unknown-property": "error",
- "no-unintended-mixed-binding": "error",
- "no-invalid-boolean-binding": "error",
- "no-expressionless-property-binding": "error",
- "no-noncallable-event-binding": "error",
- "no-boolean-in-attribute-binding": "error",
- "no-complex-attribute-binding": "error",
- "no-nullable-attribute-binding": "error",
- "no-incompatible-type-binding": "error",
- "no-invalid-directive-binding": "error",
- "no-incompatible-property-type": "error",
- "no-unknown-property-converter": "error",
- "no-invalid-attribute-name": "error",
- "no-invalid-tag-name": "error",
- "no-unknown-attribute": "off",
- "no-missing-import": "off",
- }
- }
- ]
- },
- "exclude": [
- "node_modules"
- ]
-}
\ No newline at end of file
diff --git a/packages/concatjs/test/reference_types_directive/BUILD.bazel b/packages/concatjs/test/reference_types_directive/BUILD.bazel
deleted file mode 100644
index 752a40e..0000000
--- a/packages/concatjs/test/reference_types_directive/BUILD.bazel
+++ /dev/null
@@ -1,15 +0,0 @@
-load("//packages/jasmine:index.bzl", "jasmine_node_test")
-load("//packages/concatjs:index.bzl", "ts_library")
-
-ts_library(
- name = "test_lib",
- testonly = True,
- srcs = glob(["*.spec.ts"]),
- tsconfig = ":tsconfig.json",
- deps = ["@npm//:node_modules"],
-)
-
-jasmine_node_test(
- name = "test",
- deps = [":test_lib"],
-)
diff --git a/packages/concatjs/test/reference_types_directive/reference_types.spec.ts b/packages/concatjs/test/reference_types_directive/reference_types.spec.ts
deleted file mode 100644
index 8d52416..0000000
--- a/packages/concatjs/test/reference_types_directive/reference_types.spec.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-/// <reference types="zone.js" />
-/// <reference types="hammerjs" />
-
-// The jasmine types are resolved because the tsconfig.json
-// for this compilation includes "types": ["jasmine"].
-// This file will fail to compile if that mechanism of including types
-// is broken
-
-describe('reference types directive resolution', () => {
- it('should resolve zone.js types from node_modules/zone.js/dist/zone.js.d.ts', () => {
- // The type of Zone should resolve above or this will fail to compile
- let zone: Zone;
- expect(1).toEqual(1);
- });
-
- it('should resolve hammerjs types from node_modules/@types/hammerjs/index.d.ts', () => {
- // The type of HammerStatic should resolve above or this will fail to compile
- let hammer: HammerStatic;
- expect(1).toEqual(1);
- });
-});
diff --git a/packages/concatjs/test/reference_types_directive/tsconfig.json b/packages/concatjs/test/reference_types_directive/tsconfig.json
deleted file mode 100644
index 5b841a7..0000000
--- a/packages/concatjs/test/reference_types_directive/tsconfig.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "compilerOptions": {
- "types": ["jasmine"]
- }
-}
diff --git a/packages/concatjs/test/reference_types_directive/tsconfig_types.ts b/packages/concatjs/test/reference_types_directive/tsconfig_types.ts
deleted file mode 100644
index da10367..0000000
--- a/packages/concatjs/test/reference_types_directive/tsconfig_types.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-// Cecking that `describe` is a valid symbol here to ensure
-// that @types/jasmine is getting picked up
-describe('', () => {});
-// Since "hammerjs" is not included in the types=[] array in
-// tsconfig, this should result in a compile error: TS2304: Cannot find name 'Hammer'
-console.log(typeof Hammer);
diff --git a/packages/concatjs/test/some_library/BUILD.bazel b/packages/concatjs/test/some_library/BUILD.bazel
deleted file mode 100644
index 943bce4..0000000
--- a/packages/concatjs/test/some_library/BUILD.bazel
+++ /dev/null
@@ -1,13 +0,0 @@
-load("//packages/concatjs:index.bzl", "ts_library")
-
-ts_library(
- name = "lib",
- srcs = ["library.ts"],
- # Allow this library to be imported from `some-lib`
- module_name = "some-lib",
- # The imported path should be the library.d.ts file
- module_root = "library",
- visibility = [
- "//packages/concatjs/test/foobar:__pkg__",
- ],
-)
diff --git a/packages/concatjs/test/some_library/library.ts b/packages/concatjs/test/some_library/library.ts
deleted file mode 100644
index 1cc6cf3..0000000
--- a/packages/concatjs/test/some_library/library.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-/**
- * @license
- * Copyright 2017 The Bazel Authors. All rights reserved.
- *
- * 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.
- */
-
-export const cool = 1;
diff --git a/packages/concatjs/test/some_module/BUILD.bazel b/packages/concatjs/test/some_module/BUILD.bazel
deleted file mode 100644
index 6d26bcf..0000000
--- a/packages/concatjs/test/some_module/BUILD.bazel
+++ /dev/null
@@ -1,64 +0,0 @@
-load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary")
-load("//packages/concatjs:index.bzl", "ts_library")
-load("//packages/concatjs/test/some_module:run_node_test.bzl", "ts_write_file")
-
-# We compile this library with the module_name and package_name "sm" to make it possible to use
-# `import {} from 'sm';` both at type-check time (we include the module_name mapping in the paths
-# map in tsconfig) as well as runtime (we link the module tonode_modules/package_name at runtime).
-ts_library(
- name = "some_module",
- package_name = "sm",
- srcs = ["index.ts"],
- module_name = "sm",
-)
-
-ts_library(
- name = "main",
- srcs = ["main.ts"],
- deps = [":some_module"],
-)
-
-nodejs_binary(
- name = "bin",
- data = [
- ":main",
- ":some_module",
- ],
- entry_point = ":main.ts",
-)
-
-sh_test(
- name = "module_load_test",
- srcs = ["module_load_test.sh"],
- data = [
- ":bin",
- "@build_bazel_rules_nodejs//third_party/github.com/bazelbuild/bazel/tools/bash/runfiles",
- ],
-)
-
-# ts_library for compiling the tool
-ts_library(
- name = "writer",
- srcs = ["writer.ts"],
- deps = ["@npm//@types/node"],
-)
-
-# nodejs_binary for generating an executable for the tool :writer
-nodejs_binary(
- name = "writer_bin",
- data = [
- ":writer",
- ],
- entry_point = ":writer.ts",
-)
-
-# custom rule using the executable above via run_node
-# invoked via bazel build //packages/concatjs/test/some_module:test
-# as --nobazel_patch_module_resolver is the default, the entry_point on the executable is resolved
-# to the ts file - writer.ts
-# this works for bazel run //packages/concatjs/test/some_module:writer_bin as this will patch require and resolve the
-# ts to js
-ts_write_file(
- name = "test",
- content = "hello world",
-)
diff --git a/packages/concatjs/test/some_module/index.ts b/packages/concatjs/test/some_module/index.ts
deleted file mode 100644
index 44f11e8..0000000
--- a/packages/concatjs/test/some_module/index.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export function hello() {
- console.log('hello world');
-}
diff --git a/packages/concatjs/test/some_module/main.ts b/packages/concatjs/test/some_module/main.ts
deleted file mode 100644
index 669ef79..0000000
--- a/packages/concatjs/test/some_module/main.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import {hello} from 'sm';
-
-hello();
diff --git a/packages/concatjs/test/some_module/module_load_test.sh b/packages/concatjs/test/some_module/module_load_test.sh
deleted file mode 100755
index 3e35ead..0000000
--- a/packages/concatjs/test/some_module/module_load_test.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/bin/bash
-
-# --- begin runfiles.bash initialization v2 ---
-# Copy-pasted from the Bazel Bash runfiles library v2.
-set -uo pipefail; f=build_bazel_rules_nodejs/third_party/github.com/bazelbuild/bazel/tools/bash/runfiles/runfiles.bash
-source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \
- source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \
- source "$0.runfiles/$f" 2>/dev/null || \
- source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
- source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
- { echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e
-# --- end runfiles.bash initialization v2 ---
-
-readonly OUT=$($(rlocation "build_bazel_rules_nodejs/packages/concatjs/test/some_module/bin.sh"))
-
-if [ "$OUT" != "hello world" ]; then
- echo "Expected output 'hello world' but was $OUT"
- exit 1
-fi
diff --git a/packages/concatjs/test/some_module/run_node_test.bzl b/packages/concatjs/test/some_module/run_node_test.bzl
deleted file mode 100644
index 84904c2..0000000
--- a/packages/concatjs/test/some_module/run_node_test.bzl
+++ /dev/null
@@ -1,30 +0,0 @@
-"""Contrived custom rule for writing some content to a file using run_node"""
-
-load("//:providers.bzl", "run_node")
-
-def _ts_write_file_impl(ctx):
- run_node(
- ctx = ctx,
- executable = "_writer",
- inputs = [],
- arguments = [
- ctx.attr.content,
- ctx.outputs.out.path,
- ],
- outputs = [ctx.outputs.out],
- )
-
-ts_write_file = rule(
- implementation = _ts_write_file_impl,
- outputs = {
- "out": "out.txt",
- },
- attrs = {
- "content": attr.string(),
- "_writer": attr.label(
- default = Label("//packages/concatjs/test/some_module:writer_bin"),
- cfg = "exec",
- executable = True,
- ),
- },
-)
diff --git a/packages/concatjs/test/some_module/writer.ts b/packages/concatjs/test/some_module/writer.ts
deleted file mode 100644
index 794200b..0000000
--- a/packages/concatjs/test/some_module/writer.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import {writeFileSync} from 'fs';
-
-const content = process.argv[2];
-const outputPath = process.argv[3];
-
-writeFileSync(outputPath, content, {encoding: 'utf8'});
diff --git a/packages/concatjs/test/strict_deps/BUILD b/packages/concatjs/test/strict_deps/BUILD
deleted file mode 100644
index 94ccf8f..0000000
--- a/packages/concatjs/test/strict_deps/BUILD
+++ /dev/null
@@ -1,54 +0,0 @@
-# Copyright 2017 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-load("//packages/concatjs:index.bzl", "ts_library")
-
-ts_library(
- name = "grandparent",
- srcs = ["grandparent.ts"],
-)
-
-ts_library(
- name = "parent",
- srcs = ["parent.ts"],
- # NB: We don't require the `@npm//semver` package for the typescript compile
- # action as the .d.ts files live in @types/semver. If the resulting
- # .js file is run downstream in a nodejs_binary rule, however, the
- # `@npm//semver` dep will be required at that point.
- # TODO: Is it desirable to automatically add @npm//semver as a transitive
- # dep if @npm//@types/semver is a dep so that downtream nodejs_binary
- # rules get this automatically?
- deps = [
- ":grandparent",
- "@npm//@types/semver",
- ],
-)
-
-ts_library(
- name = "strict_deps",
- srcs = ["child.ts"],
- expected_diagnostics = [
- "TS2307:child\\.ts\\(2,.*transitive dependency.*not allowed",
- ],
- deps = [":parent"],
-)
-
-ts_library(
- name = "strict_deps_npm",
- srcs = ["child2.ts"],
- expected_diagnostics = [
- "TS2307:child2\\.ts\\(2,.*transitive dependency.*not allowed",
- ],
- deps = [":parent"],
-)
diff --git a/packages/concatjs/test/strict_deps/child.ts b/packages/concatjs/test/strict_deps/child.ts
deleted file mode 100644
index f0ba5d9..0000000
--- a/packages/concatjs/test/strict_deps/child.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-// The line below is a strict deps violation of a ts_library dep
-import {Symbol} from './grandparent';
-
-console.log(Symbol);
diff --git a/packages/concatjs/test/strict_deps/child2.ts b/packages/concatjs/test/strict_deps/child2.ts
deleted file mode 100644
index b2ced6b..0000000
--- a/packages/concatjs/test/strict_deps/child2.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-// The line below is a strict deps violation of an @npm dep
-import * as semver from 'semver';
-semver.valid('1.2.3');
-
-console.log(Symbol);
diff --git a/packages/concatjs/test/strict_deps/grandparent.ts b/packages/concatjs/test/strict_deps/grandparent.ts
deleted file mode 100644
index d352bd6..0000000
--- a/packages/concatjs/test/strict_deps/grandparent.ts
+++ /dev/null
@@ -1 +0,0 @@
-export class Symbol {}
diff --git a/packages/concatjs/test/strict_deps/parent.ts b/packages/concatjs/test/strict_deps/parent.ts
deleted file mode 100644
index cffa101..0000000
--- a/packages/concatjs/test/strict_deps/parent.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import * as semver from 'semver';
-import {Symbol} from './grandparent';
-semver.valid('1.2.3');
-export const x = 1;
-console.log(Symbol);
diff --git a/packages/concatjs/test/target_module_attributes/BUILD.bazel b/packages/concatjs/test/target_module_attributes/BUILD.bazel
deleted file mode 100644
index dfe69c3..0000000
--- a/packages/concatjs/test/target_module_attributes/BUILD.bazel
+++ /dev/null
@@ -1,33 +0,0 @@
-load("//packages/jasmine:index.bzl", "jasmine_node_test")
-load("//packages/concatjs:index.bzl", "ts_library")
-load("//packages/concatjs/test/devmode_consumer:devmode_consumer.bzl", "devmode_consumer")
-load("//packages/concatjs/test/es6_consumer:es6_consumer.bzl", "es6_consumer")
-
-ts_library(
- name = "override",
- srcs = ["a.ts"],
- devmode_module = "amd",
- devmode_target = "es5",
- prodmode_module = "amd",
- prodmode_target = "es5",
- tsconfig = ":tsconfig-override.json",
-)
-
-devmode_consumer(
- name = "override_devmode_output",
- deps = [":override"],
-)
-
-es6_consumer(
- name = "override_prodmode_output",
- deps = [":override"],
-)
-
-jasmine_node_test(
- name = "override_output_test",
- srcs = ["override_output_test.js"],
- data = [
- ":override_devmode_output",
- ":override_prodmode_output",
- ],
-)
diff --git a/packages/concatjs/test/target_module_attributes/a.ts b/packages/concatjs/test/target_module_attributes/a.ts
deleted file mode 100644
index d9ec9eb..0000000
--- a/packages/concatjs/test/target_module_attributes/a.ts
+++ /dev/null
@@ -1 +0,0 @@
-export const a: any = () => 'hello world';
diff --git a/packages/concatjs/test/target_module_attributes/override_output_test.js b/packages/concatjs/test/target_module_attributes/override_output_test.js
deleted file mode 100644
index 33bf134..0000000
--- a/packages/concatjs/test/target_module_attributes/override_output_test.js
+++ /dev/null
@@ -1,37 +0,0 @@
-const fs = require('fs');
-const runfiles = require(process.env['BAZEL_NODE_RUNFILES_HELPER']);
-
-describe('googmodule', () => {
- let devmodeOutput;
- let prodmodeOutput;
- beforeAll(() => {
- devmodeOutput = runfiles.resolvePackageRelative('a.js');
- prodmodeOutput = runfiles.resolvePackageRelative('a.mjs');
- });
-
- it('should have amd module syntax in devmode', () => {
- expect(fs.readFileSync(devmodeOutput, {encoding: 'utf-8'}))
- .toContain(
- `define("build_bazel_rules_nodejs/packages/concatjs/test/target_module_attributes/a", ["require", "exports"], function (require, exports) {`);
- });
-
- it('should have es5 in devmode', () => {
- const devoutput = fs.readFileSync(devmodeOutput, {encoding: 'utf-8'});
-
- expect(devoutput).toContain(`a = function () { return 'hello world'; };`);
- expect(devoutput).toContain(`exports.a = `);
- });
-
- it('should have amd module syntax in prodmode', () => {
- expect(fs.readFileSync(prodmodeOutput, {encoding: 'utf-8'}))
- .toContain(
- `define("build_bazel_rules_nodejs/packages/concatjs/test/target_module_attributes/a", ["require", "exports"], function (require, exports) {`);
- });
-
- it('should have es5 in prodmode', () => {
- const prodoutput = fs.readFileSync(prodmodeOutput, {encoding: 'utf-8'});
-
- expect(prodoutput).toContain(`a = function () { return 'hello world'; };`);
- expect(prodoutput).toContain(`exports.a = `);
- });
-});
\ No newline at end of file
diff --git a/packages/concatjs/test/target_module_attributes/tsconfig-override.json b/packages/concatjs/test/target_module_attributes/tsconfig-override.json
deleted file mode 100644
index 85ff8fb..0000000
--- a/packages/concatjs/test/target_module_attributes/tsconfig-override.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "compilerOptions": {
- // Explicitly set types settings so typescript doesn't auto-discover types.
- // If all types are discovered then all types need to be included as deps
- // or typescript may error out with TS2688: Cannot find type definition file for 'foo'.
- "types": []
- },
-}
\ No newline at end of file
diff --git a/packages/concatjs/test/ts_library_esm_with_jest/.babelrc b/packages/concatjs/test/ts_library_esm_with_jest/.babelrc
deleted file mode 100644
index af2cb75..0000000
--- a/packages/concatjs/test/ts_library_esm_with_jest/.babelrc
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "presets": [
- [
- "@babel/preset-env",
- {
- "targets": {
- "node": "current",
- },
- },
- ],
- ]
-}
\ No newline at end of file
diff --git a/packages/concatjs/test/ts_library_esm_with_jest/BUILD.bazel b/packages/concatjs/test/ts_library_esm_with_jest/BUILD.bazel
deleted file mode 100644
index 015b515..0000000
--- a/packages/concatjs/test/ts_library_esm_with_jest/BUILD.bazel
+++ /dev/null
@@ -1,50 +0,0 @@
-load("@build_bazel_rules_nodejs//:index.bzl", "copy_to_bin")
-load("//packages/concatjs:index.bzl", "ts_library")
-load(":ts_jest_test.bzl", "ts_jest_test")
-
-ts_library(
- name = "lib",
- srcs = [
- "lib.tsx",
- ],
- # NB: hacky hidden configuration setting so that es6_sources does not include tsickle
- # .externs.js outputs
- runtime = "nodejs",
- deps = [
- "@npm//@types/node",
- ],
-)
-
-# Shenanigans for Windows which doesn't have runfiles symlinks
-# We need the jest config to be in the output tree where the specs are
-copy_to_bin(
- name = "jest_config",
- srcs = [
- "jest.config.js",
- ],
-)
-
-# Same goes for babelrc. We can't add it to the jest_config copy_to_bin
-# since must be a file that is passed to jest in the --config arg.
-copy_to_bin(
- name = "babel_rc",
- srcs = [
- ".babelrc",
- ],
-)
-
-ts_jest_test(
- name = "test",
- srcs = [
- "lib.test.ts",
- ],
- data = [
- ":babel_rc",
- ],
- jest_config = ":jest_config",
- deps = [
- ":lib",
- "@npm//@babel/preset-env",
- "@npm//babel-jest",
- ],
-)
diff --git a/packages/concatjs/test/ts_library_esm_with_jest/jest.config.js b/packages/concatjs/test/ts_library_esm_with_jest/jest.config.js
deleted file mode 100644
index 77b5245..0000000
--- a/packages/concatjs/test/ts_library_esm_with_jest/jest.config.js
+++ /dev/null
@@ -1,9 +0,0 @@
-module.exports = {
- haste: {
- enableSymlinks: true,
- },
- testEnvironment: 'node',
- transform: {'^.+\\.mjs?$': ['babel-jest', {configFile: __dirname + '/.babelrc'}]},
- testMatch: ['**/?(*.)(spec|test).?(m)js?(x)'],
- moduleFileExtensions: ['js', 'mjs'],
-};
diff --git a/packages/concatjs/test/ts_library_esm_with_jest/lib.test.ts b/packages/concatjs/test/ts_library_esm_with_jest/lib.test.ts
deleted file mode 100644
index 0ea73f6..0000000
--- a/packages/concatjs/test/ts_library_esm_with_jest/lib.test.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import {doStuff} from './lib';
-
-describe('doStuff', () => {
- it('should do some stuff', () => {
- expect(doStuff('boom')).toContain('boom');
- });
-});
diff --git a/packages/concatjs/test/ts_library_esm_with_jest/lib.tsx b/packages/concatjs/test/ts_library_esm_with_jest/lib.tsx
deleted file mode 100644
index 1ff5973..0000000
--- a/packages/concatjs/test/ts_library_esm_with_jest/lib.tsx
+++ /dev/null
@@ -1,3 +0,0 @@
-export function doStuff(a: string): string {
- return a
-}
diff --git a/packages/concatjs/test/ts_library_esm_with_jest/ts_jest_test.bzl b/packages/concatjs/test/ts_library_esm_with_jest/ts_jest_test.bzl
deleted file mode 100644
index ce0fcea..0000000
--- a/packages/concatjs/test/ts_library_esm_with_jest/ts_jest_test.bzl
+++ /dev/null
@@ -1,44 +0,0 @@
-"""Simple macro around jest_test"""
-
-load("@npm//jest-cli:index.bzl", _jest_test = "jest_test")
-load("//packages/concatjs:index.bzl", "ts_library")
-
-def ts_jest_test(name, srcs, jest_config, deps = [], data = [], **kwargs):
- """A macro around the autogenerated jest_test rule that takes typescript sources
-
-Uses ts_library prodmode esm output"""
-
- ts_library(
- name = "%s_ts" % name,
- srcs = srcs,
- data = data,
- # Ideally we'd use @types/jest, but it causes typings conflicts
- # if installed together with @types/jasmine and they both end up
- # ambiently included in a TS compile
- deps = deps + ["@npm//@types/jasmine"],
- # NB: hacky hidden configuration setting so that es6_sources does not include tsickle
- # .externs.js outputs
- runtime = "nodejs",
- # Prevent requesting the .d.ts output as that will also produce lib.test.js
- # Without sandbox (e.g. windows) that will be loaded instead of lib.test.mjs
- tags = ["manual"],
- )
- native.filegroup(
- name = "%s_esm" % name,
- srcs = [":%s_ts" % name],
- output_group = "es6_sources",
- )
-
- args = [
- "--no-cache",
- "--no-watchman",
- "--ci",
- ]
- args.extend(["--config", "$$(rlocation $(rootpath %s))" % jest_config])
-
- _jest_test(
- name = name,
- data = [jest_config, ":%s_esm" % name] + deps + data,
- templated_args = args,
- **kwargs
- )
diff --git a/packages/concatjs/test/tsconfig_extends/BUILD.bazel b/packages/concatjs/test/tsconfig_extends/BUILD.bazel
deleted file mode 100644
index 7727eb8..0000000
--- a/packages/concatjs/test/tsconfig_extends/BUILD.bazel
+++ /dev/null
@@ -1,40 +0,0 @@
-# Copyright 2017 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-load("//packages/concatjs:index.bzl", "ts_config", "ts_library")
-
-# Because our tsconfig.json has an extends property, we must also tell the
-# ts_library to include the extended tsconfig file in compilations.
-# The ts_library rule will generate its own tsconfig which extends from the
-# src file.
-# Also test that a ts_config can have a dep on another ts_config
-ts_config(
- name = "tsconfig",
- src = "tsconfig.json",
- deps = [":tsconfig_base"],
-)
-
-ts_config(
- name = "tsconfig_base",
- src = "tsconfig-base.json",
- deps = [":tsconfig-root.json"],
-)
-
-ts_library(
- name = "tsconfig_extends",
- srcs = [
- "uses_promise.ts",
- ],
- tsconfig = ":tsconfig",
-)
diff --git a/packages/concatjs/test/tsconfig_extends/tsconfig-base.json b/packages/concatjs/test/tsconfig_extends/tsconfig-base.json
deleted file mode 100644
index 639961e..0000000
--- a/packages/concatjs/test/tsconfig_extends/tsconfig-base.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "extends": "./tsconfig-root"
-}
diff --git a/packages/concatjs/test/tsconfig_extends/tsconfig-root.json b/packages/concatjs/test/tsconfig_extends/tsconfig-root.json
deleted file mode 100644
index 9aa1316..0000000
--- a/packages/concatjs/test/tsconfig_extends/tsconfig-root.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "compilerOptions": {
- "lib": ["es2015.promise", "es5"],
- // Explicitly set types settings so typescript doesn't auto-discover types.
- // If all types are discovered then all types need to be included as deps
- // or typescript may error out with TS2688: Cannot find type definition file for 'foo'.
- "types": []
- }
-}
\ No newline at end of file
diff --git a/packages/concatjs/test/tsconfig_extends/tsconfig.json b/packages/concatjs/test/tsconfig_extends/tsconfig.json
deleted file mode 100644
index 712de29..0000000
--- a/packages/concatjs/test/tsconfig_extends/tsconfig.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "extends": "./tsconfig-base"
-}
-
diff --git a/packages/concatjs/test/tsconfig_extends/uses_promise.ts b/packages/concatjs/test/tsconfig_extends/uses_promise.ts
deleted file mode 100644
index 4d2e73b..0000000
--- a/packages/concatjs/test/tsconfig_extends/uses_promise.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export function hiLater(): Promise<string> {
- return Promise.resolve('hi');
-}
diff --git a/packages/concatjs/third_party/github.com/bazelbuild/bazel/src/main/protobuf/BUILD.bazel b/packages/concatjs/third_party/github.com/bazelbuild/bazel/src/main/protobuf/BUILD.bazel
deleted file mode 100644
index 5e6ed7c..0000000
--- a/packages/concatjs/third_party/github.com/bazelbuild/bazel/src/main/protobuf/BUILD.bazel
+++ /dev/null
@@ -1,42 +0,0 @@
-# BEGIN-DEV-ONLY
-# Parts of this BUILD file only necessary when building within the bazelbuild/rules_typescript repo.
-# The generated `@bazel/typescript` npm package contains a trimmed BUILD file using # DEV-ONLY fences.
-load("@io_bazel_rules_go//go:def.bzl", "go_library")
-load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
-load("@rules_proto//proto:defs.bzl", "proto_library")
-
-package(default_visibility = ["//:__pkg__"])
-
-licenses(["notice"]) # Apache 2.0
-# END-DEV-ONLY
-
-# Export the raw proto file so protobufjs can be used reflectively without codegen
-exports_files(["worker_protocol.proto"])
-
-# BEGIN-DEV-ONLY
-proto_library(
- name = "blaze_worker_proto",
- srcs = ["worker_protocol.proto"],
- visibility = ["//visibility:public"],
-)
-
-go_proto_library(
- name = "blaze_worker_go_proto",
- importpath = "github.com/bazelbuild/rules_typescript/third_party/github.com/bazelbuild/bazel/src/main/protobuf",
- proto = ":blaze_worker_proto",
- visibility = ["//visibility:public"],
-)
-
-go_library(
- name = "go_default_library",
- embed = [":blaze_worker_go_proto"],
- importpath = "github.com/bazelbuild/rules_typescript/third_party/github.com/bazelbuild/bazel/src/main/protobuf",
- visibility = ["//visibility:public"],
-)
-
-filegroup(
- name = "npm_package_assets",
- srcs = glob(["*"]),
- visibility = ["//visibility:public"],
-)
-# END-DEV-ONLY
diff --git a/packages/concatjs/third_party/github.com/bazelbuild/bazel/src/main/protobuf/LICENSE b/packages/concatjs/third_party/github.com/bazelbuild/bazel/src/main/protobuf/LICENSE
deleted file mode 100644
index 7a4a3ea..0000000
--- a/packages/concatjs/third_party/github.com/bazelbuild/bazel/src/main/protobuf/LICENSE
+++ /dev/null
@@ -1,202 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- 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.
\ No newline at end of file
diff --git a/packages/concatjs/third_party/github.com/bazelbuild/bazel/src/main/protobuf/worker_protocol.proto b/packages/concatjs/third_party/github.com/bazelbuild/bazel/src/main/protobuf/worker_protocol.proto
deleted file mode 100644
index c628b7e..0000000
--- a/packages/concatjs/third_party/github.com/bazelbuild/bazel/src/main/protobuf/worker_protocol.proto
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2015 The Bazel Authors. All rights reserved.
-//
-// 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.
-
-syntax = "proto3";
-
-package blaze.worker;
-
-option java_package = "com.google.devtools.build.lib.worker";
-
-// An input file.
-message Input {
- // The path in the file system where to read this input artifact from. This is
- // either a path relative to the execution root (the worker process is
- // launched with the working directory set to the execution root), or an
- // absolute path.
- string path = 1;
-
- // A hash-value of the contents. The format of the contents is unspecified and
- // the digest should be treated as an opaque token.
- bytes digest = 2;
-}
-
-// This represents a single work unit that Blaze sends to the worker.
-message WorkRequest {
- repeated string arguments = 1;
-
- // The inputs that the worker is allowed to read during execution of this
- // request.
- repeated Input inputs = 2;
-
- // To support multiplex worker, each WorkRequest must have an unique ID. This
- // ID should be attached unchanged to the WorkResponse.
- int32 request_id = 3;
-}
-
-// The worker sends this message to Blaze when it finished its work on the
-// WorkRequest message.
-message WorkResponse {
- int32 exit_code = 1;
-
- // This is printed to the user after the WorkResponse has been received and is
- // supposed to contain compiler warnings / errors etc. - thus we'll use a
- // string type here, which gives us UTF-8 encoding.
- string output = 2;
-
- // To support multiplex worker, each WorkResponse must have an unique ID.
- // Since worker processes which support multiplex worker will handle multiple
- // WorkRequests in parallel, this ID will be used to determined which
- // WorkerProxy does this WorkResponse belong to.
- int32 request_id = 3;
-}
diff --git a/packages/concatjs/third_party/npm/requirejs/BUILD b/packages/concatjs/third_party/npm/requirejs/BUILD
deleted file mode 100644
index 11a14f8..0000000
--- a/packages/concatjs/third_party/npm/requirejs/BUILD
+++ /dev/null
@@ -1,7 +0,0 @@
-exports_files(["require.js"])
-
-filegroup(
- name = "package_contents",
- srcs = glob(["*"]),
- visibility = ["//packages/concatjs:__pkg__"],
-)
diff --git a/packages/concatjs/third_party/npm/requirejs/LICENSE b/packages/concatjs/third_party/npm/requirejs/LICENSE
deleted file mode 100644
index 1e53e2c..0000000
--- a/packages/concatjs/third_party/npm/requirejs/LICENSE
+++ /dev/null
@@ -1,45 +0,0 @@
-Copyright jQuery Foundation and other contributors, https://jquery.org/
-
-This software consists of voluntary contributions made by many
-individuals. For exact contribution history, see the revision history
-available at https://github.com/requirejs/r.js
-
-The following license applies to all parts of this software except as
-documented below:
-
-====
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-====
-
-Copyright and related rights for sample code are waived via CC0. Sample
-code is defined as all source code displayed within the prose of the
-documentation.
-
-CC0: http://creativecommons.org/publicdomain/zero/1.0/
-
-====
-
-Files located in the node_modules directory, and certain utilities used
-to build or test the software in the tests, build/tests, env, lib directories,
-are externally maintained libraries used by this software which have their own
-licenses; we recommend you read them, as their terms may differ from the
-terms above.
\ No newline at end of file
diff --git a/packages/concatjs/third_party/npm/requirejs/require.js b/packages/concatjs/third_party/npm/requirejs/require.js
deleted file mode 100644
index 09d21eb..0000000
--- a/packages/concatjs/third_party/npm/requirejs/require.js
+++ /dev/null
@@ -1,2146 +0,0 @@
-// clang-format off
-/** vim: et:ts=4:sw=4:sts=4
- * @license RequireJS 2.3.5 Copyright jQuery Foundation and other contributors.
- * Released under MIT license, https://github.com/requirejs/requirejs/blob/master/LICENSE
- */
-//Not using strict: uneven strict support in browsers, #392, and causes
-//problems with requirejs.exec()/transpiler plugins that may not be strict.
-/*jslint regexp: true, nomen: true, sloppy: true */
-/*global window, navigator, document, importScripts, setTimeout, opera */
-
-var requirejs, require, define;
-(function (global, setTimeout) {
- var req, s, head, baseElement, dataMain, src,
- interactiveScript, currentlyAddingScript, mainScript, subPath,
- version = '2.3.5',
- commentRegExp = /\/\*[\s\S]*?\*\/|([^:"'=]|^)\/\/.*$/mg,
- cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,
- jsSuffixRegExp = /\.js$/,
- currDirRegExp = /^\.\//,
- op = Object.prototype,
- ostring = op.toString,
- hasOwn = op.hasOwnProperty,
- isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document),
- isWebWorker = !isBrowser && typeof importScripts !== 'undefined',
- //PS3 indicates loaded and complete, but need to wait for complete
- //specifically. Sequence is 'loading', 'loaded', execution,
- // then 'complete'. The UA check is unfortunate, but not sure how
- //to feature test w/o causing perf issues.
- readyRegExp = isBrowser && navigator.platform === 'PLAYSTATION 3' ?
- /^complete$/ : /^(complete|loaded)$/,
- defContextName = '_',
- //Oh the tragedy, detecting opera. See the usage of isOpera for reason.
- isOpera = typeof opera !== 'undefined' && opera.toString() === '[object Opera]',
- contexts = {},
- cfg = {},
- globalDefQueue = [],
- useInteractive = false;
-
- //Could match something like ')//comment', do not lose the prefix to comment.
- function commentReplace(match, singlePrefix) {
- return singlePrefix || '';
- }
-
- function isFunction(it) {
- return ostring.call(it) === '[object Function]';
- }
-
- function isArray(it) {
- return ostring.call(it) === '[object Array]';
- }
-
- /**
- * Helper function for iterating over an array. If the func returns
- * a true value, it will break out of the loop.
- */
- function each(ary, func) {
- if (ary) {
- var i;
- for (i = 0; i < ary.length; i += 1) {
- if (ary[i] && func(ary[i], i, ary)) {
- break;
- }
- }
- }
- }
-
- /**
- * Helper function for iterating over an array backwards. If the func
- * returns a true value, it will break out of the loop.
- */
- function eachReverse(ary, func) {
- if (ary) {
- var i;
- for (i = ary.length - 1; i > -1; i -= 1) {
- if (ary[i] && func(ary[i], i, ary)) {
- break;
- }
- }
- }
- }
-
- function hasProp(obj, prop) {
- return hasOwn.call(obj, prop);
- }
-
- function getOwn(obj, prop) {
- return hasProp(obj, prop) && obj[prop];
- }
-
- /**
- * Cycles over properties in an object and calls a function for each
- * property value. If the function returns a truthy value, then the
- * iteration is stopped.
- */
- function eachProp(obj, func) {
- var prop;
- for (prop in obj) {
- if (hasProp(obj, prop)) {
- if (func(obj[prop], prop)) {
- break;
- }
- }
- }
- }
-
- /**
- * Simple function to mix in properties from source into target,
- * but only if target does not already have a property of the same name.
- */
- function mixin(target, source, force, deepStringMixin) {
- if (source) {
- eachProp(source, function (value, prop) {
- if (force || !hasProp(target, prop)) {
- if (deepStringMixin && typeof value === 'object' && value &&
- !isArray(value) && !isFunction(value) &&
- !(value instanceof RegExp)) {
-
- if (!target[prop]) {
- target[prop] = {};
- }
- mixin(target[prop], value, force, deepStringMixin);
- } else {
- target[prop] = value;
- }
- }
- });
- }
- return target;
- }
-
- //Similar to Function.prototype.bind, but the 'this' object is specified
- //first, since it is easier to read/figure out what 'this' will be.
- function bind(obj, fn) {
- return function () {
- return fn.apply(obj, arguments);
- };
- }
-
- function scripts() {
- return document.getElementsByTagName('script');
- }
-
- function defaultOnError(err) {
- throw err;
- }
-
- //Allow getting a global that is expressed in
- //dot notation, like 'a.b.c'.
- function getGlobal(value) {
- if (!value) {
- return value;
- }
- var g = global;
- each(value.split('.'), function (part) {
- g = g[part];
- });
- return g;
- }
-
- /**
- * Constructs an error with a pointer to an URL with more information.
- * @param {String} id the error ID that maps to an ID on a web page.
- * @param {String} message human readable error.
- * @param {Error} [err] the original error, if there is one.
- *
- * @returns {Error}
- */
- function makeError(id, msg, err, requireModules) {
- var e = new Error(msg + '\nhttp://requirejs.org/docs/errors.html#' + id);
- e.requireType = id;
- e.requireModules = requireModules;
- if (err) {
- e.originalError = err;
- }
- return e;
- }
-
- if (typeof define !== 'undefined') {
- //If a define is already in play via another AMD loader,
- //do not overwrite.
- return;
- }
-
- if (typeof requirejs !== 'undefined') {
- if (isFunction(requirejs)) {
- //Do not overwrite an existing requirejs instance.
- return;
- }
- cfg = requirejs;
- requirejs = undefined;
- }
-
- //Allow for a require config object
- if (typeof require !== 'undefined' && !isFunction(require)) {
- //assume it is a config object.
- cfg = require;
- require = undefined;
- }
-
- function newContext(contextName) {
- var inCheckLoaded, Module, context, handlers,
- checkLoadedTimeoutId,
- config = {
- //Defaults. Do not set a default for map
- //config to speed up normalize(), which
- //will run faster if there is no default.
- waitSeconds: 7,
- baseUrl: './',
- paths: {},
- bundles: {},
- pkgs: {},
- shim: {},
- config: {}
- },
- registry = {},
- //registry of just enabled modules, to speed
- //cycle breaking code when lots of modules
- //are registered, but not activated.
- enabledRegistry = {},
- undefEvents = {},
- defQueue = [],
- defined = {},
- urlFetched = {},
- bundlesMap = {},
- requireCounter = 1,
- unnormalizedCounter = 1;
-
- /**
- * Trims the . and .. from an array of path segments.
- * It will keep a leading path segment if a .. will become
- * the first path segment, to help with module name lookups,
- * which act like paths, but can be remapped. But the end result,
- * all paths that use this function should look normalized.
- * NOTE: this method MODIFIES the input array.
- * @param {Array} ary the array of path segments.
- */
- function trimDots(ary) {
- var i, part;
- for (i = 0; i < ary.length; i++) {
- part = ary[i];
- if (part === '.') {
- ary.splice(i, 1);
- i -= 1;
- } else if (part === '..') {
- // If at the start, or previous value is still ..,
- // keep them so that when converted to a path it may
- // still work when converted to a path, even though
- // as an ID it is less than ideal. In larger point
- // releases, may be better to just kick out an error.
- if (i === 0 || (i === 1 && ary[2] === '..') || ary[i - 1] === '..') {
- continue;
- } else if (i > 0) {
- ary.splice(i - 1, 2);
- i -= 2;
- }
- }
- }
- }
-
- /**
- * Given a relative module name, like ./something, normalize it to
- * a real name that can be mapped to a path.
- * @param {String} name the relative name
- * @param {String} baseName a real name that the name arg is relative
- * to.
- * @param {Boolean} applyMap apply the map config to the value. Should
- * only be done if this normalization is for a dependency ID.
- * @returns {String} normalized name
- */
- function normalize(name, baseName, applyMap) {
- var pkgMain, mapValue, nameParts, i, j, nameSegment, lastIndex,
- foundMap, foundI, foundStarMap, starI, normalizedBaseParts,
- baseParts = (baseName && baseName.split('/')),
- map = config.map,
- starMap = map && map['*'];
-
- //Adjust any relative paths.
- if (name) {
- name = name.split('/');
- lastIndex = name.length - 1;
-
- // If wanting node ID compatibility, strip .js from end
- // of IDs. Have to do this here, and not in nameToUrl
- // because node allows either .js or non .js to map
- // to same file.
- if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) {
- name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, '');
- }
-
- // Starts with a '.' so need the baseName
- if (name[0].charAt(0) === '.' && baseParts) {
- //Convert baseName to array, and lop off the last part,
- //so that . matches that 'directory' and not name of the baseName's
- //module. For instance, baseName of 'one/two/three', maps to
- //'one/two/three.js', but we want the directory, 'one/two' for
- //this normalization.
- normalizedBaseParts = baseParts.slice(0, baseParts.length - 1);
- name = normalizedBaseParts.concat(name);
- }
-
- trimDots(name);
- name = name.join('/');
- }
-
- //Apply map config if available.
- if (applyMap && map && (baseParts || starMap)) {
- nameParts = name.split('/');
-
- outerLoop: for (i = nameParts.length; i > 0; i -= 1) {
- nameSegment = nameParts.slice(0, i).join('/');
-
- if (baseParts) {
- //Find the longest baseName segment match in the config.
- //So, do joins on the biggest to smallest lengths of baseParts.
- for (j = baseParts.length; j > 0; j -= 1) {
- mapValue = getOwn(map, baseParts.slice(0, j).join('/'));
-
- //baseName segment has config, find if it has one for
- //this name.
- if (mapValue) {
- mapValue = getOwn(mapValue, nameSegment);
- if (mapValue) {
- //Match, update name to the new value.
- foundMap = mapValue;
- foundI = i;
- break outerLoop;
- }
- }
- }
- }
-
- //Check for a star map match, but just hold on to it,
- //if there is a shorter segment match later in a matching
- //config, then favor over this star map.
- if (!foundStarMap && starMap && getOwn(starMap, nameSegment)) {
- foundStarMap = getOwn(starMap, nameSegment);
- starI = i;
- }
- }
-
- if (!foundMap && foundStarMap) {
- foundMap = foundStarMap;
- foundI = starI;
- }
-
- if (foundMap) {
- nameParts.splice(0, foundI, foundMap);
- name = nameParts.join('/');
- }
- }
-
- // If the name points to a package's name, use
- // the package main instead.
- pkgMain = getOwn(config.pkgs, name);
-
- return pkgMain ? pkgMain : name;
- }
-
- function removeScript(name) {
- if (isBrowser) {
- each(scripts(), function (scriptNode) {
- if (scriptNode.getAttribute('data-requiremodule') === name &&
- scriptNode.getAttribute('data-requirecontext') === context.contextName) {
- scriptNode.parentNode.removeChild(scriptNode);
- return true;
- }
- });
- }
- }
-
- function hasPathFallback(id) {
- var pathConfig = getOwn(config.paths, id);
- if (pathConfig && isArray(pathConfig) && pathConfig.length > 1) {
- //Pop off the first array value, since it failed, and
- //retry
- pathConfig.shift();
- context.require.undef(id);
-
- //Custom require that does not do map translation, since
- //ID is "absolute", already mapped/resolved.
- context.makeRequire(null, {
- skipMap: true
- })([id]);
-
- return true;
- }
- }
-
- //Turns a plugin!resource to [plugin, resource]
- //with the plugin being undefined if the name
- //did not have a plugin prefix.
- function splitPrefix(name) {
- var prefix,
- index = name ? name.indexOf('!') : -1;
- if (index > -1) {
- prefix = name.substring(0, index);
- name = name.substring(index + 1, name.length);
- }
- return [prefix, name];
- }
-
- /**
- * Creates a module mapping that includes plugin prefix, module
- * name, and path. If parentModuleMap is provided it will
- * also normalize the name via require.normalize()
- *
- * @param {String} name the module name
- * @param {String} [parentModuleMap] parent module map
- * for the module name, used to resolve relative names.
- * @param {Boolean} isNormalized: is the ID already normalized.
- * This is true if this call is done for a define() module ID.
- * @param {Boolean} applyMap: apply the map config to the ID.
- * Should only be true if this map is for a dependency.
- *
- * @returns {Object}
- */
- function makeModuleMap(name, parentModuleMap, isNormalized, applyMap) {
- var url, pluginModule, suffix, nameParts,
- prefix = null,
- parentName = parentModuleMap ? parentModuleMap.name : null,
- originalName = name,
- isDefine = true,
- normalizedName = '';
-
- //If no name, then it means it is a require call, generate an
- //internal name.
- if (!name) {
- isDefine = false;
- name = '_@r' + (requireCounter += 1);
- }
-
- nameParts = splitPrefix(name);
- prefix = nameParts[0];
- name = nameParts[1];
-
- if (prefix) {
- prefix = normalize(prefix, parentName, applyMap);
- pluginModule = getOwn(defined, prefix);
- }
-
- //Account for relative paths if there is a base name.
- if (name) {
- if (prefix) {
- if (isNormalized) {
- normalizedName = name;
- } else if (pluginModule && pluginModule.normalize) {
- //Plugin is loaded, use its normalize method.
- normalizedName = pluginModule.normalize(name, function (name) {
- return normalize(name, parentName, applyMap);
- });
- } else {
- // If nested plugin references, then do not try to
- // normalize, as it will not normalize correctly. This
- // places a restriction on resourceIds, and the longer
- // term solution is not to normalize until plugins are
- // loaded and all normalizations to allow for async
- // loading of a loader plugin. But for now, fixes the
- // common uses. Details in #1131
- normalizedName = name.indexOf('!') === -1 ?
- normalize(name, parentName, applyMap) :
- name;
- }
- } else {
- //A regular module.
- normalizedName = normalize(name, parentName, applyMap);
-
- //Normalized name may be a plugin ID due to map config
- //application in normalize. The map config values must
- //already be normalized, so do not need to redo that part.
- nameParts = splitPrefix(normalizedName);
- prefix = nameParts[0];
- normalizedName = nameParts[1];
- isNormalized = true;
-
- url = context.nameToUrl(normalizedName);
- }
- }
-
- //If the id is a plugin id that cannot be determined if it needs
- //normalization, stamp it with a unique ID so two matching relative
- //ids that may conflict can be separate.
- suffix = prefix && !pluginModule && !isNormalized ?
- '_unnormalized' + (unnormalizedCounter += 1) :
- '';
-
- return {
- prefix: prefix,
- name: normalizedName,
- parentMap: parentModuleMap,
- unnormalized: !!suffix,
- url: url,
- originalName: originalName,
- isDefine: isDefine,
- id: (prefix ?
- prefix + '!' + normalizedName :
- normalizedName) + suffix
- };
- }
-
- function getModule(depMap) {
- var id = depMap.id,
- mod = getOwn(registry, id);
-
- if (!mod) {
- mod = registry[id] = new context.Module(depMap);
- }
-
- return mod;
- }
-
- function on(depMap, name, fn) {
- var id = depMap.id,
- mod = getOwn(registry, id);
-
- if (hasProp(defined, id) &&
- (!mod || mod.defineEmitComplete)) {
- if (name === 'defined') {
- fn(defined[id]);
- }
- } else {
- mod = getModule(depMap);
- if (mod.error && name === 'error') {
- fn(mod.error);
- } else {
- mod.on(name, fn);
- }
- }
- }
-
- function onError(err, errback) {
- var ids = err.requireModules,
- notified = false;
-
- if (errback) {
- errback(err);
- } else {
- each(ids, function (id) {
- var mod = getOwn(registry, id);
- if (mod) {
- //Set error on module, so it skips timeout checks.
- mod.error = err;
- if (mod.events.error) {
- notified = true;
- mod.emit('error', err);
- }
- }
- });
-
- if (!notified) {
- req.onError(err);
- }
- }
- }
-
- /**
- * Internal method to transfer globalQueue items to this context's
- * defQueue.
- */
- function takeGlobalQueue() {
- //Push all the globalDefQueue items into the context's defQueue
- if (globalDefQueue.length) {
- each(globalDefQueue, function(queueItem) {
- var id = queueItem[0];
- if (typeof id === 'string') {
- context.defQueueMap[id] = true;
- }
- defQueue.push(queueItem);
- });
- globalDefQueue = [];
- }
- }
-
- handlers = {
- 'require': function (mod) {
- if (mod.require) {
- return mod.require;
- } else {
- return (mod.require = context.makeRequire(mod.map));
- }
- },
- 'exports': function (mod) {
- mod.usingExports = true;
- if (mod.map.isDefine) {
- if (mod.exports) {
- return (defined[mod.map.id] = mod.exports);
- } else {
- return (mod.exports = defined[mod.map.id] = {});
- }
- }
- },
- 'module': function (mod) {
- if (mod.module) {
- return mod.module;
- } else {
- return (mod.module = {
- id: mod.map.id,
- uri: mod.map.url,
- config: function () {
- return getOwn(config.config, mod.map.id) || {};
- },
- exports: mod.exports || (mod.exports = {})
- });
- }
- }
- };
-
- function cleanRegistry(id) {
- //Clean up machinery used for waiting modules.
- delete registry[id];
- delete enabledRegistry[id];
- }
-
- function breakCycle(mod, traced, processed) {
- var id = mod.map.id;
-
- if (mod.error) {
- mod.emit('error', mod.error);
- } else {
- traced[id] = true;
- each(mod.depMaps, function (depMap, i) {
- var depId = depMap.id,
- dep = getOwn(registry, depId);
-
- //Only force things that have not completed
- //being defined, so still in the registry,
- //and only if it has not been matched up
- //in the module already.
- if (dep && !mod.depMatched[i] && !processed[depId]) {
- if (getOwn(traced, depId)) {
- mod.defineDep(i, defined[depId]);
- mod.check(); //pass false?
- } else {
- breakCycle(dep, traced, processed);
- }
- }
- });
- processed[id] = true;
- }
- }
-
- function checkLoaded() {
- var err, usingPathFallback,
- waitInterval = config.waitSeconds * 1000,
- //It is possible to disable the wait interval by using waitSeconds of 0.
- expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(),
- noLoads = [],
- reqCalls = [],
- stillLoading = false,
- needCycleCheck = true;
-
- //Do not bother if this call was a result of a cycle break.
- if (inCheckLoaded) {
- return;
- }
-
- inCheckLoaded = true;
-
- //Figure out the state of all the modules.
- eachProp(enabledRegistry, function (mod) {
- var map = mod.map,
- modId = map.id;
-
- //Skip things that are not enabled or in error state.
- if (!mod.enabled) {
- return;
- }
-
- if (!map.isDefine) {
- reqCalls.push(mod);
- }
-
- if (!mod.error) {
- //If the module should be executed, and it has not
- //been inited and time is up, remember it.
- if (!mod.inited && expired) {
- if (hasPathFallback(modId)) {
- usingPathFallback = true;
- stillLoading = true;
- } else {
- noLoads.push(modId);
- removeScript(modId);
- }
- } else if (!mod.inited && mod.fetched && map.isDefine) {
- stillLoading = true;
- if (!map.prefix) {
- //No reason to keep looking for unfinished
- //loading. If the only stillLoading is a
- //plugin resource though, keep going,
- //because it may be that a plugin resource
- //is waiting on a non-plugin cycle.
- return (needCycleCheck = false);
- }
- }
- }
- });
-
- if (expired && noLoads.length) {
- //If wait time expired, throw error of unloaded modules.
- err = makeError('timeout', 'Load timeout for modules: ' + noLoads, null, noLoads);
- err.contextName = context.contextName;
- return onError(err);
- }
-
- //Not expired, check for a cycle.
- if (needCycleCheck) {
- each(reqCalls, function (mod) {
- breakCycle(mod, {}, {});
- });
- }
-
- //If still waiting on loads, and the waiting load is something
- //other than a plugin resource, or there are still outstanding
- //scripts, then just try back later.
- if ((!expired || usingPathFallback) && stillLoading) {
- //Something is still waiting to load. Wait for it, but only
- //if a timeout is not already in effect.
- if ((isBrowser || isWebWorker) && !checkLoadedTimeoutId) {
- checkLoadedTimeoutId = setTimeout(function () {
- checkLoadedTimeoutId = 0;
- checkLoaded();
- }, 50);
- }
- }
-
- inCheckLoaded = false;
- }
-
- Module = function (map) {
- this.events = getOwn(undefEvents, map.id) || {};
- this.map = map;
- this.shim = getOwn(config.shim, map.id);
- this.depExports = [];
- this.depMaps = [];
- this.depMatched = [];
- this.pluginMaps = {};
- this.depCount = 0;
-
- /* this.exports this.factory
- this.depMaps = [],
- this.enabled, this.fetched
- */
- };
-
- Module.prototype = {
- init: function (depMaps, factory, errback, options) {
- options = options || {};
-
- //Do not do more inits if already done. Can happen if there
- //are multiple define calls for the same module. That is not
- //a normal, common case, but it is also not unexpected.
- if (this.inited) {
- return;
- }
-
- this.factory = factory;
-
- if (errback) {
- //Register for errors on this module.
- this.on('error', errback);
- } else if (this.events.error) {
- //If no errback already, but there are error listeners
- //on this module, set up an errback to pass to the deps.
- errback = bind(this, function (err) {
- this.emit('error', err);
- });
- }
-
- //Do a copy of the dependency array, so that
- //source inputs are not modified. For example
- //"shim" deps are passed in here directly, and
- //doing a direct modification of the depMaps array
- //would affect that config.
- this.depMaps = depMaps && depMaps.slice(0);
-
- this.errback = errback;
-
- //Indicate this module has be initialized
- this.inited = true;
-
- this.ignore = options.ignore;
-
- //Could have option to init this module in enabled mode,
- //or could have been previously marked as enabled. However,
- //the dependencies are not known until init is called. So
- //if enabled previously, now trigger dependencies as enabled.
- if (options.enabled || this.enabled) {
- //Enable this module and dependencies.
- //Will call this.check()
- this.enable();
- } else {
- this.check();
- }
- },
-
- defineDep: function (i, depExports) {
- //Because of cycles, defined callback for a given
- //export can be called more than once.
- if (!this.depMatched[i]) {
- this.depMatched[i] = true;
- this.depCount -= 1;
- this.depExports[i] = depExports;
- }
- },
-
- fetch: function () {
- if (this.fetched) {
- return;
- }
- this.fetched = true;
-
- context.startTime = (new Date()).getTime();
-
- var map = this.map;
-
- //If the manager is for a plugin managed resource,
- //ask the plugin to load it now.
- if (this.shim) {
- context.makeRequire(this.map, {
- enableBuildCallback: true
- })(this.shim.deps || [], bind(this, function () {
- return map.prefix ? this.callPlugin() : this.load();
- }));
- } else {
- //Regular dependency.
- return map.prefix ? this.callPlugin() : this.load();
- }
- },
-
- load: function () {
- var url = this.map.url;
-
- //Regular dependency.
- if (!urlFetched[url]) {
- urlFetched[url] = true;
- context.load(this.map.id, url);
- }
- },
-
- /**
- * Checks if the module is ready to define itself, and if so,
- * define it.
- */
- check: function () {
- if (!this.enabled || this.enabling) {
- return;
- }
-
- var err, cjsModule,
- id = this.map.id,
- depExports = this.depExports,
- exports = this.exports,
- factory = this.factory;
-
- if (!this.inited) {
- // Only fetch if not already in the defQueue.
- if (!hasProp(context.defQueueMap, id)) {
- this.fetch();
- }
- } else if (this.error) {
- this.emit('error', this.error);
- } else if (!this.defining) {
- //The factory could trigger another require call
- //that would result in checking this module to
- //define itself again. If already in the process
- //of doing that, skip this work.
- this.defining = true;
-
- if (this.depCount < 1 && !this.defined) {
- if (isFunction(factory)) {
- //If there is an error listener, favor passing
- //to that instead of throwing an error. However,
- //only do it for define()'d modules. require
- //errbacks should not be called for failures in
- //their callbacks (#699). However if a global
- //onError is set, use that.
- if ((this.events.error && this.map.isDefine) ||
- req.onError !== defaultOnError) {
- try {
- exports = context.execCb(id, factory, depExports, exports);
- } catch (e) {
- err = e;
- }
- } else {
- exports = context.execCb(id, factory, depExports, exports);
- }
-
- // Favor return value over exports. If node/cjs in play,
- // then will not have a return value anyway. Favor
- // module.exports assignment over exports object.
- if (this.map.isDefine && exports === undefined) {
- cjsModule = this.module;
- if (cjsModule) {
- exports = cjsModule.exports;
- } else if (this.usingExports) {
- //exports already set the defined value.
- exports = this.exports;
- }
- }
-
- if (err) {
- err.requireMap = this.map;
- err.requireModules = this.map.isDefine ? [this.map.id] : null;
- err.requireType = this.map.isDefine ? 'define' : 'require';
- return onError((this.error = err));
- }
-
- } else {
- //Just a literal value
- exports = factory;
- }
-
- this.exports = exports;
-
- if (this.map.isDefine && !this.ignore) {
- defined[id] = exports;
-
- if (req.onResourceLoad) {
- var resLoadMaps = [];
- each(this.depMaps, function (depMap) {
- resLoadMaps.push(depMap.normalizedMap || depMap);
- });
- req.onResourceLoad(context, this.map, resLoadMaps);
- }
- }
-
- //Clean up
- cleanRegistry(id);
-
- this.defined = true;
- }
-
- //Finished the define stage. Allow calling check again
- //to allow define notifications below in the case of a
- //cycle.
- this.defining = false;
-
- if (this.defined && !this.defineEmitted) {
- this.defineEmitted = true;
- this.emit('defined', this.exports);
- this.defineEmitComplete = true;
- }
-
- }
- },
-
- callPlugin: function () {
- var map = this.map,
- id = map.id,
- //Map already normalized the prefix.
- pluginMap = makeModuleMap(map.prefix);
-
- //Mark this as a dependency for this plugin, so it
- //can be traced for cycles.
- this.depMaps.push(pluginMap);
-
- on(pluginMap, 'defined', bind(this, function (plugin) {
- var load, normalizedMap, normalizedMod,
- bundleId = getOwn(bundlesMap, this.map.id),
- name = this.map.name,
- parentName = this.map.parentMap ? this.map.parentMap.name : null,
- localRequire = context.makeRequire(map.parentMap, {
- enableBuildCallback: true
- });
-
- //If current map is not normalized, wait for that
- //normalized name to load instead of continuing.
- if (this.map.unnormalized) {
- //Normalize the ID if the plugin allows it.
- if (plugin.normalize) {
- name = plugin.normalize(name, function (name) {
- return normalize(name, parentName, true);
- }) || '';
- }
-
- //prefix and name should already be normalized, no need
- //for applying map config again either.
- normalizedMap = makeModuleMap(map.prefix + '!' + name,
- this.map.parentMap,
- true);
- on(normalizedMap,
- 'defined', bind(this, function (value) {
- this.map.normalizedMap = normalizedMap;
- this.init([], function () { return value; }, null, {
- enabled: true,
- ignore: true
- });
- }));
-
- normalizedMod = getOwn(registry, normalizedMap.id);
- if (normalizedMod) {
- //Mark this as a dependency for this plugin, so it
- //can be traced for cycles.
- this.depMaps.push(normalizedMap);
-
- if (this.events.error) {
- normalizedMod.on('error', bind(this, function (err) {
- this.emit('error', err);
- }));
- }
- normalizedMod.enable();
- }
-
- return;
- }
-
- //If a paths config, then just load that file instead to
- //resolve the plugin, as it is built into that paths layer.
- if (bundleId) {
- this.map.url = context.nameToUrl(bundleId);
- this.load();
- return;
- }
-
- load = bind(this, function (value) {
- this.init([], function () { return value; }, null, {
- enabled: true
- });
- });
-
- load.error = bind(this, function (err) {
- this.inited = true;
- this.error = err;
- err.requireModules = [id];
-
- //Remove temp unnormalized modules for this module,
- //since they will never be resolved otherwise now.
- eachProp(registry, function (mod) {
- if (mod.map.id.indexOf(id + '_unnormalized') === 0) {
- cleanRegistry(mod.map.id);
- }
- });
-
- onError(err);
- });
-
- //Allow plugins to load other code without having to know the
- //context or how to 'complete' the load.
- load.fromText = bind(this, function (text, textAlt) {
- /*jslint evil: true */
- var moduleName = map.name,
- moduleMap = makeModuleMap(moduleName),
- hasInteractive = useInteractive;
-
- //As of 2.1.0, support just passing the text, to reinforce
- //fromText only being called once per resource. Still
- //support old style of passing moduleName but discard
- //that moduleName in favor of the internal ref.
- if (textAlt) {
- text = textAlt;
- }
-
- //Turn off interactive script matching for IE for any define
- //calls in the text, then turn it back on at the end.
- if (hasInteractive) {
- useInteractive = false;
- }
-
- //Prime the system by creating a module instance for
- //it.
- getModule(moduleMap);
-
- //Transfer any config to this other module.
- if (hasProp(config.config, id)) {
- config.config[moduleName] = config.config[id];
- }
-
- try {
- req.exec(text);
- } catch (e) {
- return onError(makeError('fromtexteval',
- 'fromText eval for ' + id +
- ' failed: ' + e,
- e,
- [id]));
- }
-
- if (hasInteractive) {
- useInteractive = true;
- }
-
- //Mark this as a dependency for the plugin
- //resource
- this.depMaps.push(moduleMap);
-
- //Support anonymous modules.
- context.completeLoad(moduleName);
-
- //Bind the value of that module to the value for this
- //resource ID.
- localRequire([moduleName], load);
- });
-
- //Use parentName here since the plugin's name is not reliable,
- //could be some weird string with no path that actually wants to
- //reference the parentName's path.
- plugin.load(map.name, localRequire, load, config);
- }));
-
- context.enable(pluginMap, this);
- this.pluginMaps[pluginMap.id] = pluginMap;
- },
-
- enable: function () {
- enabledRegistry[this.map.id] = this;
- this.enabled = true;
-
- //Set flag mentioning that the module is enabling,
- //so that immediate calls to the defined callbacks
- //for dependencies do not trigger inadvertent load
- //with the depCount still being zero.
- this.enabling = true;
-
- //Enable each dependency
- each(this.depMaps, bind(this, function (depMap, i) {
- var id, mod, handler;
-
- if (typeof depMap === 'string') {
- //Dependency needs to be converted to a depMap
- //and wired up to this module.
- depMap = makeModuleMap(depMap,
- (this.map.isDefine ? this.map : this.map.parentMap),
- false,
- !this.skipMap);
- this.depMaps[i] = depMap;
-
- handler = getOwn(handlers, depMap.id);
-
- if (handler) {
- this.depExports[i] = handler(this);
- return;
- }
-
- this.depCount += 1;
-
- on(depMap, 'defined', bind(this, function (depExports) {
- if (this.undefed) {
- return;
- }
- this.defineDep(i, depExports);
- this.check();
- }));
-
- if (this.errback) {
- on(depMap, 'error', bind(this, this.errback));
- } else if (this.events.error) {
- // No direct errback on this module, but something
- // else is listening for errors, so be sure to
- // propagate the error correctly.
- on(depMap, 'error', bind(this, function(err) {
- this.emit('error', err);
- }));
- }
- }
-
- id = depMap.id;
- mod = registry[id];
-
- //Skip special modules like 'require', 'exports', 'module'
- //Also, don't call enable if it is already enabled,
- //important in circular dependency cases.
- if (!hasProp(handlers, id) && mod && !mod.enabled) {
- context.enable(depMap, this);
- }
- }));
-
- //Enable each plugin that is used in
- //a dependency
- eachProp(this.pluginMaps, bind(this, function (pluginMap) {
- var mod = getOwn(registry, pluginMap.id);
- if (mod && !mod.enabled) {
- context.enable(pluginMap, this);
- }
- }));
-
- this.enabling = false;
-
- this.check();
- },
-
- on: function (name, cb) {
- var cbs = this.events[name];
- if (!cbs) {
- cbs = this.events[name] = [];
- }
- cbs.push(cb);
- },
-
- emit: function (name, evt) {
- each(this.events[name], function (cb) {
- cb(evt);
- });
- if (name === 'error') {
- //Now that the error handler was triggered, remove
- //the listeners, since this broken Module instance
- //can stay around for a while in the registry.
- delete this.events[name];
- }
- }
- };
-
- function callGetModule(args) {
- //Skip modules already defined.
- if (!hasProp(defined, args[0])) {
- getModule(makeModuleMap(args[0], null, true)).init(args[1], args[2]);
- }
- }
-
- function removeListener(node, func, name, ieName) {
- //Favor detachEvent because of IE9
- //issue, see attachEvent/addEventListener comment elsewhere
- //in this file.
- if (node.detachEvent && !isOpera) {
- //Probably IE. If not it will throw an error, which will be
- //useful to know.
- if (ieName) {
- node.detachEvent(ieName, func);
- }
- } else {
- node.removeEventListener(name, func, false);
- }
- }
-
- /**
- * Given an event from a script node, get the requirejs info from it,
- * and then removes the event listeners on the node.
- * @param {Event} evt
- * @returns {Object}
- */
- function getScriptData(evt) {
- //Using currentTarget instead of target for Firefox 2.0's sake. Not
- //all old browsers will be supported, but this one was easy enough
- //to support and still makes sense.
- var node = evt.currentTarget || evt.srcElement;
-
- //Remove the listeners once here.
- removeListener(node, context.onScriptLoad, 'load', 'onreadystatechange');
- removeListener(node, context.onScriptError, 'error');
-
- return {
- node: node,
- id: node && node.getAttribute('data-requiremodule')
- };
- }
-
- function intakeDefines() {
- var args;
-
- //Any defined modules in the global queue, intake them now.
- takeGlobalQueue();
-
- //Make sure any remaining defQueue items get properly processed.
- while (defQueue.length) {
- args = defQueue.shift();
- if (args[0] === null) {
- return onError(makeError('mismatch', 'Mismatched anonymous define() module: ' +
- args[args.length - 1]));
- } else {
- //args are id, deps, factory. Should be normalized by the
- //define() function.
- callGetModule(args);
- }
- }
- context.defQueueMap = {};
- }
-
- context = {
- config: config,
- contextName: contextName,
- registry: registry,
- defined: defined,
- urlFetched: urlFetched,
- defQueue: defQueue,
- defQueueMap: {},
- Module: Module,
- makeModuleMap: makeModuleMap,
- nextTick: req.nextTick,
- onError: onError,
-
- /**
- * Set a configuration for the context.
- * @param {Object} cfg config object to integrate.
- */
- configure: function (cfg) {
- //Make sure the baseUrl ends in a slash.
- if (cfg.baseUrl) {
- if (cfg.baseUrl.charAt(cfg.baseUrl.length - 1) !== '/') {
- cfg.baseUrl += '/';
- }
- }
-
- // Convert old style urlArgs string to a function.
- if (typeof cfg.urlArgs === 'string') {
- var urlArgs = cfg.urlArgs;
- cfg.urlArgs = function(id, url) {
- return (url.indexOf('?') === -1 ? '?' : '&') + urlArgs;
- };
- }
-
- //Save off the paths since they require special processing,
- //they are additive.
- var shim = config.shim,
- objs = {
- paths: true,
- bundles: true,
- config: true,
- map: true
- };
-
- eachProp(cfg, function (value, prop) {
- if (objs[prop]) {
- if (!config[prop]) {
- config[prop] = {};
- }
- mixin(config[prop], value, true, true);
- } else {
- config[prop] = value;
- }
- });
-
- //Reverse map the bundles
- if (cfg.bundles) {
- eachProp(cfg.bundles, function (value, prop) {
- each(value, function (v) {
- if (v !== prop) {
- bundlesMap[v] = prop;
- }
- });
- });
- }
-
- //Merge shim
- if (cfg.shim) {
- eachProp(cfg.shim, function (value, id) {
- //Normalize the structure
- if (isArray(value)) {
- value = {
- deps: value
- };
- }
- if ((value.exports || value.init) && !value.exportsFn) {
- value.exportsFn = context.makeShimExports(value);
- }
- shim[id] = value;
- });
- config.shim = shim;
- }
-
- //Adjust packages if necessary.
- if (cfg.packages) {
- each(cfg.packages, function (pkgObj) {
- var location, name;
-
- pkgObj = typeof pkgObj === 'string' ? {name: pkgObj} : pkgObj;
-
- name = pkgObj.name;
- location = pkgObj.location;
- if (location) {
- config.paths[name] = pkgObj.location;
- }
-
- //Save pointer to main module ID for pkg name.
- //Remove leading dot in main, so main paths are normalized,
- //and remove any trailing .js, since different package
- //envs have different conventions: some use a module name,
- //some use a file name.
- config.pkgs[name] = pkgObj.name + '/' + (pkgObj.main || 'main')
- .replace(currDirRegExp, '')
- .replace(jsSuffixRegExp, '');
- });
- }
-
- //If there are any "waiting to execute" modules in the registry,
- //update the maps for them, since their info, like URLs to load,
- //may have changed.
- eachProp(registry, function (mod, id) {
- //If module already has init called, since it is too
- //late to modify them, and ignore unnormalized ones
- //since they are transient.
- if (!mod.inited && !mod.map.unnormalized) {
- mod.map = makeModuleMap(id, null, true);
- }
- });
-
- //If a deps array or a config callback is specified, then call
- //require with those args. This is useful when require is defined as a
- //config object before require.js is loaded.
- if (cfg.deps || cfg.callback) {
- context.require(cfg.deps || [], cfg.callback);
- }
- },
-
- makeShimExports: function (value) {
- function fn() {
- var ret;
- if (value.init) {
- ret = value.init.apply(global, arguments);
- }
- return ret || (value.exports && getGlobal(value.exports));
- }
- return fn;
- },
-
- makeRequire: function (relMap, options) {
- options = options || {};
-
- function localRequire(deps, callback, errback) {
- var id, map, requireMod;
-
- if (options.enableBuildCallback && callback && isFunction(callback)) {
- callback.__requireJsBuild = true;
- }
-
- if (typeof deps === 'string') {
- if (isFunction(callback)) {
- //Invalid call
- return onError(makeError('requireargs', 'Invalid require call'), errback);
- }
-
- //If require|exports|module are requested, get the
- //value for them from the special handlers. Caveat:
- //this only works while module is being defined.
- if (relMap && hasProp(handlers, deps)) {
- return handlers[deps](registry[relMap.id]);
- }
-
- //Synchronous access to one module. If require.get is
- //available (as in the Node adapter), prefer that.
- if (req.get) {
- return req.get(context, deps, relMap, localRequire);
- }
-
- //Normalize module name, if it contains . or ..
- map = makeModuleMap(deps, relMap, false, true);
- id = map.id;
-
- if (!hasProp(defined, id)) {
- return onError(makeError('notloaded', 'Module name "' +
- id +
- '" has not been loaded yet for context: ' +
- contextName +
- (relMap ? '' : '. Use require([])')));
- }
- return defined[id];
- }
-
- //Grab defines waiting in the global queue.
- intakeDefines();
-
- //Mark all the dependencies as needing to be loaded.
- context.nextTick(function () {
- //Some defines could have been added since the
- //require call, collect them.
- intakeDefines();
-
- requireMod = getModule(makeModuleMap(null, relMap));
-
- //Store if map config should be applied to this require
- //call for dependencies.
- requireMod.skipMap = options.skipMap;
-
- requireMod.init(deps, callback, errback, {
- enabled: true
- });
-
- checkLoaded();
- });
-
- return localRequire;
- }
-
- mixin(localRequire, {
- isBrowser: isBrowser,
-
- /**
- * Converts a module name + .extension into an URL path.
- * *Requires* the use of a module name. It does not support using
- * plain URLs like nameToUrl.
- */
- toUrl: function (moduleNamePlusExt) {
- var ext,
- index = moduleNamePlusExt.lastIndexOf('.'),
- segment = moduleNamePlusExt.split('/')[0],
- isRelative = segment === '.' || segment === '..';
-
- //Have a file extension alias, and it is not the
- //dots from a relative path.
- if (index !== -1 && (!isRelative || index > 1)) {
- ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length);
- moduleNamePlusExt = moduleNamePlusExt.substring(0, index);
- }
-
- return context.nameToUrl(normalize(moduleNamePlusExt,
- relMap && relMap.id, true), ext, true);
- },
-
- defined: function (id) {
- return hasProp(defined, makeModuleMap(id, relMap, false, true).id);
- },
-
- specified: function (id) {
- id = makeModuleMap(id, relMap, false, true).id;
- return hasProp(defined, id) || hasProp(registry, id);
- }
- });
-
- //Only allow undef on top level require calls
- if (!relMap) {
- localRequire.undef = function (id) {
- //Bind any waiting define() calls to this context,
- //fix for #408
- takeGlobalQueue();
-
- var map = makeModuleMap(id, relMap, true),
- mod = getOwn(registry, id);
-
- mod.undefed = true;
- removeScript(id);
-
- delete defined[id];
- delete urlFetched[map.url];
- delete undefEvents[id];
-
- //Clean queued defines too. Go backwards
- //in array so that the splices do not
- //mess up the iteration.
- eachReverse(defQueue, function(args, i) {
- if (args[0] === id) {
- defQueue.splice(i, 1);
- }
- });
- delete context.defQueueMap[id];
-
- if (mod) {
- //Hold on to listeners in case the
- //module will be attempted to be reloaded
- //using a different config.
- if (mod.events.defined) {
- undefEvents[id] = mod.events;
- }
-
- cleanRegistry(id);
- }
- };
- }
-
- return localRequire;
- },
-
- /**
- * Called to enable a module if it is still in the registry
- * awaiting enablement. A second arg, parent, the parent module,
- * is passed in for context, when this method is overridden by
- * the optimizer. Not shown here to keep code compact.
- */
- enable: function (depMap) {
- var mod = getOwn(registry, depMap.id);
- if (mod) {
- getModule(depMap).enable();
- }
- },
-
- /**
- * Internal method used by environment adapters to complete a load event.
- * A load event could be a script load or just a load pass from a synchronous
- * load call.
- * @param {String} moduleName the name of the module to potentially complete.
- */
- completeLoad: function (moduleName) {
- var found, args, mod,
- shim = getOwn(config.shim, moduleName) || {},
- shExports = shim.exports;
-
- takeGlobalQueue();
-
- while (defQueue.length) {
- args = defQueue.shift();
- if (args[0] === null) {
- args[0] = moduleName;
- //If already found an anonymous module and bound it
- //to this name, then this is some other anon module
- //waiting for its completeLoad to fire.
- if (found) {
- break;
- }
- found = true;
- } else if (args[0] === moduleName) {
- //Found matching define call for this script!
- found = true;
- }
-
- callGetModule(args);
- }
- context.defQueueMap = {};
-
- //Do this after the cycle of callGetModule in case the result
- //of those calls/init calls changes the registry.
- mod = getOwn(registry, moduleName);
-
- if (!found && !hasProp(defined, moduleName) && mod && !mod.inited) {
- if (config.enforceDefine && (!shExports || !getGlobal(shExports))) {
- if (hasPathFallback(moduleName)) {
- return;
- } else {
- return onError(makeError('nodefine',
- 'No define call for ' + moduleName,
- null,
- [moduleName]));
- }
- } else {
- //A script that does not call define(), so just simulate
- //the call for it.
- callGetModule([moduleName, (shim.deps || []), shim.exportsFn]);
- }
- }
-
- checkLoaded();
- },
-
- /**
- * Converts a module name to a file path. Supports cases where
- * moduleName may actually be just an URL.
- * Note that it **does not** call normalize on the moduleName,
- * it is assumed to have already been normalized. This is an
- * internal API, not a public one. Use toUrl for the public API.
- */
- nameToUrl: function (moduleName, ext, skipExt) {
- var paths, syms, i, parentModule, url,
- parentPath, bundleId,
- pkgMain = getOwn(config.pkgs, moduleName);
-
- if (pkgMain) {
- moduleName = pkgMain;
- }
-
- bundleId = getOwn(bundlesMap, moduleName);
-
- if (bundleId) {
- return context.nameToUrl(bundleId, ext, skipExt);
- }
-
- //If a colon is in the URL, it indicates a protocol is used and it is just
- //an URL to a file, or if it starts with a slash, contains a query arg (i.e. ?)
- //or ends with .js, then assume the user meant to use an url and not a module id.
- //The slash is important for protocol-less URLs as well as full paths.
- if (req.jsExtRegExp.test(moduleName)) {
- //Just a plain path, not module name lookup, so just return it.
- //Add extension if it is included. This is a bit wonky, only non-.js things pass
- //an extension, this method probably needs to be reworked.
- url = moduleName + (ext || '');
- } else {
- //A module that needs to be converted to a path.
- paths = config.paths;
-
- syms = moduleName.split('/');
- //For each module name segment, see if there is a path
- //registered for it. Start with most specific name
- //and work up from it.
- for (i = syms.length; i > 0; i -= 1) {
- parentModule = syms.slice(0, i).join('/');
-
- parentPath = getOwn(paths, parentModule);
- if (parentPath) {
- //If an array, it means there are a few choices,
- //Choose the one that is desired
- if (isArray(parentPath)) {
- parentPath = parentPath[0];
- }
- syms.splice(0, i, parentPath);
- break;
- }
- }
-
- //Join the path parts together, then figure out if baseUrl is needed.
- url = syms.join('/');
- url += (ext || (/^data\:|^blob\:|\?/.test(url) || skipExt ? '' : '.js'));
- url = (url.charAt(0) === '/' || url.match(/^[\w\+\.\-]+:/) ? '' : config.baseUrl) + url;
- }
-
- return config.urlArgs && !/^blob\:/.test(url) ?
- url + config.urlArgs(moduleName, url) : url;
- },
-
- //Delegates to req.load. Broken out as a separate function to
- //allow overriding in the optimizer.
- load: function (id, url) {
- req.load(context, id, url);
- },
-
- /**
- * Executes a module callback function. Broken out as a separate function
- * solely to allow the build system to sequence the files in the built
- * layer in the right sequence.
- *
- * @private
- */
- execCb: function (name, callback, args, exports) {
- return callback.apply(exports, args);
- },
-
- /**
- * callback for script loads, used to check status of loading.
- *
- * @param {Event} evt the event from the browser for the script
- * that was loaded.
- */
- onScriptLoad: function (evt) {
- //Using currentTarget instead of target for Firefox 2.0's sake. Not
- //all old browsers will be supported, but this one was easy enough
- //to support and still makes sense.
- if (evt.type === 'load' ||
- (readyRegExp.test((evt.currentTarget || evt.srcElement).readyState))) {
- //Reset interactive script so a script node is not held onto for
- //to long.
- interactiveScript = null;
-
- //Pull out the name of the module and the context.
- var data = getScriptData(evt);
- context.completeLoad(data.id);
- }
- },
-
- /**
- * Callback for script errors.
- */
- onScriptError: function (evt) {
- var data = getScriptData(evt);
- if (!hasPathFallback(data.id)) {
- var parents = [];
- eachProp(registry, function(value, key) {
- if (key.indexOf('_@r') !== 0) {
- each(value.depMaps, function(depMap) {
- if (depMap.id === data.id) {
- parents.push(key);
- return true;
- }
- });
- }
- });
- return onError(makeError('scripterror', 'Script error for "' + data.id +
- (parents.length ?
- '", needed by: ' + parents.join(', ') :
- '"'), evt, [data.id]));
- }
- }
- };
-
- context.require = context.makeRequire();
- return context;
- }
-
- /**
- * Main entry point.
- *
- * If the only argument to require is a string, then the module that
- * is represented by that string is fetched for the appropriate context.
- *
- * If the first argument is an array, then it will be treated as an array
- * of dependency string names to fetch. An optional function callback can
- * be specified to execute when all of those dependencies are available.
- *
- * Make a local req variable to help Caja compliance (it assumes things
- * on a require that are not standardized), and to give a short
- * name for minification/local scope use.
- */
- req = requirejs = function (deps, callback, errback, optional) {
-
- //Find the right context, use default
- var context, config,
- contextName = defContextName;
-
- // Determine if have config object in the call.
- if (!isArray(deps) && typeof deps !== 'string') {
- // deps is a config object
- config = deps;
- if (isArray(callback)) {
- // Adjust args if there are dependencies
- deps = callback;
- callback = errback;
- errback = optional;
- } else {
- deps = [];
- }
- }
-
- if (config && config.context) {
- contextName = config.context;
- }
-
- context = getOwn(contexts, contextName);
- if (!context) {
- context = contexts[contextName] = req.s.newContext(contextName);
- }
-
- if (config) {
- context.configure(config);
- }
-
- return context.require(deps, callback, errback);
- };
-
- /**
- * Support require.config() to make it easier to cooperate with other
- * AMD loaders on globally agreed names.
- */
- req.config = function (config) {
- return req(config);
- };
-
- /**
- * Execute something after the current tick
- * of the event loop. Override for other envs
- * that have a better solution than setTimeout.
- * @param {Function} fn function to execute later.
- */
- req.nextTick = typeof setTimeout !== 'undefined' ? function (fn) {
- setTimeout(fn, 4);
- } : function (fn) { fn(); };
-
- /**
- * Export require as a global, but only if it does not already exist.
- */
- if (!require) {
- require = req;
- }
-
- req.version = version;
-
- //Used to filter out dependencies that are already paths.
- req.jsExtRegExp = /^\/|:|\?|\.js$/;
- req.isBrowser = isBrowser;
- s = req.s = {
- contexts: contexts,
- newContext: newContext
- };
-
- //Create default context.
- req({});
-
- //Exports some context-sensitive methods on global require.
- each([
- 'toUrl',
- 'undef',
- 'defined',
- 'specified'
- ], function (prop) {
- //Reference from contexts instead of early binding to default context,
- //so that during builds, the latest instance of the default context
- //with its config gets used.
- req[prop] = function () {
- var ctx = contexts[defContextName];
- return ctx.require[prop].apply(ctx, arguments);
- };
- });
-
- if (isBrowser) {
- head = s.head = document.getElementsByTagName('head')[0];
- //If BASE tag is in play, using appendChild is a problem for IE6.
- //When that browser dies, this can be removed. Details in this jQuery bug:
- //http://dev.jquery.com/ticket/2709
- baseElement = document.getElementsByTagName('base')[0];
- if (baseElement) {
- head = s.head = baseElement.parentNode;
- }
- }
-
- /**
- * Any errors that require explicitly generates will be passed to this
- * function. Intercept/override it if you want custom error handling.
- * @param {Error} err the error object.
- */
- req.onError = defaultOnError;
-
- /**
- * Creates the node for the load command. Only used in browser envs.
- */
- req.createNode = function (config, moduleName, url) {
- var node = config.xhtml ?
- document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') :
- document.createElement('script');
- node.type = config.scriptType || 'text/javascript';
- node.charset = 'utf-8';
- node.async = true;
- return node;
- };
-
- /**
- * Does the request to load a module for the browser case.
- * Make this a separate function to allow other environments
- * to override it.
- *
- * @param {Object} context the require context to find state.
- * @param {String} moduleName the name of the module.
- * @param {Object} url the URL to the module.
- */
- req.load = function (context, moduleName, url) {
- var config = (context && context.config) || {},
- node;
- if (isBrowser) {
- //In the browser so use a script tag
- node = req.createNode(config, moduleName, url);
-
- node.setAttribute('data-requirecontext', context.contextName);
- node.setAttribute('data-requiremodule', moduleName);
-
- //Set up load listener. Test attachEvent first because IE9 has
- //a subtle issue in its addEventListener and script onload firings
- //that do not match the behavior of all other browsers with
- //addEventListener support, which fire the onload event for a
- //script right after the script execution. See:
- //https://connect.microsoft.com/IE/feedback/details/648057/script-onload-event-is-not-fired-immediately-after-script-execution
- //UNFORTUNATELY Opera implements attachEvent but does not follow the script
- //script execution mode.
- if (node.attachEvent &&
- //Check if node.attachEvent is artificially added by custom script or
- //natively supported by browser
- //read https://github.com/requirejs/requirejs/issues/187
- //if we can NOT find [native code] then it must NOT natively supported.
- //in IE8, node.attachEvent does not have toString()
- //Note the test for "[native code" with no closing brace, see:
- //https://github.com/requirejs/requirejs/issues/273
- !(node.attachEvent.toString && node.attachEvent.toString().indexOf('[native code') < 0) &&
- !isOpera) {
- //Probably IE. IE (at least 6-8) do not fire
- //script onload right after executing the script, so
- //we cannot tie the anonymous define call to a name.
- //However, IE reports the script as being in 'interactive'
- //readyState at the time of the define call.
- useInteractive = true;
-
- node.attachEvent('onreadystatechange', context.onScriptLoad);
- //It would be great to add an error handler here to catch
- //404s in IE9+. However, onreadystatechange will fire before
- //the error handler, so that does not help. If addEventListener
- //is used, then IE will fire error before load, but we cannot
- //use that pathway given the connect.microsoft.com issue
- //mentioned above about not doing the 'script execute,
- //then fire the script load event listener before execute
- //next script' that other browsers do.
- //Best hope: IE10 fixes the issues,
- //and then destroys all installs of IE 6-9.
- //node.attachEvent('onerror', context.onScriptError);
- } else {
- node.addEventListener('load', context.onScriptLoad, false);
- node.addEventListener('error', context.onScriptError, false);
- }
- node.src = url;
-
- //Calling onNodeCreated after all properties on the node have been
- //set, but before it is placed in the DOM.
- if (config.onNodeCreated) {
- config.onNodeCreated(node, config, moduleName, url);
- }
-
- //For some cache cases in IE 6-8, the script executes before the end
- //of the appendChild execution, so to tie an anonymous define
- //call to the module name (which is stored on the node), hold on
- //to a reference to this node, but clear after the DOM insertion.
- currentlyAddingScript = node;
- if (baseElement) {
- head.insertBefore(node, baseElement);
- } else {
- head.appendChild(node);
- }
- currentlyAddingScript = null;
-
- return node;
- } else if (isWebWorker) {
- try {
- //In a web worker, use importScripts. This is not a very
- //efficient use of importScripts, importScripts will block until
- //its script is downloaded and evaluated. However, if web workers
- //are in play, the expectation is that a build has been done so
- //that only one script needs to be loaded anyway. This may need
- //to be reevaluated if other use cases become common.
-
- // Post a task to the event loop to work around a bug in WebKit
- // where the worker gets garbage-collected after calling
- // importScripts(): https://webkit.org/b/153317
- setTimeout(function() {}, 0);
- importScripts(url);
-
- //Account for anonymous modules
- context.completeLoad(moduleName);
- } catch (e) {
- context.onError(makeError('importscripts',
- 'importScripts failed for ' +
- moduleName + ' at ' + url,
- e,
- [moduleName]));
- }
- }
- };
-
- function getInteractiveScript() {
- if (interactiveScript && interactiveScript.readyState === 'interactive') {
- return interactiveScript;
- }
-
- eachReverse(scripts(), function (script) {
- if (script.readyState === 'interactive') {
- return (interactiveScript = script);
- }
- });
- return interactiveScript;
- }
-
- //Look for a data-main script attribute, which could also adjust the baseUrl.
- if (isBrowser && !cfg.skipDataMain) {
- //Figure out baseUrl. Get it from the script tag with require.js in it.
- eachReverse(scripts(), function (script) {
- //Set the 'head' where we can append children by
- //using the script's parent.
- if (!head) {
- head = script.parentNode;
- }
-
- //Look for a data-main attribute to set main script for the page
- //to load. If it is there, the path to data main becomes the
- //baseUrl, if it is not already set.
- dataMain = script.getAttribute('data-main');
- if (dataMain) {
- //Preserve dataMain in case it is a path (i.e. contains '?')
- mainScript = dataMain;
-
- //Set final baseUrl if there is not already an explicit one,
- //but only do so if the data-main value is not a loader plugin
- //module ID.
- if (!cfg.baseUrl && mainScript.indexOf('!') === -1) {
- //Pull off the directory of data-main for use as the
- //baseUrl.
- src = mainScript.split('/');
- mainScript = src.pop();
- subPath = src.length ? src.join('/') + '/' : './';
-
- cfg.baseUrl = subPath;
- }
-
- //Strip off any trailing .js since mainScript is now
- //like a module name.
- mainScript = mainScript.replace(jsSuffixRegExp, '');
-
- //If mainScript is still a path, fall back to dataMain
- if (req.jsExtRegExp.test(mainScript)) {
- mainScript = dataMain;
- }
-
- //Put the data-main script in the files to load.
- cfg.deps = cfg.deps ? cfg.deps.concat(mainScript) : [mainScript];
-
- return true;
- }
- });
- }
-
- /**
- * The function that handles definitions of modules. Differs from
- * require() in that a string for the module should be the first argument,
- * and the function to execute after dependencies are loaded should
- * return a value to define the module corresponding to the first argument's
- * name.
- */
- define = function (name, deps, callback) {
- var node, context;
-
- //Allow for anonymous modules
- if (typeof name !== 'string') {
- //Adjust args appropriately
- callback = deps;
- deps = name;
- name = null;
- }
-
- //This module may not have dependencies
- if (!isArray(deps)) {
- callback = deps;
- deps = null;
- }
-
- //If no name, and callback is a function, then figure out if it a
- //CommonJS thing with dependencies.
- if (!deps && isFunction(callback)) {
- deps = [];
- //Remove comments from the callback string,
- //look for require calls, and pull them into the dependencies,
- //but only if there are function args.
- if (callback.length) {
- callback
- .toString()
- .replace(commentRegExp, commentReplace)
- .replace(cjsRequireRegExp, function (match, dep) {
- deps.push(dep);
- });
-
- //May be a CommonJS thing even without require calls, but still
- //could use exports, and module. Avoid doing exports and module
- //work though if it just needs require.
- //REQUIRES the function to expect the CommonJS variables in the
- //order listed below.
- deps = (callback.length === 1 ? ['require'] : ['require', 'exports', 'module']).concat(deps);
- }
- }
-
- //If in IE 6-8 and hit an anonymous define() call, do the interactive
- //work.
- if (useInteractive) {
- node = currentlyAddingScript || getInteractiveScript();
- if (node) {
- if (!name) {
- name = node.getAttribute('data-requiremodule');
- }
- context = contexts[node.getAttribute('data-requirecontext')];
- }
- }
-
- //Always save off evaluating the def call until the script onload handler.
- //This allows multiple modules to be in a file without prematurely
- //tracing dependencies, and allows for anonymous module support,
- //where the module name is not known until the script onload event
- //occurs. If no context, use the global queue, and get it processed
- //in the onscript load callback.
- if (context) {
- context.defQueue.push([name, deps, callback]);
- context.defQueueMap[name] = true;
- } else {
- globalDefQueue.push([name, deps, callback]);
- }
- };
-
- define.amd = {
- jQuery: true
- };
-
- /**
- * Executes the text. Normally just uses eval, but can be modified
- * to use a better, environment-specific call. Only used for transpiling
- * loader plugins, not for plain JS modules.
- * @param {String} text the text to execute/evaluate.
- */
- req.exec = function (text) {
- /*jslint evil: true */
- return eval(text);
- };
-
- //Set up with config info.
- req(cfg);
-}(this, (typeof setTimeout === 'undefined' ? undefined : setTimeout)));
diff --git a/packages/concatjs/web_test/BUILD.bazel b/packages/concatjs/web_test/BUILD.bazel
deleted file mode 100644
index 17d5559..0000000
--- a/packages/concatjs/web_test/BUILD.bazel
+++ /dev/null
@@ -1,59 +0,0 @@
-# Copyright 2019 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
-load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary")
-
-package(default_visibility = ["//visibility:public"])
-
-exports_files(["karma.conf.js"])
-
-nodejs_binary(
- name = "karma_bin",
- data = [
- "//packages/concatjs:bazel_concatjs",
- "@npm//jasmine-core",
- "@npm//karma",
- "@npm//karma-chrome-launcher",
- "@npm//karma-firefox-launcher",
- "@npm//karma-jasmine",
- "@npm//karma-junit-reporter",
- "@npm//karma-requirejs",
- "@npm//karma-sourcemap-loader",
- "@npm//requirejs",
- ],
- entry_point = "@npm//:node_modules/karma/bin/karma",
-)
-
-bzl_library(
- name = "bzl",
- testonly = True,
- srcs = glob(["*.bzl"]),
- deps = [
- "@bazel_skylib//lib:types",
- "@build_bazel_rules_nodejs//:bzl",
- "@build_bazel_rules_nodejs//internal/js_library:bzl",
- "@io_bazel_rules_webtesting//web",
- "@rules_nodejs//nodejs:bzl",
- ],
-)
-
-filegroup(
- name = "package_contents",
- srcs = [
- "BUILD.bazel",
- "karma.conf.js",
- "karma_web_test.bzl",
- ],
-)
diff --git a/packages/concatjs/web_test/karma.conf.js b/packages/concatjs/web_test/karma.conf.js
deleted file mode 100644
index 90a03ef..0000000
--- a/packages/concatjs/web_test/karma.conf.js
+++ /dev/null
@@ -1,496 +0,0 @@
-// Karma configuration
-// GENERATED BY Bazel
-try {
- const crypto = require('crypto');
- const fs = require('fs');
- const path = require('path');
- const child_process = require('child_process');
- const runfiles = require(process.env['BAZEL_NODE_RUNFILES_HELPER']);
-
- const VERBOSE_LOGS = !!process.env['VERBOSE_LOGS'];
-
- function log_verbose(...m) {
- // This is a template file so we use __filename to output the actual filename
- if (VERBOSE_LOGS) console.error(`[${path.basename(__filename)}]`, ...m);
- }
-
- // BEGIN ENV VARS
- TMPL_env_vars
- // END ENV VARS
-
- const configPath = 'TMPL_config_file';
-
- log_verbose(`running with
- cwd: ${process.cwd()}
- configPath: ${configPath}`);
-
- /**
- * Helper function to find a particular namedFile
- * within the webTestMetadata webTestFiles
- */
- function findNamedFile(webTestMetadata, key) {
- let result;
- webTestMetadata['webTestFiles'].forEach(entry => {
- const webTestNamedFiles = entry['namedFiles'];
- if (webTestNamedFiles && webTestNamedFiles[key]) {
- result = webTestNamedFiles[key];
- }
- });
- return result;
- }
-
- /**
- * Helper function to extract a browser archive
- * and return the path to extract executable
- */
- function extractWebArchive(extractExe, archiveFile, executablePath) {
- try {
- // Paths are relative to the root runfiles folder
- extractExe = extractExe ? path.join('..', extractExe) : extractExe;
- archiveFile = path.join('..', archiveFile);
- const extractedExecutablePath = path.join(process.cwd(), executablePath);
- if (!extractExe) {
- throw new Error('No EXTRACT_EXE found');
- }
- child_process.execFileSync(
- extractExe, [archiveFile, '.'], {stdio: [process.stdin, process.stdout, process.stderr]});
- log_verbose(
- `Extracting web archive ${archiveFile} with ${extractExe} to ${extractedExecutablePath}`);
- return extractedExecutablePath;
- } catch (e) {
- console.error(`Failed to extract ${archiveFile}`);
- throw e;
- }
- }
-
- /**
- * Check if Chrome sandboxing is supported on the current platform.
- */
- function supportChromeSandboxing() {
- if (process.platform === 'darwin') {
- // Chrome 73+ fails to initialize the sandbox on OSX when running under Bazel.
- // ```
- // ERROR [launcher]: Cannot start ChromeHeadless
- // ERROR:crash_report_database_mac.mm(96)] mkdir
- // /private/var/tmp/_bazel_greg/62ef096b0da251c6d093468a1efbfbd3/execroot/angular/bazel-out/darwin-fastbuild/bin/external/io_bazel_rules_webtesting/third_party/chromium/chromium.out/chrome-mac/Chromium.app/Contents/Versions/73.0.3683.0/Chromium
- // Framework.framework/Versions/A/new: Permission denied (13) ERROR:file_io.cc(89)]
- // ReadExactly: expected 8, observed 0 ERROR:crash_report_database_mac.mm(96)] mkdir
- // /private/var/tmp/_bazel_greg/62ef096b0da251c6d093468a1efbfbd3/execroot/angular/bazel-out/darwin-fastbuild/bin/external/io_bazel_rules_webtesting/third_party/chromium/chromium.out/chrome-mac/Chromium.app/Contents/Versions/73.0.3683.0/Chromium
- // Framework.framework/Versions/A/new: Permission denied (13) Chromium Helper[94642] <Error>:
- // SeatbeltExecServer: Failed to initialize sandbox: -1 Operation not permitted Failed to
- // initialize sandbox. [0213/201206.137114:FATAL:content_main_delegate.cc(54)] Check failed:
- // false. 0 Chromium Framework 0x000000010c078bc9 ChromeMain + 43788137 1
- // Chromium Framework 0x000000010bfc0f43 ChromeMain + 43035363
- // ...
- // ```
- return false;
- }
-
- if (process.platform === 'linux') {
- // Chrome on Linux uses sandboxing, which needs user namespaces to be enabled.
- // This is not available on all kernels and it might be turned off even if it is available.
- // Notable examples where user namespaces are not available include:
- // - In Debian it is compiled-in but disabled by default.
- // - The Docker daemon for Windows or OSX does not support user namespaces.
- // We can detect if user namespaces are supported via
- // /proc/sys/kernel/unprivileged_userns_clone. For more information see:
- // https://github.com/Googlechrome/puppeteer/issues/290
- // https://superuser.com/questions/1094597/enable-user-namespaces-in-debian-kernel#1122977
- // https://github.com/karma-runner/karma-chrome-launcher/issues/158
- // https://github.com/angular/angular/pull/24906
- try {
- const res = child_process.execSync('cat /proc/sys/kernel/unprivileged_userns_clone')
- .toString()
- .trim();
- return res === '1';
- } catch (error) {
- }
- return false;
- }
-
- return true;
- }
-
- /**
- * Helper function to override base karma config values.
- */
- function overrideConfigValue(conf, name, value) {
- if (conf.hasOwnProperty(name)) {
- console.warn(
- `Your karma configuration specifies '${name}' which will be overwritten by Bazel`);
- }
- conf[name] = value;
- }
-
- /**
- * Helper function to override nested karma config values.
- */
- function overrideNestedConfigValue(conf, name, value) {
- const nameParts = name.split('.');
- const finalName = nameParts.pop();
- for (const property of nameParts) {
- if (!(property in conf)) {
- conf[property] = {};
- }
- conf = conf[property];
- }
- if (conf.hasOwnProperty(name)) {
- console.warn(
- `Your karma configuration specifies '${name}' which will be overwritten by Bazel`);
- }
- conf[finalName] = value;
- }
-
- /**
- * Helper function to merge base karma config values that are arrays.
- */
- function mergeConfigArray(conf, name, values) {
- if (!conf[name]) {
- conf[name] = [];
- }
- values.forEach(v => {
- if (!conf[name].includes(v)) {
- conf[name].push(v);
- }
- })
- }
-
- function tryRequire(packageName) {
- try {
- return require(packageName);
- } catch (e) {
- if (e && e.code === 'MODULE_NOT_FOUND') {
- return undefined;
- }
-
- throw e;
- }
- }
-
- /**
- * Configuration settings for karma under Bazel common to karma_web_test
- * and karma_web_test_suite.
- */
- function configureBazelConfig(config, conf) {
- // list of karma plugins
- mergeConfigArray(conf, 'plugins', [
- // Loads 'concat_js'
- require('@bazel/concatjs'),
- // Load plugins that are peer deps. These packages are used in this config file.
- require('karma-chrome-launcher'),
- require('karma-firefox-launcher'),
- require('karma-jasmine'),
- require('karma-requirejs'),
- require('karma-sourcemap-loader'),
- // Loads user-installed karma-* packages in the root node_modules.
- 'karma-*',
- ]);
-
- // list of karma preprocessors
- if (!conf.preprocessors) {
- conf.preprocessors = {}
- }
- conf.preprocessors['**/*.js'] = ['sourcemap'];
-
- // list of test frameworks to use
- overrideConfigValue(conf, 'frameworks', ['jasmine', 'concat_js']);
-
- // test results reporter to use
- // possible values: 'dots', 'progress'
- // available reporters: https://npmjs.org/browse/keyword/karma-reporter
- mergeConfigArray(conf, 'reporters', ['progress']);
-
- // enable / disable colors in the output (reporters and logs)
- if (!conf.colors) {
- conf.colors = true;
- }
-
- // level of logging
- // possible values: config.LOG_DISABLE || config.LOG_ERROR ||
- // config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
- conf.logLevel = VERBOSE_LOGS ? config.LOG_DEBUG : config.LOG_INFO;
-
- // enable / disable watching file and executing tests whenever
- // any file changes
- overrideConfigValue(conf, 'autoWatch', process.env['IBAZEL_NOTIFY_CHANGES'] === 'y');
-
- // Continuous Integration mode
- // if true, Karma captures browsers, runs the tests and exits
- // note: run_karma.sh may override this as a command-line option.
- overrideConfigValue(conf, 'singleRun', false);
-
- // Concurrency level
- // how many browser should be started simultaneous
- overrideConfigValue(conf, 'concurrency', Infinity);
-
- // base path that will be used to resolve all patterns
- // (eg. files, exclude)
- overrideConfigValue(conf, 'basePath', 'TMPL_runfiles_path');
-
- // Do not show "no timestamp" errors from "karma-requirejs" for proxied file
- // requests. Files which are passed as "static_files" are proxied by default and
- // therefore should not cause such an exception when loaded as expected.
- // See: https://github.com/karma-runner/karma-requirejs/issues/6
- const requireJsShowNoTimestampsError = '^(?!/base/).*$';
-
- if (conf.client) {
- overrideConfigValue(
- conf.client, 'requireJsShowNoTimestampsError', requireJsShowNoTimestampsError);
- } else {
- conf.client = {requireJsShowNoTimestampsError};
- }
-
- // Enable the junit reporter if the XML_OUTPUT_FILE environment variable
- // is defined and the karma-junit-reporter package is installed.
- // The configuration for the junit reporter will be created or overridden
- // with the configuration required for bazel to work properly.
- const testOutputFile = process.env.XML_OUTPUT_FILE;
- const karmaJunitReporterPlugin = testOutputFile ? tryRequire('karma-junit-reporter') : undefined;
- if (karmaJunitReporterPlugin) {
- mergeConfigArray(conf, 'plugins', [
- karmaJunitReporterPlugin,
- ]);
-
- mergeConfigArray(conf, 'reporters', ['junit']);
- overrideNestedConfigValue(conf, 'junitReporter.outputDir', path.dirname(testOutputFile));
- overrideNestedConfigValue(conf, 'junitReporter.outputFile', path.basename(testOutputFile));
- overrideNestedConfigValue(conf, 'junitReporter.useBrowserName', false);
- }
- }
-
- /**
- * Configure the 'files' and 'proxies' configuration attributes.
- * These are concatenated into a single file by karma-concat-js.
- */
- function configureFiles(conf) {
- overrideConfigValue(conf, 'files', []);
- overrideConfigValue(conf, 'exclude', []);
- overrideConfigValue(conf, 'proxies', {});
-
- // Static files are added to the files array but configured to not be included,
- // so karma-concat-js does not included them in the bundle. Note that we need
- // to add the static files before adding the included files as we don't want
- // to overwrite included files (changing from included to not included).
- [
- // BEGIN STATIC FILES
- TMPL_static_files
- // END STATIC FILES
- ].forEach((f) => {
- // In Windows, the runfile will probably not be symlinked. Se we need to
- // serve the real file through karma, and proxy calls to the expected file
- // location in the runfiles to the real file.
- const resolvedFile = runfiles.resolve(f);
- conf.files.push({pattern: resolvedFile, included: false});
- // Prefixing the proxy path with '/absolute' allows karma to load local
- // files. This doesn't see to be an official API.
- // https://github.com/karma-runner/karma/issues/2703
- conf.proxies['/base/' + f] = '/absolute' + resolvedFile;
- });
-
- [
- // BEGIN BOOTSTRAP FILES
- TMPL_bootstrap_files
- // END BOOTSTRAP FILES
- // BEGIN USER FILES
- TMPL_user_files
- // END USER FILES
- ].forEach(f => conf.files.push(runfiles.resolve(f)))
-
- var requireConfigContent = `
- // A simplified version of Karma's requirejs.config.tpl.js for use with Karma under Bazel.
- // This does an explicit \`require\` on each test script in the files, otherwise nothing will be loaded.
- (function(){
- var runtimeFiles = [
- // BEGIN RUNTIME FILES
- TMPL_runtime_files
- // END RUNTIME FILES
- ].map(function(file) { return file.replace(/\\.js$/, ''); });
- var allFiles = [
- // BEGIN USER FILES
- TMPL_user_files
- // END USER FILES
- ];
- var allTestFiles = [];
- allFiles.forEach(function (file) {
- if (/[^a-zA-Z0-9](spec|test)\\.js$/i.test(file) && !/\\/node_modules\\//.test(file)) {
- allTestFiles.push(file.replace(/\\.js$/, ''))
- }
- });
- require(runtimeFiles, function() { return require(allTestFiles, window.__karma__.start); });
- })();
- `;
-
- const requireConfigFile = path.join(
- process.env['TEST_TMPDIR'], crypto.randomBytes(6).readUIntLE(0, 6).toString(36) + '.js');
- fs.writeFileSync(requireConfigFile, requireConfigContent);
- conf.files.push(requireConfigFile);
- }
-
- /**
- * Configure karma under karma_web_test_suite.
- * `browsers` and `customLaunchers` are setup by Bazel.
- */
- function configureTsWebTestSuiteConfig(conf) {
- // WEB_TEST_METADATA is configured in rules_webtesting based on value
- // of the browsers attribute passed to karms_web_test_suite
- // We setup the karma configuration based on the values in this object
- if (!process.env['WEB_TEST_METADATA']) {
- // This is a karma_web_test rule since there is no WEB_TEST_METADATA
- return;
- }
-
- overrideConfigValue(conf, 'browsers', []);
- overrideConfigValue(conf, 'customLaunchers', null);
-
- const webTestMetadata = require(runfiles.resolve(process.env['WEB_TEST_METADATA']));
- log_verbose(`WEB_TEST_METADATA: ${JSON.stringify(webTestMetadata, null, 2)}`);
- if (webTestMetadata['environment'] === 'local') {
- // When a local chrome or firefox browser is chosen such as
- // "@io_bazel_rules_webtesting//browsers:chromium-local" or
- // "@io_bazel_rules_webtesting//browsers:firefox-local"
- // then the 'environment' will equal 'local' and
- // 'webTestFiles' will contain the path to the binary to use
- const extractExe = findNamedFile(webTestMetadata, 'EXTRACT_EXE');
- webTestMetadata['webTestFiles'].forEach(webTestFiles => {
- const webTestNamedFiles = webTestFiles['namedFiles'];
- const archiveFile = webTestFiles['archiveFile'];
- if (webTestNamedFiles['CHROMIUM']) {
- // When karma is configured to use Chrome it will look for a CHROME_BIN
- // environment variable.
- if (archiveFile) {
- process.env.CHROME_BIN =
- extractWebArchive(extractExe, archiveFile, webTestNamedFiles['CHROMIUM']);
- } else {
- try {
- process.env.CHROME_BIN = runfiles.resolve(webTestNamedFiles['CHROMIUM']);
- } catch {
- // Fail as this file is expected to be in runfiles
- throw new Error(`Failed to resolve rules_webtesting Chromium binary '${
- webTestNamedFiles['CHROMIUM']}' in runfiles`);
- }
- }
- // Read any additional chrome options (as specified by the
- // rules_webtesting manifest).
- const chromeOptions = (webTestMetadata['capabilities'] || {})['goog:chromeOptions'];
- const additionalArgs = (chromeOptions ? chromeOptions['args'] : []).filter(arg => {
- // We never want to 'run' Chrome in headless mode.
- return arg != '--headless';
- });
- const browser = process.env['DISPLAY'] ? 'Chrome' : 'ChromeHeadless';
- if (!supportChromeSandboxing()) {
- const launcher = 'CustomChromeWithoutSandbox';
- conf.customLaunchers =
- {[launcher]: {base: browser, flags: ['--no-sandbox', ...additionalArgs]}};
- conf.browsers.push(launcher);
- } else {
- const launcher = 'CustomChrome';
- conf.customLaunchers = {[launcher]: {base: browser, flags: additionalArgs}};
- conf.browsers.push(launcher);
- }
- }
- if (webTestNamedFiles['FIREFOX']) {
- // When karma is configured to use Firefox it will look for a
- // FIREFOX_BIN environment variable.
- if (archiveFile) {
- process.env.FIREFOX_BIN =
- extractWebArchive(extractExe, archiveFile, webTestNamedFiles['FIREFOX']);
- } else {
- try {
- process.env.FIREFOX_BIN = runfiles.resolve(webTestNamedFiles['FIREFOX']);
- } catch {
- // Fail as this file is expected to be in runfiles
- throw new Error(`Failed to resolve rules_webtesting Firefox binary '${
- webTestNamedFiles['FIREFOX']}' in runfiles`);
- }
- }
-
- // For Firefox, we need to disable the content sandbox as the browser is already being
- // launched as part of the Bazel sandbox. This is necessary because the integrated content
- // sandbox in Firefox will conflict with the Bazel sandbox due to nested sandboxing.
- // This is similar to why we disable sandbox for Chromium (as seen above).
- process.env.MOZ_DISABLE_CONTENT_SANDBOX = '1';
-
- conf.browsers.push(process.env['DISPLAY'] ? 'Firefox' : 'FirefoxHeadless');
- }
- });
- } else {
- throw new Error(`Unknown WEB_TEST_METADATA environment '${webTestMetadata['environment']}'`);
- }
-
- if (!conf.browsers.length) {
- throw new Error('No browsers configured in web test suite');
- }
- }
-
- function configureTsWebTestConfig(conf) {
- if (process.env['WEB_TEST_METADATA']) {
- // This is a karma_web_test_suite rule since there is a WEB_TEST_METADATA
- return;
- }
-
- // Fallback to using the system local chrome if no valid browsers have been
- // configured above
- if (!conf.browsers || !conf.browsers.length) {
- console.warn('No browsers configured. Configuring Karma to use system Chrome.');
- conf.browsers = [process.env['DISPLAY'] ? 'Chrome' : 'ChromeHeadless'];
- }
- }
-
- function configureFormatError(conf) {
- conf.formatError = (msg) => {
- // This is a bazel specific formatError that removes the workspace
- // name from stack traces.
- // Look for filenames of the format "(<filename>:<row>:<column>"
- const FILENAME_REGEX = /\(([^:\n\r]+)(:\d+:\d+)/gm;
- msg = msg.replace(FILENAME_REGEX, (_, p1, p2) => {
- if (p1.startsWith('../')) {
- // Remove all leading "../"
- while (p1.startsWith('../')) {
- p1 = p1.substr(3);
- }
- } else {
- // Remove workspace name(angular, ngdeps etc.) from the beginning.
- const index = p1.indexOf('/');
- if (index >= 0) {
- p1 = p1.substr(index + 1);
- }
- }
- return '(' + p1 + p2;
- });
- return msg + '\n\n';
- };
- }
-
- module.exports = function(config) {
- let conf = {};
-
- // Import the user's base karma configuration if specified
- if (configPath) {
- const baseConf = require(runfiles.resolve(configPath));
- if (typeof baseConf !== 'function') {
- throw new Error(
- 'Invalid base karma configuration. Expected config function to be exported.');
- }
- const originalSetConfig = config.set;
- config.set = function(c) {
- conf = c;
- };
- baseConf(config);
- config.set = originalSetConfig;
- log_verbose(`base karma configuration: ${JSON.stringify(conf, null, 2)}`);
- }
-
- configureBazelConfig(config, conf);
- configureFiles(conf);
- configureTsWebTestSuiteConfig(conf);
- configureTsWebTestConfig(conf);
- configureFormatError(conf);
-
- log_verbose(`karma configuration: ${JSON.stringify(conf, null, 2)}`);
-
- config.set(conf);
- }
-} catch (e) {
- console.error('Error in karma configuration', e.toString());
- throw e;
-}
diff --git a/packages/concatjs/web_test/karma_web_test.bzl b/packages/concatjs/web_test/karma_web_test.bzl
deleted file mode 100644
index f45aced..0000000
--- a/packages/concatjs/web_test/karma_web_test.bzl
+++ /dev/null
@@ -1,487 +0,0 @@
-# Copyright 2017 The Bazel Authors. All rights reserved.
-#
-# 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.
-"Unit testing with Karma"
-
-load("@rules_nodejs//nodejs:providers.bzl", "JSModuleInfo")
-load("@build_bazel_rules_nodejs//:providers.bzl", "ExternalNpmPackageInfo", "JSNamedModuleInfo", "node_modules_aspect")
-load("@build_bazel_rules_nodejs//internal/js_library:js_library.bzl", "write_amd_names_shim")
-load("@io_bazel_rules_webtesting//web:web.bzl", "web_test_suite")
-load("@io_bazel_rules_webtesting//web/internal:constants.bzl", "DEFAULT_TEST_SUITE_TAGS", "DEFAULT_WRAPPED_TEST_TAGS")
-
-KARMA_PEER_DEPS = [
- # NB: uncommented during pkg_npm
- #@external "@npm//@bazel/concatjs",
- "@npm//karma",
- "@npm//karma-chrome-launcher",
- "@npm//karma-firefox-launcher",
- "@npm//karma-jasmine",
- "@npm//karma-requirejs",
- "@npm//karma-sourcemap-loader",
- "@npm//requirejs",
-]
-
-KARMA_WEB_TEST_ATTRS = {
- "bootstrap": attr.label_list(
- doc = """JavaScript files to include *before* the module loader (require.js).
- For example, you can include Reflect,js for TypeScript decorator metadata reflection,
- or UMD bundles for third-party libraries.""",
- allow_files = [".js"],
- ),
- "config_file": attr.label(
- doc = """User supplied Karma configuration file. Bazel will override
- certain attributes of this configuration file. Attributes that are
- overridden will be outputted to the test log.""",
- allow_single_file = True,
- ),
- "configuration_env_vars": attr.string_list(
- doc = """Pass these configuration environment variables to the resulting binary.
- Chooses a subset of the configuration environment variables (taken from ctx.var), which also
- includes anything specified via the --define flag.
- Note, this can lead to different outputs produced by this rule.""",
- default = [],
- ),
- "data": attr.label_list(
- doc = "Runtime dependencies",
- allow_files = True,
- ),
- "deps": attr.label_list(
- doc = "Other targets which produce JavaScript such as `ts_library`",
- allow_files = True,
- aspects = [node_modules_aspect],
- ),
- "karma": attr.label(
- doc = "karma binary label",
- # NB: replaced during pkg_npm with "@npm//karma/bin:karma"
- default = "//packages/concatjs/web_test:karma_bin",
- executable = True,
- cfg = "exec",
- allow_files = True,
- ),
- "runtime_deps": attr.label_list(
- doc = """Dependencies which should be loaded after the module loader but before the srcs and deps.
- These should be a list of targets which produce JavaScript such as `ts_library`.
- The files will be loaded in the same order they are declared by that rule.""",
- allow_files = True,
- aspects = [node_modules_aspect],
- ),
- "srcs": attr.label_list(
- doc = "A list of JavaScript test files",
- allow_files = [".js"],
- ),
- "static_files": attr.label_list(
- doc = """Arbitrary files which are available to be served on request.
- Files are served at:
- `/base/<WORKSPACE_NAME>/<path-to-file>`, e.g.
- `/base/npm_bazel_typescript/examples/testing/static_script.js`""",
- allow_files = True,
- ),
- "_conf_tmpl": attr.label(
- default = "//packages/concatjs/web_test:karma.conf.js",
- allow_single_file = True,
- ),
-}
-
-# Avoid using non-normalized paths (workspace/../other_workspace/path)
-def _to_manifest_path(ctx, file):
- if file.short_path.startswith("../"):
- return file.short_path[3:]
- else:
- return ctx.workspace_name + "/" + file.short_path
-
-# Write the AMD names shim bootstrap file
-def _write_amd_names_shim(ctx):
- amd_names_shim = ctx.actions.declare_file(
- "_%s.amd_names_shim.js" % ctx.label.name,
- sibling = ctx.outputs.executable,
- )
- write_amd_names_shim(ctx.actions, amd_names_shim, ctx.attr.bootstrap)
- return amd_names_shim
-
-def _filter_js(files):
- return [f for f in files if f.extension == "js" or f.extension == "mjs"]
-
-def _find_dep(ctx, suffix):
- for d in ctx.files.deps:
- if (d.path.endswith(suffix)):
- return _to_manifest_path(ctx, d)
- fail("couldn't find file %s in the deps" % suffix)
-
-# Generates the karma configuration file for the rule
-def _write_karma_config(ctx, files, amd_names_shim):
- configuration = ctx.outputs.configuration
-
- config_file = None
-
- if ctx.attr.config_file:
- if JSModuleInfo in ctx.attr.config_file:
- config_file = _filter_js(ctx.attr.config_file[JSModuleInfo].direct_sources.to_list())[0]
- else:
- config_file = ctx.file.config_file
-
- # The files in the bootstrap attribute come before the require.js support.
- # Note that due to frameworks = ['jasmine'], a few scripts will come before
- # the bootstrap entries:
- # karma-jasmine/lib/boot.js
- # karma-jasmine/lib/adapter.js
- # This is desired so that the bootstrap entries can patch jasmine, as zone.js does.
- bootstrap_entries = [
- _to_manifest_path(ctx, f)
- for f in ctx.files.bootstrap
- ]
-
- # Explicitly list the requirejs library files here, rather than use
- # `frameworks: ['requirejs']`
- # so that we control the script order, and the bootstrap files come before
- # require.js.
- # That allows bootstrap files to have anonymous AMD modules, or to do some
- # polyfilling before test libraries load.
- # See https://github.com/karma-runner/karma/issues/699
- bootstrap_entries += [
- _find_dep(ctx, "requirejs/require.js"),
- _find_dep(ctx, "karma-requirejs/lib/adapter.js"),
- "/".join([ctx.workspace_name, amd_names_shim.short_path]),
- ]
-
- # Next we load the "runtime_deps" which we expect to contain named AMD modules
- # Thus they should come after the require.js script, but before any srcs or deps
- runtime_files = []
- for dep in ctx.attr.runtime_deps:
- if JSNamedModuleInfo in dep:
- for src in dep[JSNamedModuleInfo].direct_sources.to_list():
- runtime_files.append(_to_manifest_path(ctx, src))
- if not JSNamedModuleInfo in dep and not ExternalNpmPackageInfo in dep and hasattr(dep, "files"):
- # These are javascript files provided by DefaultInfo from a direct
- # dep that has no JSNamedModuleInfo provider or ExternalNpmPackageInfo
- # provider (not an npm dep). These files must be in named AMD or named
- # UMD format.
- for src in dep.files.to_list():
- runtime_files.append(_to_manifest_path(ctx, src))
-
- # Finally we load the user's srcs and deps
- user_entries = [
- _to_manifest_path(ctx, f)
- for f in files.to_list()
- if f.path.endswith(".js")
- ]
-
- # Expand static_files paths to runfiles for config
- static_files = [
- _to_manifest_path(ctx, f)
- for f in ctx.files.static_files
- ]
-
- # root-relative (runfiles) path to the directory containing karma.conf
- config_segments = len(configuration.short_path.split("/"))
-
- # configuration_env_vars are set using process.env()
- env_vars = ""
- for k in ctx.attr.configuration_env_vars:
- if k in ctx.var.keys():
- env_vars += "process.env[\"%s\"]=\"%s\";\n" % (k, ctx.var[k])
-
- ctx.actions.expand_template(
- output = configuration,
- template = ctx.file._conf_tmpl,
- substitutions = {
- "TMPL_bootstrap_files": "\n ".join(["'%s'," % e for e in bootstrap_entries]),
- "TMPL_config_file": _to_manifest_path(ctx, config_file) if config_file else "",
- "TMPL_env_vars": env_vars,
- "TMPL_runfiles_path": "/".join([".."] * config_segments),
- "TMPL_runtime_files": "\n ".join(["'%s'," % e for e in runtime_files]),
- "TMPL_static_files": "\n ".join(["'%s'," % e for e in static_files]),
- "TMPL_user_files": "\n ".join(["'%s'," % e for e in user_entries]),
- },
- )
-
- return configuration
-
-def _karma_web_test_impl(ctx):
- files_depsets = [depset(ctx.files.srcs)]
- for dep in ctx.attr.deps + ctx.attr.runtime_deps:
- if JSNamedModuleInfo in dep:
- files_depsets.append(dep[JSNamedModuleInfo].sources)
- if not JSNamedModuleInfo in dep and not ExternalNpmPackageInfo in dep and hasattr(dep, "files"):
- # These are javascript files provided by DefaultInfo from a direct
- # dep that has no JSNamedModuleInfo provider or ExternalNpmPackageInfo
- # provider (not an npm dep). These files must be in named AMD or named
- # UMD format.
- files_depsets.append(dep.files)
- files = depset(transitive = files_depsets)
-
- # Also include files from npm fine grained deps as inputs.
- # These deps are identified by the ExternalNpmPackageInfo provider.
- node_modules_depsets = []
- for dep in ctx.attr.deps + ctx.attr.runtime_deps:
- if ExternalNpmPackageInfo in dep:
- node_modules_depsets.append(dep[ExternalNpmPackageInfo].sources)
- node_modules = depset(transitive = node_modules_depsets)
-
- amd_names_shim = _write_amd_names_shim(ctx)
-
- configuration = _write_karma_config(ctx, files, amd_names_shim)
-
- ctx.actions.write(
- output = ctx.outputs.executable,
- is_executable = True,
- content = """#!/usr/bin/env bash
-# --- begin runfiles.bash initialization v2 ---
-# Copy-pasted from the Bazel Bash runfiles library v2.
-set -uo pipefail; f=build_bazel_rules_nodejs/third_party/github.com/bazelbuild/bazel/tools/bash/runfiles/runfiles.bash
-source "${{RUNFILES_DIR:-/dev/null}}/$f" 2>/dev/null || \
- source "$(grep -sm1 "^$f " "${{RUNFILES_MANIFEST_FILE:-/dev/null}}" | cut -f2- -d' ')" 2>/dev/null || \
- source "$0.runfiles/$f" 2>/dev/null || \
- source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
- source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
- {{ echo>&2 "ERROR: cannot find $f"; exit 1; }}; f=; set -e
-# --- end runfiles.bash initialization v2 ---
-
-readonly KARMA=$(rlocation "{TMPL_karma}")
-readonly CONF=$(rlocation "{TMPL_conf}")
-
-export HOME=$(mktemp -d)
-
-ARGV=( "start" ${{CONF}} )
-
-# Detect that we are running as a test, by using well-known environment
-# variables. See go/test-encyclopedia
-# Note: in Bazel 0.14 and later, TEST_TMPDIR is set for both bazel test and bazel run
-# so we also check for the BUILD_WORKSPACE_DIRECTORY which is set only for bazel run
-if [[ ! -z "${{TEST_TMPDIR:-}}" && ! -n "${{BUILD_WORKSPACE_DIRECTORY:-}}" ]]; then
- ARGV+=( "--single-run" )
-fi
-
-# Pass --node_options from args on karma node process
-NODE_OPTIONS=()
-for ARG in "$@"; do
- case "${{ARG}}" in
- --node_options=*) NODE_OPTIONS+=( "${{ARG}}" ) ;;
- esac
-done
-
-KARMA_VERSION=$(${{KARMA}} --version)
-
-printf "\n\n\n\nRunning karma tests\n-----------------------------------------------------------------------------\n"
-echo "version :" ${{KARMA_VERSION#Karma version: }}
-echo "pwd :" ${{PWD}}
-echo "conf :" ${{CONF}}
-echo "node_options:" ${{NODE_OPTIONS[@]:-}}
-printf "\n"
-
-readonly COMMAND="${{KARMA}} ${{ARGV[@]}} ${{NODE_OPTIONS[@]:-}}"
-${{COMMAND}}
-""".format(
- TMPL_karma = _to_manifest_path(ctx, ctx.executable.karma),
- TMPL_conf = _to_manifest_path(ctx, configuration),
- ),
- )
-
- config_sources = []
-
- if ctx.attr.config_file:
- if JSModuleInfo in ctx.attr.config_file:
- config_sources = ctx.attr.config_file[JSModuleInfo].sources.to_list()
- else:
- config_sources = [ctx.file.config_file]
-
- runfiles = [
- configuration,
- amd_names_shim,
- ]
- runfiles += config_sources
- runfiles += ctx.files.srcs
- runfiles += ctx.files.deps
- runfiles += ctx.files.runtime_deps
- runfiles += ctx.files.bootstrap
- runfiles += ctx.files.static_files
- runfiles += ctx.files.data
-
- return [DefaultInfo(
- files = depset([ctx.outputs.executable]),
- runfiles = ctx.runfiles(
- files = runfiles,
- transitive_files = depset(transitive = [files, node_modules]),
- ).merge(ctx.attr.karma[DefaultInfo].data_runfiles),
- executable = ctx.outputs.executable,
- )]
-
-_karma_web_test = rule(
- implementation = _karma_web_test_impl,
- test = True,
- executable = True,
- attrs = KARMA_WEB_TEST_ATTRS,
- outputs = {
- "configuration": "%{name}.conf.js",
- },
-)
-
-def karma_web_test(
- srcs = [],
- deps = [],
- data = [],
- configuration_env_vars = [],
- bootstrap = [],
- runtime_deps = [],
- static_files = [],
- config_file = None,
- tags = [],
- peer_deps = KARMA_PEER_DEPS,
- **kwargs):
- """Runs unit tests in a browser with Karma.
-
- When executed under `bazel test`, this uses a headless browser for speed.
- This is also because `bazel test` allows multiple targets to be tested together,
- and we don't want to open a Chrome window on your machine for each one. Also,
- under `bazel test` the test will execute and immediately terminate.
-
- Running under `ibazel test` gives you a "watch mode" for your tests. The rule is
- optimized for this case - the test runner server will stay running and just
- re-serve the up-to-date JavaScript source bundle.
-
- To debug a single test target, run it with `bazel run` instead. This will open a
- browser window on your computer. Also you can use any other browser by opening
- the URL printed when the test starts up. The test will remain running until you
- cancel the `bazel run` command.
-
- This rule will use your system Chrome by default. In the default case, your
- environment must specify CHROME_BIN so that the rule will know which Chrome binary to run.
- Other `browsers` and `customLaunchers` may be set using the a base Karma configuration
- specified in the `config_file` attribute.
-
- By default we open a headless Chrome. To use a real Chrome browser window, you can pass
- `--define DISPLAY=true` to Bazel, along with `configuration_env_vars = ["DISPLAY"]` on
- `karma_web_test`.
-
- Args:
- srcs: A list of JavaScript test files
- deps: Other targets which produce JavaScript such as `ts_library`
- data: Runtime dependencies
- configuration_env_vars: Pass these configuration environment variables to the resulting binary.
- Chooses a subset of the configuration environment variables (taken from ctx.var), which also
- includes anything specified via the --define flag.
- Note, this can lead to different outputs produced by this rule.
- bootstrap: JavaScript files to include *before* the module loader (require.js).
- For example, you can include Reflect,js for TypeScript decorator metadata reflection,
- or UMD bundles for third-party libraries.
- runtime_deps: Dependencies which should be loaded after the module loader but before the srcs and deps.
- These should be a list of targets which produce JavaScript such as `ts_library`.
- The files will be loaded in the same order they are declared by that rule.
- static_files: Arbitrary files which are available to be served on request.
- Files are served at:
- `/base/<WORKSPACE_NAME>/<path-to-file>`, e.g.
- `/base/npm_bazel_typescript/examples/testing/static_script.js`
- config_file: User supplied Karma configuration file. Bazel will override
- certain attributes of this configuration file. Attributes that are
- overridden will be outputted to the test log.
- tags: Standard Bazel tags, this macro adds tags for ibazel support
- peer_deps: list of peer npm deps required by karma_web_test
- **kwargs: Passed through to `karma_web_test`
- """
-
- _karma_web_test(
- srcs = srcs,
- deps = deps + peer_deps,
- data = data,
- configuration_env_vars = configuration_env_vars,
- bootstrap = bootstrap,
- runtime_deps = runtime_deps,
- static_files = static_files,
- config_file = config_file,
- tags = tags + [
- # Users don't need to know that this tag is required to run under ibazel
- "ibazel_notify_changes",
- ],
- **kwargs
- )
-
-def karma_web_test_suite(
- name,
- browsers = None,
- web_test_data = [],
- wrapped_test_tags = list(DEFAULT_WRAPPED_TEST_TAGS),
- **kwargs):
- """Defines a test_suite of web_test targets that wrap a karma_web_test target.
-
- This macro accepts all parameters in karma_web_test and adds additional parameters
- for the suite. See karma_web_test docs for all karma_web_test.
-
- The wrapping macro is `web_test_suite` which comes from rules_websting:
- https://github.com/bazelbuild/rules_webtesting/blob/master/web/web.bzl.
-
- Args:
- name: The base name of the test
- browsers: A sequence of labels specifying the browsers to use.
- web_test_data: Data dependencies for the wrapper web_test targets.
- wrapped_test_tags: A list of test tag strings to use for the wrapped
- karma_web_test target.
- **kwargs: Arguments for the wrapped karma_web_test target.
- """
-
- # Common attributes
- args = kwargs.pop("args", None)
- flaky = kwargs.pop("flaky", None)
- local = kwargs.pop("local", None)
- shard_count = kwargs.pop("shard_count", None)
- size = kwargs.pop("size", "large")
- timeout = kwargs.pop("timeout", None)
-
- # Wrapper attributes
- browser_overrides = kwargs.pop("browser_overrides", None)
- config = kwargs.pop("config", None)
- test_suite_tags = kwargs.pop("test_suite_tags", list(DEFAULT_TEST_SUITE_TAGS))
- visibility = kwargs.pop("visibility", None)
- tags = kwargs.pop("tags", []) + [
- # Users don't need to know that this tag is required to run under ibazel
- "ibazel_notify_changes",
- ]
- if browsers == None:
- browsers = ["@io_bazel_rules_webtesting//browsers:chromium-local"]
-
- # rules_webtesting requires the "native" tag for browsers
- if not "native" in tags:
- tags = tags + ["native"]
-
- # The wrapped `karma_web_test` target
- wrapped_test_name = name + "_wrapped_test"
- karma_web_test(
- name = wrapped_test_name,
- args = args,
- flaky = flaky,
- local = local,
- shard_count = shard_count,
- size = size,
- timeout = timeout,
- tags = wrapped_test_tags,
- visibility = ["//visibility:private"],
- **kwargs
- )
-
- # The wrapper `web_test_suite` target
- web_test_suite(
- name = name,
- args = args,
- flaky = flaky,
- local = local,
- shard_count = shard_count,
- size = size,
- timeout = timeout,
- launcher = ":" + wrapped_test_name,
- browsers = browsers,
- browser_overrides = browser_overrides,
- config = config,
- data = web_test_data,
- tags = tags,
- test = wrapped_test_name,
- test_suite_tags = test_suite_tags,
- visibility = visibility,
- )
diff --git a/packages/concatjs/web_test/test/karma/BUILD.bazel b/packages/concatjs/web_test/test/karma/BUILD.bazel
deleted file mode 100644
index 148f35b..0000000
--- a/packages/concatjs/web_test/test/karma/BUILD.bazel
+++ /dev/null
@@ -1,80 +0,0 @@
-# Copyright 2017 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-load("@build_bazel_rules_nodejs//:index.bzl", "generated_file_test")
-load("@io_bazel_rules_webtesting//web:web.bzl", "custom_browser")
-load("//packages/concatjs:index.bzl", "karma_web_test_suite")
-
-karma_web_test_suite(
- name = "testing",
- srcs = glob(
- ["*.js"],
- exclude = [
- "coverage_source_uncovered.js",
- "coverage_source.js",
- "coverage.spec.js",
- "unnamed-amd-module.js",
- "init-test.js",
- ],
- ),
- browsers = [
- "@io_bazel_rules_webtesting//browsers:chromium-local",
- "@io_bazel_rules_webtesting//browsers:firefox-local",
- ":custom_chrome",
- ],
- static_files = [
- "unnamed-amd-module.js",
- # Add the "init-test.js" file to the "static_files" as well. This simulates
- # a scenario where a developer has a NPM package in the "deps" that transitively
- # brings in "tslib", whereas the target in the "static_files" can also bring
- # in "tslib" transitively.
- "init-test.js",
- ],
- tags = [
- "native",
- "no-rbe",
- ],
- deps = [
- "init-test.js",
- "requirejs-config.js",
- ],
-)
-
-karma_web_test_suite(
- name = "coverage_test",
- srcs = [
- "coverage.spec.js",
- "coverage_source.js",
- "coverage_source_uncovered.js",
- ],
- browsers = [
- "@io_bazel_rules_webtesting//browsers:chromium-local",
- "@io_bazel_rules_webtesting//browsers:firefox-local",
- ],
- tags = ["native"],
-)
-
-custom_browser(
- name = "custom_chrome",
- browser = "@io_bazel_rules_webtesting//browsers:chromium-local",
- metadata = "custom_chrome.json",
- tags = ["no-rbe"],
-)
-
-generated_file_test(
- name = "test_custom_chrome_karma_conf",
- src = "karma.conf.js.golden",
- generated = "testing_wrapped_test.conf.js",
- substring_search = True,
-)
diff --git a/packages/concatjs/web_test/test/karma/amd-modules.spec.js b/packages/concatjs/web_test/test/karma/amd-modules.spec.js
deleted file mode 100644
index d971f92..0000000
--- a/packages/concatjs/web_test/test/karma/amd-modules.spec.js
+++ /dev/null
@@ -1,32 +0,0 @@
-define(
- 'build_bazel_rules_nodejs/packages/concatjs/web_test/test/karma/amd-modules.spec', ['require'], require => {
- describe('AMD module loading', () => {
- describe('unnamed amd modules', () => {
- it('should not warn if module is configured as static file', doneFn => {
- spyOn(console, 'error');
-
- require(['unnamed-module'], () => {
- // Loading such an anonymous AMD module should not cause any error messages about
- // a missing timestamp. This is a limitation of the "karma-requirejs" plugin which
- // by default always prints an error for requests through Karma's proxy.
- // See: https://github.com/karma-runner/karma-requirejs/issues/6
- expect(console.error).toHaveBeenCalledTimes(0);
- doneFn();
- });
- });
-
- it('should warn if module is not specified as static file', doneFn => {
- spyOn(console, 'error').and.callThrough();
-
- require(
- ['unnamed-module-invalid-file'],
- /* loaded callback */ () => {},
- /* error callback */ () => {
- expect(console.error)
- .toHaveBeenCalledWith(jasmine.stringMatching(/no timestamp/));
- doneFn();
- });
- });
- });
- });
- });
diff --git a/packages/concatjs/web_test/test/karma/coverage.spec.js b/packages/concatjs/web_test/test/karma/coverage.spec.js
deleted file mode 100644
index 4486f0d..0000000
--- a/packages/concatjs/web_test/test/karma/coverage.spec.js
+++ /dev/null
@@ -1,27 +0,0 @@
-(function(factory) {
-if (typeof module === 'object' && typeof module.exports === 'object') {
- var v = factory(require, exports);
- if (v !== undefined) module.exports = v;
-} else if (typeof define === 'function' && define.amd) {
- define(
- 'build_bazel_rules_nodejs/packages/concatjs/web_test/test/karma/coverage.spec',
- [
- 'require', 'exports',
- 'build_bazel_rules_nodejs/packages/concatjs/web_test/test/karma/coverage_source'
- ],
- factory);
-}
-})(function(require, exports) {
-'use strict';
-Object.defineProperty(exports, '__esModule', {value: true});
-var coverage_source_1 =
- require('build_bazel_rules_nodejs/packages/concatjs/web_test/test/karma/coverage_source');
-describe('coverage function', () => {
- it('should cover one branch', () => {
- expect(coverage_source_1.isString(2)).toBe(false);
- });
- it('should cover the other branch', () => {
- expect(coverage_source_1.isString('some string')).toBe(true);
- });
-});
-});
diff --git a/packages/concatjs/web_test/test/karma/coverage_source.js b/packages/concatjs/web_test/test/karma/coverage_source.js
deleted file mode 100644
index a1d2182..0000000
--- a/packages/concatjs/web_test/test/karma/coverage_source.js
+++ /dev/null
@@ -1,21 +0,0 @@
-(function(factory) {
-if (typeof module === 'object' && typeof module.exports === 'object') {
- var v = factory(require, exports);
- if (v !== undefined) module.exports = v;
-} else if (typeof define === 'function' && define.amd) {
- define(
- 'build_bazel_rules_nodejs/packages/concatjs/web_test/test/karma/coverage_source',
- ['require', 'exports'], factory);
-}
-})(function(require, exports) {
-'use strict';
-Object.defineProperty(exports, '__esModule', {value: true});
-function isString(input) {
- if (typeof input === 'string') {
- return true;
- } else {
- return false;
- }
-}
-exports.isString = isString;
-});
\ No newline at end of file
diff --git a/packages/concatjs/web_test/test/karma/coverage_source_uncovered.js b/packages/concatjs/web_test/test/karma/coverage_source_uncovered.js
deleted file mode 100644
index 8ad07de..0000000
--- a/packages/concatjs/web_test/test/karma/coverage_source_uncovered.js
+++ /dev/null
@@ -1,20 +0,0 @@
-(function(factory) {
-if (typeof module === 'object' && typeof module.exports === 'object') {
- var v = factory(require, exports);
- if (v !== undefined) module.exports = v;
-} else if (typeof define === 'function' && define.amd) {
- define(
- 'build_bazel_rules_nodejs/packages/concatjs/web_test/test/karma/coverage_source_uncovered',
- ['require', 'exports'], factory);
-}
-})(function(require, exports) {
-'use strict';
-Object.defineProperty(exports, '__esModule', {value: true});
-// noting in this file should be required, so we can test the c8 feature all: true
-// which will pick up files that aren't directly referenced by test files
-// but are added to coverage as empty coverage
-function notCalled(input) {
- return input * 13;
-}
-exports.notCalled = notCalled;
-});
\ No newline at end of file
diff --git a/packages/concatjs/web_test/test/karma/custom_chrome.json b/packages/concatjs/web_test/test/karma/custom_chrome.json
deleted file mode 100644
index c7798d0..0000000
--- a/packages/concatjs/web_test/test/karma/custom_chrome.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "capabilities": {
- "goog:chromeOptions": {
- "args": [
- "--remote-debugging-port=9222",
- "--headless",
- "--use-gl=swiftshader-webgl"
- ]
- }
- }
-}
diff --git a/packages/concatjs/web_test/test/karma/decrement.js b/packages/concatjs/web_test/test/karma/decrement.js
deleted file mode 100644
index 9b72703..0000000
--- a/packages/concatjs/web_test/test/karma/decrement.js
+++ /dev/null
@@ -1,17 +0,0 @@
-(function(factory) {
-if (typeof module === 'object' && typeof module.exports === 'object') {
- var v = factory(require, exports);
- if (v !== undefined) module.exports = v;
-} else if (typeof define === 'function' && define.amd) {
- define(
- 'build_bazel_rules_nodejs/packages/concatjs/web_test/test/karma/decrement', ['require', 'exports'],
- factory);
-}
-})(function(require, exports) {
-'use strict';
-Object.defineProperty(exports, '__esModule', {value: true});
-function decrement(n) {
- return n - 1;
-}
-exports.decrement = decrement;
-});
diff --git a/packages/concatjs/web_test/test/karma/decrement.spec.js b/packages/concatjs/web_test/test/karma/decrement.spec.js
deleted file mode 100644
index afddf49..0000000
--- a/packages/concatjs/web_test/test/karma/decrement.spec.js
+++ /dev/null
@@ -1,20 +0,0 @@
-(function(factory) {
-if (typeof module === 'object' && typeof module.exports === 'object') {
- var v = factory(require, exports);
- if (v !== undefined) module.exports = v;
-} else if (typeof define === 'function' && define.amd) {
- define(
- 'build_bazel_rules_nodejs/packages/concatjs/web_test/test/karma/decrement.spec',
- ['require', 'exports', 'build_bazel_rules_nodejs/packages/concatjs/web_test/test/karma/decrement'],
- factory);
-}
-})(function(require, exports) {
-'use strict';
-Object.defineProperty(exports, '__esModule', {value: true});
-var decrement_1 = require('build_bazel_rules_nodejs/packages/concatjs/web_test/test/karma/decrement');
-describe('decrementing', function() {
- it('should do that', function() {
- expect(decrement_1.decrement(1)).toBe(0);
- });
-});
-});
diff --git a/packages/concatjs/web_test/test/karma/init-test.js b/packages/concatjs/web_test/test/karma/init-test.js
deleted file mode 100644
index bb6b253..0000000
--- a/packages/concatjs/web_test/test/karma/init-test.js
+++ /dev/null
@@ -1,8 +0,0 @@
-/**
- * File that should mimic a file that is required for the tests to run. This file is used
- * to ensure that the Karma bazel rules properly include the file in the ConcatJS bundle.
- */
-
-define('build_bazel_rules_nodejs/packages/concatjs/web_test/test/karma/init-test', [], () => {
- window['__testInitialized'] = true;
-});
diff --git a/packages/concatjs/web_test/test/karma/karma.conf.js.golden b/packages/concatjs/web_test/test/karma/karma.conf.js.golden
deleted file mode 100644
index c3bb4a92..0000000
--- a/packages/concatjs/web_test/test/karma/karma.conf.js.golden
+++ /dev/null
@@ -1,5 +0,0 @@
-const chromeOptions = (webTestMetadata['capabilities'] || {})['goog:chromeOptions'];
-const additionalArgs = (chromeOptions ? chromeOptions['args'] : []).filter(arg => {
- // We never want to 'run' Chrome in headless mode.
- return arg != '--headless';
-});
diff --git a/packages/concatjs/web_test/test/karma/requirejs-config.js b/packages/concatjs/web_test/test/karma/requirejs-config.js
deleted file mode 100644
index e83fa1b..0000000
--- a/packages/concatjs/web_test/test/karma/requirejs-config.js
+++ /dev/null
@@ -1,8 +0,0 @@
-require.config({
- paths: {
- // Configure some fake AMD module that exists and should not cause a loading
- // error message from the "karma-requirejs" plugin which is enabled by default.
- 'unnamed-module': '/base/build_bazel_rules_nodejs/packages/concatjs/web_test/test/karma/unnamed-amd-module',
- 'unnamed-module-invalid-file': '/some-invalid-file-path',
- }
-});
diff --git a/packages/concatjs/web_test/test/karma/test-initialized.spec.js b/packages/concatjs/web_test/test/karma/test-initialized.spec.js
deleted file mode 100644
index 8b22e5c..0000000
--- a/packages/concatjs/web_test/test/karma/test-initialized.spec.js
+++ /dev/null
@@ -1,12 +0,0 @@
-define('build_bazel_rules_nodejs/packages/concatjs/web_test/test/karma/test-initialized.spec', [], () => {
- // Test that ensures that the "init-test.js" file has been included in the
- // ConcatJS module and was actually executed by the browser. The "init-test.js"
- // file is included in "static_files" and in the "deps" but should not be treated
- // as static file as it is specified as dependency.
- describe('Test initialization', () => {
-
- it('should have initialized tests', () => {
- expect(window['__testInitialized']).toBe(true);
- });
- });
-});
diff --git a/packages/concatjs/web_test/test/karma/tsconfig.json b/packages/concatjs/web_test/test/karma/tsconfig.json
deleted file mode 100644
index e69de29..0000000
--- a/packages/concatjs/web_test/test/karma/tsconfig.json
+++ /dev/null
diff --git a/packages/concatjs/web_test/test/karma/unnamed-amd-module.js b/packages/concatjs/web_test/test/karma/unnamed-amd-module.js
deleted file mode 100644
index fd58f4e..0000000
--- a/packages/concatjs/web_test/test/karma/unnamed-amd-module.js
+++ /dev/null
@@ -1,5 +0,0 @@
-// Unnamed AMD module definition which needs to be manually configured through
-// a "requirejs" configuration whenever this module should be loaded.
-define(function() {
- // Just an empty definition. Nothing to assert here.
-});
diff --git a/packages/concatjs/web_test/test/karma_typescript/BUILD.bazel b/packages/concatjs/web_test/test/karma_typescript/BUILD.bazel
deleted file mode 100644
index b7c3e7b..0000000
--- a/packages/concatjs/web_test/test/karma_typescript/BUILD.bazel
+++ /dev/null
@@ -1,118 +0,0 @@
-# Copyright 2017 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-load("//packages/concatjs:index.bzl", "karma_web_test_suite", "ts_library")
-load("//packages/jasmine:index.bzl", "jasmine_node_test")
-
-ts_library(
- name = "lib",
- srcs = ["decrement.ts"],
-)
-
-ts_library(
- name = "tests",
- testonly = 1,
- srcs = [
- "decrement.spec.ts",
- "foobar.spec.ts",
- ],
- deps = [
- ":lib",
- "@npm//@types/jasmine",
- ],
-)
-
-ts_library(
- name = "hello_world",
- testonly = 1,
- srcs = [
- "hello_world.ts",
- ],
-)
-
-karma_web_test_suite(
- name = "testing",
- srcs = [
- # JS files only in srcs - eval'ed but not require'd
- "foobar.js",
- ],
- browsers = [
- "@io_bazel_rules_webtesting//browsers:chromium-local",
- "@io_bazel_rules_webtesting//browsers:firefox-local",
- ],
- tags = ["native"],
- runtime_deps = [
- # typescript targets only in runtime_deps, must be TS module
- ":hello_world",
- ],
- deps = [
- # JS file, must be AMD
- "hello_world.spec.js",
- # ts_library target, must be TS module
- ":tests",
- # filegroup target (not actually used in test code)
- ":rxjs_umd_modules",
- # node module. This dep has no effect, no files is collected.
- "@npm//jasmine",
- ],
-)
-
-filegroup(
- name = "rxjs_umd_modules",
- srcs = [
- # do not sort
- "@npm//:node_modules/rxjs/bundles/rxjs.umd.js",
- ":rxjs_shims.js",
- ],
-)
-
-ts_library(
- name = "coverage_test_srcs",
- srcs = [
- "coverage_source.ts",
- "coverage_source_uncovered.ts",
- ],
-)
-
-ts_library(
- name = "coverage_test_spec_srcs",
- srcs = ["coverage.spec.ts"],
- deps = [
- ":coverage_test_srcs",
- "@npm//@types/jasmine",
- ],
-)
-
-karma_web_test_suite(
- name = "coverage_test",
- browsers = [
- "@io_bazel_rules_webtesting//browsers:chromium-local",
- "@io_bazel_rules_webtesting//browsers:firefox-local",
- ],
- tags = ["native"],
- deps = [
- # ts_library target, must be TS module
- ":coverage_test_spec_srcs",
- ],
-)
-
-jasmine_node_test(
- name = "user_files_test",
- srcs = [
- "user_files.spec.js",
- ],
- data = [
- ":testing_chromium-local",
- ],
-)
diff --git a/packages/concatjs/web_test/test/karma_typescript/coverage.spec.ts b/packages/concatjs/web_test/test/karma_typescript/coverage.spec.ts
deleted file mode 100644
index 8a2ed42..0000000
--- a/packages/concatjs/web_test/test/karma_typescript/coverage.spec.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import {isString} from './coverage_source';
-
-describe('coverage function', () => {
- it('should cover one branch', () => {
- expect(isString(2 as any)).toBe(false);
- });
- it('should cover the other branch', () => {
- expect(isString('some string')).toBe(true);
- });
-});
diff --git a/packages/concatjs/web_test/test/karma_typescript/coverage_source.ts b/packages/concatjs/web_test/test/karma_typescript/coverage_source.ts
deleted file mode 100644
index 45f569b..0000000
--- a/packages/concatjs/web_test/test/karma_typescript/coverage_source.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-export function isString(input: string) {
- if (typeof input === 'string') {
- return true;
- } else {
- return false;
- }
-}
diff --git a/packages/concatjs/web_test/test/karma_typescript/coverage_source_uncovered.ts b/packages/concatjs/web_test/test/karma_typescript/coverage_source_uncovered.ts
deleted file mode 100644
index a40d272..0000000
--- a/packages/concatjs/web_test/test/karma_typescript/coverage_source_uncovered.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-// noting in this file should be required, so we can test the c8 feature all: true
-// which will pick up files that aren't directly referenced by test files
-// but are added to coverage as empty coverage
-export function notCalled(input: number) {
- return input * 13;
-}
\ No newline at end of file
diff --git a/packages/concatjs/web_test/test/karma_typescript/decrement.spec.ts b/packages/concatjs/web_test/test/karma_typescript/decrement.spec.ts
deleted file mode 100644
index bf1bd91..0000000
--- a/packages/concatjs/web_test/test/karma_typescript/decrement.spec.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import {decrement} from './decrement';
-
-describe('decrementing', () => {
- it('should do that', () => {
- expect(decrement(1)).toBe(0);
- });
-});
diff --git a/packages/concatjs/web_test/test/karma_typescript/decrement.ts b/packages/concatjs/web_test/test/karma_typescript/decrement.ts
deleted file mode 100644
index 7173ecc..0000000
--- a/packages/concatjs/web_test/test/karma_typescript/decrement.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export function decrement(n: number) {
- return n - 1;
-}
diff --git a/packages/concatjs/web_test/test/karma_typescript/foobar.js b/packages/concatjs/web_test/test/karma_typescript/foobar.js
deleted file mode 100644
index ff1dff5..0000000
--- a/packages/concatjs/web_test/test/karma_typescript/foobar.js
+++ /dev/null
@@ -1 +0,0 @@
-window.foo = 'bar';
diff --git a/packages/concatjs/web_test/test/karma_typescript/foobar.spec.ts b/packages/concatjs/web_test/test/karma_typescript/foobar.spec.ts
deleted file mode 100644
index 8624547..0000000
--- a/packages/concatjs/web_test/test/karma_typescript/foobar.spec.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-describe('foo', () => {
- it('should be a global variable', () => {
- expect((window as any).foo).toBe('bar');
- });
-});
-
-// no-op export statement to make this file a typescript module.
-export {};
diff --git a/packages/concatjs/web_test/test/karma_typescript/hello_world.spec.js b/packages/concatjs/web_test/test/karma_typescript/hello_world.spec.js
deleted file mode 100644
index 198d5ed..0000000
--- a/packages/concatjs/web_test/test/karma_typescript/hello_world.spec.js
+++ /dev/null
@@ -1,19 +0,0 @@
-(function (factory) {
- if (typeof module === "object" && typeof module.exports === "object") {
- var v = factory(require, exports);
- if (v !== undefined) module.exports = v;
- }
- else if (typeof define === "function" && define.amd) {
- define(
- 'build_bazel_rules_nodejs/packages/concatjs/web_test/test/karma_typescript/hello_world.spec',
- ['require', 'exports'], factory);
- }
-})(function (require, exports) {
- "use strict";
- Object.defineProperty(exports, "__esModule", { value: true });
- describe('hello', () => {
- it('should be a global variable', () => {
- expect(window.hello).toBe('world');
- });
- });
-});
diff --git a/packages/concatjs/web_test/test/karma_typescript/hello_world.ts b/packages/concatjs/web_test/test/karma_typescript/hello_world.ts
deleted file mode 100644
index c2de3ac..0000000
--- a/packages/concatjs/web_test/test/karma_typescript/hello_world.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-(window as any).hello = "world";
-
-// no-op export statement to make this file a typescript module.
-export {};
diff --git a/packages/concatjs/web_test/test/karma_typescript/rxjs_shims.js b/packages/concatjs/web_test/test/karma_typescript/rxjs_shims.js
deleted file mode 100644
index 9a15da5..0000000
--- a/packages/concatjs/web_test/test/karma_typescript/rxjs_shims.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- * @license
- * Copyright Google Inc. All Rights Reserved.
- *
- * Use of this source code is governed by an MIT-style license that can be
- * found in the LICENSE file at https://angular.io/license
- */
-
-// rxjs/operators
-(function(factory) {
- if (typeof module === 'object' && typeof module.exports === 'object') {
- var v = factory(require, exports);
- if (v !== undefined) module.exports = v;
- } else if (typeof define === 'function' && define.amd) {
- define('rxjs/operators', ['exports', 'rxjs'], factory);
- }
-})(function(exports, rxjs) {
- 'use strict';
- Object.keys(rxjs.operators).forEach(function(key) { exports[key] = rxjs.operators[key]; });
- Object.defineProperty(exports, '__esModule', {value: true});
-});
-
-// rxjs/testing
-(function(factory) {
- if (typeof module === 'object' && typeof module.exports === 'object') {
- var v = factory(require, exports);
- if (v !== undefined) module.exports = v;
- } else if (typeof define === 'function' && define.amd) {
- define('rxjs/testing', ['exports', 'rxjs'], factory);
- }
-})(function(exports, rxjs) {
- 'use strict';
- Object.keys(rxjs.testing).forEach(function(key) { exports[key] = rxjs.testing[key]; });
- Object.defineProperty(exports, '__esModule', {value: true});
-});
diff --git a/packages/concatjs/web_test/test/karma_typescript/user_files.spec.js b/packages/concatjs/web_test/test/karma_typescript/user_files.spec.js
deleted file mode 100644
index 342ef42..0000000
--- a/packages/concatjs/web_test/test/karma_typescript/user_files.spec.js
+++ /dev/null
@@ -1,48 +0,0 @@
-const fs = require('fs');
-const runfiles = require(process.env['BAZEL_NODE_RUNFILES_HELPER']);
-
-describe('karma_web_test_suite', () => {
- let config;
-
- beforeAll(() => {
- config = fs.readFileSync(
- runfiles.resolve(
- 'build_bazel_rules_nodejs/packages/concatjs/web_test/test/karma_typescript/testing_wrapped_test.conf.js'),
- 'utf-8');
- });
-
- it('should load default bootstrap files', () => {
- const match = config.match(/\/\/ BEGIN BOOTSTRAP FILES(.*?)\/\/ END BOOTSTRAP FILES/s);
- expect(match).toBeTruthy();
- const files = match.pop().split(',').map(l => {
- // remove leading and trailing whitepaces, and begin quote and end quote.
- return l.trim().slice(1, -1);
- }).filter(l => !!l);
- expect(files).toEqual([
- 'npm/node_modules/requirejs/require.js',
- 'npm/node_modules/karma-requirejs/lib/adapter.js',
- 'build_bazel_rules_nodejs/packages/concatjs/web_test/test/karma_typescript/_testing_wrapped_test.amd_names_shim.js',
- ]);
- });
-
- it('should only collect node_sources and dev_scripts in user files', () => {
- const match = config.match(/\/\/ BEGIN USER FILES(.*?)\/\/ END USER FILES/s);
- expect(match).toBeTruthy();
- const files = match.pop().split(',').map(l => {
- // remove leading and trailing whitepaces, and begin quote and end quote.
- return l.trim().slice(1, -1);
- }).filter(l => !!l);
- // These are files that Karma should load, they are not necessarily
- // topologically sorted.
- expect(files).toEqual([
- 'build_bazel_rules_nodejs/packages/concatjs/web_test/test/karma_typescript/foobar.js',
- 'build_bazel_rules_nodejs/packages/concatjs/web_test/test/karma_typescript/hello_world.spec.js',
- 'build_bazel_rules_nodejs/packages/concatjs/web_test/test/karma_typescript/decrement.spec.js',
- 'build_bazel_rules_nodejs/packages/concatjs/web_test/test/karma_typescript/foobar.spec.js',
- 'build_bazel_rules_nodejs/packages/concatjs/web_test/test/karma_typescript/decrement.js',
- 'npm/node_modules/rxjs/bundles/rxjs.umd.js',
- 'build_bazel_rules_nodejs/packages/concatjs/web_test/test/karma_typescript/rxjs_shims.js',
- 'build_bazel_rules_nodejs/packages/concatjs/web_test/test/karma_typescript/hello_world.js',
- ]);
- });
-});
diff --git a/packages/concatjs/web_test/test/stack_trace/BUILD.bazel b/packages/concatjs/web_test/test/stack_trace/BUILD.bazel
deleted file mode 100644
index cb9244f..0000000
--- a/packages/concatjs/web_test/test/stack_trace/BUILD.bazel
+++ /dev/null
@@ -1,56 +0,0 @@
-# Copyright 2019 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-load("//packages/concatjs:index.bzl", "karma_web_test_suite", "ts_library")
-
-ts_library(
- name = "test_lib",
- testonly = True,
- srcs = glob(["*.spec.ts"]),
- deps = [
- "@npm//@types/jasmine",
- ],
-)
-
-# This is a test with failing test. This test is not directly run by CI.
-# The sh_test below invokes this test and checks the source mapped lines in the
-# stack trace.
-karma_web_test_suite(
- name = "karma_test",
- browsers = [
- "@io_bazel_rules_webtesting//browsers:chromium-local",
- "@io_bazel_rules_webtesting//browsers:firefox-local",
- ],
- tags = [
- "manual", # not run by CI (see comment above)
- "native", # rules_webtesting requires the "native" tag for browsers
- ],
- deps = [
- ":test_lib",
- "//packages/concatjs/web_test/test/stack_trace/test_folder:test_lib",
- ],
-)
-
-sh_test(
- name = "test_sourcemap",
- srcs = ["test_sourcemap.sh"],
- data = [
- ":karma_test_chromium-local",
- "@build_bazel_rules_nodejs//third_party/github.com/bazelbuild/bazel/tools/bash/runfiles",
- ],
- tags = [
- "browser:chromium-local",
- "fix-windows",
- ],
-)
diff --git a/packages/concatjs/web_test/test/stack_trace/failing.spec.ts b/packages/concatjs/web_test/test/stack_trace/failing.spec.ts
deleted file mode 100644
index 5b77ed5..0000000
--- a/packages/concatjs/web_test/test/stack_trace/failing.spec.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-// This dummy export ensures that this file is compiled as a module instead
-// of a script.
-export {};
-
-describe('stack trace', () => {
- it('failing test', () => {
- expect(true).toBe(false);
- });
-});
diff --git a/packages/concatjs/web_test/test/stack_trace/test_folder/BUILD.bazel b/packages/concatjs/web_test/test/stack_trace/test_folder/BUILD.bazel
deleted file mode 100644
index eda349b..0000000
--- a/packages/concatjs/web_test/test/stack_trace/test_folder/BUILD.bazel
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright 2019 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-load("//packages/concatjs:index.bzl", "ts_library")
-
-package(default_visibility = ["//visibility:public"])
-
-ts_library(
- name = "hello",
- srcs = glob(
- ["*.ts"],
- exclude = ["*.spec.ts"],
- ),
-)
-
-ts_library(
- name = "test_lib",
- testonly = True,
- srcs = glob(["*.spec.ts"]),
- deps = [
- ":hello",
- "@npm//@types/jasmine",
- ],
-)
diff --git a/packages/concatjs/web_test/test/stack_trace/test_folder/hello.ts b/packages/concatjs/web_test/test/stack_trace/test_folder/hello.ts
deleted file mode 100644
index e7e5922..0000000
--- a/packages/concatjs/web_test/test/stack_trace/test_folder/hello.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-export function sayHello(): string {
- return 'Hello';
-}
-
-export function throws(): string {
- throw new Error('Error here');
-}
\ No newline at end of file
diff --git a/packages/concatjs/web_test/test/stack_trace/test_folder/test.spec.ts b/packages/concatjs/web_test/test/stack_trace/test_folder/test.spec.ts
deleted file mode 100644
index b847675..0000000
--- a/packages/concatjs/web_test/test/stack_trace/test_folder/test.spec.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import {throws, sayHello} from './hello';
-
-describe('multiple stack frames', () => {
- it('failing test', () => {
- expect(sayHello()).toBe('World');
- });
-
- it('another failing test', () => {
- expect(throws()).toBe('something');
- });
-});
diff --git a/packages/concatjs/web_test/test/stack_trace/test_sourcemap.sh b/packages/concatjs/web_test/test/stack_trace/test_sourcemap.sh
deleted file mode 100755
index 3fa27f0..0000000
--- a/packages/concatjs/web_test/test/stack_trace/test_sourcemap.sh
+++ /dev/null
@@ -1,26 +0,0 @@
-# Execute first test.
-OUTPUT=$(${RUNFILES_DIR}/build_bazel_rules_nodejs/packages/concatjs/web_test/test/stack_trace/karma_test_chromium-local.sh)
-
-# Test whether the package relative TS path is printed in stack trace.
-echo ${OUTPUT} | grep -q "(packages/concatjs/web_test/test/stack_trace/failing.spec.ts:7:18"
-if [[ "$?" != "0" ]]; then
- echo "Did not find '(packages/concatjs/web_test/test/stack_trace/failing.spec.ts:7:18' in Karma stack trace"
- echo $OUTPUT
- exit 1
-fi
-
-# Test whether the package relative path inside a subdirectory is printed.
-echo ${OUTPUT} | grep -q "(packages/concatjs/web_test/test/stack_trace/test_folder/test.spec.ts:5:24"
-if [[ "$?" != "0" ]]; then
- echo "Did not find '(packages/concatjs/web_test/test/stack_trace/test_folder/test.spec.ts:5:24' in Karma stack trace"
- exit 1
-fi
-
-# Test whether stack trace with multiple stack frames mapped get printed.
-echo ${OUTPUT} | grep -q "(packages/concatjs/web_test/test/stack_trace/test_folder/hello.ts:6:9"
-if [[ "$?" != "0" ]]; then
- echo "Did not find '(packages/concatjs/web_test/test/stack_trace/test_folder/hello.ts:6:9' in Karma stack trace"
- exit 1
-fi
-
-exit 0
diff --git a/packages/cypress/index.bzl b/packages/cypress/index.bzl
index 4ac6b13..31ba139 100644
--- a/packages/cypress/index.bzl
+++ b/packages/cypress/index.bzl
@@ -38,53 +38,6 @@
cypress_repositories(name = "cypress", version = "MATCH_VERSION_IN_PACKAGE_JSON")
```
-
-## Example use of cypress_web_test
-This example assumes you've named your external repository for node_modules as `npm` and for cypress as `cypress`
-```python
-load("@npm//@bazel/concatjs:index.bzl", "ts_library")
-load("@npm//@bazel/cypress:index.bzl", "cypress_web_test")
-
-# You must create a cypress plugin in order to boot a server to serve your application. It can be written as a javascript file or in typescript using ts_library or ts_project.
-ts_library(
- name = "plugin_file",
- testonly = True,
- srcs = ["plugin.ts"],
- tsconfig = ":tsconfig.json",
- deps = [
- "@npm//@types/node",
- "@npm//express",
- ],
-)
-
-# You can write your cypress tests a javascript files or in typescript using ts_library or ts_project.
-ts_library(
- name = "hello_spec",
- testonly = True,
- srcs = ["hello.spec.ts"],
- tsconfig = ":tsconfig.json",
- deps = [
- "@npm//cypress",
- ],
-)
-
-cypress_web_test(
- # The name of your test target
- name = "test",
- srcs = [
- # Load javascript test files directly as sources
- "world.spec.js",
- # Load ts_library tests as a target to srcs
- ":hello_spec",
- ],
- # A cypress config file is required
- config_file = "cypress.json",
- # Any runtime dependencies you need to boot your server or run your tests
- data = [],
- # Your cypress plugin used to configure cypress and boot your server
- plugin_file = ":plugin_file",
-)
-```
"""
load(
diff --git a/packages/index.bzl b/packages/index.bzl
index 911ce96..31abd1c 100644
--- a/packages/index.bzl
+++ b/packages/index.bzl
@@ -16,7 +16,6 @@
"""
NPM_PACKAGES = ["@bazel/%s" % pkg for pkg in [
- "concatjs",
"create",
"jasmine",
"protractor",
diff --git a/packages/typescript/index.docs.bzl b/packages/typescript/index.docs.bzl
index 1e4bf2b..5ddb9f9 100644
--- a/packages/typescript/index.docs.bzl
+++ b/packages/typescript/index.docs.bzl
@@ -106,11 +106,6 @@
- We control the output format and module syntax so that downstream rules can rely on them.
- Some other options are incompatible. For example you cannot use the `--noEmit` compiler option in `tsconfig.json`.
-The only reason to use `ts_library` for new code is if you are bought-in to using a [concatjs] bundler, which requires the named AMD module format. This may be faster than other tooling, and this format can be consumed by the Closure Compiler (via integration with [tsickle](https://github.com/angular/tsickle)).
-However it is very challenging to configure and there is little available support for problems you'll run into.
-
-[concatjs]: https://www.npmjs.com/package/@bazel/concatjs
-
## Installation
Add a `devDependency` on `@bazel/typescript`