Skip to content

Commit

Permalink
Generate from angular selectors. ENG-7482 (#1653)
Browse files Browse the repository at this point in the history
* Generate from angular selectors. ENG-7482

* fmt

* using angular selector parser

* stringify values

* expand tests

* changeset
  • Loading branch information
STRd6 authored Dec 12, 2024
1 parent 74e4f18 commit 772d6f5
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .changeset/little-impalas-turn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@builder.io/mitosis': patch
---

Angular selector support in code generation
32 changes: 32 additions & 0 deletions packages/core/src/__tests__/angular.selector.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { parse } from '../generators/angular/parse-selector';

describe('Angular selectors', () => {
test('should parse gnarly selectors', () => {
expect(parse('ccc.c1#wat[co].c2[counter="cool"]#wat[x=\'y\'].c3')).toEqual({
element: 'ccc',
classNames: ['c1', 'c2', 'c3'],
attributes: {
co: '',
counter: 'cool',
id: 'wat',
x: 'y',
},
});
});

test('parsing multiple returns only the first', () => {
expect(parse('dropzone, [dropzone]')).toEqual({
element: 'dropzone',
classNames: [],
attributes: {},
});
});

test(':not parses but is unused', () => {
expect(parse('list-item:not(.foo)')).toEqual({
element: 'list-item',
classNames: [],
attributes: {},
});
});
});
46 changes: 41 additions & 5 deletions packages/core/src/generators/angular/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ import {
ToAngularOptions,
} from './types';

import { parse } from './parse-selector';

const { types } = babel;

const mappers: {
Expand Down Expand Up @@ -427,10 +429,44 @@ export const blockToAngular = ({

str += `</ng-container>`;
} else {
const elSelector = childComponents.find((impName) => impName === json.name)
? kebabCase(json.name)
: json.name;
str += `<${elSelector} `;
let element,
classNames: string[] = [],
attributes;

const isComponent = childComponents.find((impName) => impName === json.name);

if (isComponent) {
const selector = json.meta.selector || blockOptions?.selector;
if (selector) {
try {
({ element, classNames, attributes } = parse(`${selector}`));
} catch {
element = kebabCase(json.name);
}
} else {
element = kebabCase(json.name);
}
} else {
element = json.name;
}

str += `<${element} `;

// TODO: merge with existing classes/bindings
if (classNames.length) {
str += `class="${classNames.join(' ')}" `;
}

// TODO: Merge with existing properties
if (attributes) {
Object.entries(attributes).forEach(([key, value]) => {
if (value) {
str += `${key}=${JSON.stringify(value)} `;
} else {
str += `${key} `;
}
});
}

for (const key in json.properties) {
if (key.startsWith('$')) {
Expand Down Expand Up @@ -516,7 +552,7 @@ export const blockToAngular = ({
.join('\n');
}

str += `</${elSelector}>`;
str += `</${element}>`;
}
return str;
};
Expand Down
17 changes: 17 additions & 0 deletions packages/core/src/generators/angular/parse-selector.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { CssSelector } from '@angular/compiler';

export function parse(selector: string) {
const { element, classNames, attrs } = CssSelector.parse(selector)[0];
const attributes = attrs.reduce((acc, attr, i) => {
if (i % 2 === 0) {
acc[attr] = attrs[i + 1];
}
return acc;
}, {} as Record<string, string>);

return {
element,
classNames,
attributes,
};
}

0 comments on commit 772d6f5

Please sign in to comment.