postcss: Fix import error handling

Note that we will now fail if `inlineImports` is enabled and we cannot resolve an import.

You can work around this by either:

* Use url imports or imports with media queries.
* Set `skipInlineImportsNotFound=true` in the options

Also get the argument order in the different NewFileError* funcs in line.

Fixes #9895
This commit is contained in:
Bjørn Erik Pedersen
2022-05-14 15:51:04 +02:00
parent c2fa0a3320
commit 4b189d8fd9
20 changed files with 159 additions and 43 deletions

View File

@@ -28,6 +28,7 @@ import (
"github.com/gohugoio/hugo/common/collections"
"github.com/gohugoio/hugo/common/hexec"
"github.com/gohugoio/hugo/common/text"
"github.com/gohugoio/hugo/hugofs"
"github.com/gohugoio/hugo/common/hugo"
@@ -49,9 +50,10 @@ import (
const importIdentifier = "@import"
var cssSyntaxErrorRe = regexp.MustCompile(`> (\d+) \|`)
var shouldImportRe = regexp.MustCompile(`^@import ["'].*["'];?\s*(/\*.*\*/)?$`)
var (
cssSyntaxErrorRe = regexp.MustCompile(`> (\d+) \|`)
shouldImportRe = regexp.MustCompile(`^@import ["'].*["'];?\s*(/\*.*\*/)?$`)
)
// New creates a new Client with the given specification.
func New(rs *resources.Spec) *Client {
@@ -100,6 +102,12 @@ type Options struct {
// so you can have @import anywhere in the file.
InlineImports bool
// When InlineImports is enabled, we fail the build if an import cannot be resolved.
// You can enable this to allow the build to continue and leave the import statement in place.
// Note that the inline importer does not process url location or imports with media queries,
// so those will be left as-is even without enabling this option.
SkipInlineImportsNotFound bool
// Options for when not using a config file
Use string // List of postcss plugins to use
Parser string // Custom postcss parser
@@ -204,6 +212,7 @@ func (t *postcssTransformation) Transform(ctx *resources.ResourceTransformationC
imp := newImportResolver(
ctx.From,
ctx.InPath,
t.options,
t.rs.Assets.Fs, t.rs.Logger,
)
@@ -239,6 +248,7 @@ type fileOffset struct {
type importResolver struct {
r io.Reader
inPath string
opts Options
contentSeen map[string]bool
linemap map[int]fileOffset
@@ -246,12 +256,13 @@ type importResolver struct {
logger loggers.Logger
}
func newImportResolver(r io.Reader, inPath string, fs afero.Fs, logger loggers.Logger) *importResolver {
func newImportResolver(r io.Reader, inPath string, opts Options, fs afero.Fs, logger loggers.Logger) *importResolver {
return &importResolver{
r: r,
inPath: inPath,
fs: fs, logger: logger,
linemap: make(map[int]fileOffset), contentSeen: make(map[string]bool),
opts: opts,
}
}
@@ -282,21 +293,32 @@ func (imp *importResolver) importRecursive(
i := 0
for offset, line := range lines {
i++
line = strings.TrimSpace(line)
lineTrimmed := strings.TrimSpace(line)
column := strings.Index(line, lineTrimmed)
line = lineTrimmed
if !imp.shouldImport(line) {
trackLine(i, offset, line)
} else {
i--
path := strings.Trim(strings.TrimPrefix(line, importIdentifier), " \"';")
filename := filepath.Join(basePath, path)
importContent, hash := imp.contentHash(filename)
if importContent == nil {
trackLine(i, offset, "ERROR")
imp.logger.Warnf("postcss: Failed to resolve CSS @import in %q for path %q", inPath, filename)
continue
if imp.opts.SkipInlineImportsNotFound {
trackLine(i, offset, line)
continue
}
pos := text.Position{
Filename: inPath,
LineNumber: offset + 1,
ColumnNumber: column + 1,
}
return 0, "", herrors.NewFileErrorFromFileInPos(fmt.Errorf("failed to resolve CSS @import %q", filename), pos, imp.fs, nil)
}
i--
if imp.contentSeen[hash] {
i++
// Just replace the line with an empty string.
@@ -399,7 +421,7 @@ func (imp *importResolver) toFileError(output string) error {
}
defer f.Close()
ferr := herrors.NewFileError(realFilename, inErr)
ferr := herrors.NewFileError(inErr, realFilename)
pos := ferr.Position()
pos.LineNumber = file.Offset + 1
return ferr.UpdatePosition(pos).UpdateContent(f, nil)