Skip to content

Commit

Permalink
reimplement disabled paths in resolver (#238)
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Jul 8, 2020
1 parent 871c51a commit b0cc3a2
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 134 deletions.
109 changes: 62 additions & 47 deletions internal/bundler/bundler.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ type parseFlags struct {
jsxFactory []string
jsxFragment []string
isEntryPoint bool
isDisabled bool
ignoreIfUnused bool
strictClassFields bool
}
Expand Down Expand Up @@ -82,7 +81,6 @@ func parseFile(args parseArgs) {
Index: args.sourceIndex,
KeyPath: args.keyPath,
PrettyPath: args.prettyPath,
BaseName: args.baseName,
}

// Try to determine the identifier name by the absolute path, since it may
Expand All @@ -94,25 +92,34 @@ func parseFile(args parseArgs) {
source.IdentifierName = ast.GenerateNonUniqueNameFromPath(args.baseName)
}

// Disabled files are left empty
var loader config.Loader
stdin := args.options.Stdin
if !args.flags.isDisabled {
if stdin != nil {
source.Contents = stdin.Contents
source.PrettyPath = "<stdin>"
if stdin.SourceFile != "" {
source.PrettyPath = stdin.SourceFile
}
} else if args.keyPath.IsAbsolute {
var ok bool
source.Contents, ok = args.res.Read(args.keyPath.Text)
if !ok {
args.log.AddRangeError(args.importSource, args.pathRange,
fmt.Sprintf("Could not read from file: %s", args.keyPath.Text))
args.results <- parseResult{}
return
}

if stdin != nil {
// Special-case stdin
source.Contents = stdin.Contents
source.PrettyPath = "<stdin>"
if stdin.SourceFile != "" {
source.PrettyPath = stdin.SourceFile
}
loader = stdin.Loader
} else if args.keyPath.IsAbsolute {
// Read normal modules from disk
var ok bool
source.Contents, ok = args.res.Read(args.keyPath.Text)
if !ok {
args.log.AddRangeError(args.importSource, args.pathRange,
fmt.Sprintf("Could not read from file: %s", args.keyPath.Text))
args.results <- parseResult{}
return
}
loader = loaderFromFileExtension(args.options.ExtensionToLoader, args.baseName)
} else {
// Right now the only non-absolute modules are disabled ones
if !strings.HasPrefix(args.keyPath.Text, "disabled:") {
panic("Internal error")
}
loader = config.LoaderJS
}

// Allow certain properties to be overridden
Expand All @@ -126,14 +133,6 @@ func parseFile(args parseArgs) {
args.options.Strict.ClassFields = true
}

// Pick the loader based on the file extension
loader := loaderFromFileExtension(args.options.ExtensionToLoader, args.baseName)

// Special-case reading from stdin
if stdin != nil {
loader = stdin.Loader
}

result := parseResult{
source: source,
file: file{
Expand Down Expand Up @@ -310,16 +309,18 @@ func ScanBundle(log logging.Log, fs fs.FS, res resolver.Resolver, entryPaths []s
pathRange ast.Range,
isEntryPoint bool,
) uint32 {
lowerAbsPath := lowerCaseAbsPathForWindows(resolveResult.AbsolutePath)
sourceIndex, ok := visited[lowerAbsPath]
visitedKey := resolveResult.Path.Text
if resolveResult.Path.IsAbsolute {
visitedKey = lowerCaseAbsPathForWindows(visitedKey)
}
sourceIndex, ok := visited[visitedKey]
if !ok {
sourceIndex = uint32(len(sources))
visited[lowerAbsPath] = sourceIndex
visited[visitedKey] = sourceIndex
sources = append(sources, logging.Source{})
files = append(files, file{})
flags := parseFlags{
isEntryPoint: isEntryPoint,
isDisabled: resolveResult.Status == resolver.ResolveDisabled,
ignoreIfUnused: resolveResult.IgnoreIfUnused,
jsxFactory: resolveResult.JSXFactory,
jsxFragment: resolveResult.JSXFragment,
Expand All @@ -330,9 +331,9 @@ func ScanBundle(log logging.Log, fs fs.FS, res resolver.Resolver, entryPaths []s
fs: fs,
log: log,
res: res,
keyPath: ast.Path{Text: resolveResult.AbsolutePath, IsAbsolute: true},
keyPath: resolveResult.Path,
prettyPath: prettyPath,
baseName: fs.Base(resolveResult.AbsolutePath),
baseName: fs.Base(resolveResult.Path.Text),
sourceIndex: sourceIndex,
importSource: importSource,
flags: flags,
Expand All @@ -346,16 +347,25 @@ func ScanBundle(log logging.Log, fs fs.FS, res resolver.Resolver, entryPaths []s

entryPoints := []uint32{}
duplicateEntryPoints := make(map[string]bool)

for _, absPath := range entryPaths {
prettyPath := res.PrettyPath(absPath)
lowerAbsPath := lowerCaseAbsPathForWindows(absPath)

if duplicateEntryPoints[lowerAbsPath] {
log.AddError(nil, ast.Loc{}, "Duplicate entry point: "+prettyPath)
continue
}

duplicateEntryPoints[lowerAbsPath] = true
resolveResult := res.ResolveAbs(absPath)
sourceIndex := maybeParseFile(resolveResult, prettyPath, nil, ast.Range{}, true /*isEntryPoint*/)

if resolveResult == nil {
log.AddError(nil, ast.Loc{}, "Could not resolve: "+prettyPath)
continue
}

sourceIndex := maybeParseFile(*resolveResult, prettyPath, nil, ast.Range{}, true /*isEntryPoint*/)
entryPoints = append(entryPoints, sourceIndex)
}

Expand Down Expand Up @@ -389,12 +399,19 @@ func ScanBundle(log logging.Log, fs fs.FS, res resolver.Resolver, entryPaths []s

pathText := record.Path.Text
pathRange := source.RangeOfString(record.Loc)
resolveResult := res.Resolve(source.KeyPath, pathText)
resolveResult, isExternal := res.Resolve(source.KeyPath, pathText)

switch resolveResult.Status {
case resolver.ResolveEnabled, resolver.ResolveDisabled:
prettyPath := res.PrettyPath(resolveResult.AbsolutePath)
sourceIndex := maybeParseFile(resolveResult, prettyPath, &source, pathRange, false /*isEntryPoint*/)
if resolveResult == nil {
log.AddRangeError(&source, pathRange, fmt.Sprintf("Could not resolve %q", pathText))
continue
}

if !isExternal {
prettyPath := resolveResult.Path.Text
if resolveResult.Path.IsAbsolute {
prettyPath = res.PrettyPath(prettyPath)
}
sourceIndex := maybeParseFile(*resolveResult, prettyPath, &source, pathRange, false /*isEntryPoint*/)
record.SourceIndex = &sourceIndex

// Generate metadata about each import
Expand All @@ -408,16 +425,14 @@ func ScanBundle(log logging.Log, fs fs.FS, res resolver.Resolver, entryPaths []s
j.AddString(fmt.Sprintf("{\n \"path\": %s\n }",
printer.QuoteForJSON(prettyPath)))
}

case resolver.ResolveMissing:
log.AddRangeError(&source, pathRange, fmt.Sprintf("Could not resolve %q", pathText))

case resolver.ResolveExternalRelative:
} else {
// If the path to the external module is relative to the source
// file, rewrite the path to be relative to the working directory
if relPath, ok := fs.Rel(options.AbsOutputDir, resolveResult.AbsolutePath); ok {
// Prevent issues with path separators being different on Windows
record.Path.Text = strings.ReplaceAll(relPath, "\\", "/")
if resolveResult.Path.IsAbsolute {
if relPath, ok := fs.Rel(options.AbsOutputDir, resolveResult.Path.Text); ok {
// Prevent issues with path separators being different on Windows
record.Path.Text = strings.ReplaceAll(relPath, "\\", "/")
}
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions internal/bundler/bundler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1778,7 +1778,7 @@ func TestPackageJsonBrowserMapRelativeDisabled(t *testing.T) {
AbsOutputFile: "/Users/user/project/out.js",
},
expected: map[string]string{
"/Users/user/project/out.js": `// /Users/user/project/node_modules/demo-pkg/util-node.js
"/Users/user/project/out.js": `// disabled:/Users/user/project/node_modules/demo-pkg/util-node.js
var require_util_node = __commonJS(() => {
});
Expand Down Expand Up @@ -1950,13 +1950,13 @@ func TestPackageJsonBrowserMapModuleDisabled(t *testing.T) {
AbsOutputFile: "/Users/user/project/out.js",
},
expected: map[string]string{
"/Users/user/project/out.js": `// /Users/user/project/node_modules/node-pkg/index.js
var require_node_pkg = __commonJS(() => {
"/Users/user/project/out.js": `// disabled:/Users/user/project/node_modules/node-pkg/index.js
var require_index = __commonJS(() => {
});
// /Users/user/project/node_modules/demo-pkg/index.js
var require_demo_pkg = __commonJS((exports, module) => {
const fn2 = require_node_pkg();
const fn2 = require_index();
module.exports = function() {
return fn2();
};
Expand Down
7 changes: 6 additions & 1 deletion internal/bundler/linker.go
Original file line number Diff line number Diff line change
Expand Up @@ -2027,7 +2027,12 @@ func (c *linkerContext) computeChunks() []chunkMeta {
if c.options.AbsOutputFile != "" && c.fileMeta[entryPoint].entryPointStatus == entryPointUserSpecified {
entryPointName = c.fs.Base(c.options.AbsOutputFile)
} else {
entryPointName = c.stripKnownFileExtension(c.sources[entryPoint].BaseName) + ".js"
source := c.sources[entryPoint]
if source.KeyPath.IsAbsolute {
entryPointName = c.stripKnownFileExtension(c.fs.Base(source.KeyPath.Text)) + ".js"
} else {
entryPointName = source.IdentifierName + ".js"
}
}
c.fileMeta[entryPoint].entryPointName = entryPointName

Expand Down
22 changes: 13 additions & 9 deletions internal/logging/logging.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,24 +47,28 @@ type Msg struct {
type Source struct {
Index uint32

// This is a platform-dependent path that includes environment-specific things
// such as Windows backslash path separators and potentially the user's home
// directory. Only use this for passing to syscalls for reading and writing to
// the file system. Do not include this in any output data.
// This is used as a unique key to identify this source file. It should never
// be shown to the user (e.g. never print this to the terminal).
//
// If it's marked as an absolute path, it's a platform-dependent path that
// includes environment-specific things such as Windows backslash path
// separators and potentially the user's home directory. Only use this for
// passing to syscalls for reading and writing to the file system. Do not
// include this in any output data.
//
// If it's marked as not an absolute path, it's an opaque string that is used
// to refer to an automatically-generated module.
KeyPath ast.Path

// This is used for error messages and the metadata JSON file.
//
// This is a mostly platform-independent path. It's relative to the current
// working directory and always uses standard path separators. Use this for
// referencing a file in all output data. These paths still use the original
// case of the path so they may still work differently on file systems that
// are case-insensitive vs. case-sensitive.
PrettyPath string

// The name of this file without any parent directory information. It's
// useful to separate this out from other information because the other
// information may be arbitrary in the case of auto-generated modules.
BaseName string

// An identifier that is mixed in to automatically-generated symbol names to
// improve readability. For example, if the identifier is "util" then the
// symbol for an "export default" statement will be called "util_default".
Expand Down
Loading

0 comments on commit b0cc3a2

Please sign in to comment.