feat: init

This commit is contained in:
2026-02-13 22:02:30 +01:00
commit 8f9ff830fb
16711 changed files with 3307340 additions and 0 deletions

View File

@@ -0,0 +1,33 @@
import type * as ts from 'typescript';
import type { TextRange, VueCompilerOptions } from '../types';
export interface ScriptRanges extends ReturnType<typeof parseScriptRanges> {
}
export declare function parseScriptRanges(ts: typeof import('typescript'), sourceFile: ts.SourceFile, vueCompilerOptions: VueCompilerOptions): {
exportDefault: (TextRange<ts.Node> & {
expression: TextRange<ts.Expression>;
isObjectLiteral: boolean;
options?: {
isObjectLiteral: boolean;
expression: TextRange<ts.Node>;
args: TextRange<ts.ObjectLiteralExpression>;
components: TextRange<ts.ObjectLiteralExpression> | undefined;
directives: TextRange<ts.Node> | undefined;
name: TextRange<ts.StringLiteral> | undefined;
inheritAttrs: string | undefined;
} | undefined;
}) | undefined;
bindings: TextRange<ts.Node>[];
components: TextRange<ts.Node>[];
};
export declare function parseOptionsFromExtression(ts: typeof import('typescript'), exp: ts.Node, sourceFile: ts.SourceFile): {
isObjectLiteral: boolean;
expression: TextRange<ts.Node>;
args: TextRange<ts.ObjectLiteralExpression>;
argsNode: ts.ObjectLiteralExpression;
components: TextRange<ts.ObjectLiteralExpression> | undefined;
componentsNode: ts.ObjectLiteralExpression | undefined;
directives: TextRange<ts.ObjectLiteralExpression> | undefined;
name: TextRange<ts.StringLiteral> | undefined;
nameNode: ts.StringLiteral | undefined;
inheritAttrs: string | undefined;
} | undefined;

View File

@@ -0,0 +1,90 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseScriptRanges = parseScriptRanges;
exports.parseOptionsFromExtression = parseOptionsFromExtression;
const shared_1 = require("../utils/shared");
const utils_1 = require("./utils");
function parseScriptRanges(ts, sourceFile, vueCompilerOptions) {
let exportDefault;
const { bindings, components } = (0, utils_1.parseBindingRanges)(ts, sourceFile, vueCompilerOptions.extensions);
ts.forEachChild(sourceFile, child => {
if (ts.isExportAssignment(child)) {
exportDefault = {
...(0, shared_1.getStartEnd)(ts, child, sourceFile),
expression: (0, shared_1.getStartEnd)(ts, child.expression, sourceFile),
isObjectLiteral: ts.isObjectLiteralExpression(child.expression),
options: parseOptionsFromExtression(ts, child.expression, sourceFile),
};
const comment = (0, utils_1.getClosestMultiLineCommentRange)(ts, child, [], sourceFile);
if (comment) {
exportDefault.start = comment.start;
}
}
});
return {
exportDefault,
bindings,
components,
};
}
function parseOptionsFromExtression(ts, exp, sourceFile) {
let obj;
while (isAsExpression(ts, exp) || ts.isParenthesizedExpression(exp)) { // fix https://github.com/vuejs/language-tools/issues/1882
exp = exp.expression;
}
if (ts.isObjectLiteralExpression(exp)) {
obj = exp;
}
else if (ts.isCallExpression(exp) && exp.arguments.length) {
const arg0 = exp.arguments[0];
if (ts.isObjectLiteralExpression(arg0)) {
obj = arg0;
}
}
if (obj) {
let componentsOptionNode;
let directivesOptionNode;
let nameOptionNode;
let inheritAttrsOption;
ts.forEachChild(obj, node => {
if (ts.isPropertyAssignment(node) && ts.isIdentifier(node.name)) {
const name = _getNodeText(node.name);
if (name === 'components' && ts.isObjectLiteralExpression(node.initializer)) {
componentsOptionNode = node.initializer;
}
else if (name === 'directives' && ts.isObjectLiteralExpression(node.initializer)) {
directivesOptionNode = node.initializer;
}
else if (name === 'name' && ts.isStringLiteral(node.initializer)) {
nameOptionNode = node.initializer;
}
else if (name === 'inheritAttrs') {
inheritAttrsOption = _getNodeText(node.initializer);
}
}
});
return {
isObjectLiteral: ts.isObjectLiteralExpression(exp),
expression: _getStartEnd(exp),
args: _getStartEnd(obj),
argsNode: obj,
components: componentsOptionNode ? _getStartEnd(componentsOptionNode) : undefined,
componentsNode: componentsOptionNode,
directives: directivesOptionNode ? _getStartEnd(directivesOptionNode) : undefined,
name: nameOptionNode ? _getStartEnd(nameOptionNode) : undefined,
nameNode: nameOptionNode,
inheritAttrs: inheritAttrsOption,
};
}
function _getStartEnd(node) {
return (0, shared_1.getStartEnd)(ts, node, sourceFile);
}
function _getNodeText(node) {
return (0, shared_1.getNodeText)(ts, node, sourceFile);
}
}
// isAsExpression is missing in tsc
function isAsExpression(ts, node) {
return node.kind === ts.SyntaxKind.AsExpression;
}
//# sourceMappingURL=scriptRanges.js.map

