Skip to main content
Glama
push-based

Angular Toolkit MCP

by push-based
EXAMPLES.md7.63 kB
# Examples ## 1 — Basic stylesheet parsing > Parse CSS content and access the AST structure. ```ts import { parseStylesheet } from '@push-based/styles-ast-utils'; const cssContent = ` .btn { color: red; background: blue; } .card { padding: 1rem; } `; const result = parseStylesheet(cssContent, 'styles.css'); const root = result.root; console.log(`Parsed ${root.nodes.length} top-level nodes`); // → 'Parsed 2 top-level nodes' console.log(root.nodes[0].type); // → 'rule' console.log(root.nodes[0].selector); // → '.btn' ``` --- ## 2 — Using the visitor pattern > Traverse CSS AST using the visitor pattern to collect information. ```ts import { parseStylesheet, visitEachChild } from '@push-based/styles-ast-utils'; const cssContent = ` /* Main styles */ .btn { color: red; font-size: 14px; } @media (max-width: 768px) { .btn { font-size: 12px; } } `; const result = parseStylesheet(cssContent, 'styles.css'); const selectors: string[] = []; const properties: string[] = []; const mediaQueries: string[] = []; const visitor = { visitRule: (rule) => { selectors.push(rule.selector); }, visitDecl: (decl) => { properties.push(`${decl.prop}: ${decl.value}`); }, visitAtRule: (atRule) => { if (atRule.name === 'media') { mediaQueries.push(atRule.params); } }, visitComment: (comment) => { console.log(`Found comment: ${comment.text}`); }, }; visitEachChild(result.root, visitor); console.log('Selectors:', selectors); // → ['Selectors:', ['.btn', '.btn']] console.log('Properties:', properties); // → ['Properties:', ['color: red', 'font-size: 14px', 'font-size: 12px']] console.log('Media queries:', mediaQueries); // → ['Media queries:', ['(max-width: 768px)']] ``` --- ## 3 — Converting AST nodes to source locations > Convert CSS rules to linkable source locations for error reporting. ```ts import { parseStylesheet, styleAstRuleToSource, } from '@push-based/styles-ast-utils'; import { Rule } from 'postcss'; const cssContent = ` .header { background: linear-gradient(to right, #ff0000, #00ff00); padding: 2rem; } .footer { margin-top: auto; } `; const result = parseStylesheet(cssContent, 'components/layout.css'); const rules = result.root.nodes.filter( (node) => node.type === 'rule' ) as Rule[]; rules.forEach((rule, index) => { const source = styleAstRuleToSource(rule); console.log(`Rule ${index + 1}:`, { selector: rule.selector, location: `${source.file}:${source.position.startLine}:${source.position.startColumn}`, span: `${source.position.startLine}-${source.position.endLine}`, }); }); // Output: // Rule 1: { // selector: '.header', // location: 'components/layout.css:2:1', // span: '2-4' // } // Rule 2: { // selector: '.footer', // location: 'components/layout.css:6:1', // span: '6-8' // } ``` --- ## 4 — Handling inline styles with line offset > Parse inline styles and adjust line numbers for accurate source mapping. ```ts import { parseStylesheet, styleAstRuleToSource, } from '@push-based/styles-ast-utils'; import { Rule } from 'postcss'; // Simulate inline styles starting at line 15 in a component file const inlineStyles = `.component-btn { color: blue; }`; const componentFilePath = 'src/app/button.component.ts'; const styleStartLine = 15; // 0-indexed line where styles begin const result = parseStylesheet(inlineStyles, componentFilePath); const rule = result.root.nodes[0] as Rule; // Convert with line offset const source = styleAstRuleToSource(rule, styleStartLine); console.log('Inline style location:', { file: source.file, line: source.position.startLine, // → 16 (adjusted for file position) selector: rule.selector, // → '.component-btn' }); ``` --- ## 5 — Recursive node traversal > Use recursive traversal to process nested CSS structures. ```ts import { parseStylesheet, visitEachStyleNode, } from '@push-based/styles-ast-utils'; const cssContent = ` .container { display: flex; .item { flex: 1; &:hover { opacity: 0.8; } } } @supports (display: grid) { .grid-container { display: grid; grid-template-columns: repeat(3, 1fr); } } `; const result = parseStylesheet(cssContent, 'nested-styles.scss'); let depth = 0; const visitor = { visitRule: (rule) => { console.log(`${' '.repeat(depth)}Rule: ${rule.selector}`); depth++; if (rule.nodes) { visitEachStyleNode(rule.nodes, visitor); } depth--; }, visitAtRule: (atRule) => { console.log(`${' '.repeat(depth)}@${atRule.name}: ${atRule.params}`); depth++; if (atRule.nodes) { visitEachStyleNode(atRule.nodes, visitor); } depth--; }, visitDecl: (decl) => { console.log(`${' '.repeat(depth)}${decl.prop}: ${decl.value}`); }, }; visitEachStyleNode(result.root.nodes, visitor); // Output shows nested structure: // Rule: .container // display: flex // Rule: .item // flex: 1 // Rule: &:hover // opacity: 0.8 // @supports: (display: grid) // Rule: .grid-container // display: grid // grid-template-columns: repeat(3, 1fr) ``` --- ## 6 — Safe parsing with malformed CSS > Handle malformed CSS gracefully using the safe parser. ```ts import { parseStylesheet, visitEachChild } from '@push-based/styles-ast-utils'; // Malformed CSS with missing closing braces and invalid syntax const malformedCss = ` .btn { color: red background: blue; /* missing closing brace */ .card padding: 1rem; margin: invalid-value; } /* unclosed comment .footer { text-align: center; `; const result = parseStylesheet(malformedCss, 'malformed.css'); const issues: string[] = []; const visitor = { visitRule: (rule) => { console.log(`Successfully parsed rule: ${rule.selector}`); }, visitDecl: (decl) => { if (!decl.value || decl.value.includes('invalid')) { issues.push(`Invalid declaration: ${decl.prop}: ${decl.value}`); } }, }; visitEachChild(result.root, visitor); console.log(`Parsed ${result.root.nodes.length} nodes despite malformed CSS`); console.log('Issues found:', issues); // The safe parser recovers from errors and continues parsing // Output: // Successfully parsed rule: .btn // Successfully parsed rule: .card // Successfully parsed rule: .footer // Parsed 3 nodes despite malformed CSS // Issues found: ['Invalid declaration: margin: invalid-value'] ``` --- ## 7 — Collecting CSS class names > Extract all CSS class selectors from a stylesheet. ```ts import { parseStylesheet, visitEachChild } from '@push-based/styles-ast-utils'; const cssContent = ` .btn, .button { padding: 0.5rem 1rem; } .btn-primary { background: blue; } .card .header { font-weight: bold; } #main .sidebar .nav-item { list-style: none; } [data-theme="dark"] .btn { color: white; } `; const result = parseStylesheet(cssContent, 'components.css'); const classNames = new Set<string>(); const visitor = { visitRule: (rule) => { // Extract class names from selectors using regex const matches = rule.selector.match(/\.([a-zA-Z0-9_-]+)/g); if (matches) { matches.forEach((match) => { classNames.add(match.substring(1)); // Remove the dot }); } }, }; visitEachChild(result.root, visitor); console.log('Found CSS classes:', Array.from(classNames).sort()); // → ['Found CSS classes:', ['btn', 'btn-primary', 'button', 'card', 'header', 'nav-item', 'sidebar']] ``` These examples demonstrate the comprehensive CSS parsing and analysis capabilities of the `@push-based/styles-ast-utils` library for various stylesheet processing scenarios.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/push-based/angular-toolkit-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server