Sass用于解析@import语句的算法是什么?

cal*_*lum 6 sass node-sass libsass

Node.js用于解析require()调用的算法在伪代码中非常清楚地记录.

萨斯的@import声明我需要同样的事情.

我知道,@import 'foo'将尝试基本名称的各种组合foo,并_foo与扩展.scss,并.sass在同一目录中进口文件,以及相对于任何配置的"负载路径"的......但什么样的顺序,这些都试过,即什么如果有多个文件可以满足@import?以a开头./还是../影响它是否尝试加载路径?还有其他事情会尝试我没有涉及吗?.css文件怎么样?

指南并未说明"Sass很聪明,并会为您解决问题".该参考文档进入更详细,但还是不拼出来的解决步骤.

任何人都可以在伪代码中提供它使用的确切算法吗?

Jam*_*son 5

这是一个简化的算法@import <import_arg>;.这是通过阅读SASS的源代码和运行我自己的测试得出的.

def main(import_arg)
  let dirname = File.dirname(import_arg)
  let basename = File.basename(import_arg)
  if import_arg is absolute ... # omitted as this is a rare case
  else return search(dirname, basename)
end

# try resolving import argument relative to each path in load_paths
# 1. If we encounter an unambiguous match, we finish
# 2. If we encounter an ambiguous match, we give up
# see: https://stackoverflow.com/a/33588202/3649209
def search(dirname, basename)
  let cwd = operating system current working directory
  let load_paths = paths specified via SASS_PATH env variable and via --load-path options
  let search_paths = [cwd].concat(load_paths)
  for path in search_paths
    let file = find_match(File.expand_path(basename, path), basename)
    if (file != false) return file
  end
  throw "File to import not found or unreadable"
end

def find_match(directory, basename)
  let candidates = possible_files(directory, basename)
  if candiates.length == 0
    # not a single match found ... don't give up yet
    return false
  else if candidates.length > 1
    # several matching files, ambiguity! ... give up
    # throw ambiguity error
    throw "It's not clear which file to import"
  else
    # success! exactly one match found
    return candidates[0]
  end
end

# NB: this is a bit tricky to express in code
# which is why I settled for a high-level description
def possible_files(directory, basename)
  # if `basename` is of the form shown on the LHS
  # then check the filesystem for existence of
  # any of the files shown on the RHS within
  # directory `directory`. Return the list all the files
  # which do indeed exist (or [] if none exist).
  #   LHS        RHS
  #   x.sass -> _x.sass, x.sass
  #   x.scss -> _x.scss, x.scss
  #   x      -> x.scss, _x.scss, x.sass, _x.sass
  #   _x     -> _x.scss, _x.sass
end
Run Code Online (Sandbox Code Playgroud)

请注意,为了简洁起见,我使用的是Ruby File#dirname,File#basename以及File#expand类似Node.js的path.resolve.我正在使用类似Ruby的伪代码,但它仍然是伪代码.

关键点:

  • 没有优先顺序.当有几个可能的候选人时,SASS不会实施优先顺序.例如,如果你写了@import "x"并说两者x.scss并且_x.scss存在,那么sass会抛出歧义错误.同样地,如果这两个x.scssx.sass再存在时引发的多义性错误.
  • 从"从左到右"顺序尝试加载路径.它们提供了一个根或基础来解析导入(类似于UNIX使用$ PATH来查找可执行文件).始终首先尝试当前工作目录.(虽然此行为将从3.2 更改为3.4)
  • 负载路径总是不管尝试是否使用./../
  • 在sass文件中,无法导入常规.css文件

如果您想了解更多细节,我建议您阅读SASS的源代码:

编辑:我对我之前的回答感到不满意,所以我把它改写得更清楚一些.算法现在可以正确处理文件名中的下划线(以前的算法没有).我还添加了一些关键点来解决OP提出的其他问题.