"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }// src/ts.ts var _promises = require('fs/promises'); var _fs = require('fs'); var _path = require('path'); var _path2 = _interopRequireDefault(_path); var _common = require('@vue-macros/common'); var _types = require('@babel/types'); var tsFileCache = {}; async function getTSFile(filePath) { if (tsFileCache[filePath]) return tsFileCache[filePath]; const content = await _promises.readFile.call(void 0, filePath, "utf-8"); const { code, lang } = _common.getFileCodeAndLang.call(void 0, content, filePath); const program = _common.babelParse.call(void 0, code, lang); return tsFileCache[filePath] = { filePath, content, ast: program.body }; } function isTSDeclaration(node) { return _types.isDeclaration.call(void 0, node) && node.type.startsWith("TS"); } function mergeTSProperties(a, b) { return { callSignatures: [...a.callSignatures, ...b.callSignatures], constructSignatures: [...a.constructSignatures, ...b.constructSignatures], methods: { ...a.methods, ...b.methods }, properties: { ...a.properties, ...b.properties } }; } async function resolveTSProperties({ type, scope }) { switch (type.type) { case "TSInterfaceBody": return resolveTypeElements(scope, type.body); case "TSTypeLiteral": return resolveTypeElements(scope, type.members); case "TSInterfaceDeclaration": { let properties = resolveTypeElements(scope, type.body.body); if (type.extends) { const resolvedExtends = (await Promise.all( type.extends.map( (node) => node.expression.type === "Identifier" ? resolveTSReferencedType({ scope, type: node.expression }) : void 0 ) )).filter(filterValidExtends); if (resolvedExtends.length > 0) { const ext = (await Promise.all( resolvedExtends.map((resolved) => resolveTSProperties(resolved)) )).reduceRight((acc, curr) => mergeTSProperties(acc, curr)); properties = mergeTSProperties(ext, properties); } } return properties; } case "TSIntersectionType": { let properties = { callSignatures: [], constructSignatures: [], methods: {}, properties: {} }; for (const subType of type.types) { const resolved = await resolveTSReferencedType({ scope, type: subType }); if (!filterValidExtends(resolved)) continue; properties = mergeTSProperties( properties, await resolveTSProperties(resolved) ); } return properties; } case "TSMappedType": { const properties = { callSignatures: [], constructSignatures: [], methods: {}, properties: {} }; if (!type.typeParameter.constraint) return properties; const constraint = await resolveTSReferencedType({ type: type.typeParameter.constraint, scope }); if (!(constraint == null ? void 0 : constraint.type)) return properties; const types = constraint.type.type === "TSUnionType" ? constraint.type.types : [constraint.type]; for (const subType of types) { if (subType.type !== "TSLiteralType") continue; const literal = subType.literal; if (!_common.isStaticExpression.call(void 0, literal)) continue; const key = _common.resolveLiteral.call(void 0, literal ); if (!key) continue; properties.properties[String(key)] = { value: type.typeAnnotation ? { scope, type: type.typeAnnotation } : null, optional: type.optional === "+" || type.optional === true, signature: { type, scope } }; } return properties; } case "TSFunctionType": { const properties = { callSignatures: [{ type, scope }], constructSignatures: [], methods: {}, properties: {} }; return properties; } default: throw new Error(`unknown node: ${type == null ? void 0 : type.type}`); } function filterValidExtends(node) { return !isTSExports(node) && [ "TSInterfaceDeclaration", "TSTypeLiteral", "TSIntersectionType" ].includes(node == null ? void 0 : node.type.type); } } function resolveTypeElements(scope, elements) { var _a; const properties = { callSignatures: [], constructSignatures: [], methods: {}, properties: {} }; const tryGetKey = (element) => { try { return _common.resolveObjectKey.call(void 0, element.key, element.computed, false); } catch (e) { } }; for (const element of elements) { switch (element.type) { case "TSCallSignatureDeclaration": properties.callSignatures.push({ scope, type: element }); break; case "TSConstructSignatureDeclaration": properties.constructSignatures.push({ scope, type: element }); break; case "TSMethodSignature": { const key = tryGetKey(element); if (!key) continue; if (properties.properties[key]) continue; if (!properties.methods[key]) properties.methods[key] = []; if (element.typeAnnotation) { properties.methods[key].push({ scope, type: element }); } break; } case "TSPropertySignature": { const key = tryGetKey(element); if (!key) continue; if (!properties.properties[key] && !properties.methods[key]) { const type = (_a = element.typeAnnotation) == null ? void 0 : _a.typeAnnotation; properties.properties[key] = { value: type ? { type, scope } : null, optional: !!element.optional, signature: { type: element, scope } }; } break; } case "TSIndexSignature": break; } } return properties; } async function resolveTSReferencedType(ref, stacks = []) { var _a; const { scope, type } = ref; if (stacks.some((stack) => stack.scope === scope && stack.type === type)) { return ref; } stacks.push(ref); if (type.type === "TSTypeAliasDeclaration" || type.type === "TSParenthesizedType") { return resolveTSReferencedType({ scope, type: type.typeAnnotation }, stacks); } let refNames; if (type.type === "Identifier") { refNames = [type.name]; } else if (type.type === "TSTypeReference") { if (type.typeName.type === "Identifier") { refNames = [type.typeName.name]; } else { refNames = resolveTSEntityName(type.typeName).map((id) => id.name); } } else if (type.type === "TSModuleDeclaration" && type.body.type === "TSModuleBlock") { return resolveTSExports({ type: type.body, scope }); } else { return { scope, type }; } const [refName, ...restNames] = refNames; const { body, file } = resolveTSScope(scope); for (let node of body) { if (node.type === "ImportDeclaration") { const specifier = node.specifiers.find( (specifier2) => specifier2.type === "ImportSpecifier" && specifier2.imported.type === "Identifier" && specifier2.imported.name === refName || specifier2.type === "ImportNamespaceSpecifier" && specifier2.local.name === refName ); if (!specifier) continue; const resolved = await resolveTSFileId(node.source.value, file.filePath); if (!resolved) continue; const exports = await resolveTSExports(await getTSFile(resolved)); let type2 = exports; for (const name of specifier.type === "ImportSpecifier" ? refNames : restNames) { type2 = type2 == null ? void 0 : type2[name]; } return type2; } if (node.type === "ExportNamedDeclaration" && node.declaration) node = node.declaration; if (isTSDeclaration(node)) { if (((_a = node.id) == null ? void 0 : _a.type) !== "Identifier") continue; if (node.id.name !== refName) continue; const resolved = await resolveTSReferencedType( { scope, type: node }, stacks ); if (!resolved) return; if (restNames.length === 0) { return resolved; } else { let exports = resolved; for (const name of restNames) { exports = exports[name]; } return exports; } } } if (type.type === "TSTypeReference") return { scope, type }; } function resolveTSScope(scope) { const isFile = "ast" in scope; const file = isFile ? scope : resolveTSScope(scope.scope).file; const body = isFile ? scope.ast : scope.type.body; return { isFile, file, body }; } function resolveTSEntityName(node) { if (node.type === "Identifier") return [node]; else { return [...resolveTSEntityName(node.left), node.right]; } } var exportsSymbol = Symbol("exports"); var tsFileExportsCache = /* @__PURE__ */ new Map(); function isTSExports(val) { return !!val && typeof val === "object" && exportsSymbol in val; } async function resolveTSExports(scope) { var _a; if (tsFileExportsCache.has(scope)) return tsFileExportsCache.get(scope); const exports = { [exportsSymbol]: true }; tsFileExportsCache.set(scope, exports); const { body, file } = resolveTSScope(scope); for (const stmt of body) { if (stmt.type === "ExportDefaultDeclaration") { } else if (stmt.type === "ExportAllDeclaration") { const resolved = await resolveTSFileId(stmt.source.value, file.filePath); if (!resolved) continue; const sourceExports = await resolveTSExports(await getTSFile(resolved)); Object.assign(exports, sourceExports); } else if (stmt.type === "ExportNamedDeclaration") { let sourceExports; if (stmt.source) { const resolved = await resolveTSFileId(stmt.source.value, file.filePath); if (!resolved) continue; sourceExports = await resolveTSExports(await getTSFile(resolved)); } for (const specifier of stmt.specifiers) { if (specifier.type === "ExportDefaultSpecifier") { continue; } if (specifier.type === "ExportNamespaceSpecifier") { exports[specifier.exported.name] = sourceExports; } else { const exportedName = specifier.exported.type === "Identifier" ? specifier.exported.name : specifier.exported.value; if (stmt.source) { exports[exportedName] = sourceExports[specifier.local.name]; } else { exports[exportedName] = await resolveTSReferencedType({ scope, type: specifier.local }); } } } if (isTSDeclaration(stmt.declaration)) { const decl = stmt.declaration; if (((_a = decl.id) == null ? void 0 : _a.type) === "Identifier") { const exportedName = decl.id.name; exports[exportedName] = await resolveTSReferencedType({ scope, type: decl }); } } } } return exports; } var resolveTSFileIdImpl = resolveTSFileIdNode; function resolveTSFileId(id, importer) { return resolveTSFileIdImpl(id, importer); } function resolveTSFileIdNode(id, importer) { function tryResolve(id2, importer2) { const filePath = _path2.default.resolve(importer2, "..", id2); if (!_fs.existsSync.call(void 0, filePath)) return; return filePath; } return tryResolve(id, importer) || tryResolve(`${id}.ts`, importer) || tryResolve(`${id}.d.ts`, importer) || tryResolve(`${id}/index`, importer) || tryResolve(`${id}/index.ts`, importer) || tryResolve(`${id}/index.d.ts`, importer); } function setResolveTSFileIdImpl(impl) { resolveTSFileIdImpl = impl; } exports.tsFileCache = tsFileCache; exports.getTSFile = getTSFile; exports.isTSDeclaration = isTSDeclaration; exports.mergeTSProperties = mergeTSProperties; exports.resolveTSProperties = resolveTSProperties; exports.resolveTypeElements = resolveTypeElements; exports.resolveTSReferencedType = resolveTSReferencedType; exports.resolveTSScope = resolveTSScope; exports.resolveTSEntityName = resolveTSEntityName; exports.exportsSymbol = exportsSymbol; exports.tsFileExportsCache = tsFileExportsCache; exports.isTSExports = isTSExports; exports.resolveTSExports = resolveTSExports; exports.resolveTSFileId = resolveTSFileId; exports.resolveTSFileIdNode = resolveTSFileIdNode; exports.setResolveTSFileIdImpl = setResolveTSFileIdImpl;