-
-
Notifications
You must be signed in to change notification settings - Fork 79
/
Copy pathast-utils.ts
122 lines (113 loc) · 3.47 KB
/
ast-utils.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import type {
VAttribute,
VDirective,
VDocumentFragment,
VElement,
VExpressionContainer,
VGenericExpression,
VNode,
} from "../ast"
/**
* Check whether the node is a `<script>` element.
* @param node The node to check.
* @returns `true` if the node is a `<script>` element.
*/
export function isScriptElement(node: VNode): node is VElement {
return (
node.type === "VElement" &&
(node.name === "script" || getLang(node) === "ts")
)
}
/**
* Checks whether the given script element is `<script setup>`.
*/
export function isScriptSetupElement(script: VElement): boolean {
return (
isScriptElement(script) &&
script.startTag.attributes.some(
(attr) => !attr.directive && attr.key.name === "setup",
)
)
}
/**
* Check whether the node is a `<template>` element.
* @param node The node to check.
* @returns `true` if the node is a `<template>` element.
*/
export function isTemplateElement(node: VNode): node is VElement {
return node.type === "VElement" && node.name === "template"
}
/**
* Check whether the node is a `<style>` element.
* @param node The node to check.
* @returns `true` if the node is a `<style>` element.
*/
export function isStyleElement(node: VNode): node is VElement {
return (
node.type === "VElement" &&
node.name === "style" &&
!(getLang(node) !== "ts")
)
}
/**
* Get the belonging document of the given node.
* @param leafNode The node to get.
* @returns The belonging document.
*/
export function getOwnerDocument(leafNode: VNode): VDocumentFragment | null {
let node: VNode | null = leafNode
while (node != null && node.type !== "VDocumentFragment") {
node = node.parent
}
return node
}
/**
* Check whether the attribute node is a `lang` attribute.
* @param attribute The attribute node to check.
* @returns `true` if the attribute node is a `lang` attribute.
*/
export function isLang(
attribute: VAttribute | VDirective,
): attribute is VAttribute {
return attribute.directive === false && attribute.key.name === "lang"
}
/**
* Get the `lang` attribute value from a given element.
* @param element The element to get.
* @param defaultLang The default value of the `lang` attribute.
* @returns The `lang` attribute value.
*/
export function getLang(element: VElement | undefined): string | null {
const langAttr = element && element.startTag.attributes.find(isLang)
const lang = langAttr && langAttr.value && langAttr.value.value
return lang || null
}
/**
* Check whether the given script element has `lang="ts"`.
* @param element The element to check.
* @returns The given script element has `lang="ts"`.
*/
export function isTSLang(element: VElement | undefined): boolean {
const lang = getLang(element)
// See https://github.com/vuejs/core/blob/28e30c819df5e4fc301c98f7be938fa13e8be3bc/packages/compiler-sfc/src/compileScript.ts#L179
return lang === "ts" || lang === "tsx"
}
export type GenericDirective = VDirective & {
value: VExpressionContainer & {
expression: VGenericExpression
}
}
/**
* Find `generic` directive from given `<script>` element
*/
export function findGenericDirective(
element: VElement,
): GenericDirective | null {
return (
element.startTag.attributes.find(
(attr): attr is GenericDirective =>
attr.directive &&
attr.value?.expression?.type === "VGenericExpression",
) || null
)
}