generate-stubs.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. const fs = require("fs")
  2. const path = require("path")
  3. const { Project, SyntaxKind } = require("ts-morph")
  4. function traverse(container, output, prefix = "") {
  5. for (const node of container.getStatements()) {
  6. const kind = node.getKind()
  7. if (kind === SyntaxKind.ModuleDeclaration) {
  8. const name = node.getName().replace(/^['"]|['"]$/g, "")
  9. var fullPrefix
  10. if (prefix) {
  11. fullPrefix = `${prefix}.${name}`
  12. } else {
  13. fullPrefix = name
  14. }
  15. output.push(`${fullPrefix} = {};`)
  16. const body = node.getBody()
  17. if (body && body.getKind() === SyntaxKind.ModuleBlock) {
  18. traverse(body, output, fullPrefix)
  19. }
  20. } else if (kind === SyntaxKind.FunctionDeclaration) {
  21. const name = node.getName()
  22. const params = node.getParameters().map((p, i) => sanitizeParam(p.getName(), i))
  23. const typeNode = node.getReturnTypeNode()
  24. const returnType = typeNode ? typeNode.getText() : ""
  25. const ret = mapReturn(returnType)
  26. output.push(
  27. `${prefix}.${name} = function(${params.join(", ")}) { console.log('Called stubbed function: ${prefix}.${name}'); ${ret} };`,
  28. )
  29. } else if (kind === SyntaxKind.EnumDeclaration) {
  30. const name = node.getName()
  31. const members = node.getMembers().map((m) => m.getName())
  32. output.push(`${prefix}.${name} = { ${members.map((m) => `${m}: 0`).join(", ")} };`)
  33. } else if (kind === SyntaxKind.VariableStatement) {
  34. for (const decl of node.getDeclarations()) {
  35. const name = decl.getName()
  36. output.push(`${prefix}.${name} = createStub("${prefix}.${name}");`)
  37. }
  38. } else if (kind == SyntaxKind.ClassDeclaration) {
  39. const name = node.getName()
  40. output.push(
  41. `${prefix}.${name} = class { constructor(...args) {
  42. console.log('Constructed stubbed class: new ${prefix}.${name}(', args, ')');
  43. return createStub(${prefix}.${name});
  44. }};`,
  45. )
  46. } else if (kind === SyntaxKind.TypeAliasDeclaration || kind === SyntaxKind.InterfaceDeclaration) {
  47. //console.log("Skipping", SyntaxKind[kind], node.getName())
  48. // Skip interfaces and type aliases because they are only used at compile time by typescript.
  49. } else {
  50. console.log("Can't handle: ", SyntaxKind[kind])
  51. }
  52. }
  53. }
  54. function mapReturn(typeStr) {
  55. if (!typeStr) return ""
  56. if (typeStr.includes("void")) return ""
  57. if (typeStr.includes("string")) return `return '';`
  58. if (typeStr.includes("number")) return `return 0;`
  59. if (typeStr.includes("boolean")) return `return false;`
  60. if (typeStr.includes("[]")) return `return [];`
  61. if (typeStr.includes("Thenable")) return `return Promise.resolve(null);`
  62. return `return createStub("unknown");`
  63. }
  64. function sanitizeParam(name, index) {
  65. return name || `arg${index}`
  66. }
  67. async function main() {
  68. const inputPath = "node_modules/@types/vscode/index.d.ts"
  69. const outputPath = "standalone/runtime-files/vscode/vscode-stubs.js"
  70. const project = new Project()
  71. const sourceFile = project.addSourceFileAtPath(inputPath)
  72. const output = []
  73. output.push("// GENERATED CODE -- DO NOT EDIT!")
  74. output.push('console.log("Loading stubs...");')
  75. output.push('const { createStub } = require("./stub-utils")')
  76. traverse(sourceFile, output)
  77. output.push("module.exports = vscode;")
  78. output.push('console.log("Finished loading stubs");')
  79. fs.mkdirSync(path.dirname(outputPath), { recursive: true })
  80. fs.writeFileSync(outputPath, output.join("\n"))
  81. console.log(`Wrote vscode SDK stubs to ${outputPath}`)
  82. }
  83. main().catch((err) => {
  84. console.error(err)
  85. process.exit(1)
  86. })