Skip to content

Commit

Permalink
feat: STRF-10485 Nested multi file import
Browse files Browse the repository at this point in the history
  • Loading branch information
jairo-bc committed Mar 30, 2023
1 parent 14f4f79 commit 5507b5e
Showing 1 changed file with 110 additions and 14 deletions.
124 changes: 110 additions & 14 deletions lib/nodeSass/ConditionalImportFixer.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,80 @@ class ConditionalImportFixer extends BaseFixer {
async run() {
const files = [];
const scss = fs.readFileSync(this.filePath, 'utf8');
const condImportFile = await this.processCss(scss, this.transformConditionalImport());
const result = await this.processCss(scss, this.transformConditionalImport());

files.push({ filePath: this.filePath, data: condImportFile.css });
for await (const message of condImportFile.messages) {
if (message.type === 'import') {
const importFile = this.findImportedFile(message.filename, this.filePath);
const importFileScss = fs.readFileSync(importFile);
files.push({ filePath: this.filePath, data: result.css });
const imports = this.mapFilesToRootFile(result.messages, this.filePath);
const toUpdateNestedImports = [];

for await (const fileImport of imports) {
const importFile = this.findImportedFile(fileImport.file, fileImport.rootFile);
const importFileScss = fs.readFileSync(importFile, { encoding: 'utf8' });
const nestedImportFiles = await this.getNesterImportFiles(importFileScss, importFile);
if (nestedImportFiles) {
imports.push(...nestedImportFiles);
// at this moment I don't know if this is an actual mixin
toUpdateNestedImports.push(...nestedImportFiles);
} else {
const mixinFile = await this.processCss(
importFileScss,
this.transformRootToMixin(message),
this.transformRootToMixin(fileImport.file),
);
files.push({
filePath: importFile,
data: mixinFile.css,
});
}
}

if (this.shouldUpdateMixinNameInRootFile(toUpdateNestedImports)) {
const mixins = this.mapMixinNameToImportFileName(result.mixins);
// the target file is not updated right away, so the fresh content is in files object
this.updateRootFileMixinName(files, toUpdateNestedImports, mixins);
}
return files;
}

shouldUpdateMixinNameInRootFile(toUpdateNestedImports) {
return toUpdateNestedImports.length > 0;
}

updateRootFileMixinName(filesChanged, toUpdateNestedImports, mixins) {
const rootFileHash = toUpdateNestedImports.reduce((acc, fileImport) => {
if (!acc[fileImport.rootFile]) {
acc[fileImport.rootFile] = [];
}
acc[fileImport.rootFile].push(fileImport.file);
return acc;
}, {});
Object.keys(rootFileHash).forEach((rootFile) => {
const rootFileData = filesChanged.find((file) => file.filePath.includes(this.filePath));
const mixinImport = rootFileHash[rootFile]
.map((fileImport) => `@include ${fileImport}`)
.join(';\n ');
const mixinName = this.getMixinNameByImportName(mixins, rootFile);
rootFileData.data = rootFileData.data.replace(
new RegExp(`@include ${mixinName}`, 'g'),
mixinImport,
);
});
}

getMixinNameByImportName(mixins, importName) {
const found = mixins.find((m) => m.fileName === importName);
return found.mixinName;
}

mapMixinNameToImportFileName(mixins) {
return mixins.map((mixin) => {
const fileName = this.findImportedFile(mixin.importName, this.filePath);
return {
fileName,
mixinName: mixin.mixinName,
};
});
}

transformConditionalImport() {
return {
postcssPlugin: 'Transform Conditional Import',
Expand All @@ -42,20 +96,26 @@ class ConditionalImportFixer extends BaseFixer {
root.prepend(newRule);
decl.name = 'include';
// remove quotes from import
const oldName = decl.params.replace(/['"]+/g, '');
const oldName = this.prepareImportFileName(decl.params);
// replace slash with dash
decl.params = oldName.replace(/\//g, '-');
result.messages.push({
type: 'import',
filename: oldName,
const mixinName = oldName.replace(/\//g, '-');
decl.params = mixinName;
result.messages.push(oldName);
// adding new mixin info
if (!result.mixins) {
result.mixins = [];
}
result.mixins.push({
importName: oldName,
mixinName,
});
});
}
},
};
}

transformRootToMixin(data) {
transformRootToMixin(filename) {
const self = this;
return {
postcssPlugin: 'Transform Root to Mixin',
Expand All @@ -81,7 +141,7 @@ class ConditionalImportFixer extends BaseFixer {
self.formatNodes(nodes);
const newRoot = new AtRule({
name: 'mixin',
params: data.filename.replace(/\//g, '_'),
params: filename.replace(/\//g, '_'),
source: root.source,
nodes,
});
Expand All @@ -93,6 +153,38 @@ class ConditionalImportFixer extends BaseFixer {
};
}

checkForRecursiveImport() {
const self = this;
return {
postcssPlugin: 'Check for Recursive Import',
Once(root, { result }) {
const imports = [];
result.messages = [];
root.walkAtRules('import', (decl) => {
imports.push(self.prepareImportFileName(decl.params));
});
if (imports.length > 0) {
result.messages = [...imports];
}
},
};
}

async getNesterImportFiles(scss, file) {
const result = await this.processCss(scss, this.checkForRecursiveImport());
if (result.messages.length > 0) {
return this.mapFilesToRootFile(result.messages, file);
}
return null;
}

mapFilesToRootFile(files, rootFile) {
return files.map((file) => ({
file,
rootFile,
}));
}

formatNodes(nodes) {
if (nodes.length > 0) {
const spacer = this.getSpacer(nodes[0]);
Expand Down Expand Up @@ -129,6 +221,10 @@ class ConditionalImportFixer extends BaseFixer {
hasTabSpace(string) {
return /\t/g.test(string);
}

prepareImportFileName(fileName) {
return fileName.replace(/['"]+/g, '');
}
}

module.exports = ConditionalImportFixer;

0 comments on commit 5507b5e

Please sign in to comment.