View File

@@ -0,0 +1,60 @@
import type * as ts from 'typescript';
import type { TextRange, VueCompilerOptions } from '../types';
export interface CallExpressionRange {
callExp: TextRange;
exp: TextRange;
arg?: TextRange;
typeArg?: TextRange;
}
export interface DefineModel {
arg?: TextRange;
localName?: TextRange;
name?: TextRange;
type?: TextRange;
modifierType?: TextRange;
runtimeType?: TextRange;
defaultValue?: TextRange;
required?: boolean;
comments?: TextRange;
}
export interface DefineProps extends CallExpressionRange {
name?: string;
destructured?: Map<string, ts.Expression | undefined>;
destructuredRest?: string;
statement: TextRange;
}
export interface DefineEmits extends CallExpressionRange {
name?: string;
hasUnionTypeArg?: boolean;
statement: TextRange;
}
export interface DefineSlots extends CallExpressionRange {
name?: string;
statement: TextRange;
}
export interface DefineOptions {
name?: string;
inheritAttrs?: string;
}
export interface UseTemplateRef extends CallExpressionRange {
name?: string;
}
export interface ScriptSetupRanges extends ReturnType<typeof parseScriptSetupRanges> {
}
export declare function parseScriptSetupRanges(ts: typeof import('typescript'), sourceFile: ts.SourceFile, vueCompilerOptions: VueCompilerOptions): {
leadingCommentEndOffset: number;
importSectionEndOffset: number;
bindings: TextRange<ts.Node>[];
components: TextRange<ts.Node>[];
defineModel: DefineModel[];
defineProps: DefineProps | undefined;
withDefaults: CallExpressionRange | undefined;
defineEmits: DefineEmits | undefined;
defineSlots: DefineSlots | undefined;
defineExpose: CallExpressionRange | undefined;
defineOptions: DefineOptions | undefined;
useAttrs: CallExpressionRange[];
useCssModule: CallExpressionRange[];
useSlots: CallExpressionRange[];
useTemplateRef: UseTemplateRef[];
};

View File

