qingkuai-language-service
Version:
The language service for qingkuai
1,419 lines (1,392 loc) • 55.9 kB
JavaScript
'use strict';
var compiler = require('qingkuai/compiler');
var internal = require('qingkuai/internal');
const DEFAULT_POSITION = {
line: 0,
character: 0
};
const DEFAULT_RANGE = {
start: DEFAULT_POSITION,
end: DEFAULT_POSITION
};
({
...DEFAULT_RANGE});
const INTER_NAMESPACE = "__c__";
const TS_REFS_DECLARATION_LEN = 27;
const JS_REFS_DECLARATION_LEN = 32;
const TS_PROPS_DECLARATION_LEN = 28;
const JS_PROPS_DECLARATION_LEN = 33;
var GlobalTypeIdentifier = /* @__PURE__ */ ((GlobalTypeIdentifier2) => {
GlobalTypeIdentifier2["Ref"] = "Refs";
GlobalTypeIdentifier2["Prop"] = "Props";
return GlobalTypeIdentifier2;
})(GlobalTypeIdentifier || {});
const GLOBAL_TYPE_IDNTIFIERS = /* @__PURE__ */ new Set([
"Refs" /* Ref */,
"Props" /* Prop */
]);
const GLOBAL_BUILTIN_VARS = /* @__PURE__ */ new Set(["props", "refs"]);
let ts;
let fs;
let path;
exports.typeRefStatement = void 0;
exports.typeDeclarationFilePath = void 0;
exports.getConfig = void 0;
let getFullFileNames;
let getUserPreferences;
exports.getCompileInfo = void 0;
let getLineAndCharacter;
let getFormattingOptions;
let getInterIndexByLineAndCharacter;
const tsFileNameToRealPath = /* @__PURE__ */ new Map();
const resolvedQingkuaiModule = /* @__PURE__ */ new Map();
const qingkuaiDiagnostics = /* @__PURE__ */ new Map();
function createLsAdapter(options) {
ts = options.ts;
fs = options.fs;
path = options.path;
exports.getConfig = options.getConfig;
exports.getCompileInfo = options.getCompileInfo;
getFullFileNames = options.getFullFileNames;
getUserPreferences = options.getUserPreferences;
getLineAndCharacter = options.getLineAndCharacter;
options.getTsLanguageService;
getFormattingOptions = options.getFormattingOptions;
exports.typeDeclarationFilePath = options.typeDeclarationFilePath;
getInterIndexByLineAndCharacter = options.getInterIndexByLineAndCharacter;
exports.typeRefStatement = `import {${INTER_NAMESPACE},wat,waT,Wat,der,stc,rea} from "${exports.typeDeclarationFilePath}"
`;
}
const endingInvalidStrRE = /\s*;?$/;
const qkExtInImportRE = /\.qk(['"]\s*)$/;
const reactCompilerFuncRE = /^(?:rea|stc|der)$/;
const watchCompilerFuncRE = /^(?:wat|Wat|waT)$/;
const globalTypeIdentifierRE = /^(Props|Refs)$/;
const addImportTextEditRE = /^\s*import .* from/;
const validIdentifierRE = /^[a-zA-Z_$][a-zA-Z_$\d]*$/;
const existingTopScopeIdentifierRE = /^(?:rea|stc|der|wat|Wat|waT|props|refs)$/;
function debugAssert(v) {
if (!v) {
debugger;
}
}
function isNull(v) {
return v === null;
}
function isString(v) {
return typeof v === "string";
}
function isNumber(v) {
return typeof v === "number";
}
function isEmptyString(v) {
return v === "";
}
function isUndefined(v) {
return v === void 0;
}
function isQingkuaiFileName(fileName) {
return fileName.endsWith(".qk");
}
function getKindName(node) {
return ts.SyntaxKind[node.kind];
}
function isTopLevelAwait(node) {
if (!ts.isAwaitExpression(node)) {
return false;
}
while (node && !ts.isSourceFile(node)) {
if (ts.isFunctionLike(node)) {
return false;
}
node = node.parent;
}
return true;
}
function getLength(nodeOrText) {
if (!isString(nodeOrText)) {
nodeOrText = nodeOrText.getText();
}
return nodeOrText.replace(endingInvalidStrRE, "").length;
}
function isInTopScope(node) {
while (!ts.isSourceFile(node)) {
node = node.parent;
if (ts.isBlock(node) || ts.isCaseBlock(node) || ts.isModuleBlock(node) || ts.isClassExpression(node) || ts.isClassDeclaration(node) || ts.isClassStaticBlockDeclaration(node)) {
return false;
}
}
return true;
}
function isReactFuncDecalration(node) {
const { parent } = node;
if (ts.isAsExpression(parent) || ts.isSatisfiesExpression(parent) || ts.isTypeAssertionExpression(parent) || ts.isParenthesizedExpression(parent)) {
return isReactFuncDecalration(parent.parent);
}
return ts.isVariableDeclaration(parent) ? parent : null;
}
function findAncestorUntil(node, kind) {
while (node.kind !== kind) {
node = node.parent;
if (!node) {
return void 0;
}
}
return node;
}
function isEventType(type) {
if (type.isClass()) {
return false;
}
if (type.isUnion()) {
return type.types.some(isEventType);
}
return !!(type.getCallSignatures().length || type.symbol?.name === "Function");
}
function isAssignable(node, allowConst, typeChecker) {
if (ts.isIdentifier(node)) {
const symbol = typeChecker.getSymbolAtLocation(node);
if (!symbol || allowConst) {
return true;
}
for (const decl of symbol.declarations ?? []) {
if (ts.isVariableDeclaration(decl) && ts.isVariableDeclarationList(decl.parent) && decl.parent.flags & ts.NodeFlags.Const) {
return false;
}
if (ts.isImportSpecifier(decl) || ts.isImportClause(decl) || ts.isNamespaceImport(decl)) {
return false;
}
}
return true;
}
if (!ts.isPropertyAccessExpression(node) && !ts.isElementAccessExpression(node)) {
return false;
}
return !node.questionDotToken;
}
function isDeclarationOfGlobalType(symbol) {
return symbol?.declarations?.length === 1 && symbol.declarations[0].getSourceFile().fileName === exports.typeDeclarationFilePath;
}
function walk$1(node, callback) {
if (!isUndefined(node)) {
callback(node), ts.forEachChild(node, (cn) => walk$1(cn, callback));
}
}
function getNodeAt(node, pos) {
const [start, len] = [node.getStart(), node.getWidth()];
if (pos >= start && pos <= start + len) {
for (const child of node.getChildren()) {
const foundInChild = getNodeAt(child, pos);
if (foundInChild) {
return foundInChild;
}
}
return node;
}
return void 0;
}
function isBuiltInGlobalDeclaration(node, typeChecker) {
const symbol = typeChecker.getSymbolAtLocation(node);
for (const declaration of symbol?.declarations || []) {
const variableDeclaration = findAncestorUntil(
declaration,
ts.SyntaxKind.VariableDeclaration
);
return variableDeclaration && isInTopScope(variableDeclaration);
}
}
function findNodeAtPosition(sourceFile, position) {
function find(node) {
if (position >= node.getStart() && position < node.getEnd()) {
return ts.forEachChild(node, find) || node;
}
return void 0;
}
return find(sourceFile);
}
function isSymbolKey(symbol) {
if (!symbol.declarations) {
return false;
}
return symbol.declarations.some((decl) => {
const name = decl.name;
if (!name || !("expression" in name)) {
return false;
}
return ts.isIdentifier(name.expression) && name.expression.escapedText === "symbol" || ts.isComputedPropertyName(name) && ts.isPropertyAccessExpression(name.expression);
});
}
var tsAst = /*#__PURE__*/Object.freeze({
__proto__: null,
findAncestorUntil: findAncestorUntil,
findNodeAtPosition: findNodeAtPosition,
getKindName: getKindName,
getLength: getLength,
getNodeAt: getNodeAt,
isAssignable: isAssignable,
isBuiltInGlobalDeclaration: isBuiltInGlobalDeclaration,
isDeclarationOfGlobalType: isDeclarationOfGlobalType,
isEventType: isEventType,
isInTopScope: isInTopScope,
isReactFuncDecalration: isReactFuncDecalration,
isSymbolKey: isSymbolKey,
isTopLevelAwait: isTopLevelAwait,
walk: walk$1
});
function filePathToComponentName(path, filePath) {
let base = path.base(filePath);
base = base.replace(/[^a-zA-Z]*/, "");
base = base.replace(/[^a-zA-Z\d]/g, "");
if (!base) {
return "Anonymous";
}
return compiler.util.kebab2Camel(base, true);
}
function isIndexesInvalid(...items) {
return items.some((item) => {
return !item || item === -1;
});
}
function getRealPath(fileName) {
return tsFileNameToRealPath.get(fileName) || fileName;
}
function isPositionFlagSetBySourceIndex(fileName, sourceIndex, key) {
return !!(exports.getCompileInfo(fileName).positions[sourceIndex].flag & compiler.PositionFlag[key]);
}
function isPositionFlagSetByInterIndex(fileName, interIndex, key, isEnd = false) {
const sourceIndex = getSourceIndex(fileName, interIndex, isEnd);
return !isIndexesInvalid(sourceIndex) && isPositionFlagSetBySourceIndex(fileName, sourceIndex, key);
}
function isComponentIdentifier(fileName, identifier, typeChecker) {
const symbol = typeChecker.getSymbolAtLocation(identifier);
if (symbol && symbol.flags & ts.SymbolFlags.Alias) {
for (const declaration of symbol.declarations || []) {
if (ts.isImportClause(declaration) && ts.isImportDeclaration(declaration.parent) && ts.isStringLiteral(declaration.parent.moduleSpecifier)) {
const resolvedModules = resolvedQingkuaiModule.get(fileName);
return !!resolvedModules?.has(declaration.parent.moduleSpecifier.text);
}
}
}
return isInTopScope(identifier) && identifier.getText() === filePathToComponentName(path, fileName);
}
function recordRealPath(realFileName) {
if (isQingkuaiFileName(realFileName) && !tsFileNameToRealPath.has(realFileName)) {
const normalizedPath = ts.server.toNormalizedPath(realFileName).toString();
if (normalizedPath !== realFileName) {
tsFileNameToRealPath.set(normalizedPath, realFileName);
}
}
}
function getSourceIndex(fileName, interIndex, isEnd = false) {
if (!isQingkuaiFileName(fileName)) {
return interIndex;
}
const { itos } = exports.getCompileInfo(fileName);
const sourceIndex = itos[interIndex];
if (!isEnd || !isIndexesInvalid(sourceIndex)) {
return sourceIndex ?? -1;
}
const preSourceIndex = itos[interIndex - 1];
return isIndexesInvalid(sourceIndex) ? -1 : preSourceIndex + 1;
}
var qingkuai = /*#__PURE__*/Object.freeze({
__proto__: null,
getRealPath: getRealPath,
getSourceIndex: getSourceIndex,
isComponentIdentifier: isComponentIdentifier,
isPositionFlagSetByInterIndex: isPositionFlagSetByInterIndex,
isPositionFlagSetBySourceIndex: isPositionFlagSetBySourceIndex,
recordRealPath: recordRealPath
});
function proxyGetCompletionsAtPosition(languageService) {
const getCompletionsAtPosition = languageService.getCompletionsAtPosition;
languageService.getCompletionsAtPosition = (fileName, position, ...rest) => {
const originalResult = getCompletionsAtPosition.call(
languageService,
fileName,
position,
...rest
);
if (originalResult?.entries) {
originalResult.entries = originalResult.entries.filter((entry) => {
if (!entry.source) {
return true;
}
if (/\.\//.test(entry.source)) {
return !exports.typeDeclarationFilePath.startsWith(
path.resolve(path.dir(fileName), entry.source)
);
}
return entry.source !== "qingkuai/internal";
});
}
return originalResult;
};
}
function proxyResolveModuleNameLiterals(languageServiceHost, couldBeImpoted) {
const resolveModuleLiterals = languageServiceHost.resolveModuleNameLiterals;
if (isUndefined(resolveModuleLiterals)) {
return;
}
languageServiceHost.resolveModuleNameLiterals = (moduleLiterals, containingFile, ...rest) => {
const containingFileRealPath = getRealPath(containingFile);
const originalRet = resolveModuleLiterals.call(
languageServiceHost,
moduleLiterals,
containingFile,
...rest
);
const qingkuaiModules = /* @__PURE__ */ new Set();
const curDir = path.dir(containingFileRealPath);
const config = exports.getConfig(containingFileRealPath);
const fromQk = isQingkuaiFileName(containingFile);
const ret = originalRet.map((item, index) => {
const moduleText = moduleLiterals[index].text;
const isDirectory = isEmptyString(path.ext(moduleText));
const resolveAsQk = fromQk && isDirectory && config?.resolveImportExtension;
const modulePath = path.resolve(curDir, moduleText + (resolveAsQk ? ".qk" : ""));
if (!isQingkuaiFileName(modulePath)) {
return item;
}
if (!fs.exist(modulePath)) {
return {
...item,
failedLookupLocations: [modulePath]
};
}
if (!couldBeImpoted(modulePath)) {
return item;
}
qingkuaiModules.add(moduleText);
const scriptKind = languageServiceHost.getScriptKind?.(modulePath);
return {
...item,
resolvedModule: {
isExternalLibraryImport: false,
resolvedUsingTsExtension: false,
resolvedFileName: ts.server.toNormalizedPath(modulePath),
extension: scriptKind === ts.ScriptKind.TS ? ".ts" : ".js"
},
failedLookupLocations: void 0
};
});
if (qingkuaiModules.size) {
resolvedQingkuaiModule.set(containingFileRealPath, qingkuaiModules);
}
return ret;
};
}
var proxies = /*#__PURE__*/Object.freeze({
__proto__: null,
proxyGetCompletionsAtPosition: proxyGetCompletionsAtPosition,
proxyResolveModuleNameLiterals: proxyResolveModuleNameLiterals
});
const COMPILER_FUNCS = /* @__PURE__ */ new Set(["rea", "der", "stc", "wat", "Wat", "waT"]);
const SCRIPT_EXTENSIONS = /* @__PURE__ */ new Set([".d.ts", ".ts", ".tsx", ".js", ".jsx", ".json"]);
function stringify(v) {
return JSON.stringify(v);
}
function ensureExport(languageService, fileName, content, typeDeclarationLen) {
const program = languageService.getProgram();
const typeChecker = program.getTypeChecker();
const sourceFile = program.getSourceFile(fileName);
debugAssert(!!sourceFile);
const config = exports.getConfig(fileName);
const contentArr = content.split("");
const existingGlobalType = /* @__PURE__ */ new Set();
const diagnosticsCache = [];
const compileInfo = exports.getCompileInfo(fileName);
const storedTypes = /* @__PURE__ */ new Map();
const typeRefStatementLen = exports.typeRefStatement.length;
const slotInfoKeys = Object.keys(compileInfo.slotInfo);
const isTS = compileInfo.scriptKind === ts.ScriptKind.TS;
const componentName = filePathToComponentName(path, fileName);
const { slotInfo, itos, refAttrValueStartIndexes } = compileInfo;
const builtInTypeDeclarationEndIndex = exports.typeRefStatement.length + typeDeclarationLen;
slotInfoKeys.forEach((slotName) => {
slotInfo[slotName].properties.forEach((property) => {
if (isNumber(property[2])) {
storedTypes.set(property[2], "");
}
});
});
qingkuaiDiagnostics.set(fileName, diagnosticsCache);
const eliminateContentByLength = (start, length) => {
for (let i = 0; i < length; i++) {
contentArr[start + i] = " ";
}
};
const eliminateContentByRange = (start, end) => {
for (let i = start; i < end; i++) {
contentArr[i] = " ";
}
};
const markGlobalTypeExisting = (identifierName, startIndex) => {
if (startIndex > builtInTypeDeclarationEndIndex && globalTypeIdentifierRE.test(identifierName)) {
existingGlobalType.add(identifierName);
}
};
const recordQingkuaiDiagnostic = (start, length, category, message) => {
if (isUndefined(itos[start]) || itos[start] === -1) {
return;
}
diagnosticsCache.push({
start,
length,
category,
source: "qk",
file: void 0,
code: message.code,
messageText: message.msg
});
};
walk$1(sourceFile, (node) => {
const [start, length] = [node.getStart(), getLength(node)];
if (ts.isBinaryExpression(node) && storedTypes.has(node.right.pos) && node.left.getText() === INTER_NAMESPACE + ".Receiver" && node.operatorToken.kind === ts.SyntaxKind.EqualsToken) {
const type = typeChecker.getTypeAtLocation(node.right);
const typeStr = typeChecker.typeToString(type);
storedTypes.set(node.right.pos, typeStr);
}
if (isTopLevelAwait(node)) {
recordQingkuaiDiagnostic(
start,
length,
ts.DiagnosticCategory.Error,
getCompilerCommonMessage("TopLevelAwaitNotBeSupported")
);
}
if (ts.isNewExpression(node) && ts.isIdentifier(node.expression) && isComponentIdentifier(fileName, node.expression, typeChecker) && isPositionFlagSetByInterIndex(fileName, start, "inScript")) {
eliminateContentByRange(start, node.expression.getStart());
eliminateContentByRange(node.expression.getEnd(), node.getEnd());
contentArr[node.expression.getStart() - 1] = ";";
contentArr[node.getEnd() - 1] = ";";
recordQingkuaiDiagnostic(
start,
getLength(node),
ts.DiagnosticCategory.Error,
getRuntimeCommonMessage("InstantiateComponentManually")
);
}
if (!isTS && existingGlobalType.size < 2) {
const typeDefNodes = ts.getJSDocTags(node).filter((jsDocNode) => {
return ts.isJSDocTypedefTag(jsDocNode);
});
if (typeDefNodes.length > 0 && isInTopScope(node)) {
typeDefNodes.forEach((typeDefNode) => {
markGlobalTypeExisting(
ts.getNameOfJSDocTypedef(typeDefNode)?.text || "",
typeDefNode.getStart()
);
});
}
}
if (isTS && (ts.isTypeAliasDeclaration(node) || ts.isInterfaceDeclaration(node))) {
isInTopScope(node) && markGlobalTypeExisting(node.name.text, start);
}
if (ts.isParenthesizedExpression(node) && refAttrValueStartIndexes.has(start)) {
const allowConst = content[start - 1] !== " ";
if (!isAssignable(node.expression, allowConst, typeChecker)) {
recordQingkuaiDiagnostic(
node.expression.getStart(),
getLength(node.expression),
ts.DiagnosticCategory.Error,
getCompilerCommonMessage(
"BadValueToReferenceAttribute",
node.expression.getText(),
allowConst
)
);
}
}
if (isTS && ts.isImportDeclaration(node) && isInTopScope(node)) {
if (!isUndefined(node.importClause?.name) && globalTypeIdentifierRE.test(node.importClause.name.text)) {
const symbol = typeChecker.getSymbolAtLocation(node.importClause.name);
const aliasedSymbol = symbol && typeChecker.getAliasedSymbol(symbol);
if (aliasedSymbol && aliasedSymbol.flags & ts.SymbolFlags.Type) {
existingGlobalType.add(node.importClause.name.text);
}
}
if (!isUndefined(node.importClause?.namedBindings) && ts.isNamedImports(node.importClause.namedBindings)) {
for (const element of node.importClause.namedBindings.elements) {
if (!globalTypeIdentifierRE.test(element.name.text)) {
continue;
}
const symbol = typeChecker.getSymbolAtLocation(element.name);
const aliasedSymbol = symbol && typeChecker.getAliasedSymbol(symbol);
if (aliasedSymbol && aliasedSymbol.flags & ts.SymbolFlags.Type) {
existingGlobalType.add(element.name.text);
}
}
}
}
if (ts.isIdentifier(node) && compiler.util.isBannedIdentifier(node.text)) {
recordQingkuaiDiagnostic(
start,
getLength(node),
ts.DiagnosticCategory.Error,
getCompilerCommonMessage("IdentifierFormatIsNotAllowed", node.text)
);
}
if (ts.isExportAssignment(node) || node.modifiers?.some((m) => {
return m.kind === ts.SyntaxKind.ExportKeyword;
})) {
recordQingkuaiDiagnostic(
start,
length,
ts.DiagnosticCategory.Error,
getCompilerCommonMessage("BadExportRelatedStatement")
);
if (ts.isExportAssignment(node)) {
eliminateContentByLength(start, length);
}
}
if (ts.isEnumDeclaration(node) || ts.isClassDeclaration(node) || ts.isModuleDeclaration(node) || ts.isVariableDeclaration(node) || ts.isFunctionDeclaration(node)) {
if (!isUndefined(node.name)) {
const identifierName = node.name.getText();
if (identifierName === "$arg") {
if (isInTopScope(node)) {
recordQingkuaiDiagnostic(
node.name.getStart(),
getLength(node.name),
ts.DiagnosticCategory.Warning,
getCompilerCommonMessage("IdentifierMaybeOverwritten", "$arg")
);
}
} else if (existingTopScopeIdentifierRE.test(identifierName)) {
recordQingkuaiDiagnostic(
node.name.getStart(),
getLength(node.name),
ts.DiagnosticCategory.Error,
getCompilerCommonMessage("RegisterExsitingIdentifierName", identifierName)
);
}
}
}
if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && COMPILER_FUNCS.has(node.expression.text)) ;
if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && COMPILER_FUNCS.has(node.expression.text)) {
const funcName = node.expression.text;
if (reactCompilerFuncRE.test(funcName)) {
const commonDiagnosticArgs = [start, length, ts.DiagnosticCategory.Error];
if (!isInTopScope(node)) {
recordQingkuaiDiagnostic(
...commonDiagnosticArgs,
getCompilerCommonMessage("ReactCompilerFuncNotInTopScope")
);
}
const variableDeclarationNode = isReactFuncDecalration(node);
if (isNull(variableDeclarationNode)) {
recordQingkuaiDiagnostic(
...commonDiagnosticArgs,
getCompilerCommonMessage("ReactCompilerFuncWithoutVariableDeclaration")
);
} else {
if (
// prettier-ignore
node.arguments.length === 0 && (ts.isArrayBindingPattern(variableDeclarationNode.name) || ts.isObjectBindingPattern(variableDeclarationNode.name))
) {
recordQingkuaiDiagnostic(
start,
length,
ts.DiagnosticCategory.Error,
getCompilerCommonMessage("DestructureReactFuncWithNoArg", funcName)
);
}
if (config?.convenientDerivedDeclaration && variableDeclarationNode.name.getText().startsWith("$")) {
if (funcName === "der") {
recordQingkuaiDiagnostic(
variableDeclarationNode.getStart(),
getLength(variableDeclarationNode),
ts.DiagnosticCategory.Warning,
getCompilerCommonMessage("MixTwoSyntaxOfDerived")
);
} else {
recordQingkuaiDiagnostic(
variableDeclarationNode.getStart(),
getLength(variableDeclarationNode),
ts.DiagnosticCategory.Error,
getCompilerCommonMessage(
"ConvenientDerivedWithOtherReactFunc",
funcName
)
);
}
}
if (!isTS && node.arguments.length > 1 && (funcName === "der" || funcName === "stc")) {
recordQingkuaiDiagnostic(
start,
length,
ts.DiagnosticCategory.Warning,
getCompilerCommonMessage("RedundantArgsForCompilerFunc", funcName, 1)
);
}
if (!isTS && funcName === "rea" && node.arguments.length > 2) {
recordQingkuaiDiagnostic(
start,
length,
ts.DiagnosticCategory.Warning,
getCompilerCommonMessage("RedundantArgsForCompilerFunc", funcName, 2)
);
}
}
} else if (watchCompilerFuncRE.test(funcName)) {
if (node.arguments.length < 2) {
recordQingkuaiDiagnostic(
start,
length,
ts.DiagnosticCategory.Error,
getCompilerCommonMessage(
"WatchCompilerFuncMissingArg",
funcName,
node.arguments.length
)
);
} else if (!isTS && node.arguments.length > 2) {
recordQingkuaiDiagnostic(
node.getStart(),
getLength(node),
ts.DiagnosticCategory.Warning,
getCompilerCommonMessage("RedundantArgsForCompilerFunc", funcName, 2)
);
}
}
}
});
if (existingGlobalType.has(GlobalTypeIdentifier.Ref)) {
if (isTS) {
eliminateContentByLength(
typeRefStatementLen + TS_PROPS_DECLARATION_LEN,
TS_REFS_DECLARATION_LEN + 2
);
} else {
eliminateContentByLength(
typeRefStatementLen + JS_PROPS_DECLARATION_LEN + 1,
JS_REFS_DECLARATION_LEN
);
}
}
if (existingGlobalType.has(GlobalTypeIdentifier.Prop)) {
if (isTS) {
eliminateContentByLength(typeRefStatementLen, TS_PROPS_DECLARATION_LEN);
} else {
eliminateContentByLength(typeRefStatementLen + 3, JS_PROPS_DECLARATION_LEN);
}
}
const slotType = slotInfoKeys.reduce((ret, slotName, i) => {
const { properties } = slotInfo[slotName];
const key = validIdentifierRE.test(slotName) ? slotName : stringify(slotName);
const value = properties.reduce((ret2, property, i2) => {
const [name, _, iot] = property;
const key2 = validIdentifierRE.test(name) ? name : stringify(name);
const value2 = isString(iot) ? stringify(iot) : storedTypes.get(iot);
return `${ret2}${key2}:${value2}${i2 === properties.length - 1 ? "}" : ","}`;
}, "{");
return `${ret}${key}:${value}${i === slotInfoKeys.length - 1 ? "" : ","}`;
}, "");
if (isTS) {
contentArr.push(`export default class ${componentName} {
constructor(
_: ${GlobalTypeIdentifier.Prop},
__: ${GlobalTypeIdentifier.Ref},
___: {${slotType}}
){}
}`);
} else {
contentArr.push(`export default class ${componentName} {
/**
* @param {${GlobalTypeIdentifier.Prop}} _
* @param {${GlobalTypeIdentifier.Ref}} __
* @param {{${slotType}}} __
*/
constructor(_, __, ___){}
}`);
}
return contentArr.join("");
}
function getCompilerCommonMessage(key, ...args) {
return {
// @ts-ignore
msg: compiler.commonMessage[key][1](...args),
code: compiler.commonMessage[key][0]
};
}
function getRuntimeCommonMessage(key, ...args) {
return {
// @ts-ignore
msg: internal.commonMessage[key][1](...args),
code: internal.commonMessage[key][0]
};
}
function mdCodeBlockGen(lang, code) {
return "```" + lang + "\n" + code + "\n```";
}
function convertJsDocTagsToMarkdown(tags) {
const labels = tags.map((tag) => {
switch (tag.name) {
case "augments":
case "extends":
case "param":
case "template": {
const body = getTagBody(tag);
if (body?.length === 3) {
const param = body[1];
const doc = body[2];
const label2 = `*@${tag.name}* \`${param}\``;
if (!doc) {
return label2;
}
return label2 + (doc.match(/\r\n|\n/g) ? " \n" + doc : ` \u2014 ${doc}`);
}
break;
}
case "return":
case "returns": {
if (!tag.text?.length) {
return void 0;
}
break;
}
}
const label = `*@${tag.name}*`;
const text = getTagBodyText(tag);
if (!text) {
return label;
}
return label + (text.match(/\r\n|\n/g) ? " \n" + text : ` \u2014 ${text}`);
});
return labels.filter((label) => !!label).join(" \n\n");
}
function convertDisplayPartsToPlainTextWithLink(parts) {
if (isUndefined(parts)) {
return "";
}
return parts.reduce((ret, part) => {
if (part.kind === "linkText") {
let spaceIndex = part.text.indexOf(" ");
if (spaceIndex === -1) {
spaceIndex = part.text.length;
}
return ret + `[${part.text.slice(spaceIndex)}](${part.text.slice(0, spaceIndex)})`;
} else if (part.kind === "linkName") {
const target = part.target;
const args = encodeURIComponent(
JSON.stringify({
end: target.textSpan.start,
start: target.textSpan.start,
path: getRealPath(target.fileName)
})
);
return ret + `[${part.text}](command:qingkuai.openFileByFilePath?${args})`;
}
return (ret + (part.kind === "link" ? "" : part.text || "")).replace(
INTER_NAMESPACE + ".",
""
);
}, "");
}
function getTagBodyText(tag) {
if (!tag.text) {
return void 0;
}
function makeCodeblock(text2) {
if (/^\s*[~`]{3}/m.test(text2)) {
return text2;
}
return "```\n" + text2 + "\n```";
}
let text = convertDisplayPartsToPlainTextWithLink(tag.text);
switch (tag.name) {
case "example": {
const captionTagMatches = text.match(/<caption>(.*?)<\/caption>\s*(\r\n|\n)/);
if (captionTagMatches && captionTagMatches.index === 0) {
return captionTagMatches[1] + "\n" + makeCodeblock(text.slice(captionTagMatches[0].length));
} else {
return makeCodeblock(text);
}
}
case "author": {
const emailMatch = text.match(/(.+)\s<([-.\w]+@[-.\w]+)>/);
if (emailMatch === null) {
return text;
} else {
return `${emailMatch[1]} ${emailMatch[2]}`;
}
}
case "default": {
return makeCodeblock(text);
}
default: {
return text;
}
}
}
function getTagBody(tag) {
if (tag.name === "template") {
const parts = tag.text;
if (parts && typeof parts !== "string") {
const docs = parts.filter((p) => p.kind === "text");
const docsText = docs.map((p) => p.text.replace(/^\s*-?\s*/, "")).join(" ");
const params = parts.filter((p) => p.kind === "typeParameterName");
const paramsText = params.map((p) => p.text).join(", ");
return params ? ["", paramsText, docsText] : void 0;
}
}
return convertDisplayPartsToPlainTextWithLink(tag.text).split(/^(\S+)\s*-?\s*/);
}
function getAndConvertHoverTip(languageService, { fileName, pos }) {
let replacer = "";
const realPath = getRealPath(fileName);
const program = languageService.getProgram();
if (!program) {
return null;
}
const typeChecker = program.getTypeChecker();
const node = getNodeAt(program.getSourceFile(fileName), pos);
if (node && ts.isIdentifier(node)) {
const nodeRange = [node.getStart(), node.getEnd()];
if (GLOBAL_BUILTIN_VARS.has(node.text) && isBuiltInGlobalDeclaration(node, typeChecker)) {
replacer = INTER_NAMESPACE + ".";
} else if (node.text === INTER_NAMESPACE) {
return {
posRange: nodeRange,
content: "any"
};
} else if (node.parent && ts.isPropertyAccessExpression(node.parent) && node.parent.expression.getText() === INTER_NAMESPACE) {
return {
posRange: nodeRange,
content: "any"
};
} else if (isComponentIdentifier(realPath, node, typeChecker)) {
return {
posRange: [node.getStart(), node.getEnd()],
content: mdCodeBlockGen("ts", `(component) class ${node.text}`)
};
}
}
if (node && node.parent && ts.isNewExpression(node.parent) && ts.isIdentifier(node.parent.expression) && isComponentIdentifier(realPath, node.parent.expression, typeChecker)) {
return {
posRange: [node.parent.expression.getStart(), node.parent.expression.getEnd()],
content: mdCodeBlockGen("ts", `(component) class ${node.parent.expression.text}`)
};
}
const ret = languageService.getQuickInfoAtPosition(fileName, pos);
if (isUndefined(ret)) {
return null;
}
const { start, length } = ret.textSpan;
const display = convertDisplayPartsToPlainTextWithLink(ret.displayParts);
const documentation = convertDisplayPartsToPlainTextWithLink(ret.documentation);
return {
posRange: [start, start + length],
content: mdCodeBlockGen("ts", display.replace(replacer, "")) + "\n" + documentation
};
}
const lineAndCharacter = {
toSource(fileName, lineAndCharacter2, isEnd = false) {
if (!isQingkuaiFileName(fileName)) {
return lineAndCharacter2;
}
const interIndex = getInterIndexByLineAndCharacter(fileName, lineAndCharacter2);
const sourceIndex = getSourceIndex(fileName, interIndex, isEnd);
if (isIndexesInvalid(sourceIndex)) {
return void 0;
}
const position = exports.getCompileInfo(fileName).positions[sourceIndex];
return { line: position.line - 1, character: position.column };
},
toProtocolLocation(lineAndCharacter2) {
return { line: lineAndCharacter2.line + 1, offset: lineAndCharacter2.character + 1 };
}
};
const lsRange = {
fromProtocolTextSpan(fileName, span) {
const sourceStartPosition = lineAndCharacter.toSource(
fileName,
protocolLocation.toLineAndCharacter(span.start)
);
const sourceEndPosition = lineAndCharacter.toSource(
fileName,
protocolLocation.toLineAndCharacter(span.end)
);
if (!sourceStartPosition || !sourceEndPosition) {
return void 0;
}
return { start: sourceStartPosition, end: sourceEndPosition };
},
fromTextSpan(fileName, span) {
if (!isQingkuaiFileName(fileName)) {
const startLineAndCharacter = getLineAndCharacter(fileName, span.start);
const endLineAndCharacter = getLineAndCharacter(fileName, span.start + span.length);
if (!startLineAndCharacter || !endLineAndCharacter) {
return void 0;
}
return { start: startLineAndCharacter, end: endLineAndCharacter };
}
const sourceStartIndex = getSourceIndex(fileName, span.start);
const sourceEndIndex = getSourceIndex(fileName, span.start + span.length, true);
if (isIndexesInvalid(sourceStartIndex, sourceEndIndex)) {
return void 0;
}
const positions = exports.getCompileInfo(fileName).positions;
if (!positions[sourceStartIndex] && !positions[sourceEndIndex]) {
return void 0;
}
const endPosition = positions[sourceEndIndex];
const startPosition = positions[sourceStartIndex];
return {
start: {
line: startPosition.line - 1,
character: startPosition.column
},
end: {
line: endPosition.line - 1,
character: endPosition.column
}
};
},
fromSourceStartAndEnd(fileName, sourceStart, sourceEnd) {
const positions = exports.getCompileInfo(fileName).positions;
return {
start: {
line: positions[sourceStart].line - 1,
character: positions[sourceStart].column
},
end: {
line: positions[sourceEnd].line - 1,
character: positions[sourceEnd].column
}
};
}
};
const protocolLocation = {
toSource(fileName, location, isEnd = false) {
if (!isQingkuaiFileName(fileName)) {
return location;
}
const sourceLineAndCharacter = lineAndCharacter.toSource(
fileName,
this.toLineAndCharacter(location),
isEnd
);
return sourceLineAndCharacter && lineAndCharacter.toProtocolLocation(sourceLineAndCharacter);
},
toLineAndCharacter(location) {
return {
line: location.line - 1,
character: location.offset - 1
};
},
toSourceIndex(fileName, location) {
return getSourceIndex(
fileName,
getInterIndexByLineAndCharacter(fileName, this.toLineAndCharacter(location))
);
}
};
async function findComponentTagRanges(fileName, componentTag, getCompileRes) {
const ranges = [];
const cr = await getCompileRes(fileName);
walk(cr.templateNodes, (node) => {
if (node.componentTag === componentTag) {
ranges.push(cr.getRange(node.range[0], node.range[0] + node.tag.length + 1));
}
});
return ranges;
}
function walk(nodes, cb) {
for (const node of nodes) {
const ret = cb(node);
if (ret) {
return ret;
}
node.children.length && walk(node.children, cb);
}
}
async function findAndConvertReferences(languageService, getCompileRes, { fileName, pos }) {
const sourceFile = languageService.getProgram()?.getSourceFile(fileName);
if (!sourceFile) {
return null;
}
const result = [];
const node = findNodeAtPosition(sourceFile, pos);
if (node?.parent && GLOBAL_TYPE_IDNTIFIERS.has(node.getText()) && (ts.isTypeAliasDeclaration(node.parent) || ts.isInterfaceDeclaration(node.parent))) {
for (const ref of languageService.getFileReferences(fileName)) {
if (!isQingkuaiFileName(fileName)) {
continue;
}
const refRealPath = getRealPath(ref.fileName);
const ranges = await findComponentTagRanges(
refRealPath,
filePathToComponentName(path, fileName),
getCompileRes
);
ranges.forEach((range) => result.push({ fileName: refRealPath, range }));
}
}
const res = languageService.findReferences(fileName, pos);
for (const item of res || []) {
for (const ref of item.references) {
if (ref.isDefinition) {
continue;
}
const range = lsRange.fromTextSpan(ref.fileName, ref.textSpan);
range && result.push({ fileName: getRealPath(ref.fileName), range });
}
}
return result;
}
function getAndConvertDiagnostics(languageService, fileName, isSemanticProject) {
const realPath = getRealPath(fileName);
const diagnostics = [];
const diagnosticMethods = ["getSyntacticDiagnostics"];
if (isSemanticProject) {
diagnosticMethods.push("getSemanticDiagnostics", "getSuggestionDiagnostics");
}
diagnosticMethods.forEach((m) => {
diagnostics.push(...languageService[m](fileName));
});
const result = [];
for (const item of diagnostics.concat(qingkuaiDiagnostics.get(realPath) || [])) {
const start = item.start ?? 0;
const end = start + (item.length ?? 0);
const ss = getSourceIndex(fileName, start);
const se = getSourceIndex(fileName, end, true);
if (isIndexesInvalid(ss, se) || shouldBeIgnored(realPath, item, ss, se)) {
continue;
}
const relatedInformations = [];
const filteredRelatedInformations = (item.relatedInformation || []).filter((ri) => !!ri.file);
for (const ri of filteredRelatedInformations) {
let range;
const start2 = ri.start ?? 0;
const end2 = start2 + (ri.length ?? 0);
const realPath2 = getRealPath(ri.file.fileName);
if (!isQingkuaiFileName(realPath2)) {
range = {
start: getLineAndCharacter(realPath2, start2),
end: getLineAndCharacter(realPath2, end2)
};
} else {
const ss2 = getSourceIndex(realPath2, start2);
const se2 = getSourceIndex(realPath2, end2, true);
if (isIndexesInvalid(ss2, se2)) {
continue;
}
range = lsRange.fromSourceStartAndEnd(realPath2, ss2, se2);
}
relatedInformations.push({
range,
filePath: getRealPath(ri.file.fileName),
message: formatDiagnosticMessage(ri.messageText)
});
}
result.push({
relatedInformations,
code: item.code,
kind: item.category,
source: item.source || "ts",
deprecated: Boolean(item.reportsDeprecated),
unnecessary: Boolean(item.reportsUnnecessary),
message: formatDiagnosticMessage(item.messageText),
range: lsRange.fromSourceStartAndEnd(fileName, ss, se)
});
}
return result;
}
function shouldBeIgnored(fileName, item, sourceStart, sourceEnd) {
switch (item.code) {
case 2684: {
return isPositionFlagSetBySourceIndex(fileName, sourceEnd, "inNormalTagInlineEvent") || isPositionFlagSetBySourceIndex(fileName, sourceStart, "inNormalTagInlineEvent");
}
default: {
return false;
}
}
}
function formatDiagnosticMessage(mt, indentLevel = 0) {
const indent = " ".repeat(indentLevel * 2);
const eliminate = (s) => {
return s.replace(` Did you mean '${INTER_NAMESPACE}'?`, "");
};
if (isString(mt)) {
return eliminate(mt);
}
if (isUndefined(mt.next)) {
return eliminate(mt.messageText);
}
const nextMsg = mt.next.reduce((p, c) => {
return p + indent + formatDiagnosticMessage(c, indentLevel + 1);
}, "");
return eliminate(mt.messageText) + "\n" + nextMsg;
}
function getAndConvertSignatureHelp(languageService, lsParams) {
let reason = void 0;
const { fileName, pos, isRetrigger, triggerCharacter } = lsParams;
const sourceFile = languageService.getProgram()?.getSourceFile(fileName);
if (sourceFile) {
const node = getNodeAt(sourceFile, pos);
const callee = node && findAncestorUntil(node, ts.SyntaxKind.CallExpression);
if (callee?.getText().startsWith(INTER_NAMESPACE)) {
return null;
}
}
if (isRetrigger) {
reason = {
kind: "retrigger",
triggerCharacter
};
} else if (triggerCharacter) {
reason = {
kind: "characterTyped",
triggerCharacter
};
} else {
reason = {
kind: "invoked"
};
}
const options = { triggerReason: reason };
const getSignatureHelpRes = languageService?.getSignatureHelpItems(fileName, pos, options);
if (!getSignatureHelpRes) {
return null;
}
return {
signatures: convertSignatures(getSignatureHelpRes.items),
activeParameter: getActiveParameter(getSignatureHelpRes),
activeSignature: getSignatureHelpRes.selectedItemIndex
};
}
function getActiveParameter(info) {
const activeSignature = info.items[info.selectedItemIndex];
if (activeSignature?.isVariadic) {
return Math.min(info.argumentIndex, activeSignature.parameters.length - 1);
}
return info.argumentIndex;
}
function convertSignatures(items) {
return items.map((item) => {
const signatureLabelParts = [
convertDisplayPartsToPlainTextWithLink(item.prefixDisplayParts)
];
const separate = convertDisplayPartsToPlainTextWithLink(item.separatorDisplayParts);
const parameters = item.parameters.map((p, i) => {
const parameterLabel = convertDisplayPartsToPlainTextWithLink(p.displayParts);
const documentation2 = convertDisplayPartsToPlainTextWithLink(p.documentation);
signatureLabelParts.push(
parameterLabel,
i === item.parameters.length - 1 ? "" : separate
);
const parameter = { label: parameterLabel };
if (documentation2) {
parameter.documentation = {
kind: "markdown",
value: documentation2
};
}
return parameter;
});
signatureLabelParts.push(convertDisplayPartsToPlainTextWithLink(item.suffixDisplayParts));
const signature = { label: signatureLabelParts.join(""), parameters };
const documentation = convertDisplayPartsToPlainTextWithLink(item.documentation) + convertJsDocTagsToMarkdown(item.tags.filter((t) => t.name !== "param"));
if (documentation) {
signature.documentation = {
kind: "markdown",
value: documentation
};
}
return signature;
});
}
function findAndConvertImplementations(languageService, { fileName, pos }) {
const implementations = languageService.getImplementationAtPosition(fileName, pos);
if (!implementations) {
return null;
}
const result = [];
for (const { fileName: fileName2, textSpan } of implementations) {
const range = lsRange.fromTextSpan(fileName2, textSpan);
range && result.push({ range, fileName: fileName2 });
}
return result;
}
function renameAndConvert(languageService, { fileName, pos }) {
const locations = [];
const existringMap = /* @__PURE__ */ new Map();
const renameLocations = languageService.findRenameLocations(
fileName,
pos,
false,
false,
getUserPreferences(fileName)
);
if (!renameLocations) {
return null;
}
renameLocations.forEach((item) => {
const { start, length } = item.textSpan;
const realPath = getRealPath(item.fileName);
const locationItem = { fileName: realPath };
[locationItem.prefix, locationItem.suffix] = [item.prefixText, item.suffixText];
if (isQingkuaiFileName(item.fileName)) {
const sourceStart = getSourceIndex(item.fileName, start);
const existing = existringMap.get(realPath) || /* @__PURE__ */ new Set();
const sourceEnd = getSourceIndex(item.fileName, start + length, true);
const existringKey = `${sourceStart},${sourceEnd}`;
if (isIndexesInvalid(sourceStart, sourceEnd)) {
return;
}
existing.add(existringKey);
existringMap.set(realPath, existing);
locationItem.range = [sourceStart, sourceEnd];
} else {
const startLineAndCharacter = getLineAndCharacter(item.fileName, start);
const endLineAndCharacter = getLineAndCharacter(item.fileName, start + length);
if (!startLineAndCharacter || !endLineAndCharacter) {
return;
}
locationItem.loc = { start: startLineAndCharacter, end: endLineAndCharacter };
}
locations.push(locationItem);
});
return locations;
}
function prepareRenameAndConvert(languageService, { fileName, pos }) {
const renameInfo = languageService.getRenameInfo(fileName, pos, getUserPreferences(fileName));
if (!renameInfo || !renameInfo.canRename) {
return null;
}
return [
renameInfo.triggerSpan.start,
renameInfo.triggerSpan.start + renameInfo.triggerSpan.length
];
}
function getComponentInfos(languageService, fileName) {
const dirPath = path.dir(fileName);
const realPath = getRealPath(fileName);
const config = exports.getConfig(realPath);
const program = languageService.getProgram();
const sourceFile = program.getSourceFile(fileName);
const qingkuaiModules = resolvedQingkuaiModule.get(realPath);
debugAssert(!!sourceFile);
const importedQingkuaiFileNames = /* @__PURE__ */ new Set();
const componentInfos = [];
walk$1(sourceFile, (node) => {
if (ts.isImportDeclaration(node) && isInTopScope(node)) {
if (!isUndefined(node.importClause?.name)) {
const identifierName = node.importClause.name.text;
if (ts.isStringLiteral(node.moduleSpecifier) && qingkuaiModules?.has(node.moduleSpecifier.text)) {
let relativePath = node.moduleSpecifier.text;
let componentFileName = path.resolve(dirPath, node.moduleSpecifier.text);
if (!isQingkuaiFileName(componentFileName)) {
relativePath += ".qk";
componentFileName += ".qk";
}
componentInfos.push({
relativePath,
imported: true,
name: identifierName,
slotNams: getComponentSlotNames(componentFileName),
attributes: exports.getCompileInfo(componentFileName).attributeInfos
});
importedQingkuaiFileNames.add(componentFileName);
}
}
}
});
for (const currentFileName of getFullFileNames()) {
if (isQingkuaiFileName(currentFileName) && currentFileName !== fileName.toString() && !importedQingkuaiFileNames.has(currentFileName)) {
let relativePath = getRelativePathWithStartDot(dirPath, currentFileName);
if (config?.resolveImportExtension) {
relativePath = relativePath.slice(0, -path.ext(relativePath).length);
}
componentInfos.push({
imported: false,
attributes: [],
relativePath,
slotNams: getComponentSlotNames(currentFileName),
name: filePathToComponentName(path, currentFileName)
});
}
}
return componentInfos;
}
function getComponentAttributes(languageService, fileName) {
const program = languageService.getProgram();
const typeChecker = program.getTypeChecker();
const attributes = [];
const sourceFile = program.getSourceFile(fileName);
debugAssert(!!sourceFile);
sourceFile.locals?.forEach((symbol, name) => {
if (globalTypeIdentifierRE.test(name)) {
let type;
if (!ts.isJSDocTypedefTag(symbol.declarations[0])) {
type = typeChecker.getDeclaredTypeOfSymbol(symbol);
} else {
type = typeChecker.getTypeFromTypeNode(symbol.declarations[0].typeExpression);
}
if (!type.symbol || !(type.symbol.flags & ts.SymbolFlags.Type)) {
return;
}
type.getProperties().forEach((property) => {
const stringCandidates = [];
const propertyType = typeChecker.getTypeOfSymbolAtLocation(property, sourceFile);
if (propertyType.isUnion()) {
propertyType.types.forEach((t) => {
if (t.flags & ts.TypeFlags.StringLiteral) {
stringCandidates.push(JSON.parse(typeChecker.typeToString(t)));
}
});
} else if (propertyType.flags & ts.TypeFlags.StringLiteral) {
stringCandidates.push(JSON.parse(typeChecker.typeToString(propertyType)));
}
if (!isSymbolKey(property)) {
attributes.push({
stringCandidates,
name: property.name,
kind: name.slice(0, -1),
type: typeChecker.typeToString(propertyType),
isEvent: name === GlobalTypeIdentifier.Prop && isEventType(propertyType)
});
}
});
}
});
return attributes;
}
function getRelativePathWithStartDot(from, to) {
const relativePath = path.relative(from, to);
return /\.{1,2}\//.test(relativePath) ? relativePath : `./${relativePath}`;
}
function getComponentSlotNames(componentFileName) {
return Object.keys(exports.getCompileInfo(getRealPath(componentFileName)).slotInfo);
}
function getAndConvertDefinitions(languageService, { fileName, pos }) {
const data = languageService.getDefinitionAndBoundSpan(fileName, pos);
if (!data) {
return null;
}
const originRange = lsRange.fromTextSpan(fileName, data.textSpan) || DEFAULT_RANGE;
const dealtDefinitions = (data.definitions || []).map((item) => {
const range = lsRange.fromTextSpan(item.fileName, item.textSpan) || DEFAULT_RANGE;
if (item.contextSpan) {
const contextRange = lsRange.fromTextSpan(item.fileName, item.contextSpan);
return {
fileName: item.fileName,
targetSelectionRange: range,
targetRange: contextRange ?? range
};
}
return {
fileName: item.fileName,
targetRange: range,
targetSelectionRange: range
};
});
return { range: originRange, definitions: dealtDefinitions };
}
function getAndConvertTypeDefinitions(languageService, { fileName, pos }) {
const definitions = languageService.getTypeDefinitionAtPosition(fileName, pos);
if (!definitions?.length) {
return null;
}
return definitions.map((definition) => {
const realPath = g