UNPKG

@ethan-jones-vizio/sveld

Version:

Generate TypeScript definitions for your Svelte components.

563 lines (562 loc) 29.4 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; exports.__esModule = true; var compiler_1 = require("svelte/compiler"); var commentParser = __importStar(require("comment-parser")); var element_tag_map_1 = require("./element-tag-map"); var DEFAULT_SLOT_NAME = "__default__"; var ComponentParser = /** @class */ (function () { function ComponentParser(options) { this.reactive_vars = new Set(); this.vars = new Set(); this.props = new Map(); this.moduleExports = new Map(); this.slots = new Map(); this.events = new Map(); this.typedefs = new Map(); this.bindings = new Map(); this.options = options; } ComponentParser.mapToArray = function (map) { return Array.from(map, function (_a) { var key = _a[0], value = _a[1]; return value; }); }; ComponentParser.assignValue = function (value) { return value === undefined || value === "" ? undefined : value; }; ComponentParser.formatComment = function (comment) { var formatted_comment = comment; if (!formatted_comment.startsWith("/*")) { formatted_comment = "/*" + formatted_comment; } if (!formatted_comment.endsWith("*/")) { formatted_comment += "*/"; } return formatted_comment; }; ComponentParser.prototype.sourceAtPos = function (start, end) { var _a; return (_a = this.source) === null || _a === void 0 ? void 0 : _a.slice(start, end); }; ComponentParser.prototype.collectReactiveVars = function () { var _this = this; var _a; (_a = this.compiled) === null || _a === void 0 ? void 0 : _a.vars.filter(function (_a) { var reassigned = _a.reassigned, writable = _a.writable; return reassigned && writable; }).forEach(function (_a) { var name = _a.name; return _this.reactive_vars.add(name); }); }; ComponentParser.prototype.addProp = function (prop_name, data) { if (ComponentParser.assignValue(prop_name) === undefined) return; if (this.props.has(prop_name)) { var existing_slot = this.props.get(prop_name); this.props.set(prop_name, __assign(__assign({}, existing_slot), data)); } else { this.props.set(prop_name, data); } }; ComponentParser.prototype.addModuleExport = function (prop_name, data) { if (ComponentParser.assignValue(prop_name) === undefined) return; if (this.moduleExports.has(prop_name)) { var existing_slot = this.moduleExports.get(prop_name); this.moduleExports.set(prop_name, __assign(__assign({}, existing_slot), data)); } else { this.moduleExports.set(prop_name, data); } }; ComponentParser.prototype.aliasType = function (type) { if (type === "*") return "any"; return type; }; ComponentParser.prototype.addSlot = function (slot_name, slot_props, slot_fallback) { var default_slot = slot_name === undefined || slot_name === ""; var name = default_slot ? DEFAULT_SLOT_NAME : slot_name; var fallback = ComponentParser.assignValue(slot_fallback); var props = ComponentParser.assignValue(slot_props); if (this.slots.has(name)) { var existing_slot = this.slots.get(name); this.slots.set(name, __assign(__assign({}, existing_slot), { fallback: fallback, slot_props: existing_slot.slot_props === undefined ? props : existing_slot.slot_props })); } else { this.slots.set(name, { name: name, "default": default_slot, fallback: fallback, slot_props: slot_props }); } }; ComponentParser.prototype.addDispatchedEvent = function (_a) { var name = _a.name, detail = _a.detail, has_argument = _a.has_argument; if (name === undefined) return; /** * `e.detail` should be `null` if the dispatcher * is not provided a second argument and if * `@event` is not specified. */ var default_detail = !has_argument && !detail ? "null" : ComponentParser.assignValue(detail); if (this.events.has(name)) { var existing_event = this.events.get(name); this.events.set(name, __assign(__assign({}, existing_event), { detail: existing_event.detail === undefined ? default_detail : existing_event.detail })); } else { this.events.set(name, { type: "dispatched", name: name, detail: default_detail }); } }; ComponentParser.prototype.parseCustomTypes = function () { var _this = this; commentParser.parse(this.source, { spacing: "preserve" }).forEach(function (_a) { var tags = _a.tags; tags.forEach(function (_a) { var tag = _a.tag, tagType = _a.type, name = _a.name, description = _a.description; var type = _this.aliasType(tagType); switch (tag) { case "extends": _this["extends"] = { interface: name, "import": type }; break; case "restProps": _this.rest_props = { type: "Element", name: type }; break; case "slot": _this.addSlot(name, type); break; case "event": _this.addDispatchedEvent({ name: name, detail: type, has_argument: false }); break; case "typedef": _this.typedefs.set(name, { type: type, name: name, description: ComponentParser.assignValue(description), ts: /(\}|\};)$/.test(type) ? "interface ".concat(name, " ").concat(type) : "type ".concat(name, " = ").concat(type) }); break; } }); }); }; ComponentParser.prototype.cleanup = function () { this.source = undefined; this.compiled = undefined; this.parsed = undefined; this.rest_props = undefined; this["extends"] = undefined; this.componentComment = undefined; this.reactive_vars.clear(); this.props.clear(); this.moduleExports.clear(); this.slots.clear(); this.events.clear(); this.typedefs.clear(); this.bindings.clear(); }; ComponentParser.prototype.parseSvelteComponent = function (source, diagnostics) { var _this = this; var _a, _b, _c; if ((_a = this.options) === null || _a === void 0 ? void 0 : _a.verbose) { console.log("[parsing] \"".concat(diagnostics.moduleName, "\" ").concat(diagnostics.filePath)); } this.cleanup(); this.source = source; this.compiled = (0, compiler_1.compile)(source); this.parsed = (0, compiler_1.parse)(source); this.collectReactiveVars(); this.parseCustomTypes(); if ((_b = this.parsed) === null || _b === void 0 ? void 0 : _b.module) { (0, compiler_1.walk)((_c = this.parsed) === null || _c === void 0 ? void 0 : _c.module, { enter: function (node) { var _a, _b, _c, _d, _e, _f, _g, _h; if (node.type === "ExportNamedDeclaration") { var _j = ((_a = node.declaration) === null || _a === void 0 ? void 0 : _a.declarations) ? node.declaration.declarations[0] : node.declaration, declaration_type = _j.type, id = _j.id, init = _j.init, body = _j.body; var prop_name = id.name; var value = undefined; var type = undefined; var kind = node.declaration.kind; var description = undefined; var isFunction = false; var isFunctionDeclaration = false; if (init != null) { if (init.type === "ObjectExpression" || init.type === "BinaryExpression" || init.type === "ArrayExpression" || init.type === "ArrowFunctionExpression") { value = (_b = _this.sourceAtPos(init.start, init.end)) === null || _b === void 0 ? void 0 : _b.replace(/\n/g, " "); type = value; isFunction = init.type === "ArrowFunctionExpression"; if (init.type === "BinaryExpression") { if ((init === null || init === void 0 ? void 0 : init.left.type) === "Literal" && typeof (init === null || init === void 0 ? void 0 : init.left.value) === "string") { type = "string"; } } } else { if (init.type === "UnaryExpression") { value = _this.sourceAtPos(init.start, init.end); type = typeof ((_c = init.argument) === null || _c === void 0 ? void 0 : _c.value); } else { value = init.raw; type = init.value == null ? undefined : typeof init.value; } } } if (declaration_type === "FunctionDeclaration") { value = "() => " + ((_d = _this.sourceAtPos(body.start, body.end)) === null || _d === void 0 ? void 0 : _d.replace(/\n/g, " ")); type = "() => any"; kind = "function"; isFunction = true; isFunctionDeclaration = true; } if (node.leadingComments) { var last_comment = node.leadingComments[node.leadingComments.length - 1]; var comment = commentParser.parse(ComponentParser.formatComment(last_comment.value), { spacing: "preserve" }); var tag = (_e = comment[0]) === null || _e === void 0 ? void 0 : _e.tags[((_f = comment[0]) === null || _f === void 0 ? void 0 : _f.tags.length) - 1]; if ((tag === null || tag === void 0 ? void 0 : tag.tag) === "type") type = _this.aliasType(tag.type); description = ComponentParser.assignValue((_h = (_g = comment[0]) === null || _g === void 0 ? void 0 : _g.description) === null || _h === void 0 ? void 0 : _h.trim()); } if (!description && _this.typedefs.has(type)) { description = _this.typedefs.get(type).description; } _this.addModuleExport(prop_name, { name: prop_name, kind: kind, description: description, type: type, value: value, isFunction: isFunction, isFunctionDeclaration: isFunctionDeclaration, isRequired: false, constant: kind === "const", reactive: false }); } } }); } var dispatcher_name = undefined; var callees = []; (0, compiler_1.walk)({ html: this.parsed.html, instance: this.parsed.instance }, { enter: function (node, parent, prop) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p; if (node.type === "CallExpression") { if (node.callee.name === "createEventDispatcher") { dispatcher_name = parent === null || parent === void 0 ? void 0 : parent.id.name; } callees.push({ name: node.callee.name, arguments: node.arguments }); } if (node.type === "Spread" && (node === null || node === void 0 ? void 0 : node.expression.name) === "$$restProps") { if (_this.rest_props === undefined && ((parent === null || parent === void 0 ? void 0 : parent.type) === "InlineComponent" || (parent === null || parent === void 0 ? void 0 : parent.type) === "Element")) { _this.rest_props = { type: parent.type, name: parent.name }; } } if (node.type === "VariableDeclaration") { _this.vars.add(node); } if (node.type === "ExportNamedDeclaration") { // Handle renamed exports var prop_name = void 0; if (node.declaration == null && ((_a = node.specifiers[0]) === null || _a === void 0 ? void 0 : _a.type) === "ExportSpecifier") { var specifier = node.specifiers[0]; var localName_1 = specifier.local.name, exportedName = specifier.exported.name; var declaration_1; // Search through all variable declarations for this variable // Limitation: the variable must have been declared before the export _this.vars.forEach(function (varDecl) { if (varDecl.declarations.some(function (decl) { return decl.id.type === "Identifier" && decl.id.name === localName_1; })) { declaration_1 = varDecl; } }); node.declaration = declaration_1; prop_name = exportedName; } var _q = node.declaration.declarations ? node.declaration.declarations[0] : node.declaration, declaration_type = _q.type, id = _q.id, init = _q.init, body = _q.body; prop_name !== null && prop_name !== void 0 ? prop_name : (prop_name = id.name); var value = undefined; var type = undefined; var kind = node.declaration.kind; var description_1 = undefined; var isFunction = false; var isFunctionDeclaration = false; var isRequired_1 = false; if (init != null) { if (init.type === "ObjectExpression" || init.type === "BinaryExpression" || init.type === "ArrayExpression" || init.type === "ArrowFunctionExpression") { value = (_b = _this.sourceAtPos(init.start, init.end)) === null || _b === void 0 ? void 0 : _b.replace(/\n/g, " "); type = value; isFunction = init.type === "ArrowFunctionExpression"; if (init.type === "BinaryExpression") { if ((init === null || init === void 0 ? void 0 : init.left.type) === "Literal" && typeof (init === null || init === void 0 ? void 0 : init.left.value) === "string") { type = "string"; } } } else { if (init.type === "UnaryExpression") { value = _this.sourceAtPos(init.start, init.end); type = typeof ((_c = init.argument) === null || _c === void 0 ? void 0 : _c.value); } else { value = init.raw; type = init.value == null ? undefined : typeof init.value; } } } if (declaration_type === "FunctionDeclaration") { value = "() => " + ((_d = _this.sourceAtPos(body.start, body.end)) === null || _d === void 0 ? void 0 : _d.replace(/\n/g, " ")); type = "() => any"; kind = "function"; isFunction = true; isFunctionDeclaration = true; } if (node.leadingComments) { var last_comment = node.leadingComments[node.leadingComments.length - 1]; var comment = commentParser.parse(ComponentParser.formatComment(last_comment.value), { spacing: "preserve" }); var tag = (_e = comment[0]) === null || _e === void 0 ? void 0 : _e.tags[((_f = comment[0]) === null || _f === void 0 ? void 0 : _f.tags.length) - 1]; if ((tag === null || tag === void 0 ? void 0 : tag.tag) === "type") type = _this.aliasType(tag.type); description_1 = ComponentParser.assignValue((_h = (_g = comment[0]) === null || _g === void 0 ? void 0 : _g.description) === null || _h === void 0 ? void 0 : _h.trim()); var additional_tags = (_k = (_j = comment[0]) === null || _j === void 0 ? void 0 : _j.tags.filter(function (tag) { return !["type", "extends", "restProps", "slot", "event", "typedef"].includes(tag.tag); })) !== null && _k !== void 0 ? _k : []; if (additional_tags.length > 0 && description_1 === undefined) { description_1 = ""; } additional_tags.forEach(function (tag) { isRequired_1 = tag.tag === "required"; if (!isRequired_1) { description_1 += "".concat(description_1 ? "\n" : "", "@").concat(tag.tag, " ").concat(tag.name).concat(tag.description ? " ".concat(tag.description) : ""); } }); } if (!description_1 && _this.typedefs.has(type)) { description_1 = _this.typedefs.get(type).description; } _this.addProp(prop_name, { name: prop_name, kind: kind, description: description_1, type: type, value: value, isFunction: isFunction, isFunctionDeclaration: isFunctionDeclaration, isRequired: isRequired_1, constant: kind === "const", reactive: _this.reactive_vars.has(prop_name) }); } if (node.type === "Comment") { var data = (_m = (_l = node === null || node === void 0 ? void 0 : node.data) === null || _l === void 0 ? void 0 : _l.trim()) !== null && _m !== void 0 ? _m : ""; if (/^@component/.test(data)) { _this.componentComment = data.replace(/^@component/, ""); } } if (node.type === "Slot") { var slot_name = (_o = node.attributes.find(function (attr) { return attr.name === "name"; })) === null || _o === void 0 ? void 0 : _o.value[0].data; var slot_props = node.attributes .filter(function (attr) { return attr.name !== "name"; }) .reduce(function (slot_props, _a) { var _b; var name = _a.name, value = _a.value; var slot_prop_value = { value: undefined, replace: false }; if (value === undefined) return {}; if (value[0]) { var _c = value[0], type = _c.type, expression = _c.expression, raw = _c.raw, start = _c.start, end = _c.end; if (type === "Text") { slot_prop_value.value = raw; } else if (type === "AttributeShorthand") { slot_prop_value.value = expression.name; slot_prop_value.replace = true; } if (expression) { if (expression.type === "Literal") { slot_prop_value.value = expression.value; } else if (expression.type !== "Identifier") { if (expression.type === "ObjectExpression" || expression.type === "TemplateLiteral") { slot_prop_value.value = _this.sourceAtPos(start + 1, end - 1); } else { slot_prop_value.value = _this.sourceAtPos(start, end); } } } } return __assign(__assign({}, slot_props), (_b = {}, _b[name] = slot_prop_value, _b)); }, {}); var fallback = (_p = node.children) === null || _p === void 0 ? void 0 : _p.map(function (_a) { var start = _a.start, end = _a.end; return _this.sourceAtPos(start, end); }).join("").trim(); _this.addSlot(slot_name, JSON.stringify(slot_props, null, 2), fallback); } if (node.type === "EventHandler" && node.expression == null) { if (!_this.events.has(node.name) && parent !== undefined) { _this.events.set(node.name, { type: "forwarded", name: node.name, element: parent.name }); } } if ((parent === null || parent === void 0 ? void 0 : parent.type) === "Element" && node.type === "Binding" && node.name === "this") { var prop_name = node.expression.name; var element_name = parent.name; if (_this.bindings.has(prop_name)) { var existing_bindings = _this.bindings.get(prop_name); if (!existing_bindings.elements.includes(element_name)) { _this.bindings.set(prop_name, __assign(__assign({}, existing_bindings), { elements: __spreadArray(__spreadArray([], existing_bindings.elements, true), [element_name], false) })); } } else { _this.bindings.set(prop_name, { elements: [element_name] }); } } } }); if (dispatcher_name !== undefined) { callees.forEach(function (callee) { var _a; if (callee.name === dispatcher_name) { var event_name = (_a = callee.arguments[0]) === null || _a === void 0 ? void 0 : _a.value; var event_argument = callee.arguments[1]; var event_detail = event_argument === null || event_argument === void 0 ? void 0 : event_argument.value; _this.addDispatchedEvent({ name: event_name, detail: event_detail, has_argument: Boolean(event_argument) }); } }); } return { props: ComponentParser.mapToArray(this.props).map(function (prop) { if (_this.bindings.has(prop.name)) { return __assign(__assign({}, prop), { type: "null | " + _this.bindings .get(prop.name) .elements.sort() .map(function (element) { return (0, element_tag_map_1.getElementByTag)(element); }) .join(" | ") }); } return prop; }), moduleExports: ComponentParser.mapToArray(this.moduleExports), slots: ComponentParser.mapToArray(this.slots) .map(function (slot) { try { var slot_props_1 = JSON.parse(slot.slot_props); var new_props_1 = []; Object.keys(slot_props_1).forEach(function (key) { var _a; if (slot_props_1[key].replace && slot_props_1[key].value !== undefined) { slot_props_1[key].value = (_a = _this.props.get(slot_props_1[key].value)) === null || _a === void 0 ? void 0 : _a.type; } if (slot_props_1[key].value === undefined) slot_props_1[key].value = "any"; new_props_1.push("".concat(key, ": ").concat(slot_props_1[key].value)); }); var formatted_slot_props = new_props_1.length === 0 ? "{}" : "{ " + new_props_1.join(", ") + " }"; return __assign(__assign({}, slot), { slot_props: formatted_slot_props }); } catch (e) { return slot; } }) .sort(function (a, b) { if (a.name < b.name) return -1; if (a.name > b.name) return 1; return 0; }), events: ComponentParser.mapToArray(this.events), typedefs: ComponentParser.mapToArray(this.typedefs), rest_props: this.rest_props, "extends": this["extends"], componentComment: this.componentComment }; }; return ComponentParser; }()); exports["default"] = ComponentParser;