2015-12-17 11 views
6

L'algoritmo utilizzato da Node.js per risolvere una chiamata require() è molto chiaro documented in pseudocode.Qual è l'algoritmo utilizzato da Sass per risolvere un'istruzione @import?

Ho bisogno della stessa cosa per la dichiarazione @import di Sass.

so che @import 'foo' cercherà varie combinazioni delle BaseNames foo e _foo, con estensioni .scss e .sass, nella stessa directory del file di importazione e relativa a un qualsiasi dei 'percorsi di carico' configurati ... Ma in quale ordine vengono provati, ovvero cosa ha la precedenza se ci sono più file che potrebbero soddisfare lo @import? A partire da ./ o ../ influisce sul fatto che provi i percorsi di caricamento? Ci sono altre cose che proverò che non ho coperto? Che mi dici dei file .css?

guide non dice molto oltre "Sass è intelligente e lo capirà per te". Lo reference docs entra più nel dettaglio, ma continua a non precisare i passaggi della risoluzione.

Qualcuno può fornire l'algoritmo esatto che utilizza, in pseudocodice?

+0

Ti rendi conto che Sass è open source e che potresti provare a scoprirlo da solo, giusto? – cimmanon

+0

@cimmanon sì. Non credi che ci sia qualche valore in esso presente anche nello pseudocodice? – callum

risposta

5

Ecco un algoritmo semplificato per @import <import_arg>;. Questo deriva dalla lettura del codice sorgente per SASS e dall'esecuzione dei miei test.

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 

Nota per brevità, sto usando di Ruby File#dirname, File#basename così come File#expand che è come Node.js di path.resolve. Sto usando uno pseudocodice simile a Ruby ma è comunque destinato a essere pseudocodice.

Punti chiave:

  • Non c'è un ordine di precedenza. Piuttosto che implementare un ordine di precedenza, SASS rinuncia quando ci sono diversi possibili candidati. Ad esempio, se hai scritto @import "x" e dici che esistono entrambi x.scss e _x.scss, allora sass genererà un errore di ambiguità. Allo stesso modo, se esistono entrambi x.scss e x.sass, viene generato un errore di ambiguità.
  • I percorsi di caricamento vengono provati dall'ordine 'sinistra a destra'. Forniscono una radice o una base per risolvere le importazioni da (in modo simile a come UNIX usa $ PATH per trovare gli eseguibili). La directory di lavoro corrente viene sempre provata per prima. (Anche se questo comportamento will change 3,2-3,4)
  • percorsi di carico sono sempre cercato indipendentemente dal fatto che si è utilizzato ./ o ../
  • In un file sass, normali file css cannot be imported

Se volete maggiori dettagli , mi sento di raccomandare la lettura del codice sorgente del SASS:

  • il metodo di sass/lib/sass/tree/import_node.rbimport. Sulle righe 53-56 è possibile vedere lo stesso ciclo come quello all'interno della funzione search nel nostro pseudocodice.
  • il Importers::Base classe astratta sass/lib/sass/importors/base.rb. I commenti di questo file sono abbastanza utili.
  • il metodo find_real_file di sass/lib/sass/importors/filesystem.rb. Le righe 112-126 implementano la nostra funzione possible_files. La linea 156 verifica che ci sia una sola corrispondenza. Se non c'è, la riga 167 genera un errore di ambiguità, altrimenti la riga 183 preleva il file corrispondente.

Edit: Non ero felice con la mia precedente risposta così ho riscritto per essere un po 'più chiaro. Algorithm ora gestisce correttamente i caratteri di sottolineatura nel nome file (l'algoritmo precedente non l'ha fatto). Ho anche aggiunto alcuni punti chiave che rispondono alle altre domande poste dall'OP.

+0

La riga 'let dirname = File.dirname (import_arg)' mi confonde. Non vuoi la dirname del file di importazione, non il file che stai importando? – callum

+0

Inoltre, la variabile 'dirname' non sembra essere usata da nessuna parte. È passato a 'search()', ma quella funzione lo ignora. – callum

Problemi correlati