Skip to content

Commit

Permalink
feat(angular): Standalone Value Accessor for Angular OutputType (#459)
Browse files Browse the repository at this point in the history
* Provide support for standalone value accessors

* Provide support for standalone value accessors

* Chore: removed console logs and if check changed
  • Loading branch information
Samg983 authored Aug 28, 2024
1 parent 955534c commit b8930b0
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ describe('createValueAccessor', () => {

const srcFilePath = path.join(__dirname, '../resources/control-value-accessors/text-value-accessor.ts');
const srcFile = fs.readFileSync(srcFilePath, { encoding: 'utf-8' });
const finalText = createValueAccessor(srcFile, valueAccessor);
const exptectedOutput = `import { Directive, ElementRef } from '@angular/core';
const finalText = createValueAccessor(srcFile, valueAccessor, 'component');
const expectedOutput = `import { Directive, ElementRef } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { ValueAccessor } from './value-accessor';
Expand All @@ -41,6 +41,45 @@ export class TextValueAccessor extends ValueAccessor {
super(el);
}
}`;
expect(finalText.trim()).toEqual(exptectedOutput.trim().replace(/\n/g, EOL));
expect(finalText.trim()).toEqual(expectedOutput.trim().replace(/\n/g, EOL));
});
it('should create a valid {type}-value-accessor.ts file with the correct standalone option', () => {
const valueAccessor: ValueAccessor = {
elementSelectors: ['my-input[type=text]', 'my-input[type=email]'],
eventTargets: [
['myChange', 'value'],
['myEmailChange', 'value'],
],
};

const srcFilePath = path.join(__dirname, '../resources/control-value-accessors/text-value-accessor.ts');
const srcFile = fs.readFileSync(srcFilePath, { encoding: 'utf-8' });
const finalText = createValueAccessor(srcFile, valueAccessor, 'standalone');
const expectedOutput = `import { Directive, ElementRef } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { ValueAccessor } from './value-accessor';
@Directive({
/* tslint:disable-next-line:directive-selector */
selector: 'my-input[type=text], my-input[type=email]',
host: {
'(myChange)': 'handleChangeEvent($event.target.value)',
'(myEmailChange)': 'handleChangeEvent($event.target.value)'
},
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: TextValueAccessor,
multi: true
}
],standalone: true
})
export class TextValueAccessor extends ValueAccessor {
constructor(el: ElementRef) {
super(el);
}
}`;
expect(finalText.trim()).toEqual(expectedOutput.trim().replace(/\n/g, EOL));
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { ValueAccessor } from './value-accessor';
useExisting: BooleanValueAccessor,
multi: true
}
]
]<VALUE_ACCESSOR_STANDALONE>
})
export class BooleanValueAccessor extends ValueAccessor {
constructor(el: ElementRef) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { ValueAccessor } from './value-accessor';
useExisting: NumericValueAccessor,
multi: true
}
]
]<VALUE_ACCESSOR_STANDALONE>
})
export class NumericValueAccessor extends ValueAccessor {
constructor(el: ElementRef) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { ValueAccessor } from './value-accessor';
useExisting: RadioValueAccessor,
multi: true
}
]
]<VALUE_ACCESSOR_STANDALONE>
})
export class RadioValueAccessor extends ValueAccessor {
constructor(el: ElementRef) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { ValueAccessor } from './value-accessor';
useExisting: SelectValueAccessor,
multi: true
}
]
]<VALUE_ACCESSOR_STANDALONE>
})
export class SelectValueAccessor extends ValueAccessor {
constructor(el: ElementRef) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { ValueAccessor } from './value-accessor';
useExisting: TextValueAccessor,
multi: true
}
]
]<VALUE_ACCESSOR_STANDALONE>
})
export class TextValueAccessor extends ValueAccessor {
constructor(el: ElementRef) {
Expand Down
18 changes: 12 additions & 6 deletions packages/angular-output-target/src/generate-value-accessors.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { EOL } from 'os';
import path from 'path';
import type { OutputTargetAngular, ValueAccessorTypes } from './types';
import { OutputTargetAngular, OutputType, ValueAccessorTypes } from './types';
import type { CompilerCtx, ComponentCompilerMeta, Config } from '@stencil/core/internal';
import { OutputTypes } from './utils';

export interface ValueAccessor {
elementSelectors: string[];
Expand Down Expand Up @@ -54,30 +55,34 @@ export default async function generateValueAccessors(
const srcFilePath = path.join(__dirname, '../resources/control-value-accessors/', targetFileName);
const srcFileContents = await compilerCtx.fs.readFile(srcFilePath);

const finalText = createValueAccessor(srcFileContents, normalizedValueAccessors[valueAccessorType]);
const finalText = createValueAccessor(
srcFileContents,
normalizedValueAccessors[valueAccessorType],
outputTarget.outputType
);
await compilerCtx.fs.writeFile(targetFilePath, finalText);
})
);

await copyResources(config, ['value-accessor.ts'], targetDir);
}

export function createValueAccessor(srcFileContents: string, valueAccessor: ValueAccessor) {
export function createValueAccessor(srcFileContents: string, valueAccessor: ValueAccessor, outputType?: OutputType) {
const hostContents = valueAccessor.eventTargets.map((listItem) =>
VALUE_ACCESSOR_EVENTTARGETS.replace(VALUE_ACCESSOR_EVENT, listItem[0]).replace(
VALUE_ACCESSOR_TARGETATTR,
listItem[1]
)
);

return srcFileContents
.replace(VALUE_ACCESSOR_SELECTORS, valueAccessor.elementSelectors.join(', '))
.replace(VALUE_ACCESSOR_EVENTTARGETS, hostContents.join(`,${EOL}`));
.replace(VALUE_ACCESSOR_EVENTTARGETS, hostContents.join(`,${EOL}`))
.replace(VALUE_ACCESSOR_STANDALONE, outputType && outputType === OutputTypes.Standalone ? ',standalone: true' : '');
}

function copyResources(config: Config, resourcesFilesToCopy: string[], directory: string) {
if (!config.sys || !config.sys.copy) {
throw new Error('stencil is not properly intialized at this step. Notify the developer');
throw new Error('stencil is not properly initialized at this step. Notify the developer');
}
const copyTasks = resourcesFilesToCopy.map((rf) => {
return {
Expand All @@ -93,4 +98,5 @@ function copyResources(config: Config, resourcesFilesToCopy: string[], directory
const VALUE_ACCESSOR_SELECTORS = `<VALUE_ACCESSOR_SELECTORS>`;
const VALUE_ACCESSOR_EVENT = `<VALUE_ACCESSOR_EVENT>`;
const VALUE_ACCESSOR_TARGETATTR = '<VALUE_ACCESSOR_TARGETATTR>';
const VALUE_ACCESSOR_STANDALONE = '<VALUE_ACCESSOR_STANDALONE>';
const VALUE_ACCESSOR_EVENTTARGETS = ` '(<VALUE_ACCESSOR_EVENT>)': 'handleChangeEvent($event.target.<VALUE_ACCESSOR_TARGETATTR>)'`;

0 comments on commit b8930b0

Please sign in to comment.