in scripts/separate-snippets.ts [152:225]
function collectSnippets(filePath: string): SnippetsConfig {
const fileContents = fs.readFileSync(filePath).toString();
const lines = fileContents.split("\n");
const config: SnippetsConfig = {
enabled: false,
suffix: DEFAULT_SUFFIX,
map: {},
};
// If a file does not have '// [SNIPPETS_SEPARATION enabled]' in it then
// we don't process it for this script.
config.enabled = lines.some((l) => !!l.match(RE_SNIPPETS_SEPARATION));
if (!config.enabled) {
return config;
}
// If the file contains '// [SNIPPETS_SUFFIX _banana]' we use _banana (or whatever)
// as the suffix. Otherwise we default to _modular.
const suffixLine = lines.find((l) => !!l.match(RE_SNIPPETS_SUFFIX));
if (suffixLine) {
const m = suffixLine.match(RE_SNIPPETS_SUFFIX);
if (m && m[1]) {
config.suffix = m[1];
}
}
// A temporary array holding the names of snippets we're currently within.
// This allows for handling nested snippets.
let inSnippetNames: string[] = [];
for (const line of lines) {
const startMatch = line.match(RE_START_SNIPPET);
const endMatch = line.match(RE_END_SNIPPET);
if (startMatch) {
// When we find a new [START foo] tag we are now inside snippet 'foo'.
// Until we find an [END foo] tag. All lines we see between now and then
// are part of the snippet content.
const snippetName = startMatch[1];
if (config.map[snippetName] !== undefined) {
throw new Error(`Detected more than one snippet with the tag ${snippetName}!`);
}
config.map[snippetName] = [line];
inSnippetNames.push(snippetName);
} else if (endMatch) {
// When we find a new [END foo] tag we are now exiting snippet 'foo'.
const snippetName = endMatch[1];
// If we were not aware that we were inside this snippet (no previous START)
// then we hard throw.
if (!inSnippetNames.includes(snippetName)) {
throw new Error(
`Unrecognized END tag ${snippetName} in ${filePath}.`
);
}
// Collect this line as the final line of the snippet and then
// remove this snippet name from the list we're tracking.
config.map[snippetName].push(line);
inSnippetNames.splice(inSnippetNames.indexOf(snippetName), 1);
} else if (inSnippetNames.length > 0) {
// Any line that is not START or END is appended to the list of
// lines for all the snippets we're currently tracking.
for (const snippetName of inSnippetNames) {
config.map[snippetName].push(line);
}
}
}
return config;
}