@@ -0,0 +1,283 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseScriptSetupRanges = parseScriptSetupRanges;
const collectBindings_1 = require("../utils/collectBindings");
const shared_1 = require("../utils/shared");
const utils_1 = require("./utils");
const tsCheckReg = /^\/\/\s*@ts-(?:no)?check(?:$|\s)/;
function parseScriptSetupRanges(ts, sourceFile, vueCompilerOptions) {
const defineModel = [];
let defineProps;
let withDefaults;
let defineEmits;
let defineSlots;
let defineExpose;
let defineOptions;
const useAttrs = [];
const useCssModule = [];
const useSlots = [];
const useTemplateRef = [];
const text = sourceFile.text;
const leadingCommentRanges = ts.getLeadingCommentRanges(text, 0)?.reverse() ?? [];
const leadingCommentEndOffset = leadingCommentRanges.find(range => tsCheckReg.test(text.slice(range.pos, range.end)))?.end ?? 0;
let { bindings, components } = (0, utils_1.parseBindingRanges)(ts, sourceFile, vueCompilerOptions.extensions);
let foundNonImportExportNode = false;
let importSectionEndOffset = 0;
ts.forEachChild(sourceFile, node => {
if (foundNonImportExportNode
|| ts.isImportDeclaration(node)
|| ts.isExportDeclaration(node)
|| ts.isEmptyStatement(node)
// fix https://github.com/vuejs/language-tools/issues/1223
|| ts.isImportEqualsDeclaration(node)) {
return;
}
if ((ts.isTypeAliasDeclaration(node) || ts.isInterfaceDeclaration(node))
&& node.modifiers?.some(mod => mod.kind === ts.SyntaxKind.ExportKeyword)) {
return;
}
const commentRanges = ts.getLeadingCommentRanges(text, node.pos);
if (commentRanges?.length) {
const commentRange = commentRanges.sort((a, b) => a.pos - b.pos)[0];
importSectionEndOffset = commentRange.pos;
}
else {
importSectionEndOffset = (0, shared_1.getStartEnd)(ts, node, sourceFile).start;
}
foundNonImportExportNode = true;
});
ts.forEachChild(sourceFile, node => visitNode(node, [sourceFile]));
const templateRefNames = new Set(useTemplateRef.map(ref => ref.name));
bindings = bindings.filter(range => {
const name = text.slice(range.start, range.end);
return !templateRefNames.has(name);
});
return {
leadingCommentEndOffset,
importSectionEndOffset,
bindings,
components,
defineModel,
defineProps,
withDefaults,
defineEmits,
defineSlots,
defineExpose,
defineOptions,
useAttrs,
useCssModule,
useSlots,
useTemplateRef,
};
function visitNode(node, parents) {
const parent = parents[parents.length - 1];
if (ts.isCallExpression(node)
&& ts.isIdentifier(node.expression)) {
const callText = _getNodeText(node.expression);
if (vueCompilerOptions.macros.defineModel.includes(callText)) {
let localName;
let propName;
let options;
let type;
let modifierType;
let runtimeType;
let defaultValue;
let required = false;
if (ts.isVariableDeclaration(parent) && ts.isIdentifier(parent.name)) {
localName = _getStartEnd(parent.name);
}
if (node.typeArguments) {
if (node.typeArguments.length >= 1) {
type = _getStartEnd(node.typeArguments[0]);
}
if (node.typeArguments.length >= 2) {
modifierType = _getStartEnd(node.typeArguments[1]);
}
}
if (node.arguments.length >= 2) {
propName = node.arguments[0];
options = node.arguments[1];
}
else if (node.arguments.length >= 1) {
if (ts.isStringLiteralLike(node.arguments[0])) {
propName = node.arguments[0];
}
else {
options = node.arguments[0];
}
}
if (options && ts.isObjectLiteralExpression(options)) {
for (const property of options.properties) {
if (!ts.isPropertyAssignment(property) || !ts.isIdentifier(property.name)) {
continue;
}
const text = _getNodeText(property.name);
if (text === 'type') {
runtimeType = _getStartEnd(property.initializer);
}
else if (text === 'default') {
defaultValue = _getStartEnd(property.initializer);
}
else if (text === 'required' && property.initializer.kind === ts.SyntaxKind.TrueKeyword) {
required = true;
}
}
}
let name;
if (propName && ts.isStringLiteralLike(propName)) {
name = _getStartEnd(propName);
}
defineModel.push({
localName,
name,
type,
modifierType,
runtimeType,
defaultValue,
required,
comments: (0, utils_1.getClosestMultiLineCommentRange)(ts, node, parents, sourceFile),
arg: _getStartEnd(node),
});
}
else if (vueCompilerOptions.macros.defineProps.includes(callText)) {
defineProps = {
...parseCallExpressionAssignment(node, parent),
statement: getStatementRange(ts, parents, node, sourceFile),
};
if (ts.isVariableDeclaration(parent) && ts.isObjectBindingPattern(parent.name)) {
defineProps.destructured = new Map();
const identifiers = (0, collectBindings_1.collectBindingIdentifiers)(ts, parent.name);
for (const { id, isRest, initializer } of identifiers) {
const name = _getNodeText(id);
if (isRest) {
defineProps.destructuredRest = name;
}
else {
defineProps.destructured.set(name, initializer);
}
}
}
else if (ts.isCallExpression(parent)
&& vueCompilerOptions.macros.withDefaults.includes(_getNodeText(parent.expression))) {
const grand = parents.at(-2);
if (grand && ts.isVariableDeclaration(grand)) {
defineProps.name = _getNodeText(grand.name);
}
}
}
else if (vueCompilerOptions.macros.withDefaults.includes(callText)) {
const [, arg] = node.arguments;
withDefaults = {
callExp: _getStartEnd(node),
exp: _getStartEnd(node.expression),
arg: arg ? _getStartEnd(arg) : undefined,
};
}
else if (vueCompilerOptions.macros.defineEmits.includes(callText)) {
defineEmits = {
...parseCallExpressionAssignment(node, parent),
statement: getStatementRange(ts, parents, node, sourceFile),
};
if (node.typeArguments?.length && ts.isTypeLiteralNode(node.typeArguments[0])) {
for (const member of node.typeArguments[0].members) {
if (ts.isCallSignatureDeclaration(member)) {
const type = member.parameters[0]?.type;
if (type && ts.isUnionTypeNode(type)) {
defineEmits.hasUnionTypeArg = true;
break;
}
}
}
}
}
else if (vueCompilerOptions.macros.defineSlots.includes(callText)) {
defineSlots = {
...parseCallExpressionAssignment(node, parent),
statement: getStatementRange(ts, parents, node, sourceFile),
};
}
else if (vueCompilerOptions.macros.defineExpose.includes(callText)) {
defineExpose = parseCallExpression(node);
}
else if (vueCompilerOptions.macros.defineOptions.includes(callText)
&& node.arguments.length
&& ts.isObjectLiteralExpression(node.arguments[0])) {
defineOptions = {};
const obj = node.arguments[0];
for (const prop of obj.properties) {
if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) {
const name = _getNodeText(prop.name);
if (name === 'inheritAttrs') {
defineOptions.inheritAttrs = _getNodeText(prop.initializer);
}
else if (name === 'name' && ts.isStringLiteral(prop.initializer)) {
defineOptions.name = prop.initializer.text;
}
}
}
}
else if (vueCompilerOptions.composables.useAttrs.includes(callText)) {
useAttrs.push(parseCallExpression(node));
}
else if (vueCompilerOptions.composables.useCssModule.includes(callText)) {
useCssModule.push(parseCallExpression(node));
}
else if (vueCompilerOptions.composables.useSlots.includes(callText)) {
useSlots.push(parseCallExpression(node));
}
else if (vueCompilerOptions.composables.useTemplateRef.includes(callText)
&& !node.typeArguments?.length) {
useTemplateRef.push(parseCallExpressionAssignment(node, parent));
}
}
ts.forEachChild(node, child => {
if (ts.isFunctionLike(node)) {
return;
}
parents.push(node);
visitNode(child, parents);
parents.pop();
});
}
function parseCallExpression(node) {
return {
callExp: _getStartEnd(node),
exp: _getStartEnd(node.expression),
arg: node.arguments.length ? _getStartEnd(node.arguments[0]) : undefined,
typeArg: node.typeArguments?.length ? _getStartEnd(node.typeArguments[0]) : undefined,
};
}
function parseCallExpressionAssignment(node, parent) {
return {
name: ts.isVariableDeclaration(parent) && ts.isIdentifier(parent.name)
? _getNodeText(parent.name)
: undefined,
...parseCallExpression(node),
};
}
function _getStartEnd(node) {
return (0, shared_1.getStartEnd)(ts, node, sourceFile);
}
function _getNodeText(node) {
return (0, shared_1.getNodeText)(ts, node, sourceFile);
}
}
function getStatementRange(ts, parents, node, ast) {
let statementRange;
for (let i = parents.length - 1; i >= 0; i--) {
const statement = parents[i];
if (ts.isStatement(statement)) {
ts.forEachChild(statement, child => {
const range = (0, shared_1.getStartEnd)(ts, child, ast);
statementRange ??= range;
statementRange.end = range.end;
});
break;
}
}
if (!statementRange) {
statementRange = (0, shared_1.getStartEnd)(ts, node, ast);
}
return statementRange;
}
//# sourceMappingURL=scriptSetupRanges.js.map

