MCPcopy Create free account
hub / github.com/colbymchenry/codegraph / componentsIn

Function componentsIn

src/resolution/angular-template-synthesizer.ts:65–113  ·  view source on GitHub ↗

Every `@Component` class a file declares, with its selectors and template.

(file: string, content: string, nodes: readonly Node[], ctx: ResolutionContext)

Source from the content-addressed store, hash-verified

63
64/** Every `@Component` class a file declares, with its selectors and template. */
65function componentsIn(file: string, content: string, nodes: readonly Node[], ctx: ResolutionContext): AngularComponent[] {
66 const out: AngularComponent[] = [];
67 const safe = stripCommentsForRegex(content, 'typescript');
68 const decorator = /@Component\s*\(/g;
69 let m: RegExpExecArray | null;
70 while ((m = decorator.exec(safe)) !== null) {
71 const paren = m.index + m[0].length - 1;
72 const close = matchBracket(safe, paren);
73 if (close < 0) continue;
74 decorator.lastIndex = close;
75 const open = safe.indexOf('{', paren);
76 if (open < 0 || open > close) continue;
77 const objEnd = matchBracket(safe, open);
78 if (objEnd < 0) continue;
79 const cls = /^\s*(?:export\s+)?(?:default\s+)?(?:abstract\s+)?class\s+([A-Za-z_$][\w$]*)/.exec(safe.slice(close + 1, close + 400));
80 if (!cls) continue;
81 const node = nodes.find((n) => n.kind === 'class' && n.name === cls[1]);
82 if (!node) continue;
83 const fields = readFields(safe, open, objEnd);
84 const selectorText = fields.get('selector')?.text;
85 const selector = selectorText ? staticString(selectorText) : null;
86 const selectors = (selector ?? '')
87 .split(',')
88 .map((s) => s.trim())
89 .filter((s) => ELEMENT_SELECTOR.test(s));
90
91 let template: AngularComponent['template'] = null;
92 const url = fields.get('templateUrl')?.text;
93 const templateUrl = url ? staticString(url) : null;
94 if (templateUrl) {
95 const templateFile = templatePathFor(file, templateUrl);
96 const text = ctx.readFile(templateFile);
97 if (text) template = { file: templateFile, text, firstLine: 1, inline: false };
98 } else {
99 const inline = fields.get('template');
100 if (inline) {
101 // The template string's body, from the original source (stripping
102 // comments must not touch a template's text), at its own offset.
103 const quoteAt = content.indexOf(inline.text.trim()[0] ?? '`', inline.at + 'template'.length);
104 const end = quoteAt < 0 ? -1 : skipString(content, quoteAt);
105 if (end > quoteAt) {
106 template = { file, text: content.slice(quoteAt + 1, end), firstLine: lineOfOffset(content, quoteAt + 1), inline: true };
107 }
108 }
109 }
110 out.push({ node, file, selectors, template });
111 }
112 return out;
113}
114
115/** Per context, renewed with the route list (whose identity changes when the resolver's caches do). */
116const componentIndexes = new WeakMap<ResolutionContext, { source: readonly Node[]; components: AngularComponent[] }>();

Callers 1

angularComponentsFunction · 0.85

Calls 12

stripCommentsForRegexFunction · 0.90
matchBracketFunction · 0.90
readFieldsFunction · 0.90
staticStringFunction · 0.90
templatePathForFunction · 0.90
skipStringFunction · 0.90
lineOfOffsetFunction · 0.85
mapMethod · 0.80
readFileMethod · 0.80
pushMethod · 0.80
execMethod · 0.65
getMethod · 0.65

Tested by

no test coverage detected