Skip to content

Commit

Permalink
feat(compiler): export custom types in compiled output (#3710)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
tanner-reits committed Oct 12, 2022
1 parent 0510344 commit e52489e
Show file tree
Hide file tree
Showing 9 changed files with 1,246 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ const generateCustomElementsTypesOutput = async (
// entities exported there, we will re-export the typedefs iff
// the `customElementsExportBehavior` is set to barrel component exports
if (isBarrelExport) {
// If there is an `index.ts` file in the src directory, we'll re-export anything
// exported from that file
// Otherwise, we'll export everything from the auto-generated `components.d.ts`
// file in the output directory
const usersIndexJsPath = join(config.srcDir, 'index.ts');
const hasUserIndex = await compilerCtx.fs.access(usersIndexJsPath);
if (hasUserIndex) {
Expand Down
6 changes: 3 additions & 3 deletions src/compiler/sys/stencil-sys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,12 +289,12 @@ export const createSystem = (c?: { logger?: Logger }) => {
error: null,
};

remoreDirSyncRecursive(p, opts, results);
removeDirSyncRecursive(p, opts, results);

return results;
};

const remoreDirSyncRecursive = (
const removeDirSyncRecursive = (
p: string,
opts: CompilerSystemRemoveDirectoryOptions,
results: CompilerSystemRemoveDirectoryResults
Expand All @@ -309,7 +309,7 @@ export const createSystem = (c?: { logger?: Logger }) => {
const item = items.get(dirItemPath);
if (item) {
if (item.isDirectory) {
remoreDirSyncRecursive(dirItemPath, opts, results);
removeDirSyncRecursive(dirItemPath, opts, results);
} else if (item.isFile) {
const removeFileResults = removeFileSync(dirItemPath);
if (removeFileResults.error) {
Expand Down
1 change: 1 addition & 0 deletions src/compiler/transformers/test/parse-events.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ describe('parse events', () => {
references: {
Mode: {
location: 'local',
path: 'module.tsx',
},
},
});
Expand Down
9 changes: 9 additions & 0 deletions src/compiler/transformers/transform-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,15 @@ const getTypeReferenceLocation = (typeName: string, tsNode: ts.Node): d.Componen
if (isExported) {
return {
location: 'local',
// If this is a local import, we know the path to the type
// is the same as the current source file path
//
// We need to explicitly include the path here because
// future logic for generating app types will use this resolved reference
// to ensure that type name collisions do no occur in the output type
// declaration file. If this path is omitted, the correct aliased type names
// will not be used for component event definitions
path: sourceFileObj.fileName,
};
}

Expand Down
1 change: 1 addition & 0 deletions src/compiler/transpile/run-program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export const runTsProgram = async (
// Finalize components metadata
buildCtx.moduleFiles = Array.from(compilerCtx.moduleMap.values());
buildCtx.components = getComponentsFromModules(buildCtx.moduleFiles);

updateComponentBuildConditionals(compilerCtx.moduleMap, buildCtx.components);
resolveComponentDependencies(buildCtx.components);

Expand Down
51 changes: 26 additions & 25 deletions src/compiler/types/generate-app-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { updateReferenceTypeImports } from './update-import-refs';
* @returns `true` if the type declaration file written to disk has changed, `false` otherwise
*/
export const generateAppTypes = async (
config: d.Config,
config: d.ValidatedConfig,
compilerCtx: d.CompilerCtx,
buildCtx: d.BuildCtx,
destination: string
Expand All @@ -44,7 +44,7 @@ export const generateAppTypes = async (
);
}

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

// write the import statements for our type declaration file
c.push(
...Object.keys(typeImportData).map((filePath) => {
const typeData = typeImportData[filePath];
let importFilePath: string;
if (isAbsolute(filePath)) {
importFilePath = normalizePath('./' + relative(config.srcDir, filePath)).replace(/\.(tsx|ts)$/, '');
} else {
importFilePath = filePath;
}

return `import { ${typeData
.sort(sortImportNames)
.map((td) => {
if (td.localName === td.importName) {
return `${td.importName}`;
} else {
return `${td.localName} as ${td.importName}`;
}
})
.join(`, `)} } from "${importFilePath}";`;
})
);
// Map event type metadata to partial expressions (omitting import/export keywords)
// e.g. { TestEvent } from '../path/to/event/test-event.interface';
const expressions = Object.keys(typeImportData).map((filePath) => {
const typeData = typeImportData[filePath];

let importFilePath = filePath;
if (isAbsolute(filePath)) {
importFilePath = normalizePath('./' + relative(config.srcDir, filePath)).replace(/\.(tsx|ts)$/, '');
}

return `{ ${typeData
.sort(sortImportNames)
.map((td) => {
if (td.localName === td.importName) {
return `${td.importName}`;
} else {
return `${td.localName} as ${td.importName}`;
}
})
.join(`, `)} } from "${importFilePath}";`;
});

// Write all import and export statements for event types
c.push(...expressions.map((ref) => `import ${ref}`), ...expressions.map((ref) => `export ${ref}`));

c.push(`export namespace Components {`);
c.push(...modules.map((m) => `${m.component}`));
Expand Down
Loading

0 comments on commit e52489e

Please sign in to comment.