jsdoc-builder 0.0.5 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.MD +269 -58
- package/README.ja.md +304 -0
- package/README.ko.md +304 -0
- package/README.zh-CN.md +304 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +26 -5
- package/dist/index.d.ts +33 -0
- package/dist/index.js +793 -56
- package/dist/vite.d.ts +20 -0
- package/dist/vite.js +111 -0
- package/example/example.jsx +17 -0
- package/example/example.tsx +21 -0
- package/example/example.vue +36 -0
- package/package.json +20 -3
package/dist/index.js
CHANGED
|
@@ -1,71 +1,808 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
36
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
37
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
38
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
39
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
40
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
41
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
42
|
+
});
|
|
43
|
+
};
|
|
2
44
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
45
|
exports.generateJSDoc = generateJSDoc;
|
|
4
|
-
|
|
5
|
-
const
|
|
46
|
+
exports.generateJSDocFromCode = generateJSDocFromCode;
|
|
47
|
+
const ts = __importStar(require("typescript"));
|
|
48
|
+
const fs = __importStar(require("fs"));
|
|
49
|
+
const path = __importStar(require("path"));
|
|
50
|
+
const https = __importStar(require("https"));
|
|
51
|
+
const url_1 = require("url");
|
|
52
|
+
const DEFAULT_PROMPT_TEMPLATE = "Write one concise sentence for the JSDoc @description of function '{{functionName}}'. Parameters: {{parameters}}. Return type: {{returnType}}. Source: {{sourceSnippet}}";
|
|
53
|
+
const OPENAI_AI_DEFAULTS = {
|
|
54
|
+
provider: "openai",
|
|
55
|
+
model: "gpt-4o-mini",
|
|
56
|
+
baseUrl: "https://api.openai.com/v1/chat/completions",
|
|
57
|
+
timeoutMs: 12000,
|
|
58
|
+
promptTemplate: DEFAULT_PROMPT_TEMPLATE,
|
|
59
|
+
};
|
|
60
|
+
const GEMINI_AI_DEFAULTS = {
|
|
61
|
+
provider: "gemini",
|
|
62
|
+
model: "gemini-1.5-flash",
|
|
63
|
+
baseUrl: "https://generativelanguage.googleapis.com/v1beta",
|
|
64
|
+
timeoutMs: 12000,
|
|
65
|
+
promptTemplate: DEFAULT_PROMPT_TEMPLATE,
|
|
66
|
+
};
|
|
67
|
+
const DEFAULT_CONFIG = {
|
|
68
|
+
template: {
|
|
69
|
+
descriptionLine: "@description {{description}}",
|
|
70
|
+
paramLine: "@param {${type}} ${name}",
|
|
71
|
+
returnsLine: "@returns {${type}}",
|
|
72
|
+
},
|
|
73
|
+
ai: {
|
|
74
|
+
provider: OPENAI_AI_DEFAULTS.provider,
|
|
75
|
+
enabled: false,
|
|
76
|
+
model: OPENAI_AI_DEFAULTS.model,
|
|
77
|
+
baseUrl: OPENAI_AI_DEFAULTS.baseUrl,
|
|
78
|
+
timeoutMs: OPENAI_AI_DEFAULTS.timeoutMs,
|
|
79
|
+
promptTemplate: OPENAI_AI_DEFAULTS.promptTemplate,
|
|
80
|
+
},
|
|
81
|
+
includeReturnsWhenVoid: true,
|
|
82
|
+
};
|
|
6
83
|
/**
|
|
7
|
-
* Parses a TypeScript or
|
|
84
|
+
* Parses a TypeScript, JavaScript, JSX, TSX, or Vue file and adds JSDoc comments to functions.
|
|
85
|
+
* Skips functions that already have JSDoc comments.
|
|
8
86
|
* @param filePath - The path of the file to process.
|
|
9
87
|
*/
|
|
10
|
-
function generateJSDoc(
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
88
|
+
function generateJSDoc(filePath_1) {
|
|
89
|
+
return __awaiter(this, arguments, void 0, function* (filePath, options = {}) {
|
|
90
|
+
const sourceCode = fs.readFileSync(filePath, "utf-8");
|
|
91
|
+
const updatedCode = yield generateJSDocFromCode(filePath, sourceCode, options);
|
|
92
|
+
if (updatedCode !== sourceCode) {
|
|
93
|
+
fs.writeFileSync(filePath, updatedCode, "utf-8");
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
function generateJSDocFromCode(filePath_1, code_1) {
|
|
98
|
+
return __awaiter(this, arguments, void 0, function* (filePath, code, options = {}) {
|
|
99
|
+
const config = loadConfig(options);
|
|
100
|
+
return transformCode(filePath, code, config);
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
function transformCode(filePath, originalCode, config) {
|
|
104
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
105
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
106
|
+
let sourceCode = originalCode;
|
|
107
|
+
let vueScriptRange;
|
|
108
|
+
let scriptKind = resolveScriptKind(ext);
|
|
109
|
+
if (ext === ".vue") {
|
|
110
|
+
const vueScript = extractVueScript(originalCode);
|
|
111
|
+
if (!vueScript) {
|
|
112
|
+
return originalCode;
|
|
113
|
+
}
|
|
114
|
+
sourceCode = vueScript.content;
|
|
115
|
+
vueScriptRange = { start: vueScript.contentStart, end: vueScript.contentEnd };
|
|
116
|
+
scriptKind = resolveScriptKindFromVue(vueScript.openTag);
|
|
117
|
+
}
|
|
118
|
+
const sourceFile = ts.createSourceFile(filePath, sourceCode, ts.ScriptTarget.Latest, true, scriptKind);
|
|
119
|
+
const checker = createTypeChecker(filePath, sourceCode, scriptKind, sourceFile);
|
|
120
|
+
const targets = collectTargets(sourceFile, sourceCode, checker);
|
|
121
|
+
const commentMap = yield buildCommentMap(targets, config, checker);
|
|
122
|
+
if (commentMap.size === 0) {
|
|
123
|
+
return originalCode;
|
|
124
|
+
}
|
|
125
|
+
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
|
|
126
|
+
const transformer = (context) => {
|
|
127
|
+
const visit = (node) => {
|
|
128
|
+
const key = makeNodeKey(node);
|
|
129
|
+
const comment = commentMap.get(key);
|
|
130
|
+
if (comment) {
|
|
131
|
+
ts.addSyntheticLeadingComment(node, ts.SyntaxKind.MultiLineCommentTrivia, comment, true);
|
|
132
|
+
}
|
|
133
|
+
return ts.visitEachChild(node, visit, context);
|
|
134
|
+
};
|
|
135
|
+
return (node) => ts.visitNode(node, visit);
|
|
136
|
+
};
|
|
137
|
+
const result = ts.transform(sourceFile, [transformer]);
|
|
138
|
+
const transformedSourceFile = result.transformed[0];
|
|
139
|
+
let transformedScriptCode = printer.printFile(transformedSourceFile);
|
|
140
|
+
result.dispose();
|
|
141
|
+
if (ext === ".vue" && vueScriptRange) {
|
|
142
|
+
const originalScriptContent = originalCode.slice(vueScriptRange.start, vueScriptRange.end);
|
|
143
|
+
if (originalScriptContent.startsWith("\n") && !transformedScriptCode.startsWith("\n")) {
|
|
144
|
+
transformedScriptCode = `\n${transformedScriptCode}`;
|
|
145
|
+
}
|
|
146
|
+
if (originalScriptContent.endsWith("\n") && !transformedScriptCode.endsWith("\n")) {
|
|
147
|
+
transformedScriptCode = `${transformedScriptCode}\n`;
|
|
148
|
+
}
|
|
149
|
+
const updatedCode = originalCode.slice(0, vueScriptRange.start) +
|
|
150
|
+
transformedScriptCode +
|
|
151
|
+
originalCode.slice(vueScriptRange.end);
|
|
152
|
+
return updatedCode;
|
|
153
|
+
}
|
|
154
|
+
return transformedScriptCode;
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
function loadConfig(options) {
|
|
158
|
+
var _a;
|
|
159
|
+
const fileConfig = loadConfigFile(options.configPath);
|
|
160
|
+
const merged = mergeDeep(DEFAULT_CONFIG, fileConfig, (_a = options.config) !== null && _a !== void 0 ? _a : {}, options.disableAI ? { ai: { enabled: false } } : {});
|
|
161
|
+
merged.ai.provider = normalizeProvider(merged.ai.provider);
|
|
162
|
+
applyProviderDefaults(merged.ai);
|
|
163
|
+
const envApiKey = resolveApiKeyFromEnv(merged.ai.provider);
|
|
164
|
+
if (!merged.ai.apiKey && envApiKey) {
|
|
165
|
+
merged.ai.apiKey = envApiKey;
|
|
166
|
+
}
|
|
167
|
+
if (merged.ai.enabled && !merged.ai.apiKey) {
|
|
168
|
+
merged.ai.enabled = false;
|
|
169
|
+
}
|
|
170
|
+
return merged;
|
|
171
|
+
}
|
|
172
|
+
function loadConfigFile(configPath) {
|
|
173
|
+
const targetPath = configPath || path.resolve(process.cwd(), "jsdoc-builder.config.json");
|
|
174
|
+
if (!fs.existsSync(targetPath)) {
|
|
175
|
+
return {};
|
|
176
|
+
}
|
|
177
|
+
try {
|
|
178
|
+
const raw = fs.readFileSync(targetPath, "utf-8");
|
|
179
|
+
const parsed = JSON.parse(raw);
|
|
180
|
+
if (!isObject(parsed)) {
|
|
181
|
+
return {};
|
|
182
|
+
}
|
|
183
|
+
return parsed;
|
|
184
|
+
}
|
|
185
|
+
catch (_a) {
|
|
186
|
+
return {};
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
function extractVueScript(sourceCode) {
|
|
190
|
+
var _a;
|
|
191
|
+
const scriptRegex = /<script\b[^>]*>([\s\S]*?)<\/script\s*>/i;
|
|
192
|
+
const match = scriptRegex.exec(sourceCode);
|
|
193
|
+
if (!match) {
|
|
194
|
+
return undefined;
|
|
195
|
+
}
|
|
196
|
+
const full = match[0];
|
|
197
|
+
const content = (_a = match[1]) !== null && _a !== void 0 ? _a : "";
|
|
198
|
+
const contentOffset = full.indexOf(content);
|
|
199
|
+
const fullStart = match.index;
|
|
200
|
+
const contentStart = fullStart + contentOffset;
|
|
201
|
+
const contentEnd = contentStart + content.length;
|
|
202
|
+
const openTag = full.slice(0, contentOffset);
|
|
203
|
+
return {
|
|
204
|
+
openTag,
|
|
205
|
+
content,
|
|
206
|
+
contentStart,
|
|
207
|
+
contentEnd,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
function resolveScriptKind(ext) {
|
|
211
|
+
if (ext === ".js" || ext === ".mjs" || ext === ".cjs") {
|
|
212
|
+
return ts.ScriptKind.JS;
|
|
213
|
+
}
|
|
214
|
+
if (ext === ".jsx") {
|
|
215
|
+
return ts.ScriptKind.JSX;
|
|
216
|
+
}
|
|
217
|
+
if (ext === ".tsx") {
|
|
218
|
+
return ts.ScriptKind.TSX;
|
|
219
|
+
}
|
|
220
|
+
return ts.ScriptKind.TS;
|
|
221
|
+
}
|
|
222
|
+
function resolveScriptKindFromVue(openTag) {
|
|
223
|
+
const langMatch = openTag.match(/lang\s*=\s*["']?([a-zA-Z0-9-]+)/i);
|
|
224
|
+
const lang = ((langMatch === null || langMatch === void 0 ? void 0 : langMatch[1]) || "js").toLowerCase();
|
|
225
|
+
if (lang.includes("tsx")) {
|
|
226
|
+
return ts.ScriptKind.TSX;
|
|
227
|
+
}
|
|
228
|
+
if (lang.includes("jsx")) {
|
|
229
|
+
return ts.ScriptKind.JSX;
|
|
230
|
+
}
|
|
231
|
+
if (lang.includes("ts")) {
|
|
232
|
+
return ts.ScriptKind.TS;
|
|
233
|
+
}
|
|
234
|
+
return ts.ScriptKind.JS;
|
|
235
|
+
}
|
|
236
|
+
function collectTargets(sourceFile, sourceText, checker) {
|
|
237
|
+
const targets = [];
|
|
238
|
+
const walk = (node) => {
|
|
16
239
|
if (ts.isFunctionDeclaration(node) && node.name) {
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
240
|
+
const commentNode = node;
|
|
241
|
+
if (!hasJSDoc(commentNode, sourceText)) {
|
|
242
|
+
targets.push(createTarget(commentNode, node.name.text, node.parameters, inferReturnTypeText(node, checker), node.getText(sourceFile)));
|
|
243
|
+
}
|
|
20
244
|
}
|
|
21
|
-
// Check for arrow functions assigned to a constant
|
|
22
245
|
if (ts.isVariableDeclaration(node) &&
|
|
23
246
|
node.initializer &&
|
|
24
|
-
ts.isArrowFunction(node.initializer)) {
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
return node;
|
|
33
|
-
}
|
|
34
|
-
return ts.visitEachChild(node, (child) => visit(child, context), context); // Pass context to visit
|
|
35
|
-
}
|
|
36
|
-
// Create the transformer
|
|
37
|
-
const transformer = (context) => {
|
|
38
|
-
return (sourceFile) => {
|
|
39
|
-
return ts.visitNode(sourceFile, (node) => visit(node, context)); // Pass context to visit
|
|
40
|
-
};
|
|
247
|
+
(ts.isArrowFunction(node.initializer) || ts.isFunctionExpression(node.initializer))) {
|
|
248
|
+
const functionNode = node.initializer;
|
|
249
|
+
const commentNode = resolveVariableCommentNode(node);
|
|
250
|
+
if (!hasJSDoc(commentNode, sourceText)) {
|
|
251
|
+
targets.push(createTarget(commentNode, getFunctionNameFromVariable(node), functionNode.parameters, inferReturnTypeText(functionNode, checker), functionNode.getText(sourceFile)));
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
ts.forEachChild(node, walk);
|
|
41
255
|
};
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const transformedSourceFile = result.transformed[0];
|
|
45
|
-
const updatedCode = printer.printFile(transformedSourceFile);
|
|
46
|
-
fs.writeFileSync(filePath, updatedCode, "utf-8");
|
|
256
|
+
walk(sourceFile);
|
|
257
|
+
return targets;
|
|
47
258
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
259
|
+
function resolveVariableCommentNode(node) {
|
|
260
|
+
const declarationList = node.parent;
|
|
261
|
+
if (ts.isVariableDeclarationList(declarationList) &&
|
|
262
|
+
declarationList.declarations.length === 1 &&
|
|
263
|
+
ts.isVariableStatement(declarationList.parent)) {
|
|
264
|
+
return declarationList.parent;
|
|
265
|
+
}
|
|
266
|
+
return node;
|
|
267
|
+
}
|
|
268
|
+
function createTarget(commentNode, functionName, parameters, returnTypeText, sourceSnippet) {
|
|
269
|
+
return {
|
|
270
|
+
key: makeNodeKey(commentNode),
|
|
271
|
+
functionName,
|
|
272
|
+
parameters,
|
|
273
|
+
returnTypeText,
|
|
274
|
+
sourceSnippet,
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
function buildCommentMap(targets, config, checker) {
|
|
278
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
279
|
+
const entries = [];
|
|
280
|
+
for (const target of targets) {
|
|
281
|
+
const params = target.parameters.map((param, index) => ({
|
|
282
|
+
name: getParameterName(param, index),
|
|
283
|
+
type: inferParameterType(param, checker),
|
|
284
|
+
}));
|
|
285
|
+
const description = yield createDescription({
|
|
286
|
+
functionName: target.functionName,
|
|
287
|
+
returnType: target.returnTypeText,
|
|
288
|
+
parameters: params,
|
|
289
|
+
sourceSnippet: target.sourceSnippet,
|
|
290
|
+
}, config);
|
|
291
|
+
const comment = createJSDocComment(target.functionName, params, target.returnTypeText, description, config);
|
|
292
|
+
entries.push([target.key, comment]);
|
|
293
|
+
}
|
|
294
|
+
return new Map(entries);
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
function createDescription(context, config) {
|
|
298
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
299
|
+
if (!config.ai.enabled || !config.ai.apiKey) {
|
|
300
|
+
return `${context.functionName} function`;
|
|
301
|
+
}
|
|
302
|
+
const aiDescription = yield requestDescriptionFromAI(context, config.ai);
|
|
303
|
+
if (!aiDescription) {
|
|
304
|
+
return `${context.functionName} function`;
|
|
305
|
+
}
|
|
306
|
+
return aiDescription;
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
function createJSDocComment(functionName, parameters, returnType, description, config) {
|
|
310
|
+
const lines = [];
|
|
311
|
+
lines.push(formatTemplate(config.template.descriptionLine, {
|
|
312
|
+
functionName,
|
|
313
|
+
description,
|
|
314
|
+
returnType,
|
|
315
|
+
paramsCount: String(parameters.length),
|
|
60
316
|
}));
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
317
|
+
for (const param of parameters) {
|
|
318
|
+
lines.push(formatTemplate(config.template.paramLine, {
|
|
319
|
+
functionName,
|
|
320
|
+
description,
|
|
321
|
+
type: param.type,
|
|
322
|
+
name: param.name,
|
|
323
|
+
returnType,
|
|
324
|
+
}));
|
|
325
|
+
}
|
|
326
|
+
if (config.includeReturnsWhenVoid || returnType !== "void") {
|
|
327
|
+
lines.push(formatTemplate(config.template.returnsLine, {
|
|
328
|
+
functionName,
|
|
329
|
+
description,
|
|
330
|
+
type: returnType,
|
|
331
|
+
returnType,
|
|
332
|
+
}));
|
|
333
|
+
}
|
|
334
|
+
const withPrefix = lines.map((line) => ` * ${line}`);
|
|
335
|
+
return `*\n${withPrefix.join("\n")}\n `;
|
|
336
|
+
}
|
|
337
|
+
function requestDescriptionFromAI(context, aiConfig) {
|
|
338
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
339
|
+
if (!aiConfig.apiKey) {
|
|
340
|
+
return undefined;
|
|
341
|
+
}
|
|
342
|
+
const prompt = formatTemplate(aiConfig.promptTemplate, {
|
|
343
|
+
functionName: context.functionName,
|
|
344
|
+
returnType: context.returnType,
|
|
345
|
+
parameters: context.parameters.map((p) => `${p.name}:${p.type}`).join(", "),
|
|
346
|
+
sourceSnippet: context.sourceSnippet.replace(/\s+/g, " ").trim().slice(0, 300),
|
|
347
|
+
});
|
|
348
|
+
if (aiConfig.provider === "gemini") {
|
|
349
|
+
return requestDescriptionFromGemini(prompt, aiConfig);
|
|
350
|
+
}
|
|
351
|
+
return requestDescriptionFromOpenAI(prompt, aiConfig);
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
function requestDescriptionFromOpenAI(prompt, aiConfig) {
|
|
355
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
356
|
+
var _a, _b, _c;
|
|
357
|
+
const payload = {
|
|
358
|
+
model: aiConfig.model,
|
|
359
|
+
messages: [
|
|
360
|
+
{
|
|
361
|
+
role: "system",
|
|
362
|
+
content: "You write concise JSDoc descriptions. Return a single sentence with no markdown.",
|
|
363
|
+
},
|
|
364
|
+
{ role: "user", content: prompt },
|
|
365
|
+
],
|
|
366
|
+
temperature: 0.2,
|
|
367
|
+
};
|
|
368
|
+
try {
|
|
369
|
+
const response = yield postJson(aiConfig.baseUrl, payload, aiConfig.timeoutMs, {
|
|
370
|
+
Authorization: `Bearer ${aiConfig.apiKey}`,
|
|
371
|
+
});
|
|
372
|
+
const content = (_c = (_b = (_a = response === null || response === void 0 ? void 0 : response.choices) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.message) === null || _c === void 0 ? void 0 : _c.content;
|
|
373
|
+
if (typeof content !== "string") {
|
|
374
|
+
return undefined;
|
|
375
|
+
}
|
|
376
|
+
return content.replace(/[\r\n]+/g, " ").trim();
|
|
377
|
+
}
|
|
378
|
+
catch (_d) {
|
|
379
|
+
return undefined;
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
function requestDescriptionFromGemini(prompt, aiConfig) {
|
|
384
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
385
|
+
var _a, _b, _c;
|
|
386
|
+
if (!aiConfig.apiKey) {
|
|
387
|
+
return undefined;
|
|
388
|
+
}
|
|
389
|
+
const endpoint = buildGeminiEndpoint(aiConfig.baseUrl, aiConfig.model, aiConfig.apiKey);
|
|
390
|
+
const payload = {
|
|
391
|
+
systemInstruction: {
|
|
392
|
+
parts: [
|
|
393
|
+
{
|
|
394
|
+
text: "You write concise JSDoc descriptions. Return a single sentence with no markdown.",
|
|
395
|
+
},
|
|
396
|
+
],
|
|
397
|
+
},
|
|
398
|
+
contents: [
|
|
399
|
+
{
|
|
400
|
+
role: "user",
|
|
401
|
+
parts: [{ text: prompt }],
|
|
402
|
+
},
|
|
403
|
+
],
|
|
404
|
+
generationConfig: {
|
|
405
|
+
temperature: 0.2,
|
|
406
|
+
},
|
|
407
|
+
};
|
|
408
|
+
try {
|
|
409
|
+
const response = yield postJson(endpoint, payload, aiConfig.timeoutMs);
|
|
410
|
+
const parts = (_c = (_b = (_a = response === null || response === void 0 ? void 0 : response.candidates) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.content) === null || _c === void 0 ? void 0 : _c.parts;
|
|
411
|
+
if (!Array.isArray(parts)) {
|
|
412
|
+
return undefined;
|
|
413
|
+
}
|
|
414
|
+
const content = parts
|
|
415
|
+
.map((part) => (typeof (part === null || part === void 0 ? void 0 : part.text) === "string" ? part.text : ""))
|
|
416
|
+
.join(" ")
|
|
417
|
+
.trim();
|
|
418
|
+
if (!content) {
|
|
419
|
+
return undefined;
|
|
420
|
+
}
|
|
421
|
+
return content.replace(/[\r\n]+/g, " ").trim();
|
|
422
|
+
}
|
|
423
|
+
catch (_d) {
|
|
424
|
+
return undefined;
|
|
425
|
+
}
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
function postJson(endpoint, payload, timeoutMs, headers = {}) {
|
|
429
|
+
const url = new url_1.URL(endpoint);
|
|
430
|
+
return new Promise((resolve, reject) => {
|
|
431
|
+
const req = https.request({
|
|
432
|
+
protocol: url.protocol,
|
|
433
|
+
hostname: url.hostname,
|
|
434
|
+
path: `${url.pathname}${url.search}`,
|
|
435
|
+
method: "POST",
|
|
436
|
+
port: url.port || undefined,
|
|
437
|
+
headers: Object.assign({ "Content-Type": "application/json" }, headers),
|
|
438
|
+
}, (res) => {
|
|
439
|
+
let body = "";
|
|
440
|
+
res.on("data", (chunk) => {
|
|
441
|
+
body += chunk;
|
|
442
|
+
});
|
|
443
|
+
res.on("end", () => {
|
|
444
|
+
if (!res.statusCode || res.statusCode >= 400) {
|
|
445
|
+
reject(new Error("AI request failed"));
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
try {
|
|
449
|
+
resolve(JSON.parse(body));
|
|
450
|
+
}
|
|
451
|
+
catch (_a) {
|
|
452
|
+
reject(new Error("Invalid AI response"));
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
});
|
|
456
|
+
req.setTimeout(timeoutMs, () => {
|
|
457
|
+
req.destroy(new Error("AI request timeout"));
|
|
458
|
+
});
|
|
459
|
+
req.on("error", reject);
|
|
460
|
+
req.write(JSON.stringify(payload));
|
|
461
|
+
req.end();
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
function hasJSDoc(node, sourceText) {
|
|
465
|
+
var _a;
|
|
466
|
+
if (ts.getJSDocCommentsAndTags(node).length > 0) {
|
|
467
|
+
return true;
|
|
468
|
+
}
|
|
469
|
+
const ranges = (_a = ts.getLeadingCommentRanges(sourceText, node.getFullStart())) !== null && _a !== void 0 ? _a : [];
|
|
470
|
+
return ranges.some((range) => sourceText.slice(range.pos, range.end).startsWith("/**"));
|
|
471
|
+
}
|
|
472
|
+
function inferReturnTypeText(node, checker) {
|
|
473
|
+
if (checker) {
|
|
474
|
+
const signature = checker.getSignatureFromDeclaration(node);
|
|
475
|
+
if (signature) {
|
|
476
|
+
const returnType = checker.getReturnTypeOfSignature(signature);
|
|
477
|
+
const typeText = checker.typeToString(returnType);
|
|
478
|
+
if (typeText && typeText !== "{}") {
|
|
479
|
+
return typeText;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
const parameterTypes = getParameterTypeMap(node.parameters, checker);
|
|
484
|
+
if (node.type) {
|
|
485
|
+
return node.type.getText();
|
|
486
|
+
}
|
|
487
|
+
if (!node.body) {
|
|
488
|
+
return "void";
|
|
489
|
+
}
|
|
490
|
+
if (ts.isArrowFunction(node) && !ts.isBlock(node.body)) {
|
|
491
|
+
return finalizeReturnType(inferExpressionType(node.body, parameterTypes), node);
|
|
492
|
+
}
|
|
493
|
+
const returnTypes = new Set();
|
|
494
|
+
const walk = (current) => {
|
|
495
|
+
if (current !== node && isFunctionLike(current)) {
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
if (ts.isReturnStatement(current)) {
|
|
499
|
+
if (!current.expression) {
|
|
500
|
+
returnTypes.add("void");
|
|
501
|
+
}
|
|
502
|
+
else {
|
|
503
|
+
returnTypes.add(inferExpressionType(current.expression, parameterTypes));
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
ts.forEachChild(current, walk);
|
|
507
|
+
};
|
|
508
|
+
walk(node.body);
|
|
509
|
+
if (returnTypes.size === 0) {
|
|
510
|
+
return "void";
|
|
511
|
+
}
|
|
512
|
+
const types = Array.from(returnTypes).filter((type) => type !== "void");
|
|
513
|
+
if (types.length === 0) {
|
|
514
|
+
return finalizeReturnType("void", node);
|
|
515
|
+
}
|
|
516
|
+
return finalizeReturnType(types.join(" | "), node);
|
|
517
|
+
}
|
|
518
|
+
function inferExpressionType(expression, parameterTypes) {
|
|
519
|
+
if (ts.isParenthesizedExpression(expression)) {
|
|
520
|
+
return inferExpressionType(expression.expression, parameterTypes);
|
|
521
|
+
}
|
|
522
|
+
if (ts.isNumericLiteral(expression)) {
|
|
523
|
+
return "number";
|
|
524
|
+
}
|
|
525
|
+
if (ts.isStringLiteral(expression) ||
|
|
526
|
+
ts.isNoSubstitutionTemplateLiteral(expression) ||
|
|
527
|
+
ts.isTemplateExpression(expression)) {
|
|
528
|
+
return "string";
|
|
529
|
+
}
|
|
530
|
+
if (expression.kind === ts.SyntaxKind.TrueKeyword || expression.kind === ts.SyntaxKind.FalseKeyword) {
|
|
531
|
+
return "boolean";
|
|
532
|
+
}
|
|
533
|
+
if (ts.isArrayLiteralExpression(expression)) {
|
|
534
|
+
return "Array<any>";
|
|
535
|
+
}
|
|
536
|
+
if (ts.isObjectLiteralExpression(expression)) {
|
|
537
|
+
return "object";
|
|
538
|
+
}
|
|
539
|
+
if (expression.kind === ts.SyntaxKind.NullKeyword) {
|
|
540
|
+
return "null";
|
|
541
|
+
}
|
|
542
|
+
if (ts.isArrowFunction(expression) || ts.isFunctionExpression(expression)) {
|
|
543
|
+
return "Function";
|
|
544
|
+
}
|
|
545
|
+
if (ts.isIdentifier(expression)) {
|
|
546
|
+
return parameterTypes.get(expression.text) || "any";
|
|
547
|
+
}
|
|
548
|
+
if (ts.isAsExpression(expression)) {
|
|
549
|
+
return expression.type.getText();
|
|
550
|
+
}
|
|
551
|
+
if (ts.isTypeAssertionExpression(expression)) {
|
|
552
|
+
return expression.type.getText();
|
|
553
|
+
}
|
|
554
|
+
if (ts.isPrefixUnaryExpression(expression)) {
|
|
555
|
+
if (expression.operator === ts.SyntaxKind.ExclamationToken) {
|
|
556
|
+
return "boolean";
|
|
557
|
+
}
|
|
558
|
+
if (expression.operator === ts.SyntaxKind.PlusToken ||
|
|
559
|
+
expression.operator === ts.SyntaxKind.MinusToken) {
|
|
560
|
+
return "number";
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
if (ts.isBinaryExpression(expression)) {
|
|
564
|
+
const left = inferExpressionType(expression.left, parameterTypes);
|
|
565
|
+
const right = inferExpressionType(expression.right, parameterTypes);
|
|
566
|
+
const operator = expression.operatorToken.kind;
|
|
567
|
+
if (operator === ts.SyntaxKind.PlusToken) {
|
|
568
|
+
if (left === "string" || right === "string") {
|
|
569
|
+
return "string";
|
|
570
|
+
}
|
|
571
|
+
if (left === "number" && right === "number") {
|
|
572
|
+
return "number";
|
|
573
|
+
}
|
|
574
|
+
return "any";
|
|
575
|
+
}
|
|
576
|
+
if (operator === ts.SyntaxKind.MinusToken ||
|
|
577
|
+
operator === ts.SyntaxKind.AsteriskToken ||
|
|
578
|
+
operator === ts.SyntaxKind.SlashToken ||
|
|
579
|
+
operator === ts.SyntaxKind.PercentToken ||
|
|
580
|
+
operator === ts.SyntaxKind.AsteriskAsteriskToken) {
|
|
581
|
+
return "number";
|
|
582
|
+
}
|
|
583
|
+
if (operator === ts.SyntaxKind.GreaterThanToken ||
|
|
584
|
+
operator === ts.SyntaxKind.GreaterThanEqualsToken ||
|
|
585
|
+
operator === ts.SyntaxKind.LessThanToken ||
|
|
586
|
+
operator === ts.SyntaxKind.LessThanEqualsToken ||
|
|
587
|
+
operator === ts.SyntaxKind.EqualsEqualsToken ||
|
|
588
|
+
operator === ts.SyntaxKind.EqualsEqualsEqualsToken ||
|
|
589
|
+
operator === ts.SyntaxKind.ExclamationEqualsToken ||
|
|
590
|
+
operator === ts.SyntaxKind.ExclamationEqualsEqualsToken ||
|
|
591
|
+
operator === ts.SyntaxKind.InstanceOfKeyword ||
|
|
592
|
+
operator === ts.SyntaxKind.InKeyword) {
|
|
593
|
+
return "boolean";
|
|
594
|
+
}
|
|
595
|
+
if (operator === ts.SyntaxKind.AmpersandAmpersandToken ||
|
|
596
|
+
operator === ts.SyntaxKind.BarBarToken ||
|
|
597
|
+
operator === ts.SyntaxKind.QuestionQuestionToken) {
|
|
598
|
+
return left === right ? left : `${left} | ${right}`;
|
|
599
|
+
}
|
|
600
|
+
if (operator === ts.SyntaxKind.EqualsToken ||
|
|
601
|
+
operator === ts.SyntaxKind.PlusEqualsToken ||
|
|
602
|
+
operator === ts.SyntaxKind.MinusEqualsToken ||
|
|
603
|
+
operator === ts.SyntaxKind.SlashEqualsToken ||
|
|
604
|
+
operator === ts.SyntaxKind.AsteriskEqualsToken ||
|
|
605
|
+
operator === ts.SyntaxKind.PercentEqualsToken) {
|
|
606
|
+
return right;
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
if (ts.isAwaitExpression(expression)) {
|
|
610
|
+
return "Promise<any>";
|
|
611
|
+
}
|
|
612
|
+
if (ts.isConditionalExpression(expression)) {
|
|
613
|
+
const whenTrue = inferExpressionType(expression.whenTrue, parameterTypes);
|
|
614
|
+
const whenFalse = inferExpressionType(expression.whenFalse, parameterTypes);
|
|
615
|
+
return whenTrue === whenFalse ? whenTrue : `${whenTrue} | ${whenFalse}`;
|
|
616
|
+
}
|
|
617
|
+
return "any";
|
|
618
|
+
}
|
|
619
|
+
function inferParameterType(param, checker) {
|
|
620
|
+
if (checker) {
|
|
621
|
+
const type = checker.getTypeAtLocation(param);
|
|
622
|
+
const typeText = checker.typeToString(type);
|
|
623
|
+
if (typeText && typeText !== "{}") {
|
|
624
|
+
return typeText;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
if (param.type) {
|
|
628
|
+
return param.type.getText();
|
|
629
|
+
}
|
|
630
|
+
if (param.initializer) {
|
|
631
|
+
return inferExpressionType(param.initializer, new Map());
|
|
632
|
+
}
|
|
633
|
+
if (param.dotDotDotToken) {
|
|
634
|
+
return "Array<any>";
|
|
635
|
+
}
|
|
636
|
+
return "any";
|
|
637
|
+
}
|
|
638
|
+
function getFunctionNameFromVariable(node) {
|
|
639
|
+
if (ts.isIdentifier(node.name)) {
|
|
640
|
+
return node.name.text;
|
|
641
|
+
}
|
|
642
|
+
return "anonymousFunction";
|
|
643
|
+
}
|
|
644
|
+
function getParameterName(param, index) {
|
|
645
|
+
if (ts.isIdentifier(param.name)) {
|
|
646
|
+
return param.name.text;
|
|
647
|
+
}
|
|
648
|
+
return `param${index + 1}`;
|
|
649
|
+
}
|
|
650
|
+
function makeNodeKey(node) {
|
|
651
|
+
return `${node.kind}:${node.getStart()}:${node.getEnd()}`;
|
|
652
|
+
}
|
|
653
|
+
function formatTemplate(template, values) {
|
|
654
|
+
let output = template;
|
|
655
|
+
for (const [key, value] of Object.entries(values)) {
|
|
656
|
+
output = output.replace(new RegExp(`{{\\s*${escapeRegExp(key)}\\s*}}`, "g"), value);
|
|
657
|
+
output = output.replace(new RegExp(`\\$\\{\\s*${escapeRegExp(key)}\\s*\\}`, "g"), value);
|
|
658
|
+
}
|
|
659
|
+
return output;
|
|
660
|
+
}
|
|
661
|
+
function escapeRegExp(value) {
|
|
662
|
+
return value.replace(/[.*+?^${}()|[\\]\\]/g, "\\$&");
|
|
663
|
+
}
|
|
664
|
+
function mergeDeep(...sources) {
|
|
665
|
+
const result = {
|
|
666
|
+
template: Object.assign({}, DEFAULT_CONFIG.template),
|
|
667
|
+
ai: Object.assign({}, DEFAULT_CONFIG.ai),
|
|
668
|
+
includeReturnsWhenVoid: DEFAULT_CONFIG.includeReturnsWhenVoid,
|
|
669
|
+
};
|
|
670
|
+
for (const source of sources) {
|
|
671
|
+
if (!source || !isObject(source)) {
|
|
672
|
+
continue;
|
|
673
|
+
}
|
|
674
|
+
if ("template" in source && isObject(source.template)) {
|
|
675
|
+
result.template = Object.assign(Object.assign({}, result.template), source.template);
|
|
676
|
+
}
|
|
677
|
+
if ("ai" in source && isObject(source.ai)) {
|
|
678
|
+
result.ai = Object.assign(Object.assign({}, result.ai), source.ai);
|
|
679
|
+
}
|
|
680
|
+
if (typeof source.includeReturnsWhenVoid === "boolean") {
|
|
681
|
+
result.includeReturnsWhenVoid = source.includeReturnsWhenVoid;
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
return result;
|
|
685
|
+
}
|
|
686
|
+
function getParameterTypeMap(parameters, checker) {
|
|
687
|
+
const map = new Map();
|
|
688
|
+
parameters.forEach((param) => {
|
|
689
|
+
if (ts.isIdentifier(param.name)) {
|
|
690
|
+
map.set(param.name.text, inferParameterType(param, checker));
|
|
691
|
+
}
|
|
692
|
+
});
|
|
693
|
+
return map;
|
|
694
|
+
}
|
|
695
|
+
function finalizeReturnType(inferredType, node) {
|
|
696
|
+
var _a;
|
|
697
|
+
const isAsync = !!((_a = node.modifiers) === null || _a === void 0 ? void 0 : _a.some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword));
|
|
698
|
+
if (!isAsync) {
|
|
699
|
+
return inferredType;
|
|
700
|
+
}
|
|
701
|
+
if (inferredType.startsWith("Promise<")) {
|
|
702
|
+
return inferredType;
|
|
703
|
+
}
|
|
704
|
+
return `Promise<${inferredType}>`;
|
|
705
|
+
}
|
|
706
|
+
function isObject(value) {
|
|
707
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
708
|
+
}
|
|
709
|
+
function isFunctionLike(node) {
|
|
710
|
+
return (ts.isFunctionDeclaration(node) ||
|
|
711
|
+
ts.isFunctionExpression(node) ||
|
|
712
|
+
ts.isArrowFunction(node) ||
|
|
713
|
+
ts.isMethodDeclaration(node) ||
|
|
714
|
+
ts.isGetAccessorDeclaration(node) ||
|
|
715
|
+
ts.isSetAccessorDeclaration(node) ||
|
|
716
|
+
ts.isConstructorDeclaration(node));
|
|
717
|
+
}
|
|
718
|
+
function normalizeProvider(provider) {
|
|
719
|
+
return provider === "gemini" ? "gemini" : "openai";
|
|
720
|
+
}
|
|
721
|
+
function resolveApiKeyFromEnv(provider) {
|
|
722
|
+
if (provider === "gemini") {
|
|
723
|
+
return process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY;
|
|
724
|
+
}
|
|
725
|
+
return process.env.OPENAI_API_KEY;
|
|
726
|
+
}
|
|
727
|
+
function applyProviderDefaults(ai) {
|
|
728
|
+
if (ai.provider === "gemini") {
|
|
729
|
+
if (!ai.model || ai.model === OPENAI_AI_DEFAULTS.model) {
|
|
730
|
+
ai.model = GEMINI_AI_DEFAULTS.model;
|
|
731
|
+
}
|
|
732
|
+
if (!ai.baseUrl || ai.baseUrl === OPENAI_AI_DEFAULTS.baseUrl) {
|
|
733
|
+
ai.baseUrl = GEMINI_AI_DEFAULTS.baseUrl;
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
else {
|
|
737
|
+
if (!ai.model || ai.model === GEMINI_AI_DEFAULTS.model) {
|
|
738
|
+
ai.model = OPENAI_AI_DEFAULTS.model;
|
|
739
|
+
}
|
|
740
|
+
if (!ai.baseUrl || ai.baseUrl === GEMINI_AI_DEFAULTS.baseUrl) {
|
|
741
|
+
ai.baseUrl = OPENAI_AI_DEFAULTS.baseUrl;
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
if (!ai.promptTemplate) {
|
|
745
|
+
ai.promptTemplate = DEFAULT_PROMPT_TEMPLATE;
|
|
746
|
+
}
|
|
747
|
+
if (!ai.timeoutMs || ai.timeoutMs <= 0) {
|
|
748
|
+
ai.timeoutMs =
|
|
749
|
+
ai.provider === "gemini"
|
|
750
|
+
? GEMINI_AI_DEFAULTS.timeoutMs
|
|
751
|
+
: OPENAI_AI_DEFAULTS.timeoutMs;
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
function buildGeminiEndpoint(baseUrl, model, apiKey) {
|
|
755
|
+
const cleanBaseUrl = baseUrl.replace(/\/+$/, "");
|
|
756
|
+
const encodedModel = encodeURIComponent(model);
|
|
757
|
+
const encodedApiKey = encodeURIComponent(apiKey);
|
|
758
|
+
return `${cleanBaseUrl}/models/${encodedModel}:generateContent?key=${encodedApiKey}`;
|
|
759
|
+
}
|
|
760
|
+
function createTypeChecker(filePath, sourceCode, scriptKind, sourceFile) {
|
|
761
|
+
const virtualPath = resolveVirtualPath(filePath, scriptKind);
|
|
762
|
+
const options = {
|
|
763
|
+
target: ts.ScriptTarget.ESNext,
|
|
764
|
+
allowJs: true,
|
|
765
|
+
checkJs: false,
|
|
766
|
+
jsx: ts.JsxEmit.Preserve,
|
|
767
|
+
skipLibCheck: true,
|
|
768
|
+
};
|
|
769
|
+
const defaultHost = ts.createCompilerHost(options, true);
|
|
770
|
+
const normalizedVirtualPath = path.resolve(virtualPath);
|
|
771
|
+
const host = Object.assign(Object.assign({}, defaultHost), { getSourceFile: (targetFileName, languageVersion, onError, shouldCreateNewSourceFile) => {
|
|
772
|
+
if (path.resolve(targetFileName) === normalizedVirtualPath) {
|
|
773
|
+
return sourceFile;
|
|
774
|
+
}
|
|
775
|
+
return defaultHost.getSourceFile(targetFileName, languageVersion, onError, shouldCreateNewSourceFile);
|
|
776
|
+
}, readFile: (targetFileName) => {
|
|
777
|
+
if (path.resolve(targetFileName) === normalizedVirtualPath) {
|
|
778
|
+
return sourceCode;
|
|
779
|
+
}
|
|
780
|
+
return defaultHost.readFile(targetFileName);
|
|
781
|
+
}, fileExists: (targetFileName) => {
|
|
782
|
+
if (path.resolve(targetFileName) === normalizedVirtualPath) {
|
|
783
|
+
return true;
|
|
784
|
+
}
|
|
785
|
+
return defaultHost.fileExists(targetFileName);
|
|
786
|
+
} });
|
|
787
|
+
try {
|
|
788
|
+
const program = ts.createProgram([normalizedVirtualPath], options, host);
|
|
789
|
+
return program.getTypeChecker();
|
|
790
|
+
}
|
|
791
|
+
catch (_a) {
|
|
792
|
+
return undefined;
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
function resolveVirtualPath(filePath, scriptKind) {
|
|
796
|
+
const ext = path.extname(filePath);
|
|
797
|
+
if (ext && ext !== ".vue") {
|
|
798
|
+
return filePath;
|
|
799
|
+
}
|
|
800
|
+
const suffixByKind = {
|
|
801
|
+
[ts.ScriptKind.TS]: ".ts",
|
|
802
|
+
[ts.ScriptKind.TSX]: ".tsx",
|
|
803
|
+
[ts.ScriptKind.JS]: ".js",
|
|
804
|
+
[ts.ScriptKind.JSX]: ".jsx",
|
|
64
805
|
};
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
...paramTags.map((tag) => `* @param {${tag.type}} ${tag.name}`),
|
|
68
|
-
`* @returns {${returnTag.type}}`,
|
|
69
|
-
].join("\n");
|
|
70
|
-
return { comment: `*\n${commentText}\n` };
|
|
806
|
+
const suffix = suffixByKind[scriptKind] || ".js";
|
|
807
|
+
return `${filePath}${suffix}`;
|
|
71
808
|
}
|