diff --git a/packages/typescript-vfs/CHANGELOG.md b/packages/typescript-vfs/CHANGELOG.md index a527c87653ab..58f4590981e2 100644 --- a/packages/typescript-vfs/CHANGELOG.md +++ b/packages/typescript-vfs/CHANGELOG.md @@ -1,3 +1,8 @@ +### 1.5 + +- Makes `createDefaultMapFromNodeModules` pull all the `.d.ts` files from the node_modules folder, not just the `.d.ts` files which were known ahead of time. +- Updates the known .d.s files to include ones from TypeScript 5.1 beta. + ### 1.3 - Adds a JS file into the npm tarball for using with a vanilla script tag, which sets `global.tsvfs` with exported function. diff --git a/packages/typescript-vfs/src/index.ts b/packages/typescript-vfs/src/index.ts index 047ac676d3c5..e89ba2a57857 100755 --- a/packages/typescript-vfs/src/index.ts +++ b/packages/typescript-vfs/src/index.ts @@ -91,9 +91,13 @@ export function createVirtualTypeScriptEnvironment( } } +// TODO: This could be replaced by grabbing: https://github.com/microsoft/TypeScript/blob/main/src/lib/libs.json +// and then using that to generate the list of files from the server, but it is not included in the npm package + /** * Grab the list of lib files for a particular target, will return a bit more than necessary (by including - * the dom) but that's OK + * the dom) but that's OK, we're really working with the constraint that you can't get a list of files + * when running in a browser. * * @param target The compiler settings target baseline * @param ts A copy of the TypeScript module @@ -102,12 +106,18 @@ export const knownLibFilesForCompilerOptions = (compilerOptions: CompilerOptions const target = compilerOptions.target || ts.ScriptTarget.ES5 const lib = compilerOptions.lib || [] + // Note that this will include files which can't be found for particular versions of TS + // TODO: Replace this with some sort of API call if https://github.com/microsoft/TypeScript/pull/54011 + // or similar is merged. const files = [ "lib.d.ts", + "lib.decorators.d.ts", + "lib.decorators.legacy.d.ts", "lib.dom.d.ts", "lib.dom.iterable.d.ts", "lib.webworker.d.ts", "lib.webworker.importscripts.d.ts", + "lib.webworker.iterable.d.ts", "lib.scripthost.d.ts", "lib.es5.d.ts", "lib.es6.d.ts", @@ -125,6 +135,7 @@ export const knownLibFilesForCompilerOptions = (compilerOptions: CompilerOptions "lib.es2016.d.ts", "lib.es2016.full.d.ts", "lib.es2017.d.ts", + "lib.es2017.date.d.ts", "lib.es2017.full.d.ts", "lib.es2017.intl.d.ts", "lib.es2017.object.d.ts", @@ -141,28 +152,51 @@ export const knownLibFilesForCompilerOptions = (compilerOptions: CompilerOptions "lib.es2019.array.d.ts", "lib.es2019.d.ts", "lib.es2019.full.d.ts", + "lib.es2019.intl.d.ts", "lib.es2019.object.d.ts", "lib.es2019.string.d.ts", "lib.es2019.symbol.d.ts", + "lib.es2020.bigint.d.ts", "lib.es2020.d.ts", + "lib.es2020.date.d.ts", "lib.es2020.full.d.ts", - "lib.es2020.string.d.ts", - "lib.es2020.symbol.wellknown.d.ts", - "lib.es2020.bigint.d.ts", + "lib.es2020.intl.d.ts", + "lib.es2020.number.d.ts", "lib.es2020.promise.d.ts", "lib.es2020.sharedmemory.d.ts", - "lib.es2020.intl.d.ts", + "lib.es2020.string.d.ts", + "lib.es2020.symbol.wellknown.d.ts", "lib.es2021.d.ts", "lib.es2021.full.d.ts", + "lib.es2021.intl.d.ts", "lib.es2021.promise.d.ts", "lib.es2021.string.d.ts", "lib.es2021.weakref.d.ts", + "lib.es2022.array.d.ts", + "lib.es2022.d.ts", + "lib.es2022.error.d.ts", + "lib.es2022.full.d.ts", + "lib.es2022.intl.d.ts", + "lib.es2022.object.d.ts", + "lib.es2022.regexp.d.ts", + "lib.es2022.sharedmemory.d.ts", + "lib.es2022.string.d.ts", + "lib.es2023.array.d.ts", + "lib.es2023.collection.d.ts", + "lib.es2023.d.ts", + "lib.es2023.full.d.ts", + "lib.esnext.array.d.ts", + "lib.esnext.asynciterable.d.ts", + "lib.esnext.bigint.d.ts", "lib.esnext.d.ts", + "lib.esnext.decorators.d.ts", + "lib.esnext.disposable.d.ts", "lib.esnext.full.d.ts", "lib.esnext.intl.d.ts", "lib.esnext.promise.d.ts", "lib.esnext.string.d.ts", - "lib.esnext.weakref.d.ts", + "lib.esnext.symbol.d.ts", + "lib.esnext.weakref.d.ts" ] const targetToCut = ts.ScriptTarget[target] @@ -190,9 +224,15 @@ export const knownLibFilesForCompilerOptions = (compilerOptions: CompilerOptions /** * Sets up a Map with lib contents by grabbing the necessary files from * the local copy of typescript via the file system. + * + * The first two args are un-used, but kept around so as to not cause a + * semver major bump for no gain to module users. */ -export const createDefaultMapFromNodeModules = (compilerOptions: CompilerOptions, ts?: typeof import("typescript"), tsLibDirectory?: string) => { - const tsModule = ts || require("typescript") +export const createDefaultMapFromNodeModules = ( + _compilerOptions: CompilerOptions, + _ts?: typeof import("typescript"), + tsLibDirectory?: string +) => { const path = requirePath() const fs = requireFS() @@ -201,9 +241,11 @@ export const createDefaultMapFromNodeModules = (compilerOptions: CompilerOptions return fs.readFileSync(path.join(lib, name), "utf8") } - const libs = knownLibFilesForCompilerOptions(compilerOptions, tsModule) + const libFiles = fs.readdirSync(tsLibDirectory || path.dirname(require.resolve("typescript"))) + const knownLibFiles = libFiles.filter(f => f.startsWith("lib.") && f.endsWith(".d.ts")) + const fsMap = new Map() - libs.forEach(lib => { + knownLibFiles.forEach(lib => { fsMap.set("/" + lib, getLib(lib)) }) return fsMap @@ -286,9 +328,14 @@ export const createDefaultMapFromCDN = ( // Map the known libs to a node fetch promise, then return the contents function uncached() { - return Promise.all(files.map(lib => fetchlike(prefix + lib).then(resp => resp.text()))).then(contents => { - contents.forEach((text, index) => fsMap.set("/" + files[index], text)) - }) + return ( + Promise.all(files.map(lib => fetchlike(prefix + lib).then(resp => resp.text()))) + .then(contents => { + contents.forEach((text, index) => fsMap.set("/" + files[index], text)) + }) + // Return a NOOP for .d.ts files which aren't in the current build of TypeScript + .catch(() => { }) + ) } // A localstorage and lzzip aware version of the lib files @@ -310,20 +357,26 @@ export const createDefaultMapFromCDN = ( if (!content) { // Make the API call and store the text concent in the cache - return fetchlike(prefix + lib) - .then(resp => resp.text()) - .then(t => { - storelike.setItem(cacheKey, zip(t)) - return t - }) + return ( + fetchlike(prefix + lib) + .then(resp => resp.text()) + .then(t => { + storelike.setItem(cacheKey, zip(t)) + return t + }) + // Return a NOOP for .d.ts files which aren't in the current build of TypeScript + .catch(() => { }) + ) } else { return Promise.resolve(unzip(content)) } }) ).then(contents => { contents.forEach((text, index) => { - const name = "/" + files[index] - fsMap.set(name, text) + if (text) { + const name = "/" + files[index] + fsMap.set(name, text) + } }) }) } @@ -403,7 +456,12 @@ export function createSystem(files: Map): System { * a set of virtual files which are prioritised over the FS versions, then a path to the root of your * project (basically the folder your node_modules lives) */ -export function createFSBackedSystem(files: Map, _projectRoot: string, ts: TS, tsLibDirectory?: string): System { +export function createFSBackedSystem( + files: Map, + _projectRoot: string, + ts: TS, + tsLibDirectory?: string +): System { // We need to make an isolated folder for the tsconfig, but also need to be able to resolve the // existing node_modules structures going back through the history const root = _projectRoot + "/vfs" diff --git a/packages/typescript-vfs/test/index.test.ts b/packages/typescript-vfs/test/index.test.ts index 92147e52e809..e526272040c1 100644 --- a/packages/typescript-vfs/test/index.test.ts +++ b/packages/typescript-vfs/test/index.test.ts @@ -209,3 +209,8 @@ it("throws when you request a lib file which isn't in the fsMap", () => { expect(t).toThrow() }) + +it("grabs lib dts files from node_modules", async () => { + const fsMap = createDefaultMapFromNodeModules({}) + expect(fsMap.get("/lib.es2015.collection.d.ts")).toBeDefined() +})