View File

@@ -0,0 +1,7 @@
import type * as ts from 'typescript';
import type { TextRange } from '../types';
export declare function parseBindingRanges(ts: typeof import('typescript'), ast: ts.SourceFile, componentExtsensions: string[]): {
bindings: TextRange<ts.Node>[];
components: TextRange<ts.Node>[];
};
export declare function getClosestMultiLineCommentRange(ts: typeof import('typescript'), node: ts.Node, parents: ts.Node[], ast: ts.SourceFile): TextRange | undefined;

94
node_modules/@vue/language-core/lib/parsers/utils.js generated vendored Normal file
View File

@@ -0,0 +1,94 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseBindingRanges = parseBindingRanges;
exports.getClosestMultiLineCommentRange = getClosestMultiLineCommentRange;
const collectBindings_1 = require("../utils/collectBindings");
const shared_1 = require("../utils/shared");
function parseBindingRanges(ts, ast, componentExtsensions) {
const bindings = [];
const components = [];
ts.forEachChild(ast, node => {
if (ts.isVariableStatement(node)) {
for (const decl of node.declarationList.declarations) {
const ranges = (0, collectBindings_1.collectBindingRanges)(ts, decl.name, ast);
bindings.push(...ranges);
}
}
else if (ts.isFunctionDeclaration(node)) {
if (node.name && ts.isIdentifier(node.name)) {
bindings.push(_getStartEnd(node.name));
}
}
else if (ts.isClassDeclaration(node)) {
if (node.name) {
bindings.push(_getStartEnd(node.name));
}
}
else if (ts.isEnumDeclaration(node)) {
bindings.push(_getStartEnd(node.name));
}
if (ts.isImportDeclaration(node)) {
const moduleName = _getNodeText(node.moduleSpecifier).slice(1, -1);
if (node.importClause && !node.importClause.isTypeOnly) {
const { name, namedBindings } = node.importClause;
if (name) {
if (componentExtsensions.some(ext => moduleName.endsWith(ext))) {
components.push(_getStartEnd(name));
}
else {
bindings.push(_getStartEnd(name));
}
}
if (namedBindings) {
if (ts.isNamedImports(namedBindings)) {
for (const element of namedBindings.elements) {
if (element.isTypeOnly) {
continue;
}
if (element.propertyName
&& _getNodeText(element.propertyName) === 'default'
&& componentExtsensions.some(ext => moduleName.endsWith(ext))) {
components.push(_getStartEnd(element.name));
}
else {
bindings.push(_getStartEnd(element.name));
}
}
}
else {
bindings.push(_getStartEnd(namedBindings.name));
}
}
}
}
});
return {
bindings,
components,
};
function _getStartEnd(node) {
return (0, shared_1.getStartEnd)(ts, node, ast);
}
function _getNodeText(node) {
return (0, shared_1.getNodeText)(ts, node, ast);
}
}
function getClosestMultiLineCommentRange(ts, node, parents, ast) {
for (let i = parents.length - 1; i >= 0; i--) {
if (ts.isStatement(node)) {
break;
}
node = parents[i];
}
const comment = ts.getLeadingCommentRanges(ast.text, node.pos)
?.reverse()
.find(range => range.kind === 3);
if (comment) {
return {
node,
start: comment.pos,
end: comment.end,
};
}
}
//# sourceMappingURL=utils.js.map

View File

@@ -0,0 +1,2 @@
import type { RawVueCompilerOptions } from '../types';
export declare function parseVueCompilerOptions(comments: string[]): RawVueCompilerOptions | undefined;

View File

@@ -0,0 +1,22 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseVueCompilerOptions = parseVueCompilerOptions;
const syntaxReg = /^\s*@(?<key>.+?)\s+(?<value>.+?)\s*$/m;
function parseVueCompilerOptions(comments) {
const entries = comments
.map(text => {
try {
const match = text.match(syntaxReg);
if (match) {
const { key, value } = match.groups ?? {};
return [key, JSON.parse(value)];
}
}
catch { }
})
.filter(item => !!item);
if (entries.length) {
return Object.fromEntries(entries);
}
}
//# sourceMappingURL=vueCompilerOptions.js.map