( ast: AstNode[], base: string, loadStylesheet: LoadStylesheet, recurseCount = 0, track = false, )
| 14 | }> |
| 15 | |
| 16 | export async function substituteAtImports( |
| 17 | ast: AstNode[], |
| 18 | base: string, |
| 19 | loadStylesheet: LoadStylesheet, |
| 20 | recurseCount = 0, |
| 21 | track = false, |
| 22 | ) { |
| 23 | let features = Features.None |
| 24 | let promises: Promise<void>[] = [] |
| 25 | |
| 26 | walk(ast, (node) => { |
| 27 | if (node.kind === 'at-rule' && (node.name === '@import' || node.name === '@reference')) { |
| 28 | let parsed = parseImportParams(ValueParser.parse(node.params)) |
| 29 | if (parsed === null) return |
| 30 | if (node.name === '@reference') { |
| 31 | parsed.media = 'reference' |
| 32 | } |
| 33 | |
| 34 | features |= Features.AtImport |
| 35 | |
| 36 | let { uri, layer, media, supports } = parsed |
| 37 | |
| 38 | // Skip importing data or remote URIs |
| 39 | if (uri.startsWith('data:')) return |
| 40 | if (uri.startsWith('http://') || uri.startsWith('https://')) return |
| 41 | |
| 42 | let contextNode = context({}, []) |
| 43 | |
| 44 | promises.push( |
| 45 | (async () => { |
| 46 | // Since we do not have fully resolved paths in core, we can't |
| 47 | // reliably detect circular imports. Instead, we try to limit the |
| 48 | // recursion depth to a number that is too large to be reached in |
| 49 | // practice. |
| 50 | if (recurseCount > 100) { |
| 51 | throw new Error( |
| 52 | `Exceeded maximum recursion depth while resolving \`${uri}\` in \`${base}\`)`, |
| 53 | ) |
| 54 | } |
| 55 | |
| 56 | let loaded = await loadStylesheet(uri, base) |
| 57 | let ast = CSS.parse(loaded.content, { from: track ? loaded.path : undefined }) |
| 58 | await substituteAtImports(ast, loaded.base, loadStylesheet, recurseCount + 1, track) |
| 59 | |
| 60 | contextNode.nodes = buildImportNodes( |
| 61 | node, |
| 62 | [context({ base: loaded.base }, ast)], |
| 63 | layer, |
| 64 | media, |
| 65 | supports, |
| 66 | ) |
| 67 | })(), |
| 68 | ) |
| 69 | |
| 70 | // The resolved Stylesheets already have their transitive @imports |
| 71 | // resolved, so we can skip walking them. |
| 72 | return WalkAction.ReplaceSkip(contextNode) |
| 73 | } |
no test coverage detected