{"record":{"id":"341e8f6bad392c1f","repo":"microsoft/TypeScript","slug":"non-comment-test-content-appears-before-the-first","errorCode":null,"errorMessage":"Non-comment test content appears before the first '// @Filename' directive","messagePattern":"Non-comment test content appears before the first '// @Filename' directive","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/harness/harnessIO.ts","lineNumber":1302,"sourceCode":"                        content: currentFileContent!, // TODO: GH#18217\r\n                        name: currentFileName,\r\n                        fileOptions: currentFileOptions,\r\n                        originalFilePath: fileName,\r\n                        references: refs,\r\n                    };\r\n                    testUnitData.push(newTestFile);\r\n\r\n                    // Reset local data\r\n                    currentFileContent = undefined;\r\n                    currentFileOptions = {};\r\n                    currentFileName = testMetaData[2].trim();\r\n                    refs = [];\r\n                }\r\n                else {\r\n                    // First metadata marker in the file\r\n                    currentFileName = testMetaData[2].trim();\r\n                    if (currentFileContent && ts.skipTrivia(currentFileContent, 0, /*stopAfterLineBreak*/ false, /*stopAtComments*/ false) !== currentFileContent.length) {\r\n                        throw new Error(\"Non-comment test content appears before the first '// @Filename' directive\");\r\n                    }\r\n                    currentFileContent = \"\";\r\n                }\r\n            }\r\n            else {\r\n                // Subfile content line\r\n                // Append to the current subfile content, inserting a newline needed\r\n                if (currentFileContent === undefined) {\r\n                    currentFileContent = \"\";\r\n                }\r\n                else if (currentFileContent !== \"\") {\r\n                    // End-of-line\r\n                    currentFileContent = currentFileContent + \"\\n\";\r\n                }\r\n                currentFileContent = currentFileContent + line;\r\n            }\r\n        }\r\n\r","sourceCodeStart":1284,"sourceCodeEnd":1320,"githubUrl":"https://github.com/microsoft/TypeScript/blob/b465fdbfe175304d9b977da137b2c178ae1091d3/src/harness/harnessIO.ts#L1284-L1320","documentation":"Thrown by the multi-file test parser in harnessIO.ts:1302. When the parser hits the first `// @Filename` directive in a test file, it checks that any content already accumulated (`currentFileContent`) consists only of comments (skipTrivia reaches end of string). If real code precedes the first directive, the throw fires — that code has no file to belong to.","triggerScenarios":"A compiler test file begins with executable TypeScript/JavaScript statements or a file-level declaration before the first `// @Filename` directive. Only comment lines (the metadata/option block) are permitted before the first directive.","commonSituations":"Author pastes source code at the top of a test file above the `// @Filename` block; an editor auto-inserts an import or shebang line at the head; concatenating single-file tests into a multi-file test without moving the preamble under a `// @Filename`.","solutions":["Move every line of real code under a `// @Filename: <name>.ts` directive so nothing but comments precedes the first directive.","Convert stray preamble into a comment block (line-leading `//`).","Add an explicit `// @Filename: preamble.ts` directive to host the early code."],"exampleFix":"// before — code before first directive\nimport { x } from \"y\";\n// @Filename: a.ts\nexport const z = x;\n\n// after — preamble lives under a directive (or as a comment)\n// @Filename: imp.ts\nimport { x } from \"y\";\n// @Filename: a.ts\nexport const z = x;","handlingStrategy":"validation","validationCode":"// Lint a multifile test source before the parser throws.\nfunction assertNoCodeBeforeFirstFilenameDirective(source: string): void {\n  const idx = source.indexOf('// @Filename');\n  if (idx < 0) return; // not a multifile test\n  const head = source.slice(0, idx);\n  const nonComment = head.split(/\\r?\\n/).filter(l => l.trim() !== '' && !l.trim().startsWith('//'));\n  if (nonComment.length > 0) {\n    throw new Error(`Move these lines under a // @Filename directive: ${nonComment.join(' | ')}`);\n  }\n}","typeGuard":"function beginsWithFilenameDirectiveOrComments(source: string): boolean {\n  const head = source.slice(0, source.indexOf('// @Filename'));\n  return head.split(/\\r?\\n/).every(l => l.trim() === '' || l.trim().startsWith('//'));\n}","tryCatchPattern":null,"preventionTips":["Start every multifile test with the option/annotation comment block immediately followed by the first // @Filename directive.","Run a quick linter that rejects non-comment lines before the first // @Filename.","When concatenating single-file tests, prepend a // @Filename directive before each block."],"tags":["test-harness","test-parser","multifile-test","authoring"],"backgroundTag":null,"analyzedSha":"b465fdbfe175304d9b977da137b2c178ae1091d3","analyzedAt":"2026-08-12T05:38:42.698Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}