2015-12-17 1 views
6

Алгоритм, который Node.js использует для разрешения вызова require(), очень четко documented in pseudocode.Каков алгоритм, который использует Sass для решения инструкции @import?

Мне нужно то же самое для заявления Sass's @import.

Я знаю, что @import 'foo' будет попробовать различные комбинации basenames foo и _foo, с суффиксами .scss и .sass, в том же каталоге, что и файл импортирования, а также по отношению к любому из настроенных «путей нагрузки» ... Но в каком порядке они используются, т. е. что имеет преимущество, если есть несколько файлов, которые могут удовлетворить @import? Начиная с ./ или ../ влияет ли он на пути загрузки? Есть ли какие-то другие вещи, которые я попробую, чтобы я не накрыл? Как насчет .css файлов?

guide не говорит много за пределами «Сасс умный и выяснит это для вас». reference docs более подробно рассмотрите, но все еще не излагайте шаги разрешения.

Может ли кто-нибудь предоставить точный алгоритм, который он использует, в псевдокоде?

+0

Вы понимаете, что Sass является открытым исходным кодом и что вы можете найти это самостоятельно, не так ли? – cimmanon

+0

@cimmanon yep. Разве вы не думаете, что в нем есть какая-то ценность в псевдокоде? – callum

ответ

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 

Примечание для краткости я использую Руби File#dirname, File#basename, а также File#expand который, как Node.js-х path.resolve. Я использую псевдокод, подобный Ruby, но он все еще предназначен для псевдокода.

Ключевые моменты:

  • Там нет порядка старшинства. Вместо того, чтобы выполнять порядок приоритетов, SASS отказывается, когда есть несколько возможных кандидатов. Например, если вы написали @import "x" и сказали, что есть как x.scss, так и _x.scss, то sass вызовет ошибку двусмысленности. Аналогичным образом, если существуют как x.scss, так и x.sass, возникает ошибка двусмысленности.
  • Пути загрузки проверяются слева направо. Они предоставляют корень или базу для разрешения импорта (аналогично тому, как UNIX использует $ PATH для поиска исполняемых файлов). Текущий рабочий каталог всегда проверяется первым. (Хотя это поведение will change от 3,2 до 3,4)
  • пути нагрузки всегда пытались независимо от того, используется ли вы ./ или ../
  • В файле Сасс, регулярные .css файлы cannot be imported

Если вы хотите более подробно Я рекомендую прочитать исходный код Сассы:

  • import метод sass/lib/sass/tree/import_node.rb. В строках 53-56 вы можете видеть то же самое для цикла, что и внутри функции search в нашем псевдокоде.
  • Importers::Base аннотация класс sass/lib/sass/importors/base.rb. Замечания этого файла весьма удобны.
  • find_real_file способ sass/lib/sass/importors/filesystem.rb. Строки 112-126 реализуют нашу функцию possible_files. Линия 156 проверяет, что есть только одно совпадение. Если нет, то строка 167 выдает ошибку двусмысленности, иначе строка 183 выбирает один соответствующий файл.

Edit: Я не был доволен своим предыдущим ответом, поэтому я переписать его, чтобы быть немного яснее. Алгоритм теперь корректно обрабатывает символы подчеркивания в имени файла (предыдущий алгоритм не был). Я также добавил некоторые ключевые моменты, которые касаются других вопросов, заданных ОП.

+0

Линия 'let dirname = File.dirname (import_arg)' меня смущает. Вам не нужно имя файла импортируемого файла, а не импортируемый файл? – callum

+0

Кроме того, переменная 'dirname', похоже, не используется нигде. Он передается в 'search()', но эта функция игнорирует его. – callum

Смежные вопросы