-
Notifications
You must be signed in to change notification settings - Fork 245
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(jsii): incorrect symbol-id generated with typesVersions (#4037)
When using types sourced from redirected declarations files (using `typesVersions`), the `symbolId` generated for type lookups incorrectly refers to the redirected path instead of the canonical one. This adds code to reverse the `typesVersions` mapping to get back to the original and canonical path. --- By submitting this pull request, I confirm that my contribution is made under the terms of the [Apache 2.0 license]. [Apache 2.0 license]: https://www.apache.org/licenses/LICENSE-2.0
- Loading branch information
1 parent
d2ecb6d
commit 1f06ac9
Showing
4 changed files
with
186 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import * as semver from 'semver'; | ||
import * as ts from 'typescript'; | ||
|
||
export interface TypesVersions { | ||
readonly [range: string]: { | ||
readonly [glob: string]: readonly string[]; | ||
}; | ||
} | ||
|
||
export function undoTypesVersionsRedirect( | ||
sourcePath: string, | ||
typesVersionsMap: TypesVersions | undefined, | ||
): string { | ||
if (typesVersionsMap == null) { | ||
return sourcePath; | ||
} | ||
|
||
const [_, typesVersions] = | ||
Object.entries(typesVersionsMap).find(([range, _]) => | ||
semver.satisfies(ts.version, range), | ||
) ?? []; | ||
|
||
if (typesVersions == null) { | ||
return sourcePath; | ||
} | ||
|
||
for (const [orig, candidates] of Object.entries(typesVersions)) { | ||
const [found] = candidates.flatMap((candidate) => { | ||
const [before, after, ...rest] = candidate.split('*'); | ||
// There can be only 1 "*" in a typesVersions pattern. | ||
if (rest.length > 0) { | ||
return []; | ||
} | ||
if (sourcePath.startsWith(before) && sourcePath.endsWith(after)) { | ||
return [ | ||
{ | ||
before, | ||
after, | ||
length: before.length + after.length, | ||
}, | ||
]; | ||
} | ||
|
||
return []; | ||
}); | ||
|
||
if (found == null) { | ||
continue; | ||
} | ||
|
||
const [before, after, ...rest] = orig.split('*'); | ||
// There can be only 1 "*" in a typesVersions pattern. | ||
if (rest.length > 0) { | ||
continue; | ||
} | ||
|
||
// Remove the typesVersion prefix & suffix | ||
const globbed = sourcePath.slice( | ||
found.before.length, | ||
sourcePath.length - found.after.length, | ||
); | ||
// Add the original prefix & suffix | ||
return `${before}${globbed}${after}`; | ||
} | ||
|
||
// No match found... | ||
return sourcePath; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import { undoTypesVersionsRedirect } from '../lib/types-versions'; | ||
|
||
test('no configuration', () => { | ||
expect(undoTypesVersionsRedirect('test/path/index.ts', undefined)).toBe( | ||
'test/path/index.ts', | ||
); | ||
}); | ||
|
||
test('no candidate matches', () => { | ||
expect( | ||
undoTypesVersionsRedirect('test/path/index.ts', { | ||
'*': { '*': ['.types-versions/ts3.9/*'] }, | ||
}), | ||
).toBe('test/path/index.ts'); | ||
}); | ||
|
||
test('incompatible-typescript-version', () => { | ||
expect( | ||
undoTypesVersionsRedirect('test/path/index.ts', { | ||
'>99.99.99': { | ||
'*': ['test/*'], | ||
}, | ||
}), | ||
).toBe('test/path/index.ts'); | ||
}); | ||
|
||
test('simple match', () => { | ||
expect( | ||
undoTypesVersionsRedirect('test/path/index.ts', { | ||
'*': { | ||
'*': ['test/*/index.ts'], | ||
}, | ||
}), | ||
).toBe('path'); | ||
}); | ||
|
||
test('multiple typeScript versions (first one wins)', () => { | ||
expect( | ||
undoTypesVersionsRedirect('test/path/index.ts', { | ||
'>=0': { | ||
'*': ['test/*/index.ts'], | ||
}, | ||
'*': { | ||
'before/*/after.ts': ['test/*/index.ts'], | ||
}, | ||
}), | ||
).toBe('path'); | ||
}); | ||
|
||
test('prefix+suffix match', () => { | ||
expect( | ||
undoTypesVersionsRedirect('test/path/index.ts', { | ||
'*': { | ||
'before/*/after.ts': ['test/*/index.ts'], | ||
}, | ||
}), | ||
).toBe('before/path/after.ts'); | ||
}); | ||
|
||
test('multiple candidates (first match wins)', () => { | ||
expect( | ||
undoTypesVersionsRedirect('test/path/index.ts', { | ||
'*': { | ||
'before/*/after.ts': ['*/path/index.ts', 'test/*/index.ts'], | ||
}, | ||
}), | ||
).toBe('before/test/after.ts'); | ||
}); |