mirror of
https://wget.la/https://github.com/leookun/cursor-byok
synced 2026-08-18 03:57:06 +08:00
refactor: 0.1.0-beta
This commit is contained in:
@@ -0,0 +1,423 @@
|
||||
// resolver.go 解析压缩 bundle 中的局部符号、模块别名和导出别名。
|
||||
package main
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// newTypeResolver 建立消息、枚举和模块别名的统一索引。
|
||||
func newTypeResolver(messages []Message, enums []Enum, aliases aliasIndex, exportAliases aliasIndex) *TypeResolver {
|
||||
resolver := &TypeResolver{
|
||||
bySymbol: make(map[string][]symbolDef),
|
||||
byAlias: make(map[string][]symbolDef),
|
||||
byShort: make(map[string][]symbolDef),
|
||||
}
|
||||
|
||||
add := func(symbol, typeName string, pos int, moduleStart int, kind string) {
|
||||
symbol = strings.TrimSpace(symbol)
|
||||
typeName = strings.TrimSpace(typeName)
|
||||
if symbol == "" || typeName == "" {
|
||||
return
|
||||
}
|
||||
def := symbolDef{TypeName: typeName, Pos: pos, ModuleStart: moduleStart, Kind: kind}
|
||||
resolver.bySymbol[symbol] = append(resolver.bySymbol[symbol], def)
|
||||
_, shortName := parseTypeName(typeName)
|
||||
if shortName != "" {
|
||||
resolver.byShort[shortName] = append(resolver.byShort[shortName], def)
|
||||
underscoreAlias := strings.ReplaceAll(shortName, ".", "_")
|
||||
if underscoreAlias != shortName {
|
||||
resolver.byShort[underscoreAlias] = append(resolver.byShort[underscoreAlias], def)
|
||||
}
|
||||
if idx := strings.LastIndex(shortName, "."); idx > 0 && idx+1 < len(shortName) {
|
||||
resolver.byShort[shortName[idx+1:]] = append(resolver.byShort[shortName[idx+1:]], def)
|
||||
}
|
||||
if idx := strings.LastIndex(underscoreAlias, "_"); idx > 0 && idx+1 < len(underscoreAlias) {
|
||||
resolver.byShort[underscoreAlias[idx+1:]] = append(resolver.byShort[underscoreAlias[idx+1:]], def)
|
||||
}
|
||||
}
|
||||
}
|
||||
addAlias := func(symbol, typeName string, pos int, moduleStart int, kind string) {
|
||||
symbol = strings.TrimSpace(symbol)
|
||||
typeName = strings.TrimSpace(typeName)
|
||||
if symbol == "" || typeName == "" {
|
||||
return
|
||||
}
|
||||
resolver.byAlias[symbol] = append(resolver.byAlias[symbol], symbolDef{
|
||||
TypeName: typeName, Pos: pos, ModuleStart: moduleStart, Kind: kind,
|
||||
})
|
||||
}
|
||||
|
||||
for _, msg := range messages {
|
||||
add(msg.VarName, msg.TypeName, msg.Pos, msg.ModuleStart, "message")
|
||||
if msg.InternalName != "" && msg.InternalName != msg.VarName {
|
||||
add(msg.InternalName, msg.TypeName, msg.Pos, msg.ModuleStart, "message")
|
||||
}
|
||||
for _, alias := range aliasesForSymbols(aliases[msg.ModuleStart], msg.VarName, msg.InternalName) {
|
||||
addAlias(alias, msg.TypeName, msg.Pos, msg.ModuleStart, "message")
|
||||
}
|
||||
}
|
||||
for _, enum := range enums {
|
||||
add(enum.VarName, enum.TypeName, enum.Pos, enum.ModuleStart, "enum")
|
||||
for _, alias := range aliasesForSymbols(aliases[enum.ModuleStart], enum.VarName) {
|
||||
addAlias(alias, enum.TypeName, enum.Pos, enum.ModuleStart, "enum")
|
||||
}
|
||||
}
|
||||
|
||||
for _, msg := range messages {
|
||||
for _, alias := range aliasesForSymbols(exportAliases[msg.ModuleStart], msg.VarName, msg.InternalName) {
|
||||
addAlias(alias, msg.TypeName, msg.Pos, msg.ModuleStart, "message")
|
||||
}
|
||||
}
|
||||
for _, enum := range enums {
|
||||
for _, alias := range aliasesForSymbols(exportAliases[enum.ModuleStart], enum.VarName) {
|
||||
addAlias(alias, enum.TypeName, enum.Pos, enum.ModuleStart, "enum")
|
||||
}
|
||||
}
|
||||
|
||||
return resolver
|
||||
}
|
||||
|
||||
// buildAliasIndex 提取变量声明和赋值形成的局部别名。
|
||||
func buildAliasIndex(text string, moduleStarts []int) aliasIndex {
|
||||
directByModule := make(map[int]map[string]string)
|
||||
addMatches := func(matches [][]int) {
|
||||
for _, match := range matches {
|
||||
alias := strings.TrimSpace(text[match[2]:match[3]])
|
||||
target := strings.TrimSpace(text[match[4]:match[5]])
|
||||
if alias == "" || target == "" || alias == target {
|
||||
continue
|
||||
}
|
||||
moduleStart := moduleStartForPos(moduleStarts, match[0])
|
||||
if directByModule[moduleStart] == nil {
|
||||
directByModule[moduleStart] = make(map[string]string)
|
||||
}
|
||||
directByModule[moduleStart][alias] = target
|
||||
}
|
||||
}
|
||||
|
||||
addMatches(varAliasRe.FindAllStringSubmatchIndex(text, -1))
|
||||
addMatches(assignmentAliasRe.FindAllStringSubmatchIndex(text, -1))
|
||||
|
||||
resolveRoot := func(direct map[string]string, symbol string) string {
|
||||
seen := make(map[string]bool)
|
||||
current := symbol
|
||||
for {
|
||||
if seen[current] {
|
||||
return symbol
|
||||
}
|
||||
seen[current] = true
|
||||
next := direct[current]
|
||||
if next == "" {
|
||||
return current
|
||||
}
|
||||
current = next
|
||||
}
|
||||
}
|
||||
|
||||
aliasSets := make(map[int]map[string]map[string]bool)
|
||||
addAlias := func(moduleStart int, root string, alias string) {
|
||||
root = strings.TrimSpace(root)
|
||||
alias = strings.TrimSpace(alias)
|
||||
if root == "" || alias == "" || root == alias {
|
||||
return
|
||||
}
|
||||
if aliasSets[moduleStart] == nil {
|
||||
aliasSets[moduleStart] = make(map[string]map[string]bool)
|
||||
}
|
||||
if aliasSets[moduleStart][root] == nil {
|
||||
aliasSets[moduleStart][root] = make(map[string]bool)
|
||||
}
|
||||
aliasSets[moduleStart][root][alias] = true
|
||||
}
|
||||
|
||||
for moduleStart, direct := range directByModule {
|
||||
for alias := range direct {
|
||||
root := resolveRoot(direct, alias)
|
||||
addAlias(moduleStart, root, alias)
|
||||
}
|
||||
}
|
||||
|
||||
if len(aliasSets) == 0 {
|
||||
return nil
|
||||
}
|
||||
aliases := make(aliasIndex, len(aliasSets))
|
||||
for moduleStart, roots := range aliasSets {
|
||||
aliases[moduleStart] = make(map[string][]string, len(roots))
|
||||
for root, set := range roots {
|
||||
for alias := range set {
|
||||
aliases[moduleStart][root] = append(aliases[moduleStart][root], alias)
|
||||
}
|
||||
sort.Strings(aliases[moduleStart][root])
|
||||
}
|
||||
}
|
||||
return aliases
|
||||
}
|
||||
|
||||
// buildWebpackExportAliasIndex 提取 Webpack 导出表中的符号别名。
|
||||
func buildWebpackExportAliasIndex(text string, moduleStarts []int) aliasIndex {
|
||||
aliasSets := make(map[int]map[string]map[string]bool)
|
||||
addAlias := func(moduleStart int, root string, alias string) {
|
||||
root = strings.TrimSpace(root)
|
||||
alias = strings.TrimSpace(alias)
|
||||
if root == "" || alias == "" || root == alias {
|
||||
return
|
||||
}
|
||||
if aliasSets[moduleStart] == nil {
|
||||
aliasSets[moduleStart] = make(map[string]map[string]bool)
|
||||
}
|
||||
if aliasSets[moduleStart][root] == nil {
|
||||
aliasSets[moduleStart][root] = make(map[string]bool)
|
||||
}
|
||||
aliasSets[moduleStart][root][alias] = true
|
||||
}
|
||||
|
||||
// Webpack 通过 n.d(t, { KS: () => T }) 暴露成员;服务使用 r.KS,消息定义使用局部符号 T。
|
||||
for _, blockMatch := range webpackExportBlockRe.FindAllStringIndex(text, -1) {
|
||||
moduleStart := moduleStartForPos(moduleStarts, blockMatch[0])
|
||||
blockStart := blockMatch[1] - 1
|
||||
blockEnd := findMatchingBrace(text, blockStart)
|
||||
if blockEnd == -1 {
|
||||
continue
|
||||
}
|
||||
block := text[blockStart:blockEnd]
|
||||
for _, entry := range webpackExportEntryRe.FindAllStringSubmatch(block, -1) {
|
||||
addAlias(moduleStart, entry[2], entry[1])
|
||||
}
|
||||
}
|
||||
|
||||
if len(aliasSets) == 0 {
|
||||
return nil
|
||||
}
|
||||
aliases := make(aliasIndex, len(aliasSets))
|
||||
for moduleStart, roots := range aliasSets {
|
||||
aliases[moduleStart] = make(map[string][]string, len(roots))
|
||||
for root, set := range roots {
|
||||
for alias := range set {
|
||||
aliases[moduleStart][root] = append(aliases[moduleStart][root], alias)
|
||||
}
|
||||
sort.Strings(aliases[moduleStart][root])
|
||||
}
|
||||
}
|
||||
return aliases
|
||||
}
|
||||
|
||||
// aliasesForSymbols 返回目标符号集合对应的去重别名。
|
||||
func aliasesForSymbols(aliases map[string][]string, symbols ...string) []string {
|
||||
if len(aliases) == 0 {
|
||||
return nil
|
||||
}
|
||||
seen := make(map[string]bool)
|
||||
var result []string
|
||||
for _, symbol := range symbols {
|
||||
for _, alias := range aliases[strings.TrimSpace(symbol)] {
|
||||
if alias == "" || seen[alias] {
|
||||
continue
|
||||
}
|
||||
seen[alias] = true
|
||||
result = append(result, alias)
|
||||
}
|
||||
}
|
||||
sort.Strings(result)
|
||||
return result
|
||||
}
|
||||
|
||||
// looksLikeFullTypeName 判断引用是否已经是全限定协议类型名。
|
||||
func looksLikeFullTypeName(ref string) bool {
|
||||
trimmed := strings.TrimSpace(ref)
|
||||
if strings.HasPrefix(trimmed, "google.protobuf.") || strings.HasPrefix(trimmed, "google.rpc.") {
|
||||
return true
|
||||
}
|
||||
matched, _ := regexp.MatchString(`^[\w.]+\.v\d+\.[\w.]+$`, trimmed)
|
||||
return matched
|
||||
}
|
||||
|
||||
// pickBestDefinition 按模块、类别、首选包和源码距离选择定义。
|
||||
func pickBestDefinition(candidates []symbolDef, contextPos int, contextModuleStart int, preferredPkg string, expectedKind string) (symbolDef, bool) {
|
||||
if len(candidates) == 0 {
|
||||
return symbolDef{}, false
|
||||
}
|
||||
|
||||
filtered := candidates
|
||||
if strings.TrimSpace(expectedKind) != "" {
|
||||
tmp := make([]symbolDef, 0, len(candidates))
|
||||
for _, item := range candidates {
|
||||
if item.Kind == expectedKind {
|
||||
tmp = append(tmp, item)
|
||||
}
|
||||
}
|
||||
if len(tmp) > 0 {
|
||||
filtered = tmp
|
||||
}
|
||||
}
|
||||
|
||||
if strings.TrimSpace(preferredPkg) != "" {
|
||||
tmp := make([]symbolDef, 0, len(filtered))
|
||||
for _, item := range filtered {
|
||||
pkg, _ := parseTypeName(item.TypeName)
|
||||
if pkg == preferredPkg {
|
||||
tmp = append(tmp, item)
|
||||
}
|
||||
}
|
||||
if len(tmp) > 0 {
|
||||
filtered = tmp
|
||||
}
|
||||
}
|
||||
|
||||
if contextModuleStart > 0 {
|
||||
tmp := make([]symbolDef, 0, len(filtered))
|
||||
for _, item := range filtered {
|
||||
if item.ModuleStart == contextModuleStart {
|
||||
tmp = append(tmp, item)
|
||||
}
|
||||
}
|
||||
if len(tmp) > 0 {
|
||||
filtered = tmp
|
||||
}
|
||||
}
|
||||
|
||||
// 选择绝对距离最近的定义,距离相同时优先前向定义。
|
||||
bestIndex := -1
|
||||
bestDistance := 0
|
||||
bestIsFuture := false
|
||||
for index, item := range filtered {
|
||||
distance := absInt(item.Pos - contextPos)
|
||||
isFuture := item.Pos > contextPos
|
||||
if bestIndex == -1 {
|
||||
bestIndex = index
|
||||
bestDistance = distance
|
||||
bestIsFuture = isFuture
|
||||
continue
|
||||
}
|
||||
if distance < bestDistance {
|
||||
bestIndex = index
|
||||
bestDistance = distance
|
||||
bestIsFuture = isFuture
|
||||
continue
|
||||
}
|
||||
if distance == bestDistance {
|
||||
// 距离相同时优先当前位置之前的定义。
|
||||
if bestIsFuture && !isFuture {
|
||||
bestIndex = index
|
||||
bestIsFuture = isFuture
|
||||
}
|
||||
}
|
||||
}
|
||||
if bestIndex < 0 {
|
||||
return symbolDef{}, false
|
||||
}
|
||||
return filtered[bestIndex], true
|
||||
}
|
||||
|
||||
// ResolveTypeName 把局部变量、别名或短名称解析为全限定类型名。
|
||||
func (resolver *TypeResolver) ResolveTypeName(ref string, contextPos int, contextModuleStart int, preferredPkg string, expectedKind string) (string, bool) {
|
||||
if resolver == nil {
|
||||
return "", false
|
||||
}
|
||||
|
||||
trimmed := strings.TrimSpace(ref)
|
||||
if trimmed == "" {
|
||||
return "", false
|
||||
}
|
||||
if looksLikeFullTypeName(trimmed) {
|
||||
return trimmed, true
|
||||
}
|
||||
|
||||
resolveBySymbol := func(symbol string, preferSameModule bool) (string, bool) {
|
||||
candidates := resolver.bySymbol[symbol]
|
||||
if len(candidates) == 0 {
|
||||
return "", false
|
||||
}
|
||||
moduleStart := 0
|
||||
if preferSameModule {
|
||||
moduleStart = contextModuleStart
|
||||
}
|
||||
best, ok := pickBestDefinition(candidates, contextPos, moduleStart, preferredPkg, expectedKind)
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
return best.TypeName, true
|
||||
}
|
||||
resolveByAlias := func(symbol string, targetModuleStart int) (string, bool) {
|
||||
candidates := resolver.byAlias[symbol]
|
||||
if len(candidates) == 0 {
|
||||
return "", false
|
||||
}
|
||||
best, ok := pickBestDefinition(candidates, contextPos, targetModuleStart, preferredPkg, expectedKind)
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
return best.TypeName, true
|
||||
}
|
||||
resolveByShort := func(symbol string, preferSameModule bool) (string, bool) {
|
||||
candidates := resolver.byShort[symbol]
|
||||
if len(candidates) == 0 {
|
||||
return "", false
|
||||
}
|
||||
moduleStart := 0
|
||||
if preferSameModule {
|
||||
moduleStart = contextModuleStart
|
||||
}
|
||||
best, ok := pickBestDefinition(candidates, contextPos, moduleStart, preferredPkg, expectedKind)
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
return best.TypeName, true
|
||||
}
|
||||
|
||||
if typeName, ok := resolveBySymbol(trimmed, !strings.Contains(trimmed, ".")); ok {
|
||||
return typeName, true
|
||||
}
|
||||
if typeName, ok := resolveByAlias(trimmed, 0); ok {
|
||||
return typeName, true
|
||||
}
|
||||
if typeName, ok := resolveByShort(trimmed, !strings.Contains(trimmed, ".")); ok {
|
||||
return typeName, true
|
||||
}
|
||||
|
||||
if strings.Contains(trimmed, ".") {
|
||||
parts := strings.Split(trimmed, ".")
|
||||
first := parts[0]
|
||||
last := parts[len(parts)-1]
|
||||
targetModuleStart := 0
|
||||
if imports := resolver.moduleImports[contextModuleStart]; imports != nil {
|
||||
targetModuleStart = imports[first]
|
||||
}
|
||||
if typeName, ok := resolveByAlias(last, targetModuleStart); ok {
|
||||
return typeName, true
|
||||
}
|
||||
if typeName, ok := resolveBySymbol(last, false); ok {
|
||||
return typeName, true
|
||||
}
|
||||
if typeName, ok := resolveByShort(last, false); ok {
|
||||
return typeName, true
|
||||
}
|
||||
if typeName, ok := resolveBySymbol(first, false); ok {
|
||||
return typeName, true
|
||||
}
|
||||
}
|
||||
|
||||
return "", false
|
||||
}
|
||||
|
||||
// fallbackTypeToken 从无法解析的引用生成合法类型占位名。
|
||||
func fallbackTypeToken(ref string) string {
|
||||
token := strings.TrimSpace(ref)
|
||||
if token == "" {
|
||||
return token
|
||||
}
|
||||
if strings.Contains(token, ".") {
|
||||
parts := strings.Split(token, ".")
|
||||
return parts[len(parts)-1]
|
||||
}
|
||||
return token
|
||||
}
|
||||
|
||||
// absInt 返回整数绝对值。
|
||||
func absInt(value int) int {
|
||||
if value < 0 {
|
||||
return -value
|
||||
}
|
||||
return value
|
||||
}
|
||||
Reference in New Issue
Block a user