{"record":{"id":"69777c4ce8564589","repo":"angular/components","slug":"cannot-determine-child-element-indentation-because","errorCode":null,"errorMessage":"Cannot determine child element indentation because the specified Parse5 element does not have any source code location metadata.","messagePattern":"Cannot determine child element indentation because the specified Parse5 element does not have any source code location metadata\\.","errorType":"exception","errorClass":"SchematicsException","httpStatus":null,"severity":"error","filePath":"src/cdk/schematics/utils/parse5-element.ts","lineNumber":22,"sourceCode":" *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {SchematicsException} from '@angular-devkit/schematics';\nimport {DefaultTreeAdapterMap} from 'parse5';\n\n// At the time of writing `parse5` doesn't expose the node interfaces directly, even though\n// they're used as return types, but We can still access them through `DefaultTreeAdapterMap`.\nexport type Element = DefaultTreeAdapterMap['element'];\nexport type ChildNode = DefaultTreeAdapterMap['childNode'];\n\n/** Determines the indentation of child elements for the given Parse5 element. */\nexport function getChildElementIndentation(element: Element) {\n  const childElement = element.childNodes.find(node => (node as Element).tagName) as Element | null;\n\n  if ((childElement && !childElement.sourceCodeLocation) || !element.sourceCodeLocation) {\n    throw new SchematicsException(\n      'Cannot determine child element indentation because the ' +\n        'specified Parse5 element does not have any source code location metadata.',\n    );\n  }\n\n  const startColumns = childElement\n    ? // In case there are child elements inside of the element, we assume that their\n      // indentation is also applicable for other child elements.\n      childElement.sourceCodeLocation!.startCol\n    : // In case there is no child element, we just assume that child elements should be indented\n      // by two spaces.\n      element.sourceCodeLocation!.startCol + 2;\n\n  // Since Parse5 does not set the `startCol` properties as zero-based, we need to subtract\n  // one column in order to have a proper zero-based offset for the indentation.\n  return startColumns - 1;\n}\n","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/angular/components/blob/0411926e7d8ae06b32236ec1048a888cfad5abf2/src/cdk/schematics/utils/parse5-element.ts#L4-L40","documentation":"getChildElementIndentation in src/cdk/schematics/utils/parse5-element.ts measures the column of a child element to compute indentation when inserting markup into HTML. Parse5 only provides sourceCodeLocation metadata when the document is parsed with location info enabled. If neither the child element nor the given element carries sourceCodeLocation, the function cannot compute indentation and throws this SchematicsException.","triggerScenarios":"A schematic (e.g. addHtmlElementToBody/head flows that compute indentation via indentationOffset) parses index.html whose resulting Parse5 Element has no sourceCodeLocation — typically because the tree was built without location info or produced programmatically rather than parsed from source text.","commonSituations":"Mostly hit by developers writing or extending schematics that reuse these utilities: constructing Parse5 nodes manually, parsing with treeAdapter/parsing options that omit location info, or feeding already-transformed (serialized/re-parsed) HTML through the utility.","solutions":["Parse the HTML with location info enabled (default html.parse / parse5 with sourceCodeLocationInfo: true) before passing elements to getChildElementIndentation.","Pass elements obtained directly from a freshly parsed document, not programmatically created or deeply cloned nodes.","If you control the caller, fall back to a default indentation (e.g. 2 or 4 spaces) when sourceCodeLocation is unavailable instead of calling the utility.","Avoid round-tripping the HTML through serialize/parse cycles before indentation computation, which can strip location metadata."],"exampleFix":"// before\nconst html = parse5.parse(fs.readFileSync('index.html', 'utf8'), { treeAdapter: customAdapter });\n// after\nconst html = parse5.parse(fs.readFileSync('index.html', 'utf8'), { sourceCodeLocationInfo: true });","handlingStrategy":"type-guard","validationCode":"const doc = parse5.parse(html, { sourceCodeLocationInfo: true });\nif (!doc.sourceCodeLocation) throw new Error('Parse5 tree lacks source code locations; re-parse with sourceCodeLocationInfo: true');","typeGuard":"function hasSourceCodeLocation(el: parse5.Element): el is parse5.Element & { sourceCodeLocation: parse5.ElementLocation } {\n  return !!el.sourceCodeLocation && el.childNodes.some(n => 'tagName' in n && !!(n as parse5.Element).sourceCodeLocation);\n}","tryCatchPattern":"try {\n  const indent = getChildElementIndentation(head);\n} catch (e) {\n  if (String(e.message).includes('source code location metadata')) {\n    const indent = '  '; // fallback to 2-space indentation\n  } else throw e;\n}","preventionTips":["Always parse HTML with parse5's sourceCodeLocationInfo enabled when indentation utilities will run on the tree.","Never feed programmatically constructed or serialized-and-reparsed nodes into indentation helpers.","Write schematic unit tests that assert location metadata exists on the parsed fixture."],"tags":["angular","schematics","parse5","html-manipulation"],"backgroundTag":"missing-source-code-location","analyzedSha":"0411926e7d8ae06b32236ec1048a888cfad5abf2","analyzedAt":"2026-08-31T11:58:23.400Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}