diff --git a/src/compiler-host.js b/src/compiler-host.js index d602004..7ba61e2 100644 --- a/src/compiler-host.js +++ b/src/compiler-host.js @@ -323,7 +323,7 @@ export default class CompilerHost { * * @private */ - async compileUncached(filePath, hashInfo, compiler) { + async compileUncached(filePath, hashInfo, compiler, history=new Set()) { let inputMimeType = mimeTypes.lookup(filePath); if (hashInfo.isFileBinary) { @@ -336,6 +336,7 @@ export default class CompilerHost { let ctx = {}; let code = hashInfo.sourceCode || await pfs.readFile(filePath, 'utf8'); + history.add(code); if (!(await compiler.shouldCompileFile(code, ctx))) { d(`Compiler returned false for shouldCompileFile: ${filePath}`); @@ -359,6 +360,11 @@ export default class CompilerHost { if ((finalForms[result.mimeType] && !shouldInlineHtmlify) || isPassthrough) { // Got something we can use in-browser, let's return it return Object.assign(result, {dependentFiles}); + } else if (history.has(result.code)) { + d(`Compiler loop on ${filePath} after ${history.size - 1} prior candidates: assuming OK.`); + return Object.assign(result, {dependentFiles}); + } else if (history.size > 30) { + throw new Error(`Compiling ${filePath} resulted in a recursive recompilation more than 30 levels deep: assuming broken.`); } else { d(`Recursively compiling result of ${filePath} with non-final MIME type ${result.mimeType}, input was ${inputMimeType}`); @@ -373,7 +379,7 @@ export default class CompilerHost { return await this.compileUncached( `${filePath}.${mimeTypes.extension(result.mimeType || 'txt')}`, - hashInfo, compiler); + hashInfo, compiler, history); } }