idlize

Форк
0
/
SortingEmitter.ts 
144 строки · 5.5 Кб
1
/*
2
 * Copyright (c) 2024 Huawei Device Co., Ltd.
3
 * Licensed under the Apache License, Version 2.0 (the "License");
4
 * you may not use this file except in compliance with the License.
5
 * You may obtain a copy of the License at
6
 *
7
 * http://www.apache.org/licenses/LICENSE-2.0
8
 *
9
 * Unless required by applicable law or agreed to in writing, software
10
 * distributed under the License is distributed on an "AS IS" BASIS,
11
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
 * See the License for the specific language governing permissions and
13
 * limitations under the License.
14
 */
15

16
import { IndentedPrinter } from "../IndentedPrinter";
17
import * as ts from "typescript"
18
import { asString, getDeclarationsByNode, getNameWithoutQualifiersRight, heritageTypes, stringOrNone } from "../util";
19

20
export class SortingEmitter extends IndentedPrinter {
21
    currentPrinter?: IndentedPrinter
22
    emitters = new Map<string, IndentedPrinter>()
23
    deps = new Map<string, Set<string>>()
24

25
    constructor() {
26
        super()
27
    }
28

29
    private fillDeps(typeChecker: ts.TypeChecker, type: ts.TypeNode | undefined, seen: Set<string>) {
30
        if (!type) return
31
        if (ts.isTypeReferenceNode(type)) {
32
            if (seen.has(this.repr(type))) return
33
            seen.add(this.repr(type))
34
            let decls = getDeclarationsByNode(typeChecker, type.typeName)
35
            if (decls.length > 0) {
36
                let decl = decls[0]
37
                if (ts.isInterfaceDeclaration(decl)) {
38
                    decl.members
39
                        .filter(ts.isPropertySignature)
40
                        .forEach(it => this.fillDeps(typeChecker, it.type, seen))
41
                    decl.heritageClauses?.forEach(it => {
42
                        heritageTypes(typeChecker, it).forEach(it => this.fillDeps(typeChecker, it, seen))
43
                    })
44
                }
45
                if (ts.isClassDeclaration(decl)) {
46
                    decl.members
47
                        .filter(ts.isPropertyDeclaration)
48
                        .forEach(it => this.fillDeps(typeChecker, it.type, seen))
49
                    decl.heritageClauses?.forEach(it => {
50
                        heritageTypes(typeChecker, it).forEach(it => this.fillDeps(typeChecker, it, seen))
51
                    })
52
                }
53
                if (ts.isUnionTypeNode(decl)) {
54
                    decl.types
55
                        .forEach(it => this.fillDeps(typeChecker, it, seen))
56
                }
57
                /*
58
                if (ts.isTypeLiteralNode(decl)) {
59
                    decl.members
60
                        .filter(ts.isPropertyAssignment)
61
                        .forEach(it => this.fillDeps(typeChecker, i, seen))
62
                } */
63
            } else {
64
                console.log(`no decl for ${asString(type.typeName)}`)
65
            }
66
        } else if (ts.isUnionTypeNode(type)) {
67
            type.types.forEach(it => this.fillDeps(typeChecker, it, seen))
68
        }
69
    }
70

71
    startEmit(typeChecker: ts.TypeChecker, type: ts.TypeNode, name: string | undefined = undefined) {
72
        const repr = this.repr(type, name)
73
        if (this.emitters.has(repr)) throw new Error(`Already emitted ${type.getText()}`)
74
        let next = new IndentedPrinter()
75
        let seen = new Set<string>()
76
        this.fillDeps(typeChecker, type, seen)
77
        seen.delete(repr)
78
        this.deps.set(repr, seen)
79
        this.emitters.set(repr, next)
80
        this.currentPrinter = next
81
        if (seen.size > 0)
82
            console.log(`${repr}: depends on ${Array.from(seen.keys()).join(",")}`)
83
    }
84

85
    repr(type: ts.TypeNode, name: string | undefined = undefined): string {
86
        return ts.isTypeReferenceNode(type) ? getNameWithoutQualifiersRight(type.typeName)! : name!
87
    }
88

89
    printType(type: ts.TypeNode): string {
90
        return ts.isTypeReferenceNode(type)
91
            ? asString(type.typeName)
92
            : `${type.kind}:${ts.SyntaxKind[type.kind]}`
93
    }
94

95
    print(value: stringOrNone) {
96
        // console.log("print", this.currentPrinter, value)
97
        if (!this.currentPrinter) throw new Error("startEmit() first")
98
        if (value) this.currentPrinter.print(value)
99
    }
100

101
    pushIndent(): void {
102
        this.currentPrinter?.pushIndent()
103
    }
104

105
    popIndent(): void {
106
        this.currentPrinter?.popIndent()
107
    }
108

109
    getOutput(): string[] {
110
        let result: string[] = []
111
        let sortedTypes = this.getToposorted()
112
        sortedTypes.forEach(type => {
113
            let next = this.emitters.get(type)!.getOutput()
114
            result = result.concat(next)
115
        })
116
        return result
117
    }
118

119
    getToposorted(): Array<string> {
120
        // Not exactly correct for non-named types.
121
        let source = new Set(Array.from(this.emitters.keys()))
122
        let result: string[] = []
123
        // N^2, but nobody cares
124
        let added: Set<string> = new Set()
125
        while (source.size > added.size) {
126
            source.forEach(it => {
127
                if (added.has(it)) return
128
                let deps = this.deps.get(it)!
129
                let canAdd = true
130
                deps.forEach(dep => {
131
                    //console.log(`CHECK ${it} ${dep} ${source.has(dep)} ${!added.has(dep)}`)
132
                    if (source.has(dep) && !added.has(dep)) canAdd = false
133
                })
134
                if (canAdd && !added.has(it)) {
135
                    result.push(it)
136
                    added.add(it)
137
                }
138
                //console.log(`${it}: ${canAdd} depends on ${Array.from(deps).join(",")}`)
139
            })
140
        }
141
        // console.log(`DEPS [${result.join(", ")}]`)
142
        return result
143
    }
144
}

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.