UNPKG

node-sass-self-contained-importer

Version:

Used to execute sass/scss import and meanwhile resolve relative asset paths declared in the imported file as relative to the importing file. This plugin works as an importer for node-sass, so it supports gulp.js.

178 lines (145 loc) 5.61 kB
var path = require("path"), lib = require("./lib.js"), TreeNode = require("./TreeNode.js"); var ROOT = "#|ROOT|#"; /** * 从路径上最远的结点开始,依次计算并设置路径上每个结点的绝对路径 * @param {TreeNode} node 路径上最远的结点 * @param {String} [entryFileAbsolutePath] 入口文件的绝对路径 */ var calcAndSetAbsolutePathForEachNodeInThePath = function(node, entryFileAbsolutePath){ entryFileAbsolutePath = entryFileAbsolutePath || path.resolve(process.cwd(), "ROOT.SCSS"); var folder = path.dirname(entryFileAbsolutePath); lib.logger.debug("Set resolving folder as: {}. Current tree: {}", folder, node.getPathString()); var treeNodes = node.getNodeArrayFromCurrentNodeToRootNode().reverse(); for(var i = 0; i < treeNodes.length; i++){ /* 确定声明import的文件所在的目录 */ var _node = treeNodes[i]; var _importedFileAbsolutePath = _node.getAttachedData(); if(null != _importedFileAbsolutePath){ folder = path.dirname(_importedFileAbsolutePath); lib.logger.debug("Update resolving folder as: {} by node: [{}]", folder, _node.getValue()); continue; } var importedLiteral = _node.getValue(); if(importedLiteral === ROOT) continue; lib.logger.debug("Resolving file path for import: '{}'. Resolving folder: {}", importedLiteral, folder); /* 确定import的目标文件的绝对路径 */ var importedFileAbsolutePath = path.resolve(folder, importedLiteral); var existingImportedFileAbsolutePath = lib.findMatchingFilePath(importedFileAbsolutePath); if(null != existingImportedFileAbsolutePath){ _node.setAttachedData(existingImportedFileAbsolutePath); folder = path.dirname(existingImportedFileAbsolutePath); }else lib.logger.error("No scss file found for import: '{}'. Resolving folder: {}", importedLiteral, folder); } }; /** * SCSS引入解析器,用于判定特定由import语法引入路径对应的完整 */ var ScssImportCursor = function(){ var tree = TreeNode.newNode(ROOT); /* 入口文件的绝对路径 */ var entryFileAbsolutePath = path.resolve(process.cwd(), "ROOT.scss"); var pointer = tree; /** * 获取树根结点 * @returns {TreeNode} 树根结点 */ this.getTreeRootNode = function(){ return tree; }; /** * 获取当前指针位置 * @returns {TreeNode} 当前指针所指向的结点 */ this.getPointer = function(){ return pointer; }; /** * 获取入口文件的绝对路径 * @returns {String} */ this.getEntryFileAbsolutePath = function(){ return entryFileAbsolutePath; }; /** * 设置入口文件的绝对路径 * @param {String} _entryFileAbsolutePath 入口文件的绝对路径 * @returns {String} */ this.setEntryFileAbsolutePath = function(_entryFileAbsolutePath){ entryFileAbsolutePath = _entryFileAbsolutePath; return this; }; /** * 处理scss引入动作,根据import构建关联关系树 * @param {String} url 要引入的路径 * @param {String} pre 声明引入路径的上一个路径 * @returns {{urlNode: {TreeNode}, preNode: {TreeNode}}} 上一个路径对应的结点 */ this.buildTree = function(url, pre){ lib.logger.debug(">> Build tree for import: '{}' by '{}'. Current tree: {}", url, pre, pointer.getPathString()); var obj = {}; var node = pointer.findNodeByValueFromCurrentNodeToRootNode(pre); if(null == node){ if(null != pre){ node = TreeNode.newNode(pre); pointer.addNext(node); }else node = tree; } pointer = node; obj.preNode = node; var _node = TreeNode.newNode(url); node.addNext(_node); pointer = _node; obj.urlNode = _node; /* 推演关系树上各个结点对应文件的绝对路径 */ calcAndSetAbsolutePathForEachNodeInThePath(obj.urlNode, entryFileAbsolutePath); lib.logger.debug("<< Build tree for import: '{}' by '{}'. Current connection: {}", url, pre, pointer.getPathString()); return obj; }; }; /** * 根据给定的scss文件正文和路径,结合 import 语法搜索该scss依赖的其它文件 * @param {String} scssFileAbsolutePath 要搜索的入口scss文件的绝对路径 * @param {String} [scssFileContent] 要搜索的入口scss文件正文。缺省时,将自动读取 scssFileAbsolutePath 的正文 * @returns {string[]} 依赖的其它scss文件的绝对路径列表 */ ScssImportCursor.searchImportedScssFiles = function(scssFileAbsolutePath, scssFileContent){ var cursor = new ScssImportCursor().setEntryFileAbsolutePath(scssFileAbsolutePath); var search = function(scssFileAbsolutePath, scssFileContent, pre){ var arr = []; if(null === scssFileAbsolutePath || "" === scssFileAbsolutePath.trim()) return arr; if(arguments.length < 3) pre = null; if(arguments.length < 2){ scssFileContent = lib.readFile(scssFileAbsolutePath, false); if(null === scssFileContent) return arr; } var r = /@import\s+['"]\s*([^'"]+)\s*['"]/gim; var tmp; while((tmp = r.exec(scssFileContent)) != null){ var url = tmp[1]; var urlNode = cursor.buildTree(url, pre).urlNode; var importedFileAbsolutePath = urlNode.getAttachedData(); if(null == importedFileAbsolutePath) continue; arr.push(importedFileAbsolutePath); /* 执行 深度优先 搜索 */ var importedFileContent = lib.readFile(importedFileAbsolutePath, false); if(null !== importedFileContent) arr = arr.concat(search(importedFileAbsolutePath, importedFileContent, url)); } return arr; }; if(arguments.length > 1) return search(scssFileAbsolutePath, scssFileContent); else return search(scssFileAbsolutePath); }; module.exports = ScssImportCursor;