import type SpecDirectory from "./spec-directory"
import path from "path"
const HRX_SECTION_SEPARATOR = `
<===>
================================================================================
`
async function getFilesHrx(
dir: SpecDirectory,
root: string,
filenames: string[]
): Promise<string> {
const fileSections = await Promise.all(
filenames.map(async (filename) => {
const contents = await dir.readFile(filename)
const fullPath = path.resolve(dir.path, filename)
const relPath = path.relative(root, fullPath)
return `<===> ${relPath}\n${contents}`
})
)
return fileSections.join("\n")
}
async function getSubdirsHrx(
dir: SpecDirectory,
root: string
): Promise<string[]> {
let sections: string[] = []
for (const subdir of await dir.subdirs()) {
sections = sections.concat(await getHrxSections(subdir, root))
}
return sections
}
async function getDirectFileHrx(
dir: SpecDirectory,
root: string
): Promise<string> {
return await getFilesHrx(dir, root, await dir.listFiles())
}
/**
* Get the subcontents of a non-test directory as HRX.
* The first element of the returned array represents the direct files of the directory,
* and each subsequent element corresponds to a subdirectory.
*/
async function getNormalDirHrx(
dir: SpecDirectory,
root: string
): Promise<string[]> {
const directFiles = await getDirectFileHrx(dir, root)
const subdirSections = await getSubdirsHrx(dir, root)
return directFiles.length === 0
? subdirSections
: [directFiles, ...subdirSections]
}
/**
* Return the contents of a test directory as a single HRX section.
*
* The elements are printed in this order:
*
* - options.yml (if present)
* - input.sass/.scss
* - any other files, including files in subdirectories
* - output files, including implementation-specific outputs
* - warning files, including implementation-specific warnings
* - error files, including implementation-specific errors
*/
async function getTestDirHrx(
dir: SpecDirectory,
root: string
): Promise<string> {
const filenames = await dir.listFiles()
const inputFile = filenames.find((filename) =>
/input\.s[ca]ss/.test(filename)
)!
// TODO instead of sorting, just make sure the base output is written first
const outputFiles = filenames
.filter((name) => name.startsWith("output-"))
.sort()
const warningFiles = filenames
.filter((name) => name.startsWith("warning"))
.sort()
const errorFiles = filenames.filter((name) => name.startsWith("error")).sort()
const otherFiles = filenames.filter((name) => {
return !/^(output|error|warning|input\.s[ac]ss|options\.yml)/.test(name)
})
const subdirSections = await getSubdirsHrx(dir, root)
return [
dir.hasFile("options.yml")
? await getFilesHrx(dir, root, ["options.yml"])
: "",
await getFilesHrx(dir, root, [inputFile]),
await getFilesHrx(dir, root, otherFiles),
subdirSections.join("\n"),
dir.hasFile("output.css")
? await getFilesHrx(dir, root, ["output.css"])
: "",
await getFilesHrx(dir, root, outputFiles),
await getFilesHrx(dir, root, warningFiles),
await getFilesHrx(dir, root, errorFiles),
]
.filter((str) => str)
.join("\n")
}
async function getHrxSections(
dir: SpecDirectory,
root: string
): Promise<string[]> {
if (dir.isTestDir()) {
return [await getTestDirHrx(dir, root)]
} else {
return getNormalDirHrx(dir, root)
}
}
/**
* Write the contents of this directory to an HRX file.
*/
export async function toHrx(dir: SpecDirectory): Promise<string> {
const sections = await getHrxSections(dir, dir.path)
return sections.join(HRX_SECTION_SEPARATOR)
}