|
1 | 1 | import type * as d from '../../declarations';
|
2 |
| -import { dirname, join, relative } from 'path'; |
| 2 | +import { dirname, join, relative, resolve } from 'path'; |
3 | 3 | import { isOutputTargetDistTypes } from '../output-targets/output-utils';
|
4 | 4 | import { normalizePath } from '@utils';
|
5 | 5 |
|
@@ -30,6 +30,81 @@ export const updateStencilTypesImports = (typesDir: string, dtsFilePath: string,
|
30 | 30 | return dtsContent;
|
31 | 31 | };
|
32 | 32 |
|
| 33 | +/** |
| 34 | + * Utility for ensuring that naming collisions do not appear in type declaration files for a component's class members |
| 35 | + * decorated with @Prop, @Event, and @Method |
| 36 | + * @param typeReferences all type names used by a component class member |
| 37 | + * @param typeImportData locally/imported/globally used type names, which may be used to prevent naming collisions |
| 38 | + * @param sourceFilePath the path to the source file of a component using the type being inspected |
| 39 | + * @param initialType the name of the type that may be updated |
| 40 | + * @returns the updated type name, which may be the same as the initial type name provided as an argument to this |
| 41 | + * function |
| 42 | + */ |
| 43 | +export const updateTypeIdentifierNames = ( |
| 44 | + typeReferences: d.ComponentCompilerTypeReferences, |
| 45 | + typeImportData: d.TypesImportData, |
| 46 | + sourceFilePath: string, |
| 47 | + initialType: string |
| 48 | +): string => { |
| 49 | + let currentTypeName = initialType; |
| 50 | + |
| 51 | + // iterate over each of the type references, as there may be >1 reference to inspect |
| 52 | + for (let typeReference of Object.values(typeReferences)) { |
| 53 | + const importResolvedFile = getTypeImportPath(typeReference.path, sourceFilePath); |
| 54 | + |
| 55 | + if (!typeImportData.hasOwnProperty(importResolvedFile)) { |
| 56 | + continue; |
| 57 | + } |
| 58 | + |
| 59 | + for (let typesImportDatumElement of typeImportData[importResolvedFile]) { |
| 60 | + currentTypeName = updateTypeName(currentTypeName, typesImportDatumElement); |
| 61 | + } |
| 62 | + } |
| 63 | + return currentTypeName; |
| 64 | +}; |
| 65 | + |
| 66 | +/** |
| 67 | + * Determine the path of a given type reference, relative to the path of a source file |
| 68 | + * @param importResolvedFile the path to the file containing the resolve type. may be absolute or relative |
| 69 | + * @param sourceFilePath the component source file path to resolve against |
| 70 | + * @returns the path of the type import |
| 71 | + */ |
| 72 | +const getTypeImportPath = (importResolvedFile: string | undefined, sourceFilePath: string): string => { |
| 73 | + const isPathRelative = importResolvedFile && importResolvedFile.startsWith('.'); |
| 74 | + if (isPathRelative) { |
| 75 | + importResolvedFile = resolve(dirname(sourceFilePath), importResolvedFile); |
| 76 | + } |
| 77 | + |
| 78 | + return importResolvedFile; |
| 79 | +}; |
| 80 | + |
| 81 | +/** |
| 82 | + * Determine whether the string representation of a type should be replaced with an alias |
| 83 | + * @param currentTypeName the current string representation of a type |
| 84 | + * @param typeAlias a type member and a potential different name associated with the type member |
| 85 | + * @returns the updated string representation of a type. If the type is not updated, the original type name is returned |
| 86 | + */ |
| 87 | +const updateTypeName = (currentTypeName: string, typeAlias: d.TypesMemberNameData): string => { |
| 88 | + if (!typeAlias.importName) { |
| 89 | + return currentTypeName; |
| 90 | + } |
| 91 | + |
| 92 | + // TODO(STENCIL-419): Update this functionality to no longer use a regex |
| 93 | + // negative lookahead specifying that quotes that designate a string in JavaScript cannot follow some expression |
| 94 | + const endingStrChar = '(?!("|\'|`))'; |
| 95 | + /** |
| 96 | + * A regular expression that looks at type names along a [word boundary](https://www.regular-expressions.info/wordboundaries.html). |
| 97 | + * This is used as the best approximation for replacing type collisions, as this stage of compilation has only |
| 98 | + * 'flattened' type information in the form of a String. |
| 99 | + * |
| 100 | + * This regex should be expected to capture types that are found in generics, unions, intersections, etc., but not |
| 101 | + * those in string literals. We do not check for a starting quote (" | ' | `) here as some browsers do not support |
| 102 | + * negative lookbehind. This works "well enough" until STENCIL-419 is completed. |
| 103 | + */ |
| 104 | + const typeNameRegex = new RegExp(`${typeAlias.localName}\\b${endingStrChar}`, 'g'); |
| 105 | + return currentTypeName.replace(typeNameRegex, typeAlias.importName); |
| 106 | +}; |
| 107 | + |
33 | 108 | /**
|
34 | 109 | * Writes Stencil core typings file to disk for a dist-* output target
|
35 | 110 | * @param config the Stencil configuration associated with the project being compiled
|
|
0 commit comments