Skip to content

Commit e52489e

Browse files
authored
feat(compiler): export custom types in compiled output (#3710)
NOTE: This was originally introduced as a feature in Stencil 2.x, but was reverted when a breaking change was identified. Initial PR (orginally merged as a part of Stencil 2.x): #3612 Reversion of above PR (due to identified breaking change): #3708 * misc(compiler): fix typos in stencil-sys * fix(compiler): export custom event types from type declaration file This commit updates the generated `components.d.ts` file in the types directory to re-export any types used by Stencil component custom events * tests(compiler): fix path normalization for `generateAppTypes` * misc(): test-app type declarations * fix(compiler): custom event "paths" for local type definitions This commit adds logic for setting the `path` property on custom event type references in the output static event metadata for Stencil `Event()` properties * misc(): PR cleanup/feedback * test(complier): more use cases for `generateAppTypes` * test(compiler): split & add custom prop/event tests for generateAppTypes * test(compiler): use absolute paths for type references * refactor(compiler): move setting `path` on static event metadata This commit moves the setting of the `path` property on custom type references for `local` imports to the transformation function that defines the static metadata rather than this operation occurring after the transformation. Essentially, the property gets set at a higher level
1 parent 0510344 commit e52489e

File tree

9 files changed

+1246
-28
lines changed

9 files changed

+1246
-28
lines changed

src/compiler/output-targets/dist-custom-elements/custom-elements-types.ts

+4
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,10 @@ const generateCustomElementsTypesOutput = async (
105105
// entities exported there, we will re-export the typedefs iff
106106
// the `customElementsExportBehavior` is set to barrel component exports
107107
if (isBarrelExport) {
108+
// If there is an `index.ts` file in the src directory, we'll re-export anything
109+
// exported from that file
110+
// Otherwise, we'll export everything from the auto-generated `components.d.ts`
111+
// file in the output directory
108112
const usersIndexJsPath = join(config.srcDir, 'index.ts');
109113
const hasUserIndex = await compilerCtx.fs.access(usersIndexJsPath);
110114
if (hasUserIndex) {

src/compiler/sys/stencil-sys.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -289,12 +289,12 @@ export const createSystem = (c?: { logger?: Logger }) => {
289289
error: null,
290290
};
291291

292-
remoreDirSyncRecursive(p, opts, results);
292+
removeDirSyncRecursive(p, opts, results);
293293

294294
return results;
295295
};
296296

297-
const remoreDirSyncRecursive = (
297+
const removeDirSyncRecursive = (
298298
p: string,
299299
opts: CompilerSystemRemoveDirectoryOptions,
300300
results: CompilerSystemRemoveDirectoryResults
@@ -309,7 +309,7 @@ export const createSystem = (c?: { logger?: Logger }) => {
309309
const item = items.get(dirItemPath);
310310
if (item) {
311311
if (item.isDirectory) {
312-
remoreDirSyncRecursive(dirItemPath, opts, results);
312+
removeDirSyncRecursive(dirItemPath, opts, results);
313313
} else if (item.isFile) {
314314
const removeFileResults = removeFileSync(dirItemPath);
315315
if (removeFileResults.error) {

src/compiler/transformers/test/parse-events.spec.ts

+1
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ describe('parse events', () => {
105105
references: {
106106
Mode: {
107107
location: 'local',
108+
path: 'module.tsx',
108109
},
109110
},
110111
});

src/compiler/transformers/transform-utils.ts

+9
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,15 @@ const getTypeReferenceLocation = (typeName: string, tsNode: ts.Node): d.Componen
492492
if (isExported) {
493493
return {
494494
location: 'local',
495+
// If this is a local import, we know the path to the type
496+
// is the same as the current source file path
497+
//
498+
// We need to explicitly include the path here because
499+
// future logic for generating app types will use this resolved reference
500+
// to ensure that type name collisions do no occur in the output type
501+
// declaration file. If this path is omitted, the correct aliased type names
502+
// will not be used for component event definitions
503+
path: sourceFileObj.fileName,
495504
};
496505
}
497506

src/compiler/transpile/run-program.ts

+1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ export const runTsProgram = async (
6161
// Finalize components metadata
6262
buildCtx.moduleFiles = Array.from(compilerCtx.moduleMap.values());
6363
buildCtx.components = getComponentsFromModules(buildCtx.moduleFiles);
64+
6465
updateComponentBuildConditionals(compilerCtx.moduleMap, buildCtx.components);
6566
resolveComponentDependencies(buildCtx.components);
6667

src/compiler/types/generate-app-types.ts

+26-25
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { updateReferenceTypeImports } from './update-import-refs';
1919
* @returns `true` if the type declaration file written to disk has changed, `false` otherwise
2020
*/
2121
export const generateAppTypes = async (
22-
config: d.Config,
22+
config: d.ValidatedConfig,
2323
compilerCtx: d.CompilerCtx,
2424
buildCtx: d.BuildCtx,
2525
destination: string
@@ -44,7 +44,7 @@ export const generateAppTypes = async (
4444
);
4545
}
4646

47-
const writeResults = await compilerCtx.fs.writeFile(componentsDtsFilePath, componentTypesFileContent, {
47+
const writeResults = await compilerCtx.fs.writeFile(normalizePath(componentsDtsFilePath), componentTypesFileContent, {
4848
immediateWrite: true,
4949
});
5050
const hasComponentsDtsChanged = writeResults.changedContent;
@@ -92,29 +92,30 @@ const generateComponentTypesFile = (config: d.Config, buildCtx: d.BuildCtx, areT
9292
c.push(COMPONENTS_DTS_HEADER);
9393
c.push(`import { HTMLStencilElement, JSXBase } from "@stencil/core/internal";`);
9494

95-
// write the import statements for our type declaration file
96-
c.push(
97-
...Object.keys(typeImportData).map((filePath) => {
98-
const typeData = typeImportData[filePath];
99-
let importFilePath: string;
100-
if (isAbsolute(filePath)) {
101-
importFilePath = normalizePath('./' + relative(config.srcDir, filePath)).replace(/\.(tsx|ts)$/, '');
102-
} else {
103-
importFilePath = filePath;
104-
}
105-
106-
return `import { ${typeData
107-
.sort(sortImportNames)
108-
.map((td) => {
109-
if (td.localName === td.importName) {
110-
return `${td.importName}`;
111-
} else {
112-
return `${td.localName} as ${td.importName}`;
113-
}
114-
})
115-
.join(`, `)} } from "${importFilePath}";`;
116-
})
117-
);
95+
// Map event type metadata to partial expressions (omitting import/export keywords)
96+
// e.g. { TestEvent } from '../path/to/event/test-event.interface';
97+
const expressions = Object.keys(typeImportData).map((filePath) => {
98+
const typeData = typeImportData[filePath];
99+
100+
let importFilePath = filePath;
101+
if (isAbsolute(filePath)) {
102+
importFilePath = normalizePath('./' + relative(config.srcDir, filePath)).replace(/\.(tsx|ts)$/, '');
103+
}
104+
105+
return `{ ${typeData
106+
.sort(sortImportNames)
107+
.map((td) => {
108+
if (td.localName === td.importName) {
109+
return `${td.importName}`;
110+
} else {
111+
return `${td.localName} as ${td.importName}`;
112+
}
113+
})
114+
.join(`, `)} } from "${importFilePath}";`;
115+
});
116+
117+
// Write all import and export statements for event types
118+
c.push(...expressions.map((ref) => `import ${ref}`), ...expressions.map((ref) => `export ${ref}`));
118119

119120
c.push(`export namespace Components {`);
120121
c.push(...modules.map((m) => `${m.component}`));

0 commit comments

Comments
 (0)