Last active
June 6, 2018 09:00
-
-
Save abner/d3ded21a2c534b6061c3cdb1947f7fa5 to your computer and use it in GitHub Desktop.
typings-worker.js
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 worker resolves typings (.d.ts files) for the given list of dependencies. | |
self.importScripts([ | |
'https://cdnjs.cloudflare.com/ajax/libs/typescript/2.8.3/typescript.min.js' | |
]); | |
//const PACKAGES_SOURCE = 'https://unpkg.com'; | |
const PACKAGES_SOURCE = 'https://cdn.jsdelivr.net/npm' | |
const resolved = {}; | |
const downloaded = {}; | |
const loadContent = async url => { | |
try { | |
const existing = downloaded[url]; | |
if (existing) { | |
return existing; | |
} | |
const response = await fetch(url); | |
console.log(response.status, url); | |
if (response.status >= 200 && response.status < 300) { | |
const text = await response.text(); | |
downloaded[url] = text; | |
return text; | |
} | |
} catch (err) { | |
console.log('Error:', err); | |
} | |
return null; | |
}; | |
const getIndex = async lib => { | |
let packageUrl = `${PACKAGES_SOURCE}/${lib}/package.json`; | |
let content = await loadContent(packageUrl); | |
if (content) { | |
const json = JSON.parse(content); | |
if (json.typings) { | |
return new URL(json.typings, packageUrl).href; | |
} | |
packageUrl = `${PACKAGES_SOURCE}/${lib}/index.d.ts`; | |
content = await loadContent(packageUrl); | |
if (content) { | |
return new URL(packageUrl).href; | |
} | |
} | |
return null; | |
}; | |
const findReferences = sourceFile => { | |
const result = []; | |
if (sourceFile.referencedFiles.length > 0) { | |
result.push(...sourceFile.referencedFiles.map(ref => ref.fileName)); | |
} | |
function scanNode(node) { | |
if ( | |
node.kind === ts.SyntaxKind.ImportDeclaration || | |
node.kind === ts.SyntaxKind.ExportDeclaration | |
) { | |
if (node.moduleSpecifier && node.moduleSpecifier.text) { | |
result.push(node.moduleSpecifier.text); | |
} | |
} | |
ts.forEachChild(node, scanNode); | |
} | |
ts.forEachChild(sourceFile, scanNode); | |
return result; | |
}; | |
const resolveLibs = async (url, cache = {}) => { | |
if (cache[url]) { | |
return []; | |
} | |
cache[url] = true; | |
const result = []; | |
const content = await loadContent(url); | |
if (content) { | |
result.push({ | |
url: url, | |
path: url.replace(PACKAGES_SOURCE, 'node_modules') | |
}); | |
const sourceFile = ts.createSourceFile( | |
'main.ts', | |
content, | |
ts.ScriptTarget.Latest, | |
true, | |
ts.ScriptKind.TS | |
); | |
const references = findReferences(sourceFile); | |
const refLibs = await Promise.all(references.map(ref => { | |
const fileName = ref.endsWith('.d.ts') ? ref : `${ref}.d.ts`; | |
const fileUrl = new URL(fileName, url).href; | |
return resolveLibs(fileUrl, cache); | |
}); | |
if (refLibs && refLibs.length > 0) { | |
result.push(...refLibs); | |
} | |
} | |
return result; | |
}; | |
const getPackageTypings = async (lib, entryPoints) => { | |
const libUrl = `${PACKAGES_SOURCE}/${lib}`; | |
const existing = resolved[libUrl]; | |
if (existing) { | |
return existing.files || []; | |
} | |
const indexUrl = await getIndex(lib); | |
if (indexUrl) { | |
entryPoints[lib] = indexUrl.replace(PACKAGES_SOURCE, 'node_modules'); | |
const files = await resolveLibs(indexUrl); | |
resolved[libUrl] = { files }; | |
return files; | |
} | |
return []; | |
}; | |
self.addEventListener('message', async e => { | |
const { dependencies } = e.data; | |
if (dependencies && dependencies.length > 0) { | |
const entryPoints = {}; | |
const result = await Promise.all( | |
dependencies.map(libName => { | |
return getPackageTypings(libName, entryPoints); | |
}) | |
); | |
const files = result | |
.reduce((prev, curr) => prev.concat(curr), []) | |
.map(t => { | |
return { | |
...t, | |
content: downloaded[t.url] | |
}; | |
}); | |
self.postMessage({ | |
entryPoints: entryPoints, | |
files: files | |
}); | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment