Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
so1ve committed May 6, 2024
1 parent 7072a2a commit ad6db7f
Show file tree
Hide file tree
Showing 8 changed files with 255 additions and 117 deletions.
2 changes: 1 addition & 1 deletion packages/language-core/lib/codegen/common.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type * as ts from 'typescript';
import { getNodeText } from '../parsers/scriptSetupRanges';
import { getNodeText } from '../utils/parseBindings';
import type { Code, SfcBlock, VueCodeInformation } from '../types';

export const newLine = '\n';
Expand Down
5 changes: 3 additions & 2 deletions packages/language-core/lib/codegen/script/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,10 @@ export function createScriptCodegenContext(options: ScriptCodegenOptions) {
generatedPropsType: false,
scriptSetupGeneratedOffset: undefined as number | undefined,
bypassDefineComponent: options.lang === 'js' || options.lang === 'jsx',
// TODO: maybe not using substring to get names?
bindingNames: new Set([
...options.scriptRanges?.bindings.map(range => options.sfc.script!.content.substring(range.start, range.end)) ?? [],
...options.scriptSetupRanges?.bindings.map(range => options.sfc.scriptSetup!.content.substring(range.start, range.end)) ?? [],
...options.scriptRanges?.bindings.bindingRanges.map(range => options.sfc.script!.content.substring(range.start, range.end)) ?? [],
...options.scriptSetupRanges?.bindings.bindingRanges.map(range => options.sfc.scriptSetup!.content.substring(range.start, range.end)) ?? [],
]),
helperTypes,
generateHelperTypes,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ export function* generateInternalComponent(
// bindings
const templateUsageVars = getTemplateUsageVars(options, ctx);
for (const [content, bindings] of [
[options.sfc.scriptSetup.content, options.scriptSetupRanges.bindings] as const,
[options.sfc.scriptSetup.content, options.scriptSetupRanges.bindings.bindingRanges] as const,
options.sfc.script && options.scriptRanges
? [options.sfc.script.content, options.scriptRanges.bindings] as const
? [options.sfc.script.content, options.scriptRanges.bindings.bindingRanges] as const
: ['', []] as const,
]) {
for (const expose of bindings) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { isGloballyWhitelisted } from '@vue/shared';
import type * as ts from 'typescript';
import { getNodeText, getStartEnd } from '../../parsers/scriptSetupRanges';
import { getNodeText, getStartEnd } from '../../utils/parseBindings';
import type { Code, VueCodeInformation, VueCompilerOptions } from '../../types';
import { collectVars, createTsAst } from '../common';
import type { TemplateCodegenContext } from './context';
Expand Down
6 changes: 4 additions & 2 deletions packages/language-core/lib/parsers/scriptRanges.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { TextRange } from '../types';
import type * as ts from 'typescript';
import { getNodeText, getStartEnd, parseBindingRanges } from './scriptSetupRanges';
import { BindingTypes, getNodeText, getStartEnd, parseBindings } from '../utils/parseBindings';

export interface ScriptRanges extends ReturnType<typeof parseScriptRanges> { }

Expand All @@ -15,7 +15,9 @@ export function parseScriptRanges(ts: typeof import('typescript'), ast: ts.Sourc
nameOption: TextRange | undefined,
}) | undefined;

const bindings = hasScriptSetup ? parseBindingRanges(ts, ast) : [];
const bindings = hasScriptSetup
? parseBindings(ts, ast)
: { bindingRanges: [], bindingTypes: new Map<string, BindingTypes>() };

ts.forEachChild(ast, raw => {

Expand Down
108 changes: 2 additions & 106 deletions packages/language-core/lib/parsers/scriptSetupRanges.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type * as ts from 'typescript';
import type { VueCompilerOptions, TextRange } from '../types';
import { getNodeText, getStartEnd, parseBindings } from '../utils/parseBindings';

export interface ScriptSetupRanges extends ReturnType<typeof parseScriptSetupRanges> { }

Expand Down Expand Up @@ -45,7 +46,7 @@ export function parseScriptSetupRanges(
required: boolean;
isModel?: boolean;
}[] = [];
const bindings = parseBindingRanges(ts, ast);
const bindings = parseBindings(ts, ast);
const text = ast.text;
const leadingCommentEndOffset = ts.getLeadingCommentRanges(text, 0)?.reverse()[0].end ?? 0;

Expand Down Expand Up @@ -248,108 +249,3 @@ export function parseScriptSetupRanges(
});
}
}

export function parseBindingRanges(ts: typeof import('typescript'), sourceFile: ts.SourceFile) {
const bindings: TextRange[] = [];
ts.forEachChild(sourceFile, node => {
if (ts.isVariableStatement(node)) {
for (const node_2 of node.declarationList.declarations) {
const vars = _findBindingVars(node_2.name);
for (const _var of vars) {
bindings.push(_var);
}
}
}
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)) {
if (node.importClause && !node.importClause.isTypeOnly) {
if (node.importClause.name) {
bindings.push(_getStartEnd(node.importClause.name));
}
if (node.importClause.namedBindings) {
if (ts.isNamedImports(node.importClause.namedBindings)) {
for (const element of node.importClause.namedBindings.elements) {
bindings.push(_getStartEnd(element.name));
}
}
else if (ts.isNamespaceImport(node.importClause.namedBindings)) {
bindings.push(_getStartEnd(node.importClause.namedBindings.name));
}
}
}
}
});
return bindings;
function _getStartEnd(node: ts.Node) {
return getStartEnd(ts, node, sourceFile);
}
function _findBindingVars(left: ts.BindingName) {
return findBindingVars(ts, left, sourceFile);
}
}

export function findBindingVars(ts: typeof import('typescript'), left: ts.BindingName, sourceFile: ts.SourceFile) {
const vars: TextRange[] = [];
worker(left);
return vars;
function worker(_node: ts.Node) {
if (ts.isIdentifier(_node)) {
vars.push(getStartEnd(ts, _node, sourceFile));
}
// { ? } = ...
// [ ? ] = ...
else if (ts.isObjectBindingPattern(_node) || ts.isArrayBindingPattern(_node)) {
for (const property of _node.elements) {
if (ts.isBindingElement(property)) {
worker(property.name);
}
}
}
// { foo: ? } = ...
else if (ts.isPropertyAssignment(_node)) {
worker(_node.initializer);
}
// { foo } = ...
else if (ts.isShorthandPropertyAssignment(_node)) {
vars.push(getStartEnd(ts, _node.name, sourceFile));
}
// { ...? } = ...
// [ ...? ] = ...
else if (ts.isSpreadAssignment(_node) || ts.isSpreadElement(_node)) {
worker(_node.expression);
}
}
}

export function getStartEnd(
ts: typeof import('typescript'),
node: ts.Node,
sourceFile: ts.SourceFile
) {
return {
start: (ts as any).getTokenPosOfNode(node, sourceFile) as number,
end: node.end,
};
}

export function getNodeText(
ts: typeof import('typescript'),
node: ts.Node,
sourceFile: ts.SourceFile
) {
const { start, end } = getStartEnd(ts, node, sourceFile);
return sourceFile.text.substring(start, end);
}
Loading

0 comments on commit ad6db7f

Please sign in to comment.